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

本文详细介绍了蜂鸟E203处理器中NICE协处理器的设计与自定义指令的实现过程。NICE协处理器作为一个独立于主核的计算单元,通过特定的RISC-V指令调用,实现了内存与缓存数据交换、累加和加密等功能。自定义指令的创建基于RISC-V架构预留的Custom-3类型,通过扩展指令编码,实现对协处理器的调用。NICE协处理器的调用流程包括请求通道、内存请求通道、反馈通道和内存响应通道,以及相应的状态机管理。文章还展示了具体指令的编码示例和实际应用,强调了性能提升效果。


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

1. 概念

  领域特定架构(Domain Specific Architecture,DSA),使用特定的硬件做特定的事情[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'b10:1位;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)
1111011,custom3010,只读取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)
1111011,custom3010,只读取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)
1111011,custom3110,读取rs1、rd的数据0000110,指向此条指令%0 ,写回rowsum的地址%1,保存addr地址不使用
把addr、rd的地址加载到读源寄存器1,写目标寄存器rd,编译器会自动分配rs1,rd用哪一个寄存器(这里是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操作结束信号 
   //当前状态是lbuf,lbuf操作完成,则退出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_dfflr,D触发器,实现状态机
   //该模块是一个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;         //状态为sbuf,sbuf_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
   //当前状态sbuf,sbuf_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_flg,rcv_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;

   //////////// rowbuf,rowbuf是数据缓存,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 management,memory的地址
   wire [`E203_XLEN-1:0] maddr_acc_r; 
   assign nice_icb_cmd_hsked = nice_icb_cmd_valid & nice_icb_cmd_ready;   //储存请求握手
   // custom3_lbuf,lbuf,访问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;//储存响应握手
   //(当前状态lbuf,lbuf计数值为最后值,E203发出储存响应信号)或(当前状态sbuf,sbuf计数值为最后值,E203发出储存响应信号)或(当前状态rowsum,rcv_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 lsu,memory相关
   ////////////////////////////////////////////////////////////
   // 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且指令有效)或(状态lbuf,lbuf计数值小于最后值)或(状态sbuf,sbuf_cmd小于等于最后值且sbuf计数值不是最后值)或(状态rowsum,rcv_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; //(状态idle,sbuf指令)或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,注释为本人根据网络上的资料和自己的理解所写。原创不易,如果有用请给此篇博客点个赞吧!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值