1.前言 本实验中我将使用Verilog HDL语言设计一个31条指令单周期的CPU设计,并完成前仿真、后仿真和下板调试运行。设计CPU是一项繁杂的任务,在此过程中,要明确每一步设计流程,才能减少Debug的时间(改bug怎的很费时间),提高效率。 大致流程如下:列出CPU指令表→绘制各个指令的数据流图→绘制数据流总图→列出指令信号表→编写代码实现CPU基础功能→测试→仿真下板
2.指令表 31条指令表如下: 其中的指令可以分为三类,分别是:
R-type: OP为000000,由func来决定他的功能,主要用于操作寄存器之间的算术和逻辑运算。rs和rt是源寄存器,通常存操作数,rd是目标寄存器,通常存结果。shamt代表移位操作中的位移量,是立即数。
I-type: I型指令都包含了一个立即数(常数),用于与常数相关的计算,观察表发现,I型指令将rd,shamt,func替换为了immediate,因此I型指令由op直接决定,rs作为源寄存器,rd作为目标寄存器。
J-type: J型指令只有两条,用来实现无条件跳转。
3.数据通路图 R-type 1.ADD 格式:ADD rd,rs,rt 目的:与32位数相加。 描述:rd←rs+rt 将通用寄存器中存的32位数据rs与rt相加产生一个32位数据存入目标寄存器rd。 (1)如果发生了溢出,则rd不改变且产生一个溢出的异常 (2)如果相加不溢出,则产生的32位数据直接存入目标寄存器rd。 操作:rd←rs+rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A+B→result) result→rd 指令流程图:
数据通路图:
2.ADDU 格式:ADDU rd,rs,rt 目的:与32位数相加。 描述:rd←rs+rt 将通用寄存器中存的32位数据rs与rt相加产生一个32位数据存入目标寄存器rd。在任何情况下都不会有溢出的异常 操作:rd←rs+rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A+B→result) result→rd 指令流程图:
数据通路图:
3.SUB 格式:SUB rd,rs,rt 目的:与32位数相减。 描述:rd←rs-rt 将通用寄存器中存的32位数据rs与rt相减产生一个32位数据存入目标寄存器rd。 (1)如果发生了溢出,则rd不改变且产生一个溢出的异常 (2)如果相减不溢出,则产生的32位数据直接存入目标寄存器rd。 操作:rd←rs-rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A-B→result) result→rd 指令流程图:
数据通路图:
4.SUBU 格式:SUBU rd,rs,rt 目的:与32位数相减。 描述:rd←rs-rt 将通用寄存器中存的32位数据rs与rt相减产生一个32位数据存入目标寄存器rd。在任何情况下都不会有溢出的异常 操作:rd←rs-rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A-B→result) result→rd 指令流程图:
数据通路图:
5.AND 格式:AND rd,rs,rt 目的:按位逻辑与。 描述:rd←rs AND rt 将通用寄存器rs和rt中的数据每一位做按位与操作,将结果存入目标寄存器rd中。 操作:rd←rs AND rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A AND B→result) result→rd 指令流程图:
数据通路图: 6.OR 格式:OR rd,rs,rt 目的:按位逻辑或。 描述:rd←rs OR rt 将通用寄存器rs和rt中的数据每一位做按位或操作,将结果存入目标寄存器rd中。 操作:rd←rs OR rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A OR B→result) result→rd 指令流程图:
数据通路图:
7.XOR 格式:XOR rd,rs,rt 目的:按位逻辑异或。 描述:rd←rs XOR rt 将通用寄存器rs和rt中的数据每一位做按位异或操作,将结果存入目标寄存器rd中。 操作:rd←rs XOR rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A XOR B→result) result→rd 指令流程图:
数据通路图:
8.NOR 格式:NOR rd,rs,rt 目的:按位逻辑或非。 描述:rd←rs NOR rt 将通用寄存器rs和rt中的数据每一位做按位或非操作,将结果存入目标寄存器rd中。 操作:rd←rs NOR rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A NOR B→result) result→rd 指令流程图:
数据通路图:
9.SLT(set less than) 格式:SLT rd,rs,rt 目的:通过小于的比较来记录结果 描述:rd←(rs < rt) 比较在rs和rt寄存器中保存的有符号数,用boolean值保存结果到rd寄存器中。如果rs小于rt,则结果为1,反之结果为0。算数比较不会引起溢出异常。 操作:rd←(rs < rt),PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT1。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A - B→result) SF→EXT1//1位拓展到32位 EXT1_OUT→rd 指令流程图:
数据通路图:
10.SLTU 格式:SLTU rd,rs,rt 目的:通过小于的比较来记录结果 描述:rd←(rs < rt) 比较在rs和rt寄存器中保存的无符号数,用boolean值保存结果到rd寄存器中。如果rs小于rt,则结果为1,反之结果为0。算数比较不会引起溢出异常。 操作:rd←(rs < rt),PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT1。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs→A,rt→B (A - B→result) SF→EXT1//1位拓展到32位 EXT1_OUT→rd 指令流程图:
数据通路图:
11.SLL(shift left logical) 格式:SLL rd,rt,sa 目的:通过数字0填充逻辑左移 描述:rd←rt<<sa 将通用寄存器rt的内容左移sa位,空余出来的位置用0来填充,把结果存入rd寄存器 操作:rd←rt< <sa,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[10:6]→EXT5 EXT5_OUT→A rt→B (B << A→result) result→rd 指令流程图:
数据通路图:
12.SRL(shift right logical) 格式:SRL rd,rt,sa 目的:通过数字0填充逻辑右移 描述:rd←rt>>sa 将通用寄存器rt的内容右移sa位,空余出来的位置用0来填充,把结果存入rd寄存器 操作:rd←rt>>sa,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[10:6]→EXT5 EXT5_OUT→A rt→B (B >> A→result) result→rd 指令流程图:
数据通路图:
13.SRA(shift right arithmetic) 格式:SRA rd,rt,sa 目的:通过数字填充算术右移 描述:rd←rt>>sa 将通用寄存器rt的32位内容右移sa位,高位用rt[31]来填充,结果存入通用寄存器rd。 操作:rd←rt>>sa,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[10:6]→EXT5 EXT5_OUT→A rt→B (B >> A→result) result→rd 指令流程图:
数据通路图:
14.SLLV(shift left logic variable) 格式:SLLV rd,rt,rs 目的:通过数字0填充逻辑左移 描述:rd←rt<<rs 将通用寄存器rt中的内容逻辑左移,左移的位数保存在rs寄存器中,空余出来的位置用0来填充,把结果存入rd寄存器。 操作:rd←rt<<rs,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs[4:0]→EXT5 EXT5_OUT→A rt→B (B << A→result) result→rd 指令流程图:
数据通路图:
15.SRLV(shift right logic variable) 格式:SRLV rd,rt,rs 目的:通过数字0填充逻辑右移 描述:rd←rt>>rs 将通用寄存器rt中的32位内容右移,高位用rt[31]来填充,结果存入通用寄存器rd。右移的位数由通用寄存器rs中的0~4bit确定 操作:rd←rt>>rs,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs[4:0]→EXT5 EXT5_OUT→A rt→B (B >> A→result) result→rd 指令流程图:
数据通路图:
16.SRAV(shift right arithmetic variable) 格式:SRAV rd,rt,rs 目的:通过数字填充算术右移 描述:rd←rt>>rs 将通用寄存器rt中的32位内容右移,高位用rt[31]来填充,结果存入通用寄存器rd。右移的位数由通用寄存器rs中的0~4bit确定 操作:rd←rt>>rs,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: rs[4:0]→EXT5 EXT5_OUT→A rt→B (B >> A→result) result→rd 指令流程图:
数据通路图:
17.JR(jump register) 格式:JR rs 目的:使用寄存器的跳转指令 描述:PC←rs 跳转地址存放在通用寄存器rs中,直接跳转到寄存器所存地址。 操作:rd←rt>>rs,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT5。 指令周期: PC→IMEM PC+4→NPC NPC→MUX rs→MUX//多路选择器,选择rs的地址或NPC的地址 MUX_OUT→PC 指令流程图:
数据通路图:
I-type 18.ADDI 格式:ADDI rd,rs,immediate 目的:使32位数据与一个立即数相加 描述:rd←rs+immediate 一个16位有符号的立即数与通用寄存器rs中的32位数相加产生一个32位的数存入目标寄存器rd。 (1)如果发生了溢出,则rd不改变且产生一个溢出的异常 (2)如果相加不溢出,则结果存入目标寄存器rd。 操作:rd←rs+immediate,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT16。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A+B→result) result→rd 指令流程图:
数据通路图:
19.ADDIU 格式:ADDIU rd,rs,immediate 目的:使32位数据与一个立即数相加 描述:rd←rs+immediate 一个16位有符号的立即数与通用寄存器rs中的32位数相加产生一个32位的数存入目标寄存器rd。 在任何情况下都不会有溢出的异常 操作:rd←rs+immediate,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT16。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A+B→result) result→rd 指令流程图:
数据通路图:
20.ANDI 格式:ANDI,rd,rs,immediate 目的:与一个常数做按位逻辑与。 描述:rd←rs AND immediate 将16位立即数做0扩展后与通用寄存器rs中的32位数据做按位与,将结果存入目标寄存器rd 操作:rd←rs ANDI immediate,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A&B→result) result→rd 指令流程图:
数据通路图:
21.ORI 格式:ORI,rd,rs,immediate 目的:与一个常数做按位逻辑或。 描述:rd←rs ORI immediate 将16位立即数做0扩展后与通用寄存器rs中的32位数据做按位或,将结果存入目标寄存器rd 操作:rd←rs ORI immediate,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A|B→result) result→rd 指令流程图:
数据通路图:
22.XORI 格式:ORI,rd,rs,immediate 目的:与一个常数做按位逻辑异或。 描述:rd←rs XORI immediate 将16位立即数做0扩展后与通用寄存器rs中的32位数据做按位异或,将结果存入目标寄存器rd 操作:rd←rs XORI immediate,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT16。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A^B→result) result→rd 指令流程图:
数据通路图:
23.LW(Load Word) 格式:LW rd,offset(base) 目的:从内存读取一个字的有符号数据。 描述:rd←memory[base + offset] 从内存中基地址加偏移量所得到的准确地址中的内容加载到通用寄存器rd中。 操作:rd←memory[base + offset],PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT16。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A + B→result) result→DMEM_ADDR DMEM_OUT→rd 指令流程图:
数据通路图:
24.SW(Store Word) 格式:SW rt,offset(base) 目的:存一个字到内存。 描述:memory[base + offset]←rt 将通用寄存器rt中的32位数据存入内存中的有效地址,有效地址由基地址和16位偏移量相加所得。 操作:memory[base + offset]←rt,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT16。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A + B→result) Rt→DMEM result→DMEM_ADDR 指令流程图:
数据通路图:
25.BEQ(Branch if Equal) 格式:BEQ rs,rt,offset 目的:比较通用寄存器的值,然后做PC相关的分支跳转 描述:如果rs=rt,那么将offset左移两位(乘以4,因为每条指令的长度是4字节),再进行符号扩展到32位与当前pc相加,形成有效转移地址,转到该地址 如果rs!=rt,则继续执行下条指令。 操作:将rs与rt相减,若结果为0则跳转,否则不跳转。 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT18、MUX。 指令周期: PC→IMEM PC+4→NPC NPC→MUX IMEM[15:0]||02→EXT18 EXT18_OUT→ADD_A NPC→ADD_B (ADD_A+ADD_B→ADD_OUT) ADD_OUT→MUX rs→A rt→B (A-B→result) Z→MUX MUX→PC 指令流程图:
数据通路图:
26.BNE(Branch if not Equal) 格式:BNE rs,rt,offset 目的:比较通用寄存器的值,然后做PC相关的分支跳转 描述:如果rs!=rt,那么将offset左移两位(乘以4,因为每条指令的长度是4字节),再进行符号扩展到32位与当前pc相加,形成有效转移地址,转到该地址 如果rs=rt,则继续执行下条指令。 操作:将rs与rt相减,若结果不为0则跳转,否则不跳转。 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT18、MUX。 指令周期: PC→IMEM PC+4→NPC NPC→MUX IMEM[15:0]||02→EXT18 EXT18_OUT→ADD_A NPC→ADD_B (ADD_A+ADD_B→ADD_OUT) ADD_OUT→MUX rs→A rt→B (A-B→result) Z→MUX MUX→PC 指令流程图:
数据通路图:
27.SLTI(Set on Less Than Immediate) 格式:SLTI rd,rs,rt 目的:比通过跟立即数小于的比较来记录结果。 描述:rd←(rs < rt) 比较在rs和rt寄存器中保存的有符号数,用boolean值保存结果到rd寄存器中。如过rs小于rt,则结果为1,反之结果为0,。算术比较不会引起溢出异常。 操作:rd←(rs < rt),PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT1。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A-B→result) CF→EXT1 EXT1_OUT→rd 指令流程图:
数据通路图:
28.SLTIU 格式:SLTIU rd,rs,rt 目的:比通过跟立即数无符号小于的比较来记录结果。 描述:rd←(rs < rt) 比较在rs和rt寄存器中保存的无符号数,用boolean值保存结果到rd寄存器中。如过rs小于rt,则结果为1,反之结果为0,。算术比较不会引起溢出异常。 操作:rd←(rs < rt),PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT1。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B rs→A (A-B→result) CF→EXT1 EXT1_OUT→rd 指令流程图:
数据通路图:
29.LUI(Load unsigned Immediate) 格式:LUI rt,immediate 目的:把一个立即数载入到寄存器的高位,低位补0. 描述:rt←immediate||016 将一个16位的立即数载入到通用寄存器rt的高位,低16位补0。 操作:rt←immediate||016,PC←NPC(PC+4) 所需部件:PC、NPC、IMEM、Regfile、ALU、EXT16。 指令周期: ·取指周期: PC→IMEM PC+4→NPC NPC→PC ·执行周期: IMEM[15:0]→EXT16 EXT16_OUT→B result→rd 指令流程图:
数据通路图:
J-type 30.J(Jump) 格式:J target 目的:在256MB的范围内跳转。 描述:该指令无条件跳转到一个绝对地址,instr_index有26位,在左移后访问空间能达到228B,即256MB。 操作:PC←NPC(target) 所需部件:PC、NPC、IMEM、MUX、||。 指令周期: PC→IMEM PC+4→NPC NPC→MUX PC[31:28]→||_A IMEM[25:0]||02→||_B IMEM[15:0]→EXT16 ||_OUT→MUX MUX_OUT→PC 指令流程图:
数据通路图:
31.JAL(Jump) 格式:JAL target 目的:在256MB的范围内执行一个过程调用。 描述:在跳转到知道地址执行子程序调用的同时,在31号寄存器中存放返回地址(当前地址后的第二条指令地址) 操作:rd←NPC(PC+8),PC←NPC(target) 所需部件:PC、NPC、IMEM、MUX、||、Regfile、ALU。 指令周期: PC→IMEM PC+4→NPC NPC→MUX 8→A PC→B (A+B→result) result→rd PC[31:28]→||_A IMEM[25:0]||02→||_B IMEM[15:0]→EXT16 ||_OUT→MUX MUX_OUT→PC 指令流程图:
数据通路图:
4.数据通路总图 接下来,将上述31条指令的数据通路图合在一起,形成数据通路总图
注意,在绘制数据通路总图时,要按照指令顺序依次画,最好同类型指令用同样的颜色标识,方便后期查错。
5.控制部件设计 将每条指令对应的所有控制信号列出,有了数据通路图,指令表就非常好写了。我们需要做的是在表中列出每一条指令和图中涉及到的所有操作信号,根据你列出的 通路图和每条指令涉及到的操作,将每条指令对应的操作信号标注出来。 这部分内容对应的是control.v中的代码。
6.代码编写 控制器Controler 用于控制运行指令时每个元件的状态。
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 `timescale 1ns / 1ps module Controler( input add_flag, input addu_flag, input sub_flag, input subu_flag, input and_flag, input or_flag, input xor_flag, input nor_flag, input slt_flag, input sltu_flag, input sll_flag, input srl_flag, input sra_flag, input sllv_flag, input srlv_flag, input srav_flag, input jr_flag, input addi_flag, input addiu_flag, input andi_flag, input ori_flag, input xori_flag, input lw_flag, input sw_flag, input beq_flag, input bne_flag, input slti_flag, input sltiu_flag, input lui_flag, input j_flag, input jal_flag, input zero, output reg_w, output [3 :0 ] aluc, output dm_r, output dm_w, output [4 :0 ] ext_ena, output cat_ena, output [10 :0 ] mux );assign reg_w = (!jr_flag && !sw_flag && !beq_flag && !bne_flag && !j_flag) ? 1'b1 : 1'b0 ;assign aluc[3 ] = (slt_flag || sltu_flag || sllv_flag || srlv_flag || srav_flag || sll_flag || srl_flag || sra_flag || slti_flag || sltiu_flag || lui_flag) ? 1'b1 : 1'b0 ;assign aluc[2 ] = (and_flag || or_flag || xor_flag || nor_flag || sllv_flag || srlv_flag || srav_flag || sll_flag || srl_flag || sra_flag || andi_flag || ori_flag || xori_flag) ? 1'b1 : 1'b0 ;assign aluc[1 ] = (add_flag || sub_flag || xor_flag || nor_flag || slt_flag || sltu_flag || sllv_flag || sll_flag || addi_flag || xori_flag || slti_flag || sltiu_flag) ? 1'b1 : 1'b0 ;assign aluc[0 ] = (sub_flag || subu_flag || or_flag || nor_flag || slt_flag || sllv_flag || srlv_flag || sll_flag || srl_flag || ori_flag || slti_flag || lui_flag || beq_flag || bne_flag) ? 1'b1 : 1'b0 ;assign dm_r = lw_flag ? 1'b1 : 1'b0 ;assign dm_w = sw_flag ? 1'b1 : 1'b0 ;assign ext_ena[4 ] = (beq_flag || bne_flag) ? 1'b1 : 1'b0 ; assign ext_ena[3 ] = (addi_flag || addiu_flag || lw_flag || sw_flag || slti_flag || sltiu_flag) ? 1'b1 : 1'b0 ; assign ext_ena[2 ] = (andi_flag || ori_flag || xori_flag || lui_flag) ? 1'b1 : 1'b0 ; assign ext_ena[1 ] = (sll_flag || srl_flag || sra_flag) ? 1'b1 : 1'b0 ; assign ext_ena[0 ] = (slt_flag || sltu_flag || slti_flag || sltiu_flag) ? 1'b1 : 1'b0 ; assign cat_ena = (j_flag || jal_flag) ? 1'b1 : 1'b0 ;assign mux[10 ]= (sll_flag || srl_flag || sra_flag) ? 1'b1 : 1'b0 ;assign mux[9 ] = (add_flag || addu_flag || sub_flag || subu_flag || and_flag || or_flag || xor_flag || nor_flag || sll_flag || srl_flag || sra_flag || sllv_flag || srlv_flag || srav_flag || lui_flag || addi_flag || addiu_flag || andi_flag || ori_flag || xori_flag) ? 1'b1 : 1'b0 ;assign mux[8 ] = (addi_flag || addiu_flag || lw_flag || sw_flag || slti_flag || sltiu_flag) ? 1'b1 : 1'b0 ;assign mux[7 ] = jal_flag ? 1'b1 : 1'b0 ;assign mux[6 ] = beq_flag ? ~zero : (bne_flag ? zero : 1'b1 );assign mux[5 ] = (addi_flag || addiu_flag || andi_flag || ori_flag || xori_flag || lw_flag || sw_flag || slti_flag || sltiu_flag || lui_flag) ? 1'b1 : 1'b0 ;assign mux[4 ] = (!jr_flag && !j_flag && !jal_flag) ? 1'b1 : 1'b0 ;assign mux[3 ] = (sll_flag || srl_flag || sra_flag || sllv_flag || srlv_flag || srav_flag) ? 1'b1 : 1'b0 ;assign mux[2 ] = !lw_flag ? 1'b1 : 1'b0 ;assign mux[1 ] = (j_flag || jal_flag) ? 1'b1 : 1'b0 ;endmodule
译码器Decoder 将指令码转化为控制信号输出。
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 `timescale 1ns / 1ps module Decoder( input [31 :0 ] instr_in, output add_flag, output addu_flag, output sub_flag, output subu_flag, output and_flag, output or_flag, output xor_flag, output nor_flag, output slt_flag, output sltu_flag, output sll_flag, output srl_flag, output sra_flag, output sllv_flag, output srlv_flag, output srav_flag, output jr_flag, output addi_flag, output addiu_flag, output andi_flag, output ori_flag, output xori_flag, output lw_flag, output sw_flag, output beq_flag, output bne_flag, output slti_flag, output sltiu_flag, output lui_flag, output j_flag, output jal_flag, output [4 :0 ] RsC, output [4 :0 ] RtC, output [4 :0 ] RdC, output [4 :0 ] shamt, output [15 :0 ] immediate, output [25 :0 ] address );parameter ADD_OPE = 6'b100000 ;parameter ADDU_OPE = 6'b100001 ;parameter SUB_OPE = 6'b100010 ;parameter SUBU_OPE = 6'b100011 ;parameter AND_OPE = 6'b100100 ;parameter OR_OPE = 6'b100101 ;parameter XOR_OPE = 6'b100110 ;parameter NOR_OPE = 6'b100111 ;parameter SLT_OPE = 6'b101010 ;parameter SLTU_OPE = 6'b101011 ;parameter SLL_OPE = 6'b000000 ;parameter SRL_OPE = 6'b000010 ;parameter SRA_OPE = 6'b000011 ;parameter SLLV_OPE = 6'b000100 ;parameter SRLV_OPE = 6'b000110 ;parameter SRAV_OPE = 6'b000111 ;parameter JR_OPE = 6'b001000 ;parameter ADDI_OPE = 6'b001000 ;parameter ADDIU_OPE = 6'b001001 ;parameter ANDI_OPE = 6'b001100 ;parameter ORI_OPE = 6'b001101 ;parameter XORI_OPE = 6'b001110 ;parameter LW_OPE = 6'b100011 ;parameter SW_OPE = 6'b101011 ;parameter BEQ_OPE = 6'b000100 ;parameter BNE_OPE = 6'b000101 ;parameter SLTI_OPE = 6'b001010 ;parameter SLTIU_OPE = 6'b001011 ;parameter LUI_OPE = 6'b001111 ;parameter J_OPE = 6'b000010 ;parameter JAL_OPE = 6'b000011 ;assign add_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == ADD_OPE )) ? 1'b1 : 1'b0 ;assign addu_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == ADDU_OPE)) ? 1'b1 : 1'b0 ;assign sub_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SUB_OPE )) ? 1'b1 : 1'b0 ;assign subu_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SUBU_OPE)) ? 1'b1 : 1'b0 ;assign and_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == AND_OPE )) ? 1'b1 : 1'b0 ;assign or_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == OR_OPE )) ? 1'b1 : 1'b0 ;assign xor_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == XOR_OPE )) ? 1'b1 : 1'b0 ;assign nor_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == NOR_OPE )) ? 1'b1 : 1'b0 ;assign slt_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SLT_OPE )) ? 1'b1 : 1'b0 ;assign sltu_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SLTU_OPE)) ? 1'b1 : 1'b0 ;assign sll_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SLL_OPE )) ? 1'b1 : 1'b0 ;assign srl_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SRL_OPE )) ? 1'b1 : 1'b0 ;assign sra_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SRA_OPE )) ? 1'b1 : 1'b0 ;assign sllv_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SLLV_OPE)) ? 1'b1 : 1'b0 ;assign srlv_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SRLV_OPE)) ? 1'b1 : 1'b0 ;assign srav_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == SRAV_OPE)) ? 1'b1 : 1'b0 ;assign jr_flag = ((instr_in[31 :26 ] == 6'h0 ) && (instr_in[5 :0 ] == JR_OPE )) ? 1'b1 : 1'b0 ;assign addi_flag = (instr_in[31 :26 ] == ADDI_OPE ) ? 1'b1 : 1'b0 ;assign addiu_flag = (instr_in[31 :26 ] == ADDIU_OPE) ? 1'b1 : 1'b0 ;assign andi_flag = (instr_in[31 :26 ] == ANDI_OPE ) ? 1'b1 : 1'b0 ;assign ori_flag = (instr_in[31 :26 ] == ORI_OPE ) ? 1'b1 : 1'b0 ;assign xori_flag = (instr_in[31 :26 ] == XORI_OPE ) ? 1'b1 : 1'b0 ;assign lw_flag = (instr_in[31 :26 ] == LW_OPE ) ? 1'b1 : 1'b0 ;assign sw_flag = (instr_in[31 :26 ] == SW_OPE ) ? 1'b1 : 1'b0 ;assign beq_flag = (instr_in[31 :26 ] == BEQ_OPE ) ? 1'b1 : 1'b0 ;assign bne_flag = (instr_in[31 :26 ] == BNE_OPE ) ? 1'b1 : 1'b0 ;assign slti_flag = (instr_in[31 :26 ] == SLTI_OPE ) ? 1'b1 : 1'b0 ;assign sltiu_flag = (instr_in[31 :26 ] == SLTIU_OPE) ? 1'b1 : 1'b0 ;assign lui_flag = (instr_in[31 :26 ] == LUI_OPE ) ? 1'b1 : 1'b0 ;assign j_flag = (instr_in[31 :26 ] == J_OPE ) ? 1'b1 : 1'b0 ;assign jal_flag = (instr_in[31 :26 ] == JAL_OPE ) ? 1'b1 : 1'b0 ;assign RsC = (add_flag || addu_flag || sub_flag || subu_flag || and_flag || or_flag || xor_flag || nor_flag || slt_flag || sltu_flag || sllv_flag || srlv_flag || srav_flag || jr_flag || addi_flag || addiu_flag || andi_flag || ori_flag || xori_flag || lw_flag || sw_flag || beq_flag || bne_flag || slti_flag || sltiu_flag) ? instr_in[25 :21 ] : 5'hz ;assign RtC = (add_flag || addu_flag || sub_flag || subu_flag || and_flag || or_flag || xor_flag || nor_flag || slt_flag || sltu_flag || sll_flag || srl_flag || sra_flag || sllv_flag || srlv_flag || srav_flag || sw_flag || beq_flag || bne_flag ) ? instr_in[20 :16 ] : 5'hz ;assign RdC = (add_flag || addu_flag || sub_flag || subu_flag || and_flag || or_flag || xor_flag || nor_flag || slt_flag || sltu_flag || sll_flag || srl_flag || sra_flag || sllv_flag || srlv_flag || srav_flag) ? instr_in[15 :11 ] : (( addi_flag || addiu_flag || andi_flag || ori_flag || xori_flag || lw_flag || slti_flag || sltiu_flag || lui_flag) ? instr_in[20 :16 ] : (jal_flag ? 5'd31 : 5'hz ));assign shamt = (sll_flag || srl_flag || sra_flag) ? instr_in[10 :6 ] : 5'hz ; assign immediate = (addi_flag || addiu_flag || andi_flag || ori_flag || xori_flag || lw_flag || sw_flag || beq_flag || bne_flag || slti_flag || sltiu_flag || lui_flag) ? instr_in[15 :0 ] : 16'hz ;assign address = (j_flag || jal_flag) ? instr_in[25 :0 ] : 26'hz ; endmodule
算术逻辑单元ALU 完成各种算术和逻辑运算
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 `timescale 1ns / 1ps module ALU( input [3 :0 ] ALU_C, input [31 :0 ] A, input [31 :0 ] B, output [31 :0 ] OUT, output CF, output ZF, output SF, output OF ); parameter ADD = 4'b0000 ; parameter ADDU = 4'b0010 ; parameter SUB = 4'b0001 ; parameter SUBU = 4'b0011 ; parameter AND = 4'b0100 ; parameter OR = 4'b0101 ; parameter XOR = 4'b0110 ; parameter NOR = 4'b0111 ; parameter LUI = 4'b100x ; parameter SLT = 4'b1011 ; parameter SLTU = 4'b1010 ; parameter SRA = 4'b1100 ; parameter SLL = 4'b111x ; parameter SLA = 4'b111x ; parameter SRL = 4'b1101 ; reg [32 :0 ] result; wire signed [31 :0 ] s_A,s_B; assign s_A = A; assign s_B = B; always @(*) begin case (ALU_C) ADD: begin result <= s_A + s_B; end ADDU: begin result <= A + B; end SUB: begin result <= s_A - s_B; end SUBU: begin result <= A - B; end AND: begin result <= A & B; end OR: begin result <= A | B; end XOR: begin result <= A ^ B; end NOR: begin result <= ~(A | B); end LUI: begin result <= { B[15 :0 ] , 16'b0 }; end SLT: begin result <= s_A - s_B; end SLTU: begin result <= A - B; end SRA: begin result <= s_B >>> s_A; end SLL,SLA: begin result <= B << A; end SRL: begin result <= B >> A; end endcase end assign OUT = result[31 :0 ]; assign CF = result[32 ]; assign ZF = (result == 32'b0 ) ? 1 : 0 ; assign SF = (ALU_C == SLT ? (s_A < s_B): ((ALU_C == SLTU) ? (A < B): 1'b0 )); assign OF = result[32 ]; endmodule
寄存器堆Regfile 32位的寄存器堆
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 `timescale 1ns / 1ps module regfile( input reg_clk, input reg_ena, input rst_n, input reg_w, input [4 :0 ] RdC, input [4 :0 ] RtC, input [4 :0 ] RsC, input [31 :0 ] Rd_data_in, output [31 :0 ] Rs_data_out, output [31 :0 ] Rt_data_out );reg [31 :0 ] array_reg [31 :0 ];assign Rs_data_out = reg_ena ? array_reg[RsC] : 32'bz ;assign Rt_data_out = reg_ena ? array_reg[RtC] : 32'bz ;always @(negedge reg_clk or posedge rst_n)begin if (rst_n && reg_ena) begin array_reg[0 ] <= 32'h0 ; array_reg[1 ] <= 32'h0 ; array_reg[2 ] <= 32'h0 ; array_reg[3 ] <= 32'h0 ; array_reg[4 ] <= 32'h0 ; array_reg[5 ] <= 32'h0 ; array_reg[6 ] <= 32'h0 ; array_reg[7 ] <= 32'h0 ; array_reg[8 ] <= 32'h0 ; array_reg[9 ] <= 32'h0 ; array_reg[10 ] <= 32'h0 ; array_reg[11 ] <= 32'h0 ; array_reg[12 ] <= 32'h0 ; array_reg[13 ] <= 32'h0 ; array_reg[14 ] <= 32'h0 ; array_reg[15 ] <= 32'h0 ; array_reg[16 ] <= 32'h0 ; array_reg[17 ] <= 32'h0 ; array_reg[18 ] <= 32'h0 ; array_reg[19 ] <= 32'h0 ; array_reg[20 ] <= 32'h0 ; array_reg[21 ] <= 32'h0 ; array_reg[22 ] <= 32'h0 ; array_reg[23 ] <= 32'h0 ; array_reg[24 ] <= 32'h0 ; array_reg[25 ] <= 32'h0 ; array_reg[26 ] <= 32'h0 ; array_reg[27 ] <= 32'h0 ; array_reg[28 ] <= 32'h0 ; array_reg[29 ] <= 32'h0 ; array_reg[30 ] <= 32'h0 ; array_reg[31 ] <= 32'h0 ; end else if (reg_ena && reg_w && (RdC != 5'h0 )) array_reg[RdC] <= Rd_data_in;end endmodule
程序计数器PC 存储指令地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 `timescale 1ns / 1ps module PC( input pc_clk, input pc_ena, input rst_n, input [31 :0 ] pc_addr_in, output [31 :0 ] pc_addr_out );reg [31 :0 ] pc_reg = 32'h00400000 ;assign pc_addr_out = pc_ena ? pc_reg : 32'hz ;always @(negedge pc_clk or posedge rst_n)begin if (rst_n && pc_ena)begin pc_reg = 32'h00400000 ; end else if (pc_ena)begin pc_reg = pc_addr_in; end end endmodule
CPU 负责调用PC,Controller等模块
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 `timescale 1ns / 1ps module cpu( input clk, input ena, input rst_n, input [31 :0 ] instr_in, input [31 :0 ] dm_data, output dm_ena, output dm_w, output dm_r, output [31 :0 ] pc_out, output [31 :0 ] dm_addr, output [31 :0 ] dm_data_w );wire add_flag, addu_flag, sub_flag, subu_flag, and_flag, or_flag, xor_flag, nor_flag, slt_flag, sltu_flag, sll_flag, srl_flag, sra_flag, sllv_flag, srlv_flag, srav_flag, jr_flag, addi_flag, addiu_flag, andi_flag, ori_flag, xori_flag, lw_flag, sw_flag, beq_flag, bne_flag, slti_flag, sltiu_flag, lui_flag, j_flag, jal_flag; wire [4 :0 ] RsC; wire [4 :0 ] RtC; wire [4 :0 ] RdC; wire [4 :0 ] shamt; wire [15 :0 ] immediate; wire [25 :0 ] address; wire reg_w; wire [9 :0 ] mux; wire [4 :0 ] ext_ena; wire cat_ena; wire [31 :0 ] a, b; wire [3 :0 ] aluc; wire [31 :0 ] alu_data_out; wire zero, carry, negative, overflow; wire [31 :0 ] Rd_data_in; wire [31 :0 ] Rs_data_out; wire [31 :0 ] Rt_data_out; wire [31 :0 ] pc_addr_in; wire [31 :0 ] pc_addr_out; wire [31 :0 ] ext1_out;wire [31 :0 ] ext5_out;wire [31 :0 ] ext16_out;wire signed [31 :0 ] ext16_out_signed;wire signed [31 :0 ] ext18_out_signed;assign ext1_out = (slt_flag || sltu_flag) ? negative : (slti_flag || sltiu_flag) ? carry : 32'hz ;assign ext5_out = (sll_flag || srl_flag || sra_flag ||sllv_flag||srlv_flag||srav_flag) ? mux10_out : 32'hz ;assign ext16_out = (andi_flag || ori_flag || xori_flag || lui_flag) ? { 16'h0 , immediate[15 :0 ] } : 32'hz ;assign ext16_out_signed = (addi_flag || addiu_flag || lw_flag || sw_flag || slti_flag || sltiu_flag) ? { {16 {immediate[15 ]}} , immediate[15 :0 ] } : 32'hz ;assign ext18_out_signed = (beq_flag || bne_flag) ? {{14 {immediate[15 ]}}, immediate[15 :0 ], 2'b0 } : 32'hz ;wire [31 :0 ] cat_out;assign cat_out = cat_ena ? {pc_out[31 :28 ], address[25 :0 ], 2'h0 } : 32'hz ;wire [31 :0 ] npc;assign npc = pc_addr_out + 4 ;wire [31 :0 ] mux1_out;wire [31 :0 ] mux2_out;wire [31 :0 ] mux3_out;wire [31 :0 ] mux4_out;wire [31 :0 ] mux5_out;wire [31 :0 ] mux6_out;wire [31 :0 ] mux7_out;wire [31 :0 ] mux8_out;wire [31 :0 ] mux9_out;assign mux1_out = mux[1 ] ? cat_out : mux4_out;assign mux2_out = mux[2 ] ? mux9_out : dm_data;assign mux3_out = mux[3 ] ? ext5_out : Rs_data_out;assign mux4_out = mux[4 ] ? mux6_out : Rs_data_out;assign mux5_out = mux[5 ] ? mux8_out : Rt_data_out;assign mux6_out = mux[6 ] ? npc : ext18_out_signed + npc;assign mux7_out = mux[7 ] ? pc_addr_out + 4 : mux2_out;assign mux8_out = mux[8 ] ? ext16_out_signed : ext16_out;assign mux9_out = mux[9 ] ? alu_data_out : ext1_out;assign mux10_out= mux[10 ]? Rs_data_out[4 :0 ] : shamt;assign pc_addr_in = mux1_out;assign a = mux3_out;assign b = mux5_out;assign pc_out = pc_addr_out;assign dm_ena = (dm_r || dm_w) ? 1'b1 : 1'b0 ;assign dm_addr = alu_data_out;assign dm_data_w = Rt_data_out;assign Rd_data_in = mux7_out; Decoder Decoder_inst( .instr_in (instr_in), .add_flag (add_flag), .addu_flag (addu_flag), .sub_flag (sub_flag), .subu_flag (subu_flag), .and_flag (and_flag), .or_flag (or_flag), .xor_flag (xor_flag), .nor_flag (nor_flag), .slt_flag (slt_flag), .sltu_flag (sltu_flag), .sll_flag (sll_flag) , .srl_flag (srl_flag), .sra_flag (sra_flag), .sllv_flag (sllv_flag), .srlv_flag (srlv_flag), .srav_flag (srav_flag), .jr_flag (jr_flag), .addi_flag (addi_flag), .addiu_flag (addiu_flag), .andi_flag (andi_flag), .ori_flag (ori_flag), .xori_flag (xori_flag), .lw_flag (lw_flag), .sw_flag (sw_flag), .beq_flag (beq_flag), .bne_flag (bne_flag), .slti_flag (slti_flag), .sltiu_flag (sltiu_flag), .lui_flag (lui_flag), .j_flag (j_flag), .jal_flag (jal_flag), .RsC (RsC), .RtC (RtC), .RdC (RdC), .shamt (shamt), .immediate (immediate), .address (address) ); Controler Controler_inst( .add_flag (add_flag), .addu_flag (addu_flag), .sub_flag (sub_flag), .subu_flag (subu_flag), .and_flag (and_flag), .or_flag (or_flag), .xor_flag (xor_flag), .nor_flag (nor_flag), .slt_flag (slt_flag), .sltu_flag (sltu_flag), .sll_flag (sll_flag) , .srl_flag (srl_flag), .sra_flag (sra_flag), .sllv_flag (sllv_flag), .srlv_flag (srlv_flag), .srav_flag (srav_flag), .jr_flag (jr_flag), .addi_flag (addi_flag), .addiu_flag (addiu_flag), .andi_flag (andi_flag), .ori_flag (ori_flag), .xori_flag (xori_flag), .lw_flag (lw_flag), .sw_flag (sw_flag), .beq_flag (beq_flag), .bne_flag (bne_flag), .slti_flag (slti_flag), .sltiu_flag (sltiu_flag), .lui_flag (lui_flag), .j_flag (j_flag), .jal_flag (jal_flag), .zero (zero), .reg_w (reg_w), .aluc (aluc), .dm_r (dm_r), .dm_w (dm_w), .ext_ena (ext_ena), .cat_ena (cat_ena), .mux (mux) ); ALU ALU_inst( .A (a), .B (b), .ALU_C (aluc), .OUT (alu_data_out), .ZF (zero), .CF (carry), .SF (negative), .OF (overflow) ); regfile cpu_ref( .reg_clk (clk), .reg_ena (ena), .rst_n (rst_n), .reg_w (reg_w), .RdC (RdC), .RtC (RtC), .RsC (RsC), .Rd_data_in (Rd_data_in), .Rs_data_out (Rs_data_out), .Rt_data_out (Rt_data_out) ); PC PC_inst( .pc_clk (clk), .pc_ena (ena), .rst_n (rst_n), .pc_addr_in (pc_addr_in), .pc_addr_out (pc_addr_out) );endmodule
数据存储器DMEM 字长为32bit的数据存储器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 `timescale 1ns / 1ps module DMEM( input D_clk, input D_ena, input D_r, input D_w, input [10 :0 ] D_addr, input [31 :0 ] D_data_in, output [31 :0 ] D_data_out );reg [31 :0 ] dmem [31 :0 ];assign D_data_out = (D_ena && D_r && !D_w) ? dmem[D_addr] : 32'bz ;always @(negedge D_clk) if (D_ena && D_w &&!D_r) dmem[D_addr]<=D_data_in;endmodule
指令存储器IMEM 字长为32bit的指令存储器
1 2 3 4 5 6 7 8 9 10 11 12 `timescale 1ns / 1ps module IMEM( input [10 :0 ] I_addr_in, output [31 :0 ] I_instr_out ); dist_mem_gen_0 imem( .a (I_addr_in), .spo (I_instr_out) );endmodule
数据流sccomp_dataflow 最顶层的文件,负责将指令存储器IMEM、数据存储器DMEM和CPU连接起来。
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 `timescale 1ns / 1ps module sccomp_dataflow( input clk_in, input reset, output [31 :0 ] inst, output [31 :0 ] pc );wire [31 :0 ] pc_out; wire [31 :0 ] dm_addr_temp; wire [31 :0 ] im_addr_in; wire [31 :0 ] im_instr_out; assign im_addr_in = pc_out - 32'h00400000 ;wire dm_ena; wire dm_r, dm_w; wire [31 :0 ] dm_addr; wire [31 :0 ] dm_data_out; wire [31 :0 ] dm_data_w; assign dm_addr = (dm_addr_temp - 32'h10010000 )/4 ;assign pc = pc_out;assign inst = im_instr_out; IMEM imem( .I_addr_in (im_addr_in[12 :2 ]), .I_instr_out (im_instr_out) ); DMEM dmem( .D_clk (clk_in), .D_ena (dm_ena), .D_r (dm_r), .D_w (dm_w), .D_addr (dm_addr[10 :0 ]), .D_data_in (dm_data_w), .D_data_out (dm_data_out) ); cpu sccpu( .clk (clk_in), .ena (1'b1 ), .rst_n (reset), .instr_in (im_instr_out), .dm_data (dm_data_out), .dm_ena (dm_ena), .dm_w (dm_w), .dm_r (dm_r), .pc_out (pc_out), .dm_addr (dm_addr_temp), .dm_data_w (dm_data_w) );endmodule
注意:指令存储器的实现用到了IP核。
如何生成IP核: 参数配置如下: 注:此处的Coefficients File使用的是coe文件,也就是存储CPU运行的程序的文件。
如何获取.coe文件: 在Mars中编写你想要测试的汇编代码,选择assemble指令进行编译 跳转到execude界面 之后将文件以16进制导出 将文件名后缀改为.coe,之后就能将该coe文件导入IP核了。
1 2 3 4 5 6 7 8 9 # 示例:addi指令的测试代码 sll $0,$0,0 addi $0,$0,0xffffffff addi $1,$0,0x0001 addi $2,$0,0xffff8000 addi $3,$0,0x7fff addi $4,$1,0xffffffff addi $5,$2,0xffffffff addi $6,$3,0x0006
至此,我们的CPU就能正常运行代码啦,不过需要运行的代码都需要通过以上这种形式转为coe文件导入IP核才能运行