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



    前言:
      讲到蜂鸟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; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里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
    
    • 1

      其中,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;
    
    • 1
    • 2
    • 3

      当判断输入指令为其中一条时,将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;
    
    • 1
    • 2
    • 3
    • 4

      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//}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564

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

  • 相关阅读:
    面试题:经典常见排序算法 插入 冒泡 选择 归并 快速排序
    maven的下载、配置
    可以免费发外链的论坛有哪些?
    论文详读:IMPROVING CONVOLUTIONAL MODELS FOR HANDWRITTEN TEXT RECOGNITION
    基于JAVA中山学院教室管理系统计算机毕业设计源码+系统+数据库+lw文档+部署
    每日一题 712两个字符串的最小ASCLL删除和
    深度解读 Linux 内核级通用内存池 —— kmalloc 体系
    java入门 数组
    【PE806】Nim on Towers of Hanoi(汉诺塔游戏,生成函数)
    msql 批量更新生成不同的uuid()
  • 原文地址:https://blog.csdn.net/qq_43858116/article/details/125497749