gateware

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

commit 142b2fc861452602ea3a669cfc9e30f3b9c3e02c
parent fcba5a8307bc7e05e1814a3f024abf0925c0a28c
Author: Brian Swetland <swetland@frotz.net>
Date:   Sat,  1 Feb 2020 10:25:57 -0800

sdram: fancier testbench

- weird little domain specific processor to exercise this stuff
- "sdram test language" (stl) assembler for that

Diffstat:
MMakefile | 7+++++++
Ahdl/sdram/test.asm | 34++++++++++++++++++++++++++++++++++
Mhdl/sdram/testbench.sv | 372++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mproject/colorlight-sdram.def | 2+-
Mproject/test-sdram.def | 2+-
Asrc/astl.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 417 insertions(+), 109 deletions(-)

diff --git a/Makefile b/Makefile @@ -32,6 +32,13 @@ list-all-targets:: #### Tools #### +out/astl: src/astl.c + @mkdir -p out + gcc -g -Wall -O1 -o out/astl src/astl.c + +hdl/sdram/test.hex: hdl/sdram/test.asm out/astl + ./out/astl < hdl/sdram/test.asm > hdl/sdram/test.hex + out/a16: src/a16v5.c src/d16v5.c @mkdir -p out gcc -g -Wall -O1 -o out/a16 src/a16v5.c src/d16v5.c diff --git a/hdl/sdram/test.asm b/hdl/sdram/test.asm @@ -0,0 +1,34 @@ +show aa +show bb +wait .25000 +show cc +addr 10 +wri 1234 +addr 20 +wri aa55 +addr 10 +rdc 1234 +addr 20 +rdc aa55 + +auto+ +addr 0 +wrp .15 +show 42 + +p1rst +addr 0 +rdp .15 +show 43 + +show e0 +p1rst +addr 0 +show e1 +rdf .15 +show e2 +wait .30 +verify .15 +show e3 + +show ff diff --git a/hdl/sdram/testbench.sv b/hdl/sdram/testbench.sv @@ -29,157 +29,315 @@ module testbench #( reg [15:0]info_next; reg info_e_next; -reg [19:0]rd_addr = 0; -wire [15:0]rd_data; -reg rd_req = 0; reg [3:0]rd_len = 0; +reg rd_req = 0; wire rd_ack; +wire [15:0]rd_data; wire rd_rdy; -reg [19:0]wr_addr = 0; -reg [15:0]wr_data = 0; +reg [15:0]wr_len = 0; reg wr_req = 0; wire wr_ack; reg rd_req_next; reg wr_req_next; reg [3:0]rd_len_next; -reg [19:0]wr_addr_next; -reg [19:0]rd_addr_next; -reg [15:0]wr_data_next; +reg [3:0]wr_len_next; -reg done_next; -reg error_next; +reg [31:0]addr = 0; +reg [31:0]data = 0; +reg [31:0]addr_next; +reg [31:0]data_next; -reg [15:0]count = T_PWR_UP + 32; -reg [15:0]count_next; -wire [15:0]count_sub1; -wire count_done; +reg [31:0]capture = 0; +reg [31:0]capture_next; +reg match = 0; +reg match_next; -assign { count_done, count_sub1 } = { 1'b0, count } - 16'd1; +// scratch memory to capture back-to-back and burst read results +reg [31:0]scratch[0:511]; +reg [8:0]swraddr = 0; +reg [8:0]srdaddr = 0; +reg [31:0]srddata = 0; -localparam INIT = 4'd0; -localparam WRITES = 4'd1; -localparam READS = 4'd2; -localparam STOP = 4'd3; +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 [3:0]state = INIT; -reg [3:0]state_next; + if (rd_rdy) + scratch[swraddr] <= { 16'h0, rd_data }; + if (srd) + srddata <= scratch[srdaddr]; +end -reg number_next; -reg number_reset; -wire [31:0]number; +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 +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_ADDR = 4'hA; +localparam OP_DISPLAY = 4'hD; // write arg to vram +localparam OP_WAIT = 4'hF; -xorshift32 xs( - .clk(clk), - .next(number_next), - .reset(number_reset), - .data(number) -); +localparam MISC_RESET_PAT0 = 0; +localparam MISC_RESET_PAT1 = 1; +localparam MISC_HALT = 31; +localparam MISC_SET_AUTO = 2; +localparam MISC_CLR_AUTO = 3; -reg [15:0]cycles = 0; -reg [15:0]cycles_next; +localparam START = 4'd0; +localparam EXEC = 4'd1; +localparam WRITE = 4'd2; +localparam READ = 4'd3; +localparam READ2 = 4'd4; +localparam SHOW = 4'd5; +localparam SHOW2 = 4'd6; +localparam WAIT = 4'd7; +localparam HALT = 4'd8; +localparam READFAST = 4'd9; +localparam VERIFY = 4'd10; +localparam VERIFY2 = 4'd11; -reg reset = 1; +reg auto_inc = 0; +reg auto_inc_next; + +wire [31:0]pattern0; +reg pattern0_reset = 0; +reg pattern0_reset_next; +reg pattern0_step = 0; +reg pattern0_step_next; + +wire [31:0]pattern1; +reg pattern1_reset = 0; +reg pattern1_reset_next; +reg pattern1_step = 0; +reg pattern1_step_next; + +reg done_next; +reg error_next; + +reg [35:0]insram[0:1023]; +reg [35:0]ip = 0; +reg [9:0]pc = 0; + +initial $readmemh("hdl/sdram/test.hex", insram); + +reg [3:0]state = START; +reg [3:0]state_next; + +localparam COUNTMSB = 15; +localparam COUNTONE = 16'd1; +localparam COUNTZERO = 16'd0; +reg [COUNTMSB:0]count = 0; +reg [COUNTMSB:0]count_next; always_comb begin - number_reset = 0; - number_next = 0; state_next = state; - count_next = count; + addr_next = addr; + data_next = data; rd_req_next = rd_req; wr_req_next = wr_req; - wr_addr_next = wr_addr; - rd_addr_next = rd_addr; - rd_len_next = rd_len; - wr_data_next = wr_data; + count_next = count; + pattern0_reset_next = 0; + pattern1_reset_next = 0; + pattern0_step_next = 0; + pattern1_step_next = 0; + auto_inc_next = auto_inc; info_next = info; info_e_next = 0; - done_next = 0; - error_next = 0; - cycles_next = cycles + 16'd1; - - if (cycles == 16'd5000) - error_next = 1; + match_next = match; + capture_next = capture; + srd = 0; + sreset = 0; case (state) - INIT: if (count_done) begin - state_next = WRITES; - count_next = 1000; //32; - wr_addr_next = 20'hF0; - //wr_data_next = 0; - wr_data_next= number[15:0]; - number_next = 1; - wr_req_next = 1; - info_next = 16'h10FF; - info_e_next = 1; - end else begin - count_next = count_sub1; + START: begin + state_next = EXEC; end - WRITES: if (count_done) begin - state_next = READS; - number_reset = 1; - count_next = 1000; //32; - rd_addr_next = 20'hF0; - rd_req_next = 1; - wr_req_next = 0; - info_next = 16'h20EE; - info_e_next = 1; - end else begin - if (wr_ack) begin - //wr_data_next = wr_data + 1; - wr_data_next = number[15:0]; - number_next = 1; - wr_addr_next = wr_addr + 1; - count_next = count_sub1; + EXEC: begin + case (ip[35:32]) + OP_MISC: begin + if (ip[MISC_RESET_PAT0]) pattern0_reset_next = 1; + if (ip[MISC_RESET_PAT1]) pattern1_reset_next = 1; + 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; + end + OP_WAIT: begin + state_next = WAIT; +`ifdef verilator + count_next = 30; +`else + count_next = ip[COUNTMSB:0]; +`endif + end + OP_ADDR: begin + addr_next = ip[31:0]; + end + OP_WR_IMM: begin + state_next = WRITE; + data_next = ip[31:0]; + wr_req_next = 1; + end + OP_WR_PAT: begin + state_next = WRITE; + data_next = pattern0; + count_next = ip[COUNTMSB:0]; + pattern0_step_next = 1; + wr_req_next = 1; + end + OP_RD_CHK: begin + state_next = READ; + data_next = ip[31:0]; + rd_req_next = 1; + end + OP_RD_PAT: begin + state_next = READ; + data_next = pattern1; + pattern1_step_next = 1; + rd_req_next = 1; + count_next = ip[COUNTMSB:0]; + end + OP_RD_FAST: begin + state_next = READFAST; + rd_req_next = 1; + sreset = 1; + count_next = ip[COUNTMSB:0]; end + OP_DISPLAY: begin + info_next = ip[15:0]; + info_e_next = 1; + end + OP_VERIFY: begin + state_next = VERIFY; + count_next = ip[COUNTMSB:0]; + end + default: ; + endcase end - READS: if (count_done) begin - state_next = STOP; - done_next = 1; - info_next = 16'h20DD; - info_e_next = 1; + WRITE: if (wr_ack) begin + if (count == COUNTZERO) begin + state_next = EXEC; + wr_req_next = 0; + end else begin + count_next = count - COUNTONE; + data_next = pattern0; + pattern0_step_next = 1; + end + if (auto_inc) addr_next = addr + 32'd1; + end + READ: if (rd_ack) begin + state_next = READ2; rd_req_next = 0; - end else begin - if (rd_ack) begin + if (auto_inc) addr_next = addr + 32'd1; + end + READ2: if (rd_rdy) begin + state_next = SHOW; + match_next = (data[15:0] == rd_data); + capture_next = { 16'h0, rd_data }; + end + READFAST: if (rd_ack) begin + if (auto_inc) addr_next = addr + 32'd1; + if (count == COUNTZERO) begin + state_next = EXEC; rd_req_next = 0; + end else begin + count_next = count - COUNTONE; end - if (rd_rdy) begin + 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 + state_next = EXEC; + end else begin + state_next = READ; rd_req_next = 1; - rd_addr_next = rd_addr + 1; - count_next = count_sub1; - if (rd_data == number[15:0]) - info_next = { 16'h7011 }; - else - info_next = { 16'h40FF }; - //info_next = { 8'h40, rd_data[7:0] }; - number_next = 1; - info_e_next = 1; + data_next = pattern1; + pattern1_step_next = 1; + count_next = count - COUNTONE; + end + info_next = { match ? 8'h20 : 8'h40, capture[7:0] }; + info_e_next = 1; + end + VERIFY: begin + state_next = VERIFY2; + info_next = { (srddata[15:0] == pattern1[15:0]) ? 8'h20 : 8'h40, srddata[15:8] }; + info_e_next = 1; + end + VERIFY2: begin + if (count == COUNTZERO) begin + state_next = EXEC; + end else begin + state_next = VERIFY; + pattern1_step_next = 1; + count_next = count - COUNTONE; + srd = 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 + state_next = EXEC; + end else begin + count_next = count - COUNTONE; end - STOP: state_next = STOP; - default: state_next = INIT; + HALT: begin + state_next = HALT; +`ifdef verilator + $finish(); +`endif + end + default: state_next = HALT; endcase end +reg reset = 1; + always_ff @(posedge clk) begin + reset <= 0; state <= state_next; - rd_req <= rd_req_next; - wr_req <= wr_req_next; - rd_addr <= rd_addr_next; - wr_addr <= wr_addr_next; - wr_data <= wr_data_next; - rd_len <= rd_len_next; count <= count_next; + if (state_next == EXEC) begin + ip <= insram[pc]; + pc <= pc + 10'd1; + end + addr <= addr_next; + data <= data_next; + pattern0_reset <= pattern0_reset_next; + pattern1_reset <= pattern1_reset_next; + pattern0_step <= pattern0_step_next; + pattern1_step <= pattern1_step_next; + auto_inc <= auto_inc_next; info <= info_next; info_e <= info_e_next; - - cycles <= cycles_next; - done <= done_next; - error <= error_next; - reset <= 0; + match <= match_next; + capture <= capture_next; + wr_req <= wr_req_next; + rd_req <= rd_req_next; end +xorshift32 xs0( + .clk(clk), + .next(pattern0_step), + .reset(pattern0_reset), + .data(pattern0) +); +xorshift32 xs1( + .clk(clk), + .next(pattern1_step), + .reset(pattern1_reset), + .data(pattern1) +); + + sdram #( .T_PWR_UP(T_PWR_UP), .T_RI(T_RI) @@ -198,15 +356,15 @@ sdram #( `else .pin_data(sdram_data), `endif - .rd_addr(rd_addr), + .rd_addr(addr[19:0]), .rd_len(rd_len), .rd_req(rd_req), .rd_ack(rd_ack), .rd_data(rd_data), .rd_rdy(rd_rdy), - .wr_addr(wr_addr), - .wr_data(wr_data), + .wr_addr(addr[19:0]), + .wr_data(data[15:0]), .wr_len(0), .wr_req(wr_req), .wr_ack(wr_ack) diff --git a/project/colorlight-sdram.def b/project/colorlight-sdram.def @@ -3,7 +3,7 @@ PROJECT_TYPE := nextpnr-ecp5 PROJECT_SRCS := hdl/colorlight-sdram.sv hdl/colorlight.lpf PROJECT_SRCS += hdl/lattice/ecp5_pll_25_125_250.v PROJECT_SRCS += hdl/display/display.sv hdl/display/display_timing.sv -PROJECT_SRCS += hdl/sdram/testbench.sv +PROJECT_SRCS += hdl/sdram/testbench.sv hdl/sdram/test.hex PROJECT_SRCS += hdl/sdram/sdram.sv hdl/sdram/sdram_glue_ecp5.sv PROJECT_SRCS += hdl/xorshift.sv diff --git a/project/test-sdram.def b/project/test-sdram.def @@ -1,7 +1,7 @@ PROJECT_TYPE := verilator-sim -PROJECT_SRCS := hdl/sdram/testbench.sv +PROJECT_SRCS := hdl/sdram/testbench.sv hdl/sdram/test.hex PROJECT_SRCS += hdl/sdram/sdram.sv hdl/xorshift.sv PROJECT_VOPTS := -CFLAGS -DSDRAM diff --git a/src/astl.c b/src/astl.c @@ -0,0 +1,109 @@ +// Copyright 2015, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +struct { + uint64_t enc; + const char* name; + const char* args; + const char* desc; +} ops[] = { + { 0x100000000, "wri", "w", "wri # write immediate" }, + { 0x200000000, "wrp", "w", "wrp # write pattern0 #+1 times" }, + { 0x300000000, "rdc", "w", "rdi # read + check vs immediate" }, + { 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" }, + { 0xA00000000, "addr", "w", "addr # set address" }, + { 0xF00000000, "wait", "w", "wait # wait # cycles" }, + { 0x080000000, "halt", "", "halt stop processing" }, + { 0x000000001, "p0rst", "", "p0rst reset pattern0" }, + { 0x000000002, "p1rst", "", "p1rst reset pattern1" }, + { 0x000000004, "auto+", "", "auto+ enable addr auto inc" }, + { 0x000000008, "auto-", "", "auto- disble addr auto inc" }, + { 0xD00007100, "show", "b", "show # show status byte" }, + { 0x000000000, "", "", "" }, +}; + +unsigned lineno = 1; + +const char* token(void) { + static char buf[64]; + int n = 0; + for (;;) { + int c = getchar(); + if (c == '#') { // comment to EOL + for (;;) { + c = getchar(); + if (c == EOF) break; + if (c == '\n') break; + } + } + if (c == '\n') lineno++; + if (c == EOF) break; + if (isspace(c)) { + if (n) break; + } else { + buf[n++] = c; + if (n == sizeof(buf)) { + fprintf(stderr, "error: %u: token too large\n", lineno); + exit(-1); + } + } + } + buf[n] = 0; + return buf; +} + +uint32_t arg_word(const char* tok) { + if (tok[0] == 0) { + fprintf(stderr, "error: %u: missing argument\n", lineno); + exit(-1); + } + if (tok[0] == '.') return strtoul(tok+1, 0, 10); + else return strtoul(tok, 0, 16); +} +uint32_t arg_byte(const char* tok) { + uint32_t n = arg_word(tok); + if (n > 255) { + fprintf(stderr, "error: %u: byte argument too large\n", lineno); + exit(-1); + } + return n; +} + +int main(int argc, char **argv) { + if (argc != 1) { + for (unsigned n = 0; ops[n].enc; n++) { + fprintf(stderr, "%s\n", ops[n].desc); + } + return 0; + } + for (;;) { + const char* tok = token(); + if (tok[0] == 0) break; + for (unsigned n = 0; ops[n].enc; n++) { + if (!strcasecmp(ops[n].name, tok)) { + uint64_t op = ops[n].enc; + const char* args = ops[n].args; + while (*args) { + if (*args == 'w') op |= arg_word(token()); + if (*args == 'b') op |= arg_byte(token()); + args++; + } + printf("%09lx\n", op); + goto next; + } + } + fprintf(stderr, "error: %u: unknown opcode '%s'\n", lineno, tok); + exit(-1); +next: ; + } + printf("080000000\n"); + return 0; +}