jjinl的个人空间 https://blog.eetop.cn/jjinl [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

PicoRV32 笔记 04

热度 10已有 1962 次阅读| 2021-11-7 07:30 |系统分类:芯片设计| RISC-V, PicoRV32

PicoRV32 是一款RISC-V指令的实现的软核CPU。

PicoRV32实现指令rdcycle,rdcycleh,用于读取时钟计数,当使能ENABLE_COUNTERS和ENABLE_COUNTERS64,此指令便有效。

PicoRV32内部实现64bit的计数器count_cycle,定义在源码234行

在源码1486行-1492行对cout_cycle操作

由上源码可知,当使能ENABLE_COUNTERS,每个时钟的上升沿对count_cycle操作,

如果复位则count_cycle取值为0,反之自增1,如果没有使能ENABLE_COUNTERS64则把count_cycle的64bit-32bit设置为0,如果没有使能ENABLE_COUNTERS则count_cycle值为任意,与此同时对应的指令也会被取消,此时使用rdcycle,rdcycleh会导致硬件异常。

涉及到源码中对count_cycle操作的另一处,就是读取计数器的内容

在源码的1686行   “ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh”判断指令是否是 rdcycle, rdcycleh, rdinstr, rdinstrh这四条指令,如果是rdcycle,则把count_cycle[31:0]写到目标寄存器,如果是rdcycleh则把count_cycle[63:32]写到目标寄存器中。

is_rdcycle_rdcycleh_rdinstr_rdinstrh:是一个单bit信号,PicoRV32中有几个此类信号,用于对一类操作指令进行归类。

例如

assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh};

is_rdcycle_rdcycleh_rdinstr_rdinstrh:判断指令是否是  instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh其中的一个。注意 |{......} 中的|是个单目运算符,表示把组合后的信号的所有bit进行or运算。

is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal};判断指令是否是instr_lui, instr_auipc, instr_jal

is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub};判断指令是否是instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub

is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt};判断指令是否是instr_slti, instr_blt, instr_slt

is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw};判断指令是否是instr_lbu, instr_lhu, instr_lw

is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu};判断指令是is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu

is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011;判断指令是否是beq bne blt bge bltu bgeu

is_lb_lh_lw_lbu_lhu          <= mem_rdata_latched[6:0] == 7'b0000011;判断指令是否是lb lh lw lbu lhu

is_sb_sh_sw                  <= mem_rdata_latched[6:0] == 7'b0100011;判断指令是否是 sb sh sw

is_alu_reg_imm               <= mem_rdata_latched[6:0] == 7'b0010011;判断指令的原操作数是否是寄存器和立即数

is_alu_reg_reg               <= mem_rdata_latched[6:0] == 7'b0110011;判断指令的原操作数是否是寄存器和寄存器

is_slli_srli_srai <= is_alu_reg_imm && |{
                mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
                mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000,
                mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000
            };

判断指令是否是slli srli srai

is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{
                mem_rdata_q[14:12] == 3'b000,
                mem_rdata_q[14:12] == 3'b010,
                mem_rdata_q[14:12] == 3'b011,
                mem_rdata_q[14:12] == 3'b100,
                mem_rdata_q[14:12] == 3'b110,
                mem_rdata_q[14:12] == 3'b111
            };

判断指令是否是jalr addi slti sltiu xori ori andi

is_sll_srl_sra <= is_alu_reg_reg && |{
                mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000,
                mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000,
                mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000
            };

判断指令是否是sll srl sra

根据RISC-V的基础指令集RV32I表,其中47条指令,有11个opcode

7'b011_0111:  lui

7'b001_0111: auipc

7'b110_1111: jal

7'b110_0111:jalr

7'b110_0011: beq, bne, blt, bge, bltu, bgeu

7'b000_0011: lb, lh, lw, lbu, lhu

7'b010_0011: sb, sh, sw

7'b001_0011:addi, slti, sltiu, xori, ori, andi, slli, srli, srai

7'b011_0011:add, sub, sll, slt, sltu, xor, srl, sra, or, and

7'b000_1111: fence, fence.i

