189 lines
7.8 KiB
Verilog
189 lines
7.8 KiB
Verilog
/*
|
|
* DEVICE INFORMATION:
|
|
* HY57V641620FTP-7:
|
|
* RAS latency: 2 or 3 cycles
|
|
* RCD latency: 2 or 3 cycles
|
|
* full address_select available for row selection
|
|
* address_select[7:0] available for col selection
|
|
*/
|
|
|
|
module RAM(
|
|
input wire clk, // Clock signal
|
|
output reg [10:0] RAM_addr, // RAM address buffer
|
|
output reg RAM_A10, // RAM address/auto-precharge
|
|
output reg [1:0] RAM_bank_sel, // RAM bank selection
|
|
inout wire [15:0] RAM_data, // RAM data bus
|
|
output wire RAM_clk, // RAM clock signal
|
|
output wire RAM_clk_enable, // RAM enable clock
|
|
output reg RAM_enable, // RAM chip enable
|
|
output reg RAM_strobe_row, // RAM row strobe
|
|
output reg RAM_strobe_col, // RAM column strobe
|
|
output reg RAM_write_enable, // RAM data bus write enable
|
|
input wire read_rq, // Read request (Internal)
|
|
input wire write_rq, // Write request (Internal)
|
|
input wire [1:0] access_bank, // Which bank to access
|
|
output wire op_trigger, // Event trigger wire
|
|
input wire [11:0] address_select, // Address selection when accessing RAM,
|
|
input wire stop_access, // Close a row
|
|
output reg [1:0] op_bank // Bank being accessed when op_trigger is pulled high
|
|
);
|
|
|
|
parameter CPB = 4; // Specifies in bit length how many cycles a bank burst can allocate for itself before other banks are checked
|
|
parameter tRCD = 3 + 1; // Assume RCD latency of 3 cycles
|
|
parameter tRAS = 3 + 1; // Assume CAS latency of 3 cycles
|
|
|
|
reg [CPB-1:0] acc_cycles; // Cycles used on current bank
|
|
reg [1:0] acc_bank; // Which bank is allocating read cycles
|
|
reg [1:0] acc_close[0:3]; // Requests a close of the current row
|
|
reg [3:0] acc_type; // The current access type of the bank (0: READ, 1: WRITE)
|
|
reg [2:0] acc_state [0:3]; // Current access state for each bank (0: READY, 1: OPENING, 2: tRAS, 3: tRCD, 4: RW_OPEN)
|
|
reg [3:0] acc_init_callback; // Pull this high to initiate a callback
|
|
reg [1:0] event_trigger; // Event triggers drive op_trigger
|
|
|
|
wire [3:0] acc_event; // Event update callback wire
|
|
wire [2:0] callback_timeout[0:3]; // Callback clock cycle definition
|
|
|
|
Callback #(.ISIZE(3)) cb0(clk, callback_timeout[0], acc_init_callback[0], acc_event[0]);
|
|
Callback #(.ISIZE(3)) cb1(clk, callback_timeout[1], acc_init_callback[1], acc_event[1]);
|
|
Callback #(.ISIZE(3)) cb2(clk, callback_timeout[2], acc_init_callback[2], acc_event[2]);
|
|
Callback #(.ISIZE(3)) cb3(clk, callback_timeout[3], acc_init_callback[3], acc_event[3]);
|
|
|
|
|
|
// Initialize the ram in an inactive state
|
|
initial RAM_enable = 1'b1;
|
|
initial RAM_strobe_row = 1'b1;
|
|
initial RAM_strobe_col = 1'b1;
|
|
initial RAM_write_enable = 1'b1;
|
|
initial acc_bank = 1'b1;
|
|
|
|
assign op_trigger = event_trigger[0] ^ event_trigger[1];
|
|
assign RAM_clk = clk;
|
|
assign RAM_clk_enable = (acc_state[0] | acc_state[1] | acc_state[2] | acc_state[3]) ? 1'b1 : 1'b0;
|
|
|
|
genvar n;
|
|
generate
|
|
for(n = 0; n < 4; n = n + 1) begin : gen_callback_timing
|
|
assign callback_timeout[n] = acc_state[n][1] ? tRAS : tRCD;
|
|
end
|
|
endgenerate
|
|
|
|
integer i;
|
|
|
|
always @(posedge read_rq or posedge write_rq or posedge acc_event or posedge stop_access or posedge clk) begin
|
|
if(read_rq || write_rq) begin
|
|
if(acc_state[access_bank] == 3'b000) begin
|
|
RAM_enable <= 1'b0;
|
|
RAM_strobe_row <= 1'b0;
|
|
RAM_strobe_col <= 1'b1;
|
|
RAM_write_enable <= 1'b1;
|
|
|
|
RAM_bank_sel <= access_bank;
|
|
RAM_addr <= {address_select[11], address_select[9:0]};
|
|
RAM_A10 <= address_select[10];
|
|
acc_type[access_bank] <= read_rq ? 1'b0 : 1'b1;
|
|
acc_state[access_bank] <= 3'b001;
|
|
acc_init_callback[access_bank] <= 1'b1;
|
|
acc_close[access_bank] <= 1'b0;
|
|
end
|
|
end
|
|
else if(stop_access) begin
|
|
if(acc_state[access_bank])
|
|
acc_close[access_bank] <= 1'b1;
|
|
end
|
|
else if(clk) begin
|
|
for(i = 0; i < 4; i = i + 1)
|
|
if(acc_state[i] == 3'b010)
|
|
acc_init_callback[i] <= 1'b1;
|
|
|
|
if(~(acc_state[0] | acc_state[1] | acc_state[2] | acc_state[3]))
|
|
RAM_enable <= 1'b1;
|
|
|
|
// Bank access management
|
|
acc_cycles[acc_bank] <= acc_cycles[acc_bank] + 1'b1;
|
|
if(acc_cycles[acc_bank] == {CPB{1'b1}}) begin
|
|
|
|
// Close banks as needed
|
|
if(acc_close[0]) begin
|
|
acc_close[0] <= 1'b0;
|
|
RAM_bank_sel <= 2'b00;
|
|
acc_state[0] <= 3'b000;
|
|
end
|
|
else if(acc_close[1]) begin
|
|
acc_close[1] <= 1'b0;
|
|
RAM_bank_sel <= 2'b01;
|
|
acc_state[1] <= 3'b000;
|
|
end
|
|
else if(acc_close[2]) begin
|
|
acc_close[2] <= 1'b0;
|
|
RAM_bank_sel <= 2'b10;
|
|
acc_state[2] <= 3'b000;
|
|
end
|
|
else if(acc_close[3]) begin
|
|
acc_close[3] <= 1'b0;
|
|
RAM_bank_sel <= 2'b11;
|
|
acc_state[3] <= 3'b000;
|
|
end
|
|
|
|
// Increment bank tracker
|
|
if(~(acc_close[0] | acc_close[1] | acc_close[2] | acc_close[3])) begin
|
|
acc_bank <= acc_bank + 1;
|
|
acc_cycles <= {CPB{1'b0}};
|
|
end
|
|
else begin
|
|
// Trigger RAM row-close event
|
|
RAM_enable <= 1'b0;
|
|
RAM_strobe_row <= 1'b1;
|
|
RAM_strobe_col <= 1'b1;
|
|
RAM_write_enable <= 1'b0;
|
|
end
|
|
end
|
|
else begin
|
|
// Access bank
|
|
for(i = 0; i < 4; i = i + 1) begin
|
|
// Bank_{i} active and not closing and...
|
|
// Enough cycles left or when no other bank is active or...
|
|
// Bank_{i+1} at cycle limit and next banks inactive or bank is closing or...
|
|
// Bank_{i+2} at cycle limit and next bank inactive or bank is closing or...
|
|
// Bank_{i+3} at cycle limit or closing
|
|
if(!acc_close[i] && acc_state[i] == 3'b100 && (
|
|
(acc_bank == i && (acc_cycles != {CPB{1'b1}} || (acc_state[(i+1)%4] != 3'b100 && acc_state[(i+2)%4] != 3'b3100 && acc_state[(i+3)%4] != 3'b3100))) ||
|
|
(acc_bank == (i+1)%4 && ((acc_close[(i+1)%4] || acc_cycles == {CPB{1'b1}}) && acc_state[(i+2)%4] != 3'b100 && acc_state[(i+3)%4] != 3'b100)) ||
|
|
(acc_bank == (i+2)%4 && ((acc_close[(i+2)%4] || acc_cycles == {CPB{1'b1}}) && acc_state[(i+3)%4] != 3'b100)) ||
|
|
(acc_bank == (i+3)%4 && (acc_close[(i+3)%4] || acc_cycles == {CPB{1'b1}}))
|
|
)) begin
|
|
RAM_bank_sel <= i;
|
|
RAM_addr <= {2'b0, RAM_addr[7:0]};
|
|
RAM_A10 <= 1'b1;
|
|
RAM_strobe_row <= 1'b1;
|
|
RAM_strobe_col <= 1'b0;
|
|
RAM_write_enable <= ~acc_type[i];
|
|
op_bank <= i;
|
|
event_trigger[0] <= event_trigger[1] ? 1'b0 : 1'b1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else if(acc_event) begin
|
|
for(i = 0; i < 4; i = i + 1) begin
|
|
if(acc_state[i] == 3'b001) begin
|
|
RAM_bank_sel <= i;
|
|
RAM_strobe_row <= 1'b1;
|
|
RAM_strobe_col <= 1'b0;
|
|
RAM_write_enable <= ~acc_type[i];
|
|
RAM_A10 <= 1;
|
|
acc_state[i] <= 3'b010;
|
|
acc_init_callback[i] <= 1'b0;
|
|
end
|
|
else if(acc_state[i] == 3'b010) begin
|
|
acc_init_callback[i] <= 1'b0;
|
|
acc_state[i] <= 3'b100;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
// Reset op_trigger by tracking posedge-driven event_trigger
|
|
always @(negedge clk) event_trigger[1] <= event_trigger[0] ? 1'b1 : 1'b0;
|
|
|
|
endmodule
|