Merge branch 'master' into RVFI_DII, a complex merge for the fetch stage!
This commit is contained in:
322
src_Testbench/Fabrics/AXI4/AXI4_Deburster.bsv
Normal file
322
src_Testbench/Fabrics/AXI4/AXI4_Deburster.bsv
Normal file
@@ -0,0 +1,322 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package AXI4_Deburster;
|
||||
|
||||
// ================================================================
|
||||
// This package defines a AXI4-slave-to-AXI4-slave conversion module.
|
||||
// The parameter interface is an AXI4-slave that carries no burst transactions.
|
||||
// The output interface is an AXI4-slave that carries burst transactions.
|
||||
|
||||
// ================================================================
|
||||
// Bluespec library imports
|
||||
|
||||
import Vector :: *;
|
||||
import FIFOF :: *;
|
||||
import SpecialFIFOs :: *;
|
||||
import ConfigReg :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import Semi_FIFOF :: *;
|
||||
import AXI4_Types :: *;
|
||||
|
||||
// ================================================================
|
||||
// The interface for the fabric module
|
||||
|
||||
interface AXI4_Deburster_IFC #(numeric type wd_id,
|
||||
numeric type wd_addr,
|
||||
numeric type wd_data,
|
||||
numeric type wd_user);
|
||||
method Action reset;
|
||||
|
||||
// From master
|
||||
interface AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user) from_master;
|
||||
|
||||
// To slave
|
||||
interface AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user) to_slave;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// The Deburster module
|
||||
// The function parameter is an address-decode function, which
|
||||
// returns (True, slave-port-num) if address is mapped to slave-port-num
|
||||
// (False, ?) if address is unmapped to any slave port
|
||||
|
||||
module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
provisos (Add #(a__, 8, wd_addr));
|
||||
|
||||
// 0 quiet; 1: display start of burst; 2: display all traffic
|
||||
Integer cfg_verbosity = 0;
|
||||
|
||||
Reg #(Bool) rg_reset <- mkReg (True);
|
||||
|
||||
// Transactor facing master
|
||||
AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
|
||||
xactor_from_master <- mkAXI4_Slave_Xactor;
|
||||
|
||||
// Transactor facing slave
|
||||
AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
|
||||
xactor_to_slave <- mkAXI4_Master_Xactor;
|
||||
|
||||
// On a write-transaction, this register is the W-channel burst beat count
|
||||
// (0 => start of burst)
|
||||
Reg #(AXI4_Len) rg_w_beat_count <- mkReg (0);
|
||||
|
||||
// On a write-transaction, records awlen for slave
|
||||
// Size of FIFO should cover slave latency
|
||||
FIFOF #(AXI4_Len) f_w_awlen <- mkSizedFIFOF (4);
|
||||
|
||||
// On a write-transaction, this register is the B-channel burst beat count
|
||||
// which is the number of individual (non-burst) responses from the
|
||||
// slave to be combined into a single burst response to the master.
|
||||
// (0 => ready for next burst)
|
||||
Reg #(AXI4_Len) rg_b_beat_count <- mkReg (0);
|
||||
|
||||
// On a burst write-transaction, all the individual slave responses
|
||||
// may not have the same 'resp' on the B channel. This register
|
||||
// remembers the first 'non-okay' resp (if any), to be returned to
|
||||
// the master in the burst response.
|
||||
Reg #(AXI4_Resp) rg_b_resp <- mkReg (axi4_resp_okay);
|
||||
|
||||
// On a read-transaction, records arlen for slave
|
||||
// Size of FIFO should cover slave latency
|
||||
FIFOF #(AXI4_Len) f_r_arlen <- mkSizedFIFOF (4);
|
||||
|
||||
// On a read-transaction, this register is the AR-channel burst beat count
|
||||
// (0 => start of next burst)
|
||||
Reg #(AXI4_Len) rg_ar_beat_count <- mkReg (0);
|
||||
|
||||
// On a read-transaction, this register is the R-channel burst beat count
|
||||
// (0 => ready for next burst)
|
||||
Reg #(AXI4_Len) rg_r_beat_count <- mkReg (0);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Compute address for beat
|
||||
|
||||
function Bit #(wd_addr) fv_addr_for_beat (Bit #(wd_addr) start_addr,
|
||||
AXI4_Size axsize,
|
||||
AXI4_Burst axburst,
|
||||
AXI4_Len beat_count);
|
||||
Bit #(wd_addr) addr = start_addr;
|
||||
if (axburst == axburst_incr)
|
||||
addr = start_addr + (zeroExtend (beat_count) << pack (axsize));
|
||||
else if (axburst == axburst_wrap)
|
||||
addr = start_addr; // TODO: fixup
|
||||
return addr;
|
||||
endfunction
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// RESET
|
||||
|
||||
rule rl_reset (rg_reset);
|
||||
$display ("%0d: %m::AXI4_Deburster.rl_reset", cur_cycle);
|
||||
xactor_from_master.reset;
|
||||
xactor_to_slave.reset;
|
||||
|
||||
f_w_awlen.clear;
|
||||
rg_w_beat_count <= 0;
|
||||
rg_b_beat_count <= 0;
|
||||
rg_b_resp <= axi4_resp_okay;
|
||||
|
||||
f_r_arlen.clear;
|
||||
rg_ar_beat_count <= 0;
|
||||
rg_r_beat_count <= 0;
|
||||
|
||||
rg_reset <= False;
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// BEHAVIOR
|
||||
|
||||
// ----------------
|
||||
// Wr requests (AW and W channels)
|
||||
|
||||
rule rl_wr_xaction_master_to_slave;
|
||||
AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a_in = xactor_from_master.o_wr_addr.first;
|
||||
AXI4_Wr_Data #(wd_data, wd_user) d_in = xactor_from_master.o_wr_data.first;
|
||||
|
||||
// Construct output AW item
|
||||
let a_out = a_in;
|
||||
a_out.awaddr = fv_addr_for_beat (a_in.awaddr, a_in.awsize, a_in.awburst, rg_w_beat_count);
|
||||
a_out.awlen = 0;
|
||||
a_out.awburst = axburst_fixed; // Not necessary when awlen=1, but slave may be finicky
|
||||
|
||||
// Set WLAST to true since this is always last beat of outgoing xaction (awlen=1)
|
||||
let d_out = d_in;
|
||||
d_out.wlast = True;
|
||||
|
||||
// Send to slave
|
||||
xactor_to_slave.i_wr_addr.enq (a_out);
|
||||
xactor_to_slave.i_wr_data.enq (d_out);
|
||||
|
||||
xactor_from_master.o_wr_data.deq;
|
||||
|
||||
// Remember burst length so that individual responses from slave
|
||||
// can be combined into a single burst response to the master.
|
||||
if (rg_w_beat_count == 0)
|
||||
f_w_awlen.enq (a_in.awlen);
|
||||
|
||||
if (rg_w_beat_count < a_in.awlen)
|
||||
rg_w_beat_count <= rg_w_beat_count + 1;
|
||||
else begin
|
||||
// Last beat of incoming burst; done with AW item
|
||||
xactor_from_master.o_wr_addr.deq;
|
||||
rg_w_beat_count <= 0;
|
||||
|
||||
// Simulation-only assertion-check (no action, just display assertion failure)
|
||||
// Last incoming beat must have WLAST = 1
|
||||
if (! d_in.wlast) begin
|
||||
$display ("%0d: ERROR: %m::AXI4_Deburster.rl_wr_xaction_master_to_slave: m -> s", cur_cycle);
|
||||
$display (" WLAST not set on last data beat (awlen = %0d)", a_in.awlen);
|
||||
$display (" ", fshow (d_in));
|
||||
end
|
||||
end
|
||||
|
||||
// Debugging
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m::AXI4_Deburster.rl_wr_xaction_master_to_slave: m -> s, beat %0d",
|
||||
cur_cycle, rg_w_beat_count);
|
||||
if (rg_w_beat_count == 0)
|
||||
$display (" a_in : ", fshow (a_in));
|
||||
if ((rg_w_beat_count == 0) || (cfg_verbosity > 1)) begin
|
||||
$display (" d_in : ", fshow (d_in));
|
||||
$display (" a_out: ", fshow (a_out));
|
||||
$display (" d_out: ", fshow (d_out));
|
||||
end
|
||||
end
|
||||
endrule: rl_wr_xaction_master_to_slave
|
||||
|
||||
// ----------------
|
||||
// Wr responses (B channel): consume responses from slave until the
|
||||
// last response for a burst, then respond to master. Remember if
|
||||
// any of them was not an 'okay' response.
|
||||
|
||||
rule rl_wr_resp_slave_to_master;
|
||||
AXI4_Wr_Resp #(wd_id, wd_user) b_in <- pop_o (xactor_to_slave.o_wr_resp);
|
||||
|
||||
if (rg_b_beat_count < f_w_awlen.first) begin
|
||||
// Remember first non-okay response (if any) of a burst in rg_b_resp
|
||||
if ((rg_b_resp == axi4_resp_okay) && (b_in.bresp != axi4_resp_okay))
|
||||
rg_b_resp <= b_in.bresp;
|
||||
|
||||
// not last beat of burst
|
||||
rg_b_beat_count <= rg_b_beat_count + 1;
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: %m::AXI4_Deburster.rl_wr_resp_slave_to_master: m <- s, beat %0d",
|
||||
cur_cycle, rg_b_beat_count);
|
||||
$display (" Consuming and discarding beat %0d", rg_b_beat_count);
|
||||
$display (" ", fshow (b_in));
|
||||
end
|
||||
end
|
||||
else begin
|
||||
// Last beat of burst
|
||||
let b_out = b_in;
|
||||
if (rg_b_resp != axi4_resp_okay)
|
||||
b_out.bresp = rg_b_resp;
|
||||
xactor_from_master.i_wr_resp.enq (b_out);
|
||||
|
||||
f_w_awlen.deq;
|
||||
|
||||
// Get ready for next burst
|
||||
rg_b_beat_count <= 0;
|
||||
rg_b_resp <= axi4_resp_okay;
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: %m::AXI4_Deburster.rl_wr_resp_slave_to_master: m <- s, beat %0d",
|
||||
cur_cycle, rg_b_beat_count);
|
||||
$display (" b_in: ", fshow (b_in));
|
||||
$display (" b_out: ", fshow (b_out));
|
||||
end
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd requests (AR channel)
|
||||
|
||||
rule rl_rd_xaction_master_to_slave;
|
||||
AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a_in = xactor_from_master.o_rd_addr.first;
|
||||
|
||||
// Compute forwarded request for each beat, and send
|
||||
let a_out = a_in;
|
||||
a_out.araddr = fv_addr_for_beat (a_in.araddr, a_in.arsize, a_in.arburst, rg_ar_beat_count);
|
||||
a_out.arlen = 0;
|
||||
a_out.arburst = axburst_fixed; // Not necessary when arlen=1, but slave may be finicky
|
||||
xactor_to_slave.i_rd_addr.enq (a_out);
|
||||
|
||||
// On first beat, set up the response count
|
||||
if (rg_ar_beat_count == 0)
|
||||
f_r_arlen.enq (a_in.arlen);
|
||||
|
||||
if (rg_ar_beat_count < a_in.arlen)
|
||||
rg_ar_beat_count <= rg_ar_beat_count + 1;
|
||||
else begin
|
||||
// Last beat sent; done with AR item
|
||||
xactor_from_master.o_rd_addr.deq;
|
||||
rg_ar_beat_count <= 0;
|
||||
end
|
||||
|
||||
// Debugging
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m::AXI4_Deburster.rl_rd_xaction_master_to_slave: m -> s, beat %0d",
|
||||
cur_cycle, rg_ar_beat_count);
|
||||
if (rg_ar_beat_count == 0)
|
||||
$display (" a_in: ", fshow (a_in));
|
||||
if ((rg_ar_beat_count == 0) || (cfg_verbosity > 1))
|
||||
$display (" a_out: ", fshow (a_out));
|
||||
end
|
||||
endrule: rl_rd_xaction_master_to_slave
|
||||
|
||||
// ----------------
|
||||
// Rd responses
|
||||
|
||||
rule rl_rd_resp_slave_to_master;
|
||||
AXI4_Rd_Data #(wd_id, wd_data, wd_user) r_in <- pop_o (xactor_to_slave.o_rd_data);
|
||||
let arlen = f_r_arlen.first;
|
||||
|
||||
let r_out = r_in;
|
||||
if (rg_r_beat_count < arlen) begin
|
||||
// not last beat of burst
|
||||
r_out.rlast = False;
|
||||
rg_r_beat_count <= rg_r_beat_count + 1;
|
||||
end
|
||||
else begin
|
||||
// Last beat of burst
|
||||
rg_r_beat_count <= 0;
|
||||
r_out.rlast = True; // should be set already, but override if not
|
||||
f_r_arlen.deq;
|
||||
end
|
||||
|
||||
xactor_from_master.i_rd_data.enq (r_out);
|
||||
|
||||
// Debugging
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m::AXI4_Deburster.rl_rd_resp_slave_to_master: m <- s, beat %0d",
|
||||
cur_cycle, rg_r_beat_count);
|
||||
if ((rg_r_beat_count == 0) || (cfg_verbosity > 1)) begin
|
||||
$display (" r_in: ", fshow (r_in));
|
||||
$display (" r_out: ", fshow (r_out));
|
||||
end
|
||||
end
|
||||
endrule: rl_rd_resp_slave_to_master
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// INTERFACE
|
||||
|
||||
method Action reset () if (! rg_reset);
|
||||
rg_reset <= True;
|
||||
endmethod
|
||||
|
||||
interface from_master = xactor_from_master.axi_side;
|
||||
interface to_slave = xactor_to_slave .axi_side;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage: AXI4_Deburster
|
||||
@@ -28,8 +28,8 @@ import AXI4_Types :: *;
|
||||
// ================================================================
|
||||
// The interface for the fabric module
|
||||
|
||||
interface AXI4_Fabric_IFC #(numeric type num_masters,
|
||||
numeric type num_slaves,
|
||||
interface AXI4_Fabric_IFC #(numeric type tn_num_masters,
|
||||
numeric type tn_num_slaves,
|
||||
numeric type wd_id,
|
||||
numeric type wd_addr,
|
||||
numeric type wd_data,
|
||||
@@ -38,194 +38,240 @@ interface AXI4_Fabric_IFC #(numeric type num_masters,
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
|
||||
// From masters
|
||||
interface Vector #(num_masters, AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user)) v_from_masters;
|
||||
interface Vector #(tn_num_masters, AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user)) v_from_masters;
|
||||
|
||||
// To slaves
|
||||
interface Vector #(num_slaves, AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user)) v_to_slaves;
|
||||
interface Vector #(tn_num_slaves, AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user)) v_to_slaves;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// The Fabric module
|
||||
// The function parameter is an address-decode function, which returns
|
||||
// The function parameter is an address-decode function, which
|
||||
// returns (True, slave-port-num) if address is mapped to slave-port-num
|
||||
// (False, ?) if address is unmapped to any port
|
||||
// (False, ?) if address is unmapped to any slave port
|
||||
|
||||
module mkAXI4_Fabric #(function Tuple2 #(Bool, Bit #(TLog #(num_slaves)))
|
||||
module mkAXI4_Fabric #(function Tuple2 #(Bool, Bit #(TLog #(tn_num_slaves)))
|
||||
fn_addr_to_slave_num (Bit #(wd_addr) addr))
|
||||
(AXI4_Fabric_IFC #(num_masters, num_slaves, wd_id, wd_addr, wd_data, wd_user))
|
||||
(AXI4_Fabric_IFC #(tn_num_masters, tn_num_slaves, wd_id, wd_addr, wd_data, wd_user))
|
||||
|
||||
provisos (Log #(num_masters, log_nm),
|
||||
Log #(num_slaves, log_ns),
|
||||
Log #(TAdd #(num_masters, 1), log_nm_plus_1),
|
||||
Log #(TAdd #(num_slaves, 1), log_ns_plus_1),
|
||||
Add #(_dummy, TLog #(num_slaves), log_ns_plus_1));
|
||||
provisos (Log #(tn_num_masters, log_nm),
|
||||
Log #(tn_num_slaves, log_ns),
|
||||
Log #(TAdd #(tn_num_slaves, 1), log_ns_plus_1),
|
||||
Add #(_dummy, TLog #(tn_num_slaves), log_ns_plus_1));
|
||||
|
||||
Integer num_masters = valueOf (tn_num_masters);
|
||||
Integer num_slaves = valueOf (tn_num_slaves);
|
||||
|
||||
// 0: quiet; 1: show transactions
|
||||
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
|
||||
|
||||
Reg #(Bool) rg_reset <- mkReg (True);
|
||||
|
||||
// Transactors facing masters
|
||||
Vector #(num_masters, AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
Vector #(tn_num_masters, AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
xactors_from_masters <- replicateM (mkAXI4_Slave_Xactor);
|
||||
|
||||
// Transactors facing slaves
|
||||
Vector #(num_slaves, AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
Vector #(tn_num_slaves, AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
xactors_to_slaves <- replicateM (mkAXI4_Master_Xactor);
|
||||
|
||||
// FIFOs to keep track of which master originated a transaction, in
|
||||
// order to route corresponding responses back to that master.
|
||||
// Legal masters are 0..(num_masters-1)
|
||||
// The value of 'num_masters' is used for decode errors (no such slave)
|
||||
// ----------------------------------------------------------------
|
||||
// Book-keeping to keep track of which master originated a transaction, in
|
||||
// order to route corresponding responses back to that master, etc.
|
||||
// Legal slaves are 0..(num_slaves-1)
|
||||
// The "illegal" value of 'num_slaves' is used for decode errors (no such slave)
|
||||
// Size of SizedFIFOs is estimated: should cover round-trip latency to slave and back.
|
||||
|
||||
Vector #(num_masters, FIFOF #(Bit #(log_ns_plus_1))) v_f_wr_sjs <- replicateM (mkSizedFIFOF (8));
|
||||
Vector #(num_masters, FIFOF #(Bit #(wd_id))) v_f_wr_err_id <- replicateM (mkSizedFIFOF (8));
|
||||
Vector #(num_masters, FIFOF #(Bit #(wd_user))) v_f_wr_err_user <- replicateM (mkSizedFIFOF (8));
|
||||
Vector #(num_slaves, FIFOF #(Bit #(log_nm_plus_1))) v_f_wr_mis <- replicateM (mkSizedFIFOF (8));
|
||||
// ----------------
|
||||
// Write-transaction book-keeping
|
||||
|
||||
Vector #(num_masters, FIFOF #(Bit #(log_ns_plus_1))) v_f_rd_sjs <- replicateM (mkSizedFIFOF (8));
|
||||
Vector #(num_masters, FIFOF #(Bit #(wd_id))) v_f_rd_err_id <- replicateM (mkSizedFIFOF (8));
|
||||
Vector #(num_masters, FIFOF #(Bit #(wd_user))) v_f_rd_err_user <- replicateM (mkSizedFIFOF (8));
|
||||
Vector #(num_slaves, FIFOF #(Bit #(log_nm_plus_1))) v_f_rd_mis <- replicateM (mkSizedFIFOF (8));
|
||||
// On an mi->sj write-transaction, this fifo records sj for master mi
|
||||
Vector #(tn_num_masters, FIFOF #(Bit #(log_ns_plus_1))) v_f_wr_sjs <- replicateM (mkSizedFIFOF (8));
|
||||
|
||||
// On an mi->sj write-transaction, this fifo records mi for slave sj
|
||||
Vector #(tn_num_slaves, FIFOF #(Bit #(log_nm))) v_f_wr_mis <- replicateM (mkSizedFIFOF (8));
|
||||
|
||||
// On an mi->sj write-transaction, this fifo records a task (sj, awlen) for W channel
|
||||
Vector #(tn_num_masters,
|
||||
FIFOF #(Tuple2 #(Bit #(log_ns_plus_1),
|
||||
AXI4_Len))) v_f_wd_tasks <- replicateM (mkFIFOF);
|
||||
// On an mi->sj write-transaction, this register is the W-channel burst beat_count
|
||||
// (0 => ready for next burst)
|
||||
Vector #(tn_num_masters, Reg #(AXI4_Len)) v_rg_wd_beat_count <- replicateM (mkReg (0));
|
||||
|
||||
// On a write-transaction to non-exisitent slave, record id and user for error response
|
||||
Vector #(tn_num_masters,
|
||||
FIFOF #(Tuple2 #(Bit #(wd_id),
|
||||
Bit #(wd_user)))) v_f_wr_err_info <- replicateM (mkSizedFIFOF (8));
|
||||
|
||||
// ----------------
|
||||
// Read-transaction book-keeping
|
||||
|
||||
// On an mi->sj read-transaction, records sj for master mi
|
||||
Vector #(tn_num_masters, FIFOF #(Bit #(log_ns_plus_1))) v_f_rd_sjs <- replicateM (mkSizedFIFOF (8));
|
||||
// On an mi->sj read-transaction, records (mi,arlen) for slave sj
|
||||
Vector #(tn_num_slaves,
|
||||
FIFOF #(Tuple2 #(Bit #(log_nm),
|
||||
AXI4_Len))) v_f_rd_mis <- replicateM (mkSizedFIFOF (8));
|
||||
// On an mi->sj read-transaction, this register is the R-channel burst beat_count
|
||||
// (0 => ready for next burst)
|
||||
Vector #(tn_num_slaves, Reg #(AXI4_Len)) v_rg_r_beat_count <- replicateM (mkReg (0));
|
||||
|
||||
// On a read-transaction to non-exisitent slave, record id and user for error response
|
||||
Vector #(tn_num_masters,
|
||||
FIFOF #(Tuple3 #(AXI4_Len,
|
||||
Bit #(wd_id),
|
||||
Bit #(wd_user)))) v_f_rd_err_info <- replicateM (mkSizedFIFOF (8));
|
||||
|
||||
// On an mi->non-existent-slave read-transaction,
|
||||
// this register is the R-channel burst beat_count
|
||||
// (0 => ready for next burst)
|
||||
Vector #(tn_num_masters, Reg #(AXI4_Len)) v_rg_r_err_beat_count <- replicateM (mkReg (0));
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// BEHAVIOR
|
||||
// RESET
|
||||
|
||||
rule rl_reset (rg_reset);
|
||||
$display ("%0d: AXI4_Fabric.rl_reset", cur_cycle);
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1) begin
|
||||
$display ("%0d: %m.rl_reset", cur_cycle);
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1) begin
|
||||
xactors_from_masters [mi].reset;
|
||||
|
||||
v_f_wr_sjs [mi].clear;
|
||||
v_f_wr_err_id [mi].clear;
|
||||
v_f_wr_err_user [mi].clear;
|
||||
v_f_wd_tasks [mi].clear;
|
||||
v_rg_wd_beat_count [mi] <= 0;
|
||||
|
||||
v_f_wr_err_info [mi].clear;
|
||||
|
||||
v_f_rd_sjs [mi].clear;
|
||||
v_f_rd_err_id [mi].clear;
|
||||
v_f_rd_err_user [mi].clear;
|
||||
|
||||
v_f_rd_err_info [mi].clear;
|
||||
end
|
||||
|
||||
for (Integer sj = 0; sj < valueOf (num_slaves); sj = sj + 1) begin
|
||||
for (Integer sj = 0; sj < num_slaves; sj = sj + 1) begin
|
||||
xactors_to_slaves [sj].reset;
|
||||
v_f_wr_mis [sj].clear;
|
||||
v_f_rd_mis [sj].clear;
|
||||
v_rg_r_beat_count [sj] <= 0;
|
||||
end
|
||||
rg_reset <= False;
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Help functions for moving data from masters to slaves
|
||||
// BEHAVIOR
|
||||
|
||||
Integer num_slaves_i = valueOf (num_slaves);
|
||||
// ----------------------------------------------------------------
|
||||
// Predicates to check if master I has transaction for slave J
|
||||
|
||||
function Bool wr_move_from_mi_to_sj (Integer mi, Integer sj);
|
||||
function Bool fv_mi_has_wr_for_sj (Integer mi, Integer sj);
|
||||
let addr = xactors_from_masters [mi].o_wr_addr.first.awaddr;
|
||||
match { .legal, .slave_num } = fn_addr_to_slave_num (addr);
|
||||
return (legal
|
||||
&& ( (num_slaves_i == 1)
|
||||
&& ( (num_slaves == 1)
|
||||
|| (slave_num == fromInteger (sj))));
|
||||
endfunction
|
||||
|
||||
function Bool wr_illegal_sj (Integer mi);
|
||||
function Bool fv_mi_has_wr_for_none (Integer mi);
|
||||
let addr = xactors_from_masters [mi].o_wr_addr.first.awaddr;
|
||||
match { .legal, ._ } = fn_addr_to_slave_num (addr);
|
||||
return (! legal);
|
||||
endfunction
|
||||
|
||||
function Bool rd_move_from_mi_to_sj (Integer mi, Integer sj);
|
||||
function Bool fv_mi_has_rd_for_sj (Integer mi, Integer sj);
|
||||
let addr = xactors_from_masters [mi].o_rd_addr.first.araddr;
|
||||
match { .legal, .slave_num } = fn_addr_to_slave_num (addr);
|
||||
return (legal
|
||||
&& ( (num_slaves_i == 1)
|
||||
&& ( (num_slaves == 1)
|
||||
|| (slave_num == fromInteger (sj))));
|
||||
endfunction
|
||||
|
||||
function Bool rd_illegal_sj (Integer mi);
|
||||
function Bool fv_mi_has_rd_for_none (Integer mi);
|
||||
let addr = xactors_from_masters [mi].o_rd_addr.first.araddr;
|
||||
match { .legal, ._ } = fn_addr_to_slave_num (addr);
|
||||
return (! legal);
|
||||
endfunction
|
||||
|
||||
// ----------------
|
||||
// Wr requests from masters to slaves
|
||||
// ================================================================
|
||||
// Wr requests (AW, W and B channels)
|
||||
|
||||
// Legal destination slaves
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
for (Integer sj = 0; sj < valueOf (num_slaves); sj = sj + 1)
|
||||
// Wr requests to legal slaves (AW channel)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
for (Integer sj = 0; sj < num_slaves; sj = sj + 1)
|
||||
|
||||
rule rl_wr_xaction_master_to_slave (wr_move_from_mi_to_sj (mi, sj));
|
||||
rule rl_wr_xaction_master_to_slave (fv_mi_has_wr_for_sj (mi, sj));
|
||||
// Move the AW transaction
|
||||
AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_wr_addr);
|
||||
AXI4_Wr_Data #(wd_id, wd_data, wd_user) d <- pop_o (xactors_from_masters [mi].o_wr_data);
|
||||
|
||||
xactors_to_slaves [sj].i_wr_addr.enq (a);
|
||||
xactors_to_slaves [sj].i_wr_data.enq (d);
|
||||
|
||||
// Enqueue a task for the W channel
|
||||
v_f_wd_tasks [mi].enq (tuple2 (fromInteger (sj), a.awlen));
|
||||
|
||||
// Book-keeping
|
||||
v_f_wr_mis [sj].enq (fromInteger (mi));
|
||||
v_f_wr_sjs [mi].enq (fromInteger (sj));
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: wr master [%0d] -> slave [%0d]", cur_cycle, mi, sj);
|
||||
$display (" ", fshow (a));
|
||||
$display (" ", fshow (d));
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_wr_xaction_master_to_slave: m%0d -> s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// Non-existent destination slaves
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
rule rl_wr_xaction_no_such_slave (wr_illegal_sj (mi));
|
||||
// Wr requests to non-existent slave (AW channel)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
rule rl_wr_xaction_no_such_slave (fv_mi_has_wr_for_none (mi));
|
||||
AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_wr_addr);
|
||||
AXI4_Wr_Data #(wd_id, wd_data, wd_user) d <- pop_o (xactors_from_masters [mi].o_wr_data);
|
||||
AXI4_Wr_Data #(wd_data, wd_user) d <- pop_o (xactors_from_masters [mi].o_wr_data);
|
||||
|
||||
v_f_wr_sjs [mi].enq (fromInteger (valueOf (num_slaves)));
|
||||
v_f_wr_err_id [mi].enq (a.awid);
|
||||
v_f_wr_err_user [mi].enq (a.awuser);
|
||||
// Special value 'num_slaves' (not a legal sj) means "no such slave"
|
||||
v_f_wr_sjs [mi].enq (fromInteger (num_slaves));
|
||||
v_f_wr_err_info [mi].enq (tuple2 (a.awid, a.awuser));
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: wr master [%0d] -> illegal addr", cur_cycle, mi);
|
||||
// Enqueue a task for the W channel (must consume the write-data burst)
|
||||
v_f_wd_tasks [mi].enq (tuple2 (fromInteger (num_slaves), a.awlen));
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_wr_xaction_no_such_slave: m%0d -> ?",
|
||||
cur_cycle, mi);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd requests from masters to slaves
|
||||
// Wr data (W channel)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
|
||||
// Legal destination slaves
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
for (Integer sj = 0; sj < valueOf (num_slaves); sj = sj + 1)
|
||||
// Handle W channel burst
|
||||
// Invariant: v_rg_wd_beat_count == 0 between bursts
|
||||
// Note: awlen is encoded as 0..255 for burst lengths of 1..256
|
||||
rule rl_wr_xaction_master_to_slave_data (v_f_wd_tasks [mi].first matches {.sj, .awlen});
|
||||
AXI4_Wr_Data #(wd_data, wd_user) d <- pop_o (xactors_from_masters [mi].o_wr_data);
|
||||
|
||||
rule rl_rd_xaction_master_to_slave (rd_move_from_mi_to_sj (mi, sj));
|
||||
AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_rd_addr);
|
||||
// If sj is a legal slave, send it the data beat, else drop it.
|
||||
if (sj < fromInteger (num_slaves))
|
||||
xactors_to_slaves [sj].i_wr_data.enq (d);
|
||||
|
||||
xactors_to_slaves [sj].i_rd_addr.enq (a);
|
||||
if (v_rg_wd_beat_count [mi] == awlen) begin
|
||||
// End of burst
|
||||
v_f_wd_tasks [mi].deq;
|
||||
v_rg_wd_beat_count [mi] <= 0;
|
||||
|
||||
v_f_rd_mis [sj].enq (fromInteger (mi));
|
||||
v_f_rd_sjs [mi].enq (fromInteger (sj));
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: rd master [%0d] -> slave [%0d]", cur_cycle, mi, sj);
|
||||
$display (" ", fshow (a));
|
||||
// Simulation-only assertion-check (no action, just display assertion failure)
|
||||
// Final beat must have WLAST = 1
|
||||
// Rely on slave (which should also see this error) to return error response
|
||||
if (! (d.wlast)) begin
|
||||
$display ("%0d: %m.rl_wr_xaction_master_to_slave_data: ERROR: m%0d -> s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" WLAST not set on final data beat (awlen = %0d)", awlen);
|
||||
$display (" ", fshow (d));
|
||||
end
|
||||
endrule
|
||||
end
|
||||
else
|
||||
v_rg_wd_beat_count [mi] <= v_rg_wd_beat_count [mi] + 1;
|
||||
endrule
|
||||
|
||||
// Non-existent destination slaves
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
rule rl_rd_xaction_no_such_slave (rd_illegal_sj (mi));
|
||||
AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_rd_addr);
|
||||
// Wr responses from slaves to masters (B channel)
|
||||
|
||||
v_f_rd_sjs [mi].enq (fromInteger (valueOf (num_slaves)));
|
||||
v_f_rd_err_id [mi].enq (a.arid);
|
||||
v_f_rd_err_user [mi].enq (a.aruser);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: rd master [%0d] -> illegal addr", cur_cycle, mi);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Wr responses from slaves to masters
|
||||
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
for (Integer sj = 0; sj < valueOf (num_slaves); sj = sj + 1)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
for (Integer sj = 0; sj < num_slaves; sj = sj + 1)
|
||||
|
||||
rule rl_wr_resp_slave_to_master ( (v_f_wr_mis [sj].first == fromInteger (mi))
|
||||
&& (v_f_wr_sjs [mi].first == fromInteger (sj)));
|
||||
@@ -235,86 +281,149 @@ module mkAXI4_Fabric #(function Tuple2 #(Bool, Bit #(TLog #(num_slaves)))
|
||||
|
||||
xactors_from_masters [mi].i_wr_resp.enq (b);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: wr master [%0d] <- slave [%0d]", cur_cycle, mi, sj);
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_wr_resp_slave_to_master: m%0d <- s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" ", fshow (b));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Wr error responses to masters
|
||||
// Wr error responses to masters (B channel)
|
||||
// v_f_wr_sjs [mi].first has value num_slaves (illegal value)
|
||||
// v_f_wr_err_id [mi].first contains the request's 'id' data
|
||||
// v_f_wr_err_user [mi].first contains the request's 'user' data
|
||||
// v_f_wr_err_info [mi].first contains request fields 'awid' and 'awuser'
|
||||
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
|
||||
rule rl_wr_resp_err_to_master (v_f_wr_sjs [mi].first == fromInteger (valueOf (num_slaves)));
|
||||
rule rl_wr_resp_err_to_master (v_f_wr_sjs [mi].first == fromInteger (num_slaves));
|
||||
v_f_wr_sjs [mi].deq;
|
||||
v_f_wr_err_id [mi].deq;
|
||||
v_f_wr_err_user [mi].deq;
|
||||
v_f_wr_err_info [mi].deq;
|
||||
|
||||
let b = AXI4_Wr_Resp {bid: v_f_wr_err_id [mi].first,
|
||||
match { .awid, .awuser } = v_f_wr_err_info [mi].first;
|
||||
|
||||
let b = AXI4_Wr_Resp {bid: awid,
|
||||
bresp: axi4_resp_decerr,
|
||||
buser: v_f_wr_err_user [mi].first};
|
||||
buser: awuser};
|
||||
|
||||
xactors_from_masters [mi].i_wr_resp.enq (b);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: wr master [%0d] <- error", cur_cycle, mi);
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_wr_resp_err_to_master: m%0d <- err", cur_cycle, mi);
|
||||
$display (" ", fshow (b));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd responses from slaves to masters
|
||||
// ================================================================
|
||||
// Rd requests (AR and R channels)
|
||||
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
for (Integer sj = 0; sj < valueOf (num_slaves); sj = sj + 1)
|
||||
// Rd requests to legal slaves (AR channel)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
for (Integer sj = 0; sj < num_slaves; sj = sj + 1)
|
||||
|
||||
rule rl_rd_resp_slave_to_master ( (v_f_rd_mis [sj].first == fromInteger (mi))
|
||||
&& (v_f_rd_sjs [mi].first == fromInteger (sj)));
|
||||
v_f_rd_mis [sj].deq;
|
||||
v_f_rd_sjs [mi].deq;
|
||||
AXI4_Rd_Data #(wd_id, wd_data, wd_user) r <- pop_o (xactors_to_slaves [sj].o_rd_data);
|
||||
rule rl_rd_xaction_master_to_slave (fv_mi_has_rd_for_sj (mi, sj));
|
||||
AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_rd_addr);
|
||||
|
||||
xactors_from_masters [mi].i_rd_data.enq (r);
|
||||
xactors_to_slaves [sj].i_rd_addr.enq (a);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: rd master [%0d] <- slave [%0d]", cur_cycle, mi, sj);
|
||||
$display (" ", fshow (r));
|
||||
v_f_rd_mis [sj].enq (tuple2 (fromInteger (mi), a.arlen));
|
||||
v_f_rd_sjs [mi].enq (fromInteger (sj));
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_rd_xaction_master_to_slave: m%0d -> s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd error responses to masters
|
||||
// Rd requests to non-existent slave (AR channel)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
rule rl_rd_xaction_no_such_slave (fv_mi_has_rd_for_none (mi));
|
||||
AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_rd_addr);
|
||||
|
||||
v_f_rd_sjs [mi].enq (fromInteger (num_slaves));
|
||||
v_f_rd_err_info [mi].enq (tuple3 (a.arlen, a.arid, a.aruser));
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_rd_xaction_no_such_slave: m%0d -> ?",
|
||||
cur_cycle, mi);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// Rd responses from slaves to masters (R channel)
|
||||
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
for (Integer sj = 0; sj < num_slaves; sj = sj + 1)
|
||||
|
||||
rule rl_rd_resp_slave_to_master (v_f_rd_mis [sj].first matches { .mi2, .arlen }
|
||||
&&& (mi2 == fromInteger (mi))
|
||||
&&& (v_f_rd_sjs [mi].first == fromInteger (sj)));
|
||||
|
||||
AXI4_Rd_Data #(wd_id, wd_data, wd_user) r <- pop_o (xactors_to_slaves [sj].o_rd_data);
|
||||
|
||||
if (v_rg_r_beat_count [sj] == arlen) begin
|
||||
// Final beat of burst
|
||||
v_f_rd_mis [sj].deq;
|
||||
v_f_rd_sjs [mi].deq;
|
||||
v_rg_r_beat_count [sj] <= 0;
|
||||
|
||||
// Assertion-check
|
||||
// Final beat must have RLAST = 1
|
||||
// If not, and if RRESP is OK, set RRESP to AXI4_RESP_SLVERR
|
||||
if ((r.rresp == axi4_resp_okay) && (! (r.rlast))) begin
|
||||
r.rresp = axi4_resp_slverr;
|
||||
$display ("%0d: %m.rl_rd_resp_slave_to_master: ERROR: m%0d <- s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" RLAST not set on final data beat (arlen = %0d)", arlen);
|
||||
$display (" ", fshow (r));
|
||||
end
|
||||
end
|
||||
else
|
||||
v_rg_r_beat_count [sj] <= v_rg_r_beat_count [sj] + 1;
|
||||
|
||||
xactors_from_masters [mi].i_rd_data.enq (r);
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_rd_resp_slave_to_master: m%0d <- s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" r: ", fshow (r));
|
||||
end
|
||||
endrule
|
||||
|
||||
// Rd error responses to masters (R channel)
|
||||
// v_f_rd_sjs [mi].first has value num_slaves (illegal value)
|
||||
// v_f_rd_err_id [mi].first contains the request's 'id' data
|
||||
// v_f_rd_err_user [mi].first contains the request's 'user' data
|
||||
// v_f_rd_err_info [mi].first contains request fields: 'arlen', 'arid', 'aruser'
|
||||
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
|
||||
rule rl_rd_resp_err_to_master (v_f_rd_sjs [mi].first == fromInteger (valueOf (num_slaves)));
|
||||
v_f_rd_sjs [mi].deq;
|
||||
v_f_rd_err_id [mi].deq;
|
||||
v_f_rd_err_user [mi].deq;
|
||||
rule rl_rd_resp_err_to_master (v_f_rd_sjs [mi].first == fromInteger (num_slaves));
|
||||
match { .arlen, .arid, .aruser } = v_f_rd_err_info [mi].first;
|
||||
|
||||
Bit #(wd_data) data = 0;
|
||||
let r = AXI4_Rd_Data {rid: v_f_rd_err_id [mi].first,
|
||||
let r = AXI4_Rd_Data {rid: arid,
|
||||
rdata: data,
|
||||
rresp: axi4_resp_decerr,
|
||||
rlast: True,
|
||||
ruser: v_f_rd_err_user [mi].first};
|
||||
rlast: (v_rg_r_err_beat_count [mi] == arlen),
|
||||
ruser: aruser};
|
||||
|
||||
xactors_from_masters [mi].i_rd_data.enq (r);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Fabric: rd master [%0d] <- error", cur_cycle, mi);
|
||||
$display (" ", fshow (r));
|
||||
if (v_rg_r_err_beat_count [mi] == arlen) begin
|
||||
// Last beat of burst
|
||||
v_f_rd_sjs [mi].deq;
|
||||
v_f_rd_err_info [mi].deq;
|
||||
v_rg_r_err_beat_count [mi] <= 0;
|
||||
end
|
||||
else
|
||||
v_rg_r_err_beat_count [mi] <= v_rg_r_err_beat_count [mi] + 1;
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_rd_resp_err_to_master: m%0d <- err",
|
||||
cur_cycle, mi);
|
||||
$display (" r: ", fshow (r));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
function AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user) f1 (Integer j)
|
||||
|
||||
211
src_Testbench/Fabrics/AXI4/AXI4_Mem_Model.bsv
Normal file
211
src_Testbench/Fabrics/AXI4/AXI4_Mem_Model.bsv
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved.
|
||||
// Author: Rishiyur S. Nikhil
|
||||
|
||||
package AXI4_Mem_Model;
|
||||
|
||||
// ================================================================
|
||||
// A memory-model to be used as a slave on an AXI4 bus.
|
||||
// Only partical functionality; will be gradually improved over time.
|
||||
// Current status:
|
||||
// Address and Data bus widths: 64b
|
||||
// Bursts: 'fixed' and 'incr' only
|
||||
// Size: Full 64-bit width reads/writes only
|
||||
// Strobes: Not yet handled
|
||||
// memory size: See 'mem_size_word64' definition below
|
||||
|
||||
// ================================================================
|
||||
// Exports
|
||||
|
||||
export AXI4_Mem_Model_IFC (..);
|
||||
export mkAXI4_Mem_Model;
|
||||
|
||||
// ================================================================
|
||||
// Bluespec library imports
|
||||
|
||||
import RegFile :: *;
|
||||
import FIFOF :: *;
|
||||
import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Semi_FIFOF :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import AXI4_Types :: *;
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
interface AXI4_Mem_Model_IFC #(numeric type wd_id,
|
||||
numeric type wd_addr,
|
||||
numeric type wd_data,
|
||||
numeric type wd_user);
|
||||
|
||||
method Action init (Bit #(wd_addr) addr_map_base, Bit #(wd_addr) addr_map_lim);
|
||||
|
||||
interface AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user) slave;
|
||||
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// IMPLEMENTATION
|
||||
|
||||
Integer mem_size_word64 = 'h100_0000; // 16M x 64b words = 128MiB
|
||||
|
||||
function Bool fn_addr_ok (Bit #(64) base, Bit #(64) lim, Bit #(64) addr, AXI4_Size size);
|
||||
let aligned = fn_addr_is_aligned (addr, size);
|
||||
let in_range = ((base <= addr) && (addr < lim));
|
||||
return (aligned && in_range);
|
||||
endfunction
|
||||
|
||||
// ----------------
|
||||
|
||||
module mkAXI4_Mem_Model (AXI4_Mem_Model_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
provisos (NumAlias #(wd_addr, 64),
|
||||
NumAlias #(wd_data, 64));
|
||||
|
||||
// 0 = quiet; 1 = show mem transactions
|
||||
Integer verbosity = 1;
|
||||
|
||||
Reg #(Bool) rg_initialized <- mkReg (False);
|
||||
|
||||
Reg #(Bit #(wd_addr)) rg_addr_map_base <- mkRegU;
|
||||
Reg #(Bit #(wd_addr)) rg_addr_map_lim <- mkRegU;
|
||||
|
||||
AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user) xactor <- mkAXI4_Slave_Xactor;
|
||||
|
||||
RegFile #(Bit #(wd_addr), Bit #(wd_data)) rf <- mkRegFile (0, fromInteger (mem_size_word64));
|
||||
|
||||
// ================================================================
|
||||
// Read requests
|
||||
// TODO: does a bad addr return 'burst-len' err responses or just 1?
|
||||
|
||||
Reg #(Bit #(8)) rg_rd_beat <- mkReg (0);
|
||||
|
||||
// Recv request on RD_ADDR bus
|
||||
// Send burst responses on RD_DATA bus
|
||||
rule rl_read (rg_initialized);
|
||||
let rd_addr = xactor.o_rd_addr.first;
|
||||
let rf_index = ((rd_addr.araddr - rg_addr_map_base) >> 3);
|
||||
if (rd_addr.arburst == axburst_incr)
|
||||
rf_index = rf_index + zeroExtend (rg_rd_beat);
|
||||
let last = (rg_rd_beat == rd_addr.arlen);
|
||||
|
||||
let addr_ok = fn_addr_ok (rg_addr_map_base, rg_addr_map_lim, rd_addr.araddr, rd_addr.arsize);
|
||||
|
||||
let data = (addr_ok ? rf.sub (rf_index) : 0);
|
||||
|
||||
AXI4_Rd_Data #(wd_id, wd_data, wd_user)
|
||||
rd_data = AXI4_Rd_Data {rid: rd_addr.arid,
|
||||
rdata: data,
|
||||
rresp: (addr_ok ? axi4_resp_okay : axi4_resp_slverr),
|
||||
rlast: last,
|
||||
ruser: rd_addr.aruser};
|
||||
xactor.i_rd_data.enq (rd_data);
|
||||
|
||||
if (last) begin
|
||||
xactor.o_rd_addr.deq;
|
||||
rg_rd_beat <= 0;
|
||||
end
|
||||
else
|
||||
rg_rd_beat <= rg_rd_beat + 1;
|
||||
|
||||
if (verbosity != 0) begin
|
||||
$write ("%0d: %m.rl_read: ", cur_cycle);
|
||||
$write (fshow_Rd_Addr (rd_addr));
|
||||
$write (fshow_Rd_Data (rd_data));
|
||||
if (addr_ok)
|
||||
$display (" beat %0d rf_index 0x%0h", rg_rd_beat, rf_index);
|
||||
else
|
||||
$display (" beat 0x%0h BAD ADDR", rg_rd_beat);
|
||||
end
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// Write requests
|
||||
|
||||
Reg #(Bit #(8)) rg_wr_beat <- mkReg (0);
|
||||
|
||||
// Recv request on WR_ADDR bus and burst data on WR_DATA bus,
|
||||
// send final response on WR_RESP bus
|
||||
rule rl_write (rg_initialized);
|
||||
let wr_addr = xactor.o_wr_addr.first;
|
||||
let wr_data <- pop_o (xactor.o_wr_data);
|
||||
let rf_index = ((wr_addr.awaddr - rg_addr_map_base) >> 3);
|
||||
if (wr_addr.awburst == axburst_incr)
|
||||
rf_index = rf_index + zeroExtend (rg_wr_beat);
|
||||
let last = (rg_wr_beat == wr_addr.awlen);
|
||||
|
||||
let addr_ok = fn_addr_ok (rg_addr_map_base, rg_addr_map_lim, wr_addr.awaddr, wr_addr.awsize);
|
||||
|
||||
if (addr_ok)
|
||||
rf.upd (rf_index, wr_data.wdata);
|
||||
|
||||
if (verbosity != 0) begin
|
||||
$write ("%0d: %m.rl_write: ", cur_cycle);
|
||||
$write (fshow_Wr_Data (wr_data));
|
||||
$write (" ", fshow_Wr_Addr (wr_addr));
|
||||
if (addr_ok)
|
||||
$display (" beat %0d rf_index %0h", rg_wr_beat, rf_index);
|
||||
else
|
||||
$display (" beat %0d BAD ADDR", rg_wr_beat);
|
||||
end
|
||||
|
||||
if (last) begin
|
||||
AXI4_Wr_Resp #(wd_id, wd_user) wr_resp = ?;
|
||||
wr_resp = AXI4_Wr_Resp {bid: wr_addr.awid,
|
||||
bresp: (addr_ok ? axi4_resp_okay : axi4_resp_slverr),
|
||||
buser: wr_addr.awuser};
|
||||
xactor.i_wr_resp.enq (wr_resp);
|
||||
xactor.o_wr_addr.deq;
|
||||
rg_wr_beat <= 0;
|
||||
if (verbosity != 0)
|
||||
$display (" ", fshow_Wr_Resp (wr_resp));
|
||||
end
|
||||
else
|
||||
rg_wr_beat <= rg_wr_beat + 1;
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
method Action init (Bit #(wd_addr) addr_map_base, Bit #(wd_addr) addr_map_lim);
|
||||
if (addr_map_base [2:0] != 3'b0)
|
||||
$display ("%0d: %m.init: ERROR: unaligned addr_map_base 0x%0h", cur_cycle, addr_map_base);
|
||||
else if (addr_map_lim [2:0] != 3'b0)
|
||||
$display ("%0d: %m.init: ERROR: unaligned addr_map_lim 0x%0h", cur_cycle, addr_map_lim);
|
||||
else if (addr_map_lim <= addr_map_base)
|
||||
$display ("%0d: %m.init: ERROR: addr_map_base 0x%0h > addr_map_lim 0x%0h",
|
||||
cur_cycle,
|
||||
addr_map_base,
|
||||
addr_map_lim);
|
||||
else if ((addr_map_lim - addr_map_base) > fromInteger (mem_size_word64 * 8))
|
||||
$display ("%0d: %m.init: ERROR: mem size (base 0x%0h, lim 0x%0h) > max (0x%0h)",
|
||||
cur_cycle,
|
||||
addr_map_base,
|
||||
addr_map_lim,
|
||||
fromInteger (mem_size_word64 * 8));
|
||||
else begin
|
||||
xactor.reset;
|
||||
rg_addr_map_base <= addr_map_base;
|
||||
rg_addr_map_lim <= addr_map_lim;
|
||||
rg_initialized <= True;
|
||||
$display ("%0d: %m.init: addr_map_base 0x%0h, addr_map_lim 0x%0h",
|
||||
cur_cycle,
|
||||
addr_map_base,
|
||||
addr_map_lim);
|
||||
end
|
||||
endmethod
|
||||
|
||||
interface slave = xactor.axi_side;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
@@ -118,6 +118,20 @@ AXI4_Resp axi4_resp_exokay = 2'b_01;
|
||||
AXI4_Resp axi4_resp_slverr = 2'b_10;
|
||||
AXI4_Resp axi4_resp_decerr = 2'b_11;
|
||||
|
||||
// ================================================================
|
||||
// Function to check address-alignment
|
||||
|
||||
function Bool fn_addr_is_aligned (Bit #(wd_addr) addr, AXI4_Size size);
|
||||
return ( (size == axsize_1)
|
||||
|| ((size == axsize_2) && (addr [0] == 1'b0))
|
||||
|| ((size == axsize_4) && (addr [1:0] == 2'b0))
|
||||
|| ((size == axsize_8) && (addr [2:0] == 3'b0))
|
||||
|| ((size == axsize_16) && (addr [3:0] == 4'b0))
|
||||
|| ((size == axsize_32) && (addr [4:0] == 5'b0))
|
||||
|| ((size == axsize_64) && (addr [5:0] == 6'b0))
|
||||
|| ((size == axsize_128) && (addr [6:0] == 7'b0)));
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// These are the signal-level interfaces for an AXI4 master.
|
||||
// The (*..*) attributes ensure that when bsc compiles this to Verilog,
|
||||
@@ -150,7 +164,6 @@ interface AXI4_Master_IFC #(numeric type wd_id,
|
||||
// Wr Data channel
|
||||
(* always_ready, result="wvalid" *) method Bool m_wvalid; // out
|
||||
|
||||
(* always_ready, result="wid" *) method Bit #(wd_id) m_wid; // out
|
||||
(* always_ready, result="wdata" *) method Bit #(wd_data) m_wdata; // out
|
||||
(* always_ready, result="wstrb" *) method Bit #(TDiv #(wd_data, 8)) m_wstrb; // out
|
||||
(* always_ready, result="wlast" *) method Bool m_wlast; // out
|
||||
@@ -232,7 +245,6 @@ interface AXI4_Slave_IFC #(numeric type wd_id,
|
||||
// Wr Data channel
|
||||
(* always_ready, always_enabled, prefix = "" *)
|
||||
method Action m_wvalid ((* port="wvalid" *) Bool wvalid, // in
|
||||
(* port="wid" *) Bit #(wd_id) wid, // in
|
||||
(* port="wdata" *) Bit #(wd_data) wdata, // in
|
||||
(* port="wstrb" *) Bit #(TDiv #(wd_data,8)) wstrb, // in
|
||||
(* port="wlast" *) Bool wlast, // in
|
||||
@@ -306,7 +318,6 @@ instance Connectable #(AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user),
|
||||
(* fire_when_enabled, no_implicit_conditions *)
|
||||
rule rl_wr_data_channel;
|
||||
axis.m_wvalid (axim.m_wvalid,
|
||||
axim.m_wid,
|
||||
axim.m_wdata,
|
||||
axim.m_wstrb,
|
||||
axim.m_wlast,
|
||||
@@ -375,7 +386,6 @@ AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user)
|
||||
|
||||
// Wr Data channel
|
||||
method Bool m_wvalid = False; // out
|
||||
method Bit #(wd_id) m_wid = ?; // out
|
||||
method Bit #(wd_data) m_wdata = ?; // out
|
||||
method Bit #(TDiv #(wd_data, 8)) m_wstrb = ?; // out
|
||||
method Bool m_wlast = ?; // out
|
||||
@@ -446,7 +456,6 @@ AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user)
|
||||
|
||||
// Wr Data channel
|
||||
method Action m_wvalid (Bool wvalid,
|
||||
Bit #(wd_id) wid,
|
||||
Bit #(wd_data) wdata,
|
||||
Bit #(TDiv #(wd_data, 8)) wstrb,
|
||||
Bool wlast,
|
||||
@@ -591,13 +600,11 @@ deriving (Bits, FShow);
|
||||
// Write Data channel
|
||||
|
||||
typedef struct {
|
||||
Bit #(wd_id) wid;
|
||||
Bit #(wd_data) wdata;
|
||||
Bit #(TDiv #(wd_data, 8)) wstrb;
|
||||
Bool wlast;
|
||||
Bit #(wd_user) wuser;
|
||||
} AXI4_Wr_Data #(numeric type wd_id,
|
||||
numeric type wd_data,
|
||||
} AXI4_Wr_Data #(numeric type wd_data,
|
||||
numeric type wd_user)
|
||||
deriving (Bits, FShow);
|
||||
|
||||
@@ -643,6 +650,88 @@ typedef struct {
|
||||
numeric type wd_user)
|
||||
deriving (Bits, FShow);
|
||||
|
||||
// ================================================================
|
||||
// The following are specialized 'fshow' functions for AXI4 bus
|
||||
// payloads: the most common fields, and more compact.
|
||||
|
||||
function Fmt fshow_AXI4_Size (AXI4_Size size);
|
||||
Fmt result = ?;
|
||||
if (size == axsize_1) result = $format ("sz1");
|
||||
else if (size == axsize_2) result = $format ("sz2");
|
||||
else if (size == axsize_4) result = $format ("sz4");
|
||||
else if (size == axsize_8) result = $format ("sz8");
|
||||
else if (size == axsize_16) result = $format ("sz16");
|
||||
else if (size == axsize_32) result = $format ("sz32");
|
||||
else if (size == axsize_64) result = $format ("sz64");
|
||||
else if (size == axsize_128) result = $format ("sz128");
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function Fmt fshow_AXI4_Burst (AXI4_Burst burst);
|
||||
Fmt result = ?;
|
||||
if (burst == axburst_fixed) result = $format ("fixed");
|
||||
else if (burst == axburst_incr) result = $format ("incr");
|
||||
else if (burst == axburst_wrap) result = $format ("wrap");
|
||||
else result = $format ("burst:%0d", burst);
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function Fmt fshow_AXI4_Resp (AXI4_Resp resp);
|
||||
Fmt result = ?;
|
||||
if (resp == axi4_resp_okay) result = $format ("okay");
|
||||
else if (resp == axi4_resp_exokay) result = $format ("exokay");
|
||||
else if (resp == axi4_resp_slverr) result = $format ("slverr");
|
||||
else if (resp == axi4_resp_decerr) result = $format ("decerr");
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
// ----------------
|
||||
|
||||
function Fmt fshow_Wr_Addr (AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) x);
|
||||
Fmt result = ($format ("{awaddr:%0h,", x.awaddr)
|
||||
+ $format ("awlen:%0d", x.awlen)
|
||||
+ $format (",")
|
||||
+ fshow_AXI4_Size (x.awsize)
|
||||
+ $format (",")
|
||||
+ fshow_AXI4_Burst (x.awburst)
|
||||
+ $format ("}"));
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function Fmt fshow_Wr_Data (AXI4_Wr_Data #(wd_data, wd_user) x);
|
||||
let result = ($format ("{wdata:%0h,wstrb:%0h", x.wdata, x.wstrb)
|
||||
+ (x.wlast ? $format (",wlast") : $format (",.."))
|
||||
+ $format ("}"));
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function Fmt fshow_Wr_Resp (AXI4_Wr_Resp #(wd_id, wd_user) x);
|
||||
Fmt result = ($format ("{bresp:")
|
||||
+ fshow_AXI4_Resp (x.bresp)
|
||||
+ $format ("}"));
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function Fmt fshow_Rd_Addr (AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) x);
|
||||
Fmt result = ($format ("{araddr:%0h", x.araddr)
|
||||
+ $format (",arlen:%0d", x.arlen)
|
||||
+ $format (",")
|
||||
+ fshow_AXI4_Size (x.arsize)
|
||||
+ $format (",")
|
||||
+ fshow_AXI4_Burst (x.arburst)
|
||||
+ $format ("}"));
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function Fmt fshow_Rd_Data (AXI4_Rd_Data #(wd_id, wd_data, wd_user) x);
|
||||
Fmt result = ($format ("{rresp:")
|
||||
+ fshow_AXI4_Resp (x.rresp)
|
||||
+ $format (",rdata:%0h", x.rdata)
|
||||
+ (x.rlast ? $format (",rlast") : $format (",.."))
|
||||
+ $format ("}"));
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// AXI4 buffer
|
||||
|
||||
@@ -655,7 +744,7 @@ interface AXI4_Server_IFC #(numeric type wd_id,
|
||||
numeric type wd_user);
|
||||
|
||||
interface FIFOF_I #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) i_wr_addr;
|
||||
interface FIFOF_I #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) i_wr_data;
|
||||
interface FIFOF_I #(AXI4_Wr_Data #(wd_data, wd_user)) i_wr_data;
|
||||
interface FIFOF_O #(AXI4_Wr_Resp #(wd_id, wd_user)) o_wr_resp;
|
||||
|
||||
interface FIFOF_I #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) i_rd_addr;
|
||||
@@ -671,7 +760,7 @@ interface AXI4_Client_IFC #(numeric type wd_id,
|
||||
numeric type wd_user);
|
||||
|
||||
interface FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) o_wr_addr;
|
||||
interface FIFOF_O #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) o_wr_data;
|
||||
interface FIFOF_O #(AXI4_Wr_Data #(wd_data, wd_user)) o_wr_data;
|
||||
interface FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user)) i_wr_resp;
|
||||
|
||||
interface FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) o_rd_addr;
|
||||
@@ -695,7 +784,7 @@ endinterface
|
||||
module mkAXI4_Buffer (AXI4_Buffer_IFC #(wd_id, wd_addr, wd_data, wd_user));
|
||||
|
||||
FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkFIFOF;
|
||||
FIFOF #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) f_wr_data <- mkFIFOF;
|
||||
FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkFIFOF;
|
||||
FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkFIFOF;
|
||||
|
||||
FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkFIFOF;
|
||||
@@ -732,7 +821,7 @@ endmodule
|
||||
module mkAXI4_Buffer_2 (AXI4_Buffer_IFC #(wd_id, wd_addr, wd_data, wd_user));
|
||||
|
||||
FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkMaster_EdgeFIFOF;
|
||||
FIFOF #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) f_wr_data <- mkMaster_EdgeFIFOF;
|
||||
FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkMaster_EdgeFIFOF;
|
||||
FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkSlave_EdgeFIFOF;
|
||||
|
||||
FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkMaster_EdgeFIFOF;
|
||||
@@ -780,7 +869,7 @@ interface AXI4_Master_Xactor_IFC #(numeric type wd_id,
|
||||
|
||||
// FIFOF side
|
||||
interface FIFOF_I #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) i_wr_addr;
|
||||
interface FIFOF_I #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) i_wr_data;
|
||||
interface FIFOF_I #(AXI4_Wr_Data #(wd_data, wd_user)) i_wr_data;
|
||||
interface FIFOF_O #(AXI4_Wr_Resp #(wd_id, wd_user)) o_wr_resp;
|
||||
|
||||
interface FIFOF_I #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) i_rd_addr;
|
||||
@@ -798,7 +887,7 @@ module mkAXI4_Master_Xactor (AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, w
|
||||
|
||||
// These FIFOs are guarded on BSV side, unguarded on AXI side
|
||||
FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkGFIFOF (guarded, unguarded);
|
||||
FIFOF #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) f_wr_data <- mkGFIFOF (guarded, unguarded);
|
||||
FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkGFIFOF (guarded, unguarded);
|
||||
FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkGFIFOF (unguarded, guarded);
|
||||
|
||||
FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkGFIFOF (guarded, unguarded);
|
||||
@@ -836,7 +925,6 @@ module mkAXI4_Master_Xactor (AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, w
|
||||
|
||||
// Wr Data channel
|
||||
method Bool m_wvalid = f_wr_data.notEmpty;
|
||||
method Bit #(wd_id) m_wid = f_wr_data.first.wid;
|
||||
method Bit #(wd_data) m_wdata = f_wr_data.first.wdata;
|
||||
method Bit #(TDiv #(wd_data, 8)) m_wstrb = f_wr_data.first.wstrb;
|
||||
method Bool m_wlast = f_wr_data.first.wlast;
|
||||
@@ -921,7 +1009,7 @@ module mkAXI4_Master_Xactor_2 (AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data,
|
||||
Reg #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) rg_wr_addr <- mkRegU;
|
||||
|
||||
Array #(Reg #(Bool)) crg_wr_data_full <- mkCReg (3, False);
|
||||
Reg #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) rg_wr_data <- mkRegU;
|
||||
Reg #(AXI4_Wr_Data #(wd_data, wd_user)) rg_wr_data <- mkRegU;
|
||||
|
||||
Array #(Reg #(Bool)) crg_wr_resp_full <- mkCReg (3, False);
|
||||
Reg #(AXI4_Wr_Resp #(wd_id, wd_user)) rg_wr_resp <- mkRegU;
|
||||
@@ -975,7 +1063,6 @@ module mkAXI4_Master_Xactor_2 (AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data,
|
||||
|
||||
// Wr Data channel
|
||||
method Bool m_wvalid = crg_wr_data_full [port_deq];
|
||||
method Bit #(wd_id) m_wid = rg_wr_data.wid;
|
||||
method Bit #(wd_data) m_wdata = rg_wr_data.wdata;
|
||||
method Bit #(TDiv #(wd_data, 8)) m_wstrb = rg_wr_data.wstrb;
|
||||
method Bool m_wlast = rg_wr_data.wlast;
|
||||
@@ -1065,7 +1152,7 @@ interface AXI4_Slave_Xactor_IFC #(numeric type wd_id,
|
||||
|
||||
// FIFOF side
|
||||
interface FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) o_wr_addr;
|
||||
interface FIFOF_O #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) o_wr_data;
|
||||
interface FIFOF_O #(AXI4_Wr_Data #(wd_data, wd_user)) o_wr_data;
|
||||
interface FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user)) i_wr_resp;
|
||||
|
||||
interface FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) o_rd_addr;
|
||||
@@ -1083,7 +1170,7 @@ module mkAXI4_Slave_Xactor (AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_
|
||||
|
||||
// These FIFOs are guarded on BSV side, unguarded on AXI side
|
||||
FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkGFIFOF (unguarded, guarded);
|
||||
FIFOF #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) f_wr_data <- mkGFIFOF (unguarded, guarded);
|
||||
FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkGFIFOF (unguarded, guarded);
|
||||
FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkGFIFOF (guarded, unguarded);
|
||||
|
||||
FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkGFIFOF (unguarded, guarded);
|
||||
@@ -1135,14 +1222,12 @@ module mkAXI4_Slave_Xactor (AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_
|
||||
|
||||
// Wr Data channel
|
||||
method Action m_wvalid (Bool wvalid,
|
||||
Bit #(wd_id) wid,
|
||||
Bit #(wd_data) wdata,
|
||||
Bit #(TDiv #(wd_data, 8)) wstrb,
|
||||
Bool wlast,
|
||||
Bit #(wd_user) wuser);
|
||||
if (wvalid && f_wr_data.notFull)
|
||||
f_wr_data.enq (AXI4_Wr_Data {wid: wid,
|
||||
wdata: wdata,
|
||||
f_wr_data.enq (AXI4_Wr_Data {wdata: wdata,
|
||||
wstrb: wstrb,
|
||||
wlast: wlast,
|
||||
wuser: wuser});
|
||||
@@ -1229,7 +1314,7 @@ module mkAXI4_Slave_Xactor_2 (AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, w
|
||||
Reg #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) rg_wr_addr <- mkRegU;
|
||||
|
||||
Array #(Reg #(Bool)) crg_wr_data_full <- mkCReg (3, False);
|
||||
Reg #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) rg_wr_data <- mkRegU;
|
||||
Reg #(AXI4_Wr_Data #(wd_data, wd_user)) rg_wr_data <- mkRegU;
|
||||
|
||||
Array #(Reg #(Bool)) crg_wr_resp_full <- mkCReg (3, False);
|
||||
Reg #(AXI4_Wr_Resp #(wd_id, wd_user)) rg_wr_resp <- mkRegU;
|
||||
@@ -1295,15 +1380,13 @@ module mkAXI4_Slave_Xactor_2 (AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, w
|
||||
|
||||
// Wr Data channel
|
||||
method Action m_wvalid (Bool wvalid,
|
||||
Bit #(wd_id) wid,
|
||||
Bit #(wd_data) wdata,
|
||||
Bit #(TDiv #(wd_data, 8)) wstrb,
|
||||
Bool wlast,
|
||||
Bit #(wd_user) wuser);
|
||||
if (wvalid && (! crg_wr_data_full [port_enq])) begin
|
||||
crg_wr_data_full [port_enq] <= True; // enq
|
||||
rg_wr_data <= AXI4_Wr_Data {wid: wid,
|
||||
wdata: wdata,
|
||||
rg_wr_data <= AXI4_Wr_Data {wdata: wdata,
|
||||
wstrb: wstrb,
|
||||
wlast: wlast,
|
||||
wuser: wuser};
|
||||
|
||||
73
src_Testbench/Fabrics/AXI4/Unit_Test/Makefile
Normal file
73
src_Testbench/Fabrics/AXI4/Unit_Test/Makefile
Normal file
@@ -0,0 +1,73 @@
|
||||
### -*-Makefile-*-
|
||||
|
||||
# Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
# Makefile for standalone Unit Tester for Deburster (Bluesim only)
|
||||
|
||||
.PHONY: all
|
||||
all: compile simulator
|
||||
|
||||
# ================================================================
|
||||
# Search path for bsc for .bsv files
|
||||
|
||||
BSV_ADDL_LIBS=../../../../src_Core/BSV_Additional_Libs
|
||||
|
||||
BSC_PATH = -p ..:$(BSV_ADDL_LIBS):+
|
||||
|
||||
# ----------------
|
||||
# Top-level file and module
|
||||
|
||||
TOPFILE = Unit_Test_Deburster.bsv
|
||||
TOPMODULE = mkUnit_Test_Deburster
|
||||
|
||||
# ================================================================
|
||||
# bsc compilation flags
|
||||
|
||||
BSC_COMPILATION_FLAGS += \
|
||||
-keep-fires -aggressive-conditions -no-warn-action-shadowing -no-show-timestamps -check-assert \
|
||||
-suppress-warnings G0020 \
|
||||
+RTS -K128M -RTS -show-range-conflict
|
||||
|
||||
# ================================================================
|
||||
# Compile Bluesim intermediate files from BSV sources (needs Bluespec 'bsc' compiler)
|
||||
|
||||
TMP_DIRS = -bdir build_dir -simdir build_dir -info-dir build_dir
|
||||
|
||||
build_dir:
|
||||
mkdir -p $@
|
||||
|
||||
.PHONY: compile
|
||||
compile: build_dir
|
||||
@echo "INFO: Re-compiling BSV sources"
|
||||
bsc -u -elab -sim $(TMP_DIRS) $(BSC_COMPILATION_FLAGS) $(BSC_PATH) $(TOPFILE)
|
||||
@echo "INFO: Re-compiled BSV sources"
|
||||
|
||||
# ================================================================
|
||||
# Compile and link Bluesim intermediate files into a Bluesim executable
|
||||
|
||||
SIM_EXE_FILE = exe_HW_sim
|
||||
|
||||
BSC_C_FLAGS += \
|
||||
-Xc++ -D_GLIBCXX_USE_CXX11_ABI=0 \
|
||||
-Xl -v
|
||||
|
||||
.PHONY: simulator
|
||||
simulator:
|
||||
@echo "INFO: linking bsc-compiled objects into Bluesim executable"
|
||||
bsc -sim -parallel-sim-link 8 \
|
||||
$(TMP_DIRS) \
|
||||
-e $(TOPMODULE) -o ./$(SIM_EXE_FILE) \
|
||||
$(BSC_C_FLAGS)
|
||||
@echo "INFO: linked bsc-compiled objects into Bluesim executable"
|
||||
|
||||
# ================================================================
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -r -f *~ build_dir
|
||||
|
||||
.PHONY: full_clean
|
||||
full_clean: clean
|
||||
rm -r -f $(SIM_EXE_FILE)* *.log *.vcd
|
||||
|
||||
# ================================================================
|
||||
289
src_Testbench/Fabrics/AXI4/Unit_Test/Unit_Test_Deburster.bsv
Normal file
289
src_Testbench/Fabrics/AXI4/Unit_Test/Unit_Test_Deburster.bsv
Normal file
@@ -0,0 +1,289 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package Unit_Test_Deburster;
|
||||
|
||||
// ================================================================
|
||||
// Standalone unit tester for AXI4_Deburster.bsv
|
||||
|
||||
// ================================================================
|
||||
// Bluespec library imports
|
||||
|
||||
import FIFOF :: *;
|
||||
import Connectable :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import Semi_FIFOF :: *;
|
||||
import AXI4_Types :: *;
|
||||
import AXI4_Deburster :: *;
|
||||
|
||||
// ================================================================
|
||||
// Synthesized instance of Deburster
|
||||
|
||||
typedef 4 Wd_Id;
|
||||
typedef 32 Wd_Addr;
|
||||
typedef 64 Wd_Data;
|
||||
typedef 10 Wd_User;
|
||||
|
||||
typedef AXI4_Deburster_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) AXI4_Deburster_IFC_Inst;
|
||||
|
||||
(* synthesize *)
|
||||
module mkAXI4_Deburster_Inst (AXI4_Deburster_IFC_Inst);
|
||||
let m <- mkAXI4_Deburster;
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
(* synthesize *)
|
||||
module mkUnit_Test_Deburster (Empty);
|
||||
AXI4_Deburster_IFC_Inst deburster <- mkAXI4_Deburster_Inst;
|
||||
|
||||
AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master <- mkAXI4_Master_Xactor;
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave <- mkAXI4_Slave_Xactor;
|
||||
|
||||
mkConnection (master.axi_side, deburster.from_master);
|
||||
mkConnection (deburster.to_slave, slave.axi_side);
|
||||
|
||||
Reg #(Bit #(32)) rg_test <- mkReg (20); // Chooses which test to run
|
||||
|
||||
FIFOF #(Bit #(8)) f_len <- mkFIFOF;
|
||||
Reg #(Bit #(8)) rg_beat <- mkReg (0);
|
||||
Reg #(Bit #(32)) rg_idle_count <- mkReg (0);
|
||||
|
||||
// ================================================================
|
||||
// Help function to create AXI4 channel payloads
|
||||
|
||||
function AXI4_Wr_Addr #(Wd_Id, Wd_Addr, Wd_User)
|
||||
fv_mk_wr_addr (Bit #(Wd_Id) id,
|
||||
Bit #(Wd_Addr) addr,
|
||||
Bit #(8) len,
|
||||
Bit #(2) burst,
|
||||
Bit #(Wd_User) user);
|
||||
return AXI4_Wr_Addr {awid: id,
|
||||
awaddr: addr,
|
||||
awlen: len,
|
||||
awsize: axsize_8,
|
||||
awburst: burst,
|
||||
awlock: 0,
|
||||
awcache: 0,
|
||||
awprot: 0,
|
||||
awqos: 0,
|
||||
awregion: 0,
|
||||
awuser: user};
|
||||
endfunction
|
||||
|
||||
function AXI4_Wr_Data #(Wd_Data, Wd_User)
|
||||
fv_mk_wr_data (Bit #(Wd_Data) data,
|
||||
Bit #(Wd_User) user);
|
||||
Bool last = (rg_beat == f_len.first - 1);
|
||||
return AXI4_Wr_Data {wdata: data,
|
||||
wstrb: 'hFF,
|
||||
wlast: last,
|
||||
wuser: user};
|
||||
endfunction
|
||||
|
||||
function AXI4_Wr_Resp #(Wd_Id, Wd_User)
|
||||
fv_mk_wr_resp (AXI4_Wr_Addr #(Wd_Id, Wd_Addr, Wd_User) wa);
|
||||
return AXI4_Wr_Resp {bid: wa.awid,
|
||||
bresp: axi4_resp_okay,
|
||||
buser: wa.awuser};
|
||||
endfunction
|
||||
|
||||
function AXI4_Rd_Addr #(Wd_Id, Wd_Addr, Wd_User)
|
||||
fv_mk_rd_addr (Bit #(Wd_Id) id,
|
||||
Bit #(Wd_Addr) addr,
|
||||
Bit #(8) len,
|
||||
Bit #(2) burst,
|
||||
Bit #(Wd_User) user);
|
||||
return AXI4_Rd_Addr {arid: id,
|
||||
araddr: addr,
|
||||
arlen: len,
|
||||
arsize: axsize_8,
|
||||
arburst: burst,
|
||||
arlock: 0,
|
||||
arcache: 0,
|
||||
arprot: 0,
|
||||
arqos: 0,
|
||||
arregion: 0,
|
||||
aruser: user};
|
||||
endfunction
|
||||
|
||||
function AXI4_Rd_Data #(Wd_Id, Wd_Data, Wd_User)
|
||||
fv_mk_rd_data (AXI4_Rd_Addr #(Wd_Id, Wd_Addr, Wd_User) ar);
|
||||
return AXI4_Rd_Data {rid: ar.arid,
|
||||
rdata: zeroExtend (ar.araddr + 'h10_000),
|
||||
rresp: axi4_resp_okay,
|
||||
rlast: True,
|
||||
ruser: ar.aruser};
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// STIMULUS
|
||||
|
||||
Bit #(Wd_Id) id1 = 1;
|
||||
Bit #(Wd_User) user1 = 1;
|
||||
|
||||
// ----------------
|
||||
// Write tests
|
||||
|
||||
rule rl_wr_single (rg_test == 0);
|
||||
Bit #(8) len = 1;
|
||||
let wa = fv_mk_wr_addr (id1, 'h1000, (len - 1), axburst_fixed, user1);
|
||||
master.i_wr_addr.enq (wa);
|
||||
|
||||
f_len.enq (len);
|
||||
rg_idle_count <= 0;
|
||||
rg_test <= 100;
|
||||
|
||||
$display ("%0d: master.rl_wr_single: ", cur_cycle);
|
||||
$display (" ", fshow (wa));
|
||||
endrule
|
||||
|
||||
rule rl_wr_burst_addr_0 (rg_test == 10);
|
||||
Bit #(8) len = 2;
|
||||
let wa = fv_mk_wr_addr (id1, 'h1000, (len - 1), axburst_incr, user1);
|
||||
master.i_wr_addr.enq (wa);
|
||||
|
||||
f_len.enq (len);
|
||||
rg_idle_count <= 0;
|
||||
rg_test <= 11;
|
||||
|
||||
$display ("%0d: master.rl_wr_burst_addr_0: ", cur_cycle);
|
||||
$display (" ", fshow (wa));
|
||||
endrule
|
||||
|
||||
rule rl_wr_burst_addr_1 (rg_test == 11);
|
||||
Bit #(8) len = 4;
|
||||
let wa = fv_mk_wr_addr (id1, 'h2000, (len - 1), axburst_incr, user1);
|
||||
master.i_wr_addr.enq (wa);
|
||||
|
||||
f_len.enq (len);
|
||||
rg_idle_count <= 0;
|
||||
rg_test <= 100;
|
||||
|
||||
$display ("%0d: master.rl_wr_burst_addr_1: ", cur_cycle);
|
||||
$display (" ", fshow (wa));
|
||||
endrule
|
||||
|
||||
rule rl_wr_data;
|
||||
let data = 'h1_0000 + zeroExtend (rg_beat);
|
||||
let wd = fv_mk_wr_data (data, user1);
|
||||
master.i_wr_data.enq (wd);
|
||||
rg_idle_count <= 0;
|
||||
|
||||
if (rg_beat < f_len.first - 1)
|
||||
rg_beat <= rg_beat + 1;
|
||||
else begin
|
||||
rg_beat <= 0;
|
||||
f_len.deq;
|
||||
|
||||
rg_test <= '1;
|
||||
end
|
||||
|
||||
$display ("%0d: master.rl_wr_data: ", cur_cycle);
|
||||
$display (" ", fshow (wd));
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Read tests
|
||||
|
||||
rule rl_rd_single (rg_test == 2);
|
||||
let ra = fv_mk_rd_addr (id1, 'h1000, 1, axburst_fixed, user1);
|
||||
master.i_rd_addr.enq (ra);
|
||||
rg_idle_count <= 0;
|
||||
rg_test <= '1;
|
||||
|
||||
$display ("%0d: master.rd_single: ", cur_cycle);
|
||||
$display (" ", fshow (ra));
|
||||
endrule
|
||||
|
||||
rule rl_rd_burst_addr_0 (rg_test == 20);
|
||||
Bit #(8) len = 2;
|
||||
let ra = fv_mk_rd_addr (id1, 'h1000, (len - 1), axburst_incr, user1);
|
||||
master.i_rd_addr.enq (ra);
|
||||
|
||||
rg_idle_count <= 0;
|
||||
rg_test <= 21;
|
||||
|
||||
$display ("%0d: master.rl_rd_burst_addr_0: ", cur_cycle);
|
||||
$display (" ", fshow (ra));
|
||||
endrule
|
||||
|
||||
rule rl_rd_burst_addr_1 (rg_test == 21);
|
||||
Bit #(8) len = 4;
|
||||
let ra = fv_mk_rd_addr (id1, 'h2000, (len - 1), axburst_incr, user1);
|
||||
master.i_rd_addr.enq (ra);
|
||||
|
||||
rg_idle_count <= 0;
|
||||
rg_test <= 100;
|
||||
|
||||
$display ("%0d: master.rl_rd_burst_addr_1: ", cur_cycle);
|
||||
$display (" ", fshow (ra));
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// Drain and display responses received by master
|
||||
|
||||
rule rl_wr_resps;
|
||||
let wr_resp <- pop_o (master.o_wr_resp);
|
||||
$display ("%0d: master: ", cur_cycle);
|
||||
$display (" ", fshow (wr_resp));
|
||||
rg_idle_count <= 0;
|
||||
endrule
|
||||
|
||||
rule rl_rd_resps;
|
||||
let rd_resp <- pop_o (master.o_rd_data);
|
||||
$display ("%0d: master: ", cur_cycle);
|
||||
$display (" ", fshow (rd_resp));
|
||||
rg_idle_count <= 0;
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// Slave: return functional responses
|
||||
// Note: we should not be receiving any bursts, since we're fronted by the Deburster.
|
||||
|
||||
rule rl_slave_IP_model_writes;
|
||||
$display ("%0d: %m.rl_slave_IP_model_writes: ", cur_cycle);
|
||||
|
||||
let wa <- pop_o (slave.o_wr_addr);
|
||||
let wd <- pop_o (slave.o_wr_data);
|
||||
|
||||
let wr = fv_mk_wr_resp (wa);
|
||||
slave.i_wr_resp.enq (wr);
|
||||
$display (" ", fshow (wa));
|
||||
$display (" ", fshow (wd));
|
||||
$display (" ", fshow (wr));
|
||||
endrule
|
||||
|
||||
rule rl_slave_IP_model_rd_addr;
|
||||
let ra <- pop_o (slave.o_rd_addr);
|
||||
slave.i_rd_data.enq (fv_mk_rd_data (ra));
|
||||
|
||||
$display ("%0d: slave: ", cur_cycle);
|
||||
$display (" ", fshow (ra));
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
|
||||
rule rl_idle_quit;
|
||||
if (rg_idle_count == 100) begin
|
||||
$display ("%0d: UnitTest_Deburster: idle; quit", cur_cycle);
|
||||
$finish (0);
|
||||
end
|
||||
else begin
|
||||
rg_idle_count <= rg_idle_count + 1;
|
||||
end
|
||||
endrule
|
||||
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
@@ -47,7 +47,9 @@ Bits_per_Raw_Mem_Word,
|
||||
Raw_Mem_Word,
|
||||
|
||||
Mem_Controller_IFC (..),
|
||||
mkMem_Controller;
|
||||
mkMem_Controller,
|
||||
|
||||
status_mem_controller_terminated;
|
||||
|
||||
// ================================================================
|
||||
// BSV library imports
|
||||
@@ -173,6 +175,11 @@ typedef enum {STATE_POWER_ON_RESET,
|
||||
} State
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
// ================================================================
|
||||
// Catch-all status
|
||||
|
||||
Integer status_mem_controller_terminated = 1;
|
||||
|
||||
// ================================================================
|
||||
// Interface
|
||||
|
||||
@@ -189,6 +196,10 @@ interface Mem_Controller_IFC;
|
||||
// To raw memory (outside the SoC)
|
||||
interface MemoryClient #(Bits_per_Raw_Mem_Addr, Bits_per_Raw_Mem_Word) to_raw_mem;
|
||||
|
||||
// Catch-all status; return-value can identify the origin (0 = none)
|
||||
(* always_ready *)
|
||||
method Bit #(8) status;
|
||||
|
||||
// For ISA tests: watch memory writes to <tohost> addr
|
||||
method Action set_watch_tohost (Bool watch_tohost, Fabric_Addr tohost_addr);
|
||||
endinterface
|
||||
@@ -263,6 +274,9 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
Reg #(Bool) rg_watch_tohost <- mkReg (False);
|
||||
Reg #(Fabric_Addr) rg_tohost_addr <- mkReg ('h_8000_1000);
|
||||
|
||||
// Catch-all status
|
||||
Reg #(Bit #(8)) rg_status <- mkReg (0);
|
||||
|
||||
// ================================================================
|
||||
// BEHAVIOR
|
||||
|
||||
@@ -274,6 +288,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
slave_xactor.reset;
|
||||
f_raw_mem_reqs.clear;
|
||||
f_raw_mem_rsps.clear;
|
||||
rg_status <= 0;
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -535,7 +550,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
$display ("PASS");
|
||||
else
|
||||
$display ("FAIL %0d", exit_value);
|
||||
$finish (truncate (exit_value));
|
||||
rg_status <= fromInteger (status_mem_controller_terminated);
|
||||
end
|
||||
endrule
|
||||
|
||||
@@ -642,6 +657,11 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
// To raw memory (outside the SoC)
|
||||
interface to_raw_mem = toGPClient (f_raw_mem_reqs, f_raw_mem_rsps);
|
||||
|
||||
// Catch-all status; return-value can identify the origin (0 = none)
|
||||
method Bit #(8) status;
|
||||
return rg_status;
|
||||
endmethod
|
||||
|
||||
// For ISA tests: watch memory writes to <tohost> addr
|
||||
method Action set_watch_tohost (Bool watch_tohost, Fabric_Addr tohost_addr);
|
||||
rg_watch_tohost <= watch_tohost;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved.
|
||||
// Copyright (c) 2016-2020 Bluespec, Inc. All Rights Reserved.
|
||||
|
||||
//-
|
||||
// RVFI_DII modifications:
|
||||
@@ -31,6 +31,7 @@ import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
import Connectable :: *;
|
||||
import Memory :: *;
|
||||
import Clocks :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
@@ -42,8 +43,9 @@ import GetPut_Aux :: *;
|
||||
// Project imports
|
||||
|
||||
// Main fabric
|
||||
import AXI4_Types :: *;
|
||||
import AXI4_Fabric :: *;
|
||||
import AXI4_Types :: *;
|
||||
import AXI4_Fabric :: *;
|
||||
import AXI4_Deburster :: *;
|
||||
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
@@ -64,7 +66,8 @@ import Camera_Model :: *;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
import Accel_AES :: *;
|
||||
import AXI4_Accel_IFC :: *;
|
||||
import AXI4_Accel :: *;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
@@ -77,16 +80,9 @@ import Types :: *;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
import External_Control :: *; // Control requests/responses from HSFE
|
||||
import Debug_Module :: *;
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// Local types and constants
|
||||
|
||||
typedef enum {SOC_START, SOC_RESETTING, SOC_IDLE} SoC_State
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
// ================================================================
|
||||
// The outermost interface of the SoC
|
||||
|
||||
@@ -95,8 +91,11 @@ interface SoC_Top_IFC;
|
||||
method Action set_verbosity (Bit #(4) verbosity, Bit #(64) logdelay);
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// To external controller (E.g., GDB)
|
||||
interface Server #(Control_Req, Control_Rsp) server_external_control;
|
||||
// DMI (Debug Module Interface) facing remote debugger
|
||||
interface DMI dmi;
|
||||
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
interface Client #(Bool, Bool) ndm_reset_client;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
@@ -113,15 +112,29 @@ interface SoC_Top_IFC;
|
||||
interface Get #(Bit #(8)) get_to_console;
|
||||
interface Put #(Bit #(8)) put_from_console;
|
||||
|
||||
// Catch-all status; return-value can identify the origin (0 = none)
|
||||
(* always_ready *)
|
||||
method Bit #(8) status;
|
||||
|
||||
// Start CPU execution
|
||||
// For ISA tests: watch memory writes to <tohost> addr
|
||||
method Action set_watch_tohost (Bool watch_tohost, Fabric_Addr tohost_addr);
|
||||
method Action start (Fabric_Addr tohost_addr, Fabric_Addr fromhost_addr);
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// Local types and constants
|
||||
|
||||
typedef enum {SOC_START,
|
||||
SOC_RESETTING,
|
||||
SOC_IDLE} SoC_State
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
// ================================================================
|
||||
// The module
|
||||
|
||||
(* synthesize *)
|
||||
module mkSoC_Top (SoC_Top_IFC);
|
||||
module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
(SoC_Top_IFC);
|
||||
Integer verbosity = 0; // Normally 0; non-zero for debugging
|
||||
|
||||
Reg #(SoC_State) rg_state <- mkReg (SOC_START);
|
||||
@@ -130,23 +143,35 @@ module mkSoC_Top (SoC_Top_IFC);
|
||||
SoC_Map_IFC soc_map <- mkSoC_Map;
|
||||
|
||||
// Core: CPU + Near_Mem_IO (CLINT) + PLIC + Debug module (optional) + TV (optional)
|
||||
CoreW_IFC #(N_External_Interrupt_Sources) corew <- mkCoreW;
|
||||
// The Debug Module has its own RST_N reset signal (which comes
|
||||
// from outside this module as a paramter)
|
||||
CoreW_IFC #(N_External_Interrupt_Sources) corew <- mkCoreW (dm_power_on_reset);
|
||||
|
||||
// SoC Fabric
|
||||
Fabric_AXI4_IFC fabric <- mkFabric_AXI4;
|
||||
|
||||
// SoC Boot ROM
|
||||
Boot_ROM_IFC boot_rom <- mkBoot_ROM;
|
||||
// AXI4 Deburster in front of Boot_ROM
|
||||
AXI4_Deburster_IFC #(Wd_Id,
|
||||
Wd_Addr,
|
||||
Wd_Data,
|
||||
Wd_User) boot_rom_axi4_deburster <- mkAXI4_Deburster_A;
|
||||
|
||||
// SoC Memory
|
||||
Mem_Controller_IFC mem0_controller <- mkMem_Controller;
|
||||
// AXI4 Deburster in front of SoC Memory
|
||||
AXI4_Deburster_IFC #(Wd_Id,
|
||||
Wd_Addr,
|
||||
Wd_Data,
|
||||
Wd_User) mem0_controller_axi4_deburster <- mkAXI4_Deburster_A;
|
||||
|
||||
// SoC IPs
|
||||
UART_IFC uart0 <- mkUART;
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
// Accel0 master to fabric
|
||||
Accel_AES_IFC accel_aes0 <- mkAccel_AES;
|
||||
AXI4_Accel_IFC accel0 <- mkAXI4_Accel;
|
||||
`endif
|
||||
|
||||
// ----------------
|
||||
@@ -160,26 +185,28 @@ module mkSoC_Top (SoC_Top_IFC);
|
||||
mkConnection (corew.cpu_dmem_master, fabric.v_from_masters [dmem_master_num]);
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
// accel_aes0 to fabric
|
||||
mkConnection (accel_aes0.master, fabric.v_from_masters [accel0_master_num]);
|
||||
// accel to fabric
|
||||
mkConnection (accel0.master, fabric.v_from_masters [accel0_master_num]);
|
||||
`endif
|
||||
|
||||
// ----------------
|
||||
// SoC fabric slave connections
|
||||
// Note: see 'SoC_Map' for 'slave_num' definitions
|
||||
|
||||
// Fabric to Boot ROM
|
||||
mkConnection (fabric.v_to_slaves [boot_rom_slave_num], boot_rom.slave);
|
||||
// Fabric to Deburster to Boot ROM
|
||||
mkConnection (fabric.v_to_slaves [boot_rom_slave_num], boot_rom_axi4_deburster.from_master);
|
||||
mkConnection (boot_rom_axi4_deburster.to_slave, boot_rom.slave);
|
||||
|
||||
// Fabric to Mem Controller
|
||||
mkConnection (fabric.v_to_slaves [mem0_controller_slave_num], mem0_controller.slave);
|
||||
// Fabric to Deburster to Mem Controller
|
||||
mkConnection (fabric.v_to_slaves [mem0_controller_slave_num], mem0_controller_axi4_deburster.from_master);
|
||||
mkConnection (mem0_controller_axi4_deburster.to_slave, mem0_controller.slave);
|
||||
|
||||
// Fabric to UART0
|
||||
mkConnection (fabric.v_to_slaves [uart0_slave_num], uart0.slave);
|
||||
mkConnection (fabric.v_to_slaves [uart0_slave_num], uart0.slave);
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
// Fabric to accel_aes0
|
||||
mkConnection (fabric.v_to_slaves [accel0_slave_num], accel_aes0.slave);
|
||||
// Fabric to accel0
|
||||
mkConnection (fabric.v_to_slaves [accel0_slave_num], accel0.slave);
|
||||
`endif
|
||||
|
||||
`ifdef HTIF_MEMORY
|
||||
@@ -191,152 +218,89 @@ module mkSoC_Top (SoC_Top_IFC);
|
||||
// ----------------
|
||||
// Connect interrupt sources for CPU external interrupt request inputs.
|
||||
|
||||
// Reg #(Bool) rg_intr_prev <- mkReg (False); // For debugging only
|
||||
|
||||
(* fire_when_enabled, no_implicit_conditions *)
|
||||
rule rl_connect_external_interrupt_requests;
|
||||
Bool intr = uart0.intr;
|
||||
|
||||
// UART
|
||||
corew.core_external_interrupt_sources [irq_num_uart0].m_interrupt_req (intr);
|
||||
Integer last_irq_num = irq_num_uart0;
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
Bool intr_accel0 = accel0.interrupt_req;
|
||||
core.core_external_interrupt_sources [irq_num_accel0].m_interrupt_req (intr_accel0);
|
||||
last_irq_num = irq_num_accel0;
|
||||
`endif
|
||||
|
||||
// Tie off remaining interrupt request lines (1..N)
|
||||
for (Integer j = 1; j < valueOf (N_External_Interrupt_Sources); j = j + 1)
|
||||
for (Integer j = last_irq_num + 1; j < valueOf (N_External_Interrupt_Sources); j = j + 1)
|
||||
corew.core_external_interrupt_sources [j].m_interrupt_req (False);
|
||||
|
||||
// Tie off debugger interrupt
|
||||
corew.debug_external_interrupt_req (False);
|
||||
|
||||
/* For debugging only
|
||||
if ((! rg_intr_prev) && intr)
|
||||
$display ("SoC_Top: intr posedge");
|
||||
else if (rg_intr_prev && (! intr))
|
||||
$display ("SoC_Top: intr negedge");
|
||||
|
||||
rg_intr_prev <= intr;
|
||||
*/
|
||||
// Non-maskable interrupt request. [Tie-off; TODO: connect to genuine sources]
|
||||
corew.nmi_req (False);
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// RESET BEHAVIOR WITHOUT DEBUG MODULE
|
||||
// MODULE INITIALIZATIONS
|
||||
|
||||
rule rl_reset_start_2 (rg_state == SOC_START);
|
||||
corew.cpu_reset_server.request.put (?);
|
||||
mem0_controller.server_reset.request.put (?);
|
||||
uart0.server_reset.request.put (?);
|
||||
function Action fa_reset_start_actions;
|
||||
action
|
||||
mem0_controller.server_reset.request.put (?);
|
||||
uart0.server_reset.request.put (?);
|
||||
fabric.reset;
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
fabric.reset;
|
||||
function Action fa_reset_complete_actions;
|
||||
action
|
||||
let mem0_controller_rsp <- mem0_controller.server_reset.response.get;
|
||||
let uart0_rsp <- uart0.server_reset.response.get;
|
||||
|
||||
rg_state <= SOC_RESETTING;
|
||||
// Initialize address maps of slave IPs
|
||||
boot_rom.set_addr_map (soc_map.m_boot_rom_addr_base,
|
||||
soc_map.m_boot_rom_addr_lim);
|
||||
|
||||
$display ("%0d: SoC_Top. Reset start ...", cur_cycle);
|
||||
endrule
|
||||
mem0_controller.set_addr_map (soc_map.m_mem0_controller_addr_base,
|
||||
soc_map.m_mem0_controller_addr_lim);
|
||||
|
||||
// ================================================================
|
||||
// BEHAVIOR WITH DEBUG MODULE
|
||||
uart0.set_addr_map (soc_map.m_uart0_addr_base, soc_map.m_uart0_addr_lim);
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------------------------------------------------------
|
||||
// External debug requests and responses
|
||||
|
||||
FIFOF #(Control_Req) f_external_control_reqs <- mkFIFOF;
|
||||
FIFOF #(Control_Rsp) f_external_control_rsps <- mkFIFOF;
|
||||
|
||||
Control_Req req = f_external_control_reqs.first;
|
||||
|
||||
rule rl_handle_external_req_read_request (req.op == external_control_req_op_read_control_fabric);
|
||||
f_external_control_reqs.deq;
|
||||
corew.dm_dmi.read_addr (truncate (req.arg1));
|
||||
if (verbosity != 0) begin
|
||||
$display ("%0d: SoC_Top.rl_handle_external_req_read_request", cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
endrule
|
||||
|
||||
rule rl_handle_external_req_read_response;
|
||||
let x <- corew.dm_dmi.read_data;
|
||||
let rsp = Control_Rsp {status: external_control_rsp_status_ok, result: signExtend (x)};
|
||||
f_external_control_rsps.enq (rsp);
|
||||
if (verbosity != 0) begin
|
||||
$display ("%0d: SoC_Top.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;
|
||||
corew.dm_dmi.write (truncate (req.arg1), truncate (req.arg2));
|
||||
// let rsp = Control_Rsp {status: external_control_rsp_status_ok, result: 0};
|
||||
// f_external_control_rsps.enq (rsp);
|
||||
if (verbosity != 0) begin
|
||||
$display ("%0d: SoC_Top.rl_handle_external_req_write", cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
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: SoC_Top.rl_handle_external_req_err: unknown req.op", cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// NDM reset (all except Debug Module) request from debug module
|
||||
|
||||
rule rl_reset_start (rg_state != SOC_RESETTING);
|
||||
let req <- corew.dm_ndm_reset_req_get.get;
|
||||
|
||||
corew.cpu_reset_server.request.put (?);
|
||||
mem0_controller.server_reset.request.put (?);
|
||||
uart0.server_reset.request.put (?);
|
||||
|
||||
fabric.reset;
|
||||
|
||||
rg_state <= SOC_RESETTING;
|
||||
|
||||
$display ("%0d: SoC_Top.rl_reset_start (Debug Module NDM reset, all except debug module) ...",
|
||||
cur_cycle);
|
||||
endrule
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
accel0.init (fabric_default_id,
|
||||
soc_map.m_accel0_addr_base,
|
||||
soc_map.m_accel0_addr_lim);
|
||||
`endif
|
||||
|
||||
rule rl_reset_complete (rg_state == SOC_RESETTING);
|
||||
let cpu_rsp <- corew.cpu_reset_server.response.get;
|
||||
let mem0_controller_rsp <- mem0_controller.server_reset.response.get;
|
||||
let uart0_rsp <- uart0.server_reset.response.get;
|
||||
if (verbosity != 0) begin
|
||||
$display (" SoC address map:");
|
||||
$display (" Boot ROM: 0x%0h .. 0x%0h",
|
||||
soc_map.m_boot_rom_addr_base,
|
||||
soc_map.m_boot_rom_addr_lim);
|
||||
$display (" Mem0 Controller: 0x%0h .. 0x%0h",
|
||||
soc_map.m_mem0_controller_addr_base,
|
||||
soc_map.m_mem0_controller_addr_lim);
|
||||
$display (" UART0: 0x%0h .. 0x%0h",
|
||||
soc_map.m_uart0_addr_base,
|
||||
soc_map.m_uart0_addr_lim);
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
// Initialize address maps of slave IPs
|
||||
boot_rom.set_addr_map (soc_map.m_boot_rom_addr_base,
|
||||
soc_map.m_boot_rom_addr_lim);
|
||||
// ----------------
|
||||
// Initial reset
|
||||
|
||||
mem0_controller.set_addr_map (soc_map.m_mem0_controller_addr_base,
|
||||
soc_map.m_mem0_controller_addr_lim);
|
||||
rule rl_reset_start_initial (rg_state == SOC_START);
|
||||
fa_reset_start_actions;
|
||||
rg_state <= SOC_RESETTING;
|
||||
|
||||
uart0.set_addr_map (soc_map.m_uart0_addr_base, soc_map.m_uart0_addr_lim);
|
||||
$display ("%0d: %m.rl_reset_start_initial ...", cur_cycle);
|
||||
endrule
|
||||
|
||||
rule rl_reset_complete_initial (rg_state == SOC_RESETTING);
|
||||
fa_reset_complete_actions;
|
||||
rg_state <= SOC_IDLE;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
$display ("%0d: SoC_Top: NDM reset complete (all except debug module)", cur_cycle);
|
||||
`else
|
||||
$display ("%0d: SoC_Top. Reset complete ...", cur_cycle);
|
||||
`endif
|
||||
|
||||
if (verbosity != 0) begin
|
||||
$display (" SoC address map:");
|
||||
$display (" Boot ROM: 0x%0h .. 0x%0h",
|
||||
soc_map.m_boot_rom_addr_base,
|
||||
soc_map.m_boot_rom_addr_lim);
|
||||
$display (" Mem0 Controller: 0x%0h .. 0x%0h",
|
||||
soc_map.m_mem0_controller_addr_base,
|
||||
soc_map.m_mem0_controller_addr_lim);
|
||||
$display (" UART0: 0x%0h .. 0x%0h",
|
||||
soc_map.m_uart0_addr_base,
|
||||
soc_map.m_uart0_addr_lim);
|
||||
end
|
||||
$display ("%0d: %m.rl_reset_complete_initial", cur_cycle);
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
@@ -348,7 +312,11 @@ module mkSoC_Top (SoC_Top_IFC);
|
||||
|
||||
// To external controller (E.g., GDB)
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
interface server_external_control = toGPServer (f_external_control_reqs, f_external_control_rsps);
|
||||
// DMI (Debug Module Interface) facing remote debugger
|
||||
interface DMI dmi = corew.dmi;
|
||||
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
interface Client ndm_reset_client = corew.ndm_reset_client;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
@@ -365,16 +333,34 @@ module mkSoC_Top (SoC_Top_IFC);
|
||||
interface get_to_console = uart0.get_to_console;
|
||||
interface put_from_console = uart0.put_from_console;
|
||||
|
||||
// Catch-all status; return-value can identify the origin (0 = none)
|
||||
method Bit #(8) status;
|
||||
return mem0_controller.status;
|
||||
endmethod
|
||||
|
||||
// Start CPU execution
|
||||
// For ISA tests: watch memory writes to <tohost> addr
|
||||
method Action set_watch_tohost (Bool watch_tohost, Fabric_Addr tohost_addr);
|
||||
method Action start (Fabric_Addr tohost_addr, Fabric_Addr fromhost_addr);
|
||||
Bool watch_tohost = (tohost_addr != 0);
|
||||
mem0_controller.set_watch_tohost (watch_tohost, tohost_addr);
|
||||
if (watch_tohost) begin
|
||||
let fromhost_addr = 'h_8000_1040;
|
||||
corew.set_htif_addrs (tohost_addr, fromhost_addr);
|
||||
end
|
||||
corew.start (tohost_addr, fromhost_addr);
|
||||
$display ("%0d: %m.method start (tohost %0h, fromhost %0h)",
|
||||
cur_cycle, tohost_addr, fromhost_addr);
|
||||
endmethod
|
||||
endmodule: mkSoC_Top
|
||||
|
||||
// ================================================================
|
||||
// Specialization of parameterized AXI4 Deburster for this SoC.
|
||||
|
||||
(* synthesize *)
|
||||
module mkAXI4_Deburster_A (AXI4_Deburster_IFC #(Wd_Id,
|
||||
Wd_Addr,
|
||||
Wd_Data,
|
||||
Wd_User));
|
||||
let m <- mkAXI4_Deburster;
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved
|
||||
// Copyright (c) 2016-2020 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package UART_Model;
|
||||
|
||||
// ================================================================
|
||||
// This package implements a slave IP, a UART model.
|
||||
//
|
||||
// This is a very basic (and very incomplete!!) model of a classic
|
||||
// 16550 UART, just enough to do basic character reads and writes.
|
||||
// This is a basic (and somewhat incomplete) model of a classic 16550
|
||||
// UART, enough to do basic character reads and writes, interrupts,
|
||||
// etc. Just sends/receives the chars into Get/Put interfaces,
|
||||
// leaving it to external logic to manage actual physical
|
||||
// tranmit/receive. In particular, this module does nothing about
|
||||
// clock speed, baud rates, etc.
|
||||
//
|
||||
// ----------------
|
||||
// This slave IP can be attached to fabrics with 32b- or 64b-wide data channels.
|
||||
// (NOTE: this is the width of the fabric, which can be chosen
|
||||
// independently of the native width of a CPU master on the
|
||||
// fabric (such as RV32/RV64 for a RISC-V CPU).
|
||||
// When attached to 32b-wide fabric, 64-bit locations must be
|
||||
// read/written in two 32b transaction, once for the lower 32b and
|
||||
// once for the upper 32b.
|
||||
// Bus interface width: This slave IP can be attached to fabrics with
|
||||
// 32b- or 64b-wide data channels. The type parameter 'Wd_Data' in
|
||||
// Fabric_Defs.bsv specifies this.
|
||||
//
|
||||
// Address stride: the 16550 UART's registers are just 1-byte wide.
|
||||
// As a slave IP in a system, this IP places them at aligned addresses
|
||||
// with a gap of 4 or 8 bytes. This is controlled by the Integer
|
||||
// parameter 'address_stride' in this file.
|
||||
|
||||
// Some of the 'truncate()'s and 'zeroExtend()'s below are no-ops but
|
||||
// necessary to satisfy type-checking.
|
||||
// necessary to satisfy type-checking, to manage these width
|
||||
// variations.
|
||||
// ================================================================
|
||||
|
||||
export UART_IFC (..), mkUART;
|
||||
@@ -99,7 +104,7 @@ Bit #(8) uart_lsr_dr = 8'h_01; // Data Ready
|
||||
Bit #(8) uart_lsr_reset_value = (uart_lsr_temt | uart_lsr_thre);
|
||||
|
||||
// ================================================================
|
||||
// Interface
|
||||
// THIS MODULE's INTERFACE
|
||||
|
||||
interface UART_IFC;
|
||||
// Reset
|
||||
@@ -129,19 +134,57 @@ typedef enum {STATE_START,
|
||||
} Module_State
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
// ----------------
|
||||
// Split a bus address into (offset in UART, lsbs)
|
||||
// ================================================================
|
||||
// Addressing of UART registers
|
||||
|
||||
function Tuple3 #(Bit #(2), Bit #(3), Bit #(3)) split_addr (Bit #(64) addr);
|
||||
// 8-byte stride
|
||||
Bit #(2) msbs = addr [7:6];
|
||||
Bit #(3) offset = addr [5:3];
|
||||
Bit #(3) lsbs = addr [2:0];
|
||||
// ----------------------------------------------------------------
|
||||
// UART reg addresses should be at stride 4 or 8.
|
||||
|
||||
return tuple3 (msbs, offset, lsbs);
|
||||
Integer address_stride = 4;
|
||||
// Integer address_stride = 8;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Split a bus address into (offset, lsbs), based on the address
|
||||
// stride.
|
||||
|
||||
function Tuple2 #(Bit #(64), Bit #(3)) split_addr (Bit #(64) addr);
|
||||
Bit #(64) offset = ((address_stride == 4) ? (addr >> 2) : (addr >> 3));
|
||||
Bit #(3) lsbs = ((address_stride == 4) ? { 1'b0, addr [1:0] } : addr [2:0]);
|
||||
|
||||
return tuple2 (offset, lsbs);
|
||||
endfunction
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Extract data from AXI4 byte lanes, based on the AXI4 'strobe'
|
||||
// (byte-enable) bits.
|
||||
|
||||
function Bit #(64) fn_extract_AXI4_data (Bit #(64) data, Bit #(8) strb);
|
||||
Bit #(64) result = 0;
|
||||
case (strb)
|
||||
8'b_0000_0001: result = zeroExtend (data [ 7:0]);
|
||||
8'b_0000_0010: result = zeroExtend (data [15:8]);
|
||||
8'b_0000_0100: result = zeroExtend (data [23:16]);
|
||||
8'b_0000_1000: result = zeroExtend (data [31:24]);
|
||||
8'b_0001_0000: result = zeroExtend (data [39:32]);
|
||||
8'b_0010_0000: result = zeroExtend (data [47:40]);
|
||||
8'b_0100_0000: result = zeroExtend (data [55:48]);
|
||||
8'b_1000_0000: result = zeroExtend (data [63:56]);
|
||||
|
||||
8'b_0000_0011: result = zeroExtend (data [15:0]);
|
||||
8'b_0000_1100: result = zeroExtend (data [31:16]);
|
||||
8'b_0011_0000: result = zeroExtend (data [47:32]);
|
||||
8'b_1100_0000: result = zeroExtend (data [63:48]);
|
||||
|
||||
8'b_0000_1111: result = zeroExtend (data [31:0]);
|
||||
8'b_1111_0000: result = zeroExtend (data [63:32]);
|
||||
|
||||
8'b_1111_1111: result = zeroExtend (data [63:0]);
|
||||
endcase
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// THIS MODULE's IMPLEMENTATION
|
||||
|
||||
(* synthesize *)
|
||||
module mkUART (UART_IFC);
|
||||
@@ -149,6 +192,8 @@ module mkUART (UART_IFC);
|
||||
Reg #(Bit #(8)) cfg_verbosity <- mkConfigReg (0);
|
||||
|
||||
Reg #(Module_State) rg_state <- mkReg (STATE_START);
|
||||
|
||||
// These regs represent where this UART is placed in the address space.
|
||||
Reg #(Fabric_Addr) rg_addr_base <- mkRegU;
|
||||
Reg #(Fabric_Addr) rg_addr_lim <- mkRegU;
|
||||
|
||||
@@ -156,12 +201,12 @@ module mkUART (UART_IFC);
|
||||
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
|
||||
|
||||
// ----------------
|
||||
// Connector to fabric
|
||||
// Connector to AXI4 fabric
|
||||
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
|
||||
// ----------------
|
||||
// character queues to and from the console
|
||||
// character queues to and from external circuitry for the console
|
||||
|
||||
FIFOF #(Bit #(8)) f_from_console <- mkFIFOF;
|
||||
FIFOF #(Bit #(8)) f_to_console <- mkFIFOF;
|
||||
@@ -246,61 +291,71 @@ module mkUART (UART_IFC);
|
||||
let rda <- pop_o (slave_xactor.o_rd_addr);
|
||||
|
||||
let byte_addr = rda.araddr - rg_addr_base;
|
||||
let { msbs, offset, lsbs } = split_addr (zeroExtend (byte_addr));
|
||||
match { .offset, .lsbs } = split_addr (zeroExtend (byte_addr));
|
||||
|
||||
Bit #(8) rdata_byte = 0;
|
||||
AXI4_Resp rresp = axi4_resp_okay;
|
||||
|
||||
if (lsbs != 0) begin
|
||||
$display ("%0d: ERROR: UART.rl_process_rd_req: misaligned addr", cur_cycle);
|
||||
if ((rda.araddr < rg_addr_base) || (rda.araddr >= rg_addr_lim)) begin
|
||||
$display ("%0d: %m.rl_process_rd_req: ERROR: UART addr out of bounds", cur_cycle);
|
||||
$display (" UART base addr 0x%0h limit addr 0x%0h", rg_addr_base, rg_addr_lim);
|
||||
$display (" AXI4 request: ", fshow (rda));
|
||||
rresp = axi4_resp_decerr;
|
||||
end
|
||||
else if (lsbs != 0) begin
|
||||
$display ("%0d: %m.rl_process_rd_req: ERROR: UART misaligned addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
else if (msbs != 0) begin
|
||||
$display ("%0d: ERROR: UART.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
else if (offset [63:3] != 0) begin
|
||||
$display ("%0d: %m.rl_process_rd_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
rresp = axi4_resp_decerr;
|
||||
end
|
||||
|
||||
// offset 0: RBR
|
||||
else if ((offset == addr_UART_rbr) && ((rg_lcr & uart_lcr_dlab) == 0)) begin
|
||||
else if ((offset [2:0] == addr_UART_rbr) && ((rg_lcr & uart_lcr_dlab) == 0)) begin
|
||||
// Read an input char
|
||||
rg_lsr <= (rg_lsr & (~ uart_lsr_dr)); // Reset data-ready
|
||||
rdata_byte = rg_rbr;
|
||||
end
|
||||
// offset 0: DLL
|
||||
else if ((offset == addr_UART_dll) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
else if ((offset [2:0] == addr_UART_dll) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
rdata_byte = rg_dll;
|
||||
|
||||
// offset 1: IER
|
||||
else if ((offset == addr_UART_ier) && ((rg_lcr & uart_lcr_dlab) == 0))
|
||||
else if ((offset [2:0] == addr_UART_ier) && ((rg_lcr & uart_lcr_dlab) == 0))
|
||||
rdata_byte = rg_ier;
|
||||
// offset 1: DLM
|
||||
else if ((offset == addr_UART_dlm) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
else if ((offset [2:0] == addr_UART_dlm) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
rdata_byte = rg_dlm;
|
||||
|
||||
// offset 2: IIR (read-only)
|
||||
else if (offset == addr_UART_iir) rdata_byte = fn_iir();
|
||||
else if (offset [2:0] == addr_UART_iir) rdata_byte = fn_iir();
|
||||
|
||||
// offset 3: LCR
|
||||
else if (offset == addr_UART_lcr) rdata_byte = { 0, rg_lcr };
|
||||
else if (offset [2:0] == addr_UART_lcr) rdata_byte = { 0, rg_lcr };
|
||||
// offset 4: MCR
|
||||
else if (offset == addr_UART_mcr) rdata_byte = { 0, rg_mcr };
|
||||
else if (offset [2:0] == addr_UART_mcr) rdata_byte = { 0, rg_mcr };
|
||||
// offset 5: LSR
|
||||
else if (offset == addr_UART_lsr) rdata_byte = { 0, rg_lsr };
|
||||
else if (offset [2:0] == addr_UART_lsr) rdata_byte = { 0, rg_lsr };
|
||||
// offset 6: MSR
|
||||
else if (offset == addr_UART_msr) rdata_byte = { 0, rg_msr };
|
||||
else if (offset [2:0] == addr_UART_msr) rdata_byte = { 0, rg_msr };
|
||||
// offset 7: SCR
|
||||
else if (offset == addr_UART_scr) rdata_byte = { 0, rg_scr };
|
||||
else if (offset [2:0] == addr_UART_scr) rdata_byte = { 0, rg_scr };
|
||||
|
||||
else begin
|
||||
$display ("%0d: ERROR: UART.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
$display ("%0d: %m.rl_process_rd_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
rresp = axi4_resp_decerr;
|
||||
end
|
||||
|
||||
// Send read-response to bus
|
||||
// Align data byte for AXI4 data bus based on fabric-width
|
||||
Fabric_Data rdata = zeroExtend (rdata_byte);
|
||||
if ((valueOf (Wd_Data) == 64) && (byte_addr [2:0] == 3'b100))
|
||||
rdata = rdata << 32;
|
||||
|
||||
// Send read-response to bus
|
||||
let rdr = AXI4_Rd_Data {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
@@ -309,7 +364,7 @@ module mkUART (UART_IFC);
|
||||
slave_xactor.i_rd_data.enq (rdr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: UART.rl_process_rd_req", cur_cycle);
|
||||
$display ("%0d: %m.rl_process_rd_req", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
$display (" ", fshow (rdr));
|
||||
end
|
||||
@@ -324,59 +379,63 @@ module mkUART (UART_IFC);
|
||||
|
||||
Bit #(64) wdata = zeroExtend (wrd.wdata);
|
||||
Bit #(8) wstrb = zeroExtend (wrd.wstrb);
|
||||
Bit #(8) data_byte = wdata [7:0];
|
||||
Bit #(8) data_byte = truncate (fn_extract_AXI4_data (wdata, wstrb));
|
||||
|
||||
let byte_addr = wra.awaddr - rg_addr_base;
|
||||
let { msbs, offset, lsbs } = split_addr (zeroExtend (byte_addr));
|
||||
match { .offset, .lsbs } = split_addr (zeroExtend (byte_addr));
|
||||
|
||||
AXI4_Resp bresp = axi4_resp_okay;
|
||||
|
||||
if ((lsbs != 0) || (wstrb [0] == 1'b0)) begin
|
||||
$display ("%0d: ERROR: UART.rl_process_wr_req: misaligned addr", cur_cycle);
|
||||
if ((wra.awaddr < rg_addr_base) || (wra.awaddr >= rg_addr_lim)) begin
|
||||
$display ("%0d: %m.rl_process_rd_req: ERROR: UART addr out of bounds", cur_cycle);
|
||||
$display (" UART base addr 0x%0h limit addr 0x%0h", rg_addr_base, rg_addr_lim);
|
||||
$display (" AXI4 request: ", fshow (wra));
|
||||
bresp = axi4_resp_decerr;
|
||||
end
|
||||
else if (lsbs != 0) begin
|
||||
$display ("%0d: %m.rl_process_wr_req: ERROR: UART misaligned addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
else if (msbs != 0) begin
|
||||
$display ("%0d: ERROR: UART.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
else if (offset [63:3] != 0) begin
|
||||
$display ("%0d: %m.rl_process_wr_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = axi4_resp_decerr;
|
||||
end
|
||||
|
||||
// offset 0: THR
|
||||
else if ((offset == addr_UART_thr) && ((rg_lcr & uart_lcr_dlab) == 0)) begin
|
||||
else if ((offset [2:0] == addr_UART_thr) && ((rg_lcr & uart_lcr_dlab) == 0)) begin
|
||||
// Write a char to the serial line
|
||||
rg_thr <= data_byte;
|
||||
f_to_console.enq (data_byte);
|
||||
end
|
||||
// offset 0: DLL
|
||||
else if ((offset == addr_UART_dll) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
else if ((offset [2:0] == addr_UART_dll) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
rg_dll <= data_byte;
|
||||
|
||||
// offset 1: IER
|
||||
else if ((offset == addr_UART_ier) && ((rg_lcr & uart_lcr_dlab) == 0))
|
||||
else if ((offset [2:0] == addr_UART_ier) && ((rg_lcr & uart_lcr_dlab) == 0))
|
||||
rg_ier <= data_byte;
|
||||
// offset 1: DLM
|
||||
else if ((offset == addr_UART_dlm) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
else if ((offset [2:0] == addr_UART_dlm) && ((rg_lcr & uart_lcr_dlab) != 0))
|
||||
rg_dlm <= data_byte;
|
||||
|
||||
// offset 2: FCR (write-only)
|
||||
else if (offset == addr_UART_fcr) rg_fcr <= data_byte;
|
||||
else if (offset [2:0] == addr_UART_fcr) rg_fcr <= data_byte;
|
||||
|
||||
// offset 3: LCR
|
||||
else if (offset == addr_UART_lcr) rg_lcr <= data_byte;
|
||||
else if (offset [2:0] == addr_UART_lcr) rg_lcr <= data_byte;
|
||||
// offset 4: MCR
|
||||
else if (offset == addr_UART_mcr) rg_mcr <= data_byte;
|
||||
else if (offset [2:0] == addr_UART_mcr) rg_mcr <= data_byte;
|
||||
// offset 5: LSR
|
||||
else if (offset == addr_UART_lsr) noAction; // LSR is read-only
|
||||
else if (offset [2:0] == addr_UART_lsr) noAction; // LSR is read-only
|
||||
// offset 6: MSR
|
||||
else if (offset == addr_UART_msr) noAction; // MSR is read-only
|
||||
else if (offset [2:0] == addr_UART_msr) noAction; // MSR is read-only
|
||||
// offset 7: SCR
|
||||
else if (offset == addr_UART_scr) rg_scr <= data_byte;
|
||||
else if (offset [2:0] == addr_UART_scr) rg_scr <= data_byte;
|
||||
|
||||
else begin
|
||||
$display ("%0d: ERROR: UART.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
$display ("%0d: %m.rl_process_wr_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = axi4_resp_decerr;
|
||||
@@ -389,7 +448,7 @@ module mkUART (UART_IFC);
|
||||
slave_xactor.i_wr_resp.enq (wrr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: UART.rl_process_wr_req", cur_cycle);
|
||||
$display ("%0d: %m.rl_process_wr_req", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
$display (" ", fshow (wrr));
|
||||
@@ -401,6 +460,8 @@ module mkUART (UART_IFC);
|
||||
// and deposit it into RBR
|
||||
// and set it full (LSR.DR = 1)
|
||||
|
||||
(* descending_urgency = "rl_receive, rl_process_rd_req" *)
|
||||
|
||||
rule rl_receive ((rg_lsr & uart_lsr_dr) == 0);
|
||||
let ch <- pop (f_from_console);
|
||||
rg_rbr <= ch;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved.
|
||||
// Copyright (c) 2013-2020 Bluespec, Inc. All Rights Reserved.
|
||||
|
||||
//-
|
||||
// RVFI_DII modifications:
|
||||
@@ -33,9 +33,11 @@ package Top_HW_Side;
|
||||
|
||||
`include "ProcConfig.bsv"
|
||||
|
||||
import FIFOF :: *;
|
||||
import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
import Connectable :: *;
|
||||
import Clocks :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
@@ -61,6 +63,7 @@ import C_Imports :: *;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
import External_Control :: *;
|
||||
import Debug_Module :: *;
|
||||
`endif
|
||||
|
||||
`ifdef RVFI_DII
|
||||
@@ -79,45 +82,124 @@ module mkTop_HW_Side (Empty);
|
||||
`else
|
||||
module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
||||
`endif
|
||||
SoC_Top_IFC soc_top <- mkSoC_Top;
|
||||
Mem_Model_IFC mem_model <- mkMem_Model;
|
||||
|
||||
// ================================================================
|
||||
// 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).
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
let clk <- exposeCurrentClock;
|
||||
Bool initial_reset_val = False;
|
||||
Integer ndm_reset_duration = 10; // NOTE: assuming 10 cycle reset enough for NDM
|
||||
let ndm_reset_controller <- mkReset(ndm_reset_duration, initial_reset_val, clk);
|
||||
|
||||
let ndm_reset <- mkResetEither (power_on_reset, ndm_reset_controller.new_rst);
|
||||
`else
|
||||
let ndm_reset = power_on_reset;
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// 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);
|
||||
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
|
||||
soc_top.set_verbosity (verbosity, logdelay);
|
||||
|
||||
// ----------------
|
||||
// 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
|
||||
|
||||
// ================================================================
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ================================================================
|
||||
// NDM reset from DM
|
||||
|
||||
Reg #(Bit #(8)) rg_ndm_reset_delay <- mkReg (0);
|
||||
|
||||
rule rl_ndm_reset (rg_ndm_reset_delay == 0);
|
||||
let x <- soc_top.ndm_reset_client.request.get;
|
||||
ndm_reset_controller.assertReset;
|
||||
rg_ndm_reset_delay <= fromInteger (ndm_reset_duration + 200); // NOTE: heuristic
|
||||
|
||||
$display ("%0d: %m.rl_ndm_reset: asserting NDM reset (for non-DebugModule) for %0d cycles",
|
||||
cur_cycle, ndm_reset_duration);
|
||||
endrule
|
||||
|
||||
rule rl_ndm_reset_wait (rg_ndm_reset_delay != 0);
|
||||
if (rg_ndm_reset_delay == 1) begin
|
||||
fa_reset_actions;
|
||||
Bool is_running = True;
|
||||
soc_top.ndm_reset_client.response.put (is_running);
|
||||
$display ("%0d: %m.rl_ndm_reset_wait: sent NDM reset ack (for non-DebugModule) to Debug Module",
|
||||
cur_cycle);
|
||||
end
|
||||
rg_ndm_reset_delay <= rg_ndm_reset_delay - 1;
|
||||
endrule
|
||||
// ================================================================
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// BEHAVIOR
|
||||
|
||||
`ifndef RVFI_DII
|
||||
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-2019 Bluespec, Inc. All Rights Reserved.");
|
||||
$display ("================================================================");
|
||||
|
||||
rg_banner_printed <= True;
|
||||
|
||||
// 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
|
||||
soc_top.set_verbosity (verbosity, logdelay);
|
||||
|
||||
// ----------------
|
||||
// Load tohost addr from symbol-table file
|
||||
`ifndef IVERILOG
|
||||
// Note: see 'CAVEAT FOR IVERILOG USERS' above
|
||||
Bool watch_tohost <- $test$plusargs ("tohost");
|
||||
let tha <- c_get_symbol_val ("tohost");
|
||||
Fabric_Addr tohost_addr = truncate (tha);
|
||||
$display ("INFO: watch_tohost = %0d, tohost_addr = 0x%0h",
|
||||
pack (watch_tohost), tohost_addr);
|
||||
soc_top.set_watch_tohost (watch_tohost, tohost_addr);
|
||||
`endif
|
||||
fa_reset_actions;
|
||||
|
||||
// ----------------
|
||||
// Open file for Tandem Verification trace output
|
||||
@@ -154,7 +236,6 @@ module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
||||
`endif
|
||||
|
||||
endrule
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// Tandem verifier: drain and output vectors of bytes
|
||||
@@ -229,6 +310,10 @@ module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
||||
// 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];
|
||||
@@ -247,14 +332,14 @@ module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
||||
let control_req = Control_Req {op: external_control_req_op_read_control_fabric,
|
||||
arg1: zeroExtend (addr),
|
||||
arg2: 0};
|
||||
soc_top.server_external_control.request.put (control_req);
|
||||
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)};
|
||||
soc_top.server_external_control.request.put (control_req);
|
||||
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");
|
||||
@@ -269,7 +354,7 @@ module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
||||
endrule
|
||||
|
||||
rule rl_debug_client_response_send;
|
||||
let control_rsp <- soc_top.server_external_control.response.get;
|
||||
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
|
||||
@@ -278,6 +363,59 @@ module mkPre_Top_HW_Side (Toooba_RVFI_DII_Server);
|
||||
$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.dmi.read_addr (truncate (req.arg1));
|
||||
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 <- soc_top.dmi.read_data;
|
||||
let rsp = Control_Rsp {status: external_control_rsp_status_ok, result: signExtend (x)};
|
||||
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.dmi.write (truncate (req.arg1), truncate (req.arg2));
|
||||
// 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_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
|
||||
|
||||
// ================================================================
|
||||
|
||||
Reference in New Issue
Block a user