Author Topic: Need help debugging SDRAM controller  (Read 1610 times)

0 Members and 1 Guest are viewing this topic.

Offline Dukov AhzrukhalTopic starter

  • Regular Contributor
  • *
  • Posts: 51
  • Country: us
Need help debugging SDRAM controller
« on: October 13, 2020, 09:15:24 pm »
Hello everyone, I have been working on a TRS-80 project and want to start using SDRAM. I wrote a simple controller that allows me to share the SDRAM between the CPU and display controller, but I can't get it to work. I wrote a test setup that is basically the entire TRS-80 but with an Arduino driving a dummy CPU module.

The memory controller has two ports: port A (a read and write port for the CPU), and port B (a read only port for the display controller). After many hours of tweaking the SDRAM controller I realized that if I disable reading on port A the memory controller works almost perfectly (writing on port A works and reading port B works with occasional glitches).

Reading on port A works exactly the same as reading port B, so this makes no sense to me. I have tried everything I can think of, from inserting more wait states everywhere to tweaking the clock phase of the SDRAM chip. Nothing works, every time I enable reading on port A reading any address on B gives the last data written to port A. :-//

I will attach my SDRAM controller file here, as well as the top level of my test setup and the Arduino code that controls it. The SDRAM chip I'm using is the HY57V641620FTP-H.
Any help would be greatly appreciated.
 

Online asmi

  • Super Contributor
  • ***
  • Posts: 2794
  • Country: ca
Re: Need help debugging SDRAM controller
« Reply #1 on: October 13, 2020, 10:24:20 pm »
How do you expect us to help you? We can't run the simulation, as the "test" contains some irrelevant parts which we don't have a source code for, as for the actual memory controller, it looks like it's "development" involved quite a bit of copy-paste, and minimal (if any) efforts to make the code readable and understandable. HDL code in general is "famous" for being extremely hard to read and understand unless a lot of effort was invested into making it more reader-friendly. I highly recommend including a comment which will have rough state diagram and short description of what each state is supposed to represent. And this is coming from somewhere who has written quite a number of memory controllers, so I know what the data flow is supposed to be.

As I was able to decipher from the code, it looks like you are not using read-with-precharge and write-with-precharge commands, even though it looks like you manually precharge a row after every operation (which is HORRIBLY inefficient way of doing things). Why is that?

Offline Dukov AhzrukhalTopic starter

  • Regular Contributor
  • *
  • Posts: 51
  • Country: us
Re: Need help debugging SDRAM controller
« Reply #2 on: October 13, 2020, 10:38:19 pm »
If you need additional information about the test setup I will gladly provide it. I take offence to your comment because there was very little copy paste involved in making that. If you can be more specific about what is making my code difficult to read I will gladly go back and clean it up.

