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'(uns