UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor psg_
Visitor
457 Views
Registered: ‎06-24-2018

Programming to boot from flash

Jump to solution

Hi all, 

 

I am trying to do something which sounds easy, however I am unable to figure it out and have whilst I have seen a number of similar queries for older designs, it doens't seem to apply to what I am doing. 

My knowledge of formal FPGA terminology isn't that great so I will try to describe in high level and basic terms. 

My Goal: I have a VC707 evaluation board, which has a microblaze design running on the Virtex 7 FPGA.  The design is the Analog Devices FMCOMMS3 no-OS application.  I would like to power up the board and have microblaze + FMCOMMS3 application, load directly from the BPI flash. 

Current Progress:  I generated the bitstream, exported the .HDF file and loaded the FMCOMMS3 application in SDK.  I can run the application in debug mode and it does everything I want it to do in this mode.  I control the design through a terminal window which outputs some information once the application has loaded.  As I understood, these were the next steps:

1. Open Vivado and associate the .ELF file with the design

2. regenerate the bitstream

3. Create a .MCS file from this new bitstream. 

4. Specify the memory device.

5. program the memory using the .MCS file

 

When I do these 5 steps, I no longer get any output on my terminal window, however if I 'run configuration' using SDK, without resetting or programming a bitstream, the application works.  

It appears as though the bit file has loaded into flash correctly, however the application itself does not load.  Is it a simple change to the linker script to get this working properly or have I not followed the correct process?

 

Any help would be much appreciated. 

 

Phil

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Visitor psg_
Visitor
290 Views
Registered: ‎06-24-2018

Re: Programming to boot from flash

Jump to solution

Hi all, 

Quick update:  I have successfully been able to update the flash memory to boot from power up.  I will post a brief description of how I solved the issue, if you would like more details, then please feel free to message me or request in this thread.

Resolution: 

My app.ELF file was too large to fit into block RAM (BRAM), so I had to store it in Flash memory.  To load this image successfully, I needed to initialise the BRAM strings in the bitstream, with a small SREC bootloader, which fetches the app.ELF from Flash and loads it to DDR memory, for runtime execution. 

Tools:

Vivado 2018.2

Xilinx SDK 2018.2

VC707 Evaluation kit

Process:

1. Generate a bitstream from block diagram in Vivado and export the hardware definition file (system.HDF)

2. Open SDK and define a new application project called app.ELF, based on system.HDF which was just exported from Vivado.  Create it as a blank project.

3. Generate linker Script and ensure that all of the 'Section to Memory Region Mapping' sections are loading from DDR.

4. Place all C application files in the src directory and build the .ELF (Default behaviour is automatic build)

5. Still in SDK and using the xcst console, enter the following command mb-objcopy -O srec app.elf app.srec     
-This simply takes the app.ELF and converts it to app.SREC.  This SREC format is a bootable format to store in flash

6. Create a new application project, using the same .HDF.  This will be a 'SREC Bootloader' application project. 

7. Generate linker script for this SREC Bootloader and ensure that all of the sections load from ilmb (BRAM).

8. Navigate to the blconfig.h file in the src directory for the SREC bootloader and set a value for  FLASH_IMAGE_BASEADDR.  The value which you set should be as follows........FLASH_IMAGE_BASEADDR = Flash_base_address + OFFSET.   The Flash_base_address is viewable in your linker script for your app.ELF.  See image below:

 

linker script flash size.PNG

The OFFSET value, is so you can offset your app.srec image to leave room for the bitstream to be stored. For my example I used 0x01200000 as my OFFSET.

9. Go back to Vivado and in your block diagram, associate the SREC_bootloader.ELF file with the design.  Ensure that you update your associated ELF file so that it is using your SREC_bootloader.ELF rather than mb_bootloop_le.elf.  Please see the image below for my example (my app.ELF = MT_SREC_bootloader.ELF)

associate ELF.PNG

10. Re-generate the bitstream.  This will initialise your BRAM with the SREC bootloader. This should produce a fresh system.bit file.

11. Generate the memory configuration files for programming to your Flash device. Execute the following commands from the tcl console within Vivado.  I believe you can combine these two commands into the one line, however it wasn't working for me, probably due to the fact that for this device it seemed to work if I only specified an interface argument for the bitstream instead of for both. 

