【蜂鸟E203内核解析】Chap.3 自定义指令与协处理器设计

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言
  讲到蜂鸟E203就一定要学习它的NICE核包括集创赛都有要求使用。可以简单分为两步NICE协处理器怎么设计、自定义指令怎么设置才能调用所设计的NICE处理器。
  本文均为作者原创内容均来自本人的毕业设计。 未经授权严禁转载、使用。里面的插图和表格均为作者本人制作如需转载请联系我并标注引用参考。分享仅供大家学习和交流。

1. 概念

  领域特定架构Domain Specific ArchitectureDSA使用特定的硬件做特定的事情[18]也就是说将主处理器和协处理器加速器适当扩展到某些特定领域可以非常明显地提高能效比。NICE协处理器Nuclei Instruction Co-unit Extension蜂鸟内核指令协处理器扩展机制是一个独立于蜂鸟E203内核的一块运算单元[24]它能根据指令去控制系统内的资源去实现一些操作例如利用协处理器源操作数实现内存与缓存的数据交换、累加值、乘法、加密等操作从而提高RISC-V处理器特定领域的性能同时降低功耗。NICE协处理器的调用需要创建用户自定义RISC-V的指令
在这里插入图片描述

图4-8 NICE协处理器在流水线中的位置

2. NICE处理器怎么独立于“主核进程”进行调用

  调用NICE接口有4个通道请求通道、内存请求通道、响应通道、和内存响应通道。请求通道主处理器在流水线的EXU级时将指令的编码信息和源操作数传输到协处理器。反馈通道协处理器告诉主处理器其已完成了该指令并将结果反馈到主处理器。存储器请求通道协处理器向主处理器发起存储器读写请求。存储器反馈通道主处理器向协处理器写回存储器读写结果。各个通道信号说明如表4-2所示。

表4-2 每个通道的信号的详细说明
通道方向宽度信号名描述
请求通道Output1nice_req_valid主处理器发送指令请求信号给协处理器
Input1nice_req_ready协处理器返回指令接收信号到主处理器
Output32nice_req_instr自定义指令的32位完整编码
Output32nice_req_rs1源寄存器 1 的值
Output32nice_req_rs2源寄存器 2 的值
反馈通道Input1nice_rsp_valid协处理器发送反馈请求信号到主处理器
Output1nice_rsp_ready主处理器返回反馈接收信号给协处理器
Input32nice_rsp_data返回指令的执行结果
Input1nice_rsp_err返回该指令的错误标志
存储器请求通道Input1nice_icb_cmd_valid协处理器发送存储器读写的请求信号到主处理器
Output1nice_icb_cmd_ready主处理器返回存储器读写的接收信号给协处理器
Input32nice_icb_cmd_addr内存访问请求地址
Input1nice_icb_cmd_read内存访问请求的写入或读取0写1阅读
Input32nice_icb_cmd_wdata写入存储器的数据
Input2nice_icb_cmd_size读写数据的大小2'b00字节2'b01半字2'b101位2'b11保留
存储器反馈通道Output1nice_icb_rsp_valid主处理器发送存储器读写反馈请求信号到协处理器
Input1nice_icb_rsp_ready协处理器返回存储器读写反馈接收信号给主处理器
Output32nice_icb_rsp_rdata存储器读反馈的数据
Output1nice_icb_rsp_err存储器读写反馈的错误标志
Input1nice_mem_holdup协处理器占用存储器的信号防止主处理器的后续指令继续访问内存主处理器和协处理器同时访问内存可能导致竞争性失锁

  调用协处理器的方法扩展一个用RTL级代码编写的协处理器想个办法调用这个独立于流水线的计算单元调用协处理器应用起来的方法是在MCU层面在编译器里编写C语言主函数中包含指定汇编指令的调用完成驱动的配置。在nuclei-board-labs-master\e203_hbirdv2\common\demo_nice里的insc.h给了调用的示例。

// custom rowsum 
__STATIC_FORCEINLINE int custom_rowsum(int addr)
{
    int rowsum;
    
    asm volatile (
       ".insn r 0x7b, 6, 6, %0, %1, x0"
             :"=r"(rowsum)
             :"r"(addr)
     );
    
    return rowsum; 
}

这里E203内核提供了NICE接口。通过自定义指令调用协处理器的过程如图4-9所示。
在这里插入图片描述

图4-9 NICE协处理器的调用过程

  NICE指令的完整执行过程如下

  1. 主处理器的译码单元提供EXU级译码得到指令的操作码以判断其是否属于默认的自定义指令组。
  2. 如果该指令属于自定义指令请根据命令编码中的XS1位继续读取源寄存器。如果XS1和XS2位确定是否需要读取源寄存器则在EXU级读哪个通用寄存器并取出源操作数。
  3. 主处理器保持数据支持的正确性如果该指令需要读取源寄存器并且以前执行的指令依赖于先读取后写入RAW则流水线将暂停直到RAW依赖性被消除。此外主处理器将根据指令编码中的XD位进行决策以确定是否需要为预定义的命令将结果写入通用寄存器组如果需要则将索引信息存储在主处理器线程控制模块中的目标寄存器中直到写回完成以提供数据对后续命令的依赖性判断。
  4. 主处理器在EXU级通过NICE协处理器中接口的请求通道派发给外部的协处理器派发的信息包括指令的编码信息、两个32位宽的源操作数的值。指令做进一步的译码请求通道接收指令并依次执行指令。
  5. 协处理器通过反馈通道反馈结果、返回值。
  6. 主处理器提取命令并将结果写回通用寄存器如果需要写回。

3. 怎么自定义一条RISC-V指令

  RISC-V架构在32位的指令中预留了4组预定义指令类型Custom-0、Custom-1、Custom-2、Custom-3[10]这些指令是符合RISC-V架构的RV32I指令子集标准的32位指令。指令的[6:0]段为指令的操作码编码段opcode对应于协处理器4组预定义指令类型Custom-0、Custom-1、Custom-2、Custom-3如表4-2所示。

表4-2 预定义指令类型
预定义指令类型Inst[6:0] = opcode指令的操作码指令类型
Custom_010117'h0bR type
Custom_11010117'h2bR type
Custom_210110117'h5bR type
Custom_311110117'h7bR type

  NICE协处理器的指令编码如图4-8所示它属于Custom_3类型的RISC-V架构预定义指令。其指令的[6:0]段是1111011[11:7]段为指令的rd写目标寄存器。指令的12位、13位、14位分别是xs2、xs1、xd用于控制是否需要读源寄存器rs2、rs1、和rd如果是1即读取。指令的[19:15]段为rs1索引的通用寄存器并以他作为源操作数1。指令的[24:20]段为rs2索引的通用寄存器并以他作为源操作数2。指令的[31:25]段为funct7区间可作为额外的编码空间用于编码更多的指令每组预定义指令可以使用funct7区间对2^7=128条指令进行编码[25]。
