gateware

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit fe0d0a7e943c0a82de682ec89cfff40e72c6a217
parent b1ffb705c7ab63c9f1edbe9e11c1535beab5301c
Author: Brian Swetland <swetland@frotz.net>
Date:   Tue,  4 Feb 2020 04:02:43 -0800

sdram: even more work

- correctly set MODE bits
- generate mode bits and read delays from T_RCD parameter
- correct external clock to align with data
- various testbench changes
- adjust sim sdram to behave more like real hardware

Diffstat:
Mhdl/sdram/sdram.sv | 48+++++++++++++++++++++++++++++++-----------------
Mhdl/sdram/sdram_glue_ecp5.sv | 4++--
Mhdl/sdram/test.asm | 41++++++++++++++++++++++++++++++++++-------
Mhdl/sdram/testbench.sv | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/astl.c | 3+++
Msrc/sim-sdram.cpp | 6+++---
6 files changed, 222 insertions(+), 55 deletions(-)

diff --git a/hdl/sdram/sdram.sv b/hdl/sdram/sdram.sv @@ -74,6 +74,14 @@ localparam XWIDTH = (ROWBITS + BANKBITS + COLBITS); localparam BANKCOUNT = (1 << BANKBITS); +// validate T_RCD and adjust MODE bits and read latency configuration +if ((T_RCD != 2) && (T_RCD != 3)) + $error("T_RCD must be 2 or 3"); + +localparam PMSB = T_RCD; +localparam [1:0]SDRAM_CL = T_RCD; +localparam [9:0]SDRAM_MODE = { 4'b000, SDRAM_CL, 4'b0000 }; + integer i; // used by various for loops // split input address into bank, row, col @@ -156,12 +164,10 @@ localparam CMD_READ = 3'b101; // BA*=bankno, A10=AP, COLADDR localparam CMD_STOP = 3'b110; localparam CMD_NOP = 3'b111; -// TODO CL2 vs CL3 configurability here and elsewhere - -reg [3:0]rd_pipe_rdy = 0; -reg [3:0]rd_pipe_bsy = 0; -reg [3:0]rd_pipe_rdy_next; -reg [3:0]rd_pipe_bsy_next; +reg [PMSB:0]rd_pipe_rdy = 0; +reg [PMSB:0]rd_pipe_bsy = 0; +reg [PMSB:0]rd_pipe_rdy_next; +reg [PMSB:0]rd_pipe_bsy_next; reg [3:0]burst = 0; reg [3:0]burst_next; @@ -215,8 +221,8 @@ always_comb begin // read pipe regs track inbound read data (rdy) // and hold off writes (bsy) to avoid bus conflict - rd_pipe_rdy_next = { 1'b0, rd_pipe_rdy[3:1] }; - rd_pipe_bsy_next = { 1'b0, rd_pipe_bsy[3:1] }; + rd_pipe_rdy_next = { 1'b0, rd_pipe_rdy[PMSB:1] }; + rd_pipe_bsy_next = { 1'b0, rd_pipe_bsy[PMSB:1] }; if (rd_pipe_rdy[0]) begin rd_rdy_next = 1; @@ -230,7 +236,6 @@ always_comb begin state_next = INIT0; end IDLE: begin - data_oe_next = 0; if (refresh_done) begin // refresh counter has expired, precharge all and refresh state_next = REFRESH; @@ -239,7 +244,8 @@ always_comb begin io_sel_a10_next = 1; // ALL BANKS //count_next = T_RP - 2; count_next[T_RP-2] = 1; count_done_next = 0; - end else if (rd_req) begin + end else + if (rd_req) begin io_do_rd_next = 1; io_addr_next = rd_addr; burst_next = rd_len; @@ -266,8 +272,8 @@ always_comb begin cmd_next = CMD_READ; io_sel_row_next = 0; // column addr io_sel_a10_next = 0; // no auto precharge - rd_pipe_rdy_next = { 1'b1, rd_pipe_rdy[3:1] }; - rd_pipe_bsy_next = 4'b1111; + rd_pipe_rdy_next = { 1'b1, rd_pipe_rdy[PMSB:1] }; + rd_pipe_bsy_next = { PMSB + 1 { 1'b1 } }; state_next = (burst != 4'd0) ? READ : IDLE; end end @@ -285,7 +291,12 @@ always_comb begin io_sel_row_next = 0; // column addr io_sel_a10_next = 0; // no auto precharge data_oe_next = 1; - state_next = (burst != 4'd0) ? WRITE : IDLE; + if (burst != 4'd0) begin + state_next = WRITE; + end else begin + state_next = IDLE; + count_next[2] = 1; count_done_next = 0; // WR? + end end end ACTIVE: begin @@ -306,18 +317,20 @@ always_comb begin // column addressing pre-selected from initial read io_addr_next[COLBITS-1:0] = io_col_add1; cmd_next = CMD_READ; - rd_pipe_rdy_next = { 1'b1, rd_pipe_rdy[3:1] }; - rd_pipe_bsy_next = 4'b1111; + rd_pipe_rdy_next = { 1'b1, rd_pipe_rdy[PMSB:1] }; + rd_pipe_bsy_next = { PMSB + 1 { 1'b1 } }; end WRITE: begin if (burst_done) begin state_next = IDLE; + count_next[2] = 1; count_done_next = 0; // WR? end else begin burst_next = burst_sub1; end // column addressing pre-selected from initial write io_addr_next[COLBITS-1:0] = io_col_add1; cmd_next = CMD_WRITE; + data_o_next = wr_data; // handshake? data_oe_next = 1; end INIT0: if (refresh_done) begin @@ -333,8 +346,8 @@ always_comb begin cmd_next = CMD_SET_MODE; //count_next = T_MRD - 2; count_next[T_MRD-2] = 1; count_done_next = 0; - // r/w burst off, cas lat 3, sequential addr - io_addr_next[XWIDTH-1:COLBITS] = { {(AWIDTH - 10){1'b0}}, 10'b0000110000}; + io_addr_next[XWIDTH-1:COLBITS] = + { {ROWBITS-10{1'b0}}, SDRAM_MODE, {BANKBITS{1'b0}} }; io_sel_row_next = 1; // row addressing end INIT2: begin @@ -364,6 +377,7 @@ always_ff @(posedge clk) begin state <= reset ? START : state_next; count <= count_next; count_done <= count_done_next; + burst <= burst_next; refresh <= refresh_next; cmd <= cmd_next; io_do_rd <= io_do_rd_next; diff --git a/hdl/sdram/sdram_glue_ecp5.sv b/hdl/sdram/sdram_glue_ecp5.sv @@ -32,8 +32,8 @@ ODDRX1F clock_ddr ( .Q(pin_clk), .SCLK(clk), .RST(0), - .D0(0), - .D1(1) + .D0(1), + .D1(0) ); genvar n; diff --git a/hdl/sdram/test.asm b/hdl/sdram/test.asm @@ -11,24 +11,51 @@ rdc 1234 addr 20 rdc aa55 +#trigger auto+ -addr 0 -wrp .15 +addr 80 +wrp 100 show 42 p1rst -addr 0 -rdp .15 +addr 80 +rdp 100 show 43 show e0 p1rst -addr 0 + +#trigger +addr f0 +wri 8888 + +addr 80 show e1 -rdf .15 +rdf 100 show e2 wait .30 -verify .15 +verify 100 show e3 show ff + +show 00 +show 00 +#dump .250 + +p1rst +addr 80 +show bb +rdb .15 +wait .30 +verify .15 +show b0 + +addr 1000 +p0rst +#wrp ffff + +addr 1000 +p1rst +#rdp ffff +show a7 diff --git a/hdl/sdram/testbench.sv b/hdl/sdram/testbench.sv @@ -35,7 +35,7 @@ wire rd_ack; wire [15:0]rd_data; wire rd_rdy; -reg [15:0]wr_len = 0; +reg [3:0]wr_len = 0; reg wr_req = 0; wire wr_ack; @@ -59,19 +59,69 @@ reg [31:0]scratch[0:511]; reg [8:0]swraddr = 0; reg [8:0]srdaddr = 0; reg [31:0]srddata = 0; +reg [8:0]swraddr_next; +reg [8:0]srdaddr_next; -reg sreset; -reg srd; -always @(posedge clk) begin - swraddr <= sreset ? 0 : (rd_rdy ? swraddr + 9'd1 : swraddr); - srdaddr <= sreset ? 0 : (srd ? srdaddr + 9'd1 : srdaddr); +reg sreset = 0; +reg srd = 0; + +reg sreset_next; +reg srd_next; + +always_comb begin + swraddr_next = swraddr; + srdaddr_next = srdaddr; + + if (sreset) begin + swraddr_next = 0; + srdaddr_next = 0; + end else begin + if (rd_rdy) + swraddr_next = swraddr + 9'd1; + if (srd) + srdaddr_next = srdaddr + 9'd1; + end +end + +always_ff @(posedge clk) begin + swraddr <= swraddr_next; + srdaddr <= srdaddr_next; +end +always_ff @(posedge clk) begin if (rd_rdy) scratch[swraddr] <= { 16'h0, rd_data }; - if (srd) + if (srd_next) srddata <= scratch[srdaddr]; end + +wire [15:0]xdata; + +`ifdef WITH_SCOPE +reg [31:0]scope[0:511]; +reg [31:0]scdata = 0; +reg [8:0]scwp = 0; +reg [8:0]scrp = 0; +reg scgo = 0; +reg scgo_next; +reg scrd; + +wire [31:0]probe = { + 1'b0, sdram_ras_n, sdram_cas_n, sdram_we_n, sdram_addr, xdata +}; + +always @(posedge clk) begin + scwp <= (scgo && (scwp != 511)) ? scwp + 9'd1 : scwp; + scrp <= scrd ? scrp + 9'd1 : scrp; + + if (scgo) + scope[scwp] <= probe; + if (scrd) + scdata <= scope[scrp]; +end +`endif + localparam OP_MISC = 4'h0; // all 0 is NOP, see MISC_ bits localparam OP_WR_IMM = 4'h1; // value to write localparam OP_WR_PAT = 4'h2; // count to write pattern0 @@ -79,15 +129,18 @@ localparam OP_RD_CHK = 4'h3; // value to check against localparam OP_RD_PAT = 4'h4; // count to read and check vs pattern1 localparam OP_VERIFY = 4'h5; // count read data to verify vs pattern localparam OP_RD_FAST = 4'h6; // count fast read +localparam OP_RD_BURST= 4'h7; // count burst read localparam OP_ADDR = 4'hA; localparam OP_DISPLAY = 4'hD; // write arg to vram localparam OP_WAIT = 4'hF; localparam MISC_RESET_PAT0 = 0; localparam MISC_RESET_PAT1 = 1; -localparam MISC_HALT = 31; localparam MISC_SET_AUTO = 2; localparam MISC_CLR_AUTO = 3; +localparam MISC_TRIGGER = 29; +localparam MISC_DUMP = 30; +localparam MISC_HALT = 31; localparam START = 4'd0; localparam EXEC = 4'd1; @@ -99,8 +152,15 @@ localparam SHOW2 = 4'd6; localparam WAIT = 4'd7; localparam HALT = 4'd8; localparam READFAST = 4'd9; +localparam READBURST = 4'd12; localparam VERIFY = 4'd10; localparam VERIFY2 = 4'd11; +`ifdef WITH_SCOPE +localparam DUMP0 = 4'd12; +localparam DUMP1 = 4'd13; +localparam DUMP2 = 4'd14; +localparam DUMP3 = 4'd15; +`endif reg auto_inc = 0; reg auto_inc_next; @@ -116,6 +176,7 @@ reg pattern1_reset = 0; reg pattern1_reset_next; reg pattern1_step = 0; reg pattern1_step_next; +wire p1_match_srddata = (pattern1[15:0] == srddata[15:0]); reg done_next; reg error_next; @@ -134,6 +195,8 @@ localparam COUNTONE = 16'd1; localparam COUNTZERO = 16'd0; reg [COUNTMSB:0]count = 0; reg [COUNTMSB:0]count_next; +wire count_is_zero = (count == COUNTZERO); +wire [COUNTMSB:0]count_minus_one = (count - COUNTONE); always_comb begin state_next = state; @@ -141,6 +204,8 @@ always_comb begin data_next = data; rd_req_next = rd_req; wr_req_next = wr_req; + rd_len_next = rd_len; + wr_len_next = wr_len; count_next = count; pattern0_reset_next = 0; pattern1_reset_next = 0; @@ -151,8 +216,12 @@ always_comb begin info_e_next = 0; match_next = match; capture_next = capture; - srd = 0; - sreset = 0; + srd_next = 0; + sreset_next = 0; +`ifdef WITH_SCOPE + scgo_next = scgo; + scrd = 0; +`endif case (state) START: begin @@ -166,6 +235,14 @@ always_comb begin if (ip[MISC_SET_AUTO]) auto_inc_next = 1; if (ip[MISC_CLR_AUTO]) auto_inc_next = 1; if (ip[MISC_HALT]) state_next = HALT; +`ifdef WITH_SCOPE + if (ip[MISC_TRIGGER]) scgo_next = 1; + if (ip[MISC_DUMP]) begin + state_next = DUMP0; + count_next = ip[COUNTMSB:0]; + scrd = 1; + end +`endif end OP_WAIT: begin state_next = WAIT; @@ -205,9 +282,15 @@ always_comb begin OP_RD_FAST: begin state_next = READFAST; rd_req_next = 1; - sreset = 1; + sreset_next = 1; count_next = ip[COUNTMSB:0]; end + OP_RD_BURST: begin + state_next = READBURST; + rd_req_next = 1; + rd_len_next = ip[3:0]; + sreset_next = 1; + end OP_DISPLAY: begin info_next = ip[15:0]; info_e_next = 1; @@ -215,16 +298,17 @@ always_comb begin OP_VERIFY: begin state_next = VERIFY; count_next = ip[COUNTMSB:0]; + srd_next = 1; end default: ; endcase end WRITE: if (wr_ack) begin - if (count == COUNTZERO) begin + if (count_is_zero) begin state_next = EXEC; wr_req_next = 0; end else begin - count_next = count - COUNTONE; + count_next = count_minus_one; data_next = pattern0; pattern0_step_next = 1; end @@ -242,27 +326,32 @@ always_comb begin end READFAST: if (rd_ack) begin if (auto_inc) addr_next = addr + 32'd1; - if (count == COUNTZERO) begin + if (count_is_zero) begin state_next = EXEC; rd_req_next = 0; end else begin - count_next = count - COUNTONE; + count_next = count_minus_one; end end + READBURST: if (rd_ack) begin + state_next = EXEC; + rd_req_next = 0; + rd_len_next = 0; + end SHOW: begin state_next = SHOW2; info_next = { match ? 8'h20 : 8'h40, capture[15:8] }; info_e_next = 1; end SHOW2: begin - if (count == COUNTZERO) begin + if (count_is_zero) begin state_next = EXEC; end else begin state_next = READ; rd_req_next = 1; data_next = pattern1; pattern1_step_next = 1; - count_next = count - COUNTONE; + count_next = count_minus_one; end info_next = { match ? 8'h20 : 8'h40, capture[7:0] }; info_e_next = 1; @@ -273,21 +362,49 @@ always_comb begin info_e_next = 1; end VERIFY2: begin - if (count == COUNTZERO) begin + if (count_is_zero) begin state_next = EXEC; end else begin state_next = VERIFY; + count_next = count_minus_one; pattern1_step_next = 1; - count_next = count - COUNTONE; - srd = 1; + srd_next = 1; end info_next = { (srddata[15:0] == pattern1[15:0]) ? 8'h20 : 8'h40, srddata[7:0] }; info_e_next = 1; end - WAIT: if (count == 0) begin +`ifdef WITH_SCOPE + DUMP0: begin + info_next = { 8'h07, scdata[31:24] }; + info_e_next = 1; + state_next = DUMP1; + end + DUMP1: begin + info_next = { 8'h70, scdata[23:16] }; + info_e_next = 1; + state_next = DUMP2; + end + DUMP2: begin + info_next = { 8'h30, scdata[15:8] }; + info_e_next = 1; + state_next = DUMP3; + end + DUMP3: begin + info_next = { 8'h30, scdata[7:0] }; + info_e_next = 1; + if (count_is_zero) begin + state_next = EXEC; + end else begin + state_next = DUMP0; + count_next = count_minus_one; + scrd = 1; + end + end +`endif + WAIT: if (count_is_zero) begin state_next = EXEC; end else begin - count_next = count - COUNTONE; + count_next = count_minus_one; end HALT: begin state_next = HALT; @@ -322,22 +439,28 @@ always_ff @(posedge clk) begin capture <= capture_next; wr_req <= wr_req_next; rd_req <= rd_req_next; + wr_len <= wr_len_next; + rd_len <= rd_len_next; + srd <= srd_next; + sreset <= sreset_next; +`ifdef WITH_SCOPE + scgo <= scgo_next; +`endif end xorshift32 xs0( .clk(clk), - .next(pattern0_step), + .next(pattern0_step_next), .reset(pattern0_reset), .data(pattern0) ); xorshift32 xs1( .clk(clk), - .next(pattern1_step), + .next(pattern1_step_next), .reset(pattern1_reset), .data(pattern1) ); - sdram #( .T_PWR_UP(T_PWR_UP), .T_RI(T_RI) @@ -365,7 +488,7 @@ sdram #( .wr_addr(addr[19:0]), .wr_data(data[15:0]), - .wr_len(0), + .wr_len(wr_len), .wr_req(wr_req), .wr_ack(wr_ack) ); diff --git a/src/astl.c b/src/astl.c @@ -19,9 +19,12 @@ struct { { 0x400000000, "rdp", "w", "rdp # read + check vs pattern1 #+1 times" }, { 0x500000000, "verify","w", "rdp check count readbuffer vs pattern1" }, { 0x600000000, "rdf", "w", "rdp read count into readbuffer" }, + { 0x700000000, "rdb", "w", "rdp read burst count into readbuffer" }, { 0xA00000000, "addr", "w", "addr # set address" }, { 0xF00000000, "wait", "w", "wait # wait # cycles" }, { 0x080000000, "halt", "", "halt stop processing" }, + { 0x040000000, "dump", "w", "dump display # scope traces" }, + { 0x020000000, "trigger","", "trigger trigger scope capture" }, { 0x000000001, "p0rst", "", "p0rst reset pattern0" }, { 0x000000002, "p1rst", "", "p1rst reset pattern1" }, { 0x000000004, "auto+", "", "auto+ enable addr auto inc" }, diff --git a/src/sim-sdram.cpp b/src/sim-sdram.cpp @@ -148,7 +148,7 @@ int sim_sdram(unsigned ctl, unsigned addr, unsigned din, unsigned* dout) { unsigned a_col = addr & COLMASK; unsigned a_a10 = (addr >> 10) & 1; - printf("(%-4s) %06x ", cname(ctl), addr); + printf("(%-4s) %06x %04x ", cname(ctl), addr, din); for (unsigned n = 0; n < 3; n++) { if (sdram.pipe_data_e[n]) { printf("<%04x", sdram.pipe_data_o[n]); @@ -293,8 +293,8 @@ int sim_sdram(unsigned ctl, unsigned addr, unsigned din, unsigned* dout) { if (sdram.state == BANK_WRITE) { memory[sdram.addr] = din; } else { - sdram.pipe_data_o[1] = memory[sdram.addr]; - sdram.pipe_data_e[1] = 1; + sdram.pipe_data_o[0] = memory[sdram.addr]; + sdram.pipe_data_e[0] = 1; } sdram.count--; if (sdram.count == 0) {