0

This question uses some Xilinx-specific terminology.

I'm currently working with a Zynq Ultrascale+ MPSoC (CPU + FPGA in same package). I'm using a QSPI flash chip to hold the CPU configuration code, FPGA bitstream, and application (.elf). I need to transfer const data from flash to ram (external DDR) upon device initialization. There is no OS running. What's the best way to achieve this? I think I have a couple options:

1) Use BOOTGEN (flash image generation tool) to somehow store the data at a specific location in flash (not sure if this is even possible?). Then I can modify the FSBL to do a memcpy() after the DDR initialization. For the memcpy(), I would have to use the physical addresses of both the source and destination.

2) Write a C program that contains an array of const data. BOOTGEN would figure out where to locate this data in flash so I wouldn't have to worry about that. Then I could perform a memcpy() with my array as source data and a physical DDR address for the destination.

This data will eventually be accessed by the FPGA, so in either case I would have to mark out a section of DDR as reserved and non-cacheable.

Do either of these options seem reasonable? Is there a better way?

pr871
  • 1,167
  • 10
  • 23
  • How does exectuable code get from the SPI flash into the processor? Typical C startup routines will copy initialized constant data from flash to RAM as configured by the linker map, but that assumes directly addressable memories. Typically one doesn't execute out of SPI flash, but rather the hardware copies some bootloader stub to an internal SRAM, that initializes the DDR and then copies the main bootloader or mini application or whatever to DDR. – Chris Stratton May 25 '20 at 18:12
  • If the SPI flash is being read by the configuration logic of the FPGA you may be able to get the initial bit of code pre-loaded as part of that. Overall it's probably a situation where you should look at what demo projects do, and extend from whatever mechanisms they use or the documentation mentions. – Chris Stratton May 25 '20 at 18:17
  • What I have done in similar situations is taken a very careful look at the mechanisms available. A workable solution is always in the documentation, if you read it carefully enough, and if you understand in-detail how your tool chains work. Additionally, most C compilers include a linker input file which you can use to specifically locate "segments" anywhere you want into the final image. So I take all these things into account and generate the flash image I need. It ***always*** works if you have read through the documentation well enough and arrange things, accordingly. – jonk May 25 '20 at 18:46
  • @jonk So what's I'm hearing is to declare the data in a standard C program, and then modify the linker script to make sure it ends up in an appropriate place in the DDR? I won't even have to do anything in the C program? Just having the data structure declared should be enough? – pr871 May 25 '20 at 18:52
  • 1
    @pr871 "Just having the data structure declared should be enough?" -- Hell no! Why would you think so? Cripes. You have to thoroughly read ALL of the documentation. If you are the hardware engineer here and you won't be coding the application, then you will need to work out all of the necessary details and then ***document them, in detail*** so that others can use your work product, with clarity. In other words, you cannot escape knowing everything required to make a working application, even if you won't actually be writing the C code. You may have to specify the tool chain. Not coding? – jonk May 25 '20 at 18:56
  • @jonk I didn't mean it like that. I just meant that I shouldn't have to do any memcpy(). Because the linker will ensure that the data structure is copied from flash to DDR in the location that I specify when I modify the linker script, correct? – pr871 May 25 '20 at 19:01
  • @pr871 You need to fully understand how C compilers "view" their world and then how the linker tools they provide accept "control files" which can direct the linking process, under manual control. (Most include methods for this, but not all of them do.) The hardware itself will often have "built-in mechanisms," at power-up, which can reference non-volatile memory and read it. I don't know anything about the device you are using. It looks wonderful and ***expensive***, so it is way out of the league of instrumentation I've worked on in the past (lower cost, lower power.) – jonk May 25 '20 at 19:07
  • @pr871 An example case is the Analog Devices ADSP-21xx (which I used, extensively.) This device is a DSP with two separate RAM memory spaces and it doesn't execute out of external memory. So it supports various "booting mechanisms" which, at power-on, automatically read external non-volatile memory to fill its RAM (code space.) I had to carefully apply the C compiler tools, and assembly work I was doing, and their shared linker to generate the binary I needed. The RAM was way smaller, so I had to page in different routines from external ROM when needed, too. Not hard, but detailed work. – jonk May 25 '20 at 19:15
  • @jonk Ok, sounds good. I think this is the right path. I'll just have to watch for pitfalls as you say. – pr871 May 25 '20 at 19:22
  • @pr871 Also see [my discussion here](https://electronics.stackexchange.com/a/453731/38098) and this external site: [Memory Layout of C Programs](https://www.geeksforgeeks.org/memory-layout-of-c-program/). – jonk May 25 '20 at 20:01

0 Answers0