More memory interface, ALU testgen

This commit is contained in:
David Harris 2021-02-15 10:10:50 -05:00
parent 183a2dcfb5
commit 37dba8fd26
10 changed files with 317 additions and 122 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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];

View File

@ -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

View File

@ -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

View File

@ -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)
else:
asigned = a
#print("a: " + str(a) + " amsb: "+str(amsb)+ " alsbs: " + str(alsbs) + " asigned: "+str(asigned))
return asigned
def computeExpected(a, b, test, xlen):
asigned = twoscomp(a)
bsigned = twoscomp(b)
if (test == "ADD"):
return a + b
elif (test == "SUB"):
return a - b
elif (test == "SLT"):
return asigned < bsigned
elif (test == "SLTU"):
return a < b
elif (test == "XOR"):
return a ^ b
elif (test == "OR"):
return a | b
elif (test == "AND"):
return a & b
else:
die("bad test name ", test)
# exit(1)
@ -37,9 +60,9 @@ def randRegs():
else:
return reg1, reg2, reg3
def writeVector(a, b, storecmd):
def writeVector(a, b, storecmd, xlen):
global testnum
expected = computeExpected(a, b, test)
expected = computeExpected(a, b, test, xlen)
expected = expected % 2**xlen # drop carry if necessary
if (expected < 0): # take twos complement
expected = 2**xlen + expected
@ -65,7 +88,7 @@ def writeVector(a, b, storecmd):
##################################
# change these to suite your tests
tests = ["ADD", "SUB"]
tests = ["ADD", "SUB", "SLT", "SLTU", "XOR", "OR", "AND"]
author = "David_Harris@hmc.edu & Katherine Parry"
xlens = [32, 64]
numrand = 100;
@ -111,11 +134,11 @@ for xlen in xlens:
# print directed and random test vectors
for a in corners:
for b in corners:
writeVector(a, b, storecmd)
writeVector(a, b, storecmd, xlen)
for i in range(0,numrand):
a = getrandbits(xlen)
b = getrandbits(xlen)
writeVector(a, b, storecmd)
writeVector(a, b, storecmd, xlen)
# print footer

View File

@ -0,0 +1,154 @@
#!/usr/bin/python3
##################################
# testgen-SLL-SRL-SRA.py
#
# David_Harris@hmc.edu 19 January 2021
#
# Generate directed and random test vectors for RISC-V Design Validation.
##################################
##################################
# libraries
##################################
from datetime import datetime
from random import randint
from random import seed
from random import getrandbits
##################################
# functions
##################################
def twoscomp(a):
amsb = a >> (xlen-1)
alsbs = ((1 << (xlen-1)) - 1) & a
if (amsb):
asigned = a - (1<<xlen)
else:
asigned = a
#print("a: " + str(a) + " amsb: "+str(amsb)+ " alsbs: " + str(alsbs) + " asigned: "+str(asigned))
return asigned
def computeExpected(a, b, test, xlen):
asigned = twoscomp(a)
b = b % xlen
if (test == "SLL"):
return a << b
elif (test == "SRL"):
return a >> 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()