`timescale 1ns / 1ps `default_nettype none // ----------------------------------------------------------------------------- // MMIO:把外设寄存器映射到数据存储器地址空间。 // // 目前实现 LED 数据寄存器(LED_ADDR 默认 0x0000_1000,位于 4 KB 数据 RAM 之外): // * 写:sw / sb 命中该地址(按字对齐,即同一 32 位寄存器内的任意字节偏移 // 都算命中)时更新 LED 寄存器,led_valid_o 拉高一拍;sb 依据 wstrb_i 只 // 修改对应的字节通道(与 RAM 的字节写语义一致)。 // * 读:lw 命中该地址时 rdata_hit_o 拉高,顶层据此选择本模块的 rdata_o // 而不是外部 data_rdata_i,从而支持把 LED 值读回。 // // 以后要增加外设(拨码开关、UART 等)时只需在这里扩展地址译码, // 处理器核心与流水线时序不需要改动。 // ----------------------------------------------------------------------------- module cpu21_mmio #( parameter [31:0] LED_ADDR = 32'h0000_1000 ) ( input wire clk, input wire reset, // MEM 级的访存请求(来自 EX/MEM 流水寄存器) input wire mem_valid_i, input wire mem_write_i, input wire mem_read_i, input wire [31:0] addr_i, input wire [31:0] wdata_i, input wire [ 3:0] wstrb_i, // MMIO 读回 output wire [31:0] rdata_o, output wire rdata_hit_o, // LED 外设 output reg [31:0] led_data_o, output reg led_valid_o ); // 地址译码按“字”对齐:同一 32 位寄存器内的任意字节偏移都算命中, // 具体修改哪几个字节由 wstrb_i 决定(sw 全字、sb 单字节)。 wire led_wr = mem_valid_i && mem_write_i && (addr_i[31:2] == LED_ADDR[31:2]); wire led_rd = mem_valid_i && mem_read_i && (addr_i[31:2] == LED_ADDR[31:2]); assign rdata_hit_o = led_rd; assign rdata_o = led_data_o; always @(posedge clk or posedge reset) begin if (reset) begin led_data_o <= 32'b0; led_valid_o <= 1'b0; end else begin // led_valid_o 只拉高一拍,作为“本周期有 LED 写入”的指示。 led_valid_o <= 1'b0; if (led_wr) begin if (wstrb_i[0]) led_data_o[7:0] <= wdata_i[7:0]; if (wstrb_i[1]) led_data_o[15:8] <= wdata_i[15:8]; if (wstrb_i[2]) led_data_o[23:16] <= wdata_i[23:16]; if (wstrb_i[3]) led_data_o[31:24] <= wdata_i[31:24]; led_valid_o <= 1'b1; end end end endmodule `default_nettype wire