write_cfgmem -format MCS -size 128 -loaddata "up 0x01200000 app.srec" -force app_sw.MCS
 
write_cfgmem -format MCS -interface BPIx16 -size 128 -loadbit "up 0x00000000 system.bit" -force app_bit.MCS
 
NOTE: The VC707 uses a BPIx16 flash interface. I have set my bitstream to load from address 0x00000000 and my app.srec (app_sw.mcs) to load from address 0x01200000, which in this example, is the OFFSET mentioned above. 
 
12. Opening the hardware manager, add the memory configuration device and then 'Program the configuration memory device'.  First, select the app_sw.MCS file and specify the address range to be 'Entire configuration memory device'.  This erases the full memory device and place my app.srec into 0x01200000.
13. Program the configuration device again, however this time the app_bit.MCS file will be used. Only specify an address range of 'Configuration file only'.  This will only erase the range of memory associated with the bitstream and only program that range of the flash.
14.  Once this has finished, you will need to right click on your device in hardware manager and click 'Boot from configuration memory device'.  
 
Phew.......It's a long process and I will be looking to script it. 
 
If anybody would like to try and provide some feedback as to whether or not this works for them, I would greatly appreciate it!
 
Goodluck!
 
Phil
8 Replies
Scholar dgisselq
Scholar
396 Views
Registered: ‎05-21-2015

Re: Programming to boot from flash

Jump to solution

Is the application itself running and not just the terminal window?  If you toggle an LED, does it toggle after loading?

Dan

0 Kudos
Visitor psg_
Visitor
354 Views
Registered: ‎06-24-2018

Re: Programming to boot from flash

Jump to solution

Hi Dan, 

 

I tried simply toggling an LED and it doesn't work. 

 

Phil

0 Kudos
Scholar dgisselq
Scholar
343 Views
Registered: ‎05-21-2015

Re: Programming to boot from flash

Jump to solution

Just to be sure ... you created a design with no microblaze, and no flash, and just toggled an LED and you were unable to load it onto the device?

Dan

0 Kudos
Visitor psg_
Visitor
337 Views
Registered: ‎06-24-2018

Re: Programming to boot from flash

Jump to solution

My mistake, I understand you now! I am able to toggle an LED if I load a very simple bitstream (No MB, No BPI flash).

 

Perhaps I have a poor conceptual understanding of what needs to happen to program the flash memory to boot the application.  It may seem very trivial, but would you be able to outline step by step what is required to load an application into memory and have it boot upon power up?  Do you have experience with doing this in a current setup?  I'll take a shot at what I think the process is:

1. VIVADO - Starting with a block diagram, run synthesis + implementation + generate bitstream.

2. VIVADO - Export Hardware definition File (.HDF file) to SDK

3. VIVADO - download bitstream (.BIT file) to FPGA

4. SDK - Create a new project with the .HDF file and generate linker script

5. SDK - Code application and test in debug mode.  

6. VIVADO - Using the .ELF file created when building and testing the application in debug mode, associate with block design

7. VIVADO - Regenerate bitstream file (.BIT)

8. VIVADO - Generate Memory COnfiguration file (.MCS)

9. VIVADO - Add configuration memory device

10. VIVADO - Program flash memory

Some file types I don't properly understand are .SREC files and also linker scripts, specifically heap and stack size.  Do I need to have a SREC file to make this work or is it perhaps an issue with the linker script heap and stack sizes?  Is there a way I can detemine what values I should set for heap and stack size?

The instructions I have seen online throughout documentation and other threads seems to be for older versions of Vivado, SDK and even iMPACT.  I have been unable to find an up-to-date set of instructions.  

 

Best Regards, 

 

Phil

0 Kudos
Scholar dgisselq
Scholar
331 Views
Registered: ‎05-21-2015

Re: Programming to boot from flash

Jump to solution

@psg_,

Would you believe I've never used either MicroBlaze nor the Xilinx SDK?  I've been working with an open source CPU I call the ZipCPU.  Some of the steps match, but many do not.  So while I might have insight into some of your questions below, I really need to let someone more experienced with MicroBlaze answer.