7'b111_0011: ecall, ebreak,  csrrw, csrrs, csrrc, csrrwi, csrrsi, csrrci

综上所述,PicoRV32首先通过opcode对指令先对指令进行分类

信号名操作吗对应指令
instr_lui7'b011_0111lui
instr_auipc7'b001_0111auipc
instr_jal7'b110_1111jal
instr_jalr7'b110_0111, fun3=3'b000jalr
is_beq_bne_blt_bge_bltu_bgeu7'b110_0011beq,bne,blt,bge,bltu,bgeu
is_lb_lh_lw_lbu_lhu7'b000_0011lb, lh, lw, lbu, lhu
is_sb_sh_sw7'b010_0011sb, sh, sw
is_alu_reg_imm7'b001_0011addi,slti,sltiu, xori,ori,andi,slli,srli,srai
is_alu_reg_reg7'b011_0011add, sub, sll, slt, sltu,xor, srl,sra,or,and
instr_getq7'b000_1011,fun7=7'b000_0000getq
instr_setq7'b000_1011,fun7=7'b000_0001setq
instr_retirq7'b000_1011,fun7=7'b000_0010retirq
instr_maskirq7'b000_1011,fun7=7'b000_0011maskirq
instr_waitirq7'b000_1011,fun7=7'b000_0100waitirq
instr_timer7'b000_1011,fun7=7'b000_0101timer

接下来在第一分类的基础上进行细分

跳转类的指令,6条

instr_beq :is_beq_bne_blt_bge_bltu_bgeu && fun3 =  3'b000;

instr_bne:is_beq_bne_blt_bge_bltu_bgeu && fun3 = 3'b001;
 instr_blt   : is_beq_bne_blt_bge_bltu_bgeu && fun3 =  3'b100;
 instr_bge   : is_beq_bne_blt_bge_bltu_bgeu && fun3 =  3'b101;
 instr_bltu  : is_beq_bne_blt_bge_bltu_bgeu && fun3 =  3'b110;
 instr_bgeu  : is_beq_bne_blt_bge_bltu_bgeu && fun3 =  3'b111;

加载指令,5条

 instr_lb    : is_lb_lh_lw_lbu_lhu && fun3 = 3'b000;
 instr_lh    : is_lb_lh_lw_lbu_lhu && fun3 = 3'b001;
 instr_lw    : is_lb_lh_lw_lbu_lhu && fun3 = 3'b010;
 instr_lbu   : is_lb_lh_lw_lbu_lhu && fun3 = 3'b100;
 instr_lhu   : is_lb_lh_lw_lbu_lhu && fun3 = 3'b101;

存储类指令,3条

 instr_sb    : is_sb_sh_sw && fun3 = 3'b000;
 instr_sh    : is_sb_sh_sw && fun3 = 3'b001;
  instr_sw    : is_sb_sh_sw && fun3 = 3'b010;

寄存器和立即数指令,9条

  instr_addi  : is_alu_reg_imm && fun3 =3'b000;
 instr_slti  : is_alu_reg_imm && fun3 = 3'b010;
  instr_sltiu : is_alu_reg_imm && fun3 = 3'b011;
  instr_xori  : is_alu_reg_imm && fun3 =3'b100;
  instr_ori   : is_alu_reg_imm && fun3 = 3'b110;
  instr_andi  : is_alu_reg_imm && fun3 = 3'b111;

  instr_slli  : is_alu_reg_imm && fun3 = 3'b001 && fun7 = 7'b0000000;
  instr_srli  : is_alu_reg_imm && fun3 =3'b101 && fun7 = 7'b0000000;
 instr_srai  : is_alu_reg_imm && fun3 = 3'b101 && fun7 = 7'b0100000;

寄存器和寄存器指令,10条

