172 lines
6.8 KiB
Plaintext
172 lines
6.8 KiB
Plaintext
// Copyright (c) 2016-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").
|
|
//-
|
|
//-
|
|
// RVFI_DII modifications:
|
|
// Copyright (c) 2018 Peter Rugg
|
|
// 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.
|
|
//-
|
|
|
|
package Mem_Model;
|
|
|
|
// ================================================================
|
|
// A simulation model of external DRAM memory.
|
|
// Uses a register file to model memory.
|
|
|
|
// ================================================================
|
|
// BSV library imports
|
|
|
|
import RegFile :: *;
|
|
import Vector :: *;
|
|
import FIFOF :: *;
|
|
import GetPut :: *;
|
|
import ClientServer :: *;
|
|
import Memory :: *;
|
|
|
|
// ----------------
|
|
// BSV additional libs
|
|
|
|
import Cur_Cycle :: *;
|
|
import GetPut_Aux :: *;
|
|
|
|
// ================================================================
|
|
// Project imports
|
|
|
|
import Mem_Controller :: *;
|
|
`ifdef RVFI_DII
|
|
import RVFI_DII :: *;
|
|
`endif
|
|
|
|
// ================================================================
|
|
// Mem Model interface
|
|
|
|
interface Mem_Model_IFC;
|
|
// The read/write interface
|
|
interface MemoryServer #(Bits_per_Raw_Mem_Addr, Bits_per_Raw_Mem_Word) mem_server;
|
|
endinterface
|
|
|
|
typedef 'h4000_0000 Bytes_Per_Mem;
|
|
`ifdef RVFI_DII
|
|
typedef 'h0000_0000 Zeroed_0_start;
|
|
typedef 'h0080_0000 Zeroed_0_end;
|
|
typedef 'h3f00_0000 Zeroed_1_start;
|
|
typedef 'h3fff_ff00 Zeroed_1_end;
|
|
typedef TLog#(TDiv#(Bits_per_Raw_Mem_Word,8)) ByteOffsetInWord;
|
|
typedef 8192 ZeroMemWidth;
|
|
typedef TLog#(ZeroMemWidth) LogZMWidth;
|
|
Integer lineInZeroesOffsetWidth = valueOf(LogZMWidth);
|
|
typedef Bit#(TSub#(TSub#(TLog#(TSub#(Zeroed_0_end, Zeroed_0_start)), LogZMWidth), ByteOffsetInWord)) Offset_Zeroes_0;
|
|
typedef Bit#(TSub#(TSub#(TLog#(TSub#(Zeroed_1_end, Zeroed_1_start)), LogZMWidth), ByteOffsetInWord)) Offset_Zeroes_1;
|
|
`endif
|
|
|
|
// ================================================================
|
|
// Mem Model implementation
|
|
|
|
(* synthesize *)
|
|
module mkMem_Model (Mem_Model_IFC);
|
|
|
|
Integer verbosity = 0; // 0 = quiet; 1 = verbose
|
|
|
|
Raw_Mem_Addr alloc_size = fromInteger(valueOf(TDiv#(TMul#(Bytes_Per_Mem,8), Bits_per_Raw_Mem_Word))); //(raw mem words)
|
|
|
|
`ifdef RVFI_DII
|
|
Raw_Mem_Addr zeroed_0_start = fromInteger(valueOf(TDiv#(Zeroed_0_start, TDiv#(Bits_per_Raw_Mem_Word, 8))));
|
|
Raw_Mem_Addr zeroed_0_end = fromInteger(valueOf(TDiv#(Zeroed_0_end, TDiv#(Bits_per_Raw_Mem_Word, 8))));
|
|
Raw_Mem_Addr zeroed_1_start = fromInteger(valueOf(TDiv#(Zeroed_1_start, TDiv#(Bits_per_Raw_Mem_Word, 8))));
|
|
Raw_Mem_Addr zeroed_1_end = fromInteger(valueOf(TDiv#(Zeroed_1_end, TDiv#(Bits_per_Raw_Mem_Word, 8))));
|
|
|
|
RegFile #(Raw_Mem_Addr, Bit #(Bits_per_Raw_Mem_Word)) rf <- mkRegFile (0, alloc_size - 1);
|
|
//zeroes register allows quick resetting of memory. If bit of zeroes is 0 then corresponding entry of rf is 0.
|
|
|
|
RegFile #(Offset_Zeroes_0, Bit #(ZeroMemWidth)) zeroes_0 <- mkRegFileFull;
|
|
RegFile #(Offset_Zeroes_1, Bit #(ZeroMemWidth)) zeroes_1 <- mkRegFileFull;
|
|
Reg#(Bool) reset_done <- mkReg(False);
|
|
Reg#(Offset_Zeroes_0) reset_count_0 <- mkReg(~0);
|
|
Reg#(Offset_Zeroes_1) reset_count_1 <- mkReg(~0);
|
|
rule doZeroesReset(!reset_done);
|
|
zeroes_0.upd(reset_count_0, 0);
|
|
zeroes_1.upd(reset_count_1, 0);
|
|
if (reset_count_0 != 0) reset_count_0 <= reset_count_0 - 1;
|
|
if (reset_count_1 != 0) reset_count_1 <= reset_count_1 - 1;
|
|
if (reset_count_0 == 0 && reset_count_1 == 0) reset_done <= True;
|
|
endrule
|
|
`else
|
|
RegFile #(Raw_Mem_Addr, Bit #(Bits_per_Raw_Mem_Word)) rf <- mkRegFileLoad ("Mem.hex", 0, alloc_size - 1);
|
|
Reg#(Bool) reset_done <- mkReg(True);
|
|
`endif
|
|
|
|
FIFOF #(MemoryResponse #(Bits_per_Raw_Mem_Word)) f_raw_mem_rsps <- mkFIFOF;
|
|
|
|
// ----------------------------------------------------------------
|
|
// INTERFACE
|
|
|
|
interface MemoryServer mem_server;
|
|
interface Put request;
|
|
method Action put (MemoryRequest #(Bits_per_Raw_Mem_Addr, Bits_per_Raw_Mem_Word) req) if (reset_done);
|
|
`ifdef RVFI_DII
|
|
Bit#(LogZMWidth) offsetLo = truncate((req.address - zeroed_0_start));
|
|
Offset_Zeroes_0 word0 = truncate((req.address - zeroed_0_start)>>lineInZeroesOffsetWidth);
|
|
Bit#(ZeroMemWidth) zeroes_0_word = zeroes_0.sub(word0);
|
|
Offset_Zeroes_1 word1 = truncate((req.address - zeroed_1_start)>>lineInZeroesOffsetWidth);
|
|
Bit#(ZeroMemWidth) zeroes_1_word = zeroes_1.sub(word1);
|
|
`endif
|
|
if (req.address >= alloc_size) begin
|
|
$display ("%0d: ERROR: Mem_Model.request.put: addr 0x%0h >= size 0x%0h (num raw-mem words)",
|
|
cur_cycle, req.address, alloc_size);
|
|
$finish (1); // Assertion failure: address out of bounds
|
|
end
|
|
else if (req.write) begin
|
|
`ifdef RVFI_DII
|
|
if (req.address >= zeroed_0_start && req.address < zeroed_0_end && zeroes_0_word[offsetLo] == 0) begin
|
|
zeroes_0_word[offsetLo] = 1;
|
|
zeroes_0.upd(word0, zeroes_0_word);
|
|
end
|
|
if (req.address >= zeroed_1_start && req.address < zeroed_1_end && zeroes_1_word[offsetLo] == 0) begin
|
|
zeroes_1_word[offsetLo] = 1;
|
|
zeroes_1.upd(word1, zeroes_1_word);
|
|
end
|
|
`endif
|
|
rf.upd (req.address, req.data);
|
|
if (verbosity != 0)
|
|
$display ("%0d: Mem_Model write [0x%0h] <= 0x%0h", cur_cycle, req.address, req.data);
|
|
end
|
|
else begin
|
|
let x = rf.sub (req.address);
|
|
`ifdef RVFI_DII
|
|
$display("req addr: ", fshow(req.address), ", zeroed_0_start: ", fshow(zeroed_0_start), "-", fshow(zeroed_0_end),
|
|
", zeroed_1_start: ", fshow(zeroed_1_start), "-", fshow(zeroed_1_end));
|
|
if (req.address < zeroed_0_end && req.address >= zeroed_0_start && zeroes_0.sub(word0)[offsetLo] == 0) x = 0;
|
|
if (req.address < zeroed_1_end && req.address >= zeroed_1_start && zeroes_1.sub(word1)[offsetLo] == 0) x = 0;
|
|
`endif
|
|
let rsp = MemoryResponse {data: x};
|
|
f_raw_mem_rsps.enq (rsp);
|
|
if (verbosity != 0)
|
|
$display ("%0d: Mem_Model read [0x%0h] => 0x%0h", cur_cycle, req.address, x);
|
|
end
|
|
endmethod
|
|
endinterface
|
|
|
|
interface Get response = toGet (f_raw_mem_rsps);
|
|
endinterface
|
|
endmodule
|
|
|
|
// ================================================================
|
|
|
|
endpackage
|