Were this my own flow, I would ...

  1. Adjust the hardware components composing the design
  2. Run AutoFPGA to connect them together
  3. AutoFPGA creates the toplevel design, a main design beneath it, header files describing each of my peripherals, and the linker script
  4. At this point, I can build any .bit files or simulations--everything is present, even though the software isn't
  5. I can then use the linker script to build any software I might wish to use
  6. I might then build my software and simulate the design (using Verilator), or
  7. Alternative (if I think simulation works) I can load the design onto the board.  Typically when I do this, the CPU is off.  Once the design is on the board, I can then use the design to load and start different programs onto the board.  Sometimes this loads the design into flash, sometimes not, depending upon my needs.
  8. In my case and flow, the software is placed onto the flash as a separate step disconnected from the build step, but certainly a necessary step any time the design gets reconfigured.

As built currently, this flow only works with "Wishbone" components, not (yet) with AXI so ... you might struggle to swap flows.

I've only recently adjusted this flow so that I can load and run a program from an SD card.  That requires creating a (block ROM), using a special linker script and program (no C standard library--sort of like grub for Linux or "BIOS" for Windows).  This program then loads an SD card file into RAM and jumps to the first address of RAM.  I've thought of using this file to then program the flash, but haven't gotten that far.  All my work is open source if you are interested, but I digress.

None of this is what you are asking for, so let me answer what I can:

  1. The first problem is that "how much memory" is within your design, and where that memory maps to in your designs address space can change.  That needs to be fixed before the software can be built, so Vivado would need to examine your design, assign addresses to memory components, and generate a linker script.
  2. Sorry, I don't understand SREC files either, although I do understand linker scripts somewhat
  3. Sometimes you can estimate stack size by estimating how deep your design will ever get into recursions, and then measure the size of the local variables on the stack at every level.  This is only approximate--it doesn't capture the space required for saved registers, nor does it capture the space required for internal library routine calls over which you have no control.  Another method of estimating stack size is to interrupt the CPU mid-execution and measure the stacks location.  Alternately, you can just eyeball a number and change it if/when things fail.
  4. The same is true of the heap.  Unlike the stack, the heap grows with every call to malloc(), so sometimes you can estimate how many times you'll call malloc() and how much memory your design will need in those calls.  Again, this works if you aren't using a standard library, because the standard library (which creates the malloc call) is going to use some amount as well.  Perhaps you might want to run your design and try to do a malloc.  If it comes back successfully, and library routines are working, then you have enough space.

I understand these are really insufficient answers, so I'm going to hope someone else offers a better answer.

Dan

Visitor psg_
Visitor
327 Views
Registered: ‎06-24-2018

Re: Programming to boot from flash

Jump to solution

Thanks for the comprehensive response!  Whilst it doesn't directly solve or point me to a solution for what I am doing, I really appreciate the explanation of stack and heap and how they relate to the application I am designing. 

 

I also enjoy hearing about other projects and what you're doing for them.  Having been an RF and photonics engineer for 5 years, the digital domain is all new to me so piecing together teminology, architecture and design flow for multi-generation integrated tools with a self-learning approach is tricky!

 

Thanks again.

 

Phil

0 Kudos
Visitor psg_
Visitor
314 Views
Registered: ‎06-24-2018

Re: Programming to boot from flash

Jump to solution

Quick update:

Here is a screenshot of my linker script:

Linker_script_setup.PNG

From what I can understand, associating a .ELF file in  Vivado actually populates the BRAM init strings and is actually placing the ELF file into soft controller memory.  What I have in this linker script has 'axi_ddr_cntrl' throughout.  Intuitively, I would say this is trying to store everything into external DDR memory, is this correct?  Would that then mean that when I associate the .ELF file in Vivado and create the .MCS, the bitstream loads from flash, but is then trying to look in DDR memory for the .ELF, when I have actually placed the .ELF in BRAM?  This would explain why I see nothing happening.  

 

If these assumptions are all correct, then what do I change in my linker script to 'point' the boot process at my ELF file?  I believe the 'sys_ilmb_cntlr' is the BRAM controller, but how do I determine if my base address and size is correct?  Also, which 'Section Name' would I change to use as the 'sys_ilmb_cntlr'?

 

