diff --git a/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh b/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh index 11c34645f..f694b112a 100755 --- a/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh +++ b/wally-pipelined/linux-testgen/linux-testvectors/tvLinker.sh @@ -1,9 +1,5 @@ echo "Warning: this script will only work if your repo is on Tera" -ln -s /courses/e190ax/buildroot_boot/parsedCSRs.txt parsedCSRs.txt -ln -s /courses/e190ax/buildroot_boot/parsedMemRead.txt parsedMemRead.txt -ln -s /courses/e190ax/buildroot_boot/parsedMemWrite.txt parsedMemWrite.txt -ln -s /courses/e190ax/buildroot_boot/parsedPC.txt parsedPC.txt -ln -s /courses/e190ax/buildroot_boot/parsedRegs.txt parsedRegs.txt +ln -s /courses/e190ax/buildroot_boot/all.txt all.txt ln -s /courses/e190ax/buildroot_boot/bootmem.txt bootmem.txt ln -s /courses/e190ax/buildroot_boot/ram.txt ram.txt echo "Done!" diff --git a/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh b/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh index 183d6a6ec..bded8a16e 100755 --- a/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh +++ b/wally-pipelined/linux-testgen/linux-testvectors/tvUnlinker.sh @@ -1,10 +1,6 @@ # This could be nice to use if you want to mess with the testvectors # without corrupting the stable copies on Tera. -unlink parsedCSRs.txt -unlink parsedMemRead.txt -unlink parsedMemWrite.txt -unlink parsedPC.txt -unlink parsedRegs.txt +unlink all.txt unlink bootmem.txt unlink ram.txt echo "Done!" diff --git a/wally-pipelined/linux-testgen/testvector-generation/GenerateCheckpoint.sh b/wally-pipelined/linux-testgen/testvector-generation/GenerateCheckpoint.sh new file mode 100755 index 000000000..e9bf5167d --- /dev/null +++ b/wally-pipelined/linux-testgen/testvector-generation/GenerateCheckpoint.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Oftentimes this script runs so long you'll go to sleep. +# But you don't want the script to die when your computer goes to sleep. +# So consider invoking this with nohup (i.e. "nohup ./logAllBuildroot.sh") +# You can run "tail -f nohup.out" to see what would've +# outputted to the terminal if you didn't use nohup + +# use on tera. +customQemu="/courses/e190ax/qemu_sim/rv64_initrd/qemu_experimental/qemu/build/qemu-system-riscv64" +# use on other systems +#customQemu="qemu-system-riscv64" + +instrs=8500000 + +imageDir="../buildroot-image-output" +outDir="../linux-testvectors/checkpoint$instrs" +intermedDir="$outDir/intermediate-outputs" + + +read -p "This scripts is going to create a checkpoint at $instrs instrs. +Is that what you wanted? (y/n) " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]] +then + mkdir -p $outDir + mkdir -p $intermedDir + ($customQemu -M virt -nographic -bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio -rtc clock=vm -icount shift=1 -d nochain,cpu,in_asm -serial /dev/null -singlestep -gdb tcp::1240 -S 2>&1 1>&2 | ./parse_qemu.py | ./parseNew.py | ./remove_dup.awk > $intermedDir/rawTrace.txt) & riscv64-unknown-elf-gdb -x ./checkpoint.gdb -ex "createCheckpoint $instrs \"$intermedDir\"" + ./fix_mem.py "$intermedDir/ramGDB.txt" "$outDir/ram.txt" + ./parseState.py "$outDir" +else + echo "You can change the number of instructions by editing the \"instrs\" variable in this script." + echo "Have a nice day!" +fi diff --git a/wally-pipelined/linux-testgen/testvector-generation/checkpoint.gdb b/wally-pipelined/linux-testgen/testvector-generation/checkpoint.gdb new file mode 100755 index 000000000..8ffd8e982 --- /dev/null +++ b/wally-pipelined/linux-testgen/testvector-generation/checkpoint.gdb @@ -0,0 +1,53 @@ +define createCheckpoint + # GDB config + set pagination off + set logging overwrite on + set logging redirect on + set confirm off + + # QEMU must also use TCP port 1240 + target extended-remote :1240 + + # Argument Parsing + set $statePath=$arg1 + set $ramPath=$arg1 + eval "set $statePath = \"%s/stateGDB.txt\"", $statePath + eval "set $ramPath = \"%s/ramGDB.txt\"", $ramPath + + # Symbol file + file ../buildroot-image-output/vmlinux + + # Step over reset vector into actual code + stepi 1000 + # Set breakpoint for where to stop + b do_idle + # Proceed to checkpoint + printf "GDB proceeding to checkpoint at %d instrs\n", $arg0 + stepi $arg0-1000 + + printf "Reached checkpoint at %d instrs\n", $arg0 + + # Log all registers to a file + printf "GDB storing state to %s\n", $statePath + set logging file $statePath + set logging on + info all-registers + set logging off + + # Log main memory to a file + printf "GDB storing RAM to %s\n", $ramPath + set logging file ../linux-testvectors/intermediate-outputs/ramGDB.txt + set logging on + x/134217728xb 0x80000000 + set logging off + + # Continue to checkpoint; stop on the 3rd time + # Should reach login prompt by then + printf "GDB continuing execution to login prompt\n" + ignore 1 2 + c + + printf "GDB reached login prompt!\n" + kill + q +end diff --git a/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py b/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py index 66ff9cf03..0e2fbf82c 100755 --- a/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py +++ b/wally-pipelined/linux-testgen/testvector-generation/fix_mem.py @@ -6,9 +6,10 @@ if len(sys.argv) != 3: inputFile = sys.argv[1] outputFile = sys.argv[2] if not os.path.exists(inputFile): - sys.exit('Error input file '+inputFile+'not found') -print('Translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)) + sys.exit('Error input file '+inputFile+' not found') +print('Begin translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)) with open(inputFile, 'r') as f: with open(outputFile, 'w') as w: for l in f: w.write(f'{"".join([x[2:] for x in l.split()[:0:-1]])}\n') +print('Finished translating '+os.path.basename(inputFile)+' to '+os.path.basename(outputFile)+'!') diff --git a/wally-pipelined/linux-testgen/testvector-generation/parseNew.py b/wally-pipelined/linux-testgen/testvector-generation/parseNew.py index 719286a2f..7c2c00245 100755 --- a/wally-pipelined/linux-testgen/testvector-generation/parseNew.py +++ b/wally-pipelined/linux-testgen/testvector-generation/parseNew.py @@ -140,6 +140,7 @@ CurrentInstr = ['0', '0', None, 'other', {'zero': 0, 'ra': 0, 'sp': 0, 'gp': 0, lineNum = 0 StartLine = 0 EndLine = 0 +numInstrs = 0 #instructions = [] MemAdr = 0 lines = [] @@ -195,6 +196,10 @@ for line in fileinput.input('-'): lines.clear() #instructions.append(MoveInstrToRegWriteLst) PrintInstr(MoveInstrToRegWriteLst, sys.stdout) + numInstrs +=1 + if (numInstrs % 1e4 == 0): + sys.stderr.write('Trace parser reached '+str(numInstrs/1.0e6)+' million instrs.\n') + sys.stderr.flush() lineNum += 1 diff --git a/wally-pipelined/linux-testgen/testvector-generation/parseState.py b/wally-pipelined/linux-testgen/testvector-generation/parseState.py new file mode 100755 index 000000000..0a0c8c8b5 --- /dev/null +++ b/wally-pipelined/linux-testgen/testvector-generation/parseState.py @@ -0,0 +1,79 @@ +#! /usr/bin/python3 +import sys + +################ +# Helper Funcs # +################ + +def tokenize(string): + tokens = [] + token = '' + whitespace = 0 + prevWhitespace = 0 + for char in string: + prevWhitespace = whitespace + whitespace = char in ' \t\n' + if (whitespace): + if ((not prevWhitespace) and (token != '')): + tokens.append(token) + token = '' + else: + token = token + char + return tokens + +############# +# Main Code # +############# +print("Begin parsing state.") + +# Parse Args +if len(sys.argv) != 2: + sys.exit('Error parseState.py expects 1 arg:\n parseState.py ') +outDir = sys.argv[1] +stateGDBpath = outDir+'/intermediate-outputs/stateGDB1K.txt' +if not os.path.exists(stateGDBpath): + sys.exit('Error input file '+stateGDBpath+'not found') + +listCSRs = ['hpmcounter','pmpcfg','pmpaddr'] +singleCSRs = ['mip','mie','mscratch','mcause','mepc','mtvec','medeleg','mideleg','mcounteren','sscratch','scause','sepc','stvec','sedeleg','sideleg','scounteren','satp','mstatus'] + +# Initialize List CSR files to empty +# (because later we'll open them in append mode) +for csr in listCSRs: + outFileName = 'checkpoint-'+csr.upper() + outFile = open(outDir+outFileName, 'w') + outFile.close() + +# Initial State for Main Loop +currState = 'regFile' +regFileIndex = 0 +outFileName = 'checkpoint-regfile.txt' +outFile = open(outDir+outFileName, 'w') + +# Main Loop +with open(stateGDBpath, 'r') as stateGDB: + for line in stateGDB: + line = tokenize(line) + name = line[0] + val = line[1][2:] + if (currState == 'regFile'): + if (regFileIndex == 0 and name != 'zero'): + print('Whoops! Expected regFile registers to come first, starting with zero') + exit(1) + outFile.write(val+'\n') + regFileIndex += 1 + if (regFileIndex == 32): + outFile.close() + currState = 'CSRs' + elif (currState == 'CSRs'): + if name in singleCSRs: + outFileName = 'checkpoint-'+name.upper() + outFile = open(outDir+outFileName, 'w') + outFile.write(val+'\n') + outFile.close() + elif name.strip('0123456789') in listCSRs: + outFileName = 'checkpoint-'+name.upper().strip('0123456789') + outFile = open(outDir+outFileName, 'a') + outFile.write(val+'\n') + outFile.close() +print("Finished parsing state!") diff --git a/wally-pipelined/src/generic/flop.sv b/wally-pipelined/src/generic/flop.sv index cb583de2e..82c64c567 100644 --- a/wally-pipelined/src/generic/flop.sv +++ b/wally-pipelined/src/generic/flop.sv @@ -25,6 +25,8 @@ `include "wally-config.vh" /* verilator lint_off DECLFILENAME */ +// Note that non-zero RESET_VAL's are only ever intended for simulation purposes (to start mid-execution from a checkpoint) + // ordinary flip-flop module flop #(parameter WIDTH = 8) ( @@ -40,10 +42,11 @@ endmodule module flopr #(parameter WIDTH = 8) ( input logic clk, reset, input logic [WIDTH-1:0] d, - output logic [WIDTH-1:0] q); + output logic [WIDTH-1:0] q, + input var [WIDTH-1:0] RESET_VAL=0); always_ff @(posedge clk, posedge reset) - if (reset) q <= #1 0; + if (reset) q <= #1 RESET_VAL; else q <= #1 d; endmodule @@ -61,10 +64,11 @@ endmodule module flopenrc #(parameter WIDTH = 8) ( input logic clk, reset, clear, en, input logic [WIDTH-1:0] d, - output logic [WIDTH-1:0] q); + output logic [WIDTH-1:0] q, + input var [WIDTH-1:0] RESET_VAL=0); always_ff @(posedge clk, posedge reset) - if (reset) q <= #1 0; + if (reset) q <= #1 RESET_VAL; else if (en) if (clear) q <= #1 0; else q <= #1 d; @@ -74,10 +78,11 @@ endmodule module flopenr #(parameter WIDTH = 8) ( input logic clk, reset, en, input logic [WIDTH-1:0] d, - output logic [WIDTH-1:0] q); + output logic [WIDTH-1:0] q, + input var [WIDTH-1:0] RESET_VAL=0); always_ff @(posedge clk, posedge reset) - if (reset) q <= #1 0; + if (reset) q <= #1 RESET_VAL; else if (en) q <= #1 d; endmodule @@ -99,10 +104,11 @@ module floprc #(parameter WIDTH = 8) ( input logic reset, input logic clear, input logic [WIDTH-1:0] d, - output logic [WIDTH-1:0] q); + output logic [WIDTH-1:0] q, + input var RESET_VAL=0); always_ff @(posedge clk, posedge reset) - if (reset) q <= #1 0; + if (reset) q <= #1 RESET_VAL; else if (clear) q <= #1 0; else q <= #1 d; diff --git a/wally-pipelined/src/ieu/regfile.sv b/wally-pipelined/src/ieu/regfile.sv index 73b62a579..8139e0b35 100644 --- a/wally-pipelined/src/ieu/regfile.sv +++ b/wally-pipelined/src/ieu/regfile.sv @@ -44,7 +44,13 @@ module regfile ( // reset is intended for simulation only, not synthesis always_ff @(negedge clk or posedge reset) - if (reset) for(i=1; i<32; i++) rf[i] <= 0; + if (reset) + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-regfile.txt"}, rf); + `else + for(i=1; i<32; i++) rf[i] <= 0; + `endif + else if (we3) rf[a3] <= wd3; assign #2 rd1 = (a1 != 0) ? rf[a1] : 0; diff --git a/wally-pipelined/src/privileged/csrc.sv b/wally-pipelined/src/privileged/csrc.sv index 3b1e544d7..da8aca05b 100644 --- a/wally-pipelined/src/privileged/csrc.sv +++ b/wally-pipelined/src/privileged/csrc.sv @@ -70,24 +70,24 @@ module csrc #(parameter // ... more counters //HPMCOUNTER31H = 12'hC9F ) ( - input logic clk, reset, - input logic StallD, StallE, StallM, StallW, + input logic clk, reset, + input logic StallD, StallE, StallM, StallW, input logic FlushD, FlushE, FlushM, FlushW, - input logic InstrValidM, LoadStallD, CSRMWriteM, - input logic BPPredDirWrongM, - input logic BTBPredPCWrongM, - input logic RASPredPCWrongM, - input logic BPPredClassNonCFIWrongM, - input logic [4:0] InstrClassM, - input logic DCacheMiss, - input logic DCacheAccess, - input logic [11:0] CSRAdrM, - input logic [1:0] PrivilegeModeW, + input logic InstrValidM, LoadStallD, CSRMWriteM, + input logic BPPredDirWrongM, + input logic BTBPredPCWrongM, + input logic RASPredPCWrongM, + input logic BPPredClassNonCFIWrongM, + input logic [4:0] InstrClassM, + input logic DCacheMiss, + input logic DCacheAccess, + input logic [11:0] CSRAdrM, + input logic [1:0] PrivilegeModeW, input logic [`XLEN-1:0] CSRWriteValM, - input logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW, - input logic [63:0] MTIME_CLINT, MTIMECMP_CLINT, + input logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW, + input logic [63:0] MTIME_CLINT, MTIMECMP_CLINT, output logic [`XLEN-1:0] CSRCReadValM, - output logic IllegalCSRCAccessM + output logic IllegalCSRCAccessM ); generate @@ -97,14 +97,22 @@ module csrc #(parameter logic [63:0] HPMCOUNTER3_REGW, HPMCOUNTER4_REGW; // add more performance counters here if desired logic [63:0] CYCLEPlusM, INSTRETPlusM; logic [63:0] HPMCOUNTER3PlusM, HPMCOUNTER4PlusM; - // logic [`XLEN-1:0] NextTIMEM; + // logic [`XLEN-1:0] NextTIMEM; logic [`XLEN-1:0] NextCYCLEM, NextINSTRETM; logic [`XLEN-1:0] NextHPMCOUNTER3M, NextHPMCOUNTER4M; logic WriteCYCLEM, WriteINSTRETM; logic WriteHPMCOUNTER3M, WriteHPMCOUNTER4M; logic [4:0] CounterNumM; logic [`COUNTERS-1:3][`XLEN-1:0] HPMCOUNTER_REGW, HPMCOUNTERH_REGW; - logic InstrValidNotFlushedM; + var [`COUNTERS-1:3][`XLEN-1:0] initHPMCOUNTER; + logic InstrValidNotFlushedM; + + initial + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-HPMCOUNTER.txt"}, initHPMCOUNTER); + `else + initHPMCOUNTER = {(`COUNTERS-3){`XLEN'b0}}; + `endif assign InstrValidNotFlushedM = InstrValidM & ~StallW & ~FlushW; @@ -130,121 +138,116 @@ module csrc #(parameter //assign NextHPMCOUNTER3M = WriteHPMCOUNTER3M ? CSRWriteValM : HPMCOUNTER3PlusM[`XLEN-1:0]; //assign NextHPMCOUNTER4M = WriteHPMCOUNTER4M ? CSRWriteValM : HPMCOUNTER4PlusM[`XLEN-1:0]; - // parameterized number of additional counters - if (`COUNTERS > 3) begin + // parameterized number of additional counters + if (`COUNTERS > 3) begin logic [`COUNTERS-1:3] WriteHPMCOUNTERM; logic [`COUNTERS-1:0] CounterEvent; logic [63:0] /*HPMCOUNTER_REGW[`COUNTERS-1:3], */ HPMCOUNTERPlusM[`COUNTERS-1:3]; logic [`XLEN-1:0] NextHPMCOUNTERM[`COUNTERS-1:3]; genvar i; - // could replace special counters 0-2 with this loop for all counters assign CounterEvent[0] = 1'b1; assign CounterEvent[1] = 1'b0; - if(`QEMU) begin - assign CounterEvent[`COUNTERS-1:2] = 0; - end else begin - - logic LoadStallE, LoadStallM; - - flopenrc #(1) LoadStallEReg(.clk, .reset, .clear(FlushE), .en(~StallE), .d(LoadStallD), .q(LoadStallE)); - flopenrc #(1) LoadStallMReg(.clk, .reset, .clear(FlushM), .en(~StallM), .d(LoadStallE), .q(LoadStallM)); - - assign CounterEvent[2] = InstrValidNotFlushedM; - assign CounterEvent[3] = LoadStallM & InstrValidNotFlushedM; - assign CounterEvent[4] = BPPredDirWrongM & InstrValidNotFlushedM; - assign CounterEvent[5] = InstrClassM[0] & InstrValidNotFlushedM; - assign CounterEvent[6] = BTBPredPCWrongM & InstrValidNotFlushedM; - assign CounterEvent[7] = (InstrClassM[4] | InstrClassM[2] | InstrClassM[1]) & InstrValidNotFlushedM; - assign CounterEvent[8] = RASPredPCWrongM & InstrValidNotFlushedM; - assign CounterEvent[9] = InstrClassM[3] & InstrValidNotFlushedM; - assign CounterEvent[10] = BPPredClassNonCFIWrongM & InstrValidNotFlushedM; - assign CounterEvent[11] = DCacheAccess & InstrValidNotFlushedM; - assign CounterEvent[12] = DCacheMiss & InstrValidNotFlushedM; - assign CounterEvent[`COUNTERS-1:13] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions - end - - for (i = 3; i < `COUNTERS; i = i+1) begin - assign WriteHPMCOUNTERM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERBASE + i); - assign NextHPMCOUNTERM[i][`XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][`XLEN-1:0]; - always @(posedge clk, posedge reset) // ModelSim doesn't like syntax of passing array element to flop - if (reset) HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 0; - else if (~StallW) HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERM[i]; - //flopr #(`XLEN) HPMCOUNTERreg[i](clk, reset, NextHPMCOUNTERM[i], HPMCOUNTER_REGW[i]); - - if (`XLEN==32) begin - logic [`COUNTERS-1:3] WriteHPMCOUNTERHM; - logic [`XLEN-1:0] NextHPMCOUNTERHM[`COUNTERS-1:3]; - assign HPMCOUNTERPlusM[i] = {HPMCOUNTERH_REGW[i], HPMCOUNTER_REGW[i]} + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]}; - assign WriteHPMCOUNTERHM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERHBASE + i); - assign NextHPMCOUNTERHM[i] = WriteHPMCOUNTERHM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][63:32]; - always @(posedge clk, posedge reset) // ModelSim doesn't like syntax of passing array element to flop - if (reset) HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 0; - else if (~StallW) HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERHM[i]; - //flopr #(`XLEN) HPMCOUNTERHreg[i](clk, reset, NextHPMCOUNTERHM[i], HPMCOUNTER_REGW[i][63:32]); - end else begin - assign HPMCOUNTERPlusM[i] = HPMCOUNTER_REGW[i] + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]}; - end + if(`QEMU) assign CounterEvent[`COUNTERS-1:2] = 0; + else begin + logic LoadStallE, LoadStallM; + flopenrc #(1) LoadStallEReg(.clk, .reset, .clear(FlushE), .en(~StallE), .d(LoadStallD), .q(LoadStallE)); + flopenrc #(1) LoadStallMReg(.clk, .reset, .clear(FlushM), .en(~StallM), .d(LoadStallE), .q(LoadStallM)); + + assign CounterEvent[2] = InstrValidNotFlushedM; + assign CounterEvent[3] = LoadStallM & InstrValidNotFlushedM; + assign CounterEvent[4] = BPPredDirWrongM & InstrValidNotFlushedM; + assign CounterEvent[5] = InstrClassM[0] & InstrValidNotFlushedM; + assign CounterEvent[6] = BTBPredPCWrongM & InstrValidNotFlushedM; + assign CounterEvent[7] = (InstrClassM[4] | InstrClassM[2] | InstrClassM[1]) & InstrValidNotFlushedM; + assign CounterEvent[8] = RASPredPCWrongM & InstrValidNotFlushedM; + assign CounterEvent[9] = InstrClassM[3] & InstrValidNotFlushedM; + assign CounterEvent[10] = BPPredClassNonCFIWrongM & InstrValidNotFlushedM; + assign CounterEvent[11] = DCacheAccess & InstrValidNotFlushedM; + assign CounterEvent[12] = DCacheMiss & InstrValidNotFlushedM; + assign CounterEvent[`COUNTERS-1:13] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions end - end + + for (i = 3; i < `COUNTERS; i = i+1) begin + assign WriteHPMCOUNTERM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERBASE + i); + assign NextHPMCOUNTERM[i][`XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][`XLEN-1:0]; + always @(posedge clk, posedge reset) // ModelSim doesn't like syntax of passing array element to flop + if (reset) HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 initHPMCOUNTER[i]; + else if (~StallW) HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERM[i]; + //flopr #(`XLEN) HPMCOUNTERreg[i](clk, reset, NextHPMCOUNTERM[i], HPMCOUNTER_REGW[i]); + + if (`XLEN==32) begin + logic [`COUNTERS-1:3] WriteHPMCOUNTERHM; + logic [`XLEN-1:0] NextHPMCOUNTERHM[`COUNTERS-1:3]; + assign HPMCOUNTERPlusM[i] = {HPMCOUNTERH_REGW[i], HPMCOUNTER_REGW[i]} + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]}; + assign WriteHPMCOUNTERHM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERHBASE + i); + assign NextHPMCOUNTERHM[i] = WriteHPMCOUNTERHM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][63:32]; + always @(posedge clk, posedge reset) // ModelSim doesn't like syntax of passing array element to flop + if (reset) HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 0; + else if (~StallW) HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERHM[i]; + //flopr #(`XLEN) HPMCOUNTERHreg[i](clk, reset, NextHPMCOUNTERHM[i], HPMCOUNTER_REGW[i][63:32]); + end else begin + assign HPMCOUNTERPlusM[i] = HPMCOUNTER_REGW[i] + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]}; + end + end + end // Write / update counters // Only the Machine mode versions of the counter CSRs are writable - if (`XLEN==64) begin// 64-bit counters - // flopr #(64) TIMEreg(clk, reset, WriteTIMEM ? CSRWriteValM : TIME_REGW + 1, TIME_REGW); // may count off a different clock*** - // flopenr #(64) TIMECMPreg(clk, reset, WriteTIMECMPM, CSRWriteValM, TIMECMP_REGW); - flopr #(64) CYCLEreg(clk, reset, NextCYCLEM, CYCLE_REGW); - flopr #(64) INSTRETreg(clk, reset, NextINSTRETM, INSTRET_REGW); - //flopr #(64) HPMCOUNTER3reg(clk, reset, NextHPMCOUNTER3M, HPMCOUNTER3_REGW); - //flopr #(64) HPMCOUNTER4reg(clk, reset, NextHPMCOUNTER4M, HPMCOUNTER4_REGW); - end else begin // 32-bit low and high counters - logic WriteTIMEHM, WriteTIMECMPHM, WriteCYCLEHM, WriteINSTRETHM; - //logic WriteHPMCOUNTER3HM, WriteHPMCOUNTER4HM; - logic [`XLEN-1:0] NextCYCLEHM, NextTIMEHM, NextINSTRETHM; - //logic [`XLEN-1:0] NextHPMCOUNTER3HM, NextHPMCOUNTER4HM; + if (`XLEN==64) begin// 64-bit counters + // flopr #(64) TIMEreg(clk, reset, WriteTIMEM ? CSRWriteValM : TIME_REGW + 1, TIME_REGW); // may count off a different clock*** + // flopenr #(64) TIMECMPreg(clk, reset, WriteTIMECMPM, CSRWriteValM, TIMECMP_REGW); + flopr #(64) CYCLEreg(clk, reset, NextCYCLEM, CYCLE_REGW); + flopr #(64) INSTRETreg(clk, reset, NextINSTRETM, INSTRET_REGW); + //flopr #(64) HPMCOUNTER3reg(clk, reset, NextHPMCOUNTER3M, HPMCOUNTER3_REGW); + //flopr #(64) HPMCOUNTER4reg(clk, reset, NextHPMCOUNTER4M, HPMCOUNTER4_REGW); + end else begin // 32-bit low and high counters + logic WriteTIMEHM, WriteTIMECMPHM, WriteCYCLEHM, WriteINSTRETHM; + //logic WriteHPMCOUNTER3HM, WriteHPMCOUNTER4HM; + logic [`XLEN-1:0] NextCYCLEHM, NextTIMEHM, NextINSTRETHM; + //logic [`XLEN-1:0] NextHPMCOUNTER3HM, NextHPMCOUNTER4HM; - // Write Enables - // assign WriteTIMEHM = CSRMWriteM && (CSRAdrM == MTIMEH); - // assign WriteTIMECMPHM = CSRMWriteM && (CSRAdrM == MTIMECMPH); - assign WriteCYCLEHM = CSRMWriteM && (CSRAdrM == MCYCLEH); - assign WriteINSTRETHM = CSRMWriteM && (CSRAdrM == MINSTRETH); - //assign WriteHPMCOUNTER3HM = CSRMWriteM && (CSRAdrM == MHPMCOUNTER3H); - //assign WriteHPMCOUNTER4HM = CSRMWriteM && (CSRAdrM == MHPMCOUNTER4H); - assign NextCYCLEHM = WriteCYCLEM ? CSRWriteValM : CYCLEPlusM[63:32]; - // assign NextTIMEHM = WriteTIMEHM ? CSRWriteValM : TIMEPlusM[63:32]; - assign NextINSTRETHM = WriteINSTRETHM ? CSRWriteValM : INSTRETPlusM[63:32]; - //assign NextHPMCOUNTER3HM = WriteHPMCOUNTER3HM ? CSRWriteValM : HPMCOUNTER3PlusM[63:32]; - //assign NextHPMCOUNTER4HM = WriteHPMCOUNTER4HM ? CSRWriteValM : HPMCOUNTER4PlusM[63:32]; + // Write Enables + // assign WriteTIMEHM = CSRMWriteM && (CSRAdrM == MTIMEH); + // assign WriteTIMECMPHM = CSRMWriteM && (CSRAdrM == MTIMECMPH); + assign WriteCYCLEHM = CSRMWriteM && (CSRAdrM == MCYCLEH); + assign WriteINSTRETHM = CSRMWriteM && (CSRAdrM == MINSTRETH); + //assign WriteHPMCOUNTER3HM = CSRMWriteM && (CSRAdrM == MHPMCOUNTER3H); + //assign WriteHPMCOUNTER4HM = CSRMWriteM && (CSRAdrM == MHPMCOUNTER4H); + assign NextCYCLEHM = WriteCYCLEM ? CSRWriteValM : CYCLEPlusM[63:32]; + // assign NextTIMEHM = WriteTIMEHM ? CSRWriteValM : TIMEPlusM[63:32]; + assign NextINSTRETHM = WriteINSTRETHM ? CSRWriteValM : INSTRETPlusM[63:32]; + //assign NextHPMCOUNTER3HM = WriteHPMCOUNTER3HM ? CSRWriteValM : HPMCOUNTER3PlusM[63:32]; + //assign NextHPMCOUNTER4HM = WriteHPMCOUNTER4HM ? CSRWriteValM : HPMCOUNTER4PlusM[63:32]; - // Counter CSRs - // flopr #(32) TIMEreg(clk, reset, NextTIMEM, TIME_REGW); // may count off a different clock*** - // flopenr #(32) TIMECMPreg(clk, reset, WriteTIMECMPM, CSRWriteValM, TIMECMP_REGW[31:0]); - flopr #(32) CYCLEreg(clk, reset, NextCYCLEM, CYCLE_REGW[31:0]); - flopr #(32) INSTRETreg(clk, reset, NextINSTRETM, INSTRET_REGW[31:0]); - //flopr #(32) HPMCOUNTER3reg(clk, reset, NextHPMCOUNTER3M, HPMCOUNTER3_REGW[31:0]); - //flopr #(32) HPMCOUNTER4reg(clk, reset, NextHPMCOUNTER4M, HPMCOUNTER4_REGW[31:0]); - // flopr #(32) TIMEHreg(clk, reset, NextTIMEHM, TIME_REGW); // may count off a different clock*** - // flopenr #(32) TIMECMPHreg(clk, reset, WriteTIMECMPHM, CSRWriteValM, TIMECMP_REGW[63:32]); - flopr #(32) CYCLEHreg(clk, reset, NextCYCLEHM, CYCLE_REGW[63:32]); - flopr #(32) INSTRETHreg(clk, reset, NextINSTRETHM, INSTRET_REGW[63:32]); - //flopr #(32) HPMCOUNTER3Hreg(clk, reset, NextHPMCOUNTER3HM, HPMCOUNTER3_REGW[63:32]); - //flopr #(32) HPMCOUNTER4Hreg(clk, reset, NextHPMCOUNTER4HM, HPMCOUNTER4_REGW[63:32]); - end + // Counter CSRs + // flopr #(32) TIMEreg(clk, reset, NextTIMEM, TIME_REGW); // may count off a different clock*** + // flopenr #(32) TIMECMPreg(clk, reset, WriteTIMECMPM, CSRWriteValM, TIMECMP_REGW[31:0]); + flopr #(32) CYCLEreg(clk, reset, NextCYCLEM, CYCLE_REGW[31:0]); + flopr #(32) INSTRETreg(clk, reset, NextINSTRETM, INSTRET_REGW[31:0]); + // flopr #(32) HPMCOUNTER3reg(clk, reset, NextHPMCOUNTER3M, HPMCOUNTER3_REGW[31:0]); + // flopr #(32) HPMCOUNTER4reg(clk, reset, NextHPMCOUNTER4M, HPMCOUNTER4_REGW[31:0]); + // flopr #(32) TIMEHreg(clk, reset, NextTIMEHM, TIME_REGW); // may count off a different clock*** + // flopenr #(32) TIMECMPHreg(clk, reset, WriteTIMECMPHM, CSRWriteValM, TIMECMP_REGW[63:32]); + flopr #(32) CYCLEHreg(clk, reset, NextCYCLEHM, CYCLE_REGW[63:32]); + flopr #(32) INSTRETHreg(clk, reset, NextINSTRETHM, INSTRET_REGW[63:32]); + //flopr #(32) HPMCOUNTER3Hreg(clk, reset, NextHPMCOUNTER3HM, HPMCOUNTER3_REGW[63:32]); + //flopr #(32) HPMCOUNTER4Hreg(clk, reset, NextHPMCOUNTER4HM, HPMCOUNTER4_REGW[63:32]); + end - // eventually move TIME and TIMECMP to the CLINT -- Ben 06/17/21: sure let's give that a shot! - // run TIME off asynchronous reference clock - // synchronize write enable to TIME - // four phase handshake to synchronize reads from TIME + // eventually move TIME and TIMECMP to the CLINT -- Ben 06/17/21: sure let's give that a shot! + // run TIME off asynchronous reference clock + // synchronize write enable to TIME + // four phase handshake to synchronize reads from TIME - // interrupt on timer compare - // ability to disable optional CSRs + // interrupt on timer compare + // ability to disable optional CSRs // Read Counters, or cause excepiton if insufficient privilege in light of COUNTEREN flags assign CounterNumM = CSRAdrM[4:0]; // which counter to read? if (`XLEN==64) // 64-bit counter reads always_comb - if (PrivilegeModeW == `M_MODE || - MCOUNTEREN_REGW[CounterNumM] && (PrivilegeModeW == `S_MODE || SCOUNTEREN_REGW[CounterNumM])) begin + if (PrivilegeModeW == `M_MODE || MCOUNTEREN_REGW[CounterNumM] && (PrivilegeModeW == `S_MODE || SCOUNTEREN_REGW[CounterNumM])) begin IllegalCSRCAccessM = 0; if (CSRAdrM >= MHPMCOUNTERBASE+3 && CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CSRAdrM-MHPMCOUNTERBASE]; else if (CSRAdrM >= HPMCOUNTERBASE+3 && CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CSRAdrM-HPMCOUNTERBASE]; @@ -309,7 +312,7 @@ module csrc #(parameter IllegalCSRCAccessM = 1; // no privileges for this csr CSRCReadValM = 0; end - end else begin + end else begin // not `ZICOUNTERS_SUPPORTED assign CSRCReadValM = 0; assign IllegalCSRCAccessM = 1; end @@ -356,20 +359,20 @@ module csrc #(parameter MPHMEVENTBASE = 12'h320, HPMCOUNTERBASE = 12'hC00, HPMCOUNTERHBASE = 12'hC80, - )(input logic clk, reset, - input logic StallD, StallE, StallM, StallW, - input logic InstrValidM, LoadStallD, CSRMWriteM, - input logic BPPredDirWrongM, - input logic BTBPredPCWrongM, - input logic RASPredPCWrongM, - input logic BPPredClassNonCFIWrongM, - input logic [4:0] InstrClassM, - input logic [11:0] CSRAdrM, - input logic [1:0] PrivilegeModeW, + )(input logic clk, reset, + input logic StallD, StallE, StallM, StallW, + input logic InstrValidM, LoadStallD, CSRMWriteM, + input logic BPPredDirWrongM, + input logic BTBPredPCWrongM, + input logic RASPredPCWrongM, + input logic BPPredClassNonCFIWrongM, + input logic [4:0] InstrClassM, + input logic [11:0] CSRAdrM, + input logic [1:0] PrivilegeModeW, input logic [`XLEN-1:0] CSRWriteValM, - input logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW, + input logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW, output logic [`XLEN-1:0] CSRCReadValM, - output logic IllegalCSRCAccessM); + output logic IllegalCSRCAccessM); // counters diff --git a/wally-pipelined/src/privileged/csri.sv b/wally-pipelined/src/privileged/csri.sv index 3b54d871a..7ef9051f7 100644 --- a/wally-pipelined/src/privileged/csri.sv +++ b/wally-pipelined/src/privileged/csri.sv @@ -79,14 +79,24 @@ module csri #(parameter assign SIP_WRITE_MASK = 12'h000; end always @(posedge clk, posedge reset) begin // *** I strongly feel that IntInM should go directly to IP_REGW -- Ben 9/7/21 - if (reset) IP_REGW_writeable <= 10'b0; + if (reset) + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MIP.txt"}, IP_REGW_writeable); + `else + IP_REGW_writeable <= 10'b0; + `endif else if (WriteMIPM) IP_REGW_writeable <= (CSRWriteValM[9:0] & MIP_WRITE_MASK[9:0]) | IntInM[9:0]; // MTIP unclearable else if (WriteSIPM) IP_REGW_writeable <= (CSRWriteValM[9:0] & SIP_WRITE_MASK[9:0]) | IntInM[9:0]; // MTIP unclearable // else if (WriteUIPM) IP_REGW = (CSRWriteValM & 12'hBBB) | (NextIPM & 12'h080); // MTIP unclearable else IP_REGW_writeable <= IP_REGW_writeable | IntInM[9:0]; // *** check this turns off interrupts properly even when MIDELEG changes end always @(posedge clk, posedge reset) begin - if (reset) IE_REGW <= 12'b0; + if (reset) + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MIE.txt"}, IE_REGW); + `else + IE_REGW <= 12'b0; + `endif else if (WriteMIEM) IE_REGW <= (CSRWriteValM[11:0] & 12'hAAA); // MIE controls M and S fields else if (WriteSIEM) IE_REGW <= (CSRWriteValM[11:0] & 12'h222) | (IE_REGW & 12'h888); // only S fields // else if (WriteUIEM) IE_REGW = (CSRWriteValM & 12'h111) | (IE_REGW & 12'hAAA); // only U field diff --git a/wally-pipelined/src/privileged/csrm.sv b/wally-pipelined/src/privileged/csrm.sv index a3baaaec4..f3f5d631b 100644 --- a/wally-pipelined/src/privileged/csrm.sv +++ b/wally-pipelined/src/privileged/csrm.sv @@ -85,15 +85,45 @@ module csrm #(parameter logic [`XLEN-1:0] MISA_REGW, MHARTID_REGW; logic [`XLEN-1:0] MSCRATCH_REGW, MCAUSE_REGW, MTVAL_REGW; - logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM; - logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM; - logic WriteMCOUNTERENM, WriteMCOUNTINHIBITM; + var [`XLEN-1:0] initMSCRATCH, initMCAUSE, initMEPC, initMTVEC, initMEDELEG, initMIDELEG; + var [31:0] initMCOUNTEREN, initMCOUNTINHIBIT; + var [`PMP_ENTRIES-1:0][7:0] initPMPCFG_ARRAY; + var [`PMP_ENTRIES-1:0][`XLEN-1:0] initPMPADDR_ARRAY; + + logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM; + logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM; + logic WriteMCOUNTERENM, WriteMCOUNTINHIBITM; logic [`PMP_ENTRIES-1:0] WritePMPCFGM; logic [`PMP_ENTRIES-1:0] WritePMPADDRM ; logic [`PMP_ENTRIES-1:0] ADDRLocked, CFGLocked; localparam MISA_26 = (`MISA) & 32'h03ffffff; + initial begin + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MSCRATCH.txt"}, initMSCRATCH); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MCAUSE.txt"}, initMCAUSE); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MEPC.txt"}, initMEPC); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MTVEC.txt"}, initMTVEC); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MEDELEG.txt"}, initMEDELEG); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MIDELEG.txt"}, initMIDELEG); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MCOUNTEREN.txt"}, initMCOUNTEREN); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-PMPCFG.txt"}, initPMPCFG_ARRAY); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-PMPADDR.txt"}, initPMPADDR_ARRAY); + `else + initMSCRATCH = `XLEN'b0; + initMCAUSE = `XLEN'b0; + initMEPC = `XLEN'b0; + initMTVEC = `XLEN'b0; + initMEDELEG = `XLEN'b0; + initMIDELEG = `XLEN'b0; + initMCOUNTEREN = 32'b0; + initMCOUNTINHIBIT = 32'b0; + initPMPCFG_ARRAY = {`PMP_ENTRIES{8'b0}}; + initPMPADDR_ARRAY = {`PMP_ENTRIES{`XLEN'b0}}; + `endif + end + // MISA is hardwired. Spec says it could be written to disable features, but this is not supported by Wally assign MISA_REGW = {(`XLEN == 32 ? 2'b01 : 2'b10), {(`XLEN-28){1'b0}}, MISA_26[25:0]}; @@ -115,33 +145,31 @@ module csrm #(parameter assign IllegalCSRMWriteReadonlyM = CSRMWriteM && (CSRAdrM == MVENDORID || CSRAdrM == MARCHID || CSRAdrM == MIMPID || CSRAdrM == MHARTID); // CSRs - flopenl #(`XLEN) MTVECreg(clk, reset, WriteMTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, `XLEN'b0, MTVEC_REGW); //busybear: changed reset value to 0 + flopenl #(`XLEN) MTVECreg(clk, reset, WriteMTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, initMTVEC, MTVEC_REGW); //busybear: changed reset value to 0 generate if (`S_SUPPORTED | (`U_SUPPORTED & `N_SUPPORTED)) begin // DELEG registers should exist - flopenl #(`XLEN) MEDELEGreg(clk, reset, WriteMEDELEGM, CSRWriteValM & MEDELEG_MASK /*12'h7FF*/, `XLEN'b0, MEDELEG_REGW); - flopenl #(`XLEN) MIDELEGreg(clk, reset, WriteMIDELEGM, CSRWriteValM & MIDELEG_MASK /*12'h222*/, `XLEN'b0, MIDELEG_REGW); + flopenl #(`XLEN) MEDELEGreg(clk, reset, WriteMEDELEGM, CSRWriteValM & MEDELEG_MASK /*12'h7FF*/, initMEDELEG, MEDELEG_REGW); + flopenl #(`XLEN) MIDELEGreg(clk, reset, WriteMIDELEGM, CSRWriteValM & MIDELEG_MASK /*12'h222*/, initMIDELEG, MIDELEG_REGW); end else begin assign MEDELEG_REGW = 0; assign MIDELEG_REGW = 0; end endgenerate -// flopenl #(`XLEN) MIPreg(clk, reset, WriteMIPM, CSRWriteValM, zero, MIP_REGW); -// flopenl #(`XLEN) MIEreg(clk, reset, WriteMIEM, CSRWriteValM, zero, MIE_REGW); - flopenr #(`XLEN) MSCRATCHreg(clk, reset, WriteMSCRATCHM, CSRWriteValM, MSCRATCH_REGW); - flopenr #(`XLEN) MEPCreg(clk, reset, WriteMEPCM, NextEPCM, MEPC_REGW); - flopenr #(`XLEN) MCAUSEreg(clk, reset, WriteMCAUSEM, NextCauseM, MCAUSE_REGW); + flopenr #(`XLEN) MSCRATCHreg(clk, reset, WriteMSCRATCHM, CSRWriteValM, MSCRATCH_REGW, initMSCRATCH); + flopenr #(`XLEN) MEPCreg(clk, reset, WriteMEPCM, NextEPCM, MEPC_REGW, initMEPC); + flopenr #(`XLEN) MCAUSEreg(clk, reset, WriteMCAUSEM, NextCauseM, MCAUSE_REGW, initMCAUSE); if(`QEMU) assign MTVAL_REGW = `XLEN'b0; else flopenr #(`XLEN) MTVALreg(clk, reset, WriteMTVALM, NextMtvalM, MTVAL_REGW); generate if (`BUSYBEAR == 1) flopenl #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, {CSRWriteValM[31:2],1'b0,CSRWriteValM[0]}, 32'b0, MCOUNTEREN_REGW); else if (`BUILDROOT == 1) - flopenl #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, CSRWriteValM[31:0], 32'h0, MCOUNTEREN_REGW); + flopenl #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, CSRWriteValM[31:0], initMCOUNTEREN, MCOUNTEREN_REGW); else flopenl #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, CSRWriteValM[31:0], 32'hFFFFFFFF, MCOUNTEREN_REGW); endgenerate - flopenl #(32) MCOUNTINHIBITreg(clk, reset, WriteMCOUNTINHIBITM, CSRWriteValM[31:0], 32'h0, MCOUNTINHIBIT_REGW); + flopenl #(32) MCOUNTINHIBITreg(clk, reset, WriteMCOUNTINHIBITM, CSRWriteValM[31:0], initMCOUNTINHIBIT, MCOUNTINHIBIT_REGW); // There are PMP_ENTRIES = 0, 16, or 64 PMPADDR registers, each of which has its own flop @@ -158,14 +186,14 @@ module csrm #(parameter assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7] | (PMPCFG_ARRAY_REGW[i+1][7] & PMPCFG_ARRAY_REGW[i+1][4:3] == 2'b01); assign WritePMPADDRM[i] = (CSRMWriteM & (CSRAdrM == (PMPADDR0+i))) & ~StallW & ~ADDRLocked[i]; - flopenr #(`XLEN) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM, PMPADDR_ARRAY_REGW[i]); + flopenr #(`XLEN) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM, PMPADDR_ARRAY_REGW[i], initPMPADDR_ARRAY[i]); if (`XLEN==64) begin assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+2*(i/8)))) & ~StallW & ~CFGLocked[i]; - flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i]); + flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i], initPMPCFG_ARRAY[i]); end else begin assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+i/4))) & ~StallW & ~CFGLocked[i]; // assign WritePMPCFGHM[i] = (CSRMWriteM && (CSRAdrM == PMPCFG0+2*i+1)) && ~StallW; - flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%4)*8+7:(i%4)*8], PMPCFG_ARRAY_REGW[i]); + flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%4)*8+7:(i%4)*8], PMPCFG_ARRAY_REGW[i], initPMPCFG_ARRAY[i]); // flopenr #(`XLEN) PMPCFGHreg(clk, reset, WritePMPCFGHM[i], CSRWriteValM, PMPCFG_ARRAY_REGW[i][63:32]); end end diff --git a/wally-pipelined/src/privileged/csrs.sv b/wally-pipelined/src/privileged/csrs.sv index f3c9a4f94..2fffbced2 100644 --- a/wally-pipelined/src/privileged/csrs.sv +++ b/wally-pipelined/src/privileged/csrs.sv @@ -74,6 +74,30 @@ module csrs #(parameter logic WriteSSCRATCHM, WriteSEPCM; logic WriteSCAUSEM, WriteSTVALM, WriteSATPM, WriteSCOUNTERENM; logic [`XLEN-1:0] SSCRATCH_REGW, SCAUSE_REGW, STVAL_REGW; + var [`XLEN-1:0] initSSCRATCH, initSCAUSE, initSEPC, initSTVEC, initSEDELEG, initSIDELEG, initSATP; + var [31:0] initSCOUNTEREN; + + initial begin + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SSCRATCH.txt"}, initSSCRATCH); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SCAUSE.txt"}, initSCAUSE); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SEPC.txt"}, initSEPC); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-STVEC.txt"}, initSTVEC); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SEDELEG.txt"}, initSEDELEG); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SIDELEG.txt"}, initSIDELEG); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SCOUNTEREN.txt"}, initSCOUNTEREN); + $readmemh({`LINUX_CHECKPOINT,"checkpoint-SATP.txt"}, initSATP); + `else + initSSCRATCH = `XLEN'b0; + initSCAUSE = `XLEN'b0; + initSEPC = `XLEN'b0; + initSTVEC = `XLEN'b0; + initSEDELEG = `XLEN'b0; + initSIDELEG = `XLEN'b0; + initSCOUNTEREN = 32'b0; + initSATP = `XLEN'b0; + `endif + end assign WriteSSTATUSM = CSRSWriteM && (CSRAdrM == SSTATUS) && ~StallW; assign WriteSTVECM = CSRSWriteM && (CSRAdrM == STVEC) && ~StallW; @@ -85,28 +109,28 @@ module csrs #(parameter assign WriteSCOUNTERENM = CSRSWriteM && (CSRAdrM == SCOUNTEREN) && ~StallW; // CSRs - flopenl #(`XLEN) STVECreg(clk, reset, WriteSTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, `XLEN'b0, STVEC_REGW); //busybear: change reset to 0 - flopenr #(`XLEN) SSCRATCHreg(clk, reset, WriteSSCRATCHM, CSRWriteValM, SSCRATCH_REGW); - flopenr #(`XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW); - flopenl #(`XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, NextCauseM, `XLEN'b0, SCAUSE_REGW); + flopenl #(`XLEN) STVECreg(clk, reset, WriteSTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, initSTVEC, STVEC_REGW); //busybear: change reset to 0 + flopenr #(`XLEN) SSCRATCHreg(clk, reset, WriteSSCRATCHM, CSRWriteValM, SSCRATCH_REGW, initSSCRATCH); + flopenr #(`XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW, initSEPC); + flopenl #(`XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, NextCauseM, initSCAUSE, SCAUSE_REGW); if(`QEMU) assign STVAL_REGW = `XLEN'b0; else flopenr #(`XLEN) STVALreg(clk, reset, WriteSTVALM, NextMtvalM, STVAL_REGW); if (`MEM_VIRTMEM) - flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW); + flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW, initSATP); else assign SATP_REGW = 0; // hardwire to zero if virtual memory not supported if (`BUSYBEAR == 1) flopenl #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, {CSRWriteValM[31:2],1'b0,CSRWriteValM[0]}, 32'b0, SCOUNTEREN_REGW); else if (`BUILDROOT == 1) - flopenl #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], 32'h0, SCOUNTEREN_REGW); + flopenl #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], initSCOUNTEREN, SCOUNTEREN_REGW); else flopenl #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], 32'hFFFFFFFF, SCOUNTEREN_REGW); if (`N_SUPPORTED) begin logic WriteSEDELEGM, WriteSIDELEGM; assign WriteSEDELEGM = CSRSWriteM && (CSRAdrM == SEDELEG); assign WriteSIDELEGM = CSRSWriteM && (CSRAdrM == SIDELEG); - flopenl #(`XLEN) SEDELEGreg(clk, reset, WriteSEDELEGM, CSRWriteValM & SEDELEG_MASK /* 12'h1FF */, `XLEN'b0, SEDELEG_REGW); - flopenl #(`XLEN) SIDELEGreg(clk, reset, WriteSIDELEGM, CSRWriteValM, `XLEN'b0, SIDELEG_REGW); + flopenl #(`XLEN) SEDELEGreg(clk, reset, WriteSEDELEGM, CSRWriteValM & SEDELEG_MASK /* 12'h1FF */, initSEDELEG, SEDELEG_REGW); + flopenl #(`XLEN) SIDELEGreg(clk, reset, WriteSIDELEGM, CSRWriteValM, initSIDELEG, SIDELEG_REGW); end else begin assign SEDELEG_REGW = 0; assign SIDELEG_REGW = 0; diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index dfa2132d9..113515b26 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -46,6 +46,15 @@ module csrsr ( logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT; logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE; + var [`XLEN-1:0] initMSTATUS; + initial begin + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"checkpoint-MSTATUS.txt"}, initMSTATUS); + `else + initMSTATUS = `XLEN'b0; + `endif + end + // STATUS REGISTER FIELD // See Privileged Spec Section 3.1.6 // Lower privilege status registers are a subset of the full status register @@ -108,23 +117,33 @@ module csrsr ( // registers for STATUS bits // complex register with reset, write enable, and the ability to update other bits in certain cases + // these null things are needed to make the following LHS assignment legal; this is probably a crappy way of doing things always_ff @(posedge clk, posedge reset) if (reset) begin - STATUS_TSR_INT <= #1 0; - STATUS_TW_INT <= #1 0; - STATUS_TVM_INT <= #1 0; - STATUS_MXR_INT <= #1 0; - STATUS_SUM_INT <= #1 0; - STATUS_MPRV_INT <= #1 0; // Per Priv 3.3 - STATUS_FS_INT <= #1 0; //2'b01; // busybear: change all these reset values to 0 - STATUS_MPP <= #1 0; //`M_MODE; - STATUS_SPP <= #1 0; //1'b1; - STATUS_MPIE <= #1 0; //1; - STATUS_SPIE <= #1 0; //`S_SUPPORTED; - STATUS_UPIE <= #1 0; // `U_SUPPORTED; - STATUS_MIE <= #1 0; // Per Priv 3.3 - STATUS_SIE <= #1 0; //`S_SUPPORTED; - STATUS_UIE <= #1 0; //`U_SUPPORTED; + //STATUS_TSR_INT <= #1 0; + //STATUS_TW_INT <= #1 0; + //STATUS_TVM_INT <= #1 0; + //STATUS_MXR_INT <= #1 0; + //STATUS_SUM_INT <= #1 0; + //STATUS_MPRV_INT <= #1 0; // Per Priv 3.3 + //STATUS_FS_INT <= #1 0; //2'b01; // busybear: change all these reset values to 0 + //STATUS_MPP <= #1 0; //`M_MODE; + //STATUS_SPP <= #1 0; //1'b1; + //STATUS_MPIE <= #1 0; //1; + //STATUS_SPIE <= #1 0; //`S_SUPPORTED; + //STATUS_UPIE <= #1 0; // `U_SUPPORTED; + //STATUS_MIE <= #1 0; // Per Priv 3.3 + //STATUS_SIE <= #1 0; //`S_SUPPORTED; + //STATUS_UIE <= #1 0; //`U_SUPPORTED; + // + // *** this assumes XLEN == 64. + // I don't like using generates to respond to XLEN. + // I'd rather have an XLEN64 so that we could use `ifdefs -- Ben 9/21 + {STATUS_TSR_INT,STATUS_TW_INT,STATUS_TVM_INT,STATUS_MXR_INT,STATUS_SUM_INT,STATUS_MPRV_INT} <= #1 initMSTATUS[22:17]; + {STATUS_FS_INT,STATUS_MPP} <= #1 initMSTATUS[14:11]; + {STATUS_SPP,STATUS_MPIE} <= #1 initMSTATUS[8:7]; + {STATUS_SPIE,STATUS_UPIE,STATUS_MIE} <= #1 initMSTATUS[5:3]; + {STATUS_SIE,STATUS_UIE} <= #1 initMSTATUS[1:0]; end else if (~StallW) begin if (FRegWriteM | WriteFRMM | WriteFFLAGSM) STATUS_FS_INT <= #12'b11; // mark Float State dirty *** this should happen in M stage, be part of if/else; diff --git a/wally-pipelined/testbench/testbench-linux.sv b/wally-pipelined/testbench/testbench-linux.sv index 64bd24e70..7dbed0e09 100644 --- a/wally-pipelined/testbench/testbench-linux.sv +++ b/wally-pipelined/testbench/testbench-linux.sv @@ -21,24 +21,33 @@ // 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. + +// When letting Wally go for it, let wally generate own interrupts /////////////////////////////////////////// `include "wally-config.vh" +//`define CHECKPOINT +`define LINUX_CHECKPOINT "../linux-testgen/linux-testvectors/checkpoint1K" + `define DEBUG_TRACE 0 -`define DontHaltOnCSRMisMatch 1 +// Debug Levels +// 0: don't check against QEMU +// 1: print disagreements with QEMU, but only halt on PCW disagreements +// 2: halt on any disagreement with QEMU except CSRs +// 3: halt on all disagreements with QEMU +// 4: print memory accesses whenever they happen +// 5: print everything module testbench(); - parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*6779000; // # of instructions at which to turn on waves in graphical sim - + parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*8700000; // # of instructions at which to turn on waves in graphical sim string ProgramAddrMapFile, ProgramLabelMapFile; /////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// DUT ///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// logic clk, reset; - logic [`AHBW-1:0] readDataExpected; logic [31:0] HADDR; logic [`AHBW-1:0] HWDATA; @@ -51,7 +60,6 @@ module testbench(); logic HCLK, HRESETn; logic [`AHBW-1:0] HRDATAEXT; logic HREADYEXT, HRESPEXT; - logic [31:0] GPIOPinsIn; logic [31:0] GPIOPinsOut, GPIOPinsEn; logic UARTSin, UARTSout; @@ -73,9 +81,11 @@ module testbench(); // Testbench Core integer warningCount = 0; integer errorCount = 0; + integer MIPexpected; // P, Instr Checking logic [`XLEN-1:0] PCW; integer data_file_all; + string name; // Write Back stage signals needed for trace compare, but don't actually // exist in CPU. @@ -85,7 +95,6 @@ module testbench(); logic checkInstrW; //integer RegAdr; - integer fault; logic TrapW; @@ -129,17 +138,27 @@ module testbench(); logic forcedInterrupt; integer NumCSRMIndex; integer NumCSRWIndex; - integer NumCSRPostWIndex; -// logic CurrentInterruptForce; + integer NumCSRPostWIndex; logic [`XLEN-1:0] InstrCountW; - // ----------- - // Error Macro - // ----------- - `define ERROR \ - errorCount +=1; \ - $display("processed %0d instructions with %0d warnings", InstrCountW, warningCount); \ - $stop; + // ------ + // Macros + // ------ + + `define CSRwarn(CSR) \ + begin \ + $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], CSR, ExpectedCSRArrayValueW[NumCSRPostWIndex]); \ + if (CSR != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin \ + $display("%tns, %d instrs: CSR %s = %016x, does not equal expected value %016x", $time, InstrCountW, ExpectedCSRArrayW[NumCSRPostWIndex], CSR, ExpectedCSRArrayValueW[NumCSRPostWIndex]); \ + if(`DEBUG_TRACE >= 3) fault = 1; \ + end \ + end + + `define checkEQ(NAME, VAL, EXPECTED) \ + if(VAL != EXPECTED) begin \ + $display("%tns, %d instrs: %s %x differs from expected %x", $time, InstrCountW, NAME, VAL, EXPECTED); \ + if ((NAME == "PCW") || (`DEBUG_TRACE >= 2)) fault = 1; \ + end initial begin data_file_all = $fopen({`LINUX_TEST_VECTORS,"all.txt"}, "r"); @@ -149,16 +168,11 @@ module testbench(); force dut.hart.priv.ExtIntM = 0; end -/* -----\/----- EXCLUDED -----\/----- - initial begin - CurrentInterruptForce = 1'b0; - end - -----/\----- EXCLUDED -----/\----- */ assign checkInstrM = dut.hart.ieu.InstrValidM & ~dut.hart.priv.trap.InstrPageFaultM & ~dut.hart.priv.trap.InterruptM & ~dut.hart.StallM; - // trapW will already be invalid in there was an InstrPageFault in the previous instruction. - assign checkInstrW = dut.hart.ieu.InstrValidW & ~dut.hart.StallW; + assign checkInstrW = dut.hart.ieu.InstrValidW & ~dut.hart.StallW; // trapW will already be invalid in there was an InstrPageFault in the previous instruction. + // Additonal W stage registers flopenrc #(`XLEN) MemAdrWReg(clk, reset, dut.hart.FlushW, ~dut.hart.StallW, dut.hart.ieu.dp.MemAdrM, MemAdrW); flopenrc #(`XLEN) WriteDataWReg(clk, reset, dut.hart.FlushW, ~dut.hart.StallW, dut.hart.WriteDataM, WriteDataW); flopenrc #(`XLEN) PCWReg(clk, reset, dut.hart.FlushW, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.PCM, PCW); @@ -176,8 +190,9 @@ module testbench(); // always check PC, instruction bits if (checkInstrM) begin // read 1 line of the trace file - matchCount = $fgets(line, data_file_all); - if(`DEBUG_TRACE > 1) $display("Time %t, line %x", $time, line); + matchCount = $fgets(line, data_file_all); + if(`DEBUG_TRACE >= 5) $display("Time %t, line %x", $time, line); + // extract PC, Instr matchCount = $sscanf(line, "%x %x %s", ExpectedPCM, ExpectedInstrM, textM); //$display("matchCount %d, PCM %x ExpectedInstrM %x textM %x", matchCount, ExpectedPCM, ExpectedInstrM, textM); @@ -213,21 +228,17 @@ module testbench(); RegWriteM = ExpectedTokens[MarkerIndex]; matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%d", ExpectedRegAdrM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedRegValueM); - MarkerIndex += 3; - - // parse memory address, read data, and/or write data + // parse memory address, read data, and/or write data end else if(ExpectedTokens[MarkerIndex].substr(0, 2) == "Mem") begin MemOpM = ExpectedTokens[MarkerIndex]; matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedMemAdrM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+2], "%x", ExpectedMemWriteDataM); matchCount = $sscanf(ExpectedTokens[MarkerIndex+3], "%x", ExpectedMemReadDataM); - MarkerIndex += 4; - - // parse CSRs, because there are 1 or more CSRs after the CSR token - // we check if the CSR token or the number of CSRs is greater than 0. - // if so then we want to parse for a CSR. + // parse CSRs, because there are 1 or more CSRs after the CSR token + // we check if the CSR token or the number of CSRs is greater than 0. + // if so then we want to parse for a CSR. end else if(ExpectedTokens[MarkerIndex] == "CSR" || NumCSRM > 0) begin if(ExpectedTokens[MarkerIndex] == "CSR") begin // all additional CSR's won't have this token. @@ -235,30 +246,13 @@ module testbench(); end matchCount = $sscanf(ExpectedTokens[MarkerIndex], "%s", ExpectedCSRArrayM[NumCSRM]); matchCount = $sscanf(ExpectedTokens[MarkerIndex+1], "%x", ExpectedCSRArrayValueM[NumCSRM]); - MarkerIndex += 2; - - // if we get an xcause with the interrupt bit set we must generate an interrupt as interrupts - // are imprecise. Forcing the trap at this time will allow wally to track what qemu does. - // the msb of xcause will be set. - // bits 1:0 select mode; 0 = user, 1 = superviser, 3 = machine - // bits 3:2 select the type of interrupt, 0 = software, 1 = timer, 2 = external - if(ExpectedCSRArrayM[NumCSRM].substr(1, 5) == "cause" && (ExpectedCSRArrayValueM[NumCSRM][`XLEN-1] == 1'b1)) begin - //what type? - ExpectedIntType = ExpectedCSRArrayValueM[NumCSRM] & 64'h0000_000C; - $display("%tns, %d instrs: CSR = %s. Forcing interrupt of cause = %x", $time, InstrCountW, ExpectedCSRArrayM[NumCSRM], ExpectedCSRArrayValueM[NumCSRM]); - forcedInterrupt = 1; - if(ExpectedIntType == 0) begin - force dut.hart.priv.SwIntM = 1'b1; - $display("Activate spoofed SwIntM"); - end else if(ExpectedIntType == 4) begin - force dut.hart.priv.TimerIntM = 1'b1; - $display("Activate spoofed TimeIntM"); - end else if(ExpectedIntType == 8) begin - force dut.hart.priv.ExtIntM = 1'b1; - $display("Activate spoofed ExtIntM"); - end else forcedInterrupt = 0; - end + // match MIP to QEMU's because interrupts are imprecise + if(ExpectedCSRArrayM[NumCSRM].substr(0, 2) == "mip") begin + $display("%tns: Updating MIP to %x",$time,ExpectedCSRArrayValueM[NumCSRM]); + MIPexpected = ExpectedCSRArrayValueM[NumCSRM]; + force dut.hart.priv.csr.genblk1.csri.MIP_REGW = MIPexpected; + end NumCSRM++; end end @@ -268,12 +262,10 @@ module testbench(); force dut.hart.ieu.dp.ReadDataM = ExpectedMemReadDataM; end if(textM.substr(0,5) == "rdtime") begin - $display("%tns, %d instrs: Overwrite MTIME_CLINT on read of MTIME in memory stage.", $time, InstrCountW); + //$display("%tns, %d instrs: Overwrite MTIME_CLINT on read of MTIME in memory stage.", $time, InstrCountW); force dut.uncore.clint.clint.MTIME = ExpectedRegValueM; - //dut.hart.ieu.dp.regf.wd3 end - - end // if (checkInstrM) + end end // step 1: register expected state into the write back stage. @@ -320,37 +312,16 @@ module testbench(); ExpectedCSRArrayValueW[NumCSRWIndex] = ExpectedCSRArrayValueM[NumCSRWIndex]; end end - // override on special conditions #1; - - + // override on special conditions if(~dut.hart.StallW) begin if(textW.substr(0,5) == "rdtime") begin - $display("%tns, %d instrs: Releasing force of MTIME_CLINT.", $time, InstrCountW); + //$display("%tns, %d instrs: Releasing force of MTIME_CLINT.", $time, InstrCountW); release dut.uncore.clint.clint.MTIME; - //release dut.hart.ieu.dp.regf.wd3; - end - + end if (ExpectedMemAdrM == 'h10000005) begin //$display("%tns, %d instrs: releasing force of ReadDataM.", $time, InstrCountW); - release dut.hart.ieu.dp.ReadDataM; - end - - // force interrupts to 0 - if (forcedInterrupt) begin - forcedInterrupt = 0; - if(ExpectedIntType == 0) begin - force dut.hart.priv.SwIntM = 1'b0; - $display("Deactivate spoofed SwIntM"); - end - else if(ExpectedIntType == 4) begin - force dut.hart.priv.TimerIntM = 1'b0; - $display("Deactivate spoofed TimeIntM"); - end - else if(ExpectedIntType == 8) begin - force dut.hart.priv.ExtIntM = 1'b0; - $display("Deactivate spoofed ExtIntM"); - end + release dut.hart.ieu.dp.ReadDataM; end end end @@ -365,212 +336,65 @@ module testbench(); if (InstrCountW == waveOnICount) $stop; // print progress message if (InstrCountW % 'd100000 == 0) $display("Reached %d instructions", InstrCountW); - // check PCW fault = 0; - if(PCW != ExpectedPCW) begin - $display("PCW: %016x does not equal ExpectedPCW: %016x", PCW, ExpectedPCW); - fault = 1; - end - - // check instruction value - if(dut.hart.ifu.InstrW != ExpectedInstrW) begin - $display("InstrW: %x does not equal ExpectedInstrW: %x", dut.hart.ifu.InstrW, ExpectedInstrW); - fault = 1; - end - - // check the number of instructions - if(dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW != InstrCountW) begin - $display("%t, Number of instruction Retired = %d does not equal number of instructions in trace = %d", $time, dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW, InstrCountW); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - - #2; // delay 2 ns. - - - if(`DEBUG_TRACE > 2) begin - $display("Reg Write Address: %02d ? expected value: %02d", dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW); - $display("RF[%02d]: %016x ? expected value: %016x", ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW); - end - - if (RegWriteW == "GPR") begin - if (dut.hart.ieu.dp.regf.a3 != ExpectedRegAdrW) begin - $display("Reg Write Address: %02d does not equal expected value: %02d", dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW); - fault = 1; + if (`DEBUG_TRACE >= 1) begin + `checkEQ("PCW",PCW,ExpectedPCW) + `checkEQ("InstrW",dut.hart.ifu.InstrW,ExpectedInstrW) + `checkEQ("Instr Count",dut.hart.priv.csr.genblk1.counters.genblk1.INSTRET_REGW,InstrCountW) + #2; // delay 2 ns. + if(`DEBUG_TRACE >= 5) begin + $display("%tns, %d instrs: Reg Write Address %02d ? expected value: %02d", $time, InstrCountW, dut.hart.ieu.dp.regf.a3, ExpectedRegAdrW); + $display("%tns, %d instrs: RF[%02d] %016x ? expected value: %016x", $time, InstrCountW, ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW); end - - if (dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW] != ExpectedRegValueW) begin - $display("RF[%02d]: %016x does not equal expected value: %016x", ExpectedRegAdrW, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW); - fault = 1; - end - end - - if (MemOpW.substr(0,2) == "Mem") begin - if(`DEBUG_TRACE > 3) $display("\tMemAdrW: %016x ? expected: %016x", MemAdrW, ExpectedMemAdrW); - - // always check address - if (MemAdrW != ExpectedMemAdrW) begin - $display("MemAdrW: %016x does not equal expected value: %016x", MemAdrW, ExpectedMemAdrW); - fault = 1; - end - - // check read data - if(MemOpW == "MemR" || MemOpW == "MemRW") begin - if(`DEBUG_TRACE > 3) $display("\tReadDataW: %016x ? expected: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); - if (dut.hart.ieu.dp.ReadDataW != ExpectedMemReadDataW) begin - $display("ReadDataW: %016x does not equal expected value: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); - fault = 1; - end - end - - // check write data - else if(ExpectedTokens[MarkerIndex] == "MemW" || ExpectedTokens[MarkerIndex] == "MemRW") begin - if(`DEBUG_TRACE > 3) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW); - if (WriteDataW != ExpectedMemWriteDataW) begin - $display("WriteDataW: %016x does not equal expected value: %016x", WriteDataW, ExpectedMemWriteDataW); - fault = 1; - end - end - end - - - // check csr - //$display("%t, about to check csr, NumCSRW = %d", $time, NumCSRW); - for(NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) begin - /* -----\/----- EXCLUDED -----\/----- - if(`DEBUG_TRACE > 0) begin - $display("%t, NumCSRPostWIndex = %d, Expected CSR: %s = %016x", $time, NumCSRPostWIndex, ExpectedCSRArrayW[NumCSRPostWIndex], ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - -----/\----- EXCLUDED -----/\----- */ - case(ExpectedCSRArrayW[NumCSRPostWIndex]) - "mhartid": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end + if (RegWriteW == "GPR") begin + `checkEQ("Reg Write Address",dut.hart.ieu.dp.regf.a3,ExpectedRegAdrW) + $sprintf(name,"RF[%02d]",ExpectedRegAdrW); + `checkEQ(name, dut.hart.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW) + end + if (MemOpW.substr(0,2) == "Mem") begin + if(`DEBUG_TRACE >= 4) $display("\tMemAdrW: %016x ? expected: %016x", MemAdrW, ExpectedMemAdrW); + `checkEQ("MemAdrW",MemAdrW,ExpectedMemAdrW) + if(MemOpW == "MemR" || MemOpW == "MemRW") begin + if(`DEBUG_TRACE >= 4) $display("\tReadDataW: %016x ? expected: %016x", dut.hart.ieu.dp.ReadDataW, ExpectedMemReadDataW); + `checkEQ("ReadDataW",dut.hart.ieu.dp.ReadDataW,ExpectedMemReadDataW) + end else if(ExpectedTokens[MarkerIndex] == "MemW" || ExpectedTokens[MarkerIndex] == "MemRW") begin + if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW); + `checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW) end - "mstatus": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if ((dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW) != (ExpectedCSRArrayValueW[NumCSRPostWIndex])) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "mtvec": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "mip": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIP_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MIP_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIP_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "mie": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MIE_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "mideleg": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "medeleg": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "mepc": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MEPC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "mtval": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "sepc": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.SEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrs.SEPC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.SEPC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "scause": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "stvec": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.STVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrs.STVEC_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.STVEC_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - "stval": begin - if(`DEBUG_TRACE > 0) begin - $display("CSR: %s = %016x, expected = %016x", ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - end - if (dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin - $display("%t, CSR: %s = %016x, does not equal expected value %016x", $time, ExpectedCSRArrayW[NumCSRPostWIndex], dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW, ExpectedCSRArrayValueW[NumCSRPostWIndex]); - if(!`DontHaltOnCSRMisMatch) fault = 1; - end - end - endcase // case (ExpectedCSRArrayW[NumCSRPostWIndex]) - end // for (NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) - if (fault == 1) begin `ERROR end + end + // check csr + for(NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) begin + case(ExpectedCSRArrayW[NumCSRPostWIndex]) + "mhartid": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MHARTID_REGW) + "mstatus": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MSTATUS_REGW) + "mtvec": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MTVEC_REGW) + "mip": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MIP_REGW) + "mie": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MIE_REGW) + "mideleg":`CSRwarn(dut.hart.priv.csr.genblk1.csrm.MIDELEG_REGW) + "medeleg": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MEDELEG_REGW) + "mepc": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MEPC_REGW) + "mtval": `CSRwarn(dut.hart.priv.csr.genblk1.csrm.MTVAL_REGW) + "sepc": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.SEPC_REGW) + "scause": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.genblk1.SCAUSE_REGW) + "stvec": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.STVEC_REGW) + "stval": `CSRwarn(dut.hart.priv.csr.genblk1.csrs.genblk1.STVAL_REGW) + endcase + end + if (fault == 1) begin + errorCount +=1; + $display("processed %0d instructions with %0d warnings", InstrCountW, warningCount); + $stop; + end + end // if (`DEBUG_TRACE >= 1) end // if (checkInstrW) end // always @ (negedge clk) // track the current function FunctionName FunctionName(.reset(reset), - .clk(clk), - .ProgramAddrMapFile(ProgramAddrMapFile), - .ProgramLabelMapFile(ProgramLabelMapFile)); + .clk(clk), + .ProgramAddrMapFile(ProgramAddrMapFile), + .ProgramLabelMapFile(ProgramLabelMapFile)); /////////////////////////////////////////////////////////////////////////////// @@ -587,7 +411,11 @@ module testbench(); // initial loading of memories initial begin $readmemh({`LINUX_TEST_VECTORS,"bootmem.txt"}, dut.uncore.bootdtim.bootdtim.RAM, 'h1000 >> 3); - $readmemh({`LINUX_TEST_VECTORS,"ram.txt"}, dut.uncore.dtim.RAM); + `ifdef CHECKPOINT + $readmemh({`LINUX_CHECKPOINT,"ram.txt"}, dut.uncore.dtim.RAM); + `else + $readmemh({`LINUX_TEST_VECTORS,"ram.txt"}, dut.uncore.dtim.RAM); + `endif $readmemb(`TWO_BIT_PRELOAD, dut.hart.ifu.bpred.bpred.Predictor.DirPredictor.PHT.memory); $readmemb(`BTB_PRELOAD, dut.hart.ifu.bpred.bpred.TargetPredictor.memory.memory); ProgramAddrMapFile = {`LINUX_TEST_VECTORS,"vmlinux.objdump.addr"};