mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-04-27 04:47:18 +00:00
Archie: 128bit SDRAM interface (by Sorgelig)
This commit is contained in:
@@ -155,6 +155,7 @@ wire sirq_n;
|
||||
wire ram_cs;
|
||||
wire vid_we;
|
||||
wire snd_ack, snd_req;
|
||||
wire [31:0] cpu_dout;
|
||||
|
||||
memc MEMC(
|
||||
|
||||
@@ -170,7 +171,8 @@ memc MEMC(
|
||||
.cpu_we ( cpu_we ),
|
||||
.cpu_sel ( cpu_sel ),
|
||||
.cpu_ack ( cpu_ack ),
|
||||
.cpu_err ( cpu_err ),
|
||||
.cpu_err ( cpu_err ),
|
||||
.cpu_dout ( cpu_dout ),
|
||||
|
||||
// memory interface
|
||||
.mem_addr_o ( MEM_ADDR_O ),
|
||||
@@ -180,6 +182,7 @@ memc MEMC(
|
||||
.mem_sel_o ( MEM_SEL_O ),
|
||||
.mem_we_o ( MEM_WE_O ),
|
||||
.mem_cti_o ( MEM_CTI_O ),
|
||||
.mem_dat_i ( MEM_DAT_I ),
|
||||
|
||||
// vidc interface
|
||||
.hsync ( HSYNC ),
|
||||
@@ -390,7 +393,7 @@ assign cpu_dat_i = floppy_en ? {24'd0, floppy_dat_o} :
|
||||
latches_en ? {24'd0, latches_dat_o} :
|
||||
podules_en ? {16'd0, pod_dat_o} :
|
||||
ioc_cs & ~ioc_sext ? {24'd0, ioc_dat_o} :
|
||||
ram_cs ? MEM_DAT_I :
|
||||
ram_cs ? cpu_dout :
|
||||
32'hFFFF_FFFF;
|
||||
|
||||
assign I2C_CLOCK = ioc_cout[1];
|
||||
|
||||
@@ -37,6 +37,7 @@ module memc(
|
||||
input cpu_cyc,
|
||||
output cpu_err,
|
||||
output cpu_ack,
|
||||
output [31:0] cpu_dout,
|
||||
|
||||
input [25:0] cpu_address,
|
||||
input [3:0] cpu_sel,
|
||||
@@ -47,6 +48,7 @@ module memc(
|
||||
output mem_cyc_o,
|
||||
output mem_we_o,
|
||||
output [3:0] mem_sel_o,
|
||||
input [31:0] mem_dat_i,
|
||||
|
||||
input mem_ack_i,
|
||||
output [2:0] mem_cti_o, // burst / normal
|
||||
@@ -127,13 +129,8 @@ localparam REG_SendN = 3'b101;
|
||||
localparam REG_Sptr = 3'b110;
|
||||
localparam REG_Ctrl = 3'b111;
|
||||
|
||||
wire table_valid;
|
||||
wire err;
|
||||
wire memw;
|
||||
wire logcs;
|
||||
wire vidc_cs;
|
||||
wire mem_virtual;
|
||||
wire[25:0] phys_address;
|
||||
wire table_valid;
|
||||
|
||||
memc_translator PAGETABLES(
|
||||
|
||||
@@ -174,9 +171,21 @@ initial begin
|
||||
|
||||
end
|
||||
|
||||
always @(posedge clkcpu) begin
|
||||
reg [31:0] cache_data[4];
|
||||
reg cache_valid;
|
||||
reg [23:4] cache_addr;
|
||||
reg cache_ack;
|
||||
|
||||
if (rst_i == 1'b1) begin
|
||||
assign cpu_dout = cache_data[caddr[3:2]];
|
||||
|
||||
always @(posedge clkcpu) begin
|
||||
reg cache_rcv, cache_test;
|
||||
reg [1:0] cache_cnt;
|
||||
reg [1:0] cache_wraddr;
|
||||
|
||||
cache_ack <= 0;
|
||||
|
||||
if (rst_i) begin
|
||||
|
||||
vid_init <= INITIAL_SCREEN_BASE;
|
||||
cur_init <= INITIAL_CURSOR_BASE;
|
||||
@@ -191,15 +200,33 @@ always @(posedge clkcpu) begin
|
||||
memc_control[11] <= 1'b0; // disable sound dma on reset.
|
||||
|
||||
dma_request_r <= 1'b0;
|
||||
cache_rcv <= 0;
|
||||
cache_valid <= 0;
|
||||
cache_test <= 0;
|
||||
|
||||
end else begin
|
||||
|
||||
if(cache_rcv & mem_ack_i) begin
|
||||
cache_data[cache_wraddr] <= mem_dat_i;
|
||||
cache_wraddr <= cache_wraddr + 1'd1;
|
||||
cache_cnt <= cache_cnt + 1'd1;
|
||||
if(cache_cnt == 2) cache_ack <= 1;
|
||||
if(&cache_cnt) begin
|
||||
cache_rcv <= 0;
|
||||
cache_valid <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
dma_request_r <= dma_request;
|
||||
|
||||
// cpu cycle.
|
||||
if (cpu_cyc & cpu_stb) begin
|
||||
|
||||
cache_test <= 1;
|
||||
if(cache_valid & (cache_addr == caddr[23:4]) & ~cpu_mem_we) begin
|
||||
// cache hit
|
||||
if(~cache_test) cache_ack <= 1;
|
||||
end
|
||||
else begin
|
||||
// logic to ensure that the rom overlay gets deactivated.
|
||||
if (cpu_address[25:24] == 2'b11) begin
|
||||
|
||||
@@ -209,16 +236,18 @@ always @(posedge clkcpu) begin
|
||||
|
||||
// ensure no video cycle is active or about to start.
|
||||
if (~dma_request_r & ~dma_in_progress) begin
|
||||
|
||||
cpu_load <= 1'b1;
|
||||
|
||||
if(~cpu_load) begin
|
||||
if(cpu_mem_we) begin
|
||||
if(cache_addr == caddr[23:4]) cache_valid <= 0;
|
||||
end
|
||||
else begin
|
||||
{cache_addr,cache_wraddr} <= caddr[23:2];
|
||||
cache_valid <= 0;
|
||||
cache_rcv <= 1;
|
||||
cache_cnt <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
// prevent the cpu hogging the bus.
|
||||
if (cpu_load & dma_request_r & (cpu_ack | cpu_err)) begin
|
||||
|
||||
cpu_load <= 1'b0;
|
||||
|
||||
end
|
||||
|
||||
if (memw) begin
|
||||
@@ -233,11 +262,9 @@ always @(posedge clkcpu) begin
|
||||
REG_Cinit: cur_init <= {cpu_address[16:2], 4'b0000};
|
||||
|
||||
REG_Sstart: begin
|
||||
|
||||
$display("Sstart: %x", {cpu_address[16:2], 4'b0000});
|
||||
snd_next_valid <= 1'b1;
|
||||
snd_start <= {cpu_address[16:2], 4'b0000};
|
||||
|
||||
end
|
||||
|
||||
REG_SendN: begin
|
||||
@@ -269,11 +296,13 @@ always @(posedge clkcpu) begin
|
||||
endcase
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
cpu_load <= 1'b0;
|
||||
|
||||
cpu_load <= 0;
|
||||
cache_rcv <= 0;
|
||||
cache_test <= 0;
|
||||
end
|
||||
|
||||
// video dma stuff.
|
||||
@@ -338,12 +367,12 @@ always @(posedge clkcpu) begin
|
||||
if ((vidak & vid_load) == 1'b1) begin
|
||||
|
||||
// advance the pointer to the next location.
|
||||
vid_address <= vid_address + 4'd4;
|
||||
vid_address <= vid_address + 19'd4;
|
||||
|
||||
end else if ((vidak & cur_load) == 1'b1) begin
|
||||
|
||||
// advance the cursor pointer to the next location.
|
||||
cur_address <= cur_address + 4'd4;
|
||||
cur_address <= cur_address + 19'd4;
|
||||
|
||||
end
|
||||
|
||||
@@ -364,7 +393,7 @@ always @(posedge clkcpu) begin
|
||||
if ((sndak & snd_load) == 1'b1) begin
|
||||
|
||||
// advance the pointer to the next location.
|
||||
snd_sptr <= snd_sptr + 4'd4;
|
||||
snd_sptr <= snd_sptr + 19'd4;
|
||||
end
|
||||
|
||||
end else begin
|
||||
@@ -394,35 +423,38 @@ wire [21:2] ram_page = memc_control[3:2] == 2'b00 ? {3'd0, cpu_address[18:2]}:
|
||||
assign mem_addr_o = vid_load ? {5'd0, vid_address[18:2]} :
|
||||
cur_load ? {5'd0, cur_address[18:2]} :
|
||||
snd_load ? {5'd0, snd_sptr[18:2]} :
|
||||
phycs ? {2'd0, ram_page} : // use physical memory
|
||||
caddr;
|
||||
|
||||
wire [23:2] caddr = phycs ? {2'd0, ram_page} : // use physical memory
|
||||
romcs ? {3'b010, cpu_address[20:2]} : // use 2mb and up for rom space.
|
||||
table_valid & logcs ? phys_address[23:2] : 22'd0; // use logical memory.
|
||||
|
||||
|
||||
// does this cpu cycle need to go to external RAM/ROM?
|
||||
assign cpu_ram_cycle = cpu_cyc & cpu_stb & (table_valid | phycs | romcs);
|
||||
//assign cpu_ram_cycle = cpu_cyc & cpu_stb & (table_valid | phycs | romcs);
|
||||
|
||||
assign mem_cyc_o = cpu_load ? cpu_cyc : dma_in_progress;
|
||||
assign mem_cyc_o = cpu_load ? cpu_cyc & ~err : dma_in_progress;
|
||||
assign mem_stb_o = cpu_load ? cpu_stb : dma_in_progress;
|
||||
assign mem_sel_o = cpu_load ? cpu_sel : 4'b1111;
|
||||
assign mem_we_o = cpu_load ? cpu_we & (phycs & spvmd | table_valid & logcs) & ~romcs : 1'b0;
|
||||
assign mem_cti_o = cpu_load ? 3'b000 : 3'b010;
|
||||
assign mem_we_o = cpu_load ? cpu_mem_we : 1'b0;
|
||||
assign mem_cti_o = 3'b010;
|
||||
|
||||
wire cpu_mem_we = cpu_we & ((phycs & spvmd) | (table_valid & logcs)) & ~romcs;
|
||||
|
||||
assign address_valid = (logcs & table_valid) | rom_low_cs| ioc_cs | memw | tablew | vidc_cs | (phycs & ~cpu_we) | (phycs & spvmd & cpu_we) | romcs;
|
||||
assign err = ~address_valid;
|
||||
wire err = ~address_valid;
|
||||
|
||||
assign cpu_ack = cpu_load ? mem_ack_i & ~err : 1'b0;
|
||||
assign cpu_ack = (mem_we_o ? mem_ack_i : cache_ack) & ~err;
|
||||
assign cpu_err = cpu_load ? mem_ack_i & err : 1'b0;
|
||||
|
||||
assign tablew = cpu_load & cpu_cyc & cpu_we & spvmd & (cpu_address[25:23] == 3'b111) & (cpu_address[12] == 0) & (cpu_address[7] == 0); // &3800000+
|
||||
assign memw = cpu_load & cpu_cyc & cpu_we & spvmd & (cpu_address[25:21] == 5'b11011); // &3600000
|
||||
wire memw = cpu_load & cpu_cyc & cpu_we & spvmd & (cpu_address[25:21] == 5'b11011); // &3600000
|
||||
assign vidw = cpu_load & cpu_cyc & cpu_we & vidc_cs; // &3400000
|
||||
|
||||
// bus chip selects
|
||||
assign logcs = cpu_address[25] == 1'b0; // 0000000-&1FFFFFF
|
||||
wire logcs = cpu_address[25] == 1'b0; // 0000000-&1FFFFFF
|
||||
assign phycs = cpu_address[25:24] == 2'b10; //&2000000 - &2FFFFFF
|
||||
assign ioc_cs = spvmd & (cpu_address[25:22] == 4'b1100); //&3000000 - &33FFFFF
|
||||
assign vidc_cs = spvmd & (cpu_address[25:21] == 5'b11010); // &3400000 - &35FFFFF (WE & SPVMD)
|
||||
wire vidc_cs = spvmd & (cpu_address[25:21] == 5'b11010); // &3400000 - &35FFFFF (WE & SPVMD)
|
||||
assign rom_low_cs = (cpu_address[25:22] == 4'b1101);
|
||||
|
||||
assign romcs = ((cpu_address[25:23] == 3'b111) | (cpu_address[25:19] == 7'h00) & rom_overlay);
|
||||
@@ -433,6 +465,6 @@ assign sndak = cpu_load ? 1'b0 : sound_dma_ip & mem_ack_i;
|
||||
assign sirq_n = snd_next_valid;
|
||||
assign ram_cs = table_valid | phycs | romcs;
|
||||
|
||||
assign mem_virtual = table_valid & ~cpu_address[25];
|
||||
//wire mem_virtual= table_valid & ~cpu_address[25];
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* sdram_defines.v
|
||||
|
||||
Copyright (c) 2013-2014, Stephen J. Leary
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Stephen J. Leary nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL STEPHEN J. LEARY BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
localparam RASCAS_DELAY = 3'd3; // tRCD=20ns -> 3 cycles@128MHz
|
||||
localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8, 111 = continuous.
|
||||
localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
|
||||
localparam CAS_LATENCY = 3'd3; // 2/3 allowed
|
||||
localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
|
||||
localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write
|
||||
localparam WRITE_BURST = 1'b0; // 0= write burst enabled, 1=only single access write
|
||||
localparam RFC_DELAY = 4'd7; // tRFC=66ns -> 9 cycles@128MHz
|
||||
|
||||
// all possible commands
|
||||
localparam CMD_INHIBIT = 4'b1111;
|
||||
localparam CMD_NOP = 4'b0111;
|
||||
localparam CMD_ACTIVE = 4'b0011;
|
||||
localparam CMD_READ = 4'b0101;
|
||||
localparam CMD_WRITE = 4'b0100;
|
||||
localparam CMD_BURST_TERMINATE = 4'b0110;
|
||||
localparam CMD_PRECHARGE = 4'b0010;
|
||||
localparam CMD_AUTO_REFRESH = 4'b0001;
|
||||
localparam CMD_LOAD_MODE = 4'b0000;
|
||||
@@ -1,5 +1,4 @@
|
||||
/* sdram_top.v
|
||||
|
||||
/*
|
||||
Copyright (c) 2013-2014, Stephen J. Leary
|
||||
All rights reserved.
|
||||
|
||||
@@ -26,105 +25,115 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
module sdram_top (
|
||||
|
||||
module sdram_top
|
||||
(
|
||||
// interface to the MT48LC16M16 chip
|
||||
input sd_clk, // sdram is accessed at 128MHz
|
||||
input sd_rst, // reset the sdram controller.
|
||||
output sd_cke, // clock enable.
|
||||
inout reg[15:0]sd_dq, // 16 bit bidirectional data bus
|
||||
output reg[12:0]sd_addr, // 13 bit multiplexed address bus
|
||||
output reg[1:0] sd_dqm = 2'b00, // two byte masks
|
||||
output reg[1:0] sd_ba = 2'b00, // two banks
|
||||
output sd_cs_n, // a single chip select
|
||||
output sd_we_n, // write enable
|
||||
output sd_ras_n, // row address select
|
||||
output sd_cas_n, // columns address select
|
||||
output reg sd_ready = 0, // sd ready.
|
||||
input sd_clk, // sdram is accessed at 128MHz
|
||||
input sd_rst, // reset the sdram controller.
|
||||
output sd_cke, // clock enable.
|
||||
inout reg[15:0] sd_dq, // 16 bit bidirectional data bus
|
||||
output reg[12:0] sd_addr, // 13 bit multiplexed address bus
|
||||
output [1:0] sd_dqm, // two byte masks
|
||||
output reg [1:0] sd_ba, // two banks
|
||||
output sd_cs_n, // a single chip select
|
||||
output sd_we_n, // write enable
|
||||
output sd_ras_n, // row address select
|
||||
output sd_cas_n, // columns address select
|
||||
output reg sd_ready, // sd ready.
|
||||
|
||||
// cpu/chipset interface
|
||||
|
||||
input wb_clk, // 32MHz chipset clock to which sdram state machine is synchonized
|
||||
input [31:0] wb_dat_i, // data input from chipset/cpu
|
||||
output reg[31:0]wb_dat_o = 0, // data output to chipset/cpu
|
||||
output reg wb_ack = 0,
|
||||
input [23:0] wb_adr, // lower 2 bits are ignored.
|
||||
input [3:0] wb_sel, //
|
||||
input [2:0] wb_cti, // cycle type.
|
||||
input wb_stb, //
|
||||
input wb_cyc, // cpu/chipset requests cycle
|
||||
input wb_we // cpu/chipset requests write
|
||||
input wb_clk, // 32MHz chipset clock to which sdram state machine is synchonized
|
||||
input [31:0] wb_dat_i, // data input from chipset/cpu
|
||||
output reg[31:0] wb_dat_o = 0, // data output to chipset/cpu
|
||||
output reg wb_ack = 0,
|
||||
input [23:0] wb_adr, // lower 2 bits are ignored.
|
||||
input [3:0] wb_sel, //
|
||||
input [2:0] wb_cti, // cycle type.
|
||||
input wb_stb, //
|
||||
input wb_cyc, // cpu/chipset requests cycle
|
||||
input wb_we // cpu/chipset requests write
|
||||
);
|
||||
|
||||
`include "sdram_defines.v"
|
||||
localparam RASCAS_DELAY = 3'd3; // tRCD=20ns -> 3 cycles@128MHz
|
||||
localparam BURST_LENGTH = 3'b011; // 000=1, 001=2, 010=4, 011=8, 111 = continuous.
|
||||
localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
|
||||
localparam CAS_LATENCY = 3'd3; // 2/3 allowed
|
||||
localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
|
||||
localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write
|
||||
localparam WRITE_BURST = 1'b0; // 0= write burst enabled, 1=only single access write
|
||||
localparam RFC_DELAY = 4'd7; // tRFC=66ns -> 9 cycles@128MHz
|
||||
|
||||
// all possible commands
|
||||
localparam CMD_NOP = 4'b0111;
|
||||
localparam CMD_ACTIVE = 4'b0011;
|
||||
localparam CMD_READ = 4'b0101;
|
||||
localparam CMD_WRITE = 4'b0100;
|
||||
localparam CMD_BURST_TERMINATE = 4'b0110;
|
||||
localparam CMD_PRECHARGE = 4'b0010;
|
||||
localparam CMD_AUTO_REFRESH = 4'b0001;
|
||||
localparam CMD_LOAD_MODE = 4'b0000;
|
||||
|
||||
localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
|
||||
|
||||
reg [3:0] t;
|
||||
reg [4:0] reset;
|
||||
reg [3:0] t;
|
||||
reg [4:0] reset;
|
||||
reg[31:0] sd_dat[4]; // data output to chipset/cpu
|
||||
|
||||
reg[31:0] sd_dat = 0; // data output to chipset/cpu
|
||||
reg[31:0] sd_dat_nxt = 0; // data output to chipset/cpu
|
||||
|
||||
reg sd_stb = 1'b0; // copy of the wishbone bus signal.
|
||||
reg sd_we = 1'b0; // copy of the wishbone bus signal.
|
||||
reg sd_cyc = 1'b0; // copy of the wishbone bus signal.
|
||||
reg sd_burst = 1'b0;
|
||||
|
||||
reg [3:0] sd_cycle= 4'd0;
|
||||
reg sd_done = 1'b0;
|
||||
|
||||
reg [3:0] sd_cmd = 4'd0; // current command sent to sd ram
|
||||
reg [3:0] sd_cmd; // current command sent to sd ram
|
||||
|
||||
reg [9:0] sd_refresh = 10'd0;
|
||||
reg sd_auto_refresh = 1'b0;
|
||||
wire sd_req = wb_stb & wb_cyc & ~wb_ack;
|
||||
reg [11:0] sd_active_row[3:0];
|
||||
reg [3:0] sd_bank_active;
|
||||
wire [1:0] sd_bank = wb_adr[22:21];
|
||||
wire [11:0] sd_row = wb_adr[20:9];
|
||||
wire sd_req = wb_stb & wb_cyc & ~wb_ack;
|
||||
wire sd_reading = wb_stb & wb_cyc & ~wb_we;
|
||||
wire sd_writing = wb_stb & wb_cyc & wb_we;
|
||||
|
||||
initial begin
|
||||
t = 4'd0;
|
||||
reset = 5'h1f;
|
||||
sd_addr = 13'd0;
|
||||
sd_cmd = CMD_INHIBIT;
|
||||
t = 4'd0;
|
||||
reset = 5'h1f;
|
||||
sd_cmd = CMD_NOP;
|
||||
sd_ready= 0;
|
||||
end
|
||||
|
||||
localparam CYCLE_PRECHARGE = 4'd0;
|
||||
localparam CYCLE_RAS_START = 4'd3;
|
||||
localparam CYCLE_IDLE = 4'd0;
|
||||
localparam CYCLE_RAS_START = CYCLE_IDLE;
|
||||
localparam CYCLE_RFSH_START = CYCLE_RAS_START;
|
||||
localparam CYCLE_CAS0 = CYCLE_RAS_START + RASCAS_DELAY;
|
||||
localparam CYCLE_CAS1 = CYCLE_CAS0 + 4'd1;
|
||||
localparam CYCLE_CAS2 = CYCLE_CAS1 + 4'd1;
|
||||
localparam CYCLE_CAS3 = CYCLE_CAS2 + 4'd1;
|
||||
localparam CYCLE_READ0 = CYCLE_CAS0 + CAS_LATENCY + 4'd1;
|
||||
localparam CYCLE_READ1 = CYCLE_READ0+ 1'd1;
|
||||
localparam CYCLE_READ2 = CYCLE_READ1+ 1'd1;
|
||||
localparam CYCLE_READ3 = CYCLE_READ2+ 1'd1;
|
||||
localparam CYCLE_END = CYCLE_READ3+ 1'd1;
|
||||
localparam CYCLE_RFSH_END = CYCLE_RFSH_START + RFC_DELAY;
|
||||
localparam CYCLE_CAS0 = CYCLE_RAS_START + RASCAS_DELAY;
|
||||
localparam CYCLE_CAS1 = CYCLE_CAS0 + 4'd1;
|
||||
localparam CYCLE_CAS2 = CYCLE_CAS1 + 4'd1;
|
||||
localparam CYCLE_CAS3 = CYCLE_CAS2 + 4'd1;
|
||||
localparam CYCLE_READ0 = CYCLE_CAS0 + CAS_LATENCY + 4'd1;
|
||||
localparam CYCLE_READ1 = CYCLE_READ0+ 1'd1;
|
||||
localparam CYCLE_READ2 = CYCLE_READ1+ 1'd1;
|
||||
localparam CYCLE_READ3 = CYCLE_READ2+ 1'd1;
|
||||
localparam CYCLE_READ4 = CYCLE_READ3+ 1'd1;
|
||||
localparam CYCLE_READ5 = CYCLE_READ4+ 1'd1;
|
||||
localparam CYCLE_READ6 = CYCLE_READ5+ 1'd1;
|
||||
localparam CYCLE_READ7 = CYCLE_READ6+ 1'd1;
|
||||
localparam CYCLE_RFSH_END = CYCLE_RFSH_START + RFC_DELAY;
|
||||
|
||||
localparam RAM_CLK = 128000000;
|
||||
localparam REFRESH_PERIOD = (RAM_CLK / (16 * 8192)) - CYCLE_END;
|
||||
|
||||
`ifdef VERILATOR
|
||||
reg [15:0] sd_q;
|
||||
assign sd_dq = (sd_writing && (sd_cycle == CYCLE_CAS1 || sd_cycle == CYCLE_CAS2)) ? sd_q : 16'bZZZZZZZZZZZZZZZZ;
|
||||
`endif
|
||||
localparam RAM_CLK = 120000000;
|
||||
localparam REFRESH_PERIOD = (RAM_CLK / (16 * 8192));
|
||||
|
||||
always @(posedge sd_clk) begin
|
||||
reg sd_reqD, sd_reqD2;
|
||||
reg sd_newreq;
|
||||
reg [3:0] sd_cycle = CYCLE_IDLE;
|
||||
reg [2:0] word;
|
||||
|
||||
`ifndef VERILATOR
|
||||
sd_dq <= 16'bZZZZZZZZZZZZZZZZ;
|
||||
`endif
|
||||
sd_dq <= 16'bZZZZZZZZZZZZZZZZ;
|
||||
sd_cmd <= CMD_NOP;
|
||||
|
||||
sd_reqD <= sd_req;
|
||||
if(~sd_reqD & sd_req) sd_newreq <= 1;
|
||||
|
||||
if (sd_rst) begin
|
||||
t <= 4'd0;
|
||||
t <= 0;
|
||||
reset <= 5'h1f;
|
||||
sd_addr <= 13'd0;
|
||||
sd_ready <= 0;
|
||||
sd_addr <= 0;
|
||||
sd_ready <= 0;
|
||||
sd_ba <= 0;
|
||||
end else begin
|
||||
if (!sd_ready) begin
|
||||
t <= t + 4'd1;
|
||||
@@ -138,7 +147,7 @@ always @(posedge sd_clk) begin
|
||||
if(reset == 13) begin
|
||||
$display("precharging all banks");
|
||||
sd_cmd <= CMD_PRECHARGE;
|
||||
sd_addr[10] <= 1'b1; // precharge all banks
|
||||
sd_addr[10] <= 1'b1; // precharge all banks
|
||||
end
|
||||
|
||||
if(reset == 2) begin
|
||||
@@ -152,222 +161,130 @@ always @(posedge sd_clk) begin
|
||||
sd_addr <= MODE;
|
||||
end
|
||||
|
||||
if(reset == 0) sd_ready <= 1;
|
||||
if(!reset) sd_ready <= 1;
|
||||
word <= 0;
|
||||
end
|
||||
end else begin
|
||||
|
||||
// bring the wishbone bus signal into the ram clock domain.
|
||||
|
||||
sd_we <= wb_we;
|
||||
if (sd_req) begin
|
||||
sd_stb <= wb_stb;
|
||||
sd_cyc <= wb_cyc;
|
||||
end
|
||||
|
||||
sd_refresh <= sd_refresh + 9'd1;
|
||||
if(word) begin
|
||||
word <= word + 1'd1;
|
||||
sd_dat[word[2:1]][{word[0],4'b0000} +:16] <= sd_dq;
|
||||
end
|
||||
|
||||
// this is the auto refresh code.
|
||||
// it kicks in so that 8192 auto refreshes are
|
||||
// issued in a 64ms period. Other bus operations
|
||||
// are stalled during this period.
|
||||
if ((sd_refresh > REFRESH_PERIOD) && (sd_cycle == 4'd0)) begin
|
||||
sd_auto_refresh <= 1'b1;
|
||||
if ((sd_refresh > REFRESH_PERIOD) && !sd_cycle) begin
|
||||
sd_auto_refresh<= 1'b1;
|
||||
sd_refresh <= 10'd0;
|
||||
sd_cmd <= CMD_PRECHARGE;
|
||||
sd_addr[10] <= 1;
|
||||
sd_bank_active <= 0;
|
||||
sd_cmd <= CMD_AUTO_REFRESH;
|
||||
end else if (sd_auto_refresh) begin
|
||||
// while the cycle is active count.
|
||||
sd_cycle <= sd_cycle + 3'd1;
|
||||
case (sd_cycle)
|
||||
CYCLE_RFSH_START: begin
|
||||
sd_cmd <= CMD_AUTO_REFRESH;
|
||||
end
|
||||
CYCLE_RFSH_END: begin
|
||||
if(sd_cycle == CYCLE_RFSH_END) begin
|
||||
// reset the count.
|
||||
sd_auto_refresh <= 1'b0;
|
||||
sd_cycle <= 4'd0;
|
||||
sd_auto_refresh <= 0;
|
||||
sd_cycle <= CYCLE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
else begin
|
||||
// count while the cycle is active
|
||||
if(sd_cycle != CYCLE_IDLE) sd_cycle <= sd_cycle + 3'd1;
|
||||
|
||||
end else if (sd_cyc | (sd_cycle != 0) | (sd_cycle == 0 && sd_req)) begin
|
||||
|
||||
// while the cycle is active count.
|
||||
sd_cycle <= sd_cycle + 3'd1;
|
||||
case (sd_cycle)
|
||||
CYCLE_PRECHARGE: begin
|
||||
if (~sd_bank_active[sd_bank])
|
||||
sd_cycle <= CYCLE_RAS_START;
|
||||
else if (sd_active_row[sd_bank] == sd_row)
|
||||
sd_cycle <= CYCLE_CAS0 - 1'd1; // FIXME: Why doesn't work without -1?
|
||||
else begin
|
||||
sd_cmd <= CMD_PRECHARGE;
|
||||
sd_addr[10] <= 0;
|
||||
sd_ba <= sd_bank;
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_RAS_START: begin
|
||||
sd_cmd <= CMD_ACTIVE;
|
||||
sd_addr <= { 1'b0, sd_row };
|
||||
sd_ba <= sd_bank;
|
||||
sd_active_row[sd_bank] <= sd_row;
|
||||
sd_bank_active[sd_bank] <= 1;
|
||||
|
||||
if(sd_reading) begin
|
||||
sd_dqm <= 2'b00;
|
||||
end else begin
|
||||
sd_dqm <= 2'b11;
|
||||
case(sd_cycle)
|
||||
CYCLE_IDLE: begin
|
||||
if(sd_newreq) begin
|
||||
sd_cmd <= CMD_ACTIVE;
|
||||
sd_addr <= wb_adr[21:10];
|
||||
sd_ba <= wb_adr[23:22];
|
||||
sd_cycle <= sd_cycle + 3'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// this is the first CAS cycle
|
||||
CYCLE_CAS0: begin
|
||||
// always, always read on a 32bit boundary and completely ignore the lsb of wb_adr.
|
||||
sd_addr <= { 4'b0000, wb_adr[23], wb_adr[8:2], 1'b0 }; // no auto precharge
|
||||
sd_dqm <= ~wb_sel[1:0];
|
||||
sd_ba <= sd_bank;
|
||||
sd_addr <= { 4'b0000, wb_adr[9:1] }; // no auto precharge
|
||||
|
||||
if (sd_reading) begin
|
||||
sd_cmd <= CMD_READ;
|
||||
sd_cmd <= CMD_READ;
|
||||
sd_addr[10] <= 1; // auto precharge
|
||||
end else if (sd_writing) begin
|
||||
sd_cmd <= CMD_WRITE;
|
||||
`ifdef VERILATOR
|
||||
sd_q <= wb_dat_i[15:0];
|
||||
`else
|
||||
sd_dq <= wb_dat_i[15:0];
|
||||
`endif
|
||||
sd_cmd <= CMD_WRITE;
|
||||
sd_addr[12:11] <= ~wb_sel[1:0];
|
||||
sd_dq <= wb_dat_i[15:0];
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_CAS1: begin
|
||||
// now we access the second part of the 32 bit location.
|
||||
sd_addr <= { 4'b0000, wb_adr[23], wb_adr[8:2], 1'b1 }; // no auto precharge
|
||||
sd_dqm <= ~wb_sel[3:2];
|
||||
if (sd_reading) begin
|
||||
sd_cmd <= CMD_READ;
|
||||
if (burst_mode & can_burst) begin
|
||||
sd_burst <= 1'b1;
|
||||
end
|
||||
end else if (sd_writing) begin
|
||||
sd_cmd <= CMD_WRITE;
|
||||
sd_done <= ~sd_done;
|
||||
`ifdef VERILATOR
|
||||
sd_q <= wb_dat_i[31:16];
|
||||
`else
|
||||
sd_dq <= wb_dat_i[31:16];
|
||||
`endif
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_CAS2: begin
|
||||
if (sd_burst) begin
|
||||
// always, always read on a 32bit boundary and completely ignore the lsb of wb_adr.
|
||||
sd_addr <= { 4'b0000, wb_adr[23], wb_adr[8:3], 2'b10 }; // no auto precharge
|
||||
sd_dqm <= ~wb_sel[1:0];
|
||||
if (sd_reading) begin
|
||||
sd_cmd <= CMD_READ;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_CAS3: begin
|
||||
if (sd_burst) begin
|
||||
// always, always read on a 32bit boundary and completely ignore the lsb of wb_adr.
|
||||
sd_addr <= { 4'b0000, wb_adr[23], wb_adr[8:3], 2'b11 }; // no auto precharge
|
||||
sd_dqm <= ~wb_sel[3:2];
|
||||
if (sd_reading) begin
|
||||
sd_cmd <= CMD_READ;
|
||||
end
|
||||
if (sd_writing) begin
|
||||
sd_addr[10] <= 1; // auto precharge
|
||||
sd_addr[0] <= 1;
|
||||
sd_cmd <= CMD_WRITE;
|
||||
sd_addr[12:11] <= ~wb_sel[3:2];
|
||||
sd_done <= ~sd_done;
|
||||
sd_newreq <= 0;
|
||||
sd_dq <= wb_dat_i[31:16];
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_READ0: begin
|
||||
if (sd_reading) begin
|
||||
sd_dat[15:0] <= sd_dq;
|
||||
sd_dat[0][15:0]<= sd_dq;
|
||||
word <= 1;
|
||||
end else begin
|
||||
if (sd_writing) sd_cycle <= CYCLE_END;
|
||||
end
|
||||
if (sd_writing) sd_cycle <= CYCLE_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_READ1: begin
|
||||
if (sd_reading) begin
|
||||
sd_dat[31:16] <= sd_dq;
|
||||
sd_done <= ~sd_done;
|
||||
end
|
||||
sd_done <= ~sd_done;
|
||||
sd_newreq <= 0;
|
||||
end
|
||||
|
||||
CYCLE_READ2: begin
|
||||
if (sd_reading) begin
|
||||
sd_dat_nxt[15:0] <= sd_dq;
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_READ3: begin
|
||||
if (sd_reading) begin
|
||||
sd_dat_nxt[31:16] <= sd_dq;
|
||||
end
|
||||
end
|
||||
|
||||
CYCLE_END: begin
|
||||
sd_burst <= 1'b0;
|
||||
sd_cyc <= 1'b0;
|
||||
sd_stb <= 1'b0;
|
||||
CYCLE_READ5: begin
|
||||
sd_cycle <= CYCLE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end else begin
|
||||
sd_cycle <= 4'd0;
|
||||
sd_burst <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg wb_burst;
|
||||
|
||||
always @(posedge wb_clk) begin
|
||||
reg sd_doneD;
|
||||
reg [1:0] word;
|
||||
|
||||
sd_doneD <= sd_done;
|
||||
wb_ack <= (sd_done ^ sd_doneD) & ~wb_ack;
|
||||
|
||||
wb_ack <= 0;
|
||||
|
||||
if(word) word <= word + 1'd1;
|
||||
|
||||
if (wb_stb & wb_cyc) begin
|
||||
|
||||
if ((sd_done ^ sd_doneD) & ~wb_ack) begin
|
||||
|
||||
wb_dat_o <= sd_dat;
|
||||
wb_burst <= burst_mode;
|
||||
|
||||
wb_dat_o <= sd_dat[0];
|
||||
word <= ~wb_cti[2] & (wb_cti[1] ^ wb_cti[0]); // burst constant/incremental
|
||||
wb_ack <= 1;
|
||||
end
|
||||
|
||||
if (word) begin
|
||||
wb_dat_o <= sd_dat[word];
|
||||
wb_ack <= 1;
|
||||
end
|
||||
|
||||
if (wb_ack & wb_burst) begin
|
||||
|
||||
wb_ack <= 1'b1;
|
||||
wb_burst <= 1'b0;
|
||||
wb_dat_o <= sd_dat_nxt;
|
||||
|
||||
end
|
||||
|
||||
|
||||
end else begin
|
||||
|
||||
wb_burst <= 1'b0;
|
||||
|
||||
end
|
||||
|
||||
|
||||
else begin
|
||||
word <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
wire burst_mode = wb_cti == 3'b010;
|
||||
wire can_burst = wb_adr[2] === 1'b0;
|
||||
wire sd_reading = sd_stb & sd_cyc & ~sd_we;
|
||||
wire sd_writing = sd_stb & sd_cyc & sd_we;
|
||||
|
||||
// drive control signals according to current command
|
||||
assign sd_cs_n = sd_cmd[3];
|
||||
assign sd_ras_n = sd_cmd[2];
|
||||
assign sd_cas_n = sd_cmd[1];
|
||||
assign sd_we_n = sd_cmd[0];
|
||||
assign sd_cke = 1'b1;
|
||||
assign sd_cke = 1'b1;
|
||||
assign sd_dqm = sd_addr[12:11];
|
||||
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user