diff --git a/wally-pipelined/src/ebu/ahblite.sv b/wally-pipelined/src/ebu/ahblite.sv index 36882428..e917b668 100644 --- a/wally-pipelined/src/ebu/ahblite.sv +++ b/wally-pipelined/src/ebu/ahblite.sv @@ -38,9 +38,8 @@ module ahblite ( // Signals from Instruction Cache input logic [`XLEN-1:0] InstrPAdrF, // *** rename these to match block diagram input logic InstrReadF, - input logic ResolveBranchD, +// input logic ResolveBranchD, output logic [31:0] InstrRData, -// output logic IReady, // Signals from Data Cache input logic [`XLEN-1:0] MemPAdrM, input logic MemReadM, MemWriteM, @@ -48,7 +47,6 @@ module ahblite ( input logic [1:0] MemSizeM, // Return from bus output logic [`XLEN-1:0] ReadDataW, -// output logic DReady, // AHB-Lite external signals input logic [`AHBW-1:0] HRDATA, input logic HREADY, HRESP, @@ -61,14 +59,12 @@ module ahblite ( output logic [3:0] HPROT, output logic [1:0] HTRANS, output logic HMASTLOCK, - // Delayed signals for subword write + // Delayed signals for writes output logic [2:0] HADDRD, output logic [3:0] HSIZED, output logic HWRITED, - // Acknowledge - output logic InstrAckD, MemAckW, // Stalls - output logic InstrStall, DataStall + output logic InstrStall,/*InstrUpdate, */DataStall ); logic GrantData; @@ -81,12 +77,61 @@ module ahblite ( assign HCLK = clk; assign HRESETn = ~reset; - // Arbitrate requests by giving data priority over instructions - assign GrantData = MemReadM | MemWriteM; - // *** initially support HABW = XLEN // track bus state + // Data accesses have priority over instructions. However, if a data access comes + // while an instruction read is occuring, the instruction read finishes before + // the data access can take place. + typedef enum {IDLE, MEMREAD, MEMWRITE, INSTRREAD, INSTRREADMEMPENDING} statetype; + statetype BusState, NextBusState; + + always_ff @(posedge HCLK, negedge HRESETn) + if (~HRESETn) BusState <= #1 IDLE; + else BusState <= #1 NextBusState; + + always_comb + case (BusState) + IDLE: if (MemReadM) NextBusState = MEMREAD; // Memory has pirority over instructions + else if (MemWriteM) NextBusState = MEMWRITE; + else if (InstrReadF) NextBusState = INSTRREAD; + else NextBusState = IDLE; + MEMREAD: if (~HREADY) NextBusState = MEMREAD; + else if (InstrReadF) NextBusState = INSTRREAD; + else NextBusState = IDLE; + MEMWRITE: if (~HREADY) NextBusState = MEMWRITE; + else if (InstrReadF) NextBusState = INSTRREAD; + else NextBusState = IDLE; + INSTRREAD: //if (~HREADY & (MemReadM | MemWriteM)) NextBusState = INSTRREADMEMPENDING; // *** shouldn't happen, delete + if (~HREADY) NextBusState = INSTRREAD; + else NextBusState = IDLE; + INSTRREADMEMPENDING: if (~HREADY) NextBusState = INSTRREADMEMPENDING; // *** shouldn't happen, delete + else if (MemReadM) NextBusState = MEMREAD; + else NextBusState = MEMWRITE; // must be write if not a read. Don't return to idle. + endcase + + // stall signals + assign #2 DataStall = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) || (NextBusState == INSTRREADMEMPENDING); + assign #1 InstrStall = (NextBusState == INSTRREAD); + // assign InstrUpdate = (BusState == INSTRREADMEMPENDING) && (NextBusState != INSTRREADMEMPENDING); + + // bus outputs + assign #1 GrantData = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE); + assign #1 HADDR = (GrantData) ? MemPAdrM[31:0] : InstrPAdrF[31:0]; + assign #1 HSIZE = GrantData ? {1'b0, MemSizeM} : ISize; + assign HBURST = 3'b000; // Single burst only supported; consider generalizing for cache fillsfH + assign HPROT = 4'b0011; // not used; see Section 3.7 + assign HTRANS = (NextBusState != IDLE) ? 2'b10 : 2'b00; // NONSEQ if reading or writing, IDLE otherwise + assign HMASTLOCK = 0; // no locking supported + assign HWRITE = (NextBusState == MEMWRITE); + // delay write data by one cycle for + flop #(`XLEN) wdreg(HCLK, WriteDataM, HWDATA); // delay HWDATA by 1 cycle per spec; *** assumes AHBW = XLEN + // delay signals for subword writes + flop #(3) adrreg(HCLK, HADDR[2:0], HADDRD); + flop #(4) sizereg(HCLK, {UnsignedLoadM, HSIZE}, HSIZED); + flop #(1) writereg(HCLK, HWRITE, HWRITED); + + /* typedef enum {IDLE, MEMREAD, MEMWRITE, INSTRREAD} statetype; statetype AdrState, DataState, NextAdrState; // what is happening in the first and second phases of the bus always_ff @(posedge HCLK, negedge HRESETn) @@ -117,13 +162,42 @@ module ahblite ( assign MemAckW = (AdrState == MEMREAD || AdrState == MEMWRITE) && HREADY; assign InstrAckD = (AdrState == INSTRREAD) && HREADY; + // State machines for stalls (probably can merge with FSM above***) + // Idle, DataBusy, InstrBusy. Stall while in busystate add suffixes + logic MemState, NextMemState, InstrState, NextInstrState; + flopr #(1) msreg(HCLK, ~HRESETn, NextMemState, MemState); + flopr #(1) isreg(HCLK, ~HRESETn, NextInstrState, InstrState); +/* always_ff @(posedge HCLK, negedge HRESETn) + if (~HRESETn) MemState <= 0; + else MemState <= NextMemState; + assign NextMemState = (MemState == 0 && InstrState == 0 && (MemReadM || MemWriteM)) || (MemState == 1 && ~MemAckW); + assign DataStall = NextMemState; +/* always_ff @(posedge HCLK, negedge HRESETn) + if (~HRESETn) InstrState <= 0; + else InstrState <= NextInstrState; + + assign NextInstrState = (InstrState == 0 && MemState == 0 && (~MemReadM && ~MemWriteM && InstrReadF)) || + (InstrState == 1 && ~InstrAckD) || + (InstrState == 1 && ResolveBranchD); // dh 2/8/2021 fixing; delete this later +/* assign NextInstrState = (InstrState == 0 && MemState == 0 && (~MemReadM && ~MemWriteM)) || + (InstrState == 1 && ~InstrAckD); // *** removed InstrReadF above dh 2/9/20 + assign InstrStall = NextInstrState | MemState | NextMemState; // *** check this, explain better + // temporarily turn off stalls and check it works + //assign DataStall = 0; + //assign InstrStall = 0; + + assign DReady = HREADY & GrantData; // ***unused? + assign IReady = HREADY & InstrReadF & ~GrantData; // maybe unused?*** + +*/ + // Choose ISize based on XLen generate //if (`AHBW == 32) assign ISize = 3'b010; // 32-bit transfers //else assign ISize = 3'b011; // 64-bit transfers assign ISize = 3'b010; // 32 bit instructions for now; later improve for filling cache with full width endgenerate - +/* // drive bus outputs assign HADDR = GrantData ? MemPAdrM[31:0] : InstrPAdrF[31:0]; //assign HWDATA = WriteDataW; @@ -134,41 +208,16 @@ module ahblite ( assign HPROT = 4'b0011; // not used; see Section 3.7 assign HTRANS = InstrReadF | MemReadM | MemWriteM ? 2'b10 : 2'b00; // NONSEQ if reading or writing, IDLE otherwise assign HMASTLOCK = 0; // no locking supported - + */ // Route signals to Instruction and Data Caches // *** assumes AHBW = XLEN assign InstrRData = HRDATAMasked[31:0]; - assign IReady = HREADY & InstrReadF & ~GrantData; // maybe unused?*** // assign ReadDataW = HRDATAMasked; assign ReadDataM = HRDATAMasked; // changed from W to M dh 2/7/2021 - flopenrc #(`XLEN) ReadDataWReg(clk, reset, FlushW, ~StallW, ReadDataM, ReadDataW); - assign DReady = HREADY & GrantData; // ***unused? + assign CaptureDataM = (BusState == MEMREAD) && (NextBusState != MEMREAD); + flopenr #(`XLEN) ReadDataWReg(clk, reset, CaptureDataM, ReadDataM, ReadDataW); - // State machines for stalls (probably can merge with FSM above***) - // Idle, DataBusy, InstrBusy. Stall while in busystate add suffixes - logic MemState, NextMemState, InstrState, NextInstrState; - flopr #(1) msreg(HCLK, ~HRESETn, NextMemState, MemState); - flopr #(1) isreg(HCLK, ~HRESETn, NextInstrState, InstrState); -/* always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) MemState <= 0; - else MemState <= NextMemState; */ - assign NextMemState = (MemState == 0 && InstrState == 0 && (MemReadM || MemWriteM)) || (MemState == 1 && ~MemAckW); - assign DataStall = NextMemState; -/* always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) InstrState <= 0; - else InstrState <= NextInstrState;*/ - - assign NextInstrState = (InstrState == 0 && MemState == 0 && (~MemReadM && ~MemWriteM && InstrReadF)) || - (InstrState == 1 && ~InstrAckD) || - (InstrState == 1 && ResolveBranchD); // dh 2/8/2021 fixing; delete this later -/* assign NextInstrState = (InstrState == 0 && MemState == 0 && (~MemReadM && ~MemWriteM)) || - (InstrState == 1 && ~InstrAckD); // *** removed InstrReadF above dh 2/9/20 */ - assign InstrStall = NextInstrState | MemState | NextMemState; // *** check this, explain better - // temporarily turn off stalls and check it works - //assign DataStall = 0; - //assign InstrStall = 0; - // stalls // Stall MEM stage if data is being accessed and bus isn't yet ready //assign DataStall = GrantData & ~HREADY; diff --git a/wally-pipelined/src/generic/flop.sv b/wally-pipelined/src/generic/flop.sv index 263a4fb9..7e954a8f 100644 --- a/wally-pipelined/src/generic/flop.sv +++ b/wally-pipelined/src/generic/flop.sv @@ -47,6 +47,16 @@ module flopr #(parameter WIDTH = 8) ( else q <= #1 d; endmodule +// flop with enable +module flopen #(parameter WIDTH = 8) ( + input logic clk, en, + input logic [WIDTH-1:0] d, + output logic [WIDTH-1:0] q); + + always_ff @(posedge clk) + if (en) q <= #1 d; +endmodule + // flop with enable, asynchronous reset, synchronous clear module flopenrc #(parameter WIDTH = 8) ( input logic clk, reset, clear, en, diff --git a/wally-pipelined/src/hazard/hazard.sv b/wally-pipelined/src/hazard/hazard.sv index 88d78ee4..c45fb47f 100644 --- a/wally-pipelined/src/hazard/hazard.sv +++ b/wally-pipelined/src/hazard/hazard.sv @@ -56,12 +56,12 @@ module hazard( assign BranchFlushDE = PCSrcE | RetM | TrapM; - assign StallFCause = InstrStall | CSRWritePendingDEM; // stall at fetch if unable to get the instruction, + assign StallFCause = /*InstrStall | */ CSRWritePendingDEM; // stall at fetch if unable to get the instruction, // or if a CSR will be written and may change system behavior assign StallDCause = LoadStallD; // stall in decode if instruction is a load dependent on previous assign StallECause = 0; assign StallMCause = 0; // sDataStall; // not yet used*** - assign StallWCause = DataStall; // | InstrStall; + assign StallWCause = DataStall | InstrStall; // Each stage stalls if the next stage is stalled or there is a cause to stall this stage. assign StallF = StallD | StallFCause; diff --git a/wally-pipelined/src/ifu/ifu.sv b/wally-pipelined/src/ifu/ifu.sv index 6c16ebd8..3ba28a05 100644 --- a/wally-pipelined/src/ifu/ifu.sv +++ b/wally-pipelined/src/ifu/ifu.sv @@ -67,18 +67,20 @@ module ifu ( // *** put memory interface on here, InstrF becomes output assign InstrPAdrF = PCF; // *** no MMU - assign InstrReadF = ~StallD; // *** & ICacheMissF; add later + //assign InstrReadF = ~StallD; // *** & ICacheMissF; add later + assign InstrReadF = 1; // *** & ICacheMissF; add later assign PrivilegedChangePCM = RetM | TrapM; - assign StallExceptResolveBranchesF = StallF & ~(PCSrcE | PrivilegedChangePCM); + //assign StallExceptResolveBranchesF = StallF & ~(PCSrcE | PrivilegedChangePCM); // dh 2/8/2022 keep in instruction fetch stall mode when taking branch - flopr #(1) rbreg(clk, reset, (PCSrcE | PrivilegedChangePCM), ResolveBranchD); + //flopr #(1) rbreg(clk, reset, (PCSrcE | PrivilegedChangePCM), ResolveBranchD); mux3 #(`XLEN) pcmux(PCPlus2or4F, PCTargetE, PrivilegedNextPCM, {PrivilegedChangePCM, PCSrcE}, UnalignedPCNextF); assign PCNextF = {UnalignedPCNextF[`XLEN-1:1], 1'b0}; // hart-SPEC p. 21 about 16-bit alignment - flopenl #(`XLEN) pcreg(clk, reset, ~StallExceptResolveBranchesF, PCNextF, `RESET_VECTOR, PCF); +// flopenl #(`XLEN) pcreg(clk, reset, ~StallExceptResolveBranchesF, PCNextF, `RESET_VECTOR, PCF); + flopenl #(`XLEN) pcreg(clk, reset, ~StallF, PCNextF, `RESET_VECTOR, PCF); // pcadder // add 2 or 4 to the PC, based on whether the instruction is 16 bits or 32 diff --git a/wally-pipelined/src/privileged/csr.sv b/wally-pipelined/src/privileged/csr.sv index 496b0a08..e1e76aa0 100644 --- a/wally-pipelined/src/privileged/csr.sv +++ b/wally-pipelined/src/privileged/csr.sv @@ -28,7 +28,7 @@ module csr ( input logic clk, reset, - input logic FlushW, + input logic FlushW, StallW, input logic [31:0] InstrM, input logic [`XLEN-1:0] PCM, SrcAM, input logic CSRWriteM, TrapM, MTrapM, STrapM, UTrapM, mretM, sretM, uretM, diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index 6db96dcc..ecfbecfd 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -27,7 +27,7 @@ `include "wally-config.vh" module csrsr ( - input logic clk, reset, + input logic clk, reset, StallW, input logic WriteMSTATUSM, WriteSSTATUSM, WriteUSTATUSM, input logic TrapM, FloatRegWriteW, input logic [1:0] NextPrivilegeModeM, PrivilegeModeW, @@ -118,7 +118,7 @@ module csrsr ( STATUS_MIE <= 0; // Per Priv 3.3 STATUS_SIE <= `S_SUPPORTED; STATUS_UIE <= `U_SUPPORTED; - end else begin + end else if (~StallW) begin if (WriteMSTATUSM) begin STATUS_SUM_INT <= CSRWriteValM[18]; STATUS_MPRV_INT <= CSRWriteValM[17]; diff --git a/wally-pipelined/src/privileged/privileged.sv b/wally-pipelined/src/privileged/privileged.sv index be97b51c..6b124972 100644 --- a/wally-pipelined/src/privileged/privileged.sv +++ b/wally-pipelined/src/privileged/privileged.sv @@ -1,5 +1,5 @@ /////////////////////////////////////////// -// exceptions.sv +// privileged.sv // // Written: David_Harris@hmc.edu 5 January 2021 // Modified: @@ -45,7 +45,7 @@ module privileged ( input logic [`XLEN-1:0] InstrMisalignedAdrM, MemAdrM, input logic [4:0] SetFflagsM, output logic [2:0] FRM_REGW, - input logic FlushD, FlushE, FlushM, StallD + input logic FlushD, FlushE, FlushM, StallD, StallW ); logic [1:0] NextPrivilegeModeM, PrivilegeModeW; @@ -81,8 +81,8 @@ module privileged ( // PrivilegeMode FSM always_comb - if (reset) NextPrivilegeModeM = `M_MODE; // Privilege resets to 11 (Machine Mode) - else if (mretM) NextPrivilegeModeM = STATUS_MPP; + /* if (reset) NextPrivilegeModeM = `M_MODE; // Privilege resets to 11 (Machine Mode) // moved reset to flop + else */ if (mretM) NextPrivilegeModeM = STATUS_MPP; else if (sretM) NextPrivilegeModeM = {1'b0, STATUS_SPP}; else if (uretM) NextPrivilegeModeM = `U_MODE; else if (TrapM) begin // Change privilege based on DELEG registers (see 3.1.8) @@ -96,7 +96,7 @@ module privileged ( else NextPrivilegeModeM = `M_MODE; end else NextPrivilegeModeM = PrivilegeModeW; - flop #(2) privmodereg(clk, NextPrivilegeModeM, PrivilegeModeW); + flopenl #(2) privmodereg(clk, reset, ~StallW, NextPrivilegeModeM, `M_MODE, PrivilegeModeW); /////////////////////////////////////////// // decode privileged instructions diff --git a/wally-pipelined/src/uncore/dtim.sv b/wally-pipelined/src/uncore/dtim.sv index 61118360..4216b356 100644 --- a/wally-pipelined/src/uncore/dtim.sv +++ b/wally-pipelined/src/uncore/dtim.sv @@ -37,6 +37,7 @@ module dtim ( logic [`XLEN-1:0] RAM[0:65535]; logic [18:0] HWADDR; + logic [`XLEN-1:0] HREADTim0; // logic [`XLEN-1:0] write; logic [15:0] entry; @@ -44,27 +45,28 @@ module dtim ( logic [3:0] busycount; // busy FSM to extend READY signal -/* always_ff @(posedge HCLK, negedge HRESETn) + always_ff @(posedge HCLK, negedge HRESETn) if (~HRESETn) begin HREADYTim <= 1; end else begin if (HREADYTim & HSELTim) begin busycount <= 0; - HREADYTim <= 0; + HREADYTim <= #1 0; end else if (~HREADYTim) begin - if (busycount == 0) begin // TIM latency, for testing purposes - HREADYTim <= 1; + if (busycount == 2) begin // TIM latency, for testing purposes + HREADYTim <= #1 1; end else begin busycount <= busycount + 1; end end - end*/ - always_ff @(posedge HCLK, negedge HRESETn) + end + + /* always_ff @(posedge HCLK, negedge HRESETn) if (~HRESETn) begin HREADYTim <= 0; end else begin HREADYTim <= HSELTim; // always respond one cycle later - end + end */ assign memread = MemRWtim[1]; @@ -73,77 +75,32 @@ module dtim ( // memwrite <= MemRWtim[0]; // delay memwrite to write phase assign HRESPTim = 0; // OK // assign HREADYTim = 1; // Respond immediately; *** extend this - - // word aligned reads -/* generate - if (`XLEN==64) - assign #2 entry = HADDR[18:3]; - else - assign #2 entry = HADDR[17:2]; - endgenerate */ -// assign HREADTim = RAM[entry]; -// assign HREADTim = HREADYTim ? RAM[entry] : ~RAM[entry]; // *** temproary mess up read value before ready - // write each byte based on the byte mask - // UInstantiate a byte-writable memory here if possible - // and drop tihs masking logic. Otherwise, use the masking - // from dmem - /*generate - - if (`XLEN==64) begin - always_comb begin - write=HREADTim; - if (ByteMaskM[0]) write[7:0] = HWDATA[7:0]; - if (ByteMaskM[1]) write[15:8] = HWDATA[15:8]; - if (ByteMaskM[2]) write[23:16] = HWDATA[23:16]; - if (ByteMaskM[3]) write[31:24] = HWDATA[31:24]; - if (ByteMaskM[4]) write[39:32] = HWDATA[39:32]; - if (ByteMaskM[5]) write[47:40] = HWDATA[47:40]; - if (ByteMaskM[6]) write[55:48] = HWDATA[55:48]; - if (ByteMaskM[7]) write[63:56] = HWDATA[63:56]; - end - always_ff @(posedge clk) - if (memwrite) RAM[HADDR[18:3]] <= write; - end else begin // 32-bit - always_comb begin - write=HREADTim; - if (ByteMaskM[0]) write[7:0] = HWDATA[7:0]; - if (ByteMaskM[1]) write[15:8] = HWDATA[15:8]; - if (ByteMaskM[2]) write[23:16] = HWDATA[23:16]; - if (ByteMaskM[3]) write[31:24] = HWDATA[31:24]; - end - always_ff @(posedge clk) - if (memwrite) RAM[HADDR[17:2]] <= write; - end - endgenerate */ // Model memory read and write - // If write occurs at end of phase (rising edge of clock), - // then read of same address on next cycle won't work. Would need to bypass. - // Faking for now with negedge clock write. Will need to adjust this to - // match capabilities of FPGA or actual chip RAM. - // Also, writes occuring later than reads throws off single ported RAM that - // might be asked to write on one instruction and read on the next and would need - // to stall because both accesses happen on same cycle with AHB delay generate if (`XLEN == 64) begin - always_ff @(negedge HCLK) - if (memwrite) RAM[HWADDR[17:3]] <= HWDATA; +// always_ff @(negedge HCLK) +// if (memwrite) RAM[HWADDR[17:3]] <= HWDATA; always_ff @(posedge HCLK) begin //if (memwrite) RAM[HADDR[17:3]] <= HWDATA; HWADDR <= HADDR; - HREADTim <= RAM[HADDR[17:3]]; + HREADTim0 <= RAM[HADDR[17:3]]; + if (memwrite && HREADYTim) RAM[HWADDR[17:3]] <= HWDATA; end end else begin - always_ff @(negedge HCLK) - if (memwrite) RAM[HWADDR[17:2]] <= HWDATA; +// always_ff @(negedge HCLK) +// if (memwrite) RAM[HWADDR[17:2]] <= HWDATA; always_ff @(posedge HCLK) begin //if (memwrite) RAM[HADDR[17:2]] <= HWDATA; HWADDR <= HADDR; - HREADTim <= RAM[HADDR[17:2]]; + HREADTim0 <= RAM[HADDR[17:2]]; + if (memwrite && HREADYTim) RAM[HWADDR[17:2]] <= HWDATA; end end endgenerate + + assign HREADTim = HREADYTim ? HREADTim0 : 'bz; endmodule diff --git a/wally-pipelined/testgen/testgen-ADD-SUB.py b/wally-pipelined/testgen/testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py similarity index 82% rename from wally-pipelined/testgen/testgen-ADD-SUB.py rename to wally-pipelined/testgen/testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py index 16e02be6..9f795036 100755 --- a/wally-pipelined/testgen/testgen-ADD-SUB.py +++ b/wally-pipelined/testgen/testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 ################################## -# testgen-ADD-SUB.py +# testgen-ADD-SUB-SLT-SLTU-XOR-OR-AND.py # # David_Harris@hmc.edu 19 January 2021 # @@ -19,11 +19,34 @@ from random import getrandbits # functions ################################## -def computeExpected(a, b, test): +def twoscomp(a): + amsb = a >> (xlen-1) + alsbs = ((1 << (xlen-1)) - 1) & a + if (amsb): + asigned = a - (1<> (xlen-1) + alsbs = ((1 << (xlen-1)) - 1) & a + if (amsb): + asigned = a - (1<> b + elif (test == "SRA"): + return asigned >> b + else: + die("bad test name ", test) + # exit(1) + +def randRegs(): + reg1 = randint(1,31) + reg2 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2, reg3 + +def writeVector(a, b, storecmd, xlen): + global testnum + expected = computeExpected(a, b, test, xlen) + expected = expected % 2**xlen # drop carry if necessary + if (expected < 0): # take twos complement + expected = 2**xlen + expected + reg1, reg2, reg3 = randRegs() + lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a) + lines = lines + "), rs2:x" + str(reg2) + "(" +formatstr.format(b) + lines = lines + "), result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n" + lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n" + lines = lines + "li x" + str(reg2) + ", MASK_XLEN(" + formatstr.format(b) + ")\n" + lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", x" + str(reg2) + "\n" + lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n" + lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, " + str(reg3) +", "+formatstr.format(expected)+")\n" + f.write(lines) + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# change these to suite your tests +tests = ["SLL", "SRL", "SRA"] +author = "David_Harris@hmc.edu" +xlens = [32, 64] +numrand = 48 + +# setup +seed(0) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + for test in tests: + corners = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1, + 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1] + if (xlen == 32): + shamt = [0, 1, 2, 3, 4, 8, 15, 16, 29, 30, 31] + else: + shamt = [0, 1, 3, 8, 15, 16, 29, 31, 32, 47, 48, 62, 63] + + imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/" + basename = "WALLY-" + test + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + for a in corners: + for b in shamt: + writeVector(a, b, storecmd, xlen) + for i in range(0,numrand): + a = getrandbits(xlen) + b = getrandbits(xlen) + writeVector(a, b, storecmd, xlen) + + + # print footer + h = open("testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + + + +