Forum Discussion
NIOSII addressing for 32 bit wide SDRAM
Hello, first time poster here.
As the title suggests, I have an FPGA accessing a 32 bit wide DDR2 device (actually 2x 16 bit devices with appropriately shared signals). Using SOPC builder to generate a simple system with mainly NIOSII/f and one HPCII DDR2 controller. The controller is running full rate which means the "local width" is 64 bits. The DDR2 size is 256MB so the span is 0x10000000 (bytes) and the base address is 0x20000000 in SOPC. I am trying to confirm how to access all of the memory. Should I use IOWR/IORD or IOWR_32DIRECT/IORD_32DIRECT? If I use IOWR_32DIRECT/IORD_32DIRECT then should I read/write as: IOWR_32DIRECT(BASE, 0, val); IOWR_32DIRECT(BASE, 4, val); IOWR_32DIRECT(BASE, 8, val); ... IOWR_32DIRECT(BASE, 0xFFFFFFC, val); else should the address increments be multiples of 8. Else what? Thank-you.27 Replies
- Altera_Forum
Honored Contributor
May seem like a silly question but I ask because when using inc of 8 and writing
data=addr to the given addr then values are all unique and read value = written value. But with 8 then the memory span seems incorrect and I can't go beyond 0x10000000 else read all F's. It also does not seem logical to use 8 as I believe we are using byte addressing and a 32DIRECT access would hit 4 of these byte addresses at a time. However, when using 4x addressing there is 2x duplication between subsequent addresses when reading back. There could be timing issues relating to this but I wanted to make sure that I am at least doing the right thing in the NIOS code first. Thank-you. - Altera_Forum
Honored Contributor
The IOWR/IORD macros assume word addressing (32-bit). I recommend being explicit and just use the width specific macros: IORD_<8/16/32>DIRECT and IOWR_<8/16/32>DIRECT. This way you can use them to access narrow data and won't have some confusing mix of the two macro types in your code.
So by using the _32DIRECT macros you are correctly incrementing the address by 4 bytes at a time. To debug the issue you are seeing I recommend simulating the design. Write a few values out to the memory and then read them back and watch the transactions on the fabric to see if you are getting what you expect returned in hardware. - Altera_Forum
Honored Contributor
Thanks for the reply, BadOmen.
As mentioned: >>Using SOPC builder to generate a simple system with mainly NIOSII/f and one >>HPCII DDR2 controller. Would you recommend trying to close timing on this project before anything else though? If so, if I am going to run this thing at 200MHz with a -6 ArriaIIGX then perhaps I need to alter the HDL indirectly through SOPC changes(either parametric for the given current components or architecturally by for example adding a pipelining bridge) as "Report Timing" in Timequest shows a number of violations(neg slack) even for clk to clk transfers(ie. launch and latch clock are the same). Hints here? SignalTap of use here also versus setting up sims? Your thoughts? Regards. - Altera_Forum
Honored Contributor
Yes you should close timing before expecting your software to work. Same goes for using Signaltap II. I also would prototype at a much lower speed to start, make sure the memory accesses are functional, and then crank the clock up.
If you simulate this system you won't need to meeting timing since you'll just be verifying it at a functional timing level. After the functionality looks right in simulation then you could move on closing timing. clk to clk transfers are going to be the majority of your design (register to register transfers will normally be on the same domain). If the TNS (total negative slack) is close to 0 then you could probably just do some Quartus II setting tweaks to meet timing. If the TNS is high then you might need architectural changes to achieve 200MHz. - Altera_Forum
Honored Contributor
Thanks again, BadOmen.
On the topic of timing closure: I have noticed even for clk to clk transfers that some designers use constraints such as set_max_delay to fix the offending constraints. Is this good practice or are we just asking for trouble and should this only be done as a last resort? Or should, as you say, procedures such as HDL modifications, architectural changes, or Quartus settings tweaks(for small TNS) be explored first? >>>you could probably just do some Quartus II setting tweaks to meet timing. Perhaps using the Quartus tool "advisors" for this or are they not so good? Perhaps if the violation count is low then one might opt for constraining the few violating paths but in my case there are too many to count so probably I need to either lower the clock speed or make some architectural changes and not even think about trying to constrain with say set_max_delay, eh? Or perhaps entertain a faster part (ie. -4)? Thoughts? Regards. - Altera_Forum
Honored Contributor
It is difficult to say what would be a good or bad constraint without knowing the design. I would take a look at the Timequest documentation to learn the best practices. Also for the SDRAM you have added it's automatically generated constraints to your Quartus project correct?
- Altera_Forum
Honored Contributor
Thanks,
>>I would take a look at the Timequest documentation to learn the best practices. I have read through mountains of material and took the approx one hour online training and saw little practical value there. I found that the online training lacked examples of the nature "here is a violation and here is how we fix it and here is why we do it this way." Same thing with the TimeQuest docs. They seem to focus on "here are the tools and good luck." Hence the questions. :) >>Also for the SDRAM you have added it's automatically generated constraints to your >>Quartus project correct? That is correct. Actually, when I contacted support about failing constraints they made a couple of changes to the proj settings and gave me an additional.sdc file to further constrain the DDR which had a bunch of constraints like: set_max_delay -to [get_keepers *stage_counter\[*] 10.459 They have not solved my problems so I turn to the forum. Regards. - Altera_Forum
Honored Contributor
FYI: here is the output from the test(below).
I now have the NIOS processor running at 50MHz and all Critical Warnings removed such that I have timing closure. FYI: output results did not change from 200MHz case. Thoughts on the pattern error? Some kinda configuration adjustment for the NIOS or DDR2 HPCII in SOPC? Thank-you. OUTPUT -------- ddr_test_fulldata: 1: wrote 00000001, test_addr 00000000, read_val 00000004, device 0 ddr_test_fulldata: 2: wrote 00000002, test_addr 00000004, read_val 00000004, device 0 ddr_test_fulldata: 3: wrote 00000004, test_addr 00000008, read_val 00000008, device 0 ddr_test_fulldata: 4: wrote 00000008, test_addr 0000000c, read_val 00000008, device 0 ddr_test_fulldata: 5: wrote 00000010, test_addr 00000010, read_val 00000040, device 0 ddr_test_fulldata: 6: wrote 00000020, test_addr 00000014, read_val 00000040, device 0 ddr_test_fulldata: 7: wrote 00000040, test_addr 00000018, read_val 00000080, device 0 ddr_test_fulldata: 8: wrote 00000080, test_addr 0000001c, read_val 00000080, device 0 ddr_test_fulldata: 9: wrote 00000100, test_addr 00000020, read_val 00000400, device 0 ddr_test_fulldata: 10: wrote 00000200, test_addr 00000024, read_val 00000400, device 0 ddr_test_fulldata: 11: wrote 00000400, test_addr 00000028, read_val 00000800, device 0 ddr_test_fulldata: 12: wrote 00000800, test_addr 0000002c, read_val 00000800, device 0 ddr_test_fulldata: 13: wrote 00001000, test_addr 00000030, read_val 00004000, device 0 ddr_test_fulldata: 14: wrote 00002000, test_addr 00000034, read_val 00004000, device 0 ddr_test_fulldata: 15: wrote 00004000, test_addr 00000038, read_val 00008000, device 0 ddr_test_fulldata: 16: wrote 00008000, test_addr 0000003c, read_val 00008000, device 0 ddr_test_fulldata: 17: wrote 00010000, test_addr 00000040, read_val 00040000, device 0 ddr_test_fulldata: 18: wrote 00020000, test_addr 00000044, read_val 00040000, device 0 ddr_test_fulldata: 19: wrote 00040000, test_addr 00000048, read_val 00080000, device 0 ddr_test_fulldata: 20: wrote 00080000, test_addr 0000004c, read_val 00080000, device 0 ddr_test_fulldata: 21: wrote 00100000, test_addr 00000050, read_val 00400000, device 0 ddr_test_fulldata: 22: wrote 00200000, test_addr 00000054, read_val 00400000, device 0 ddr_test_fulldata: 23: wrote 00400000, test_addr 00000058, read_val 00800000, device 0 ddr_test_fulldata: 24: wrote 00800000, test_addr 0000005c, read_val 00800000, device 0 ddr_test_fulldata: 25: wrote 01000000, test_addr 00000060, read_val 04000000, device 0 ddr_test_fulldata: 26: wrote 02000000, test_addr 00000064, read_val 04000000, device 0 ddr_test_fulldata: 27: wrote 04000000, test_addr 00000068, read_val 08000000, device 0 ddr_test_fulldata: 28: wrote 08000000, test_addr 0000006c, read_val 08000000, device 0 ddr_test_fulldata: 29: wrote 10000000, test_addr 00000070, read_val 40000000, device 0 ddr_test_fulldata: 30: wrote 20000000, test_addr 00000074, read_val 40000000, device 0 ddr_test_fulldata: 31: wrote 40000000, test_addr 00000078, read_val 80000000, device 0 ddr_test_fulldata: 32: wrote 80000000, test_addr 0000007c, read_val 80000000, device 0 - Altera_Forum
Honored Contributor
So, I did a bunch of testing and experimenting and I need help
to clarify things that may put this thing to rest. Firstly, I have only NIOS, DDR, On-chip mem, and JTAG in the system and I have reduced the clocks for all possible to the 50MHz sysclk. With this, all critical warnings have been removed as previously stated. The result with 4x address incrementing is like this: 1: wrote 00000001, test_addr 00000000, read_val 00000004, device 0 2: wrote 00000002, test_addr 00000004, read_val 00000004, device 0 3: wrote 00000004, test_addr 00000008, read_val 00000008, device 0 4: wrote 00000008, test_addr 0000000c, read_val 00000008, device 0 5: wrote 00000010, test_addr 00000010, read_val 00000040, device 0 6: wrote 00000020, test_addr 00000014, read_val 00000040, device 0 7: wrote 00000040, test_addr 00000018, read_val 00000080, device 0 8: wrote 00000080, test_addr 0000001c, read_val 00000080, device 0 ... etc, etc and with 8x address incrementing is like this: 1: wrote 00000001, test_addr 00000000, read_val 00000001, device 0 2: wrote 00000002, test_addr 00000008, read_val 00000002, device 0 3: wrote 00000004, test_addr 00000010, read_val 00000004, device 0 4: wrote 00000008, test_addr 00000018, read_val 00000008, device 0 5: wrote 00000010, test_addr 00000020, read_val 00000010, device 0 6: wrote 00000020, test_addr 00000028, read_val 00000020, device 0 7: wrote 00000040, test_addr 00000030, read_val 00000040, device 0 8: wrote 00000080, test_addr 00000038, read_val 00000080, device 0 etc, etc, ... 8x incrementing looks to provide correct results but that means that since we only get 4 bytes per read from NIOS that we are missing the other 4 bytes assuming the addresses provided to the _32DIRECT RD/WR macros are byte addresses. I confirmed that with 8x addr incrementing that I cannot write past the span of 0x10000000(256MB which is size of device). I used SignalTap to look at the *local* signals and addresses and this seems the root of the problem. When using 4x incrementing then the local_address increases as 0,0,1,1,2,2,3,3, etc. for every local_read_req pulse. When using 8x incrementing then the local_address increases as 0,1,2,3, etc. So, here, 8x looks correct but then since I can only access up to the span 0x10000000 (256MB if byte addr) before NIOS returns 0xFFFFFFFF as data and the devices are 256MB then half the addresses are not available apparently. Note for the reads the data for one of the 8x reads on this local_rdata bus (64 bits wide) is: 0x00000002_00000002 Note for the reads the data for one of the 4x reads on this local_rdata bus (64 bits wide) is: 0x00000004_00000004 How do I access ____ALL____ 256MB of this device. The emi_ddr_ug.pdf by Altera shows local_address on page 121 which talks about "LSB of column address on memory side is ignored" which may be of some relevance. Does this mean we ____WILL____ only see half of our memory??? Thank-you. - Altera_Forum
Honored Contributor
Has anyone had this same experience as in my post# 10?
Thank-you.