@@ -341,32 +341,51 @@ const std::map<uint32_t, Altera::max10_mem_t> Altera::max10_memory_map = {
341341 },
342342};
343343
344- /* Write an arbitrary file in UFM1 and UFM0
345- * FIXME: in some mode its also possible to uses CFM2 & CFM1
344+ /* Write an arbitrary file in UFM1, UFM0 by default and also CFM2 and CFM1 if
345+ * requested.
346346 */
347- bool Altera::max10_program_ufm (const Altera::max10_mem_t *mem, unsigned int offset)
347+ bool Altera::max10_program_ufm (const Altera::max10_mem_t *mem, uint32_t offset,
348+ uint8_t update_sectors)
348349{
350+ uint32_t start_addr = 0 ; // 32bit align
351+ uint32_t end_addr = 0 ; // 32bit align
352+ uint8_t erase_sectors_mask;
353+
354+ /* check CFM0 is not mentionned */
355+ if (update_sectors & (1 << 4 ))
356+ std::runtime_error (" Error: CFM0 cant't be used to store User Binary" );
357+
358+ /* First task: search for the first and the last sector to use */
359+ sectors_mask_start_end_addr (mem, update_sectors,
360+ &start_addr, &end_addr, &erase_sectors_mask);
361+
349362 RawParser _bit (_filename, true );
350363 _bit.parse ();
351- _bit.displayHeader ();
364+ if (_verbose)
365+ _bit.displayHeader ();
366+
352367 const uint8_t *data = _bit.getData ();
353368 const uint32_t length = _bit.getLength () / 8 ;
354- const uint32_t base_addr = mem->ufm_addr + offset;
369+ const uint32_t base_addr = start_addr + offset / 4 ; // 32bit align
370+ const uint32_t flash_len = (end_addr - base_addr) * 4 ; // Byte align
355371
356- uint8_t *buff = ( uint8_t *) malloc (length);
357- if (!buff ) {
358- printError (" max10_program_ufm: Failed to allocate buffer " );
372+ /* check */
373+ if (base_addr > end_addr ) { // wrong offset
374+ printError (" Error: start offset is out of xFM region " );
359375 return false ;
360376 }
361-
362- /* check */
363- const uint32_t ufmx_len = 4 * (mem->ufm_len [0 ] + mem->ufm_len [1 ]);
364- if (base_addr > length) {
365- printError (" Error: start offset is out of UFM region" );
377+ if (flash_len < length) { // too big file
378+ printError (" Error: no enough space to write\n " );
379+ return false ;
380+ }
381+ if (base_addr + (length / 4 ) > end_addr) {
382+ printError (" Error: end address is out of xFM region" );
366383 return false ;
367384 }
368- if (base_addr + length > ufmx_len) {
369- printError (" Error: end address is out of UFM region" );
385+
386+ uint8_t *buff = (uint8_t *)malloc (length);
387+ if (!buff) {
388+ printError (" max10_program_ufm: Failed to allocate buffer" );
370389 return false ;
371390 }
372391
@@ -377,18 +396,23 @@ bool Altera::max10_program_ufm(const Altera::max10_mem_t *mem, unsigned int offs
377396 }
378397 }
379398
399+ printf (" %x %x %x %x\n " , update_sectors, erase_sectors_mask,
400+ base_addr, end_addr);
401+
380402 // Start!
381403 max10_flow_enable ();
382404
383- /* Erase UFM1 & UFM0 */
384- printInfo (" Erase UFM " , false );
385- max10_flow_erase (mem, 0x3 );
405+ /* Erase xFM sectors */
406+ printInfo (" Erase xFM " , false );
407+ max10_flow_erase (mem, erase_sectors_mask );
386408 printInfo (" Done" );
387409
388- /* Program UFM1 & UFM0 */
410+ /* Program xFM */
389411 // Simplify code:
390- // UFM0 follows UFM1, so we don't need to iterate
391- printInfo (" Write UFM" );
412+ // UFM0 follows UFM1,
413+ // CFM2 follow UFM0, etc...
414+ // so we don't need to iterate
415+ printInfo (" Write xFM" );
392416 writeXFM (buff, base_addr, 0 , length / 4 );
393417
394418 /* Verify */
@@ -417,8 +441,12 @@ void Altera::max10_program(unsigned int offset)
417441 }
418442 const Altera::max10_mem_t mem = mem_map->second ;
419443
444+ /* Check for a full update or only for a subset */
445+ update_sectors = max10_flash_sectors_to_mask (_flash_sectors);
446+
420447 if (_file_extension != " pof" ) {
421- max10_program_ufm (&mem, offset);
448+ max10_program_ufm (&mem, offset,
449+ (_flash_sectors.size () == 0 ) ? 0 : update_sectors);
422450 return ;
423451 }
424452
@@ -471,39 +499,17 @@ void Altera::max10_program(unsigned int offset)
471499
472500 // UFM Mapping
473501 ufm_data[1 ] = _bit.getData (" UFM" );
474- ufm_data[0 ] = &ufm_data[1 ][mem.ufm_len [0 ] * 4 ]; // Just after UFM1 (but size may differs
502+ ufm_data[0 ] = &ufm_data[1 ][mem.ufm_len [1 ] * 4 ]; // Just after UFM1 (but size may differs
475503
476504 // CFM Mapping
477- cfm_data[2 ] = &ufm_data[0 ][mem.ufm_len [1 ] * 4 ]; // First CFM section in FPGA internal flash
505+ cfm_data[2 ] = &ufm_data[0 ][mem.ufm_len [0 ] * 4 ]; // First CFM section in FPGA internal flash
478506 cfm_data[1 ] = &cfm_data[2 ][mem.cfm_len [2 ] * 4 ]; // Second CFM section but just after CFM2
479507 cfm_data[0 ] = &cfm_data[1 ][mem.cfm_len [1 ] * 4 ]; // last CFM section but just after CFM1
480508
481509 // DSM Mapping
482510 const uint8_t *dsm_data = _bit.getData (" ICB" );
483511 const int dsm_len = _bit.getLength (" ICB" ) / 32 ; // getLength (bits) dsm_len in 32bits word
484512
485- /* Check for a full update or only for a subset */
486- if (_flash_sectors.size () > 0 ) {
487- const std::vector<std::string> sectors = splitString (_flash_sectors, ' ,' );
488- update_sectors = 0 ;
489- for (const auto §or: sectors) {
490- if (sector == " UFM1" )
491- update_sectors |= (1 << 0 );
492- else if (sector == " UFM0" )
493- update_sectors |= (1 << 1 );
494- else if (sector == " CFM2" )
495- update_sectors |= (1 << 2 );
496- else if (sector == " CFM1" )
497- update_sectors |= (1 << 3 );
498- else if (sector == " CFM0" )
499- update_sectors |= (1 << 4 );
500- else
501- throw std::runtime_error (" Unknown sector " + sector);
502- }
503- } else { // full update
504- update_sectors = 0x1F ;
505- }
506-
507513 // Start!
508514 max10_flow_enable ();
509515
@@ -913,6 +919,79 @@ bool Altera::max10_dump()
913919 return true ;
914920}
915921
922+ uint8_t Altera::max10_flash_sectors_to_mask (std::string flash_sectors)
923+ {
924+ uint8_t mask = 0 ;
925+
926+ if (flash_sectors.size () > 0 ) {
927+ const std::vector<std::string> sectors = splitString (flash_sectors, ' ,' );
928+ for (const auto §or: sectors) {
929+ if (sector == " UFM1" )
930+ mask |= (1 << 0 );
931+ else if (sector == " UFM0" )
932+ mask |= (1 << 1 );
933+ else if (sector == " CFM2" )
934+ mask |= (1 << 2 );
935+ else if (sector == " CFM1" )
936+ mask |= (1 << 3 );
937+ else if (sector == " CFM0" )
938+ mask |= (1 << 4 );
939+ else
940+ throw std::runtime_error (" Unknown sector " + sector);
941+ }
942+ } else { // full update
943+ mask = 0x1F ;
944+ }
945+
946+ return mask;
947+ }
948+
949+ bool Altera::sectors_mask_start_end_addr (const Altera::max10_mem_t *mem,
950+ const uint8_t update_sectors, uint32_t *start, uint32_t *end,
951+ uint8_t *sectors_mask)
952+ {
953+ uint32_t saddr = mem->ufm_addr ;
954+ uint32_t eaddr = saddr;
955+ uint8_t start_bit = 0 , end_bit = 0 ;
956+ /* For sake of simplicity: create an array with all length aligned
957+ * as it in MAX10 devices
958+ */
959+ const uint32_t mem_map_length[] = {
960+ mem->ufm_len [1 ], mem->ufm_len [0 ],
961+ mem->cfm_len [2 ], mem->cfm_len [1 ]
962+ };
963+
964+ if (update_sectors == 0 ) {
965+ eaddr = mem->ufm_addr + (mem->ufm_len [0 ] + mem->ufm_len [1 ]);
966+ *sectors_mask = 0x3 ;
967+ } else {
968+ /* eaddr start with full memory size */
969+ for (uint8_t i = 0 ; i < 4 ; i++)
970+ eaddr += mem_map_length[i];
971+ /* search first bit == 1 and increment start address */
972+ for (uint8_t i = 0 ; i < 4 ; i++) {
973+ if (update_sectors & (1 << i)) {
974+ start_bit = i;
975+ break ;
976+ }
977+ saddr += mem_map_length[i];
978+ }
979+
980+ /* decrement eaddr until last bit == 1 found */
981+ for (uint8_t i = 3 ; i >= 0 ; i--) {
982+ if (update_sectors & (1 << i)) {
983+ end_bit = i + 1 ;
984+ break ;
985+ }
986+ eaddr -= mem_map_length[i];
987+ }
988+ *sectors_mask = ((1 << end_bit) - 1 ) - ((1 << start_bit) - 1 );
989+ }
990+ *start = saddr;
991+ *end = eaddr;
992+ return true ;
993+ }
994+
916995/* SPI interface */
917996
918997int Altera::spi_put (uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len)
0 commit comments