VX_lsu_slice.sv
内存调度器
wire lsu_mem_req_valid;
wire lsu_mem_req_rw;
wire [NUM_LANES-1:0] lsu_mem_req_mask;
wire [NUM_LANES-1:0][LSU_WORD_SIZE-1:0] lsu_mem_req_byteen;
wire [NUM_LANES-1:0][LSU_ADDR_WIDTH-1:0] lsu_mem_req_addr;
wire [NUM_LANES-1:0][`ADDR_TYPE_WIDTH-1:0] lsu_mem_req_atype;
wire [NUM_LANES-1:0][(LSU_WORD_SIZE*8)-1:0] lsu_mem_req_data;
wire [LSU_TAG_WIDTH-1:0] lsu_mem_req_tag;
wire lsu_mem_req_ready;
wire lsu_mem_rsp_valid;
wire [NUM_LANES-1:0] lsu_mem_rsp_mask;
wire [NUM_LANES-1:0][(LSU_WORD_SIZE*8)-1:0] lsu_mem_rsp_data;
wire [LSU_TAG_WIDTH-1:0] lsu_mem_rsp_tag;
wire lsu_mem_rsp_ready;
`RESET_RELAY (mem_scheduler_reset, reset);
VX_mem_scheduler #(
.INSTANCE_ID ($sformatf("%s-scheduler", INSTANCE_ID)),
.CORE_REQS (NUM_LANES),
.MEM_CHANNELS(NUM_LANES),
.WORD_SIZE (LSU_WORD_SIZE),
.LINE_SIZE (LSU_WORD_SIZE),
.ADDR_WIDTH (LSU_ADDR_WIDTH),
.ATYPE_WIDTH (`ADDR_TYPE_WIDTH),
.TAG_WIDTH (TAG_WIDTH),
.CORE_QUEUE_SIZE (`LSUQ_IN_SIZE),
.MEM_QUEUE_SIZE (`LSUQ_OUT_SIZE),
.UUID_WIDTH (`UUID_WIDTH),
.RSP_PARTIAL (1),
.MEM_OUT_BUF (0),
.CORE_OUT_BUF(0)
) mem_scheduler (
.clk (clk),
.reset (mem_scheduler_reset),
// Input request
.core_req_valid (mem_req_valid),
.core_req_rw (mem_req_rw),
.core_req_mask (mem_req_mask),
.core_req_byteen(mem_req_byteen),
.core_req_addr (mem_req_addr),
.core_req_atype (mem_req_atype),
.core_req_data (mem_req_data),
.core_req_tag (mem_req_tag),
.core_req_ready (mem_req_ready),
`UNUSED_PIN (core_req_empty),
`UNUSED_PIN (core_write_notify),
// Output response
.core_rsp_valid (mem_rsp_valid),
.core_rsp_mask (mem_rsp_mask),
.core_rsp_data (mem_rsp_data),
.core_rsp_tag (mem_rsp_tag),
.core_rsp_sop (mem_rsp_sop),
.core_rsp_eop (mem_rsp_eop),
.core_rsp_ready (mem_rsp_ready),
// Memory request
.mem_req_valid (lsu_mem_req_valid),
.mem_req_rw (lsu_mem_req_rw),
.mem_req_mask (lsu_mem_req_mask),
.mem_req_byteen (lsu_mem_req_byteen),
.mem_req_addr (lsu_mem_req_addr),
.mem_req_atype (lsu_mem_req_atype),
.mem_req_data (lsu_mem_req_data),
.mem_req_tag (lsu_mem_req_tag),
.mem_req_ready (lsu_mem_req_ready),
// Memory response
.mem_rsp_valid (lsu_mem_rsp_valid),
.mem_rsp_mask (lsu_mem_rsp_mask),
.mem_rsp_data (lsu_mem_rsp_data),
.mem_rsp_tag (lsu_mem_rsp_tag),
.mem_rsp_ready (lsu_mem_rsp_ready)
);
assign lsu_mem_if.req_valid = lsu_mem_req_valid;
assign lsu_mem_if.req_data.mask = lsu_mem_req_mask;
assign lsu_mem_if.req_data.rw = lsu_mem_req_rw;
assign lsu_mem_if.req_data.byteen = lsu_mem_req_byteen;
assign lsu_mem_if.req_data.addr = lsu_mem_req_addr;
assign lsu_mem_if.req_data.atype = lsu_mem_req_atype;
assign lsu_mem_if.req_data.data = lsu_mem_req_data;
assign lsu_mem_if.req_data.tag = lsu_mem_req_tag;
assign lsu_mem_req_ready = lsu_mem_if.req_ready;
assign lsu_mem_rsp_valid = lsu_mem_if.rsp_valid;
assign lsu_mem_rsp_mask = lsu_mem_if.rsp_data.mask;
assign lsu_mem_rsp_data = lsu_mem_if.rsp_data.data;
assign lsu_mem_rsp_tag = lsu_mem_if.rsp_data.tag;
assign lsu_mem_if.rsp_ready = lsu_mem_rsp_ready;
wire [`UUID_WIDTH-1:0] rsp_uuid;
wire [`NW_WIDTH-1:0] rsp_wid;
wire [`PC_BITS-1:0] rsp_pc;
wire rsp_wb;
wire [`NR_BITS-1:0] rsp_rd;
wire [`INST_LSU_BITS-1:0] rsp_op_type;
wire [NUM_LANES-1:0][REQ_ASHIFT-1:0] rsp_align;
wire [PID_WIDTH-1:0] rsp_pid;
`UNUSED_VAR (rsp_op_type)
这段代码实现了一个LSU(Load/Store Unit)模块的内存请求和响应处理逻辑。它包括信号定义、内存调度器实例化、信号赋值以及内存响应标签的解包。
主要功能
- 信号定义:定义了与内存请求和响应相关的信号,包括请求有效性、读写标志、掩码、字节使能、地址、数据和标签等。
- 内存调度器实例化:实例化了
VX_mem_scheduler
模块,用于协调内存请求和响应的调度。 - 信号赋值:将内部信号赋值给接口信号,以便与外部模块进行通信。
- 内存响应标签解包:将内存响应标签解包为各个字段,以便进一步处理。
接口描述
-
输入接口:
core_req_valid
:内存请求有效信号。core_req_rw
:读写标志。core_req_mask
:请求掩码。core_req_byteen
:字节使能信号。core_req_addr
:请求地址。core_req_atype
:地址类型。core_req_data
:请求数据。core_req_tag
:请求标签。core_req_ready
:内存调度器是否准备好接收请求。
-
输出接口:
core_rsp_valid
:内存响应有效信号。core_rsp_mask
:响应掩码。core_rsp_data
:响应数据。core_rsp_tag
:响应标签。core_rsp_sop
:响应开始信号。core_rsp_eop
:响应结束信号。core_rsp_ready
:内存调度器是否准备好发送响应。
输入数据流
- 内存请求信号:
mem_req_valid
:指示内存请求是否有效。mem_req_rw
:内存请求的读/写标志。mem_req_mask
:内存请求的掩码。mem_req_byteen
:内存请求的字节使能信号。mem_req_addr
:内存请求的地址。mem_req_atype
:内存请求的地址类型。mem_req_data
:内存请求的数据。mem_req_tag
:内存请求的标签。mem_req_ready
:指示内存系统是否准备好接收请求。
输出数据流
- 内存响应信号:
mem_rsp_valid
:指示内存响应是否有效。mem_rsp_mask
:内存响应的掩码。mem_rsp_data
:内存响应的数据。mem_rsp_tag
:内存响应的标签。mem_rsp_ready
:指示核心是否准备好接收响应。
解包内存响应标签
// unpack memory response tag
assign {
rsp_uuid,
rsp_wid,
rsp_pc,
rsp_wb,
rsp_rd,
rsp_op_type,
rsp_align,
rsp_pid,
pkt_raddr,
rsp_is_fence
} = mem_rsp_tag;
- 解包(unpack):将
mem_rsp_tag
信号解包成多个单独的信号。这些信号包含了内存响应的各种信息,例如唯一标识符(UUID)、工作线程ID(wid)、程序计数器(PC)、写回标志(wb)、目的寄存器(rd)、操作类型(op_type)、对齐信息(align)、进程ID(pid)、包读地址(pkt_raddr)和栅栏标志(fence)。
加载响应数据的格式化
// load response formatting
reg [NUM_LANES-1:0][`XLEN-1:0] rsp_data;
`ifdef XLEN_64
`ifdef EXT_F_ENABLE
// apply nan-boxing to flw outputs
wire rsp_is_float = rsp_rd[5];
`else
wire rsp_is_float = 0;
`endif
`endif
- rsp_data:用于存储每个通道的加载响应数据。
- rsp_is_float:在64位架构且启用浮点扩展(EXT_F_ENABLE)的情况下,判断目标寄存器是否为浮点寄存器。
数据位宽处理
根据架构位宽(32位或64位),对数据进行处理和格式化。
for (genvar i = 0; i < NUM_LANES; i++) begin
`ifdef XLEN_64
wire [63:0] rsp_data64 = mem_rsp_data[i];
wire [31:0] rsp_data32 = (rsp_align[i][2] ? mem_rsp_data[i][63:32] : mem_rsp_data[i][31:0]);
`else
wire [31:0] rsp_data32 = mem_rsp_data[i];
`endif
wire [15:0] rsp_data16 = rsp_align[i][1] ? rsp_data32[31:16] : rsp_data32[15:0];
wire [7:0] rsp_data8 = rsp_align[i][0] ? rsp_data16[15:8] : rsp_data16[7:0];
- rsp_data64:在64位架构下,从
mem_rsp_data
中提取64位数据。 - rsp_data32:从
mem_rsp_data
中提取32位数据,根据rsp_align
决定高位或低位。 - rsp_data16:从
rsp_data32
中提取16位数据,根据rsp_align
决定高位或低位。 - rsp_data8:从
rsp_data16
中提取8位数据,根据rsp_align
决定高位或低位。
根据操作类型格式化数据
always @(*) begin
case (`INST_LSU_FMT(rsp_op_type))
`INST_FMT_B: rsp_data[i] = `XLEN'(signed'(rsp_data8));
`INST_FMT_H: rsp_data[i] = `XLEN'(signed'(rsp_data16));
`INST_FMT_BU: rsp_data[i] = `XLEN'(unsigned'(rsp_data8));
`INST_FMT_HU: rsp_data[i] = `XLEN'(unsigned'(rsp_data16));
`ifdef XLEN_64
`INST_FMT_W: rsp_data[i] = rsp_is_float ? (`XLEN'(rsp_data32) | 64'hffffffff00000000) : `XLEN'(signed'(rsp_data32));
`INST_FMT_WU: rsp_data[i] = `XLEN'(unsigned'(rsp_data32));
`INST_FMT_D: rsp_data[i] = `XLEN'(signed'(rsp_data64));
`else
`INST_FMT_W: rsp_data[i] = `XLEN'(signed'(rsp_data32));
`endif
default: rsp_data[i] = 'x;
endcase
end
end
INST_LSU_FMT(rsp_op_type)
:根据操作类型,选择不同的数据格式化方式。INST_FMT_B
:将rsp_data8
扩展为XLEN
位的有符号数。INST_FMT_H
:将rsp_data16
扩展为XLEN
位的有符号数。INST_FMT_BU
:将rsp_data8
扩展为XLEN
位的无符号数。INST_FMT_HU
:将rsp_data16
扩展为XLEN
位的无符号数。INST_FMT_W
:在64位架构下,如果是浮点数,进行NaN-boxing,否则将rsp_data32
扩展为XLEN
位的有符号数。INST_FMT_WU
:将rsp_data32
扩展为XLEN
位的无符号数。INST_FMT_D
:在64位架构下,将rsp_data64
扩展为XLEN
位的有符号数。- default:默认情况下,将
rsp_data[i]
置为未定义值。
总结
这段代码实现了内存响应的解包和加载数据的格式化。通过解包内存响应标签,将内存响应的各个字段分离出来,并根据操作类型,对加载的数据进行格式化处理,确保数据在不同位宽和格式下能够正确处理和使用。
提交
// commit
VX_elastic_buffer #(
.DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + 1 + `NR_BITS + (NUM_LANES * `XLEN) + PID_WIDTH + 1 + 1),
.SIZE (2)
) rsp_buf (
.clk (clk),
.reset (reset),
.valid_in (mem_rsp_valid),
.ready_in (mem_rsp_ready),
.data_in ({rsp_uuid, rsp_wid, mem_rsp_mask, rsp_pc, rsp_wb, rsp_rd, rsp_data, rsp_pid, mem_rsp_sop_pkt, mem_rsp_eop_pkt}),
.data_out ({commit_rsp_if.data.uuid, commit_rsp_if.data.wid, commit_rsp_if.data.tmask, commit_rsp_if.data.PC, commit_rsp_if.data.wb, commit_rsp_if.data.rd, commit_rsp_if.data.data, commit_rsp_if.data.pid, commit_rsp_if.data.sop, commit_rsp_if.data.eop}),
.valid_out (commit_rsp_if.valid),
.ready_out (commit_rsp_if.ready)
);
VX_elastic_buffer #(
.DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + PID_WIDTH + 1 + 1),
.SIZE (2)
) no_rsp_buf (
.clk (clk),
.reset (reset),
.valid_in (no_rsp_buf_valid),
.ready_in (no_rsp_buf_ready),
.data_in ({execute_if.data.uuid, execute_if.data.wid, execute_if.data.tmask, execute_if.data.PC, execute_if.data.pid, execute_if.data.sop, execute_if.data.eop}),
.data_out ({commit_no_rsp_if.data.uuid, commit_no_rsp_if.data.wid, commit_no_rsp_if.data.tmask, commit_no_rsp_if.data.PC, commit_no_rsp_if.data.pid, commit_no_rsp_if.data.sop, commit_no_rsp_if.data.eop}),
.valid_out (commit_no_rsp_if.valid),
.ready_out (commit_no_rsp_if.ready)
);
assign commit_no_rsp_if.data.rd = '0;
assign commit_no_rsp_if.data.wb = 1'b0;
assign commit_no_rsp_if.data.data = commit_rsp_if.data.data; // arbiter MUX optimization
VX_stream_arb #(
.NUM_INPUTS (2),
.DATAW (RSP_ARB_DATAW),
.ARBITER ("P"), // prioritize commit_rsp_if
.OUT_BUF (3)
) rsp_arb (
.clk (clk),
.reset (reset),
.valid_in ({commit_no_rsp_if.valid, commit_rsp_if.valid}),
.ready_in ({commit_no_rsp_if.ready, commit_rsp_if.ready}),
.data_in ({commit_no_rsp_if.data, commit_rsp_if.data}),
.data_out (commit_if.data),
.valid_out (commit_if.valid),
.ready_out (commit_if.ready),
`UNUSED_PIN (sel_out)
);
这段代码实现了内存响应数据的提交逻辑,使用了弹性缓冲区(VX_elastic_buffer
)和流仲裁器(VX_stream_arb
)模块。
提交响应数据 (commit response data
)
// commit
VX_elastic_buffer #(
.DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + 1 + `NR_BITS + (NUM_LANES * `XLEN) + PID_WIDTH + 1 + 1),
.SIZE (2)
) rsp_buf (
.clk (clk),
.reset (reset),
.valid_in (mem_rsp_valid),
.ready_in (mem_rsp_ready),
.data_in ({rsp_uuid, rsp_wid, mem_rsp_mask, rsp_pc, rsp_wb, rsp_rd, rsp_data, rsp_pid, mem_rsp_sop_pkt, mem_rsp_eop_pkt}),
.data_out ({commit_rsp_if.data.uuid, commit_rsp_if.data.wid, commit_rsp_if.data.tmask, commit_rsp_if.data.PC, commit_rsp_if.data.wb, commit_rsp_if.data.rd, commit_rsp_if.data.data, commit_rsp_if.data.pid, commit_rsp_if.data.sop, commit_rsp_if.data.eop}),
.valid_out (commit_rsp_if.valid),
.ready_out (commit_rsp_if.ready)
);
- rsp_buf:这是一个弹性缓冲区,用于存储和传输内存响应数据。
- DATAW:数据宽度,包括UUID、工作线程ID、掩码、程序计数器、写回标志、目标寄存器、数据、进程ID、SOP和EOP信号。
- SIZE:缓冲区大小,这里设置为2。
- clk:时钟信号。
- reset:复位信号。
- valid_in:输入数据有效信号。
- ready_in:输入数据准备好信号。
- data_in:输入数据,包括各个字段的组合。
- data_out:输出数据,传递给
commit_rsp_if
接口。 - valid_out:输出数据有效信号。
- ready_out:输出数据准备好信号。
提交无响应数据 (commit no response data
)
VX_elastic_buffer #(
.DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + PID_WIDTH + 1 + 1),
.SIZE (2)
) no_rsp_buf (
.clk (clk),
.reset (reset),
.valid_in (no_rsp_buf_valid),
.ready_in (no_rsp_buf_ready),
.data_in ({execute_if.data.uuid, execute_if.data.wid, execute_if.data.tmask, execute_if.data.PC, execute_if.data.pid, execute_if.data.sop, execute_if.data.eop}),
.data_out ({commit_no_rsp_if.data.uuid, commit_no_rsp_if.data.wid, commit_no_rsp_if.data.tmask, commit_no_rsp_if.data.PC, commit_no_rsp_if.data.pid, commit_no_rsp_if.data.sop, commit_no_rsp_if.data.eop}),
.valid_out (commit_no_rsp_if.valid),
.ready_out (commit_no_rsp_if.ready)
);
assign commit_no_rsp_if.data.rd = '0;
assign commit_no_rsp_if.data.wb = 1'b0;
assign commit_no_rsp_if.data.data = commit_rsp_if.data.data; // arbiter MUX optimization
-
no_rsp_buf:这是另一个弹性缓冲区,用于存储和传输无响应数据。
- DATAW:数据宽度,包括UUID、工作线程ID、掩码、程序计数器、进程ID、SOP和EOP信号。
- SIZE:缓冲区大小,这里设置为2。
- clk:时钟信号。
- reset:复位信号。
- valid_in:输入数据有效信号。
- ready_in:输入数据准备好信号。
- data_in:输入数据,包括各个字段的组合。
- data_out:输出数据,传递给
commit_no_rsp_if
接口。 - valid_out:输出数据有效信号。
- ready_out:输出数据准备好信号。
-
assign 语句:
- commit_no_rsp_if.data.rd:将目标寄存器设为0。
- commit_no_rsp_if.data.wb:将写回标志设为0。
- commit_no_rsp_if.data.data:将数据设为
commit_rsp_if.data.data
,用于仲裁器MUX优化。
响应数据仲裁 (response data arbitration
)
VX_stream_arb #(
.NUM_INPUTS (2),
.DATAW (RSP_ARB_DATAW),
.ARBITER ("P"), // prioritize commit_rsp_if
.OUT_BUF (3)
) rsp_arb (
.clk (clk),
.reset (reset),
.valid_in ({commit_no_rsp_if.valid, commit_rsp_if.valid}),
.ready_in ({commit_no_rsp_if.ready, commit_rsp_if.ready}),
.data_in ({commit_no_rsp_if.data, commit_rsp_if.data}),
.data_out (commit_if.data),
.valid_out (commit_if.valid),
.ready_out (commit_if.ready),
`UNUSED_PIN (sel_out)
);
- rsp_arb:这是一个流仲裁器,用于仲裁多个输入的数据流,并输出到
commit_if
接口。- NUM_INPUTS:输入数据流的数量,这里设置为2。
- DATAW:数据宽度。
- ARBITER:仲裁策略,这里设置为"P",优先处理
commit_rsp_if
。 - OUT_BUF:输出缓冲区大小,这里设置为3。
- clk:时钟信号。
- reset:复位信号。
- valid_in:输入数据有效信号,包含
commit_no_rsp_if
和commit_rsp_if
的有效信号。 - ready_in:输入数据准备好信号,包含
commit_no_rsp_if
和commit_rsp_if
的准备好信号。 - data_in:输入数据,包含
commit_no_rsp_if
和commit_rsp_if
的数据。 - data_out:输出数据,传递给
commit_if
接口。 - valid_out:输出数据有效信号。
- ready_out:输出数据准备好信号。
总结
这段代码实现了内存响应数据的提交逻辑,包括响应数据和无响应数据的处理。使用弹性缓冲区(VX_elastic_buffer
)存储和传输数据,并通过流仲裁器(VX_stream_arb
)仲裁多个输入的数据流,最终输出到 commit_if
接口。这确保了内存响应数据的有效传输和处理。
Trace
`ifdef DBG_TRACE_MEM
always @(posedge clk) begin
if (execute_if.valid && fence_lock) begin
`TRACE(1, ("%d: *** %s fence wait\n", $time, INSTANCE_ID));
end
if (mem_req_fire) begin
if (mem_req_rw) begin
`TRACE(1, ("%d: %s Wr Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, INSTANCE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask));
`TRACE_ARRAY1D(1, "0x%h", full_addr, NUM_LANES);
`TRACE(1, (", atype="));
`TRACE_ARRAY1D(1, "%b", mem_req_atype, NUM_LANES);
`TRACE(1, (", byteen=0x%0h, data=", mem_req_byteen));
`TRACE_ARRAY1D(1, "0x%0h", mem_req_data, NUM_LANES);
`TRACE(1, (", tag=0x%0h (#%0d)\n", mem_req_tag, execute_if.data.uuid));
end else begin
`TRACE(1, ("%d: %s Rd Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, INSTANCE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask));
`TRACE_ARRAY1D(1, "0x%h", full_addr, NUM_LANES);
`TRACE(1, (", atype="));
`TRACE_ARRAY1D(1, "%b", mem_req_atype, NUM_LANES);
`TRACE(1, (", byteen=0x%0h, rd=%0d, tag=0x%0h (#%0d)\n", mem_req_byteen, execute_if.data.rd, mem_req_tag, execute_if.data.uuid));
end
end
if (mem_rsp_fire) begin
`TRACE(1, ("%d: %s Rsp: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d, sop=%b, eop=%b, data=",
$time, INSTANCE_ID, rsp_wid, {rsp_pc, 1'b0}, mem_rsp_mask, rsp_rd, mem_rsp_sop, mem_rsp_eop));
`TRACE_ARRAY1D(1, "0x%0h", mem_rsp_data, NUM_LANES);
`TRACE(1, (", tag=0x%0h (#%0d)\n", mem_rsp_tag, rsp_uuid));
end
end
`endif
`ifdef DBG_SCOPE_LSU
VX_scope_tap #(
.SCOPE_ID (3),
.TRIGGERW (3),
.PROBEW (1 + NUM_LANES*(`XLEN + LSU_WORD_SIZE + LSU_WORD_SIZE*8) + `UUID_WIDTH + NUM_LANES*LSU_WORD_SIZE*8 + `UUID_WIDTH)
) scope_tap (
.clk (clk),
.reset (scope_reset),
.start (1'b0),
.stop (1'b0),
.triggers({reset, mem_req_fire, mem_rsp_fire}),
.probes ({mem_req_rw, full_addr, mem_req_byteen, mem_req_data, execute_if.data.uuid, rsp_data, rsp_uuid}),
.bus_in (scope_bus_in),
.bus_out(scope_bus_out)
);
`else
`SCOPE_IO_UNUSED()
`endif
这段代码实现了内存请求和响应的调试跟踪和范围探针(scope tap)功能。
内存请求和响应的调试跟踪
`ifdef DBG_TRACE_MEM
always @(posedge clk) begin
if (execute_if.valid && fence_lock) begin
`TRACE(1, ("%d: *** %s fence wait\n", $time, INSTANCE_ID));
end
if (mem_req_fire) begin
if (mem_req_rw) begin
`TRACE(1, ("%d: %s Wr Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, INSTANCE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask));
`TRACE_ARRAY1D(1, "0x%h", full_addr, NUM_LANES);
`TRACE(1, (", atype="));
`TRACE_ARRAY1D(1, "%b", mem_req_atype, NUM_LANES);
`TRACE(1, (", byteen=0x%0h, data=", mem_req_byteen));
`TRACE_ARRAY1D(1, "0x%0h", mem_req_data, NUM_LANES);
`TRACE(1, (", tag=0x%0h (#%0d)\n", mem_req_tag, execute_if.data.uuid));
end else begin
`TRACE(1, ("%d: %s Rd Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, INSTANCE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask));
`TRACE_ARRAY1D(1, "0x%h", full_addr, NUM_LANES);
`TRACE(1, (", atype="));
`TRACE_ARRAY1D(1, "%b", mem_req_atype, NUM_LANES);
`TRACE(1, (", byteen=0x%0h, rd=%0d, tag=0x%0h (#%0d)\n", mem_req_byteen, execute_if.data.rd, mem_req_tag, execute_if.data.uuid));
end
end
if (mem_rsp_fire) begin
`TRACE(1, ("%d: %s Rsp: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d, sop=%b, eop=%b, data=",
$time, INSTANCE_ID, rsp_wid, {rsp_pc, 1'b0}, mem_rsp_mask, rsp_rd, mem_rsp_sop, mem_rsp_eop));
`TRACE_ARRAY1D(1, "0x%0h", mem_rsp_data, NUM_LANES);
`TRACE(1, (", tag=0x%0h (#%0d)\n", mem_rsp_tag, rsp_uuid));
end
end
`endif
- 条件编译指令 (
ifdef DBG_TRACE_MEM
):用于在编译时选择性包含调试跟踪代码。 always @(posedge clk)
:在每个时钟上升沿触发。if (execute_if.valid && fence_lock)
:如果执行接口有效且栅栏锁定,则记录栅栏等待信息。if (mem_req_fire)
:如果内存请求触发(有效且准备好),则记录请求信息。if (mem_req_rw)
:如果是写请求,记录写请求的详细信息。else
:如果是读请求,记录读请求的详细信息。
if (mem_rsp_fire)
:如果内存响应触发(有效且准备好),则记录响应信息。
范围探针(scope tap)的实现
`ifdef DBG_SCOPE_LSU
VX_scope_tap #(
.SCOPE_ID (3),
.TRIGGERW (3),
.PROBEW (1 + NUM_LANES*(`XLEN + LSU_WORD_SIZE + LSU_WORD_SIZE*8) + `UUID_WIDTH + NUM_LANES*LSU_WORD_SIZE*8 + `UUID_WIDTH)
) scope_tap (
.clk (clk),
.reset (scope_reset),
.start (1'b0),
.stop (1'b0),
.triggers({reset, mem_req_fire, mem_rsp_fire}),
.probes ({mem_req_rw, full_addr, mem_req_byteen, mem_req_data, execute_if.data.uuid, rsp_data, rsp_uuid}),
.bus_in (scope_bus_in),
.bus_out(scope_bus_out)
);
`else
`SCOPE_IO_UNUSED()
`endif
- 条件编译指令 (
ifdef DBG_SCOPE_LSU
):用于在编译时选择性包含范围探针代码。 VX_scope_tap
:实例化一个范围探针模块,用于调试和监控内部信号。SCOPE_ID
:范围探针的ID,这里设置为3。TRIGGERW
:触发信号的宽度,这里设置为3。PROBEW
:探针信号的宽度,计算得出。clk
:时钟信号。reset
:复位信号。start
和stop
:控制范围探针的启动和停止信号,这里都设置为0。triggers
:触发信号,包括复位信号、内存请求触发信号和内存响应触发信号。probes
:探针信号,包括内存请求的读写标志、完整地址、字节使能信号、请求数据、UUID、响应数据和响应UUID。bus_in
和bus_out
:范围探针的输入和输出总线信号。
总结
这段代码实现了内存请求和响应的调试跟踪和范围探针功能。通过条件编译指令,可以在编译时选择性包含这些调试功能,以便在运行时记录和监控内存请求和响应的详细信息。这对于调试和优化内存访问操作非常有用。