在这里插入图片描述

图4-8 NICE协处理器的指令编码

  一组预定义指令可以使用funct7区间对2^7=128条指令进行编码四组预定义指令组可以对4*128=512条指令编码读取两个源寄存器写回一个目标寄存器。如果一些指令仅读取一个源寄存器或者无须写回目标寄存器则可以使用这些不必要的位用来编码更多的NICE协处理器指令。

  如果我们这条指令需要读取源寄存器相当于硬件模块的数据缓存寄存器那么他会在处理器的EXU级可以进行译码并且有访问内存接口读出源操作数相当于源寄存器所对应的地址源寄存器发过来的数据存放的地方而内存相当于目的寄存器。源操作数32位相当于内存中存放数据的空间的地址。并且每次在这个空间存取数据都会使得32位源操作数加4bits。

4. NICE指令设计

  实例协处理器的软件驱动RISC-V架构中的汇编代码中用户自定义指令需要通过伪指令.insn来实现对于R类型指令“.insn”的使用格式如下

.insn r opcode, func3, func7, rd, rs1, rs2

  其中insn用于告诉编译器当前指令是内嵌汇编的指令r表示指令类型是R-typeopcode表示指令的[6:0]段操作码编码段func3是第[14:12位]的xd、xs1、xs2控制位func7是自定义代码的[32:25]段rd是指令的[11:7]段rs1是指令的[19:15]段rs2是指令的[24:20]段。
在这里插入图片描述

图4-11 自定义RISC-V指令的指令编码
表4-5 预定义指令类型
指令内嵌汇编调用opcodefunc3func7rdrs1rs2
clw
读内存
".insn r 0x7b, 2, 1, x0, %1, x0"
:"=r"(zero)
:"r"(addr)
1111011custom3010只读取rs1的数据0000001指向此条指令00000零寄存器%1保存addr地址不使用
把addr的地址加载到源寄存器1编译器会自动分配rs1用哪一个寄存器这里是x10执行lbuf操作将数据导入nice_core。
cow
写内存
".insn r 0x7b, 2, 2, x0, %1, x0"
:"=r"(zero)
:"r"(addr)
1111011custom3010只读取rs1的数据0000010指向此条指令00000零寄存器%1保存addr地址不使用
把addr的地址加载到源寄存器1编译器会自动分配rs1用哪一个寄存器这里是x10执行sbuf操作将nice_core的数据导出addr。
cacc
累加值
".insn r 0x7b, 6, 6, %0, %1, x0"
:"=r"(rowsum)
:"r"(addr)
1111011custom3110读取rs1、rd的数据0000110指向此条指令%0 写回rowsum的地址%1保存addr地址不使用
把addr、rd的地址加载到读源寄存器1写目标寄存器rd编译器会自动分配rs1rd用哪一个寄存器这里是x10、x11执行sumrow操作计算后的值写回到rd寄存器。

5. NICE协处理器的设计

  NICE_CORE部分的调用“加速”模块的代码解读
  首先经过EXU进入NICE后的先要解码判断是否是custom3类型扩展指令判断func3字段以及func7对指令进行译码判断输入那一条指令

wire custom3_lbuf     = opcode_custom3 & rv32_func3_010 & rv32_func7_0000001;
wire custom3_sbuf     = opcode_custom3 & rv32_func3_010 & rv32_func7_0000010;
wire custom3_rowsum   = opcode_custom3 & rv32_func3_110 & rv32_func7_0000110;

  当判断输入指令为其中一条时将custom_multi_cyc_op和custom_mem_op置1用于后续操作和存储判断

//  multi-cyc op
wire custom_multi_cyc_op = custom3_lbuf | custom3_sbuf | custom3_rowsum;
// need access memory
wire custom_mem_op = custom3_lbuf | custom3_sbuf | custom3_rowsum;

  FSM状态机判断指令的状态切换对应已知的自定义NICE指令不同的调用。
在这里插入图片描述
在这里插入图片描述

6. 自定义指令与NICE协处理器的验证

  可以看到自定义指令进行数据读写比普通C语言模式进行数据读写少了368个时钟周期。性能得到很大的提升。将会在下一chap里详细讲解论述
在这里插入图片描述

7. e203_subsys_nice_core.v注释

/*
e203_subsys_nice_core模块为协处理模块由E203的cpu模块驱动完成数据交互。
NICE模块的信号主要由CPU内部的三个模块处理分为别
(1)e203_ifu:取指令单元取指令以及生成PC
(2)e203_exu:执行单元(完成执行、存储操作并提交写回
(3)e203_lsu:存储器访问单元
nice_req_inst则主要涉及(1)(2)两个部分。
部分(1)在e203_ifu模块中由e203_ifu_ifetch向e203_ifu_ift2icb发送PC地址来获得指令。随后e203_ifu_ift2icb通过ifu_rsp_instr信号回传指令。

随后e203_ifu_ifetch通过ifu_o_ir回传指令到e203_core.v中的e203_ifu模块。并同时传递给e203_exu模块的i_ir。e203_exu将其传递给e203_exu_alu的i_instr并最终传递给e203_exu_nice模块由该模块输出nice_req_inst信号指令给e203_subsys_nice_core协处理器。
*/
/*                                                                      
 Copyright 2018-2020 Nuclei System Technology, Inc.                
                                                                         
 Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0                          
                                                                         
  Unless required by applicable law or agreed to in writing, software    
 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.                                          
 */