I am not using read and write with automatic precharge simply because from the data sheet it is not obvious how to do that (I don't know how many wait states I would need). If you can explain that to me I can change my code to work that way.

I will attach the code for the display controller, in case it helps you. It provides the HSYNC signal to the memory controller, so refresh always happens when the display controller is not active.

EDIT: I removed the commented out code (my failed attempts of getting this to work) and changed the code to use automatic precharge. It still fails in the exact same way if I enable reading in port A.
I will attach the new file here.
« Last Edit: October 13, 2020, 11:12:27 pm by Dukov Ahzrukhal »
 

Online asmi

  • Super Contributor
  • ***
  • Posts: 2794
  • Country: ca
Re: Need help debugging SDRAM controller
« Reply #3 on: October 14, 2020, 12:46:28 am »
Sorry, I didn't mean to offend anyone. It's just "I sing what I see, and I see what I sing" (C)
Can you please provide a code for controller with that reading over port A enabled, so that I would be able to see the code which actually has a problem.
Also, in general, all SDRAMs (including SDR and all DDRx ones) work the same way - you open a row, you work with it however long you need, then you close it. If at a time of issuing a read/write command you know for fact that you won't need to access that row anymore (or that you know that you will need to access a different row in the same bank), you can use auto precharge command. Also keep in mind that you can use different banks in parallel, as each bank can have it's own open row - just make sure you close them all before you do a refresh. You can so some very clever tricks with banks, for example - double-buffering - have your CPU write framebuffer into bank 1, while the video controller reads a previous frame off bank 0, then at some point you swap these around. Also consider using bursts at least for frame reads - this will give you much greater bandwidth and efficiency as you will better amortize initial access latency.
Finally, I'd highly recommend you to read through Micron's datasheet for SDRAM: https://www.micron.com/products/dram/sdram/part-catalog/mt48lc32m8a2p-6a It's more detailed as far as timings are concerned. But more importantly - on the page I've linked there is a verilog simulation model for their memory chips - this way you can verify in simulation that your controller code's behavior is correct without the need to debug it in hardware, which is more complicated and is much slower. Also Micron's sim model will report errors if any timing parameters are violated. I know you don't use Micron part on your board, but I suspect all SDRAM chips operate sufficiently similar to one another that it shouldn't matter as long as timing parameters are correct.
« Last Edit: October 14, 2020, 12:52:38 am by asmi »
 
The following users thanked this post: Dukov Ahzrukhal

Offline Dukov AhzrukhalTopic starter

  • Regular Contributor
  • *
  • Posts: 51
  • Country: us
Re: Need help debugging SDRAM controller
« Reply #4 on: October 14, 2020, 01:06:17 am »
I'll be sure to look at the link you provided, as I certainly agree that it would be easier to debug this with a simulation. I will also attach the file with reading port A enabled here. It is almost identical to the previous one, with the only difference being in S_write_A (one line has been uncommented, and one line has been commented).

I have another FPGA board with a similar SDRAM chip, If this works at all in a simulation I will test it on that board to make sure the issue not bad SDRAM chip.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Need help debugging SDRAM controller
« Reply #5 on: October 14, 2020, 01:23:23 am »
I mapped out the state transitions

Code: [Select]
_reset          => S_init
S_init           => S_init_NOP
S_init_NOP       => S_mode
S_mode           => S_mode_NOP
S_mode_NOP       => S_refresh_1

S_activate_A     => S_activate_A_NOP
S_activate_A_NOP => S_write_A
S_write_A        => S_write_NOP
S_write_NOP      => S_activate_B


S_precharge_A     => S_precharge_A_NOP
S_precharge_A_NOP => S_refresh_1
                  => S_refresh_2
                  => S_activate_B

S_activate_B      => S_activate_B_NOP
S_activate_B_NOP  => S_read_B
S_read_B          => S_read_B_NOP
S_read_B_NOP      => S_gate_B
S_gate_B          => S_activate_A

S_refresh_1       => S_refresh_NOP_11
S_refresh_NOP_11  => S_refresh_NOP_12
S_refresh_NOP_12  => S_refresh_NOP_13
S_refresh_NOP_13  => S_activate_A

S_refresh_2       => S_refresh_2
S_refresh_NOP_21  => S_refresh_NOP_22
S_refresh_NOP_22  => S_refresh_NOP_23
S_refresh_NOP_23  => S_activate_A

Does it matter that the 'S_activate_B" branch is longer than "S_refresh_1" or "S_refresh_2" (5 states/cycles vs 4 four the others)

Also, last time I wrote a SDRAM controller there were logs of requirements on the powerup sequence - so many clocks before you set the mode word and afterwards.

Why is refresh_flag_2 begin set in so many states? it feels wrong... I guess you are trying to issue two refreshes after each rising edge of hsync?
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline Dukov AhzrukhalTopic starter

  • Regular Contributor
  • *
  • Posts: 51
  • Country: us
Re: Need help debugging SDRAM controller
« Reply #6 on: October 14, 2020, 01:47:26 am »
I am indeed trying to get 2 refresh cycles on every edge of HSYNC. Your comment made me realize that I should be doing the refresh on the falling edge, not the rising edge. I fixed this issue, but it didn't really change anything.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Need help debugging SDRAM controller
« Reply #7 on: October 14, 2020, 03:05:14 am »
I am indeed trying to get 2 refresh cycles on every edge of HSYNC. Your comment made me realize that I should be doing the refresh on the falling edge, not the rising edge. I fixed this issue, but it didn't really change anything.

Is the difference that when Port B is active it takes 11 cycles to get back to S_Activate_A, vs when it is doing a refresh it takes only 10 cycles to get back to S_Activate_A relevant?

Also, what clock rate are you running at?

For for consistent timing, you really want to latch the SDRAM_DQ in the IO buffers, at the moment it is either latched in a_data_out or b_data_out, which will be implemented your FPGA's fabric, changing timing by a few ns.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline Dukov AhzrukhalTopic starter

  • Regular Contributor
  • *
  • Posts: 51
  • Country: us
Re: Need help debugging SDRAM controller
« Reply #8 on: October 14, 2020, 03:59:33 am »
Is the difference that when Port B is active it takes 11 cycles to get back to S_Activate_A, vs when it is doing a refresh it takes only 10 cycles to get back to S_Activate_A relevant?

Also, what clock rate are you running at?

For for consistent timing, you really want to latch the SDRAM_DQ in the IO buffers, at the moment it is either latched in a_data_out or b_data_out, which will be implemented your FPGA's fabric, changing timing by a few ns.

The clock rate is 50 MHz for the memory controller, 0.89MHz for the CPU, and 25MHz for the VDG. Timings for the VGD get a little bit complicated, but what is important is that it reads approximately once every 40 cycles of the 50MHz clock. I don't think it matters that when port B is active it takes 11 cycles to get back to S_activate_A. Since the CPU runs at a low clock speed and the VDG does not read data often the timing requirements are not hard to meet.

Since the address and RW signals from the CPU and VDG are driven by slower clocks, any single read or write may be executed multiple times by the memory controller. Its not the most elegant design, but I think it should work.

I don't fully understand what you said about latching the data in the IO buffers. How do I make that happen? I don't think it matters for this design since its fairly low speed, but I am curious to know anyways as it might help me with future projects.

Edit:
I got a simulation with the SDRAM model working, and this time the test bench does not include anything but the memory and controller. I'll post the files here in case someone wants to run it.
I'll take a close look at it later today and hopefully find the issue.

Edit: I fixed it. My mistakes were embarrassingly stupid. Thank you asmi for providing me the link to the memory model.
« Last Edit: October 14, 2020, 05:51:37 pm by Dukov Ahzrukhal »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf