From deb778089774906f6534fdd6d6d2ef1511363b55 Mon Sep 17 00:00:00 2001 From: bbracker Date: Fri, 12 Feb 2021 00:02:45 -0500 Subject: [PATCH] bus rw bugfix and peripherals testing --- .../regression/wally-peripherals.do | 108 +++++++ wally-pipelined/src/uncore/uartPC16550D.sv | 13 +- wally-pipelined/src/uncore/uncore.sv | 2 +- .../testbench/testbench-peripherals.sv | 305 ++++++++++++++++++ 4 files changed, 420 insertions(+), 8 deletions(-) create mode 100644 wally-pipelined/regression/wally-peripherals.do create mode 100644 wally-pipelined/testbench/testbench-peripherals.sv diff --git a/wally-pipelined/regression/wally-peripherals.do b/wally-pipelined/regression/wally-peripherals.do new file mode 100644 index 000000000..d9d9daa37 --- /dev/null +++ b/wally-pipelined/regression/wally-peripherals.do @@ -0,0 +1,108 @@ +# wally-peripherals.do +# +# Created by Ben Bracker (bbracker@hmc.edu) on 11 Feb. 2021 +# +# Based on wally-pipelined.do by +# James Stine, 2008; David Harris 2021 +# Go Cowboys!!!!!! + +# Use this wally-pipelined.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do wally-pipelined.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do wally-pipelined.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +# suppress spurious warnngs about +# "Extra checking for conflicts with always_comb done at vopt time" +# because vsim will run vopt + +# default to config/rv64ic, but allow this to be overridden at the command line. For example: +# do wally-pipelined.do ../config/rv32ic +# That said, I don't think there are any peripherals that use anything but rv64i just yet. +switch $argc { + 0 {vlog +incdir+../config/rv64ic ../testbench/testbench-peripherals.sv ../src/*/*.sv -suppress 2583} + 1 {vlog +incdir+$1 ../testbench/testbench-peripherals.sv ../src/*/*.sv -suppress 2583} +} +# start and run simulation +# remove +acc flag for faster sim during regressions if there is no need to access internal signals +vopt +acc work.testbench -o workopt +vsim workopt + +view wave + +-- display input and output signals as hexidecimal values +# Diplays All Signals recursively +add wave /testbench/clk +add wave /testbench/reset +add wave -divider +add wave /testbench/dut/hart/ebu/IReadF +add wave /testbench/dut/hart/DataStall +add wave /testbench/dut/hart/InstrStall +add wave /testbench/dut/hart/StallF +add wave /testbench/dut/hart/StallD +add wave /testbench/dut/hart/FlushD +add wave /testbench/dut/hart/FlushE +add wave /testbench/dut/hart/FlushM +add wave /testbench/dut/hart/FlushW + +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCF +add wave -hex /testbench/dut/hart/ifu/InstrF +add wave /testbench/InstrFName +#add wave -hex /testbench/dut/hart/ifu/PCD +add wave -hex /testbench/dut/hart/ifu/InstrD +add wave /testbench/InstrDName +add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCE +#add wave -hex /testbench/dut/hart/ifu/InstrE +add wave /testbench/InstrEName +add wave -hex /testbench/dut/hart/ieu/dp/SrcAE +add wave -hex /testbench/dut/hart/ieu/dp/SrcBE +add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE +add wave /testbench/dut/hart/ieu/dp/PCSrcE +add wave -divider +#add wave -hex /testbench/dut/hart/ifu/PCM +#add wave -hex /testbench/dut/hart/ifu/InstrM +add wave /testbench/InstrMName +add wave /testbench/dut/uncore/dtim/memwrite +add wave -hex /testbench/dut/uncore/HADDR +add wave -hex /testbench/dut/uncore/HWDATA +add wave -divider +add wave -hex /testbench/dut/hart/ifu/PCW +add wave /testbench/InstrWName +add wave /testbench/dut/hart/ieu/dp/RegWriteW +add wave -hex /testbench/dut/hart/ieu/dp/ResultW +add wave -hex /testbench/dut/hart/ieu/dp/RdW +add wave -divider +add wave -hex /testbench/dut/uncore/uart/u/* +add wave -divider +#add ww +add wave -hex -r /testbench/* + +-- Set Wave Output Items +TreeUpdate [SetDefaultTree] +WaveRestoreZoom {0 ps} {100 ps} +configure wave -namecolwidth 250 +configure wave -valuecolwidth 120 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +set DefaultRadix hexadecimal + +-- Run the Simulation +run 5000 +#run -all +#quit diff --git a/wally-pipelined/src/uncore/uartPC16550D.sv b/wally-pipelined/src/uncore/uartPC16550D.sv index ec3e25227..445dca38c 100644 --- a/wally-pipelined/src/uncore/uartPC16550D.sv +++ b/wally-pipelined/src/uncore/uartPC16550D.sv @@ -76,7 +76,6 @@ module uartPC16550D( // shift registrs and FIFOs logic [9:0] rxshiftreg; - logic [11:0] txshiftreg; logic [10:0] rxfifo[15:0]; logic [7:0] txfifo[15:0]; logic [3:0] rxfifohead, rxfifotail, txfifohead, txfifotail, rxfifotriggerlevel; @@ -323,7 +322,7 @@ module uartPC16550D( txbitssent <= 0; end else if ((txstate == UART_IDLE) && txsrfull) begin // start transmitting txstate <= UART_ACTIVE; - txoversampledcnt <= 0; + txoversampledcnt <= 1; txbitssent <= 0; end else if (txbaudpulse & (txstate == UART_ACTIVE)) begin txoversampledcnt <= txoversampledcnt + 1; @@ -366,7 +365,7 @@ module uartPC16550D( // registers & FIFO always_ff @(posedge HCLK, negedge HRESETn) if (~HRESETn) begin - txfifohead <= 0; txfifotail <= 0; txhrfull <= 0; txsrfull <= 0; TXHR <= 0; txsr <= 0; + txfifohead <= 0; txfifotail <= 0; txhrfull <= 0; txsrfull <= 0; TXHR <= 0; txsr <= 12'hfff; end else begin if (~MEMWb && A == 3'b000 && ~DLAB) begin // writing transmit holding register or fifo if (fifoenabled) begin @@ -378,19 +377,19 @@ module uartPC16550D( end $display("UART transmits: %c",Din); // for testbench end - if (txstate == UART_IDLE) // move data into tx shift register if available - if (fifoenabled) + if (txstate == UART_IDLE) begin // move data into tx shift register if available + if (fifoenabled) begin if (~txfifoempty) begin txsr <= txdata; txfifotail <= txfifotail+1; txsrfull <= 1; end - else if (txhrfull) begin + end else if (txhrfull) begin txsr <= txdata; txhrfull <= 0; txsrfull <= 1; end - else if (txstate == UART_DONE) txsrfull <= 0; // done transmitting shift register + end else if (txstate == UART_DONE) txsrfull <= 0; // done transmitting shift register else if (txstate == UART_ACTIVE && txnextbit) txsr <= {txsr[10:0], 1'b1}; // shift txhr if (!MEMWb && A == 3'b010) // writes to FIFO control register if (Din[2] | ~Din[0]) begin // tx FIFO reste or FIFO disable clears FIFO contents diff --git a/wally-pipelined/src/uncore/uncore.sv b/wally-pipelined/src/uncore/uncore.sv index ada1eb93c..170e02c85 100644 --- a/wally-pipelined/src/uncore/uncore.sv +++ b/wally-pipelined/src/uncore/uncore.sv @@ -58,7 +58,7 @@ module uncore ( logic HSELTim, HSELCLINT, HSELGPIO, PreHSELUART, HSELUART; logic HRESPTim, HRESPCLINT, HRESPGPIO, HRESPUART; logic HREADYTim, HREADYCLINT, HREADYGPIO, HREADYUART; - logic MemRW; + logic [1:0] MemRW; logic [1:0] MemRWtim, MemRWclint, MemRWgpio, MemRWuart; logic UARTIntr;// *** will need to tie INTR to an interrupt handler diff --git a/wally-pipelined/testbench/testbench-peripherals.sv b/wally-pipelined/testbench/testbench-peripherals.sv new file mode 100644 index 000000000..24180431d --- /dev/null +++ b/wally-pipelined/testbench/testbench-peripherals.sv @@ -0,0 +1,305 @@ +/////////////////////////////////////////// +// testbench-peripherals.sv +// +// Written: Ben Bracker (bbracker@hmc.edu) 11 Feb. 2021 +// Based on: testbench-imperas.sv by David Harris +// +// Purpose: Wally Testbench and helper modules +// Applies test programs meant to test peripherals +// These tests assume the processor itself is already working! +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +`include "wally-config.vh" + +module testbench(); + logic clk; + logic reset; + + int test, i, errors, totalerrors; + logic [31:0] sig32[0:10000]; + logic [`XLEN-1:0] signature[0:10000]; + logic [`XLEN-1:0] testadr; + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + logic [31:0] InstrW; + logic [`XLEN-1:0] meminit; + + string tests[] = '{ + "peripherals/WALLY-UART", "2000" + }; + + logic [`AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic [31:0] HADDR; + logic [`AHBW-1:0] HWDATA; + logic HWRITE; + logic [2:0] HSIZE; + logic [2:0] HBURST; + logic [3:0] HPROT; + logic [1:0] HTRANS; + logic HMASTLOCK; + logic HCLK, HRESETn; + + + // pick tests based on modes supported + // *** actually I no longer support this + // would need to put this back in if you wanted to test anything other than rv64i + + string signame, memfilename; + + logic [31:0] GPIOPinsIn, GPIOPinsOut, GPIOPinsEn; + logic UARTSin, UARTSout; + + // instantiate device to be tested + assign GPIOPinsIn = 0; + assign UARTSin = 1; + assign HREADYEXT = 1; + assign HRESPEXT = 0; + assign HRDATAEXT = 0; + + wallypipelinedsoc dut(.*); + + // Track names of instructions + instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE, + dut.hart.ifu.InstrD, dut.hart.ifu.InstrE, + dut.hart.ifu.InstrM, InstrW, + InstrDName, InstrEName, InstrMName, InstrWName); + + // initialize tests + initial + begin + test = 0; + totalerrors = 0; + testadr = 0; + // fill memory with defined values to reduce Xs in simulation + if (`XLEN == 32) meminit = 32'hFEDC0123; + else meminit = 64'hFEDCBA9876543210; + for (i=0; i<=65535; i = i+1) begin + //dut.imem.RAM[i] = meminit; + // dut.uncore.RAM[i] = meminit; + end + // read test vectors into memory + memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + reset = 1; # 22; reset = 0; + end + + // generate clock to sequence tests + always + begin + clk = 1; # 5; clk = 0; # 5; + end + + // check results + always @(negedge clk) + begin + if (dut.hart.priv.EcallFaultM && + (dut.hart.ieu.dp.regf.rf[3] == 1 || (dut.hart.ieu.dp.regf.we3 && dut.hart.ieu.dp.regf.a3 == 3 && dut.hart.ieu.dp.regf.wd3 == 1))) begin + $display("Code ended with ecall with gp = 1"); + #60; // give time for instructions in pipeline to finish + // clear signature to prevent contamination from previous tests + for(i=0; i<10000; i=i+1) begin + sig32[i] = 'bx; + end + + // read signature, reformat in 64 bits if necessary + signame = {"../../imperas-riscv-tests/work/", tests[test], ".signature.output"}; + $readmemh(signame, sig32); + i = 0; + while (i < 10000) begin + if (`XLEN == 32) begin + signature[i] = sig32[i]; + i = i+1; + end else begin + signature[i/2] = {sig32[i+1], sig32[i]}; + i = i + 2; + end + end + + // Check errors + i = 0; + errors = 0; + if (`XLEN == 32) + testadr = tests[test+1].atohex()/4; + else + testadr = tests[test+1].atohex()/8; + /* verilator lint_off INFINITELOOP */ + while (signature[i] !== 'bx) begin + //$display("signature[%h] = %h", i, signature[i]); + if (signature[i] !== dut.uncore.dtim.RAM[testadr+i]) begin + if (signature[i+4] !== 'bx || signature[i] !== 32'hFFFFFFFF) begin + // report errors unless they are garbage at the end of the sim + // kind of hacky test for garbage right now + errors = errors+1; + $display(" Error on test %s result %d: adr = %h sim = %h, signature = %h", + tests[test], i, (testadr+i)*`XLEN/8, dut.uncore.dtim.RAM[testadr+i], signature[i]); + end + end + i = i + 1; + end + /* verilator lint_on INFINITELOOP */ + if (errors == 0) $display("%s succeeded. Brilliant!!!", tests[test]); + else begin + $display("%s failed with %d errors. :(", tests[test], errors); + totalerrors = totalerrors+1; + end + test = test + 2; + if (test == tests.size()) begin + if (totalerrors == 0) $display("SUCCESS! All tests ran without failures."); + else $display("FAIL: %d test programs had errors", totalerrors); + $stop; + end + else begin + memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + $display("Read memfile %s", memfilename); + reset = 1; # 17; reset = 0; + end + end + end +endmodule + +/* verilator lint_on STMTDLY */ +/* verilator lint_on WIDTH */ + +module instrTrackerTB( + input logic clk, reset, FlushE, + input logic [31:0] InstrD, + input logic [31:0] InstrE, InstrM, + output logic [31:0] InstrW, + output string InstrDName, InstrEName, InstrMName, InstrWName); + + // stage Instr to Writeback for visualization + flopr #(32) InstrWReg(clk, reset, InstrM, InstrW); + + instrNameDecTB ddec(InstrD, InstrDName); + instrNameDecTB edec(InstrE, InstrEName); + instrNameDecTB mdec(InstrM, InstrMName); + instrNameDecTB wdec(InstrW, InstrWName); +endmodule + +// decode the instruction name, to help the test bench +module instrNameDecTB( + input logic [31:0] instr, + output string name); + + logic [6:0] op; + logic [2:0] funct3; + logic [6:0] funct7; + logic [11:0] imm; + + assign op = instr[6:0]; + assign funct3 = instr[14:12]; + assign funct7 = instr[31:25]; + assign imm = instr[31:20]; + + // it would be nice to add the operands to the name + // create another variable called decoded + + always_comb + casez({op, funct3}) + 10'b0000000_000: name = "BAD"; + 10'b0000011_000: name = "LB"; + 10'b0000011_001: name = "LH"; + 10'b0000011_010: name = "LW"; + 10'b0000011_011: name = "LD"; + 10'b0000011_100: name = "LBU"; + 10'b0000011_101: name = "LHU"; + 10'b0000011_110: name = "LWU"; + 10'b0010011_000: if (instr[31:15] == 0 && instr[11:7] ==0) name = "NOP/FLUSH"; + else name = "ADDI"; + 10'b0010011_001: if (funct7[6:1] == 6'b000000) name = "SLLI"; + else name = "ILLEGAL"; + 10'b0010011_010: name = "SLTI"; + 10'b0010011_011: name = "SLTIU"; + 10'b0010011_100: name = "XORI"; + 10'b0010011_101: if (funct7[6:1] == 6'b000000) name = "SRLI"; + else if (funct7[6:1] == 6'b010000) name = "SRAI"; + else name = "ILLEGAL"; + 10'b0010011_110: name = "ORI"; + 10'b0010011_111: name = "ANDI"; + 10'b0010111_???: name = "AUIPC"; + 10'b0100011_000: name = "SB"; + 10'b0100011_001: name = "SH"; + 10'b0100011_010: name = "SW"; + 10'b0100011_011: name = "SD"; + 10'b0011011_000: name = "ADDIW"; + 10'b0011011_001: name = "SLLIW"; + 10'b0011011_101: if (funct7 == 7'b0000000) name = "SRLIW"; + else if (funct7 == 7'b0100000) name = "SRAIW"; + else name = "ILLEGAL"; + 10'b0111011_000: if (funct7 == 7'b0000000) name = "ADDW"; + else if (funct7 == 7'b0100000) name = "SUBW"; + else name = "ILLEGAL"; + 10'b0111011_001: name = "SLLW"; + 10'b0111011_101: if (funct7 == 7'b0000000) name = "SRLW"; + else if (funct7 == 7'b0100000) name = "SRAW"; + else name = "ILLEGAL"; + 10'b0110011_000: if (funct7 == 7'b0000000) name = "ADD"; + else if (funct7 == 7'b0000001) name = "MUL"; + else if (funct7 == 7'b0100000) name = "SUB"; + else name = "ILLEGAL"; + 10'b0110011_001: if (funct7 == 7'b0000000) name = "SLL"; + else if (funct7 == 7'b0000001) name = "MULH"; + else name = "ILLEGAL"; + 10'b0110011_010: if (funct7 == 7'b0000000) name = "SLT"; + else if (funct7 == 7'b0000001) name = "MULHSU"; + else name = "ILLEGAL"; + 10'b0110011_011: if (funct7 == 7'b0000000) name = "SLTU"; + else if (funct7 == 7'b0000001) name = "DIV"; + else name = "ILLEGAL"; + 10'b0110011_100: if (funct7 == 7'b0000000) name = "XOR"; + else if (funct7 == 7'b0000001) name = "MUL"; + else name = "ILLEGAL"; + 10'b0110011_101: if (funct7 == 7'b0000000) name = "SRL"; + else if (funct7 == 7'b0000001) name = "DIVU"; + else if (funct7 == 7'b0100000) name = "SRA"; + else name = "ILLEGAL"; + 10'b0110011_110: if (funct7 == 7'b0000000) name = "OR"; + else if (funct7 == 7'b0000001) name = "REM"; + else name = "ILLEGAL"; + 10'b0110011_111: if (funct7 == 7'b0000000) name = "AND"; + else if (funct7 == 7'b0000001) name = "REMU"; + else name = "ILLEGAL"; + 10'b0110111_???: name = "LUI"; + 10'b1100011_000: name = "BEQ"; + 10'b1100011_001: name = "BNE"; + 10'b1100011_100: name = "BLT"; + 10'b1100011_101: name = "BGE"; + 10'b1100011_110: name = "BLTU"; + 10'b1100011_111: name = "BGEU"; + 10'b1100111_000: name = "JALR"; + 10'b1101111_???: name = "JAL"; + 10'b1110011_000: if (imm == 0) name = "ECALL"; + else if (imm == 1) name = "EBREAK"; + else if (imm == 2) name = "URET"; + else if (imm == 258) name = "SRET"; + else if (imm == 770) name = "MRET"; + else name = "ILLEGAL"; + 10'b1110011_001: name = "CSRRW"; + 10'b1110011_010: name = "CSRRS"; + 10'b1110011_011: name = "CSRRC"; + 10'b1110011_101: name = "CSRRWI"; + 10'b1110011_110: name = "CSRRSI"; + 10'b1110011_111: name = "CSRRCI"; + 10'b0001111_???: name = "FENCE"; + default: name = "ILLEGAL"; + endcase +endmodule