450 lines
15 KiB
Plaintext
450 lines
15 KiB
Plaintext
// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved
|
|
//
|
|
//-
|
|
// RVFI_DII + CHERI modifications:
|
|
// Copyright (c) 2020 Jonathan Woodruff
|
|
// All rights reserved.
|
|
//
|
|
// This software was developed by SRI International and the University of
|
|
// Cambridge Computer Laboratory (Department of Computer Science and
|
|
// Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
|
|
// DARPA SSITH research programme.
|
|
//
|
|
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
|
|
//-
|
|
|
|
// ================================================================
|
|
// Definition of Tandem Verifier Packets.
|
|
// The CPU sends out such a packet for each instruction retired.
|
|
// A Tandem Verifier contains a "golden model" simulator of the RISC-V
|
|
// ISA, and verifies that the information in the packet is correct,
|
|
// instruction by instruction.
|
|
|
|
// ================================================================
|
|
|
|
package TV_Info;
|
|
|
|
// ================================================================
|
|
// Bluespec library imports
|
|
|
|
import DefaultValue :: *;
|
|
import Vector :: *;
|
|
|
|
// ================================================================
|
|
// Project imports
|
|
|
|
import ISA_Decls :: *;
|
|
|
|
// ================================================================
|
|
|
|
typedef enum {// These are not from instruction flow and do not have a PC or instruction
|
|
TRACE_RESET,
|
|
TRACE_GPR_WRITE,
|
|
TRACE_FPR_WRITE,
|
|
TRACE_CSR_WRITE,
|
|
TRACE_MEM_WRITE,
|
|
|
|
// These are from instruction flow and have a PC and instruction
|
|
TRACE_OTHER,
|
|
TRACE_I_RD, TRACE_F_GRD, TRACE_F_FRD,
|
|
TRACE_I_LOAD, TRACE_F_LOAD,
|
|
TRACE_I_STORE, TRACE_F_STORE,
|
|
TRACE_AMO,
|
|
TRACE_TRAP,
|
|
TRACE_RET,
|
|
TRACE_CSRRX,
|
|
|
|
// These are from an interrupt and has a PC but no instruction
|
|
TRACE_INTR
|
|
} Trace_Op
|
|
deriving (Bits, Eq, FShow);
|
|
|
|
typedef struct {
|
|
Trace_Op op;
|
|
WordXL pc;
|
|
ISize instr_sz;
|
|
Bit #(32) instr;
|
|
RegName rd;
|
|
WordXL word1;
|
|
WordXL word2;
|
|
Bit #(64) word3; // Wider than WordXL because can contain paddr (in RV32, paddr can be 34 bits)
|
|
WordXL word4;
|
|
`ifdef ISA_F
|
|
WordFL word5;
|
|
`endif
|
|
} Trace_Data
|
|
deriving (Bits);
|
|
|
|
// RESET
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x
|
|
function Trace_Data mkTrace_RESET ();
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_RESET;
|
|
return td;
|
|
endfunction
|
|
|
|
// GPR_WRITE
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x rdval
|
|
function Trace_Data mkTrace_GPR_WRITE (RegName rd, WordXL rdval);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_GPR_WRITE;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
return td;
|
|
endfunction
|
|
|
|
// FPR_WRITE
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x rdval
|
|
function Trace_Data mkTrace_FPR_WRITE (RegName rd, WordXL rdval);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_FPR_WRITE;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
return td;
|
|
endfunction
|
|
|
|
// CSR_WRITE
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x csraddr csrval
|
|
function Trace_Data mkTrace_CSR_WRITE (CSR_Addr csraddr, WordXL csrval);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_CSR_WRITE;
|
|
td.word3 = zeroExtend (csraddr);
|
|
td.word4 = csrval;
|
|
return td;
|
|
endfunction
|
|
|
|
// MEM_WRITE
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x sz stval paddr
|
|
function Trace_Data mkTrace_MEM_WRITE (MemReqSize sz, WordXL stval, Bit #(64) paddr);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_MEM_WRITE;
|
|
td.word1 = zeroExtend (sz);
|
|
td.word2 = stval;
|
|
td.word3 = paddr;
|
|
return td;
|
|
endfunction
|
|
|
|
// OTHER
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x
|
|
function Trace_Data mkTrace_OTHER (WordXL pc, ISize isize, Bit #(32) instr);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_OTHER;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
return td;
|
|
endfunction
|
|
|
|
// I_RD
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x x rdval
|
|
function Trace_Data mkTrace_I_RD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_I_RD;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
return td;
|
|
endfunction
|
|
|
|
`ifdef ISA_F
|
|
// F_FRD
|
|
// op pc instr_sz instr rd word1 word2 word3 word4 word5
|
|
// x x x x x fflags mstatus rdval
|
|
function Trace_Data mkTrace_F_FRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, Bit#(5) fflags, WordXL mstatus);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_F_FRD;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word2 = extend (fflags);
|
|
td.word4 = mstatus;
|
|
td.word5 = rdval;
|
|
return td;
|
|
endfunction
|
|
|
|
// F_GRD
|
|
// op pc instr_sz instr rd word1 word2 word3 word4 word5
|
|
// x x x x x rdval fflags mstatus
|
|
function Trace_Data mkTrace_F_GRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, Bit#(5) fflags, WordXL mstatus);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_F_GRD;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
td.word2 = extend (fflags);
|
|
td.word4 = mstatus;
|
|
return td;
|
|
endfunction
|
|
`endif
|
|
|
|
// I_LOAD
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x x rdval eaddr
|
|
function Trace_Data mkTrace_I_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, WordXL eaddr);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_I_LOAD;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
td.word3 = zeroExtend (eaddr);
|
|
return td;
|
|
endfunction
|
|
|
|
// I_STORE
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x funct3 stval eaddr
|
|
function Trace_Data mkTrace_I_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_I_STORE;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.word1 = zeroExtend (funct3);
|
|
td.word2 = stval;
|
|
td.word3 = zeroExtend (eaddr);
|
|
return td;
|
|
endfunction
|
|
|
|
`ifdef ISA_F
|
|
// F_LOAD
|
|
// op pc instr_sz instr rd word1 word2 word3 word4 word5
|
|
// x x x x x eaddr mstatus rdval
|
|
function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, WordXL eaddr, WordXL mstatus);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_F_LOAD;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word3 = zeroExtend (eaddr);
|
|
td.word4 = mstatus;
|
|
td.word5 = rdval;
|
|
return td;
|
|
endfunction
|
|
|
|
// F_STORE
|
|
// op pc instr_sz instr rd word1 word2 word3 word4 word5
|
|
// x x x x funct3 eaddr stval
|
|
function Trace_Data mkTrace_F_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordFL stval, WordXL eaddr);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_F_STORE;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.word3 = zeroExtend (eaddr);
|
|
td.word5 = stval;
|
|
return td;
|
|
endfunction
|
|
|
|
function Trace_Data fv_trace_update_mstatus_fs (Trace_Data td, Bit #(2) fs);
|
|
let ntd = td;
|
|
ntd.word4 = fv_assign_bits (td.word4, fromInteger (mstatus_fs_bitpos), fs);
|
|
return (ntd);
|
|
endfunction
|
|
|
|
function Trace_Data fv_trace_update_fcsr_fflags (Trace_Data td, Bit #(5) fflags);
|
|
let ntd = td;
|
|
ntd.word2 = (td.word2 | extend (fflags));
|
|
return (ntd);
|
|
endfunction
|
|
`endif
|
|
|
|
// AMO
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x x rdval stval eaddr funct3
|
|
function Trace_Data mkTrace_AMO (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr,
|
|
RegName rd, WordXL rdval, WordXL stval, WordXL eaddr);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_AMO;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
td.word2 = stval;
|
|
td.word3 = zeroExtend (eaddr);
|
|
td.word4 = zeroExtend (funct3);
|
|
return td;
|
|
endfunction
|
|
|
|
// TRAP
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x priv mstatus mcause mepc mtval
|
|
function Trace_Data mkTrace_TRAP (WordXL pc, ISize isize, Bit #(32) instr,
|
|
Priv_Mode priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_TRAP;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = zeroExtend (priv);
|
|
td.word1 = mstatus;
|
|
td.word2 = mcause;
|
|
td.word3 = zeroExtend (mepc);
|
|
td.word4 = mtval;
|
|
return td;
|
|
endfunction
|
|
|
|
// RET
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x x x priv mstatus
|
|
function Trace_Data mkTrace_RET (WordXL pc, ISize isize, Bit #(32) instr, Priv_Mode priv, WordXL mstatus);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_RET;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = zeroExtend (priv);
|
|
td.word1 = mstatus;
|
|
return td;
|
|
endfunction
|
|
|
|
// CSRRX
|
|
// op pc instr_sz instr rd word1 word2 word3 word4 word5
|
|
// x x x x x rdval [1] mstatus_valid csraddr csrval mstatus
|
|
// [0] csrvalid
|
|
function Trace_Data mkTrace_CSRRX (WordXL pc, ISize isize, Bit #(32) instr,
|
|
RegName rd, WordXL rdval,
|
|
Bool csrvalid, CSR_Addr csraddr, WordXL csrval,
|
|
Bool mstatus_valid,
|
|
WordXL mstatus);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_CSRRX;
|
|
td.pc = pc;
|
|
td.instr_sz = isize;
|
|
td.instr = instr;
|
|
td.rd = rd;
|
|
td.word1 = rdval;
|
|
td.word2 = ((mstatus_valid ? 2 : 0) | (csrvalid ? 1 : 0));
|
|
td.word3 = zeroExtend (csraddr);
|
|
td.word4 = csrval;
|
|
`ifdef ISA_F
|
|
td.word5 = mstatus;
|
|
`endif
|
|
return td;
|
|
endfunction
|
|
|
|
// INTR
|
|
// op pc instr_sz instr rd word1 word2 word3 word4
|
|
// x x priv mstatus mcause mepc mtval
|
|
function Trace_Data mkTrace_INTR (WordXL pc,
|
|
Priv_Mode priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
|
|
Trace_Data td = ?;
|
|
td.op = TRACE_INTR;
|
|
td.pc = pc;
|
|
td.rd = zeroExtend (priv);
|
|
td.word1 = mstatus;
|
|
td.word2 = mcause;
|
|
td.word3 = zeroExtend (mepc);
|
|
td.word4 = mtval;
|
|
return td;
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// Display of Trace_Data for debugging
|
|
|
|
instance FShow #(Trace_Data);
|
|
function Fmt fshow (Trace_Data td);
|
|
Fmt fmt = $format ("Trace_Data{", fshow (td.op));
|
|
|
|
if (td.op == TRACE_RESET) begin
|
|
end
|
|
|
|
else if ((td.op == TRACE_GPR_WRITE) || (td.op == TRACE_FPR_WRITE))
|
|
fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1);
|
|
|
|
else if (td.op == TRACE_CSR_WRITE)
|
|
fmt = fmt + $format (" csraddr %0h csrval %0h", td.word3, td.word4);
|
|
|
|
else if (td.op == TRACE_MEM_WRITE)
|
|
fmt = fmt + $format (" sz %0d stval %0h paddr %0h", td.word1, td.word2, td.word3);
|
|
|
|
else begin
|
|
fmt = fmt + $format (" pc %0h", td.pc);
|
|
|
|
if (td.op != TRACE_INTR)
|
|
fmt = fmt + $format (" instr.%0d %0h:", pack (td.instr_sz), td.instr);
|
|
|
|
if (td.op == TRACE_I_RD)
|
|
fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1);
|
|
`ifdef ISA_F
|
|
else if (td.op == TRACE_F_FRD)
|
|
fmt = fmt + $format (" rd %0d rdval %0h fflags %05b", td.rd, td.word5, td.word2);
|
|
|
|
else if (td.op == TRACE_F_GRD)
|
|
fmt = fmt + $format (" rd %0d rdval %0h fflags %05b", td.rd, td.word1, td.word2);
|
|
|
|
else if (td.op == TRACE_F_LOAD)
|
|
fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h",
|
|
td.rd, td.word5, td.word3);
|
|
|
|
else if (td.op == TRACE_F_STORE)
|
|
fmt = fmt + $format (" stval %0h eaddr %0h", td.word5, td.word3);
|
|
`endif
|
|
else if (td.op == TRACE_I_LOAD)
|
|
fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h",
|
|
td.rd, td.word1, td.word3);
|
|
|
|
else if (td.op == TRACE_I_STORE)
|
|
fmt = fmt + $format (" stval %0h eaddr %0h", td.word2, td.word3);
|
|
|
|
else if (td.op == TRACE_AMO)
|
|
fmt = fmt + $format (" rd %0d rdval %0h stval %0h eaddr %0h",
|
|
td.rd, td.word1, td.word2, td.word3);
|
|
|
|
else if (td.op == TRACE_CSRRX)
|
|
fmt = fmt + $format (" rd %0d rdval %0h csraddr %0h csrval %0h",
|
|
td.rd, td.word1, td.word3, td.word4);
|
|
|
|
else if ((td.op == TRACE_TRAP) || (td.op == TRACE_INTR))
|
|
fmt = fmt + $format (" priv %0d mstatus %0h mcause %0h mepc %0h mtval %0h",
|
|
td.rd, td.word1, td.word2, td.word3, td.word4);
|
|
|
|
else if (td.op == TRACE_RET)
|
|
fmt = fmt + $format (" priv %0d mstatus %0h", td.rd, td.word1);
|
|
end
|
|
|
|
fmt = fmt + $format ("}");
|
|
return fmt;
|
|
endfunction
|
|
endinstance
|
|
|
|
// ================================================================
|
|
// Trace_Data is encoded in module mkTV_Encode into vectors of bytes,
|
|
// which are eventually streamed out to an on-line tandem verifier/
|
|
// analyzer (or to a file for off-line tandem-verification/analysis).
|
|
|
|
// Various 'transactions' produce a Trace_Data struct (e.g., reset,
|
|
// each instruction retirement, each GDB write to registers or memory,
|
|
// etc.). Each struct is encoded into a vector of bytes; the number
|
|
// of bytes depends on the kind of transaction and various encoding
|
|
// choices.
|
|
|
|
typedef 72 TV_VB_SIZE; // max bytes needed for each transaction
|
|
typedef Vector #(TV_VB_SIZE, Byte) TV_Vec_Bytes;
|
|
|
|
// ================================================================
|
|
|
|
typedef struct {
|
|
Bit #(32) num_bytes;
|
|
TV_Vec_Bytes vec_bytes;
|
|
} Info_CPU_to_Verifier deriving (Bits, FShow);
|
|
|
|
// ================================================================
|
|
|
|
endpackage
|