$25
To interface the 64Mbyte SDram memory chip on the DE1Soc board to the 68k processor and modify the Address decoder and Dtack generator.
To replace the Static Ram in the 68k system with SDram as the main system memory, i.e. to be able to download to and run programs directly from Dram.
This assignment can be done in groups of 2
Rational: Dram memory is commonly used in 16/32 bit computers in place of Sram when large amounts of memory are required (e.g. multi-megabytes). However Dram is more complicated to interface to the CPU and requires a dedicated controller to handle the interface, timing, initialisation and refreshing of dram memory chips. This Lab will involve the design of such a controller and allow us to replace the Sram from Assignment 1 with Dram.
Intro and Explanation of Assignment
Make sure you have downloaded Lectures 10 & 11 on Synchronous Dram (and have read and understood it fully).
Make sure you have downloaded the 68k project for CPEN 412 students from the Canvas site (you should still have this from assignment 1), along with other software and documentation such as the 68000 ‘C’ compiler/IDE and Hyper-terminal. Install these and make sure they work.
Open the 68k project in Quartus. You will see a basic Dram interface in the top level schematic as shown below.
The SDram chip on the DE1 is an ISSI-ID42S1632D, a 64M byte device, organised as 32M x 16 bits, see data sheet posted on 412 Canvas site (make sure this is the same device you have on your DE1, if not search the internet for your board’s device, but it will most likely have the same timings as these are pretty standard within the SDram community).
· If you double click on the SDram interface symbol above in the top level schematic, you can open up the hierarchy to expose the insides (see below).
The signals on the left connect to the 68000. The signals on the right connect mostly to the SDRam chips itself with the exception of the following signals:-
DataOut[15..0] (which connects to the 68k’s data bus in on the top level schematic). Note how data is passed back to the 68k via the tri-state buffer which is activated when the 68k’s WE_L = 1 (i.e. a Read) and DramSelect_H from the address decoder = 1, in other words, tri-stating and enabling of the data output buffers is automatic, given the logic above.
DramDtack_L (which drives the Dtack generator on the top level schematic and provides Dtack back to the 68k when dram is accessed).
ResetOut_L which provides a reset signal to the 68k to hold it in a reset state while the SDram controller initialises the SDram memory during a power-on or user reset. This is to prevent the 68k accessing SDram until SDram has been initialised by the dram controller.
DramState – this 5 bit bus may optionally be used during simulation only to check your dram controller state machine operation (i.e. for debugging only). If you wish to make use of this, wire up the signal/bus to an output pin on the TOP level schematic and recompile/re-simulate. Note however that because the fitter may run out of FPGA pins to assign this signal to, the compiled design may not download to the DE1 correctly (it may hang during the download with the green “download” LED staying lit). If this happens you will have to remove the pin from the top level schematic and re-compile.
All SDram signals should have been set up in the Quartus pin planner but just check that they have been assigned. Consult the DE1 board user manual for pin numbering.
You will notice that the SDram signals discussed in the lecture are all present above, e.g. CKE, CS, RAS, CAS, WE, a 13 bit address bus (sdram_a[12..0]), a
2 bit bank address (sdram_ba[1..0]) and a 16 bit bi-directional data bus sdram_dq[15..0].
In addition, the 68k’s UDS/LDS signals drive the SDram chip signals DQMH and DQML signals (labelled sdram_dqm[1] and sdram_dqm[0] above) which select which halves of the 16 bit SDram data bus are active during byte/word transfers to/from dram.
On the LHS, we see a Reset input which will come from the right most push button (key[0]) on the DE1, this will reset the DramController (and the 68k) and force it to reinitialise the SDram memory chip.
We also see a DramSelect_H (notice it is active high, not low) signal which comes from the main address decoder on the top level schematic.
We also see a Clock signal which comes from a 50Mhz oscillator on the DE1 via a phase locked loop on the top level schematic (see below)
You will notice that the clock that drives the SDram memory above is set up in the phase locked loop (PLL) to be the inverse (i.e. 180 degrees out of phase) to the clock that drives the SDram controller. If you double click on the PLL symbol above, you will see the phase and frequency adjustments this device creates from the basic DE1 50Mhz oscillator/clock.
The fact that the dram system controller receives a clock that is 180 degrees out of phase with the clock sent to the Dram memory chip itself, allows the SDram controller to set up the SDram signals (RAS, CAS, WE etc) on one edge of the clock, and then acted on by the SDram memory on the opposite edge of the clock (i.e. ½ a clock later). This allows the SDram controller signals to reach the SDram memory and meet their set up time. By altering the phase relationship between these two clock signals we can minutely adjust timings to allow for propagation delays and capacitive loads etc on the DE1 board. Such an approach is common in very high speed systems but is less critical here (where a simple inverter would suffice) since only a 50Mhz clock is used.
The rest of the signals on the LHS come from the 68k. Notice that DataIn[15..0] comes from the 68k’s data out bus, i.e. it is driven by the 68k when writing to the dram and the signal DataOut[15..0] (on the rhs) is driven by the SDram controller and connects to the 68k’s data in bus. That is, the dram controller drives DataOut[15..0] during a 68k read operation – don’t misunderstand this.
The main block in the schematic above (labelled M68kDramController_Verilog) is a file (double click to open it) in the form of a state machine.
1.0 Signal Descriptions for the Dram Controller State Machine
Double click on the M68kDramController_Verilog symbol above and you will open a Verilog file that starts off looking like this, i.e. defines all the inputs and outputs.
1.1 Constants Defining Sdram Commands
SDram commands are presented to the SDram memory chip via the 5 signals below (see lecture on synchronous dram).
SDRam_CKE_H,
SDRam_CS_L,
SDRam_RAS_L,
SDRam_CAS_L,
SDRam_WE_L
Further down the file you will see the most commonly used SDram commands (we don’t use them all in this project) defined as 5 bit constants representing the values of the 5 signals above required to generate that command, e.g. Compare these values to the ones on Page 7 of lecture 10/11
1.2 Internal Signal Connecting Building Blocks
There are several internal Verilog signals that can be driven or read by logic in your circuit. These are listed below and are yours to drive as part of your assignment to connect various building blocks and Verilog processes together.
1.3 Internal Programmable Timers
There are two 16 bit programmable timers in the Verilog file, the first is a general purpose timer that can be loaded with any 16 bit unsigned value and then left to count down under the control of a 50Mhz clock upon which it stops counting and issues a Timer Done signal.
This is useful during the powering up sequence where we need to wait for at least 100us which can be expressed in terms of a number of clock pulses loaded into the timer.
The second timer is similar to the first and can be used to generate refresh requests at the desired interval of 7.5us.
You could add other timers/counters if you wish depending upon how you choose to implement your design.
1.4 Latching Data during a Dram Read
There is a Verilog process in the SDram controller to latch data from the SDram during a 68k Read operation and keep presenting it to the 68k until the end of the 68k’s read cycle.
This latch is important, and the loading of at the right time is critical because the SDram only outputs data during a read operation for 1 SDram clock cycle (see lecture 10/11 pages 8, 9 and 31). You will remember that after issuing the read command, you have to wait 2 clock cycles – the CAS latency – before the data becomes available – and then the data is removed on the next clock.
The 68k requires the data be present until the end of its read bus cycle, i.e. the start of 68k internal state S7 – see Lecture 10/11 page 33 and also lecture 7/8 page 14 – long after the SDram has removed it – this is why the latch needs to grab the data, hold it and present it back to the 68k until the 68k finishes the read operation.
You can trigger the latch to save the SDram data by setting the signal DramDataLatch_H to logic 1. The data will be latched on the falling edge of the next sdram controller clock.
1.5 SDram Controller “State Register”
There is a register driven off the main clock which holds the current state of the SDram controller and also that presents a command (the value of the 5 bit ‘command’ signal described earlier in Section 1.2) to the SDram on each rising edge of the clock.
The signal FPGAWritingtoSdram_H is used to control the bi-directional data bus connected SDram controller output to the SDram bi-directional data bus. If you set this signal high, it will turn on the SDram controller data bus drivers to allow drive data to be driven into the SDram memory during a 68k write cycle. If this signal is low, it then the SDram controller data bus drivers will tri-state so the SDram memory can drive data out and onto the 68k’s data bus a 68k read cycle.
1.6 SDram Controller State Machine
The SDram controller is itself a state machine and needs to transition through a number of states following a power on reset (e.g. initialise the SDram memory by programming mode register etc.) as well as respond to 68k read and write requests.
The 5 bit signal NextState listed previously is used to define the current state of the SDram controller. To start you off, I have provided some simple states associated with reset initialisation. You will have to add your own states as part of the assignment.
Here is the Verilog code to generate the next state (based on current state and input signals) and also the outputs in the current state.
Note it contains some default values for signals (to void the Verilog compiler inferring latches). You may need to override these defaults in some parts of your code.
Notice the default Command and NextState values. Override these where necessary in your code (and any others such as CPUReset_L, CPU_Dtack_L etc.) If you add any new signals of your own remember to add defaults for them here.
NOTE: I would suggest that during the early development and simulation of your design, you load the timer with a very small value like binary 1000 (i.e decimal 8) above, otherwise, 100us is a very long time to simulate and you may run out of simulation time in Quartus before this 100us has elapsed but don’t worry about it, the power on phase and initialisation of an FPGA takes longer than 100us so it’s not likely to be a problem even when we have finished.
Part A
Modify the Verilog code for the state machine above (adding new states as and where required) to Initialise the SDram memory chips following a reset input to the state machine (see lecture 10/11 starting Page 14 for a description of what needs to happen). This involves using the timer and some degree of generous dram timing with NOPs (remember this initialisation code that is executed once only at power on or reset, so speed is not important here) to
Wait 8 clock cycles after the removal of the Reset input, keeping the SDram CKE signal low. See Lecture 10/11 Page 17 (and note above)
Issue 1 NOP command
Issue a pre-charge all banks command followed by 1 NOP command. See Lecture 10/11 Page 17
Perform at least 10 refresh operations (with at least 3 NOPs after each one - again being cautious) including the last one. See Lecture 10/11 Page 18 and Note 1 below.
Program the dram chip Mode Register command (remember to present the mode data on the Dram Address Bus at this time), followed by at least 3 NOPs - See Lecture 10/11 Page 19 and finally
Program/load the refresh timer to produce refresh request timeouts at the 7.5uS intervals required for this dram.
Note 1: For this assignment, you must implement some kind of loop counter to count the 10 refresh operations (i.e. don’t just create 40 new states that you cycle through – that is inefficient, creating lots of logic). Create some kind of loop in your state machine to cycle 10 times through the same “refresh + 3 NOP” sequence.
Given that each SDram command is 1 clock period in length, we could count something like 40 states/clock pulses and use that to terminate the loop or you use a counter to count 10 times around the loop. Check your simulation when you have implemented this.
Once the initialisation of the SDram memory has been done, and the refresh timer programmed, your state machine should enter an idle state and start issuing NOP commands to the SDram memory with every clock.
In this idle state it should only respond to the refresh timer requests and issue autorefresh commands to the SDram memory as follows (you will need a number of new states for this). See Pages 40/41 of lecture lecture 10/11
Issue a pre-charge all banks command (IMPORTANT: remember to set A10 = 1) when issuing this command which means that the bank address is irrelevant.
Issue a NOP command
Issue a Refresh command.
Issue 3 NOP commands after the above refresh
Once this has been done, reload the refresh timer again and return to the Idle state and wait for the next refresh request from the refresh timer.
Simulate the signals at the SDram using the built in Quartus simulator. Verify that the initialisation procedure for the SDram is being followed (your simulation waveform should look like that on pages 17-19 of lecture 10/11 and also that refresh operations are being carried out at the specified time interval required for this assignment of 7.5us.
Download the new project (.sof file) to the DE1 and verify that everything still works in your system (You can still communicate with hyperterminal), and that you haven’t broken anything. At this point the 68k will still be running off the SRam from assignment 1 – not dram - so it should still work.
Next Step - Connecting the Dram Controller Reset Out to the 68k
In the top level 68k project schematic, you will see that the reset button on the DE1 (Key[0]) is wired into both the SDram controller and the 68k processor. You should now break the link from the reset button to the 68k (leaving the reset still connected to the SDram controller).
Now connect the Reset out from the SDram controller to the reset in pin of the 68k. This means that the reset to the CPU is now under the control of the SDram controller. This to prevent the 68k using the dram while the dram is going through its initialisation phase.
Modify the SDram controller state machine, to produce a reset out (active low) to the cpu when the SDram controller receives an active low reset in. It should continue to produce a reset out to the CPU until the initialisaton phase for the SDram is complete. The reset to the 68k can then be negated (taken high) when the SDram controller enters its idle state.
Re-compile and Simulate (make sure 68k does not come out of reset state until the SDram controller has finished initialisation).
Download the new project (.sof file) to the DE1 and verify that everything still works in your system (You can communicate with hyperterminal). Note we are still not using the dram, but we have modified the processor reset to come from our SDram controller state machine (which may have bugs) so we want to make sure we haven’t broken anything.
Modifying the Address Decoder and Dtack generator to account for SDram
Re-design the address decoder for the top level schematic in your 68k project to produce a DramSelect_H output to the SDram controller whenever the CPU accesses memory within the specified range allocated for the SDram i.e. from a base address of $F000 0000 up to $F3FF FFFF (i.e. a range of 64Mbytes).
Important: Modify your Dtack generator on the top level of the 68k project to correctly produce a Dtack back to the 68k. Don’t break the default Dtack generator code (the code that produces dtack for everything else accessed by the 68k).
It’s important that when the 68k accesses Dram (i.e. the address decoder is producing a dram select signal), the Dtack generator supplies the 68k with the Dtack produced by the Dram controller itself not some default dtack.
The reason for this (and not simply producing a Dtack to 68k regardless of circumstance) is that if the Dram controller is performing a Dram refresh, the 68k must be made to wait until that refresh has completed and the Dram controller state machine has then entered one of it’s “read or write to Dram” states (see Part B). Failure to appreciate this, will likely mean your 68k will not work when you switch from Sram to Dram later. Here’s the pseudo code for the Dtack generator
Set DtackOut_L to inactive ; -- default is NO dtack when AS_L is inactive
if(68k performs an access, i.e. AS_L is asserted)
Give an active DtackOut_L back to 68k -- default is no wait states
-- now override the statement directly above for those devices that
-- can supply their own dtack i.e. dram and canbus controllers
-- those that cannot, will thus use the default with no wait states
if(68k is accessing Dram)
Give the 68k the Dtack from the Dram Controller
else if(CanBusSelect_H = '1') then
Give the 68k the Dtack from Canbus Controller
end if ;
end if ;
Recompile your design and make sure there are no errors. Also resimulate your design to make sure there are no obvious delays - note the 8 clock cycle delay after power on for the dram controller which keeps the 68k in a reset state for that period.
Download the design (sof) to the DE1 and make sure everything still works, i.e you can still communicate via hyperterminal with the 68k
Dealing with Read/Write requests from the 68k
Now we are going to modify the state machine to include additional states to deal with read and write requests from the 68k. This means that in the IDLE state, our state machine must deal not only with Refresh requests that come from the refresh timer, but also read/write requests from the 68k.
This doesn’t mean that we do them concurrently, it means we do them one after the other if they happen to coincide (i.e. a refresh request occurs at the same time as a read or write request from the 68k or vice versa). A pseudo code description of the operation is given below.
A read or write by the 68k to the SDram is indicated when AS_L goes low and the SDram controller receives a DramSelect_H signal from the address decoder on the top level schematic.
///////////////////////////////////////////////////////////////////////////////////////////////////
// Main IDLE state: Enter here after initialisation and return here after every transaction, e.g.
// refreshing, reading, writing operations.
///////////////////////////////////////////////////////////////////////////////////////////////////
else if the current state of the sdram controller is the IDLE state
Make sure CPU reset is '1' (inactive)
issue a NOP command to the Sdram memory
if refresh timer is requesting a refresh operation
Next state should be a refresh state (i.e. previously written refresh state)
otherwise if CPU is accessing dram (i.e. DramSelect_L = '0' and AS_L = '0')
Issue a 13 bit Row Address to the Sdram from CPU
Issue a 2 bit Bank Address to the Sdram
Issue a BankActivate command to the sdram
If CPU is attempting to READ from sdram NextState is one that issues a Read command (i.e. Issue CAS/col addr) ;
Otherwise (CPU must be attempting to WRITE to the sdram)
NextState is one where we wait for 68k’s UDS or LDS signals to go low;
otherwise
Stay in this idle state
end if
end if
///////////////////////////////////////////////////////////////////////////////////////////////////
// State associated with a 68k write where we wait for 68k’s UDS or LDS or both to go low
///////////////////////////////////////////////////////////////////////////////////////////////////
else if the current state of the sdram controller is waiting for 68k’s UDS or LDS or both to go low
Make sure CPU reset is '1' (inactive)
if either of 68k’s UDS or LDS (or both) go low
issue an 10 bit Column address (make sure A10 on Sdram = 1 for precharge all banks operation)
issue a 2 bit Bank Address (the same value we issued in idle state when starting the write operation)
issue a WriteAutoPrecharge command to the sdram
issue a CPU_Dtack_L back to the 68k’s dtack generator
turn on the sdram controller bi-directional data lines so we can drive data into sdram memory
copy 68k’s data out bus to Sdram memory chip data bus (don’t worry about width, it’s
defined by UDS and LDS connected to DQMH/DQML)
NextState should be one that waits for 1 clock cycle after write (this is an sdram timing requirement)
otherwise
stay in this state
end if
///////////////////////////////////////////////////////////////////////////////////////////////////
// State associated with Memory writes where we wait for one clock cycle after a write
///////////////////////////////////////////////////////////////////////////////////////////////////
else if the current state is to wait 1 clock cycle after a write
Make sure CPU reset is '1' (inactive)
Keep issuing Dtack back to 68k issue a NOP command to the sdram;
Keep driving the bidirectional data lines (i.e. not tri-state) to the sdram chip
Keep presenting 68k data to sdram memory
Next state should be one that waits for 68k to terminate its (current) bus cycle.
///////////////////////////////////////////////////////////////////////////////////////////////////
// State associated with issuing Read command (i.e. CAS) during a 68k Read
///////////////////////////////////////////////////////////////////////////////////////////////////
else if the current State is one where we want to read (following a bank activate) then
Make sure CPU reset is '1' (inactive)
Issue an 10 bit Column Address to the sdram memory (remember to set A10 on the sdram to ‘1’)
Issue a 2 bit BankAddress to the sdram memory (the same value we issued in idle state when we started a read operation)
Issue a ReadAutoPrecharge command to sdram memory;
Issue a Timer Load signal to start CAS latency period
Set Timer Value to 2 to cause latency of 2 clock periods
Next state is one where we wait for CAS latency to expire after read commnd
///////////////////////////////////////////////////////////////////////////////////////////////////
// States where we wait for CAS latency
///////////////////////////////////////////////////////////////////////////////////////////////////
else if the current State is waiting for cas latency to expire (timer not reached 0)
Make sure CPU reset is '1' (inactive)
Keep issuing Dtack back to 68k
Issue a NOP Command to Sdram memory
Enable Data latch to capture output from sdram on second clock after issueing ReadAutoPrecharge command (CAS latency = 2)
If the Timer has expired (2 clock periods)
Next state should be one that waits for 68k to terminate its (current) bus cycle.
Otherwise
Stay in this state
end if ;
///////////////////////////////////////////////////////////////////////////////////////////////////
// State associated with waiting for 68k to terminate current bus cycle
///////////////////////////////////////////////////////////////////////////////////////////////////
else if the current state is waiting for 68k to terminate current read or write cycle
Make sure CPU reset is '1' (inactive)
Issue a NOP Command to sdram memory
If the 68k is still driving either UDS or LDS (or both) low (still not finished bus cycle)
Keep issuing dtack to 68k
Stay in this state;
Otherwise
go to the idle state ;
end if ;
// this last ‘else’ is a catch all to make sure we don’t create memory for any signals
else
Make sure CPU reset is '1' (inactive)
Issue a NOP Command to sdram memory
Go to IDLE state
end if ;
// END of state machine Process
Testing the Read and Write operation
If you have translated the above pseudo code correctly into Verilog, we should still be able to communicate with the 68k via Hyperterminal (since the 68k is still running off Sram) and we can now perform a memory test.
Test your dram memory operation using the built in Memory examine and change command ‘M’ in the debugger (which does byte read and write operations)
This is useful because you can individually write to a location in Dram and the debugger will verify the write by printing out what it read back. If the 68k hangs at any point then it highlights a Dtack (or CPU reset) problem. Perhaps your dtack generator is not correct, or the states that drive dtack in the SDRam controller when reading/writing to dram are not correct.
If you can write but always read the same incorrect value back, perhaps that points to an incorrect Data Latch operation (remember the 2 clock CAS latency) or perhaps not correctly turning on/off the controller buffers that allow data to be read/written to the Dram over the bi-directional data bus.
In addition you could use the memory fill/memory dump commands and even, the memory test program you wrote inside the debugger for Assignment 1. Obviously you should test using an address range that coincides with the Dram i.e. somewhere between $F000 0000 and $F3FF FFFF which is not used by the debugger, so you can test any part of it.
The most critical operation (from a dram controller perspective) is dealing with back to back 16 bit reads and writes, e.g. when the 68k reads or writes 32 bits of data from/to dram. If possible, try to test your memory using those 32 bit reads/writes. Also test for 16 and 8 bit operation if that’s possible with your code.
If this checks out, there is a very high probability that the dram is working correctly so proceed to the next step, otherwise, you have a problem and need to fix it before going any further.
Replacing the Static Ram with Dram
Having verified that the Dram works correctly for 8, 16 and 32 bit read/writes, modify the design of the 68k’s main address decoder on the top level schematic to place the SDram in the memory map such that it responds to the base address hex 0800 0000 (i.e. the address previously occupied by the Static ram) up to hex 0BFF FFFF.
You must also change the base address of the static ram from it’s previous base address of hex 0800 0000 (which now conflicts with the dram) to a new base address of hex F000_0000 to F003_FFFF.
Now recompile. If all is good, when you download the new .sof file to the DE1 and reset your new system, it will use the SDram for the debug monitor and your programs, instead of the static ram.
IMPORTANT If your Dram controller is not correctly working, the system will now "hang/crash" even when you release the reset button (there will be no debugger prompt in hyperterminal). In this case you will have to re-simulate and debug (see below).
Simulating your design to check or debug Dram controller operation
Run the Quartus simulator on your design. The debug monitor has been written (as part of the debugger cstart.asm file) to get the 68k to perform a 32 bit read and a 32 bit write operation to address hex 0806 0000 shortly after a reset.
The code below shows the 68k assembly language instructions inside the cstart.asm file for the debug monitor project that perform these reads and writes
********************************************************************
** Add some 68000 instructions to read and write to memory, IO etc.
** This doesn't do anything important, it just creates read and write bus cycles to ** specific addresses which help with debugging hardware in Quartus simulations
********************************************************************
; perform some dummy read/write of 32 bit values to memory to see
; waveforms during a simulation
move.l #$11223344,$08060000 write 32 bit data, to dram at 08060000
move.l $08060000,d0 read back 32 bits and store in register d0
Locate the point in the simulation waveform where this takes place (see below) and check that the simulation waveform looks like the waveforms shown below (1 waveform for reading, 1 waveform for writing), particularly in relation to the SDram signals. These waveforms come from pages 28 and 33 of lecture 10/11 on synchronous drams.
The important things to notice here are the SDram signals. There should be a bank activate command (RAS goes low), some NOP’s and a read or write command (CAS goes low). Also WE will go low if the 68k is writing.
During a write, make sure the CAS signal does not go low until after UDS/LDS goes low. Also check the SDram address and bank signal and that A10 is ‘1’ (i.e. the hex 400/401 on the SDram address bus below) when issuing the read or write command.
Write simulation waveform
Read simulation waveform
If you get the 68k debug prompt in hyperterminal when you power up your DE1 board or press reset, then everything is working correctly. If not, use the simulation waveforms to figure out what is going wrong.
Run a memory Test
Use the 68k debug monitor commands to run a memory test on the dram, use the memory examine and modify command, as well as the memory test you integrated into the debugger in assignment 1 to check out your SDram controller and memory between addresses $0900 0000 to $097F FFFF which are not used by the debug monitor. Fix your design if it fails.
Try downloading a previously written C program (like the one wrote for assignment 1) to the DE1 Dram memory (previously SRam) and verify that it still works – if you have got this to work – congratulations buy yourself a drink!!!!.
Recompiling the Debug Monitor
At the moment the debug monitor is still set up as if it were limited to the 256k static ram chip that we used in Assignment 1. Let’s change it so that the full 64MB can be used
If you go back and open the debug monitor project in IDE68K then open the M68kdebug.c file, you will see the following #defines at the top of the source files
Make the modifications outlined below in red. In particular, setting the top of the stack to just beyond the top of the SDRam space at address 0C000000 (as well as the Ram based exception vector table we may use in another assignment on interrupt driven IO devices)
#include "DebugMonitor.h"
// use hex 08030000 for a system running from sram or
// hex 0B000000 for system running from dram
#define StartOfExceptionVectorTable 0x0B000000
// use 0C000000 for dram or hex 08040000 for sram
#define TopOfStack 0x0C000000
In addition, you will have to change the cstart_V4.0 – DebugMonitor.asm file to make similar changes for the new memory map as shown below. Comment out the existing “equ” statement and uncomment the ones in red below
Now recompile the debug monitor, recreate the “.mif” file using Visual Studio (as we did in Assignment 1). Download the new “.mif” file to the DE1 (using the Quartus In-System Memory Content Editor from the Tools Menu.
In hyperterminal enter the ‘r’ command for register dump, you should see this where the system stack pointer (A7) is set to address hex 0C000000. If this works, you can recompile the project to make the changes permanent (make sure your new “.mif” file replaces the default one for the ROM in the quartus project folder – it should be called M68kdebugmonitor.mif.
Making a turn key system
If this works, recompile the Quartus project (so the new debugger code is incorporated into the generated “.sof” file) and convert the “.sof” file to a “.jic” file and program it into the EPCS serial prom device like you did in Assignment 1. This should make a turn key system that boots on power on.
What to do if the design doesn’t work?
In the simulator:-
Check your 68k’s reset signal. Make sure you keep reset inactive (i.e. high) at all times except during the initialisation states. If you forget, the default is to reset the processor, so the 68k will get a reset all the time - check SDram controller reset_out signal in simulation - make sure it doesn't go high except during initialisation.
Check your address decoder on the top level schematic and chip select to the SDram controller. Make sure the SDram controller is responding to the addresses it should.
Simulation should verify that when the 68k reads or writes to the address of the SDram – the SDram controller should issue an activate command followed by read or write commands. If not, your address decoder might be wrong.
Check the Dtack out from the SDram controller and the one given back to the CPU. Make sure the 68k is actually getting a Dtack when it accesses the SDram. If not check the Dtack generator on the top level schematic and Dtack out from the dram controller.
Make sure you enable the data latch in your SDram controller at the correct time, 2 clock cycles after the dram receives CAS* during a read command. It has to be enabled for precisely one clock cycle/state during a read. If possible bring this signal out to the top level schematic and add it to the simulations. Make sure it is enabled 2 Dram memory chip clock cycles after CAS signal sent out. (Remember the Dram controller and the Dram memory chip run off inverted clocks, so a positive edge on the controller clock is a negative edge on the dram memory clock).
During a 68k write, make sure you turn on the FPGA data-out buffers to the SDram memory (i.e. they are not tri-stated), otherwise the SDram won’t get any data to store.
Also make sure you are not sending a write command to the SDram memory until the 68k has asserted its UDS*/LDS* signals and only send the write command for only 1 clock period.
Make sure A10 on the SDram chip is set to logic ‘1’ whenever you issue a read or write with autoprecharge command to the SDram. This will cause the SDram to internally precharge itself after each access – if A10 does not equal 1, the SDram will not be ready for the next operation. Check on the simulation waveform. For example, in verilog we could write this to make use of concatenation operator
DramAddress <= { 3’b001, Address[10:1] } ;
During a 68k read, make sure the data you latched from the SDram after 2 clock periods (i.e. the CAS* latency) is still presented to the CPU until the end of the read cycle when AS* goes inactive (high).
Q: What if my memory works with the debug monitor, that is, I can read and write bytes, but the memory test fails or I cannot run program code from the dram?
A: Check your state machine is returning to the idle state at the end of a bus cycle and is ready to start the next one asap. For example, the 68k does a 32 bit read/write as two successive 16 bit read/write operation with very little time in between. In the simulator waveform file, find where the 68k does a 32 bit read and write as two 16 bit read/write, check that your dram controller is responding to BOTH 16 bit transfers.
Check you have CKE active to the SDram at all times after initialisation
Check you have everything set up in the pin planner (it should be correct as it was set up in the project I gave you, but things can get screwed, so check them).
Check that during a read or write you present the correct row and column address and bank address and that you activate a bank/row followed by read/write (i.e. a column/bank address and CAS* and WE* where appropriate
Make sure your refreshing is working as per spec.