本次解析模块内容:
div
ctrl
rib
regs(简单,看原作者解释即可)
csr_regs(和regs长得同父同母)
参考文献:从零开始写RISC-V处理器 | liangkangnan的博客 (gitee.io)
参考代码:tinyriscv: 一个从零开始写的极简、非常易懂的RISC-V处理器核。 (gitee.com)
目录
div
`include "defines.v"
// 除法模块
// 试商法实现32位整数除法
// 每次除法运算至少需要33个时钟周期才能完成
//负数的补码取反+1 得出正数原码
//正数的原码取反+1 得出负数补码
module div(
input wire clk,
input wire rst,
// from ex
input wire[`RegBus] dividend_i, // 被除数
input wire[`RegBus] divisor_i, // 除数
input wire start_i, // 开始信号,运算期间这个信号需要一直保持有效
input wire[2:0] op_i, // 具体是哪一条指令
input wire[`RegAddrBus] reg_waddr_i, // 运算结束后需要写的寄存器
// to ex
output reg[`RegBus] result_o, // 除法结果,高32位是余数,低32位是商
output reg ready_o, // 运算结束信号
output reg busy_o, // 正在运算信号
output reg[`RegAddrBus] reg_waddr_o // 运算结束后需要写的寄存器
);
// 状态定义
localparam STATE_IDLE = 4'b0001;
localparam STATE_START = 4'b0010;
localparam STATE_CALC = 4'b0100;
localparam STATE_END = 4'b1000;
reg[`RegBus] dividend_r;//buffer
reg[`RegBus] divisor_r;
reg[2:0] op_r;
reg[3:0] state;
reg[31:0] count;
reg[`RegBus] div_result;
reg[`RegBus] div_remain;
reg[`RegBus] minuend;
reg invert_result;
wire op_div = (op_r == `INST_DIV);
wire op_divu = (op_r == `INST_DIVU);
wire op_rem = (op_r == `INST_REM);
wire op_remu = (op_r == `INST_REMU);
wire[31:0] dividend_invert = (-dividend_r);//被除数的相反数,这里是直接用一个负号把求补码然后取反+1的操作给忽略了,只能说RTL语言现在太简化了
wire[31:0] divisor_invert = (-divisor_r);//除数的相反数
wire minuend_ge_divisor = minuend >= divisor_r;//这是一个标志信号,表示验证的被除部分大于除数,这样就可以在当前除数位赋值为1
wire[31:0] minuend_sub_res = minuend - divisor_r;//这是判断完被除部分大于除数之后,留下的余数,这时候需要继续向下1bit 1bit读取
wire[31:0] div_result_tmp = minuend_ge_divisor? ({div_result[30:0], 1'b1}): ({div_result[30:0], 1'b0});//这里其实是一个左移位寄存器的机制,通过不断左移,慢慢拼接出完整的结果
wire[31:0] minuend_tmp = minuend_ge_divisor? minuend_sub_res[30:0]: minuend[30:0];//这里是对操作的被除部分进行进位以及保留
// 状态机实现
always @ (posedge clk) begin
if (rst == `RstEnable) begin//初始化
state <= STATE_IDLE;
ready_o <= `DivResultNotReady;
result_o <= `ZeroWord;
div_result <= `ZeroWord;
div_remain <= `ZeroWord;
op_r <= 3'h0;
reg_waddr_o <= `ZeroWord;
dividend_r <= `ZeroWord;
divisor_r <= `ZeroWord;
minuend <= `ZeroWord;
invert_result <= 1'b0;
busy_o <= `False;
count <= `ZeroWord;
end else begin
case (state)
STATE_IDLE: begin
if (start_i == `DivStart) begin
op_r <= op_i;//引入opcode
dividend_r <= dividend_i;//引入被除数
divisor_r <= divisor_i;//引入除数
reg_waddr_o <= reg_waddr_i;//引入要把结果写入的寄存器地址
state <= STATE_START;
busy_o <= `True;//开启忙状态
end else begin
op_r <= 3'h0;
reg_waddr_o <= `ZeroWord;
dividend_r <= `ZeroWord;
divisor_r <= `ZeroWord;
ready_o <= `DivResultNotReady;
result_o <= `ZeroWord;
busy_o <= `False;
end
end
STATE_START: begin
if (start_i == `DivStart) begin
// 除数为0
if (divisor_r == `ZeroWord) begin
if (op_div | op_divu) begin
result_o <= 32'hffffffff;//这里表示运算不合法
end else begin
result_o <= dividend_r;//其余情况应该是与求余数,因为运算不合法,所以没有触发除法操作,余数就是被除数本身
end
ready_o <= `DivResultReady;
state <= STATE_IDLE;
busy_o <= `False;
// 除数不为0
end else begin
busy_o <= `True;//开始运算,继续忙
count <= 32'h40000000;//这个暂且不清楚⭐
state <= STATE_CALC;
div_result <= `ZeroWord;
div_remain <= `ZeroWord;
// DIV和REM这两条指令是有符号数运算指令
if (op_div | op_rem) begin
// 被除数求相反数
if (dividend_r[31] == 1'b1) begin
dividend_r <= dividend_invert;//将被除数正数化
minuend <= dividend_invert[31];//这个表示将被除数的头一位放入 被除部分 这里其实就是进行循环读取的时候了,一个一个读入,并不断判断是否大于除数,一旦出现大于的情况,马上在原地留个1,算出相减结果并替代,然后继续读
end else begin
minuend <= dividend_r[31];//这里同样是将除数正数化,因为负数很难拿来计算,算法和正数不一致,一般都是先全部化为正数
end
// 除数求相反数
if (divisor_r[31] == 1'b1) begin
divisor_r <= divisor_invert;
end
end else begin
minuend <= dividend_r[31];
end
// 运算结束后是否要对结果取补码
if ((op_div && (dividend_r[31] ^ divisor_r[31] == 1'b1))//这一点主要是判断除数和被除数是不是只有单个负号,这样的话会导致负数结果的出现
|| (op_rem && (dividend_r[31] == 1'b1))) begin //求余算符的话你的结果正负取决于你的被除数: 被除数:- 除数:+ 余数结果:-
invert_result <= 1'b1; //这种情况下结果要取反,因为原结果是负数 //被除数:+ 除数:- 余数结果: +
end else begin
invert_result <= 1'b0;
end
end
end else begin
state <= STATE_IDLE;
result_o <= `ZeroWord;
ready_o <= `DivResultNotReady;
busy_o <= `False;
end
end
/*-------------------------------------------------------------------------------------------------------------*/
STATE_CALC: begin
if (start_i == `DivStart) begin
dividend_r <= {dividend_r[30:0], 1'b0};//被除数逻辑左移
div_result <= div_result_tmp;//这个主要是不断让结果低位左移,让新进来的数从右到左移动,逐步形成除法结果
count <= {1'b0, count[31:1]};//count的位数是32位,应该是作为移位寄存器拿来计数的?从左到右的移位寄存器
if (|count) begin
minuend <= {minuend_tmp[30:0], dividend_r[30]};
end else begin
state <= STATE_END;
if (minuend_ge_divisor) begin
div_remain <= minuend_sub_res;
end else begin
div_remain <= minuend;
end
end
end else begin
state <= STATE_IDLE;
result_o <= `ZeroWord;
ready_o <= `DivResultNotReady;
busy_o <= `False;
end
end
/*---------------------------------------------------------------------------------------------------------------*/
STATE_END: begin
if (start_i == `DivStart) begin
ready_o <= `DivResultReady;//结束标志
state <= STATE_IDLE;
busy_o <= `False;//关掉忙信号
if (op_div | op_divu) begin
if (invert_result) begin
result_o <= (-div_result);//执行上一步所判断出来的结果取反信号
end else begin
result_o <= div_result;
end
end else begin
if (invert_result) begin
result_o <= (-div_remain);//这里是余数的取反信号,同样是上一步得来的,具体的触发条件看上一步就可以了
end else begin
result_o <= div_remain;
end
end
end else begin
state <= STATE_IDLE;
result_o <= `ZeroWord;
ready_o <= `DivResultNotReady;
busy_o <= `False;
end
end
endcase
end
end
endmodule
ctrl
`include "defines.v"
// 控制模块
// 发出跳转、暂停流水线信号
//主要接收来自于: 总线读取时的冲刷流水线、jtag调试、ex对解码的执行、以及中断触发所产生的流水线暂停/跳转
module ctrl(
input wire rst,
// from ex
input wire jump_flag_i,
input wire[`InstAddrBus] jump_addr_i,
input wire hold_flag_ex_i,
// from rib
input wire hold_flag_rib_i,
// from jtag
input wire jtag_halt_flag_i,
// from clint
input wire hold_flag_clint_i,
//----------------------------------------------------
//to ex id clint
output reg[`Hold_Flag_Bus] hold_flag_o,//连接各个流水线触发器,可以控制流水进程
// to pc_reg
output reg jump_flag_o,
output reg[`InstAddrBus] jump_addr_o
);
always @ (*) begin
jump_addr_o = jump_addr_i;//来自于ex模块
jump_flag_o = jump_flag_i;//来自于ex模块
// 默认不暂停
hold_flag_o = `Hold_None;
// 按优先级处理不同模块的请求
if (jump_flag_i == `JumpEnable || hold_flag_ex_i == `HoldEnable || hold_flag_clint_i == `HoldEnable) begin
// 暂停整条流水线
hold_flag_o = `Hold_Id;
end else if (hold_flag_rib_i == `HoldEnable) begin
// 暂停PC,即取指地址不变
hold_flag_o = `Hold_Pc;
end else if (jtag_halt_flag_i == `HoldEnable) begin
// 暂停整条流水线
hold_flag_o = `Hold_Id;
end else begin
hold_flag_o = `Hold_None;
end
end
endmodule
reg
`include "defines.v"
// 通用寄存器模块
module regs(
input wire clk,
input wire rst,
// from ex
input wire we_i, // 写寄存器标志
input wire[`RegAddrBus] waddr_i, // 写寄存器地址
input wire[`RegBus] wdata_i, // 写寄存器数据
// from jtag
input wire jtag_we_i, // 写寄存器标志
input wire[`RegAddrBus] jtag_addr_i, // 读、写寄存器地址
input wire[`RegBus] jtag_data_i, // 写寄存器数据
// from id
input wire[`RegAddrBus] raddr1_i, // 读寄存器1地址
// to id
output reg[`RegBus] rdata1_o, // 读寄存器1数据
// from id
input wire[`RegAddrBus] raddr2_i, // 读寄存器2地址
// to id
output reg[`RegBus] rdata2_o, // 读寄存器2数据
// to jtag
output reg[`RegBus] jtag_data_o // 读寄存器数据
);
reg[`RegBus] regs[0:`RegNum - 1];
// 写寄存器
always @ (posedge clk) begin
if (rst == `RstDisable) begin
// 优先ex模块写操作
if ((we_i == `WriteEnable) && (waddr_i != `ZeroReg)) begin
regs[waddr_i] <= wdata_i;
end else if ((jtag_we_i == `WriteEnable) && (jtag_addr_i != `ZeroReg)) begin
regs[jtag_addr_i] <= jtag_data_i;
end
end
end
// 读寄存器1
always @ (*) begin
if (raddr1_i == `ZeroReg) begin
rdata1_o = `ZeroWord;
// 如果读地址等于写地址,并且正在写操作,则直接返回写数据
end else if (raddr1_i == waddr_i && we_i == `WriteEnable) begin
rdata1_o = wdata_i;
end else begin
rdata1_o = regs[raddr1_i];
end
end
// 读寄存器2
always @ (*) begin
if (raddr2_i == `ZeroReg) begin
rdata2_o = `ZeroWord;
// 如果读地址等于写地址,并且正在写操作,则直接返回写数据
end else if (raddr2_i == waddr_i && we_i == `WriteEnable) begin
rdata2_o = wdata_i;
end else begin
rdata2_o = regs[raddr2_i];
end
end
// jtag读寄存器
always @ (*) begin
if (jtag_addr_i == `ZeroReg) begin
jtag_data_o = `ZeroWord;
end else begin
jtag_data_o = regs[jtag_addr_i];
end
end
endmodule
csr_regs
`include "defines.v"
// CSR寄存器模块
module csr_reg(
input wire clk,
input wire rst,
// form ex
input wire we_i, // ex模块写寄存器标志
input wire[`MemAddrBus] raddr_i, // ex模块读寄存器地址
input wire[`MemAddrBus] waddr_i, // ex模块写寄存器地址
input wire[`RegBus] data_i, // ex模块写寄存器数据
// from clint
input wire clint_we_i, // clint模块写寄存器标志
input wire[`MemAddrBus] clint_raddr_i, // clint模块读寄存器地址
input wire[`MemAddrBus] clint_waddr_i, // clint模块写寄存器地址
input wire[`RegBus] clint_data_i, // clint模块写寄存器数据
output wire global_int_en_o, // 全局中断使能标志
// to clint
output reg[`RegBus] clint_data_o, // clint模块读寄存器数据
output wire[`RegBus] clint_csr_mtvec, // mtvec
output wire[`RegBus] clint_csr_mepc, // mepc
output wire[`RegBus] clint_csr_mstatus, // mstatus
// to ex
output reg[`RegBus] data_o // ex模块读寄存器数据
);
reg[`DoubleRegBus] cycle;
reg[`RegBus] mtvec;
reg[`RegBus] mcause;
reg[`RegBus] mepc;
reg[`RegBus] mie;
reg[`RegBus] mstatus;
reg[`RegBus] mscratch;
assign global_int_en_o = (mstatus[3] == 1'b1)? `True: `False;
assign clint_csr_mtvec = mtvec;
assign clint_csr_mepc = mepc;
assign clint_csr_mstatus = mstatus;
// cycle counter
// 复位撤销后就一直计数
always @ (posedge clk) begin
if (rst == `RstEnable) begin
cycle <= {`ZeroWord, `ZeroWord};
end else begin
cycle <= cycle + 1'b1;
end
end
// write reg
// 写寄存器操作
always @ (posedge clk) begin
if (rst == `RstEnable) begin
mtvec <= `ZeroWord;
mcause <= `ZeroWord;
mepc <= `ZeroWord;
mie <= `ZeroWord;
mstatus <= `ZeroWord;
mscratch <= `ZeroWord;
end else begin
// 优先响应ex模块的写操作
if (we_i == `WriteEnable) begin
case (waddr_i[11:0])
`CSR_MTVEC: begin
mtvec <= data_i;
end
`CSR_MCAUSE: begin
mcause <= data_i;
end
`CSR_MEPC: begin
mepc <= data_i;
end
`CSR_MIE: begin
mie <= data_i;
end
`CSR_MSTATUS: begin
mstatus <= data_i;
end
`CSR_MSCRATCH: begin
mscratch <= data_i;
end
default: begin
end
endcase
// clint模块写操作
end else if (clint_we_i == `WriteEnable) begin
case (clint_waddr_i[11:0])
`CSR_MTVEC: begin
mtvec <= clint_data_i;
end
`CSR_MCAUSE: begin
mcause <= clint_data_i;
end
`CSR_MEPC: begin
mepc <= clint_data_i;
end
`CSR_MIE: begin
mie <= clint_data_i;
end
`CSR_MSTATUS: begin
mstatus <= clint_data_i;
end
`CSR_MSCRATCH: begin
mscratch <= clint_data_i;
end
default: begin
end
endcase
end
end
end
// read reg
// ex模块读CSR寄存器
always @ (*) begin
if ((waddr_i[11:0] == raddr_i[11:0]) && (we_i == `WriteEnable)) begin
data_o = data_i;
end else begin
case (raddr_i[11:0])
`CSR_CYCLE: begin
data_o = cycle[31:0];
end
`CSR_CYCLEH: begin
data_o = cycle[63:32];
end
`CSR_MTVEC: begin
data_o = mtvec;
end
`CSR_MCAUSE: begin
data_o = mcause;
end
`CSR_MEPC: begin
data_o = mepc;
end
`CSR_MIE: begin
data_o = mie;
end
`CSR_MSTATUS: begin
data_o = mstatus;
end
`CSR_MSCRATCH: begin
data_o = mscratch;
end
default: begin
data_o = `ZeroWord;
end
endcase
end
end
// read reg
// clint模块读CSR寄存器
always @ (*) begin
if ((clint_waddr_i[11:0] == clint_raddr_i[11:0]) && (clint_we_i == `WriteEnable)) begin
clint_data_o = clint_data_i;
end else begin
case (clint_raddr_i[11:0])
`CSR_CYCLE: begin
clint_data_o = cycle[31:0];
end
`CSR_CYCLEH: begin
clint_data_o = cycle[63:32];
end
`CSR_MTVEC: begin
clint_data_o = mtvec;
end
`CSR_MCAUSE: begin
clint_data_o = mcause;
end
`CSR_MEPC: begin
clint_data_o = mepc;
end
`CSR_MIE: begin
clint_data_o = mie;
end
`CSR_MSTATUS: begin
clint_data_o = mstatus;
end
`CSR_MSCRATCH: begin
clint_data_o = mscratch;
end
default: begin
clint_data_o = `ZeroWord;
end
endcase
end
end
endmodule
rib
`include "defines.v"
// RIB总线模块
module rib(
input wire clk,
input wire rst,
// master 0 interface
input wire[`MemAddrBus] m0_addr_i, // 主设备0读、写地址
input wire[`MemBus] m0_data_i, // 主设备0写数据
output reg[`MemBus] m0_data_o, // 主设备0读取到的数据
input wire m0_req_i, // 主设备0访问请求标志
input wire m0_we_i, // 主设备0写标志
// master 1 interface
input wire[`MemAddrBus] m1_addr_i, // 主设备1读、写地址
input wire[`MemBus] m1_data_i, // 主设备1写数据
output reg[`MemBus] m1_data_o, // 主设备1读取到的数据
input wire m1_req_i, // 主设备1访问请求标志
input wire m1_we_i, // 主设备1写标志
// master 2 interface
input wire[`MemAddrBus] m2_addr_i, // 主设备2读、写地址
input wire[`MemBus] m2_data_i, // 主设备2写数据
output reg[`MemBus] m2_data_o, // 主设备2读取到的数据
input wire m2_req_i, // 主设备2访问请求标志
input wire m2_we_i, // 主设备2写标志
// master 3 interface
input wire[`MemAddrBus] m3_addr_i, // 主设备3读、写地址
input wire[`MemBus] m3_data_i, // 主设备3写数据
output reg[`MemBus] m3_data_o, // 主设备3读取到的数据
input wire m3_req_i, // 主设备3访问请求标志
input wire m3_we_i, // 主设备3写标志
// slave 0 interface
output reg[`MemAddrBus] s0_addr_o, // 从设备0读、写地址
output reg[`MemBus] s0_data_o, // 从设备0写数据
input wire[`MemBus] s0_data_i, // 从设备0读取到的数据
output reg s0_we_o, // 从设备0写标志
// slave 1 interface
output reg[`MemAddrBus] s1_addr_o, // 从设备1读、写地址
output reg[`MemBus] s1_data_o, // 从设备1写数据
input wire[`MemBus] s1_data_i, // 从设备1读取到的数据
output reg s1_we_o, // 从设备1写标志
// slave 2 interface
output reg[`MemAddrBus] s2_addr_o, // 从设备2读、写地址
output reg[`MemBus] s2_data_o, // 从设备2写数据
input wire[`MemBus] s2_data_i, // 从设备2读取到的数据
output reg s2_we_o, // 从设备2写标志
// slave 3 interface
output reg[`MemAddrBus] s3_addr_o, // 从设备3读、写地址
output reg[`MemBus] s3_data_o, // 从设备3写数据
input wire[`MemBus] s3_data_i, // 从设备3读取到的数据
output reg s3_we_o, // 从设备3写标志
// slave 4 interface
output reg[`MemAddrBus] s4_addr_o, // 从设备4读、写地址
output reg[`MemBus] s4_data_o, // 从设备4写数据
input wire[`MemBus] s4_data_i, // 从设备4读取到的数据
output reg s4_we_o, // 从设备4写标志
// slave 5 interface
output reg[`MemAddrBus] s5_addr_o, // 从设备5读、写地址
output reg[`MemBus] s5_data_o, // 从设备5写数据
input wire[`MemBus] s5_data_i, // 从设备5读取到的数据
output reg s5_we_o, // 从设备5写标志
output reg hold_flag_o // 暂停流水线标志
);
// 访问地址的最高4位决定要访问的是哪一个从设备
// 因此最多支持16个从设备
parameter [3:0]slave_0 = 4'b0000;
parameter [3:0]slave_1 = 4'b0001;
parameter [3:0]slave_2 = 4'b0010;
parameter [3:0]slave_3 = 4'b0011;
parameter [3:0]slave_4 = 4'b0100;
parameter [3:0]slave_5 = 4'b0101;
parameter [1:0]grant0 = 2'h0;
parameter [1:0]grant1 = 2'h1;
parameter [1:0]grant2 = 2'h2;
parameter [1:0]grant3 = 2'h3;
wire[3:0] req;
reg[1:0] grant;
// 主设备请求信号
assign req = {m3_req_i, m2_req_i, m1_req_i, m0_req_i};
// 仲裁逻辑
// 固定优先级仲裁机制
// 优先级由高到低:主设备3,主设备0,主设备2,主设备1
always @ (*) begin//if - else if 是一种带有优先级电路的语法
if (req[3]) begin
grant = grant3;
hold_flag_o = `HoldEnable;
end else if (req[0]) begin
grant = grant0;
hold_flag_o = `HoldEnable;
end else if (req[2]) begin
grant = grant2;
hold_flag_o = `HoldEnable;
end else begin
grant = grant1;
hold_flag_o = `HoldDisable;
end
end
// 根据仲裁结果,选择(访问)对应的从设备
always @ (*) begin//根据顺序执行原则,先把初始值复位上
m0_data_o = `ZeroWord;
m1_data_o = `INST_NOP;//这个是默认的授权主机
m2_data_o = `ZeroWord;
m3_data_o = `ZeroWord;
s0_addr_o = `ZeroWord;
s1_addr_o = `ZeroWord;
s2_addr_o = `ZeroWord;
s3_addr_o = `ZeroWord;
s4_addr_o = `ZeroWord;
s5_addr_o = `ZeroWord;
s0_data_o = `ZeroWord;
s1_data_o = `ZeroWord;
s2_data_o = `ZeroWord;
s3_data_o = `ZeroWord;
s4_data_o = `ZeroWord;
s5_data_o = `ZeroWord;
s0_we_o = `WriteDisable;
s1_we_o = `WriteDisable;
s2_we_o = `WriteDisable;
s3_we_o = `WriteDisable;
s4_we_o = `WriteDisable;
s5_we_o = `WriteDisable;
case (grant)
grant0: begin
case (m0_addr_i[31:28])
slave_0: begin
s0_we_o = m0_we_i;
s0_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
s0_data_o = m0_data_i;//主从交互口打开
m0_data_o = s0_data_i;
end
slave_1: begin
s1_we_o = m0_we_i;
s1_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
s1_data_o = m0_data_i;
m0_data_o = s1_data_i;
end
slave_2: begin
s2_we_o = m0_we_i;
s2_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
s2_data_o = m0_data_i;
m0_data_o = s2_data_i;
end
slave_3: begin
s3_we_o = m0_we_i;
s3_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
s3_data_o = m0_data_i;
m0_data_o = s3_data_i;
end
slave_4: begin
s4_we_o = m0_we_i;
s4_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
s4_data_o = m0_data_i;
m0_data_o = s4_data_i;
end
slave_5: begin
s5_we_o = m0_we_i;
s5_addr_o = {{4'h0}, {m0_addr_i[27:0]}};
s5_data_o = m0_data_i;
m0_data_o = s5_data_i;
end
default: begin
end
endcase
end
grant1: begin
case (m1_addr_i[31:28])
slave_0: begin
s0_we_o = m1_we_i;
s0_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
s0_data_o = m1_data_i;
m1_data_o = s0_data_i;
end
slave_1: begin
s1_we_o = m1_we_i;
s1_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
s1_data_o = m1_data_i;
m1_data_o = s1_data_i;
end
slave_2: begin
s2_we_o = m1_we_i;
s2_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
s2_data_o = m1_data_i;
m1_data_o = s2_data_i;
end
slave_3: begin
s3_we_o = m1_we_i;
s3_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
s3_data_o = m1_data_i;
m1_data_o = s3_data_i;
end
slave_4: begin
s4_we_o = m1_we_i;
s4_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
s4_data_o = m1_data_i;
m1_data_o = s4_data_i;
end
slave_5: begin
s5_we_o = m1_we_i;
s5_addr_o = {{4'h0}, {m1_addr_i[27:0]}};
s5_data_o = m1_data_i;
m1_data_o = s5_data_i;
end
default: begin
end
endcase
end
grant2: begin
case (m2_addr_i[31:28])
slave_0: begin
s0_we_o = m2_we_i;
s0_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
s0_data_o = m2_data_i;
m2_data_o = s0_data_i;
end
slave_1: begin
s1_we_o = m2_we_i;
s1_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
s1_data_o = m2_data_i;
m2_data_o = s1_data_i;
end
slave_2: begin
s2_we_o = m2_we_i;
s2_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
s2_data_o = m2_data_i;
m2_data_o = s2_data_i;
end
slave_3: begin
s3_we_o = m2_we_i;
s3_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
s3_data_o = m2_data_i;
m2_data_o = s3_data_i;
end
slave_4: begin
s4_we_o = m2_we_i;
s4_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
s4_data_o = m2_data_i;
m2_data_o = s4_data_i;
end
slave_5: begin
s5_we_o = m2_we_i;
s5_addr_o = {{4'h0}, {m2_addr_i[27:0]}};
s5_data_o = m2_data_i;
m2_data_o = s5_data_i;
end
default: begin
end
endcase
end
grant3: begin
case (m3_addr_i[31:28])
slave_0: begin
s0_we_o = m3_we_i;
s0_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
s0_data_o = m3_data_i;
m3_data_o = s0_data_i;
end
slave_1: begin
s1_we_o = m3_we_i;
s1_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
s1_data_o = m3_data_i;
m3_data_o = s1_data_i;
end
slave_2: begin
s2_we_o = m3_we_i;
s2_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
s2_data_o = m3_data_i;
m3_data_o = s2_data_i;
end
slave_3: begin
s3_we_o = m3_we_i;
s3_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
s3_data_o = m3_data_i;
m3_data_o = s3_data_i;
end
slave_4: begin
s4_we_o = m3_we_i;
s4_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
s4_data_o = m3_data_i;
m3_data_o = s4_data_i;
end
slave_5: begin
s5_we_o = m3_we_i;
s5_addr_o = {{4'h0}, {m3_addr_i[27:0]}};
s5_data_o = m3_data_i;
m3_data_o = s5_data_i;
end
default: begin
end
endcase
end
default: begin
end
endcase
end
endmodule