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_lui 7'b011_0111 lui
instr_auipc 7'b001_0111 auipc
instr_jal 7'b110_1111 jal
instr_jalr 7'b110_0111, fun3=3'b000 jalr
is_beq_bne_blt_bge_bltu_bgeu 7'b110_0011 beq,bne,blt,bge,bltu,bgeu
is_lb_lh_lw_lbu_lhu 7'b000_0011 lb, lh, lw, lbu, lhu
is_sb_sh_sw 7'b010_0011 sb, sh, sw
is_alu_reg_imm 7'b001_0011 addi,slti,sltiu, xori,ori,andi,slli,srli,srai
is_alu_reg_reg 7'b011_0011 add, sub, sll, slt, sltu,xor, srl,sra,or,and
instr_getq 7'b000_1011,fun7=7'b000_0000 getq
instr_setq 7'b000_1011,fun7=7'b000_0001 setq
instr_retirq 7'b000_1011,fun7=7'b000_0010 retirq
instr_maskirq 7'b000_1011,fun7=7'b000_0011 maskirq
instr_waitirq 7'b000_1011,fun7=7'b000_0100 waitirq
instr_timer 7'b000_1011,fun7=7'b000_0101 timer

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

跳转类的指令,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相关推荐

  1. 取得 Git 仓库 —— Git 学习笔记 04

    取得 Git 仓库 -- Git 学习笔记 04 我认为, Git 的学习分为两大块:一是工作区.索引.本地版本库之间的交互:二是本地版本库和远程版本库之间的交互.第一块是基础,第二块是难点. 下面, ...

  2. SpringMVC-学习笔记04【SpringMVC返回值类型及响应数据类型】

    Java后端 学习路线 笔记汇总表[黑马程序员] SpringMVC-学习笔记01[SpringMVC概述及入门案例][day01] SpringMVC-学习笔记02[参数绑定及自定义类型转换] Sp ...

  3. Spring-学习笔记04【Spring的常用注解】

    Java后端 学习路线 笔记汇总表[黑马程序员] Spring-学习笔记01[Spring框架简介][day01] Spring-学习笔记02[程序间耦合] Spring-学习笔记03[Spring的 ...

  4. MyBatis-学习笔记04【04.自定义Mybatis框架基于注解开发】

    Java后端 学习路线 笔记汇总表[黑马程序员] MyBatis-学习笔记01[01.Mybatis课程介绍及环境搭建][day01] MyBatis-学习笔记02[02.Mybatis入门案例] M ...

  5. JavaWeb黑马旅游网-学习笔记04【BaseServlet抽取】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  6. Maven-学习笔记04【基础-Maven生命周期和概念模型图】

    Java后端 学习路线 笔记汇总表[黑马程序员] 黑马程序员(腾讯微云)Maven基础讲义.pdf Maven-学习笔记01[基础-Maven基本概念] Maven-学习笔记02[基础-Maven的安 ...

  7. Redis-学习笔记04【Jedis代码操作】

    Java后端 学习路线 笔记汇总表[黑马程序员] Redis-学习笔记01[Redis环境搭建] Redis-学习笔记02[Redis命令操作] Redis-学习笔记03[Redis持久化] Redi ...

  8. Ajax和JSON-学习笔记04【JSON_解析器】

    Java后端 学习路线 笔记汇总表[黑马程序员] Ajax和JSON-学习笔记01[原生JS方式实现Ajax] Ajax和JSON-学习笔记02[JQuery方式实现Ajax] Ajax和JSON-学 ...

  9. JQuery-学习笔记04【基础——JQuery基础案例】

    Java后端 学习路线 笔记汇总表[黑马程序员] JQuery-学习笔记01[基础--JQuery基础]--[day01] JQuery-学习笔记02[基础--JQuery选择器] JQuery-学习 ...

最新文章

  1. 用手指触碰电子,用心灵感受震荡
  2. python100个必背知识-学Python必背的初级单词,你都背了吗?
  3. 10进制与16进制之间的转换 delphi
  4. [转]在ubuntu上安装chrome浏览器
  5. centos6 配置ip、服务
  6. [LeetCode] 1091. Shortest Path in Binary Matrix
  7. 最近读的那些性能测试书
  8. 匀光匀色--直方图匹配算法实现与应用
  9. python的类作用_python——类中的self到底的作用及三个应用场景
  10. D3Vueecharts个人乱记
  11. 使用Dagger 2在GWT中进行依赖注入
  12. Jmeter——for循环控制器和if逻辑控制器
  13. ubuntu 安装yar和使用
  14. iPhone+wp7并行初体验
  15. 3.1EDA和数据描述: 探索性数据分析
  16. 如何在Mac上组合歌曲?
  17. JAVA输入jdb,解决 JAVA 单步调试键盘输入被 JDB 占用的问题
  18. dbeaver查看执行计划_SAP学习基础篇(52):PP模块-物料需求计划
  19. 简单java游戏代码_Java经典小游戏——贪吃蛇简单实现(附源码)
  20. 软件测试金九银十即将到来,求职套路多你有多大把握拿offer

热门文章

  1. lol韩服游戏内设置_LOL韩服更新账号教程 LOL韩服不能玩解决办法
  2. LAMPDISCUZ论坛
  3. 中国撸串大数据:13万家烧烤店的吃货最爱
  4. 从csdn搬家到博客园的说明
  5. 为了升级到架构师,程序员无需过度关注哪些技能?哪些技能不可缺?
  6. python反转一个三位整数的多种方法
  7. 多线程进阶(并发编程JUC)
  8. 海报设计创意套路大解析
  9. stack around the variable “XX” was corrupted的解决方法
  10. 台阶问题——动态规划