Best Regards,

 

Phil

0 Kudos
Highlighted
Visitor psg_
Visitor
291 Views
Registered: ‎06-24-2018

Re: Programming to boot from flash

Jump to solution

Hi all, 

Quick update:  I have successfully been able to update the flash memory to boot from power up.  I will post a brief description of how I solved the issue, if you would like more details, then please feel free to message me or request in this thread.

Resolution: 

My app.ELF file was too large to fit into block RAM (BRAM), so I had to store it in Flash memory.  To load this image successfully, I needed to initialise the BRAM strings in the bitstream, with a small SREC bootloader, which fetches the app.ELF from Flash and loads it to DDR memory, for runtime execution. 

Tools:

Vivado 2018.2

Xilinx SDK 2018.2

VC707 Evaluation kit

Process:

1. Generate a bitstream from block diagram in Vivado and export the hardware definition file (system.HDF)

2. Open SDK and define a new application project called app.ELF, based on system.HDF which was just exported from Vivado.  Create it as a blank project.

3. Generate linker Script and ensure that all of the 'Section to Memory Region Mapping' sections are loading from DDR.

4. Place all C application files in the src directory and build the .ELF (Default behaviour is automatic build)

5. Still in SDK and using the xcst console, enter the following command mb-objcopy -O srec app.elf app.srec     
-This simply takes the app.ELF and converts it to app.SREC.  This SREC format is a bootable format to store in flash

6. Create a new application project, using the same .HDF.  This will be a 'SREC Bootloader' application project. 

7. Generate linker script for this SREC Bootloader and ensure that all of the sections load from ilmb (BRAM).

8. Navigate to the blconfig.h file in the src directory for the SREC bootloader and set a value for  FLASH_IMAGE_BASEADDR.  The value which you set should be as follows........FLASH_IMAGE_BASEADDR = Flash_base_address + OFFSET.   The Flash_base_address is viewable in your linker script for your app.ELF.  See image below:

 

linker script flash size.PNG

The OFFSET value, is so you can offset your app.srec image to leave room for the bitstream to be stored. For my example I used 0x01200000 as my OFFSET.

9. Go back to Vivado and in your block diagram, associate the SREC_bootloader.ELF file with the design.  Ensure that you update your associated ELF file so that it is using your SREC_bootloader.ELF rather than mb_bootloop_le.elf.  Please see the image below for my example (my app.ELF = MT_SREC_bootloader.ELF)

associate ELF.PNG

10. Re-generate the bitstream.  This will initialise your BRAM with the SREC bootloader. This should produce a fresh system.bit file.

11. Generate the memory configuration files for programming to your Flash device. Execute the following commands from the tcl console within Vivado.  I believe you can combine these two commands into the one line, however it wasn't working for me, probably due to the fact that for this device it seemed to work if I only specified an interface argument for the bitstream instead of for both. 

write_cfgmem -format MCS -size 128 -loaddata "up 0x01200000 app.srec" -force app_sw.MCS
 
write_cfgmem -format MCS -interface BPIx16 -size 128 -loadbit "up 0x00000000 system.bit" -force app_bit.MCS
 
NOTE: The VC707 uses a BPIx16 flash interface. I have set my bitstream to load from address 0x00000000 and my app.srec (app_sw.mcs) to load from address 0x01200000, which in this example, is the OFFSET mentioned above. 
 
12. Opening the hardware manager, add the memory configuration device and then 'Program the configuration memory device'.  First, select the app_sw.MCS file and specify the address range to be 'Entire configuration memory device'.  This erases the full memory device and place my app.srec into 0x01200000.
13. Program the configuration device again, however this time the app_bit.MCS file will be used. Only specify an address range of 'Configuration file only'.  This will only erase the range of memory associated with the bitstream and only program that range of the flash.
14.  Once this has finished, you will need to right click on your device in hardware manager and click 'Boot from configuration memory device'.  
 
Phew.......It's a long process and I will be looking to script it. 
 
If anybody would like to try and provide some feedback as to whether or not this works for them, I would greatly appreciate it!
 
Goodluck!
 
Phil