Port AXI4 changes from Flute
This commit is contained in:
@@ -1,322 +0,0 @@
|
||||
// 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
|
||||
@@ -1,448 +0,0 @@
|
||||
// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package AXI4_Fabric;
|
||||
|
||||
// ================================================================
|
||||
// This package defines a fabric connecting CPUs, Memories and DMAs
|
||||
// and other IP blocks.
|
||||
|
||||
// ================================================================
|
||||
// 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_Fabric_IFC #(numeric type tn_num_masters,
|
||||
numeric type tn_num_slaves,
|
||||
numeric type wd_id,
|
||||
numeric type wd_addr,
|
||||
numeric type wd_data,
|
||||
numeric type wd_user);
|
||||
method Action reset;
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
|
||||
// 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 #(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 (True, slave-port-num) if address is mapped to slave-port-num
|
||||
// (False, ?) if address is unmapped to any slave port
|
||||
|
||||
module mkAXI4_Fabric #(function Tuple2 #(Bool, Bit #(TLog #(tn_num_slaves)))
|
||||
fn_addr_to_slave_num (Bit #(wd_addr) addr))
|
||||
(AXI4_Fabric_IFC #(tn_num_masters, tn_num_slaves, wd_id, wd_addr, wd_data, wd_user))
|
||||
|
||||
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 #(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 #(tn_num_slaves, AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
|
||||
xactors_to_slaves <- replicateM (mkAXI4_Master_Xactor);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 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.
|
||||
|
||||
// ----------------
|
||||
// Write-transaction book-keeping
|
||||
|
||||
// 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));
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// RESET
|
||||
|
||||
rule rl_reset (rg_reset);
|
||||
$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_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_info [mi].clear;
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// BEHAVIOR
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Predicates to check if master I has transaction for slave J
|
||||
|
||||
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 == 1)
|
||||
|| (slave_num == fromInteger (sj))));
|
||||
endfunction
|
||||
|
||||
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 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 == 1)
|
||||
|| (slave_num == fromInteger (sj))));
|
||||
endfunction
|
||||
|
||||
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 (AW, W and B channels)
|
||||
|
||||
// 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 (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);
|
||||
xactors_to_slaves [sj].i_wr_addr.enq (a);
|
||||
|
||||
// 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 > 0) begin
|
||||
$display ("%0d: %m.rl_wr_xaction_master_to_slave: m%0d -> s%0d",
|
||||
cur_cycle, mi, sj);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// 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_data, wd_user) d <- pop_o (xactors_from_masters [mi].o_wr_data);
|
||||
|
||||
// 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));
|
||||
|
||||
// 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
|
||||
|
||||
// Wr data (W channel)
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 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);
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
|
||||
// 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
|
||||
end
|
||||
else
|
||||
v_rg_wd_beat_count [mi] <= v_rg_wd_beat_count [mi] + 1;
|
||||
endrule
|
||||
|
||||
// Wr responses from slaves to masters (B channel)
|
||||
|
||||
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)));
|
||||
v_f_wr_mis [sj].deq;
|
||||
v_f_wr_sjs [mi].deq;
|
||||
AXI4_Wr_Resp #(wd_id, wd_user) b <- pop_o (xactors_to_slaves [sj].o_wr_resp);
|
||||
|
||||
xactors_from_masters [mi].i_wr_resp.enq (b);
|
||||
|
||||
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 (B channel)
|
||||
// v_f_wr_sjs [mi].first has value num_slaves (illegal value)
|
||||
// v_f_wr_err_info [mi].first contains request fields 'awid' and 'awuser'
|
||||
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
|
||||
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_info [mi].deq;
|
||||
|
||||
match { .awid, .awuser } = v_f_wr_err_info [mi].first;
|
||||
|
||||
let b = AXI4_Wr_Resp {bid: awid,
|
||||
bresp: axi4_resp_decerr,
|
||||
buser: awuser};
|
||||
|
||||
xactors_from_masters [mi].i_wr_resp.enq (b);
|
||||
|
||||
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 requests (AR and R channels)
|
||||
|
||||
// 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_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_to_slaves [sj].i_rd_addr.enq (a);
|
||||
|
||||
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 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_info [mi].first contains request fields: 'arlen', 'arid', 'aruser'
|
||||
|
||||
for (Integer mi = 0; mi < num_masters; mi = mi + 1)
|
||||
|
||||
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: arid,
|
||||
rdata: data,
|
||||
rresp: axi4_resp_decerr,
|
||||
rlast: (v_rg_r_err_beat_count [mi] == arlen),
|
||||
ruser: aruser};
|
||||
|
||||
xactors_from_masters [mi].i_rd_data.enq (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)
|
||||
= xactors_from_masters [j].axi_side;
|
||||
function AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user) f2 (Integer j)
|
||||
= xactors_to_slaves [j].axi_side;
|
||||
|
||||
method Action reset () if (! rg_reset);
|
||||
rg_reset <= True;
|
||||
endmethod
|
||||
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
cfg_verbosity <= verbosity;
|
||||
endmethod
|
||||
|
||||
interface v_from_masters = genWith (f1);
|
||||
interface v_to_slaves = genWith (f2);
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage: AXI4_Fabric
|
||||
@@ -1,211 +0,0 @@
|
||||
// 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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +0,0 @@
|
||||
### -*-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
|
||||
|
||||
# ================================================================
|
||||
@@ -1,289 +0,0 @@
|
||||
// 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
|
||||
@@ -1,322 +0,0 @@
|
||||
// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package AXI4_Lite_Fabric;
|
||||
|
||||
// ================================================================
|
||||
// This package defines a fabric connecting CPUs, Memories and DMAs
|
||||
// and other IP blocks.
|
||||
|
||||
// ================================================================
|
||||
// Bluespec library imports
|
||||
|
||||
import Vector :: *;
|
||||
import FIFOF :: *;
|
||||
import SpecialFIFOs :: *;
|
||||
import ConfigReg :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import Semi_FIFOF :: *;
|
||||
import AXI4_Lite_Types :: *;
|
||||
|
||||
// ================================================================
|
||||
// The interface for the fabric module
|
||||
|
||||
interface AXI4_Lite_Fabric_IFC #(numeric type num_masters,
|
||||
numeric type num_slaves,
|
||||
numeric type wd_addr,
|
||||
numeric type wd_data,
|
||||
numeric type wd_user);
|
||||
method Action reset;
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
|
||||
// From masters
|
||||
interface Vector #(num_masters, AXI4_Lite_Slave_IFC #(wd_addr, wd_data, wd_user)) v_from_masters;
|
||||
|
||||
// To slaves
|
||||
interface Vector #(num_slaves, AXI4_Lite_Master_IFC #(wd_addr, wd_data, wd_user)) v_to_slaves;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// The Fabric module
|
||||
// The function parameter is an address-decode function, which returns
|
||||
// returns (True, slave-port-num) if address is mapped to slave-port-num
|
||||
// (False, ?) if address is unmapped to any port
|
||||
|
||||
module mkAXI4_Lite_Fabric #(function Tuple2 #(Bool, Bit #(TLog #(num_slaves)))
|
||||
fn_addr_to_slave_num (Bit #(wd_addr) addr))
|
||||
(AXI4_Lite_Fabric_IFC #(num_masters, num_slaves, 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));
|
||||
|
||||
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
|
||||
|
||||
Reg #(Bool) rg_reset <- mkReg (True);
|
||||
|
||||
// Transactors facing masters
|
||||
Vector #(num_masters, AXI4_Lite_Slave_Xactor_IFC #(wd_addr, wd_data, wd_user))
|
||||
xactors_from_masters <- replicateM (mkAXI4_Lite_Slave_Xactor);
|
||||
|
||||
// Transactors facing slaves
|
||||
Vector #(num_slaves, AXI4_Lite_Master_Xactor_IFC #(wd_addr, wd_data, wd_user))
|
||||
xactors_to_slaves <- replicateM (mkAXI4_Lite_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)
|
||||
|
||||
Vector #(num_masters, FIFOF #(Bit #(log_ns_plus_1))) v_f_wr_sjs <- 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));
|
||||
|
||||
Vector #(num_masters, FIFOF #(Bit #(log_ns_plus_1))) v_f_rd_sjs <- 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));
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// BEHAVIOR
|
||||
|
||||
rule rl_reset (rg_reset);
|
||||
$display ("%0d: AXI4_Lite_Fabric.rl_reset", cur_cycle);
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1) begin
|
||||
xactors_from_masters [mi].reset;
|
||||
|
||||
v_f_wr_sjs [mi].clear;
|
||||
v_f_wr_err_user [mi].clear;
|
||||
|
||||
v_f_rd_sjs [mi].clear;
|
||||
v_f_rd_err_user [mi].clear;
|
||||
end
|
||||
|
||||
for (Integer sj = 0; sj < valueOf (num_slaves); sj = sj + 1) begin
|
||||
xactors_to_slaves [sj].reset;
|
||||
v_f_wr_mis [sj].clear;
|
||||
v_f_rd_mis [sj].clear;
|
||||
end
|
||||
rg_reset <= False;
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Help functions for moving data from masters to slaves
|
||||
|
||||
Integer num_slaves_i = valueOf (num_slaves);
|
||||
|
||||
function Bool wr_move_from_mi_to_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)
|
||||
|| (slave_num == fromInteger (sj))));
|
||||
endfunction
|
||||
|
||||
function Bool wr_illegal_sj (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);
|
||||
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)
|
||||
|| (slave_num == fromInteger (sj))));
|
||||
endfunction
|
||||
|
||||
function Bool rd_illegal_sj (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
|
||||
|
||||
// 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)
|
||||
|
||||
rule rl_wr_xaction_master_to_slave (wr_move_from_mi_to_sj (mi, sj));
|
||||
AXI4_Lite_Wr_Addr #(wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_wr_addr);
|
||||
AXI4_Lite_Wr_Data #(wd_data) 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);
|
||||
|
||||
v_f_wr_mis [sj].enq (fromInteger (mi));
|
||||
v_f_wr_sjs [mi].enq (fromInteger (sj));
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: wr master [%0d] -> slave [%0d]", cur_cycle, mi, sj);
|
||||
$display (" ", fshow (a));
|
||||
$display (" ", fshow (d));
|
||||
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));
|
||||
AXI4_Lite_Wr_Addr #(wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_wr_addr);
|
||||
AXI4_Lite_Wr_Data #(wd_data) d <- pop_o (xactors_from_masters [mi].o_wr_data);
|
||||
|
||||
v_f_wr_sjs [mi].enq (fromInteger (valueOf (num_slaves)));
|
||||
v_f_wr_err_user [mi].enq (a.awuser);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: wr master [%0d] -> illegal addr", cur_cycle, mi);
|
||||
$display (" ", fshow (a));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd requests from masters to slaves
|
||||
|
||||
// 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)
|
||||
|
||||
rule rl_rd_xaction_master_to_slave (rd_move_from_mi_to_sj (mi, sj));
|
||||
AXI4_Lite_Rd_Addr #(wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_rd_addr);
|
||||
|
||||
xactors_to_slaves [sj].i_rd_addr.enq (a);
|
||||
|
||||
v_f_rd_mis [sj].enq (fromInteger (mi));
|
||||
v_f_rd_sjs [mi].enq (fromInteger (sj));
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: rd master [%0d] -> slave [%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_rd_xaction_no_such_slave (rd_illegal_sj (mi));
|
||||
AXI4_Lite_Rd_Addr #(wd_addr, wd_user) a <- pop_o (xactors_from_masters [mi].o_rd_addr);
|
||||
|
||||
v_f_rd_sjs [mi].enq (fromInteger (valueOf (num_slaves)));
|
||||
v_f_rd_err_user [mi].enq (a.aruser);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_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)
|
||||
|
||||
rule rl_wr_resp_slave_to_master ( (v_f_wr_mis [sj].first == fromInteger (mi))
|
||||
&& (v_f_wr_sjs [mi].first == fromInteger (sj)));
|
||||
v_f_wr_mis [sj].deq;
|
||||
v_f_wr_sjs [mi].deq;
|
||||
AXI4_Lite_Wr_Resp #(wd_user) b <- pop_o (xactors_to_slaves [sj].o_wr_resp);
|
||||
|
||||
xactors_from_masters [mi].i_wr_resp.enq (b);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: wr master [%0d] <- slave [%0d]", cur_cycle, mi, sj);
|
||||
$display (" ", fshow (b));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Wr error responses to masters
|
||||
// v_f_wr_sjs [mi].first has value num_slaves (illegal value)
|
||||
// v_f_wr_err_user [mi].first contains the request's 'user' data
|
||||
|
||||
for (Integer mi = 0; mi < valueOf (num_masters); mi = mi + 1)
|
||||
|
||||
rule rl_wr_resp_err_to_master (v_f_wr_sjs [mi].first == fromInteger (valueOf (num_slaves)));
|
||||
v_f_wr_sjs [mi].deq;
|
||||
v_f_wr_err_user [mi].deq;
|
||||
|
||||
let b = AXI4_Lite_Wr_Resp {bresp: AXI4_LITE_DECERR, buser: v_f_wr_err_user [mi].first};
|
||||
|
||||
xactors_from_masters [mi].i_wr_resp.enq (b);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: wr master [%0d] <- error", cur_cycle, mi);
|
||||
$display (" ", fshow (b));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd 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)
|
||||
|
||||
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_Lite_Rd_Data #(wd_data, wd_user) r <- pop_o (xactors_to_slaves [sj].o_rd_data);
|
||||
|
||||
xactors_from_masters [mi].i_rd_data.enq (r);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: rd master [%0d] <- slave [%0d]", cur_cycle, mi, sj);
|
||||
$display (" ", fshow (r));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Rd error responses to masters
|
||||
// v_f_rd_sjs [mi].first has value num_slaves (illegal value)
|
||||
// v_f_rd_err_user [mi].first contains the request's 'user' data
|
||||
|
||||
for (Integer mi = 0; mi < valueOf (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_user [mi].deq;
|
||||
|
||||
Bit #(wd_data) data = 0;
|
||||
let r = AXI4_Lite_Rd_Data {rresp: AXI4_LITE_DECERR, ruser: v_f_rd_err_user [mi].first, rdata: data};
|
||||
|
||||
xactors_from_masters [mi].i_rd_data.enq (r);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: AXI4_Lite_Fabric: rd master [%0d] <- error", cur_cycle, mi);
|
||||
$display (" ", fshow (r));
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// INTERFACE
|
||||
|
||||
function AXI4_Lite_Slave_IFC #(wd_addr, wd_data, wd_user) f1 (Integer j)
|
||||
= xactors_from_masters [j].axi_side;
|
||||
function AXI4_Lite_Master_IFC #(wd_addr, wd_data, wd_user) f2 (Integer j)
|
||||
= xactors_to_slaves [j].axi_side;
|
||||
|
||||
method Action reset () if (! rg_reset);
|
||||
rg_reset <= True;
|
||||
endmethod
|
||||
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
cfg_verbosity <= verbosity;
|
||||
endmethod
|
||||
|
||||
interface v_from_masters = genWith (f1);
|
||||
interface v_to_slaves = genWith (f2);
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage: AXI4_Lite_Fabric
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,151 +0,0 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package AXI4_AXI4_Lite_Adapters;
|
||||
|
||||
// ================================================================
|
||||
// Adapters for interconnecting AXI4 and AXI4_Lite.
|
||||
|
||||
// Ref: ARM document:
|
||||
// AMBA AXI and ACE Protocol Specification
|
||||
// AXI3, AXI4, and AXI4-Lite
|
||||
// ACE and ACE-Lite
|
||||
// ARM IHI 0022E (ID022613)
|
||||
// Issue E, 22 Feb 2013
|
||||
|
||||
// See export list below
|
||||
|
||||
// ================================================================
|
||||
// Exports
|
||||
|
||||
export
|
||||
|
||||
fn_AXI4_Lite_Master_IFC_to_AXI4_Master_IFC;
|
||||
|
||||
// ================================================================
|
||||
// BSV library imports
|
||||
|
||||
import FIFOF :: *;
|
||||
import Connectable :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Semi_FIFOF :: *;
|
||||
import EdgeFIFOFs :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import AXI4_Lite_Types :: *;
|
||||
import AXI4_Types :: *;
|
||||
|
||||
// ================================================================
|
||||
// Compute the encoding of AWSIZE/ARSIZE
|
||||
|
||||
function Bit #(3) wd_data_to_axsize (Integer wd_data_i);
|
||||
Bit #(3) axsize = ( (wd_data_i == 32)
|
||||
? 3'b_010
|
||||
: ( (wd_data_i == 64)
|
||||
? 3'b_011
|
||||
: 3'b_000));
|
||||
return axsize;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
|
||||
function AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user)
|
||||
fn_AXI4_Lite_Master_IFC_to_AXI4_Master_IFC
|
||||
(AXI4_Lite_Master_IFC #(wd_addr, wd_data, wd_user) axi4_lite);
|
||||
|
||||
return
|
||||
interface AXI4_Master_IFC;
|
||||
|
||||
// ----------------
|
||||
// Wr Addr channel
|
||||
// output buses
|
||||
method Bool m_awvalid = axi4_lite.m_awvalid;
|
||||
|
||||
method Bit #(wd_id) m_awid = 0;
|
||||
method Bit #(wd_addr) m_awaddr = axi4_lite.m_awaddr;
|
||||
method Bit #(8) m_awlen = 0; // burst length = awlen+1
|
||||
method Bit #(3) m_awsize = wd_data_to_axsize (valueOf (wd_data));
|
||||
method Bit #(2) m_awburst = 2'b_00; // FIXED
|
||||
method Bit #(1) m_awlock = 0; // NORMAL
|
||||
method Bit #(4) m_awcache = 4'b_0000; // Device Non-Bufferable
|
||||
method Bit #(3) m_awprot = axi4_lite.m_awprot;
|
||||
method Bit #(4) m_awqos = 4'b_0000;
|
||||
method Bit #(4) m_awregion = 4'b_0000;
|
||||
method Bit #(wd_user) m_awuser = 0;
|
||||
|
||||
// input buses
|
||||
method Action m_awready (Bool awready) = axi4_lite.m_awready (awready);
|
||||
|
||||
// ----------------
|
||||
// Wr Data channel
|
||||
// output buses
|
||||
method Bool m_wvalid = axi4_lite.m_wvalid;
|
||||
|
||||
method Bit #(wd_id) m_wid = 0;
|
||||
method Bit #(wd_data) m_wdata = axi4_lite.m_wdata;
|
||||
method Bit #(TDiv #(wd_data, 8)) m_wstrb = axi4_lite.m_wstrb;
|
||||
method Bool m_wlast = True;
|
||||
method Bit #(wd_user) m_wuser = 0;
|
||||
|
||||
// input buses
|
||||
method Action m_wready (Bool wready) = axi4_lite.m_wready (wready);
|
||||
|
||||
// ----------------
|
||||
// Wr Response channel
|
||||
// input buses
|
||||
method Action m_bvalid (Bool bvalid,
|
||||
Bit #(wd_id) bid,
|
||||
Bit #(2) bresp,
|
||||
Bit #(wd_user) buser) = axi4_lite.m_bvalid (bvalid,
|
||||
bresp,
|
||||
0);
|
||||
|
||||
// output buses
|
||||
method Bool m_bready = axi4_lite.m_bready;
|
||||
|
||||
// ----------------
|
||||
// Rd Addr channel
|
||||
// output buses
|
||||
method Bool m_arvalid = axi4_lite.m_arvalid;
|
||||
|
||||
method Bit #(wd_id) m_arid = 0;
|
||||
method Bit #(wd_addr) m_araddr = axi4_lite.m_araddr;
|
||||
method Bit #(8) m_arlen = 0; // burst length = awlen+1
|
||||
method Bit #(3) m_arsize = wd_data_to_axsize (valueOf (wd_data));
|
||||
method Bit #(2) m_arburst = 2'b_00; // FIXED
|
||||
method Bit #(1) m_arlock = 0; // NORMAL
|
||||
method Bit #(4) m_arcache = 4'b_0000; // Device Non-Bufferable
|
||||
method Bit #(3) m_arprot = axi4_lite.m_arprot;
|
||||
method Bit #(4) m_arqos = 4'b_0000;
|
||||
method Bit #(4) m_arregion = 4'b_0000;
|
||||
method Bit #(wd_user) m_aruser = axi4_lite.m_aruser;
|
||||
|
||||
// input buses
|
||||
method Action m_arready (Bool arready) = axi4_lite.m_arready (arready);
|
||||
|
||||
// ----------------
|
||||
// Rd Data channel
|
||||
// input buses
|
||||
method Action m_rvalid (Bool rvalid,
|
||||
Bit #(wd_id) rid,
|
||||
Bit #(wd_data) rdata,
|
||||
Bit #(2) rresp,
|
||||
Bool rlast,
|
||||
Bit #(wd_user) ruser) = axi4_lite.m_rvalid (rvalid,
|
||||
rresp,
|
||||
rdata,
|
||||
0);
|
||||
|
||||
// output buses
|
||||
method Bool m_rready = axi4_lite.m_rready;
|
||||
|
||||
endinterface;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
@@ -23,12 +23,14 @@ import ConfigReg :: *;
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Semi_FIFOF :: *;
|
||||
import AXI4 :: *;
|
||||
import SourceSink :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import AXI4_Types :: *;
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
|
||||
// ================================================================
|
||||
// Include the auto-generated BSV-include file with the ROM function
|
||||
@@ -49,7 +51,9 @@ interface Boot_ROM_IFC;
|
||||
method Action set_addr_map (Fabric_Addr addr_base, Fabric_Addr addr_lim);
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave;
|
||||
interface AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) slave;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
@@ -68,7 +72,9 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
// ----------------
|
||||
// Connector to fabric
|
||||
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
AXI4_Slave_Width_Xactor#(Wd_SId, Wd_Addr, Wd_Data_Periph, Wd_Data,
|
||||
Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph, Wd_AR_User_Periph, Wd_R_User_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave_xactor <- mkAXI4_Slave_Zeroing_Xactor;
|
||||
|
||||
// ----------------
|
||||
|
||||
@@ -97,14 +103,14 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
// Handle fabric read requests
|
||||
|
||||
rule rl_process_rd_req (rg_module_ready);
|
||||
let rda <- pop_o (slave_xactor.o_rd_addr);
|
||||
let rda <- get(slave_xactor.master.ar);
|
||||
|
||||
let byte_addr = rda.araddr - rg_addr_base;
|
||||
|
||||
AXI4_Resp rresp = axi4_resp_okay;
|
||||
AXI4_Resp rresp = OKAY;
|
||||
Bit #(64) data64 = 0;
|
||||
if (! fn_addr_is_ok (rg_addr_base, rda.araddr, rg_addr_lim)) begin
|
||||
rresp = axi4_resp_slverr;
|
||||
rresp = SLVERR;
|
||||
$display ("%0d: ERROR: Boot_ROM.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
end
|
||||
@@ -117,14 +123,14 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
Bit #(32) d1 = fn_read_ROM_4 (byte_addr);
|
||||
data64 = { 0, d1 };
|
||||
end
|
||||
|
||||
|
||||
Bit #(Wd_Data) rdata = truncate (data64);
|
||||
let rdr = AXI4_Rd_Data {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser};
|
||||
slave_xactor.i_rd_data.enq (rdr);
|
||||
let rdr = AXI4_RFlit {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
|
||||
if (verbosity > 0) begin
|
||||
$display ("%0d: Boot_ROM.rl_process_rd_req: ", cur_cycle);
|
||||
@@ -137,20 +143,20 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
// Handle fabric write requests: ignore all of them (this is a ROM)
|
||||
|
||||
rule rl_process_wr_req (rg_module_ready);
|
||||
let wra <- pop_o (slave_xactor.o_wr_addr);
|
||||
let wrd <- pop_o (slave_xactor.o_wr_data);
|
||||
let wra <- get(slave_xactor.master.aw);
|
||||
let wrd <- get(slave_xactor.master.w);
|
||||
|
||||
AXI4_Resp bresp = axi4_resp_okay;
|
||||
AXI4_Resp bresp = OKAY;
|
||||
if (! fn_addr_is_ok (rg_addr_base, wra.awaddr, rg_addr_lim)) begin
|
||||
bresp = axi4_resp_slverr;
|
||||
bresp = SLVERR;
|
||||
$display ("%0d: ERROR: Boot_ROM.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
end
|
||||
|
||||
let wrr = AXI4_Wr_Resp {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser};
|
||||
slave_xactor.i_wr_resp.enq (wrr);
|
||||
let wrr = AXI4_BFlit {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
|
||||
if (verbosity > 0) begin
|
||||
$display ("%0d: Boot_ROM.rl_process_wr_req; ignoring all writes", cur_cycle);
|
||||
@@ -187,13 +193,14 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
rg_addr_base <= addr_base;
|
||||
rg_addr_lim <= addr_lim;
|
||||
rg_module_ready <= True;
|
||||
slave_xactor.clear;
|
||||
if (verbosity > 0) begin
|
||||
$display ("%0d: Boot_ROM.set_addr_map: base 0x%0h lim 0x%0h", cur_cycle, addr_base, addr_lim);
|
||||
end
|
||||
endmethod
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface slave = slave_xactor.axi_side;
|
||||
interface slave = slave_xactor.slaveSynth;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -69,13 +69,14 @@ import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Semi_FIFOF :: *;
|
||||
import ByteLane :: *;
|
||||
import AXI4 :: *;
|
||||
import SourceSink :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
import AXI4_Types :: *;
|
||||
|
||||
// ================================================================
|
||||
// Raw mem data width: 256 (bits/ 32 x Byte/ 8 x Word32/ 4 x Word64)
|
||||
@@ -126,14 +127,14 @@ Integer lo_fabric_data = 3;
|
||||
// ================================================================
|
||||
|
||||
function Bool fn_addr_is_aligned (Fabric_Addr addr, AXI4_Size size);
|
||||
Bool is_aligned = ( (size == axsize_1)
|
||||
|| ((size == axsize_2) && (addr [0] == 1'h0))
|
||||
|| ((size == axsize_4) && (addr [1:0] == 2'h0))
|
||||
|| ((size == axsize_8) && (addr [2:0] == 3'h0))
|
||||
|| ((size == axsize_16) && (addr [3:0] == 4'h0))
|
||||
|| ((size == axsize_32) && (addr [4:0] == 5'h0))
|
||||
|| ((size == axsize_64) && (addr [5:0] == 6'h0))
|
||||
|| ((size == axsize_128) && (addr [6:0] == 7'h0)));
|
||||
Bool is_aligned = ( (size == 1)
|
||||
|| ((size == 2) && (addr [0] == 1'h0))
|
||||
|| ((size == 4) && (addr [1:0] == 2'h0))
|
||||
|| ((size == 8) && (addr [2:0] == 3'h0))
|
||||
|| ((size == 16) && (addr [3:0] == 4'h0))
|
||||
|| ((size == 32) && (addr [4:0] == 5'h0))
|
||||
|| ((size == 64) && (addr [5:0] == 6'h0))
|
||||
|| ((size == 128) && (addr [6:0] == 7'h0)));
|
||||
return is_aligned;
|
||||
endfunction
|
||||
|
||||
@@ -183,6 +184,8 @@ Integer status_mem_controller_terminated = 1;
|
||||
// ================================================================
|
||||
// Interface
|
||||
|
||||
typedef Wd_AW_User Wd_User;
|
||||
export Wd_User;
|
||||
interface Mem_Controller_IFC;
|
||||
// Reset
|
||||
interface Server #(Bit #(0), Bit #(0)) server_reset;
|
||||
@@ -191,7 +194,8 @@ interface Mem_Controller_IFC;
|
||||
method Action set_addr_map (Fabric_Addr addr_base, Fabric_Addr addr_lim);
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave;
|
||||
interface AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave;
|
||||
|
||||
// To raw memory (outside the SoC)
|
||||
interface MemoryClient #(Bits_per_Raw_Mem_Addr, Bits_per_Raw_Mem_Word) to_raw_mem;
|
||||
@@ -215,7 +219,7 @@ deriving (Bits, Eq, FShow);
|
||||
typedef struct {Req_Op req_op;
|
||||
|
||||
// AW and AR channel info
|
||||
Fabric_Id id;
|
||||
Bit#(Wd_SId) id;
|
||||
Fabric_Addr addr;
|
||||
AXI4_Len len;
|
||||
AXI4_Size size;
|
||||
@@ -252,7 +256,9 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
|
||||
|
||||
// Communication with fabric
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
AXI4_Slave_Width_Xactor#(Wd_SId, Wd_Addr, Wd_Data_Periph, Wd_Data,
|
||||
Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph, Wd_AR_User_Periph, Wd_R_User_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave_xactor <- mkAXI4_Slave_Zeroing_Xactor;
|
||||
|
||||
// Requests merged from the (WrA, WrD) and RdA channels
|
||||
FIFOF #(Req) f_reqs <- mkPipelineFIFOF;
|
||||
@@ -285,7 +291,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
|
||||
function Action fa_reset_actions;
|
||||
action
|
||||
slave_xactor.reset;
|
||||
slave_xactor.clear;
|
||||
f_raw_mem_reqs.clear;
|
||||
f_raw_mem_rsps.clear;
|
||||
rg_status <= 0;
|
||||
@@ -326,7 +332,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
// Merge requests into a single queue, prioritizing reads over writes
|
||||
|
||||
rule rl_merge_rd_req;
|
||||
let rda <- pop_o (slave_xactor.o_rd_addr);
|
||||
let rda <- get(slave_xactor.master.ar);
|
||||
let req = Req {req_op: REQ_OP_RD,
|
||||
id: rda.arid,
|
||||
addr: rda.araddr,
|
||||
@@ -351,8 +357,8 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
|
||||
(* descending_urgency = "rl_merge_rd_req, rl_merge_wr_req" *)
|
||||
rule rl_merge_wr_req;
|
||||
let wra <- pop_o (slave_xactor.o_wr_addr);
|
||||
let wrd <- pop_o (slave_xactor.o_wr_data);
|
||||
let wra <- get(slave_xactor.master.aw);
|
||||
let wrd <- get(slave_xactor.master.w);
|
||||
let req = Req {req_op: REQ_OP_WR,
|
||||
id: wra.awid,
|
||||
addr: wra.awaddr,
|
||||
@@ -481,12 +487,12 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
// Select the fabric data word of interest
|
||||
Bit #(Wd_Data) rdata = raw_mem_word_V_fabric_data [n];
|
||||
|
||||
let rdr = AXI4_Rd_Data {rid: f_reqs.first.id,
|
||||
rdata: rdata,
|
||||
rresp: axi4_resp_okay,
|
||||
rlast: True,
|
||||
ruser: f_reqs.first.user};
|
||||
slave_xactor.i_rd_data.enq (rdr);
|
||||
let rdr = AXI4_RFlit {rid: f_reqs.first.id,
|
||||
rdata: rdata,
|
||||
rresp: OKAY,
|
||||
rlast: True,
|
||||
ruser: f_reqs.first.user}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
f_reqs.deq;
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
@@ -525,10 +531,10 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
rg_cached_raw_mem_word <= pack (raw_mem_word_V_Word64);
|
||||
rg_cached_clean <= False;
|
||||
|
||||
let wrr = AXI4_Wr_Resp {bid: f_reqs.first.id,
|
||||
bresp: axi4_resp_okay,
|
||||
buser: f_reqs.first.user};
|
||||
slave_xactor.i_wr_resp.enq (wrr);
|
||||
let wrr = AXI4_BFlit {bid: f_reqs.first.id,
|
||||
bresp: OKAY,
|
||||
buser: f_reqs.first.user}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
f_reqs.deq;
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
@@ -593,12 +599,12 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
&& (! fn_addr_is_ok (rg_addr_base, f_reqs.first.addr, rg_addr_lim, f_reqs.first.size))
|
||||
&& (f_reqs.first.req_op == REQ_OP_RD));
|
||||
Fabric_Data rdata = zeroExtend (f_reqs.first.addr);
|
||||
let rdr = AXI4_Rd_Data {rid: f_reqs.first.id,
|
||||
rdata: rdata, // for debugging only
|
||||
rresp: axi4_resp_slverr,
|
||||
rlast: True,
|
||||
ruser: f_reqs.first.user};
|
||||
slave_xactor.i_rd_data.enq (rdr);
|
||||
let rdr = AXI4_RFlit {rid: f_reqs.first.id,
|
||||
rdata: rdata, // for debugging only
|
||||
rresp: SLVERR,
|
||||
rlast: True,
|
||||
ruser: f_reqs.first.user}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
f_reqs.deq;
|
||||
|
||||
$write ("%0d: ERROR: Mem_Controller:", cur_cycle);
|
||||
@@ -614,10 +620,10 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
rule rl_invalid_wr_address ( (rg_state == STATE_READY)
|
||||
&& (! fn_addr_is_ok (rg_addr_base, f_reqs.first.addr, rg_addr_lim, f_reqs.first.size))
|
||||
&& (f_reqs.first.req_op == REQ_OP_WR));
|
||||
let wrr = AXI4_Wr_Resp {bid: f_reqs.first.id,
|
||||
bresp: axi4_resp_slverr,
|
||||
buser: f_reqs.first.user};
|
||||
slave_xactor.i_wr_resp.enq (wrr);
|
||||
let wrr = AXI4_BFlit {bid: f_reqs.first.id,
|
||||
bresp: SLVERR,
|
||||
buser: f_reqs.first.user}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
f_reqs.deq;
|
||||
|
||||
$write ("%0d: ERROR: Mem_Controller:", cur_cycle);
|
||||
@@ -652,7 +658,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
endmethod
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface slave = slave_xactor.axi_side;
|
||||
interface slave = slave_xactor.slaveSynth;
|
||||
|
||||
// To raw memory (outside the SoC)
|
||||
interface to_raw_mem = toGPClient (f_raw_mem_reqs, f_raw_mem_rsps);
|
||||
|
||||
@@ -31,6 +31,7 @@ export imem_master_num;
|
||||
export dmem_master_num;
|
||||
|
||||
export Num_Slaves;
|
||||
export Wd_SId;
|
||||
export boot_rom_slave_num;
|
||||
export mem0_controller_slave_num;
|
||||
export uart0_slave_num;
|
||||
@@ -42,7 +43,7 @@ export irq_num_uart0;
|
||||
// ================================================================
|
||||
// Bluespec library imports
|
||||
|
||||
// None
|
||||
import Routable :: *; // For Range
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
@@ -86,29 +87,12 @@ SoC_Map_Struct {
|
||||
// Interface and module for the address map
|
||||
|
||||
interface SoC_Map_IFC;
|
||||
(* always_ready *) method Fabric_Addr m_near_mem_io_addr_base;
|
||||
(* always_ready *) method Fabric_Addr m_near_mem_io_addr_size;
|
||||
(* always_ready *) method Fabric_Addr m_near_mem_io_addr_lim;
|
||||
|
||||
(* always_ready *) method Fabric_Addr m_plic_addr_base;
|
||||
(* always_ready *) method Fabric_Addr m_plic_addr_size;
|
||||
(* always_ready *) method Fabric_Addr m_plic_addr_lim;
|
||||
|
||||
(* always_ready *) method Fabric_Addr m_uart0_addr_base;
|
||||
(* always_ready *) method Fabric_Addr m_uart0_addr_size;
|
||||
(* always_ready *) method Fabric_Addr m_uart0_addr_lim;
|
||||
|
||||
(* always_ready *) method Fabric_Addr m_boot_rom_addr_base;
|
||||
(* always_ready *) method Fabric_Addr m_boot_rom_addr_size;
|
||||
(* always_ready *) method Fabric_Addr m_boot_rom_addr_lim;
|
||||
|
||||
(* always_ready *) method Fabric_Addr m_mem0_controller_addr_base;
|
||||
(* always_ready *) method Fabric_Addr m_mem0_controller_addr_size;
|
||||
(* always_ready *) method Fabric_Addr m_mem0_controller_addr_lim;
|
||||
|
||||
(* always_ready *) method Fabric_Addr m_tcm_addr_base;
|
||||
(* always_ready *) method Fabric_Addr m_tcm_addr_size;
|
||||
(* always_ready *) method Fabric_Addr m_tcm_addr_lim;
|
||||
(* always_ready *) method Range#(Wd_Addr) m_near_mem_io_addr_range;
|
||||
(* always_ready *) method Range#(Wd_Addr) m_plic_addr_range;
|
||||
(* always_ready *) method Range#(Wd_Addr) m_uart0_addr_range;
|
||||
(* always_ready *) method Range#(Wd_Addr) m_boot_rom_addr_range;
|
||||
(* always_ready *) method Range#(Wd_Addr) m_mem0_controller_addr_range;
|
||||
(* always_ready *) method Range#(Wd_Addr) m_tcm_addr_range;
|
||||
|
||||
(* always_ready *)
|
||||
method Bool m_is_mem_addr (Fabric_Addr addr);
|
||||
@@ -132,57 +116,42 @@ module mkSoC_Map (SoC_Map_IFC);
|
||||
// ----------------------------------------------------------------
|
||||
// Near_Mem_IO (including CLINT, the core-local interruptor)
|
||||
|
||||
Fabric_Addr near_mem_io_addr_base = 'h_0200_0000;
|
||||
Fabric_Addr near_mem_io_addr_size = 'h_0000_C000; // 48K
|
||||
Fabric_Addr near_mem_io_addr_lim = near_mem_io_addr_base + near_mem_io_addr_size;
|
||||
|
||||
function Bool fn_is_near_mem_io_addr (Fabric_Addr addr);
|
||||
return ((near_mem_io_addr_base <= addr) && (addr < near_mem_io_addr_lim));
|
||||
endfunction
|
||||
let near_mem_io_addr_range = Range {
|
||||
base: 'h_0200_0000,
|
||||
size: 'h_0000_C000 // 48K
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// PLIC
|
||||
|
||||
Fabric_Addr plic_addr_base = 'h_0C00_0000;
|
||||
Fabric_Addr plic_addr_size = 'h_0040_0000; // 4M
|
||||
Fabric_Addr plic_addr_lim = plic_addr_base + plic_addr_size;
|
||||
|
||||
function Bool fn_is_plic_addr (Fabric_Addr addr);
|
||||
return ((plic_addr_base <= addr) && (addr < plic_addr_lim));
|
||||
endfunction
|
||||
let plic_addr_range = Range {
|
||||
base: 'h0C00_0000,
|
||||
size: 'h0040_0000 // 4M
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// UART 0
|
||||
|
||||
Fabric_Addr uart0_addr_base = 'hC000_0000;
|
||||
Fabric_Addr uart0_addr_size = 'h0000_0080; // 128
|
||||
Fabric_Addr uart0_addr_lim = uart0_addr_base + uart0_addr_size;
|
||||
|
||||
function Bool fn_is_uart0_addr (Fabric_Addr addr);
|
||||
return ((uart0_addr_base <= addr) && (addr < uart0_addr_lim));
|
||||
endfunction
|
||||
let uart0_addr_range = Range {
|
||||
base: 'hC000_0000,
|
||||
size: 'h0000_0080 // 128
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Boot ROM
|
||||
|
||||
Fabric_Addr boot_rom_addr_base = 'h_0000_1000;
|
||||
Fabric_Addr boot_rom_addr_size = 'h_0000_1000; // 4K
|
||||
Fabric_Addr boot_rom_addr_lim = boot_rom_addr_base + boot_rom_addr_size;
|
||||
|
||||
function Bool fn_is_boot_rom_addr (Fabric_Addr addr);
|
||||
return ((boot_rom_addr_base <= addr) && (addr < boot_rom_addr_lim));
|
||||
endfunction
|
||||
let boot_rom_addr_range = Range {
|
||||
base: 'h_0000_1000,
|
||||
size: 'h_0000_1000 // 4K
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Main Mem Controller 0
|
||||
|
||||
Fabric_Addr mem0_controller_addr_base = 'h_8000_0000;
|
||||
Fabric_Addr mem0_controller_addr_size = 'h_1000_0000; // 256 MB
|
||||
Fabric_Addr mem0_controller_addr_lim = mem0_controller_addr_base + mem0_controller_addr_size;
|
||||
|
||||
function Bool fn_is_mem0_controller_addr (Fabric_Addr addr);
|
||||
return ((mem0_controller_addr_base <= addr) && (addr < mem0_controller_addr_lim));
|
||||
endfunction
|
||||
let mem0_controller_addr_range = Range {
|
||||
base: 'h_8000_0000,
|
||||
size: 'h_1000_0000 // 256 MB
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Tightly-coupled memory ('TCM'; optional)
|
||||
@@ -198,13 +167,11 @@ module mkSoC_Map (SoC_Map_IFC);
|
||||
`endif
|
||||
Integer bytes_per_TCM = kB_per_TCM * 'h400;
|
||||
|
||||
Fabric_Addr tcm_addr_base = 'h_0000_0000;
|
||||
Fabric_Addr tcm_addr_size = fromInteger (bytes_per_TCM);
|
||||
Fabric_Addr tcm_addr_lim = tcm_addr_base + tcm_addr_size;
|
||||
let tcm_addr_range = Range {
|
||||
base: 'h_0000_0000,
|
||||
size: fromInteger (bytes_per_TCM)
|
||||
};
|
||||
|
||||
function Bool fn_is_tcm_addr (Fabric_Addr addr);
|
||||
return ((tcm_addr_base <= addr) && (addr < tcm_addr_lim));
|
||||
endfunction
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Memory address predicate
|
||||
@@ -212,9 +179,8 @@ module mkSoC_Map (SoC_Map_IFC);
|
||||
// (Caches need this information to cache these addresses.)
|
||||
|
||||
function Bool fn_is_mem_addr (Fabric_Addr addr);
|
||||
return ( fn_is_mem0_controller_addr (addr)
|
||||
|| fn_is_tcm_addr (addr)
|
||||
);
|
||||
return ( inRange(mem0_controller_addr_range, addr)
|
||||
|| inRange(tcm_addr_range, addr));
|
||||
endfunction
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
@@ -223,52 +189,36 @@ module mkSoC_Map (SoC_Map_IFC);
|
||||
// (Caches need this information to avoid cacheing these addresses.)
|
||||
|
||||
function Bool fn_is_IO_addr (Fabric_Addr addr);
|
||||
return ( fn_is_boot_rom_addr (addr)
|
||||
|| fn_is_near_mem_io_addr (addr)
|
||||
|| fn_is_plic_addr (addr)
|
||||
|| fn_is_uart0_addr (addr)
|
||||
);
|
||||
return ( inRange(boot_rom_addr_range, addr)
|
||||
|| inRange(near_mem_io_addr_range, addr)
|
||||
|| inRange(plic_addr_range, addr)
|
||||
|| inRange(uart0_addr_range, addr));
|
||||
endfunction
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// PC, MTVEC and NMIVEC reset values
|
||||
|
||||
Bit #(64) pc_reset_value = boot_rom_addr_base;
|
||||
Bit #(64) pc_reset_value = rangeBase(boot_rom_addr_range);
|
||||
Bit #(64) mtvec_reset_value = 'h1000; // TODO
|
||||
Bit #(64) nmivec_reset_value = ?; // TODO
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
method Fabric_Addr m_near_mem_io_addr_base = near_mem_io_addr_base;
|
||||
method Fabric_Addr m_near_mem_io_addr_size = near_mem_io_addr_size;
|
||||
method Fabric_Addr m_near_mem_io_addr_lim = near_mem_io_addr_lim;
|
||||
method Range#(Wd_Addr) m_near_mem_io_addr_range = near_mem_io_addr_range;
|
||||
method Range#(Wd_Addr) m_plic_addr_range = plic_addr_range;
|
||||
method Range#(Wd_Addr) m_uart0_addr_range = uart0_addr_range;
|
||||
method Range#(Wd_Addr) m_boot_rom_addr_range = boot_rom_addr_range;
|
||||
|
||||
method Fabric_Addr m_plic_addr_base = plic_addr_base;
|
||||
method Fabric_Addr m_plic_addr_size = plic_addr_size;
|
||||
method Fabric_Addr m_plic_addr_lim = plic_addr_lim;
|
||||
method Range#(Wd_Addr) m_mem0_controller_addr_range = mem0_controller_addr_range;
|
||||
|
||||
method Fabric_Addr m_uart0_addr_base = uart0_addr_base;
|
||||
method Fabric_Addr m_uart0_addr_size = uart0_addr_size;
|
||||
method Fabric_Addr m_uart0_addr_lim = uart0_addr_lim;
|
||||
|
||||
method Fabric_Addr m_boot_rom_addr_base = boot_rom_addr_base;
|
||||
method Fabric_Addr m_boot_rom_addr_size = boot_rom_addr_size;
|
||||
method Fabric_Addr m_boot_rom_addr_lim = boot_rom_addr_lim;
|
||||
|
||||
method Fabric_Addr m_mem0_controller_addr_base = mem0_controller_addr_base;
|
||||
method Fabric_Addr m_mem0_controller_addr_size = mem0_controller_addr_size;
|
||||
method Fabric_Addr m_mem0_controller_addr_lim = mem0_controller_addr_lim;
|
||||
|
||||
method Fabric_Addr m_tcm_addr_base = tcm_addr_base;
|
||||
method Fabric_Addr m_tcm_addr_size = tcm_addr_size;
|
||||
method Fabric_Addr m_tcm_addr_lim = tcm_addr_lim;
|
||||
method Range#(Wd_Addr) m_tcm_addr_range = tcm_addr_range;
|
||||
|
||||
method Bool m_is_mem_addr (Fabric_Addr addr) = fn_is_mem_addr (addr);
|
||||
|
||||
method Bool m_is_IO_addr (Fabric_Addr addr) = fn_is_IO_addr (addr);
|
||||
|
||||
method Bool m_is_near_mem_IO_addr (Fabric_Addr addr) = fn_is_near_mem_io_addr (addr);
|
||||
method Bool m_is_near_mem_IO_addr (Fabric_Addr addr) = inRange (near_mem_io_addr_range, addr);
|
||||
|
||||
method Bit #(64) m_pc_reset_value = pc_reset_value;
|
||||
method Bit #(64) m_mtvec_reset_value = mtvec_reset_value;
|
||||
@@ -292,6 +242,10 @@ Integer boot_rom_slave_num = 0;
|
||||
Integer mem0_controller_slave_num = 1;
|
||||
Integer uart0_slave_num = 2;
|
||||
|
||||
// ================================================================
|
||||
// Width of fabric 'id' buses
|
||||
typedef TAdd#(TAdd#(Wd_MId, TLog#(Num_Masters)),1) Wd_SId;
|
||||
|
||||
// ================================================================
|
||||
// Interrupt request numbers (== index in to vector of
|
||||
// interrupt-request lines in Core)
|
||||
|
||||
@@ -32,24 +32,21 @@ import ClientServer :: *;
|
||||
import Connectable :: *;
|
||||
import Memory :: *;
|
||||
import Clocks :: *;
|
||||
import Vector :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Routable :: *;
|
||||
import AXI4 :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
// Main fabric
|
||||
import AXI4_Types :: *;
|
||||
import AXI4_Fabric :: *;
|
||||
import AXI4_Deburster :: *;
|
||||
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
import SoC_Fabric :: *;
|
||||
|
||||
// SoC components (CPU, mem, and IPs)
|
||||
|
||||
@@ -147,24 +144,19 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
// 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;
|
||||
AXI4_Shim#(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User)
|
||||
boot_rom_axi4_deburster <- mkBurstToNoBurst;
|
||||
|
||||
// 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;
|
||||
AXI4_Shim#(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User)
|
||||
mem0_controller_axi4_deburster <- mkBurstToNoBurst;
|
||||
|
||||
// SoC IPs
|
||||
UART_IFC uart0 <- mkUART;
|
||||
@@ -178,43 +170,62 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
// SoC fabric master connections
|
||||
// Note: see 'SoC_Map' for 'master_num' definitions
|
||||
|
||||
Vector#(Num_Masters, AXI4_Master_Synth #(TAdd#(Wd_MId,1), Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0))
|
||||
master_vector = newVector;
|
||||
|
||||
// CPU IMem master to fabric
|
||||
mkConnection (corew.cpu_imem_master, fabric.v_from_masters [imem_master_num]);
|
||||
master_vector[imem_master_num] = corew.cpu_imem_master;
|
||||
|
||||
// CPU DMem master to fabric
|
||||
mkConnection (corew.cpu_dmem_master, fabric.v_from_masters [dmem_master_num]);
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
// accel to fabric
|
||||
mkConnection (accel0.master, fabric.v_from_masters [accel0_master_num]);
|
||||
`endif
|
||||
master_vector[dmem_master_num] = corew.cpu_dmem_master;
|
||||
|
||||
// ----------------
|
||||
// SoC fabric slave connections
|
||||
// Note: see 'SoC_Map' for 'slave_num' definitions
|
||||
|
||||
// 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);
|
||||
Vector#(Num_Slaves, AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0))
|
||||
slave_vector = newVector;
|
||||
Vector#(Num_Slaves, Range#(Wd_Addr)) route_vector = newVector;
|
||||
|
||||
// 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 Boot ROM
|
||||
let br <- fromAXI4_Slave_Synth(boot_rom.slave);
|
||||
mkConnection(boot_rom_axi4_deburster.master, br);
|
||||
let ug_boot_rom_slave <- toUnguarded_AXI4_Slave(boot_rom_axi4_deburster.slave);
|
||||
slave_vector[boot_rom_slave_num] = toAXI4_Slave_Synth(zeroSlaveUserFields(ug_boot_rom_slave));
|
||||
route_vector[boot_rom_slave_num] = soc_map.m_boot_rom_addr_range;
|
||||
|
||||
// Fabric to Mem Controller
|
||||
let mem <- fromAXI4_Slave_Synth(mem0_controller.slave);
|
||||
mkConnection(mem0_controller_axi4_deburster.master, mem);
|
||||
let ug_mem0_slave <- toUnguarded_AXI4_Slave(mem0_controller_axi4_deburster.slave);
|
||||
slave_vector[mem0_controller_slave_num] = toAXI4_Slave_Synth(zeroSlaveUserFields(ug_mem0_slave));
|
||||
route_vector[mem0_controller_slave_num] = soc_map.m_mem0_controller_addr_range;
|
||||
|
||||
// Fabric to UART0
|
||||
mkConnection (fabric.v_to_slaves [uart0_slave_num], uart0.slave);
|
||||
let uart0_slave <- fromAXI4_Slave_Synth(uart0.slave);
|
||||
slave_vector[uart0_slave_num] = toAXI4_Slave_Synth(zeroSlaveUserFields(uart0_slave));
|
||||
route_vector[uart0_slave_num] = soc_map.m_uart0_addr_range;
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
// Fabric to accel0
|
||||
mkConnection (fabric.v_to_slaves [accel0_slave_num], accel0.slave);
|
||||
let accel0_slave <- fromAXI4_Slave_Synth(accel0.slave);
|
||||
slave_vector[accel0_slave_num] = toAXI4_Slave_Synth(zeroSlaveUserFields(accel0_slave));
|
||||
route_vector[accel0_slave_num] = soc_map.m_accel0_addr_range;
|
||||
`endif
|
||||
|
||||
`ifdef HTIF_MEMORY
|
||||
AXI4_Slave_IFC#(Wd_Id, Wd_Addr, Wd_Data, Wd_User) htif <- mkAxi4LRegFile(bytes_per_htif);
|
||||
|
||||
mkConnection (fabric.v_to_slaves [htif_slave_num], htif);
|
||||
slave_vector[htif_slave_num] = htif;
|
||||
route_vector[htif_slave_num] = soc_map.m_htif_addr_range;
|
||||
`endif
|
||||
|
||||
// SoC Fabric
|
||||
let bus <- mkAXI4Bus_Synth (routeFromMappingTable(route_vector),
|
||||
master_vector, slave_vector);
|
||||
|
||||
// ----------------
|
||||
// Connect interrupt sources for CPU external interrupt request inputs.
|
||||
|
||||
@@ -228,7 +239,7 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
Bool intr_accel0 = accel0.interrupt_req;
|
||||
core.core_external_interrupt_sources [irq_num_accel0].m_interrupt_req (intr_accel0);
|
||||
corew.core_external_interrupt_sources [irq_num_accel0].m_interrupt_req (intr_accel0);
|
||||
last_irq_num = irq_num_accel0;
|
||||
`endif
|
||||
|
||||
@@ -247,7 +258,8 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
action
|
||||
mem0_controller.server_reset.request.put (?);
|
||||
uart0.server_reset.request.put (?);
|
||||
fabric.reset;
|
||||
boot_rom_axi4_deburster.clear;
|
||||
mem0_controller_axi4_deburster.clear;
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -257,31 +269,32 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
let uart0_rsp <- uart0.server_reset.response.get;
|
||||
|
||||
// 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);
|
||||
boot_rom.set_addr_map (rangeBase(soc_map.m_boot_rom_addr_range),
|
||||
rangeTop(soc_map.m_boot_rom_addr_range));
|
||||
|
||||
mem0_controller.set_addr_map (soc_map.m_mem0_controller_addr_base,
|
||||
soc_map.m_mem0_controller_addr_lim);
|
||||
mem0_controller.set_addr_map (rangeBase(soc_map.m_mem0_controller_addr_range),
|
||||
rangeTop(soc_map.m_mem0_controller_addr_range));
|
||||
|
||||
uart0.set_addr_map (soc_map.m_uart0_addr_base, soc_map.m_uart0_addr_lim);
|
||||
uart0.set_addr_map (rangeBase(soc_map.m_uart0_addr_range),
|
||||
rangeTop(soc_map.m_uart0_addr_range));
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
accel0.init (fabric_default_id,
|
||||
soc_map.m_accel0_addr_base,
|
||||
soc_map.m_accel0_addr_lim);
|
||||
soc_map.m_accel0_addr_range.base,
|
||||
rangeTop(soc_map.m_accel0_addr_range));
|
||||
`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);
|
||||
rangeBase(soc_map.m_boot_rom_addr_range),
|
||||
rangeTop(soc_map.m_boot_rom_addr_range));
|
||||
$display (" Mem0 Controller: 0x%0h .. 0x%0h",
|
||||
soc_map.m_mem0_controller_addr_base,
|
||||
soc_map.m_mem0_controller_addr_lim);
|
||||
rangeBase(soc_map.m_mem0_controller_addr_range),
|
||||
rangeTop(soc_map.m_mem0_controller_addr_range));
|
||||
$display (" UART0: 0x%0h .. 0x%0h",
|
||||
soc_map.m_uart0_addr_base,
|
||||
soc_map.m_uart0_addr_lim);
|
||||
rangeBase(soc_map.m_uart0_addr_range),
|
||||
rangeTop(soc_map.m_uart0_addr_range));
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
@@ -349,18 +362,6 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
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
|
||||
|
||||
@@ -43,12 +43,14 @@ import ConfigReg :: *;
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Semi_FIFOF :: *;
|
||||
import AXI4 :: *;
|
||||
import SourceSink :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import AXI4_Types :: *;
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
|
||||
// ================================================================
|
||||
// UART registers and their address offsets
|
||||
@@ -114,7 +116,9 @@ interface UART_IFC;
|
||||
method Action set_addr_map (Fabric_Addr addr_base, Fabric_Addr addr_lim);
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave;
|
||||
interface AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) slave;
|
||||
|
||||
// To external console
|
||||
interface Get #(Bit #(8)) get_to_console;
|
||||
@@ -203,7 +207,9 @@ module mkUART (UART_IFC);
|
||||
// ----------------
|
||||
// Connector to AXI4 fabric
|
||||
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
AXI4_Slave_Width_Xactor#(Wd_SId, Wd_Addr, Wd_Data_Periph, Wd_Data,
|
||||
Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph, Wd_AR_User_Periph, Wd_R_User_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave_xactor <- mkAXI4_Slave_Zeroing_Xactor;
|
||||
|
||||
// ----------------
|
||||
// character queues to and from external circuitry for the console
|
||||
@@ -275,7 +281,7 @@ module mkUART (UART_IFC);
|
||||
rg_msr <= 0;
|
||||
rg_scr <= 0;
|
||||
|
||||
slave_xactor.reset;
|
||||
slave_xactor.clear;
|
||||
rg_state <= STATE_READY;
|
||||
|
||||
f_reset_rsps.enq (?);
|
||||
@@ -288,29 +294,29 @@ module mkUART (UART_IFC);
|
||||
// Handle fabric read requests
|
||||
|
||||
rule rl_process_rd_req (rg_state == STATE_READY);
|
||||
let rda <- pop_o (slave_xactor.o_rd_addr);
|
||||
let rda <- get(slave_xactor.master.ar);
|
||||
|
||||
let byte_addr = rda.araddr - rg_addr_base;
|
||||
match { .offset, .lsbs } = split_addr (zeroExtend (byte_addr));
|
||||
|
||||
Bit #(8) rdata_byte = 0;
|
||||
AXI4_Resp rresp = axi4_resp_okay;
|
||||
AXI4_Resp rresp = OKAY;
|
||||
|
||||
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;
|
||||
rresp = 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;
|
||||
rresp = SLVERR;
|
||||
end
|
||||
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;
|
||||
rresp = DECERR;
|
||||
end
|
||||
|
||||
// offset 0: RBR
|
||||
@@ -347,7 +353,7 @@ module mkUART (UART_IFC);
|
||||
else begin
|
||||
$display ("%0d: %m.rl_process_rd_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
rresp = axi4_resp_decerr;
|
||||
rresp = DECERR;
|
||||
end
|
||||
|
||||
// Align data byte for AXI4 data bus based on fabric-width
|
||||
@@ -356,12 +362,12 @@ module mkUART (UART_IFC);
|
||||
rdata = rdata << 32;
|
||||
|
||||
// Send read-response to bus
|
||||
let rdr = AXI4_Rd_Data {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser};
|
||||
slave_xactor.i_rd_data.enq (rdr);
|
||||
let rdr = AXI4_RFlit {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: %m.rl_process_rd_req", cur_cycle);
|
||||
@@ -374,8 +380,8 @@ module mkUART (UART_IFC);
|
||||
// Handle fabric write requests
|
||||
|
||||
rule rl_process_wr_req (rg_state == STATE_READY);
|
||||
let wra <- pop_o (slave_xactor.o_wr_addr);
|
||||
let wrd <- pop_o (slave_xactor.o_wr_data);
|
||||
let wra <- get(slave_xactor.master.aw);
|
||||
let wrd <- get(slave_xactor.master.w);
|
||||
|
||||
Bit #(64) wdata = zeroExtend (wrd.wdata);
|
||||
Bit #(8) wstrb = zeroExtend (wrd.wstrb);
|
||||
@@ -384,23 +390,25 @@ module mkUART (UART_IFC);
|
||||
let byte_addr = wra.awaddr - rg_addr_base;
|
||||
match { .offset, .lsbs } = split_addr (zeroExtend (byte_addr));
|
||||
|
||||
AXI4_Resp bresp = axi4_resp_okay;
|
||||
AXI4_Resp bresp = OKAY;
|
||||
|
||||
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;
|
||||
bresp = DECERR;
|
||||
end
|
||||
else if (lsbs != 0) begin
|
||||
$display ("%0d: %m.rl_process_wr_req: ERROR: UART misaligned addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
bresp = axi4_resp_slverr;
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = SLVERR;
|
||||
end
|
||||
else if (offset [63:3] != 0) begin
|
||||
$display ("%0d: %m.rl_process_wr_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
bresp = axi4_resp_decerr;
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = DECERR;
|
||||
end
|
||||
|
||||
// offset 0: THR
|
||||
@@ -438,14 +446,14 @@ module mkUART (UART_IFC);
|
||||
$display ("%0d: %m.rl_process_wr_req: ERROR: UART unsupported addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = axi4_resp_decerr;
|
||||
bresp = DECERR;
|
||||
end
|
||||
|
||||
// Send write-response to bus
|
||||
let wrr = AXI4_Wr_Resp {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser};
|
||||
slave_xactor.i_wr_resp.enq (wrr);
|
||||
let wrr = AXI4_BFlit {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: %m.rl_process_wr_req", cur_cycle);
|
||||
@@ -495,7 +503,7 @@ module mkUART (UART_IFC);
|
||||
endmethod
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface slave = slave_xactor.axi_side;
|
||||
interface slave = slave_xactor.slaveSynth;
|
||||
|
||||
// To external console
|
||||
interface put_from_console = toPut (f_from_console);
|
||||
|
||||
Reference in New Issue
Block a user