Hello everyone, I'm just wondering if anyone has written a memory controller for the on-board memory for the DE0 Nano(IS42216160B) and wouldn't mind posting their code.
I made a memory controller for it but it doesn't seem to work so I wanted to see a reference to try to figure out what I'm doing wrong.
Just so you guys don't think I'm just trying to get some code without writing any myself I'll post my code. But I'm not asking anyone to look through it(I imagine that would be very painful).
I found one resource where someone did write a memory controller for it but it was in VHDL (which I don't know) and it had a lot of features that I didn't need which made it harder to read.
module Memory_Controller(
input wire Clock_50MHZ, RW, Reset, Execute,
input wire[5:0] Data_In,
input wire[10:0] Addr_In, // In the form [A12, A11, A8-A0]
inout wire [5:0] Mem_IO,
output wire[5:0] Data_Out,
output wire[10:0] Addr_Out,
output wire Data_Ready, CS, RAS, CAS, WE, BA0, BA1, A9, A10, CKE, Ready, DQML, DQMH
);
// This is a basic memory controller for the IS42S16160B memory chip. Which has 256 Mb of memory in 16 bit words.
// RW: 1 means write, 0 means read
// Symbolic mode register defintion
localparam[14:0] mode_reg = 15'b00000100010000;
// Symbolic OP-Code definition. The OP Code is in the form [!CS, !RAS, !CAS, !WE]
localparam[3:0]
read = 4'b0101,
write = 4'b0100,
nop = 4'b0111,
activate = 4'b0011,
refresh = 4'b0001,
load_mode_reg = 4'b0000,
precharge = 4'b0010;
// Symbolic state defintions
localparam[4:0]
Start = 5'b00000,
Start_NOP = 5'b00001,
Start_Precharge = 5'b00010,
Start_Refresh = 5'b00011,
Start_Refresh_Loop = 5'b00100,
Load_Mode_Reg = 5'b00101,
Load_Mode_Reg_NOP1 = 5'b00110,
Load_Mode_Reg_NOP2 = 5'b00111,
Idle = 5'b01000,
Refresh = 5'b01001,
Refresh_NOP1 = 5'b01010,
Refresh_NOP2 = 5'b01011,
Refresh_NOP3 = 5'b01100,
Refresh_NOP4 = 5'b01101,
Activate = 5'b01110,
Activate_NOP = 5'b01111,
Read = 5'b10000,
Read_NOP1 = 5'b10001,
Read_NOP2 = 5'b10010,
Write = 5'b10011,
Write_NOP1 = 5'b10100,
Precharge = 5'b10101,
Precharge_NOP = 5'b10110;
// Internal defintions
reg[10:0] address, address_next;
reg[4:0] state, state_next;
reg[3:0] op_code, op_code_next;
reg[5:0] data_out, data_out_next, mem_io, mem_io_next;
reg[1:0] nop_count, nop_count_next;
reg[3:0] refresh_count, refresh_count_next;
reg ready, ready_next, data_ready, data_ready_next, ba0, ba0_next, ba1, ba1_next, a9, a9_next, a10, a10_next;
// FSMD register and data specifications
always @(posedge Clock_50MHZ)
begin
if(!Reset)
begin
state <= Start;
op_code <= nop;
nop_count <= 0;
refresh_count <= 0;
ready <= 0;
data_ready <= 0;
address <= 0;
ba0 <= 0;
ba1 <= 1;
a9 <= 0;
a10 <= 0;
mem_io <= 0;
data_out <= 0;
end
else
begin
state <= state_next;
op_code <= op_code_next;
nop_count <= nop_count_next;
refresh_count <= refresh_count_next;
ready <= ready_next;
data_ready <= data_ready_next;
address <= address_next;
ba0 <= ba0_next;
ba1 <= ba1_next;
a9 <= a9_next;
a10 <= a10_next;
mem_io <= mem_io_next;
data_out <= data_out_next;
end
end
// FSMD next state definitions
always @*
begin
// Define default values
state_next = state;
op_code_next = op_code;
nop_count_next = nop_count;
refresh_count_next = refresh_count;
ready_next = ready;
data_ready_next = data_ready;
address_next = address;
ba0_next = ba0;
ba1_next = ba1;
a9_next = a9;
a10_next = a10;
mem_io_next = mem_io;
data_out_next = data_out;
case(state)
// Initialization sequence
Start:
begin
data_out_next = 0;
ready_next = 0;
op_code_next = nop;
data_ready_next = 0;
refresh_count_next = 0;
mem_io_next = 0;
ba0_next = 0; // These two may need to be different but I think they can be constant.
ba1_next = 0; // They are essentually MSB of the address.
state_next = Start_NOP;
end
Start_NOP:
begin
op_code_next = nop;
state_next = Start_Precharge;
end
Start_Precharge:
begin
op_code_next = refresh;
nop_count_next = 0;
state_next = Start_Refresh;
end
Start_Refresh:
begin
op_code_next = nop;
nop_count_next = nop_count + 2'd1;
if(nop_count == 1) // Four nops are needed in total. This will achive two and the other comes from the state
state_next = Start_Refresh_Loop; // one of the state transisions later on.
else
state_next = Start_Refresh;
end
Start_Refresh_Loop:
begin
op_code_next = nop;
refresh_count_next = refresh_count + 4'd1;
if(refresh_count == 10)
state_next = Start_Precharge;
else
begin
op_code_next = load_mode_reg;
{ba1_next, ba0_next, address_next[10], address_next[9], a10_next, a9_next, address_next[8:0]} = mode_reg;
state_next = Load_Mode_Reg;
end
end
Load_Mode_Reg:
begin
op_code_next = nop;
state_next = Load_Mode_Reg_NOP1;
end
Load_Mode_Reg_NOP1:
begin
op_code_next = nop;
state_next = Load_Mode_Reg_NOP2;
end
Load_Mode_Reg_NOP2:
begin
op_code_next = nop;
refresh_count_next = 0;
a10_next = 0;
state_next = Idle;
end
// Idle
Idle:
begin
data_out_next = data_out;
ready_next = 1;
refresh_count_next = refresh_count + 4'd1;
op_code_next = nop;
if(refresh_count == 400) //REMOVE////////// replace with frequency dependant value later
begin
op_code_next = refresh;
state_next = Refresh;
end
else if((refresh_count != 400)&&Execute)
begin
op_code_next = activate;
ready_next = 0;
data_ready_next = 0;
state_next = Activate;
end
else
begin
state_next = Idle;
end
end
// Refresh sequence
Refresh:
begin
op_code_next = nop;
state_next = Refresh_NOP1;
end
Refresh_NOP1:
begin
op_code_next = nop;
state_next = Refresh_NOP2;
end
Refresh_NOP2:
begin
op_code_next = nop;
state_next = Refresh_NOP3;
end
Refresh_NOP3:
begin
op_code_next = nop;
state_next = Refresh_NOP4;
end
Refresh_NOP4:
begin
op_code_next = nop;
state_next = Idle;
end
// Activate sequence
Activate:
begin
address_next = Addr_In;
op_code_next = nop;
state_next = Activate_NOP;
end
Activate_NOP:
begin
if(RW) // Write
begin
op_code_next = write;
mem_io_next = Data_In;
state_next = Write;
end
else // Read
begin
op_code_next = read;
state_next = Read;
end
end
// Write sequence
Write:
begin
op_code_next = nop;
state_next = Write_NOP1;
end
Write_NOP1:
begin
op_code_next = precharge;
state_next = Precharge;
end
// Read sequence
Read:
begin
op_code_next = nop;
state_next = Read_NOP1;
end
Read_NOP1:
begin
op_code_next = nop;
data_out_next = Mem_IO; // ????? mem_io ?
state_next = Read_NOP2;
end
Read_NOP2:
begin
op_code_next = precharge;
data_ready_next = 1;
state_next = Precharge;
end
// Precharge sequence
Precharge:
begin
op_code_next = nop;
state_next = Precharge_NOP;
end
Precharge_NOP:
begin
op_code_next = nop;
state_next = Idle;
end
default:
state_next = Idle;
endcase
end
// Connections
assign Mem_IO = (RW) ? mem_io : 6'bz;
assign DQMH = 0;
assign DQML = 0;
assign Data_Out = data_out;
assign CS = op_code[3];
assign RAS = op_code[2];
assign CAS = op_code[1];
assign WE = op_code[0];
assign CKE = 1; // Clock enable. Might need a non constant value for start up.
assign BA0 = ba0;
assign BA1 = ba1;
assign A9 = a9;
assign A10 = a10; // Selects which banks to activate. Since I'm always using the same banks, IE BA0/BA1 constant, it shouldn't matter.
assign Addr_Out = address;
assign Data_Ready = data_ready;
assign Ready = ready;
endmodule
I know this is a long shot but I thought I would try.
Thank you!