Merge branch 'CHERI' into pdr32-tmp

and get it to build!
This commit is contained in:
Jonathan Woodruff
2020-03-26 18:03:58 +00:00
1115 changed files with 1472029 additions and 327565 deletions

View File

@@ -21,9 +21,9 @@ import AXI4_Types :: *;
// we get exactly the signals specified in the ARM spec.
interface AXI4_Stream_Master_IFC #(numeric type wd_id,
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
(* always_ready, result="tvalid" *) method Bool m_tvalid; // out
(* always_ready, result="tid" *) method Bit #(wd_id) m_tid; // out
@@ -45,18 +45,18 @@ endinterface: AXI4_Stream_Master_IFC
// we get exactly the signals specified in the ARM spec.
interface AXI4_Stream_Slave_IFC #(numeric type wd_id,
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
(* always_ready, always_enabled, prefix = "" *)
method Action m_tvalid ((* port="tvalid" *) Bool tvalid, // in
(* port="tid" *) Bit #(wd_id) tid, // in
(* port="tdata" *) Bit #(wd_data) tdata, // in
(* port="tstrb" *) Bit #(TDiv #(wd_data,8)) tstrb, // in
(* port="tkeep" *) Bit #(TDiv #(wd_data,8)) tkeep, // in
(* port="tlast" *) Bool tlast, // in
(* port="tdest" *) Bit #(wd_dest) tdest, // in
(* port="tuser" *) Bit #(wd_user) tuser); // in
(* port="tid" *) Bit #(wd_id) tid, // in
(* port="tdata" *) Bit #(wd_data) tdata, // in
(* port="tstrb" *) Bit #(TDiv #(wd_data,8)) tstrb, // in
(* port="tkeep" *) Bit #(TDiv #(wd_data,8)) tkeep, // in
(* port="tlast" *) Bool tlast, // in
(* port="tdest" *) Bit #(wd_dest) tdest, // in
(* port="tuser" *) Bit #(wd_user) tuser); // in
(* always_ready, result="tready" *)
method Bool m_tready; // out
endinterface: AXI4_Stream_Slave_IFC
@@ -65,32 +65,32 @@ endinterface: AXI4_Stream_Slave_IFC
// Connecting signal-level interfaces
instance Connectable #(AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user),
AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user));
AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user));
module mkConnection #(AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user) axim,
AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user) axis)
(Empty);
AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user) axis)
(Empty);
(* fire_when_enabled, no_implicit_conditions *)
rule rl_data_channel;
axis.m_tvalid (axim.m_tvalid,
axim.m_tid,
axim.m_tdata,
axim.m_tstrb,
axim.m_tkeep,
axim.m_tlast,
axim.m_tdest,
axim.m_tuser);
axim.m_tready (axis.m_tready);
axis.m_tvalid (axim.m_tvalid,
axim.m_tid,
axim.m_tdata,
axim.m_tstrb,
axim.m_tkeep,
axim.m_tlast,
axim.m_tdest,
axim.m_tuser);
axim.m_tready (axis.m_tready);
endrule
endmodule
endinstance
instance Connectable #(AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user),
AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user));
AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user));
module mkConnection #(AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user) axis,
AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user) axim)
(Empty);
AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user) axim)
(Empty);
mkConnection(axim, axis);
endmodule
endinstance
@@ -117,17 +117,17 @@ AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user) axi4_stream_dummy_mas
AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user) axi4_stream_dummy_slave
= interface AXI4_Stream_Slave_IFC
method Action m_tvalid (wvalid,
wid,
wdata,
wstrb,
wkeep,
wlast,
wdest,
wuser);
noAction;
endmethod
method Bool m_tready = True;
method Action m_tvalid (wvalid,
wid,
wdata,
wstrb,
wkeep,
wlast,
wdest,
wuser);
noAction;
endmethod
method Bool m_tready = True;
endinterface;
// ****************************************************************
@@ -143,28 +143,28 @@ AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user) axi4_stream_dummy_slav
function FIFOF_I #(t) fn_crg_and_rg_to_FIFOF_I (Reg #(Bool) rg_full, Reg #(t) rg_data);
return interface FIFOF_I;
method Action enq (t x) if (! rg_full);
rg_full <= True;
rg_data <= x;
endmethod
method Bool notFull;
return (! rg_full);
endmethod
endinterface;
method Action enq (t x) if (! rg_full);
rg_full <= True;
rg_data <= x;
endmethod
method Bool notFull;
return (! rg_full);
endmethod
endinterface;
endfunction
function FIFOF_O #(t) fn_crg_and_rg_to_FIFOF_O (Reg #(Bool) rg_full, Reg #(t) rg_data);
return interface FIFOF_O;
method t first () if (rg_full);
return rg_data;
endmethod
method Action deq () if (rg_full);
rg_full <= False;
endmethod
method notEmpty;
return rg_full;
endmethod
endinterface;
method t first () if (rg_full);
return rg_data;
endmethod
method Action deq () if (rg_full);
rg_full <= False;
endmethod
method notEmpty;
return rg_full;
endmethod
endinterface;
endfunction
// ================================================================
@@ -179,18 +179,18 @@ typedef struct {
Bit #(wd_dest) tdest;
Bit #(wd_user) tuser;
} AXI4_Stream #(numeric type wd_id,
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user)
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user)
deriving (Bits, FShow);
// ================================================================
// Master transactor interface
interface AXI4_Stream_Master_Xactor_IFC #(numeric type wd_id,
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
method Action reset;
// AXI side
interface AXI4_Stream_Master_IFC #(wd_id, wd_dest, wd_data, wd_user) axi_side;
@@ -220,18 +220,18 @@ module mkAXI4_Stream_Master_Xactor (AXI4_Stream_Master_Xactor_IFC #(wd_id, wd_de
// AXI side
interface axi_side = interface AXI4_Stream_Master_IFC;
method m_tvalid = f_data.notEmpty;
method m_tid = f_data.first.tid;
method m_tdata = f_data.first.tdata;
method m_tstrb = f_data.first.tstrb;
method m_tkeep = f_data.first.tkeep;
method m_tlast = f_data.first.tlast;
method m_tdest = f_data.first.tdest;
method m_tuser = f_data.first.tuser;
method Action m_tready (Bool tready);
if (f_data.notEmpty && tready) f_data.deq;
endmethod
endinterface;
method m_tvalid = f_data.notEmpty;
method m_tid = f_data.first.tid;
method m_tdata = f_data.first.tdata;
method m_tstrb = f_data.first.tstrb;
method m_tkeep = f_data.first.tkeep;
method m_tlast = f_data.first.tlast;
method m_tdest = f_data.first.tdest;
method m_tuser = f_data.first.tuser;
method Action m_tready (Bool tready);
if (f_data.notEmpty && tready) f_data.deq;
endmethod
endinterface;
// FIFOF side
interface i_stream = to_FIFOF_I (f_data);
@@ -241,9 +241,9 @@ endmodule: mkAXI4_Stream_Master_Xactor
// Slave transactor interface
interface AXI4_Stream_Slave_Xactor_IFC #(numeric type wd_id,
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
method Action reset;
// AXI side
interface AXI4_Stream_Slave_IFC #(wd_id, wd_dest, wd_data, wd_user) axi_side;
@@ -272,28 +272,28 @@ module mkAXI4_Stream_Slave_Xactor (AXI4_Stream_Slave_Xactor_IFC #(wd_id, wd_dest
// AXI side
interface axi_side = interface AXI4_Stream_Slave_IFC;
method Action m_tvalid (Bool tvalid,
Bit #(wd_id) tid,
Bit #(wd_data) tdata,
Bit #(TDiv #(wd_data, 8)) tstrb,
Bit #(TDiv #(wd_data, 8)) tkeep,
Bool tlast,
Bit #(wd_dest) tdest,
Bit #(wd_user) tuser);
if (tvalid && f_data.notFull)
f_data.enq (AXI4_Stream {tid: tid,
tdata: tdata,
tstrb: tstrb,
tkeep: tkeep,
tlast: tlast,
tdest: tdest,
tuser: tuser});
endmethod
method Action m_tvalid (Bool tvalid,
Bit #(wd_id) tid,
Bit #(wd_data) tdata,
Bit #(TDiv #(wd_data, 8)) tstrb,
Bit #(TDiv #(wd_data, 8)) tkeep,
Bool tlast,
Bit #(wd_dest) tdest,
Bit #(wd_user) tuser);
if (tvalid && f_data.notFull)
f_data.enq (AXI4_Stream {tid: tid,
tdata: tdata,
tstrb: tstrb,
tkeep: tkeep,
tlast: tlast,
tdest: tdest,
tuser: tuser});
endmethod
method Bool m_tready;
return f_data.notFull;
endmethod
endinterface;
method Bool m_tready;
return f_data.notFull;
endmethod
endinterface;
// FIFOF side
interface o_stream = to_FIFOF_O (f_data);
@@ -347,92 +347,92 @@ module mkAXI4_Master_Xactor_2 (AXI4_Master_Xactor_IFC #(wd_id, wd_dest, wd_data,
// AXI side
interface axi_side = interface AXI4_Master_IFC;
// Wr Addr channel
method Bool m_awvalid = crg_wr_addr_full [port_deq];
method Bit #(wd_id) m_awid = rg_wr_addr.awid;
method Bit #(wd_dest) m_awaddr = rg_wr_addr.awaddr;
method Bit #(8) m_awlen = rg_wr_addr.awlen;
method AXI4_Size m_awsize = rg_wr_addr.awsize;
method Bit #(2) m_awburst = rg_wr_addr.awburst;
method Bit #(1) m_awlock = rg_wr_addr.awlock;
method Bit #(4) m_awcache = rg_wr_addr.awcache;
method Bit #(3) m_awprot = rg_wr_addr.awprot;
method Bit #(4) m_awqos = rg_wr_addr.awqos;
method Bit #(4) m_awregion = rg_wr_addr.awregion;
method Bit #(wd_user) m_awuser = rg_wr_addr.awuser;
method Action m_awready (Bool awready);
if (crg_wr_addr_full [port_deq] && awready)
crg_wr_addr_full [port_deq] <= False; // deq
endmethod
// Wr Addr channel
method Bool m_awvalid = crg_wr_addr_full [port_deq];
method Bit #(wd_id) m_awid = rg_wr_addr.awid;
method Bit #(wd_dest) m_awaddr = rg_wr_addr.awaddr;
method Bit #(8) m_awlen = rg_wr_addr.awlen;
method AXI4_Size m_awsize = rg_wr_addr.awsize;
method Bit #(2) m_awburst = rg_wr_addr.awburst;
method Bit #(1) m_awlock = rg_wr_addr.awlock;
method Bit #(4) m_awcache = rg_wr_addr.awcache;
method Bit #(3) m_awprot = rg_wr_addr.awprot;
method Bit #(4) m_awqos = rg_wr_addr.awqos;
method Bit #(4) m_awregion = rg_wr_addr.awregion;
method Bit #(wd_user) m_awuser = rg_wr_addr.awuser;
method Action m_awready (Bool awready);
if (crg_wr_addr_full [port_deq] && awready)
crg_wr_addr_full [port_deq] <= False; // deq
endmethod
// Wr Data channel
method Bool m_wvalid = crg_wr_data_full [port_deq];
method Bit #(wd_id) m_wid = rg_wr_data.wid;
method Bit #(wd_data) m_wdata = rg_wr_data.wdata;
method Bit #(TDiv #(wd_data, 8)) m_wstrb = rg_wr_data.wstrb;
method Bool m_wlast = rg_wr_data.wlast;
method Bit #(wd_user) m_wuser = rg_wr_data.wuser;
method Action m_wready (Bool wready);
if (crg_wr_data_full [port_deq] && wready)
crg_wr_data_full [port_deq] <= False;
endmethod
// Wr Data channel
method Bool m_wvalid = crg_wr_data_full [port_deq];
method Bit #(wd_id) m_wid = rg_wr_data.wid;
method Bit #(wd_data) m_wdata = rg_wr_data.wdata;
method Bit #(TDiv #(wd_data, 8)) m_wstrb = rg_wr_data.wstrb;
method Bool m_wlast = rg_wr_data.wlast;
method Bit #(wd_user) m_wuser = rg_wr_data.wuser;
method Action m_wready (Bool wready);
if (crg_wr_data_full [port_deq] && wready)
crg_wr_data_full [port_deq] <= False;
endmethod
// Wr Response channel
method Action m_bvalid (Bool bvalid,
Bit #(wd_id) bid,
Bit #(2) bresp,
Bit #(wd_user) buser);
if (bvalid && (! (crg_wr_resp_full [port_enq]))) begin
crg_wr_resp_full [port_enq] <= True;
rg_wr_resp <= AXI4_Wr_Resp {bid: bid,
bresp: bresp,
buser: buser};
end
endmethod
// Wr Response channel
method Action m_bvalid (Bool bvalid,
Bit #(wd_id) bid,
Bit #(2) bresp,
Bit #(wd_user) buser);
if (bvalid && (! (crg_wr_resp_full [port_enq]))) begin
crg_wr_resp_full [port_enq] <= True;
rg_wr_resp <= AXI4_Wr_Resp {bid: bid,
bresp: bresp,
buser: buser};
end
endmethod
method Bool m_bready;
return (! (crg_wr_resp_full [port_enq]));
endmethod
method Bool m_bready;
return (! (crg_wr_resp_full [port_enq]));
endmethod
// Rd Addr channel
method Bool m_arvalid = crg_rd_addr_full [port_deq];
method Bit #(wd_id) m_arid = rg_rd_addr.arid;
method Bit #(wd_dest) m_araddr = rg_rd_addr.araddr;
method Bit #(8) m_arlen = rg_rd_addr.arlen;
method AXI4_Size m_arsize = rg_rd_addr.arsize;
method Bit #(2) m_arburst = rg_rd_addr.arburst;
method Bit #(1) m_arlock = rg_rd_addr.arlock;
method Bit #(4) m_arcache = rg_rd_addr.arcache;
method Bit #(3) m_arprot = rg_rd_addr.arprot;
method Bit #(4) m_arqos = rg_rd_addr.arqos;
method Bit #(4) m_arregion = rg_rd_addr.arregion;
method Bit #(wd_user) m_aruser = rg_rd_addr.aruser;
method Action m_arready (Bool arready);
if (crg_rd_addr_full [port_deq] && arready)
crg_rd_addr_full [port_deq] <= False; // deq
endmethod
// Rd Addr channel
method Bool m_arvalid = crg_rd_addr_full [port_deq];
method Bit #(wd_id) m_arid = rg_rd_addr.arid;
method Bit #(wd_dest) m_araddr = rg_rd_addr.araddr;
method Bit #(8) m_arlen = rg_rd_addr.arlen;
method AXI4_Size m_arsize = rg_rd_addr.arsize;
method Bit #(2) m_arburst = rg_rd_addr.arburst;
method Bit #(1) m_arlock = rg_rd_addr.arlock;
method Bit #(4) m_arcache = rg_rd_addr.arcache;
method Bit #(3) m_arprot = rg_rd_addr.arprot;
method Bit #(4) m_arqos = rg_rd_addr.arqos;
method Bit #(4) m_arregion = rg_rd_addr.arregion;
method Bit #(wd_user) m_aruser = rg_rd_addr.aruser;
method Action m_arready (Bool arready);
if (crg_rd_addr_full [port_deq] && arready)
crg_rd_addr_full [port_deq] <= False; // deq
endmethod
// Rd Data channel
method Action m_rvalid (Bool rvalid,
Bit #(wd_id) rid,
Bit #(wd_data) rdata,
Bit #(2) rresp,
Bool rlast,
Bit #(wd_user) ruser);
if (rvalid && (! (crg_rd_data_full [port_enq])))
crg_rd_data_full [port_enq] <= True;
rg_rd_data <= (AXI4_Rd_Data {rid: rid,
rdata: rdata,
rresp: rresp,
rlast: rlast,
ruser: ruser});
endmethod
// Rd Data channel
method Action m_rvalid (Bool rvalid,
Bit #(wd_id) rid,
Bit #(wd_data) rdata,
Bit #(2) rresp,
Bool rlast,
Bit #(wd_user) ruser);
if (rvalid && (! (crg_rd_data_full [port_enq])))
crg_rd_data_full [port_enq] <= True;
rg_rd_data <= (AXI4_Rd_Data {rid: rid,
rdata: rdata,
rresp: rresp,
rlast: rlast,
ruser: ruser});
endmethod
method Bool m_rready;
return (! (crg_rd_data_full [port_enq]));
endmethod
method Bool m_rready;
return (! (crg_rd_data_full [port_enq]));
endmethod
endinterface;
endinterface;
// FIFOF side
interface i_wr_addr = fn_crg_and_rg_to_FIFOF_I (crg_wr_addr_full [port_enq], rg_wr_addr);
@@ -447,9 +447,9 @@ endmodule: mkAXI4_Master_Xactor_2
// Slave transactor interface
interface AXI4_Slave_Xactor_IFC #(numeric type wd_id,
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
numeric type wd_dest,
numeric type wd_data,
numeric type wd_user);
method Action reset;
// AXI side
@@ -493,109 +493,109 @@ module mkAXI4_Slave_Xactor (AXI4_Slave_Xactor_IFC #(wd_id, wd_dest, wd_data, wd_
endmethod
// AXI side
interface axi_side = interface AXI4_Slave_IFC;
// Wr Addr channel
method Action m_awvalid (Bool awvalid,
Bit #(wd_id) awid,
Bit #(wd_dest) awaddr,
Bit #(8) awlen,
AXI4_Size awsize,
Bit #(2) awburst,
Bit #(1) awlock,
Bit #(4) awcache,
Bit #(3) awprot,
Bit #(4) awqos,
Bit #(4) awregion,
Bit #(wd_user) awuser);
if (awvalid && f_wr_addr.notFull)
f_wr_addr.enq (AXI4_Wr_Addr {awid: awid,
awaddr: awaddr,
awlen: awlen,
awsize: awsize,
awburst: awburst,
awlock: awlock,
awcache: awcache,
awprot: awprot,
awqos: awqos,
awregion: awregion,
awuser: awuser});
endmethod
// Wr Addr channel
method Action m_awvalid (Bool awvalid,
Bit #(wd_id) awid,
Bit #(wd_dest) awaddr,
Bit #(8) awlen,
AXI4_Size awsize,
Bit #(2) awburst,
Bit #(1) awlock,
Bit #(4) awcache,
Bit #(3) awprot,
Bit #(4) awqos,
Bit #(4) awregion,
Bit #(wd_user) awuser);
if (awvalid && f_wr_addr.notFull)
f_wr_addr.enq (AXI4_Wr_Addr {awid: awid,
awaddr: awaddr,
awlen: awlen,
awsize: awsize,
awburst: awburst,
awlock: awlock,
awcache: awcache,
awprot: awprot,
awqos: awqos,
awregion: awregion,
awuser: awuser});
endmethod
method Bool m_awready;
return f_wr_addr.notFull;
endmethod
method Bool m_awready;
return f_wr_addr.notFull;
endmethod
// Wr Data channel
method Action m_wvalid (Bool wvalid,
Bit #(wd_id) wid,
Bit #(wd_data) wdata,
it #(TDiv #(wd_data, 8)) wstrb,
Bool wlast,
Bit #(wd_user) wuser);
if (wvalid && f_wr_data.notFull)
f_wr_data.enq (AXI4_Wr_Data {wid: wid,
wdata: wdata,
wstrb: wstrb,
wlast: wlast,
wuser: wuser});
endmethod
// Wr Data channel
method Action m_wvalid (Bool wvalid,
Bit #(wd_id) wid,
Bit #(wd_data) wdata,
it #(TDiv #(wd_data, 8)) wstrb,
Bool wlast,
Bit #(wd_user) wuser);
if (wvalid && f_wr_data.notFull)
f_wr_data.enq (AXI4_Wr_Data {wid: wid,
wdata: wdata,
wstrb: wstrb,
wlast: wlast,
wuser: wuser});
endmethod
method Bool m_wready;
return f_wr_data.notFull;
endmethod
method Bool m_wready;
return f_wr_data.notFull;
endmethod
// Wr Response channel
method Bool m_bvalid = f_wr_resp.notEmpty;
method Bit #(wd_id) m_bid = f_wr_resp.first.bid;
method Bit #(2) m_bresp = f_wr_resp.first.bresp;
method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
method Action m_bready (Bool bready);
if (bready && f_wr_resp.notEmpty)
f_wr_resp.deq;
endmethod
// Wr Response channel
method Bool m_bvalid = f_wr_resp.notEmpty;
method Bit #(wd_id) m_bid = f_wr_resp.first.bid;
method Bit #(2) m_bresp = f_wr_resp.first.bresp;
method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
method Action m_bready (Bool bready);
if (bready && f_wr_resp.notEmpty)
f_wr_resp.deq;
endmethod
// Rd Addr channel
method Action m_arvalid (Bool arvalid,
Bit #(wd_id) arid,
Bit #(wd_dest) araddr,
Bit #(8) arlen,
AXI4_Size arsize,
Bit #(2) arburst,
Bit #(1) arlock,
Bit #(4) arcache,
Bit #(3) arprot,
Bit #(4) arqos,
Bit #(4) arregion,
Bit #(wd_user) aruser);
if (arvalid && f_rd_addr.notFull)
f_rd_addr.enq (AXI4_Rd_Addr {arid: arid,
araddr: araddr,
arlen: arlen,
arsize: arsize,
arburst: arburst,
arlock: arlock,
arcache: arcache,
arprot: arprot,
arqos: arqos,
arregion: arregion,
aruser: aruser});
endmethod
// Rd Addr channel
method Action m_arvalid (Bool arvalid,
Bit #(wd_id) arid,
Bit #(wd_dest) araddr,
Bit #(8) arlen,
AXI4_Size arsize,
Bit #(2) arburst,
Bit #(1) arlock,
Bit #(4) arcache,
Bit #(3) arprot,
Bit #(4) arqos,
Bit #(4) arregion,
Bit #(wd_user) aruser);
if (arvalid && f_rd_addr.notFull)
f_rd_addr.enq (AXI4_Rd_Addr {arid: arid,
araddr: araddr,
arlen: arlen,
arsize: arsize,
arburst: arburst,
arlock: arlock,
arcache: arcache,
arprot: arprot,
arqos: arqos,
arregion: arregion,
aruser: aruser});
endmethod
method Bool m_arready;
return f_rd_addr.notFull;
endmethod
method Bool m_arready;
return f_rd_addr.notFull;
endmethod
// Rd Data channel
method Bool m_rvalid = f_rd_data.notEmpty;
method Bit #(wd_id) m_rid = f_rd_data.first.rid;
method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
method Bit #(2) m_rresp = f_rd_data.first.rresp;
method Bool m_rlast = f_rd_data.first.rlast;
method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
method Action m_rready (Bool rready);
if (rready && f_rd_data.notEmpty)
f_rd_data.deq;
endmethod
endinterface;
// Rd Data channel
method Bool m_rvalid = f_rd_data.notEmpty;
method Bit #(wd_id) m_rid = f_rd_data.first.rid;
method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
method Bit #(2) m_rresp = f_rd_data.first.rresp;
method Bool m_rlast = f_rd_data.first.rlast;
method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
method Action m_rready (Bool rready);
if (rready && f_rd_data.notEmpty)
f_rd_data.deq;
endmethod
endinterface;
// FIFOF side
interface o_wr_addr = to_FIFOF_O (f_wr_addr);
@@ -650,116 +650,116 @@ module mkAXI4_Slave_Xactor_2 (AXI4_Slave_Xactor_IFC #(wd_id, wd_dest, wd_data, w
// AXI side
interface axi_side = interface AXI4_Slave_IFC;
// Wr Addr channel
method Action m_awvalid (Bool awvalid,
Bit #(wd_id) awid,
Bit #(wd_dest) awaddr,
Bit #(8) awlen,
AXI4_Size awsize,
Bit #(2) awburst,
Bit #(1) awlock,
Bit #(4) awcache,
Bit #(3) awprot,
Bit #(4) awqos,
Bit #(4) awregion,
Bit #(wd_user) awuser);
// Wr Addr channel
method Action m_awvalid (Bool awvalid,
Bit #(wd_id) awid,
Bit #(wd_dest) awaddr,
Bit #(8) awlen,
AXI4_Size awsize,
Bit #(2) awburst,
Bit #(1) awlock,
Bit #(4) awcache,
Bit #(3) awprot,
Bit #(4) awqos,
Bit #(4) awregion,
Bit #(wd_user) awuser);
if (awvalid && (! crg_wr_addr_full [port_enq])) begin
crg_wr_addr_full [port_enq] <= True; // enq
rg_wr_addr <= AXI4_Wr_Addr {awid: awid,
awaddr: awaddr,
awlen: awlen,
awsize: awsize,
awburst: awburst,
awlock: awlock,
awcache: awcache,
awprot: awprot,
awqos: awqos,
awregion: awregion,
awuser: awuser};
end
endmethod
if (awvalid && (! crg_wr_addr_full [port_enq])) begin
crg_wr_addr_full [port_enq] <= True; // enq
rg_wr_addr <= AXI4_Wr_Addr {awid: awid,
awaddr: awaddr,
awlen: awlen,
awsize: awsize,
awburst: awburst,
awlock: awlock,
awcache: awcache,
awprot: awprot,
awqos: awqos,
awregion: awregion,
awuser: awuser};
end
endmethod
method Bool m_awready;
return (! crg_wr_addr_full [port_enq]);
endmethod
method Bool m_awready;
return (! crg_wr_addr_full [port_enq]);
endmethod
// Wr Data channel
method Action m_wvalid (Bool wvalid,
Bit #(wd_id) wid,
Bit #(wd_data) wdata,
Bit #(TDiv #(wd_data, 8)) wstrb,
Bool wlast,
Bit #(wd_user) wuser);
if (wvalid && (! crg_wr_data_full [port_enq])) begin
crg_wr_data_full [port_enq] <= True; // enq
rg_wr_data <= AXI4_Wr_Data {wid: wid,
wdata: wdata,
wstrb: wstrb,
wlast: wlast,
wuser: wuser};
end
endmethod
// Wr Data channel
method Action m_wvalid (Bool wvalid,
Bit #(wd_id) wid,
Bit #(wd_data) wdata,
Bit #(TDiv #(wd_data, 8)) wstrb,
Bool wlast,
Bit #(wd_user) wuser);
if (wvalid && (! crg_wr_data_full [port_enq])) begin
crg_wr_data_full [port_enq] <= True; // enq
rg_wr_data <= AXI4_Wr_Data {wid: wid,
wdata: wdata,
wstrb: wstrb,
wlast: wlast,
wuser: wuser};
end
endmethod
method Bool m_wready;
return (! crg_wr_data_full [port_enq]);
endmethod
method Bool m_wready;
return (! crg_wr_data_full [port_enq]);
endmethod
// Wr Response channel
method Bool m_bvalid = crg_wr_resp_full [port_deq];
method Bit #(wd_id) m_bid = rg_wr_resp.bid;
method Bit #(2) m_bresp = rg_wr_resp.bresp;
method Bit #(wd_user) m_buser = rg_wr_resp.buser;
method Action m_bready (Bool bready);
if (bready && crg_wr_resp_full [port_deq])
crg_wr_resp_full [port_deq] <= False; // deq
endmethod
// Wr Response channel
method Bool m_bvalid = crg_wr_resp_full [port_deq];
method Bit #(wd_id) m_bid = rg_wr_resp.bid;
method Bit #(2) m_bresp = rg_wr_resp.bresp;
method Bit #(wd_user) m_buser = rg_wr_resp.buser;
method Action m_bready (Bool bready);
if (bready && crg_wr_resp_full [port_deq])
crg_wr_resp_full [port_deq] <= False; // deq
endmethod
// Rd Addr channel
method Action m_arvalid (Bool arvalid,
Bit #(wd_id) arid,
Bit #(wd_dest) araddr,
Bit #(8) arlen,
AXI4_Size arsize,
Bit #(2) arburst,
Bit #(1) arlock,
Bit #(4) arcache,
Bit #(3) arprot,
Bit #(4) arqos,
Bit #(4) arregion,
Bit #(wd_user) aruser);
if (arvalid && (! crg_rd_addr_full [port_enq])) begin
crg_rd_addr_full [port_enq] <= True; // enq
rg_rd_addr <= AXI4_Rd_Addr {arid: arid,
araddr: araddr,
arlen: arlen,
arsize: arsize,
arburst: arburst,
arlock: arlock,
arcache: arcache,
arprot: arprot,
arqos: arqos,
arregion: arregion,
aruser: aruser};
end
endmethod
// Rd Addr channel
method Action m_arvalid (Bool arvalid,
Bit #(wd_id) arid,
Bit #(wd_dest) araddr,
Bit #(8) arlen,
AXI4_Size arsize,
Bit #(2) arburst,
Bit #(1) arlock,
Bit #(4) arcache,
Bit #(3) arprot,
Bit #(4) arqos,
Bit #(4) arregion,
Bit #(wd_user) aruser);
if (arvalid && (! crg_rd_addr_full [port_enq])) begin
crg_rd_addr_full [port_enq] <= True; // enq
rg_rd_addr <= AXI4_Rd_Addr {arid: arid,
araddr: araddr,
arlen: arlen,
arsize: arsize,
arburst: arburst,
arlock: arlock,
arcache: arcache,
arprot: arprot,
arqos: arqos,
arregion: arregion,
aruser: aruser};
end
endmethod
method Bool m_arready;
return (! crg_rd_addr_full [port_enq]);
endmethod
method Bool m_arready;
return (! crg_rd_addr_full [port_enq]);
endmethod
// Rd Data channel
method Bool m_rvalid = crg_rd_data_full [port_deq];
method Bit #(wd_id) m_rid = rg_rd_data.rid;
method Bit #(wd_data) m_rdata = rg_rd_data.rdata;
method Bit #(2) m_rresp = rg_rd_data.rresp;
method Bool m_rlast = rg_rd_data.rlast;
method Bit #(wd_user) m_ruser = rg_rd_data.ruser;
method Action m_rready (Bool rready);
if (rready && crg_rd_data_full [port_deq])
crg_rd_data_full [port_deq] <= False; // deq
endmethod
endinterface;
// Rd Data channel
method Bool m_rvalid = crg_rd_data_full [port_deq];
method Bit #(wd_id) m_rid = rg_rd_data.rid;
method Bit #(wd_data) m_rdata = rg_rd_data.rdata;
method Bit #(2) m_rresp = rg_rd_data.rresp;
method Bool m_rlast = rg_rd_data.rlast;
method Bit #(wd_user) m_ruser = rg_rd_data.ruser;
method Action m_rready (Bool rready);
if (rready && crg_rd_data_full [port_deq])
crg_rd_data_full [port_deq] <= False; // deq
endmethod
endinterface;
// FIFOF side
interface o_wr_addr = fn_crg_and_rg_to_FIFOF_O (crg_wr_addr_full [port_deq], rg_wr_addr);

View File

@@ -49,8 +49,8 @@ endfunction
// Update an n-byte word taking into account an n-bit strobe
function Bit# (TMul #(n,8)) fn_update_strobed_bytes (Bit# (TMul #(n,8)) old_data,
Bit# (TMul #(n,8)) new_data,
Bit #(n) strobe);
Bit# (TMul #(n,8)) new_data,
Bit #(n) strobe);
Bit# (TMul #(n,8)) mask = fn_strobe_to_mask (strobe);
return ((old_data & (~ mask)) | (new_data & mask));
endfunction
@@ -68,8 +68,8 @@ endfunction
// 32b version
function Tuple3 #(Bool, //
Bit #(4), // strobe
Bit #(32)) // lane-adjusted data
Bit #(4), // strobe
Bit #(32)) // lane-adjusted data
fn_lane_adjust_32b (Bit #(32) addr, Bit #(3) dw, Bit #(32) data);
Bit #(4) strobe = 0;
@@ -77,20 +77,20 @@ function Tuple3 #(Bool, //
case (dw)
1: case (addr [1:0])
2'b00: begin strobe = 'b_0001; end
2'b01: begin strobe = 'b_0010; data = (data << 8); end
2'b10: begin strobe = 'b_0100; data = (data << 16); end
2'b11: begin strobe = 'b_1000; data = (data << 24); end
endcase
2'b00: begin strobe = 'b_0001; end
2'b01: begin strobe = 'b_0010; data = (data << 8); end
2'b10: begin strobe = 'b_0100; data = (data << 16); end
2'b11: begin strobe = 'b_1000; data = (data << 24); end
endcase
2: case (addr [1:0])
2'b00: begin strobe = 'b_0011; end
2'b10: begin strobe = 'b_1100; data = (data << 16); end
default: err = True;
endcase
2'b00: begin strobe = 'b_0011; end
2'b10: begin strobe = 'b_1100; data = (data << 16); end
default: err = True;
endcase
4: case (addr [1:0])
2'b00: strobe = 'b_1111;
default: err = True;
endcase
2'b00: strobe = 'b_1111;
default: err = True;
endcase
default: err = True;
endcase
return tuple3 (err, strobe, data);
@@ -100,8 +100,8 @@ endfunction
// 64b version
function Tuple3 #(Bool, // err: misaligned, or bad data_width
Bit #(8), // strobe
Bit #(64)) // lane-adjusted data
Bit #(8), // strobe
Bit #(64)) // lane-adjusted data
fn_lane_adjust_64b (Bit #(64) addr, Bit #(4) dw, Bit #(64) data);
Bit #(8) strobe = 0;
@@ -109,31 +109,31 @@ function Tuple3 #(Bool, // err: misaligned, or bad data_width
case (dw)
1: case (addr [2:0])
3'b000: begin strobe = 'b_0000_0001; end
3'b001: begin strobe = 'b_0000_0010; data = (data << 8); end
3'b010: begin strobe = 'b_0000_0100; data = (data << 16); end
3'b011: begin strobe = 'b_0000_1000; data = (data << 24); end
3'b100: begin strobe = 'b_0001_0000; data = (data << 32); end
3'b101: begin strobe = 'b_0010_0000; data = (data << 40); end
3'b110: begin strobe = 'b_0100_0000; data = (data << 48); end
3'b111: begin strobe = 'b_1000_0000; data = (data << 56); end
endcase
3'b000: begin strobe = 'b_0000_0001; end
3'b001: begin strobe = 'b_0000_0010; data = (data << 8); end
3'b010: begin strobe = 'b_0000_0100; data = (data << 16); end
3'b011: begin strobe = 'b_0000_1000; data = (data << 24); end
3'b100: begin strobe = 'b_0001_0000; data = (data << 32); end
3'b101: begin strobe = 'b_0010_0000; data = (data << 40); end
3'b110: begin strobe = 'b_0100_0000; data = (data << 48); end
3'b111: begin strobe = 'b_1000_0000; data = (data << 56); end
endcase
2: case (addr [2:0])
3'b000: begin strobe = 'b_0000_0011; end
3'b010: begin strobe = 'b_0000_1100; data = (data << 16); end
3'b100: begin strobe = 'b_0011_0000; data = (data << 32); end
3'b110: begin strobe = 'b_1100_0000; data = (data << 48); end
default: err = True;
endcase
3'b000: begin strobe = 'b_0000_0011; end
3'b010: begin strobe = 'b_0000_1100; data = (data << 16); end
3'b100: begin strobe = 'b_0011_0000; data = (data << 32); end
3'b110: begin strobe = 'b_1100_0000; data = (data << 48); end
default: err = True;
endcase
3: case (addr [2:0])
3'b000: begin strobe = 'b_0000_1111; end
3'b100: begin strobe = 'b_1111_0000; data = (data << 32); end
default: err = True;
endcase
3'b000: begin strobe = 'b_0000_1111; end
3'b100: begin strobe = 'b_1111_0000; data = (data << 32); end
default: err = True;
endcase
4: case (addr [2:0])
3'b000: begin strobe = 'b_1111_1111; end
default: err = True;
endcase
3'b000: begin strobe = 'b_1111_1111; end
default: err = True;
endcase
default: err = True;
endcase
return tuple3 (err, strobe, data);
@@ -146,27 +146,27 @@ endfunction
// 32b version
function Tuple2 #(Bool, // err: misaligned, or bad data_width
Bit #(32)) // lane-unadjusted data
Bit #(32)) // lane-unadjusted data
fn_lane_unadjust_32b (Bit #(32) addr, Bit #(3) dw, Bit #(32) data);
Bool err = False;
case (dw)
1: case (addr [1:0])
2'b00: data = (data >> 0);
2'b01: data = (data >> 8);
2'b10: data = (data >> 16);
2'b11: data = (data >> 24);
endcase
2'b00: data = (data >> 0);
2'b01: data = (data >> 8);
2'b10: data = (data >> 16);
2'b11: data = (data >> 24);
endcase
2: case (addr [1:0])
2'b00: data = (data >> 0);
2'b10: data = (data >> 16);
default: err = True;
endcase
2'b00: data = (data >> 0);
2'b10: data = (data >> 16);
default: err = True;
endcase
4: case (addr [1:0])
2'b00: data = (data >> 0);
default: err = True;
endcase
2'b00: data = (data >> 0);
default: err = True;
endcase
default: err = True;
endcase
return tuple2 (err, data);
@@ -176,38 +176,38 @@ endfunction
// 64b version
function Tuple2 #(Bool, // err: misaligned, or bad data_width
Bit #(64)) // lane-unadjusted data
Bit #(64)) // lane-unadjusted data
fn_lane_unadjust_64b (Bit #(64) addr, Bit #(4) dw, Bit #(64) data);
Bool err = False;
case (dw)
1: case (addr [2:0])
3'b000: data = (data >> 0);
3'b001: data = (data >> 8);
3'b010: data = (data >> 16);
3'b011: data = (data >> 24);
3'b100: data = (data >> 32);
3'b101: data = (data >> 40);
3'b110: data = (data >> 48);
3'b111: data = (data >> 56);
endcase
3'b000: data = (data >> 0);
3'b001: data = (data >> 8);
3'b010: data = (data >> 16);
3'b011: data = (data >> 24);
3'b100: data = (data >> 32);
3'b101: data = (data >> 40);
3'b110: data = (data >> 48);
3'b111: data = (data >> 56);
endcase
2: case (addr [2:0])
3'b000: data = (data >> 0);
3'b010: data = (data >> 16);
3'b100: data = (data >> 32);
3'b110: data = (data >> 48);
default: err = True;
endcase
3'b000: data = (data >> 0);
3'b010: data = (data >> 16);
3'b100: data = (data >> 32);
3'b110: data = (data >> 48);
default: err = True;
endcase
4: case (addr [2:0])
3'b000: data = (data >> 0);
3'b100: data = (data >> 32);
default: err = True;
endcase
3'b000: data = (data >> 0);
3'b100: data = (data >> 32);
default: err = True;
endcase
8: case (addr [2:0])
3'b000: data = (data >> 0);
default: err = True;
endcase
3'b000: data = (data >> 0);
default: err = True;
endcase
default: err = True;
endcase
return tuple2 (err, data);

View File

@@ -39,16 +39,16 @@ module mkCreditCounter (CreditCounter_IFC #(w));
method Action incr;
if (crg [0] == maxBound) begin
$display ("%0d: ERROR: CreditCounter: overflow", cur_cycle);
$finish (1); // Assertion failure
$display ("%0d: ERROR: CreditCounter: overflow", cur_cycle);
$finish (1); // Assertion failure
end
crg [0] <= crg [0] + 1;
endmethod
method Action decr () if (crg [1] != 0);
if (crg [1] == 0) begin
$display ("%0d: ERROR: CreditCounter: underflow", cur_cycle);
$finish (1); // Assertion failure
$display ("%0d: ERROR: CreditCounter: underflow", cur_cycle);
$finish (1); // Assertion failure
end
crg [1] <= crg [1] - 1;
endmethod

View File

@@ -6,9 +6,9 @@ package Cur_Cycle;
// A convenience function to return the current cycle number during BSV simulations
ActionValue #(Bit #(32)) cur_cycle = actionvalue
Bit #(32) t <- $stime;
return t / 10;
endactionvalue;
Bit #(32) t <- $stime;
return t / 10;
endactionvalue;
// ================================================================

View File

@@ -26,26 +26,26 @@ endfunction
// 'put' is always enabled and just discards its argument.
Get #(t) getstub = interface Get;
method ActionValue #(t) get () if (False);
return ?;
endmethod
endinterface;
method ActionValue #(t) get () if (False);
return ?;
endmethod
endinterface;
Put #(t) putstub = interface Put;
method Action put (t x) if (True);
noAction;
endmethod
endinterface;
method Action put (t x) if (True);
noAction;
endmethod
endinterface;
Client #(t1,t2) client_stub = interface Client;
interface request = getstub;
interface response = putstub;
endinterface;
interface request = getstub;
interface response = putstub;
endinterface;
Server #(t1,t2) server_stub = interface Server;
interface request = putstub;
interface response = getstub;
endinterface;
interface request = putstub;
interface response = getstub;
endinterface;
// ================================================================
// For debugging, a convenience function to display full/empty status of a FIFO
@@ -96,30 +96,30 @@ endmodule
// dequeue side: never ready
FIFOF #(t) dummy_FIFOF = interface FIFOF;
method Action enq (x) if (False);
noAction;
endmethod
method Action enq (x) if (False);
noAction;
endmethod
method notFull;
return False;
endmethod
method notFull;
return False;
endmethod
method first () if (False);
return ?;
endmethod
method first () if (False);
return ?;
endmethod
method Action deq () if (False);
noAction;
endmethod
method Action deq () if (False);
noAction;
endmethod
method notEmpty;
return False;
endmethod
method notEmpty;
return False;
endmethod
method Action clear;
noAction;
endmethod
endinterface;
method Action clear;
noAction;
endmethod
endinterface;
// ================================================================

View File

@@ -41,34 +41,34 @@ endtypeclass
instance To_FIFOF_IO#(FIFOF#(t), t);
function FIFOF_I #(t) to_FIFOF_I (FIFOF #(t) f);
return interface FIFOF_I;
method enq (x) = f.enq (x);
method notFull = f.notFull;
endinterface;
method enq (x) = f.enq (x);
method notFull = f.notFull;
endinterface;
endfunction
function FIFOF_O #(t) to_FIFOF_O (FIFOF #(t) f);
return interface FIFOF_O;
method first = f.first;
method deq = f.deq;
method notEmpty = f.notEmpty;
endinterface;
method first = f.first;
method deq = f.deq;
method notEmpty = f.notEmpty;
endinterface;
endfunction
endinstance
instance To_FIFOF_IO#(FIFOLevelIfc#(t,n), t);
function FIFOF_I #(t) to_FIFOF_I (FIFOLevelIfc #(t,n) f);
return interface FIFOF_I;
method enq (x) = f.enq (x);
method notFull = f.notFull;
endinterface;
method enq (x) = f.enq (x);
method notFull = f.notFull;
endinterface;
endfunction
function FIFOF_O #(t) to_FIFOF_O (FIFOLevelIfc #(t,n) f);
return interface FIFOF_O;
method first = f.first;
method deq = f.deq;
method notEmpty = f.notEmpty;
endinterface;
method first = f.first;
method deq = f.deq;
method notEmpty = f.notEmpty;
endinterface;
endfunction
endinstance
@@ -78,24 +78,24 @@ endinstance
instance ToGet#(FIFOF_O#(t), t);
function toGet(ff) = (
interface Get;
method get();
actionvalue
ff.deq;
return ff.first;
endactionvalue
endmethod
method get();
actionvalue
ff.deq;
return ff.first;
endactionvalue
endmethod
endinterface
);
);
endinstance
instance ToPut#(FIFOF_I#(t), t);
function toPut(ff) = (
interface Put;
method Action put(x);
ff.enq(x);
endmethod
method Action put(x);
ff.enq(x);
endmethod
endinterface
);
);
endinstance
// ================================================================
@@ -107,8 +107,8 @@ endinstance
instance Connectable #(FIFOF_O #(t), FIFOF_I #(t));
module mkConnection #(FIFOF_O #(t) fo, FIFOF_I #(t) fi) (Empty);
rule rl_connect;
fi.enq (fo.first);
fo.deq;
fi.enq (fo.first);
fo.deq;
endrule
endmodule
endinstance
@@ -128,8 +128,8 @@ endinstance
instance Connectable #(FIFOF_O #(t), FIFOF #(t));
module mkConnection #(FIFOF_O #(t) fo, FIFOF #(t) fi) (Empty);
rule rl_connect;
fi.enq (fo.first);
fo.deq;
fi.enq (fo.first);
fo.deq;
endrule
endmodule
endinstance
@@ -140,8 +140,8 @@ endinstance
instance Connectable #(FIFOF #(t), FIFOF_I #(t));
module mkConnection #(FIFOF #(t) fo, FIFOF_I #(t) fi) (Empty);
rule rl_connect;
fi.enq (fo.first);
fo.deq;
fi.enq (fo.first);
fo.deq;
endrule
endmodule
endinstance
@@ -162,29 +162,29 @@ endfunction
// dummy_FIFO_I that never accepts anything (always "full")
FIFOF_I #(t) dummy_FIFOF_I = interface FIFOF_I;
method Action enq (x) if (False);
noAction;
endmethod
method notFull;
return False;
endmethod
endinterface;
method Action enq (x) if (False);
noAction;
endmethod
method notFull;
return False;
endmethod
endinterface;
// Dummy FIFO_O that never yields anything (always "empty")
FIFOF_O #(t) dummy_FIFOF_O = interface FIFOF_O;
method first () if (False);
return ?;
endmethod
method first () if (False);
return ?;
endmethod
method Action deq () if (False);
noAction;
endmethod
method Action deq () if (False);
noAction;
endmethod
method notEmpty;
return False;
endmethod
endinterface;
method notEmpty;
return False;
endmethod
endinterface;
// ================================================================

229
src_Core/CHERI/ScrFile.bsv Normal file
View File

@@ -0,0 +1,229 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
// CHERI modifications:
// Copyright (c) 2020 Jonathan Woodruff
// All rights reserved.
//
// This software was developed by SRI International and the University of
// Cambridge Computer Laboratory (Department of Computer Science and
// Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
// DARPA SSITH research programme.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
`include "ProcConfig.bsv"
import Types::*;
import ProcTypes::*;
import DefaultValue::*;
import ConfigReg::*;
import Ehr::*;
import GetPut::*;
import Vector::*;
import CHERICap::*;
import CHERICC_Fat::*;
import ISA_Decls_CHERI::*;
// ================================================================
// BSV additional libs
import Cur_Cycle::*;
// ================================================================
// Project imports from Toooba
import SoC_Map::*;
// ================================================================
// Information returned on traps and mret/sret/uret
typedef struct {
Addr new_pc;
} Scr_Trap_Updates
deriving (Bits, FShow);
typedef struct {
Addr new_pc;
} Scr_RET_Updates
deriving (Bits, FShow);
typedef struct {
Addr top;
Addr base;
HardPerms perms;
} ScrVMInfo
deriving (Bits, FShow);
typedef struct {
Bool cap_mode;
} ScrDecodeInfo
deriving (Bits, FShow);
// ================================================================
interface ScrFile;
// Read
method CapReg rd(SCR csr);
// normal write by RWSpecialCap inst to any SCR
method Action scrInstWr(SCR csr, CapReg x);
interface Vector#(SupSize, Put#(CapReg)) pccWr;
// The WARL transform performed during CSRRx writes to a CSR
method CapReg warl_xform (SCR csr, CapReg x);
// Methods for handling traps
method ActionValue#(Scr_Trap_Updates) trap(Trap t, Addr pc, Addr faultAddr, Bit #(32) orig_inst);
method ActionValue#(Scr_RET_Updates) sret;
method ActionValue#(Scr_RET_Updates) mret;
// Outputs for CSRs that the rest of the processor needs to know about
method ScrVMInfo pccCheck;
method ScrVMInfo ddcCheck;
method ScrDecodeInfo decodeInfo;
// terminate
method ActionValue#(void) terminate;
endinterface
// same as EHR except that read port 0 is not ordered with other methods. Read
// port 1 will still get bypassing from write port 0.
module mkConfigEhr#(t init)(Ehr#(n, t)) provisos(Bits#(t, w));
Ehr#(n, t) data <- mkEhr(init);
Wire#(t) read <- mkBypassWire;
(* fire_when_enabled, no_implicit_conditions *)
rule setRead;
read <= data[0];
endrule
Ehr#(n, t) ifc = ?;
ifc[0] = (interface Reg;
method _read = read._read;
method _write = data[0]._write;
endinterface);
for(Integer i = 1; i < valueOf(n); i = i+1) begin
ifc[i] = (interface Reg;
method _read = data[i]._read;
method _write = data[i]._write;
endinterface);
end
return ifc;
endmodule
module mkScrFile (ScrFile);
RiscVISASubset isa = defaultValue;
let mkCsrReg = mkConfigReg;
let mkCsrEhr = mkConfigEhr;
// User level SCRs
Ehr#(SupSize, CapReg) pcc_reg <- mkCsrEhr(defaultValue);
Reg#(CapReg) ddc_reg <- mkCsrReg(defaultValue);
// User level SCRs with accessSysRegs
Reg#(CapReg) utcc_reg <- mkCsrReg(defaultValue);
Reg#(CapReg) utdc_reg <- mkCsrReg(nullCap);
Reg#(CapReg) uScratchC_reg <- mkCsrReg(nullCap);
Reg#(CapReg) uepcc_reg <- mkCsrReg(defaultValue);
// System level SCRs with accessSysRegs
Reg#(CapReg) stcc_reg <- mkCsrReg(defaultValue);
Reg#(CapReg) stdc_reg <- mkCsrReg(nullCap);
Reg#(CapReg) sScratchC_reg <- mkCsrReg(nullCap);
Reg#(CapReg) sepcc_reg <- mkCsrReg(defaultValue);
// Machine level SCRs with accessSysRegs
Reg#(CapReg) mtcc_reg <- mkCsrReg(defaultValue);
Reg#(CapReg) mtdc_reg <- mkCsrReg(nullCap);
Reg#(CapReg) mScratchC_reg <- mkCsrReg(nullCap);
Reg#(CapReg) mepcc_reg <- mkCsrReg(defaultValue);
// Function for getting a csr given an index
function Reg#(CapReg) get_scr(SCR scr);
return (case (scr)
// User SCRs
SCR_PCC: pcc_reg[0];
SCR_DDC: ddc_reg;
// User CSRs with accessSysRegs
SCR_UTCC: utcc_reg;
SCR_UTDC: utdc_reg;
SCR_UScratchC: uScratchC_reg;
SCR_UEPCC: uepcc_reg;
// System CSRs with accessSysRegs
SCR_STCC: stcc_reg;
SCR_STDC: stdc_reg;
SCR_SScratchC: sScratchC_reg;
SCR_SEPCC: sepcc_reg;
// Machine CSRs with accessSysRegs
SCR_MTCC: mtcc_reg;
SCR_MTDC: mtdc_reg;
SCR_MScratchC: mScratchC_reg;
SCR_MEPCC: mepcc_reg;
endcase);
endfunction
// ================================================================
// INTERFACE
method CapReg rd(SCR scr);
return get_scr(scr)._read;
endmethod
method Action scrInstWr(SCR csr, CapReg x);
get_scr(csr)._write(x);
endmethod
interface pccWr = map(toPut,pcc_reg);
method ActionValue#(Scr_Trap_Updates) trap(Trap t, Addr pc, Addr addr, Bit #(32) orig_inst);
return ?;
endmethod
method ActionValue#(Scr_RET_Updates) mret;
return ?;
endmethod
method ActionValue#(Scr_RET_Updates) sret;
return ?;
endmethod
method ScrVMInfo pccCheck;
return ScrVMInfo {
top: truncate(getTop(pcc_reg[0])),
base: truncate(getBase(pcc_reg[0])),
perms: getHardPerms(pcc_reg[0])
};
endmethod
method ScrVMInfo ddcCheck;
// for load/store, need to consider MPRV
return ScrVMInfo {
top: truncate(getTop(ddc_reg)),
base: truncate(getBase(ddc_reg)),
perms: getHardPerms(ddc_reg)
};
endmethod
method ScrDecodeInfo decodeInfo =
ScrDecodeInfo{cap_mode: getFlags(pcc_reg[0])==1'b1};
endmodule

View File

@@ -174,9 +174,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LWSP (MISA misa, Bit #(2) xl, Instr
Bit #(8) offset = { imm_at_6_2 [1:0], imm_at_12, imm_at_6_2 [4:2], 2'b0};
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_LWSP));
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_LWSP));
RegName rs1 = reg_sp;
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LW, rd, op_LOAD);
@@ -194,11 +194,11 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LDSP (MISA misa, Bit #(2) xl, Instr
Bit #(9) offset = { imm_at_6_2 [2:0], imm_at_12, imm_at_6_2 [4:3], 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_LDSP)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_LDSP)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
RegName rs1 = reg_sp;
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LD, rd, op_LOAD);
@@ -217,10 +217,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LQSP (MISA misa, Bit #(2) xl, Instr
Bit #(10) offset = { imm_at_6_2 [3:0], imm_at_12, imm_at_6_2 [4], 4'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_LQSP)
&& (xl == misa_mxl_128));
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_LQSP)
&& (xl == misa_mxl_128));
RegName rs1 = reg_sp;
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LQ, rd, op_LOAD);
@@ -239,10 +239,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FLWSP (MISA misa, Bit #(2) xl, Inst
Bit #(8) offset = { imm_at_6_2 [1:0], imm_at_12, imm_at_6_2 [4:2], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_FLWSP)
&& (misa.f == 1'b1));
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_FLWSP)
&& (misa.f == 1'b1));
RegName rs1 = reg_sp;
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLW, rd, op_LOAD_FP);
@@ -261,12 +261,12 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FLDSP (MISA misa, Bit #(2) xl, Inst
Bit #(9) offset = { imm_at_6_2 [2:0], imm_at_12, imm_at_6_2 [4:3], 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_FLDSP)
&& (misa.d == 1'b1)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C2)
&& (rd != 0)
&& (funct3 == funct3_C_FLDSP)
&& (misa.d == 1'b1)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
RegName rs1 = reg_sp;
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLD, rd, op_LOAD_FP);
@@ -287,8 +287,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SWSP (MISA misa, Bit #(2) xl, Inst
Bit #(8) offset = { imm_at_12_7 [1:0], imm_at_12_7 [5:2], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct3 == funct3_C_SWSP));
&& (op == opcode_C2)
&& (funct3 == funct3_C_SWSP));
RegName rs1 = reg_sp;
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SW, op_STORE);
@@ -306,10 +306,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SDSP (MISA misa, Bit #(2) xl, Inst
Bit #(9) offset = { imm_at_12_7 [2:0], imm_at_12_7 [5:3], 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct3 == funct3_C_SDSP)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C2)
&& (funct3 == funct3_C_SDSP)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
RegName rs1 = reg_sp;
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SD, op_STORE);
@@ -328,9 +328,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SQSP (MISA misa, Bit #(2) xl, Inst
Bit #(10) offset = { imm_at_12_7 [3:0], imm_at_12_7 [5:4], 4'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct3 == funct3_C_SQSP)
&& (xl == misa_mxl_128));
&& (op == opcode_C2)
&& (funct3 == funct3_C_SQSP)
&& (xl == misa_mxl_128));
RegName rs1 = reg_sp;
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SQ, op_STORE);
@@ -349,8 +349,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FSWSP (MISA misa, Bit #(2) xl, Ins
Bit #(8) offset = { imm_at_12_7 [1:0], imm_at_12_7 [5:2], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct3 == funct3_C_FSWSP));
&& (op == opcode_C2)
&& (funct3 == funct3_C_FSWSP));
RegName rs1 = reg_sp;
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSW, op_STORE_FP);
@@ -369,10 +369,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FSDSP (MISA misa, Bit #(2) xl, Ins
Bit #(9) offset = { imm_at_12_7 [2:0], imm_at_12_7 [5:3], 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct3 == funct3_C_FSDSP)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C2)
&& (funct3 == funct3_C_FSDSP)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
RegName rs1 = reg_sp;
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSD, op_STORE_FP);
@@ -393,8 +393,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LW (MISA misa, Bit #(2) xl, Instr
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_LW));
&& (op == opcode_C0)
&& (funct3 == funct3_C_LW));
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LW, rd, op_LOAD);
@@ -411,10 +411,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LD (MISA misa, Bit #(2) xl, Instr
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_LD)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C0)
&& (funct3 == funct3_C_LD)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LD, rd, op_LOAD);
@@ -432,9 +432,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LQ (MISA misa, Bit #(2) xl, Instr
Bit #(9) offset = { imm_at_12_10 [0], imm_at_6_5, imm_at_12_10 [2], imm_at_12_10 [1], 4'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_LQ)
&& (xl == misa_mxl_128));
&& (op == opcode_C0)
&& (funct3 == funct3_C_LQ)
&& (xl == misa_mxl_128));
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LQ, rd, op_LOAD);
@@ -452,8 +452,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FLW (MISA misa, Bit #(2) xl, Inst
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_FLW));
&& (op == opcode_C0)
&& (funct3 == funct3_C_FLW));
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLW, rd, op_LOAD_FP);
@@ -471,10 +471,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FLD (MISA misa, Bit #(2) xl, Inst
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_FLD)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C0)
&& (funct3 == funct3_C_FLD)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLD, rd, op_LOAD_FP);
@@ -494,8 +494,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SW (MISA misa, Bit #(2) xl, Instr
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_SW));
&& (op == opcode_C0)
&& (funct3 == funct3_C_SW));
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SW, op_STORE);
@@ -512,8 +512,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SD (MISA misa, Bit #(2) xl, Instr
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_SD));
&& (op == opcode_C0)
&& (funct3 == funct3_C_SD));
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SD, op_STORE);
@@ -531,8 +531,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SQ (MISA misa, Bit #(2) xl, Instr
Bit #(9) offset = { imm_at_12_10 [0], imm_at_6_5, imm_at_12_10 [2], imm_at_12_10 [1], 4'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_SQ));
&& (op == opcode_C0)
&& (funct3 == funct3_C_SQ));
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SQ, op_STORE);
@@ -550,8 +550,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FSW (MISA misa, Bit #(2) xl, Inst
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_FSW));
&& (op == opcode_C0)
&& (funct3 == funct3_C_FSW));
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSW, op_STORE_FP);
@@ -569,8 +569,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_FSD (MISA misa, Bit #(2) xl, Inst
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_FSD));
&& (op == opcode_C0)
&& (funct3 == funct3_C_FSD));
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSD, op_STORE_FP);
@@ -589,18 +589,18 @@ function Tuple2 #(Bool, Instr) fv_decode_C_J (MISA misa, Bit #(2) xl, Instr_
// Instr fields: CJ-type
match { .funct3, .imm_at_12_2, .op } = fv_ifields_CJ_type (instr_C);
Bit #(12) offset = {imm_at_12_2 [10],
imm_at_12_2 [6],
imm_at_12_2 [8:7],
imm_at_12_2 [4],
imm_at_12_2 [5],
imm_at_12_2 [0],
imm_at_12_2 [9],
imm_at_12_2 [3:1],
1'b0};
imm_at_12_2 [6],
imm_at_12_2 [8:7],
imm_at_12_2 [4],
imm_at_12_2 [5],
imm_at_12_2 [0],
imm_at_12_2 [9],
imm_at_12_2 [3:1],
1'b0};
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_J));
&& (op == opcode_C1)
&& (funct3 == funct3_C_J));
RegName rd = reg_zero;
Bit #(21) imm21 = signExtend (offset);
@@ -616,19 +616,19 @@ function Tuple2 #(Bool, Instr) fv_decode_C_JAL (MISA misa, Bit #(2) xl, Inst
// Instr fields: CJ-type
match { .funct3, .imm_at_12_2, .op } = fv_ifields_CJ_type (instr_C);
Bit #(12) offset = {imm_at_12_2 [10],
imm_at_12_2 [6],
imm_at_12_2 [8:7],
imm_at_12_2 [4],
imm_at_12_2 [5],
imm_at_12_2 [0],
imm_at_12_2 [9],
imm_at_12_2 [3:1],
1'b0};
imm_at_12_2 [6],
imm_at_12_2 [8:7],
imm_at_12_2 [4],
imm_at_12_2 [5],
imm_at_12_2 [0],
imm_at_12_2 [9],
imm_at_12_2 [3:1],
1'b0};
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_JAL)
&& (xl == misa_mxl_32));
&& (op == opcode_C1)
&& (funct3 == funct3_C_JAL)
&& (xl == misa_mxl_32));
RegName rd = reg_ra;
Bit #(21) imm21 = signExtend (offset);
@@ -645,10 +645,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_JR (MISA misa, Bit #(2) xl, Instr
match { .funct4, .rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct4 == funct4_C_JR)
&& (rs1 != 0)
&& (rs2 == 0));
&& (op == opcode_C2)
&& (funct4 == funct4_C_JR)
&& (rs1 != 0)
&& (rs2 == 0));
RegName rd = reg_zero;
Bit #(12) imm12 = 0;
@@ -664,10 +664,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_JALR (MISA misa, Bit #(2) xl, Ins
match { .funct4, .rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct4 == funct4_C_JALR)
&& (rs1 != 0)
&& (rs2 == 0));
&& (op == opcode_C2)
&& (funct4 == funct4_C_JALR)
&& (rs1 != 0)
&& (rs2 == 0));
RegName rd = reg_ra;
Bit #(12) imm12 = 0;
@@ -685,8 +685,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_BEQZ (MISA misa, Bit #(2) xl, Ins
Bit #(9) offset = { imm_at_12_10 [2], imm_at_6_2 [4:3], imm_at_6_2 [0], imm_at_12_10 [1:0], imm_at_6_2 [2:1], 1'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_BEQZ));
&& (op == opcode_C1)
&& (funct3 == funct3_C_BEQZ));
RegName rs2 = reg_zero;
Bit #(13) imm13 = signExtend (offset);
@@ -704,8 +704,8 @@ function Tuple2 #(Bool, Instr) fv_decode_C_BNEZ (MISA misa, Bit #(2) xl, Ins
Bit #(9) offset = { imm_at_12_10 [2], imm_at_6_2 [4:3], imm_at_6_2 [0], imm_at_12_10 [1:0], imm_at_6_2 [2:1], 1'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_BNEZ));
&& (op == opcode_C1)
&& (funct3 == funct3_C_BNEZ));
RegName rs2 = reg_zero;
Bit #(13) imm13 = signExtend (offset);
@@ -726,9 +726,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LI (MISA misa, Bit #(2) xl, Instr
Bit #(6) imm6 = { imm_at_12, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_LI)
&& (rd != 0));
&& (op == opcode_C1)
&& (funct3 == funct3_C_LI)
&& (rd != 0));
RegName rs1 = reg_zero;
Bit #(12) imm12 = signExtend (imm6);
@@ -746,11 +746,11 @@ function Tuple2 #(Bool, Instr) fv_decode_C_LUI (MISA misa, Bit #(2) xl, Inst
Bit #(6) nzimm6 = { imm_at_12, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_LUI)
&& (rd != 0)
&& (rd != 2)
&& (nzimm6 != 0));
&& (op == opcode_C1)
&& (funct3 == funct3_C_LUI)
&& (rd != 0)
&& (rd != 2)
&& (nzimm6 != 0));
Bit #(20) imm20 = signExtend (nzimm6);
let instr = mkInstr_U_type (imm20, rd, op_LUI);
@@ -770,10 +770,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ADDI (MISA misa, Bit #(2) xl, Ins
Bit #(6) nzimm6 = { imm_at_12, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_ADDI)
&& (rd_rs1 != 0)
&& (nzimm6 != 0));
&& (op == opcode_C1)
&& (funct3 == funct3_C_ADDI)
&& (rd_rs1 != 0)
&& (nzimm6 != 0));
Bit #(12) imm12 = signExtend (nzimm6);
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDI, rd_rs1, op_OP_IMM);
@@ -790,10 +790,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_NOP (MISA misa, Bit #(2) xl, Inst
Bit #(6) nzimm6 = { imm_at_12, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_NOP)
&& (rd_rs1 == 0)
&& (nzimm6 == 0));
&& (op == opcode_C1)
&& (funct3 == funct3_C_NOP)
&& (rd_rs1 == 0)
&& (nzimm6 == 0));
Bit #(12) imm12 = signExtend (nzimm6);
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDI, rd_rs1, op_OP_IMM);
@@ -810,11 +810,11 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ADDIW (MISA misa, Bit #(2) xl, In
Bit #(6) imm6 = { imm_at_12, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_ADDIW)
&& (rd_rs1 != 0)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C1)
&& (funct3 == funct3_C_ADDIW)
&& (rd_rs1 != 0)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
Bit #(12) imm12 = signExtend (imm6);
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDIW, rd_rs1, op_OP_IMM_32);
@@ -831,10 +831,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ADDI16SP (MISA misa, Bit #(2) xl,
Bit #(10) nzimm10 = { imm_at_12, imm_at_6_2 [2:1], imm_at_6_2 [3], imm_at_6_2 [0], imm_at_6_2 [4], 4'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_ADDI16SP)
&& (rd_rs1 == reg_sp)
&& (nzimm10 != 0));
&& (op == opcode_C1)
&& (funct3 == funct3_C_ADDI16SP)
&& (rd_rs1 == reg_sp)
&& (nzimm10 != 0));
Bit #(12) imm12 = signExtend (nzimm10);
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDI, rd_rs1, op_OP_IMM);
@@ -851,9 +851,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ADDI4SPN (MISA misa, Bit #(2) xl,
Bit #(10) nzimm10 = { imm_at_12_5 [5:2], imm_at_12_5 [7:6], imm_at_12_5 [0], imm_at_12_5 [1], 2'b0 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C0)
&& (funct3 == funct3_C_ADDI4SPN)
&& (nzimm10 != 0));
&& (op == opcode_C0)
&& (funct3 == funct3_C_ADDI4SPN)
&& (nzimm10 != 0));
RegName rs1 = reg_sp;
Bit #(12) imm12 = zeroExtend (nzimm10);
@@ -871,15 +871,15 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SLLI (MISA misa, Bit #(2) xl, Ins
Bit #(6) shamt6 = { imm_at_12, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct3 == funct3_C_SLLI)
&& (rd_rs1 != 0)
&& (op == opcode_C2)
&& (funct3 == funct3_C_SLLI)
&& (rd_rs1 != 0)
&& (shamt6 != 0)
&& ((xl == misa_mxl_32) ? (imm_at_12 == 0) : True));
&& ((xl == misa_mxl_32) ? (imm_at_12 == 0) : True));
Bit #(12) imm12 = ( (xl == misa_mxl_32)
? { msbs7_SLLI, imm_at_6_2 }
: { msbs6_SLLI, shamt6 } );
? { msbs7_SLLI, imm_at_6_2 }
: { msbs6_SLLI, shamt6 } );
let instr = mkInstr_I_type (imm12, rd_rs1, f3_SLLI, rd_rs1, op_OP_IMM);
return tuple2 (is_legal, instr);
@@ -896,16 +896,16 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SRLI (MISA misa, Bit #(2) xl, Ins
Bit #(6) shamt6 = { shamt6_5, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_SRLI)
&& (funct2 == funct2_C_SRLI)
&& (rd_rs1 != 0)
&& (op == opcode_C1)
&& (funct3 == funct3_C_SRLI)
&& (funct2 == funct2_C_SRLI)
&& (rd_rs1 != 0)
&& (shamt6 != 0)
&& ((xl == misa_mxl_32) ? (shamt6_5 == 0) : True));
&& ((xl == misa_mxl_32) ? (shamt6_5 == 0) : True));
Bit #(12) imm12 = ( (xl == misa_mxl_32)
? { msbs7_SRLI, imm_at_6_2 }
: { msbs6_SRLI, shamt6 } );
? { msbs7_SRLI, imm_at_6_2 }
: { msbs6_SRLI, shamt6 } );
let instr = mkInstr_I_type (imm12, rd_rs1, f3_SRLI, rd_rs1, op_OP_IMM);
return tuple2 (is_legal, instr);
@@ -922,16 +922,16 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SRAI (MISA misa, Bit #(2) xl, Ins
Bit #(6) shamt6 = { shamt6_5, imm_at_6_2 };
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_SRAI)
&& (funct2 == funct2_C_SRAI)
&& (rd_rs1 != 0)
&& (op == opcode_C1)
&& (funct3 == funct3_C_SRAI)
&& (funct2 == funct2_C_SRAI)
&& (rd_rs1 != 0)
&& (shamt6 != 0)
&& ((xl == misa_mxl_32) ? (shamt6_5 == 0) : True));
&& ((xl == misa_mxl_32) ? (shamt6_5 == 0) : True));
Bit #(12) imm12 = ( (xl == misa_mxl_32)
? { msbs7_SRAI, imm_at_6_2 }
: { msbs6_SRAI, shamt6 } );
? { msbs7_SRAI, imm_at_6_2 }
: { msbs6_SRAI, shamt6 } );
let instr = mkInstr_I_type (imm12, rd_rs1, f3_SRAI, rd_rs1, op_OP_IMM);
return tuple2 (is_legal, instr);
@@ -948,9 +948,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ANDI (MISA misa, Bit #(2) xl, Ins
Bit #(2) funct2 = imm_at_12_10 [1:0];
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct3 == funct3_C_ANDI)
&& (funct2 == funct2_C_ANDI));
&& (op == opcode_C1)
&& (funct3 == funct3_C_ANDI)
&& (funct2 == funct2_C_ANDI));
Bit #(12) imm12 = signExtend (imm6);
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ANDI, rd_rs1, op_OP_IMM);
@@ -968,10 +968,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_MV (MISA misa, Bit #(2) xl, Instr
match { .funct4, .rd_rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct4 == funct4_C_MV)
&& (rd_rs1 != 0)
&& (rs2 != 0));
&& (op == opcode_C2)
&& (funct4 == funct4_C_MV)
&& (rd_rs1 != 0)
&& (rs2 != 0));
RegName rs1 = reg_zero;
let instr = mkInstr_R_type (funct7_ADD, rs2, rs1, funct3_ADD, rd_rs1, op_OP);
@@ -986,10 +986,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ADD (MISA misa, Bit #(2) xl, Inst
match { .funct4, .rd_rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct4 == funct4_C_ADD)
&& (rd_rs1 != 0)
&& (rs2 != 0));
&& (op == opcode_C2)
&& (funct4 == funct4_C_ADD)
&& (rd_rs1 != 0)
&& (rs2 != 0));
let instr = mkInstr_R_type (funct7_ADD, rs2, rd_rs1, funct3_ADD, rd_rs1, op_OP);
@@ -1004,9 +1004,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_AND (MISA misa, Bit #(2) xl, Inst
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct6 == funct6_C_AND)
&& (funct2 == funct2_C_AND));
&& (op == opcode_C1)
&& (funct6 == funct6_C_AND)
&& (funct2 == funct2_C_AND));
let instr = mkInstr_R_type (funct7_AND, rs2, rd_rs1, funct3_AND, rd_rs1, op_OP);
@@ -1021,9 +1021,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_OR (MISA misa, Bit #(2) xl, Instr
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct6 == funct6_C_OR)
&& (funct2 == funct2_C_OR));
&& (op == opcode_C1)
&& (funct6 == funct6_C_OR)
&& (funct2 == funct2_C_OR));
let instr = mkInstr_R_type (funct7_OR, rs2, rd_rs1, funct3_OR, rd_rs1, op_OP);
@@ -1038,9 +1038,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_XOR (MISA misa, Bit #(2) xl, Inst
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct6 == funct6_C_XOR)
&& (funct2 == funct2_C_XOR));
&& (op == opcode_C1)
&& (funct6 == funct6_C_XOR)
&& (funct2 == funct2_C_XOR));
let instr = mkInstr_R_type (funct7_XOR, rs2, rd_rs1, funct3_XOR, rd_rs1, op_OP);
@@ -1055,9 +1055,9 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SUB (MISA misa, Bit #(2) xl, Inst
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct6 == funct6_C_SUB)
&& (funct2 == funct2_C_SUB));
&& (op == opcode_C1)
&& (funct6 == funct6_C_SUB)
&& (funct2 == funct2_C_SUB));
let instr = mkInstr_R_type (funct7_SUB, rs2, rd_rs1, funct3_SUB, rd_rs1, op_OP);
@@ -1072,11 +1072,11 @@ function Tuple2 #(Bool, Instr) fv_decode_C_ADDW (MISA misa, Bit #(2) xl, Ins
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct6 == funct6_C_ADDW)
&& (funct2 == funct2_C_ADDW)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C1)
&& (funct6 == funct6_C_ADDW)
&& (funct2 == funct2_C_ADDW)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
let instr = mkInstr_R_type (funct7_ADDW, rs2, rd_rs1, funct3_ADDW, rd_rs1, op_OP_32);
@@ -1091,11 +1091,11 @@ function Tuple2 #(Bool, Instr) fv_decode_C_SUBW (MISA misa, Bit #(2) xl, Ins
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C1)
&& (funct6 == funct6_C_SUBW)
&& (funct2 == funct2_C_SUBW)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
&& (op == opcode_C1)
&& (funct6 == funct6_C_SUBW)
&& (funct2 == funct2_C_SUBW)
&& ( (xl == misa_mxl_64)
|| (xl == misa_mxl_128)));
let instr = mkInstr_R_type (funct7_SUBW, rs2, rd_rs1, funct3_SUBW, rd_rs1, op_OP_32);
@@ -1113,10 +1113,10 @@ function Tuple2 #(Bool, Instr) fv_decode_C_EBREAK (MISA misa, Bit #(2) xl, I
match { .funct4, .rd_rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
Bool is_legal = ((misa.c == 1'b1)
&& (op == opcode_C2)
&& (funct4 == funct4_C_EBREAK)
&& (rd_rs1 == 0)
&& (rs2 == 0));
&& (op == opcode_C2)
&& (funct4 == funct4_C_EBREAK)
&& (rd_rs1 == 0)
&& (rs2 == 0));
Bit #(12) imm12 = f12_EBREAK;
let instr = mkInstr_I_type (imm12, rd_rs1, f3_PRIV, rd_rs1, op_SYSTEM);

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +9,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -21,8 +22,6 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Portions Copyright (c) Bluespec, Inc.
`include "ProcConfig.bsv"
import Vector::*;
@@ -34,7 +33,7 @@ import Assert::*;
import Cntrs::*;
import ConfigReg::*;
import FIFO::*;
import Fifo::*;
import Fifos::*;
import Ehr::*;
import Connectable::*;
@@ -87,6 +86,30 @@ import Toooba_RVFI_DII_Bridge::*;
`endif
import CsrFile :: *;
import ScrFile :: *;
// ================================================================
// Toooba
import Cur_Cycle :: *;
import FIFOF :: *;
import GetPut_Aux :: *;
`ifdef INCLUDE_GDB_CONTROL
import DM_CPU_Req_Rsp :: *;
`endif
`ifdef INCLUDE_TANDEM_VERIF
import Trace_Data2 :: *;
`endif
// ================================================================
`ifdef SECURITY
`define SECURITY_OR_INCLUDE_GDB_CONTROL
`elsif INCLUDE_GDB_CONTROL
`define SECURITY_OR_INCLUDE_GDB_CONTROL
`endif
interface CoreReq;
method Action start(
@@ -140,12 +163,27 @@ interface Core;
method Action setMEIP (Bit #(1) v);
method Action setSEIP (Bit #(1) v);
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (Bit #(1) v);
`ifdef RVFI_DII
interface Toooba_RVFI_DII_Server rvfi_dii_server;
`endif
`ifdef INCLUDE_GDB_CONTROL
interface Server #(Bool, Bool) hart0_run_halt_server;
interface Server #(DM_CPU_Req #(5, 64), DM_CPU_Rsp #(64)) hart0_gpr_mem_server;
`ifdef ISA_F
interface Server #(DM_CPU_Req #(5, 64), DM_CPU_Rsp #(64)) hart0_fpr_mem_server;
`endif
interface Server #(DM_CPU_Req #(12, 64), DM_CPU_Rsp #(64)) hart0_csr_mem_server;
`endif
`ifdef INCLUDE_TANDEM_VERIF
// Note: this is a SupSize vector of streams of Trace_Data2 structs,
// each of which has a serialnum field. Each of the SupSize
// streams has serialnums in increasing order. Each serialnum
// appears exactly once in exactly one of the streams. Thus, the
// channels can easily be merged into a single program-order stream.
interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV;
`endif
endinterface
// fixpoint to instantiate modules
@@ -157,9 +195,22 @@ interface CoreFixPoint;
interface Reg#(Bool) doStatsIfc;
endinterface
typedef enum {
`ifdef INCLUDE_GDB_CONTROL
CORE_HALTING,
CORE_HALTED,
`endif
CORE_RUNNING
} Core_Run_State
deriving (Bits, Eq, FShow);
(* synthesize *)
module mkCore#(CoreId coreId)(Core);
let verbose = False;
// ================================================================
Integer verbosity = 0; // More levels of verbosity control than 'Bool verbose'
Reg#(Bool) outOfReset <- mkReg(False);
rule rl_outOfReset if (!outOfReset);
$fwrite(stderr, "mkProc came out of reset\n");
@@ -168,11 +219,24 @@ module mkCore#(CoreId coreId)(Core);
Reg#(Bool) started <- mkReg(False);
// ================================================================
`ifdef INCLUDE_GDB_CONTROL
// Using a ConfigReg since scheduling of reads/writes not critical (TODO: verify this)
Reg #(Core_Run_State) rg_core_run_state <- mkConfigReg (CORE_RUNNING);
`endif
`ifdef INCLUDE_TANDEM_VERIF
Vector #(SupSize, FIFOF #(Trace_Data2)) v_f_to_TV <- replicateM (mkFIFOF);
`endif
// ================================================================
// front end
FetchStage fetchStage <- mkFetchStage;
ITlb iTlb = fetchStage.iTlbIfc;
ICoCache iMem = fetchStage.iMemIfc;
// ================================================================
// If using Direct Instruction Injection then make a
// bridge that can insert instructions.
@@ -187,8 +251,10 @@ module mkCore#(CoreId coreId)(Core);
// back end
RFileSynth rf <- mkRFileSynth;
// Bluespec: CsrFile including external interrupt request methods
// Bluespec: CsrFile including external interrupt request methods
CsrFile csrf <- mkCsrFile(zeroExtend(coreId)); // hartid in CSRF should be core id
// Special Capability register file
ScrFile scaprf <- mkScrFile();
RegRenamingTable regRenamingTable <- mkRegRenamingTable;
EpochManager epochManager <- mkEpochManager;
@@ -242,19 +308,7 @@ module mkCore#(CoreId coreId)(Core);
);
// whether perf data is collected
Reg#(Bool) doStatsReg <- mkConfigReg(False);
// redirect func
//function Action redirectFunc(Addr trap_pc, Maybe#(SpecTag) spec_tag, InstTag inst_tag );
//action
// if (verbose) $fdisplay(stdout, "[redirect_action] new pc = 0x%8x, spec_tag = ", trap_pc, fshow(spec_tag));
// epochManager.redirect;
// fetchStage.redirect(trap_pc);
// if (spec_tag matches tagged Valid .valid_spec_tag) begin
// globalSpecUpdate.incorrectSpec(valid_spec_tag, inst_tag);
// end
//endaction
//endfunction
Reg#(Bool) doStatsReg <- mkConfigReg(False);
// write aggressive elements + wakupe reservation stations
function Action writeAggr(Integer wrAggrPort, PhyRIndx dst);
@@ -302,6 +356,7 @@ module mkCore#(CoreId coreId)(Core);
method rf_rd1 = rf.read[aluRdPort(i)].rd1;
method rf_rd2 = rf.read[aluRdPort(i)].rd2;
method csrf_rd = csrf.rd;
method scaprf_rd = scaprf.rd;
method rob_getPC = rob.getOrigPC[i].get;
method rob_getPredPC = rob.getOrigPredPC[i].get;
method rob_getOrig_Inst = rob.getOrig_Inst[i].get;
@@ -332,7 +387,7 @@ module mkCore#(CoreId coreId)(Core);
let train <- toGet(trainBPQ[i]).get;
fetchStage.train_predictors(
train.pc, train.nextPc, train.iType, train.taken,
train.dpTrain, train.mispred
train.dpTrain, train.mispred, train.isCompressed
);
endrule
end
@@ -345,6 +400,7 @@ module mkCore#(CoreId coreId)(Core);
method rf_rd2 = rf.read[fpuMulDivRdPort(i)].rd2;
method rf_rd3 = rf.read[fpuMulDivRdPort(i)].rd3;
method csrf_rd = csrf.rd;
method scaprf_rd = scaprf.rd;
method rob_setExecuted = rob.setExecuted_doFinishFpuMulDiv[i].set;
method Action writeRegFile(PhyRIndx dst, Data data);
writeAggr(fpuMulDivWrAggrPort(i), dst);
@@ -361,8 +417,12 @@ module mkCore#(CoreId coreId)(Core);
method rf_rd1 = rf.read[memRdPort].rd1;
method rf_rd2 = rf.read[memRdPort].rd2;
method csrf_rd = csrf.rd;
method scaprf_rd = scaprf.rd;
method rob_getPC = rob.getOrigPC[valueof(AluExeNum)].get; // last getPC port
method rob_setExecuted_doFinishMem = rob.setExecuted_doFinishMem;
`ifdef INCLUDE_TANDEM_VERIF
method rob_setExecuted_doFinishMem_RegData = rob.setExecuted_doFinishMem_RegData;
`endif
method rob_setExecuted_deqLSQ = rob.setExecuted_deqLSQ;
method isMMIOAddr = mmio.isMMIOAddr;
method mmioReq = mmio.dataReq;
@@ -407,13 +467,15 @@ module mkCore#(CoreId coreId)(Core);
Reg#(Bool) flush_tlbs <- mkReg(False);
Reg#(Bool) update_vm_info <- mkReg(False);
Reg#(Bool) flush_reservation <- mkReg(False);
`ifdef SECURITY
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
Reg#(Bool) flush_caches <- mkReg(False);
Reg#(Bool) flush_brpred <- mkReg(False);
`else
Reg#(Bool) flush_caches <- mkReadOnlyReg(False);
Reg#(Bool) flush_brpred <- mkReadOnlyReg(False);
`endif
`ifdef SELF_INV_CACHE
Reg#(Bool) reconcile_i <- mkReg(False);
`else
@@ -484,6 +546,7 @@ module mkCore#(CoreId coreId)(Core);
interface sbConsIfc = sbCons;
interface sbAggrIfc = sbAggr;
interface csrfIfc = csrf;
interface scaprfIfc = scaprf;
interface emIfc = epochManager;
interface smIfc = specTagManager;
interface rsAluIfc = reservationStationAlu;
@@ -500,6 +563,9 @@ module mkCore#(CoreId coreId)(Core);
`endif
endmethod
method doStats = coreFix.doStatsIfc._read;
`ifdef INCLUDE_GDB_CONTROL
method Bool core_is_running = (rg_core_run_state == CORE_RUNNING);
`endif
endinterface);
RenameStage renameStage <- mkRenameStage(renameInput);
@@ -508,20 +574,55 @@ module mkCore#(CoreId coreId)(Core);
interface robIfc = rob;
interface rtIfc = regRenamingTable;
interface csrfIfc = csrf;
interface scaprfIfc = scaprf;
method stbEmpty = stb.isEmpty;
method stqEmpty = lsq.stqEmpty;
method lsqSetAtCommit = lsq.setAtCommit;
method tlbNoPendingReq = iTlb.noPendingReq && dTlb.noPendingReq;
method setFlushTlbs = flush_tlbs._write(True);
method setUpdateVMInfo = update_vm_info._write(True);
method setFlushReservation = flush_reservation._write(True);
method setFlushBrPred = flush_brpred._write(True);
method setFlushCaches = flush_caches._write(True);
method setFlushTlbs;
action
flush_tlbs <= True;
// $display ("%0d: %m.commitInput.setFlushTlbs", cur_cycle);
endaction
endmethod
method setUpdateVMInfo;
action
update_vm_info <= True;
// $display ("%0d: %m.commitInput.setUpdateVMInfo", cur_cycle);
endaction
endmethod
method setFlushReservation;
action
flush_reservation <= True;
// $display ("%0d: %m.commitInput.setFlushReservation", cur_cycle);
endaction
endmethod
method setFlushBrPred;
action
flush_brpred <= True;
// $display ("%0d: %m.commitInput.setFlushBrPred", cur_cycle);
endaction
endmethod
method setFlushCaches;
action
flush_caches <= True;
// $display ("%0d: %m.commitInput.setFlushCaches", cur_cycle);
endaction
endmethod
method setReconcileI = reconcile_i._write(True);
method setReconcileD = reconcile_d._write(True);
method killAll = coreFix.killAll;
method redirectPc = fetchStage.redirect;
method setFetchWaitRedirect = fetchStage.setWaitRedirect;
`ifdef INCLUDE_GDB_CONTROL
method setFetchWaitFlush = fetchStage.setWaitFlush;
`endif
method incrementEpoch = epochManager.incrementEpoch;
method commitCsrInstOrInterrupt = csrInstOrInterruptInflight_commit._write(False);
method doStats = coreFix.doStatsIfc._read;
@@ -532,6 +633,11 @@ module mkCore#(CoreId coreId)(Core);
return False;
`endif
endmethod
`ifdef INCLUDE_TANDEM_VERIF
interface v_to_TV = map (toPut, v_f_to_TV);
`endif
endinterface);
CommitStage commitStage <- mkCommitStage(commitInput);
@@ -568,11 +674,13 @@ module mkCore#(CoreId coreId)(Core);
if (flush_reservation) begin
flush_reservation <= False;
dMem.resetLinkAddr;
// $display ("%0d: %m.rule prepareCachesAndTlbs: flushing reservation", cur_cycle);
end
if (flush_tlbs) begin
flush_tlbs <= False;
iTlb.flush;
dTlb.flush;
// $display ("%0d: %m.rule prepareCachesAndTlbs: flushing iTlb and dTlb", cur_cycle);
end
if (update_vm_info) begin
update_vm_info <= False;
@@ -581,10 +689,11 @@ module mkCore#(CoreId coreId)(Core);
iTlb.updateVMInfo(vmI);
dTlb.updateVMInfo(vmD);
l2Tlb.updateVMInfo(vmI, vmD);
// $display ("%0d: %m.rule prepareCachesAndTlbs: updating VMInfo", cur_cycle);
end
endrule
`ifdef SECURITY
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
// Use wires to capture flush regs and empty signals. This is ok because
// there cannot be any activity to make empty -> not-empty or need-flush ->
// no-need-flush when we are trying to flush.
@@ -593,6 +702,7 @@ module mkCore#(CoreId coreId)(Core);
rule setDoFlushCaches(flush_caches && fetchStage.emptyForFlush && lsq.noWrongPathLoads);
doFlushCaches.send;
// $display ("%0d: %m.rl_setDoFlushCaches", cur_cycle);
endrule
rule setDoFlushBrPred(flush_brpred && fetchStage.emptyForFlush);
@@ -605,6 +715,7 @@ module mkCore#(CoreId coreId)(Core);
flush_caches <= False;
iMem.flush;
dMem.flush;
// $display ("%0d: %m.rule flushCaches (imem and dmem)", cur_cycle);
endrule
// security flush branch predictors: wait for wrong path inst fetches to
@@ -612,6 +723,7 @@ module mkCore#(CoreId coreId)(Core);
rule flushBrPred(doFlushBrPred);
flush_brpred <= False;
fetchStage.flush_predictors;
// $display ("%0d: %m.rule flushBrPred", cur_cycle);
endrule
`endif
@@ -656,9 +768,12 @@ module mkCore#(CoreId coreId)(Core);
`endif // SELF_INV_CACHE
rule readyToFetch(
`ifdef INCLUDE_GDB_CONTROL
(rg_core_run_state == CORE_RUNNING) &&
`endif
!flush_reservation && !flush_tlbs && !update_vm_info
&& iTlb.flush_done && dTlb.flush_done
`ifdef SECURITY
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
&& !flush_caches && !flush_brpred
&& iMem.flush_done && dMem.flush_done
&& fetchStage.flush_predictors_done
@@ -671,6 +786,15 @@ module mkCore#(CoreId coreId)(Core);
`endif
);
fetchStage.done_flushing();
`ifdef INCLUDE_GDB_CONTROL
if (commitStage.is_debug_halted) begin
started <= False;
rg_core_run_state <= CORE_HALTING;
if (verbosity >= 1)
$display ("%0d: %m.rule readyToFetch: halting for debug mode", cur_cycle);
end
`endif
endrule
`ifdef PERF_COUNT
@@ -930,6 +1054,280 @@ module mkCore#(CoreId coreId)(Core);
endrule
`endif
`ifdef INCLUDE_GDB_CONTROL
// ================================================================
// DEBUG MODULE INTERFACE
Bool show_DM_interactions = False; // for debugging the interactions
// ----------------------------------------------------------------
// Debug Module GPR read/write
FIFOF #(DM_CPU_Req #(5, 64)) f_gpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(64)) f_gpr_rsps <- mkFIFOF1;
rule rl_debug_gpr_read ( (rg_core_run_state == CORE_HALTED)
&& f_gpr_reqs.notEmpty
&& (! f_gpr_reqs.first.write));
let req <- pop (f_gpr_reqs);
Bit #(5) regnum = req.address;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Gpr regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
let data_out = rf.read [debuggerPort].rd1 (phy_rindx);
let rsp = DM_CPU_Rsp {ok: True, data: data_out};
f_gpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_read_gpr: reg %0d => 0x%0h", cur_cycle, regnum, data_out);
endrule
rule rl_debug_gpr_write ( (rg_core_run_state == CORE_HALTED)
&& f_gpr_reqs.notEmpty
&& f_gpr_reqs.first.write);
let req <- pop (f_gpr_reqs);
Bit #(5) regnum = req.address;
let data_in = req.data;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Gpr regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
rf.write [debuggerPort].wr (phy_rindx, data_in);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_gpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_gpr_write: reg %0d <= 0x%0h (phy_rindx = %0d)",
cur_cycle, regnum, data_in, phy_rindx);
endrule
rule rl_debug_gpr_access_busy (rg_core_run_state == CORE_RUNNING);
let req <- pop (f_gpr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_gpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_gpr_access_busy", cur_cycle);
endrule
`ifdef ISA_F
// ----------------------------------------------------------------
// Debug Module FPR read/write
FIFOF #(DM_CPU_Req #(5, 64)) f_fpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(64)) f_fpr_rsps <- mkFIFOF1;
rule rl_debug_fpr_read ( (rg_core_run_state == CORE_HALTED)
&& (! f_gpr_reqs.notEmpty) // prioritize gpr reqs
&& (! f_fpr_reqs.first.write));
let req <- pop (f_fpr_reqs);
Bit #(5) regnum = req.address;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Fpu regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
let data_out = rf.read [debuggerPort].rd1 (phy_rindx);
let rsp = DM_CPU_Rsp {ok: True, data: data_out};
f_fpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_read_fpr: reg %0d => 0x%0h", cur_cycle, regnum, data_out);
endrule
rule rl_debug_fpr_write ( (rg_core_run_state == CORE_HALTED)
&& (! f_gpr_reqs.notEmpty) // prioritize gpr reqs
&& f_fpr_reqs.first.write);
let req <- pop (f_fpr_reqs);
Bit #(5) regnum = req.address;
let data_in = req.data;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Fpu regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
rf.write [debuggerPort].wr (phy_rindx, data_in);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_fpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_write_fpr: reg %0d <= 0x%0h (phy_rindx %0d)",
cur_cycle, regnum, data_in, phy_rindx);
endrule
rule rl_debug_fpr_access_busy ( (rg_core_run_state == CORE_RUNNING)
&& f_fpr_reqs.notEmpty);
let req <- pop (f_fpr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_fpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_fpr_access_busy", cur_cycle);
endrule
`endif
// ----------------------------------------------------------------
// Debug Module CSR read/write
// Debugger CSR read/write request/response
FIFOF #(DM_CPU_Req #(12, 64)) f_csr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(64)) f_csr_rsps <- mkFIFOF1;
rule rl_debug_csr_read ( (rg_core_run_state == CORE_HALTED)
&& (! f_csr_reqs.first.write));
let req <- pop (f_csr_reqs);
Bit #(12) csr_addr = req.address;
let data_out = csrf.rd (unpack (csr_addr));
let rsp = DM_CPU_Rsp {ok: True, data: data_out};
f_csr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_read_csr: csr [%0h] => 0x%0h", cur_cycle, csr_addr, data_out);
endrule
rule rl_debug_csr_write ( (rg_core_run_state == CORE_HALTED)
&& f_csr_reqs.first.write);
let req <- pop (f_csr_reqs);
Bit #(12) csr_addr = req.address;
let data_in = req.data;
csrf.csrInstWr (unpack (csr_addr), data_in);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_csr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_write_csr: csr [%0h] <= 0x%0h", cur_cycle, csr_addr, data_in);
endrule
rule rl_debug_csr_access_busy (rg_core_run_state == CORE_RUNNING);
let req <- pop (f_csr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_csr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_csr_access_busy", cur_cycle);
endrule
// ----------------------------------------------------------------
// Debug Module run-halt control
FIFOF #(Bool) f_run_halt_reqs <- mkFIFOF;
FIFOF #(Bool) f_run_halt_rsps <- mkFIFOF;
// ----------------
// Debug Module Halt control
rule rl_debug_halt_req ( (rg_core_run_state == CORE_RUNNING)
&& (f_run_halt_reqs.first == False));
f_run_halt_reqs.deq;
// Debugger 'halt' request (e.g., GDB '^C' command)
// This is initiated just like an interrupt.
renameStage.debug_halt_req;
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_halt_req", cur_cycle);
endrule
rule rl_debug_halt_req_already_halted ( (rg_core_run_state != CORE_RUNNING)
&& (f_run_halt_reqs.first == False));
f_run_halt_reqs.deq;
// Notify debugger that we're halted, but otherwise ignore the request
f_run_halt_rsps.enq (False);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_halt_req_already_halted", cur_cycle);
endrule
// Monitors when we've reached halted state while running
// (due to halt, step or EBREAK) and notifies DM
rule rl_debug_halted (rg_core_run_state == CORE_HALTING);
// Notify debugger that we've halted
f_run_halt_rsps.enq (False);
rg_core_run_state <= CORE_HALTED;
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_halted", cur_cycle);
endrule
// ----------------
// Debug Module Resume (run) control
// Resume command when in debug mode
rule rl_debug_resume ( (rg_core_run_state == CORE_HALTED)
&& (f_run_halt_reqs.first == True)
// prioritise gpr/fpr/csr read/write requests before resuming
&& (! f_gpr_reqs.notEmpty)
`ifdef ISA_F
&& (! f_fpr_reqs.notEmpty)
`endif
&& (! f_csr_reqs.notEmpty));
f_run_halt_reqs.deq;
// In Debug Mode, debugger may have updated DCSR (hence privilege level, DCSR[1:0]),
// and also other VM-related state.
// The following TLB actions update to a consistent state.
iTlb.flush;
dTlb.flush;
let vmI = csrf.vmI;
let vmD = csrf.vmD;
iTlb.updateVMInfo(vmI);
dTlb.updateVMInfo(vmD);
l2Tlb.updateVMInfo(vmI, vmD);
let startpc = csrf.dpc_read;
fetchStage.redirect (startpc);
renameStage.debug_resume;
commitStage.debug_resume;
started <= True;
rg_core_run_state <= CORE_RUNNING;
// Notify debugger that we've started running
f_run_halt_rsps.enq (True);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_resume, dpc = 0x%0h", cur_cycle, startpc);
endrule
// Run command when already running
rule rl_debug_run_redundant ( (rg_core_run_state == CORE_RUNNING)
&& (f_run_halt_reqs.first == True));
f_run_halt_reqs.deq;
// Notify debugger that we're running
f_run_halt_rsps.enq (True);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_run_redundant", cur_cycle);
endrule
// ================================================================
`endif
// ================================================================
// INTERFACE
interface CoreReq coreReq;
method Action start(
Bit#(64) startpc,
@@ -941,8 +1339,11 @@ module mkCore#(CoreId coreId)(Core);
`endif
);
started <= True;
`ifdef INCLUDE_GDB_CONTROL
rg_core_run_state <= CORE_RUNNING;
`endif
mmio.setHtifAddrs(toHostAddr, fromHostAddr);
// start rename debug
commitStage.startRenameDebug;
endmethod
@@ -999,7 +1400,7 @@ module mkCore#(CoreId coreId)(Core);
interface checkStarted = nullGet;
`endif
endinterface
`ifdef RVFI_DII
interface Toooba_RVFI_DII_Server rvfi_dii_server = rvfi_bridge.rvfi_dii_server;
`endif
@@ -1013,7 +1414,17 @@ module mkCore#(CoreId coreId)(Core);
method Action setMEIP (v) = csrf.setMEIP (v);
method Action setSEIP (v) = csrf.setSEIP (v);
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (v) = csrf.setDEIP (v);
endmodule
`ifdef INCLUDE_GDB_CONTROL
interface Server hart0_run_halt_server = toGPServer (f_run_halt_reqs, f_run_halt_rsps);
interface Server hart0_gpr_mem_server = toGPServer (f_gpr_reqs, f_gpr_rsps);
`ifdef ISA_F
interface Server hart0_fpr_mem_server = toGPServer (f_fpr_reqs, f_fpr_rsps);
`endif
interface Server hart0_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps);
`endif
`ifdef INCLUDE_TANDEM_VERIF
interface v_to_TV = map (toGet, v_f_to_TV);
`endif
endmodule

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +9,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -21,8 +22,6 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Portions Copyright (c) Bluespec, Inc.
`include "ProcConfig.bsv"
import Types::*;
import ProcTypes::*;
@@ -30,13 +29,55 @@ import DefaultValue::*;
import ConcatReg::*;
import ConfigReg::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import Vector::*;
import FIFO::*;
import GetPut::*;
import BuildVector::*;
//import TRNG::*;
// ================================================================
// BSV additional libs
import Cur_Cycle :: *;
// ================================================================
// Project imports from Toooba
import SoC_Map :: *;
// ================================================================
// Information returned on traps and mret/sret/uret
typedef Bit#(SizeOf#(Exception)) Cause;
typedef struct {
Addr new_pc;
`ifdef INCLUDE_TANDEM_VERIF
// The fields below are for tandem verification only
Bit #(2) prv;
Data status;
Data cause;
Data epc;
Data tval;
`endif
} Trap_Updates
deriving (Bits, FShow);
typedef struct {
Addr new_pc;
`ifdef INCLUDE_TANDEM_VERIF
// The fields below are for tandem verification only
Bit #(2) prv;
Data status;
`endif
} RET_Updates
deriving (Bits, FShow);
// ================================================================
interface CsrFile;
// Read
method Data rd(CSR csr);
@@ -45,12 +86,23 @@ interface CsrFile;
// normal write by FPU inst to FPU CSR
method Bool fpuInstNeedWr(Bit#(5) fflags, Bool fpu_dirty);
method Action fpuInstWr(Bit#(5) fflags); // FPU must become dirty
`ifdef INCLUDE_TANDEM_VERIF
// Returns new fcsr and mstatus (pure function)
method Tuple2 #(Bit #(5), Data) fpuInst_csr_updates (Bit #(5) fflags,
Bool init_for_way0,
Bit #(5) old_fflags,
Data old_mstatus);
method Data getMIP;
`endif
// The WARL transform performed during CSRRx writes to a CSR
method Data warl_xform (CSR csr, Data x);
// Methods for handling traps
method Maybe#(Interrupt) pending_interrupt;
method ActionValue#(Addr) trap(Trap t, Addr pc, Addr faultAddr);
method ActionValue#(Addr) sret;
method ActionValue#(Addr) mret;
method ActionValue#(Trap_Updates) trap(Trap t, Addr pc, Addr faultAddr, Bit #(32) orig_inst);
method ActionValue#(RET_Updates) sret;
method ActionValue#(RET_Updates) mret;
// Outputs for CSRs that the rest of the processor needs to know about
method VMInfo vmI;
@@ -79,9 +131,6 @@ interface CsrFile;
method Action setMEIP (Bit #(1) v);
method Action setSEIP (Bit #(1) v);
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (Bit #(1) v);
// performance stats is collected or not
method Bool doPerfStats;
// send/recv updates on stats CSR globally
@@ -90,6 +139,26 @@ interface CsrFile;
// terminate
method ActionValue#(void) terminate;
`ifdef INCLUDE_GDB_CONTROL
// Read dpc
method Addr dpc_read ();
// Update dpc
method Action dpc_write (Addr pc);
// Check whether to enter Debug Mode based on dcsr.{ebreakm, ebreaks, ebreaku}
method Bit #(1) dcsr_break_bit;
// Read dcsr[2], the step bit
method Bit #(1) dcsr_step_bit;
// Update 'cause' in DCSR
// Is invoked by logic that stops a hart, to enter Debug Mode
(* always_ready *)
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
`endif
endinterface
// Fancy Reg functions
@@ -240,14 +309,17 @@ module mkCsrFile #(Data hartid)(CsrFile);
// current prv level (this is not a csr...)
Reg#(Bit#(2)) prv_reg <- mkCsrReg(prvM);
// Machine level CSRs
// mstatus
Reg#(Bit#(2)) xs_reg <- mkReadOnlyReg(0); // XXX no extension
Reg#(Bit#(2)) fs_reg <- (isa.f || isa.d) ? mkCsrReg(0) : mkReadOnlyReg(0);
Reg#(Bit#(2)) fs_reg <- (isa.f || isa.d) ? mkCsrReg(2'b01) : mkReadOnlyReg(0);
Reg#(Bit#(1)) sd_reg = readOnlyReg(
((xs_reg == 2'b11) || (fs_reg == 2'b11)) ? 1 : 0
);
function Bit #(1) fn_sd_val (Bit #(2) xs_val, Bit #(2) fs_val);
return (((xs_val == 2'b11) || (fs_val == 2'b11)) ? 1 : 0);
endfunction
Reg#(Bit#(2)) sxl_reg = readOnlyReg(getXLBits);
Reg#(Bit#(2)) uxl_reg = readOnlyReg(getXLBits);
Reg#(Bit#(1)) tsr_reg <- mkCsrReg(0);
@@ -286,6 +358,25 @@ module mkCsrFile #(Data hartid)(CsrFile);
ie_vec[prvM], readOnlyReg(1'b0),
ie_vec[prvS], ie_vec[prvU]
);
function Data fn_mstatus_val (Bit #(2) sxl_val, Bit #(2) uxl_val,
Bit #(1) tsr_val, Bit #(1) tw_val, Bit #(1) tvm_val,
Bit #(1) mxr_val, Bit #(1) sum_val, Bit #(1) mprv_val,
Bit #(2) xs_val, Bit #(2) fs_val,
Bit #(2) mpp_val, Bit #(1) spp_val,
Bit #(1) prev_ie_vec_prvM_val,
Bit #(1) prev_ie_vec_prvS_val, Bit #(1) prev_ie_vec_prvU_val,
Bit #(1) ie_vec_prvM_val,
Bit #(1) ie_vec_prvS_val, Bit #(1) ie_vec_prvU_val);
return {fn_sd_val (xs_val, fs_val),
27'b0, sxl_val, uxl_val, 9'b0,
tsr_val, tw_val, tvm_val, mxr_val, sum_val, mprv_val, xs_val, fs_val,
mpp_val, 2'b0, spp_val,
prev_ie_vec_prvM_val, 1'b0,
prev_ie_vec_prvS_val, prev_ie_vec_prvU_val,
ie_vec_prvM_val, 1'b0,
ie_vec_prvS_val, ie_vec_prvU_val};
endfunction
// misa
Reg#(Data) misa_csr = readOnlyReg({getXLBits, 36'b0, getExtensionBits(isa)});
// medeleg: some exceptions don't exist, fix corresponding bits to 0
@@ -309,7 +400,6 @@ module mkCsrFile #(Data hartid)(CsrFile);
readOnlyReg(1'b0), mideleg_1_0_reg
);
// mie
Reg #(Bit #(1)) debug_int_en = readOnlyReg (1);
Vector#(4, Reg#(Bit#(1))) external_int_en_vec = replicate(readOnlyReg(0));
external_int_en_vec[prvU] <- mkCsrReg(0);
external_int_en_vec[prvS] <- mkCsrReg(0);
@@ -322,16 +412,14 @@ module mkCsrFile #(Data hartid)(CsrFile);
software_int_en_vec[prvU] <- mkCsrReg(0);
software_int_en_vec[prvS] <- mkCsrReg(0);
software_int_en_vec[prvM] <- mkCsrReg(0);
Reg#(Data) mie_csr = concatReg15(
readOnlyReg(49'b0),
debug_int_en, // mie [14]
readOnlyReg(2'b0),
Reg#(Data) mie_csr = concatReg13(
readOnlyReg(52'b0),
external_int_en_vec[prvM], readOnlyReg(1'b0),
external_int_en_vec[prvS], external_int_en_vec[prvU],
external_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: external_int_en_vec[prvU],
timer_int_en_vec[prvM], readOnlyReg(1'b0),
timer_int_en_vec[prvS], timer_int_en_vec[prvU],
timer_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: timer_int_en_vec[prvU],
software_int_en_vec[prvM], readOnlyReg(1'b0),
software_int_en_vec[prvS], software_int_en_vec[prvU]
software_int_en_vec[prvS], readOnlyReg(1'b0) // only if misa.N: software_int_en_vec[prvU]
);
// mtvec
Reg#(Bit#(62)) mtvec_base_hi_reg <- mkCsrReg(0); // this is BASE[63:2]
@@ -355,38 +443,52 @@ module mkCsrFile #(Data hartid)(CsrFile);
Reg#(Data) mepc_csr <- mkCsrReg(0);
// mcause
Reg#(Bit#(1)) mcause_interrupt_reg <- mkCsrReg(0);
Reg#(Bit#(4)) mcause_code_reg <- mkCsrReg(0);
Reg#(Cause) mcause_code_reg <- mkCsrReg(0);
Reg#(Data) mcause_csr = concatReg3(
mcause_interrupt_reg, readOnlyReg(59'b0), mcause_code_reg
mcause_interrupt_reg, readOnlyReg(0), mcause_code_reg
);
function Data fn_mcause_val (Bit #(1) mcause_interrupt_val, Cause mcause_code_val);
return { mcause_interrupt_val, 'b0, mcause_code_val };
endfunction
// mtval (mbadaddr in spike)
Reg#(Data) mtval_csr <- mkCsrReg(0);
// mip
Reg #(Bit #(1)) debug_int_pend <- mkCsrReg (0);
Vector#(4, Reg#(Bit#(1))) external_int_pend_vec = replicate(readOnlyReg(0));
external_int_pend_vec[prvU] <- mkCsrReg(0);
external_int_pend_vec[prvS] <- mkCsrReg(0);
external_int_pend_vec[prvM] <- mkCsrReg(0);
external_int_pend_vec[prvM] <- mkCsrReg(0); // TODO: bug (writeable by CSRRx)?
Vector#(4, Reg#(Bit#(1))) timer_int_pend_vec = replicate(readOnlyReg(0));
timer_int_pend_vec[prvU] <- mkCsrReg(0);
timer_int_pend_vec[prvS] <- mkCsrReg(0);
timer_int_pend_vec[prvM] <- mkCsrReg(0);
timer_int_pend_vec[prvM] <- mkCsrReg(0); // TODO: bug (writeable by CSRRx)?
Vector#(4, Reg#(Bit#(1))) software_int_pend_vec = replicate(readOnlyReg(0));
software_int_pend_vec[prvU] <- mkCsrReg(0);
software_int_pend_vec[prvS] <- mkCsrReg(0);
software_int_pend_vec[prvM] <- mkCsrReg(0);
Reg#(Data) mip_csr = concatReg15(
readOnlyReg(49'b0),
debug_int_pend,
readOnlyReg(2'b0),
external_int_pend_vec[prvM], readOnlyReg(1'b0),
external_int_pend_vec[prvS], external_int_pend_vec[prvU],
readOnlyReg(timer_int_pend_vec[prvM]), // MTIP is read-only to software
software_int_pend_vec[prvM] <- mkCsrReg(0); // TODO: bug (writeable by CSRRx)?
Reg#(Data) mip_csr = concatReg13(
readOnlyReg(52'b0),
// External interrupts
readOnlyReg(external_int_pend_vec[prvM]), // MEIP is read-only to software
readOnlyReg(1'b0),
timer_int_pend_vec[prvS], timer_int_pend_vec[prvU],
software_int_pend_vec[prvM], readOnlyReg(1'b0),
software_int_pend_vec[prvS], software_int_pend_vec[prvU]
external_int_pend_vec[prvS],
readOnlyReg(1'b0), // only if misa.N: external_int_pend_vec[prvU],
// Timer interrupts
readOnlyReg(timer_int_pend_vec[prvM]), // MTIP is read-only to software
readOnlyReg(1'b0),
timer_int_pend_vec[prvS],
readOnlyReg(1'b0), // only if misa.N: timer_int_pend_vec[prvU],
// Software interrupts
readOnlyReg(software_int_pend_vec[prvM]), // MSIP is read-only to software
readOnlyReg(1'b0),
software_int_pend_vec[prvS],
readOnlyReg(1'b0) // only if misa.N: software_int_pend_vec[prvU]
);
// MIP and MIE fields are WARL (Write Any Read Legal)
// We support M-privilege and S-privilege bits only;
// this mask allows only those bits through.
Data mip_mie_warl_mask = zeroExtend (12'h_222);
// minstret
Ehr#(2, Data) minstret_ehr <- mkCsrEhr(0);
Reg#(Data) minstret_csr = minstret_ehr[0];
@@ -411,14 +513,32 @@ module mkCsrFile #(Data hartid)(CsrFile);
readOnlyReg(2'b0), prev_ie_vec[prvS], prev_ie_vec[prvU],
readOnlyReg(2'b0), ie_vec[prvS], ie_vec[prvU]
);
function Data fn_sstatus_val (Bit #(2) uxl_val,
Bit #(1) mxr_val, Bit #(1) sum_val,
Bit #(2) xs_val, Bit #(2) fs_val,
Bit #(1) spp_val,
Bit #(1) prev_ie_vec_prvS_val,
Bit #(1) prev_ie_vec_prvU_val,
Bit #(1) ie_vec_prvS_val,
Bit #(1) ie_vec_prvU_val);
return {fn_sd_val (xs_val, fs_val),
27'b0, 2'b0, uxl_val, 12'b0,
mxr_val, sum_val, 1'b0, xs_val, fs_val,
4'b0, spp_val,
2'b0,
prev_ie_vec_prvS_val, prev_ie_vec_prvU_val,
2'b0,
ie_vec_prvS_val, ie_vec_prvU_val};
endfunction
// sie: restricted view of mie
Reg#(Data) sie_csr = concatReg9(
readOnlyReg(54'b0),
external_int_en_vec[prvS], external_int_en_vec[prvU],
external_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: external_int_en_vec[prvU],
readOnlyReg(2'b0),
timer_int_en_vec[prvS], timer_int_en_vec[prvU],
timer_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: timer_int_en_vec[prvU],
readOnlyReg(2'b0),
software_int_en_vec[prvS], software_int_en_vec[prvU]
software_int_en_vec[prvS], readOnlyReg(1'b0) // only if misa.N: software_int_en_vec[prvU]
);
// stvec
Reg#(Bit#(62)) stvec_base_hi_reg <- mkCsrReg(0); // BASE[63:2]
@@ -442,21 +562,31 @@ module mkCsrFile #(Data hartid)(CsrFile);
Reg#(Data) sepc_csr <- mkCsrReg(0);
// scause
Reg#(Bit#(1)) scause_interrupt_reg <- mkCsrReg(0);
Reg#(Bit#(4)) scause_code_reg <- mkCsrReg(0);
Reg#(Cause) scause_code_reg <- mkCsrReg(0);
Reg#(Data) scause_csr = concatReg3(
scause_interrupt_reg, readOnlyReg(59'b0), scause_code_reg
scause_interrupt_reg, readOnlyReg('b0), scause_code_reg
);
function Data fn_scause_val (Bit #(1) scause_interrupt_val, Cause scause_code_val);
return { scause_interrupt_val, 0, scause_code_val };
endfunction
// stval (sbadaddr in spike)
Reg#(Data) stval_csr <- mkCsrReg(0);
// sip: restricted view of mip
Reg#(Data) sip_csr = concatReg9(
readOnlyReg(54'b0),
external_int_pend_vec[prvS], external_int_pend_vec[prvU],
external_int_pend_vec[prvS], readOnlyReg(1'b0), // only if misa.N: external_int_pend_vec[prvU],
readOnlyReg(2'b0),
timer_int_pend_vec[prvS], timer_int_pend_vec[prvU],
timer_int_pend_vec[prvS], readOnlyReg(1'b0), // only if misa.N: timer_int_pend_vec[prvU],
readOnlyReg(2'b0),
software_int_pend_vec[prvS], software_int_pend_vec[prvU]
software_int_pend_vec[prvS], readOnlyReg(1'b0) // only if misa.N: software_int_pend_vec[prvU]
);
// SIP and SIE fields are WARL (Write Any Read Legal)
// We support S-privilege bits only;
// this mask allows only those bits through.
Data sip_sie_warl_mask = zeroExtend (12'h_222);
// satp (sptbr in spike): FIXME we only support Bare and Sv39, so we hack
// the encoding of mode[3:0] field. Only mode[3] is relevant, other bits
// are always 0
@@ -470,7 +600,7 @@ module mkCsrFile #(Data hartid)(CsrFile);
// User level CSRs
// According to spike, any write to fflags/frm/fcsr will set fs_reg as
// dirty, regardless of whether the write truly changes value or not.
// Besides, any non-zero FP exception flags will also make fs_reg dirty.
// Besides, any non-zero FP exception flags will also make fs_reg dirty.
// fflags: if we directly change fflags_reg (instead of fflags_csr), then
// we must set fs_reg manually
Reg#(Bit#(5)) fflags_reg <- mkCsrReg(0);
@@ -501,6 +631,43 @@ module mkCsrFile #(Data hartid)(CsrFile);
StatsCsr stats_module <- mkStatsCsr;
Reg#(Data) stats_csr = stats_module.reg_ifc;
Reg #(Data) rg_tselect <- mkConfigReg (0);
// Note: ISA test rv64mi-p-breakpoint assumes tdata1's reset value == 0
// Until we implement trigger functionality,
// force 'tdata1.type' field ([xlen-1:xlen-4]) to zero
// meaning: 'There is no trigger at this tselect'
Reg #(Bit #(4)) rg_tdata1_type <- mkReadOnlyReg (0);
Reg #(Bit #(1)) rg_tdata1_dmode <- mkCsrReg (0);
Reg #(Bit #(59)) rg_tdata1_data <- mkCsrReg (0);
Reg #(Data) rg_tdata1 = concatReg3 (rg_tdata1_type, rg_tdata1_dmode, rg_tdata1_data);
Reg #(Data) rg_tdata2 <- mkConfigRegU;
Reg #(Data) rg_tdata3 <- mkConfigRegU;
`ifdef INCLUDE_GDB_CONTROL
// DCSR is 32b even in RV64
Bit #(32) dcsr_reset_value = {4'h4, // [31:28] xdebugver
12'h0, // [27:16] reserved
1'h0, // [15] ebreakm
1'h0, // [14] reserved
1'h0, // [13] ebreaks
1'h0, // [12] ebreaku
1'h0, // [11] stepie
1'h0, // [10] stopcount
1'h0, // [9] stoptime
3'h0, // [8:6] cause // WARNING: 0 is non-standard
1'h0, // [5] reserved
1'h1, // [4] mprven
1'h0, // [3] nmip // non-maskable interrupt pending
1'h0, // [2] step
2'h3}; // [1:0] prv (machine mode)
// RV64: dcsr's upper 32b zeroExtended/ignored
Reg #(Data) rg_dcsr <- mkConfigReg (zeroExtend (dcsr_reset_value));
Reg #(Data) rg_dpc <- mkConfigReg (truncate (soc_map_struct.pc_reset_value));
Reg #(Data) rg_dscratch0 <- mkConfigRegU;
Reg #(Data) rg_dscratch1 <- mkConfigRegU;
`endif
`ifdef SECURITY
// sanctum machine CSRs
@@ -607,16 +774,117 @@ module mkCsrFile #(Data hartid)(CsrFile);
CSRmspec: mspec_csr;
CSRtrng: trng_csr;
`endif
CSRtselect: rg_tselect;
CSRtdata1: rg_tdata1;
CSRtdata2: rg_tdata2;
CSRtdata3: rg_tdata3;
`ifdef INCLUDE_GDB_CONTROL
CSRdcsr: rg_dcsr; // TODO: take NMI into account (cf. Piccolo/Flute)
CSRdpc: rg_dpc;
CSRdscratch0: rg_dscratch0;
CSRdscratch1: rg_dscratch1;
`endif
default: readOnlyReg(64'b0);
endcase);
endfunction
// ================================================================
// This function is the WARL (Write Any Read Legal) transform
// performed during CSR writes. Currently it duplicates the logic
// in the _write method of CSRs; ideally this function should be
// separate from the _write method, which should remain as an
// ordinary _write. The WARL'd value is needed for Tandem
// Verification.
function Data fv_warl_xform (CSR csr, Data x);
Asid x_asid = truncate (x [59:44]);
Bit #(16) asid = zeroExtend (x_asid);
return (
case (csr)
// Machine CSRs
CSRmisa: {getXLBits, 36'b0, getExtensionBits(isa)};
CSRmvendorid: 0;
CSRmarchid: 0;
CSRmimpid: 0;
CSRmhartid: hartid;
CSRmstatus: fn_mstatus_val (getXLBits, // sxl
getXLBits, // uxl
x [22], // tsr
x [21], // tw
x [20], // tvm
x [19], // mxr
x [18], // sum
x [17], // mprv
2'b0, // xs
((isa.f || isa.d) ? x [14:13] : 2'b0), // fs
x [12:11], // mpp
x [8], // spp
x [7], // prev_ie_vec[prvM]
x [5], // prev_ie_vec[prvS]
x [4], // prev_ie_vec[prvU]
x [3], // ie_vec[prvM]
x [1], // ie_vec[prvS]
x [0]); // ie_vec[prvU]
CSRmtvec: { x[63:2], 1'b0, x[0]};
CSRmedeleg: { 48'b0, x[15], 1'b0, x[13:12], x[11], 1'b0, x[9:0]};
CSRmideleg: { 52'b0, x[11], 1'b0, x[9:8], x[7], 1'b0, x[5:4], x[3], 1'b0, x[1:0]};
CSRmip: ((mip_csr & (~ mip_mie_warl_mask)) | (x & mip_mie_warl_mask));
CSRmie: (x & mip_mie_warl_mask);
CSRmcounteren: { 61'b0, x[2:0]};
CSRmcause: { x[63], 59'b0, x[3:0] };
CSRtdata1: { 4'b0, x [59:0] }; // Force tdata.type == 0 ("no trigger at this tselect")
// Supervisor level CSRs
CSRsstatus: fn_sstatus_val (getXLBits, // uxl
x [19], // mxr
x [18], // sum
2'b0, // xs
((isa.f || isa.d) ? x [14:13] : 2'b0), // fs
x [8], // spp
x [5], // prev_ie_vec[prvS]
x [4], // prev_ie_vec[prvU]
x [1], // ie_vec[prvS]
x [0]); // ie_vec[prvU]
CSRstvec: { x[63:2], 1'b0, x[0]};
CSRsip: ((sip_csr & (~ sip_sie_warl_mask)) | (x & sip_sie_warl_mask));
CSRsie: (x & sip_sie_warl_mask);
CSRscounteren: { 61'b0, x[2:0]};
CSRscause: { x[63], 59'b0, x[3:0] };
CSRsatp: { x[63], 3'b0, asid, x [43:0] };
// User level CSRs
CSRfflags: { 59'b0, x [4:0] };
CSRfrm: { 61'b0, x [2:0] };
CSRfcsr: { 56'b0, x [7:0] };
`ifdef INCLUDE_GDB_CONTROL
// Debug Mode CSRs
CSRdcsr: { 32'b0, x[31:28], 12'b0, x[14], 1'b0, x[13:6], 1'b0, x[4:0] };
`endif
default: x;
endcase);
endfunction
// ================================================================
// INTERFACE
method Data rd(CSR csr);
return get_csr(csr)._read;
endmethod
method Action csrInstWr(CSR csr, Data x);
get_csr(csr)._write(x);
`ifdef INCLUDE_GDB_CONTROL
if (csr == CSRdcsr) begin
let prv = x [1:0];
prv_reg <= prv;
end
`endif
endmethod
method Bool fpuInstNeedWr(Bit#(5) fflags, Bool fpu_dirty);
@@ -633,6 +901,35 @@ module mkCsrFile #(Data hartid)(CsrFile);
fflags_reg <= fflags_reg | fflags;
endmethod
`ifdef INCLUDE_TANDEM_VERIF
method Tuple2 #(Bit #(5), Data) fpuInst_csr_updates (Bit #(5) fflags,
Bool init_for_way0,
Bit #(5) old_fflags,
Data old_mstatus);
// Note: old_fflags and old_mstatus are accumulated in
// sequential program order, and so may differ from fflags_reg
// and mstatus_csr, which only change after superscalar-wide
// retirement.
Bit #(5) old_fflags1 = (init_for_way0 ? fflags_reg : old_fflags);
Data old_mstatus1 = (init_for_way0 ? mstatus_csr : old_mstatus);
Bit #(5) new_fflags = (old_fflags1 | fflags);
Data new_mstatus = { 1'b1, old_mstatus1 [62:15], 2'b11, old_mstatus1 [12:0] };
return tuple2 (new_fflags, new_mstatus);
endmethod
method Data getMIP;
return mip_csr;
endmethod
`endif
method Data warl_xform (CSR csr, Data x);
return fv_warl_xform (csr, x);
endmethod
method Maybe#(Interrupt) pending_interrupt;
// first get all the pending interrupts
Bit#(InterruptNum) pend_ints = truncate(mie_csr & mip_csr);
@@ -662,18 +959,19 @@ module mkCsrFile #(Data hartid)(CsrFile);
end
endmethod
method ActionValue#(Addr) trap(Trap t, Addr pc, Addr addr);
method ActionValue#(Trap_Updates) trap(Trap t, Addr pc, Addr addr, Bit #(32) orig_inst);
// figure out trap cause & trap val
Bit#(1) cause_interrupt = 0;
Bit#(4) cause_code = 0;
Cause cause_code = 0;
Data trap_val = 0;
case(t) matches
tagged Exception .e: begin
cause_code = pack(e);
trap_val = (case(e)
IllegalInst: zeroExtend (orig_inst);
InstAddrMisaligned, Breakpoint: return pc;
InstAccessFault, InstPageFault,
InstAccessFault, InstPageFault,
LoadAddrMisaligned, LoadAccessFault,
StoreAddrMisaligned, StoreAccessFault,
LoadPageFault, StorePageFault: return addr;
@@ -682,7 +980,7 @@ module mkCsrFile #(Data hartid)(CsrFile);
endcase);
end
tagged Interrupt .i: begin
cause_code = pack(i);
cause_code = zeroExtend(pack(i));
cause_interrupt = 1;
end
endcase
@@ -716,7 +1014,25 @@ module mkCsrFile #(Data hartid)(CsrFile);
scause_code_reg <= cause_code;
stval_csr <= trap_val;
// return next pc
return getNextPc(stvec_mode_low_reg, stvec_base_hi_reg);
// return getNextPc(stvec_mode_low_reg, stvec_base_hi_reg);
Data sstatus_val = fn_sstatus_val (uxl_reg,
mxr_reg, sum_reg,
xs_reg, fs_reg,
/* spp_reg */ prv_reg [0],
/* prev_ie_vec_[prvS] */ ie_vec[prvS],
prev_ie_vec [prvU],
/* ie_vec [prvS] */ 0,
ie_vec [prvU]);
Data scause_val = fn_scause_val (cause_interrupt, cause_code);
return Trap_Updates {new_pc: getNextPc(stvec_mode_low_reg, stvec_base_hi_reg)
`ifdef INCLUDE_TANDEM_VERIF
, prv: prvS,
status: sstatus_val,
cause: scause_val,
epc: pc,
tval: trap_val
`endif
};
end
else begin
// ie/prv stack
@@ -730,25 +1046,85 @@ module mkCsrFile #(Data hartid)(CsrFile);
mcause_code_reg <= cause_code;
mtval_csr <= trap_val;
// return next pc
return getNextPc(mtvec_mode_low_reg, mtvec_base_hi_reg);
// return getNextPc(mtvec_mode_low_reg, mtvec_base_hi_reg);
Data mstatus_val = fn_mstatus_val (sxl_reg, uxl_reg,
tsr_reg, tw_reg, tvm_reg,
mxr_reg, sum_reg, mprv_reg,
xs_reg, fs_reg,
/* mpp */ prv_reg, spp_reg,
/* prev_ie_vec [prvM] */ ie_vec [prvM],
prev_ie_vec [prvS],
prev_ie_vec [prvU],
/* ie_vec [prvM] */ 0,
ie_vec [prvS],
ie_vec [prvU]);
Data mcause_val = fn_mcause_val (cause_interrupt, cause_code);
return Trap_Updates {new_pc: getNextPc(mtvec_mode_low_reg, mtvec_base_hi_reg)
`ifdef INCLUDE_TANDEM_VERIF
, prv: prvM,
status: mstatus_val,
cause: mcause_val,
epc: pc,
tval: trap_val
`endif
};
end
// XXX yield load reservation should be done outside this method
endmethod
method ActionValue#(Addr) mret;
method ActionValue#(RET_Updates) mret;
prv_reg <= prev_prv_vec[prvM];
prev_prv_vec[prvM] <= prvU;
ie_vec[prvM] <= prev_ie_vec[prvM];
prev_ie_vec[prvM] <= 1;
return mepc_csr;
Data mstatus_val = fn_mstatus_val(sxl_reg, uxl_reg,
tsr_reg, tw_reg, tvm_reg,
mxr_reg, sum_reg, mprv_reg,
xs_reg, fs_reg,
/* mpp */ prvU,
spp_reg,
/* prev_ie_vec [prvM] */ 1,
prev_ie_vec [prvS],
prev_ie_vec [prvU],
/* ie_vec [prvM] */ prev_ie_vec[prvM],
ie_vec [prvS],
ie_vec [prvU]);
return RET_Updates {new_pc: mepc_csr
`ifdef INCLUDE_TANDEM_VERIF
, prv: prev_prv_vec[prvM],
status: mstatus_val
`endif
};
endmethod
method ActionValue#(Addr) sret;
method ActionValue#(RET_Updates) sret;
prv_reg <= prev_prv_vec[prvS];
prev_prv_vec[prvS] <= prvU;
ie_vec[prvS] <= prev_ie_vec[prvS];
prev_ie_vec[prvS] <= 1;
return sepc_csr;
// For Tandem Verification, we return the full underlying MSTATUS register
Data mstatus_val = fn_mstatus_val(sxl_reg, uxl_reg,
tsr_reg, tw_reg, tvm_reg,
mxr_reg, sum_reg, mprv_reg,
xs_reg, fs_reg,
mpp_reg,
/* spp_reg */ prvU [0],
prev_ie_vec [prvM],
/* prev_ie_vec_[prvS] */ 1,
prev_ie_vec [prvU],
ie_vec [prvM],
/* ie_vec [prvS] */ prev_ie_vec[prvS],
ie_vec [prvU]);
return RET_Updates {new_pc: sepc_csr
`ifdef INCLUDE_TANDEM_VERIF
, prv: prev_prv_vec[prvS],
status: mstatus_val
`endif
};
endmethod
method VMInfo vmI;
@@ -845,15 +1221,53 @@ module mkCsrFile #(Data hartid)(CsrFile);
external_int_pend_vec[prvS] <= v;
endmethod
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (Bit #(1) v);
debug_int_pend <= v;
endmethod
method terminate = terminate_module.terminate;
// performance stats
method doPerfStats = stats_module.doPerfStats;
method sendDoStats = stats_module.sendDoStats;
method recvDoStats = stats_module.recvDoStats;
// ----------------
// Bluespec:
// Methods when Debug Module is present
`ifdef INCLUDE_GDB_CONTROL
// Read dpc
method Addr dpc_read ();
return rg_dpc;
endmethod
// Update dpc
method Action dpc_write (Addr pc);
rg_dpc <= pc;
endmethod
// Check whether to enter Debug Mode based on dcsr.{ebreakm, ebreaks, ebreaku}
method Bit #(1) dcsr_break_bit;
return case (prv_reg)
prvM: rg_dcsr [15];
prvS: rg_dcsr [13];
prvU: rg_dcsr [12];
endcase;
endmethod
// Check whether to enter Debug Mode based on dcsr.step
method Bit #(1) dcsr_step_bit;
return rg_dcsr [2];
endmethod
// Update 'cause' in DCSR
// Is invoked by logic that stops a hart, to enter Debug Mode
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
rg_dcsr <= { 32'b0, rg_dcsr [31:9], dcsr_cause, rg_dcsr [5:2], prv_reg };
/*
$display ("%0d: %m mkCsrFile.method-dcsr_cause_write: cause %0d, prv %0d",
cur_cycle, dcsr_cause, prv_reg);
*/
endmethod
`endif
endmodule

View File

@@ -46,10 +46,10 @@ endinterface
module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
(LLC_AXI4_Adapter_IFC)
provisos(Bits#(idT, a__),
Bits#(childT, b__),
FShow#(ToMemMsg#(idT, childT)),
FShow#(MemRsMsg#(idT, childT)),
Add#(SizeOf#(Line), 0, 512)); // assert Line sz = 512
Bits#(childT, b__),
FShow#(ToMemMsg#(idT, childT)),
FShow#(MemRsMsg#(idT, childT)),
Add#(SizeOf#(Line), 0, 512)); // assert Line sz = 512
// Verbosity: 0: quiet; 1: LLC transactions; 2: loop detail
Integer verbosity = 0;
@@ -69,61 +69,60 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
// Send a read-request into the fabric
function Action fa_fabric_send_read_req (Fabric_Addr addr);
action
AXI4_Size size = axsize_8;
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: addr,
arlen: 0, // burst len = arlen+1
arsize: size,
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
AXI4_Size size = axsize_8;
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: addr,
arlen: 0, // burst len = arlen+1
arsize: size,
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
// Debugging
if (cfg_verbosity > 1) begin
$display (" ", fshow (mem_req_rd_addr));
end
// Debugging
if (cfg_verbosity > 1) begin
$display (" ", fshow (mem_req_rd_addr));
end
endaction
endfunction
// Send a write-request into the fabric
function Action fa_fabric_send_write_req (Fabric_Addr addr, Fabric_Strb strb, Bit #(64) st_val);
action
AXI4_Size size = axsize_8;
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: addr,
awlen: 0, // burst len = awlen+1
awsize: size,
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
AXI4_Size size = axsize_8;
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: addr,
awlen: 0, // burst len = awlen+1
awsize: size,
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
wdata: st_val,
wstrb: strb,
wlast: True,
wuser: fabric_default_user};
let mem_req_wr_data = AXI4_Wr_Data {wdata: st_val,
wstrb: strb,
wlast: True,
wuser: fabric_default_user};
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
master_xactor.i_wr_data.enq (mem_req_wr_data);
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
master_xactor.i_wr_data.enq (mem_req_wr_data);
// Expect a fabric response
ctr_wr_rsps_pending.incr;
// Expect a fabric response
ctr_wr_rsps_pending.incr;
// Debugging
if (cfg_verbosity > 1) begin
$display (" To fabric: ", fshow (mem_req_wr_addr));
$display (" ", fshow (mem_req_wr_data));
end
// Debugging
if (cfg_verbosity > 1) begin
$display (" To fabric: ", fshow (mem_req_wr_addr));
$display (" ", fshow (mem_req_wr_data));
end
endaction
endfunction
@@ -139,11 +138,11 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
Reg #(Bit #(512)) rg_cline <- mkRegU;
rule rl_handle_read_req (llc.toM.first matches tagged Ld .ld
&&& (ctr_wr_rsps_pending.value == 0));
&&& (ctr_wr_rsps_pending.value == 0));
if ((cfg_verbosity > 0) && (rg_rd_req_beat == 0)) begin
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_req: Ld request from LLC to memory: beat %0d",
cur_cycle, rg_rd_req_beat);
$display (" ", fshow (ld));
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_req: Ld request from LLC to memory: beat %0d",
cur_cycle, rg_rd_req_beat);
$display (" ", fshow (ld));
end
Addr line_addr = { ld.addr [63:6], 6'h0 }; // Addr of containing cache line
@@ -151,10 +150,10 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
fa_fabric_send_read_req (line_addr | offset);
if (rg_rd_req_beat == 0)
f_pending_reads.enq (ld);
f_pending_reads.enq (ld);
if (rg_rd_req_beat == 7)
llc.toM.deq;
llc.toM.deq;
rg_rd_req_beat <= rg_rd_req_beat + 1;
endrule
@@ -163,30 +162,30 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
let mem_rsp <- pop_o (master_xactor.o_rd_data);
if (cfg_verbosity > 1) begin
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_rsps: beat %0d ", cur_cycle, rg_rd_rsp_beat);
$display (" ", fshow (mem_rsp));
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_rsps: beat %0d ", cur_cycle, rg_rd_rsp_beat);
$display (" ", fshow (mem_rsp));
end
if (mem_rsp.rresp != axi4_resp_okay) begin
// TODO: need to raise a non-maskable interrupt (NMI) here
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_rsp: fabric response error; exit", cur_cycle);
$display (" ", fshow (mem_rsp));
$finish (1);
// TODO: need to raise a non-maskable interrupt (NMI) here
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_rsp: fabric response error; exit", cur_cycle);
$display (" ", fshow (mem_rsp));
$finish (1);
end
// Shift next 64 bits from fabric into the cache line being assembled
let new_cline = { mem_rsp.rdata, rg_cline [511:64] };
if (rg_rd_rsp_beat == 7) begin
let ldreq <- pop (f_pending_reads);
MemRsMsg #(idT, childT) resp = MemRsMsg {data: unpack (new_cline),
child: ldreq.child,
id: ldreq.id};
let ldreq <- pop (f_pending_reads);
MemRsMsg #(idT, childT) resp = MemRsMsg {data: unpack (new_cline),
child: ldreq.child,
id: ldreq.id};
llc.rsFromM.enq (resp);
llc.rsFromM.enq (resp);
if (cfg_verbosity > 1)
$display (" Response to LLC: ", fshow (resp));
if (cfg_verbosity > 1)
$display (" Response to LLC: ", fshow (resp));
end
rg_cline <= new_cline;
@@ -204,8 +203,8 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
rule rl_handle_write_req (llc.toM.first matches tagged Wb .wb);
if ((cfg_verbosity > 0) && (rg_wr_req_beat == 0)) begin
$display ("%d: LLC_AXI4_Adapter.rl_handle_write_req: Wb request from LLC to memory:", cur_cycle);
$display (" ", fshow (wb));
$display ("%d: LLC_AXI4_Adapter.rl_handle_write_req: Wb request from LLC to memory:", cur_cycle);
$display (" ", fshow (wb));
end
Addr line_addr = { wb.addr [63:6], 6'h0 }; // Addr of containing cache line
@@ -218,10 +217,10 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
fa_fabric_send_write_req (line_addr | offset, strb8, data64);
if (rg_wr_req_beat == 0)
f_pending_writes.enq (wb);
f_pending_writes.enq (wb);
if (rg_wr_req_beat == 7)
llc.toM.deq;
llc.toM.deq;
rg_wr_req_beat <= rg_wr_req_beat + 1;
endrule
@@ -233,29 +232,29 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
let wr_resp <- pop_o (master_xactor.o_wr_resp);
if (cfg_verbosity > 1) begin
$display ("%0d: LLC_AXI4_Adapter.rl_discard_write_rsp: beat %0d ", cur_cycle, rg_wr_rsp_beat);
$display (" ", fshow (wr_resp));
$display ("%0d: LLC_AXI4_Adapter.rl_discard_write_rsp: beat %0d ", cur_cycle, rg_wr_rsp_beat);
$display (" ", fshow (wr_resp));
end
if (ctr_wr_rsps_pending.value == 0) begin
$display ("%0d: ERROR: LLC_AXI4_Adapter.rl_discard_write_rsp: unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1); // Assertion failure
$display ("%0d: ERROR: LLC_AXI4_Adapter.rl_discard_write_rsp: unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1); // Assertion failure
end
ctr_wr_rsps_pending.decr;
if (wr_resp.bresp != axi4_resp_okay) begin
// TODO: need to raise a non-maskable interrupt (NMI) here
$display ("%0d: LLC_AXI4_Adapter.rl_discard_write_rsp: fabric response error: exit", cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1);
// TODO: need to raise a non-maskable interrupt (NMI) here
$display ("%0d: LLC_AXI4_Adapter.rl_discard_write_rsp: fabric response error: exit", cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1);
end
if (rg_wr_rsp_beat == 7) begin
let wrreq <- pop (f_pending_writes);
// LLC does not expect any response for writes
let wrreq <- pop (f_pending_writes);
// LLC does not expect any response for writes
end
rg_wr_rsp_beat <= rg_wr_rsp_beat + 1;

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2018 Massachusetts Institute of Technology
// Portions (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -21,8 +22,6 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Portions (c) 2019 Bluespec, Inc.
// This file is adapted from: MIT-riscy/riscy-OOO/procs/lib/MMIOPlatform.bsv
// Modifications to fit into Bluespec's RISC-V execution environments.
@@ -47,7 +46,7 @@ import GetPut_Aux :: *;
// ----------------
// From MIT RISCY-OOO
import Fifo::*;
import Fifos::*;
import Types::*;
import ProcTypes::*;
import CCTypes::*;
@@ -82,31 +81,31 @@ function Bit #(64) fn_extract_and_extend_bytes (Bit #(2) sz, Bit #(64) byte_addr
case (sz)
sz_B: case (addr_lsbs)
'h0: result = zeroExtend (word64 [ 7: 0]);
'h1: result = zeroExtend (word64 [15: 8]);
'h2: result = zeroExtend (word64 [23:16]);
'h3: result = zeroExtend (word64 [31:24]);
'h4: result = zeroExtend (word64 [39:32]);
'h5: result = zeroExtend (word64 [47:40]);
'h6: result = zeroExtend (word64 [55:48]);
'h7: result = zeroExtend (word64 [63:56]);
endcase
'h0: result = zeroExtend (word64 [ 7: 0]);
'h1: result = zeroExtend (word64 [15: 8]);
'h2: result = zeroExtend (word64 [23:16]);
'h3: result = zeroExtend (word64 [31:24]);
'h4: result = zeroExtend (word64 [39:32]);
'h5: result = zeroExtend (word64 [47:40]);
'h6: result = zeroExtend (word64 [55:48]);
'h7: result = zeroExtend (word64 [63:56]);
endcase
sz_H: case (addr_lsbs)
'h0: result = zeroExtend (word64 [15: 0]);
'h2: result = zeroExtend (word64 [31:16]);
'h4: result = zeroExtend (word64 [47:32]);
'h6: result = zeroExtend (word64 [63:48]);
endcase
'h0: result = zeroExtend (word64 [15: 0]);
'h2: result = zeroExtend (word64 [31:16]);
'h4: result = zeroExtend (word64 [47:32]);
'h6: result = zeroExtend (word64 [63:48]);
endcase
sz_W: case (addr_lsbs)
'h0: result = zeroExtend (word64 [31: 0]);
'h4: result = zeroExtend (word64 [63:32]);
endcase
'h0: result = zeroExtend (word64 [31: 0]);
'h4: result = zeroExtend (word64 [63:32]);
endcase
sz_D: case (addr_lsbs) // D
'h0: result = word64;
endcase
'h0: result = word64;
endcase
endcase
return result;
endfunction
@@ -128,31 +127,31 @@ function Bit #(64) fn_update_bytes (Bit #(2) sz, Bit #(64) byte_addr, Bit #(64)
case (sz)
sz_B: case (addr_lsbs)
'h0: result = { st_val [63:8], value [7:0] };
'h1: result = { st_val [63:16], value [7:0], st_val [7:0] };
'h2: result = { st_val [63:24], value [7:0], st_val [15:0] };
'h3: result = { st_val [63:32], value [7:0], st_val [23:0] };
'h4: result = { st_val [63:40], value [7:0], st_val [31:0] };
'h5: result = { st_val [63:48], value [7:0], st_val [39:0] };
'h6: result = { st_val [63:56], value [7:0], st_val [47:0] };
'h7: result = { value [7:0], st_val [55:0] };
endcase
'h0: result = { st_val [63:8], value [7:0] };
'h1: result = { st_val [63:16], value [7:0], st_val [7:0] };
'h2: result = { st_val [63:24], value [7:0], st_val [15:0] };
'h3: result = { st_val [63:32], value [7:0], st_val [23:0] };
'h4: result = { st_val [63:40], value [7:0], st_val [31:0] };
'h5: result = { st_val [63:48], value [7:0], st_val [39:0] };
'h6: result = { st_val [63:56], value [7:0], st_val [47:0] };
'h7: result = { value [7:0], st_val [55:0] };
endcase
sz_H: case (addr_lsbs)
'h0: result = { st_val [63:16], value [15:0] };
'h2: result = { st_val [63:32], value [15:0], st_val [15:0] };
'h4: result = { st_val [63:48], value [15:0], st_val [31:0] };
'h6: result = { value [15:0], st_val [47:0] };
endcase
'h0: result = { st_val [63:16], value [15:0] };
'h2: result = { st_val [63:32], value [15:0], st_val [15:0] };
'h4: result = { st_val [63:48], value [15:0], st_val [31:0] };
'h6: result = { value [15:0], st_val [47:0] };
endcase
sz_W: case (addr_lsbs)
'h0: result = { st_val [63:32], value [31:0] };
'h4: result = { value [31:0], st_val [31:0] };
endcase
'h0: result = { st_val [63:32], value [31:0] };
'h4: result = { value [31:0], st_val [31:0] };
endcase
sz_D: case (addr_lsbs) // D
'h0: result = st_val;
endcase
'h0: result = st_val;
endcase
endcase
return result;
endfunction
@@ -164,10 +163,10 @@ endfunction
// Updates the relevant bytes of st_val.
function Bit #(64) fn_amo_op (Bit #(2) sz, // encodes data size (.W or .D)
AmoFunc amofunc, // encodes the AMO op
Bit #(64) addr, // lsbs indicate which 32b W in 64b D (.W)
Bit #(64) ld_val, // 64b value loaded from mem
Bit #(64) st_val); // 64b value from CPU reg Rs2
AmoFunc amofunc, // encodes the AMO op
Bit #(64) addr, // lsbs indicate which 32b W in 64b D (.W)
Bit #(64) ld_val, // 64b value loaded from mem
Bit #(64) st_val); // 64b value from CPU reg Rs2
// Extract relevant bytes of ld_val and st_val
Bit #(64) w1 = fn_extract_and_extend_bytes (sz, addr, ld_val);
Bit #(64) w2 = fn_extract_and_extend_bytes (sz, addr, st_val);
@@ -233,7 +232,7 @@ typedef union tagged {
} MMIOPlatformReq deriving(Bits, Eq, FShow);
module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
Server #(MMIOCRq, MMIODataPRs) mmio_fabric_adapter_core_side)
Server #(MMIOCRq, MMIODataPRs) mmio_fabric_adapter_core_side)
(MMIOPlatform)
provisos (Bits #(Data, 64)); // this module assumes Data is 64-bit wide
@@ -269,7 +268,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
Reg#(SupWaySel) fetchingWay <- mkRegU;
// the already fetched insts
Vector#(TSub#(SupSize, 1),
Reg#(Instruction)) fetchedInsts <- replicateM(mkRegU);
Reg#(Instruction)) fetchedInsts <- replicateM(mkRegU);
// we need to wait for resp from cores when we need to change MTIP
Reg#(Vector#(CoreNum, Bool)) waitMTIPCRs <- mkRegU;
@@ -289,7 +288,8 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
// To avoid posting timer interrupt repeatedly, we keep a copy of MTIP
// here. Since each core cannot write MTIP by CSRXXX inst, the only way to
// change MTIP is through here.
Vector#(CoreNum, Reg#(Bool)) mtip <- replicateM(mkReg(False));
// We initialize to True to avoid an timer interrupt at start of time.
Vector#(CoreNum, Reg#(Bool)) mtip <- replicateM(mkReg(True));
// pass mtime to each core
rule propagateTime(state != Init);
@@ -323,13 +323,13 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
Vector#(CoreNum, Bool) needTimerInt = replicate(False);
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
if(!mtip[i] && mtimecmp[i] <= mtime) begin
cores[i].pRq.enq(MMIOPRq {
target: MTIP,
func: St,
data: 1
cores[i].pRq.enq(MMIOPRq {
target: MTIP,
func: St,
data: 1
});
mtip[i] <= True;
needTimerInt[i] = True;
mtip[i] <= True;
needTimerInt[i] = True;
end
end
if(needTimerInt != replicate(False)) begin
@@ -337,11 +337,11 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
curReq <= TimerInterrupt;
waitMTIPCRs <= needTimerInt;
if(verbosity > 0) begin
$display("[Platform - SelectReq] timer interrupt",
", mtime %x", mtime,
", mtimcmp ", fshow(readVReg(mtimecmp)),
", old mtip ", fshow(readVReg(mtip)),
", new interrupts ", fshow(needTimerInt));
$display("[Platform - SelectReq] timer interrupt",
", mtime %x", mtime,
", mtimcmp ", fshow(readVReg(mtimecmp)),
", old mtip ", fshow(readVReg(mtip)),
", new interrupts ", fshow(needTimerInt));
end
end
else begin
@@ -349,57 +349,57 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
function Bool hasReq(Integer i) = cores[i].cRq.notEmpty;
Vector#(CoreNum, Integer) idxVec = genVector;
if(find(hasReq, idxVec) matches tagged Valid .i) begin
cores[i].cRq.deq;
MMIOCRq req = cores[i].cRq.first;
// record req
reqCore <= fromInteger(i);
reqFunc <= req.func;
reqAmofunc <= case (req.func) matches
tagged Amo .f : f;
default: None;
endcase;
reqBE <= req.byteEn;
reqData <= req.data;
reqSz <= sz_D; // TODO: may be sz_H, sz_B or sz_W
// set up bookkeepings in case of inst fetch (other
// bookkeepings are set at processing time)
instSel <= truncate(req.addr >> valueof(LgInstSzBytes));
fetchingWay <= 0;
// find out which MMIO reg/device is being requested
DataAlignedAddr addr = getDataAlignedAddr(req.addr);
MMIOPlatformReq newReq = Invalid;
cores[i].cRq.deq;
MMIOCRq req = cores[i].cRq.first;
// record req
reqCore <= fromInteger(i);
reqFunc <= req.func;
reqAmofunc <= case (req.func) matches
tagged Amo .f : f;
default: None;
endcase;
reqBE <= req.byteEn;
reqData <= req.data;
reqSz <= sz_D; // TODO: may be sz_H, sz_B or sz_W
// set up bookkeepings in case of inst fetch (other
// bookkeepings are set at processing time)
instSel <= truncate(req.addr >> valueof(LgInstSzBytes));
fetchingWay <= 0;
// find out which MMIO reg/device is being requested
DataAlignedAddr addr = getDataAlignedAddr(req.addr);
MMIOPlatformReq newReq = Invalid;
if(addr >= msipBaseAddr && addr < msipBoundAddr) begin
newReq = MSIP (truncate(addr - msipBaseAddr));
end
if(addr >= msipBaseAddr && addr < msipBoundAddr) begin
newReq = MSIP (truncate(addr - msipBaseAddr));
end
else if(addr >= mtimecmpBaseAddr &&
addr < mtimecmpBoundAddr)
begin
newReq = MTimeCmp (truncate(addr - mtimecmpBaseAddr));
end
addr < mtimecmpBoundAddr)
begin
newReq = MTimeCmp (truncate(addr - mtimecmpBaseAddr));
end
else if(addr == mtimeBaseAddr) begin
// assume mtime is of size Data
newReq = MTime;
end
// assume mtime is of size Data
newReq = MTime;
end
else if(addr == toHostAddr) begin
// assume tohost is of size Data
newReq = ToHost;
end
// assume tohost is of size Data
newReq = ToHost;
end
else if(addr == fromHostAddr) begin
// assume fromhost is of size Data
newReq = FromHost;
end
// assume fromhost is of size Data
newReq = FromHost;
end
else begin // Send all remaining reqs to the fabric adapter, as is
newReq = MMIO_Fabric_Adapter (req.addr);
end
newReq = MMIO_Fabric_Adapter (req.addr);
end
curReq <= newReq;
// process valid req
state <= ProcessReq;
if(verbosity > 0) begin
$display("[Platform - SelectReq] core %d, req ", i, fshow(req));
$display(" req type ", fshow(newReq));
end
// process valid req
state <= ProcessReq;
if(verbosity > 0) begin
$display("[Platform - SelectReq] core %d, req ", i, fshow(req));
$display(" req type ", fshow(newReq));
end
end
end
endrule
@@ -408,14 +408,14 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
rule waitTimerInterruptDone(state == WaitResp && curReq == TimerInterrupt);
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
if(waitMTIPCRs[i]) begin
cores[i].cRs.deq;
cores[i].cRs.deq;
end
end
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - Done] timer interrupt",
", mtip ", fshow(readVReg(mtip)),
", waitCRs ", fshow(waitMTIPCRs));
", mtip ", fshow(readVReg(mtip)),
", waitCRs ", fshow(waitMTIPCRs));
end
endrule
@@ -442,17 +442,17 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
state <= SelectReq;
cores[reqCore].pRs.enq(InstFetch (replicate(Invalid)));
if(verbosity > 0) begin
$display("[Platform - process msip] cannot do inst fetch");
$display("[Platform - process msip] cannot do inst fetch");
end
end
else if(upper_en && !upper_valid) begin
// access invalid core's MSIP, fault
state <= SelectReq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: False, data: ?
}));
valid: False, data: ?
}));
if(verbosity > 0) begin
$display("[Platform - process msip] access invalid core");
$display("[Platform - process msip] access invalid core");
end
end
else if(reqFunc matches tagged Amo .amoFunc) begin
@@ -461,61 +461,61 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
// resp is different from load that valid data is already shifted
// to LSBs). Besides, we only use the lower 32 bits of reqData.
if(lower_en && upper_en) begin
state <= SelectReq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: False, data: ?
}));
if(verbosity > 0) begin
$display("[Platform - process msip] ",
"AMO cannot access 2 cores");
end
state <= SelectReq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: False, data: ?
}));
if(verbosity > 0) begin
$display("[Platform - process msip] ",
"AMO cannot access 2 cores");
end
end
else if(lower_en) begin
cores[lower_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: truncate(reqData)
});
waitLowerMSIPCRs <= Valid (lower_core);
waitUpperMSIPCRs <= Invalid;
state <= WaitResp;
cores[lower_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: truncate(reqData)
});
waitLowerMSIPCRs <= Valid (lower_core);
waitUpperMSIPCRs <= Invalid;
state <= WaitResp;
end
else if(upper_en) begin
cores[upper_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: truncate(reqData)
});
waitLowerMSIPCRs <= Valid (upper_core);
waitUpperMSIPCRs <= Invalid;
state <= WaitResp;
cores[upper_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: truncate(reqData)
});
waitLowerMSIPCRs <= Valid (upper_core);
waitUpperMSIPCRs <= Invalid;
state <= WaitResp;
end
else begin
// AMO access nothing: fault
state <= SelectReq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: False, data: ?
}));
if(verbosity > 0) begin
// AMO access nothing: fault
state <= SelectReq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: False, data: ?
}));
if(verbosity > 0) begin
$display("[Platform - process msip] access nothing");
end
end
end
end
else begin
// normal load and store
if(lower_en) begin
cores[lower_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: zeroExtend(reqData[0])
});
cores[lower_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: zeroExtend(reqData[0])
});
end
if(upper_en) begin
cores[upper_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: zeroExtend(reqData[32])
});
cores[upper_core].pRq.enq(MMIOPRq {
target: MSIP,
func: reqFunc,
data: zeroExtend(reqData[32])
});
end
state <= WaitResp;
waitLowerMSIPCRs <= lower_en ? Valid (lower_core) : Invalid;
@@ -524,33 +524,33 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
endrule
rule waitMSIPDone(
curReq matches tagged MSIP .offset &&& state == WaitResp
);
curReq matches tagged MSIP .offset &&& state == WaitResp
);
Bit#(32) lower_data = 0;
Bit#(32) upper_data = 0;
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
if (waitLowerMSIPCRs matches tagged Valid .c &&&
c == fromInteger(i)) begin
cores[i].cRs.deq;
lower_data = zeroExtend(cores[i].cRs.first.data);
end
else if(waitUpperMSIPCRs matches tagged Valid .c &&&
c == fromInteger(i)) begin
cores[i].cRs.deq;
upper_data = zeroExtend(cores[i].cRs.first.data);
end
c == fromInteger(i)) begin
cores[i].cRs.deq;
lower_data = zeroExtend(cores[i].cRs.first.data);
end
else if(waitUpperMSIPCRs matches tagged Valid .c &&&
c == fromInteger(i)) begin
cores[i].cRs.deq;
upper_data = zeroExtend(cores[i].cRs.first.data);
end
end
state <= SelectReq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: True,
// for AMO, resp data should be signExtend(lower_data). However,
// lower_data is just 1 or 0, and upper_data is always 0, so we
// don't need to do signExtend.
data: {upper_data, lower_data}
}));
valid: True,
// for AMO, resp data should be signExtend(lower_data). However,
// lower_data is just 1 or 0, and upper_data is always 0, so we
// don't need to do signExtend.
data: {upper_data, lower_data}
}));
if(verbosity > 0) begin
$display("[Platform - msip done] lower %x, upper %x",
lower_data, upper_data);
lower_data, upper_data);
end
endrule
@@ -560,11 +560,11 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
Bool doubleWord = reqBE[4] && reqBE[0];
Bool upper32 = reqBE[4] && !reqBE[0];
let amoInst = AmoInst {
func: amoFunc,
doubleWord: doubleWord,
aq: False,
rl: False
};
func: amoFunc,
doubleWord: doubleWord,
aq: False,
rl: False
};
return amoExec(amoInst, orig, reqData, upper32);
end
else begin
@@ -572,9 +572,9 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
Vector#(NumBytes, Bit#(8)) data = unpack(orig);
Vector#(NumBytes, Bit#(8)) wrVec = unpack(reqData);
for(Integer i = 0; i < valueof(NumBytes); i = i+1) begin
if(reqBE[i]) begin
data[i] = wrVec[i];
end
if(reqBE[i]) begin
data[i] = wrVec[i];
end
end
return pack(data);
end
@@ -597,81 +597,81 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
// handle mtimecmp access
rule processMTimeCmp(
curReq matches tagged MTimeCmp .offset &&& state == ProcessReq
curReq matches tagged MTimeCmp .offset &&& state == ProcessReq
);
if(isInstFetch) begin
state <= SelectReq;
cores[reqCore].pRs.enq(InstFetch (replicate(Invalid)));
if(verbosity > 0) begin
$display("[Platform - process mtimecmp] cannot do inst fetch");
$display("[Platform - process mtimecmp] cannot do inst fetch");
end
end
else if(offset > fromInteger(valueof(CoreNum) - 1)) begin
// access invalid core's mtimecmp, fault
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: False, data: ?
}));
valid: False, data: ?
}));
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - process mtimecmp] access fault");
$display("[Platform - process mtimecmp] access fault");
end
end
else begin
let oldMTimeCmp = mtimecmp[offset];
if(reqFunc == Ld) begin
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: True,
data: oldMTimeCmp
}));
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - process mtimecmp] read done, data %x",
oldMTimeCmp);
end
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: True,
data: oldMTimeCmp
}));
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - process mtimecmp] read done, data %x",
oldMTimeCmp);
end
end
else begin
// do updates for store or AMO
let newData = getWriteData(oldMTimeCmp);
mtimecmp[offset] <= newData;
// get and record amo resp
let respData = getAmoResp(oldMTimeCmp);
amoResp <= respData;
// check changes to MTIP
if(newData <= mtime && !mtip[offset]) begin
// need to post new timer interrupt
mtip[offset] <= True;
cores[offset].pRq.enq(MMIOPRq {
target: MTIP,
func: St,
// do updates for store or AMO
let newData = getWriteData(oldMTimeCmp);
mtimecmp[offset] <= newData;
// get and record amo resp
let respData = getAmoResp(oldMTimeCmp);
amoResp <= respData;
// check changes to MTIP
if(newData <= mtime && !mtip[offset]) begin
// need to post new timer interrupt
mtip[offset] <= True;
cores[offset].pRq.enq(MMIOPRq {
target: MTIP,
func: St,
data: 1
});
state <= WaitResp;
end
});
state <= WaitResp;
end
else if(newData > mtime && mtip[offset]) begin
// need to clear timer interrupt
mtip[offset] <= False;
cores[offset].pRq.enq(MMIOPRq {
target: MTIP,
func: St,
// need to clear timer interrupt
mtip[offset] <= False;
cores[offset].pRq.enq(MMIOPRq {
target: MTIP,
func: St,
data: 0
});
state <= WaitResp;
end
});
state <= WaitResp;
end
else begin
// nothing happens to mtip, just finish this req
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: True,
// store doesn't need resp data, just fill in AMO resp
data: respData
// nothing happens to mtip, just finish this req
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: True,
// store doesn't need resp data, just fill in AMO resp
data: respData
}));
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - process mtimecmp] ",
"no change to mtip ", fshow(readVReg(mtip)),
", mtime %x", mtime,
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - process mtimecmp] ",
"no change to mtip ", fshow(readVReg(mtip)),
", mtime %x", mtime,
", old mtimecmp ", fshow(readVReg(mtimecmp)),
", new mtimecmp[%d] %x", offset, newData);
end
", new mtimecmp[%d] %x", offset, newData);
end
end
end
end
@@ -682,17 +682,17 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
);
cores[offset].cRs.deq;
cores[reqCore].pRs.enq(DataAccess (MMIODataPRs {
valid: True,
// store doesn't need resp data, just fill in AMO resp. We cannot
// recompute AMO resp now, because mtimecmp has changed
data: amoResp
}));
valid: True,
// store doesn't need resp data, just fill in AMO resp. We cannot
// recompute AMO resp now, because mtimecmp has changed
data: amoResp
}));
state <= SelectReq;
if(verbosity > 0) begin
$display("[Platform - mtimecmp done]",
", mtime %x", mtime,
", mtimecmp ", fshow(readVReg(mtimecmp)),
", mtip ", fshow(readVReg(mtip)));
", mtime %x", mtime,
", mtimecmp ", fshow(readVReg(mtimecmp)),
", mtip ", fshow(readVReg(mtip)));
end
endrule
@@ -889,30 +889,30 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
// Forward the request as-is to the fabric adapter.
rule rl_mmio_to_fabric_req (curReq matches tagged MMIO_Fabric_Adapter .addr
&&& (state == ProcessReq)
&&& (isLd || isSt));
&&& (state == ProcessReq)
&&& (isLd || isSt));
let req = MMIOCRq {addr:addr, func:reqFunc, byteEn:reqBE, data:reqData};
mmio_fabric_adapter_core_side.request.put (req);
state <= WaitResp;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_to_fabric_req");
$display (" ", fshow (req));
$display ("MMIOPlatform.rl_mmio_to_fabric_req");
$display (" ", fshow (req));
end
endrule
// Forward the fabric-adapter's response as-is to the core.
rule rl_mmio_from_fabric_rsp (curReq matches tagged MMIO_Fabric_Adapter .addr
&&& (state == WaitResp)
&&& (isLd || isSt));
&&& (state == WaitResp)
&&& (isLd || isSt));
MMIODataPRs dprs <- mmio_fabric_adapter_core_side.response.get;
let prs = tagged DataAccess dprs;
cores[reqCore].pRs.enq (prs);
state <= SelectReq;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_rsp");
$display (" ", fshow (prs));
$display ("MMIOPlatform.rl_mmio_from_fabric_rsp");
$display (" ", fshow (prs));
end
endrule
@@ -920,8 +920,8 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
// MMIO to Fabric: AMO (not Instruction Fetch)
rule rl_mmio_to_fabric_amo_req (curReq matches tagged MMIO_Fabric_Adapter .addr
&&& (state == ProcessReq)
&&& isAmo);
&&& (state == ProcessReq)
&&& isAmo);
// Send a load-request to the fabric adapter.
// Align addr to 8-byte boundary (FabricData-aligned)
Addr addr1 = { addr [63:3], 3'b_000 };
@@ -930,41 +930,41 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
state <= WaitResp;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_to_fabric_amo_req: addr 0x%0h", addr);
$display (" ", fshow (req));
$display ("MMIOPlatform.rl_mmio_to_fabric_amo_req: addr 0x%0h", addr);
$display (" ", fshow (req));
end
endrule
// Get the Load-response; do the AMO op; send final write back to fabric, and respond to core
rule rl_mmio_from_fabric_amo_rsp (curReq matches tagged MMIO_Fabric_Adapter .addr
&&& (state == WaitResp)
&&& isAmo);
&&& (state == WaitResp)
&&& isAmo);
MMIODataPRs dprs <- mmio_fabric_adapter_core_side.response.get;
if (! dprs.valid) begin
// Access fault
let prs = tagged DataAccess dprs;
cores[reqCore].pRs.enq (prs);
state <= SelectReq;
// Access fault
let prs = tagged DataAccess dprs;
cores[reqCore].pRs.enq (prs);
state <= SelectReq;
end
else begin
// Do the AMO op on the loaded value and the store value
let ld_val = dprs.data;
let new_st_val = fn_amo_op (reqSz, reqAmofunc, addr, ld_val, reqData);
// Do the AMO op on the loaded value and the store value
let ld_val = dprs.data;
let new_st_val = fn_amo_op (reqSz, reqAmofunc, addr, ld_val, reqData);
// Write back new st_val to fabric
let req = MMIOCRq {addr:addr, func:tagged St, byteEn:reqBE, data:new_st_val};
mmio_fabric_adapter_core_side.request.put (req);
// Write back new st_val to fabric
let req = MMIOCRq {addr:addr, func:tagged St, byteEn:reqBE, data:new_st_val};
mmio_fabric_adapter_core_side.request.put (req);
let prs = tagged DataAccess (MMIODataPRs { valid: True, data: ld_val });
cores[reqCore].pRs.enq (prs);
state <= SelectReq;
let prs = tagged DataAccess (MMIODataPRs { valid: True, data: ld_val });
cores[reqCore].pRs.enq (prs);
state <= SelectReq;
if (verbosity > 1) begin
$display ("MMIO_Platform.rl_mmio_from_fabric_amo_rsp: addr 0x%0h, size %0d, amofunc %0d",
addr, reqSz, reqAmofunc);
$display (" ld_val 0x%0h op st_val 0x%0h => new_st_val 0x%0h", ld_val, reqData, new_st_val);
end
if (verbosity > 1) begin
$display ("MMIO_Platform.rl_mmio_from_fabric_amo_rsp: addr 0x%0h, size %0d, amofunc %0d",
addr, reqSz, reqAmofunc);
$display (" ld_val 0x%0h op st_val 0x%0h => new_st_val 0x%0h", ld_val, reqData, new_st_val);
end
end
endrule
@@ -980,8 +980,8 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
// fetchingWay: initial 0
rule rl_mmio_to_fabric_ifetch_req (curReq matches tagged MMIO_Fabric_Adapter .addr
&&& (state == ProcessReq)
&&& isInstFetch);
&&& (state == ProcessReq)
&&& isInstFetch);
// Note: addr may not be FabricData-aligned; result will be Data that contains addr
// TODO: currently assumes superscalarity fits in fabric width
Addr addr1 = { addr [63:3], 3'b_000 };
@@ -990,79 +990,79 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
state <= WaitResp;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_to_fabric_ifetch_req: addr 0x%0h fetchingWay %0d",
addr, fetchingWay);
$display (" ", fshow (req));
$display ("MMIOPlatform.rl_mmio_to_fabric_ifetch_req: addr 0x%0h fetchingWay %0d",
addr, fetchingWay);
$display (" ", fshow (req));
end
endrule
rule rl_mmio_from_fabric_ifetch_rsp (curReq matches tagged MMIO_Fabric_Adapter .addr
&&& (state == WaitResp)
&&& isInstFetch);
&&& (state == WaitResp)
&&& isInstFetch);
MMIODataPRs dprs <- mmio_fabric_adapter_core_side.response.get;
if (! dprs.valid) begin
// Access fault
// Access fault
Vector #(SupSize, Maybe #(Instruction)) resp = replicate (Invalid);
for(Integer i = 0; i < valueof (SupSize); i = i+1) begin
if (fromInteger (i) < fetchingWay)
resp [i] = Valid (fetchedInsts [i]);
if (fromInteger (i) < fetchingWay)
resp [i] = Valid (fetchedInsts [i]);
else if (fromInteger (i) == fetchingWay)
resp [i] = tagged Invalid;
resp [i] = tagged Invalid;
end
cores[reqCore].pRs.enq (tagged InstFetch (resp));
state <= SelectReq;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_ifetch_rsp: access fault; final resp to core:");
$display (" ", fshow (resp));
end
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_ifetch_rsp: access fault; final resp to core:");
$display (" ", fshow (resp));
end
end
else begin
// No access fault
let data = dprs.data;
// No access fault
let data = dprs.data;
SupWaySel maxWay = 0;
if(reqFunc matches tagged Inst .w) begin
maxWay = w;
end
// View Data as a vector of instructions
// View Data as a vector of instructions
Vector#(DataSzInst, Instruction) instVec = unpack(data);
// extract inst from resp data
Instruction inst = instVec[instSel];
// check whether we are done or not
if (fetchingWay >= maxWay) begin
// all 0..maxWay insts are fetched; we can resp now
// all 0..maxWay insts are fetched; we can resp now
Vector#(SupSize, Maybe#(Instruction)) resp = replicate(Invalid);
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
if(fromInteger(i) < fetchingWay) begin
if(fromInteger(i) < fetchingWay) begin
resp[i] = Valid (fetchedInsts[i]);
end
end
else if(fromInteger(i) == fetchingWay) begin
resp[i] = Valid (inst);
end
end
end
cores[reqCore].pRs.enq (tagged InstFetch (resp));
state <= SelectReq;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_ifetch_rsp: final resp to core:");
$display (" ", fshow (resp));
end
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_ifetch_rsp: final resp to core:");
$display (" ", fshow (resp));
end
end
else begin
// continue to fetch next inst, save current inst, increment offset
fetchedInsts[fetchingWay] <= inst;
fetchingWay <= fetchingWay + 1;
instSel <= instSel + 1;
curReq <= MMIO_Fabric_Adapter (instSel == maxBound ? addr + 8 : addr);
curReq <= MMIO_Fabric_Adapter (instSel == maxBound ? addr + 8 : addr);
state <= ProcessReq;
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_ifetch_rsp:");
$display (" fetchingWay %0d instSel %0d inst 0x%0h", fetchingWay, instSel, inst);
end
if (verbosity > 0) begin
$display ("MMIOPlatform.rl_mmio_from_fabric_ifetch_rsp:");
$display (" fetchingWay %0d instSel %0d inst 0x%0h", fetchingWay, instSel, inst);
end
end
end
endrule

View File

@@ -1,5 +1,14 @@
// Copyright (c) 2019-2020 Bluespec, Inc.
package MMIO_AXI4_Adapter;
// ================================================================
// This is an adapter to connect MIT's RISCY-OOO to an AXI4 fabric in
// Bluespec's Toooba setup. All IO traffic to the fabric flows through
// this. Note: a few IO addresses (e.g., MTIME, MTIMECMP, MSIP,
// TOHOST, FROMHOST are intercepted and handled before they reach this
// adapter).
// ================================================================
// BSV lib imports
@@ -30,6 +39,7 @@ import ProcTypes :: *;
import AXI4_Types :: *;
import Fabric_Defs :: *;
import SoC_Map :: *;
// ================================================================
@@ -56,6 +66,8 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
FIFOF #(MMIOCRq) f_reqs_from_core <- mkFIFOF;
FIFOF #(MMIODataPRs) f_rsps_to_core <- mkFIFOF;
SoC_Map_IFC soc_map <- mkSoC_Map; // for m_is_IO_addr
// ================================================================
// Fabric request/response
@@ -70,61 +82,75 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
// Send a read-request into the fabric
function Action fa_fabric_send_read_req (Fabric_Addr addr);
action
AXI4_Size size = axsize_8;
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: addr,
arlen: 0, // burst len = arlen+1
arsize: size,
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
AXI4_Size size = axsize_8;
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: addr,
arlen: 0, // burst len = arlen+1
arsize: size,
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
// Debugging
if (cfg_verbosity > 0) begin
$display (" ", fshow (mem_req_rd_addr));
end
// Debugging
if (cfg_verbosity > 0) begin
$display (" ", fshow (mem_req_rd_addr));
end
endaction
endfunction
// Send a write-request into the fabric
function Action fa_fabric_send_write_req (Fabric_Addr addr, Fabric_Strb strb, Bit #(64) st_val);
action
AXI4_Size size = axsize_8;
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: addr,
awlen: 0, // burst len = awlen+1
awsize: size,
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
AXI4_Size size = axsize_8;
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: addr,
awlen: 0, // burst len = awlen+1
awsize: size,
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
wdata: st_val,
wstrb: strb,
wlast: True,
wuser: fabric_default_user};
let mem_req_wr_data = AXI4_Wr_Data {wdata: st_val,
wstrb: strb,
wlast: True,
wuser: fabric_default_user};
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
master_xactor.i_wr_data.enq (mem_req_wr_data);
`ifdef FABRIC64
// Work-around for a misbehavior on Xilinx UART and its
// Xilinx AXI4 adapter. On 64-bit fabrics, for a write where
// axsize says '8 bytes' but wstrb is for <= 4 bytes, the
// adapter converts it two 32-bit writes, one of which has
// wstrb=4'b0000. The Xilinx UART, in turn ignores wstrb and
// therefore performs a spurious write. This workaround
// changes axsize for such writes to '4 bytes', avoiding this
// problem.
// Expect a fabric response
ctr_wr_rsps_pending.incr;
if (strb [7:4] == 0 || strb [3:0] == 0) begin
mem_req_wr_addr.awsize = axsize_4;
end
`endif
// Debugging
if (cfg_verbosity > 0) begin
$display (" To fabric: ", fshow (mem_req_wr_addr));
$display (" ", fshow (mem_req_wr_data));
end
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
master_xactor.i_wr_data.enq (mem_req_wr_data);
// Expect a fabric response
ctr_wr_rsps_pending.incr;
// Debugging
if (cfg_verbosity > 0) begin
$display (" To fabric: ", fshow (mem_req_wr_addr));
$display (" ", fshow (mem_req_wr_data));
end
endaction
endfunction
@@ -134,15 +160,29 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
// This is just an adapter from MMIOCRq/MMIODataPRs to AXI4
rule rl_handle_read_req (f_reqs_from_core.first.func matches Ld
&&& (ctr_wr_rsps_pending.value == 0));
&&& (ctr_wr_rsps_pending.value == 0));
let req <- pop (f_reqs_from_core);
if (cfg_verbosity > 0) begin
$display ("%0d: MMIO_AXI4_Adapter.rl_handle_read_req: Ld request", cur_cycle);
$display (" ", fshow (req));
$display ("%0d: %m.rl_handle_read_req: Ld request", cur_cycle);
$display (" ", fshow (req));
end
fa_fabric_send_read_req (req.addr);
// Technically the following check for legal IO addrs is not
// necessary; the AXI4 fabric should return a DECERR for illegal
// addrs; but not all AXI4 fabrics do the right thing.
if (soc_map.m_is_IO_addr (req.addr))
fa_fabric_send_read_req (req.addr);
else begin
let rsp = MMIODataPRs {valid: False,
data: req.addr}; // For debugging convenience only
f_rsps_to_core.enq (rsp);
if (cfg_verbosity > 0) begin
$display ("%0d: %m.rl_handle_read_req: unmapped IO address; returning error response",
cur_cycle);
$display (" ", fshow (req));
end
end
endrule
// ----------------
@@ -151,21 +191,21 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
let mem_rsp <- pop_o (master_xactor.o_rd_data);
if (cfg_verbosity > 0) begin
$display ("%0d: MMIO_AXI4_Adapter.rl_handle_read_rsps ", cur_cycle);
$display (" ", fshow (mem_rsp));
$display ("%0d: %m.rl_handle_read_rsps ", cur_cycle);
$display (" ", fshow (mem_rsp));
end
if ((cfg_verbosity > 0) && (mem_rsp.rresp != axi4_resp_okay)) begin
$display ("%0d: MMIO_AXI4_Adapter.rl_handle_read_rsp: fabric response error", cur_cycle);
$display (" ", fshow (mem_rsp));
$display ("%0d: %m.rl_handle_read_rsp: fabric response error", cur_cycle);
$display (" ", fshow (mem_rsp));
end
let rsp = MMIODataPRs {valid: (mem_rsp.rresp == axi4_resp_okay),
data: mem_rsp.rdata};
data: mem_rsp.rdata};
f_rsps_to_core.enq (rsp);
if (cfg_verbosity > 0)
$display (" Response MMIO to core: ", fshow (rsp));
$display (" Response MMIO to core: ", fshow (rsp));
endrule
// ================================================================
@@ -175,11 +215,25 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
let req <- pop (f_reqs_from_core);
if (cfg_verbosity > 0) begin
$display ("%d: MMIO_AXI4_Adapter.rl_handle_write_req: St request:", cur_cycle);
$display (" ", fshow (req));
$display ("%d: %m.rl_handle_write_req: St request:", cur_cycle);
$display (" ", fshow (req));
end
fa_fabric_send_write_req (req.addr, pack (req.byteEn), req.data);
// Technically the following check for legal IO addrs is not
// necessary; the AXI4 fabric should return a DECERR for illegal
// addrs; but not all AXI4 fabrics do the right thing.
if (soc_map.m_is_IO_addr (req.addr))
fa_fabric_send_write_req (req.addr, pack (req.byteEn), req.data);
else begin
let rsp = MMIODataPRs {valid: False,
data: req.addr}; // For debugging convenience only
f_rsps_to_core.enq (rsp);
if (cfg_verbosity > 0) begin
$display ("%0d: %m.rl_handle_write_req: unmapped IO address; returning error response",
cur_cycle);
$display (" ", fshow (req));
end
end
endrule
// ----------------
@@ -189,28 +243,28 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
let wr_resp <- pop_o (master_xactor.o_wr_resp);
if (cfg_verbosity > 0) begin
$display ("%0d: MMIO_AXI4_Adapter.rl_discard_write_rsp", cur_cycle);
$display (" ", fshow (wr_resp));
$display ("%0d: %m.rl_discard_write_rsp", cur_cycle);
$display (" ", fshow (wr_resp));
end
if (ctr_wr_rsps_pending.value == 0) begin
$display ("%0d: ERROR: MMIO_AXI4_Adapter.rl_discard_write_rsp: unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1); // Assertion failure
$display ("%0d:%m.rl_discard_write_rsp: ERROR:unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1); // Assertion failure
end
ctr_wr_rsps_pending.decr;
if (wr_resp.bresp != axi4_resp_okay) begin
// TODO: need to raise a non-maskable interrupt (NMI) here
$display ("%0d: MMIO_AXI4_Adapter.rl_discard_write_rsp: fabric response error: exit", cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1);
// TODO: need to raise a non-maskable interrupt (NMI) here
$display ("%0d:%m.rl_discard_write_rsp: ERROR: fabric response error: exit.", cur_cycle);
$display (" ", fshow (wr_resp));
$finish (1);
end
else begin
let rsp = MMIODataPRs {valid: True, data: 0};
f_rsps_to_core.enq (rsp);
let rsp = MMIODataPRs {valid: True, data: 0};
f_rsps_to_core.enq (rsp);
end
endrule
@@ -219,17 +273,16 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
function Bool fn_is_Ld_or_St (MMIOCRq req);
return case (req.func) matches
Ld : True;
St : True;
default: False;
endcase;
Ld : True;
St : True;
default: False;
endcase;
endfunction
rule rl_handle_non_Ld_St (! fn_is_Ld_or_St (f_reqs_from_core.first));
let req <- pop (f_reqs_from_core);
$display ("%0d: ERROR: MMIO_AXI4_Adapter.rl_handle_non_Ld_St",
cur_cycle);
$display ("%0d:%m.rl_handle_non_Ld_St: ERROR: neither Ld nor St? exit.", cur_cycle);
$display (" ", fshow (req));
$finish (1); // Assertion failure
endrule

View File

@@ -1,6 +1,9 @@
package Proc;
// Note: this module corresponds to module 'mkCPU' in Piccolo/Flute.
// Copyright (c) 2018 Massachusetts Institute of Technology
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -22,8 +25,6 @@ package Proc;
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Portions Copyright (c) 2019 Bluespec, Inc.
// ================================================================
// BSV lib imports
@@ -77,17 +78,13 @@ import SoC_Map :: *;
import AXI4_Types :: *;
import Fabric_Defs :: *;
`ifdef INCLUDE_GDB_CONTROL
import DM_CPU_Req_Rsp :: *;
`endif
`ifdef INCLUDE_TANDEM_VERIF
import TV_Info :: *;
`endif
`ifdef EXTERNAL_DEBUG_MODULE
`undef INCLUDE_GDB_CONTROL
import ProcTypes :: *;
import Trace_Data2 :: *;
`endif
// ================================================================
@@ -108,50 +105,6 @@ module mkProc (Proc_IFC);
// Verbosity: 0=quiet; 1=instruction trace; 2=more detail
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
// ----------------
// Reset requests and responses (TODO: to be implemented)
FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF;
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
// ----------------
// Communication to/from External debug module (TODO: to be implemented)
`ifdef INCLUDE_GDB_CONTROL
// Debugger run-control
FIFOF #(Bool) f_run_halt_reqs <- mkFIFOF;
FIFOF #(Bool) f_run_halt_rsps <- mkFIFOF;
// Stop-request from debugger (e.g., GDB ^C or Dsharp 'stop')
Reg #(Bool) rg_stop_req <- mkReg (False);
// Count instrs after step-request from debugger (via dcsr.step)
Reg #(Bit #(1)) rg_step_count <- mkReg (0);
// Debugger GPR read/write request/response
FIFOF #(DM_CPU_Req #(5, XLEN)) f_gpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_gpr_rsps <- mkFIFOF1;
`ifdef ISA_F
// Debugger FPR read/write request/response
FIFOF #(DM_CPU_Req #(5, FLEN)) f_fpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(FLEN)) f_fpr_rsps <- mkFIFOF1;
`endif
// Debugger CSR read/write request/response
FIFOF #(DM_CPU_Req #(12, XLEN)) f_csr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_csr_rsps <- mkFIFOF1;
`endif
// ----------------
// Tandem Verification (TODO: to be implemented)
`ifdef INCLUDE_TANDEM_VERIF
FIFOF #(Trace_Data) f_trace_data <- mkFIFOF;
`endif
// ----------------
// MMIO
@@ -163,7 +116,7 @@ module mkProc (Proc_IFC);
mmioToP[i] = core[i].mmioToPlatform;
end
MMIOPlatform mmioPlatform <- mkMMIOPlatform (mmioToP,
mmio_axi4_adapter.core_side);
mmio_axi4_adapter.core_side);
// last level cache
LLCache llc <- mkLLCache;
@@ -185,16 +138,11 @@ module mkProc (Proc_IFC);
tlbToMem[i] = core[i].tlbToMem;
end
// Stub out memLoader (TODO: can be Debug Module's access)
let memLoaderStub = interface MemLoaderMemClient;
interface memReq = nullFifoDeq;
interface respSt = nullFifoEnq;
endinterface;
mkLLCDmaConnect(llc.dma, memLoaderStub, tlbToMem);
// Note: mkLLCDmaConnect is Toooba version, different from riscy-ooo version
let llc_mem_server <- mkLLCDmaConnect(llc.dma, tlbToMem);
// ================================================================
// interface LLC to AXI4
// interface Back-side of LLC to AXI4
LLC_AXI4_Adapter_IFC llc_axi4_adapter <- mkLLC_AXi4_Adapter (llc.to_mem);
@@ -205,7 +153,7 @@ module mkProc (Proc_IFC);
rule broadcastStats;
Bool doStats <- core[i].sendDoStats;
for(Integer j = 0; j < valueof(CoreNum); j = j+1) begin
core[j].recvDoStats(doStats);
core[j].recvDoStats(doStats);
end
llc.perf.setStatus(doStats);
endrule
@@ -216,74 +164,64 @@ module mkProc (Proc_IFC);
for(Integer j = 0; j < valueof(CoreNum); j = j+1) begin
rule rl_dummy1;
let x <- core[j].deadlock.dCacheCRqStuck.get;
let x <- core[j].deadlock.dCacheCRqStuck.get;
endrule
rule rl_dummy2;
let x <- core[j].deadlock.dCachePRqStuck.get;
let x <- core[j].deadlock.dCachePRqStuck.get;
endrule
rule rl_dummy3;
let x <- core[j].deadlock.iCacheCRqStuck.get;
let x <- core[j].deadlock.iCacheCRqStuck.get;
endrule
rule rl_dummy4;
let x <- core[j].deadlock.iCachePRqStuck.get;
let x <- core[j].deadlock.iCachePRqStuck.get;
endrule
rule rl_dummy5;
let x <- core[j].deadlock.renameInstStuck.get;
let x <- core[j].deadlock.renameInstStuck.get;
endrule
rule rl_dummy6;
let x <- core[j].deadlock.renameCorrectPathStuck.get;
let x <- core[j].deadlock.renameCorrectPathStuck.get;
endrule
rule rl_dummy7;
let x <- core[j].deadlock.commitInstStuck.get;
let x <- core[j].deadlock.commitInstStuck.get;
endrule
rule rl_dummy8;
let x <- core[j].deadlock.commitUserInstStuck.get;
let x <- core[j].deadlock.commitUserInstStuck.get;
endrule
rule rl_dummy9;
let x <- core[j].deadlock.checkStarted.get;
let x <- core[j].deadlock.checkStarted.get;
endrule
rule rl_dummy20;
let x <- core[j].renameDebug.renameErr.get;
let x <- core[j].renameDebug.renameErr.get;
endrule
end
// ================================================================
// Reset
rule rl_reset;
let x <- pop (f_reset_reqs);
llc_axi4_adapter.reset;
mmio_axi4_adapter.reset;
f_reset_rsps.enq (?);
endrule
// ----------------
// Termination detection
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
rule rl_terminate;
let x <- core[i].coreIndInv.terminate;
$display ("Core %d terminated", i);
let x <- core[i].coreIndInv.terminate;
$display ("Core %d terminated", i);
endrule
end
// ================================================================
// Print out values written 'tohost'
rule rl_tohost;
let x <- mmioPlatform.to_host;
$display ("%0d: mmioPlatform.rl_tohost: 0x%0x (= %0d)", cur_cycle, x, x);
if (x != 0) begin
// Standard RISC-V ISA tests finish by writing a value tohost with x[0]==1.
// Further when x[63:1]==0, all tests within the program pass,
// otherwise x[63:1] = the test within the program that failed.
let failed_testnum = (x >> 1);
if (failed_testnum == 0)
$display ("PASS");
else
$display ("FAIL %0d", failed_testnum);
$finish (0);
// Standard RISC-V ISA tests finish by writing a value tohost with x[0]==1.
// Further when x[63:1]==0, all tests within the program pass,
// otherwise x[63:1] = the test within the program that failed.
let failed_testnum = (x >> 1);
if (failed_testnum == 0)
$display ("PASS");
else
$display ("FAIL %0d", failed_testnum);
$finish (0);
end
endrule
@@ -292,21 +230,19 @@ module mkProc (Proc_IFC);
// ================================================================
// INTERFACE
// Reset
interface Server hart0_server_reset = toGPServer (f_reset_reqs, f_reset_rsps);
// ----------------
// Start the cores running
// Use toHostAddr = 0 if not monitoring tohost
method Action start (Addr startpc, Addr tohostAddr, Addr fromhostAddr);
action
for(Integer i = 0; i < valueof(CoreNum); i = i+1)
core[i].coreReq.start (startpc, tohostAddr, fromhostAddr);
for(Integer i = 0; i < valueof(CoreNum); i = i+1)
core[i].coreReq.start (startpc, tohostAddr, fromhostAddr);
endaction
mmioPlatform.start (tohostAddr, fromhostAddr);
$display ("Proc.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
startpc, tohostAddr, fromhostAddr);
$display ("%0d: %m.method start: startpc %0h, tohostAddr %0h, fromhostAddr %0h",
cur_cycle, startpc, tohostAddr, fromhostAddr);
endmethod
// ----------------
@@ -329,13 +265,6 @@ module mkProc (Proc_IFC);
core[0].setSEIP (pack (x));
endmethod
// ----------------
// External interrupt [14] to go into Debug Mode
method Action debug_external_interrupt_req (Bool set_not_clear);
core[0].setDEIP (pack (set_not_clear));
endmethod
// ----------------
// Non-maskable interrupt
@@ -350,11 +279,9 @@ module mkProc (Proc_IFC);
endmethod
// ----------------
// Optional interface to Tandem Verifier
// Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory)
`ifdef INCLUDE_TANDEM_VERIF
interface Get trace_data_out = toGet (f_trace_data);
`endif
interface debug_module_mem_server = llc_mem_server;
`ifdef RVFI_DII
interface Toooba_RVFI_DII_Server rvfi_dii_server = core[0].rvfi_dii_server;
@@ -364,25 +291,25 @@ module mkProc (Proc_IFC);
// Optional interface to Debug Module
`ifdef INCLUDE_GDB_CONTROL
// run-control, other
interface Server hart0_server_run_halt = toGPServer (f_run_halt_reqs, f_run_halt_rsps);
// run/halt, gpr, mem and csr control goes to core
interface Server hart0_run_halt_server = core [0].hart0_run_halt_server;
interface Put hart0_put_other_req;
method Action put (Bit #(4) req);
cfg_verbosity <= req;
cfg_verbosity <= req;
endmethod
endinterface
// GPR access
interface Server hart0_gpr_mem_server = toGPServer (f_gpr_reqs, f_gpr_rsps);
interface Server hart0_gpr_mem_server = core[0].hart0_gpr_mem_server;
`ifdef ISA_F
// FPR access
interface Server hart0_fpr_mem_server = toGPServer (f_fpr_reqs, f_fpr_rsps);
interface Server hart0_fpr_mem_server = core[0].hart0_fpr_mem_server;
`endif
interface Server hart0_csr_mem_server = core[0].hart0_csr_mem_server;
`endif
// CSR access
interface Server hart0_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps);
`ifdef INCLUDE_TANDEM_VERIF
interface v_to_TV = core [0].v_to_TV;
`endif
endmodule: mkProc

View File

@@ -1,10 +1,11 @@
// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved
// Copyright (c) 2016-2020 Bluespec, Inc. All Rights Reserved
package Proc_IFC;
// ================================================================
// BSV library imports
import Vector :: *;
import GetPut :: *;
import ClientServer :: *;
@@ -21,7 +22,8 @@ import DM_CPU_Req_Rsp :: *;
`endif
`ifdef INCLUDE_TANDEM_VERIF
import TV_Info :: *;
import ProcTypes :: *;
import Trace_Data2 :: *;
`endif
`ifdef RVFI_DII
@@ -36,11 +38,10 @@ import Types :: *;
// because the RISCY-OOO mkProc contains those elements.
interface Proc_IFC;
// Reset
interface Server #(Token, Token) hart0_server_reset;
// ----------------
// Start the cores running
// Use toHostAddr = 0 if not monitoring tohost
method Action start (Addr startpc, Addr tohostAddr, Addr fromhostAddr);
// ----------------
@@ -61,12 +62,6 @@ interface Proc_IFC;
(* always_ready, always_enabled *)
method Action s_external_interrupt_req (Bool set_not_clear);
// ----------------
// External interrupt [14] to go into Debug Mode
(* always_ready, always_enabled *)
method Action debug_external_interrupt_req (Bool set_not_clear);
// ----------------
// Non-maskable interrupt
@@ -79,11 +74,9 @@ interface Proc_IFC;
method Action set_verbosity (Bit #(4) verbosity);
// ----------------
// Optional interface to Tandem Verifier
// Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory)
`ifdef INCLUDE_TANDEM_VERIF
interface Get #(Trace_Data) trace_data_out;
`endif
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) debug_module_mem_server;
`ifdef RVFI_DII
interface Toooba_RVFI_DII_Server rvfi_dii_server;
@@ -93,20 +86,24 @@ interface Proc_IFC;
// Optional interface to Debug Module
`ifdef INCLUDE_GDB_CONTROL
// run-control, other
interface Server #(Bool, Bool) hart0_server_run_halt;
interface Put #(Bit #(4)) hart0_put_other_req;
// GPR access
interface Server #(Bool, Bool) hart0_run_halt_server;
interface Server #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) hart0_gpr_mem_server;
`ifdef ISA_F
// FPR access
interface Server #(DM_CPU_Req #(5, FLEN), DM_CPU_Rsp #(FLEN)) hart0_fpr_mem_server;
`endif
// CSR access
interface Server #(DM_CPU_Req #(12, XLEN), DM_CPU_Rsp #(XLEN)) hart0_csr_mem_server;
// Non-standard
interface Put #(Bit #(4)) hart0_put_other_req;
`endif
`ifdef INCLUDE_TANDEM_VERIF
// Note: this is a SupSize vector of streams of Trace_Data2 structs,
// each of which has a serialnum field. Each of the SupSize
// streams has serialnums in increasing order. Each serialnum
// appears exactly once in exactly one of the streams. Thus, the
// channels can easily be merged into a single program-order stream.
interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV;
`endif
endinterface

View File

@@ -1,8 +1,21 @@
// Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved.
// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved.
package CoreW;
// ================================================================
// This package is called 'CoreW' for 'Core Wrapper'
// and corresponds to 'Core' in Piccolo and Flute.
//
// Here in Toooba, we use the name 'CoreW' to avoid a name-clash with
// an inner module called 'Core' in MIT's RISCY-OOO.
//
// The specific correspondence with Piccolo/Flute structure is:
// Piccolo/Flute Toooba
// mkCore mkCoreW
// mkProc
// mkCPU mkCore
// This package defines:
// Core_IFC
// mkCore #(Core_IFC)
@@ -19,12 +32,12 @@ package CoreW;
// ================================================================
// BSV library imports
import Vector :: *;
import FIFOF :: *;
import GetPut :: *;
import ClientServer :: *;
import Connectable :: *;
import Clocks :: *;
import Vector :: *;
import FIFOF :: *;
import GetPut :: *;
import ClientServer :: *;
import Connectable :: *;
import Clocks :: *;
// ----------------
// BSV additional libs
@@ -35,6 +48,13 @@ import GetPut_Aux :: *;
// ================================================================
// Project imports
// ----------------
// From RISCY-ooo
import ProcTypes :: *;
// ----------------
// From Toooba
// Main fabric
import AXI4_Types :: *;
import AXI4_Fabric :: *;
@@ -52,8 +72,10 @@ import Proc_IFC :: *;
import Proc :: *;
`ifdef INCLUDE_TANDEM_VERIF
import TV_Info :: *;
import TV_Encode :: *;
import TV_Info :: *;
import Trace_Data2 :: *;
import TV_Encode :: *;
import Trace_Data2_to_Trace_Data :: *;
`endif
// TV_Taps needed when both GDB_CONTROL and TANDEM_VERIF are present
@@ -69,13 +91,52 @@ import DM_CPU_Req_Rsp ::*;
// The Core module
(* synthesize *)
module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
module mkCoreW #(Reset dm_power_on_reset)
(CoreW_IFC #(N_External_Interrupt_Sources));
`ifdef EXTERNAL_DEBUG_MODULE
// ================================================================
// Notes on 'reset'
// This module's default reset (Verilog RST_N) is a
// 'non-debug-module reset', or 'ndm-reset': it resets everything
// in mkCoreW other than the optional RISC-V Debug Module (DM).
// DM is reset ONLY by 'dm_power_on_reset' (parameter of this module).
// This is expected to be performed exactly once, on power-up.
// Note: DM has an internal functionality that the DM spec calls
// 'dm_reset'. This is not really an electrical reset, it is just
// a module initializer wholly within the DM to put it into a
// known state. To be able to do a dm_reset, the DM has to be
// working already, at least to the point that it can field DMI
// requests from the external debugger asking the DM to proform a
// dm_reset.
// DM can ask the environment to perform an 'ndm-reset', which the
// environment does by asserting the default reset (RST_N). At the
// same time, the environment may also reset part or all of the
// rest of the SoC.
// DM can also individually reset each hart in mkCPU.
// 'hart' = hardware thread = independent PC and fetch-and-execute pipeline.
// mkCPU (instantiated in this module) has one or more harts.
// This hart-reset logic is entirely within this module.
// ================================================================
// The CPU's (hart's) reset is the ``or'' of the default reset
// (power-on reset) and the Debug Module's 'hart_reset' control.
let ndm_reset <- exposeCurrentReset;
`ifdef INCLUDE_GDB_CONTROL
let clk <- exposeCurrentClock;
let cpu_reset <- mkReset(50, True, clk);
let cpu_halt <- mkReset(50, True, clk);
let cpu_reset_either <- mkResetEither(cpu_reset.new_rst, cpu_halt.new_rst);
Bool initial_reset_val = False;
Integer hart_reset_duration = 10; // NOTE: assuming 10 cycle reset enough for hart
let dm_hart0_reset_controller <- mkReset(hart_reset_duration, initial_reset_val, clk);
let hart0_reset <- mkResetEither (ndm_reset, dm_hart0_reset_controller.new_rst);
`else
let hart0_reset = ndm_reset;
`endif
// ================================================================
@@ -84,12 +145,9 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
// System address map
SoC_Map_IFC soc_map <- mkSoC_Map;
// McStriiv processor
`ifdef EXTERNAL_DEBUG_MODULE
Proc_IFC proc <- mkProc(reset_by cpu_reset_either);
`else
Proc_IFC proc <- mkProc;
`endif
// RISCY-OOO processor
// TODO (when we do multicore): need resets for each core.
Proc_IFC proc <- mkProc (reset_by hart0_reset);
// A 2x3 fabric for connecting {CPU, Debug_Module} to {Fabric, PLIC}
Fabric_2x3_IFC fabric_2x3 <- mkFabric_2x3;
@@ -97,231 +155,99 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
// PLIC (Platform-Level Interrupt Controller)
PLIC_IFC_16_2_7 plic <- mkPLIC_16_2_7;
// Reset requests from SoC and responses to SoC
FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF;
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
`ifdef INCLUDE_GDB_CONTROL
// Debug Module
Debug_Module_IFC debug_module <- mkDebug_Module (reset_by dm_power_on_reset);
`endif
`ifdef INCLUDE_TANDEM_VERIF
// The TV encoder transforms Trace_Data structures produced by the CPU and DM
// The following are a superscalar-wide set of transformers from RISCY-OOO output Trace_Data2
// to Trace_Data which is input to the TV encoder
Vector #(SupSize, Trace_Data2_to_Trace_Data_IFC) v_td2_to_td <- replicateM (mkTrace_Data2_to_Trace_Data);
// The TV encoder transforms Trace_Data structures from the CPU and DM
// into encoded byte vectors for transmission to the Tandem Verifier
TV_Encode_IFC tv_encode <- mkTV_Encode;
`endif
`ifdef INCLUDE_GDB_CONTROL
// Debug Module
Debug_Module_IFC debug_module <- mkDebug_Module;
`endif
// HTIF locations (for debugging only)
Reg #(Bit #(64)) rg_tohost_addr <- mkReg (0);
Reg #(Bit #(64)) rg_fromhost_addr <- mkReg (0);
// ================================================================
// RESET
// There are two sources of reset requests to the CPU: externally
// from the SoC and, optionally, the DM. The SoC requires a
// response, the DM does not. When both requestors are present
// (i.e., DM is present), we merge the reset requests into the CPU,
// and we remember which one was the requestor in
// f_reset_requestor, so that we know whether or not to respond to
// the SoC.
Bit #(1) reset_requestor_dm = 0;
Bit #(1) reset_requestor_soc = 1;
`ifdef INCLUDE_GDB_CONTROL
FIFOF #(Bit #(1)) f_reset_requestor <- mkFIFOF;
`endif
// Reset-hart0 request from SoC
rule rl_cpu_hart0_reset_from_soc_start;
let req <- pop (f_reset_reqs);
`ifdef EXTERNAL_DEBUG_MODULE
cpu_reset.assertReset;
`else
proc.hart0_server_reset.request.put (?); // CPU
`endif
plic.server_reset.request.put (?); // PLIC
fabric_2x3.reset; // Local 2x3 Fabric
// Hart-reset from DM
`ifdef INCLUDE_GDB_CONTROL
`ifndef EXTERNAL_DEBUG_MODULE
// Remember the requestor, so we can respond to it
f_reset_requestor.enq (reset_requestor_soc);
`endif
`endif
$display ("%0d: Core.rl_cpu_hart0_reset_from_soc_start", cur_cycle);
Reg #(Bit #(8)) rg_hart0_reset_delay <- mkReg (0);
Reg #(Bit #(64)) rg_tohost_addr <- mkReg (0);
Reg #(Bit #(64)) rg_fromhost_addr <- mkReg (0);
rule rl_dm_hart0_reset (rg_hart0_reset_delay == 0);
let x <- debug_module.hart0_reset_client.request.get;
dm_hart0_reset_controller.assertReset;
rg_hart0_reset_delay <= fromInteger (hart_reset_duration + 200); // NOTE: heuristic
$display ("%0d: %m.rl_dm_hart0_reset: asserting hart0 reset for %0d cycles",
cur_cycle, hart_reset_duration);
endrule
`ifdef INCLUDE_GDB_CONTROL
`ifndef EXTERNAL_DEBUG_MODULE
// Reset-hart0 from Debug Module
rule rl_cpu_hart0_reset_from_dm_start;
let req <- debug_module.hart0_get_reset_req.get;
rule rl_dm_hart0_reset_wait (rg_hart0_reset_delay != 0);
if (rg_hart0_reset_delay == 1) begin
let pc = soc_map_struct.pc_reset_value;
proc.start (pc, rg_tohost_addr, rg_fromhost_addr);
proc.hart0_server_reset.request.put (?); // CPU
plic.server_reset.request.put (?); // PLIC
fabric_2x3.reset; // Local 2x3 fabric
// Remember the requestor, so we can respond to it
f_reset_requestor.enq (reset_requestor_dm);
$display ("%0d: Core.rl_cpu_hart0_reset_from_dm_start", cur_cycle);
endrule
`endif
`endif
`ifdef EXTERNAL_DEBUG_MODULE
rule rl_cpu_hart0_reset_complete(!cpu_reset.isAsserted);
`else
rule rl_cpu_hart0_reset_complete;
let rsp1 <- proc.hart0_server_reset.response.get; // CPU
`endif
let rsp3 <- plic.server_reset.response.get; // PLIC
plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base),
zeroExtend (soc_map.m_plic_addr_lim));
Bit #(1) requestor = reset_requestor_soc;
`ifdef INCLUDE_GDB_CONTROL
`ifndef EXTERNAL_DEBUG_MODULE
requestor <- pop (f_reset_requestor);
`endif
`endif
if (requestor == reset_requestor_soc)
f_reset_rsps.enq (?);
`ifndef EXTERNAL_DEBUG_MODULE
// Start running the cores
proc.start (soc_map_struct.pc_reset_value,
rg_tohost_addr,
rg_fromhost_addr);
`endif
$display ("%0d: Core.rl_cpu_hart0_reset_complete; started running proc", cur_cycle);
Bool is_running = True;
debug_module.hart0_reset_client.response.put (is_running);
$display ("%0d: %m.rl_dm_hart0_reset_wait: proc.start (pc %0h, tohostAddr %0h, fromhostAddr %0h",
cur_cycle, pc, rg_tohost_addr, rg_fromhost_addr);
end
rg_hart0_reset_delay <= rg_hart0_reset_delay - 1;
endrule
`endif
`ifdef INCLUDE_GDB_CONTROL
// ================================================================
// Direct DM-to-CPU connections
// Direct DM-to-CPU connections for run-control and other misc requests
`ifdef INCLUDE_GDB_CONTROL
`ifndef EXTERNAL_DEBUG_MODULE
// DM to CPU connections for run-control and other misc requests
mkConnection (debug_module.hart0_client_run_halt, proc.hart0_server_run_halt);
mkConnection (debug_module.hart0_client_run_halt, proc.hart0_run_halt_server);
mkConnection (debug_module.hart0_get_other_req, proc.hart0_put_other_req);
`endif
`endif
// external debug module connections
`ifdef INCLUDE_GDB_CONTROL
`ifdef EXTERNAL_DEBUG_MODULE
Reg#(Bool) once <- mkReg(False, reset_by cpu_reset_either);
rule rl_once(!once && !cpu_reset.isAsserted && !cpu_halt.isAsserted);
proc.hart0_server_reset.request.put(?);
once <= True;
endrule
rule rl_hart0_server_reset;
let tmp <- proc.hart0_server_reset.response.get;
proc.start (soc_map_struct.pc_reset_value,
rg_tohost_addr,
rg_fromhost_addr);
endrule
rule rl_hart0_server_run_halt;
let tmp <- proc.hart0_server_run_halt.response.get;
endrule
Reg#(Bool) hart0_halt <- mkReg(False);
rule rl_halt_reset(hart0_halt);
cpu_halt.assertReset;
endrule
rule rl_halt;
let halt <- debug_module.hart0_client_run_halt.request.get;
hart0_halt <= !halt;
debug_module.hart0_client_run_halt.response.put(halt);
endrule
rule rl_gpr;
let req <- debug_module.hart0_gpr_mem_client.request.get;
debug_module.hart0_gpr_mem_client.response.put(DM_CPU_Rsp { ok: True, data: 0 });
endrule
`ifdef ISA_F
rule rl_fpr;
let req <- debug_module.hart0_fpr_mem_client.request.get;
debug_module.hart0_fpr_mem_client.response.put(DM_CPU_Rsp { ok: True, data: 0 });
endrule
`endif
rule rl_csr;
let req <- debug_module.hart0_csr_mem_client.request.get;
debug_module.hart0_csr_mem_client.response.put(DM_CPU_Rsp { ok: True, data: 0 });
endrule
rule rl_cpu_hart0_reset_from_dm_start;
let req <- debug_module.hart0_get_reset_req.get;
cpu_reset.assertReset;
f_reset_requestor.enq (reset_requestor_dm);
endrule
rule rl_cpu_hart0_reset_from_dm_complete (f_reset_requestor.first == reset_requestor_dm && !cpu_reset.isAsserted);
f_reset_requestor.deq;
endrule
`endif
`endif
`ifdef INCLUDE_TANDEM_VERIF
// ================================================================
// Other CPU/DM/TV connections
// (depends on whether DM, TV or both are present)
// Direct CPU-to-TV connections for TV trace data
for (Integer j = 0; j < valueOf (SupSize); j = j + 1) begin
// CPU Trace_Data2 output streams to Trace_Data2_to_Trace_Data converters
mkConnection (proc.v_to_TV [j], v_td2_to_td [j].in);
// Trace_Data2_to_Trace_Data converters to TV encoder
mkConnection (v_td2_to_td [j].out, tv_encode.v_cpu_in [j]);
end
`endif
`ifdef INCLUDE_GDB_CONTROL
`ifdef INCLUDE_TANDEM_VERIF
// BEGIN SECTION: GDB and TV
// ----------------------------------------------------------------
// DM and TV both present. We instantiate 'taps' into connections
// where the DM writes CPU GPRs, CPU FPRs, CPU CSRs, and main memory,
// in order to produce corresponding writes for the Tandem Verifier.
// Then, we merge the Trace_Data from these three taps with the
// Trace_Data produced by the PROC.
FIFOF #(Trace_Data) f_trace_data_merged <- mkFIFOF;
// Connect merged trace data to trace encoder
mkConnection (toGet (f_trace_data_merged), tv_encode.trace_data_in);
// Merge-in CPU's trace data.
// This is equivalent to: mkConnection (proc.trace_data_out, toPut (f_trace_data_merged))
// but using a rule allows us to name it in scheduling attributes.
rule merge_cpu_trace_data;
let tmp <- proc.trace_data_out.get;
f_trace_data_merged.enq (tmp);
endrule
// ================================================================
// BEGIN SECTION: DM and TV both present
// We instantiate 'taps' into connections where DM writes CPU GPRs,
// FPRs, CSRs, and main memory. The tap outputs go the TV encoder,
// to keep the tandem verifier in sync with DM updates to the CPU.
// Create a tap for DM's memory-writes to the bus, and merge-in the trace data.
DM_Mem_Tap_IFC dm_mem_tap <- mkDM_Mem_Tap;
mkConnection (debug_module.master, dm_mem_tap.slave);
let dm_master_local = dm_mem_tap.master;
rule merge_dm_mem_trace_data;
rule rl_merge_dm_mem_trace_data;
let tmp <- dm_mem_tap.trace_data_out.get;
f_trace_data_merged.enq (tmp);
tv_encode.dm_in.put (tmp);
endrule
`ifndef EXTERNAL_DEBUG_MODULE
// Create a tap for DM's GPR writes to the CPU, and merge-in the trace data.
DM_GPR_Tap_IFC dm_gpr_tap_ifc <- mkDM_GPR_Tap;
mkConnection (debug_module.hart0_gpr_mem_client, dm_gpr_tap_ifc.server);
mkConnection (dm_gpr_tap_ifc.client, proc.hart0_gpr_mem_server);
rule merge_dm_gpr_trace_data;
rule rl_merge_dm_gpr_trace_data;
let tmp <- dm_gpr_tap_ifc.trace_data_out.get;
f_trace_data_merged.enq (tmp);
tv_encode.dm_in.put (tmp);
endrule
`ifdef ISA_F_OR_D
@@ -330,9 +256,9 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
mkConnection (debug_module.hart0_fpr_mem_client, dm_fpr_tap_ifc.server);
mkConnection (dm_fpr_tap_ifc.client, proc.hart0_fpr_mem_server);
rule merge_dm_fpr_trace_data;
rule rl_merge_dm_fpr_trace_data;
let tmp <- dm_fpr_tap_ifc.trace_data_out.get;
f_trace_data_merged.enq (tmp);
tv_encode.dm_in.put (tmp);
endrule
`endif
// for ifdef ISA_F_OR_D
@@ -342,25 +268,25 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
mkConnection(debug_module.hart0_csr_mem_client, dm_csr_tap.server);
mkConnection(dm_csr_tap.client, proc.hart0_csr_mem_server);
`ifdef ISA_F_OR_D
(* descending_urgency = "merge_dm_fpr_trace_data, merge_dm_gpr_trace_data" *)
`endif
(* descending_urgency = "merge_dm_gpr_trace_data, merge_dm_csr_trace_data" *)
(* descending_urgency = "merge_dm_csr_trace_data, merge_dm_mem_trace_data" *)
(* descending_urgency = "merge_dm_mem_trace_data, merge_cpu_trace_data" *)
rule merge_dm_csr_trace_data;
rule rl_merge_dm_csr_trace_data;
let tmp <- dm_csr_tap.trace_data_out.get;
f_trace_data_merged.enq(tmp);
tv_encode.dm_in.put(tmp);
endrule
`ifdef ISA_F_OR_D
(* descending_urgency = "rl_merge_dm_fpr_trace_data, rl_merge_dm_gpr_trace_data" *)
`endif
(* descending_urgency = "rl_merge_dm_gpr_trace_data, rl_merge_dm_csr_trace_data" *)
(* descending_urgency = "rl_merge_dm_csr_trace_data, rl_merge_dm_mem_trace_data" *)
rule rl_bogus_for_sched_attributes;
endrule
// END SECTION: GDB and TV
`else
// for ifdef INCLUDE_TANDEM_VERIF
// ----------------------------------------------------------------
// BEGIN SECTION: GDB and no TV
// END SECTION: DM and TV
// ================================================================
`else // of ifdef INCLUDE_TANDEM_VERIF
// ================================================================
// BEGIN SECTION: DM, no TV
`ifndef EXTERNAL_DEBUG_MODULE
// Connect DM's GPR interface directly to CPU
mkConnection (debug_module.hart0_gpr_mem_client, proc.hart0_gpr_mem_server);
@@ -371,33 +297,30 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
// Connect DM's CSR interface directly to CPU
mkConnection (debug_module.hart0_csr_mem_client, proc.hart0_csr_mem_server);
`endif
// DM's bus master is directly the bus master
let dm_master_local = debug_module.master;
// END SECTION: GDB and no TV
`endif
// for ifdef INCLUDE_TANDEM_VERIF
// END SECTION: DM, no TV
// ================================================================
`endif // for ifdef INCLUDE_TANDEM_VERIF
// ================================================================
`else // for ifdef INCLUDE_GDB_CONTROL
// ================================================================
// BEGIN SECTION: no DM
`else
// for ifdef INCLUDE_GDB_CONTROL
// BEGIN SECTION: no GDB
// No DM, so 'DM bus master' is dummy
// No DM, so 'DM bus master' is AXI4 dummy
AXI4_Master_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User)
dm_master_local = dummy_AXI4_Master_ifc;
`ifdef INCLUDE_TANDEM_VERIF
// ----------------------------------------------------------------
// BEGIN SECTION: no GDB, TV
// TV, no DM: stub out the dm input to TV
Get #(Trace_Data) gs = getstub;
mkConnection (tv_encode.dm_in, gs);
`endif
`endif // for ifdef INCLUDE_GDB_CONTROL
// Connect CPU's TV out directly to TV encoder
mkConnection (proc.trace_data_out, tv_encode.trace_data_in);
// END SECTION: no GDB, TV
`endif
`endif
// for ifdef INCLUDE_GDB_CONTROL
// ================================================================
// Connect the local 2x3 fabric
@@ -407,12 +330,10 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
mkConnection (dm_master_local, fabric_2x3.v_from_masters [debug_module_sba_master_num]);
// Slaves on the local 2x3 fabric
// default slave is taken out directly to the Core interface
mkConnection (fabric_2x3.v_to_slaves [plic_slave_num], plic.axi4_slave);
// TODO: This slave can be connected to mkLLCDmaConnect for Debug Module System Bus Access
AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) dummy_slave = dummy_AXI4_Slave_ifc;
mkConnection (fabric_2x3.v_to_slaves [near_mem_io_slave_num], dummy_slave);
// Two of the slaves are connected here.
// The third slave (default slave) is taken out directly to the Core interface
mkConnection (fabric_2x3.v_to_slaves [plic_slave_num], plic.axi4_slave);
mkConnection (fabric_2x3.v_to_slaves [llc_slave_num], proc.debug_module_mem_server);
// ================================================================
// Connect external interrupt lines from PLIC to CPU
@@ -427,13 +348,6 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
// $display ("%0d: Core.rl_relay_external_interrupts: relaying: %d", cur_cycle, pack (x));
endrule
// TODO: fixup. Need to combine NMIs from multiple sources (cache, fabric, devices, ...)
rule rl_relay_non_maskable_interrupt;
proc.non_maskable_interrupt_req (False);
// $display ("%0d: Core.rl_relay_non_maskable_interrupts: relaying: %d", cur_cycle, pack (x));
endrule
// ================================================================
// INTERFACE
@@ -445,16 +359,26 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
proc.set_verbosity (verbosity);
endmethod
method Action set_htif_addrs (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
// ----------------------------------------------------------------
// Start
method Action start (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base),
zeroExtend (soc_map.m_plic_addr_lim));
let pc = soc_map_struct.pc_reset_value;
proc.start (pc, tohost_addr, fromhost_addr);
`ifdef INCLUDE_GDB_CONTROL
// Save for potential future use by rl_dm_hart0_reset
rg_tohost_addr <= tohost_addr;
rg_fromhost_addr <= fromhost_addr;
`endif
$display ("%0d: %m.method start: proc.start (pc %0h, tohostAddr %0h, fromhostAddr %0h)",
cur_cycle, pc, tohost_addr, fromhost_addr);
endmethod
// ----------------------------------------------------------------
// Soft reset
interface Server cpu_reset_server = toGPServer (f_reset_reqs, f_reset_rsps);
// ----------------------------------------------------------------
// AXI4 Fabric interfaces
@@ -469,43 +393,44 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
interface core_external_interrupt_sources = plic.v_sources;
// ----------------
// External interrupt [14] to go into Debug Mode
method Action debug_external_interrupt_req (Bool set_not_clear);
proc.debug_external_interrupt_req (set_not_clear);
endmethod
// ----------------------------------------------------------------
// Optional TV interface
// Non-maskable interrupt request
`ifdef INCLUDE_TANDEM_VERIF
interface Get tv_verifier_info_get;
method ActionValue #(Info_CPU_to_Verifier) get();
match { .n, .v } <- tv_encode.tv_vb_out.get;
return (Info_CPU_to_Verifier { num_bytes: n, vec_bytes: v });
endmethod
endinterface
`endif
method Action nmi_req (Bool set_not_clear);
// TODO: fixup; passing const False for now
proc.non_maskable_interrupt_req (False);
endmethod
`ifdef RVFI_DII
interface Toooba_RVFI_DII_Server rvfi_dii_server = proc.rvfi_dii_server;
`endif
`ifdef INCLUDE_GDB_CONTROL
// ----------------------------------------------------------------
// Optional DM interfaces
`ifdef INCLUDE_GDB_CONTROL
// ----------------
// DMI (Debug Module Interface) facing remote debugger
interface DMI dm_dmi = debug_module.dmi;
interface DMI dmi = debug_module.dmi;
// ----------------
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
interface Get dm_ndm_reset_req_get = debug_module.get_ndm_reset_req;
interface Client ndm_reset_client = debug_module.ndm_reset_client;
`endif
`ifdef INCLUDE_TANDEM_VERIF
// ----------------------------------------------------------------
// Optional TV interface
interface Get tv_verifier_info_get;
method ActionValue #(Info_CPU_to_Verifier) get();
match { .n, .v } <- tv_encode.out.get;
return (Info_CPU_to_Verifier { num_bytes: n, vec_bytes: v });
endmethod
endinterface
`endif
endmodule: mkCoreW
@@ -531,22 +456,19 @@ typedef 3 Num_Slaves_2x3;
typedef Bit #(TLog #(Num_Slaves_2x3)) Slave_Num_2x3;
Slave_Num_2x3 default_slave_num = 0;
Slave_Num_2x3 plic_slave_num = 1;
// TODO: repurpose this for Debug Module System Bus Access to connect to mkLLCDramConnect
Slave_Num_2x3 near_mem_io_slave_num = 2;
Slave_Num_2x3 default_slave_num = 0; // for I/O, uncached memory, etc.
Slave_Num_2x3 plic_slave_num = 1; // PLIC mem-mapped registers
Slave_Num_2x3 llc_slave_num = 2; // Normal cached memory (connects to coherent Last-Level Cache)
// ----------------
// Specialization of parameterized AXI4 fabric for 2x3 Core fabric
typedef AXI4_Fabric_IFC #(Num_Masters_2x3,
Num_Slaves_2x3,
Wd_Id,
Wd_Addr,
Wd_Data,
Wd_User) Fabric_2x3_IFC;
Num_Slaves_2x3,
Wd_Id,
Wd_Addr,
Wd_Data,
Wd_User) Fabric_2x3_IFC;
// ----------------
@@ -561,16 +483,16 @@ module mkFabric_2x3 (Fabric_2x3_IFC);
// Any addr is legal, and there is only one slave to service it.
function Tuple2 #(Bool, Slave_Num_2x3) fn_addr_to_slave_num_2x3 (Fabric_Addr addr);
if ( (soc_map.m_near_mem_io_addr_base <= addr)
&& (addr < soc_map.m_near_mem_io_addr_lim))
return tuple2 (True, near_mem_io_slave_num);
if ( (soc_map.m_mem0_controller_addr_base <= addr)
&& (addr < soc_map.m_mem0_controller_addr_lim))
return tuple2 (True, llc_slave_num);
else if ( (soc_map.m_plic_addr_base <= addr)
&& (addr < soc_map.m_plic_addr_lim))
return tuple2 (True, plic_slave_num);
&& (addr < soc_map.m_plic_addr_lim))
return tuple2 (True, plic_slave_num);
else
return tuple2 (True, default_slave_num);
return tuple2 (True, default_slave_num);
endfunction
AXI4_Fabric_IFC #(Num_Masters_2x3, Num_Slaves_2x3, Wd_Id, Wd_Addr, Wd_Data, Wd_User)

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved.
// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved.
package CoreW_IFC;
@@ -6,9 +6,8 @@ package CoreW_IFC;
// This package defines the interface of a CoreW module which
// contains:
// - mkProc (the RISC-V CPU; this a variant of MIT's RISCY-OOO mkProc)
// Note: MIT's RISCY-OOO internally contains a 'mkCore'
// and hence this interface and its module is called
// 'CoreW', to disambiguate.
// Note: MIT's RISCY-OOO internally has a 'mkCore' and hence this
// interface and its module is called 'CoreW', to disambiguate.
// - mkFabric_2x3
// - mkNear_Mem_IO_AXI4
// - mkPLIC_16_2_7
@@ -32,10 +31,6 @@ import Fabric_Defs :: *;
// External interrupt request interface
import PLIC :: *;
`ifdef INCLUDE_TANDEM_VERIF
import TV_Info :: *;
`endif
`ifdef INCLUDE_GDB_CONTROL
import Debug_Module :: *;
`endif
@@ -44,22 +39,26 @@ import Debug_Module :: *;
import Types :: *;
`endif
`ifdef INCLUDE_TANDEM_VERIF
import ProcTypes :: *;
import Trace_Data2 :: *;
import TV_Info :: *;
`endif
// ================================================================
// The CoreW interface
interface CoreW_IFC #(numeric type t_n_interrupt_sources);
// ----------------------------------------------------------------
// Debugging: set core's verbosity, htif addrs
// Debugging: set core's verbosity
method Action set_verbosity (Bit #(4) verbosity, Bit #(64) logdelay);
method Action set_htif_addrs (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
// ----------------------------------------------------------------
// Soft reset
// Start
interface Server #(Bit #(0), Bit #(0)) cpu_reset_server;
method Action start (Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
// ----------------------------------------------------------------
// AXI4 Fabric interfaces
@@ -75,40 +74,41 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources);
interface Vector #(t_n_interrupt_sources, PLIC_Source_IFC) core_external_interrupt_sources;
// ----------------
// External interrupt [14] to go into Debug Mode
// ----------------------------------------------------------------
// Non-maskable interrupt request
(* always_ready, always_enabled *)
method Action debug_external_interrupt_req (Bool set_not_clear);
// ----------------------------------------------------------------
// Optional Tandem Verifier interface output tuples (n,vb),
// where 'vb' is a vector of bytes
// with relevant bytes in locations [0]..[n-1]
`ifdef INCLUDE_TANDEM_VERIF
interface Get #(Info_CPU_to_Verifier) tv_verifier_info_get;
`endif
method Action nmi_req (Bool set_not_clear);
`ifdef RVFI_DII
interface Toooba_RVFI_DII_Server rvfi_dii_server;
`endif
`ifdef INCLUDE_GDB_CONTROL
// ----------------------------------------------------------------
// Optional Debug Module interfaces
`ifdef INCLUDE_GDB_CONTROL
// ----------------
// DMI (Debug Module Interface) facing remote debugger
interface DMI dm_dmi;
interface DMI dmi;
// ----------------
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
interface Get #(Bit #(0)) dm_ndm_reset_req_get;
interface Client #(Bool, Bool) ndm_reset_client;
`endif
`ifdef INCLUDE_TANDEM_VERIF
// ----------------------------------------------------------------
// Optional Tandem Verifier interface output tuples (n,vb),
// where 'vb' is a vector of bytes
// with relevant bytes in locations [0]..[n-1]
interface Get #(Info_CPU_to_Verifier) tv_verifier_info_get;
`endif
endinterface
// ================================================================

View File

@@ -1,10 +1,14 @@
// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved.
// Copyright (c) 2013-2020 Bluespec, Inc. All Rights Reserved.
package TV_Encode;
// ================================================================
// module mkTV_Encode is a transforming FIFO
// converting Trace_Data into encoded byte vectors
// module mkTV_Encode inputs:
// - A superscalar-wide vector of (serial_num, Trace_Data) streams
// from a superscalar CPU
// - A Trace_Data stream
// from the Debug Module
// and produces an output stream of encoded byte vectors.
// ================================================================
// BSV lib imports
@@ -18,26 +22,37 @@ import Connectable :: *;
// ----------------
// BSV additional libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
// ================================================================
// Project imports
// ----------------
// From RISCY-OOO
import ProcTypes :: *;
// ----------------
// From Toooba
import ISA_Decls :: *;
import TV_Info :: *;
// ================================================================
interface TV_Encode_IFC;
method Action reset;
// Superscalar trace data from the CPU.
// Each item in the stream is (serialnum, td).
interface Vector #(SupSize, Put #(Tuple2 #(Bit #(64), Trace_Data))) v_cpu_in;
// This module receives Trace_Data structs from the CPU and Debug Module
interface Put #(Trace_Data) trace_data_in;
// Trace data from the Debug Module
interface Put #(Trace_Data) dm_in;
// This module produces tuples (n,vb),
// where 'vb' is a vector of bytes
// with relevant bytes in locations [0]..[n-1]
interface Get #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) tv_vb_out;
interface Get #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) out;
endinterface
// ================================================================
@@ -45,20 +60,58 @@ endinterface
(* synthesize *)
module mkTV_Encode (TV_Encode_IFC);
Reg #(Bool) rg_reset_done <- mkReg (True);
Integer verbosity = 0; // For debugging
// Keep track of last PC for more efficient encoding of incremented PCs
// TODO: currently always sending full PC
Reg #(WordXL) rg_last_pc <- mkReg (0);
FIFOF #(Trace_Data) f_trace_data <- mkFIFOF;
FIFOF #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) f_vb <- mkFIFOF;
// Superscalar-wide inputs from CPU
Vector #(SupSize, FIFOF #(Tuple2 #(Bit #(64), Trace_Data))) v_f_cpu_ins <- replicateM (mkFIFOF);
Reg #(Bit #(64)) rg_serialnum <- mkReg (0);
// Input from Debug Module
FIFOF #(Trace_Data) f_dm_in <- mkFIFOF;
// Merges CPU and Debug Module inputs
FIFOF #(Trace_Data) f_merged <- mkFIFOF;
// Encoded output
FIFOF #(Tuple2 #(Bit #(32), TV_Vec_Bytes)) f_out <- mkFIFOF;
// ----------------------------------------------------------------
// BEHAVIOR
// BEHAVIOR: MERGING
// v_f_cpu_ins and f_dm_in are merged into f_merged
rule rl_log_trace_RESET (rg_reset_done && (f_trace_data.first.op == TRACE_RESET));
let td <- pop (f_trace_data);
// v_f_cpu_ins are merged in program order (using serialnum)
for (Integer j = 0; j < valueOf (SupSize); j = j + 1)
rule rl_merge_cpu_ins (tpl_1 (v_f_cpu_ins [j].first) == rg_serialnum);
let td = tpl_2 (v_f_cpu_ins [j].first);
v_f_cpu_ins [j].deq;
f_merged.enq (td);
rg_serialnum <= rg_serialnum + 1;
if (verbosity != 0) begin
$display ("%0d: %m.rl_merge_cpu_in [%0d]: serialnum = %0d", cur_cycle, j, rg_serialnum);
end
endrule
// f_dm_ins is merged in at any time
rule rl_merge_dm_in;
// let td <- pop (f_dm_in.first); // Surprise: this gives no type-check error?
let td = f_dm_in.first; f_dm_in.deq;
f_merged.enq (td);
if (verbosity != 0) begin
$display ("%0d: %m.rl_merge_dm_in", cur_cycle);
end
endrule
// ----------------------------------------------------------------
// BEHAVIOR: ENCODING
rule rl_log_trace_RESET (f_merged.first.op == TRACE_RESET);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -70,11 +123,11 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1);
match { .nnN, .xN } = vsubst (nn1, x1, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_GPR_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_GPR_WRITE));
let td <- pop (f_trace_data);
rule rl_log_trace_GPR_WRITE (f_merged.first.op == TRACE_GPR_WRITE);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -88,11 +141,11 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_FPR_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_FPR_WRITE));
let td <- pop (f_trace_data);
rule rl_log_trace_FPR_WRITE (f_merged.first.op == TRACE_FPR_WRITE);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -106,11 +159,11 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_CSR_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_CSR_WRITE));
let td <- pop (f_trace_data);
rule rl_log_trace_CSR_WRITE (f_merged.first.op == TRACE_CSR_WRITE);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -124,11 +177,11 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_MEM_WRITE (rg_reset_done && (f_trace_data.first.op == TRACE_MEM_WRITE));
let td <- pop (f_trace_data);
rule rl_log_trace_MEM_WRITE (f_merged.first.op == TRACE_MEM_WRITE);
let td <- pop (f_merged);
Bit #(2) mem_req_size = td.word1 [1:0];
Byte size_and_mem_req_op = { 2'b0, mem_req_size, te_mem_req_op_Store };
@@ -157,11 +210,11 @@ module mkTV_Encode (TV_Encode_IFC);
//match { .nnN, .xN } = vsubst (nn7, x7, nN, vbN);
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_OTHER (rg_reset_done && (f_trace_data.first.op == TRACE_OTHER));
let td <- pop (f_trace_data);
rule rl_log_trace_OTHER (f_merged.first.op == TRACE_OTHER);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -175,11 +228,14 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
if (verbosity != 0)
$display ("%0d: %m.rl_log_trace_OTHER, pc = %0h", cur_cycle, td.pc);
endrule
rule rl_log_trace_I_RD (rg_reset_done && (f_trace_data.first.op == TRACE_I_RD));
let td <- pop (f_trace_data);
rule rl_log_trace_I_RD (f_merged.first.op == TRACE_I_RD);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -195,30 +251,68 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3);
match { .nnN, .xN } = vsubst (nn3, x3, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
if (verbosity != 0)
$display ("%0d: %m.rl_log_trace_I_RD, pc = %0h", cur_cycle, td.pc);
endrule
rule rl_log_trace_F_RD (rg_reset_done && (f_trace_data.first.op == TRACE_F_RD));
let td <- pop (f_trace_data);
`ifdef ISA_F
// New opcode to track GPR updates due to F/D instructions. Also updates
// the CSR FFLAGS
rule rl_log_trace_F_GRD (f_merged.first.op == TRACE_F_GRD);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
match { .n1, .vb1 } = encode_pc (td.pc);
match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr);
match { .n3, .vb3 } = encode_reg (fv_fpr_regnum (td.rd), td.word1);
match { .n3, .vb3 } = encode_reg (fv_gpr_regnum (td.rd), td.word1);
match { .n4, .vb4 } = encode_reg (fv_csr_regnum (csr_addr_fflags), td.word2);
match { .n5, .vb5 } = encode_reg (fv_csr_regnum (csr_addr_mstatus), td.word4);
match { .nN, .vbN } = encode_byte (te_op_end_group);
// Concatenate components into a single byte vec
match { .nn0, .x0 } = vsubst ( 0, ?, n0, vb0);
match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nnN, .xN } = vsubst (nn2, x2, nN, vbN);
match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5);
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_I_LOAD (rg_reset_done && (f_trace_data.first.op == TRACE_I_LOAD));
let td <- pop (f_trace_data);
// New opcode to track FPR updates due to F/D instructions. Also updates
// the CSRs FFLAGS and MSTATUS
rule rl_log_trace_F_FRD (f_merged.first.op == TRACE_F_FRD);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
match { .n1, .vb1 } = encode_pc (td.pc);
match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr);
match { .n3, .vb3 } = encode_fpr (fv_fpr_regnum (td.rd), td.word5);
match { .n4, .vb4 } = encode_reg (fv_csr_regnum (csr_addr_fflags), td.word2);
match { .n5, .vb5 } = encode_reg (fv_csr_regnum (csr_addr_mstatus), td.word4);
match { .nN, .vbN } = encode_byte (te_op_end_group);
// Concatenate components into a single byte vec
match { .nn0, .x0 } = vsubst ( 0, ?, n0, vb0);
match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5);
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
f_out.enq (tuple2 (nnN, xN));
endrule
`endif
rule rl_log_trace_I_LOAD (f_merged.first.op == TRACE_I_LOAD);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -236,18 +330,20 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_F_LOAD (rg_reset_done && (f_trace_data.first.op == TRACE_F_LOAD));
let td <- pop (f_trace_data);
`ifdef ISA_F
rule rl_log_trace_F_LOAD (f_merged.first.op == TRACE_F_LOAD);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
match { .n1, .vb1 } = encode_pc (td.pc);
match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr);
match { .n3, .vb3 } = encode_reg (fv_fpr_regnum (td.rd), td.word1);
match { .n3, .vb3 } = encode_fpr (fv_fpr_regnum (td.rd), td.word5);
match { .n4, .vb4 } = encode_eaddr (truncate (td.word3));
match { .n5, .vb5 } = encode_reg (fv_csr_regnum (csr_addr_mstatus), td.word4);
match { .nN, .vbN } = encode_byte (te_op_end_group);
// Concatenate components into a single byte vec
@@ -256,16 +352,17 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5);
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
`endif
rule rl_log_trace_STORE (rg_reset_done && (f_trace_data.first.op == TRACE_STORE));
let td <- pop (f_trace_data);
rule rl_log_trace_I_STORE (f_merged.first.op == TRACE_I_STORE);
let td <- pop (f_merged);
let funct3 = instr_funct3 (td.instr); // TODO: what if it's a 16b instr?
let mem_req_size = funct3 [1:0];
let mem_req_size = td.word1 [1:0]; // funct3
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -283,14 +380,39 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_AMO (rg_reset_done && (f_trace_data.first.op == TRACE_AMO));
let td <- pop (f_trace_data);
`ifdef ISA_F
rule rl_log_trace_F_STORE (f_merged.first.op == TRACE_F_STORE);
let td <- pop (f_merged);
let funct3 = instr_funct3 (td.instr); // TODO: what if it's a 16b instr?
let mem_req_size = funct3 [1:0];
let mem_req_size = td.word1 [1:0]; // funct3
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
match { .n1, .vb1 } = encode_pc (td.pc);
match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr);
match { .n3, .vb3 } = encode_fstval (mem_req_size, td.word5);
match { .n4, .vb4 } = encode_eaddr (truncate (td.word3));
match { .nN, .vbN } = encode_byte (te_op_end_group);
// Concatenate components into a single byte vec
match { .nn0, .x0 } = vsubst ( 0, ?, n0, vb0);
match { .nn1, .x1 } = vsubst (nn0, x0, n1, vb1);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
f_out.enq (tuple2 (nnN, xN));
endrule
`endif
rule rl_log_trace_AMO (f_merged.first.op == TRACE_AMO);
let td <- pop (f_merged);
let mem_req_size = td.word4 [1:0]; // funct3
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -310,20 +432,31 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5);
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
if (verbosity != 0)
$display ("%0d: %m.rl_log_trace_AMO, pc = %0h", cur_cycle, td.pc);
endrule
rule rl_log_trace_CSRRX (rg_reset_done && (f_trace_data.first.op == TRACE_CSRRX));
let td <- pop (f_trace_data);
rule rl_log_trace_CSRRX (f_merged.first.op == TRACE_CSRRX);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
match { .n1, .vb1 } = encode_pc (td.pc);
match { .n2, .vb2 } = encode_instr (td.instr_sz, td.instr);
match { .n3, .vb3 } = encode_reg (fv_gpr_regnum (td.rd), td.word1);
match { .n4, .vb4 } = ((td.word2 == 0)
? tuple2 (0, ?) // CSR was not written
: encode_reg (fv_csr_regnum (truncate (td.word3)), td.word4));
Bool csr_written = (td.word2 [0] == 1'b1);
match { .n4, .vb4 } = (csr_written
? encode_reg (fv_csr_regnum (truncate (td.word3)), td.word4)
: tuple2 (0, ?));
`ifdef ISA_F
// MSTATUS.FS and .SD also updated if CSR instr wrote FFLAGS, FRM or FCSR
Bool mstatus_written = (td.word2 [1] == 1'b1);
match { .n5, .vb5 } = (mstatus_written
? encode_reg (fv_csr_regnum (csr_addr_mstatus), td.word5)
: tuple2 (0, ?));
`endif
match { .nN, .vbN } = encode_byte (te_op_end_group);
// Concatenate components into a single byte vec
@@ -332,13 +465,18 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn2, .x2 } = vsubst (nn1, x1, n2, vb2);
match { .nn3, .x3 } = vsubst (nn2, x2, n3, vb3);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
`ifdef ISA_F
match { .nn5, .x5 } = vsubst (nn4, x4, n5, vb5);
match { .nnN, .xN } = vsubst (nn5, x5, nN, vbN);
`else
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
`endif
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_TRAP (rg_reset_done && (f_trace_data.first.op == TRACE_TRAP));
let td <- pop (f_trace_data);
rule rl_log_trace_TRAP (f_merged.first.op == TRACE_TRAP);
let td <- pop (f_merged);
// Use new priv mode to decide which trap regs are updated (M, S or U priv)
Priv_Mode priv = truncate (td.rd);
@@ -347,28 +485,28 @@ module mkTV_Encode (TV_Encode_IFC);
CSR_Addr csr_addr_epc = csr_addr_mepc;
CSR_Addr csr_addr_tval = csr_addr_mtval;
if (priv == s_Priv_Mode) begin
csr_addr_status = csr_addr_sstatus;
csr_addr_cause = csr_addr_scause;
csr_addr_epc = csr_addr_sepc;
csr_addr_tval = csr_addr_stval;
csr_addr_status = csr_addr_sstatus;
csr_addr_cause = csr_addr_scause;
csr_addr_epc = csr_addr_sepc;
csr_addr_tval = csr_addr_stval;
end
else if (priv == u_Priv_Mode) begin
csr_addr_status = csr_addr_ustatus;
csr_addr_cause = csr_addr_ucause;
csr_addr_epc = csr_addr_uepc;
csr_addr_tval = csr_addr_utval;
csr_addr_status = csr_addr_ustatus;
csr_addr_cause = csr_addr_ucause;
csr_addr_epc = csr_addr_uepc;
csr_addr_tval = csr_addr_utval;
end
// Omit the instruction if cause is instruction fault since the instruction is then bogus
Bool is_instr_fault = ( (truncate (td.word2) == exc_code_INSTR_ACCESS_FAULT)
|| (truncate (td.word2) == exc_code_INSTR_PAGE_FAULT));
|| (truncate (td.word2) == exc_code_INSTR_PAGE_FAULT));
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
match { .n1, .vb1 } = encode_pc (td.pc);
match { .n2, .vb2 } = (is_instr_fault
? tuple2 (0, ?)
: encode_instr (td.instr_sz, td.instr));
? tuple2 (0, ?)
: encode_instr (td.instr_sz, td.instr));
match { .n3, .vb3 } = encode_priv (td.rd);
match { .n4, .vb4 } = encode_reg (fv_csr_regnum (csr_addr_status), td.word1);
match { .n5, .vb5 } = encode_reg (fv_csr_regnum (csr_addr_cause), td.word2);
@@ -387,11 +525,11 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn7, .x7 } = vsubst (nn6, x6, n7, vb7);
match { .nnN, .xN } = vsubst (nn7, x7, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_INTR (rg_reset_done && (f_trace_data.first.op == TRACE_INTR));
let td <- pop (f_trace_data);
rule rl_log_trace_INTR (f_merged.first.op == TRACE_INTR);
let td <- pop (f_merged);
// Use new priv mode to decide which trap regs are updated (M, S or U priv)
Priv_Mode priv = truncate (td.rd);
@@ -400,16 +538,16 @@ module mkTV_Encode (TV_Encode_IFC);
CSR_Addr csr_addr_epc = csr_addr_mepc;
CSR_Addr csr_addr_tval = csr_addr_mtval;
if (priv == s_Priv_Mode) begin
csr_addr_status = csr_addr_sstatus;
csr_addr_cause = csr_addr_scause;
csr_addr_epc = csr_addr_sepc;
csr_addr_tval = csr_addr_stval;
csr_addr_status = csr_addr_sstatus;
csr_addr_cause = csr_addr_scause;
csr_addr_epc = csr_addr_sepc;
csr_addr_tval = csr_addr_stval;
end
else if (priv == u_Priv_Mode) begin
csr_addr_status = csr_addr_ustatus;
csr_addr_cause = csr_addr_ucause;
csr_addr_epc = csr_addr_uepc;
csr_addr_tval = csr_addr_utval;
csr_addr_status = csr_addr_ustatus;
csr_addr_cause = csr_addr_ucause;
csr_addr_epc = csr_addr_uepc;
csr_addr_tval = csr_addr_utval;
end
// Encode components of td into byte vecs
@@ -432,11 +570,11 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn6, .x6 } = vsubst (nn5, x5, n6, vb6);
match { .nnN, .xN } = vsubst (nn6, x6, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
rule rl_log_trace_RET (rg_reset_done && (f_trace_data.first.op == TRACE_RET));
let td <- pop (f_trace_data);
rule rl_log_trace_RET (f_merged.first.op == TRACE_RET);
let td <- pop (f_merged);
// Encode components of td into byte vecs
match { .n0, .vb0 } = encode_byte (te_op_begin_group);
@@ -454,17 +592,15 @@ module mkTV_Encode (TV_Encode_IFC);
match { .nn4, .x4 } = vsubst (nn3, x3, n4, vb4);
match { .nnN, .xN } = vsubst (nn4, x4, nN, vbN);
f_vb.enq (tuple2 (nnN, xN));
f_out.enq (tuple2 (nnN, xN));
endrule
// ----------------------------------------------------------------
// INTERFACE
method Action reset ();
endmethod
interface Put trace_data_in = toPut (f_trace_data);
interface Get tv_vb_out = toGet (f_vb);
interface v_cpu_in = map (toPut, v_f_cpu_ins);
interface dm_in = toPut (f_dm_in);
interface out = toGet (f_out);
endmodule
// ****************************************************************
@@ -546,15 +682,15 @@ endfunction
// vsubst substitutes vb1[j1:j1+j2-1] with vb2[0:j2-1]
function Tuple2 #(Bit #(32),
Vector #(TV_VB_SIZE, Byte))
Vector #(TV_VB_SIZE, Byte))
vsubst (Bit #(32) j1, Vector #(TV_VB_SIZE, Byte) vb1,
Bit #(32) j2, Vector #(m, Byte) vb2);
Bit #(32) j2, Vector #(m, Byte) vb2);
function Byte f (Integer j);
Byte x = vb1 [j];
Bit #(32) jj = fromInteger (j);
if ((j1 <= jj) && (jj < j1 + j2))
x = vb2 [jj - j1];
x = vb2 [jj - j1];
return x;
endfunction
@@ -648,6 +784,29 @@ function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_reg (Bit #(16) r
return tuple2 (n, vb);
endfunction
`ifdef ISA_F
function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_fpr (Bit #(16) regnum, WordFL word);
Vector #(TV_VB_SIZE, Byte) vb = newVector;
Bit #(32) n = 0;
vb [0] = te_op_full_reg;
vb [1] = regnum [7:0];
vb [2] = regnum [15:8];
vb [3] = word[7:0];
vb [4] = word [15:8];
vb [5] = word [23:16];
vb [6] = word [31:24];
n = 7;
`ifdef ISA_D
vb [7] = word [39:32];
vb [8] = word [47:40];
vb [9] = word [55:48];
vb [10] = word [63:56];
n = 11;
`endif
return tuple2 (n, vb);
endfunction
`endif
function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_priv (Bit #(5) priv);
Vector #(TV_VB_SIZE, Byte) vb = newVector;
vb [0] = te_op_addl_state;
@@ -700,11 +859,11 @@ function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_stval (MemReqSiz
Vector #(TV_VB_SIZE, Byte) vb = newVector;
vb [0] = te_op_addl_state;
vb [1] = case (mem_req_size)
f3_SIZE_B: te_op_addl_state_data8;
f3_SIZE_H: te_op_addl_state_data16;
f3_SIZE_W: te_op_addl_state_data32;
f3_SIZE_D: te_op_addl_state_data64;
endcase;
f3_SIZE_B: te_op_addl_state_data8;
f3_SIZE_H: te_op_addl_state_data16;
f3_SIZE_W: te_op_addl_state_data32;
f3_SIZE_D: te_op_addl_state_data64;
endcase;
vb [2] = word [7:0];
vb [3] = word [15:8];
vb [4] = word [23:16];
@@ -719,6 +878,31 @@ function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_stval (MemReqSiz
return tuple2 (n, vb);
endfunction
`ifdef ISA_F
function Tuple2 #(Bit #(32), Vector #(TV_VB_SIZE, Byte)) encode_fstval (MemReqSize mem_req_size, WordFL word);
Vector #(TV_VB_SIZE, Byte) vb = newVector;
vb [0] = te_op_addl_state;
vb [1] = case (mem_req_size)
f3_SIZE_B: te_op_addl_state_data8; // not possible
f3_SIZE_H: te_op_addl_state_data16; // not possible
f3_SIZE_W: te_op_addl_state_data32;
f3_SIZE_D: te_op_addl_state_data64;
endcase;
vb [2] = word [7:0];
vb [3] = word [15:8];
vb [4] = word [23:16];
vb [5] = word [31:24];
`ifdef ISA_D
vb [6] = word [39:32];
vb [7] = word [47:40];
vb [8] = word [55:48];
vb [9] = word [63:56];
`endif
Bit #(32) n = (1 << pack(mem_req_size)) + 2;
return tuple2 (n, vb);
endfunction
`endif
// ================================================================
endpackage

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2018-2019 Bluespec, Inc. All Rights Reserved.
// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved.
package TV_Taps;
@@ -73,24 +73,35 @@ module mkDM_Mem_Tap (DM_Mem_Tap_IFC);
master_xactor.i_wr_data.enq (wr_data);
// Tap
Bit #(64) paddr = ?;
Bit #(64) stval = ?;
Bit #(64) paddr = ?;
Bit #(64) stval = ?;
Integer sh = 0;
Fabric_Data mask = 0;
MemReqSize sz = ?;
case (wr_data.wstrb)
`ifdef FABRIC64
if (wr_data.wstrb == 'h0f) begin
paddr = zeroExtend (wr_addr.awaddr);
stval = (wr_data.wdata & 'h_FFFF_FFFF);
end
else if (wr_data.wstrb == 'hf0) begin
paddr = zeroExtend (wr_addr.awaddr);
stval = ((wr_data.wdata >> 32) & 'h_FFFF_FFFF);
end
else
dynamicAssert(False, "mkDM_Mem_Tap: unsupported byte enables");
`else
'hFF: begin sh= 0; mask = 'hFFFF_FFFF_FFFF_FFFF; sz=f3_SIZE_D; end
'hF0: begin sh=32; mask = 'hFFFF_FFFF; sz=f3_SIZE_W; end
'hC0: begin sh=48; mask = 'hFFFF; sz=f3_SIZE_H; end
'h30: begin sh=32; mask = 'hFFFF; sz=f3_SIZE_H; end
'h80: begin sh=56; mask = 'hFF; sz=f3_SIZE_B; end
'h40: begin sh=48; mask = 'hFF; sz=f3_SIZE_B; end
'h20: begin sh=40; mask = 'hFF; sz=f3_SIZE_B; end
'h10: begin sh=32; mask = 'hFF; sz=f3_SIZE_B; end
`endif
'hF: begin sh= 0; mask = 'hFFFF_FFFF; sz=f3_SIZE_W; end
'hC: begin sh=16; mask = 'hFFFF; sz=f3_SIZE_H; end
'h3: begin sh= 0; mask = 'hFFFF; sz=f3_SIZE_H; end
'h8: begin sh=24; mask = 'hFF; sz=f3_SIZE_B; end
'h4: begin sh=16; mask = 'hFF; sz=f3_SIZE_B; end
'h2: begin sh= 8; mask = 'hFF; sz=f3_SIZE_B; end
'h1: begin sh= 0; mask = 'hFF; sz=f3_SIZE_B; end
default: dynamicAssert(False, "mkDM_Mem_Tap: unsupported byte enables");
endcase
paddr = zeroExtend (wr_addr.awaddr);
stval = zeroExtend (wr_data.wdata);
`endif
Trace_Data td = mkTrace_MEM_WRITE (f3_SIZE_W, truncate (stval), paddr);
stval = ((zeroExtend (wr_data.wdata) >> sh) & mask);
Trace_Data td = mkTrace_MEM_WRITE (sz, truncate (stval), paddr);
f_trace_data.enq (td);
endrule
@@ -139,9 +150,9 @@ module mkDM_GPR_Tap (DM_GPR_Tap_IFC);
// Snoop writes and send trace data to TV
if (req.write) begin
Trace_Data td;
td = mkTrace_GPR_WRITE (req.address, req.data);
f_trace_data.enq (td);
Trace_Data td;
td = mkTrace_GPR_WRITE (req.address, req.data);
f_trace_data.enq (td);
end
endrule
@@ -181,9 +192,9 @@ module mkDM_FPR_Tap (DM_FPR_Tap_IFC);
// Snoop writes and send trace data to TV
if (req.write) begin
Trace_Data td;
td = mkTrace_FPR_WRITE (req.address, req.data);
f_trace_data.enq (td);
Trace_Data td;
td = mkTrace_FPR_WRITE (req.address, req.data);
f_trace_data.enq (td);
end
endrule
@@ -223,8 +234,8 @@ module mkDM_CSR_Tap (DM_CSR_Tap_IFC);
// Snoop writes and send trace data to TV
if (req.write) begin
Trace_Data td = mkTrace_CSR_WRITE (req.address, req.data);
f_trace_data.enq (td);
Trace_Data td = mkTrace_CSR_WRITE (req.address, req.data);
f_trace_data.enq (td);
end
endrule

View File

@@ -0,0 +1,60 @@
// Copyright (c) 2020 Bluespec, Inc. All Rights Reserved.
package Trace_Data2;
// ================================================================
// Project imports
// ----------------
// From RISCY-OOO
import Types :: *;
import ProcTypes :: *;
import ReorderBuffer :: *;
// ================================================================
// This struct has a subset of the fields of struct ToReorderBuffer in
// Toooba/RISCY-OOO, to be encoded and emitted for Tandem
// Verification.
// In RISCY-OOO's CommitStage, when we dequeue (retire) an entry
// (struct ToReorderBuffer), we simply copy out these fields and
// enqueue this struct into a FIFO. All transformations/encoding for
// TV are done on the dequeue side of the FIFO. Thus, this should not
// add to the critical path or scheduling requirements of CommitStage.
typedef struct {
// TV message serial number
Bit #(64) serial_num;
// For asynchronous CSR updates (e.g., MIP change on external interrupt)
Maybe #(Tuple2 #(Bit #(12), Data)) maybe_csr_upd;
// Remaining fields relevant only if maybe_csr_upd is Invalid
Addr pc;
Bit #(32) orig_inst; // original 16b or 32b instruction ([1:0] will distinguish 16b or 32b)
IType iType;
Maybe#(ArchRIndx) dst; // Invalid, GPR or FPR destination ("Rd")
Data dst_data;
Data store_data; // For mem instrs that store data
ByteEn store_data_BE;
Maybe #(CSR) csr;
Maybe #(Trap) trap;
Addr tval; // in case of trap
PPCVAddrCSRData ppc_vaddr_csrData;
Bit #(5) fflags;
Bool will_dirty_fpu_state; // True means 2'b11 will be written to FS
Data mstatus; // For Fpu ops, since [MX] bit may have changed
// Trap updates
Bit #(2) prv;
Addr tvec;
Data status;
Data cause;
Data epc;
} Trace_Data2
deriving (Bits, Eq, FShow);
// ================================================================
endpackage

View File

@@ -0,0 +1,252 @@
// Copyright (c) 2020 Bluespec, Inc. All Rights Reserved.
package Trace_Data2_to_Trace_Data;
// ================================================================
// This package defines a module to transform a stream of Trace_Data2
// to a stream of (serial_num, Trace_Data)
// ================================================================
// BSV library imports
import FIFOF :: *;
import GetPut :: *;
// ----------------
// BSV additional libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
// ================================================================
// Project riscy-ooo imports (for fields in Trace_Data2)
import Types :: *;
import ProcTypes :: *;
import ReorderBuffer :: *; // for PPCVAddrCSRData
// ================================================================
// Project Toooba imports
import ISA_Decls :: *;
import TV_Info :: *;
import Trace_Data2 :: *;
// ================================================================
interface Trace_Data2_to_Trace_Data_IFC;
// From Toooba's CommitStage
interface Put #(Trace_Data2) in;
// To Trace Encoder
interface Get #(Tuple2 #(Bit #(64), Trace_Data)) out;
endinterface
// ================================================================
(* synthesize *)
module mkTrace_Data2_to_Trace_Data (Trace_Data2_to_Trace_Data_IFC);
Integer verbosity = 1; // for debugging
// Input stream
FIFOF #(Trace_Data2) f_in <- mkFIFOF;
// Output stream
FIFOF #(Tuple2 #(Bit #(64), Trace_Data)) f_out <- mkFIFOF;
// ================================================================
// Transformer: Trace_Data2 -> (serial_num, Trace_Data)
function ActionValue #(Tuple2 #(Bit #(64), Trace_Data)) fav_td2_to_td (Trace_Data2 td2);
actionvalue
let serial_num = td2.serial_num;
Trace_Data td = ?;
ISize isize = ((td2.orig_inst [1:0] == 2'b11) ? ISIZE32BIT : ISIZE16BIT);
Addr fall_thru_PC = td2.pc + ((td2.orig_inst [1:0] == 2'b11) ? 4 : 2);
Bit #(3) st_funct3 = (td2.store_data_BE [7] ? 3'b_011 // Doubleword
: (td2.store_data_BE [3] ? 3'b_010 // Word
: (td2.store_data_BE [1] ? 3'b_001 // HalfWord
: 3'b000))); // Byte
Bit #(5) gpr_rd = 0;
if (td2.dst matches tagged Valid (tagged Gpr .r)) gpr_rd = r;
if (serial_num == 0)
td = mkTrace_RESET;
else if (td2.maybe_csr_upd matches tagged Valid { .csr_addr, .csr_value })
td = mkTrace_CSR_WRITE (csr_addr, csr_value);
else if (isValid (td2.trap))
td = mkTrace_TRAP (td2.tvec,
isize,
td2.orig_inst,
td2.prv,
td2.status,
td2.cause,
td2.epc,
td2.tval);
else if (td2.ppc_vaddr_csrData matches tagged PPC .target_addr
&&& (td2.iType == Br))
td = mkTrace_OTHER (target_addr, isize, td2.orig_inst);
else if (td2.ppc_vaddr_csrData matches tagged PPC .target_addr
&&& ( (td2.iType == J)
|| (td2.iType == Jr)))
td = mkTrace_I_RD (target_addr,
isize,
td2.orig_inst,
gpr_rd,
td2.dst_data); // return-pc
else if ( (td2.iType == Alu)
|| (td2.iType == Auipc))
td = mkTrace_I_RD (fall_thru_PC,
isize,
td2.orig_inst,
gpr_rd,
td2.dst_data); // rd_val
else if (td2.dst matches tagged Valid (tagged Fpu .fpr_rd)
&&& (td2.iType == Fpu))
td = mkTrace_F_FRD (fall_thru_PC,
isize,
td2.orig_inst,
fpr_rd,
td2.dst_data, // rdval
td2.fflags,
td2.mstatus); // [FX] updated
else if (td2.iType == Fpu)
td = mkTrace_F_GRD (fall_thru_PC,
isize,
td2.orig_inst,
gpr_rd,
td2.dst_data, // rdval
td2.fflags,
td2.mstatus); // [FX] updated
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
&&& td2.dst matches tagged Valid (tagged Fpu .fpr_rd)
&&& (td2.iType == Ld))
td = mkTrace_F_LOAD (fall_thru_PC,
isize,
td2.orig_inst,
fpr_rd,
td2.dst_data, // rd_val
eaddr,
td2.mstatus);
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
&&& (td2.iType == Ld))
td = mkTrace_I_LOAD (fall_thru_PC,
isize,
td2.orig_inst,
gpr_rd,
td2.dst_data, // rd_val
eaddr);
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
&&& (td2.iType == St))
td = mkTrace_I_STORE (fall_thru_PC,
st_funct3,
isize,
td2.orig_inst,
td2.store_data, // rs2_val
eaddr);
else if (td2.ppc_vaddr_csrData matches tagged CSRData .csr_data
&&& (td2.iType == Csr))
begin
Bit #(3) funct3 = td2.orig_inst [14:12];
Bit #(5) rs1_or_imm = td2.orig_inst [19:15];
Bool csr_valid = False;
CSR_Addr csr_addr = 0;
if (td2.csr matches tagged Valid .c) begin
csr_addr = pack (c);
csr_valid = ( (funct3 [1:0] == 2'b01) // CSRRW, CSRRWI
|| ( ( (funct3 [1:0] == 2'b10) // CSRRS, CSRRSI
|| (funct3 [1:0] == 2'b11)) // CSRRC, CSRRCI
&& (rs1_or_imm != 0)));
end
td = mkTrace_CSRRX (fall_thru_PC,
isize,
td2.orig_inst,
gpr_rd,
td2.dst_data, // rdval
csr_valid,
csr_addr,
csr_data,
// For CSR writes to FFLAGS/FRM/FCSR, also changes MSTATUS
td2.will_dirty_fpu_state,
td2.mstatus);
end
else if ( (td2.iType == Mret)
|| (td2.iType == Sret))
td = mkTrace_RET (td2.pc, isize, td2.orig_inst, td2.prv, td2.status);
else if ( (td2.iType == Fence)
|| (td2.iType == FenceI)
|| (td2.iType == SFence)
|| (td2.iType == Ecall) // Handled by TRAP above?
|| (td2.iType == Ebreak)) // Handled by TRAP above?
td = mkTrace_OTHER (fall_thru_PC, isize, td2.orig_inst);
else if (td2.ppc_vaddr_csrData matches tagged VAddr .eaddr
&&& ( (td2.iType == Amo)
|| (td2.iType == Lr)
|| (td2.iType == Sc)))
td = mkTrace_AMO (fall_thru_PC,
st_funct3,
isize,
td2.orig_inst,
gpr_rd,
td2.dst_data, // rd_val
td2.store_data, // rs2_val
eaddr);
else if ( (td2.iType == Unsupported)
|| (td2.iType == Nop)
|| (td2.iType == Interrupt))
td = mkTrace_OTHER (fall_thru_PC, isize, td2.orig_inst);
else begin
if (verbosity > 0) begin
$display (" fav_td2_to_td: TBD: Unknown iType: Using mkTrace_OTHER for now");
$display (" ", fshow (td2));
end
td = mkTrace_OTHER (fall_thru_PC, isize, td2.orig_inst);
end
return tuple2 (serial_num, td);
endactionvalue
endfunction
// ================================================================
// RULES
rule rl_td2_to_td;
Trace_Data2 td2 <- pop (f_in);
if (verbosity > 1)
$display ("%0d: %m.rl_td2_to_td: serial_num:%0d PC:0x%0h instr:0x%08h",
cur_cycle, td2.serial_num, td2.pc, td2.orig_inst,
" iType:", fshow (td2.iType));
match { .serial_num, .td } <- fav_td2_to_td (td2);
f_out.enq (tuple2 (serial_num, td));
endrule
// ================================================================
// INTERFACE
interface in = toPut (f_in);
interface out = toGet (f_out);
endmodule
// ================================================================
endpackage

View File

@@ -58,18 +58,18 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
Reg #(Bool) rg_start_reg_access <- mkReg (False);
// FIFOs for request/response to access GPRs
FIFOF #(DM_CPU_Req #(5, XLEN)) f_hart0_gpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_gpr_rsps <- mkFIFOF1;
FIFOF #(DM_CPU_Req #(5, XLEN)) f_hart0_gpr_reqs <- mkFIFOF;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_gpr_rsps <- mkFIFOF;
// FIFOs for request/response to access FPRs
`ifdef ISA_F
FIFOF #(DM_CPU_Req #(5, FLEN)) f_hart0_fpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(FLEN)) f_hart0_fpr_rsps <- mkFIFOF1;
FIFOF #(DM_CPU_Req #(5, FLEN)) f_hart0_fpr_reqs <- mkFIFOF;
FIFOF #(DM_CPU_Rsp #(FLEN)) f_hart0_fpr_rsps <- mkFIFOF;
`endif
// FIFOs for request/response to access CSRs
FIFOF #(DM_CPU_Req #(12, XLEN)) f_hart0_csr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_csr_rsps <- mkFIFOF1;
FIFOF #(DM_CPU_Req #(12, XLEN)) f_hart0_csr_reqs <- mkFIFOF;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_hart0_csr_rsps <- mkFIFOF;
// ----------------------------------------------------------------
// rg_data0
@@ -89,33 +89,36 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
Reg #(Bool) rg_abstractcs_busy <- mkRegU;
Reg #(DM_abstractcs_cmderr) rg_abstractcs_cmderr <- mkRegU;
Bit #(5) abstractcs_progsize = 0;
Bit #(5) abstractcs_datacount = 0;
// Size of program buffer, in 32b words
Bit #(5) abstractcs_progbufsize = 0;
// Number of data registers implemented (rg_data0, rg_data1)
Bit #(4) abstractcs_datacount = ((xlen == 32) ? 1 : 2);
DM_Word virt_rg_abstractcs = {3'b0,
abstractcs_progsize,
11'b0,
pack (rg_abstractcs_busy),
1'b0,
pack (rg_abstractcs_cmderr),
3'b0,
abstractcs_datacount};
abstractcs_progbufsize,
11'b0,
pack (rg_abstractcs_busy),
1'b0,
pack (rg_abstractcs_cmderr),
4'b0,
abstractcs_datacount};
function Action fa_rg_abstractcs_write (DM_Word dm_word);
action
if (rg_abstractcs_busy) begin
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_BUSY;
$display ("%0d: DM_Abstract_Commands.write: [abstractcs] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" DM is busy with a previous abstract command");
end
else if (fn_abstractcs_cmderr (dm_word) != DM_ABSTRACTCS_CMDERR_NONE) begin
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_NONE;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write [abstractcs]: clearing cmderr", cur_cycle);
end
else begin
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write [abstractcs]: cmderr unchanged", cur_cycle);
end
if (rg_abstractcs_busy) begin
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_BUSY;
$display ("%0d: DM_Abstract_Commands.write: [abstractcs] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" DM is busy with a previous abstract command");
end
else if (fn_abstractcs_cmderr (dm_word) != DM_ABSTRACTCS_CMDERR_NONE) begin
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_NONE;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write [abstractcs]: clearing cmderr", cur_cycle);
end
else begin
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write [abstractcs]: cmderr unchanged", cur_cycle);
end
endaction
endfunction
@@ -141,78 +144,78 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
function Action fa_rg_command_write (DM_Word dm_word);
action
// TODO: check that CPU is halted, else set cmderr = DM_ABSTRACTCS_CMDERR_HALT_RESUME
// TODO: check that CPU is halted, else set cmderr = DM_ABSTRACTCS_CMDERR_HALT_RESUME
DM_abstractcs_cmderr cmderr = rg_abstractcs_cmderr;
let size = fn_command_access_reg_size (dm_word);
DM_abstractcs_cmderr cmderr = rg_abstractcs_cmderr;
let size = fn_command_access_reg_size (dm_word);
// Ignore if 'cmderr' is non-zero
if (cmderr != DM_ABSTRACTCS_CMDERR_NONE) begin
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" Ignoring since 'cmderr' is 0x%0h", cmderr);
end
else begin
if (rg_abstractcs_busy) begin
cmderr = DM_ABSTRACTCS_CMDERR_BUSY;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" DM is busy with a previous abstract command");
end
// Ignore if 'cmderr' is non-zero
if (cmderr != DM_ABSTRACTCS_CMDERR_NONE) begin
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" Ignoring since 'cmderr' is 0x%0h", cmderr);
end
else begin
if (rg_abstractcs_busy) begin
cmderr = DM_ABSTRACTCS_CMDERR_BUSY;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" DM is busy with a previous abstract command");
end
// Only 'Access Reg' cmdtype is supported
else if (fn_command_cmdtype (dm_word) != DM_COMMAND_CMDTYPE_ACCESS_REG) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" ", fshow (fn_command_cmdtype (dm_word)), " not supported");
end
// Only 'Access Reg' cmdtype is supported
else if (fn_command_cmdtype (dm_word) != DM_COMMAND_CMDTYPE_ACCESS_REG) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" ", fshow (fn_command_cmdtype (dm_word)), " not supported");
end
`ifdef RV32
// Only lower 32-bit access is supported
else if (size != DM_COMMAND_ACCESS_REG_SIZE_LOWER32) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, ",
fshow (fn_command_access_reg_size (dm_word)), " not supported in RV32 mode");
end
// Only lower 32-bit access is supported
else if (size != DM_COMMAND_ACCESS_REG_SIZE_LOWER32) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, ",
fshow (fn_command_access_reg_size (dm_word)), " not supported in RV32 mode");
end
`endif
`ifdef RV64
// Only lower 32-bit and 64-bit access is supported
else if (size != DM_COMMAND_ACCESS_REG_SIZE_LOWER64)
begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, ",
fshow (fn_command_access_reg_size (dm_word)), " not supported in RV64 mode");
end
// Only lower 32-bit and 64-bit access is supported
else if (size != DM_COMMAND_ACCESS_REG_SIZE_LOWER64)
begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, ",
fshow (fn_command_access_reg_size (dm_word)), " not supported in RV64 mode");
end
`endif
// 'postexec' is not supported
else if (fn_command_access_reg_postexec (dm_word) == True) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, postexec not supported");
end
// 'postexec' is not supported
else if (fn_command_access_reg_postexec (dm_word) == True) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, postexec not supported");
end
// non-'transfer' is not supported
else if (fn_command_access_reg_transfer (dm_word) == False) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, no-transfer not supported");
end
// non-'transfer' is not supported
else if (fn_command_access_reg_transfer (dm_word) == False) begin
cmderr = DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: ERROR", cur_cycle, dm_word);
$display (" For DM_COMMAND_CMDTYPE_ACCESS_REG, no-transfer not supported");
end
else begin
Bool is_write = fn_command_access_reg_write (dm_word);
Bit #(13) regno = truncate (fn_command_access_reg_regno (dm_word));
else begin
Bool is_write = fn_command_access_reg_write (dm_word);
Bit #(13) regno = truncate (fn_command_access_reg_regno (dm_word));
rg_command_access_reg_write <= is_write;
rg_command_access_reg_regno <= regno;
rg_abstractcs_busy <= True;
rg_start_reg_access <= True;
cmderr = DM_ABSTRACTCS_CMDERR_NONE;
rg_command_access_reg_write <= is_write;
rg_command_access_reg_regno <= regno;
rg_abstractcs_busy <= True;
rg_start_reg_access <= True;
cmderr = DM_ABSTRACTCS_CMDERR_NONE;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write: [command] <= 0x%08h: OKAY", cur_cycle, dm_word);
end
rg_abstractcs_cmderr <= cmderr;
end
end
rg_abstractcs_cmderr <= cmderr;
end
endaction
endfunction
@@ -220,14 +223,14 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Register reads and writes
Bool is_csr = ( (fromInteger (dm_command_access_reg_regno_csr_0) <= rg_command_access_reg_regno)
&& (rg_command_access_reg_regno <= fromInteger (dm_command_access_reg_regno_csr_FFF)));
&& (rg_command_access_reg_regno <= fromInteger (dm_command_access_reg_regno_csr_FFF)));
Bool is_gpr = ( (fromInteger (dm_command_access_reg_regno_gpr_0) <= rg_command_access_reg_regno)
&& (rg_command_access_reg_regno <= fromInteger (dm_command_access_reg_regno_gpr_1F)));
&& (rg_command_access_reg_regno <= fromInteger (dm_command_access_reg_regno_gpr_1F)));
`ifdef ISA_F
Bool is_fpr = ( (fromInteger (dm_command_access_reg_regno_fpr_0) <= rg_command_access_reg_regno)
&& (rg_command_access_reg_regno <= fromInteger (dm_command_access_reg_regno_fpr_1F)));
&& (rg_command_access_reg_regno <= fromInteger (dm_command_access_reg_regno_fpr_1F)));
`else
Bool is_fpr = False;
`endif
@@ -240,33 +243,33 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Write CSR
rule rl_csr_write_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& rg_command_access_reg_write
&& is_csr);
&& rg_start_reg_access
&& rg_command_access_reg_write
&& is_csr);
let req = DM_CPU_Req {write: True,
address: csr_addr,
address: csr_addr,
`ifdef RV32
data: rg_data0
data: rg_data0
`endif
`ifdef RV64
data: {rg_data1, rg_data0}
data: {rg_data1, rg_data0}
`endif
};
};
f_hart0_csr_reqs.enq (req);
rg_start_reg_access <= False;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_csr_write_start: ", cur_cycle, fshow (req));
$display ("%0d: DM_Abstract_Commands.rl_csr_write_start: ", cur_cycle, fshow (req));
endrule
// ----------------
rule rl_csr_write_finish (rg_abstractcs_busy
&& rg_command_access_reg_write
&& is_csr);
&& rg_command_access_reg_write
&& is_csr);
let rsp <- pop (f_hart0_csr_rsps);
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_csr_write_finish: ", cur_cycle, fshow (rsp));
$display ("%0d: DM_Abstract_Commands.rl_csr_write_finish: ", cur_cycle, fshow (rsp));
rg_abstractcs_cmderr <= (rsp.ok ? DM_ABSTRACTCS_CMDERR_NONE : DM_ABSTRACTCS_CMDERR_HALT_RESUME);
rg_abstractcs_busy <= False;
@@ -276,26 +279,26 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Read CSR
rule rl_csr_read_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& is_csr);
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& is_csr);
Bit #(XLEN) data = ?;
let req = DM_CPU_Req {write: False, address: csr_addr, data: data};
f_hart0_csr_reqs.enq (req);
rg_start_reg_access <= False;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_csr_read_start: ", cur_cycle, fshow (req));
$display ("%0d: DM_Abstract_Commands.rl_csr_read_start: ", cur_cycle, fshow (req));
endrule
// ----------------
rule rl_csr_read_finish ( rg_abstractcs_busy
&& (! rg_command_access_reg_write)
&& is_csr);
&& (! rg_command_access_reg_write)
&& is_csr);
let rsp <- pop (f_hart0_csr_rsps);
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_csr_read_finish: ", cur_cycle, fshow (rsp));
$display ("%0d: DM_Abstract_Commands.rl_csr_read_finish: ", cur_cycle, fshow (rsp));
rg_abstractcs_cmderr <= (rsp.ok ? DM_ABSTRACTCS_CMDERR_NONE : DM_ABSTRACTCS_CMDERR_HALT_RESUME);
`ifdef RV32
@@ -312,32 +315,32 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Write GPR
rule rl_gpr_write_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& rg_command_access_reg_write
&& is_gpr);
&& rg_start_reg_access
&& rg_command_access_reg_write
&& is_gpr);
let req = DM_CPU_Req {write: True,
address: gpr_addr,
address: gpr_addr,
`ifdef RV32
data: rg_data0
data: rg_data0
`endif
`ifdef RV64
data: {rg_data1, rg_data0}
data: {rg_data1, rg_data0}
`endif
};
};
f_hart0_gpr_reqs.enq (req);
rg_start_reg_access <= False;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_gpr_write_start: ", cur_cycle, fshow (req));
$display ("%0d: DM_Abstract_Commands.rl_gpr_write_start: ", cur_cycle, fshow (req));
endrule
// ----------------
rule rl_gpr_write_finish ( rg_abstractcs_busy
&& rg_command_access_reg_write
&& is_gpr);
&& rg_command_access_reg_write
&& is_gpr);
let rsp <- pop (f_hart0_gpr_rsps);
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_gpr_write_finish: ", cur_cycle, fshow (rsp));
$display ("%0d: DM_Abstract_Commands.rl_gpr_write_finish: ", cur_cycle, fshow (rsp));
rg_abstractcs_cmderr <= (rsp.ok ? DM_ABSTRACTCS_CMDERR_NONE : DM_ABSTRACTCS_CMDERR_HALT_RESUME);
rg_abstractcs_busy <= False;
@@ -347,26 +350,26 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Read GPR
rule rl_gpr_read_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& is_gpr);
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& is_gpr);
Bit #(XLEN) data = ?;
let req = DM_CPU_Req {write: False, address: gpr_addr, data: data };
f_hart0_gpr_reqs.enq (req);
rg_start_reg_access <= False;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_gpr_read_start: ", cur_cycle, fshow (req));
$display ("%0d: DM_Abstract_Commands.rl_gpr_read_start: ", cur_cycle, fshow (req));
endrule
// ----------------
rule rl_gpr_read_finish ( rg_abstractcs_busy
&& (! rg_command_access_reg_write)
&& is_gpr);
&& (! rg_command_access_reg_write)
&& is_gpr);
let rsp <- pop (f_hart0_gpr_rsps);
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_gpr_read_finish: ", cur_cycle, fshow (rsp));
$display ("%0d: DM_Abstract_Commands.rl_gpr_read_finish: ", cur_cycle, fshow (rsp));
`ifdef RV32
rg_data0 <= rsp.data;
@@ -385,32 +388,32 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
`ifdef ISA_F
rule rl_fpr_write_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& rg_command_access_reg_write
&& is_fpr);
&& rg_start_reg_access
&& rg_command_access_reg_write
&& is_fpr);
let req = DM_CPU_Req {write: True,
address: fpr_addr,
address: fpr_addr,
`ifdef RV32
data: rg_data0
data: rg_data0
`endif
`ifdef RV64
data: {rg_data1, rg_data0}
data: {rg_data1, rg_data0}
`endif
};
};
f_hart0_fpr_reqs.enq (req);
rg_start_reg_access <= False;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_fpr_write_start: ", cur_cycle, fshow (req));
$display ("%0d: DM_Abstract_Commands.rl_fpr_write_start: ", cur_cycle, fshow (req));
endrule
// ----------------
rule rl_fpr_write_finish ( rg_abstractcs_busy
&& rg_command_access_reg_write
&& is_fpr);
&& rg_command_access_reg_write
&& is_fpr);
let rsp <- pop (f_hart0_fpr_rsps);
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_fpr_write_finish: ", cur_cycle, fshow (rsp));
$display ("%0d: DM_Abstract_Commands.rl_fpr_write_finish: ", cur_cycle, fshow (rsp));
rg_abstractcs_cmderr <= (rsp.ok ? DM_ABSTRACTCS_CMDERR_NONE : DM_ABSTRACTCS_CMDERR_HALT_RESUME);
rg_abstractcs_busy <= False;
@@ -420,26 +423,26 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Read FPR
rule rl_fpr_read_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& is_fpr);
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& is_fpr);
Bit #(XLEN) data = ?;
let req = DM_CPU_Req {write: False, address: fpr_addr, data: data };
f_hart0_fpr_reqs.enq (req);
rg_start_reg_access <= False;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_fpr_read_start: ", cur_cycle, fshow (req));
$display ("%0d: DM_Abstract_Commands.rl_fpr_read_start: ", cur_cycle, fshow (req));
endrule
// ----------------
rule rl_fpr_read_finish ( rg_abstractcs_busy
&& (! rg_command_access_reg_write)
&& is_fpr);
&& (! rg_command_access_reg_write)
&& is_fpr);
let rsp <- pop (f_hart0_fpr_rsps);
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_fpr_read_finish: ", cur_cycle, fshow (rsp));
$display ("%0d: DM_Abstract_Commands.rl_fpr_read_finish: ", cur_cycle, fshow (rsp));
`ifdef RV32
rg_data0 <= rsp.data;
@@ -458,12 +461,12 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
// Read/Write unknown address
rule rl_unknown_write_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& rg_command_access_reg_write
&& (! is_csr) && (! is_gpr) && (! is_fpr));
&& rg_start_reg_access
&& rg_command_access_reg_write
&& (! is_csr) && (! is_gpr) && (! is_fpr));
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_unknown_write_start: unknown RISC-V regno [0x%0h] <= 0x%08h",
cur_cycle, rg_command_access_reg_regno, rg_data0);
$display ("%0d: DM_Abstract_Commands.rl_unknown_write_start: unknown RISC-V regno [0x%0h] <= 0x%08h",
cur_cycle, rg_command_access_reg_regno, rg_data0);
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_OTHER;
rg_start_reg_access <= False;
@@ -471,12 +474,12 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
endrule
rule rl_unknown_read_start ( rg_abstractcs_busy
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& (! is_csr) && (! is_gpr) && (! is_fpr));
&& rg_start_reg_access
&& (! rg_command_access_reg_write)
&& (! is_csr) && (! is_gpr) && (! is_fpr));
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.rl_unknown_read_start: unknown RISC-V regno [0x%0h]",
cur_cycle, rg_command_access_reg_regno);
$display ("%0d: DM_Abstract_Commands.rl_unknown_read_start: unknown RISC-V regno [0x%0h]",
cur_cycle, rg_command_access_reg_regno);
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_OTHER;
rg_start_reg_access <= False;
@@ -506,7 +509,7 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
`endif
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands: reset", cur_cycle);
$display ("%0d: DM_Abstract_Commands: reset", cur_cycle);
endmethod
// ----------------
@@ -514,64 +517,64 @@ module mkDM_Abstract_Commands (DM_Abstract_Commands_IFC);
method ActionValue #(DM_Word) av_read (DM_Addr dm_addr);
actionvalue
let dm_addr_name = fshow_dm_addr (dm_addr);
DM_Word dm_word = case (dm_addr)
dm_addr_abstractcs: virt_rg_abstractcs;
dm_addr_command: virt_rg_command;
dm_addr_data0: rg_data0;
let dm_addr_name = fshow_dm_addr (dm_addr);
DM_Word dm_word = case (dm_addr)
dm_addr_abstractcs: virt_rg_abstractcs;
dm_addr_command: virt_rg_command;
dm_addr_data0: rg_data0;
`ifdef RV64
dm_addr_data1: rg_data1;
dm_addr_data1: rg_data1;
`endif
// dm_addr_data2..data3
// dm_addr_abstractauto
// dm_addr_progbuf0..15
endcase;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.av_read: [", cur_cycle, dm_addr_name, "] => 0x%08h", dm_word);
return dm_word;
// dm_addr_data2..data3
// dm_addr_abstractauto
// dm_addr_progbuf0..15
endcase;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.av_read: [", cur_cycle, dm_addr_name, "] => 0x%08h", dm_word);
return dm_word;
endactionvalue
endmethod
method Action write (DM_Addr dm_addr, DM_Word dm_word);
action
let dm_addr_name = fshow_dm_addr (dm_addr);
let dm_addr_name = fshow_dm_addr (dm_addr);
if (dm_addr == dm_addr_abstractcs)
fa_rg_abstractcs_write (dm_word);
if (dm_addr == dm_addr_abstractcs)
fa_rg_abstractcs_write (dm_word);
else if (rg_abstractcs_cmderr != DM_ABSTRACTCS_CMDERR_NONE) begin
if (verbosity != 0) begin
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name, "] <= 0x%08h: ERROR", dm_word);
$display (" Ignoring: previous cmderr ", fshow (rg_abstractcs_cmderr));
end
end
else if (rg_abstractcs_cmderr != DM_ABSTRACTCS_CMDERR_NONE) begin
if (verbosity != 0) begin
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name, "] <= 0x%08h: ERROR", dm_word);
$display (" Ignoring: previous cmderr ", fshow (rg_abstractcs_cmderr));
end
end
else if (dm_addr == dm_addr_command)
fa_rg_command_write (dm_word);
else if (dm_addr == dm_addr_command)
fa_rg_command_write (dm_word);
else if (dm_addr == dm_addr_data0) begin
rg_data0 <= dm_word;
else if (dm_addr == dm_addr_data0) begin
rg_data0 <= dm_word;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name, "] <= 0x%08h", dm_word);
end
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name, "] <= 0x%08h", dm_word);
end
`ifdef RV64
else if (dm_addr == dm_addr_data1) begin
rg_data1 <= dm_word;
else if (dm_addr == dm_addr_data1) begin
rg_data1 <= dm_word;
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name, "] <= 0x%08h", dm_word);
end
if (verbosity != 0)
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name, "] <= 0x%08h", dm_word);
end
`endif
else begin
// dm_addr_data2..12
// dm_addr_abstractauto
// dm_addr_progbuf0..15
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
else begin
// dm_addr_data2..12
// dm_addr_abstractauto
// dm_addr_progbuf0..15
rg_abstractcs_cmderr <= DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED;
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name,
"] <= 0x%08h: ERROR: not supported", dm_word);
end
$display ("%0d: DM_Abstract_Commands.write: [", cur_cycle, dm_addr_name,
"] <= 0x%08h: ERROR: not supported", dm_word);
end
endaction
endmethod

View File

@@ -83,49 +83,49 @@ DM_Addr dm_addr_sbdata3 = 'h3f;
function Fmt fshow_dm_addr (DM_Addr dm_addr);
return case (dm_addr)
// Run Control
dm_addr_dmcontrol: $format ("dm_addr_dmcontrol");
dm_addr_dmstatus: $format ("dm_addr_dmstatus");
dm_addr_hartinfo: $format ("dm_addr_hartinfo");
dm_addr_haltsum: $format ("dm_addr_haltsum");
dm_addr_hawindowsel: $format ("dm_addr_hawindowsel");
dm_addr_hawindow: $format ("dm_addr_hawindow");
dm_addr_devtreeaddr0: $format ("dm_addr_devtreeaddr0");
dm_addr_authdata: $format ("dm_addr_authdata");
dm_addr_haltregion0: $format ("dm_addr_haltregion0");
dm_addr_haltregion31: $format ("dm_addr_haltregion31");
// Run Control
dm_addr_dmcontrol: $format ("dm_addr_dmcontrol");
dm_addr_dmstatus: $format ("dm_addr_dmstatus");
dm_addr_hartinfo: $format ("dm_addr_hartinfo");
dm_addr_haltsum: $format ("dm_addr_haltsum");
dm_addr_hawindowsel: $format ("dm_addr_hawindowsel");
dm_addr_hawindow: $format ("dm_addr_hawindow");
dm_addr_devtreeaddr0: $format ("dm_addr_devtreeaddr0");
dm_addr_authdata: $format ("dm_addr_authdata");
dm_addr_haltregion0: $format ("dm_addr_haltregion0");
dm_addr_haltregion31: $format ("dm_addr_haltregion31");
dm_addr_verbosity: $format ("dm_addr_verbosity");
// Abstract Commands
dm_addr_abstractcs: $format ("dm_addr_abstractcs");
dm_addr_command: $format ("dm_addr_command");
dm_addr_data0: $format ("dm_addr_data0");
dm_addr_data1: $format ("dm_addr_data1");
dm_addr_data2: $format ("dm_addr_data2");
dm_addr_data3: $format ("dm_addr_data3");
dm_addr_data4: $format ("dm_addr_data4");
dm_addr_data5: $format ("dm_addr_data5");
dm_addr_data6: $format ("dm_addr_data6");
dm_addr_data7: $format ("dm_addr_data7");
dm_addr_data8: $format ("dm_addr_data8");
dm_addr_data9: $format ("dm_addr_data9");
dm_addr_data10: $format ("dm_addr_data10");
dm_addr_data11: $format ("dm_addr_data11");
dm_addr_abstractauto: $format ("dm_addr_abstractauto");
dm_addr_progbuf0: $format ("dm_addr_progbuf0");
// Abstract Commands
dm_addr_abstractcs: $format ("dm_addr_abstractcs");
dm_addr_command: $format ("dm_addr_command");
dm_addr_data0: $format ("dm_addr_data0");
dm_addr_data1: $format ("dm_addr_data1");
dm_addr_data2: $format ("dm_addr_data2");
dm_addr_data3: $format ("dm_addr_data3");
dm_addr_data4: $format ("dm_addr_data4");
dm_addr_data5: $format ("dm_addr_data5");
dm_addr_data6: $format ("dm_addr_data6");
dm_addr_data7: $format ("dm_addr_data7");
dm_addr_data8: $format ("dm_addr_data8");
dm_addr_data9: $format ("dm_addr_data9");
dm_addr_data10: $format ("dm_addr_data10");
dm_addr_data11: $format ("dm_addr_data11");
dm_addr_abstractauto: $format ("dm_addr_abstractauto");
dm_addr_progbuf0: $format ("dm_addr_progbuf0");
// System Bus
dm_addr_sbcs: $format ("dm_addr_sbcs");
dm_addr_sbaddress0: $format ("dm_addr_sbaddress0");
dm_addr_sbaddress1: $format ("dm_addr_sbaddress1");
dm_addr_sbaddress2: $format ("dm_addr_sbaddress2");
dm_addr_sbdata0: $format ("dm_addr_sbdata0");
dm_addr_sbdata1: $format ("dm_addr_sbdata1");
dm_addr_sbdata2: $format ("dm_addr_sbdata2");
dm_addr_sbdata3: $format ("dm_addr_sbdata3");
// System Bus
dm_addr_sbcs: $format ("dm_addr_sbcs");
dm_addr_sbaddress0: $format ("dm_addr_sbaddress0");
dm_addr_sbaddress1: $format ("dm_addr_sbaddress1");
dm_addr_sbaddress2: $format ("dm_addr_sbaddress2");
dm_addr_sbdata0: $format ("dm_addr_sbdata0");
dm_addr_sbdata1: $format ("dm_addr_sbdata1");
dm_addr_sbdata2: $format ("dm_addr_sbdata2");
dm_addr_sbdata3: $format ("dm_addr_sbdata3");
default: $format ("<Unknown dm_abstract_command dm_addr 0x%0h>", dm_addr);
endcase;
default: $format ("<Unknown dm_abstract_command dm_addr 0x%0h>", dm_addr);
endcase;
endfunction
// ================================================================
@@ -135,21 +135,21 @@ endfunction
// 'dmcontrol' register
function DM_Word fn_mk_dmcontrol (Bool haltreq,
Bool resumereq,
Bool hartreset,
Bool hasel,
Bit #(10) hartsel,
Bool ndmreset,
Bool dmactive);
Bool resumereq,
Bool hartreset,
Bool hasel,
Bit #(10) hartsel,
Bool ndmreset,
Bool dmactive);
return {pack (haltreq),
pack (resumereq),
pack (hartreset),
2'b0,
pack (hasel),
hartsel,
14'b0,
pack (ndmreset),
pack (dmactive)};
pack (resumereq),
pack (hartreset),
2'b0,
pack (hasel),
hartsel,
14'b0,
pack (ndmreset),
pack (dmactive)};
endfunction
function Bool fn_dmcontrol_haltreq (DM_Word dm_word);
@@ -241,23 +241,23 @@ endfunction
function Fmt fshow_dmstatus (DM_Word x);
Fmt fmt_version = ( (x[3:0] == 0)
? $format ("v.none")
: ( (x[3:0] == 1)
? $format ("v0.11")
: ( (x[3:0] == 2)
? $format ("v0.13")
: $format ("v??"))));
? $format ("v.none")
: ( (x[3:0] == 1)
? $format ("v0.11")
: ( (x[3:0] == 2)
? $format ("v0.13")
: $format ("v??"))));
return ( $format ("(all/any) ")
+ $format ("resumeack %0d/%0d ", x[17], x[16])
+ $format ("nonexistent %0d/%0d ", x[15], x[14])
+ $format ("unavail %0d/%0d ", x[13], x[12])
+ $format ("running %0d/%0d ", x[11], x[10])
+ $format ("halted %0d/%0d ", x[9], x[8])
+ $format ("authenticated %0d ", x[7])
+ $format ("authbusy %0d ", x[6])
+ $format ("devtreevalid %0d ", x[4])
+ fmt_version);
+ $format ("resumeack %0d/%0d ", x[17], x[16])
+ $format ("nonexistent %0d/%0d ", x[15], x[14])
+ $format ("unavail %0d/%0d ", x[13], x[12])
+ $format ("running %0d/%0d ", x[11], x[10])
+ $format ("halted %0d/%0d ", x[9], x[8])
+ $format ("authenticated %0d ", x[7])
+ $format ("authbusy %0d ", x[6])
+ $format ("devtreevalid %0d ", x[4])
+ fmt_version);
endfunction
// ================================================================
@@ -267,13 +267,13 @@ endfunction
// 'dm_abstractcs' register
typedef enum {DM_ABSTRACTCS_CMDERR_NONE, // 0
DM_ABSTRACTCS_CMDERR_BUSY, // 1
DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED, // 2
DM_ABSTRACTCS_CMDERR_EXCEPTION, // 3
DM_ABSTRACTCS_CMDERR_HALT_RESUME, // 4
DM_ABSTRACTCS_CMDERR_UNDEF5, // 5
DM_ABSTRACTCS_CMDERR_UNDEF6, // 6
DM_ABSTRACTCS_CMDERR_OTHER // 7
DM_ABSTRACTCS_CMDERR_BUSY, // 1
DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED, // 2
DM_ABSTRACTCS_CMDERR_EXCEPTION, // 3
DM_ABSTRACTCS_CMDERR_HALT_RESUME, // 4
DM_ABSTRACTCS_CMDERR_UNDEF5, // 5
DM_ABSTRACTCS_CMDERR_UNDEF6, // 6
DM_ABSTRACTCS_CMDERR_OTHER // 7
} DM_abstractcs_cmderr
deriving (Bits, Eq, FShow);
@@ -304,18 +304,18 @@ endfunction
// 'command' register
typedef enum {DM_COMMAND_CMDTYPE_ACCESS_REG,
DM_COMMAND_CMDTYPE_QUICK_ACCESS
DM_COMMAND_CMDTYPE_QUICK_ACCESS
} DM_command_cmdtype
deriving (Bits, Eq, FShow);
typedef enum {DM_COMMAND_ACCESS_REG_SIZE_UNDEF0, // 0
DM_COMMAND_ACCESS_REG_SIZE_UNDEF1, // 1
DM_COMMAND_ACCESS_REG_SIZE_LOWER32, // 2
DM_COMMAND_ACCESS_REG_SIZE_LOWER64, // 3
DM_COMMAND_ACCESS_REG_SIZE_LOWER128, // 4
DM_COMMAND_ACCESS_REG_SIZE_UNDEF5, // 5
DM_COMMAND_ACCESS_REG_SIZE_UNDEF6, // 6
DM_COMMAND_ACCESS_REG_SIZE_UNDEF7 // 7
DM_COMMAND_ACCESS_REG_SIZE_UNDEF1, // 1
DM_COMMAND_ACCESS_REG_SIZE_LOWER32, // 2
DM_COMMAND_ACCESS_REG_SIZE_LOWER64, // 3
DM_COMMAND_ACCESS_REG_SIZE_LOWER128, // 4
DM_COMMAND_ACCESS_REG_SIZE_UNDEF5, // 5
DM_COMMAND_ACCESS_REG_SIZE_UNDEF6, // 6
DM_COMMAND_ACCESS_REG_SIZE_UNDEF7 // 7
} DM_command_access_reg_size
deriving (Bits, Eq, FShow);
@@ -327,20 +327,20 @@ Integer dm_command_access_reg_regno_fpr_0 = 'h1020;
Integer dm_command_access_reg_regno_fpr_1F = 'h103F;
function DM_Word fn_mk_command_access_reg (DM_command_access_reg_size size,
Bool postexec,
Bool transfer,
Bool write,
Bit #(16) regno);
Bool postexec,
Bool transfer,
Bool write,
Bit #(16) regno);
Bit #(8) b8_cmdtype = zeroExtend (pack (DM_COMMAND_CMDTYPE_ACCESS_REG));
Bit #(3) b3_size = pack (size);
return {b8_cmdtype,
1'b0,
b3_size,
1'b0,
pack (postexec),
pack (transfer),
pack (write),
regno};
1'b0,
b3_size,
1'b0,
pack (postexec),
pack (transfer),
pack (write),
regno};
endfunction
function DM_command_cmdtype fn_command_cmdtype (DM_Word dm_word);
@@ -374,10 +374,10 @@ endfunction
// 'dm_sbcs' register
typedef enum {DM_SBACCESS_8_BIT,
DM_SBACCESS_16_BIT,
DM_SBACCESS_32_BIT,
DM_SBACCESS_64_BIT,
DM_SBACCESS_128_BIT
DM_SBACCESS_16_BIT,
DM_SBACCESS_32_BIT,
DM_SBACCESS_64_BIT,
DM_SBACCESS_128_BIT
} DM_sbaccess
deriving (Bits, Eq, FShow);
@@ -392,47 +392,47 @@ function Integer fn_sbaccess_to_addr_incr (DM_sbaccess sbaccess);
endfunction
typedef enum {DM_SBERROR_NONE, // 0
DM_SBERROR_TIMEOUT, // 1
DM_SBERROR_BADADDR, // 2
DM_SBERROR_OTHER, // 3
DM_SBERROR_BUSY_STALE, // 4
DM_SBERROR_UNDEF5, // 5
DM_SBERROR_UNDEF6, // 6
DM_SBERROR_UNDEF7_W1C // 7, used in writes, to clear sberror
DM_SBERROR_TIMEOUT, // 1
DM_SBERROR_BADADDR, // 2
DM_SBERROR_OTHER, // 3
DM_SBERROR_BUSY_STALE, // 4
DM_SBERROR_UNDEF5, // 5
DM_SBERROR_UNDEF6, // 6
DM_SBERROR_UNDEF7_W1C // 7, used in writes, to clear sberror
} DM_sberror
deriving (Bits, Eq, FShow);
// Constructor
function DM_Word fn_mk_sbcs_val (Bit #(3) sbversion,
Bool sbbusyerror,
Bool sbbusy,
Bool sbreadonaddr,
DM_sbaccess sbaccess,
Bool sbautoincrement,
Bool sbreadondata,
DM_sberror sberror,
Bit #(7) sbasize,
Bit #(1) sbaccess128,
Bit #(1) sbaccess64,
Bit #(1) sbaccess32,
Bit #(1) sbaccess16,
Bit #(1) sbaccess8);
Bool sbbusyerror,
Bool sbbusy,
Bool sbreadonaddr,
DM_sbaccess sbaccess,
Bool sbautoincrement,
Bool sbreadondata,
DM_sberror sberror,
Bit #(7) sbasize,
Bit #(1) sbaccess128,
Bit #(1) sbaccess64,
Bit #(1) sbaccess32,
Bit #(1) sbaccess16,
Bit #(1) sbaccess8);
return {sbversion,
6'b0,
pack (sbbusyerror),
pack (sbbusy),
pack (sbreadonaddr),
pack (sbaccess),
pack (sbautoincrement),
pack (sbreadondata),
pack (sberror),
sbasize,
sbaccess128,
sbaccess64,
sbaccess32,
sbaccess16,
sbaccess8};
6'b0,
pack (sbbusyerror),
pack (sbbusy),
pack (sbreadonaddr),
pack (sbaccess),
pack (sbautoincrement),
pack (sbreadondata),
pack (sberror),
sbasize,
sbaccess128,
sbaccess64,
sbaccess32,
sbaccess16,
sbaccess8};
endfunction
// Selectors
@@ -456,35 +456,35 @@ function Bool fn_sbcs_sbaccess8 (DM_Word dm_word); return unpack (
function Fmt fshow_sbcs (DM_Word dm_word);
return ( $format ("SBCS{")
+ $format ("sbversion %0d", fn_sbcs_sbversion (dm_word))
+ $format (" sbbusyerror %0d", fn_sbcs_sbbusyerror (dm_word))
+ $format (" sbbusy %0d", fn_sbcs_sbbusy (dm_word))
+ $format (" sbreadonaddr ") + fshow (fn_sbcs_sbreadonaddr (dm_word))
+ $format (" sbaccess ") + fshow (fn_sbcs_sbaccess (dm_word))
+ $format (" sbautoincrement ") + fshow (fn_sbcs_sbautoincrement (dm_word))
+ $format (" sbreadondata ") + fshow (fn_sbcs_sbreadondata (dm_word))
+ $format (" sberror ") + fshow (fn_sbcs_sberror (dm_word))
+ $format (" sbasize %0d", fn_sbcs_sbasize (dm_word))
+ $format (" sbaccess")
+ ((fn_sbcs_sbaccess128 (dm_word)) ? $format ("_128") : $format ("x"))
+ ((fn_sbcs_sbaccess64 (dm_word)) ? $format ("_64") : $format ("x"))
+ ((fn_sbcs_sbaccess32 (dm_word)) ? $format ("_32") : $format ("x"))
+ ((fn_sbcs_sbaccess16 (dm_word)) ? $format ("_16") : $format ("x"))
+ ((fn_sbcs_sbaccess8 (dm_word)) ? $format ("_8") : $format ("x"))
+ $format ("}"));
+ $format ("sbversion %0d", fn_sbcs_sbversion (dm_word))
+ $format (" sbbusyerror %0d", fn_sbcs_sbbusyerror (dm_word))
+ $format (" sbbusy %0d", fn_sbcs_sbbusy (dm_word))
+ $format (" sbreadonaddr ") + fshow (fn_sbcs_sbreadonaddr (dm_word))
+ $format (" sbaccess ") + fshow (fn_sbcs_sbaccess (dm_word))
+ $format (" sbautoincrement ") + fshow (fn_sbcs_sbautoincrement (dm_word))
+ $format (" sbreadondata ") + fshow (fn_sbcs_sbreadondata (dm_word))
+ $format (" sberror ") + fshow (fn_sbcs_sberror (dm_word))
+ $format (" sbasize %0d", fn_sbcs_sbasize (dm_word))
+ $format (" sbaccess")
+ ((fn_sbcs_sbaccess128 (dm_word)) ? $format ("_128") : $format ("x"))
+ ((fn_sbcs_sbaccess64 (dm_word)) ? $format ("_64") : $format ("x"))
+ ((fn_sbcs_sbaccess32 (dm_word)) ? $format ("_32") : $format ("x"))
+ ((fn_sbcs_sbaccess16 (dm_word)) ? $format ("_16") : $format ("x"))
+ ((fn_sbcs_sbaccess8 (dm_word)) ? $format ("_8") : $format ("x"))
+ $format ("}"));
endfunction
// ================================================================
// DCSR 'cause' field values
typedef enum {DCSR_CAUSE_RESERVED0,
DCSR_CAUSE_EBREAK,
DCSR_CAUSE_TRIGGER,
DCSR_CAUSE_HALTREQ,
DCSR_CAUSE_STEP,
DCSR_CAUSE_RESERVED5,
DCSR_CAUSE_RESERVED6,
DCSR_CAUSE_RESERVED7
DCSR_CAUSE_EBREAK,
DCSR_CAUSE_TRIGGER,
DCSR_CAUSE_HALTREQ,
DCSR_CAUSE_STEP,
DCSR_CAUSE_RESERVED5,
DCSR_CAUSE_RESERVED6,
DCSR_CAUSE_RESERVED7
} DCSR_Cause
deriving (Bits, Eq, FShow);
@@ -500,12 +500,12 @@ endinterface
// A dummy interface to tie off DMI if it is not used.
DMI dummy_DMI_ifc = interface DMI;
method Action read_addr (DM_Addr dm_addr) = noAction;
method ActionValue #(DM_Word) read_data = actionvalue
return 0;
endactionvalue;
method Action write (DM_Addr dm_addr, DM_Word dm_word) = noAction;
endinterface;
method Action read_addr (DM_Addr dm_addr) = noAction;
method ActionValue #(DM_Word) read_data = actionvalue
return 0;
endactionvalue;
method Action write (DM_Addr dm_addr, DM_Word dm_word) = noAction;
endinterface;
// ================================================================

View File

@@ -9,9 +9,15 @@ package DM_Run_Control;
// ================================================================
// BSV library imports
import FIFOF :: *;
import GetPut :: *;
import ClientServer :: *;
import FIFOF :: *;
import GetPut :: *;
import ClientServer :: *;
// ----------------
// Other library imports
import Cur_Cycle :: *;
import GetPut_Aux :: *;
// ================================================================
// Project imports
@@ -33,13 +39,14 @@ interface DM_Run_Control_IFC;
// ----------------
// Facing a hart: reset and run-control
interface Get #(Token) hart0_get_reset_req;
interface Client #(Bool, Bool) hart0_reset_client;
interface Client #(Bool, Bool) hart0_client_run_halt;
interface Get #(Bit #(4)) hart0_get_other_req;
// ----------------
// Facing Platform: Non-Debug-Module Reset (reset all except DM)
interface Get #(Token) get_ndm_reset_req;
// Bool indicates 'running' hart state.
interface Client #(Bool, Bool) ndm_reset_client;
endinterface
// ================================================================
@@ -52,7 +59,8 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
// ----------------------------------------------------------------
// NDM Reset
FIFOF #(Token) f_ndm_reset_reqs <- mkFIFOF;
FIFOF #(Bool) f_ndm_reset_reqs <- mkFIFOF;
FIFOF #(Bool) f_ndm_reset_rsps <- mkFIFOF;
// ----------------------------------------------------------------
// Hart0 run control
@@ -60,7 +68,8 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
Reg #(Bool) rg_hart0_running <- mkRegU;
// Reset requests to hart
FIFOF #(Token) f_hart0_reset_reqs <- mkFIFOF;
FIFOF #(Bool) f_hart0_reset_reqs <- mkFIFOF;
FIFOF #(Bool) f_hart0_reset_rsps <- mkFIFOF;
// Run/halt requests to hart and responses
FIFOF #(Bool) f_hart0_run_halt_reqs <- mkFIFOF;
@@ -81,7 +90,13 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
// 'anyXX' = 'allXX'
// 'allrunning' = NOT 'allhalted'
Reg#(Bool) rg_dmstatus_allresumeack <- mkRegU;
Bool dmstatus_impebreak = False;
Reg #(Bool) rg_hart0_hasreset <- mkRegU;
Bool dmstatus_allhavereset = rg_hart0_hasreset;
Bool dmstatus_anyhavereset = rg_hart0_hasreset;
Reg #(Bool) rg_dmstatus_allresumeack <- mkRegU;
Bool dmstatus_allresumeack = rg_dmstatus_allresumeack;
Bool dmstatus_anyresumeack = rg_dmstatus_allresumeack;
@@ -89,8 +104,9 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
Bool dmstatus_allnonexistent = False;
Bool dmstatus_anynonexistent = dmstatus_allnonexistent;
Bool dmstatus_allunavail = False;
Bool dmstatus_anyunavail = dmstatus_allunavail;
Reg #(Bool) rg_dmstatus_allunavail <- mkReg (False);
Bool dmstatus_allunavail = rg_dmstatus_allunavail;
Bool dmstatus_anyunavail = rg_dmstatus_allunavail;
Bool dmstatus_allrunning = rg_hart0_running;
Bool dmstatus_anyrunning = dmstatus_allrunning;
@@ -98,22 +114,26 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
Bool dmstatus_allhalted = (! rg_hart0_running);
Bool dmstatus_anyhalted = dmstatus_allhalted;
DM_Word virt_rg_dmstatus = {14'b0,
pack (dmstatus_allresumeack),
pack (dmstatus_anyresumeack),
pack (dmstatus_allnonexistent),
pack (dmstatus_anynonexistent),
pack (dmstatus_allunavail),
pack (dmstatus_anyunavail),
pack (dmstatus_allrunning),
pack (dmstatus_anyrunning),
pack (dmstatus_allhalted),
pack (dmstatus_anyhalted),
pack (True), // authenticated
pack (False), // authbusy
1'b0,
pack (False), // devtreevalid
4'h2}; // version
DM_Word virt_rg_dmstatus = {9'b0,
pack (dmstatus_impebreak),
2'b0,
pack (dmstatus_allhavereset),
pack (dmstatus_anyhavereset),
pack (dmstatus_allresumeack),
pack (dmstatus_anyresumeack),
pack (dmstatus_allnonexistent),
pack (dmstatus_anynonexistent),
pack (dmstatus_allunavail),
pack (dmstatus_anyunavail),
pack (dmstatus_allrunning),
pack (dmstatus_anyrunning),
pack (dmstatus_allhalted),
pack (dmstatus_anyhalted),
pack (True), // authenticated
pack (False), // authbusy
1'b0,
pack (False), // devtreevalid
4'h2}; // version
// ----------------------------------------------------------------
// rg_dmcontrol
@@ -125,112 +145,131 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
Reg #(Bool) rg_dmcontrol_dmactive <- mkReg (False);
DM_Word virt_rg_dmcontrol = {2'b0, // haltreq, resumereq (w-o)
pack (rg_dmcontrol_hartreset),
2'b0,
pack (False), // hasel
10'b0, // hartsel
14'b0,
pack (rg_dmcontrol_ndmreset),
pack (rg_dmcontrol_dmactive)};
pack (rg_dmcontrol_hartreset),
2'b0,
pack (False), // hasel
10'b0, // hartsel
14'b0,
pack (rg_dmcontrol_ndmreset),
pack (rg_dmcontrol_dmactive)};
function Action fa_rg_dmcontrol_write (DM_Word dm_word);
action
let haltreq = fn_dmcontrol_haltreq (dm_word);
let resumereq = fn_dmcontrol_resumereq (dm_word);
let hartreset = fn_dmcontrol_hartreset (dm_word);
let hasel = fn_dmcontrol_hasel (dm_word);
let hartsel = fn_dmcontrol_hartsel (dm_word);
let ndmreset = fn_dmcontrol_ndmreset (dm_word);
let dmactive = fn_dmcontrol_dmactive (dm_word);
let haltreq = fn_dmcontrol_haltreq (dm_word);
let resumereq = fn_dmcontrol_resumereq (dm_word);
let hartreset = fn_dmcontrol_hartreset (dm_word);
let hasel = fn_dmcontrol_hasel (dm_word);
let hartsel = fn_dmcontrol_hartsel (dm_word);
let ndmreset = fn_dmcontrol_ndmreset (dm_word);
let dmactive = fn_dmcontrol_dmactive (dm_word);
rg_dmcontrol_haltreq <= haltreq;
rg_dmcontrol_hartreset <= hartreset;
rg_dmcontrol_ndmreset <= ndmreset;
rg_dmcontrol_dmactive <= dmactive;
rg_dmcontrol_haltreq <= haltreq;
rg_dmcontrol_hartreset <= hartreset;
rg_dmcontrol_ndmreset <= ndmreset;
rg_dmcontrol_dmactive <= dmactive;
// Debug Module reset
if (! dmactive) begin
// Reset the DM module itself
$display ("DM_Run_Control.write: dmcontrol 0x%08h (dmactive=0): resetting Debug Module",
dm_word);
// Debug Module reset
if (! dmactive) begin
// Reset the DM module itself
$display ("%0d: %m.dmcontrol_write 0x%08h (dmactive=0): resetting Debug Module",
cur_cycle, dm_word);
// Error-checking
if (ndmreset) begin
$display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
dm_word);
$display (" [1] (ndmreset) and [0] (dmactive) both asserted");
$display (" dmactive has priority; ignoring ndmreset");
end
if (hartreset) begin
$display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
dm_word);
$display (" [29] (hartreset) and [0] (dmactive) both asserted");
$display (" dmactive has priority; ignoring hartreset");
end
// Error-checking
if (ndmreset) begin
$display (" WARNING: DM_Run_Control: dmcontrol_write 0x%08h:", dm_word);
$display (" [1] (ndmreset) and [0] (dmactive) both asserted");
$display (" dmactive has priority; ignoring ndmreset");
end
if (hartreset) begin
$display (" WARNING: DM_Run_Control: dmcontrol_write 0x%08h:", dm_word);
$display (" [29] (hartreset) and [0] (dmactive) both asserted");
$display (" dmactive has priority; ignoring hartreset");
end
// No action here; other rules will fire (see method dmactive, Debug_Module.rl_reset)
noAction;
end
// No action here; other rules will fire (see method dmactive, Debug_Module.rl_reset)
noAction;
end
// Platform reset (non-Debug Module)
else if (ndmreset) begin
$display ("DM_Run_Control.write: dmcontrol 0x%08h: ndmreset=1: resetting platform",
dm_word);
f_ndm_reset_reqs.enq (?);
rg_hart0_running <= True; // Must be same as run/halt state of CPU after hart_reset!
// Ignore if NDM reset is in progress
else if (rg_dmstatus_allunavail) begin
$display ("%0d: %m.dmcontrol_write 0x%0h: ndm reset in progress; ignoring this write",
cur_cycle, dm_word);
end
// Error-checking
if (hartreset) begin
$display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
dm_word);
$display (" Both ndmreset (bit 1) and hartreset (bit 29) are asserted");
$display (" ndmreset has priority; ignoring hartreset");
end
end
else begin
// Deassert platform reset
if ((verbosity != 0) && rg_dmcontrol_ndmreset)
$display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing ndmreset", dm_word);
// Non-Debug-Module reset (platform reset) posedge: ignore
else if ((! rg_dmcontrol_ndmreset) && ndmreset) begin
if (verbosity != 0)
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 0->1: ignoring",
cur_cycle, dm_word);
end
// Hart reset
if (hartreset) begin
if (verbosity != 0)
$display ("DM_Run_Control.write: dmcontrol 0x%08h: hartreset=1: resetting hart",
dm_word);
f_hart0_reset_reqs.enq (?);
rg_hart0_running <= True; // Must be same as run/halt state of CPU after hart_reset!
end
else begin
// Deassert hart reset
if ((verbosity != 0) && rg_dmcontrol_hartreset)
$display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing hartreset", dm_word);
// Non-Debug-Module reset (platform reset) negedge: do it
else if (rg_dmcontrol_ndmreset && (! ndmreset)) begin
Bool running = (! haltreq);
if (verbosity != 0) begin
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 1->0: resetting platform",
cur_cycle, dm_word);
$display (" Requested 'running' state = ", fshow (running));
end
if (hasel)
$display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: 'hasel' is not supported",
dm_word);
f_ndm_reset_reqs.enq (running);
rg_dmstatus_allunavail <= True;
if (hartsel != 0)
$display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: hartsel 0x%0h not supported",
dm_word, hartsel);
// Error-checking
if (hartreset) begin
$display (" WARNING: %m.dmcontrol_write 0x%08h:", dm_word);
$display (" Both ndmreset [1] and hartreset [29] are asserted");
$display (" ndmreset has priority; ignoring hartreset");
end
if (haltreq && resumereq) begin
$display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: haltreq=1 and resumereq=1",
dm_word);
$display (" This behavior is 'undefined' in the spec; ignoring");
end
// Resume hart(s) if not running
else if (resumereq && (! rg_hart0_running)) begin
f_hart0_run_halt_reqs.enq (True);
rg_dmstatus_allresumeack <= False;
$display ("DM_Run_Control.write: hart0 resume request");
end
// Halt hart(s)
else if (haltreq && rg_hart0_running) begin
f_hart0_run_halt_reqs.enq (False);
$display ("DM_Run_Control.write: hart0 halt request");
end
end
end
end
// Hart reset
else if (hartreset) begin
Bool running = (! haltreq);
f_hart0_reset_reqs.enq (running);
rg_hart0_hasreset <= True;
// Deassert platform reset
if (verbosity != 0) begin
$display ("%0d: %m.dmcontrol_write 0x%08h: hartreset=1: resetting hart",
cur_cycle, dm_word);
$display (" Requested 'running' state = ", fshow (running));
end
end
// run/halt commands
else begin
// Deassert hart reset
if ((verbosity != 0) && rg_dmcontrol_hartreset)
$display ("%0d: %m.dmcontrol_write 0x%08h: clearing hartreset",
cur_cycle, dm_word);
if (hasel)
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: hasel is not supported",
cur_cycle, dm_word);
if (hartsel != 0)
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: hartsel 0x%0h not supported",
cur_cycle, dm_word, hartsel);
if (haltreq && resumereq) begin
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: haltreq=1 and resumereq=1",
cur_cycle, dm_word);
$display (" This behavior is 'undefined' in the spec; ignoring");
end
// Resume hart(s) if not running
else if (resumereq && (! rg_hart0_running)) begin
f_hart0_run_halt_reqs.enq (True);
rg_dmstatus_allresumeack <= False;
$display ("%0d: %m.dmcontrol_write: hart0 resume request", cur_cycle);
end
// Halt hart(s)
else if (haltreq && rg_hart0_running) begin
f_hart0_run_halt_reqs.enq (False);
$display ("%0d: %m.dmcontrol_write: hart0 halt request", cur_cycle);
end
end
endaction
endfunction
@@ -250,19 +289,37 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
Reg #(Bit #(4)) rg_verbosity <- mkRegU;
// ----------------------------------------------------------------
// System responses
rule rl_hart0_run_rsp;
let x = f_hart0_run_halt_rsps.first;
f_hart0_run_halt_rsps.deq;
// Response from system for hart0 reset
rule rl_hart0_reset_rsp;
Bool running <- pop (f_hart0_reset_rsps);
rg_hart0_hasreset <= False;
rg_hart0_running <= running;
rg_hart0_running <= x;
if (x) begin
rg_dmstatus_allresumeack <= True;
$display ("DM_Run_Control: hart0 running");
end
else begin
$display ("DM_Run_Control: hart0 halted");
end
if (verbosity != 0)
$display ("%0d: %m.rl_hart0_reset_rsp: hart running = ", cur_cycle, fshow (running));
endrule
// Response from system for NDM reset
rule rl_ndm_reset_rsp;
Bool running <- pop (f_ndm_reset_rsps);
rg_hart0_running <= running;
rg_dmstatus_allunavail <= False;
// if (verbosity != 0) TODO: UNCOMMENT AFTER DEBUGGING
$display ("%0d: %m.rl_ndm_reset_rsp: hart running = ", cur_cycle, fshow (running));
endrule
// Response from system for run/halt request
rule rl_hart0_run_rsp (! f_ndm_reset_rsps.notEmpty);
let running <- pop (f_hart0_run_halt_rsps);
rg_hart0_running <= running;
if (running)
rg_dmstatus_allresumeack <= True;
if (verbosity != 0)
$display ("%0d: %m.rl_hart0_run_rsp: 'running' = ", cur_cycle, fshow (running));
endrule
// ----------------------------------------------------------------
@@ -274,9 +331,12 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
method Action reset;
f_ndm_reset_reqs.clear;
f_ndm_reset_rsps.clear;
rg_hart0_running <= True; // Must be same as run/halt state of CPU after hart_reset!
f_hart0_reset_reqs.clear;
f_hart0_reset_rsps.clear;
rg_hart0_running <= True; // Safe approximation of whether the CPU is running or not
f_hart0_run_halt_reqs.clear;
f_hart0_run_halt_rsps.clear;
@@ -285,12 +345,14 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
rg_dmcontrol_ndmreset <= False;
rg_dmcontrol_dmactive <= True; // DM module is now active
rg_hart0_hasreset <= False;
rg_dmstatus_allresumeack <= False;
rg_dmstatus_allunavail <= False; // NDM not in progress
rg_verbosity <= 0;
if (verbosity != 0)
$display ("DM_Run_Control: reset");
$display ("%0d: %m.reset", cur_cycle);
endmethod
// ----------------
@@ -298,46 +360,46 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
method ActionValue #(DM_Word) av_read (DM_Addr dm_addr);
actionvalue
DM_Word dm_word = case (dm_addr)
dm_addr_dmcontrol: virt_rg_dmcontrol;
dm_addr_dmstatus: virt_rg_dmstatus;
dm_addr_haltsum: haltsum;
dm_addr_haltregion0: haltregion0;
dm_addr_verbosity: extend (rg_verbosity);
endcase;
DM_Word dm_word = case (dm_addr)
dm_addr_dmcontrol: virt_rg_dmcontrol;
dm_addr_dmstatus: virt_rg_dmstatus;
dm_addr_haltsum: haltsum;
dm_addr_haltregion0: haltregion0;
dm_addr_verbosity: extend (rg_verbosity);
endcase;
if (verbosity != 0)
$display ("DM_Run_Control.av_read: [", fshow_dm_addr (dm_addr), "] => 0x%08h", dm_word);
if (verbosity != 0)
$display ("%0d: %m.av_read: [", cur_cycle, fshow_dm_addr (dm_addr), "] => 0x%08h", dm_word);
return dm_word;
return dm_word;
endactionvalue
endmethod
method Action write (DM_Addr dm_addr, DM_Word dm_word);
action
if (verbosity != 0)
$display ("DM_Run_Control.write: [", fshow_dm_addr (dm_addr), "] <= 0x%08h", dm_word);
if (verbosity != 0)
$display ("%0d: %m.write: [", cur_cycle, fshow_dm_addr (dm_addr), "] <= 0x%08h", dm_word);
case (dm_addr)
dm_addr_dmcontrol: fa_rg_dmcontrol_write (dm_word);
dm_addr_verbosity: begin
rg_verbosity <= truncate (dm_word);
f_hart0_other_reqs.enq (truncate (dm_word));
end
default: noAction;
endcase
case (dm_addr)
dm_addr_dmcontrol: fa_rg_dmcontrol_write (dm_word);
dm_addr_verbosity: begin
rg_verbosity <= truncate (dm_word);
f_hart0_other_reqs.enq (truncate (dm_word));
end
default: noAction;
endcase
endaction
endmethod
// ----------------
// Facing Hart: Reset, Run-control, etc.
interface Get hart0_get_reset_req = toGet (f_hart0_reset_reqs);
interface Client hart0_reset_client = toGPClient (f_hart0_reset_reqs, f_hart0_reset_rsps);
interface Client hart0_client_run_halt = toGPClient (f_hart0_run_halt_reqs, f_hart0_run_halt_rsps);
interface Get hart0_get_other_req = toGet (f_hart0_other_reqs);
// ----------------
// Facing Platform: Non-Debug-Module Reset (reset all except DM)
interface Get get_ndm_reset_req = toGet (f_ndm_reset_reqs);
interface Client ndm_reset_client = toGPClient (f_ndm_reset_reqs, f_ndm_reset_rsps);
endmodule
// ================================================================

View File

@@ -49,11 +49,11 @@ endinterface
function AXI4_Size fn_DM_sbaccess_to_AXI4_Size (DM_sbaccess sbaccess);
AXI4_Size axi4_size = case (sbaccess)
DM_SBACCESS_8_BIT: axsize_1;
DM_SBACCESS_16_BIT: axsize_2;
DM_SBACCESS_32_BIT: axsize_4;
DM_SBACCESS_64_BIT: axsize_8;
endcase;
DM_SBACCESS_8_BIT: axsize_1;
DM_SBACCESS_16_BIT: axsize_2;
DM_SBACCESS_32_BIT: axsize_4;
DM_SBACCESS_64_BIT: axsize_8;
endcase;
return axi4_size;
endfunction
@@ -68,8 +68,8 @@ endfunction
// - word with correct byte(s) shifted into LSBs and zero extended
function Bit #(64) fn_extract_and_extend_bytes (DM_sbaccess sbaccess,
Bit #(64) read_addr,
Bit #(64) word64);
Bit #(64) read_addr,
Bit #(64) word64);
Bit #(3) addr_lsbs = read_addr [2:0];
if (valueOf (Wd_Data) == 32)
addr_lsbs = (addr_lsbs & 'h3);
@@ -77,31 +77,31 @@ function Bit #(64) fn_extract_and_extend_bytes (DM_sbaccess sbaccess,
Bit #(64) result = 0;
case (sbaccess)
DM_SBACCESS_8_BIT: case (addr_lsbs)
'h0: result = zeroExtend (word64 [ 7: 0]);
'h1: result = zeroExtend (word64 [15: 8]);
'h2: result = zeroExtend (word64 [23:16]);
'h3: result = zeroExtend (word64 [31:24]);
'h4: result = zeroExtend (word64 [39:32]);
'h5: result = zeroExtend (word64 [47:40]);
'h6: result = zeroExtend (word64 [55:48]);
'h7: result = zeroExtend (word64 [63:56]);
endcase
'h0: result = zeroExtend (word64 [ 7: 0]);
'h1: result = zeroExtend (word64 [15: 8]);
'h2: result = zeroExtend (word64 [23:16]);
'h3: result = zeroExtend (word64 [31:24]);
'h4: result = zeroExtend (word64 [39:32]);
'h5: result = zeroExtend (word64 [47:40]);
'h6: result = zeroExtend (word64 [55:48]);
'h7: result = zeroExtend (word64 [63:56]);
endcase
DM_SBACCESS_16_BIT: case (addr_lsbs)
'h0: result = zeroExtend (word64 [15: 0]);
'h2: result = zeroExtend (word64 [31:16]);
'h4: result = zeroExtend (word64 [47:32]);
'h6: result = zeroExtend (word64 [63:48]);
endcase
'h0: result = zeroExtend (word64 [15: 0]);
'h2: result = zeroExtend (word64 [31:16]);
'h4: result = zeroExtend (word64 [47:32]);
'h6: result = zeroExtend (word64 [63:48]);
endcase
DM_SBACCESS_32_BIT: case (addr_lsbs)
'h0: result = zeroExtend (word64 [31: 0]);
'h4: result = zeroExtend (word64 [63:32]);
endcase
'h0: result = zeroExtend (word64 [31: 0]);
'h4: result = zeroExtend (word64 [63:32]);
endcase
DM_SBACCESS_64_BIT: case (addr_lsbs)
'h0: result = word64;
endcase
'h0: result = word64;
endcase
endcase
return result;
endfunction
@@ -110,12 +110,12 @@ endfunction
// Compute address, data and strobe (byte-enables) for writes to fabric
function Tuple4 #(Fabric_Addr, // addr is 32b- or 64b-aligned
Fabric_Data, // data is lane-aligned
Fabric_Strb, // strobe
AXI4_Size) // 8 for 8-byte writes, else 4
Fabric_Data, // data is lane-aligned
Fabric_Strb, // strobe
AXI4_Size) // 8 for 8-byte writes, else 4
fn_to_fabric_write_fields (DM_sbaccess sbaccess, // size of access
Bit #(64) addr,
Bit #(64) word64); // data is in lsbs
Bit #(64) addr,
Bit #(64) word64); // data is in lsbs
// First compute addr, data and strobe for a 64b-wide fabric
Bit #(8) strobe64 = 0;
@@ -125,24 +125,24 @@ function Tuple4 #(Fabric_Addr, // addr is 32b- or 64b-aligned
case (sbaccess)
DM_SBACCESS_8_BIT: begin
word64 = (word64 << shift_bits);
strobe64 = ('b_1 << shift_bytes);
axsize = axsize_1;
end
word64 = (word64 << shift_bits);
strobe64 = ('b_1 << shift_bytes);
axsize = axsize_1;
end
DM_SBACCESS_16_BIT: begin
word64 = (word64 << shift_bits);
strobe64 = ('b_11 << shift_bytes);
axsize = axsize_2;
end
word64 = (word64 << shift_bits);
strobe64 = ('b_11 << shift_bytes);
axsize = axsize_2;
end
DM_SBACCESS_32_BIT: begin
word64 = (word64 << shift_bits);
strobe64 = ('b_1111 << shift_bytes);
axsize = axsize_4;
end
word64 = (word64 << shift_bits);
strobe64 = ('b_1111 << shift_bytes);
axsize = axsize_4;
end
DM_SBACCESS_64_BIT: begin
strobe64 = 'b_1111_1111;
axsize = axsize_8;
end
strobe64 = 'b_1111_1111;
axsize = axsize_8;
end
endcase
// Adjust for 32b fabrics
@@ -163,8 +163,8 @@ endfunction: fn_to_fabric_write_fields
// System Bus access states
typedef enum {SB_NOTBUSY,
SB_READ_FINISH,
SB_WRITE_FINISH
SB_READ_FINISH,
SB_WRITE_FINISH
} SB_State
deriving (Bits, Eq, FShow);
@@ -179,7 +179,7 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
// ----------------------------------------------------------------
// Interface to memory fabric
AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master_xactor <- mkAXI4_Master_Xactor_2;
AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master_xactor <- mkAXI4_Master_Xactor;
// ----------------------------------------------------------------
// System Bus state
@@ -218,25 +218,25 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
UInt #(3) sbversion = 1;
DM_Word virt_rg_sbcs = {pack (sbversion),
6'b0,
pack (rg_sbcs_sbbusyerror),
pack (sbbusy),
pack (rg_sbcs_sbreadonaddr),
pack (rg_sbcs_sbaccess),
pack (rg_sbcs_sbautoincrement),
pack (rg_sbcs_sbreadondata),
pack (rg_sbcs_sberror),
6'b0,
pack (rg_sbcs_sbbusyerror),
pack (sbbusy),
pack (rg_sbcs_sbreadonaddr),
pack (rg_sbcs_sbaccess),
pack (rg_sbcs_sbautoincrement),
pack (rg_sbcs_sbreadondata),
pack (rg_sbcs_sberror),
`ifdef RV64
7'd64, // sbasize -- address size
7'd64, // sbasize -- address size
`endif
`ifdef RV32
7'd32, // sbasize -- address size
7'd32, // sbasize -- address size
`endif
1'b0, // sbaccess128
1'b0, // sbaccess64
1'b1, // sbaccess32
1'b1, // sbaccess16
1'b1}; // sbaccess8
1'b0, // sbaccess128
1'b0, // sbaccess64
1'b1, // sbaccess32
1'b1, // sbaccess16
1'b1}; // sbaccess8
// ----------------
// Local defs and help functions
@@ -245,16 +245,16 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function Action fa_sbaddress_incr (Bit #(64) addr64);
action
Bit #(64) next_sbaddress = addr64 + fromInteger (addr_incr);
Bit #(64) next_sbaddress = addr64 + fromInteger (addr_incr);
`ifdef RV64
rg_sbaddress1 <= next_sbaddress [63:32];
rg_sbaddress1 <= next_sbaddress [63:32];
`else
rg_sbaddress1 <= 0;
rg_sbaddress1 <= 0;
`endif
rg_sbaddress0 <= next_sbaddress [31:0];
rg_sbaddress0 <= next_sbaddress [31:0];
if (verbosity != 0)
$display (" Increment sbaddr 0x%08h -> 0x%08h", addr64, next_sbaddress);
if (verbosity != 0)
$display (" Increment sbaddr 0x%08h -> 0x%08h", addr64, next_sbaddress);
endaction
endfunction
@@ -263,30 +263,30 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function Action fa_fabric_send_read_req (Bit #(64) addr64);
action
Fabric_Addr fabric_addr = truncate (addr64);
let rda = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: fabric_addr,
arlen: 0, // burst len = arlen+1
arsize: fn_DM_sbaccess_to_AXI4_Size (rg_sbcs_sbaccess),
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
master_xactor.i_rd_addr.enq (rda);
Fabric_Addr fabric_addr = truncate (addr64);
let rda = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: fabric_addr,
arlen: 0, // burst len = arlen+1
arsize: fn_DM_sbaccess_to_AXI4_Size (rg_sbcs_sbaccess),
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
master_xactor.i_rd_addr.enq (rda);
// Save read-address for byte-lane extraction from later response
// (since rg_sbaddress may be incremented by then).
rg_sbaddress_reading <= addr64;
// Save read-address for byte-lane extraction from later response
// (since rg_sbaddress may be incremented by then).
rg_sbaddress_reading <= addr64;
rg_sb_state <= SB_READ_FINISH;
rg_sb_state <= SB_READ_FINISH;
if (verbosity != 0) begin
$display (" DM_System_Bus.fa_fabric_send_read_req, and => SB_READ_FINISH ");
$display (" ", fshow (rda));
end
if (verbosity != 0) begin
$display (" DM_System_Bus.fa_fabric_send_read_req, and => SB_READ_FINISH ");
$display (" ", fshow (rda));
end
endaction
endfunction
@@ -295,41 +295,40 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function Action fa_fabric_send_write_req (Bit #(64) data64);
action
match {.fabric_addr,
.fabric_data,
.fabric_strb,
.fabric_size} = fn_to_fabric_write_fields (rg_sbcs_sbaccess, sbaddress, data64);
// fabric_addr is always fabric-data-width aligned
// fabric_data is properly lane-adjusted
// fabric_strb identifies the lanes to be written
// awsize is always the fabric width
match {.fabric_addr,
.fabric_data,
.fabric_strb,
.fabric_size} = fn_to_fabric_write_fields (rg_sbcs_sbaccess, sbaddress, data64);
// fabric_addr is always fabric-data-width aligned
// fabric_data is properly lane-adjusted
// fabric_strb identifies the lanes to be written
// awsize is always the fabric width
let wra = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: fabric_addr,
awlen: 0, // burst len = awlen+1
awsize: fabric_size,
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
master_xactor.i_wr_addr.enq (wra);
let wra = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: fabric_addr,
awlen: 0, // burst len = awlen+1
awsize: fabric_size,
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
master_xactor.i_wr_addr.enq (wra);
let wrd = AXI4_Wr_Data {wid: fabric_default_id,
wdata: fabric_data,
wstrb: fabric_strb,
wlast: True,
wuser: fabric_default_user};
master_xactor.i_wr_data.enq (wrd);
let wrd = AXI4_Wr_Data {wdata: fabric_data,
wstrb: fabric_strb,
wlast: True,
wuser: fabric_default_user};
master_xactor.i_wr_data.enq (wrd);
if (verbosity != 0) begin
$display (" DM_System_Bus.fa_fabric_send_write_req:");
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
end
if (verbosity != 0) begin
$display (" DM_System_Bus.fa_fabric_send_write_req:");
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
end
endaction
endfunction
@@ -338,54 +337,54 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function Action fa_rg_sbcs_write (DM_Word dm_word);
action
Bool sbbusyerror = unpack (dm_word [22]);
Bool sbreadonaddr = unpack (dm_word [20]);
DM_sbaccess sbaccess = unpack (dm_word [19:17]);
Bool sbautoincrement = unpack (dm_word [16]);
Bool sbreadondata = unpack (dm_word [15]);
DM_sberror sberror = unpack (dm_word [14:12]);
Bool sbbusyerror = unpack (dm_word [22]);
Bool sbreadonaddr = unpack (dm_word [20]);
DM_sbaccess sbaccess = unpack (dm_word [19:17]);
Bool sbautoincrement = unpack (dm_word [16]);
Bool sbreadondata = unpack (dm_word [15]);
DM_sberror sberror = unpack (dm_word [14:12]);
// No-op if not clearing existing sberror
if ((rg_sbcs_sberror != DM_SBERROR_NONE) && (sberror == DM_SBERROR_NONE)) begin
// Existing error is not being cleared
$display ("DM_System_Bus.sbcs_write <= 0x%08h: ERROR", dm_word);
$display (" ERROR: existing sberror (0x%0h) is not being cleared.", rg_sbcs_sberror);
$display (" Must be cleared to re-enable system bus access.");
end
// No-op if not clearing existing sberror
if ((rg_sbcs_sberror != DM_SBERROR_NONE) && (sberror == DM_SBERROR_NONE)) begin
// Existing error is not being cleared
$display ("DM_System_Bus.sbcs_write <= 0x%08h: ERROR", dm_word);
$display (" ERROR: existing sberror (0x%0h) is not being cleared.", rg_sbcs_sberror);
$display (" Must be cleared to re-enable system bus access.");
end
// No-op if not clearing existing sbbusyerror
else if (rg_sbcs_sbbusyerror && (! sbbusyerror)) begin
$display ("DM_System_Bus.sbcs_write <= 0x%08h: ERROR", dm_word);
$display (" ERROR: existing sbbusyerror (%0d) is not being cleared.", rg_sbcs_sbbusyerror);
$display (" Must be cleared to re-enable system bus access.");
end
// No-op if not clearing existing sbbusyerror
else if (rg_sbcs_sbbusyerror && (! sbbusyerror)) begin
$display ("DM_System_Bus.sbcs_write <= 0x%08h: ERROR", dm_word);
$display (" ERROR: existing sbbusyerror (%0d) is not being cleared.", rg_sbcs_sbbusyerror);
$display (" Must be cleared to re-enable system bus access.");
end
// Check that requested access size is supported
else if ( (sbaccess == DM_SBACCESS_128_BIT)
|| (sbaccess == DM_SBACCESS_64_BIT))
begin
rg_sbcs_sberror <= DM_SBERROR_OTHER;
$display ("DM_System_Bus.sbcs_write <= 0x%08h: ERROR", dm_word);
$display (" ERROR: sbaccess ", fshow (sbaccess), " not supported");
end
// Check that requested access size is supported
else if ( (sbaccess == DM_SBACCESS_128_BIT)
|| (sbaccess == DM_SBACCESS_64_BIT))
begin
rg_sbcs_sberror <= DM_SBERROR_OTHER;
$display ("DM_System_Bus.sbcs_write <= 0x%08h: ERROR", dm_word);
$display (" ERROR: sbaccess ", fshow (sbaccess), " not supported");
end
// Ok
else begin
if (verbosity != 0) begin
$display (" DM_System_Bus.sbcs_write: ", fshow_sbcs (dm_word));
if (rg_sbcs_sberror != DM_SBERROR_NONE)
$display (" Clearing sbcs.sberror");
if (rg_sbcs_sbbusyerror)
$display (" Clearing sbcs.sbbusyerror");
end
// Ok
else begin
if (verbosity != 0) begin
$display (" DM_System_Bus.sbcs_write: ", fshow_sbcs (dm_word));
if (rg_sbcs_sberror != DM_SBERROR_NONE)
$display (" Clearing sbcs.sberror");
if (rg_sbcs_sbbusyerror)
$display (" Clearing sbcs.sbbusyerror");
end
rg_sbcs_sbbusyerror <= False;
rg_sbcs_sbreadonaddr <= sbreadonaddr;
rg_sbcs_sbaccess <= sbaccess;
rg_sbcs_sbautoincrement <= sbautoincrement;
rg_sbcs_sbreadondata <= sbreadondata;
rg_sbcs_sberror <= DM_SBERROR_NONE;
end
rg_sbcs_sbbusyerror <= False;
rg_sbcs_sbreadonaddr <= sbreadonaddr;
rg_sbcs_sbaccess <= sbaccess;
rg_sbcs_sbautoincrement <= sbautoincrement;
rg_sbcs_sbreadondata <= sbreadondata;
rg_sbcs_sberror <= DM_SBERROR_NONE;
end
endaction
endfunction: fa_rg_sbcs_write
@@ -394,54 +393,54 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function Action fa_rg_sbaddress_write (DM_Addr dm_addr, DM_Word dm_word);
action
// Debug announce
if (verbosity != 0) begin
$write ("DM_System_Bus.sbaddress.write: [0x%08h] <= 0x%08h", dm_addr, dm_word);
if (rg_sbcs_sbreadonaddr) begin
$write ("; readonaddr");
if (rg_sbcs_sbautoincrement)
$write ("; autoincrement");
end
$display ("");
end
// Debug announce
if (verbosity != 0) begin
$write ("DM_System_Bus.sbaddress.write: [0x%08h] <= 0x%08h", dm_addr, dm_word);
if (rg_sbcs_sbreadonaddr) begin
$write ("; readonaddr");
if (rg_sbcs_sbautoincrement)
$write ("; autoincrement");
end
$display ("");
end
if (sbbusy) begin
$display ("DM_System_Bus.sbaddress.write: busy, setting sbbusyerror");
rg_sbcs_sbbusyerror <= True;
end
if (sbbusy) begin
$display ("DM_System_Bus.sbaddress.write: busy, setting sbbusyerror");
rg_sbcs_sbbusyerror <= True;
end
else if (rg_sbcs_sbbusyerror)
$display ("DM_System_Bus.sbaddress.write: ignoring due to sbbusyerror");
else if (rg_sbcs_sbbusyerror)
$display ("DM_System_Bus.sbaddress.write: ignoring due to sbbusyerror");
else if (rg_sbcs_sberror != DM_SBERROR_NONE)
$display ("DM_System_Bus.sbaddress.write: ignoring due to sberror = 0x%0h",
rg_sbcs_sberror);
else if (rg_sbcs_sberror != DM_SBERROR_NONE)
$display ("DM_System_Bus.sbaddress.write: ignoring due to sberror = 0x%0h",
rg_sbcs_sberror);
else if (dm_addr == dm_addr_sbaddress0) begin
Bit #(64) addr64 = { rg_sbaddress1, dm_word };
if (rg_sbcs_sbreadonaddr) begin
fa_fabric_send_read_req (addr64);
if (rg_sbcs_sbautoincrement)
fa_sbaddress_incr (addr64);
else
rg_sbaddress0 <= dm_word;
end
else
rg_sbaddress0 <= dm_word;
end
else if (dm_addr == dm_addr_sbaddress0) begin
Bit #(64) addr64 = { rg_sbaddress1, dm_word };
if (rg_sbcs_sbreadonaddr) begin
fa_fabric_send_read_req (addr64);
if (rg_sbcs_sbautoincrement)
fa_sbaddress_incr (addr64);
else
rg_sbaddress0 <= dm_word;
end
else
rg_sbaddress0 <= dm_word;
end
else begin // (dm_addr == dm_addr_sbaddress1)
else begin // (dm_addr == dm_addr_sbaddress1)
`ifdef RV32
rg_sbaddress1 <= 0;
if (verbosity != 0)
$display ("DM_System_Bus.write: [sbaddress1] <= 0 (RV32: ignoring arg value 0x%08h)",
dm_word);
rg_sbaddress1 <= 0;
if (verbosity != 0)
$display ("DM_System_Bus.write: [sbaddress1] <= 0 (RV32: ignoring arg value 0x%08h)",
dm_word);
`else
rg_sbaddress1 <= dm_word;
if (verbosity != 0)
$display ("DM_System_Bus.write: [sbaddress1] <= 0x%08h", dm_word);
rg_sbaddress1 <= dm_word;
if (verbosity != 0)
$display ("DM_System_Bus.write: [sbaddress1] <= 0x%08h", dm_word);
`endif
end
end
endaction
endfunction
@@ -450,35 +449,35 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function ActionValue #(DM_Word) fav_rg_sbdata_read (DM_Addr dm_addr);
actionvalue
DM_Word result = 0;
if (sbbusy) begin
$display ("DM_System_Bus.sbdata.read: busy, setting sbbusyerror");
rg_sbcs_sbbusyerror <= True;
end
DM_Word result = 0;
if (sbbusy) begin
$display ("DM_System_Bus.sbdata.read: busy, setting sbbusyerror");
rg_sbcs_sbbusyerror <= True;
end
else if (rg_sbcs_sbbusyerror)
$display ("DM_System_Bus.sbdata.read: ignoring due to sbbusyerror");
else if (rg_sbcs_sbbusyerror)
$display ("DM_System_Bus.sbdata.read: ignoring due to sbbusyerror");
else if (rg_sbcs_sberror != DM_SBERROR_NONE)
$display ("DM_System_Bus.sbdata.read: ignoring due to sberror = 0x%0h", rg_sbcs_sberror);
else if (rg_sbcs_sberror != DM_SBERROR_NONE)
$display ("DM_System_Bus.sbdata.read: ignoring due to sberror = 0x%0h", rg_sbcs_sberror);
else begin
if (dm_addr == dm_addr_sbdata0)
result = rg_sbdata0;
/* FUTURE: when supporting DM_SBACCESS_64_BIT
else if (dm_addr == dm_addr_sbdata1)
result = rg_sbdata1;
*/
else begin
if (dm_addr == dm_addr_sbdata0)
result = rg_sbdata0;
/* FUTURE: when supporting DM_SBACCESS_64_BIT
else if (dm_addr == dm_addr_sbdata1)
result = rg_sbdata1;
*/
// Increment sbaddress if needed
if (rg_sbcs_sbautoincrement)
fa_sbaddress_incr (sbaddress);
// Increment sbaddress if needed
if (rg_sbcs_sbautoincrement)
fa_sbaddress_incr (sbaddress);
// Auto-read next data if needed
if (rg_sbcs_sbreadondata && (dm_addr == dm_addr_sbdata0))
fa_fabric_send_read_req (sbaddress);
end
return result;
// Auto-read next data if needed
if (rg_sbcs_sbreadondata && (dm_addr == dm_addr_sbdata0))
fa_fabric_send_read_req (sbaddress);
end
return result;
endactionvalue
endfunction
@@ -488,19 +487,19 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
(* descending_urgency = "rl_sb_read_finish, reset" *)
(* descending_urgency = "rl_sb_read_finish, write" *)
rule rl_sb_read_finish ( (rg_sb_state == SB_READ_FINISH)
&& (rg_sbcs_sberror == DM_SBERROR_NONE));
&& (rg_sbcs_sberror == DM_SBERROR_NONE));
let rdr <- pop_o (master_xactor.o_rd_data);
if (verbosity != 0)
$display ("DM_System_Bus.rule_sb_read_finish: rdr = ", fshow (rdr));
$display ("DM_System_Bus.rule_sb_read_finish: rdr = ", fshow (rdr));
// Extract relevant bytes from fabric data
Bit #(64) rdata64 = zeroExtend (rdr.rdata);
Bit #(64) data = fn_extract_and_extend_bytes (rg_sbcs_sbaccess, rg_sbaddress_reading, rdata64);
if (rdr.rresp != axi4_resp_okay) begin
$display ("DM_System_Bus.rule_sb_read_finish: setting rg_sbcs_sberror to DM_SBERROR_OTHER\n");
$display (" rdr = ", fshow (rdr));
rg_sbcs_sberror <= DM_SBERROR_OTHER;
$display ("DM_System_Bus.rule_sb_read_finish: setting rg_sbcs_sberror to DM_SBERROR_OTHER\n");
$display (" rdr = ", fshow (rdr));
rg_sbcs_sberror <= DM_SBERROR_OTHER;
end
rg_sbdata0 <= data [31:0];
@@ -509,10 +508,10 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
*/
if (verbosity != 0) begin
$display ("DM_System_Bus.rule_sb_read_finish: addr 0x%0h, sbaccess %0d (%0d bytes)",
rg_sbaddress_reading, rg_sbcs_sbaccess, addr_incr);
$display (" rg_sbdata0 <= 0x%0h", data);
$display (" module state => SB_NOTBUSY");
$display ("DM_System_Bus.rule_sb_read_finish: addr 0x%0h, sbaccess %0d (%0d bytes)",
rg_sbaddress_reading, rg_sbcs_sbaccess, addr_incr);
$display (" rg_sbdata0 <= 0x%0h", data);
$display (" module state => SB_NOTBUSY");
end
rg_sb_state <= SB_NOTBUSY;
@@ -523,41 +522,41 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
function Action fa_rg_sbdata_write (DM_Addr dm_addr, DM_Word dm_word);
action
if (sbbusy) begin
$display ("DM_System_Bus.sbdata.write: busy, setting sbbusyerror");
rg_sbcs_sbbusyerror <= True;
end
if (sbbusy) begin
$display ("DM_System_Bus.sbdata.write: busy, setting sbbusyerror");
rg_sbcs_sbbusyerror <= True;
end
else if (rg_sbcs_sbbusyerror) begin
$display ("DM_System_Bus.sbdata.write: ignoring due to sbbusyerror");
end
else if (rg_sbcs_sbbusyerror) begin
$display ("DM_System_Bus.sbdata.write: ignoring due to sbbusyerror");
end
else if (rg_sbcs_sberror != DM_SBERROR_NONE) begin
$display ("DM_System_Bus.sbdata.write: ignoring due to sberror = 0x%0h",
rg_sbcs_sberror);
end
else if (rg_sbcs_sberror != DM_SBERROR_NONE) begin
$display ("DM_System_Bus.sbdata.write: ignoring due to sberror = 0x%0h",
rg_sbcs_sberror);
end
else begin
if (verbosity != 0)
$display (" DM_System_Bus.fa_rg_sbdata_write: dm_addr 0x%08h dm_word 0x%08h",
dm_addr, dm_word);
else begin
if (verbosity != 0)
$display (" DM_System_Bus.fa_rg_sbdata_write: dm_addr 0x%08h dm_word 0x%08h",
dm_addr, dm_word);
if (dm_addr == dm_addr_sbdata0)
rg_sbdata0 <= dm_word;
/* FUTURE: when supporting DM_SBACCESS_64_BIT
else if (dm_addr == dm_addr_sbdata1)
rg_sbdata1 <= dm_word;
*/
if (dm_addr == dm_addr_sbdata0)
rg_sbdata0 <= dm_word;
/* FUTURE: when supporting DM_SBACCESS_64_BIT
else if (dm_addr == dm_addr_sbdata1)
rg_sbdata1 <= dm_word;
*/
// Initiate system bus write if writing to sbdata0
if (dm_addr == dm_addr_sbdata0) begin
fa_fabric_send_write_req (zeroExtend (dm_word));
// Initiate system bus write if writing to sbdata0
if (dm_addr == dm_addr_sbdata0) begin
fa_fabric_send_write_req (zeroExtend (dm_word));
// Increment sbaddr ifneeded
if (rg_sbcs_sbautoincrement)
fa_sbaddress_incr (sbaddress);
end
end
// Increment sbaddr ifneeded
if (rg_sbcs_sbautoincrement)
fa_sbaddress_incr (sbaddress);
end
end
endaction
endfunction
@@ -567,7 +566,7 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
rule rl_sb_write_response;
let wrr <- pop_o (master_xactor.o_wr_resp);
if (wrr.bresp != axi4_resp_okay)
rg_sbcs_sberror <= DM_SBERROR_OTHER;
rg_sbcs_sberror <= DM_SBERROR_OTHER;
endrule
// ================================================================
@@ -590,7 +589,7 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
rg_sbdata0 <= 0;
if (verbosity != 0)
$display ("DM_System_Bus: reset");
$display ("DM_System_Bus: reset");
endmethod
// ----------------
@@ -601,55 +600,55 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
// workable for a true JTAG transport.
method ActionValue #(DM_Word) av_read (DM_Addr dm_addr) if (!sbbusy);
actionvalue
DM_Word dm_word = 0;
DM_Word dm_word = 0;
if (dm_addr == dm_addr_sbcs) begin
dm_word = virt_rg_sbcs;
if (verbosity != 0)
$display ("DM_System_Bus.read: [sbcs] => ", fshow_sbcs (dm_word));
end
if (dm_addr == dm_addr_sbcs) begin
dm_word = virt_rg_sbcs;
if (verbosity != 0)
$display ("DM_System_Bus.read: [sbcs] => ", fshow_sbcs (dm_word));
end
else if (dm_addr == dm_addr_sbaddress0) begin
dm_word = rg_sbaddress0;
if (verbosity != 0)
$display ("DM_System_Bus.read: [sbaddress0] => 0x%08h", dm_word);
end
else if (dm_addr == dm_addr_sbaddress0) begin
dm_word = rg_sbaddress0;
if (verbosity != 0)
$display ("DM_System_Bus.read: [sbaddress0] => 0x%08h", dm_word);
end
else if (dm_addr == dm_addr_sbaddress1) begin
dm_word = rg_sbaddress1;
if (verbosity != 0)
$display ("DM_System_Bus.read: [sbaddress1] => 0x%08h", dm_word);
end
else if (dm_addr == dm_addr_sbaddress1) begin
dm_word = rg_sbaddress1;
if (verbosity != 0)
$display ("DM_System_Bus.read: [sbaddress1] => 0x%08h", dm_word);
end
else if (dm_addr == dm_addr_sbdata0) begin
dm_word <- fav_rg_sbdata_read (dm_addr_sbdata0);
end
else if (dm_addr == dm_addr_sbdata0) begin
dm_word <- fav_rg_sbdata_read (dm_addr_sbdata0);
end
else begin
// Unsupported dm address
dm_word = 0;
$display ("DM_System_Bus.read: [", fshow_dm_addr (dm_addr), "] not supported");
end
return dm_word;
else begin
// Unsupported dm address
dm_word = 0;
$display ("DM_System_Bus.read: [", fshow_dm_addr (dm_addr), "] not supported");
end
return dm_word;
endactionvalue
endmethod
method Action write (DM_Addr dm_addr, DM_Word dm_word);
action
if (dm_addr == dm_addr_sbcs)
if (dm_addr == dm_addr_sbcs)
fa_rg_sbcs_write (dm_word);
else if ((dm_addr == dm_addr_sbaddress0) || (dm_addr == dm_addr_sbaddress1))
fa_rg_sbaddress_write (dm_addr, dm_word);
else if ((dm_addr == dm_addr_sbaddress0) || (dm_addr == dm_addr_sbaddress1))
fa_rg_sbaddress_write (dm_addr, dm_word);
else if (dm_addr == dm_addr_sbdata0) // FUTURE: || (dm_addr == dm_addr_sbdata1)
fa_rg_sbdata_write (dm_addr, dm_word);
else if (dm_addr == dm_addr_sbdata0) // FUTURE: || (dm_addr == dm_addr_sbdata1)
fa_rg_sbdata_write (dm_addr, dm_word);
else begin
// Unsupported dm_addr
let addr_name = fshow_dm_addr (dm_addr);
$display ("DM_System_Bus.write: [", addr_name, "] <= 0x%08h; addr not supported", dm_word);
end
else begin
// Unsupported dm_addr
let addr_name = fshow_dm_addr (dm_addr);
$display ("DM_System_Bus.write: [", addr_name, "] <= 0x%08h; addr not supported", dm_word);
end
endaction
endmethod

View File

@@ -96,7 +96,7 @@ interface Debug_Module_IFC;
// This section replicated for additional harts.
// Reset and run-control
interface Get #(Token) hart0_get_reset_req;
interface Client #(Bool, Bool) hart0_reset_client;
interface Client #(Bool, Bool) hart0_client_run_halt;
interface Get #(Bit #(4)) hart0_get_other_req;
@@ -115,7 +115,8 @@ interface Debug_Module_IFC;
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
interface Get #(Token) get_ndm_reset_req;
// Bool indicates 'running' hart state.
interface Client #(Bool, Bool) ndm_reset_client;
// Read/Write RISC-V memory
interface AXI4_Master_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master;
@@ -126,6 +127,9 @@ endinterface
(* synthesize *)
module mkDebug_Module (Debug_Module_IFC);
// Local verbosity: 0 = quiet; 1 = print DMI transactions
Integer verbosity = 0;
// The three parts
DM_Run_Control_IFC dm_run_control <- mkDM_Run_Control;
DM_Abstract_Commands_IFC dm_abstract_commands <- mkDM_Abstract_Commands;
@@ -151,116 +155,127 @@ module mkDebug_Module (Debug_Module_IFC);
interface DMI dmi;
method Action read_addr (DM_Addr dm_addr);
f_read_addr.enq(dm_addr);
f_read_addr.enq(dm_addr);
if (verbosity != 0)
$display ("%0d: %m.DMI read: dm_addr 0x%0h", cur_cycle, dm_addr);
endmethod
method ActionValue #(DM_Word) read_data;
let dm_addr = f_read_addr.first;
f_read_addr.deq;
let dm_addr = f_read_addr.first;
f_read_addr.deq;
DM_Word dm_word = ?;
DM_Word dm_word = ?;
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_haltregion0)
|| (dm_addr == dm_addr_haltregion31)
|| (dm_addr == dm_addr_verbosity))
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_haltregion0)
|| (dm_addr == dm_addr_haltregion31)
|| (dm_addr == dm_addr_verbosity))
dm_word <- dm_run_control.av_read (dm_addr);
dm_word <- dm_run_control.av_read (dm_addr);
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
dm_word <- dm_abstract_commands.av_read (dm_addr);
dm_word <- dm_abstract_commands.av_read (dm_addr);
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
dm_word <- dm_system_bus.av_read (dm_addr);
dm_word <- dm_system_bus.av_read (dm_addr);
else begin
// TODO: set error status?
dm_word = 0;
end
else begin
// TODO: set error status?
dm_word = 0;
end
return dm_word;
if (verbosity != 0)
$display ("%0d: %m.DMI read response: dm_addr 0x%0h, dm_word 0x%0h",
cur_cycle, dm_addr, dm_word);
return dm_word;
endmethod
method Action write (DM_Addr dm_addr, DM_Word dm_word);
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_haltregion0)
|| (dm_addr == dm_addr_haltregion31)
|| (dm_addr == dm_addr_verbosity))
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_haltregion0)
|| (dm_addr == dm_addr_haltregion31)
|| (dm_addr == dm_addr_verbosity))
dm_run_control.write (dm_addr, dm_word);
dm_run_control.write (dm_addr, dm_word);
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
dm_abstract_commands.write (dm_addr, dm_word);
dm_abstract_commands.write (dm_addr, dm_word);
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
dm_system_bus.write (dm_addr, dm_word);
dm_system_bus.write (dm_addr, dm_word);
else begin
// TODO: set error status?
noAction;
end
else begin
// TODO: set error status?
noAction;
end
if (verbosity != 0)
$display ("%0d: %m.DMI write: dm_addr 0x%0h, dm_word 0x%0h",
cur_cycle, dm_addr, dm_word);
endmethod
endinterface
@@ -268,7 +283,7 @@ module mkDebug_Module (Debug_Module_IFC);
// Facing CPU/hart0
// Reset and run-control
interface Get hart0_get_reset_req = dm_run_control.hart0_get_reset_req;
interface Client hart0_reset_client = dm_run_control.hart0_reset_client;
interface Client hart0_client_run_halt = dm_run_control.hart0_client_run_halt;
interface Get hart0_get_other_req = dm_run_control.hart0_get_other_req;
@@ -287,7 +302,7 @@ module mkDebug_Module (Debug_Module_IFC);
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
interface Get get_ndm_reset_req = dm_run_control.get_ndm_reset_req;
interface Client ndm_reset_client = dm_run_control.ndm_reset_client;
// Read/Write RISC-V memory
interface AXI4_Master_IFC master = dm_system_bus.master;

View File

@@ -1,3 +1,206 @@
'Debug_Module' implements a Debug Module for RISC-V processors in
accordance with the RISC-V standard "External Debug Support" spec:
RISC-V External Debug Support
Version 0.13.2
d5029366d59e8563c08b6b9435f82573b603e48e
Fri Mar 22 09:06:04 2019 -0700
Note: the spec is independent of any particular RISC-V CPU
implementation. It just specifies the standard registers in the Debug
Module that can be read and written by an external debugger (such as
GDB). It specifies the address map of these registers, and the
semantics, i.e., what happens when one reads or writes these
registers. The spec does not say anything about how this spec is
implemented.
Please see comments in Debug_Module.bsv for more details on our
implementation of the Debug Module spec. This implementation is also
not specific to any particular CPU implementation. We use it in
multiple Bluespec RISC-V CPU implementations, and it could be used
with other CPU implementations as well.
// ================================================================
What follows is a concise cheat-sheet for the registers in the Debug Module.
DM_Addr dm_addr_data0 = 'h04;
DM_Addr dm_addr_data1 = 'h05;
DM_Addr dm_addr_data2 = 'h06;
DM_Addr dm_addr_data3 = 'h07;
DM_Addr dm_addr_data4 = 'h08;
DM_Addr dm_addr_data5 = 'h09;
DM_Addr dm_addr_data6 = 'h0a;
DM_Addr dm_addr_data7 = 'h0b;
DM_Addr dm_addr_data8 = 'h0c;
DM_Addr dm_addr_data9 = 'h0d;
DM_Addr dm_addr_data10 = 'h0d;
DM_Addr dm_addr_data11 = 'h0f;
// ----------------
// Run Control
DM_Addr dm_addr_dmcontrol = 'h10;
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
| | | | 0 | | | | | 0 0 | | | |dmactive
| | | | | | | | | | | |ndmreset
| | | | | | | | | | |clrresethaltreq
| | | | | | | | | |setresethaltreq
| | | | | | | |-----------10-----------|hartselhi
| | | | | |------------10--------------|hartsello
| | | | |hasel
| | | | 0: Single hart selected (hartsel)
| | | | 1: Multiple harts selected (hartsel + hart array mask)
| | | |ackhavereset
| | |hartreset
| |resumereq
|haltreq
DM_Addr dm_addr_dmstatus = 'h11;
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
0 0 0 0 0 0 0 0 | | 0 0 | | | | | | | | | | | | | | | | |--4--|version
| | | | | | | | | | | | | | | | | | | 0: no DM present
| | | | | | | | | | | | | | | | | | | 1: DM v011
| | | | | | | | | | | | | | | | | | | 2: DM v013
| | | | | | | | | | | | | | | | | | | 15: DM vUnknown
| | | | | | | | | | | | | | | | | |confstrptrvalid
| | | | | | | | | | | | | | | | |hasresethaltreq
| | | | | | | | | | | | | | | |authbusy
| | | | | | | | | | | | | | |authenticated
| | | | | | | | | | | | | |anyhalted
| | | | | | | | | | | | |allhalted
| | | | | | | | | | | |anyrunning
| | | | | | | | | | |allrunning
| | | | | | | | | |anyunavail
| | | | | | | | |allunavail
| | | | | | | |anynonexistent
| | | | | | |allnonexistent
| | | | | |anyresumeack
| | | | |allresumeack
| | | |anyhavereset
| | |allhavereset
| |impebreak
| 0 No implicit EBREAK at end of PB
| 1 Implicit EBREAK at end of PB
DM_Addr dm_addr_hartinfo = 'h12;
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
0 0 0 0 0 0 0 0 | | 0 0 0 | | | |-----------12-----------|dataaddr
| | | |----4---|datasize
|----4---|nscratch |dataaccess
DM_Addr dm_addr_haltsum1 = 'h13;
DM_Addr dm_addr_hawindowsel = 'h14;
DM_Addr dm_addr_hawindow = 'h15;
// ----------------
// Abstract commands (read/write RISC-V registers and RISC-V CSRs)
DM_Addr dm_addr_abstractcs = 'h16;
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
0 0 0 | | 0 0 0 0 0 0 0 0 0 0 0 | 0 | | 0 0 0 0 |--4--|datacount
0 0 0 |-----5------|progbufsize |busy |-3-|cmderr
DM_Addr dm_addr_command = 'h17;
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
| 0 | | | | | | |-----------------16------------------|regno
| | | | | | | | 0x0000-0x0FFF CSRs (dpc => PC)
| | | | | | | | 0x1000-0x101F GPRs
| | | | | | | | 0x1020-0x103F Floating Point Regs
| | | | | | | | 0xC000-0xFFFF Reserved
| | | | | | |write
| | | | | | 0: specified reg -> arg0 of data
| | | | | | 1: specified reg <- arg0 of data
| | | | | |transfer
| | | | | 0 Don't do the 'write' op
| | | | | 1 Do the 'write' op
| | | | | Allows exec of PB without valid vals in 'size' and 'regno'
| | | | |postexec
| | | | 1 exec Program Buffer exactly once after the xfer
| | | |aarpostincrement
| |--3--|aarsize
| 2 Lowest 32b of reg
| 3 Lowest 64b of reg
| 4 Lowest 128b of reg
|---------8-----------|cmdtype
0 ACCESS_REG
1 QUICK_ACCESS
DM_Addr dm_addr_abstractauto = 'h18;
DM_Addr dm_addr_confstrptr0 = 'h19;
DM_Addr dm_addr_confstrptr1 = 'h1a;
DM_Addr dm_addr_confstrptr2 = 'h1b;
DM_Addr dm_addr_confstrptr3 = 'h1c;
DM_Addr dm_addr_nextdm = 'h1d;
DM_Addr dm_addr_progbuf0 = 'h20;
DM_Addr dm_addr_progbuf1 = 'h21;
DM_Addr dm_addr_progbuf2 = 'h22;
DM_Addr dm_addr_progbuf3 = 'h23;
DM_Addr dm_addr_progbuf4 = 'h24;
DM_Addr dm_addr_progbuf5 = 'h25;
DM_Addr dm_addr_progbuf6 = 'h26;
DM_Addr dm_addr_progbuf7 = 'h27;
DM_Addr dm_addr_progbuf8 = 'h28;
DM_Addr dm_addr_progbuf9 = 'h29;
DM_Addr dm_addr_progbuf10 = 'h2a;
DM_Addr dm_addr_progbuf11 = 'h2b;
DM_Addr dm_addr_progbuf12 = 'h2c;
DM_Addr dm_addr_progbuf13 = 'h2d;
DM_Addr dm_addr_progbuf14 = 'h2e;
DM_Addr dm_addr_progbuf15 = 'h2f;
DM_Addr dm_addr_authdata = 'h30;
DM_Addr dm_addr_haltsum2 = 'h34;
DM_Addr dm_addr_haltsum3 = 'h35;
DM_Addr dm_addr_sbaddress3 = 'h37;
// ----------------
// System Bus access (read/write RISC-V memory/devices)
DM_Addr dm_addr_sbcs = 'h38;
31.30.29.28| 27.26.25.24| 23.22.21.20| 19.18.17.16| 15.14.13.12| 11.10.9.8| 7.6.5.4| 3.2.1.0|
| | 0 0 0 0 0 0 | | | | | | | | | | | | | | | |sbaccess8
| | | | | | | | | | | | | | | | |sbaccess16
| | | | | | | | | | | | | | | |sbaccess32
| | | | | | | | | | | | | | |sbaccess64
| | | | | | | | | | | | | |sbaccess128
| | | | | | | | | | | |-----7-------|sbasize
| | | | | | | | | |--3--|sberror
| | | | | | | | | 0: no bus err
| | | | | | | | | 1: timeout
| | | | | | | | | 2: bad addr
| | | | | | | | | 3: alignment err
| | | | | | | | | 4: unsupported size
| | | | | | | | | 7: other
| | | | | | | | |sbreadondata: read on sbdata0 triggers sb read
| | | | | | | |sbautoincrement
| | | | | |--3--|sbaccess
| | | | | 0:8b, 1:16b, 2:32b, 3:64b, 4:128b
| | | | |sbreadonaddr
| | | | 1 Every write to sbaddress0 triggers sb read at new addr
| | | |sbbusy
| | |sbbusyerror
|--3--|sbversion
0: System Bus interface spec version < 2018-01-01
1: This System Bus interface spec version
DM_Addr dm_addr_sbaddress0 = 'h39;
DM_Addr dm_addr_sbaddress1 = 'h3a;
DM_Addr dm_addr_sbaddress2 = 'h3b;
DM_Addr dm_addr_sbdata0 = 'h3c;
DM_Addr dm_addr_sbdata1 = 'h3d;
DM_Addr dm_addr_sbdata2 = 'h3e;
DM_Addr dm_addr_sbdata3 = 'h3f;
DM_Addr dm_addr_haltsum0 = 'h40;
// ================================================================
// ================================================================
// OLDER VERSIONS OF THE DEBUG MODULE SPEC
// ================================================================
// ================================================================
'Debug_Module' implements a Debug Module for RISC-V processors in
accordance with the RISC-V standard "External Debug Support" spec:

View File

@@ -46,8 +46,8 @@ module mkTestbench (Empty);
rule rl_count_cycles;
if (rg_cycle == fromInteger (100)) begin
$display ("Testench: stopping at cycle %0d", cycle_limit);
$finish (0);
$display ("Testench: stopping at cycle %0d", cycle_limit);
$finish (0);
end
rg_cycle <= rg_cycle +1;
endrule
@@ -90,8 +90,8 @@ module mkTestbench (Empty);
let rda <- pop_o (dm.master.fo_rda);
let data = rda.addr + 2; // Bogus data, for now
let rdr = TRX_RdR {trans_id: rda.trans_id,
status : TRX_OKAY,
data : data};
status : TRX_OKAY,
data : data};
dm.master.fi_rdr.enq (rdr);
$display ("Testbench: memory read [0x%08h] => 0x%08h", rda.addr, data);
endrule
@@ -100,7 +100,7 @@ module mkTestbench (Empty);
let wra <- pop_o (dm.master.fo_wra);
let wrd <- pop_o (dm.master.fo_wrd);
let wrr = TRX_WrR {trans_id: wra.trans_id,
status : TRX_OKAY};
status : TRX_OKAY};
dm.master.fi_wrr.enq (wrr);
$display ("Testbench: memory write [0x%08h] <= 0x%08h", wra.addr, wrd.data);
endrule
@@ -114,34 +114,34 @@ module mkTestbench (Empty);
function Stmt fn_stmt_read_reg (Bit #(16) regno);
return
seq
$display ("----------------\nRead RISC-V reg");
// Clear any prior error status
dm.write (dm_addr_abstractcs, fn_mk_abstractcs (dm_cmderr_w1c));
// Perform the read
dm.write (dm_addr_command,
fn_mk_command_access_reg (DM_COMMAND_ACCESS_REG_SIZE_LOWER32,
False, // postexec
True, // transfer
False, // write
regno));
// Read status to check no error
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
while (fn_abstractcs_busy (rg_abstractcs)) seq
$display ("Testbench: read reg: busy");
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
endseq
if (fn_abstractcs_cmderr (rg_abstractcs) != DM_ABSTRACTCS_CMDERR_NONE)
$display ("Testbench: read reg => ", fshow (fn_abstractcs_cmderr (rg_abstractcs)));
else action
let x <- dm.av_read (dm_addr_data0);
$display ("Testbench: read reg => 0x%08h", x);
endaction
$display ("----------------\nRead RISC-V reg");
// Clear any prior error status
dm.write (dm_addr_abstractcs, fn_mk_abstractcs (dm_cmderr_w1c));
// Perform the read
dm.write (dm_addr_command,
fn_mk_command_access_reg (DM_COMMAND_ACCESS_REG_SIZE_LOWER32,
False, // postexec
True, // transfer
False, // write
regno));
// Read status to check no error
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
while (fn_abstractcs_busy (rg_abstractcs)) seq
$display ("Testbench: read reg: busy");
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
endseq
if (fn_abstractcs_cmderr (rg_abstractcs) != DM_ABSTRACTCS_CMDERR_NONE)
$display ("Testbench: read reg => ", fshow (fn_abstractcs_cmderr (rg_abstractcs)));
else action
let x <- dm.av_read (dm_addr_data0);
$display ("Testbench: read reg => 0x%08h", x);
endaction
endseq;
endfunction
@@ -149,31 +149,31 @@ module mkTestbench (Empty);
function Stmt fn_stmt_write_reg (Bit #(16) regno, Bit #(32) data);
return
seq
$display ("----------------\nWrite RISC-V reg");
// Clear any prior error status
dm.write (dm_addr_abstractcs, fn_mk_abstractcs (dm_cmderr_w1c));
// Write data0
dm.write (dm_addr_data0, data);
// Perform the write
dm.write (dm_addr_command,
fn_mk_command_access_reg (DM_COMMAND_ACCESS_REG_SIZE_LOWER32,
False, // postexec
True, // transfer
True, // write
regno));
// Read status to check no error
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
while (fn_abstractcs_busy (rg_abstractcs)) seq
$display ("Testbench: write reg: busy");
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
endseq
$display ("Testbench: write reg => ", fshow (fn_abstractcs_cmderr (rg_abstractcs)));
$display ("----------------\nWrite RISC-V reg");
// Clear any prior error status
dm.write (dm_addr_abstractcs, fn_mk_abstractcs (dm_cmderr_w1c));
// Write data0
dm.write (dm_addr_data0, data);
// Perform the write
dm.write (dm_addr_command,
fn_mk_command_access_reg (DM_COMMAND_ACCESS_REG_SIZE_LOWER32,
False, // postexec
True, // transfer
True, // write
regno));
// Read status to check no error
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
while (fn_abstractcs_busy (rg_abstractcs)) seq
$display ("Testbench: write reg: busy");
action
let x <- dm.av_read (dm_addr_abstractcs);
rg_abstractcs <= x;
endaction
endseq
$display ("Testbench: write reg => ", fshow (fn_abstractcs_cmderr (rg_abstractcs)));
endseq;
endfunction
@@ -188,102 +188,102 @@ module mkTestbench (Empty);
Stmt stmt_wait_for_sb_nonbusy = (
seq
rg_busy <= True;
while (rg_busy) seq
delay (1);
action
let x <- dm.av_read (dm_addr_sbcs);
let sberror = fn_sbcs_sberror (x);
rg_busy <= (sberror == DM_SBERROR_BUSY_STALE);
if ( (sberror != DM_SBERROR_NONE)
&& (sberror != DM_SBERROR_BUSY_STALE))
begin
$display ("Testbench: stmt_wait_for_sb_nonbusy: ", fshow (sberror));
$finish (1);
end
endaction
endseq
rg_busy <= True;
while (rg_busy) seq
delay (1);
action
let x <- dm.av_read (dm_addr_sbcs);
let sberror = fn_sbcs_sberror (x);
rg_busy <= (sberror == DM_SBERROR_BUSY_STALE);
if ( (sberror != DM_SBERROR_NONE)
&& (sberror != DM_SBERROR_BUSY_STALE))
begin
$display ("Testbench: stmt_wait_for_sb_nonbusy: ", fshow (sberror));
$finish (1);
end
endaction
endseq
endseq);
// Do a single-read from memory
Stmt stmt_mem_read_1 = (
seq
dm.write (dm_addr_sbaddress0, 'h1_0000);
dm.write (dm_addr_sbcs, fn_mk_sbcs (True, // sbsingleread
DM_SBACCESS_32_BIT,
False, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
action
let x <- dm.av_read (dm_addr_sbdata0);
$display ("stmt_mem_read_1: read-data = 0x%08h", x);
endaction
dm.write (dm_addr_sbaddress0, 'h1_0000);
dm.write (dm_addr_sbcs, fn_mk_sbcs (True, // sbsingleread
DM_SBACCESS_32_BIT,
False, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
action
let x <- dm.av_read (dm_addr_sbdata0);
$display ("stmt_mem_read_1: read-data = 0x%08h", x);
endaction
endseq);
// Do a multiple-read from memory
Stmt stmt_mem_read_4 = (
seq
dm.write (dm_addr_sbaddress0, 'h1_0000);
dm.write (dm_addr_sbcs, fn_mk_sbcs (True, // sbsingleread
DM_SBACCESS_32_BIT,
True, // sbautoincrement
True, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
for (rg_j <= 0; rg_j < 3; rg_j <= rg_j + 1) seq
stmt_wait_for_sb_nonbusy;
action
let x <- dm.av_read (dm_addr_sbdata0);
$display ("stmt_mem_read_4: read-data [%0d] = 0x%08h", rg_j, x);
endaction
endseq
dm.write (dm_addr_sbcs, fn_mk_sbcs (False, // sbsingleread
DM_SBACCESS_32_BIT,
False, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
action
let x <- dm.av_read (dm_addr_sbdata0);
$display ("stmt_mem_read_4: read-data [%0d] = 0x%08h", rg_j, x);
endaction
dm.write (dm_addr_sbaddress0, 'h1_0000);
dm.write (dm_addr_sbcs, fn_mk_sbcs (True, // sbsingleread
DM_SBACCESS_32_BIT,
True, // sbautoincrement
True, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
for (rg_j <= 0; rg_j < 3; rg_j <= rg_j + 1) seq
stmt_wait_for_sb_nonbusy;
action
let x <- dm.av_read (dm_addr_sbdata0);
$display ("stmt_mem_read_4: read-data [%0d] = 0x%08h", rg_j, x);
endaction
endseq
dm.write (dm_addr_sbcs, fn_mk_sbcs (False, // sbsingleread
DM_SBACCESS_32_BIT,
False, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
action
let x <- dm.av_read (dm_addr_sbdata0);
$display ("stmt_mem_read_4: read-data [%0d] = 0x%08h", rg_j, x);
endaction
endseq);
// Do a single-write to memory
Stmt stmt_mem_write_1 = (
seq
dm.write (dm_addr_sbcs, fn_mk_sbcs (False, // sbsingleread
DM_SBACCESS_32_BIT,
False, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
dm.write (dm_addr_sbaddress0, 'h1_0000);
dm.write (dm_addr_sbdata0, 'h_BEEF);
dm.write (dm_addr_sbcs, fn_mk_sbcs (False, // sbsingleread
DM_SBACCESS_32_BIT,
False, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
dm.write (dm_addr_sbaddress0, 'h1_0000);
dm.write (dm_addr_sbdata0, 'h_BEEF);
endseq);
// Do a multiple-write to memory
Stmt stmt_mem_write_4 = (
seq
dm.write (dm_addr_sbcs, fn_mk_sbcs (False, // sbsingleread
DM_SBACCESS_32_BIT,
True, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
action
rg_addr <= 'h_2000;
rg_data <= 'h_DAFA_0000;
endaction
dm.write (dm_addr_sbaddress0, rg_addr);
for (rg_j <= 0; rg_j < 4; rg_j <= rg_j + 1) seq
stmt_wait_for_sb_nonbusy;
action
$display ("stmt_mem_write_4: [0x%08h] x = 0x%08h", rg_addr + rg_j, rg_data);
dm.write (dm_addr_sbdata0, rg_data);
rg_data <= rg_data + 1;
endaction
endseq
dm.write (dm_addr_sbcs, fn_mk_sbcs (False, // sbsingleread
DM_SBACCESS_32_BIT,
True, // sbautoincrement
False, // sbautoread
DM_SBERROR_UNDEF7_W1C)); // clear sberror
stmt_wait_for_sb_nonbusy;
action
rg_addr <= 'h_2000;
rg_data <= 'h_DAFA_0000;
endaction
dm.write (dm_addr_sbaddress0, rg_addr);
for (rg_j <= 0; rg_j < 4; rg_j <= rg_j + 1) seq
stmt_wait_for_sb_nonbusy;
action
$display ("stmt_mem_write_4: [0x%08h] x = 0x%08h", rg_addr + rg_j, rg_data);
dm.write (dm_addr_sbdata0, rg_data);
rg_data <= rg_data + 1;
endaction
endseq
endseq);
// ================================================================
@@ -291,173 +291,173 @@ module mkTestbench (Empty);
let dmcontrol_dm_reset
= fn_mk_dmcontrol (False, // haltreq
False, // resumereq
False, // hartreset
False, // hasel
0, // hartsel,
False, // ndmreset
False); // dmactive; assert reset
False, // resumereq
False, // hartreset
False, // hasel
0, // hartsel,
False, // ndmreset
False); // dmactive; assert reset
let dmcontrol_ndmreset
= fn_mk_dmcontrol (False, // haltreq
False, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
True, // ndmreset
True); // dmactive
False, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
True, // ndmreset
True); // dmactive
let dmcontrol_err_hasel
= fn_mk_dmcontrol (False, // haltreq
False, // resumereq
False, // hartreset
True, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
False, // resumereq
False, // hartreset
True, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
let dmcontrol_err_hartsel
= fn_mk_dmcontrol (False, // haltreq
False, // resumereq
False, // hartreset
False, // hasel,
3, // hartsel
False, // ndmreset
True); // dmactive
False, // resumereq
False, // hartreset
False, // hasel,
3, // hartsel
False, // ndmreset
True); // dmactive
let dmcontrol_hartreset
= fn_mk_dmcontrol (False, // haltreq
False, // resumereq
True, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
False, // resumereq
True, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
let dmcontrol_err_haltreq_resumereq
= fn_mk_dmcontrol (True, // haltreq
True, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
True, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
let dmcontrol_haltreq
= fn_mk_dmcontrol (True, // haltreq
False, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
False, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
let dmcontrol_resumereq
= fn_mk_dmcontrol (False, // haltreq
True, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
True, // resumereq
False, // hartreset
False, // hasel,
0, // hartsel
False, // ndmreset
True); // dmactive
function Stmt fn_stmt_run_control (DM_Word dm_word);
return seq
dm.write (dm_addr_dmcontrol, dm_word);
delay (5);
// Check and show status
action
let x <- dm.av_read (dm_addr_dmstatus);
$display (" ", fshow_dmstatus (x));
endaction
endseq;
dm.write (dm_addr_dmcontrol, dm_word);
delay (5);
// Check and show status
action
let x <- dm.av_read (dm_addr_dmstatus);
$display (" ", fshow_dmstatus (x));
endaction
endseq;
endfunction
// ----------------
// For single-step, set 'step' bit in DCSR, then run
let dcsr_step = {4'h4, // xdebugver
12'b0,
1'b0, // ebreakm
1'b0,
1'b0, // ebreaks
1'b0, // ebreaku
1'b0, // stepie
1'b0, // stepcount
1'b0, // steptime
3'b0, // cause
3'b0,
1'b1, // step
2'h3};
12'b0,
1'b0, // ebreakm
1'b0,
1'b0, // ebreaks
1'b0, // ebreaku
1'b0, // stepie
1'b0, // stepcount
1'b0, // steptime
3'b0, // cause
3'b0,
1'b1, // step
2'h3};
Stmt stmt_single_step = (
seq
// set 'step' in dcsr
fn_stmt_write_reg (fromInteger (dm_command_access_reg_regno_csr_0 + csr_addr_dcsr),
dcsr_step); // priv
fn_stmt_run_control (dmcontrol_resumereq);
// set 'step' in dcsr
fn_stmt_write_reg (fromInteger (dm_command_access_reg_regno_csr_0 + csr_addr_dcsr),
dcsr_step); // priv
fn_stmt_run_control (dmcontrol_resumereq);
endseq);
// ================================================================
// Top-level test. Comment/Uncomment desired parts.
Stmt test = seq
// Reset DM
$display ("----------------\n'Testbench: Reset DM'");
fn_stmt_run_control (dmcontrol_dm_reset);
// Reset DM
$display ("----------------\n'Testbench: Reset DM'");
fn_stmt_run_control (dmcontrol_dm_reset);
/*
$display ("----------------\n'Testbench: Reset Platform'");
fn_stmt_run_control (dmcontrol_ndmreset);
/*
$display ("----------------\n'Testbench: Reset Platform'");
fn_stmt_run_control (dmcontrol_ndmreset);
$display ("----------------\n'Testbench: Err hasel'");
fn_stmt_run_control (dmcontrol_err_hasel);
$display ("----------------\n'Testbench: Err hasel'");
fn_stmt_run_control (dmcontrol_err_hasel);
$display ("----------------\n'Testbench: Err hartsel'");
fn_stmt_run_control (dmcontrol_err_hartsel);
$display ("----------------\n'Testbench: Err hartsel'");
fn_stmt_run_control (dmcontrol_err_hartsel);
$display ("----------------\n'Testbench: Reset hart'");
fn_stmt_run_control (dmcontrol_hartreset);
$display ("----------------\n'Testbench: Reset hart'");
fn_stmt_run_control (dmcontrol_hartreset);
$display ("----------------\n'Testbench: Err haltreq and resumereq'");
fn_stmt_run_control (dmcontrol_err_haltreq_resumereq);
$display ("----------------\n'Testbench: Err haltreq and resumereq'");
fn_stmt_run_control (dmcontrol_err_haltreq_resumereq);
$display ("----------------\n'Testbench: Continue'");
fn_stmt_run_control (dmcontrol_resumereq);
$display ("----------------\n'Testbench: Continue'");
fn_stmt_run_control (dmcontrol_resumereq);
$display ("----------------\n'Testbench: Halt'");
fn_stmt_run_control (dmcontrol_haltreq);
$display ("----------------\n'Testbench: Halt'");
fn_stmt_run_control (dmcontrol_haltreq);
$display ("----------------\n'Testbench: Single step'");
stmt_single_step;
*/
$display ("----------------\n'Testbench: Single step'");
stmt_single_step;
*/
$display ("----------------\n'Testbench: Read GPR'");
fn_stmt_read_reg (fromInteger (dm_command_access_reg_regno_gpr_0 + 5));
$display ("----------------\n'Testbench: Read CSR'");
fn_stmt_read_reg (fromInteger (dm_command_access_reg_regno_csr_0 + 3));
$display ("----------------\n'Testbench: Read GPR'");
fn_stmt_read_reg (fromInteger (dm_command_access_reg_regno_gpr_0 + 5));
$display ("----------------\n'Testbench: Read CSR'");
fn_stmt_read_reg (fromInteger (dm_command_access_reg_regno_csr_0 + 3));
$display ("----------------\n'Testbench: Write GPR'");
fn_stmt_write_reg (fromInteger (dm_command_access_reg_regno_gpr_0 + 5), 'h_AAAA_0005);
$display ("----------------\n'Testbench: Write CSR'");
fn_stmt_write_reg (fromInteger (dm_command_access_reg_regno_csr_0 + 3), 'h_CCCC_0003);
$display ("----------------\n'Testbench: Write GPR'");
fn_stmt_write_reg (fromInteger (dm_command_access_reg_regno_gpr_0 + 5), 'h_AAAA_0005);
$display ("----------------\n'Testbench: Write CSR'");
fn_stmt_write_reg (fromInteger (dm_command_access_reg_regno_csr_0 + 3), 'h_CCCC_0003);
/*
$display ("----------------\n'Testbench: Read 1'");
stmt_mem_read_1;
/*
$display ("----------------\n'Testbench: Read 1'");
stmt_mem_read_1;
$display ("----------------\n'Testbench: Write 1'");
stmt_mem_write_1;
$display ("----------------\n'Testbench: Write 1'");
stmt_mem_write_1;
$display ("----------------\n'Testbench: Read 4'");
stmt_mem_read_4;
$display ("----------------\n'Testbench: Read 4'");
stmt_mem_read_4;
$display ("----------------\n'Testbench: Write 4'");
stmt_mem_write_4;
*/
$display ("----------------\n'Testbench: Write 4'");
stmt_mem_write_4;
*/
await (False);
endseq;
await (False);
endseq;
mkAutoFSM (test);
@@ -518,9 +518,9 @@ module mkHart_Model #(parameter Bit #(10) hart_id) (Hart_DM_IFC);
rg_hart_running <= True;
if (rg_hart_running)
$display ("Testbench.hart [%0d].rl_resume_hart: already running", hart_id);
$display ("Testbench.hart [%0d].rl_resume_hart: already running", hart_id);
else
$display ("Testbench.hart [%0d].rl_resume_hart: resuming", hart_id);
$display ("Testbench.hart [%0d].rl_resume_hart: resuming", hart_id);
f_hart_run_rsps.enq (True);
endrule
@@ -530,9 +530,9 @@ module mkHart_Model #(parameter Bit #(10) hart_id) (Hart_DM_IFC);
rg_hart_running <= False;
if (rg_hart_running)
$display ("Testbench.hart [%0d].rl_halt_hart: halting", hart_id);
$display ("Testbench.hart [%0d].rl_halt_hart: halting", hart_id);
else
$display ("Testbench.hart [%0d].rl_halt_hart: already halted", hart_id);
$display ("Testbench.hart [%0d].rl_halt_hart: already halted", hart_id);
f_hart_run_rsps.enq (False);
endrule
@@ -544,8 +544,8 @@ module mkHart_Model #(parameter Bit #(10) hart_id) (Hart_DM_IFC);
let rda <- pop_o (trx_buf_gprs.master.fo_rda);
Bit #(32) data = extend (rda.addr) + 'h1000;
let rdr = TRX_RdR {trans_id: rda.trans_id,
status: TRX_OKAY,
data: data};
status: TRX_OKAY,
data: data};
trx_buf_gprs.master.fi_rdr.enq (rdr);
$display ("Testbench.hart [%0d]: Read GPR [%0h] => 0x%08h", hart_id, rda.addr, data);
endrule
@@ -554,8 +554,8 @@ module mkHart_Model #(parameter Bit #(10) hart_id) (Hart_DM_IFC);
let rda <- pop_o (trx_buf_csrs.master.fo_rda);
Bit #(32) data = extend (rda.addr) + 'h2000;
let rdr = TRX_RdR {trans_id: rda.trans_id,
status: TRX_OKAY,
data: data};
status: TRX_OKAY,
data: data};
trx_buf_csrs.master.fi_rdr.enq (rdr);
$display ("Testbench.hart [%0d]: Read CSR [%0h] => 0x%08h", hart_id, rda.addr, data);
endrule

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved
// Copyright (c) 2013-2020 Bluespec, Inc. All Rights Reserved
// ================================================================
// ISA defs for UC Berkeley RISC V
@@ -234,28 +234,28 @@ deriving (FShow, Bits);
function Decoded_Instr fv_decode (Instr instr);
return Decoded_Instr {opcode: instr_opcode (instr),
rd: instr_rd (instr),
rs1: instr_rs1 (instr),
rs2: instr_rs2 (instr),
rs3: instr_rs3 (instr),
csr: instr_csr (instr),
rd: instr_rd (instr),
rs1: instr_rs1 (instr),
rs2: instr_rs2 (instr),
rs3: instr_rs3 (instr),
csr: instr_csr (instr),
funct3: instr_funct3 (instr),
funct5: instr_funct5 (instr),
funct7: instr_funct7 (instr),
funct10: instr_funct10 (instr),
funct3: instr_funct3 (instr),
funct5: instr_funct5 (instr),
funct7: instr_funct7 (instr),
funct10: instr_funct10 (instr),
imm12_I: instr_I_imm12 (instr),
imm12_S: instr_S_imm12 (instr),
imm13_SB: instr_SB_imm13 (instr),
imm20_U: instr_U_imm20 (instr),
imm21_UJ: instr_UJ_imm21 (instr),
imm12_I: instr_I_imm12 (instr),
imm12_S: instr_S_imm12 (instr),
imm13_SB: instr_SB_imm13 (instr),
imm20_U: instr_U_imm20 (instr),
imm21_UJ: instr_UJ_imm21 (instr),
pred: instr_pred (instr),
succ: instr_succ (instr),
pred: instr_pred (instr),
succ: instr_succ (instr),
aqrl: instr_aqrl (instr)
};
aqrl: instr_aqrl (instr)
};
endfunction
// Decodes if we need to read the GPR register file. This step becomes necessary
@@ -269,7 +269,7 @@ endfunction
// if (di.opcode != op_FP) begin
// return (tuple2 (False, True)); // Regular op with GPR read
// end
//
//
// // This is an FP operation. The following f5 values would work for F and
// // D subsets
// else begin
@@ -361,13 +361,27 @@ RegName reg_s10 = 26; RegName reg_s11 = 27;
RegName reg_t3 = 28; RegName reg_t4 = 29; RegName reg_t5 = 30; RegName reg_t6 = 31;
// ----------------
// Is 'r' a standard register for PC save/restore on call/return?
// This function is used in branch-predictors for managing the return-address stack.
function Bool fn_reg_is_link (RegName r);
return ((r == x1) || (r == x5));
endfunction
// ================================================================
// Kinds of memory access (excluding AMOs)
typedef enum { Access_RWX_R, Access_RWX_W, Access_RWX_X } Access_RWX
deriving (Eq, Bits, FShow);
// ================================================================
// Data sizes for LOAD/STORE
typedef enum {BITS8,
BITS16,
BITS32,
BITS64 // Even in RV32, to allow for Double (floating point)
BITS16,
BITS32,
BITS64 // Even in RV32, to allow for Double (floating point)
} Mem_Data_Size
deriving (Eq, Bits, FShow);
@@ -429,23 +443,23 @@ deriving (FShow);
instance Bits #(Fence_Ordering, 8);
function Bit #(8) pack (Fence_Ordering fo);
return {pack (fo.pi),
pack (fo.po),
pack (fo.pr),
pack (fo.pw),
pack (fo.si),
pack (fo.so),
pack (fo.sr),
pack (fo.sw) };
pack (fo.po),
pack (fo.pr),
pack (fo.pw),
pack (fo.si),
pack (fo.so),
pack (fo.sr),
pack (fo.sw) };
endfunction
function Fence_Ordering unpack (Bit #(8) b8);
return Fence_Ordering {pi: unpack (b8 [7]),
po: unpack (b8 [6]),
pr: unpack (b8 [5]),
pw: unpack (b8 [4]),
si: unpack (b8 [3]),
so: unpack (b8 [2]),
sr: unpack (b8 [1]),
sw: unpack (b8 [0]) };
po: unpack (b8 [6]),
pr: unpack (b8 [5]),
pw: unpack (b8 [4]),
si: unpack (b8 [3]),
so: unpack (b8 [2]),
sr: unpack (b8 [1]),
sw: unpack (b8 [0]) };
endfunction
endinstance
@@ -599,10 +613,10 @@ Bit #(10) f10_REMUW = 10'b000_0001_111;
function Bool is_OP_32_MUL_DIV_REM (Bit #(10) f10);
return ( (f10 == f10_MULW)
|| (f10 == f10_DIVW)
|| (f10 == f10_DIVUW)
|| (f10 == f10_REMW)
|| (f10 == f10_REMUW));
|| (f10 == f10_DIVW)
|| (f10 == f10_DIVUW)
|| (f10 == f10_REMW)
|| (f10 == f10_REMUW));
endfunction
// ================================================================
@@ -788,15 +802,15 @@ endfunction
// Check if a rounding mode value in the FCSR.FRM is valid
function Bool fv_fcsr_frm_valid (Bit #(3) frm);
return ( (frm != 3'b101)
return ( (frm != 3'b101)
&& (frm != 3'b110)
&& (frm != 3'b111)
);
endfunction
endfunction
// Check if a rounding mode value in the instr is valid
function Bool fv_inst_frm_valid (Bit #(3) frm);
return ( (frm != 3'b101)
return ( (frm != 3'b101)
&& (frm != 3'b110)
);
endfunction
@@ -827,12 +841,12 @@ function Bool fv_is_fp_instr_legal (
return (f2 == f2_S); // Only SP is legal
`endif
else
if ( (f7 == f7_FADD_S)
|| (f7 == f7_FSUB_S)
|| (f7 == f7_FMUL_S)
if ( (f7 == f7_FADD_S)
|| (f7 == f7_FSUB_S)
|| (f7 == f7_FMUL_S)
`ifdef ISA_FD_DIV
|| (f7 == f7_FDIV_S)
|| (f7 == f7_FSQRT_S)
|| (f7 == f7_FDIV_S)
|| (f7 == f7_FSQRT_S)
`endif
|| ((f7 == f7_FSGNJ_S) && ( rm == 0))
|| ((f7 == f7_FSGNJ_S) && ( rm == 1))
@@ -842,10 +856,10 @@ function Bool fv_is_fp_instr_legal (
`ifdef RV64
|| ((f7 == f7_FCVT_L_S) && (rs2 == 2))
|| ((f7 == f7_FCVT_LU_S)&& (rs2 == 3))
`endif
`endif
|| ((f7 == f7_FCVT_S_W) && (rs2 == 0))
|| ((f7 == f7_FCVT_S_WU)&& (rs2 == 1))
`ifdef RV64
|| ((f7 == f7_FCVT_S_WU)&& (rs2 == 1))
`ifdef RV64
|| ((f7 == f7_FCVT_S_L) && (rs2 == 2))
|| ((f7 == f7_FCVT_S_LU)&& (rs2 == 3))
`endif
@@ -858,12 +872,12 @@ function Bool fv_is_fp_instr_legal (
|| ((f7 == f7_FMV_W_X) && ( rm == 0))
|| ((f7 == f7_FCLASS_S) && ( rm == 1))
`ifdef ISA_D
|| (f7 == f7_FADD_D)
|| (f7 == f7_FSUB_D)
|| (f7 == f7_FMUL_D)
|| (f7 == f7_FADD_D)
|| (f7 == f7_FSUB_D)
|| (f7 == f7_FMUL_D)
`ifdef ISA_FD_DIV
|| (f7 == f7_FDIV_D)
|| (f7 == f7_FSQRT_D)
|| (f7 == f7_FDIV_D)
|| (f7 == f7_FSQRT_D)
`endif
|| ((f7 == f7_FSGNJ_D) && ( rm == 0))
|| ((f7 == f7_FSGNJ_D) && ( rm == 1))
@@ -873,10 +887,10 @@ function Bool fv_is_fp_instr_legal (
`ifdef RV64
|| ((f7 == f7_FCVT_L_D) && (rs2 == 2))
|| ((f7 == f7_FCVT_LU_D)&& (rs2 == 3))
`endif
`endif
|| ((f7 == f7_FCVT_D_W) && (rs2 == 0))
|| ((f7 == f7_FCVT_D_WU)&& (rs2 == 1))
`ifdef RV64
|| ((f7 == f7_FCVT_D_WU)&& (rs2 == 1))
`ifdef RV64
|| ((f7 == f7_FCVT_D_L) && (rs2 == 2))
|| ((f7 == f7_FCVT_D_LU)&& (rs2 == 3))
`endif
@@ -970,7 +984,7 @@ endfunction
function Bool f3_is_CSRR_S_or_C (Bit #(3) f3);
return ((f3 == f3_CSRRS) || (f3 == f3_CSRRSI) ||
(f3 == f3_CSRRC) || (f3 == f3_CSRRCI));
(f3 == f3_CSRRC) || (f3 == f3_CSRRCI));
endfunction
// ================================================================
@@ -987,11 +1001,11 @@ Priv_Mode m_Priv_Mode = 2'b11;
function Fmt fshow_Priv_Mode (Priv_Mode pm);
return case (pm)
u_Priv_Mode: $format ("U");
s_Priv_Mode: $format ("S");
m_Priv_Mode: $format ("M");
default: $format ("RESERVED");
endcase;
u_Priv_Mode: $format ("U");
s_Priv_Mode: $format ("S");
m_Priv_Mode: $format ("M");
default: $format ("RESERVED");
endcase;
endfunction
// ================================================================
@@ -1092,7 +1106,7 @@ CSR_Addr csr_addr_hpmcounter29h = 12'hC9D; // Upper 32 bits of performance
CSR_Addr csr_addr_hpmcounter30h = 12'hC9E; // Upper 32 bits of performance-monitoring counter
CSR_Addr csr_addr_hpmcounter31h = 12'hC9F; // Upper 32 bits of performance-monitoring counter
// Information from the CSR on a new trap.
// Information from the CSR on a new trap.
typedef struct {
Addr pc;
WordXL mstatus;

View File

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2019 Peter Rugg
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory (Department of Computer Science and
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
* DARPA SSITH research programme.
*
* @BERI_LICENSE_HEADER_START@
*
* Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. BERI licenses this
* file to you under the BERI Hardware-Software License, Version 1.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.beri-open-systems.org/legal/license-1-0.txt
*
* Unless required by applicable law or agreed to in writing, Work distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @BERI_LICENSE_HEADER_END@
*/
import ISA_Decls::*;
import CHERICap::*;
import CHERICC_Fat::*;
typedef TMul#(XLEN, 2) CLEN;
// Exception codes
typedef enum {
None = 5'd0,
LengthViolation = 5'd1,
TagViolation = 5'd2,
SealViolation = 5'd3,
TypeViolation = 5'd4,
CallTrap = 5'd5,
ReturnTrap = 5'd6,
StackUnderflow = 5'd7,
MMUStoreCapProhibit = 5'd8,
RepresentViolation = 5'd9,
UnalignedBase = 5'd10,
// 5'd11 - 5'd15 reserved
GlobalViolation = 5'd16,
PermitXViolation = 5'd17,
PermitRViolation = 5'd18,
PermitWViolation = 5'd19,
PermitRCapViolation = 5'd20,
PermitWCapViolation = 5'd21,
PermitWLocalCapViolation = 5'd22,
PermitSealViolation = 5'd23,
PermitASRViolation = 5'd24,
PermitCCallViolation = 5'd25,
PermitUnsealViolation = 5'd26,
PermitSetCIDViolation = 5'd27
// 5'd28 - 5'd31 reserved
} CHERIException deriving(Bits, Eq, FShow);
// SCR map
typedef enum {
SCR_PCC = 5'd00,
SCR_DDC = 5'd01,
SCR_UTCC = 5'd04,
SCR_UTDC = 5'd05,
SCR_UScratchC = 5'd06,
SCR_UEPCC = 5'd07,
SCR_STCC = 5'd12,
SCR_STDC = 5'd13,
SCR_SScratchC = 5'd14,
SCR_SEPCC = 5'd15,
SCR_MTCC = 5'd28,
SCR_MTDC = 5'd29,
SCR_MScratchC = 5'd30,
SCR_MEPCC = 5'd31
} SCR deriving(Bits, Eq, FShow);
function CapPipe update_scr_via_csr (CapPipe old_scr, WordXL new_csr);
let new_scr = setOffset(old_scr, new_csr);
let ret = new_scr.value;
if (!new_scr.exact || isSealed(old_scr)) begin
ret = setValidCap(ret, False);
end
return ret;
endfunction
RegName cCallRD = 31;
// Instruction field encodings
// Top-level opcodes
Opcode op_cap_Manip = 7'h5b;
//Opcode op_cap_Mem = 7'h0b; // Not yet implemented
// ================================================================
// op_cap_Manip opcode subdivision
// f3 selects between immediate and 3-reg instructions
Bit #(3) f3_cap_ThreeOp = 3'h0;
Bit #(3) f3_cap_CIncOffsetImmediate = 3'h1;
Bit #(3) f3_cap_CSetBoundsImmediate = 3'h2;
// 3'h3-3'h7 unused
// ================================================================
// op_cap_ThreeOp opcode subdivision
// f7 selects between 3-reg operations
// 7'h00 unused
Bit #(7) f7_cap_CSpecialRW = 7'h01;
// 7'h02-7'h07 unused
Bit #(7) f7_cap_CSetBounds = 7'h08;
Bit #(7) f7_cap_CSetBoundsExact = 7'h09;
// 7'h0a unused
Bit #(7) f7_cap_CSeal = 7'h0b;
Bit #(7) f7_cap_CUnseal = 7'h0c;
Bit #(7) f7_cap_CAndPerm = 7'h0d;
Bit #(7) f7_cap_CSetFlags = 7'h0e;
Bit #(7) f7_cap_CSetOffset = 7'h0f;
Bit #(7) f7_cap_CSetAddr = 7'h10;
Bit #(7) f7_cap_CIncOffset = 7'h11;
Bit #(7) f7_cap_CToPtr = 7'h12;
Bit #(7) f7_cap_CFromPtr = 7'h13;
Bit #(7) f7_cap_CSub = 7'h14;
// 7'h15-7'h1c unused
Bit #(7) f7_cap_CBuildCap = 7'h1d;
Bit #(7) f7_cap_CCopyType = 7'h1e;
Bit #(7) f7_cap_CCSeal = 7'h1f;
Bit #(7) f7_cap_CTestSubset = 7'h20;
// 7'h21-7'hfb unused
Bit #(7) f7_cap_Stores = 7'h7c;
Bit #(7) f7_cap_Loads = 7'h7d;
Bit #(7) f7_cap_TwoSrc = 7'h7e;
Bit #(7) f7_cap_TwoOp = 7'h7f;
// ================================================================
// f7_cap_TwoSrc opcode subdivision
// rd selects between 2-reg operations
// 5'h00 unused
Bit #(5) rd_cap_CCall = 5'h01;
// 5'h02-5'h1f unused
// ================================================================
// f7_cap_TwoOp opcode subdivision
// f5rs2 selects between 2-reg operations (f5rs2 instead of f5 because f5
// is already used in RISC-V and is in a different position
Bit #(5) f5rs2_cap_CGetPerm = 5'h00;
Bit #(5) f5rs2_cap_CGetType = 5'h01;
Bit #(5) f5rs2_cap_CGetBase = 5'h02;
Bit #(5) f5rs2_cap_CGetLen = 5'h03;
Bit #(5) f5rs2_cap_CGetTag = 5'h04;
Bit #(5) f5rs2_cap_CGetSealed = 5'h05;
Bit #(5) f5rs2_cap_CGetOffset = 5'h06;
Bit #(5) f5rs2_cap_CGetFlags = 5'h07;
Bit #(5) f5rs2_cap_CRRL = 5'h08;
Bit #(5) f5rs2_cap_CRAM = 5'h09;
Bit #(5) f5rs2_cap_CMove = 5'h0a;
Bit #(5) f5rs2_cap_CClearTag = 5'h0b;
Bit #(5) f5rs2_cap_CJALR = 5'h0c;
Bit #(5) f5rs2_cap_CClearReg = 5'h0d;
// 5'h0e unused
Bit #(5) f5rs2_cap_CGetAddr = 5'h0f;
Bit #(5) f5rs2_cap_CClearFPReg = 5'h10;
// 5'h11-5'h1f unused (5'h1f reserved for 1-reg instructions
// ================================================================
// f7_cap_{Load, Store} opcode subdivision
MemReqSize cap_mem_SIZE_B = 'h0;
MemReqSize cap_mem_SIZE_H = 'h1;
MemReqSize cap_mem_SIZE_W = 'h2;
MemReqSize cap_mem_SIZE_D = 'h3;
//MemReqSize f5rs2_cap_mem_SIZE_Q = 'h4; //TODO
Bit #(1) cap_mem_ddc = 1'h0;
Bit #(1) cap_mem_cap = 1'h1;
Bit #(1) cap_mem_unsigned = 1'h1;
Bit #(1) cap_mem_signed = 1'h0;
// ================================================================
// Other:
// Region in MISC_MEM for LQ
Bit #(3) f3_LQ = 3'h2;
Bit #(3) f3_SQ = 3'b100;
`ifdef RV64
Bit #(3) w_SIZE_CAP = f3_SQ;
Bit #(3) w_SIZE_MAX = f3_SQ;
`else //RV32
Bit #(3) w_SIZE_CAP = f3_SD;
Bit #(3) w_SIZE_MAX = f3_SD;
`endif
Bit #(3) f3_AMO_CAP = w_SIZE_CAP;

View File

@@ -201,56 +201,56 @@ Bit #(2) misa_mxl_128 = 3;
function WordXL misa_to_word (MISA ms);
return {ms.mxl,
0, // expands appropriately for RV32 and RV64
ms.z, ms.y,
ms.x, ms.w, ms.v, ms.u, ms.t, ms.s, ms.r, ms.q,
ms.p, ms.o, ms.n, ms.m, ms.l, ms.k, ms.j, ms.i,
ms.h, ms.g, ms.f, ms.e, ms.d, ms.c, ms.b, ms.a};
0, // expands appropriately for RV32 and RV64
ms.z, ms.y,
ms.x, ms.w, ms.v, ms.u, ms.t, ms.s, ms.r, ms.q,
ms.p, ms.o, ms.n, ms.m, ms.l, ms.k, ms.j, ms.i,
ms.h, ms.g, ms.f, ms.e, ms.d, ms.c, ms.b, ms.a};
endfunction
function MISA word_to_misa (WordXL x);
return MISA {mxl: x [xlen-1:xlen-2],
z: x [25], y: x [24],
x: x [23], w: x [22], v: x [21], u: x [20], t: x [19], s: x [18], r: x [17], q: x [16],
p: x [15], o: x [14], n: x [13], m: x [12], l: x [11], k: x [10], j: x [9], i: x [8],
h: x [7], g: x [6], f: x [5], e: x [4], d: x [3], c: x [2], b: x [1], a: x [0]};
z: x [25], y: x [24],
x: x [23], w: x [22], v: x [21], u: x [20], t: x [19], s: x [18], r: x [17], q: x [16],
p: x [15], o: x [14], n: x [13], m: x [12], l: x [11], k: x [10], j: x [9], i: x [8],
h: x [7], g: x [6], f: x [5], e: x [4], d: x [3], c: x [2], b: x [1], a: x [0]};
endfunction
instance FShow #(MISA);
function Fmt fshow (MISA misa);
let fmt_mxl = case (misa.mxl)
1: $format ("mxl 32");
2: $format ("mxl 64");
3: $format ("mxl 128");
default: $format ("mxl unknown %0d", misa.mxl);
endcase;
1: $format ("mxl 32");
2: $format ("mxl 64");
3: $format ("mxl 128");
default: $format ("mxl unknown %0d", misa.mxl);
endcase;
return ( fmt_mxl
+ $format ((misa.z == 1'b1) ? "Z" : "")
+ $format ((misa.y == 1'b1) ? "Y" : "")
+ $format ((misa.x == 1'b1) ? "X" : "")
+ $format ((misa.w == 1'b1) ? "W" : "")
+ $format ((misa.v == 1'b1) ? "V" : "")
+ $format ((misa.u == 1'b1) ? "U" : "")
+ $format ((misa.t == 1'b1) ? "T" : "")
+ $format ((misa.s == 1'b1) ? "S" : "")
+ $format ((misa.r == 1'b1) ? "R" : "")
+ $format ((misa.q == 1'b1) ? "Q" : "")
+ $format ((misa.p == 1'b1) ? "P" : "")
+ $format ((misa.o == 1'b1) ? "O" : "")
+ $format ((misa.n == 1'b1) ? "N" : "")
+ $format ((misa.m == 1'b1) ? "M" : "")
+ $format ((misa.l == 1'b1) ? "L" : "")
+ $format ((misa.k == 1'b1) ? "K" : "")
+ $format ((misa.j == 1'b1) ? "J" : "")
+ $format ((misa.i == 1'b1) ? "I" : "")
+ $format ((misa.h == 1'b1) ? "H" : "")
+ $format ((misa.g == 1'b1) ? "G" : "")
+ $format ((misa.f == 1'b1) ? "F" : "")
+ $format ((misa.d == 1'b1) ? "E" : "")
+ $format ((misa.d == 1'b1) ? "D" : "")
+ $format ((misa.c == 1'b1) ? "C" : "")
+ $format ((misa.b == 1'b1) ? "B" : "")
+ $format ((misa.a == 1'b1) ? "A" : ""));
+ $format ((misa.z == 1'b1) ? "Z" : "")
+ $format ((misa.y == 1'b1) ? "Y" : "")
+ $format ((misa.x == 1'b1) ? "X" : "")
+ $format ((misa.w == 1'b1) ? "W" : "")
+ $format ((misa.v == 1'b1) ? "V" : "")
+ $format ((misa.u == 1'b1) ? "U" : "")
+ $format ((misa.t == 1'b1) ? "T" : "")
+ $format ((misa.s == 1'b1) ? "S" : "")
+ $format ((misa.r == 1'b1) ? "R" : "")
+ $format ((misa.q == 1'b1) ? "Q" : "")
+ $format ((misa.p == 1'b1) ? "P" : "")
+ $format ((misa.o == 1'b1) ? "O" : "")
+ $format ((misa.n == 1'b1) ? "N" : "")
+ $format ((misa.m == 1'b1) ? "M" : "")
+ $format ((misa.l == 1'b1) ? "L" : "")
+ $format ((misa.k == 1'b1) ? "K" : "")
+ $format ((misa.j == 1'b1) ? "J" : "")
+ $format ((misa.i == 1'b1) ? "I" : "")
+ $format ((misa.h == 1'b1) ? "H" : "")
+ $format ((misa.g == 1'b1) ? "G" : "")
+ $format ((misa.f == 1'b1) ? "F" : "")
+ $format ((misa.d == 1'b1) ? "E" : "")
+ $format ((misa.d == 1'b1) ? "D" : "")
+ $format ((misa.c == 1'b1) ? "C" : "")
+ $format ((misa.b == 1'b1) ? "B" : "")
+ $format ((misa.a == 1'b1) ? "A" : ""));
endfunction
endinstance
@@ -314,43 +314,43 @@ function Fmt fshow_mstatus (MISA misa, WordXL mstatus);
Bit #(2) mpp = fv_get_bits (mstatus, fromInteger (mstatus_mpp_bitpos));
return ( $format ("MStatus{")
+ $format ("sd:%0d", fv_mstatus_sd (mstatus))
+ $format ("sd:%0d", fv_mstatus_sd (mstatus))
+ ((misa.mxl == misa_mxl_64) ? $format (" sxl:%0d uxl:%0d", sxl, uxl) : $format (""))
+ ((misa.mxl == misa_mxl_64) ? $format (" sxl:%0d uxl:%0d", sxl, uxl) : $format (""))
+ $format (" tsr:%0d", mstatus [mstatus_tsr_bitpos])
+ $format (" tw:%0d", mstatus [mstatus_tw_bitpos])
+ $format (" tvm:%0d", mstatus [mstatus_tvm_bitpos])
+ $format (" mxr:%0d", mstatus [mstatus_mxr_bitpos])
+ $format (" sum:%0d", mstatus [mstatus_sum_bitpos])
+ $format (" mprv:%0d", mstatus [mstatus_mprv_bitpos])
+ $format (" tsr:%0d", mstatus [mstatus_tsr_bitpos])
+ $format (" tw:%0d", mstatus [mstatus_tw_bitpos])
+ $format (" tvm:%0d", mstatus [mstatus_tvm_bitpos])
+ $format (" mxr:%0d", mstatus [mstatus_mxr_bitpos])
+ $format (" sum:%0d", mstatus [mstatus_sum_bitpos])
+ $format (" mprv:%0d", mstatus [mstatus_mprv_bitpos])
+ $format (" xs:%0d", xs)
+ $format (" fs:%0d", fs)
+ $format (" xs:%0d", xs)
+ $format (" fs:%0d", fs)
+ $format (" mpp:%0d", mpp)
+ $format (" spp:%0d", mstatus [mstatus_spp_bitpos])
+ $format (" mpp:%0d", mpp)
+ $format (" spp:%0d", mstatus [mstatus_spp_bitpos])
+ $format (" pies:%0d_%0d%0d",
mstatus [mstatus_mpie_bitpos], mstatus [mstatus_spie_bitpos], mstatus [mstatus_upie_bitpos])
+ $format (" pies:%0d_%0d%0d",
mstatus [mstatus_mpie_bitpos], mstatus [mstatus_spie_bitpos], mstatus [mstatus_upie_bitpos])
+ $format (" ies:%0d_%0d%0d",
mstatus [mstatus_mie_bitpos], mstatus [mstatus_sie_bitpos], mstatus [mstatus_uie_bitpos])
+ $format ("}")
);
+ $format (" ies:%0d_%0d%0d",
mstatus [mstatus_mie_bitpos], mstatus [mstatus_sie_bitpos], mstatus [mstatus_uie_bitpos])
+ $format ("}")
);
endfunction
// ----------------
// Help functions to manipulate mstatus on traps and trap-returns
function Priv_Mode fv_new_priv_on_exception (MISA misa,
Priv_Mode from_priv,
Bool interrupt,
Exc_Code exc_code,
Bit #(16) medeleg,
Bit #(12) mideleg,
Bit #(16) sedeleg,
Bit #(12) sideleg);
Priv_Mode from_priv,
Bool interrupt,
Exc_Code exc_code,
Bit #(16) medeleg,
Bit #(12) mideleg,
Bit #(16) sedeleg,
Bit #(12) sideleg);
Priv_Mode to_priv = m_Priv_Mode;
Bit #(1) deleg_bit = 1'b0;
@@ -358,39 +358,39 @@ function Priv_Mode fv_new_priv_on_exception (MISA misa,
if (from_priv < m_Priv_Mode) begin
// If S is supported
if (misa.s == 1'b1) begin
// Look in medeleg/mideleg for the cause bit; if set, delegate.
if (interrupt)
deleg_bit = mideleg [exc_code];
else
deleg_bit = medeleg [exc_code];
if (deleg_bit == 1'b1) begin
// If the current priv mode is S, then delegate to S.
to_priv = s_Priv_Mode;
// If the current priv mode is U, and user mode traps are supported,
// then consult sedeleg/sideleg to determine if delegated to U mode.
if ((from_priv == u_Priv_Mode) && (misa.n == 1'b1)) begin
if (interrupt)
deleg_bit = sideleg [exc_code];
else
deleg_bit = sedeleg [exc_code];
if (deleg_bit == 1'b1)
to_priv = u_Priv_Mode;
end
end
// Look in medeleg/mideleg for the cause bit; if set, delegate.
if (interrupt)
deleg_bit = mideleg [exc_code];
else
deleg_bit = medeleg [exc_code];
if (deleg_bit == 1'b1) begin
// If the current priv mode is S, then delegate to S.
to_priv = s_Priv_Mode;
// If the current priv mode is U, and user mode traps are supported,
// then consult sedeleg/sideleg to determine if delegated to U mode.
if ((from_priv == u_Priv_Mode) && (misa.n == 1'b1)) begin
if (interrupt)
deleg_bit = sideleg [exc_code];
else
deleg_bit = sedeleg [exc_code];
if (deleg_bit == 1'b1)
to_priv = u_Priv_Mode;
end
end
end
else begin
// S is not supported
// If user mode traps are supported,
// then consult medele/mideleg to determine if delegated to U mode.
if (misa.n == 1'b1) begin
// Look in medeleg/mideleg for the cause bit; if set, delegate.
if (interrupt)
deleg_bit = mideleg [exc_code];
else
deleg_bit = medeleg [exc_code];
if (deleg_bit == 1'b1)
to_priv = u_Priv_Mode;
end
// S is not supported
// If user mode traps are supported,
// then consult medele/mideleg to determine if delegated to U mode.
if (misa.n == 1'b1) begin
// Look in medeleg/mideleg for the cause bit; if set, delegate.
if (interrupt)
deleg_bit = mideleg [exc_code];
else
deleg_bit = medeleg [exc_code];
if (deleg_bit == 1'b1)
to_priv = u_Priv_Mode;
end
end
end
@@ -407,14 +407,14 @@ function WordXL fv_new_mstatus_on_exception (WordXL mstatus, Priv_Mode from_y, P
// xPP = y Assert: (to_x == m_Priv_Mode) || (to_x == s_Priv_Mode)
mstatus = ( (to_x == m_Priv_Mode)
? fv_assign_bits (mstatus, fromInteger (mstatus_mpp_bitpos), from_y)
: fv_assign_bit (mstatus, fromInteger (mstatus_spp_bitpos), from_y [0]));
? fv_assign_bits (mstatus, fromInteger (mstatus_mpp_bitpos), from_y)
: fv_assign_bit (mstatus, fromInteger (mstatus_spp_bitpos), from_y [0]));
return mstatus;
endfunction
function Tuple2 #(WordXL, Priv_Mode) fv_new_mstatus_on_ret (MISA misa,
WordXL mstatus,
Priv_Mode from_x);
WordXL mstatus,
Priv_Mode from_x);
Bit #(6) ie_from_x = extend (from_x);
Bit #(6) pie_from_x = fromInteger (mstatus_upie_bitpos) + extend (from_x);
@@ -478,20 +478,20 @@ deriving (Bits, FShow);
function WordXL mcounteren_to_word (MCounteren mc);
return {0,
mc.ir,
mc.tm,
mc.cy};
mc.tm,
mc.cy};
endfunction
function MCounteren word_to_mcounteren (WordXL x);
return MCounteren {ir: x[2],
tm: x[1],
cy: x[0]};
cy: x[0]};
endfunction
function MCounteren mcounteren_reset_value;
return MCounteren {ir: 1'b0,
tm: 1'b0,
cy: 1'b0};
cy: 1'b0};
endfunction
// ================================================================
@@ -521,9 +521,9 @@ deriving (Bits);
instance FShow #(MCause);
function Fmt fshow (MCause mc);
if (mc.interrupt == 1)
return fshow_interrupt_Exc_Code (mc.exc_code);
return fshow_interrupt_Exc_Code (mc.exc_code);
else
return fshow_trap_Exc_Code (mc.exc_code);
return fshow_trap_Exc_Code (mc.exc_code);
endfunction
endinstance
@@ -533,7 +533,7 @@ endfunction
function MCause word_to_mcause (WordXL x);
return MCause {interrupt: msb (x),
exc_code: truncate (x)};
exc_code: truncate (x)};
endfunction
// Exception Codes in mcause
@@ -583,47 +583,47 @@ Exc_Code exc_code_STORE_AMO_PAGE_FAULT = 15;
function Fmt fshow_interrupt_Exc_Code (Exc_Code exc_code);
return case (exc_code)
exc_code_USER_SW_INTERRUPT: $format ("USER_SW_INTERRUPT");
exc_code_SUPERVISOR_SW_INTERRUPT: $format ("SUPERVISOR_SW_INTERRUPT");
exc_code_HYPERVISOR_SW_INTERRUPT: $format ("HYPERVISOR_SW_INTERRUPT");
exc_code_MACHINE_SW_INTERRUPT: $format ("MACHINE_SW_INTERRUPT");
exc_code_USER_SW_INTERRUPT: $format ("USER_SW_INTERRUPT");
exc_code_SUPERVISOR_SW_INTERRUPT: $format ("SUPERVISOR_SW_INTERRUPT");
exc_code_HYPERVISOR_SW_INTERRUPT: $format ("HYPERVISOR_SW_INTERRUPT");
exc_code_MACHINE_SW_INTERRUPT: $format ("MACHINE_SW_INTERRUPT");
exc_code_USER_TIMER_INTERRUPT: $format ("USER_TIMER_INTERRUPT");
exc_code_SUPERVISOR_TIMER_INTERRUPT: $format ("SUPERVISOR_TIMER_INTERRUPT");
exc_code_HYPERVISOR_TIMER_INTERRUPT: $format ("HYPERVISOR_TIMER_INTERRUPT");
exc_code_MACHINE_TIMER_INTERRUPT: $format ("MACHINE_TIMER_INTERRUPT");
exc_code_USER_TIMER_INTERRUPT: $format ("USER_TIMER_INTERRUPT");
exc_code_SUPERVISOR_TIMER_INTERRUPT: $format ("SUPERVISOR_TIMER_INTERRUPT");
exc_code_HYPERVISOR_TIMER_INTERRUPT: $format ("HYPERVISOR_TIMER_INTERRUPT");
exc_code_MACHINE_TIMER_INTERRUPT: $format ("MACHINE_TIMER_INTERRUPT");
exc_code_USER_EXTERNAL_INTERRUPT: $format ("USER_EXTERNAL_INTERRUPT");
exc_code_SUPERVISOR_EXTERNAL_INTERRUPT: $format ("SUPERVISOR_EXTERNAL_INTERRUPT");
exc_code_HYPERVISOR_EXTERNAL_INTERRUPT: $format ("HYPERVISOR_EXTERNAL_INTERRUPT");
exc_code_MACHINE_EXTERNAL_INTERRUPT: $format ("MACHINE_EXTERNAL_INTERRUPT");
default: $format ("unknown interrupt Exc_Code %d", exc_code);
endcase;
exc_code_USER_EXTERNAL_INTERRUPT: $format ("USER_EXTERNAL_INTERRUPT");
exc_code_SUPERVISOR_EXTERNAL_INTERRUPT: $format ("SUPERVISOR_EXTERNAL_INTERRUPT");
exc_code_HYPERVISOR_EXTERNAL_INTERRUPT: $format ("HYPERVISOR_EXTERNAL_INTERRUPT");
exc_code_MACHINE_EXTERNAL_INTERRUPT: $format ("MACHINE_EXTERNAL_INTERRUPT");
default: $format ("unknown interrupt Exc_Code %d", exc_code);
endcase;
endfunction
function Fmt fshow_trap_Exc_Code (Exc_Code exc_code);
return case (exc_code)
exc_code_INSTR_ADDR_MISALIGNED: $format ("INSTRUCTION_ADDR_MISALIGNED");
exc_code_INSTR_ACCESS_FAULT: $format ("INSTRUCTION_ACCESS_FAULT");
exc_code_ILLEGAL_INSTRUCTION: $format ("ILLEGAL_INSTRUCTION");
exc_code_BREAKPOINT: $format ("BREAKPOINT");
exc_code_INSTR_ADDR_MISALIGNED: $format ("INSTRUCTION_ADDR_MISALIGNED");
exc_code_INSTR_ACCESS_FAULT: $format ("INSTRUCTION_ACCESS_FAULT");
exc_code_ILLEGAL_INSTRUCTION: $format ("ILLEGAL_INSTRUCTION");
exc_code_BREAKPOINT: $format ("BREAKPOINT");
exc_code_LOAD_ADDR_MISALIGNED: $format ("LOAD_ADDR_MISALIGNED");
exc_code_LOAD_ACCESS_FAULT: $format ("LOAD_ACCESS_FAULT");
exc_code_LOAD_ADDR_MISALIGNED: $format ("LOAD_ADDR_MISALIGNED");
exc_code_LOAD_ACCESS_FAULT: $format ("LOAD_ACCESS_FAULT");
exc_code_STORE_AMO_ADDR_MISALIGNED: $format ("STORE_AMO_ADDR_MISALIGNED");
exc_code_STORE_AMO_ACCESS_FAULT: $format ("STORE_AMO_ACCESS_FAULT");
exc_code_STORE_AMO_ADDR_MISALIGNED: $format ("STORE_AMO_ADDR_MISALIGNED");
exc_code_STORE_AMO_ACCESS_FAULT: $format ("STORE_AMO_ACCESS_FAULT");
exc_code_ECALL_FROM_U: $format ("ECALL_FROM_U");
exc_code_ECALL_FROM_S: $format ("ECALL_FROM_S");
exc_code_ECALL_FROM_M: $format ("ECALL_FROM_M");
exc_code_ECALL_FROM_U: $format ("ECALL_FROM_U");
exc_code_ECALL_FROM_S: $format ("ECALL_FROM_S");
exc_code_ECALL_FROM_M: $format ("ECALL_FROM_M");
exc_code_INSTR_PAGE_FAULT: $format ("INSTRUCTION_PAGE_FAULT");
exc_code_LOAD_PAGE_FAULT: $format ("LOAD_PAGE_FAULT");
exc_code_STORE_AMO_PAGE_FAULT: $format ("STORE_AMO_PAGE_FAULT");
exc_code_INSTR_PAGE_FAULT: $format ("INSTRUCTION_PAGE_FAULT");
exc_code_LOAD_PAGE_FAULT: $format ("LOAD_PAGE_FAULT");
exc_code_STORE_AMO_PAGE_FAULT: $format ("STORE_AMO_PAGE_FAULT");
default: $format ("unknown trap Exc_Code %d", exc_code);
endcase;
default: $format ("unknown trap Exc_Code %d", exc_code);
endcase;
endfunction
// ================================================================
@@ -632,44 +632,44 @@ endfunction
// and if so, corresponding exception code
function Maybe #(Exc_Code) fv_interrupt_pending (MISA misa,
WordXL mstatus,
WordXL mip,
WordXL mie,
Bit #(12) mideleg,
Bit #(12) sideleg,
Priv_Mode cur_priv);
WordXL mstatus,
WordXL mip,
WordXL mie,
Bit #(12) mideleg,
Bit #(12) sideleg,
Priv_Mode cur_priv);
function Maybe #(Exc_Code) fv_interrupt_i_pending (Exc_Code i);
Bool intr_pending = ((mip [i] == 1) && (mie [i] == 1));
Priv_Mode handler_priv;
if (mideleg [i] == 1)
if (misa.u == 1)
if (misa.s == 1)
// System with M, S, U
if (sideleg [i] == 1)
if (misa.n == 1)
// M->S->U delegation
handler_priv = u_Priv_Mode;
else
// Error: SIDELEG [i] should not be 1 if MISA.N is 0
handler_priv = m_Priv_Mode;
else
if (misa.u == 1)
if (misa.s == 1)
// System with M, S, U
if (sideleg [i] == 1)
if (misa.n == 1)
// M->S->U delegation
handler_priv = u_Priv_Mode;
else
// Error: SIDELEG [i] should not be 1 if MISA.N is 0
handler_priv = m_Priv_Mode;
else
// M->S delegation
handler_priv = s_Priv_Mode;
else
// System with M, U
if (misa.n == 1)
// M->U delegation
handler_priv = u_Priv_Mode;
else
// Error: MIDELEG [i] should not be 1 if MISA.N is 0
handler_priv = m_Priv_Mode;
else
// Error: System with M only; MIDELEG [i] should not be 1
handler_priv = m_Priv_Mode;
handler_priv = s_Priv_Mode;
else
// System with M, U
if (misa.n == 1)
// M->U delegation
handler_priv = u_Priv_Mode;
else
// Error: MIDELEG [i] should not be 1 if MISA.N is 0
handler_priv = m_Priv_Mode;
else
// Error: System with M only; MIDELEG [i] should not be 1
handler_priv = m_Priv_Mode;
else
// no delegation
handler_priv = m_Priv_Mode;
// no delegation
handler_priv = m_Priv_Mode;
Bool xie;
if (cur_priv == u_Priv_Mode)
@@ -680,10 +680,10 @@ function Maybe #(Exc_Code) fv_interrupt_pending (MISA misa,
xie = (mstatus [mstatus_mie_bitpos] == 1);
else
// Error: unexpected mode
xie = False;
xie = False;
Bool glob_enabled = ( (cur_priv < handler_priv)
|| ((cur_priv == handler_priv) && xie));
|| ((cur_priv == handler_priv) && xie));
return ((intr_pending && glob_enabled) ? (tagged Valid i) : (tagged Invalid));
endfunction

View File

@@ -342,19 +342,19 @@ endfunction
function Bool is_invalid_pte (PTE pte);
return ( (fn_PTE_to_V (pte) == 0)
|| ( (fn_PTE_to_R (pte) == 0)
&& (fn_PTE_to_W (pte) == 1)));
|| ( (fn_PTE_to_R (pte) == 0)
&& (fn_PTE_to_W (pte) == 1)));
endfunction
// ----------------
// Check if PTE bits deny a virtual-mem access
function Bool is_pte_denial (Bool dmem_not_imem, // load-store or fetch?
Bool read_not_write,
Priv_Mode priv,
Bit #(1) sstatus_SUM,
Bit #(1) mstatus_MXR,
PTE pte);
Bool read_not_write,
Priv_Mode priv,
Bit #(1) sstatus_SUM,
Bit #(1) mstatus_MXR,
PTE pte);
let pte_u = fn_PTE_to_U (pte);
let pte_x = fn_PTE_to_X (pte);
@@ -362,7 +362,7 @@ function Bool is_pte_denial (Bool dmem_not_imem, // load-store or f
let pte_r = fn_PTE_to_R (pte);
Bool priv_deny = ( ((priv == u_Priv_Mode) && (pte_u == 1'b0))
|| ((priv == s_Priv_Mode) && (pte_u == 1'b1) && (sstatus_SUM == 1'b0)));
|| ((priv == s_Priv_Mode) && (pte_u == 1'b1) && (sstatus_SUM == 1'b0)));
Bool access_fetch = ((! dmem_not_imem) && read_not_write);
Bool access_load = (dmem_not_imem && read_not_write);
@@ -371,8 +371,8 @@ function Bool is_pte_denial (Bool dmem_not_imem, // load-store or f
let pte_r_mxr = (pte_r | (mstatus_MXR & pte_x));
Bool access_ok = ( (access_fetch && (pte_x == 1'b1))
|| (access_load && (pte_r_mxr == 1'b1))
|| (access_store && (pte_w == 1'b1)));
|| (access_load && (pte_r_mxr == 1'b1))
|| (access_store && (pte_w == 1'b1)));
return (priv_deny || (! access_ok));
@@ -383,7 +383,7 @@ endfunction
function Bool is_pte_A_D_fault (Bool read_not_write, PTE pte);
return ( (fn_PTE_to_A (pte) == 0)
|| ((! read_not_write) && (fn_PTE_to_D (pte) == 0)));
|| ((! read_not_write) && (fn_PTE_to_D (pte) == 0)));
endfunction
// ----------------
@@ -391,8 +391,8 @@ endfunction
function Exc_Code fn_page_fault_exc_code (Bool dmem_not_imem, Bool read_not_write);
return ((! dmem_not_imem) ? exc_code_INSTR_PAGE_FAULT
:(read_not_write ? exc_code_LOAD_PAGE_FAULT
: exc_code_STORE_AMO_PAGE_FAULT));
:(read_not_write ? exc_code_LOAD_PAGE_FAULT
: exc_code_STORE_AMO_PAGE_FAULT));
endfunction
`else // ifdef ISA_PRIV_S
@@ -414,8 +414,8 @@ endfunction
function Exc_Code fn_access_exc_code (Bool dmem_not_imem, Bool read_not_write);
return ((! dmem_not_imem) ? exc_code_INSTR_ACCESS_FAULT
:(read_not_write ? exc_code_LOAD_ACCESS_FAULT
: exc_code_STORE_AMO_ACCESS_FAULT));
:(read_not_write ? exc_code_LOAD_ACCESS_FAULT
: exc_code_STORE_AMO_ACCESS_FAULT));
endfunction
// ================================================================

View File

@@ -25,25 +25,25 @@ import ISA_Decls :: *;
// ================================================================
typedef enum {// These are not from instruction flow and do not have a PC or instruction
TRACE_RESET,
TRACE_GPR_WRITE,
TRACE_FPR_WRITE,
TRACE_CSR_WRITE,
TRACE_MEM_WRITE,
TRACE_RESET,
TRACE_GPR_WRITE,
TRACE_FPR_WRITE,
TRACE_CSR_WRITE,
TRACE_MEM_WRITE,
// These are from instruction flow and have a PC and instruction
TRACE_OTHER,
TRACE_I_RD, TRACE_F_RD,
TRACE_I_LOAD, TRACE_F_LOAD,
TRACE_STORE,
TRACE_AMO,
TRACE_TRAP,
TRACE_RET,
TRACE_CSRRX,
// These are from instruction flow and have a PC and instruction
TRACE_OTHER,
TRACE_I_RD, TRACE_F_GRD, TRACE_F_FRD,
TRACE_I_LOAD, TRACE_F_LOAD,
TRACE_I_STORE, TRACE_F_STORE,
TRACE_AMO,
TRACE_TRAP,
TRACE_RET,
TRACE_CSRRX,
// These are from an interrupt and has a PC but no instruction
TRACE_INTR
} Trace_Op
// These are from an interrupt and has a PC but no instruction
TRACE_INTR
} Trace_Op
deriving (Bits, Eq, FShow);
typedef struct {
@@ -56,6 +56,9 @@ typedef struct {
WordXL word2;
Bit #(64) word3; // Wider than WordXL because can contain paddr (in RV32, paddr can be 34 bits)
WordXL word4;
`ifdef ISA_F
WordFL word5;
`endif
} Trace_Data
deriving (Bits);
@@ -139,19 +142,39 @@ function Trace_Data mkTrace_I_RD (WordXL pc, ISize isize, Bit #(32) instr, RegNa
return td;
endfunction
// F_RD
// op pc instr_sz instr rd word1 word2 word3 word4
// x x x x x rdval
function Trace_Data mkTrace_F_RD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval);
`ifdef ISA_F
// F_FRD
// op pc instr_sz instr rd word1 word2 word3 word4 word5
// x x x x x fflags mstatus rdval
function Trace_Data mkTrace_F_FRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, Bit#(5) fflags, WordXL mstatus);
Trace_Data td = ?;
td.op = TRACE_F_RD;
td.op = TRACE_F_FRD;
td.pc = pc;
td.instr_sz = isize;
td.instr = instr;
td.rd = rd;
td.word2 = extend (fflags);
td.word4 = mstatus;
td.word5 = rdval;
return td;
endfunction
// F_GRD
// op pc instr_sz instr rd word1 word2 word3 word4 word5
// x x x x x rdval fflags mstatus
function Trace_Data mkTrace_F_GRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, Bit#(5) fflags, WordXL mstatus);
Trace_Data td = ?;
td.op = TRACE_F_GRD;
td.pc = pc;
td.instr_sz = isize;
td.instr = instr;
td.rd = rd;
td.word1 = rdval;
td.word2 = extend (fflags);
td.word4 = mstatus;
return td;
endfunction
`endif
// I_LOAD
// op pc instr_sz instr rd word1 word2 word3 word4
@@ -168,40 +191,70 @@ function Trace_Data mkTrace_I_LOAD (WordXL pc, ISize isize, Bit #(32) instr, Reg
return td;
endfunction
// F_LOAD
// I_STORE
// op pc instr_sz instr rd word1 word2 word3 word4
// x x x x x rdval eaddr
function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, WordXL eaddr);
// x x x x funct3 stval eaddr
function Trace_Data mkTrace_I_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr);
Trace_Data td = ?;
td.op = TRACE_I_STORE;
td.pc = pc;
td.instr_sz = isize;
td.instr = instr;
td.word1 = zeroExtend (funct3);
td.word2 = stval;
td.word3 = zeroExtend (eaddr);
return td;
endfunction
`ifdef ISA_F
// F_LOAD
// op pc instr_sz instr rd word1 word2 word3 word4 word5
// x x x x x eaddr mstatus rdval
function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, WordXL eaddr, WordXL mstatus);
Trace_Data td = ?;
td.op = TRACE_F_LOAD;
td.pc = pc;
td.instr_sz = isize;
td.instr = instr;
td.rd = rd;
td.word1 = rdval;
td.word3 = zeroExtend (eaddr);
td.word4 = mstatus;
td.word5 = rdval;
return td;
endfunction
// STORE
// op pc instr_sz instr rd word1 word2 word3 word4
// x x x x stval eaddr
function Trace_Data mkTrace_STORE (WordXL pc, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr);
// F_STORE
// op pc instr_sz instr rd word1 word2 word3 word4 word5
// x x x x funct3 eaddr stval
function Trace_Data mkTrace_F_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordFL stval, WordXL eaddr);
Trace_Data td = ?;
td.op = TRACE_STORE;
td.op = TRACE_F_STORE;
td.pc = pc;
td.instr_sz = isize;
td.instr = instr;
td.word2 = stval;
td.word3 = zeroExtend (eaddr);
td.word5 = stval;
return td;
endfunction
function Trace_Data fv_trace_update_mstatus_fs (Trace_Data td, Bit #(2) fs);
let ntd = td;
ntd.word4 = fv_assign_bits (td.word4, fromInteger (mstatus_fs_bitpos), fs);
return (ntd);
endfunction
function Trace_Data fv_trace_update_fcsr_fflags (Trace_Data td, Bit #(5) fflags);
let ntd = td;
ntd.word2 = (td.word2 | extend (fflags));
return (ntd);
endfunction
`endif
// AMO
// op pc instr_sz instr rd word1 word2 word3 word4
// x x x x x rdval stval eaddr
function Trace_Data mkTrace_AMO (WordXL pc, ISize isize, Bit #(32) instr,
RegName rd, WordXL rdval, WordXL stval, WordXL eaddr);
// x x x x x rdval stval eaddr funct3
function Trace_Data mkTrace_AMO (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr,
RegName rd, WordXL rdval, WordXL stval, WordXL eaddr);
Trace_Data td = ?;
td.op = TRACE_AMO;
td.pc = pc;
@@ -211,6 +264,7 @@ function Trace_Data mkTrace_AMO (WordXL pc, ISize isize, Bit #(32) instr,
td.word1 = rdval;
td.word2 = stval;
td.word3 = zeroExtend (eaddr);
td.word4 = zeroExtend (funct3);
return td;
endfunction
@@ -218,7 +272,7 @@ endfunction
// op pc instr_sz instr rd word1 word2 word3 word4
// x x x x priv mstatus mcause mepc mtval
function Trace_Data mkTrace_TRAP (WordXL pc, ISize isize, Bit #(32) instr,
Priv_Mode priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
Priv_Mode priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
Trace_Data td = ?;
td.op = TRACE_TRAP;
td.pc = pc;
@@ -247,10 +301,14 @@ function Trace_Data mkTrace_RET (WordXL pc, ISize isize, Bit #(32) instr, Priv_M
endfunction
// CSRRX
// op pc instr_sz instr rd word1 word2 word3 word4
// x x x x x rdval csrvalid csraddr csrval
// op pc instr_sz instr rd word1 word2 word3 word4 word5
// x x x x x rdval [1] mstatus_valid csraddr csrval mstatus
// [0] csrvalid
function Trace_Data mkTrace_CSRRX (WordXL pc, ISize isize, Bit #(32) instr,
RegName rd, WordXL rdval, Bool csrvalid, CSR_Addr csraddr, WordXL csrval);
RegName rd, WordXL rdval,
Bool csrvalid, CSR_Addr csraddr, WordXL csrval,
Bool mstatus_valid,
WordXL mstatus);
Trace_Data td = ?;
td.op = TRACE_CSRRX;
td.pc = pc;
@@ -258,9 +316,12 @@ function Trace_Data mkTrace_CSRRX (WordXL pc, ISize isize, Bit #(32) instr,
td.instr = instr;
td.rd = rd;
td.word1 = rdval;
td.word2 = (csrvalid ? 1 : 0);
td.word2 = ((mstatus_valid ? 2 : 0) | (csrvalid ? 1 : 0));
td.word3 = zeroExtend (csraddr);
td.word4 = csrval;
`ifdef ISA_F
td.word5 = mstatus;
`endif
return td;
endfunction
@@ -268,7 +329,7 @@ endfunction
// op pc instr_sz instr rd word1 word2 word3 word4
// x x priv mstatus mcause mepc mtval
function Trace_Data mkTrace_INTR (WordXL pc,
Priv_Mode priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
Priv_Mode priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
Trace_Data td = ?;
td.op = TRACE_INTR;
td.pc = pc;
@@ -291,44 +352,57 @@ instance FShow #(Trace_Data);
end
else if ((td.op == TRACE_GPR_WRITE) || (td.op == TRACE_FPR_WRITE))
fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1);
fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1);
else if (td.op == TRACE_CSR_WRITE)
fmt = fmt + $format (" csraddr %0h csrval %0h", td.word3, td.word4);
fmt = fmt + $format (" csraddr %0h csrval %0h", td.word3, td.word4);
else if (td.op == TRACE_MEM_WRITE)
fmt = fmt + $format (" sz %0d stval %0h paddr %0h", td.word1, td.word2, td.word3);
fmt = fmt + $format (" sz %0d stval %0h paddr %0h", td.word1, td.word2, td.word3);
else begin
fmt = fmt + $format (" pc %0h", td.pc);
fmt = fmt + $format (" pc %0h", td.pc);
if (td.op != TRACE_INTR)
fmt = fmt + $format (" instr.%0d %0h:", pack (td.instr_sz), td.instr);
if (td.op != TRACE_INTR)
fmt = fmt + $format (" instr.%0d %0h:", pack (td.instr_sz), td.instr);
if ((td.op == TRACE_I_RD) || (td.op == TRACE_F_RD))
fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1);
if (td.op == TRACE_I_RD)
fmt = fmt + $format (" rd %0d rdval %0h", td.rd, td.word1);
`ifdef ISA_F
else if (td.op == TRACE_F_FRD)
fmt = fmt + $format (" rd %0d rdval %0h fflags %05b", td.rd, td.word5, td.word2);
else if ((td.op == TRACE_I_LOAD) || (td.op == TRACE_F_LOAD))
fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h",
td.rd, td.word1, td.word3);
else if (td.op == TRACE_F_GRD)
fmt = fmt + $format (" rd %0d rdval %0h fflags %05b", td.rd, td.word1, td.word2);
else if (td.op == TRACE_STORE)
fmt = fmt + $format (" stval %0h eaddr %0h", td.word2, td.word3);
else if (td.op == TRACE_F_LOAD)
fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h",
td.rd, td.word5, td.word3);
else if (td.op == TRACE_AMO)
fmt = fmt + $format (" rd %0d rdval %0h stval %0h eaddr %0h",
td.rd, td.word1, td.word2, td.word3);
else if (td.op == TRACE_F_STORE)
fmt = fmt + $format (" stval %0h eaddr %0h", td.word5, td.word3);
`endif
else if (td.op == TRACE_I_LOAD)
fmt = fmt + $format (" rd %0d rdval %0h eaddr %0h",
td.rd, td.word1, td.word3);
else if (td.op == TRACE_CSRRX)
fmt = fmt + $format (" rd %0d rdval %0h csraddr %0h csrval %0h",
td.rd, td.word1, td.word3, td.word4);
else if (td.op == TRACE_I_STORE)
fmt = fmt + $format (" stval %0h eaddr %0h", td.word2, td.word3);
else if ((td.op == TRACE_TRAP) || (td.op == TRACE_INTR))
fmt = fmt + $format (" priv %0d mstatus %0h mcause %0h mepc %0h mtval %0h",
td.rd, td.word1, td.word2, td.word3, td.word4);
else if (td.op == TRACE_AMO)
fmt = fmt + $format (" rd %0d rdval %0h stval %0h eaddr %0h",
td.rd, td.word1, td.word2, td.word3);
else if (td.op == TRACE_RET)
fmt = fmt + $format (" priv %0d mstatus %0h", td.rd, td.word1);
else if (td.op == TRACE_CSRRX)
fmt = fmt + $format (" rd %0d rdval %0h csraddr %0h csrval %0h",
td.rd, td.word1, td.word3, td.word4);
else if ((td.op == TRACE_TRAP) || (td.op == TRACE_INTR))
fmt = fmt + $format (" priv %0d mstatus %0h mcause %0h mepc %0h mtval %0h",
td.rd, td.word1, td.word2, td.word3, td.word4);
else if (td.op == TRACE_RET)
fmt = fmt + $format (" priv %0d mstatus %0h", td.rd, td.word1);
end
fmt = fmt + $format ("}");

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
// Copyright (c) 2019-2020 Bluespec, Inc. All Rights Reserved
package PLIC;
@@ -71,8 +71,8 @@ endinterface
// PLIC interface
interface PLIC_IFC #(numeric type t_n_external_sources,
numeric type t_n_targets,
numeric type t_max_priority);
numeric type t_n_targets,
numeric type t_max_priority);
// Debugging
method Action set_verbosity (Bit #(4) verbosity);
method Action show_PLIC_state;
@@ -98,10 +98,11 @@ endinterface
module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
provisos (Add #(1, t_n_external_sources, t_n_sources), // source 0 is reserved for 'no source'
Add #(_any_0, TLog #(t_n_sources), T_wd_source_id),
Add #(_any_1, TLog #(t_n_targets), T_wd_target_id),
Log #(TAdd #(t_max_priority, 1), t_wd_priority));
Add #(_any_0, TLog #(t_n_sources), T_wd_source_id),
Add #(_any_1, TLog #(t_n_targets), T_wd_target_id),
Log #(TAdd #(t_max_priority, 1), t_wd_priority));
// 0 = quiet; 1 = show PLIC transactions; 2 = also show AXI4 transactions
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
// Source_Ids and Priorities are read and written over the memory interface
@@ -150,7 +151,7 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
// Interrupt enables from source to target
Vector #(t_n_targets,
Vector #(t_n_sources, Reg #(Bool))) vvrg_ie <- replicateM (replicateM (mkReg (False)));
Vector #(t_n_sources, Reg #(Bool))) vvrg_ie <- replicateM (replicateM (mkReg (False)));
// ================================================================
// Compute outputs for each target (combinational)
@@ -163,42 +164,42 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
// Note: source_ids begin at 1, not 0.
for (Integer source_id = 1; source_id < n_sources; source_id = source_id + 1)
if ( vrg_source_ip [source_id]
&& (vrg_source_prio [source_id] > max_prio)
&& (vvrg_ie [target_id][source_id])) begin
max_id = fromInteger (source_id);
max_prio = vrg_source_prio [source_id];
end
if ( vrg_source_ip [source_id]
&& (vrg_source_prio [source_id] > max_prio)
&& (vvrg_ie [target_id][source_id])) begin
max_id = fromInteger (source_id);
max_prio = vrg_source_prio [source_id];
end
// Assert: if any interrupt is pending (max_id > 0), then prio > 0
return tuple2 (max_prio, max_id);
endfunction
function Action fa_show_PLIC_state;
action
$display ("----------------");
$write ("Src IPs :");
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", pack (vrg_source_ip [source_id]));
$display ("");
$display ("----------------");
$write ("Src IPs :");
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", pack (vrg_source_ip [source_id]));
$display ("");
$write ("Src Prios:");
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", vrg_source_prio [source_id]);
$display ("");
$write ("Src Prios:");
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", vrg_source_prio [source_id]);
$display ("");
$write ("Src busy :");
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", pack (vrg_source_busy [source_id]));
$display ("");
$write ("Src busy :");
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", pack (vrg_source_busy [source_id]));
$display ("");
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1) begin
$write ("T %0d IEs :", target_id);
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", vvrg_ie [target_id][source_id]);
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (fromInteger (target_id));
$display (" MaxPri %0d, Thresh %0d, MaxId %0d, Svcing %0d",
max_prio, vrg_target_threshold [target_id], max_id, vrg_servicing_source [target_id]);
end
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1) begin
$write ("T %0d IEs :", target_id);
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
$write (" %0d", vvrg_ie [target_id][source_id]);
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (fromInteger (target_id));
$display (" MaxPri %0d, Thresh %0d, MaxId %0d, Svcing %0d",
max_prio, vrg_target_threshold [target_id], max_id, vrg_servicing_source [target_id]);
end
endaction
endfunction
@@ -207,25 +208,25 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
rule rl_reset;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_reset", cur_cycle);
$display ("%0d: PLIC.rl_reset", cur_cycle);
let x <- pop (f_reset_reqs);
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1) begin
vrg_source_ip [source_id] <= False;
vrg_source_busy [source_id] <= False;
vrg_source_prio [source_id] <= 0;
vrg_source_ip [source_id] <= False;
vrg_source_busy [source_id] <= False;
vrg_source_prio [source_id] <= 0;
end
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1) begin
// Mask all interrupts with highest threshold
vrg_target_threshold [target_id] <= '1;
vrg_servicing_source [target_id] <= 0;
// Mask all interrupts with highest threshold
vrg_target_threshold [target_id] <= '1;
vrg_servicing_source [target_id] <= 0;
end
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1)
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
vvrg_ie [target_id][source_id] <= False;
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
vvrg_ie [target_id][source_id] <= False;
slave_xactor.reset;
@@ -244,8 +245,8 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
let rda <- pop_o (slave_xactor.o_rd_addr);
if (cfg_verbosity > 1) begin
$display ("%0d: PLIC.rl_process_rd_req:", cur_cycle);
$display (" ", fshow (rda));
$display ("%0d: PLIC.rl_process_rd_req:", cur_cycle);
$display (" ", fshow (rda));
end
let addr_offset = rda.araddr - rg_addr_base;
@@ -253,148 +254,148 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
AXI4_Resp rresp = axi4_resp_okay;
if (rda.araddr < rg_addr_base) begin
// Technically this should not happen: the fabric should
// never have delivered such an addr to this IP.
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
$display (" ", fshow (rda));
rresp = axi4_resp_decerr;
// Technically this should not happen: the fabric should
// never have delivered such an addr to this IP.
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
$display (" ", fshow (rda));
rresp = axi4_resp_decerr;
end
// Source Priority
else if (addr_offset < 'h1000) begin
Bit #(T_wd_source_id) source_id = truncate (addr_offset [11:2]);
if ((0 < source_id) && (source_id <= fromInteger (n_sources - 1))) begin
rdata = changeWidth (vrg_source_prio [source_id]);
Bit #(T_wd_source_id) source_id = truncate (addr_offset [11:2]);
if ((0 < source_id) && (source_id <= fromInteger (n_sources - 1))) begin
rdata = changeWidth (vrg_source_prio [source_id]);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Source Priority: source %0d = 0x%0h",
cur_cycle, source_id, rdata);
end
else
rresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Source Priority: source %0d = 0x%0h",
cur_cycle, source_id, rdata);
end
else
rresp = axi4_resp_slverr;
end
// Source IPs (interrupt pending).
// Return 32 consecutive IP bits starting with addr.
else if (('h1000 <= addr_offset) && (addr_offset < 'h2000)) begin
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [11:0], 5'h0 });
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [11:0], 5'h0 });
function Bool fn_ip_source_id (Integer source_id_offset);
let source_id = source_id_base + fromInteger (source_id_offset);
Bool ip_source_id = ( (source_id <= fromInteger (n_sources - 1))
? vrg_source_ip [source_id]
: False);
return ip_source_id;
endfunction
function Bool fn_ip_source_id (Integer source_id_offset);
let source_id = source_id_base + fromInteger (source_id_offset);
Bool ip_source_id = ( (source_id <= fromInteger (n_sources - 1))
? vrg_source_ip [source_id]
: False);
return ip_source_id;
endfunction
if (source_id_base <= fromInteger (n_sources - 1)) begin
Bit #(32) v_ip = pack (genWith (fn_ip_source_id));
rdata = changeWidth (v_ip);
if (source_id_base <= fromInteger (n_sources - 1)) begin
Bit #(32) v_ip = pack (genWith (fn_ip_source_id));
rdata = changeWidth (v_ip);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Intr Pending 32 bits from source %0d = 0x%0h",
cur_cycle, source_id_base, rdata);
end
else
rresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Intr Pending 32 bits from source %0d = 0x%0h",
cur_cycle, source_id_base, rdata);
end
else
rresp = axi4_resp_slverr;
end
// Source IEs (interrupt enables) for a target
// Return 32 consecutive IE bits starting with addr.
// Target 0 addrs: 2000-207F, Target 1 addrs: 2080-20FF, ...
else if (('h2000 <= addr_offset) && (addr_offset < 'h3000)) begin
Bit #(T_wd_target_id) target_id = truncate (addr_offset [11:7]);
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [6:0], 5'h0 });
Bit #(T_wd_target_id) target_id = truncate (addr_offset [11:7]);
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [6:0], 5'h0 });
function Bool fn_ie_source_id (Integer source_id_offset);
let source_id = fromInteger (source_id_offset) + source_id_base;
return ( (source_id <= fromInteger (n_sources - 1))
? vvrg_ie [target_id][source_id]
: False);
endfunction
function Bool fn_ie_source_id (Integer source_id_offset);
let source_id = fromInteger (source_id_offset) + source_id_base;
return ( (source_id <= fromInteger (n_sources - 1))
? vvrg_ie [target_id][source_id]
: False);
endfunction
if ( (source_id_base <= fromInteger (n_sources - 1))
&& (target_id <= fromInteger (n_targets - 1))) begin
Bit #(32) v_ie = pack (genWith (fn_ie_source_id));
rdata = changeWidth (v_ie);
if ( (source_id_base <= fromInteger (n_sources - 1))
&& (target_id <= fromInteger (n_targets - 1))) begin
Bit #(32) v_ie = pack (genWith (fn_ie_source_id));
rdata = changeWidth (v_ie);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Intr Enable 32 bits from source %0d = 0x%0h",
cur_cycle, source_id_base, rdata);
end
else
rresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Intr Enable 32 bits from source %0d = 0x%0h",
cur_cycle, source_id_base, rdata);
end
else
rresp = axi4_resp_slverr;
end
// Target threshold
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0000) begin
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
if (target_id <= fromInteger (n_targets - 1)) begin
rdata = changeWidth (vrg_target_threshold [target_id]);
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
if (target_id <= fromInteger (n_targets - 1)) begin
rdata = changeWidth (vrg_target_threshold [target_id]);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Threshold for target %0d = 0x%0h",
cur_cycle, target_id, rdata);
end
else
rresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Threshold for target %0d = 0x%0h",
cur_cycle, target_id, rdata);
end
else
rresp = axi4_resp_slverr;
end
// Interrupt service claim by target
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0004) begin
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (target_id);
Bool eip = (max_prio > vrg_target_threshold [target_id]);
if (target_id <= fromInteger (n_targets - 1)) begin
if (vrg_servicing_source [target_id] != 0) begin
$display ("%0d: ERROR: PLIC: target %0d claiming without prior completion",
cur_cycle, target_id);
$display (" Still servicing interrupt from source %0d", vrg_servicing_source [target_id]);
$display (" Trying to claim service for source %0d", max_id);
$display (" Ignoring.");
rresp = axi4_resp_slverr;
end
else begin
if (max_id != 0) begin
vrg_source_ip [max_id] <= False;
vrg_source_busy [max_id] <= True;
vrg_servicing_source [target_id] <= truncate (max_id);
rdata = changeWidth (max_id);
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (target_id);
Bool eip = (max_prio > vrg_target_threshold [target_id]);
if (target_id <= fromInteger (n_targets - 1)) begin
if (vrg_servicing_source [target_id] != 0) begin
$display ("%0d: ERROR: PLIC: target %0d claiming without prior completion",
cur_cycle, target_id);
$display (" Still servicing interrupt from source %0d", vrg_servicing_source [target_id]);
$display (" Trying to claim service for source %0d", max_id);
$display (" Ignoring.");
rresp = axi4_resp_slverr;
end
else begin
if (max_id != 0) begin
vrg_source_ip [max_id] <= False;
vrg_source_busy [max_id] <= True;
vrg_servicing_source [target_id] <= truncate (max_id);
rdata = changeWidth (max_id);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Claim for target %0d = 0x%0h",
cur_cycle, target_id, rdata);
end
end
end
else
rresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_rd_req: reading Claim for target %0d = 0x%0h",
cur_cycle, target_id, rdata);
end
end
end
else
rresp = axi4_resp_slverr;
end
else
rresp = axi4_resp_slverr;
rresp = axi4_resp_slverr;
if (rresp != axi4_resp_okay) begin
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
$display (" ", fshow (rda));
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
$display (" ", fshow (rda));
end
if ((valueOf (Wd_Data) == 64) && ((addr_offset & 'h7) == 'h4))
rdata = { rdata [31:0], 32'h0 };
rdata = { rdata [31:0], 32'h0 };
// Send read-response to bus
Fabric_Data x = truncate (rdata);
let rdr = AXI4_Rd_Data {rid: rda.arid,
rdata: x,
rresp: rresp,
rlast: True,
ruser: rda.aruser};
rdata: x,
rresp: rresp,
rlast: True,
ruser: rda.aruser};
slave_xactor.i_rd_data.enq (rdr);
if (cfg_verbosity > 1) begin
$display ("%0d: PLIC.rl_process_rd_req", cur_cycle);
$display (" ", fshow (rda));
$display (" ", fshow (rdr));
$display ("%0d: PLIC.rl_process_rd_req", cur_cycle);
$display (" ", fshow (rda));
$display (" ", fshow (rdr));
end
endrule: rl_process_rd_req
@@ -408,139 +409,139 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
let wra <- pop_o (slave_xactor.o_wr_addr);
let wrd <- pop_o (slave_xactor.o_wr_data);
if (cfg_verbosity > 1) begin
$display ("%0d: PLIC.rl_process_wr_req", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
$display ("%0d: PLIC.rl_process_wr_req", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
end
let addr_offset = wra.awaddr - rg_addr_base;
let wdata32 = (((valueOf (Wd_Data) == 64) && ((addr_offset & 'h7) == 'h4))
? wrd.wdata [63:32]
: wrd.wdata [31:0]);
? wrd.wdata [63:32]
: wrd.wdata [31:0]);
let bresp = axi4_resp_okay;
if (wra.awaddr < rg_addr_base) begin
// Technically this should not happen: the fabric should
// never have delivered such an addr to this IP.
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
bresp = axi4_resp_decerr;
// Technically this should not happen: the fabric should
// never have delivered such an addr to this IP.
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
bresp = axi4_resp_decerr;
end
// Source priority
else if (addr_offset < 'h1000) begin
Bit #(T_wd_source_id) source_id = truncate (addr_offset [11:2]);
if ((0 < source_id) && (source_id <= fromInteger (n_sources - 1))) begin
vrg_source_prio [source_id] <= changeWidth (wdata32);
Bit #(T_wd_source_id) source_id = truncate (addr_offset [11:2]);
if ((0 < source_id) && (source_id <= fromInteger (n_sources - 1))) begin
vrg_source_prio [source_id] <= changeWidth (wdata32);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing Source Priority: source %0d = 0x%0h",
cur_cycle, source_id, wdata32);
end
else begin
// Note: write to source_id 0 is error; should it just be ignored?
bresp = axi4_resp_slverr;
end
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing Source Priority: source %0d = 0x%0h",
cur_cycle, source_id, wdata32);
end
else begin
// Note: write to source_id 0 is error; should it just be ignored?
bresp = axi4_resp_slverr;
end
end
// Source IPs (interrupt pending).
// Read-only, so ignore write; just check that addr ok.
else if (('h1000 <= addr_offset) && (addr_offset < 'h2000)) begin
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [11:0], 5'h0 });
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [11:0], 5'h0 });
if (source_id_base <= fromInteger (n_sources - 1)) begin
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: Ignoring write to Read-only Intr Pending 32 bits from source %0d",
cur_cycle, source_id_base);
end
else
bresp = axi4_resp_slverr;
if (source_id_base <= fromInteger (n_sources - 1)) begin
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: Ignoring write to Read-only Intr Pending 32 bits from source %0d",
cur_cycle, source_id_base);
end
else
bresp = axi4_resp_slverr;
end
// Source IEs (interrupt enables) for a target
// Write 32 consecutive IE bits starting with addr.
// Target 0 addrs: 2000-207F, Target 1 addrs: 2080-20FF, ...
else if (('h2000 <= addr_offset) && (addr_offset < 'h3000)) begin
Bit #(T_wd_target_id) target_id = truncate (addr_offset [11:7]);
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [6:0], 5'h0 });
Bit #(T_wd_target_id) target_id = truncate (addr_offset [11:7]);
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [6:0], 5'h0 });
if ( (source_id_base <= fromInteger (n_sources - 1))
&& (target_id <= fromInteger (n_targets - 1))) begin
for (Bit #(T_wd_source_id) k = 0; k < 32; k = k + 1) begin
Bit #(T_wd_source_id) source_id = source_id_base + k;
if (source_id <= fromInteger (n_sources - 1))
vvrg_ie [target_id][source_id] <= unpack (wdata32 [k]);
end
if ( (source_id_base <= fromInteger (n_sources - 1))
&& (target_id <= fromInteger (n_targets - 1))) begin
for (Bit #(T_wd_source_id) k = 0; k < 32; k = k + 1) begin
Bit #(T_wd_source_id) source_id = source_id_base + k;
if (source_id <= fromInteger (n_sources - 1))
vvrg_ie [target_id][source_id] <= unpack (wdata32 [k]);
end
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing Intr Enable 32 bits for target %0d from source %0d = 0x%0h",
cur_cycle, target_id, source_id_base, wdata32);
end
else
bresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing Intr Enable 32 bits for target %0d from source %0d = 0x%0h",
cur_cycle, target_id, source_id_base, wdata32);
end
else
bresp = axi4_resp_slverr;
end
// Target threshold
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0000) begin
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
if (target_id <= fromInteger (n_targets - 1)) begin
vrg_target_threshold [target_id] <= changeWidth (wdata32);
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
if (target_id <= fromInteger (n_targets - 1)) begin
vrg_target_threshold [target_id] <= changeWidth (wdata32);
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing threshold for target %0d = 0x%0h",
cur_cycle, target_id, wdata32);
end
else
bresp = axi4_resp_slverr;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing threshold for target %0d = 0x%0h",
cur_cycle, target_id, wdata32);
end
else
bresp = axi4_resp_slverr;
end
// Interrupt service completion by target
// Actual memory-write-data is irrelevant.
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0004) begin
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
Bit #(T_wd_source_id) source_id = zeroExtend (vrg_servicing_source [target_id]);
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
Bit #(T_wd_source_id) source_id = zeroExtend (vrg_servicing_source [target_id]);
if (target_id <= fromInteger (n_targets - 1)) begin
if (vrg_source_busy [source_id]) begin
vrg_source_busy [source_id] <= False;
vrg_servicing_source [target_id] <= 0;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing completion for target %0d for source 0x%0h",
cur_cycle, target_id, source_id);
end
else begin
$display ("%0d: ERROR: PLIC: interrupt completion to source that is not being serviced",
cur_cycle);
$display (" Completion message from target %0d to source %0d", target_id, source_id);
$display (" Ignoring");
bresp = axi4_resp_slverr;
end
end
else
bresp = axi4_resp_slverr;
if (target_id <= fromInteger (n_targets - 1)) begin
if (vrg_source_busy [source_id]) begin
vrg_source_busy [source_id] <= False;
vrg_servicing_source [target_id] <= 0;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.rl_process_wr_req: writing completion for target %0d for source 0x%0h",
cur_cycle, target_id, source_id);
end
else begin
$display ("%0d: ERROR: PLIC: interrupt completion to source that is not being serviced",
cur_cycle);
$display (" Completion message from target %0d to source %0d", target_id, source_id);
$display (" Ignoring");
bresp = axi4_resp_slverr;
end
end
else
bresp = axi4_resp_slverr;
end
else
bresp = axi4_resp_slverr;
bresp = axi4_resp_slverr;
if (bresp != axi4_resp_okay) begin
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
end
// Send write-response to bus
let wrr = AXI4_Wr_Resp {bid: wra.awid,
bresp: bresp,
buser: wra.awuser};
bresp: bresp,
buser: wra.awuser};
slave_xactor.i_wr_resp.enq (wrr);
if (cfg_verbosity > 1) begin
$display ("%0d: PLIC.AXI4.rl_process_wr_req", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
$display (" ", fshow (wrr));
$display ("%0d: PLIC.AXI4.rl_process_wr_req", cur_cycle);
$display (" ", fshow (wra));
$display (" ", fshow (wrd));
$display (" ", fshow (wrr));
end
endrule: rl_process_wr_req
@@ -549,18 +550,18 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
function PLIC_Source_IFC fn_mk_PLIC_Source_IFC (Integer source_id);
return interface PLIC_Source_IFC;
method Action m_interrupt_req (Bool set_not_clear);
action
if (! vrg_source_busy [source_id]) begin
vrg_source_ip [source_id] <= set_not_clear;
method Action m_interrupt_req (Bool set_not_clear);
action
if (! vrg_source_busy [source_id + 1]) begin
vrg_source_ip [source_id + 1] <= set_not_clear;
if ((cfg_verbosity > 0) && (vrg_source_ip [source_id] != set_not_clear))
$display ("%0d: Changing vrg_source_ip [%0d] to %0d",
cur_cycle, source_id, pack (set_not_clear));
end
endaction
endmethod
endinterface;
if ((cfg_verbosity > 0) && (vrg_source_ip [source_id + 1] != set_not_clear))
$display ("%0d: %m.m_interrupt_req: changing vrg_source_ip [%0d] to %0d",
cur_cycle, source_id + 1, pack (set_not_clear));
end
endaction
endmethod
endinterface;
endfunction
// ================================================================
@@ -568,12 +569,12 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
function PLIC_Target_IFC fn_mk_PLIC_Target_IFC (Integer target_id);
return interface PLIC_Target_IFC;
method Bool m_eip; // external interrupt pending
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (fromInteger (target_id));
Bool eip = (max_prio > vrg_target_threshold [target_id]);
return eip;
endmethod
endinterface;
method Bool m_eip; // external interrupt pending
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (fromInteger (target_id));
Bool eip = (max_prio > vrg_target_threshold [target_id]);
return eip;
endmethod
endinterface;
endfunction
// ================================================================
@@ -594,18 +595,18 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
// set_addr_map should be called after this module's reset
method Action set_addr_map (Bit #(64) addr_base, Bit #(64) addr_lim);
if (addr_base [1:0] != 0)
$display ("%0d: WARNING: PLIC.set_addr_map: addr_base 0x%0h is not 4-Byte-aligned",
cur_cycle, addr_base);
$display ("%0d: WARNING: PLIC.set_addr_map: addr_base 0x%0h is not 4-Byte-aligned",
cur_cycle, addr_base);
if (addr_lim [1:0] != 0)
$display ("%0d: WARNING: PLIC.set_addr_map: addr_lim 0x%0h is not 4-Byte-aligned",
cur_cycle, addr_lim);
$display ("%0d: WARNING: PLIC.set_addr_map: addr_lim 0x%0h is not 4-Byte-aligned",
cur_cycle, addr_lim);
rg_addr_base <= addr_base;
rg_addr_lim <= addr_lim;
if (cfg_verbosity > 0)
$display ("%0d: PLIC.set_addr_map: base 0x%0h limit 0x%0h", cur_cycle, addr_base, addr_lim);
$display ("%0d: PLIC.set_addr_map: base 0x%0h limit 0x%0h", cur_cycle, addr_base, addr_lim);
endmethod
// Memory-mapped access

View File

@@ -28,8 +28,8 @@ typedef 2 PLIC_N_Targets;
typedef 7 PLIC_Max_Priority;
typedef PLIC_IFC #(N_External_Interrupt_Sources,
PLIC_N_Targets,
PLIC_Max_Priority) PLIC_IFC_16_2_7;
PLIC_N_Targets,
PLIC_Max_Priority) PLIC_IFC_16_2_7;
(* synthesize *)
module mkPLIC_16_2_7 (PLIC_IFC_16_2_7);

View File

@@ -1,4 +1,29 @@
The (relative) Memory map for this PLIC follows the one given in:
// Copyright (c) 2019-2020 Bluespec, Inc. All Rights Reserved
>================================================================
Our BSV PLIC here follows the example of the SiFive PLIC spec
described below ("Background"), in order to be able to use the same
Linux driver.
>================================================================
Background on PLIC ("Platform Level Interrupt Controller")
As of this writing (2019-04-29), there is not yet any official PLIC
spec for RISC-V.
In an earlier version (v1.10) of the RISC-V Privilege Architecture
spec, Chapter 7 was a PLIC spec, but it was taken out of the Priv Arch
spec to be considered separately in the future as part of a platform
spec rather than as part of the ISA spec. That chapter spec was
partial in that, while it described the required functionality, it did
not specify any specific address map for the functional components.
SiFive has implemented that PLIC spec for their cores, taking
particular decisions for memory mappings, etc., and they have
implemented a Linux driver for it.
Below is a summary of their (relative) Memory map for the PLIC the
following SiFive chip:
SiFive U54-MC Core Complex Manual, v1p0, Oct 4 2017
Chapter 8 Platform Level Interrupt Controller, pp.32-38.
@@ -27,7 +52,7 @@ IP (Interrupt Pending) array: 32 sources per 32b word
>----------------
Reserved
0x1018 ... 0x1FFF
0x1040 ... 0x1FFF
>----------------
IE (interrupt enables) array for Hart0 M mode (1 bit per source)
@@ -105,30 +130,32 @@ Reserved
>----------------
Threshold (of priority) and Claim/Complete registers
0x0C20 0000 Hart 0 M-mode
0x0C20 0004 Hart 0 M-mode claim/complete
0x0020 0000 Hart 0 M-mode
0x0020 0004 Hart 0 M-mode claim/complete
>----------------
0x0C20 1000 Hart 1 M-mode
0x0C20 1004 Hart 1 M-mode claim/complete
0x0020 1000 Hart 1 M-mode
0x0020 1004 Hart 1 M-mode claim/complete
>----------------
0x0C20 2000 Hart 1 S-mode
0x0C20 2004 Hart 1 S-mode claim/complete
0x0020 2000 Hart 1 S-mode
0x0020 2004 Hart 1 S-mode claim/complete
>----------------
0x0C20 3000 Hart 2 M-mode
0x0C20 3004 Hart 2 M-mode claim/complete
0x0020 3000 Hart 2 M-mode
0x0020 3004 Hart 2 M-mode claim/complete
>----------------
0x0C20 4000 Hart 2 S-mode
0x0C20 4004 Hart 2 S-mode claim/complete
0x0020 4000 Hart 2 S-mode
0x0020 4004 Hart 2 S-mode claim/complete
>----------------
0x0C20 5000 Hart 3 M-mode
0x0C20 5004 Hart 3 M-mode claim/complete
0x0020 5000 Hart 3 M-mode
0x0020 5004 Hart 3 M-mode claim/complete
>----------------
0x0C20 6000 Hart 3 S-mode
0x0C20 6004 Hart 3 S-mode claim/complete
0x0020 6000 Hart 3 S-mode
0x0020 6004 Hart 3 S-mode claim/complete
>----------------
0x0C20 7000 Hart 4 M-mode
0x0C20 7004 Hart 4 M-mode claim/complete
0x0020 7000 Hart 4 M-mode
0x0020 7004 Hart 4 M-mode claim/complete
>----------------
0x0C20 8000 Hart 4 S-mode
0x0C20 8004 Hart 4 S-mode claim/complete
0x0020 8000 Hart 4 S-mode
0x0020 8004 Hart 4 S-mode claim/complete
>----------------
>================================================================

View File

@@ -72,76 +72,76 @@ module mkTest_PLIC (Empty);
function Action fa_read_req (Integer addr);
action
let fabric_addr = soc_map.m_plic_addr_base + fromInteger (addr);
let fabric_addr = soc_map.m_plic_addr_base + fromInteger (addr);
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: fabric_addr,
arlen: 0, // burst len = arlen+1
arsize: zeroExtend (axsize_4),
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
f_read_addr.enq (fabric_addr);
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
araddr: fabric_addr,
arlen: 0, // burst len = arlen+1
arsize: zeroExtend (axsize_4),
arburst: fabric_default_burst,
arlock: fabric_default_lock,
arcache: fabric_default_arcache,
arprot: fabric_default_prot,
arqos: fabric_default_qos,
arregion: fabric_default_region,
aruser: fabric_default_user};
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
f_read_addr.enq (fabric_addr);
endaction
endfunction
function Action fa_read_rsp;
action
let fabric_addr <- pop (f_read_addr);
let rd_data <- pop_o (master_xactor.o_rd_data);
if (rd_data.rresp != axi4_resp_okay) begin
$display ("ERROR: fa_read_rsp: fabric response error");
$display (" ", fshow (rd_data));
end
let x = (((valueOf (Wd_Data) == 64) && ((fabric_addr & 'h7) == 'h4))
? (rd_data.rdata >> 32)
: rd_data.rdata);
f_read_data.enq (x);
let fabric_addr <- pop (f_read_addr);
let rd_data <- pop_o (master_xactor.o_rd_data);
if (rd_data.rresp != axi4_resp_okay) begin
$display ("ERROR: fa_read_rsp: fabric response error");
$display (" ", fshow (rd_data));
end
let x = (((valueOf (Wd_Data) == 64) && ((fabric_addr & 'h7) == 'h4))
? (rd_data.rdata >> 32)
: rd_data.rdata);
f_read_data.enq (x);
endaction
endfunction
function Action fa_write_req (Integer addr, Fabric_Data data);
action
let fabric_addr = soc_map.m_plic_addr_base + fromInteger (addr);
let fabric_addr = soc_map.m_plic_addr_base + fromInteger (addr);
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: fabric_addr,
awlen: 0, // burst len = awlen+1
awsize: zeroExtend (axsize_4),
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
awaddr: fabric_addr,
awlen: 0, // burst len = awlen+1
awsize: zeroExtend (axsize_4),
awburst: fabric_default_burst,
awlock: fabric_default_lock,
awcache: fabric_default_awcache,
awprot: fabric_default_prot,
awqos: fabric_default_qos,
awregion: fabric_default_region,
awuser: fabric_default_user};
let x = (((valueOf (Wd_Data) == 64) && ((fabric_addr & 'h7) == 'h4))
? (data << 32)
: data);
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
wdata: x,
wstrb: '1,
wlast: True,
wuser: fabric_default_user};
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
master_xactor.i_wr_data.enq (mem_req_wr_data);
let x = (((valueOf (Wd_Data) == 64) && ((fabric_addr & 'h7) == 'h4))
? (data << 32)
: data);
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
wdata: x,
wstrb: '1,
wlast: True,
wuser: fabric_default_user};
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
master_xactor.i_wr_data.enq (mem_req_wr_data);
endaction
endfunction
function Action fa_write_rsp;
action
let wr_resp <- pop_o (master_xactor.o_wr_resp);
let wr_resp <- pop_o (master_xactor.o_wr_resp);
if (wr_resp.bresp != axi4_resp_okay) begin
$display ("ERROR: rl_discard_write_rsp: fabric response error");
$display (" ", fshow (wr_resp));
end
if (wr_resp.bresp != axi4_resp_okay) begin
$display ("ERROR: rl_discard_write_rsp: fabric response error");
$display (" ", fshow (wr_resp));
end
endaction
endfunction
@@ -150,50 +150,50 @@ module mkTest_PLIC (Empty);
function Action fa_print_plic_eips ();
action
$write ("PLIC.v_target eip =");
$write (" ", fshow (plic.v_targets [0].m_eip));
$write (" ", fshow (plic.v_targets [1].m_eip));
$display ("");
$write ("PLIC.v_target eip =");
$write (" ", fshow (plic.v_targets [0].m_eip));
$write (" ", fshow (plic.v_targets [1].m_eip));
$display ("");
endaction
endfunction
function Stmt fstmt_set_source_priority (Integer src, Priority prio);
return seq
fa_write_req (src * 4, zeroExtend (prio));
fa_write_rsp;
endseq;
fa_write_req (src * 4, zeroExtend (prio));
fa_write_rsp;
endseq;
endfunction
function Stmt fstmt_set_target_ies (Integer target, Bit #(32) ies);
return seq
fa_write_req ('h2000 + (target * 'h80), zeroExtend (ies));
fa_write_rsp;
endseq;
fa_write_req ('h2000 + (target * 'h80), zeroExtend (ies));
fa_write_rsp;
endseq;
endfunction
function Stmt fstmt_set_target_threshold (Integer target, Priority threshold);
return seq
fa_write_req ('h20_0000 + (target * 'h1000), zeroExtend (threshold));
fa_write_rsp;
endseq;
fa_write_req ('h20_0000 + (target * 'h1000), zeroExtend (threshold));
fa_write_rsp;
endseq;
endfunction
function Stmt fstmt_claim (Integer target);
return seq
fa_read_req ('h20_0004 + (target * 'h1000));
fa_read_rsp;
action
let x <- pop (f_read_data);
$display ("fstmt_claim: PLIC returned %0d", x);
endaction
endseq;
fa_read_req ('h20_0004 + (target * 'h1000));
fa_read_rsp;
action
let x <- pop (f_read_data);
$display ("fstmt_claim: PLIC returned %0d", x);
endaction
endseq;
endfunction
function Stmt fstmt_complete (Integer target, Source_Id source_id);
return seq
fa_write_req ('h20_0004 + (target * 'h1000), zeroExtend (source_id));
fa_write_rsp;
endseq;
fa_write_req ('h20_0004 + (target * 'h1000), zeroExtend (source_id));
fa_write_rsp;
endseq;
endfunction
// ================================================================
@@ -204,89 +204,89 @@ module mkTest_PLIC (Empty);
// Drive all interrupt requests from local regs
for (Integer j = 0; j < n_external_interrupt_sources; j = j + 1)
rule rl_drive_irq;
plic.v_sources [j].m_interrupt_req (vrg_irqs [j]);
plic.v_sources [j].m_interrupt_req (vrg_irqs [j]);
endrule
// ================================================================
Stmt init = seq
action
$display ("Initializing PLIC");
plic.server_reset.request.put (?);
endaction
action
let rsp <- plic.server_reset.response.get;
plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base),
zeroExtend (soc_map.m_plic_addr_lim));
endaction
fstmt_set_source_priority (1, 0);
fstmt_set_source_priority (2, 0);
fstmt_set_source_priority (3, 0);
fstmt_set_source_priority (4, 0);
action
$display ("Initializing PLIC");
plic.server_reset.request.put (?);
endaction
action
let rsp <- plic.server_reset.response.get;
plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base),
zeroExtend (soc_map.m_plic_addr_lim));
endaction
fstmt_set_source_priority (1, 0);
fstmt_set_source_priority (2, 0);
fstmt_set_source_priority (3, 0);
fstmt_set_source_priority (4, 0);
fstmt_set_source_priority (5, 0);
fstmt_set_source_priority (6, 0);
fstmt_set_source_priority (7, 0);
fstmt_set_source_priority (8, 0);
fstmt_set_source_priority (5, 0);
fstmt_set_source_priority (6, 0);
fstmt_set_source_priority (7, 0);
fstmt_set_source_priority (8, 0);
fstmt_set_source_priority (9, 0);
fstmt_set_source_priority (10, 0);
fstmt_set_source_priority (11, 0);
fstmt_set_source_priority (12, 0);
fstmt_set_source_priority (9, 0);
fstmt_set_source_priority (10, 0);
fstmt_set_source_priority (11, 0);
fstmt_set_source_priority (12, 0);
fstmt_set_source_priority (13, 0);
fstmt_set_source_priority (14, 0);
fstmt_set_source_priority (15, 0);
fstmt_set_source_priority (16, 0);
fstmt_set_source_priority (13, 0);
fstmt_set_source_priority (14, 0);
fstmt_set_source_priority (15, 0);
fstmt_set_source_priority (16, 0);
fstmt_set_target_ies (target_0, 0);
fstmt_set_target_ies (target_1, 0);
fstmt_set_target_ies (target_0, 0);
fstmt_set_target_ies (target_1, 0);
fstmt_set_target_threshold (target_0, 7);
fstmt_set_target_threshold (target_1, 7);
delay (5);
$display ("Finished Initializing PLIC");
endseq;
fstmt_set_target_threshold (target_0, 7);
fstmt_set_target_threshold (target_1, 7);
delay (5);
$display ("Finished Initializing PLIC");
endseq;
Stmt test1 = seq
$display (">---------------- TEST 1");
plic.set_verbosity (1);
fstmt_set_source_priority (5, 4);
$display (">---------------- TEST 1");
plic.set_verbosity (1);
fstmt_set_source_priority (5, 4);
fstmt_set_target_ies (target_0, 'b10_0000); // bit 5
fstmt_set_target_threshold (target_0, 4);
fstmt_set_target_ies (target_0, 'b10_0000); // bit 5
fstmt_set_target_threshold (target_0, 4);
fstmt_set_target_ies (target_1, 'b10_0000); // bit 5
fstmt_set_target_threshold (target_1, 2);
fstmt_set_target_ies (target_1, 'b10_0000); // bit 5
fstmt_set_target_threshold (target_1, 2);
plic.show_PLIC_state;
fa_print_plic_eips;
plic.show_PLIC_state;
fa_print_plic_eips;
vrg_irqs [5] <= True;
delay (2);
plic.show_PLIC_state;
fa_print_plic_eips;
vrg_irqs [5] <= True;
delay (2);
plic.show_PLIC_state;
fa_print_plic_eips;
fstmt_set_target_threshold (target_0, 3);
plic.show_PLIC_state;
fa_print_plic_eips;
fstmt_set_target_threshold (target_0, 3);
plic.show_PLIC_state;
fa_print_plic_eips;
fstmt_claim (target_1);
plic.show_PLIC_state;
fa_print_plic_eips;
fstmt_claim (target_1);
plic.show_PLIC_state;
fa_print_plic_eips;
fstmt_complete (target_1, 5);
plic.show_PLIC_state;
fa_print_plic_eips;
endseq;
fstmt_complete (target_1, 5);
plic.show_PLIC_state;
fa_print_plic_eips;
endseq;
// ================================================================
mkAutoFSM (seq
init;
test1;
$finish (0);
endseq);
init;
test1;
$finish (0);
endseq);
endmodule

View File

@@ -22,7 +22,7 @@
// SOFTWARE.
import Ehr::*;
import Fifo::*;
import Fifos::*;
import Vector::*;
import RWBramCore::*;
import FShow::*;

View File

@@ -28,7 +28,7 @@ import CacheUtils::*;
import CCTypes::*;
import Types::*;
import FShow::*;
import Fifo::*;
import Fifos::*;
import Ehr::*;
typedef struct {
@@ -118,7 +118,7 @@ module mkXBar#(
for(Integer i = 0; i < valueOf(srcNum); i = i+1) begin
if(isDeqSrc(fromInteger(i))) begin
propDstIdx[i][1] <= Invalid;
if (verbose)
if (verbose)
$display("%t XBar %m: deq src %d", $time, i);
doAssert(isValid(propDstIdx[i][1]), "src must be proposing");
end
@@ -133,7 +133,7 @@ module mkXBar#(
rule doEnq(enqDst[i][1] matches tagged Valid .d);
dstIfc[i].put(d);
enqDst[i][1] <= Invalid; // reset enq command
if (verbose)
if (verbose)
$display("%t XBAR %m: enq dst %d ; ", $time, i, fshow(d));
endrule
end

View File

@@ -40,7 +40,7 @@ import CCPipe::*;
import L1Pipe ::*;
import FShow::*;
import DefaultValue::*;
import Fifo::*;
import Fifos::*;
import CacheUtils::*;
import Performance::*;
import LatencyTimer::*;
@@ -545,7 +545,7 @@ module mkIBank#(
doAssert(isValid(cRqEOC), "cRq hit on another cRq, cRqEOC must be true");
cRqMshr.pipelineResp.setSucc(fromMaybe(?, cRqEOC), Valid (n));
cRqSetDepNoCacheChange;
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: own by other cRq ", $time,
fshow(cOwner), ", depend on cRq ", fshow(cRqEOC)
);
@@ -557,7 +557,7 @@ module mkIBank#(
"cRq swapped in by previous cRq, tag must match & cs = S"
);
// Hit
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: own by itself, hit", $time);
cRqHit(n, procRq);
end
@@ -566,7 +566,7 @@ module mkIBank#(
// cache has no owner, cRq must just go through tag match
// check for cRqEOC to append to dependency chain
if(cRqEOC matches tagged Valid .k) begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, depend on cRq ", $time, fshow(k));
cRqMshr.pipelineResp.setSucc(k, Valid (n));
cRqSetDepNoCacheChange;
@@ -574,18 +574,18 @@ module mkIBank#(
else if(ram.info.cs == I || ram.info.tag == getTag(procRq.addr)) begin
// No Replacement necessary
if(ram.info.cs > I) begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, hit", $time);
cRqHit(n, procRq);
end
else begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, miss no replace", $time);
cRqMissNoReplacement;
end
end
else begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, replace", $time);
cRqReplacement;
end
@@ -627,14 +627,14 @@ module mkIBank#(
// pRq is always directly handled: either dropped or Done
if(pipeOut.pRqMiss) begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: pRq: drop", $time);
// pRq can be directly dropped, no successor (since just go through pipeline)
pRqMshr.pipelineResp.releaseEntry(n);
pipeline.deqWrite(Invalid, pipeOut.ram, False);
end
else begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: pRq: valid process", $time);
// should process pRq
doAssert(ram.info.cs == S && pRq.toState == I && ram.info.tag == getTag(pRq.addr),
@@ -677,13 +677,13 @@ module mkIBank#(
// flush always goes through cache pipeline, and is directly handled
// here: either dropped or Done
if(ram.info.cs == I) begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: flush: drop", $time);
// flush can be directly dropped
pRqMshr.pipelineResp.releaseEntry(n);
end
else begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: flush: valid process", $time);
pRqMshr.pipelineResp.setDone(n);
rsToPIndexQ.enq(PRq (n));
@@ -751,7 +751,7 @@ module mkIBank#(
);
cRqIndexQ.deq;
cRqMshr.sendRsToC.releaseEntry(cRqIndexQ.first); // release MSHR entry
if (verbose)
if (verbose)
$display("%t I %m sendRsToC: ", $time,
fshow(cRqIndexQ.first), " ; ",
fshow(inst)

View File

@@ -210,7 +210,7 @@ module mkICRqMshrSafe#(
initIdx <= initIdx + 1;
if(initIdx == fromInteger(valueOf(cRqNum) - 1)) begin
inited <= True;
if (verbose)
if (verbose)
$display("%t ICRqMshrSafe %m: init empty entry done", $time);
end
endrule

View File

@@ -31,7 +31,7 @@ import Types::*;
import CCTypes::*;
import DefaultValue::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import MshrDeadlockChecker::*;
// MSHR dependency chain invariant:
@@ -116,7 +116,7 @@ module mkIPRqMshrSafe(
initIdx <= initIdx + 1;
if(initIdx == fromInteger(valueOf(pRqNum) - 1)) begin
inited <= True;
if (verbose)
if (verbose)
$display("%t IPRqMshrSafe %m: init empty entry done", $time);
end
endrule

View File

@@ -41,7 +41,7 @@ import L1Pipe ::*;
import FShow::*;
import DefaultValue::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import CacheUtils::*;
import CrossBar::*;
import Performance::*;
@@ -520,7 +520,7 @@ module mkL1Bank#(
},
line: newLine // write new data into cache
}, True); // hit, so update rep info
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: Hit func: update ram: ", $time,
fshow(newLine), " ; ",
fshow(succ)
@@ -534,7 +534,7 @@ module mkL1Bank#(
req: req,
succ: succ
});
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: Hit func: AMO process in next cycle", $time);
end
endaction
@@ -618,7 +618,7 @@ module mkL1Bank#(
end
// release MSHR entry
cRqMshr.pipelineResp.releaseEntry(n);
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: Sc early fail func: ", $time,
fshow(resetOwner), " ; ",
fshow(succ)
@@ -722,7 +722,7 @@ module mkL1Bank#(
doAssert(isValid(cRqEOC), ("cRq hit on another cRq, cRqEOC must be true"));
cRqMshr.pipelineResp.setSucc(fromMaybe(?, cRqEOC), Valid (n));
cRqSetDepNoCacheChange;
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by other cRq ", $time,
fshow(cOwner), ", depend on cRq ", fshow(cRqEOC)
);
@@ -736,7 +736,7 @@ module mkL1Bank#(
);
// Hit or Miss (but no replacement)
if(enough_cs) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by itself, hit", $time);
cRqHit(n, procRq);
end
@@ -744,14 +744,14 @@ module mkL1Bank#(
// Sc already fails, so we don't need to req parent. Since
// Sc is the owner of the line, we need to reset owner to
// Invalid.
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by itself, Sc early fails, ",
$time, fshow(linkAddr)
);
cRqScEarlyFail(True);
end
else begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by itself, miss no replace", $time);
cRqMissNoReplacement;
end
@@ -767,7 +767,7 @@ module mkL1Bank#(
// check for cRqEOC to append to dependency chain
// Only append to dep-chain if is in Init state
if(cRqEOC matches tagged Valid .k &&& cState == Init) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, depend on cRq, ", $time,
fshow(cState), " ; ", fshow(cRqEOC)
);
@@ -779,7 +779,7 @@ module mkL1Bank#(
if(tag_match && enough_cs) begin
// Hit
doAssert(cs_valid, "hit, so cs must > I");
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, hit", $time);
cRqHit(n, procRq);
end
@@ -787,7 +787,7 @@ module mkL1Bank#(
// Sc already fails, so we don't need to req parent. Since
// there is no owner of the line, we can reset owner to
// Invalid.
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, Sc early fails, ",
$time, fshow(linkAddr)
);
@@ -795,12 +795,12 @@ module mkL1Bank#(
end
else if(cs_valid && !tag_match) begin
// Req parent, need replacement
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, replace", $time);
cRqReplacement;
end
else begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, miss no replace", $time);
// Req parent, no replacement needed
cRqMissNoReplacement;
@@ -841,7 +841,7 @@ module mkL1Bank#(
// and pRq is always directly handled: either dropped or Done
if(pipeOut.pRqMiss || ram.info.cs <= pRq.toState || ram.info.tag != getTag(pRq.addr)) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: pRq: drop", $time);
// pRq can be directly dropped
// must go through tag match, no successor
@@ -859,7 +859,7 @@ module mkL1Bank#(
// must be the case the pRq overtakes cRq
L1CRqState cState = pipeOutCState;
cRqSlotT cSlot = pipeOutCSlot;
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: pRq: overtake cRq: ", $time,
fshow(cOwner), " ; ",
fshow(cRq), " ; ",
@@ -891,7 +891,7 @@ module mkL1Bank#(
});
end
else begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: pRq: valid process", $time);
// line must NOT be owned
doAssert(ram.info.owner == Invalid,
@@ -937,13 +937,13 @@ module mkL1Bank#(
// flush always goes through cache pipeline, and is directly handled
// here: either dropped or Done
if(ram.info.cs == I) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: flush: drop", $time);
// flush can be directly dropped
pRqMshr.pipelineResp.releaseEntry(n);
end
else begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: flush: valid process", $time);
pRqMshr.pipelineResp.setDone_setData(n, ram.info.cs == M ? Valid (ram.line) : Invalid);
rsToPIndexQ.enq(PRq (n));

View File

@@ -220,7 +220,7 @@ module mkL1CRqMshrSafe#(
initIdx <= initIdx + 1;
if(initIdx == fromInteger(valueOf(cRqNum) - 1)) begin
inited <= True;
if (verbose)
if (verbose)
$display("%t L1CRqMshrSafe %m: init empty entry done", $time);
end
endrule

View File

@@ -30,7 +30,7 @@ import Types::*;
import CCTypes::*;
import DefaultValue::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import MshrDeadlockChecker::*;
// MSHR dependency chain invariant:
@@ -124,7 +124,7 @@ module mkL1PRqMshrSafe(
initIdx <= initIdx + 1;
if(initIdx == fromInteger(valueOf(pRqNum) - 1)) begin
inited <= True;
if (verbose)
if (verbose)
$display("%t L1PRqMshrSafe %m: init empty entry done", $time);
end
endrule

View File

@@ -230,7 +230,7 @@ module mkL1Pipe(
return actionvalue
function tagT getTag(Addr a) = truncateLSB(a);
if (verbose)
if (verbose)
$display("%t L1 %m tagMatch: ", $time,
fshow(cmd), " ; ",
fshow(getTag(getAddrFromCmd(cmd))),

View File

@@ -31,7 +31,7 @@ import CCPipe::*;
import LLPipe ::*;
import FShow::*;
import DefaultValue::*;
import Fifo::*;
import Fifos::*;
import CacheUtils::*;
import Performance::*;
import LatencyTimer::*;
@@ -555,7 +555,7 @@ module mkLLBank#(
});
toMQ.enq(msg);
toMInfoQ.deq; // deq info
if (verbose)
if (verbose)
$display("%t LL %m sendToM: load only: ", $time, fshow(msg));
doAssert(!isValid(data), "cannot have data");
doAssert(!doLdAfterReplace, "doLdAfterReplace should be false");
@@ -580,7 +580,7 @@ module mkLLBank#(
toMInfoQ.deq; // deq info
// dma write can be resp (i.e. mshr entry can be released)
rsStToDmaIndexQ_sendToM.enq(n);
if (verbose)
if (verbose)
$display("%t LL %m sendToM: dma write: ", $time, fshow(msg));
doAssert(isRqFromDma(cRq.id), "must be dma write");
doAssert(isValid(data), "dma write must have data");
@@ -604,7 +604,7 @@ module mkLLBank#(
// whole thing is done, reset bit and deq info
toMInfoQ.deq;
doLdAfterReplace <= False;
if (verbose)
if (verbose)
$display("%t LL %m sendToM: rep then ld: ld: ", $time, fshow(msg));
`ifdef PERF_COUNT
// performance counter: start miss timer
@@ -620,7 +620,7 @@ module mkLLBank#(
toMQ.enq(msg);
// don't deq info, do ld next time
doLdAfterReplace <= True;
if (verbose)
if (verbose)
$display("%t LL %m sendToM: rep then ld: rep: ", $time, fshow(msg));
end
doAssert(isRqFromC(cRq.id), "must be child req");
@@ -1168,7 +1168,7 @@ module mkLLBank#(
// add to same addr dependency
cRqMshr.pipelineResp.setAddrSucc(m, Valid (n));
cRqSetDepNoCacheChange;
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq: own by other cRq, same addr dep: ", $time,
fshow(cOwner), " ; ", fshow(cRqEOC)
);
@@ -1178,7 +1178,7 @@ module mkLLBank#(
// add to rep dependency
cRqMshr.pipelineResp.setRepSucc(cOwner.mshrIdx, Valid (n));
cRqSetDepNoCacheChange;
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq: own by other cRq, rep dep: ", $time,
fshow(cOwner)
);
@@ -1200,12 +1200,12 @@ module mkLLBank#(
// req from child, get dir pend
Vector#(childNum, DirPend) dirPend = getDirPendNonCompatForChild;
if(dirPend == replicate(Invalid)) begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq from child: own by itself, hit", $time);
cRqFromCHit(n, cRq, False);
end
else begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq from child: own by itself, miss no replace: ", $time,
fshow(dirPend)
);
@@ -1216,12 +1216,12 @@ module mkLLBank#(
// req from DMA, get dir pend
Vector#(childNum, DirPend) dirPend = getDirPendNonCompatForDma;
if(dirPend == replicate(Invalid)) begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq from dma: own by itself, hit", $time);
cRqFromDmaHit(n, cRq);
end
else begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq from dma: own by itself, miss by children: ", $time);
cRqFromDmaMissByChildren(dirPend);
end
@@ -1237,7 +1237,7 @@ module mkLLBank#(
// only check for cRqEOC to append to dependency chain when firt time go through tag match
if(cRqEOC matches tagged Valid .m &&& cState == Init) begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq: no owner, depend on cRq ", $time,
fshow(cState), " ; ",
fshow(cRqEOC)
@@ -1253,12 +1253,12 @@ module mkLLBank#(
// No Replacement necessary, check dir
Vector#(childNum, DirPend) dirPend = getDirPendNonCompatForChild;
if(ram.info.cs > I && dirPend == replicate(Invalid)) begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq: no owner, hit", $time);
cRqFromCHit(n, cRq, False);
end
else begin
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq: no owner, miss no replace: ", $time,
fshow(dirPend)
);
@@ -1268,7 +1268,7 @@ module mkLLBank#(
else begin
// need replacement, check dir
Vector#(childNum, DirPend) dirPend = getDirPendNonI;
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq: no owner, replace: ", $time,
fshow(dirPend)
);
@@ -1289,7 +1289,7 @@ module mkLLBank#(
end
else begin
// miss in LLC, so req mem and req is done!
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRq from dma: no owner, miss req mem", $time);
toMInfoQ.enq(ToMemInfo {
mshrIdx: n,
@@ -1355,7 +1355,7 @@ module mkLLBank#(
cRqT cRq = pipeOutCRq;
cRqSlotT cSlot = pipeOutCSlot;
LLCRqState cState = pipeOutCState;
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRs: match cRq: ", $time,
fshow(cOwner), " ; ",
fshow(cRq), " ; ",
@@ -1380,7 +1380,7 @@ module mkLLBank#(
// replacement done, evict line
Maybe#(cRqIndexT) repSucc = pipeOutRepSucc;
cRqFromCEvict(cOwner.mshrIdx, cRq, repSucc);
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRs: match cRq: replace done: ", $time,
fshow(repSucc)
);
@@ -1394,7 +1394,7 @@ module mkLLBank#(
waitP: cSlot.waitP,
dirPend: newDirPend
});
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRs: match cRq: replace not done: ", $time,
fshow(newDirPend)
);
@@ -1419,7 +1419,7 @@ module mkLLBank#(
end
end
endcase
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRs: match cRq: cRq in WaitSt: ", $time,
fshow(newDirPend)
);
@@ -1446,7 +1446,7 @@ module mkLLBank#(
end
else begin
// does not match any cRq, so just deq pipe & write ram
if (verbose)
if (verbose)
$display("%t LL %m pipelineResp: cRs: no owner: ", $time);
pipeline.deqWrite(Invalid, ram, False);
end

View File

@@ -30,7 +30,7 @@ import Types::*;
import CCTypes::*;
import DefaultValue::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import MshrDeadlockChecker::*;
// MSHR dependency chain invariant:
@@ -250,7 +250,7 @@ module mkLLCRqMshr#(
initIdx <= initIdx + 1;
if(initIdx == fromInteger(valueOf(cRqNum) - 1)) begin
inited <= True;
if (verbose)
if (verbose)
$display("%t LLCRqMshrSafe %m: init empty entry done", $time);
end
endrule

View File

@@ -202,7 +202,7 @@ module mkLLPipe(
return actionvalue
function tagT getTag(Addr a) = truncateLSB(a);
if (verbose)
if (verbose)
$display("%t LL %m tagMatch: ", $time,
fshow(cmd), " ; ",
fshow(getTag(getAddrFromCmd(cmd))), " ; ",

View File

@@ -22,7 +22,7 @@
// SOFTWARE.
import BRAMCore::*;
import Fifo::*;
import Fifos::*;
interface RWBramCore#(type addrT, type dataT);
method Action wrReq(addrT a, dataT d);

View File

@@ -22,7 +22,7 @@
// SOFTWARE.
import Vector::*;
import Fifo::*;
import Fifos::*;
import CCTypes::*;
import RWBramCore::*;

View File

@@ -39,7 +39,7 @@ import CCPipe::*;
import SelfInvIPipe ::*;
import FShow::*;
import DefaultValue::*;
import Fifo::*;
import Fifos::*;
import CacheUtils::*;
import Performance::*;
import LatencyTimer::*;
@@ -408,7 +408,7 @@ module mkSelfInvIBank#(
doAssert(isValid(cRqEOC), "cRq hit on another cRq, cRqEOC must be true");
cRqMshr.pipelineResp.setSucc(fromMaybe(?, cRqEOC), Valid (n));
cRqSetDepNoCacheChange;
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: own by other cRq ", $time,
fshow(cOwner), ", depend on cRq ", fshow(cRqEOC)
);
@@ -421,7 +421,7 @@ module mkSelfInvIBank#(
"cRq swapped in by previous cRq, tag must match & cs = S"
);
// Hit
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: own by itself, hit", $time);
cRqHit(n, procRq);
end
@@ -430,19 +430,19 @@ module mkSelfInvIBank#(
// cache has no owner, cRq must just go through tag match
// check for cRqEOC to append to dependency chain
if(cRqEOC matches tagged Valid .k) begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, depend on cRq ", $time, fshow(k));
cRqMshr.pipelineResp.setSucc(k, Valid (n));
cRqSetDepNoCacheChange;
end
else if(ram.info.cs > I && ram.info.tag == getTag(procRq.addr)) begin
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, hit", $time);
cRqHit(n, procRq);
end
else begin
// can always sliently replace
if (verbose)
if (verbose)
$display("%t I %m pipelineResp: cRq: no owner, miss no replace", $time);
cRqMissNoReplacement;
end
@@ -515,7 +515,7 @@ module mkSelfInvIBank#(
);
cRqIndexQ.deq;
cRqMshr.sendRsToC.releaseEntry(cRqIndexQ.first); // release MSHR entry
if (verbose)
if (verbose)
$display("%t I %m sendRsToC: ", $time,
fshow(cRqIndexQ.first), " ; ",
fshow(inst)

View File

@@ -26,7 +26,7 @@ import ConfigReg::*;
import Vector::*;
import FShow::*;
import Types::*;
import Fifo::*;
import Fifos::*;
import CCTypes::*;
import CCPipe::*;
import RWBramCore::*;

View File

@@ -41,7 +41,7 @@ import SelfInvL1Pipe ::*;
import FShow::*;
import DefaultValue::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import CacheUtils::*;
import CrossBar::*;
import Performance::*;
@@ -524,7 +524,7 @@ module mkSelfInvL1Bank#(
},
line: newLine // write new data into cache
}, True); // hit, so update rep info
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: Hit func: update ram: ", $time,
fshow(newLine), " ; ",
fshow(succ), " ; ",
@@ -545,7 +545,7 @@ module mkSelfInvL1Bank#(
req: req,
succ: succ
});
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: Hit func: AMO process in next cycle", $time);
end
endaction
@@ -630,7 +630,7 @@ module mkSelfInvL1Bank#(
end
// release MSHR entry
cRqMshr.pipelineResp.releaseEntry(n);
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: Sc early fail func: ", $time,
fshow(resetOwner), " ; ",
fshow(succ)
@@ -742,7 +742,7 @@ module mkSelfInvL1Bank#(
doAssert(isValid(cRqEOC), ("cRq hit on another cRq, cRqEOC must be true"));
cRqMshr.pipelineResp.setSucc(fromMaybe(?, cRqEOC), Valid (n));
cRqSetDepNoCacheChange;
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by other cRq ", $time,
fshow(cOwner), ", depend on cRq ", fshow(cRqEOC)
);
@@ -754,7 +754,7 @@ module mkSelfInvL1Bank#(
doAssert(tag_match, "cRq swapped in by previous cRq, tag must match");
// Hit or Miss (but no replacement)
if(enough_cs) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by itself, hit", $time);
cRqHit(n, procRq, False);
end
@@ -762,14 +762,14 @@ module mkSelfInvL1Bank#(
// Sc already fails, so we don't need to req parent. Since
// Sc is the owner of the line, we need to reset owner to
// Invalid.
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by itself, Sc early fails, ",
$time, fshow(linkAddr)
);
cRqScEarlyFail(True);
end
else begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: own by itself, miss no replace", $time);
cRqMissNoReplacement;
end
@@ -785,7 +785,7 @@ module mkSelfInvL1Bank#(
// check for cRqEOC to append to dependency chain
// Only append to dep-chain if is in Init state
if(cRqEOC matches tagged Valid .k &&& cState == Init) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, depend on cRq ", $time,
fshow(cState), " ; ", fshow(cRqEOC)
);
@@ -797,7 +797,7 @@ module mkSelfInvL1Bank#(
if(tag_match && enough_cs) begin
// Hit
doAssert(cs_valid, "hit, so cs must > I");
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, hit", $time);
cRqHit(n, procRq, False);
end
@@ -805,7 +805,7 @@ module mkSelfInvL1Bank#(
// Sc already fails, so we don't need to req parent. Since
// there is no owner of the line, we can reset owner to
// Invalid.
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, Sc early fails, ",
$time, fshow(linkAddr)
);
@@ -813,14 +813,14 @@ module mkSelfInvL1Bank#(
end
else if(cs_needs_evict && !tag_match) begin
// Req parent, need replacement
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: no owner, replace", $time);
cRqReplacement;
end
else begin
// Req parent, no Replacement necessary, we can silently replace S line
Bool silent_replace = ram.info.cs == S && !tag_match;
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: cRq: ",
"no owner, miss no replace, silent replace ",
$time, fshow(silent_replace));
@@ -867,7 +867,7 @@ module mkSelfInvL1Bank#(
doAssert(pRq.toState == S, "must downgrade to S");
if(pipeOut.pRqMiss || ram.info.cs <= pRq.toState || ram.info.tag != getTag(pRq.addr)) begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: pRq: drop", $time);
// pRq can be directly dropped
// must go through tag match, no successor
@@ -881,7 +881,7 @@ module mkSelfInvL1Bank#(
end
end
else begin
if (verbose)
if (verbose)
$display("%t L1 %m pipelineResp: pRq: valid process", $time);
// line must NOT be owned
doAssert(ram.info.owner == Invalid,

View File

@@ -25,7 +25,7 @@ import Assert::*;
import ConfigReg::*;
import Vector::*;
import FShow::*;
import Fifo::*;
import Fifos::*;
import Types::*;
import CCTypes::*;
import CCPipe::*;

View File

@@ -30,7 +30,7 @@ import LLCRqMshr::*;
import CCPipe::*;
import SelfInvLLPipe ::*;
import FShow::*;
import Fifo::*;
import Fifos::*;
import CacheUtils::*;
import Performance::*;
import LatencyTimer::*;

View File

@@ -201,7 +201,7 @@ module mkSelfInvLLPipe(
return actionvalue
function tagT getTag(Addr a) = truncateLSB(a);
if (verbose)
if (verbose)
$display("%t LL %m tagMatch: ", $time,
fshow(cmd), " ; ",
fshow(getTag(getAddrFromCmd(cmd))), " ; ",

View File

@@ -96,7 +96,7 @@ endmodule
module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
provisos (Bits#(t,sizet),
Add#(1,a__,sizet));
Add#(1,a__,sizet));
String fifo_size = "18Kb";
Vector#(TDiv#(sizet,36),X7FifoSyncMacro#(36)) fifos <- replicateM(vmkBramFifo(fifo_size, srcClock, srcReset, dstClock, dstReset));
Wire#(Bit#(1)) rdenWire <- mkDWire(0, clocked_by dstClock, reset_by dstReset);
@@ -107,19 +107,19 @@ module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Res
Reg#(Bit#(9)) rdcount <- mkReg(0, clocked_by dstClock, reset_by dstReset);
Reg#(Bit#(9)) wrcount <- mkReg(0, clocked_by srcClock, reset_by srcReset);
rule rdenRule;
fifos[i].rden(rdenWire);
fifos[i].rden(rdenWire);
endrule
rule wrenRule;
fifos[i].wren(wrenWire);
fifos[i].wren(wrenWire);
endrule
rule inputs;
fifos[i].din(dinWires[i]);
fifos[i].din(dinWires[i]);
endrule
rule countrds;
rdcount <= fifos[i].rdcount();
rdcount <= fifos[i].rdcount();
endrule
rule countwrs;
wrcount <= fifos[i].wrcount();
wrcount <= fifos[i].wrcount();
endrule
end
@@ -147,7 +147,7 @@ endmodule
module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
provisos (Bits#(t,sizet),
Add#(1,a__,sizet));
Add#(1,a__,sizet));
let syncFifo <- mkDualClockBramFIFOF(srcClock, srcReset, dstClock, dstReset);
method enq = syncFifo.enq;
@@ -158,7 +158,7 @@ endmodule
`else // compatibility mode
module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
provisos (Bits#(t,sizet),
Add#(1,a__,sizet));
Add#(1,a__,sizet));
let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
method enq = syncFifo.enq;
method deq = syncFifo.deq;
@@ -168,7 +168,7 @@ module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Res
endmodule
module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
provisos (Bits#(t,sizet),
Add#(1,a__,sizet));
Add#(1,a__,sizet));
let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
method enq = syncFifo.enq;

View File

@@ -27,6 +27,18 @@ interface ResetGuard;
method Bool isReady;
endinterface
`ifdef BSIM
module mkResetGuard(ResetGuard);
Reg#(Bool) ready <- mkReg(False);
(* no_implicit_conditions, fire_when_enabled *)
rule rl_ready;
ready <= True;
endrule
method isReady = ready;
endmodule
`else
import "BVI" reset_guard =
module mkResetGuard(ResetGuard);
default_clock clk(CLK);
@@ -36,3 +48,4 @@ module mkResetGuard(ResetGuard);
schedule (isReady) CF (isReady);
endmodule
`endif

View File

@@ -76,10 +76,15 @@ module mkIntDivUnsignedSim(IntDivUnsignedImport);
let {dividend, user} = dividendQ.first;
let divisor = divisorQ.first;
// Be careful to avoid divide-by-zero in bluesim's C++, which turns
// res = cond ? exp1 : exp2
// into
// tmp1 = exp1; tmp2 = exp2; res = cond ? tmp1 : tmp2
// so we must give a fake non-zero input even if it looks unused.
UInt#(64) a = unpack(dividend);
UInt#(64) b = unpack(divisor);
Bit#(64) q = pack(a / b);
Bit#(64) r = pack(a % b);
UInt#(64) b = divisor == 0 ? 1 : unpack(divisor);
Bit#(64) q = divisor == 0 ? maxBound : pack(a / b);
Bit#(64) r = divisor == 0 ? dividend : pack(a % b);
respQ.enq(tuple2({q, r}, user));
endrule

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +8,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -40,6 +40,11 @@ import ReorderBuffer::*;
import SpecFifo::*;
import HasSpecBits::*;
import Bypass::*;
import CHERICap::*;
import CHERICC_Fat::*;
import ISA_Decls_CHERI::*;
import Cur_Cycle :: *;
// ALU pipeline has 4 stages
// dispatch -> reg read -> exe -> finish (write reg)
@@ -78,6 +83,7 @@ typedef struct {
Maybe#(PhyDst) dst;
InstTag tag;
DirPredTrainInfo dpTrain;
Bool isCompressed;
// result
Data data; // alu compute result
Maybe#(Data) csrData; // data to write CSR file
@@ -126,6 +132,7 @@ typedef struct {
Bool taken;
DirPredTrainInfo dpTrain;
Bool mispred;
Bool isCompressed;
} FetchTrainBP deriving(Bits, Eq, FShow);
interface AluExeInput;
@@ -136,14 +143,19 @@ interface AluExeInput;
method Data rf_rd2(PhyRIndx rindx);
// CSR file
method Data csrf_rd(CSR csr);
// Special Capability Register file.
method CapReg scaprf_rd(SCR csr);
// ROB
method Addr rob_getPC(InstTag t);
method Addr rob_getPredPC(InstTag t);
method Bit #(32) rob_getOrig_Inst (InstTag t);
method Action rob_setExecuted(
InstTag t,
Data dst_data,
Maybe#(Data) csrData,
ControlFlow cf
ControlFlow cf,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
`endif
@@ -207,7 +219,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
if(x.regs.dst matches tagged Valid .dst) begin
inIfc.setRegReadyAggr(dst.indx);
end
// go to next stage
dispToRegQ.enq(ToSpecFifo {
data: AluDispatchToRegRead {
@@ -261,7 +273,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
rVal2: rVal2,
pc: pc,
ppc: ppc,
orig_inst: orig_inst,
orig_inst: orig_inst,
spec_tag: x.spec_tag
},
spec_bits: dispToReg.spec_bits
@@ -280,7 +292,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
if (verbosity > 0) begin
$display ("AluExePipeline.doExeAlu: regToExe = ", fshow (regToExe));
$display ("AluExePipeline.doExeAlu: exec_result = ", fshow (exec_result));
end
end
// when inst needs to store csrData in ROB, it must have iType = Csr, cannot mispredict
if(isValid(x.dInst.csr)) begin
@@ -301,6 +313,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
dst: x.dst,
tag: x.tag,
dpTrain: x.dpTrain,
isCompressed: x.orig_inst[1:0] != 2'b11,
data: exec_result.data,
csrData: isValid(x.dInst.csr) ? Valid (exec_result.csrData) : tagged Invalid,
`ifdef RVFI
@@ -331,8 +344,11 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
// update the instruction in the reorder buffer.
inIfc.rob_setExecuted(
x.tag,
x.data,
x.csrData,
x.controlFlow
x.controlFlow,
tagged Invalid,
cast(inIfc.scaprf_rd(SCR_PCC))
`ifdef RVFI
, x.traceBundle
`endif
@@ -352,7 +368,8 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
iType: x.iType,
taken: x.controlFlow.taken,
dpTrain: x.dpTrain,
mispred: True
mispred: True,
isCompressed: x.isCompressed
});
`ifdef PERF_COUNT
// performance counter
@@ -370,7 +387,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
if (x.spec_tag matches tagged Valid .valid_spec_tag) begin
inIfc.correctSpec(valid_spec_tag);
end
// train branch predictor if needed
// train branch predictor if needed
// since we can only do 1 training in a cycle, split the rule
// XXX not training JAL, reduce chance of conflicts
if(x.iType == Jr || x.iType == Br) begin
@@ -380,7 +397,8 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
iType: x.iType,
taken: x.controlFlow.taken,
dpTrain: x.dpTrain,
mispred: False
mispred: False,
isCompressed: x.isCompressed
});
end
end
@@ -408,4 +426,3 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
endcase);
endmethod
endmodule

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +9,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -27,6 +28,7 @@ import GetPut::*;
import Cntrs::*;
import ConfigReg::*;
import FIFO::*;
import FIFOF::*;
import Types::*;
import ProcTypes::*;
import CCTypes::*;
@@ -35,13 +37,22 @@ import ReorderBuffer::*;
import ReorderBufferSynth::*;
import RenamingTable::*;
import CsrFile::*;
import ScrFile::*;
import StoreBuffer::*;
import VerificationPacket::*;
import RenameDebugIF::*;
import CHERICap::*;
import CHERICC_Fat::*;
import ISA_Decls_CHERI::*;
`ifdef RVFI
import RVFI_DII_Types::*;
`endif
import Cur_Cycle :: *;
`ifdef INCLUDE_TANDEM_VERIF
import Trace_Data2 :: *;
`endif
typedef struct {
// info about the inst blocking at ROB head
@@ -60,7 +71,7 @@ typedef struct {
Bool stbEmpty;
Bool stqEmpty;
Bool tlbNoPendingReq;
// CSR info: previlige mode
// CSR info: privilege mode
Bit#(2) prv;
// inst count
Data instCount;
@@ -71,6 +82,7 @@ interface CommitInput;
interface ReorderBufferSynth robIfc;
interface RegRenamingTable rtIfc;
interface CsrFile csrfIfc;
interface ScrFile scaprfIfc;
// no stores
method Bool stbEmpty;
method Bool stqEmpty;
@@ -94,6 +106,9 @@ interface CommitInput;
`endif
);
method Action setFetchWaitRedirect;
`ifdef INCLUDE_GDB_CONTROL
method Action setFetchWaitFlush;
`endif
method Action incrementEpoch;
// record if we commit a CSR inst or interrupt
method Action commitCsrInstOrInterrupt;
@@ -101,6 +116,10 @@ interface CommitInput;
method Bool doStats;
// deadlock check
method Bool checkDeadlock;
`ifdef INCLUDE_TANDEM_VERIF
interface Vector #(SupSize, Put #(Trace_Data2)) v_to_TV;
`endif
endinterface
typedef struct {
@@ -113,7 +132,7 @@ typedef struct {
interface CommitStage;
// performance
method Data getPerf(ComStagePerfType t);
method Data getPerf(ComStagePerfType t);
// deadlock check
interface Get#(CommitStuck) commitInstStuck;
interface Get#(CommitStuck) commitUserInstStuck;
@@ -124,18 +143,23 @@ interface CommitStage;
// RVFI trace report. Not an input?
method Get#(Rvfi_Traces) rvfi;
`endif
`ifdef INCLUDE_GDB_CONTROL
method Bool is_debug_halted;
method Action debug_resume;
`endif
endinterface
// we apply actions the end of commit rule
// use struct to record actions to be done
typedef struct {
Addr pc;
CapPipe pc;
Addr addr;
Trap trap;
Bit #(32) orig_inst;
`ifdef RVFI_DII
ToReorderBuffer x;
`endif
} CommitTrap deriving(Bits, Eq, FShow);
} CommitTrap deriving(Bits, FShow);
`ifdef RVFI
function Bool is_16b_inst (Bit #(n) inst);
@@ -147,7 +171,7 @@ typedef struct {
Data mepc;
Data stvec;
Data mtvec;
} TraceStateBundle deriving(Bits, Eq, FShow);
} TraceStateBundle deriving(Bits, FShow);
function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot, Dii_Id traceCnt, TraceStateBundle tsb, Data next_pc);
Addr addr = 0;
@@ -165,7 +189,7 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot,
endcase
case (rot.ppc_vaddr_csrData) matches
tagged VAddr .vaddr: begin
addr = vaddr;
addr = getAddr(vaddr);
case (rot.lsqTag) matches
tagged Ld .l: rmask = rot.traceBundle.memByteEn;
tagged St .s: begin
@@ -174,7 +198,7 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot,
end
endcase
end
tagged PPC .ppc: next_pc = ppc;
tagged PPC .ppc: next_pc = getAddr(ppc);
tagged CSRData .csrdata: data = csrdata;
endcase
end
@@ -188,7 +212,7 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot,
rvfi_rs2_addr: rot.orig_inst[24:20],
rvfi_rs1_data: ?,
rvfi_rs2_data: ?,
rvfi_pc_rdata: rot.pc,
rvfi_pc_rdata: getAddr(rot.pc),
rvfi_pc_wdata: next_pc,
rvfi_mem_wdata: wdata,
rvfi_rd_addr: rd,
@@ -201,17 +225,123 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot,
endfunction
`endif
module mkCommitStage#(CommitInput inIfc)(CommitStage);
Bool verbose = True;
`ifdef INCLUDE_GDB_CONTROL
// Bluespec: for lightweight verbosity trace
Integer verbosity = 0;
Reg #(Bit #(64)) rg_instret <- mkReg (0);
typedef enum {
RUN_STATE_RUNNING, // Normal state
RUN_STATE_DEBUGGER_HALTED // When halted for debugger
} Run_State
deriving (Eq, FShow, Bits);
`endif
module mkCommitStage#(CommitInput inIfc)(CommitStage);
Bool verbose = False;
Integer verbosity = 0; // Bluespec: for lightweight verbosity trace
// Used to inform tandem-verifier about program order.
// 0 is used to indicate we've just come out of reset
// TODO: we could use fewer bits and allow and recognize wraparound.
Reg #(Bit #(64)) rg_serial_num <- mkReg (0);
`ifdef INCLUDE_TANDEM_VERIF
FIFOF #(ToReorderBuffer) f_rob_data <- mkFIFOF;
`endif
`ifdef INCLUDE_GDB_CONTROL
Reg #(Run_State) rg_run_state <- mkReg (RUN_STATE_RUNNING);
`endif
`ifdef INCLUDE_TANDEM_VERIF
Integer way0 = 0;
ToReorderBuffer no_deq_data = ?;
Bit #(5) no_fflags = ?;
Data no_mstatus = ?;
Maybe #(Trap_Updates) no_trap_updates = tagged Invalid;
Maybe #(RET_Updates) no_ret_updates = tagged Invalid;
function Action fa_to_TV (Integer way,
Bit #(64) serial_num,
Maybe #(Tuple2 #(Bit #(12), Data)) maybe_csr_upd,
ToReorderBuffer deq_data,
Bit #(5) fflags,
Data mstatus,
Maybe #(Trap_Updates) m_trap_updates,
Maybe #(RET_Updates) m_ret_updates);
action
let tval = (m_trap_updates matches tagged Valid .tu ? tu.tval : deq_data.tval);
let upd_pc = (m_ret_updates matches tagged Valid .ru ? ru.new_pc : deq_data.pc);
let x = Trace_Data2 {serial_num: serial_num,
maybe_csr_upd: maybe_csr_upd,
pc: upd_pc,
orig_inst: deq_data.orig_inst,
iType: deq_data.iType,
dst: deq_data.dst,
dst_data: deq_data.dst_data,
store_data: deq_data.store_data,
store_data_BE: deq_data.store_data_BE,
csr: deq_data.csr,
trap: deq_data.trap,
tval: tval,
ppc_vaddr_csrData: deq_data.ppc_vaddr_csrData,
fflags: fflags, // deq_data.fflags only has incremental flags
will_dirty_fpu_state: deq_data.will_dirty_fpu_state,
mstatus: mstatus, // when SD/XS/FS have changed
// Trap and RET updates
prv: ( m_trap_updates matches tagged Valid .tu
? tu.prv
: (m_ret_updates matches tagged Valid .ru
? ru.prv
: ?)),
status: ( m_trap_updates matches tagged Valid .tu
? tu.status
: (m_ret_updates matches tagged Valid .ru
? ru.status
: ?)),
tvec: fromMaybe (?, m_trap_updates).new_pc,
cause: fromMaybe (?, m_trap_updates).cause,
epc: fromMaybe (?, m_trap_updates).epc
};
inIfc.v_to_TV [way].put (x);
endaction
endfunction
Reg #(Bool) rg_just_after_reset <- mkReg (True);
rule rl_send_tv_reset (rg_just_after_reset);
Bit #(64) serial_num = 0;
fa_to_TV (way0, serial_num,
tagged Invalid,
no_deq_data, no_fflags, no_mstatus, no_trap_updates, no_ret_updates);
rg_just_after_reset <= False;
rg_serial_num <= 1;
endrule
Reg #(Data) rg_old_mip_csr_val <- mkReg (0);
Data new_mip_csr_val = inIfc.csrfIfc.getMIP;
Bool send_mip_csr_change_to_tv = (new_mip_csr_val != rg_old_mip_csr_val);
rule rl_send_mip_csr_change_to_tv ((! rg_just_after_reset) && send_mip_csr_change_to_tv);
fa_to_TV (way0, rg_serial_num,
tagged Valid (tuple2 (pack (CSRmip), new_mip_csr_val)),
no_deq_data, no_fflags, no_mstatus, no_trap_updates, no_ret_updates);
rg_old_mip_csr_val <= new_mip_csr_val;
rg_serial_num <= rg_serial_num + 1;
endrule
`else
Bool send_mip_csr_change_to_tv = False;
`endif
// func units
ReorderBufferSynth rob = inIfc.robIfc;
RegRenamingTable regRenamingTable = inIfc.rtIfc;
CsrFile csrf = inIfc.csrfIfc;
ScrFile scaprf = inIfc.scaprfIfc;
// FIXME FIXME FIXME wires to set atCommit in LSQ: avoid scheduling cycle.
// Using wire should be fine, because LSQ does not need to see atCommit
@@ -263,7 +393,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// RVFI trace report. Not an input?
FIFO#(Rvfi_Traces) rvfiQ <- mkFIFO;
Reg#(Dii_Id) traceCnt <- mkReg(0);
function TraceStateBundle getTSB();
return TraceStateBundle{
sepc: csrf.rd(CSRsepc),
@@ -432,12 +562,56 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
endaction
endfunction
`ifdef INCLUDE_GDB_CONTROL
// Maintain system consistency when halting into debug mode
// This code is patterned after 'makeSystemConsistent' above
function Action makeSystemConsistent_for_debug_mode;
action
inIfc.setFlushTlbs;
// notify TLB to keep update of CSR changes
inIfc.setUpdateVMInfo;
// always wait store buffer and SQ to be empty
when(inIfc.stbEmpty && inIfc.stqEmpty, noAction);
// We wait TLB to finish all requests and become sync with memory.
// Notice that currently TLB is read only, so TLB is always in sync
// with memory (i.e., there is no write to commit to memory). Since all
// insts have been killed, nothing can be issued to D TLB at this time.
// Since fetch stage is set to wait for redirect, fetch1 stage is
// stalled, and nothing can be issued to I TLB at this time.
// Therefore, we just need to make sure that I and D TLBs are not
// handling any miss req. Besides, when I and D TLBs do not have any
// miss req, L2 TLB must be idling.
when(inIfc.tlbNoPendingReq, noAction);
// yield load reservation in cache
inIfc.setFlushReservation;
inIfc.setFlushBrPred;
inIfc.setFlushCaches;
`ifdef SELF_INV_CACHE
// reconcile I$
if(reconcileI) begin
inIfc.setReconcileI;
end
`ifdef SYSTEM_SELF_INV_L1D
// FIXME is this reconcile of D$ necessary?
inIfc.setReconcileD;
`endif
`endif
endaction
endfunction
`endif
// TODO Currently we don't check spec bits == 0 when we commit an
// instruction. This is because killings of wrong path instructions are
// done in a single cycle. However, when we make killings distributed or
// pipelined, then we need to check spec bits at commit port.
rule doCommitTrap_flush(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
!isValid(commitTrap) &&&
rob.deqPort[0].deq_data.trap matches tagged Valid .trap
);
@@ -448,30 +622,34 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// record trap info
Addr vaddr = ?;
if ( (trap == tagged Exception InstAccessFault)
|| (trap == tagged Exception InstPageFault)) begin
vaddr = x.tval;
end
|| (trap == tagged Exception InstPageFault)) begin
vaddr = x.tval;
end
else if(x.ppc_vaddr_csrData matches tagged VAddr .va) begin
vaddr = va;
vaddr = getAddr(va);
end
let commitTrap_val = Valid (CommitTrap {
trap: trap,
pc: x.pc,
addr: vaddr
addr: vaddr,
orig_inst: x.orig_inst
`ifdef RVFI_DII
, x: x
`endif
});
});
commitTrap <= commitTrap_val;
`ifdef INCLUDE_TANDEM_VERIF
f_rob_data.enq (x); // Save data to be sent to TV in rule doCommitTrap_handle, next
`endif
if (verbosity > 0) begin
$display ("instret:%0d PC:0x%0h instr:0x%08h", rg_instret, x.pc, x.orig_inst,
" iType:", fshow (x.iType), " [doCommitTrap]");
end
if (verbosity >= 1) begin
$display ("instret:%0d PC:0x%0h instr:0x%08h", rg_serial_num, x.pc, x.orig_inst,
" iType:", fshow (x.iType), " [doCommitTrap]");
end
if (verbose) begin
$display ("CommitStage.doCommitTrap_flush: deq_data: ", fshow (x));
$display ("CommitStage.doCommitTrap_flush: commitTrap: ", fshow (commitTrap_val));
end
$display ("CommitStage.doCommitTrap_flush: deq_data: ", fshow (x));
$display ("CommitStage.doCommitTrap_flush: commitTrap: ", fshow (commitTrap_val));
end
// flush everything. Only increment epoch and stall fetch when we haven
// not done it yet (we may have already done them at rename stage)
@@ -501,41 +679,104 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
doAssert(x.spec_bits == 0, "cannot have spec bits");
endrule
rule doCommitTrap_handle(commitTrap matches tagged Valid .trap);
rule doCommitTrap_handle(
commitTrap matches tagged Valid .trap
`ifdef INCLUDE_GDB_CONTROL
&&& (rg_run_state == RUN_STATE_RUNNING)
`endif
&&& (! send_mip_csr_change_to_tv));
// reset commitTrap
commitTrap <= Invalid;
`ifdef INCLUDE_TANDEM_VERIF
let x = f_rob_data.first;
f_rob_data.deq;
`endif
// notify commit of interrupt (so MMIO pRq may be handled)
if(trap.trap matches tagged Interrupt .inter) begin
inIfc.commitCsrInstOrInterrupt;
end
if (verbose) $display ("CommitStage.doCommitTrap_handle: ", fshow (commitTrap));
// trap handling & redirect
let new_pc <- csrf.trap(trap.trap, trap.pc, trap.addr);
inIfc.redirectPc(new_pc
`ifdef INCLUDE_GDB_CONTROL
else if (trap.trap == tagged Exception Breakpoint) begin
inIfc.commitCsrInstOrInterrupt; // TODO: Why?
end
`endif
Bool debugger_halt = False;
`ifdef INCLUDE_GDB_CONTROL
if ((trap.trap == tagged Interrupt DebugHalt)
|| (trap.trap == tagged Interrupt DebugStep)
|| ((trap.trap == tagged Exception Breakpoint) && (csrf.dcsr_break_bit == 1'b1)))
begin
debugger_halt = True;
// Flush everything (tlbs, caches, reservation, branch predictor);
// reconcilei and I; update VM info.
makeSystemConsistent_for_debug_mode;
// Save values in debugger CSRs
Bit #(3) dcsr_cause = ( (trap.trap == tagged Interrupt DebugHalt)
? 3
: ( (trap.trap == tagged Interrupt DebugStep)
? 4
: 1));
csrf.dcsr_cause_write (dcsr_cause);
csrf.dpc_write (trap.pc);
// Tell fetch stage to wait for redirect
// Note: rule doCommitTrap_flush may have done this already; redundant call is ok.
inIfc.setFetchWaitRedirect;
inIfc.setFetchWaitFlush;
// Go to quiescent state until debugger resumes execution
rg_run_state <= RUN_STATE_DEBUGGER_HALTED;
if (verbosity >= 2)
$display ("%0d: %m.commitStage.doCommitTrap_handle; debugger halt:", cur_cycle);
end
`endif
if (! debugger_halt) begin
// trap handling & redirect
let trap_updates <- csrf.trap(trap.trap, getAddr(trap.pc), trap.addr, trap.orig_inst);
let cap_trap_updates <- scaprf.trap(trap.trap, getAddr(trap.pc), trap.addr, trap.orig_inst);
inIfc.redirectPc(trap_updates.new_pc
`ifdef RVFI_DII
, trap.x.diid + 1
, trap.x.diid + 1
`endif
);
);
`ifdef RVFI
Rvfi_Traces rvfis = replicate(tagged Invalid);
rvfis[0] = genRVFI(trap.x, traceCnt, getTSB(), new_pc);
rvfiQ.enq(rvfis);
traceCnt <= traceCnt + 1;
Rvfi_Traces rvfis = replicate(tagged Invalid);
rvfis[0] = genRVFI(trap.x, traceCnt, getTSB(), trap_updates.new_pc);
rvfiQ.enq(rvfis);
traceCnt <= traceCnt + 1;
`endif
// system consistency
// TODO spike flushes TLB here, but perhaps it is because spike's TLB
// does not include prv info, and it has to flush when prv changes.
// XXX As approximation, Trap may cause context switch, so flush for
// security
makeSystemConsistent(False, True, False);
`ifdef INCLUDE_TANDEM_VERIF
fa_to_TV (way0, rg_serial_num,
tagged Invalid,
x, no_fflags, no_mstatus, tagged Valid trap_updates, no_ret_updates);
`endif
rg_serial_num <= rg_serial_num + 1;
// system consistency
// TODO spike flushes TLB here, but perhaps it is because spike's TLB
// does not include prv info, and it has to flush when prv changes.
// XXX As approximation, Trap may cause context switch, so flush for
// security
makeSystemConsistent(False, True, False);
end
endrule
// commit misspeculated load
rule doCommitKilledLd(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
!isValid(commitTrap) &&&
!isValid(rob.deqPort[0].deq_data.trap) &&&
rob.deqPort[0].deq_data.ldKilled matches tagged Valid .killBy
@@ -546,7 +787,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// kill everything, redirect, and increment epoch
inIfc.killAll;
inIfc.redirectPc(x.pc
inIfc.redirectPc(getAddr(x.pc)
`ifdef RVFI_DII
, x.diid
`endif
@@ -574,25 +815,33 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// commit system inst
rule doCommitSystemInst(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
!isValid(rob.deqPort[0].deq_data.ldKilled) &&
rob.deqPort[0].deq_data.rob_inst_state == Executed &&
isSystem(rob.deqPort[0].deq_data.iType)
isSystem(rob.deqPort[0].deq_data.iType) &&
(! send_mip_csr_change_to_tv)
);
rob.deqPort[0].deq;
let x = rob.deqPort[0].deq_data;
if(verbose) $display("[doCommitSystemInst] ", fshow(x));
if (verbosity > 0) begin
$display("instret:%0d PC:0x%0h instr:0x%08h", rg_instret, x.pc, x.orig_inst,
" iType:", fshow (x.iType), " [doCommitSystemInst]");
rg_instret <= rg_instret + 1;
end
if (verbosity >= 1) begin
$display("instret:%0d PC:0x%0h instr:0x%08h", rg_serial_num, x.pc, x.orig_inst,
" iType:", fshow (x.iType), " [doCommitSystemInst]");
end
// we claim a phy reg for every inst, so commit its renaming
regRenamingTable.commit[0].commit;
Bool write_satp = False; // flush tlb when satp csr is modified
`ifdef INCLUDE_TANDEM_VERIF
Data new_mstatus = no_mstatus;
`endif
Bool write_satp = False; // flush tlb when satp csr is modified
Bool flush_security = False; // flush for security when the flush csr is written
if(x.iType == Csr) begin
// notify commit of CSR (so MMIO pRq may be handled)
@@ -607,6 +856,17 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
doAssert(False, "must have csr data");
end
csrf.csrInstWr(csr_idx, csr_data);
`ifdef INCLUDE_TANDEM_VERIF
Data data_warl_xformed = csrf.warl_xform (csr_idx, csr_data);
x.ppc_vaddr_csrData = tagged CSRData data_warl_xformed;
if (x.will_dirty_fpu_state) begin
Data old_mstatus = csrf.rd (CSRmstatus);
new_mstatus = { 1'b1, old_mstatus [62:15], 2'b11, old_mstatus [12:0] };
end
`endif
// check if satp is modified or not
write_satp = csr_idx == CSRsatp;
`ifdef SECURITY
@@ -615,13 +875,25 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
end
// redirect (Sret and Mret redirect pc is got from CSRF)
Addr next_pc = x.ppc_vaddr_csrData matches tagged PPC .ppc ? ppc : (x.pc + 4);
doAssert(next_pc == x.pc + 4, "ppc must be pc + 4");
Addr next_pc = x.ppc_vaddr_csrData matches tagged PPC .ppc ? getAddr(ppc) : (getAddr(x.pc) + 4);
doAssert(next_pc == getAddr(x.pc) + 4, "ppc must be pc + 4");
`ifdef INCLUDE_TANDEM_VERIF
Maybe #(RET_Updates) m_ret_updates = no_ret_updates;
`endif
if(x.iType == Sret) begin
next_pc <- csrf.sret;
RET_Updates ret_updates <- csrf.sret;
next_pc = ret_updates.new_pc;
Scr_RET_Updates scr_ret_updates <- scaprf.sret;
`ifdef INCLUDE_TANDEM_VERIF
m_ret_updates = tagged Valid ret_updates;
`endif
end
else if(x.iType == Mret) begin
next_pc <- csrf.mret;
RET_Updates ret_updates <- csrf.mret;
next_pc = ret_updates.new_pc;
`ifdef INCLUDE_TANDEM_VERIF
m_ret_updates = tagged Valid ret_updates;
`endif
end
inIfc.redirectPc(next_pc
`ifdef RVFI_DII
@@ -636,6 +908,13 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
traceCnt <= traceCnt + 1;
`endif
`ifdef INCLUDE_TANDEM_VERIF
fa_to_TV (way0, rg_serial_num,
tagged Invalid,
x, no_fflags, new_mstatus, no_trap_updates, m_ret_updates);
`endif
rg_serial_num <= rg_serial_num + 1;
// rename stage only sends out system inst when ROB is empty, so no
// need to flush ROB again
@@ -672,7 +951,9 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// checks
doAssert(x.epochIncremented, "must have already incremented epoch");
doAssert((x.iType == Csr) == isValid(x.csr), "only CSR has valid csr idx");
doAssert(x.fflags == 0 && !x.will_dirty_fpu_state, "cannot dirty FPU");
// RSN 2020-03-08: Removed this assertion. Csr instrs that write to
// fflags/frm/fcsr do indeed 'dirty' the fpu state
// doAssert(x.fflags == 0 && !x.will_dirty_fpu_state, "cannot dirty FPU");
doAssert(x.spec_bits == 0, "cannot have spec bits");
doAssert(x.claimed_phy_reg, "must have claimed phy reg");
`ifdef RENAME_DEBUG
@@ -709,11 +990,15 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// commit normal: fire when at least one commit can be done
rule doCommitNormalInst(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
!isValid(rob.deqPort[0].deq_data.ldKilled) &&
rob.deqPort[0].deq_data.rob_inst_state == Executed &&
!isSystem(rob.deqPort[0].deq_data.iType)
!isSystem(rob.deqPort[0].deq_data.iType) &&
(! send_mip_csr_change_to_tv)
);
// stop superscalar commit after we
// 1. see a trap or system inst or killed Ld
@@ -747,6 +1032,12 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
Bit #(64) instret = 0;
`ifdef INCLUDE_TANDEM_VERIF
// These variables accumulate fflags and mstatus in sequential Program Order ('po')
// (whereas the 'fflags' variable does just one update after superscalar retirement).
Bit #(5) po_fflags = ?;
Data po_mstatus = ?;
`endif
// compute what actions to take
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
if(!stop && rob.deqPort[i].canDeq) begin
@@ -761,15 +1052,32 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
else begin
if (verbose) $display("[doCommitNormalInst - %d] ", i, fshow(inst_tag), " ; ", fshow(x));
`ifdef RVFI
rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace), getTSB(), x.pc + (is_16b_inst(x.orig_inst) ? 2:4));
rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace), getTSB(), getAddr(x.pc) + (is_16b_inst(x.orig_inst) ? 2:4));
whichTrace = whichTrace + 1;
`endif
if (verbosity > 0) begin
$display("instret:%0d PC:0x%0h instr:0x%08h", rg_instret + instret, x.pc, x.orig_inst,
" iType:", fshow (x.iType), " [doCommitNormalInst [%0d]]", i);
instret = instret + 1;
end
if (verbosity >= 1) begin
$display("instret:%0d PC:0x%0h instr:0x%08h", rg_serial_num + instret, x.pc, x.orig_inst,
" iType:", fshow (x.iType), " [doCommitNormalInst [%0d]]", i);
end
`ifdef INCLUDE_TANDEM_VERIF
Bool init_for_way0 = (i == 0);
match {. new_fflags, .new_mstatus} = csrf.fpuInst_csr_updates (x.fflags,
init_for_way0,
po_fflags,
po_mstatus);
po_fflags = new_fflags;
po_mstatus = new_mstatus;
fa_to_TV (i, rg_serial_num + instret,
tagged Invalid,
x,
po_fflags,
po_mstatus,
no_trap_updates, no_ret_updates);
`endif
instret = instret + 1;
// inst can be committed, deq it
rob.deqPort[i].deq;
@@ -778,6 +1086,9 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
regRenamingTable.commit[i].commit;
doAssert(x.claimed_phy_reg, "should have renamed");
if (x.ppc_vaddr_csrData matches tagged PPC .ppc)
scaprf.pccWr[i].put(cast(ppc));
`ifdef RENAME_DEBUG
// send debug msg for rename error
if(!x.claimed_phy_reg && !isValid(renameError)) begin
@@ -822,7 +1133,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
end
end
end
rg_instret <= rg_instret + instret;
rg_serial_num <= rg_serial_num + instret;
// write FPU csr
if(csrf.fpuInstNeedWr(fflags, will_dirty_fpu_state)) begin
@@ -873,6 +1184,8 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
`endif
endrule
// ================================================================
// INTERFACE
method Data getPerf(ComStagePerfType t);
return (case(t)
@@ -926,4 +1239,17 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
endmethod
interface renameErr = nullGet;
`endif
`ifdef INCLUDE_GDB_CONTROL
method Bool is_debug_halted;
return (rg_run_state == RUN_STATE_DEBUGGER_HALTED);
endmethod
method Action debug_resume () if (rg_run_state == RUN_STATE_DEBUGGER_HALTED);
rg_run_state <= RUN_STATE_RUNNING;
if (verbosity >= 2)
$display ("%0d: %m.commitStage.debug_resume", cur_cycle);
endmethod
`endif
endmodule

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +8,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -39,6 +39,9 @@ import SpecFifo::*;
import MulDiv::*;
import Fpu::*;
import Bypass::*;
import CHERICap::*;
import CHERICC_Fat::*;
import ISA_Decls_CHERI::*;
typedef struct {
// inst info
@@ -90,8 +93,10 @@ interface FpuMulDivExeInput;
method Data rf_rd3(PhyRIndx rindx);
// CSR file
method Data csrf_rd(CSR csr);
// Special Capability Register file.
method CapReg scaprf_rd(SCR csr);
// ROB
method Action rob_setExecuted(InstTag t, Bit#(5) fflags);
method Action rob_setExecuted(InstTag t, Data dst_data, Bit#(5) fflags, Maybe#(Exception) cast, CapPipe pcc);
// global broadcast methods
// write reg file & set both conservative and aggressive sb & wake up inst
@@ -120,7 +125,7 @@ module mkFpuMulDivExePipeline#(FpuMulDivExeInput inIfc)(FpuMulDivExePipeline);
// pipeline fifos
let dispToRegQ <- mkFpuMulDivDispToRegFifo;
let regToExeQ <- mkFpuMulDivRegToExeFifo;
// wire to recv bypass
Vector#(TMul#(2, AluExeNum), RWire#(Tuple2#(PhyRIndx, Data))) bypassWire <- replicateM(mkRWire);
@@ -144,7 +149,7 @@ module mkFpuMulDivExePipeline#(FpuMulDivExeInput inIfc)(FpuMulDivExePipeline);
// FPU MUL DIV never have exception or misprecition, so no spec tag
doAssert(!isValid(x.spec_tag), "FpuMulDiv should not carry any spec tag");
// go to next stage
dispToRegQ.enq(ToSpecFifo {
data: FpuMulDivDispatchToRegRead {
@@ -228,7 +233,7 @@ module mkFpuMulDivExePipeline#(FpuMulDivExeInput inIfc)(FpuMulDivExePipeline);
inIfc.writeRegFile(valid_dst.indx, data);
end
// update the instruction in the reorder buffer.
inIfc.rob_setExecuted(tag, fflags);
inIfc.rob_setExecuted(tag, data, fflags, tagged Invalid, cast(inIfc.scaprf_rd(SCR_PCC)));
// since FPU op has no spec tag, this doFinish rule is ordered before
// other rules that calls incorrectSpec, and BSV compiler creates
// cycles in scheduling. We manually creates a conflict between this

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +8,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -27,7 +27,7 @@ import BuildVector::*;
import GetPut::*;
import ClientServer::*;
import Cntrs::*;
import Fifo::*;
import Fifos::*;
import Ehr::*;
import Types::*;
import ProcTypes::*;
@@ -50,6 +50,11 @@ import CCTypes::*;
import L1CoCache::*;
import Bypass::*;
import LatencyTimer::*;
import CHERICap::*;
import CHERICC_Fat::*;
import ISA_Decls_CHERI::*;
import Cur_Cycle :: *;
typedef struct {
// inst info
@@ -78,9 +83,14 @@ typedef struct {
LdStQTag ldstq_tag;
// result
ByteEn shiftedBE;
Addr vaddr; // virtual addr
CapPipe vaddr; // virtual addr
`ifdef INCLUDE_TANDEM_VERIF
// for those mem instrs that store data
Data store_data;
ByteEn store_data_BE;
`endif
Bool misaligned;
} MemExeToFinish deriving(Bits, Eq, FShow);
} MemExeToFinish deriving(Bits, FShow);
// bookkeeping when waiting for MMIO resp which may cause exception
typedef struct {
@@ -124,7 +134,7 @@ typedef DTlb#(MemExeToFinish) DTlbSynth;
module mkDTlbSynth(DTlbSynth);
function TlbReq getTlbReq(MemExeToFinish x);
return TlbReq {
addr: x.vaddr,
addr: getAddr(x.vaddr),
write: (case(x.mem_func)
St, Sc, Amo: True;
default: False;
@@ -143,18 +153,27 @@ interface MemExeInput;
method Data rf_rd2(PhyRIndx rindx);
// CSR file
method Data csrf_rd(CSR csr);
// Special Capability Register file.
method CapReg scaprf_rd(SCR csr);
// ROB
method Addr rob_getPC(InstTag t);
method Action rob_setExecuted_doFinishMem(InstTag t, Addr vaddr, Bool access_at_commit, Bool non_mmio_st_done
method Action rob_setExecuted_doFinishMem(InstTag t,
CapPipe vaddr,
Data store_data, ByteEn store_data_BE,
Bool access_at_commit, Bool non_mmio_st_done,
Maybe#(Exception) cause, CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
, ExtraTraceBundle tb
`endif
);
`ifdef INCLUDE_TANDEM_VERIF
method Action rob_setExecuted_doFinishMem_RegData (InstTag t, Data dst_data);
`endif
);
method Action rob_setExecuted_deqLSQ(InstTag t, Maybe#(Exception) cause, Maybe#(LdKilledBy) ld_killed
`ifdef RVFI
, ExtraTraceBundle tb
, ExtraTraceBundle tb
`endif
);
);
// MMIO
method Bool isMMIOAddr(Addr a);
method Action mmioReq(MMIOCRq r);
@@ -162,7 +181,7 @@ interface MemExeInput;
method Action mmioRespDeq;
// global broadcast methods
// set aggressive sb & wake up RS
// set aggressive sb & wake up RS
method Action setRegReadyAggr_mem(PhyRIndx dst);
method Action setRegReadyAggr_forward(PhyRIndx dst);
// write reg file & set conservative sb
@@ -369,7 +388,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
// executed after address transation
doAssert(!(x.data.mem_func == St && isValid(x.regs.dst)),
"St cannot have dst reg");
// go to next stage
dispToRegQ.enq(ToSpecFifo {
data: MemDispatchToRegRead {
@@ -436,9 +455,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
if(verbose) $display("[doExeMem] ", fshow(regToExe));
// get virtual addr & St/Sc/Amo data
Addr vaddr = x.rVal1 + signExtend(x.imm);
CapPipe vaddr = modifyOffset(setAddrUnsafe(almightyCap, x.rVal1), signExtend(x.imm), True).value;
Data data = x.rVal2;
`ifdef RVFI_DII
memData[pack(x.ldstq_tag)] <= data;
$display("%t : memData[%x] <= %x", $time(), pack(x.ldstq_tag), data);
@@ -451,7 +470,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
Bit#(TLog#(NumBytes)) byteOffset = truncate(addr);
return tuple2(unpack(pack(be) << byteOffset), d << {byteOffset, 3'b0});
endfunction
let {shiftBE, shiftData} = getShiftedBEData(vaddr, origBE, data);
let {shiftBE, shiftData} = getShiftedBEData(getAddr(vaddr), origBE, data);
// update LSQ data now
if(x.ldstq_tag matches tagged St .stTag) begin
@@ -467,7 +486,11 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
ldstq_tag: x.ldstq_tag,
shiftedBE: shiftBE,
vaddr: vaddr,
misaligned: memAddrMisaligned(vaddr, origBE)
`ifdef INCLUDE_TANDEM_VERIF
store_data: data,
store_data_BE: origBE,
`endif
misaligned: memAddrMisaligned(getAddr(vaddr), origBE)
},
specBits: regToExe.spec_bits
});
@@ -496,6 +519,13 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
if(verbose) $display("[doFinishMem] ", fshow(dTlbResp));
if(isValid(cause) && verbose) $display(" [doFinishMem - dTlb response] PAGEFAULT!");
Data store_data = ?;
ByteEn store_data_BE = ?;
`ifdef INCLUDE_TANDEM_VERIF
store_data = x.store_data;
store_data_BE = x.store_data_BE;
`endif
// check misalignment
if(!isValid(cause) && x.misaligned) begin
case(x.mem_func)
@@ -530,28 +560,28 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
endcase);
Bool access_at_commit = !isValid(cause) && (isMMIO || isLrScAmo);
Bool non_mmio_st_done = !isValid(cause) && !isMMIO && x.mem_func == St;
inIfc.rob_setExecuted_doFinishMem(
x.tag,
x.vaddr,
access_at_commit,
non_mmio_st_done
CapPipe pcc = cast(inIfc.scaprf_rd(SCR_PCC));
CapPipe ddc = cast(inIfc.scaprf_rd(SCR_DDC));
Bool ddc_out_of_bounds = !isInBounds(modifyOffset(ddc,getAddr(x.vaddr),True).value,True);
Bool out_of_bounds = (getFlags(pcc) == 1'b1) ? isInBounds(x.vaddr, False):ddc_out_of_bounds;
inIfc.rob_setExecuted_doFinishMem(x.tag, x.vaddr, store_data, store_data_BE,
access_at_commit, non_mmio_st_done,
(out_of_bounds) ? Valid(CHERIFault):Invalid,
pcc
`ifdef RVFI
, ExtraTraceBundle{
regWriteData: memData[pack(x.ldstq_tag)],
memByteEn: unpack(pack(x.shiftedBE) >> x.vaddr[2:0])
}
`endif
);
`ifdef RVFI
$display("%t : memData[%x]: %x", $time(), pack(x.ldstq_tag), memData[pack(x.ldstq_tag)]);
, ExtraTraceBundle{
regWriteData: memData[pack(x.ldstq_tag)],
memByteEn: unpack(pack(x.shiftedBE) >> getAddr(x.vaddr)[2:0])
}
`endif
);
// update LSQ
LSQUpdateAddrResult updRes <- lsq.updateAddr(
x.ldstq_tag, cause, paddr, isMMIO, x.shiftedBE
);
// issue non-MMIO Ld which has no excpetion and is not waiting for
// issue non-MMIO Ld which has no exception and is not waiting for
// wrong path resp
if (x.mem_func == Ld && !isMMIO &&
!isValid(cause) && !updRes.waitWPResp) begin
@@ -674,6 +704,11 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
if(verbose) $display("%t : ", $time, rule_name, " ", fshow(tag), "; ", fshow(data), "; ", fshow(res));
if(res.dst matches tagged Valid .dst) begin
inIfc.writeRegFile(dst.indx, res.data);
`ifdef INCLUDE_TANDEM_VERIF
inIfc.rob_setExecuted_doFinishMem_RegData (res.instTag, res.data);
`endif
`ifdef PERF_COUNT
// perf: load to use latency
let lat <- ldToUseLatTimer.done(tag);
@@ -693,7 +728,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
end
endaction
endfunction
rule doRespLdMem;
memRespLdQ.deq;
let {t, d} = memRespLdQ.first;
@@ -828,11 +863,14 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
waitLrScAmoMMIOResp <= Invalid;
// get resp data (need shifting)
let d <- toGet(respLrScAmoQ).get;
Data resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
Data resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
// write reg file & set ROB as Executed & wakeup rs
if(lsqDeqLd.dst matches tagged Valid .dst) begin
inIfc.writeRegFile(dst.indx, resp);
inIfc.setRegReadyAggr_mem(dst.indx);
`ifdef INCLUDE_TANDEM_VERIF
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqLd.instTag, resp);
`endif
end
inIfc.rob_setExecuted_deqLSQ(
lsqDeqLd.instTag,
@@ -918,6 +956,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
if(lsqDeqLd.dst matches tagged Valid .dst) begin
inIfc.writeRegFile(dst.indx, resp);
inIfc.setRegReadyAggr_mem(dst.indx);
`ifdef INCLUDE_TANDEM_VERIF
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqLd.instTag, resp);
`endif
end
inIfc.rob_setExecuted_deqLSQ(lsqDeqLd.instTag, Invalid, Invalid
`ifdef RVFI
@@ -1166,6 +1207,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
if(lsqDeqSt.dst matches tagged Valid .dst) begin
inIfc.writeRegFile(dst.indx, resp);
inIfc.setRegReadyAggr_mem(dst.indx);
`ifdef INCLUDE_TANDEM_VERIF
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqSt.instTag, resp);
`endif
end
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, Invalid, Invalid
`ifdef RVFI
@@ -1269,6 +1313,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
if(lsqDeqSt.dst matches tagged Valid .dst) begin
inIfc.writeRegFile(dst.indx, resp);
inIfc.setRegReadyAggr_mem(dst.indx);
`ifdef INCLUDE_TANDEM_VERIF
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqSt.instTag, resp);
`endif
end
inIfc.rob_setExecuted_deqLSQ(lsqDeqSt.instTag, Invalid, Invalid
`ifdef RVFI

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +9,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -25,7 +26,7 @@
import Vector::*;
import GetPut::*;
import Cntrs::*;
import Fifo::*;
import Fifos::*;
import FIFO::*;
import Types::*;
import ProcTypes::*;
@@ -40,6 +41,7 @@ import ReorderBufferSynth::*;
import Scoreboard::*;
import ScoreboardSynth::*;
import CsrFile::*;
import ScrFile::*;
import SpecTagManager::*;
import EpochManager::*;
import ReservationStationEhr::*;
@@ -47,6 +49,11 @@ import ReservationStationAlu::*;
import ReservationStationMem::*;
import ReservationStationFpuMulDiv::*;
import SplitLSQ::*;
import CHERICap::*;
import CHERICC_Fat::*;
import ISA_Decls_CHERI::*;
import Cur_Cycle :: *;
typedef struct {
FetchDebugState fetch;
@@ -61,6 +68,7 @@ interface RenameInput;
interface ScoreboardCons sbConsIfc;
interface ScoreboardAggr sbAggrIfc;
interface CsrFile csrfIfc;
interface ScrFile scaprfIfc;
interface EpochManager emIfc;
interface SpecTagManager smIfc;
interface Vector#(AluExeNum, ReservationStationAlu) rsAluIfc;
@@ -75,6 +83,9 @@ interface RenameInput;
method Bool checkDeadlock;
// performance
method Bool doStats;
`ifdef INCLUDE_GDB_CONTROL
method Bool core_is_running;
`endif
endinterface
interface RenameStage;
@@ -83,10 +94,16 @@ interface RenameStage;
// deadlock check
interface Get#(RenameStuck) renameInstStuck;
interface Get#(RenameStuck) renameCorrectPathStuck;
`ifdef INCLUDE_GDB_CONTROL
method Action debug_halt_req;
method Action debug_resume;
`endif
endinterface
module mkRenameStage#(RenameInput inIfc)(RenameStage);
Bool verbose = False;
Integer verbosity = 0;
// func units
FetchStage fetchStage = inIfc.fetchIfc;
@@ -95,6 +112,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
ScoreboardCons sbCons = inIfc.sbConsIfc;
ScoreboardAggr sbAggr = inIfc.sbAggrIfc;
CsrFile csrf = inIfc.csrfIfc;
ScrFile scaprf = inIfc.scaprfIfc;
EpochManager epochManager = inIfc.emIfc;
SpecTagManager specTagManager = inIfc.smIfc;
Vector#(AluExeNum, ReservationStationAlu) reservationStationAlu = inIfc.rsAluIfc;
@@ -153,6 +171,24 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
endrule
`endif
`ifdef INCLUDE_GDB_CONTROL
// Is set to Valid DebugHalt on debugger halt request
// Is set to Valid DebugStep on dcsr[stepbit]==1 and one instruction has been processed.
// Note (step): 1st instruction is guaranteed architectural, cannot possibly be speculative.
// Note (step): 1st instruction may trap; we halt pointing at the trap vector
Reg #(Maybe #(Interrupt)) rg_m_halt_req <- mkReg (tagged Invalid);
function Action fa_step_check;
action
if (csrf.dcsr_step_bit == 1'b1) begin
rg_m_halt_req <= tagged Valid DebugStep;
if (verbosity >= 2)
$display ("%0d: %m.renameStage.fa_step_check: rg_m_halt_req <= tagged Valid DebugStep", cur_cycle);
end
endaction
endfunction
`endif
// kill wrong path inst
// XXX we have to make this a separate rule instead of merging it with rename correct path
// This is because the rename correct path rule is conflict with other rules that redirect
@@ -185,8 +221,8 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
function Bool fn_ArchReg_is_FpuReg (Maybe #(ArchRIndx) m_arch_r_indx);
Bool result = False;
if (m_arch_r_indx matches tagged Valid .arch_r_indx)
if (arch_r_indx matches tagged Fpu .fpu_r_index)
result = True;
if (arch_r_indx matches tagged Fpu .fpu_r_index)
result = True;
return result;
endfunction
@@ -199,40 +235,48 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// If Fpu regs are accessed, trap if mstatus_fs is "Off" (2'b00)
Bool fpr_access = ( fn_ArchReg_is_FpuReg (x.regs.src1)
|| fn_ArchReg_is_FpuReg (x.regs.src2)
|| isValid (x.regs.src3)
|| fn_ArchReg_is_FpuReg (x.regs.dst));
|| fn_ArchReg_is_FpuReg (x.regs.src2)
|| isValid (x.regs.src3)
|| fn_ArchReg_is_FpuReg (x.regs.dst));
let mstatus = csrf.rd (CSRmstatus);
Bool fs_trap = ((mstatus [14:13] == 2'b00) && fpr_access);
// Check CSR access permission
Bool csr_access_trap = False;
if (x.dInst.iType == Csr) begin
Bit #(12) csr_addr = case (x.dInst.csr) matches
tagged Valid .c: pack (c);
default: 12'hCFF;
endcase;
let rs1 = case (x.regs.src2) matches
tagged Valid (tagged Gpr .r) : r;
default: 0;
endcase;
let imm = case (x.dInst.imm) matches
tagged Valid .n: n;
default: 0;
endcase;
Bool writes_csr = ((x.dInst.execFunc == tagged Alu Csrw) || (rs1 != 0) || (imm != 0));
Bool read_only = (csr_addr [11:10] == 2'b11);
Bit #(12) csr_addr = case (x.dInst.csr) matches
tagged Valid .c: pack (c);
default: 12'hCFF;
endcase;
let rs1 = case (x.regs.src2) matches
tagged Valid (tagged Gpr .r) : r;
default: 0;
endcase;
let imm = case (x.dInst.imm) matches
tagged Valid .n: n;
default: 0;
endcase;
Bool writes_csr = ((x.dInst.execFunc == tagged Alu Csrw) || (rs1 != 0) || (imm != 0));
Bool read_only = (csr_addr [11:10] == 2'b11);
Bool write_deny = (writes_csr && read_only);
Bool priv_deny = (csrf.decodeInfo.prv < csr_addr [9:8]);
csr_access_trap = (write_deny || priv_deny);
end
Bool priv_deny = (csrf.decodeInfo.prv < csr_addr [9:8]);
Bool unimplemented = (csr_addr == 12'h8ff); // Added by Bluespec
csr_access_trap = (write_deny || priv_deny || unimplemented);
end
// Check WFI trap (using a time-out of 0)
Bit #(32) inst_WFI = 32'h_1050_0073;
Bit #(1) mstatus_tw = mstatus [21];
Bool wfi_trap = ( (x.inst == inst_WFI)
&& (mstatus_tw == 1'b1)
&& (csrf.decodeInfo.prv < prvM));
&& (mstatus_tw == 1'b1)
&& (csrf.decodeInfo.prv < prvM));
`ifdef INCLUDE_GDB_CONTROL
if (rg_m_halt_req matches tagged Valid .cause) begin
// Stop due to debugger halt or step
trap = tagged Valid (tagged Interrupt cause);
end else
`endif
if (isValid(x.cause)) begin
// previously found exception
@@ -244,9 +288,9 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// newly found exception
trap = tagged Valid (tagged Exception fromMaybe(?, new_exception));
end
else if (fs_trap || csr_access_trap || wfi_trap) begin
else if (fs_trap || csr_access_trap || wfi_trap) begin
trap = tagged Valid (tagged Exception IllegalInst);
end
end
return trap;
endfunction
@@ -271,8 +315,23 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& epochManager.checkEpoch[0].check(fetchStage.pipelines[0].first.main_epoch) // correct path
&& isValid(firstTrap) // take trap
&& rob.isEmpty // stall for ROB empty
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
if (verbosity >= 1) begin
if (firstTrap == tagged Valid (tagged Interrupt DebugHalt))
$display ("%0d: %m.renameStage.doRenaming_Trap: DebugHalt", cur_cycle);
else if (firstTrap == tagged Valid (tagged Interrupt DebugStep))
$display ("%0d: %m.renameStage.doRenaming_Trap: DebugStep", cur_cycle);
else if (firstTrap == tagged Valid (tagged Exception Breakpoint))
$display ("%0d: %m.renameStage.doRenaming_Trap: Breakpoint", cur_cycle);
end
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
@@ -293,15 +352,21 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// This avoids doing incorrect work
incrEpochStallFetch;
// just place it in the reorder buffer
let y = ToReorderBuffer{pc: pc,
orig_inst: orig_inst,
let y = ToReorderBuffer{pc: setAddr(almightyCap, pc).value,
orig_inst: orig_inst,
iType: dInst.iType,
dst: arch_regs.dst,
dst_data: ?, // Available only after execution
`ifdef INCLUDE_TANDEM_VERIF
store_data: ?,
store_data_BE: ?,
`endif
csr: dInst.csr,
claimed_phy_reg: False, // no renaming is done
trap: firstTrap,
tval: tval,
tval: tval,
// default values of FullResult
ppc_vaddr_csrData: PPC (ppc), // default use PPC
ppc_vaddr_csrData: PPC (setAddr(almightyCap, pc).value), // default use PPC
fflags: 0,
////////
will_dirty_fpu_state: False,
@@ -322,6 +387,12 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
if(firstTrap matches tagged Valid (tagged Interrupt .i)) begin
inIfc.issueCsrInstOrInterrupt;
end
`ifdef INCLUDE_GDB_CONTROL
else if (firstTrap == tagged Valid (tagged Exception Breakpoint)) begin
inIfc.issueCsrInstOrInterrupt;
end
`endif
`ifdef CHECK_DEADLOCK
renameCorrectPath.send;
`endif
@@ -380,11 +451,18 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& !isValid(firstTrap) // not trap
&& firstReplay // system inst needs replay
&& rob.isEmpty // stall for ROB empty
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
let dst = x.regs.dst;
let ppc = x.ppc;
let main_epoch = x.main_epoch;
let dpTrain = x.dpTrain;
@@ -459,16 +537,34 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
will_dirty_fpu_state = True;
doAssert(False, "system inst never touches FP regs");
end
// CSR instrs that touch certain FP CSRs will dirty FP state.
if (dInst.csr matches tagged Valid .csr
&&& ((dInst.iType == Csr)
&& ((csr == CSRfflags) || (csr == CSRfrm) || (csr == CSRfcsr))))
begin
Bool is_CSRR_W = (dInst.execFunc == tagged Alu Csrw);
Bool rs1_is_0 = ((arch_regs.src2 == tagged Valid (tagged Gpr 0))
|| (dInst.imm == tagged Valid 0));
will_dirty_fpu_state = (is_CSRR_W || (! rs1_is_0));
end
RobInstState rob_inst_state = to_exec ? NotDone : Executed;
let y = ToReorderBuffer{pc: pc,
orig_inst: orig_inst,
let y = ToReorderBuffer{pc: setAddr(cast(scaprf.rd(SCR_PCC)), pc).value,
orig_inst: orig_inst,
iType: dInst.iType,
dst: arch_regs.dst,
dst_data: ?, // Available only after execution
`ifdef INCLUDE_TANDEM_VERIF
store_data: ?,
store_data_BE: ?,
`endif
csr: dInst.csr,
claimed_phy_reg: True, // XXX we always claim a free reg in rename
trap: Invalid, // no trap
tval: 0,
tval: 0,
// default values of FullResult
ppc_vaddr_csrData: PPC (ppc), // default use PPC
ppc_vaddr_csrData: PPC (setAddr(almightyCap, ppc).value), // default use PPC
fflags: 0,
////////
will_dirty_fpu_state: will_dirty_fpu_state,
@@ -529,8 +625,14 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// turn off speculation for mem inst only, and first inst is mem
&& (specNonMem && firstMem)
&& rob.isEmpty // stall for ROB empty to process mem inst
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
@@ -598,7 +700,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
regs_ready: regs_ready_aggr // mem currently recv bypass
});
end
doAssert(ppc == fallthrough_pc, "Mem next PC is not PC+4/PC+2");
doAssert(ppc == fallthrough_pc, "Mem next PC is not PC+4/PC+2");
doAssert(!isValid(dInst.csr), "Mem never explicitly read/write CSR");
doAssert((dInst.iType != Fence) == isValid(dInst.imm),
"Mem (non-Fence) needs imm for virtual addr");
@@ -626,8 +728,14 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
end
RobInstState rob_inst_state = NotDone; // mem inst always needs execution
let y = ToReorderBuffer{pc: pc,
orig_inst: orig_inst,
orig_inst: orig_inst,
iType: dInst.iType,
dst: arch_regs.dst,
dst_data: ?, // Available only after execution
`ifdef INCLUDE_TANDEM_VERIF
store_data: ?,
store_data_BE: ?,
`endif
csr: dInst.csr,
claimed_phy_reg: True, // XXX we always claim a free reg in rename
trap: Invalid, // no trap
@@ -692,6 +800,9 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& (!specNone || rob.isEmpty)
// don't process mem inst if we don't allow speculation for mem inst only
&& !(specNonMem && firstMem)
`endif
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
// we stop superscalar rename when an instruction cannot be processed:
@@ -700,6 +811,11 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// (c) It is system inst (we handle system inst in a separate rule)
// (d) It does not have enough resource
Bool stop = False;
`ifdef INCLUDE_GDB_CONTROL
// (e) One rename has been done and dcsr.step is set
Bool debug_step = False;
`endif
// We automatically stop after an inst cannot be deq from fetch stage
// because canDeq signal for sup-fifo is consecutive
@@ -737,7 +853,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
if(!stop && fetchStage.pipelines[i].canDeq) begin
let x = fetchStage.pipelines[i].first; // don't deq now, inst may not have resource
let pc = x.pc;
let orig_inst = x.orig_inst;
let orig_inst = x.orig_inst;
let ppc = x.ppc;
let main_epoch = x.main_epoch;
let dpTrain = x.dpTrain;
@@ -748,6 +864,13 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
Addr fallthrough_pc = ((orig_inst[1:0] == 2'b11) ? pc + 4 : pc + 2);
`ifdef INCLUDE_GDB_CONTROL
if ((i != 0) && (csrf.dcsr_step_bit == 1'b1)) begin
stop = True;
debug_step = True;
end
`endif
// check for wrong path, if wrong path, don't process it, leave to the other rule in next cycle
if(!epochManager.checkEpoch[i].check(main_epoch)) begin
stop = True;
@@ -942,7 +1065,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// deq fetch & update epochs match
fetchStage.pipelines[i].deq;
epochManager.updatePrevEpoch[i].update(main_epoch);
// Claim a speculation tag
if (new_speculation) begin
specTagClaimed = True; // mark resource used
@@ -968,15 +1091,21 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
end
RobInstState rob_inst_state = (to_exec || to_mem || to_FpuMulDiv) ? NotDone : Executed;
let y = ToReorderBuffer{pc: pc,
orig_inst: orig_inst,
let y = ToReorderBuffer{pc: setAddr(cast(scaprf.rd(SCR_PCC)), pc).value,
orig_inst: orig_inst,
iType: dInst.iType,
dst: arch_regs.dst,
dst_data: ?, // Available only after execution
`ifdef INCLUDE_TANDEM_VERIF
store_data: ?,
store_data_BE: ?,
`endif
csr: dInst.csr,
claimed_phy_reg: True, // XXX we always claim a free reg in rename
trap: Invalid, // no trap
tval: 0,
tval: 0,
// default values of FullResult
ppc_vaddr_csrData: PPC (ppc), // default use PPC
ppc_vaddr_csrData: PPC (setAddr(almightyCap, ppc).value), // default use PPC
fflags: 0,
////////
will_dirty_fpu_state: will_dirty_fpu_state,
@@ -1007,6 +1136,11 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
end
end
`ifdef INCLUDE_GDB_CONTROL
if (debug_step)
rg_m_halt_req <= tagged Valid DebugStep;
`endif
// only fire this rule if we make some progress
// otherwise this rule may block other rules forever
when(doCorrectPath, noAction);
@@ -1047,4 +1181,19 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
default: 0;
endcase);
endmethod
`ifdef INCLUDE_GDB_CONTROL
method Action debug_halt_req () if (rg_m_halt_req == tagged Invalid);
rg_m_halt_req <= tagged Valid DebugHalt;
if (verbosity >= 1)
$display ("%0d: %m.renameStage.renameStage.debug_halt_req", cur_cycle);
endmethod
method Action debug_resume;
rg_m_halt_req <= tagged Invalid;
if (verbosity >= 1)
$display ("%0d: %m.renameStage.renameStage.debug_resume", cur_cycle);
endmethod
`endif
endmodule

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -35,8 +36,8 @@ typedef TDiv#(SupSize, 2) FpuMulDivExeNum;
// Phy RFile
// write: Alu < FpuMulDiv < Mem
// read: Alu, FpuMulDiv, Mem
typedef TAdd#(1, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileWrPortNum;
typedef TAdd#(1, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileRdPortNum;
typedef TAdd#(2, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileWrPortNum;
typedef TAdd#(2, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileRdPortNum;
// sb lazy lookup num: same as RFile read, becaues all pipelines recv bypass
typedef RFileRdPortNum SbLazyLookupPortNum;
@@ -65,6 +66,7 @@ Integer memWrAggrPort = 1 + valueof(FpuMulDivExeNum) + valueof(AluExeNum);
function Integer aluRdPort(Integer i) = i;
function Integer fpuMulDivRdPort(Integer i) = valueof(AluExeNum) + i;
Integer memRdPort = valueof(FpuMulDivExeNum) + valueof(AluExeNum);
Integer debuggerPort = memRdPort + 1;
// ports for correct spec, ordering doesn't matter
typedef TAdd#(2, AluExeNum) CorrectSpecPortNum;

View File

@@ -31,8 +31,8 @@ export NextAddrPred(..);
export mkBtb;
interface NextAddrPred;
method Addr predPc(Addr pc);
method Action update(Addr pc, Addr nextPc, Bool taken);
method Maybe#(Addr) predPc(Addr pc);
method Action update(Addr pc, Addr brTarget, Bool taken);
// security
method Action flush;
method Bool flush_done;
@@ -96,13 +96,13 @@ module mkBtb(NextAddrPred);
endrule
`endif
method Addr predPc(Addr pc);
method Maybe#(Addr) predPc(Addr pc);
BtbIndex index = getIndex(pc);
BtbTag tag = getTag(pc);
if(valid[index] && tag == tags.sub(index))
return next_addrs.sub(index);
return tagged Valid next_addrs.sub(index);
else
return (pc + 4);
return tagged Invalid;
endmethod
method Action update(Addr pc, Addr nextPc, Bool taken);

View File

@@ -29,7 +29,7 @@ import GetPut::*;
import ClientServer::*;
import Connectable::*;
import Vector::*;
import Fifo::*;
import Fifos::*;
import Ehr::*;
import FIFO::*;
import FIFOF::*;

View File

@@ -31,7 +31,7 @@ import TlbTypes::*;
import Performance::*;
import FullAssocTlb::*;
import ConfigReg::*;
import Fifo::*;
import Fifos::*;
import Cntrs::*;
import SafeCounter::*;
import CacheUtils::*;

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +8,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -28,6 +28,7 @@ import ProcTypes::*;
import MemoryTypes::*;
import Vector::*;
import DefaultValue::*;
import ISA_Decls_CHERI::*;
Bit#(3) memWU = 3'b110;
@@ -150,7 +151,8 @@ function DecodeResult decode(Instruction inst);
iType: Unsupported,
execFunc: tagged Other,
csr: tagged Invalid,
imm: tagged Invalid
imm: tagged Invalid,
capChecks: unpack(0)
};
ArchRegs regs = ArchRegs {
src1: tagged Invalid,
@@ -174,6 +176,8 @@ function DecodeResult decode(Instruction inst);
// For "A" ISA extension
Bool aq = unpack(inst[ 26 ]);
Bool rl = unpack(inst[ 25 ]);
// For "xCHERI" ISA extension
let funct5rs2 = inst[ 24 : 20 ];
ImmData immI = signExtend(inst[31:20]);
ImmData immS = signExtend({ inst[31:25], inst[11:7] });
@@ -721,83 +725,83 @@ function DecodeResult decode(Instruction inst);
end
end
opCHERI: begin
OpCHERI: begin
case (funct3)
f3_CIncOffsetImmediate: begin
f3_cap_CIncOffsetImmediate: begin
end
f3_CSetBoundsImmediate: begin
f3_cap_CSetBoundsImmediate: begin
end
f3_ThreeOp: begin
f3_cap_ThreeOp: begin
case (funct7)
f7_CSpecialRW: begin
f7_cap_CSpecialRW: begin
end
f7_CSetBounds: begin
f7_cap_CSetBounds: begin
end
f7_CSetBoundsExact: begin
f7_cap_CSetBoundsExact: begin
end
f7_CSetOffset: begin
f7_cap_CSetOffset: begin
end
f7_CSetAddr: begin
f7_cap_CSetAddr: begin
end
f7_CIncOffset: begin
f7_cap_CIncOffset: begin
end
f7_CSeal: begin
f7_cap_CSeal: begin
end
f7_CCSeal: begin
f7_cap_CCSeal: begin
end
f7_TwoSrc: begin
f7_cap_TwoSrc: begin
end
f7_CUnseal: begin
f7_cap_CUnseal: begin
end
f7_CTestSubset: begin
f7_cap_CTestSubset: begin
end
f7_CCopyType: begin
f7_cap_CCopyType: begin
end
f7_CAndPerm: begin
f7_cap_CAndPerm: begin
end
f7_CSetFlags: begin
f7_cap_CSetFlags: begin
end
f7_CToPtr: begin
f7_cap_CToPtr: begin
end
f7_CFromPtr: begin
f7_cap_CFromPtr: begin
end
f7_CSub: begin
f7_cap_CSub: begin
end
f7_CBuildCap: begin
f7_cap_CBuildCap: begin
end
f7_Loads: begin
f7_cap_Loads: begin
end
f7_Stores: begin
f7_cap_Stores: begin
end
f7_TwoOp: begin
f7_cap_TwoOp: begin
case (funct5rs2)
f5rs2_CGetLen: begin
f5rs2_cap_CGetLen: begin
end
f5rs2_CGetBase: begin
f5rs2_cap_CGetBase: begin
end
f5rs2_CGetTag: begin
f5rs2_cap_CGetTag: begin
end
f5rs2_CGetSealed: begin
f5rs2_cap_CGetSealed: begin
end
f5rs2_CRRL: begin
f5rs2_cap_CRRL: begin
end
f5rs2_CRAM: begin
f5rs2_cap_CRAM: begin
end
f5rs2_CMove: begin
f5rs2_cap_CMove: begin
end
f5rs2_CClearTag: begin
f5rs2_cap_CClearTag: begin
end
f5rs2_CGetAddr: begin
f5rs2_cap_CGetAddr: begin
end
f5rs2_CGetOffset: begin
f5rs2_cap_CGetOffset: begin
end
f5rs2_CGetFlags: begin
f5rs2_cap_CGetFlags: begin
end
f5rs2_CGetPerm: begin
f5rs2_cap_CGetPerm: begin
end
f5rs2_CJARL: begin
f5rs2_cap_CJALR: begin
end
f5rs2_CGetType: begin
f5rs2_cap_CGetType: begin
end
endcase
end

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +8,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -26,6 +26,8 @@
import Types::*;
import ProcTypes::*;
import Vector::*;
import CHERICap::*;
import CHERICC_Fat::*;
(* noinline *)
function Data alu(Data a, Data b, AluFunc func);
@@ -54,62 +56,62 @@ function Data alu(Data a, Data b, AluFunc func);
endfunction
(* noinline *)
function CapPipe capModify(CapPipe a, CapPipe b, AluCapFunc func);
function CapPipe capModify(CapPipe a, CapPipe b, CapModifyFunc func);
CapPipe res = (case(func) matches
tagged ModifyOffset (offsetOp):
modifyOffset(a, b, offsetOp == IncOffset)
tagged SpecialRW :
error("SpecialRW not yet implemented")
tagged SetAddr :
setAddr(a, getAddr(b))
tagged Seal :
setType(a, truncate(getAddr(b)))
tagged Unseal :
setType(a, -1)
tagged AndPerm :
setPerms(a, pack(getPerms(a)) & truncate(getAddr(b)))
tagged SetFlags :
setFlags(a, truncate(getAddr(b)));
tagged BuildCap :
setValidCap(a, True);
tagged CMove :
a
tagged ClearTag :
setValidCap(a, False);
tagged CJALR :
error("CJALR not yet implemented")
default : 0;
tagged ModifyOffset .incOffsetBool:
modifyOffset(a, getAddr(b), incOffsetBool).value;
tagged SetBounds .exact :
setBounds(a, getAddr(b)).value;
//tagged SpecialRW :
// error("SpecialRW not yet implemented");
tagged SetAddr :
setAddr(a, getAddr(b)).value;
tagged Seal :
setType(a, truncate(getAddr(b)));
tagged Unseal :
setType(a, -1);
tagged AndPerm :
setPerms(a, pack(getPerms(a)) & truncate(getAddr(b)));
tagged SetFlags :
setFlags(a, truncate(getAddr(b)));
tagged BuildCap :
setValidCap(a, True);
tagged CMove :
a;
tagged ClearTag :
setValidCap(a, False);
//tagged CJALR :
// error("CJALR not yet implemented");
default : nullCap;
endcase);
return res;
endfunction
(* noinline *)
function Data capInspect(CapPipe a, CapPipe b, CapInspectFunc func);
SetBoundsReturn boundsResult = combinedSetBounds(a, getAddr(b), func.SetBounds);
CapPipe res = (case(func) matches
tagged TestSubset :
error("TestSubset not yet implemented")
Data res = (case(func) matches
//tagged TestSubset :
// error("TestSubset not yet implemented");
tagged CSub :
getAddr(a) - getAddr(b)
(getAddr(a) - getAddr(b));
tagged GetBase :
getBase(a)
getBase(a);
tagged GetTag :
getTag(a)
zeroExtend(pack(isValidCap(a)));
tagged GetSealed :
getSealed(a)
zeroExtend(pack(isSealed(a)));
tagged GetAddr :
getAddr(a)
getAddr(a);
tagged GetOffset :
getOffset(a)
getOffset(a);
tagged GetFlags :
getFlags(a)
zeroExtend(getFlags(a));
tagged GetPerm :
getPerms(a)
zeroExtend(getPerms(a));
tagged GetType :
getType(a)
signExtend(getType(a));
tagged ToPtr :
getAddr(a) - getBase(b);
tagged CJALR :
(getAddr(a) - getBase(b));
default : 0;
endcase);
return res;
@@ -173,8 +175,9 @@ function ExecResult basicExec(DecodedInst dInst, Data rVal1, Data rVal2, Addr pc
AluFunc alu_f = dInst.execFunc matches tagged Alu .alu_f ? alu_f : Add;
Data alu_result = alu(rVal1, aluVal2, alu_f);
Data inspect_result = capInspect(rVal1, aluVal2, dInst.execFunc.CapInspect);
CapPipe modify_resut = capModify(rVal1, aluVal2, dInst.execFunc.capModify);
// Pass capabilities into these functions when they are passed in.
Data inspect_result = capInspect(nullWithAddr(rVal1), nullWithAddr(aluVal2), dInst.execFunc.CapInspect);
CapPipe modify_result = capModify(nullWithAddr(rVal1), nullWithAddr(aluVal2), dInst.execFunc.CapModify);
// Default branch function is not taken
BrFunc br_f = dInst.execFunc matches tagged Br .br_f ? br_f : NT;
@@ -189,8 +192,8 @@ function ExecResult basicExec(DecodedInst dInst, Data rVal1, Data rVal2, Addr pc
J, Jr : (pc + fallthrough_incr); // could be computed with alu
Auipc : (pc + fromMaybe(?, getDInstImm(dInst))); // could be computed with alu
Csr : rVal1;
capInspect : inspect_result;
capModify : modify_result;
CapInspect : inspect_result;
CapModify : getAddr(modify_result); // Obviously return the whole thing when data is a capability.
default : alu_result;
endcase);
csr_data = alu_result;
@@ -317,4 +320,3 @@ function Tuple2#(ByteEn, Data) scatterStore(Addr addr, ByteEn byteEn, Data data)
return tuple2(unpack(pack(byteEn) << (offset)), data << {(offset), 3'b0});
end
endfunction

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2019 Bluepec, Inc
// This package implements utility functions used by the floating point
// related logic
package FP_Utils;
import FloatingPoint::*;
function FloatingPoint#(e,m) canonicalNaN = FloatingPoint{sign: False, exp: '1, sfd: 1 << (valueof(m)-1)};
// nanbox-ing and its inverse (unbox-ing)
// If the raw bits are nan-boxed, the fv_nanbox(fv_unbox) are identity
// functions. However, if the raw input was not properly nanboxed, then the
// output would be a canonical NaN
// Take a single precision value and nanboxes it to be able to write it to a
// 64-bit FPR register file. This is necessary if single precision operands
// used with a register file capable of holding double precision values
function Bit #(64) fv_nanbox (Bit #(64) x);
Bit #(64) fill_bits = (64'h1 << 32) - 1; // [31: 0] all ones
Bit #(64) fill_mask = (fill_bits << 32); // [63:32] all ones
return (x | fill_mask);
endfunction
// Take a 64-bit value and check if it is properly nanboxed if operating in a DP
// capable environment. If not properly nanboxed, return canonicalNaN32
function Float fv_unbox (Bit #(64) x);
//`ifdef ISA_D
if (x [63:32] == 32'hffffffff)
return (unpack (x [31:0]));
else
return (canonicalNaN);
//`else
// return (unpack (x [31:0]));
//`endif
endfunction
endpackage

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2016, 2017 Massachusetts Institute of Technology
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -41,6 +42,7 @@ import XilinxFpu::*;
import HasSpecBits::*;
import SpecFifo::*;
import SpecPoisonFifo::*;
import FP_Utils::*;
export FpuResult(..);
export FpuResp(..);
@@ -50,8 +52,6 @@ export mkFpuExecPipeline;
typedef FloatingPoint::RoundMode FpuRoundMode;
typedef FloatingPoint::Exception FpuException;
function FloatingPoint#(e,m) canonicalNaN = FloatingPoint{sign: False, exp: '1, sfd: 1 << (valueof(m)-1)};
typedef struct {
Data data;
Bit#(5) fflags;
@@ -172,26 +172,36 @@ function Tuple2#(FloatingPoint#(e,m), FpuException) fcvt_f_wu (Bit#(64) in_bits,
endfunction
function Tuple2#(Bit#(64), FpuException) fmin_s(Bit#(64) in1, Bit#(64) in2);
Float in1_f = unpack(in1[31:0]);
Float in2_f = unpack(in2[31:0]);
// nirajns: interpret the inputs as floats. Observe that this function
// receives raw bits.
Float in1_f = fv_unbox(in1);
Float in2_f = fv_unbox(in2);
Bit #(64) in1_f_packed = fv_nanbox (zeroExtend(pack(in1_f)));
Bit #(64) in2_f_packed = fv_nanbox (zeroExtend(pack(in2_f)));
Float nan_f = qnan(); // canonical NAN
FpuException e = unpack(0);
if (isSNaN(in1_f) || isSNaN(in2_f) || (isNaN(in1_f) && isNaN(in2_f))) begin
// nirajns: TEST 21 failure on fmin ISA tests
// e.invalid_op should only be signalled only if either operand is a sNaN
// as the fmin and fmax are quiet comparison
if (isSNaN(in1_f) || isSNaN(in2_f)) begin
e.invalid_op = True;
return tuple2(zeroExtend(pack(nan_f)), e);
end
if (isNaN(in1_f) && isNaN(in2_f)) begin
return tuple2(fv_nanbox (zeroExtend(pack(nan_f))), e);
end else if (isNaN(in2_f)) begin
return tuple2(in1, e);
return tuple2(in1_f_packed, e);
end else if (isNaN(in1_f)) begin
return tuple2(in2, e);
return tuple2(in2_f_packed, e);
end else begin
let signLT = (in1_f.sign && !in2_f.sign);
let signEQ = in1_f.sign == in2_f.sign;
let absLT = {in1_f.exp, in1_f.sfd} < {in2_f.exp, in2_f.sfd};
if (signLT || (signEQ && (in1_f.sign ? !absLT : absLT))) begin
return tuple2(in1, e);
return tuple2(in1_f_packed, e);
end else begin
return tuple2(in2, e);
return tuple2(in2_f_packed, e);
end
end
endfunction
@@ -202,9 +212,14 @@ function Tuple2#(Bit#(64), FpuException) fmin_d(Bit#(64) in1, Bit#(64) in2);
Double nan_f = qnan(); // canonical NAN
FpuException e = unpack(0);
if (isSNaN(in1_f) || isSNaN(in2_f) || (isNaN(in1_f) && isNaN(in2_f))) begin
// nirajns: TEST 21 failure on fmin ISA tests
// e.invalid_op should only be signalled only if either operand is a sNaN
// as the fmin and fmax are quiet comparison
if (isSNaN(in1_f) || isSNaN(in2_f)) begin
e.invalid_op = True;
return tuple2(pack(nan_f), e);
end
if (isNaN(in1_f) && isNaN(in2_f)) begin
return tuple2(zeroExtend(pack(nan_f)), e);
end else if (isNaN(in2_f)) begin
return tuple2(in1, e);
end else if (isNaN(in1_f)) begin
@@ -222,26 +237,39 @@ function Tuple2#(Bit#(64), FpuException) fmin_d(Bit#(64) in1, Bit#(64) in2);
endfunction
function Tuple2#(Bit#(64), FpuException) fmax_s(Bit#(64) in1, Bit#(64) in2);
Float in1_f = unpack(in1[31:0]);
Float in2_f = unpack(in2[31:0]);
// nirajns: interpret the inputs as floats. Observe that this function
// receives raw bits.
// If the raw bits are nan-boxed, the fv_nanbox(fv_unbox) are identity
// functions. However, if the raw input was not properly nanboxed, then
// the output would be a canonical NaN
Float in1_f = fv_unbox(in1);
Float in2_f = fv_unbox(in2);
Bit #(64) in1_f_packed = fv_nanbox (zeroExtend(pack(in1_f)));
Bit #(64) in2_f_packed = fv_nanbox (zeroExtend(pack(in2_f)));
Float nan_f = qnan(); // canonical NAN
FpuException e = unpack(0);
if (isSNaN(in1_f) || isSNaN(in2_f) || (isNaN(in1_f) && isNaN(in2_f))) begin
// nirajns: TEST 21 failure on fmin ISA tests
// e.invalid_op should only be signalled only if either operand is a sNaN
// as the fmin and fmax are quiet comparison
if (isSNaN(in1_f) || isSNaN(in2_f)) begin
e.invalid_op = True;
return tuple2(zeroExtend(pack(nan_f)), e);
end
if (isNaN(in1_f) && isNaN(in2_f)) begin
return tuple2(fv_nanbox (zeroExtend(pack(nan_f))), e);
end else if (isNaN(in2_f)) begin
return tuple2(in1, e);
return tuple2(in1_f_packed, e);
end else if (isNaN(in1_f)) begin
return tuple2(in2, e);
return tuple2(in2_f_packed, e);
end else begin
let signGT = (!in1_f.sign && in2_f.sign);
let signEQ = in1_f.sign == in2_f.sign;
let absGT = {in1_f.exp, in1_f.sfd} > {in2_f.exp, in2_f.sfd};
if (signGT || (signEQ && (in1_f.sign ? !absGT : absGT))) begin
return tuple2(in1, e);
return tuple2(in1_f_packed, e);
end else begin
return tuple2(in2, e);
return tuple2(in2_f_packed, e);
end
end
endfunction
@@ -252,9 +280,14 @@ function Tuple2#(Bit#(64), FpuException) fmax_d(Bit#(64) in1, Bit#(64) in2);
Double nan_f = qnan(); // canonical NAN
FpuException e = unpack(0);
if (isSNaN(in1_f) || isSNaN(in2_f) || (isNaN(in1_f) && isNaN(in2_f))) begin
// nirajns: TEST 21 failure on fmin ISA tests
// e.invalid_op should only be signalled only if either operand is a sNaN
// as the fmin and fmax are quiet comparison
if (isSNaN(in1_f) || isSNaN(in2_f)) begin
e.invalid_op = True;
return tuple2(pack(nan_f), e);
end
if (isNaN(in1_f) && isNaN(in2_f)) begin
return tuple2(zeroExtend(pack(nan_f)), e);
end else if (isNaN(in2_f)) begin
return tuple2(in1, e);
end else if (isNaN(in1_f)) begin
@@ -417,8 +450,9 @@ function FpuResult execFpuSimple(FpuInst fpu_inst, Data rVal1, Data rVal2);
if (fpu_inst.precision == Single) begin
// single precision
Float in1 = unpack(rVal1[31:0]);
Float in2 = unpack(rVal2[31:0]);
// nirajns: interpret them as floats
Float in1 = fv_unbox(rVal1);
Float in2 = fv_unbox(rVal2);
Float dst = unpack(0);
Maybe#(Data) full_dst = Invalid;
FpuException e = unpack(0);
@@ -436,18 +470,33 @@ function FpuResult execFpuSimple(FpuInst fpu_inst, Data rVal1, Data rVal2);
{x, e} = fmax_s(rVal1, rVal2);
full_dst = tagged Valid x;
end
FEq: dst = unpack(zeroExtend(pack(compareFP(in1, in2) == EQ)));
FEq: begin
// nirajns: TEST 10 failure on fcmp ISA tests
Data x;
if (isNaN (in1) || isNaN (in2)) x = 0;
else x = zeroExtend(pack(compareFP(in1, in2) == EQ));
if (isSNaN(in1) || isSNaN(in2)) begin
e.invalid_op = True;
end
full_dst = tagged Valid x;
end
FLt: begin
dst = unpack(zeroExtend(pack(compareFP(in1, in2) == LT)));
Data x;
if (isNaN (in1) || isNaN (in2)) x = 0;
else x = zeroExtend(pack(compareFP(in1, in2) == LT));
if (isNaN(in1) || isNaN(in2)) begin
e.invalid_op = True;
end
full_dst = tagged Valid x;
end
FLe: begin
dst = unpack(zeroExtend(pack((compareFP(in1, in2) == LT) || (compareFP(in1, in2) == EQ))));
Data x;
if (isNaN (in1) || isNaN (in2)) x = 0;
else x = zeroExtend(pack((compareFP(in1, in2) == LT) || (compareFP(in1, in2) == EQ)));
if (isNaN(in1) || isNaN(in2)) begin
e.invalid_op = True;
end
full_dst = tagged Valid x;
end
// CLASS functions
FClass: begin
@@ -481,9 +530,11 @@ function FpuResult execFpuSimple(FpuInst fpu_inst, Data rVal1, Data rVal2);
dst.sign = unpack(pack(in1.sign) ^ pack(in2.sign));
end
// Float -> Bits
FMv_XF: full_dst = tagged Valid signExtend(pack(in1));
// nirajns: don't interpret the bits - use raw bits rVal1
FMv_XF: full_dst = tagged Valid signExtend(pack(rVal1[31:0]));
// Bits -> Float
FMv_FX: full_dst = tagged Valid zeroExtend(pack(in1));
// nirajns: don't interpret the bits - use raw bits rVal1
FMv_FX: full_dst = tagged Valid fv_nanbox (zeroExtend(pack(rVal1[31:0])));
// Float -> Float
FCvt_FF: begin
Double in1_double = unpack(rVal1);
@@ -529,7 +580,7 @@ function FpuResult execFpuSimple(FpuInst fpu_inst, Data rVal1, Data rVal2);
if (isNaN(dst)) dst = canonicalNaN;
end
endcase
fpu_result.data = (full_dst matches tagged Valid .data ? data : zeroExtend(pack(dst)));
fpu_result.data = (full_dst matches tagged Valid .data ? data : fv_nanbox(zeroExtend(pack(dst))));
fpu_result.fflags = pack(e);
end else if (fpu_inst.precision == Double) begin
// double precision
@@ -552,15 +603,24 @@ function FpuResult execFpuSimple(FpuInst fpu_inst, Data rVal1, Data rVal2);
{x, e} = fmax_d(rVal1, rVal2);
full_dst = tagged Valid x;
end
FEq: dst = unpack(zeroExtend(pack(compareFP(in1, in2) == EQ)));
FEq: begin
// nirajns: TEST 10 failure on fcmp ISA tests
if (isNaN (in1) || isNaN (in2)) dst = unpack (0);
else dst = unpack(zeroExtend(pack(compareFP(in1, in2) == EQ)));
if (isSNaN(in1) || isSNaN(in2)) begin
e.invalid_op = True;
end
end
FLt: begin
dst = unpack(zeroExtend(pack(compareFP(in1, in2) == LT)));
if (isNaN (in1) || isNaN (in2)) dst = unpack (0);
else dst = unpack(zeroExtend(pack(compareFP(in1, in2) == LT)));
if (isNaN(in1) || isNaN(in2)) begin
e.invalid_op = True;
end
end
FLe: begin
dst = unpack(zeroExtend(pack((compareFP(in1, in2) == LT) || (compareFP(in1, in2) == EQ))));
if (isNaN (in1) || isNaN (in2)) dst = unpack (0);
else dst = unpack(zeroExtend(pack((compareFP(in1, in2) == LT) || (compareFP(in1, in2) == EQ))));
if (isNaN(in1) || isNaN(in2)) begin
e.invalid_op = True;
end
@@ -720,7 +780,7 @@ module mkFpuExecPipeline(FpuExec);
// canonicalize NaN
out_f = isNaN(out_f) ? canonicalNaN : out_f;
res = FpuResult {
data: zeroExtend(pack(out_f)),
data: fv_nanbox (zeroExtend(pack(out_f))),
fflags: pack(info.exc_conv_in | exc_op | exc_conv_out)
};
end
@@ -778,9 +838,10 @@ module mkFpuExecPipeline(FpuExec);
Double in3 = unpack(rVal3);
if (fpu_inst.precision == Single) begin
// conver single to double
Float f1 = unpack(rVal1[31:0]);
Float f2 = unpack(rVal2[31:0]);
Float f3 = unpack(rVal3[31:0]);
// nirajns: interpret the raw bits as floats first
Float f1 = fv_unbox(rVal1);
Float f2 = fv_unbox(rVal2);
Float f3 = fv_unbox(rVal3);
let {d1, exc1} = fcvt_d_s(f1, fpu_rm);
let {d2, exc2} = fcvt_d_s(f2, fpu_rm);
let {d3, exc3} = fcvt_d_s(f3, fpu_rm);

View File

@@ -31,7 +31,7 @@ import TlbTypes::*;
import Performance::*;
import FullAssocTlb::*;
import ConfigReg::*;
import Fifo::*;
import Fifos::*;
import Cntrs::*;
import SafeCounter::*;
import CacheUtils::*;

View File

@@ -33,7 +33,7 @@ import CacheUtils::*;
import Types::*;
import ProcTypes::*;
import Performance::*;
import Fifo::*;
import Fifos::*;
import CCTypes::*;
import L1Pipe::*;
import L1CRqMshr::*;

View File

@@ -33,7 +33,7 @@ import Performance::*;
import FullAssocTlb::*;
import ConfigReg::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import Cntrs::*;
import SafeCounter::*;
import CacheUtils::*;
@@ -628,10 +628,10 @@ module mkL2Tlb(L2Tlb::L2Tlb);
transCache.addEntry(cRq.vpn, walkLevel, pte.ppn, vm_info.asid);
end
end
else if (! isPpnAligned (pte.ppn, walkLevel)) begin
// Leaf page, but PPN is not aligne
pageFault("PPN is not aligned");
end
else if (! isPpnAligned (pte.ppn, walkLevel)) begin
// Leaf page, but PPN is not aligne
pageFault("PPN is not aligned");
end
else begin
// leaf page, get new entry
Vpn masked_vpn = getMaskedVpn(cRq.vpn, walkLevel);

View File

@@ -1,6 +1,19 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
// This file is a modified version of: RISCY_OOO/procs/lib/LLCDmaConnect.bsv
// Bluespec: this file is has many modifications.
// The original module had 3 params and had an Empty interface.
// The 2nd param was: MemLoaderMemClient memLoader
// which issued only write-transactions (to load memory).
// The module discarded write responses, and ignored read-requests.
// Here, that module parameter is removed and, instead, the module has an
// AXI4_Slave interface, to be connected to the AXI4_Master of the
// Debug Module. This axi4_slave accepts, processes and responds
// to both read and write transactions.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -21,12 +34,31 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import FShow::*;
import GetPut::*;
import Vector::*;
import BuildVector::*;
import FIFO::*;
import Assert::*;
// ================================================================
// BSV library imports
import FIFOF :: *;
import Connectable :: *;
import FShow :: *;
import GetPut :: *;
import Vector :: *;
import BuildVector :: *;
import FIFO :: *;
import Assert :: *;
// ----------------
// BSV additional libs
import Cur_Cycle :: *;
import Semi_FIFOF :: *;
import EdgeFIFOFs :: *;
// ================================================================
// Project imports
// ----------------
// From RISCY-OOO
import Types::*;
import ProcTypes::*;
@@ -37,6 +69,15 @@ import MemLoader::*;
import CrossBar::*;
import MemLoader::*;
// ----------------
// From Toooba
import AXI4_Types :: *;
import Fabric_Defs :: *;
import Semi_FIFOF :: *;
// ================================================================
typedef struct {
CoreId core;
TlbMemReqId id;
@@ -48,15 +89,277 @@ typedef union tagged {
TlbDmaReqId Tlb;
} LLCDmaReqId deriving(Bits, Eq, FShow);
module mkLLCDmaConnect#(
// ================================================================
// Help functions for read-modify-writes of 4-Byte values on a 64-Byte Cache Line
typedef enum {CACHELINE_CACHE_INVALID,
CACHELINE_CACHE_WRITING_BACK,
CACHELINE_CACHE_RELOADING,
CACHELINE_CACHE_CLEAN,
CACHELINE_CACHE_DIRTY
} Cacheline_Cache_State
deriving (Bits, Eq, FShow);
function Addr fn_align_addr_to_line (Addr addr);
Addr line_addr = { addr [63:6], 6'b0 };
return line_addr;
endfunction
function Bool fn_addr_is_in_line (Addr addr, Addr line_addr);
return (fn_align_addr_to_line (addr) == line_addr);
endfunction
function Bit #(64) fn_expand_strb_to_mask (Bit #(8) strb);
function Bit #(8) fn_bit_to_byte (Integer j);
return ((strb [j] == 1'b1) ? 8'hFF : 8'h00);
endfunction
Vector #(8, Bit #(8)) v = genWith (fn_bit_to_byte);
return pack (v);
endfunction
// ================================================================
module mkLLCDmaConnect #(
DmaServer#(LLCDmaReqId) llc,
MemLoaderMemClient memLoader,
// MemLoaderMemClient memLoader, // REPLACED BY AXI4_Slave_interface
Vector#(CoreNum, TlbMemClient) tlb
)(Empty) provisos (
)(AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User)) provisos (
Alias#(dmaRqT, DmaRq#(LLCDmaReqId))
);
Bool verbose = False;
Integer verbosity = 0;
// When debugger reads a word, request a line from LLC, and remember dword-in-line here
FIFOF #(Bit #(3)) f_dword_in_line <- mkFIFOF;
// Slave transactor for requests from Debug Module
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) axi4_slave_xactor <- mkAXI4_Slave_Xactor;
// ================================================================
// These regs are a 1-location local cache for an LLC Cache Line,
// to avoid doing a full read-modify-write to the LLC on each transaction.
Reg #(Cacheline_Cache_State) rg_cacheline_cache_state <- mkReg (CACHELINE_CACHE_CLEAN);
Reg #(Addr) rg_cacheline_cache_addr <- mkReg (1); // never matches an LLC line addr
Reg #(Line) rg_cacheline_cache_data <- mkRegU;
// Writeback dirty cacheline_cache if no new store requests within n-cycles
Reg #(Bit #(10)) rg_cacheline_cache_dirty_delay <- mkReg (0);
// ================================================================
// Write transactions from the external client (e.g., Debug Module)
// Respond to store-requests from the external client on store-hit
rule rl_handle_MemLoader_st_req ( ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|| (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY))
&& (fn_addr_is_in_line (axi4_slave_xactor.o_wr_addr.first.awaddr,
rg_cacheline_cache_addr)));
let wr_addr <- pop_o (axi4_slave_xactor.o_wr_addr);
let wr_data <- pop_o (axi4_slave_xactor.o_wr_data);
Addr addr = wr_addr.awaddr;
Bit #(64) data = wr_data.wdata;
Bit #(64) mask = fn_expand_strb_to_mask (wr_data.wstrb);
// Read rg_cacheline_cache_data as 64-bit words
Vector #(8, Bit #(64)) line_dwords = unpack (pack (rg_cacheline_cache_data));
// Modify relevant bytes of relevant dword
Bit #(3) dword_in_line = addr [5:3];
Bit #(64) old_dword = line_dwords [dword_in_line];
Bit #(64) new_dword = ((old_dword & (~ mask)) | (data & mask));
line_dwords [dword_in_line] = new_dword;
// Save it
rg_cacheline_cache_data <= unpack (pack (line_dwords));
rg_cacheline_cache_state <= CACHELINE_CACHE_DIRTY;
rg_cacheline_cache_dirty_delay <= '1; // start write-back delay countdown
// Send response to external client
AXI4_Wr_Resp #(Wd_Id, Wd_User)
wr_resp = AXI4_Wr_Resp {bid: 0, // TODO: change uniformly to Fabric_id
bresp: axi4_resp_okay,
buser: ?};
axi4_slave_xactor.i_wr_resp.enq (wr_resp);
if (verbosity >= 2) begin
$display ("%0d: %m.rl_handle_MemLoader_st_req: addr %0h data %0h strb %0h",
cur_cycle, wr_addr.awaddr, wr_data.wdata, wr_data.wstrb);
$display (" old_dword: %0h", old_dword);
$display (" new_dword: %0h", old_dword);
end
endrule
// ================================================================
// Read transactions from the external memory client (e.g., Debug Module)
// Responds to load-requests from the external client on load-hit
rule rl_handle_MemLoader_ld_req ( ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|| (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY))
&& (fn_addr_is_in_line (axi4_slave_xactor.o_rd_addr.first.araddr,
rg_cacheline_cache_addr)));
let rd_addr <- pop_o (axi4_slave_xactor.o_rd_addr);
Addr addr = rd_addr.araddr;
// Read rg_cacheline_cache as 64-bit words
Vector #(8, Bit #(64)) line_dwords = unpack (pack (rg_cacheline_cache_data));
Bit #(3) dword_in_line = addr [5:3];
Bit #(64) dword = line_dwords [dword_in_line];
// Send response to external client
AXI4_Rd_Data #(Wd_Id, Wd_Data, Wd_User)
rd_data = AXI4_Rd_Data {rid: 0, // TODO: fixup
rdata: dword,
rresp: axi4_resp_okay,
rlast: True,
ruser: ?};
axi4_slave_xactor.i_rd_data.enq (rd_data);
if (verbosity >= 2) begin
$display ("%0d: %m.rl_handle_MemLoader_ld_req: addr %0h", cur_cycle, rd_addr.araddr);
$display (" dword: %0h", dword);
end
endrule
// ----------------------------------------------------------------
// Miss and writeback processing
// Maintain dirty delay countdown
rule rl_cacheline_cache_writeback_dirty_delay ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
&& (rg_cacheline_cache_dirty_delay != 0));
rg_cacheline_cache_dirty_delay <= rg_cacheline_cache_dirty_delay - 1;
endrule
function Action fa_writeback;
action
dmaRqT req = DmaRq {addr: rg_cacheline_cache_addr,
byteEn: replicate (True), // Write all bytes
data: rg_cacheline_cache_data,
id: tagged MemLoader (?) // TODO: use wr_addr.awid?
};
llc.memReq.enq (req);
// $display ("%0d: %m.fa_writeback line at %0h", cur_cycle, rg_cacheline_cache_addr);
// $display (" data %0128h", rg_cacheline_cache_data);
endaction
endfunction
// Initiate writeback if dirty for full delay
rule rl_cacheline_cache_writeback_dirty_aged ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
&& (rg_cacheline_cache_dirty_delay == 0));
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_writeback_dirty_aged.", cur_cycle);
$display (" Old line addr %0h", rg_cacheline_cache_addr);
end
fa_writeback;
rg_cacheline_cache_state <= CACHELINE_CACHE_WRITING_BACK;
endrule
// Initiate writeback if dirty and next request is store-miss
rule rl_cacheline_cache_writeback_st_miss ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_wr_addr.first.awaddr,
rg_cacheline_cache_addr)));
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_writeback_st_miss.", cur_cycle);
$display (" Old line addr %0h", rg_cacheline_cache_addr);
$display (" New addr %0h", axi4_slave_xactor.o_wr_addr.first.awaddr);
end
fa_writeback;
rg_cacheline_cache_state <= CACHELINE_CACHE_WRITING_BACK;
endrule
// Initiate writeback if dirty and next request is load-miss
rule rl_cacheline_cache_writeback_ld_miss ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_rd_addr.first.araddr,
rg_cacheline_cache_addr)));
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_writeback_ld_miss.", cur_cycle);
$display (" Old line addr %0h", rg_cacheline_cache_addr);
$display (" New addr %0h", axi4_slave_xactor.o_wr_addr.first.awaddr);
end
fa_writeback;
rg_cacheline_cache_state <= CACHELINE_CACHE_WRITING_BACK;
endrule
// Finish writeback
rule rl_cacheline_cache_writeback_finish (llc.respSt.first matches tagged MemLoader .id
&&& (rg_cacheline_cache_state == CACHELINE_CACHE_WRITING_BACK));
let resp = llc.respSt.first;
llc.respSt.deq;
rg_cacheline_cache_state <= CACHELINE_CACHE_CLEAN;
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_writeback_finish. Line addr %0h",
cur_cycle, rg_cacheline_cache_addr);
$display (" Line data %0h", rg_cacheline_cache_data);
end
endrule
function Action fa_initiate_reload (Addr addr);
action
let line_addr = fn_align_addr_to_line (addr);
dmaRqT req = DmaRq {addr: line_addr,
byteEn: replicate (False), // all False means 'read'
data: ?,
id: tagged MemLoader (?)}; // TODO: change uniformly to wr_addr.awid
llc.memReq.enq (req);
rg_cacheline_cache_addr <= line_addr;
if (verbosity >= 2) begin
$display (" fa_initiate_reload: line_addr %0h", line_addr);
end
endaction
endfunction
// Initiate reload when cacheline_cache is clean on store-miss
rule rl_cacheline_cache_reload_req_st ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_wr_addr.first.awaddr,
rg_cacheline_cache_addr)));
let addr = axi4_slave_xactor.o_wr_addr.first.awaddr;
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_reload_req_st for addr %0h", cur_cycle, addr);
end
fa_initiate_reload (addr);
rg_cacheline_cache_state <= CACHELINE_CACHE_RELOADING;
endrule
// Initiate reload when cacheline_cache is clean on load-miss
rule rl_cacheline_cache_reload_req_ld ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
&& (! fn_addr_is_in_line (axi4_slave_xactor.o_rd_addr.first.araddr,
rg_cacheline_cache_addr)));
let addr = axi4_slave_xactor.o_rd_addr.first.araddr;
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_reload_req_ld for addr %0h", cur_cycle, addr);
end
fa_initiate_reload (addr);
rg_cacheline_cache_state <= CACHELINE_CACHE_RELOADING;
endrule
// Finish reload
rule rl_cacheline_cache_reload_finish (llc.respLd.first.id matches tagged MemLoader .id
&&& (rg_cacheline_cache_state == CACHELINE_CACHE_RELOADING));
let resp = llc.respLd.first;
llc.respLd.deq;
rg_cacheline_cache_state <= CACHELINE_CACHE_CLEAN;
rg_cacheline_cache_data <= resp.data;
if (verbosity >= 2) begin
$display ("%0d: %m.rl_cacheline_cache_reload_finish. Line addr %0h", cur_cycle, rg_cacheline_cache_addr);
$display (" Line data %0h", resp.data);
end
endrule
// ================================================================
// Transactions from the TLB
// Expecting only LOAD requests from TLB
// This section is unchanged from the original riscy-ooo module.
// helper functions for cross bar
function XBarDstInfo#(Bit#(0), Tuple2#(CoreId, TlbMemReq)) getTlbDst(CoreId core, TlbMemReq r);
return XBarDstInfo {idx: 0, data: tuple2(core, r)};
@@ -83,24 +386,13 @@ module mkLLCDmaConnect#(
};
endfunction
// send req to LLC
rule sendMemLoaderReqToLLC;
memLoader.memReq.deq;
let r = memLoader.memReq.first;
dmaRqT req = DmaRq {
addr: r.addr,
byteEn: r.byteEn,
data: r.data,
id: MemLoader (r.id)
};
llc.memReq.enq(req);
if(verbose) begin
$display("[LLCDmaConnnect sendMemLoaderReqToLLC] ",
fshow(r), " ; ", fshow(req));
end
endrule
// Prioritize external mem client over Tlb
(* descending_urgency = "rl_cacheline_cache_writeback_dirty_aged, sendTlbReqToLLC" *)
(* descending_urgency = "rl_cacheline_cache_writeback_st_miss, sendTlbReqToLLC" *)
(* descending_urgency = "rl_cacheline_cache_writeback_ld_miss, sendTlbReqToLLC" *)
(* descending_urgency = "rl_cacheline_cache_reload_req_st, sendTlbReqToLLC" *)
(* descending_urgency = "rl_cacheline_cache_reload_req_ld, sendTlbReqToLLC" *)
(* descending_urgency = "sendMemLoaderReqToLLC, sendTlbReqToLLC" *)
rule sendTlbReqToLLC;
let {c, r} <- toGet(tlbQ).get;
let req = getTlbDmaReq(c, r);
@@ -110,16 +402,6 @@ module mkLLCDmaConnect#(
end
endrule
// send Ld resp from LLC
rule sendLdRespToMemLoader(llc.respLd.first.id matches tagged MemLoader .id);
llc.respLd.deq;
if(verbose) begin
$display("[LLCDmaConnect sendLdRespToMemLoader] ",
fshow(llc.respLd.first));
end
doAssert(False, "No mem loader ld");
endrule
rule sendLdRespToTlb(llc.respLd.first.id matches tagged Tlb .id);
llc.respLd.deq;
let resp = llc.respLd.first;
@@ -133,16 +415,6 @@ module mkLLCDmaConnect#(
end
endrule
// send St resp from LLC
rule sendStRespToMemLoader(llc.respSt.first matches tagged MemLoader .id);
llc.respSt.deq;
memLoader.respSt.enq(id);
if(verbose) begin
$display("[LLCDmaConnect sendStRespToMemLoader] ",
fshow(llc.respSt.first));
end
endrule
rule sendStRespToTlb(llc.respSt.first matches tagged Tlb .id);
llc.respSt.deq;
if(verbose) begin
@@ -150,4 +422,9 @@ module mkLLCDmaConnect#(
end
doAssert(False, "No TLB st");
endrule
// ================================================================
// INTERFACE
return axi4_slave_xactor.axi_side;
endmodule

View File

@@ -30,7 +30,7 @@ import Types::*;
import CCTypes::*;
import DefaultValue::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import MshrDeadlockChecker::*;
import LLCRqMshr::*;

View File

@@ -29,7 +29,7 @@ import Connectable::*;
import GetPut::*;
import Assert::*;
import CacheUtils::*;
import Fifo::*;
import Fifos::*;
import Types::*;
import ProcTypes::*;
import CCTypes::*;

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2018 Massachusetts Institute of Technology
// Portions copyright (c) 2019-2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -58,7 +59,7 @@ DataAlignedAddr mainMemBaseAddr = getDataAlignedAddr(soc_map_struct.main_mem_a
// upper bound addr (bound itself is invalid addr) for each MMIO reg/device
// (aligned to Data)
DataAlignedAddr mainMemBoundAddr = (mainMemBaseAddr +
getDataAlignedAddr(soc_map_struct.main_mem_addr_size));
getDataAlignedAddr(soc_map_struct.main_mem_addr_size));
DataAlignedAddr msipBoundAddr = msipBaseAddr +
fromInteger(valueof(TDiv#(CoreNum, 2)));
DataAlignedAddr mtimecmpBoundAddr = mtimecmpBaseAddr +

View File

@@ -26,7 +26,7 @@ import ConfigReg::*;
import ProcTypes::*;
import MMIOAddrs::*;
import CacheUtils::*;
import Fifo::*;
import Fifos::*;
import Amo::*;
import MMIOInst::*;

View File

@@ -23,7 +23,7 @@
import Vector::*;
import ConfigReg::*;
import Fifo::*;
import Fifos::*;
import Types::*;
import ProcTypes::*;
import CCTypes::*;

View File

@@ -29,7 +29,7 @@ import Connectable::*;
import FShow::*;
import FIFO::*;
import Vector::*;
import Fifo::*;
import Fifos::*;
import Types::*;
import ProcTypes::*;
import CCTypes::*;

View File

@@ -21,7 +21,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Fifo::*;
import Fifos::*;
typedef union tagged {
reqT Req;

View File

@@ -25,7 +25,7 @@
import BuildVector::*;
import Types::*;
import ProcTypes::*;
import Fifo::*;
import Fifos::*;
import FIFO::*;
import XilinxIntMul::*;
import XilinxIntDiv::*;

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Portions (c) 2020 Bluespec, Inc.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +9,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -184,6 +185,7 @@ typedef enum {
Fnmsub = 7'b1001011,
Fnmadd = 7'b1001111,
OpFp = 7'b1010011,
OpCHERI = 7'b1011011,
Branch = 7'b1100011,
Jalr = 7'b1100111,
Jal = 7'b1101111,
@@ -194,7 +196,7 @@ function Opcode unpackOpcode(Bit#(7) x);
return (case(x)
pack(Opcode'(Load )): (Load );
pack(Opcode'(LoadFp )): (LoadFp );
pack(Opcode'(MiscMem)): (MiscMem);
pack(Opcode'(MiscMem)): (MiscMem);
pack(Opcode'(OpImm )): (OpImm );
pack(Opcode'(Auipc )): (Auipc );
pack(Opcode'(OpImm32)): (OpImm32);
@@ -275,8 +277,22 @@ typedef enum {
// sanctum user CSR
CSRtrng = 12'hcc0, // random number for secure boot
`endif
CSRtselect = 12'h7A0, // Debug/trace tselect
CSRtdata1 = 12'h7A1, // Debug/trace tdata1
CSRtdata2 = 12'h7A2, // Debug/trace tdata2
CSRtdata3 = 12'h7A3, // Debug/trace tdata3
`ifdef INCLUDE_GDB_CONTROL
CSRdcsr = 12'h7B0, // Debug control and status
CSRdpc = 12'h7B1, // Debug PC
CSRdscratch0 = 12'h7B2, // Debug scratch0
CSRdscratch1 = 12'h7B3, // Debug scratch1
`endif
// CSR that catches all the unimplemented CSRs. To avoid exception on this,
// make it a user non-standard read/write CSR.
// Bluespec: in RenameStage.getTrap(), we force this to be a csr_access_trap
CSRnone = 12'h8ff
} CSR deriving(Bits, Eq, FShow);
@@ -332,6 +348,19 @@ function CSR unpackCSR(Bit#(12) x);
pack(CSR'(CSRmspec )): (CSRmspec );
pack(CSR'(CSRtrng )): (CSRtrng );
`endif
pack(CSR'(CSRtselect )): (CSRtselect );
pack(CSR'(CSRtdata1 )): (CSRtdata1 );
pack(CSR'(CSRtdata2 )): (CSRtdata2 );
pack(CSR'(CSRtdata3 )): (CSRtdata3 );
`ifdef INCLUDE_GDB_CONTROL
pack(CSR'(CSRdcsr )): (CSRdcsr );
pack(CSR'(CSRdpc )): (CSRdpc );
pack(CSR'(CSRdscratch0 )): (CSRdscratch0 );
pack(CSR'(CSRdscratch1 )): (CSRdscratch1 );
`endif
default : (CSRnone );
endcase);
endfunction
@@ -355,6 +384,7 @@ typedef enum {
FenceI, SFence,
Ecall, Ebreak,
Sret, Mret, // do not support URET
CapInspect, CapModify,
Interrupt // we may turn an inst to an interrupt in implementation
} IType deriving(Bits, Eq, FShow);
@@ -373,16 +403,40 @@ typedef enum {
typedef enum {
SetOffset, IncOffset
} ModifyOffsetFunc
} ModifyOffsetFunc deriving(Bits, Eq, FShow);
typedef enum {
SetBounds, SetBoundsExact, CRRL, CRAM
} SetBoundsFunc
} SetBoundsFunc deriving(Bits, Eq, FShow);
typedef union tagged {
Bool ModifyOffset;
Bool SetBounds;
} AluCapFunc deriving(Bits, Eq, FShow);
void SpecialRW;
void SetAddr;
void Seal;
void Unseal;
void AndPerm;
void SetFlags;
void BuildCap;
void CMove;
void ClearTag;
void CJALR;
} CapModifyFunc deriving(Bits, Eq, FShow);
typedef union tagged {
void TestSubset;
void CSub;
void GetBase;
void GetTag;
void GetSealed;
void GetAddr;
void GetOffset;
void GetFlags;
void GetPerm;
void GetType;
void ToPtr;
} CapInspectFunc deriving(Bits, Eq, FShow);
typedef enum {Mul, Mulh, Div, Rem} MulDivFunc deriving(Bits, Eq, FShow);
@@ -426,6 +480,8 @@ typedef union tagged {
MemInst Mem;
MulDivInst MulDiv;
FpuInst Fpu;
CapInspectFunc CapInspect;
CapModifyFunc CapModify;
void Other;
} ExecFunc deriving(Bits, Eq, FShow);
@@ -457,33 +513,6 @@ typedef enum {
CHERIFault = 5'd28
} Exception deriving(Bits, Eq, FShow);
typedef enum {
None = 5'd0,
LengthViolation = 5'd1,
TagViolation = 5'd2,
SealViolation = 5'd3,
TypeViolation = 5'd4,
CallTrap = 5'd5,
ReturnTrap = 5'd6,
StackUnderflow = 5'd7,
MMUStoreCapProhibit = 5'd8,
RepresentViolation = 5'd9,
UnalignedBase = 5'd10,
// 5'd11 - 5'd15 reserved
GlobalViolation = 5'd16,
PermitXViolation = 5'd17,
PermitRViolation = 5'd18,
PermitWViolation = 5'd19,
PermitRCapViolation = 5'd20,
PermitWCapViolation = 5'd21,
PermitWLocalCapViolation = 5'd22,
PermitSealViolation = 5'd23,
PermitASRViolation = 5'd24,
PermitCCallViolation = 5'd25,
PermitUnsealViolation = 5'd26,
PermitSetCIDViolation = 5'd27
// 5'd28 - 5'd31 reserved
typedef enum {
UserSoftware = 4'd0,
SupervisorSoftware = 4'd1,
@@ -493,13 +522,20 @@ typedef enum {
MachineTimer = 4'd7,
UserExternal = 4'd8,
SupervisorExternel = 4'd9,
MachineExternal = 4'd11,
MachineExternal = 4'd11
`ifdef INCLUDE_GDB_CONTROL
, DebugHalt = 4'd14, // Debugger halt command (^C in GDB)
DebugStep = 4'd15 // dcsr.step is set and 1 instr has been processed
`endif
DebugExternal = 4'd14 // Bluespec: for debug mode
} Interrupt deriving(Bits, Eq, FShow);
// typedef 12 InterruptNum;
typedef 15 InterruptNum; // Bluespec: extended to 15 bits for debug interrupt
`ifdef INCLUDE_GDB_CONTROL
typedef 16 InterruptNum; // With debugger
`else
typedef 12 InterruptNum; // Without debugger
`endif
// Traps are either an exception or an interrupt
typedef union tagged {
@@ -627,7 +663,7 @@ typedef struct {
Bool b_points_to_a_type;
Bool b_addr_valid_type;
Bool b_perm_subset_a;
} CapChecks;
} CapChecks deriving(Bits, Eq, FShow);
typedef struct {
IType iType;
@@ -995,7 +1031,7 @@ function Fmt showInst(Instruction inst);
privMRET: fshow("mret");
privWFI: fshow("wfi");
default: (
funct7 == privSFENCEVMA ?
funct7 == privSFENCEVMA ?
(fshow("sfence.vma ") + fshow(rs1) + fshow(" ") + fshow(rs2)) :
fshow("SYSTEM not implemented")
);
@@ -1012,4 +1048,3 @@ function Fmt showInst(Instruction inst);
return ret;
endfunction

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2017 Massachusetts Institute of Technology
//
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -8,10 +8,10 @@
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -33,6 +33,10 @@ import RevertingVirtualReg::*;
`ifdef RVFI_DII
import RVFI_DII_Types::*;
`endif
import CHERICap::*;
import CHERICC_Fat::*;
import Cur_Cycle :: *;
// right after execution, full_result has more up-to-date data (e.g. ppc of mispredicted branch)
// some parts of full_result are for verification
@@ -42,10 +46,10 @@ import RVFI_DII_Types::*;
// csrData is only used by iType = Csr
// vaddr is only used by mem inst in page fault
typedef union tagged {
Addr PPC; // at default store ppc
Addr VAddr; // for mem inst, store vaddr
CapPipe PPC; // at default store ppc
CapPipe VAddr; // for mem inst, store vaddr
Data CSRData; // for Csr inst, store csr_data
} PPCVAddrCSRData deriving(Bits, Eq, FShow);
} PPCVAddrCSRData deriving(Bits, FShow);
`ifdef RVFI
typedef struct {
@@ -55,9 +59,16 @@ typedef struct {
`endif
typedef struct {
Addr pc;
CapPipe pc;
Bit #(32) orig_inst; // original 16b or 32b instruction ([1:0] will distinguish 16b or 32b)
IType iType;
Maybe#(ArchRIndx) dst; // Invalid, GPR or FPR destination ("Rd")
Data dst_data; // Output of instruction into destination register
`ifdef INCLUDE_TANDEM_VERIF
// Store-data, for those mem instrs that store data
Data store_data;
ByteEn store_data_BE;
`endif
Maybe#(CSR) csr;
Bool claimed_phy_reg; // whether we need to commmit renaming
Maybe#(Trap) trap;
@@ -91,7 +102,7 @@ typedef struct {
`ifdef RVFI
ExtraTraceBundle traceBundle;
`endif
} ToReorderBuffer deriving(Bits, Eq, FShow);
} ToReorderBuffer deriving(Bits, FShow);
typedef enum {
NotDone,
@@ -100,8 +111,11 @@ typedef enum {
interface Row_setExecuted_doFinishAlu;
method Action set(
Data dst_data,
Maybe#(Data) csrData,
ControlFlow cf
ControlFlow cf,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
`endif
@@ -109,7 +123,7 @@ interface Row_setExecuted_doFinishAlu;
endinterface
interface Row_setExecuted_doFinishFpuMulDiv;
method Action set(Bit#(5) fflags);
method Action set(Data dst_data, Bit#(5) fflags, Maybe#(Exception) cause, CapPipe pcc);
endinterface
interface ReorderBufferRowEhr#(numeric type aluExeNum, numeric type fpuMulDivExeNum);
@@ -130,11 +144,22 @@ interface ReorderBufferRowEhr#(numeric type aluExeNum, numeric type fpuMulDivExe
// faulting inst cannot have this set, since there is no access to
// perform), and non-MMIO St can become Executed (NOTE faulting
// instructions are not Executed, they are set at deqLSQ time)
method Action setExecuted_doFinishMem(Addr vaddr, Bool access_at_commit, Bool non_mmio_st_done
method Action setExecuted_doFinishMem(CapPipe vaddr,
Data store_data, ByteEn store_data_BE,
Bool access_at_commit, Bool non_mmio_st_done,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
, ExtraTraceBundle tb
`endif
);
`ifdef INCLUDE_TANDEM_VERIF
// Used after a Ld, Lr, Sc, Amo to record reg data
method Action setExecuted_doFinishMem_RegData (Data dst_data);
`endif
`ifdef INORDER_CORE
// in-order core sets LSQ tag after getting out of issue queue
method Action setLSQTag(LdStQTag t, Bool isFence);
@@ -152,9 +177,17 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
Add#(1, a__, aluExeNum), Add#(1, b__, fpuMulDivExeNum)
);
Integer trap_deq_port = 0;
Integer trap_deqLSQ_port = 0; // write trap
Integer trap_finishMem_port = 1; // write trap
Integer trap_enq_port = 2; // write trap
function Integer trap_finishAlu_port(Integer i) = i;
function Integer trap_finishFpuMulDiv_port(Integer i) = valueof(aluExeNum) + i;
Integer trap_deqLSQ_port = valueof(TAdd#(aluExeNum, TDiv#(aluExeNum,2)));
Integer trap_finishMem_port = valueof(TAdd#(aluExeNum, TDiv#(aluExeNum,2))); // write trap
Integer trap_enq_port = 1 + valueof(TAdd#(aluExeNum, TDiv#(aluExeNum,2)));
Integer pc_deq_port = 0;
function Integer pc_finishAlu_port(Integer i) = i;
Integer pc_deqLSQ_port = valueof(aluExeNum);
Integer pc_finishMem_port = valueof(aluExeNum);
Integer pc_enq_port = 1 + valueof(aluExeNum);
Integer pvc_deq_port = 0;
function Integer pvc_finishAlu_port(Integer i) = i; // write ppc_vaddr_csrData
@@ -198,13 +231,20 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
Integer sb_enq_port = 1; // write spec_bits
Integer sb_correctSpec_port = 2; // write spec_bits
Reg#(Addr) pc <- mkRegU;
Ehr#(TAdd#(2, aluExeNum), CapPipe) pc <- mkEhr(?);
Reg #(Bit #(32)) orig_inst <- mkRegU;
Reg#(IType) iType <- mkRegU;
Reg #(Maybe #(ArchRIndx)) rg_dst_reg <- mkRegU;
Reg #(Data) rg_dst_data <- mkRegU;
`ifdef INCLUDE_TANDEM_VERIF
Reg #(Data) rg_store_data <- mkRegU;
Reg #(ByteEn) rg_store_data_BE <- mkRegU;
`endif
Reg#(Maybe#(CSR)) csr <- mkRegU;
Reg#(Bool) claimed_phy_reg <- mkRegU;
Ehr#(3, Maybe#(Trap)) trap <- mkEhr(?);
Ehr#(3, Addr) tval <- mkEhr(?);
Ehr#(TAdd#(TAdd#(2, TDiv#(aluExeNum,2)), aluExeNum), Maybe#(Trap)) trap <- mkEhr(?);
Ehr#(3, Maybe#(Trap)) mem_early_trap <- mkEhr(?);
Ehr#(TAdd#(TAdd#(2, TDiv#(aluExeNum,2)), aluExeNum), Addr) tval <- mkEhr(?);
Ehr#(TAdd#(2, aluExeNum), PPCVAddrCSRData) ppc_vaddr_csrData <- mkEhr(?);
Ehr#(TAdd#(1, fpuMulDivExeNum), Bit#(5)) fflags <- mkEhr(?);
Reg#(Bool) will_dirty_fpu_state <- mkRegU;
@@ -228,27 +268,42 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
Wire#(Addr) predPcWire <- mkBypassWire;
(* fire_when_enabled, no_implicit_conditions *)
rule setPcWires;
predPcWire <= ppc_vaddr_csrData[0] matches tagged PPC .a ? a : 0;
predPcWire <= ppc_vaddr_csrData[0] matches tagged PPC .a ? getAddr(a) : 0;
endrule
Vector#(aluExeNum, Row_setExecuted_doFinishAlu) aluSetExe;
for(Integer i = 0; i < valueof(aluExeNum); i = i+1) begin
aluSetExe[i] = (interface Row_setExecuted_doFinishAlu;
method Action set(
Data dst_data,
Maybe#(Data) csrData,
ControlFlow cf
ControlFlow cf,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
`endif
);
// inst is done
rob_inst_state[state_finishAlu_port(i)] <= Executed;
rob_inst_state[state_finishAlu_port(i)] <= Executed;
// Destination register data, for Tandem Verification
rg_dst_data <= dst_data;
// update PPC or csrData (vaddr is always useless for ALU results)
if(csrData matches tagged Valid .d) begin
ppc_vaddr_csrData[pvc_finishAlu_port(i)] <= CSRData (d);
end
else begin
ppc_vaddr_csrData[pvc_finishAlu_port(i)] <= PPC (cf.nextPc);
ppc_vaddr_csrData[pvc_finishAlu_port(i)] <= PPC (setAddr(almightyCap, cf.nextPc).value);
end
CapPipe new_pcc = setAddrUnsafe(pcc, getAddr(pc[pc_finishAlu_port(i)]));
pc[pc_finishAlu_port(i)] <= new_pcc;
if (!isInBounds(new_pcc, False)) begin
trap[trap_finishAlu_port(i)] <= Valid (tagged Exception CHERIFault);
tval[trap_finishAlu_port(i)] <= tval[trap_finishAlu_port(i)];
end else if (cause matches tagged Valid .exp) begin
trap[trap_finishAlu_port(i)] <= Valid (tagged Exception exp);
tval[trap_finishAlu_port(i)] <= tval[trap_finishAlu_port(i)];
end
`ifdef RVFI
//$display("%t : traceBundle = ", $time(), fshow(tb), " in Row_setExecuted_doFinishAlu for %x", pc);
@@ -258,20 +313,30 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
endmethod
endinterface);
end
Vector#(fpuMulDivExeNum, Row_setExecuted_doFinishFpuMulDiv) fpuMulDivExe;
for(Integer i = 0; i < valueof(fpuMulDivExeNum); i = i+1) begin
fpuMulDivExe[i] = (interface Row_setExecuted_doFinishFpuMulDiv;
method Action set(Bit#(5) new_fflags);
method Action set(Data dst_data, Bit#(5) new_fflags, Maybe#(Exception) cause, CapPipe pcc);
// inst is done
rob_inst_state[state_finishFpuMulDiv_port(i)] <= Executed;
rob_inst_state[state_finishFpuMulDiv_port(i)] <= Executed;
rg_dst_data <= dst_data;
// update fflags
fflags[fflags_finishFpuMulDiv_port(i)] <= new_fflags;
CapPipe new_pcc = setAddrUnsafe(pcc, getAddr(pc[pc_finishAlu_port(i)]));
if (!isInBounds(new_pcc, False)) begin
trap[trap_finishFpuMulDiv_port(i)] <= Valid (tagged Exception CHERIFault);
tval[trap_finishFpuMulDiv_port(i)] <= tval[trap_finishAlu_port(i)];
end else if (cause matches tagged Valid .exp) begin
trap[trap_finishFpuMulDiv_port(i)] <= Valid (tagged Exception exp);
tval[trap_finishFpuMulDiv_port(i)] <= tval[trap_finishAlu_port(i)];
end
//pc[pc_finishFpuMulDiv_port(i)] <= newPcc; //XXX add pcc checks on FPU instructions
endmethod
endinterface);
end
method Addr getOrigPC = pc;
method Addr getOrigPC = getAddr(pc[0]);
method Addr getOrigPredPC = predPcWire;
method Bit #(32) getOrig_Inst = orig_inst;
@@ -279,9 +344,13 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
interface setExecuted_doFinishFpuMulDiv = fpuMulDivExe;
method Action setExecuted_doFinishMem(Addr vaddr, Bool access_at_commit, Bool non_mmio_st_done
method Action setExecuted_doFinishMem(CapPipe vaddr,
Data store_data, ByteEn store_data_BE,
Bool access_at_commit, Bool non_mmio_st_done,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
, ExtraTraceBundle tb
`endif
);
doAssert(!(access_at_commit && non_mmio_st_done),
@@ -296,13 +365,34 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
`ifdef RVFI
//$display("%t : traceBundle = ", $time(), fshow(tb), " in setExecuted_doFinishMem for %x", pc);
traceBundle[pvc_finishMem_port] <= tb;
`endif
`ifdef INCLUDE_TANDEM_VERIF
// Store-data (for mem instrs that store data)
rg_store_data <= store_data;
rg_store_data_BE <= store_data_BE;
`endif
// update access at commit
memAccessAtCommit[accessCom_finishMem_port] <= access_at_commit;
// udpate non mmio st
nonMMIOStDone[nonMMIOSt_finishMem_port] <= non_mmio_st_done;
CapPipe new_pcc = setAddrUnsafe(pcc, getAddr(pc[pc_finishMem_port]));
pc[pc_finishMem_port] <= new_pcc;
if (!isInBounds(new_pcc, False)) begin
mem_early_trap[0] <= Valid (tagged Exception CHERIFault);
tval[trap_finishMem_port] <= tval[trap_finishMem_port];
end else if (cause matches tagged Valid .exp) begin
mem_early_trap[0] <= Valid (tagged Exception exp);
tval[trap_finishMem_port] <= tval[trap_finishMem_port];
end
endmethod
`ifdef INCLUDE_TANDEM_VERIF
// Used after a Ld, Lr, Sc, Amo to record reg data
method Action setExecuted_doFinishMem_RegData (Data dst_data);
rg_dst_data <= dst_data;
endmethod
`endif
`ifdef INORDER_CORE
method Action setLSQTag(LdStQTag t, Bool isFence);
lsqTag <= t;
@@ -312,9 +402,13 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
`endif
method Action write_enq(ToReorderBuffer x);
pc <= x.pc;
pc[pc_enq_port] <= x.pc;
orig_inst <= x.orig_inst;
iType <= x.iType;
rg_dst_reg <= x.dst;
// rg_dst_data will be written after inst execution
// rg_store_data will be written in Mem pipeline
// rg_store_data_BE will be written in Mem pipeline
csr <= x.csr;
claimed_phy_reg <= x.claimed_phy_reg;
trap[trap_enq_port] <= x.trap;
@@ -325,6 +419,7 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
rob_inst_state[state_enq_port] <= x.rob_inst_state;
epochIncremented <= x.epochIncremented;
spec_bits[sb_enq_port] <= x.spec_bits;
mem_early_trap[1] <= Invalid;
`ifdef INORDER_CORE
// in-order core enqs to LSQ later, so don't set LSQ tag; and other
// flags should default to false
@@ -352,9 +447,15 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
method ToReorderBuffer read_deq;
return ToReorderBuffer {
pc: pc,
orig_inst: orig_inst,
pc: pc[pc_deq_port],
orig_inst: orig_inst,
iType: iType,
dst: rg_dst_reg,
dst_data: rg_dst_data,
`ifdef INCLUDE_TANDEM_VERIF
store_data: rg_store_data,
store_data_BE: rg_store_data_BE,
`endif
csr: csr,
claimed_phy_reg: claimed_phy_reg,
trap: trap[trap_deq_port],
@@ -405,11 +506,10 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
//$display("%t: Wrote tb for deqLSQ ", $time(), fshow(tb));
`endif
// record trap
doAssert(!isValid(trap[trap_deqLSQ_port]), "cannot have trap");
if(cause matches tagged Valid .e) begin
trap[trap_deqLSQ_port] <= Valid (Exception (e));
// TODO: shouldn't we record tval here as well?
end
//doAssert(!isValid(trap[trap_deqLSQ_port]), "cannot have trap");
if (isValid(mem_early_trap[0])) trap[trap_deqLSQ_port] <= mem_early_trap[0];
else if(cause matches tagged Valid .e) trap[trap_deqLSQ_port] <= Valid (Exception (e));
// TODO: shouldn't we record tval here as well?
// record ld misspeculation
ldKilled[ldKill_deqLSQ_port] <= ld_killed;
endmethod
@@ -466,8 +566,11 @@ endinterface
interface ROB_setExecuted_doFinishAlu;
method Action set(InstTag x,
Data dst_data,
Maybe#(Data) csrData,
ControlFlow cf
ControlFlow cf,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
`endif
@@ -475,7 +578,7 @@ interface ROB_setExecuted_doFinishAlu;
endinterface
interface ROB_setExecuted_doFinishFpuMulDiv;
method Action set(InstTag x, Bit#(5) fflags);
method Action set(InstTag x, Data dst_data, Bit#(5) fflags, Maybe#(Exception) cause, CapPipe pcc);
endinterface
interface ROB_getOrigPC;
@@ -496,7 +599,7 @@ interface SupReorderBuffer#(numeric type aluExeNum, numeric type fpuMulDivExeNum
interface Vector#(SupSize, ROB_DeqPort) deqPort;
// record that we have notified LSQ about inst reaching commit
// record that we have notified LSQ about inst reaching commit
method Action setLSQAtCommitNotified(InstTag x);
// deqLSQ rules set ROB state
method Action setExecuted_deqLSQ(InstTag x, Maybe#(Exception) cause, Maybe#(LdKilledBy) ld_killed
@@ -508,11 +611,22 @@ interface SupReorderBuffer#(numeric type aluExeNum, numeric type fpuMulDivExeNum
interface Vector#(aluExeNum, ROB_setExecuted_doFinishAlu) setExecuted_doFinishAlu;
interface Vector#(fpuMulDivExeNum, ROB_setExecuted_doFinishFpuMulDiv) setExecuted_doFinishFpuMulDiv;
// doFinishMem, after addr translation
method Action setExecuted_doFinishMem(InstTag x, Addr vaddr, Bool access_at_commit, Bool non_mmio_st_done
method Action setExecuted_doFinishMem(InstTag x,
CapPipe vaddr,
Data store_data, ByteEn store_data_BE,
Bool access_at_commit, Bool non_mmio_st_done,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
, ExtraTraceBundle tb
`endif
);
`ifdef INCLUDE_TANDEM_VERIF
// Used after a Ld, Lr, Sc, Amo to record reg data
method Action setExecuted_doFinishMem_RegData (InstTag x, Data dst_data);
`endif
`ifdef INORDER_CORE
// in-order core sets LSQ tag after getting out of issue queue
method Action setLSQTag(InstTag x, LdStQTag t, Bool isFence);
@@ -784,7 +898,7 @@ module mkSupReorderBuffer#(
function Bool getDepOn(Integer i) = row[w][i].dependsOn_wrongSpec(specTag);
depVec[w] = map(getDepOn, genVector);
end
if (verbose)
if (verbose)
$display("[ROB incorrectSpec] ",
fshow(specTag), " ; ",
fshow(killInstTag), " ; ",
@@ -992,8 +1106,11 @@ module mkSupReorderBuffer#(
aluSetExeIfc[i] = (interface ROB_setExecuted_doFinishAlu;
method Action set(
InstTag x,
Data dst_data,
Maybe#(Data) csrData,
ControlFlow cf
ControlFlow cf,
Maybe#(Exception) cause,
CapPipe pcc
`ifdef RVFI
, ExtraTraceBundle tb
`endif
@@ -1001,8 +1118,11 @@ module mkSupReorderBuffer#(
all(id, readVReg(setExeAlu_SB_enq)) // ordering: < enq
);
row[x.way][x.ptr].setExecuted_doFinishAlu[i].set(
dst_data,
csrData,
cf
cf,
cause,
pcc
`ifdef RVFI
, tb
`endif
@@ -1015,11 +1135,11 @@ module mkSupReorderBuffer#(
for(Integer i = 0; i < valueof(fpuMulDivExeNum); i = i+1) begin
fpuMulDivSetExeIfc[i] = (interface ROB_setExecuted_doFinishFpuMulDiv;
method Action set(
InstTag x, Bit#(5) fflags
InstTag x, Data dst_data, Bit#(5) fflags, Maybe#(Exception) cause, CapPipe pcc
) if(
all(id, readVReg(setExeFpuMulDiv_SB_enq)) // ordering: < enq
);
row[x.way][x.ptr].setExecuted_doFinishFpuMulDiv[i].set(fflags);
row[x.way][x.ptr].setExecuted_doFinishFpuMulDiv[i].set(dst_data, fflags, cause, pcc);
endmethod
endinterface);
end
@@ -1095,20 +1215,31 @@ module mkSupReorderBuffer#(
interface setExecuted_doFinishFpuMulDiv = fpuMulDivSetExeIfc;
method Action setExecuted_doFinishMem(
InstTag x, Addr vaddr, Bool access_at_commit, Bool non_mmio_st_done
InstTag x, CapPipe vaddr, Data store_data, ByteEn store_data_BE, Bool access_at_commit,
Bool non_mmio_st_done, Maybe#(Exception) cause, CapPipe pcc
`ifdef RVFI
, tb
`endif
) if(
all(id, readVReg(setExeMem_SB_enq)) // ordering: < enq
);
row[x.way][x.ptr].setExecuted_doFinishMem(vaddr, access_at_commit, non_mmio_st_done
row[x.way][x.ptr].setExecuted_doFinishMem(vaddr,
store_data, store_data_BE,
access_at_commit, non_mmio_st_done,
cause, pcc
`ifdef RVFI
, tb
, tb
`endif
);
endmethod
`ifdef INCLUDE_TANDEM_VERIF
// Used after a Ld, Lr, Sc, Amo to record reg data
method Action setExecuted_doFinishMem_RegData (InstTag x, Data dst_data);
row[x.way][x.ptr].setExecuted_doFinishMem_RegData (dst_data);
endmethod
`endif
`ifdef INORDER_CORE
method Action setLSQTag(InstTag x, LdStQTag t, Bool isFence);
row[x.way][x.ptr].setLSQTag(t, isFence);

View File

@@ -24,7 +24,7 @@
`include "ProcConfig.bsv"
import Vector::*;
import Fifo::*;
import Fifos::*;
import ProcTypes::*;
import CsrFile::*; // for mkReadOnlyReg
import Ehr::*;

View File

@@ -33,6 +33,7 @@ import HasSpecBits::*;
import SpecFifo::*;
import StoreBuffer::*;
import Exec::*;
import FP_Utils::*;
// I don't want to export auxiliary functions, so manually export all types
export LdQMemFunc(..);
@@ -279,6 +280,9 @@ typedef struct {
typedef struct {
Bool wrongPath;
Maybe#(PhyDst) dst;
`ifdef INCLUDE_TANDEM_VERIF
InstTag instTag; // For recording Ld data in ROB
`endif
Data data;
} LSQRespLdResult deriving(Bits, Eq, FShow);
@@ -1974,6 +1978,9 @@ module mkSplitLSQ(SplitLSQ);
let res = LSQRespLdResult {
wrongPath: False,
dst: Invalid,
`ifdef INCLUDE_TANDEM_VERIF
instTag: ld_instTag [t], // For recording Ld data in ROB
`endif
data: ?
};
if(ld_waitWPResp_resp[t]) begin
@@ -1993,9 +2000,20 @@ module mkSplitLSQ(SplitLSQ);
// mark load as done, and shift resp
ld_done_resp[t] <= True;
res.wrongPath = False;
// nirajns: checking if this is a 32-bit load response to a FPR
// In that case, the data needs to be nanboxed before writing to
// the register files as the Toooba FPR is 64-bit
let bEn = ld_byteEn[t];
let dst = ld_dst[t];
let is32BitLd = (bEn[3] && !bEn[7]);
res.dst = ld_dst[t];
res.data = gatherLoad(ld_paddr_resp[t], ld_byteEn[t],
ld_unsigned[t], alignedData);
if (dst.Valid.isFpuReg && is32BitLd)
res.data = fv_nanbox (gatherLoad(ld_paddr_resp[t], ld_byteEn[t],
ld_unsigned[t], alignedData));
else
res.data = gatherLoad(ld_paddr_resp[t], ld_byteEn[t],
ld_unsigned[t], alignedData);
end
if(verbose) begin
$display("[LSQ - respLd] ", fshow(t), "; ", fshow(alignedData),

View File

@@ -24,7 +24,7 @@
import Vector::*;
import Assert::*;
import Ehr::*;
import Fifo::*;
import Fifos::*;
import Types::*;
import ProcTypes::*;
import TlbTypes::*;