instr_add   : is_alu_reg_reg &&fun3 = 3'b000 && fun7 = 7'b0000000;
 instr_sub   : is_alu_reg_reg && fun3 = 3'b000 && fun7 = 7'b0100000;
  instr_sll   : is_alu_reg_reg && fun3 = 3'b001 && fun7 = 7'b0000000;
  instr_slt   : is_alu_reg_reg && fun3 = 3'b010 && fun7 = 7'b0000000;
  instr_sltu  : is_alu_reg_reg && fun3 = 3'b011 && fun7 = 7'b0000000;
 instr_xor   : is_alu_reg_reg && fun3 = 3'b100 && fun7 = 7'b0000000;
 instr_srl   : is_alu_reg_reg && fun3 = 3'b101 && fun7 = 7'b0000000;
 instr_sra   : is_alu_reg_reg && fun3 = 3'b101 && fun7 = 7'b0100000;
 instr_or    : is_alu_reg_reg && fun3 = 3'b110 && fun7 = 7'b0000000;
 instr_and   : is_alu_reg_reg && fun3 = 3'b111 && fun7 = 7'b0000000;

经过上述细分,支持的指令都可以识别到,接下来把相近功能的指令进行合并

is_lui_auipc_jal:判断指令是否是instr_lui, instr_auipc, instr_jal,

            这三条指令整合到一个信号,是因为这三个指令格式基本相同

            20bit立即数   |    5bit rd |    7bit操作码

        唯一的差别是jal指令的20位立即数排列方式不一样

        对于lui指令,把指令跟随的立即数低位补上12'b0加上高位一同放到目标寄存器,

                                rd = (imm<<12)

        对于auipc指令,把pc寄存器的值加上{立即数,12'b0}放到目标寄存器

                        rd = pc + (imm<<12)

        对于jal指令,跳转到地址,并把跳转前的下一条指令地址存储到rd中

                    rd = pc + 4

                    pc = pc + imm

is_slti_blt_slt:判断指令是否是slti, blt, slt.

        slti: 小于置位,当rs1 < 立即数[11:0] 时候设置rd为1,反之设置为0。 slt =set less then

        slt:小于置位,当rs1 < rs2时候,rd为1,反之为0

        blt: 小于跳转,当rs1 < rs2时候

is_lb_lh_lw_lbu_lhu:判断指令是否为lb, lh, lw, lbu, lhu

                lb: rs1+12位立即数符号扩展后作为地址,读取一个字节并作符号扩展后存放到rd中

                lh: rs1+12位立即数符号扩展后作为地址,读取一个16bit并作符号扩展后存放到rd中

                lw: rs1+12位立即数符号扩展后作为地址,读取一个32bit后存放到rd中

                lbu: rs1+12位立即数符号扩展后作为地址,读取一个8bit并作0扩展后存放到rd中

                lhu: rs1+12位立即数符号扩展后作为地址,读取一个16bit并作0扩展后存放到rd中

            公共的操作是提取地址

is_slli_srli_srai:判断指令是否是slli, srli, srai.这三条指令格式相同,除了操作码不一样

            slli: 把rs1左移n位,低位补0,结果写入rd中

            srli:把rs1右移n位,高位补0,结果写入rd中

            srai:把rs1右移n位,高位位补符号位,结果写入rd中

is_sb_sh_sw:判断指令是否为sb, sh,sw

                sb:  rs1+12位立即数符号扩展后作为地址,把rs2最低8bit作为数据写到总线上

                sh:  rs1+12位立即数符号扩展后作为地址,把rs2最低16bit作为数据写到总线上

                sw:  rs1+12位立即数符号扩展后作为地址,把rs2为数据写到总线上

            公共部分提取地址

is_sll_srl_sra:判断指令是否为sll, srl, sra,这三条指令格式相同,除了操作码不同

                sll :把寄存器rs1 左移 rs2位, rs2只有低5位有效

                srl :把寄存器rs1 右移 rs2位, rs2只有低5位有效

                sra :把寄存器rs1 右移 rs2位, 高位填充符号位,rs2只有低5位有效

....

PicoRV32 笔记 04 - jjinl的个人页面 - OSCHINA https://my.oschina.net/jjinl/blog/5290920


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 1

    粉丝
  • 1

    好友
  • 0

    获赞
  • 0

    评论
  • 60

    访问数
关闭

站长推荐 上一条 /2 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-4-20 20:51 , Processed in 0.032845 second(s), 14 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部