446 lines
15 KiB
Plaintext
446 lines
15 KiB
Plaintext
// Copyright (c) 2013-2020 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").
|
|
//-
|
|
|
|
package Top_HW_Side;
|
|
|
|
// ================================================================
|
|
// mkTop_HW_Side is the top-level system for simulation.
|
|
// mkMem_Model is a memory model.
|
|
|
|
// **** CAVEAT FOR IVERILOG USERS: The 'C_Imports' sections below are
|
|
// disabled for IVerilog until we find a clean solution. They depend
|
|
// on imported C which is non-trivial in IVerilog because IVerilog
|
|
// still depends on the older Verilog VPI standard instead of the
|
|
// newer DPI-C standard. C-imported functions are used for:
|
|
// UART input polling and character-reading
|
|
// Writing tandem-verfication encoded trace data
|
|
|
|
// (Note: UART output does not depend on C-imported functions and so
|
|
// will work ok even in IVerilog)
|
|
|
|
// ================================================================
|
|
// BSV lib imports
|
|
|
|
`include "ProcConfig.bsv"
|
|
|
|
import FIFOF :: *;
|
|
import GetPut :: *;
|
|
import ClientServer :: *;
|
|
import Connectable :: *;
|
|
import Clocks :: *;
|
|
|
|
// ----------------
|
|
// BSV additional libs
|
|
|
|
import Cur_Cycle :: *;
|
|
import GetPut_Aux :: *;
|
|
|
|
// ================================================================
|
|
// Project imports
|
|
|
|
import WindCoreInterface :: *;
|
|
import AXI4Lite :: *;
|
|
import SourceSink :: *;
|
|
import ISA_Decls :: *;
|
|
import TV_Info :: *;
|
|
import SoC_Top :: *;
|
|
import Mem_Controller :: *;
|
|
import Mem_Model :: *;
|
|
import Fabric_Defs :: *;
|
|
|
|
import PLIC :: *;
|
|
|
|
`ifndef IVERILOG
|
|
import C_Imports :: *;
|
|
`endif
|
|
|
|
`ifdef INCLUDE_GDB_CONTROL
|
|
import External_Control :: *;
|
|
import Debug_Module :: *;
|
|
`endif
|
|
|
|
`ifdef RVFI_DII
|
|
import RVFI_DII :: *;
|
|
import Types :: *;
|
|
import ProcTypes :: *;
|
|
`endif
|
|
|
|
// ================================================================
|
|
// Top-level module.
|
|
// Instantiates the SoC.
|
|
// Instantiates a memory model.
|
|
|
|
`ifndef RVFI_DII
|
|
(* synthesize *)
|
|
module mkTop_HW_Side (Empty);
|
|
`else
|
|
module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
|
`endif
|
|
|
|
// ================================================================
|
|
// The RISC-V Debug Module is at the following point in the module hierarchy:
|
|
// soc_top.corew.debug_module
|
|
// (instances of mkSoC_Top, mkCoreW, mkDebug_Module)
|
|
|
|
// The Debug Module is reset only once, on power-up, hence we pass
|
|
// its reset down from here.
|
|
|
|
// (power-on reset) and the Debug Module's 'hart_reset' control.
|
|
|
|
let power_on_reset <- exposeCurrentReset;
|
|
let dm_power_on_reset = power_on_reset;
|
|
|
|
// The rest of the system (soc_top and mem_model) are reset:
|
|
// - on power-on, and
|
|
// - when the Debug Module requests an NDM reset (for non-DebugModule).
|
|
|
|
let ndm_reset = power_on_reset;
|
|
|
|
// ================================================================
|
|
// STATE
|
|
|
|
SoC_Top_IFC soc_top <- mkSoC_Top (dm_power_on_reset, reset_by ndm_reset);
|
|
Mem_Model_IFC mem_model <- mkMem_Model (reset_by ndm_reset);
|
|
|
|
// Connect SoC to raw memory
|
|
let memCnx <- mkConnection (soc_top.to_raw_mem, mem_model.mem_server, reset_by ndm_reset);
|
|
|
|
// ================================================================
|
|
// Actions on reset
|
|
|
|
function Action fa_reset_actions;
|
|
action
|
|
`ifndef RVFI_DII
|
|
$display ("================================================================");
|
|
$display ("Bluespec RISC-V standalone system simulation v1.2");
|
|
$display ("Copyright (c) 2017-2019 Bluespec, Inc. All Rights Reserved.");
|
|
$display ("================================================================");
|
|
`endif
|
|
// Set CPU verbosity and logdelay (simulation only)
|
|
Bool v1 <- $test$plusargs ("v1");
|
|
Bool v2 <- $test$plusargs ("v2");
|
|
Bit #(4) verbosity = ((v2 ? 2 : (v1 ? 1 : 0)));
|
|
Bit #(64) logdelay = 0; // # of instructions after which to set verbosity
|
|
|
|
// ----------------
|
|
// Load optional tohost and fromhost addrs from symbol-table file
|
|
Fabric_Addr tohost_addr = 0;
|
|
Fabric_Addr fromhost_addr = 0;
|
|
|
|
Bool watch_tohost <- $test$plusargs ("tohost");
|
|
`ifndef IVERILOG
|
|
// Note: see 'CAVEAT FOR IVERILOG USERS' above
|
|
if (watch_tohost) begin
|
|
let tha <- c_get_symbol_val ("tohost");
|
|
tohost_addr = truncate (tha);
|
|
|
|
let fha <- c_get_symbol_val ("fromhost");
|
|
fromhost_addr = truncate (fha);
|
|
end
|
|
`endif
|
|
$display ("INFO: watch_tohost %d, tohost_addr = 0x%0h, fromhost_addr = 0x%0h",
|
|
watch_tohost, tohost_addr, fromhost_addr);
|
|
soc_top.start (tohost_addr, fromhost_addr);
|
|
endaction
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// BEHAVIOR
|
|
|
|
Reg #(Bool) rg_banner_printed <- mkReg (False);
|
|
|
|
// Display a banner
|
|
rule rl_step0 (! rg_banner_printed);
|
|
rg_banner_printed <= True;
|
|
|
|
fa_reset_actions;
|
|
|
|
// ----------------
|
|
// Open file for Tandem Verification trace output
|
|
`ifdef INCLUDE_TANDEM_VERIF
|
|
`ifndef IVERILOG
|
|
// Note: see 'CAVEAT FOR IVERILOG USERS' above
|
|
let success <- c_trace_file_open ('h_AA);
|
|
if (success == 0) begin
|
|
$display ("ERROR: Top_HW_Side.rl_step0: error opening trace file.");
|
|
$display (" Aborting.");
|
|
$finish (1);
|
|
end
|
|
else
|
|
$display ("Top_HW_Side.rl_step0: opened trace file.");
|
|
`else
|
|
$display ("Warning: tandem verification output logs not available in IVerilog");
|
|
`endif
|
|
`endif
|
|
|
|
// ----------------
|
|
// Open connection to remote debug client
|
|
`ifdef INCLUDE_GDB_CONTROL
|
|
`ifndef IVERILOG
|
|
// Note: see 'CAVEAT FOR IVERILOG USERS' above
|
|
let dmi_status <- c_debug_client_connect (dmi_default_tcp_port);
|
|
if (dmi_status != dmi_status_ok) begin
|
|
$display ("ERROR: Top_HW_Side.rl_step0: error opening debug client connection.");
|
|
$display (" Aborting.");
|
|
$finish (1);
|
|
end
|
|
`else
|
|
$display ("Warning: Debug client connection not available in IVerilog");
|
|
`endif
|
|
`endif
|
|
|
|
endrule
|
|
|
|
// ================================================================
|
|
// Tandem verifier: drain and output vectors of bytes
|
|
|
|
`ifdef INCLUDE_TANDEM_VERIF
|
|
rule rl_tv_vb_out;
|
|
let tv_info <- soc_top.tv_verifier_info_get.get;
|
|
let n = tv_info.num_bytes;
|
|
let vb = tv_info.vec_bytes;
|
|
|
|
`ifndef IVERILOG
|
|
Bit #(32) success = 1;
|
|
|
|
for (Bit #(32) j = 0; j < fromInteger (valueOf (TV_VB_SIZE)); j = j + 8) begin
|
|
Bit #(64) w64 = { vb [j+7], vb [j+6], vb [j+5], vb [j+4], vb [j+3], vb [j+2], vb [j+1], vb [j] };
|
|
let success1 <- c_trace_file_load_word64_in_buffer (j, w64);
|
|
end
|
|
|
|
if (success == 0)
|
|
$display ("ERROR: Top_HW_Side.rl_tv_vb_out: error loading %0d bytes into buffer", n);
|
|
else begin
|
|
// Send the data
|
|
success <- c_trace_file_write_buffer (n);
|
|
if (success == 0)
|
|
$display ("ERROR: Top_HW_Side.rl_tv_vb_out: error writing out bytevec data buffer (%0d bytes)", n);
|
|
end
|
|
|
|
if (success == 0) begin
|
|
$finish (1);
|
|
end
|
|
`endif
|
|
endrule
|
|
`endif
|
|
|
|
// ================================================================
|
|
// UART console I/O
|
|
|
|
// Relay system console output to terminal
|
|
|
|
rule rl_relay_console_out;
|
|
let ch <- soc_top.get_to_console.get;
|
|
$write ("%c", ch);
|
|
$fflush (stdout);
|
|
endrule
|
|
|
|
// Poll terminal input and relay any chars into system console input.
|
|
// Note: rg_console_in_poll is used to poll only every N cycles, whenever it wraps around to 0.
|
|
// Note: see 'CAVEAT FOR IVERILOG USERS' above for why this is ifdef'd out for iVerilog users.
|
|
|
|
`ifndef IVERILOG
|
|
|
|
Reg #(Bit #(12)) rg_console_in_poll <- mkReg (0);
|
|
|
|
rule rl_relay_console_in;
|
|
if (rg_console_in_poll == 0) begin
|
|
Bit #(8) ch <- c_trygetchar (?);
|
|
if (ch != 0) begin
|
|
soc_top.put_from_console.put (ch);
|
|
/*
|
|
$write ("%0d: Top_HW_Side.bsv.rl_relay_console: ch = 0x%0h", cur_cycle, ch);
|
|
if (ch >= 'h20) $write (" ('%c')", ch);
|
|
$display ("");
|
|
*/
|
|
end
|
|
end
|
|
rg_console_in_poll <= rg_console_in_poll + 1;
|
|
endrule
|
|
|
|
`endif
|
|
|
|
// ================================================================
|
|
// Interaction with remote debug client
|
|
|
|
`ifdef INCLUDE_GDB_CONTROL
|
|
|
|
FIFOF #(Control_Req) f_external_control_reqs <- mkFIFOF;
|
|
FIFOF #(Control_Rsp) f_external_control_rsps <- mkFIFOF;
|
|
|
|
rule rl_debug_client_request_recv;
|
|
Bit #(64) req <- c_debug_client_request_recv ('hAA);
|
|
Bit #(8) status = req [63:56];
|
|
Bit #(32) data = req [55:24];
|
|
Bit #(16) addr = req [23:8];
|
|
Bit #(8) op = req [7:0];
|
|
if (status == dmi_status_err) begin
|
|
$display ("%0d: Top_HW_Side.rl_debug_client_request_recv: receive error; aborting",
|
|
cur_cycle);
|
|
$finish (1);
|
|
end
|
|
else if (status == dmi_status_ok) begin
|
|
// $write ("%0d: Top_HW_Side.rl_debug_client_request_recv:", cur_cycle);
|
|
if (op == dmi_op_read) begin
|
|
// $display (" READ 0x%0h", addr);
|
|
let control_req = Control_Req {op: external_control_req_op_read_control_fabric,
|
|
arg1: zeroExtend (addr),
|
|
arg2: 0};
|
|
f_external_control_reqs.enq (control_req);
|
|
end
|
|
else if (op == dmi_op_write) begin
|
|
// $display (" WRITE 0x%0h 0x%0h", addr, data);
|
|
let control_req = Control_Req {op: external_control_req_op_write_control_fabric,
|
|
arg1: zeroExtend (addr),
|
|
arg2: zeroExtend (data)};
|
|
f_external_control_reqs.enq (control_req);
|
|
end
|
|
else if (op == dmi_op_shutdown) begin
|
|
$display ("Top_HW_Side.rl_debug_client_request_recv: SHUTDOWN");
|
|
$finish (0);
|
|
end
|
|
else if (op == dmi_op_start_command) begin // For debugging only
|
|
// $display (" START COMMAND ================================");
|
|
end
|
|
else
|
|
$display (" Top_HW_Side.rl_debug_client_request_recv: UNRECOGNIZED OP %0d; ignoring", op);
|
|
end
|
|
endrule
|
|
|
|
rule rl_debug_client_response_send;
|
|
let control_rsp <- pop (f_external_control_rsps);
|
|
// $display ("Top_HW_Side.rl_debug_client_response_send: 0x%0h", control_rsp.result);
|
|
let status <- c_debug_client_response_send (truncate (control_rsp.result));
|
|
if (status == dmi_status_err) begin
|
|
$display ("%0d: Top_HW_Side.rl_debug_client_response_send: send error; aborting",
|
|
cur_cycle);
|
|
$finish (1);
|
|
end
|
|
endrule
|
|
|
|
// ----------------------------------------------------------------
|
|
// External debug requests and responses
|
|
|
|
Control_Req req = f_external_control_reqs.first;
|
|
Integer dmi_verbosity = 0; // For debugging
|
|
|
|
rule rl_handle_external_req_read_request (req.op == external_control_req_op_read_control_fabric);
|
|
f_external_control_reqs.deq;
|
|
soc_top.debug_subordinate.ar.put(AXI4Lite_ARFlit { araddr: truncate (req.arg1)
|
|
, arprot: ?, aruser: ? });
|
|
if (dmi_verbosity != 0) begin
|
|
$display ("%0d: %m.rl_handle_external_req_read_request", cur_cycle);
|
|
$display (" ", fshow (req));
|
|
end
|
|
endrule
|
|
|
|
rule rl_handle_external_req_read_response;
|
|
let x <- get (soc_top.debug_subordinate.r);
|
|
let rsp = Control_Rsp {status: external_control_rsp_status_ok, result: signExtend (x.rdata)};
|
|
f_external_control_rsps.enq (rsp);
|
|
if (dmi_verbosity != 0) begin
|
|
$display ("%0d: %m.rl_handle_external_req_read_response", cur_cycle);
|
|
$display (" ", fshow (rsp));
|
|
end
|
|
endrule
|
|
|
|
rule rl_handle_external_req_write (req.op == external_control_req_op_write_control_fabric);
|
|
f_external_control_reqs.deq;
|
|
soc_top.debug_subordinate.aw.put(AXI4Lite_AWFlit { awaddr: truncate (req.arg1)
|
|
, awprot: ?, awuser: ? });
|
|
soc_top.debug_subordinate.w.put(AXI4Lite_WFlit { wdata: truncate (req.arg2)
|
|
, wstrb: ~0, wuser: ? });
|
|
// let rsp = Control_Rsp {status: external_control_rsp_status_ok, result: 0};
|
|
// f_external_control_rsps.enq (rsp);
|
|
if (dmi_verbosity != 0) begin
|
|
$display ("%0d: %m.rl_handle_external_req_write", cur_cycle);
|
|
$display (" ", fshow (req));
|
|
end
|
|
endrule
|
|
|
|
rule rl_drain_debug_write_rsps; soc_top.debug_subordinate.b.drop; endrule
|
|
|
|
rule rl_handle_external_req_err ( (req.op != external_control_req_op_read_control_fabric)
|
|
&& (req.op != external_control_req_op_write_control_fabric));
|
|
f_external_control_reqs.deq;
|
|
let rsp = Control_Rsp {status: external_control_rsp_status_err, result: 0};
|
|
f_external_control_rsps.enq (rsp);
|
|
|
|
$display ("%0d: %m.rl_handle_external_req_err: unknown req.op", cur_cycle);
|
|
$display (" ", fshow (req));
|
|
endrule
|
|
|
|
(* descending_urgency = "rl_handle_external_req_read_request, rl_handle_external_req_read_response" *)
|
|
(* descending_urgency = "rl_handle_external_req_read_response, rl_handle_external_req_write" *)
|
|
(* descending_urgency = "rl_handle_external_req_read_response, rl_handle_external_req_err" *)
|
|
(* descending_urgency = "rl_handle_external_req_write, rl_handle_external_req_err" *)
|
|
rule rl_handle_external_dummy_for_urgency_attribs_only;
|
|
endrule
|
|
`endif
|
|
|
|
// ================================================================
|
|
// INTERFACE
|
|
|
|
// None (this is top-level)
|
|
|
|
// Except RVFI_DII interface if enabled
|
|
`ifdef RVFI_DII
|
|
return soc_top.rvfi_dii_server;
|
|
`endif
|
|
|
|
endmodule
|
|
|
|
// ================================================================
|
|
|
|
`ifdef RVFI_DII
|
|
// ================================================================
|
|
// mkPiccolo_RVFI_DII instantiates the toplevel with the RVFI_DII
|
|
// interfaces enabled, allowing testing with directly
|
|
// ================================================================
|
|
|
|
(* synthesize *)
|
|
module mkTop_HW_Side(Empty)
|
|
|
|
provisos (Add#(a__, TDiv#(DataSz,8), 8), Add#(b__, DataSz, 64), Add#(c__, TDiv#(DataSz,8), 8), Add#(d__, DataSz, 64));
|
|
|
|
Reg #(Bool) rg_banner_printed <- mkReg (False);
|
|
|
|
// Display a banner
|
|
rule rl_step0 (! rg_banner_printed);
|
|
$display ("================================================================");
|
|
$display ("Bluespec RISC-V standalone system simulation v1.2");
|
|
$display ("Copyright (c) 2017-2018 Bluespec, Inc. All Rights Reserved.");
|
|
$display ("================================================================");
|
|
|
|
rg_banner_printed <= True;
|
|
endrule
|
|
|
|
RVFI_DII_Bridge #(DataSz, DataSz, TMul#(SupSize, 2), SupSize) bridge <- mkRVFI_DII_Bridge("", 5001);
|
|
let dut <- mkPre_Top_HW_Side(reset_by bridge.new_rst);
|
|
mkConnection(bridge.client.report, dut.trace_report);
|
|
|
|
rule rl_provide_instr;
|
|
Dii_Parcel_Id req <- dut.seqReqFirst.get;
|
|
Dii_Parcel_Resps resps <- bridge.client.getParcels(req);
|
|
dut.parcelResps.put(resps);
|
|
endrule
|
|
endmodule
|
|
|
|
`endif
|
|
// ================================================================
|
|
|
|
endpackage: Top_HW_Side
|