//=====================================================================
//
// Designer   : LZB
//
// Description:
//  The Module to realize a simple NICE core
//
// ====================================================================
`include "e203_defines.v"

`ifdef E203_HAS_NICE//{
module e203_subsysk_nice_core (
    // System	
    input                         nice_clk            ,
    input                         nice_rst_n	      ,
    output                        nice_active	      ,
    output                        nice_mem_holdup     ,//avoid memory read or write by other devices
//    output                      nice_rsp_err_irq,
    // Control cmd_req
    input                         nice_req_valid       ,//E203 send a nice request
    output                        nice_req_ready       ,//nice can receive request
    input  [`E203_XLEN-1:0]       nice_req_inst        ,//custom instruction
    input  [`E203_XLEN-1:0]       nice_req_rs1         ,//the register 1
    input  [`E203_XLEN-1:0]       nice_req_rs2         ,//the register 2
    // Control cmd_rsp	
    output                        nice_rsp_valid       ,//nice send response
    input                         nice_rsp_ready       ,//e203 can receive response
//NICE接口信号中有两个数据传输信号 nice_rsp_rdat和nice_icb_cmd_wdata。这两个信号对应不同的寄存器。
    output [`E203_XLEN-1:0]       nice_rsp_rdat        ,//compute result ,nice_rsp_rdat对应每一行的相加结果且每次ROWSUM计算完成后均通过nice_rsp_rdat上传结果这是通过RD寄存器不会涉及memory的操作
    output                        nice_rsp_err         ,//nice has error
    // Memory lsu_req	
    output                        nice_icb_cmd_valid   ,//nice send a memory request
    input                         nice_icb_cmd_ready   ,//e203 can receive memory request
    output [`E203_ADDR_SIZE-1:0]  nice_icb_cmd_addr    ,//memory request address
    output                        nice_icb_cmd_read    ,//0:write 1:read
    output [`E203_XLEN-1:0]       nice_icb_cmd_wdata   ,//write data request是NICE与memory之间传输的数据首先读取RS寄存器中存储的内存地址随后完成对应内存地址的数据读写
//    output [`E203_XLEN_MW-1:0]  nice_icb_cmd_wmask   ,
    output [1:0]                  nice_icb_cmd_size    ,//00:byte 01:half-word 10:word
    // Memory lsu_rsp	
    input                         nice_icb_rsp_valid   ,//e203 send memory response
    output                        nice_icb_rsp_ready   ,//nice can receive memory
    input  [`E203_XLEN-1:0]       nice_icb_rsp_rdata   ,//the data read from memory
    input                         nice_icb_rsp_err      //error during memory access

);

   localparam ROWBUF_DP = 4;
   localparam ROWBUF_IDX_W = 2;
   localparam ROW_IDX_W = 2;
   localparam COL_IDX_W = 4;
   localparam PIPE_NUM = 3;


// here we only use custom3: 
// CUSTOM0 = 7'h0b, R type
// CUSTOM1 = 7'h2b, R tpye
// CUSTOM2 = 7'h5b, R type
// CUSTOM3 = 7'h7b, R type

// RISC-V format  
//	.insn r  0x33,  0,  0, a0, a1, a2       0:  00c58533[ 	]+add [ 	]+a0,a1,a2
//	.insn i  0x13,  0, a0, a1, 13           4:  00d58513[ 	]+addi[ 	]+a0,a1,13
//	.insn i  0x67,  0, a0, 10(a1)           8:  00a58567[ 	]+jalr[ 	]+a0,10 (a1)
//	.insn s   0x3,  0, a0, 4(a1)            c:  00458503[ 	]+lb  [ 	]+a0,4(a1)
//	.insn sb 0x63,  0, a0, a1, target       10: feb508e3[ 	]+beq [ 	]+a0,a1,0 target
//	.insn sb 0x23,  0, a0, 4(a1)            14: 00a58223[ 	]+sb  [ 	]+a0,4(a1)
//	.insn u  0x37, a0, 0xfff                18: 00fff537[ 	]+lui [ 	]+a0,0xfff
//	.insn uj 0x6f, a0, target               1c: fe5ff56f[ 	]+jal [ 	]+a0,0 target
//	.insn ci 0x1, 0x0, a0, 4                20: 0511    [ 	]+addi[ 	]+a0,a0,4
//	.insn cr 0x2, 0x8, a0, a1               22: 852e    [ 	]+mv  [ 	]+a0,a1
//	.insn ciw 0x0, 0x0, a1, 1               24: 002c    [ 	]+addi[ 	]+a1,sp,8
//	.insn cb 0x1, 0x6, a1, target           26: dde9    [ 	]+beqz[ 	]+a1,0 target
//	.insn cj 0x1, 0x5, target               28: bfe1    [ 	]+j   [ 	]+0 targe

   
   // decode
   
   wire [6:0] opcode      = {7{nice_req_valid}} & nice_req_inst[6:0]; //opcode是前7位
   wire [2:0] rv32_func3  = {3{nice_req_valid}} & nice_req_inst[14:12];//rv32_func3为{14->12}
   wire [6:0] rv32_func7  = {7{nice_req_valid}} & nice_req_inst[31:25];//rv32_func7为{31->25}

//   wire opcode_custom0 = (opcode == 7'b0001011); 
//   wire opcode_custom1 = (opcode == 7'b0101011); 
//   wire opcode_custom2 = (opcode == 7'b1011011); 
   wire opcode_custom3 = (opcode == 7'b1111011); //NICE使用了custom3型的RISC-V指令

   wire rv32_func3_000 = (rv32_func3 == 3'b000); //func3相关
   wire rv32_func3_001 = (rv32_func3 == 3'b001); 
   wire rv32_func3_010 = (rv32_func3 == 3'b010); 
   wire rv32_func3_011 = (rv32_func3 == 3'b011); 
   wire rv32_func3_100 = (rv32_func3 == 3'b100); 
   wire rv32_func3_101 = (rv32_func3 == 3'b101); 
   wire rv32_func3_110 = (rv32_func3 == 3'b110); 
   wire rv32_func3_111 = (rv32_func3 == 3'b111); 

   wire rv32_func7_0000000 = (rv32_func7 == 7'b0000000); //func7相关
   wire rv32_func7_0000001 = (rv32_func7 == 7'b0000001); 
   wire rv32_func7_0000010 = (rv32_func7 == 7'b0000010); 
   wire rv32_func7_0000011 = (rv32_func7 == 7'b0000011); 
   wire rv32_func7_0000100 = (rv32_func7 == 7'b0000100); 
   wire rv32_func7_0000101 = (rv32_func7 == 7'b0000101); 
   wire rv32_func7_0000110 = (rv32_func7 == 7'b0000110); 
   wire rv32_func7_0000111 = (rv32_func7 == 7'b0000111); 

   
   // custom3:
   // Supported format: only R type here
   // Supported instr:
   //  1. custom3 lbuf: load data(in memory) to row_buf
   //     lbuf (a1)
   //     .insn r opcode, func3, func7, rd, rs1, rs2    
   //  2. custom3 sbuf: store data(in row_buf) to memory
   //     sbuf (a1)
   //     .insn r opcode, func3, func7, rd, rs1, rs2    
   //  3. custom3 acc rowsum: load data from memory(@a1), accumulate row datas and write back 
   //     rowsum rd, a1, x0
   //     .insn r opcode, func3, func7, rd, rs1, rs2    
   
   //定义三条自定义指令在custom3情况下与func3、func7的关系
   wire custom3_lbuf     = opcode_custom3 & rv32_func3_010 & rv32_func7_0000001; //lbuf读取rs1
   wire custom3_sbuf     = opcode_custom3 & rv32_func3_010 & rv32_func7_0000010; //lbuf读取rs1
   wire custom3_rowsum   = opcode_custom3 & rv32_func3_110 & rv32_func7_0000110; //lbuf读取rs1写回rd

   
   //  multi-cyc op 
   //定义两个信号分别代表协处理器指令和需要访问memory
   
   wire custom_multi_cyc_op = custom3_lbuf | custom3_sbuf | custom3_rowsum;
   // need access memory
   wire custom_mem_op = custom3_lbuf | custom3_sbuf | custom3_rowsum;
 
   
   // NICE FSM NICE内部对指令的调度使用状态机有四个状态空闲和三个指令状态
   
   parameter NICE_FSM_WIDTH = 2; //初始化状态
   parameter IDLE     = 2'd0; 
   parameter LBUF     = 2'd1; 
   parameter SBUF     = 2'd2; 
   parameter ROWSUM   = 2'd3; 

   //现态和次态
   wire [NICE_FSM_WIDTH-1:0] state_r;          //状态指针
   wire [NICE_FSM_WIDTH-1:0] nxt_state;        //下一状态
   wire [NICE_FSM_WIDTH-1:0] state_idle_nxt;   //下一状态为初始化IDLE
   wire [NICE_FSM_WIDTH-1:0] state_lbuf_nxt;   //下一状态为lbuf
   wire [NICE_FSM_WIDTH-1:0] state_sbuf_nxt;   //下一状态为sbuf
   wire [NICE_FSM_WIDTH-1:0] state_rowsum_nxt; //下一状态为rowsum行累加

   wire nice_req_hsked;    //与cpu握手信号cpu发送指令
   wire nice_rsp_hsked;    //与cpu握手信号向cpu发送结果
   wire nice_icb_rsp_hsked;//与memory握手信号
   wire illgel_instr = ~(custom_multi_cyc_op);//为1没有输入指令illgel_instr为0代表是协处理器指令为1代表不是
     
   //定义状态离开使能信号四个状态的和真实状态的共5个
   wire state_idle_exit_ena;  //退出初始化状态使能
   wire state_lbuf_exit_ena;  //退出lbuf状态使能 
   wire state_sbuf_exit_ena;  //退出sbuf状态使能  
   wire state_rowsum_exit_ena;//退出rowsum行累加状态使能 
   wire state_ena;            //状态使能

   //定义现在是什么状态的四个信号
   wire state_is_idle     = (state_r == IDLE);  //state是idle时当前状态是初始化
   wire state_is_lbuf     = (state_r == LBUF);  //state是lbuf时当前状态是lbuf状态 
   wire state_is_sbuf     = (state_r == SBUF);  //state是sbuf时当前状态是sbuf状态
   wire state_is_rowsum   = (state_r == ROWSUM);//state是rowsum时当前状态是行累加状态 
   
   /状态转换
   //当前状态是初始化状态且cpu请求握手成功且当前没有指令在操作则退出初始化状态
   assign state_idle_exit_ena = state_is_idle & nice_req_hsked & ~illgel_instr; 
   //判断初始化状态的下一个状态输入指令是lbuf进入LBUF状态。。。否则保持初始化。三个指令状态的次态都为IDLE
   assign state_idle_nxt =  custom3_lbuf    ? LBUF   : 
                            custom3_sbuf    ? SBUF   :
                            custom3_rowsum  ? ROWSUM :
			    IDLE;

   wire lbuf_icb_rsp_hsked_last;//lbuf操作结束信号 
   //当前状态是lbuflbuf操作完成则退出lbuf状态使能为1
   //给状态离开使能信号赋值当现态为IDLE并且nice_req_hsked)并且当前为三指令之一state_idle_exit_ena为高
   assign state_lbuf_exit_ena = state_is_lbuf & lbuf_icb_rsp_hsked_last; 
   //现态为lbuf并且(lbuf_icb_rsp_hsked_last)state_lbuf_exit_ena为高
   assign state_lbuf_nxt = IDLE;//lbuf下一状态是idle以下类似
   wire sbuf_icb_rsp_hsked_last; 
   assign state_sbuf_exit_ena = state_is_sbuf & sbuf_icb_rsp_hsked_last; 
   assign state_sbuf_nxt = IDLE;
   wire rowsum_done; 
   assign state_rowsum_exit_ena = state_is_rowsum & rowsum_done; 
   assign state_rowsum_nxt = IDLE;

   //次态赋值当退出相应操作结束时状态使能为1时下一个状态切换至IDLE初始化
   assign nxt_state =   ({NICE_FSM_WIDTH{state_idle_exit_ena   }} & state_idle_nxt   )
                      | ({NICE_FSM_WIDTH{state_lbuf_exit_ena   }} & state_lbuf_nxt   ) 
                      | ({NICE_FSM_WIDTH{state_sbuf_exit_ena   }} & state_sbuf_nxt   ) 
                      | ({NICE_FSM_WIDTH{state_rowsum_exit_ena }} & state_rowsum_nxt ) 
                      ;
   //状态转换使能为四个使能的或。当退出相应操作使能为1时将状态使能置为1
   assign state_ena =   state_idle_exit_ena | state_lbuf_exit_ena 
                      | state_sbuf_exit_ena | state_rowsum_exit_ena;
   //时序状态机调用sirv_gnrl_dfflrD触发器实现状态机
   //该模块是一个buffer当状态切换至使能为1时输入下一个状态打一拍后从state_r输出
   sirv_gnrl_dfflr #(NICE_FSM_WIDTH)   state_dfflr (state_ena, nxt_state, state_r, nice_clk, nice_rst_n);

   
   // instr EXU
   
   wire [ROW_IDX_W-1:0]  clonum = 2'b10;  // fixed clonum///01
   //wire [COL_IDX_W-1:0]  rownum;

    1. custom3_lbuf
   ///这里是一个lbuf的计数器
   wire [ROWBUF_IDX_W-1:0] lbuf_cnt_r;   //现在计数值3个
   wire [ROWBUF_IDX_W-1:0] lbuf_cnt_nxt; //下一个计数值
   wire lbuf_cnt_clr;                    //计数清零使能
   wire lbuf_cnt_incr;                   //计数增加使能
   wire lbuf_cnt_ena;                    //计数D触发器使能
   wire lbuf_cnt_last;                   //计数到最后值
   wire lbuf_icb_rsp_hsked;              //状态机为lbuf并且储存响应握手成功
   wire nice_rsp_valid_lbuf;             //状态机为lbuf计数到最后值E203发出储存响应信号
   wire nice_icb_cmd_valid_lbuf;         //状态机为lbuf计数值小于最后值

   //信号赋值
   //已知assign nice_icb_rsp_hsked = nice_icb_rsp_valid & nice_icb_rsp_ready;并且nice_icb_rsp_ready is 1'b1 always所以nice_icb_rsp_hsked = nice_icb_rsp_valid
   assign lbuf_icb_rsp_hsked = state_is_lbuf & nice_icb_rsp_hsked; //当前状态为lbuf储存响应握手
   assign lbuf_icb_rsp_hsked_last = lbuf_icb_rsp_hsked & lbuf_cnt_last; //当前状态为lbuf储存响应握手计数为最后值
   assign lbuf_cnt_last = (lbuf_cnt_r == clonum); //即计数到最后值也就是lbuf_cnt_r为clonum2‘b10
   //已知assign nice_req_hsked = nice_req_valid & nice_req_ready;所以lbuf_cnt_clr含义为当前指令为lbuf命令请求握手
   assign lbuf_cnt_clr = custom3_lbuf & nice_req_hsked;
   assign lbuf_cnt_incr = lbuf_icb_rsp_hsked & ~lbuf_cnt_last;//当前状态为lbuf储存响应握手计数值不是最后值
   assign lbuf_cnt_ena = lbuf_cnt_clr | lbuf_cnt_incr;//当前指令为lbuf命令请求握手或者当前状态lbuf储存指令握手计数值不是最后值
   //当前指令lbuf命令请求握手lbuf_cnt_nxt归零当前状态lbuf储存响应握手计数值不是最后值lbuf_cnt_nxt为lbuf_cnt_r+1
   assign lbuf_cnt_nxt =   ({ROWBUF_IDX_W{lbuf_cnt_clr }} & {ROWBUF_IDX_W{1'b0}})
                         | ({ROWBUF_IDX_W{lbuf_cnt_incr}} & (lbuf_cnt_r + 1'b1) )
                         ;
   //D触发器构成时序计数器时钟nice_clk ; 复位信号nice_rst_n ; 使能信号lbuf_cnt_ena ;输入数据lbuf_cnt_nxt  输出数据lbuf_cnt_r
   sirv_gnrl_dfflr #(ROWBUF_IDX_W)   lbuf_cnt_dfflr (lbuf_cnt_ena, lbuf_cnt_nxt, lbuf_cnt_r, nice_clk, nice_rst_n);

   // nice_rsp_valid wait for nice_icb_rsp_valid in LBUF
   assign nice_rsp_valid_lbuf = state_is_lbuf & lbuf_cnt_last & nice_icb_rsp_valid;//当前状态为lbuf计数值为最后值E203发出储存响应信号

   // nice_icb_cmd_valid sets when lbuf_cnt_r is not full in LBUF
   assign nice_icb_cmd_valid_lbuf = (state_is_lbuf & (lbuf_cnt_r < clonum));//当前状态为lbuf且现计数值小于最后值

    2. custom3_sbuf
   wire [ROWBUF_IDX_W-1:0] sbuf_cnt_r;   //当前计数值
   wire [ROWBUF_IDX_W-1:0] sbuf_cnt_nxt; //下个计数值
   wire sbuf_cnt_clr;
   wire sbuf_cnt_incr;                   //sbuf_cnt增加使能
   wire sbuf_cnt_ena;                    //D触发器使能
   wire sbuf_cnt_last;                   //当前计数值为最后值
   wire sbuf_icb_cmd_hsked;              //当前状态为sbuf或(状态为IDLE且指令为sbuf)储存握手成功
   wire sbuf_icb_rsp_hsked;              //当前状态为sbuf储存响应握手成功
   wire nice_rsp_valid_sbuf;             //状态机为sbuf计数到最后值E203发出储存响应信号
   wire nice_icb_cmd_valid_sbuf;         //状态为sbufsbuf_cmd_cnt_r小于等于最后值sbuf_cnt不是最后值
   wire nice_icb_cmd_hsked;              //储存请求握手成功

   assign sbuf_icb_cmd_hsked = (state_is_sbuf | (state_is_idle & custom3_sbuf)) & nice_icb_cmd_hsked;//当前状态为sbuf或idle状态指令为sbuf)储存请求握手成功
   assign sbuf_icb_rsp_hsked = state_is_sbuf & nice_icb_rsp_hsked;//当前状态sbuf储存响应握手
   assign sbuf_icb_rsp_hsked_last = sbuf_icb_rsp_hsked & sbuf_cnt_last;//当前状态sbuf储存响应握手计数值为最后值
   assign sbuf_cnt_last = (sbuf_cnt_r == clonum);//计数值为最后值
   //assign sbuf_cnt_clr = custom3_sbuf & nice_req_hsked;
   assign sbuf_cnt_clr = sbuf_icb_rsp_hsked_last;//就是sbuf_icb_rsp_hsked_last当前状态sbuf储存响应握手计数值为最后值
   assign sbuf_cnt_incr = sbuf_icb_rsp_hsked & ~sbuf_cnt_last;//当前状态sbuf储存响应握手计数值不是最后值
   assign sbuf_cnt_ena = sbuf_cnt_clr | sbuf_cnt_incr; //当前状态sbuf储存响应握手、
   //当前状态sbuf储存响应握手计数值为最后值则为2'b00否则为现在计数值+1
   assign sbuf_cnt_nxt =   ({ROWBUF_IDX_W{sbuf_cnt_clr }} & {ROWBUF_IDX_W{1'b0}})
                         | ({ROWBUF_IDX_W{sbuf_cnt_incr}} & (sbuf_cnt_r + 1'b1) )
                         ;
   //D触发器构成时序计数器
   sirv_gnrl_dfflr #(ROWBUF_IDX_W)   sbuf_cnt_dfflr (sbuf_cnt_ena, sbuf_cnt_nxt, sbuf_cnt_r, nice_clk, nice_rst_n);

   // nice_rsp_valid wait for nice_icb_rsp_valid in SBUF
   //当前状态sbuf计数值为最后值E203发出储存响应信号
   assign nice_rsp_valid_sbuf = state_is_sbuf & sbuf_cnt_last & nice_icb_rsp_valid;
   
   //sbuf_cmd计数器
   wire [ROWBUF_IDX_W-1:0] sbuf_cmd_cnt_r;  //sbuf_cmd现计数值
   wire [ROWBUF_IDX_W-1:0] sbuf_cmd_cnt_nxt;//sbuf_cmd下个计数值 
   wire sbuf_cmd_cnt_clr;                   //当前状态sbuf储存响应握手sbuf计数值为最后值
   wire sbuf_cmd_cnt_incr;                  //当前状态为sbuf或idle状态指令为sbuf)储存请求握手成功subf_cmd计数值不是最后值
   wire sbuf_cmd_cnt_ena;                   //当前状态sbuf储存响应握手sbuf计数值为最后值或当前状态为sbuf或idle状态指令为sbuf)储存请求握手成功subf_cmd计数值不是最后值
   wire sbuf_cmd_cnt_last;                  //sbuf_cmd计数值为最后值

   assign sbuf_cmd_cnt_last = (sbuf_cmd_cnt_r == clonum); //sbuf_cmd计数值为最后值
   assign sbuf_cmd_cnt_clr = sbuf_icb_rsp_hsked_last;     //当前状态sbuf储存响应握手sbuf计数值为最后值
   assign sbuf_cmd_cnt_incr = sbuf_icb_cmd_hsked & ~sbuf_cmd_cnt_last;//当前状态为sbuf或idle状态指令为sbuf)储存请求握手成功subf_cmd计数值不是最后值
   assign sbuf_cmd_cnt_ena = sbuf_cmd_cnt_clr | sbuf_cmd_cnt_incr;//当前状态sbuf储存响应握手sbuf计数值为最后值或当前状态为sbuf或idle状态指令为sbuf)储存请求握手成功subf_cmd计数值不是最后值
   //当前状态sbuf储存响应握手sbuf计数为最后值为2'b00当前状态为sbuf或idle状态指令为sbuf)储存请求握手成功sbuf_cmd计数值不是最后值为sbuf_cmd_cnt_r+1
   assign sbuf_cmd_cnt_nxt =   ({ROWBUF_IDX_W{sbuf_cmd_cnt_clr }} & {ROWBUF_IDX_W{1'b0}})
                             | ({ROWBUF_IDX_W{sbuf_cmd_cnt_incr}} & (sbuf_cmd_cnt_r + 1'b1) )
   
   //D触发器构成时序计数器                          ;
   sirv_gnrl_dfflr #(ROWBUF_IDX_W)   sbuf_cmd_cnt_dfflr (sbuf_cmd_cnt_ena, sbuf_cmd_cnt_nxt, sbuf_cmd_cnt_r, nice_clk, nice_rst_n);

   // nice_icb_cmd_valid sets when sbuf_cmd_cnt_r is not full in SBUF
   //当前状态sbufsbuf_cmd小于等于最后值sbuf不等于最后值
   assign nice_icb_cmd_valid_sbuf = (state_is_sbuf & (sbuf_cmd_cnt_r <= clonum) & (sbuf_cnt_r != clonum));


    3. custom3_rowsum
   // rowbuf counter 
   wire [ROWBUF_IDX_W-1:0] rowbuf_cnt_r; 
   wire [ROWBUF_IDX_W-1:0] rowbuf_cnt_nxt; 
   wire rowbuf_cnt_clr;
   wire rowbuf_cnt_incr;
   wire rowbuf_cnt_ena;
   wire rowbuf_cnt_last;
   wire rowbuf_icb_rsp_hsked;
   wire rowbuf_rsp_hsked;
   wire nice_rsp_valid_rowsum;

   //信号赋值
   assign rowbuf_rsp_hsked = nice_rsp_valid_rowsum & nice_rsp_ready;
   assign rowbuf_icb_rsp_hsked = state_is_rowsum & nice_icb_rsp_hsked;
   assign rowbuf_cnt_last = (rowbuf_cnt_r == clonum);
   assign rowbuf_cnt_clr = rowbuf_icb_rsp_hsked & rowbuf_cnt_last;
   assign rowbuf_cnt_incr = rowbuf_icb_rsp_hsked & ~rowbuf_cnt_last;
   assign rowbuf_cnt_ena = rowbuf_cnt_clr | rowbuf_cnt_incr;
   assign rowbuf_cnt_nxt =   ({ROWBUF_IDX_W{rowbuf_cnt_clr }} & {ROWBUF_IDX_W{1'b0}})
                           | ({ROWBUF_IDX_W{rowbuf_cnt_incr}} & (rowbuf_cnt_r + 1'b1))
                           ;
   //assign nice_icb_cmd_valid_rowbuf =   (state_is_idle & custom3_rowsum)
   //                                  | (state_is_rowsum & (rowbuf_cnt_r <= clonum) & (clonum != 0))
   //                                  ;

   //D触发器构成时序计数器
   sirv_gnrl_dfflr #(ROWBUF_IDX_W)   rowbuf_cnt_dfflr (rowbuf_cnt_ena, rowbuf_cnt_nxt, rowbuf_cnt_r, nice_clk, nice_rst_n);
  
   //rowsum的recieve data buffer
   // recieve data buffer, to make sure rowsum ops come from registers 
   wire rcv_data_buf_ena;
   wire rcv_data_buf_set;
   wire rcv_data_buf_clr;
   wire rcv_data_buf_valid;
   wire [`E203_XLEN-1:0] rcv_data_buf; 
   wire [ROWBUF_IDX_W-1:0] rcv_data_buf_idx; 
   wire [ROWBUF_IDX_W-1:0] rcv_data_buf_idx_nxt; 

   //信号赋值
   assign rcv_data_buf_set = rowbuf_icb_rsp_hsked;
   assign rcv_data_buf_clr = rowbuf_rsp_hsked;
   assign rcv_data_buf_ena = rcv_data_buf_clr | rcv_data_buf_set;
   assign rcv_data_buf_idx_nxt =   ({ROWBUF_IDX_W{rcv_data_buf_clr}} & {ROWBUF_IDX_W{1'b0}})
                                 | ({ROWBUF_IDX_W{rcv_data_buf_set}} & rowbuf_cnt_r        );

   //D触发器构成时序计数器第一个是使能信号的一个时钟延迟第二个是输入数据的缓冲第三个是对rowbuf写入的序号
   sirv_gnrl_dfflr #(1)   rcv_data_buf_valid_dfflr (1'b1, rcv_data_buf_ena, rcv_data_buf_valid, nice_clk, nice_rst_n);
   sirv_gnrl_dfflr #(`E203_XLEN)   rcv_data_buf_dfflr (rcv_data_buf_ena, nice_icb_rsp_rdata, rcv_data_buf, nice_clk, nice_rst_n);
   sirv_gnrl_dfflr #(ROWBUF_IDX_W)   rowbuf_cnt_d_dfflr (rcv_data_buf_ena, rcv_data_buf_idx_nxt, rcv_data_buf_idx, nice_clk, nice_rst_n);

   // rowsum的累加器模块
   // rowsum accumulator 
   wire [`E203_XLEN-1:0] rowsum_acc_r;
   wire [`E203_XLEN-1:0] rowsum_acc_nxt;
   wire [`E203_XLEN-1:0] rowsum_acc_adder;
   wire rowsum_acc_ena;
   wire rowsum_acc_set;
   wire rowsum_acc_flg;
   wire nice_icb_cmd_valid_rowsum;
   wire [`E203_XLEN-1:0] rowsum_res;

   //rowsum的累加信号赋值
   //rowsum_acc_flgrcv_data_buf_idx非零且上个周期的状态为rowsum时储存响应握手或E203发出nice_rsp_ready信号
   assign rowsum_acc_set = rcv_data_buf_valid & (rcv_data_buf_idx == {ROWBUF_IDX_W{1'b0}});//32'b0
   assign rowsum_acc_flg = rcv_data_buf_valid & (rcv_data_buf_idx != {ROWBUF_IDX_W{1'b0}});
   assign rowsum_acc_adder = rcv_data_buf + rowsum_acc_r;**************最重要的加法运算assign <寄存器类型变量> = <赋值表达式>****//
   assign rowsum_acc_ena = rowsum_acc_set | rowsum_acc_flg;
   assign rowsum_acc_nxt =   ({`E203_XLEN{rowsum_acc_set}} & rcv_data_buf)
                           | ({`E203_XLEN{rowsum_acc_flg}} & rowsum_acc_adder)
                           ;
   //D触发器构成时序累加的时序操作
   sirv_gnrl_dfflr #(`E203_XLEN)   rowsum_acc_dfflr (rowsum_acc_ena, rowsum_acc_nxt, rowsum_acc_r, nice_clk, nice_rst_n);

   assign rowsum_done = state_is_rowsum & nice_rsp_hsked;
   assign rowsum_res  = rowsum_acc_r;  //rowsum finishes when the last acc data is added to rowsum_acc_r  

    nice_icb_cmd_valid sets when rcv_data_buf_idx is not full in LBUF 
   assign nice_rsp_valid_rowsum = state_is_rowsum & (rcv_data_buf_idx == clonum) & ~rowsum_acc_flg;

   // nice_icb_cmd_valid sets when rcv_data_buf_idx is not full in LBUF
   assign nice_icb_cmd_valid_rowsum = state_is_rowsum & (rcv_data_buf_idx < clonum) & ~rowsum_acc_flg;

    rowbufrowbuf是数据缓存lbuf和rowsum会写入sbuf会读出
   // rowbuf access list:
   //  1. lbuf will write to rowbuf, write data comes from memory, data length is defined by clonum 
   //  2. sbuf will read from rowbuf, and store it to memory, data length is defined by clonum 
   //  3. rowsum will accumulate data, and store to rowbuf, data length is defined by clonum 
   wire [`E203_XLEN-1:0] rowbuf_r [ROWBUF_DP-1:0];   //4个32位的数据
   wire [`E203_XLEN-1:0] rowbuf_wdat [ROWBUF_DP-1:0];//4个32位的数据
   wire [ROWBUF_DP-1:0]  rowbuf_we;                  //4位宽的数据
   wire [ROWBUF_IDX_W-1:0] rowbuf_idx_mux;           //rowbuf的序号选择
   wire [`E203_XLEN-1:0] rowbuf_wdat_mux;            //rowbuf的写入数据选择
   wire rowbuf_wr_mux;                               //rowbuf的写入信号选择
   //wire [ROWBUF_IDX_W-1:0] sbuf_idx; 
   
   // lbuf write to rowbuf
   wire [ROWBUF_IDX_W-1:0] lbuf_idx = lbuf_cnt_r;          //lbuf写入的序号写入序号选择为lbuf_cnt_r即lbuf计数的时序输出当前的计数值从0到2
   wire lbuf_wr = lbuf_icb_rsp_hsked;                      //lbuf写入的使能写入使能为lbuf_icb_rsp_hsked即当前状态为lbuf储存响应握手
   wire [`E203_XLEN-1:0] lbuf_wdata = nice_icb_rsp_rdata;  //lbuf写入的数据写入数据外部输入的从memory读取的数据

   // rowsum write to rowbuf(column accumulated data)
   wire [ROWBUF_IDX_W-1:0] rowsum_idx = rcv_data_buf_idx;  //rowsum写入的序号写入序号选择为rcv_data_buf_idx当前的计数值从0到2
   wire rowsum_wr = rcv_data_buf_valid;                    //rowsum写入的使能写入使能为rcv_data_buf-valid是rcv_data_buf_ena缓冲一个时钟
   wire [`E203_XLEN-1:0] rowsum_wdata = rowbuf_r[rowsum_idx] + rcv_data_buf; //	rowsum写入的数据写入数据为rowbuf_r当前数据与rcv_data_buf的加和

   // rowbuf write mux
   //写入数据选择
   assign rowbuf_wdat_mux =   ({`E203_XLEN{lbuf_wr  }} & lbuf_wdata  )
                            | ({`E203_XLEN{rowsum_wr}} & rowsum_wdata)
                            ;
   //写入使能选择lbuf_wr与rowsum_wr的或
   assign rowbuf_wr_mux   =  lbuf_wr | rowsum_wr;
   //写入序号选择若lbuf_wr为高则为luf_idx若rowsum_wr为高则为rowsum_dix
   assign rowbuf_idx_mux  =   ({ROWBUF_IDX_W{lbuf_wr  }} & lbuf_idx  )
                            | ({ROWBUF_IDX_W{rowsum_wr}} & rowsum_idx)
                            ;  
   
   D触发器构成时序///
   //实例化4个输入的32位的D触发器
   // rowbuf inst
   genvar i;
   generate 
     for (i=0; i<ROWBUF_DP; i=i+1) begin:gen_rowbuf
       //rowbuf_we为使能信号为rowbuf_wr_mux与一个表达式的与i的低2位与rowbuf_idx_mux相等才可以
       assign rowbuf_we[i] =   (rowbuf_wr_mux & (rowbuf_idx_mux == i[ROWBUF_IDX_W-1:0]))
                             ;
       //rowbuf_wdat为输入数据使能时为rowbuf_wdat_mux
       assign rowbuf_wdat[i] =   ({`E203_XLEN{rowbuf_we[i]}} & rowbuf_wdat_mux   )
                               ;
  
       sirv_gnrl_dfflr #(`E203_XLEN) rowbuf_dfflr (rowbuf_we[i], rowbuf_wdat[i], rowbuf_r[i], nice_clk, nice_rst_n);
     end
   endgenerate

    mem aacess addr managementmemory的地址
   wire [`E203_XLEN-1:0] maddr_acc_r; 
   assign nice_icb_cmd_hsked = nice_icb_cmd_valid & nice_icb_cmd_ready;   //储存请求握手
   // custom3_lbuflbuf访问memory的使能
   //当前状态为idle命令为lbuf并且储存请求握手或当前状态lbuf储存请求握手
   //wire [`E203_XLEN-1:0] lbuf_maddr    = state_is_idle ? nice_req_rs1 : maddr_acc_r ; 
   wire lbuf_maddr_ena    =   (state_is_idle & custom3_lbuf & nice_icb_cmd_hsked)
                            | (state_is_lbuf & nice_icb_cmd_hsked)
                            ;

   // custom3_sbuf sbuf访问memory的使能
   //当前状态为idle命令为sbuf并且储存请求握手或当前状态sbuf储存请求握手
   //wire [`E203_XLEN-1:0] sbuf_maddr    = state_is_idle ? nice_req_rs1 : maddr_acc_r ; 
   wire sbuf_maddr_ena    =   (state_is_idle & custom3_sbuf & nice_icb_cmd_hsked)
                            | (state_is_sbuf & nice_icb_cmd_hsked)
                            ;

   // custom3_rowsum	rowsum访问memory的使能
   //当前状态为idle命令为rowsum并且储存请求握手或当前状态rowsum储存请求握手
   //wire [`E203_XLEN-1:0] rowsum_maddr  = state_is_idle ? nice_req_rs1 : maddr_acc_r ; 
   wire rowsum_maddr_ena  =   (state_is_idle & custom3_rowsum & nice_icb_cmd_hsked)
                            | (state_is_rowsum & nice_icb_cmd_hsked)
                            ;

   // maddr acc 
   //wire  maddr_incr = lbuf_maddr_ena | sbuf_maddr_ena | rowsum_maddr_ena | rbuf_maddr_ena;
   //当前状态为idle命令有效并且储存请求握手或当前状态非idle储存请求握手
   wire  maddr_ena = lbuf_maddr_ena | sbuf_maddr_ena | rowsum_maddr_ena;//访问memory的使能
   //当前状态为idle命令为有效并且储存请求握手
   wire  maddr_ena_idle = maddr_ena & state_is_idle;//访问memory的使能且当前状态为idle
  
  //当前状态为idle命令为有效并且储存请求握手为寄存器1值否则为maddr_acc_r.且每次读写的内存地址逐次加4
//maddr_acc_r即为rs1寄存器地址每次加4这是因为32/8=4对于32位数据在memory中需要占据4个字节。
   wire [`E203_XLEN-1:0] maddr_acc_op1 = maddr_ena_idle ? nice_req_rs1 : maddr_acc_r; // not reused
   //32/8 = 4所以每次要加4
   wire [`E203_XLEN-1:0] maddr_acc_op2 = maddr_ena_idle ? `E203_XLEN'h4 : `E203_XLEN'h4; 
   //下一个地址为当前地址+4
   wire [`E203_XLEN-1:0] maddr_acc_next = maddr_acc_op1 + maddr_acc_op2;//操作数1操作数2
   wire  maddr_acc_ena = maddr_ena;  //	访问memory的使能为当前状态为idle命令有效并且储存请求握手或当前状态非idle储存请求握手
   
   //D触发器使能信号maddr_acc_ena输入数据maddr_acc_next输出maddr_acc_r
   sirv_gnrl_dfflr #(`E203_XLEN)   maddr_acc_dfflr (maddr_acc_ena, maddr_acc_next, maddr_acc_r, nice_clk, nice_rst_n);

   
   // Control cmd_req
   
   assign nice_req_hsked = nice_req_valid & nice_req_ready;//命令请求握手
   //nice发出的命令请求握手信号当前状态是idle且指令有效则为nice_icb_cmd_ready否则为1'b1
   assign nice_req_ready = state_is_idle & (custom_mem_op ? nice_icb_cmd_ready : 1'b1);

   
   // Control cmd_rsp
   
   assign nice_rsp_hsked = nice_rsp_valid & nice_rsp_ready; //命令响应握手
   assign nice_icb_rsp_hsked = nice_icb_rsp_valid & nice_icb_rsp_ready;//储存响应握手
   //当前状态lbuflbuf计数值为最后值E203发出储存响应信号或当前状态sbufsbuf计数值为最后值E203发出储存响应信号或当前状态rowsumrcv_data_buf_idx计数值为最后值rowsum_acc_flg为低或rcv_data_buf_idx非零且上个周期的状态为rowsum时储存响应握手或E203发出nice_rsp_ready信号
   assign nice_rsp_valid = nice_rsp_valid_rowsum | nice_rsp_valid_sbuf | nice_rsp_valid_lbuf;
   assign nice_rsp_rdat  = {`E203_XLEN{state_is_rowsum}} & rowsum_res;//当前状态为rowsum时为rowsum_res

   // memory access bus error
   //assign nice_rsp_err_irq  =   (nice_icb_rsp_hsked & nice_icb_rsp_err)
   //                          | (nice_req_hsked & illgel_instr)
   //                          ; 
   assign nice_rsp_err   =   (nice_icb_rsp_hsked & nice_icb_rsp_err);//储存响应握手且在访问memory时出错

   
   // Memory lsumemory相关
   
   // memory access list:
   //  1. In IDLE, custom_mem_op will access memory(lbuf/sbuf/rowsum)
   //  2. In LBUF, it will read from memory as long as lbuf_cnt_r is not full
   //  3. In SBUF, it will write to memory as long as sbuf_cnt_r is not full
   //  3. In ROWSUM, it will read from memory as long as rowsum_cnt_r is not full
   //assign nice_icb_rsp_ready = state_is_ldst_rsp & nice_rsp_ready; 
   // rsp always ready
   assign nice_icb_rsp_ready = 1'b1; //始终为1'b1
   wire [ROWBUF_IDX_W-1:0] sbuf_idx = sbuf_cmd_cnt_r; 

   //当前状态为idle且E203发出nice_req_valid且指令有效或状态lbuflbuf计数值小于最后值或状态sbufsbuf_cmd小于等于最后值且sbuf计数值不是最后值或状态rowsumrcv_data_buf计数值小于最后值且rcv_data_buf_idx非零且上个周期的状态为rowsum时储存响应握手或E203发出nice_rsp_ready信号
   assign nice_icb_cmd_valid =   (state_is_idle & nice_req_valid & custom_mem_op)
                              | nice_icb_cmd_valid_lbuf
                              | nice_icb_cmd_valid_sbuf
                              | nice_icb_cmd_valid_rowsum
                              ;
   assign nice_icb_cmd_addr  = (state_is_idle & custom_mem_op) ? nice_req_rs1 :
                              maddr_acc_r;//状态idle且命令有效为寄存器1否则为maddr_acc_r
   assign nice_icb_cmd_read  = (state_is_idle & custom_mem_op) ? (custom3_lbuf | custom3_rowsum) : 
                              state_is_sbuf ? 1'b0 : 
                              1'b1;//状态idle且为lbuf或rowsumz指令为1为sbuf指令为0或者为sbuf状态为0否则为1
   assign nice_icb_cmd_wdata = (state_is_idle & custom3_sbuf) ? rowbuf_r[sbuf_idx] :
                              state_is_sbuf ? rowbuf_r[sbuf_idx] : 
                              `E203_XLEN'b0; //状态idlesbuf指令或subf状态为rowbuf_r[sbuf_idx]否则为0

   //assign nice_icb_cmd_wmask = {`sirv_XLEN_MW{custom3_sbuf}} & 4'b1111;
   assign nice_icb_cmd_size  = 2'b10;//为2代表4字节32位宽数据
   assign nice_mem_holdup    =  state_is_lbuf | state_is_sbuf | state_is_rowsum; //为非idle状态访问memory锁

   
   // nice_active
   
   assign nice_active = state_is_idle ? nice_req_valid : 1'b1;

endmodule
`endif//}

ps注释为本人根据网络上的资料和自己的理解所写。原创不易如果有用请给此篇博客点个赞吧

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6