3623 字
18 分钟
计组实验期末



测试指令共分11段(Test_all.coe,已载入初始工程rom中),其中,每段由实验讲义中的12条指令另加跳转测试指令12条,共24条。
由拨码开关sw_i选择起始地址进入,具体如下。
| beq | bne | blt | bge | bltu | bgeu | jal | jalr | sll | srl | sra | |
| Sw_i [5:2] | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 |
例如sw_i[5:2]=0101,则对应于bgeu测试指令段。
Sll,srl,sra均为r型指令,作为保底,不要与slli,srli,srai
// 起始地址选择参考样例
`timescale 1ns / 1psmodule PC(clk, rst, NPC, PCwr,PC,sw_i);
input clk; input rst; input [31:0] NPC; input wire PCwr; input [3:0] sw_i; output reg [31:0] PC;
always @(posedge clk, negedge rst) //added for final test 2024.12.19 //choose the test code init address //PC initialization if (!rst) begin case (sw_i) 4'b0000:PC <= 32'h0000_0000; //beq 4'b0001:PC <= 32'h0000_0080; //bne 4'b0010:PC <= 32'h0000_0100; //blt 4'b0011:PC <= 32'h0000_0180; //bge 4'b0100:PC <= 32'h0000_0200; //bltu 4'b0101:PC <= 32'h0000_0280; //bgeu 4'b0110:PC <= 32'h0000_0300; //jal 4'b0111:PC <= 32'h0000_037c; //jalr 4'b1000:PC <= 32'h0000_03f0; //sll 4'b1001:PC <= 32'h0000_0410; //srl 4'b1010:PC <= 32'h0000_0430; //sra endcase// PC <= 32'h0000_0000; end else if (PCwr==1'b0)//sw_i[1]= 1, PC <= NPC;
endmodule容易出错的地方
- PC,rom_addr的复位时机要同时(要么都异步复位(写在敏感列表),要么都同步复位(不写在敏感列表)),否则复位会出现部分复位(复位后: A->E->F->…)
- Ctrl中指令解析错误,要严格检查解析Opcode,Funct是否正确;以及生成信号是否有遗漏
- WD的赋值采取组合逻辑的呈现:
always@(*)(reg) 还是assign(wire)- 前者可能要使用到块内初始化,这引入了多重赋值和时序竞争的可能性
- 后者直接定义了
WD与其右侧信号之间的逻辑关系,没有内部的初始化或覆盖步骤,而且连续赋值消除了always块内多重赋值带来的所有时序竞争或仿真器对非阻塞赋值的特殊处理,从而确保在任何观察点,WD都反映了 MUX 逻辑的正确输出 - 但一般简单情形下都适用,这里也是
- 一般主模块下首先默认是用wire,wire具有快的性质
- 模块例化出口端口要用wire连接
- 指令是否有效,观察alu很容易判断:如果运算结果不应该为0,但为0(因为设置了ALUOp的case:default:C为0),则说明Ctrl模块下该指令的解析出错或生成ALUOp信号遗漏了该指令
代码
下面代码忽略U型指令:lui, auipc以及除了加法的其他运算(or,ori,slt等)
代码亮点
- alu module中把branch指令的各种标志用Zero统一起来
- 使用 PC和NPC module独立处理PC
核心代码
SCPU_TOP
`timescale 1ns / 1ps
// 37条指令module SCPU_TOP( input clk, input rstn, // 低电平有效,按下后为0 input [15:0] sw_i, output [7:0] disp_seg_o, output [7:0] disp_an_o);reg [31:0] clkdiv;wire Clk_CPU;
always @(posedge clk or negedge rstn) begin if(!rstn) clkdiv <= 0; else clkdiv <= clkdiv + 1'b1;end
assign Clk_CPU = (sw_i[15])?clkdiv[27]:clkdiv[25]; // 2^27 和 2^25分频
reg [63:0] display_data;
reg [5:0] led_data_addr;reg [63:0] led_disp_data;parameter LED_DATA_NUM = 19;
reg [63:0] LED_DATA[18:0];initial begin LED_DATA[0] = 64'hC6F6F6F0C6F6F6F0; LED_DATA[1] = 64'hF9F6F6CFF9F6F6CF; LED_DATA[2] = 64'hFFC6F0FFFFC6F0FF; LED_DATA[3] = 64'hFFC0FFFFFFC0FFFF; LED_DATA[4] = 64'hFFA3FFFFFFA3FFFF; LED_DATA[5] = 64'hFFFFA3FFFFFFA3FF; LED_DATA[6] = 64'hFFFF9CFFFFFF9CFF; LED_DATA[7] = 64'hFF9EBCFFFF9EBCFF; LED_DATA[8] = 64'hFF9CFFFFFF9CFFFF; LED_DATA[9] = 64'hFFC0FFFFFFC0FFFF; LED_DATA[10] = 64'hFFA3FFFFFFA3FFFF; LED_DATA[11] = 64'hFFA7B3FFFFA7B3FF; LED_DATA[12] = 64'hFFC6F0FFFFC6F0FF; LED_DATA[13] = 64'hF9F6F6CFF9F6F6CF; LED_DATA[14] = 64'h9EBEBEBC9EBEBEBC; LED_DATA[15] = 64'h2737373327373733; LED_DATA[16] = 64'h505454EC505454EC; LED_DATA[17] = 64'h744454F8744454F8; LED_DATA[18] = 64'h0062080000620800;end
always @(posedge Clk_CPU or negedge rstn) begin if(!rstn) begin led_data_addr <= 6'd0; led_disp_data <= 64'b1; end else if(sw_i[0] == 1'b1) begin if(led_data_addr == LED_DATA_NUM) begin led_data_addr <= 6'd0; led_disp_data <= LED_DATA[0]; end else begin led_disp_data <= LED_DATA[led_data_addr]; led_data_addr <= led_data_addr + 1'b1; end end else led_data_addr <= led_data_addr;end
wire [31:0] instr;reg [31:0] reg_data;reg [31:0] alu_disp_data;reg [31:0] dmem_data;
// PCwire [31:0] PC;wire [31:0] NPC;wire PCwr = ~sw_i[1];wire [2:0] NPCOp;
// ROMreg [5:0] rom_addr;
// RFwire RegWrite;wire [31:0] WD;wire [31:0] RD1,RD2;
reg [5:0] reg_addr; // 显示用
// ALUwire [31:0] A,B;wire [4:0] ALUOp;wire [31:0] aluout;wire Zero;
reg [2:0] alu_addr;
// DMwire MemWrite;wire [5:0] dm_addr;wire [31:0] dm_din;wire [2:0] DMType;wire [31:0] dm_dout;
reg [6:0] dmem_addr; // 显示用
// Ctrlwire [5:0] EXTOp;wire [1:0] WDSel;wire ALUSrc;
// EXTwire [31:0] immout;
always @(sw_i) begin if(sw_i[0] == 0) begin case(sw_i[14:11]) 4'b1000 : display_data <= instr; 4'b0100 : display_data <= reg_data; 4'b0010 : display_data <= alu_disp_data; 4'b0001 : display_data <= dmem_data; default : display_data <= instr; endcase end else display_data = led_disp_data;end
// 例化显示模块seg7x16 u_seg7x16( .clk(clk), .rstn(rstn), .disp_mode(sw_i[0]), .i_data(display_data), .disp_seg_o(disp_seg_o), .disp_an_o(disp_an_o));///////////////////////////////////////////////////////
// 例化PC_Unit module 时序逻辑PC_Unit U_PC(.clk(Clk_CPU),.rst(~rstn),.NPC(NPC),.PCwr(PCwr),.PC(PC));
// 例化NPC_Unit module 组合逻辑NPC_Unit U_NPC(.PC(PC),.NPCOp(NPCOp),.IMM(immout),.aluout(aluout),.NPC(NPC));
// 例化ROM模块dist_mem_im U_IM( .a(rom_addr), .spo(instr));
// 每个CLK_CPU获得一个新指令// 关注上升沿:上升沿PC更新为NPC,所以rom_addr也应更新为NPC以取下条指令 always @(posedge Clk_CPU or negedge rstn) begin if(!rstn) rom_addr <= 6'b0; else if(sw_i[1] == 1'b0) rom_addr <= NPC >> 2; // rom以1为单位,指令以4为单位,所以除以4以映射rom else rom_addr <= rom_addr; end
//Decodewire [6:0] Op = instr[6:0];wire [6:0] Funct7 = instr[31:25];wire [2:0] Funct3 = instr[14:12];wire [4:0] rs1 = instr[19:15];wire [4:0] rs2 = instr[24:20];wire [4:0] rd = instr[11:7];wire [4:0] iimm_shamt= instr[24:20];wire [11:0] iimm = instr[31:20]; // jalr, load, itypewire [11:0] simm = {instr[31:25],instr[11:7]};wire [11:0] bimm = {instr[31],instr[7],instr[30:25],instr[11:8]};wire [19:0] uimm = instr[31:12]; // lui, auipcwire [19:0] jimm = {instr[31],instr[19:12],instr[20],instr[30:21]}; // jal
// 例化ctrl模块 组合逻辑ctrl u_ctrl( .Op(Op), .Funct7(Funct7), .Funct3(Funct3), .Zero(Zero), .RegWrite(RegWrite), .MemWrite(MemWrite), .EXTOp(EXTOp), .ALUOp(ALUOp), .ALUSrc(ALUSrc), .NPCOp(NPCOp), .DMType(DMType), .WDSel(WDSel));
// 例化EXT模块 组合逻辑EXT U_EXT( .iimm_shamt(iimm_shamt), .iimm(iimm), .simm(simm), .bimm(bimm), .uimm(uimm), .jimm(jimm), .EXTOp(EXTOp), .immout(immout));
// 赋值
// ALU_DM->RF RF_WD// WDSel FromALU 2'b00// WDSel FromMEM 2'b01// WDSel FromPC 2'b10//always @(*) begin// WD <= 32'h0;// case(WDSel)// 00: WD <= aluout;// 01: WD <= dm_dout;// 10: WD <= PC + 4;// default: WD <= 32'h0;// endcase//end
// WDSel FromALU 2'b00// WDSel FromMEM 2'b01// WDSel FromPC 2'b10assign WD = (WDSel == 2'b10) ? (PC + 4) : (WDSel == 2'b01) ? dm_dout : (WDSel == 2'b00) ? aluout : 32'h00000000;
// RF->ALU ALU_A_Bassign A = RD1;assign B = (ALUSrc == 1'b0)?RD2:immout;
// ALU->DM DM_addr_dinassign dm_addr = aluout;assign dm_din = RD2;
// 例化RF模块 时序逻辑RF U_RF( .clk(Clk_CPU), .rstn(rstn), .RFWr(RegWrite), .sw_i(sw_i), .A1(rs1), .A2(rs2), .A3(rd), .WD(WD), .RD1(RD1), .RD2(RD2));
// 循环显示32个寄存器的内容always @(posedge Clk_CPU or negedge rstn) begin if(!rstn) begin reg_addr <= 5'b0; reg_data <= 32'b0; end else if(sw_i[13] == 1'b1)begin reg_addr <= reg_addr + 1'b1; reg_data <= U_RF.rf[reg_addr]; endend
/////////////////////////////////////////////////////
// 例化alu模块 组合逻辑alu U_alu( .A(A), .B(B), .ALUOp(ALUOp), .C(aluout), .Zero(Zero));
// 循环显示A B Zero四个值always @(posedge Clk_CPU or negedge rstn) begin if(!rstn) alu_addr <= 3'b0; else alu_addr <= alu_addr + 1'b1; case(alu_addr) // 下面用普通reg接收signed数据,只会数据位复制 3'b001:alu_disp_data <= U_alu.A; 3'b010:alu_disp_data <= U_alu.B; 3'b011:alu_disp_data <= U_alu.C; 3'b100:alu_disp_data <= U_alu.Zero; default:alu_disp_data <= 32'hFFFFFFFF; endcaseend
//////////////////////////////////////////////////////
// 例化dm模块 时序逻辑dm U_DM( .clk(Clk_CPU), .DMWr(MemWrite), .addr(dm_addr), .din(dm_din), .DMType(DMType), .dout(dm_dout));
// 循环显示Data Memory内容parameter DM_DATA_NUM = 16;always @(posedge Clk_CPU or negedge rstn) begin if(!rstn) begin dmem_addr <= 7'b0; dmem_data <= 32'hFFFFFFFF; end else if(sw_i[11] == 1'b1) begin dmem_addr <= dmem_addr + 1'b1; dmem_data <= U_DM.dmem[dmem_addr][7:0]; if(dmem_addr == DM_DATA_NUM) begin // DM_DATA_NUM是不能取到的,所以此时马上切为0 dmem_addr <= 7'd0; dmem_data <= 32'hFFFFFFFF; end endend
endmodulePC
module PC_Unit( input clk, input rst, input [31:0] NPC, input PCwr, output reg [31:0] PC);// 由于主模块下各rstn复位都是异步复位,所以关于rstn的同时集体复位,这里应该采取异步复位,所以敏感列表里应有rst// 否则只有在posedge clk下rst为1才复位,则为同步复位always @(posedge clk or posedge rst) begin if(rst) PC <= 32'b0; else if(PCwr) PC <= NPC;endendmoduleNPC
`define NPC_PLUS4 3'b000`define NPC_BRANCH 3'b001`define NPC_JUMP 3'b010`define NPC_JALR 3'b100
module NPC_Unit( input [31:0] PC, input [2:0] NPCOp, input [31:0] IMM, input [31:0] aluout, output reg [31:0] NPC);always @(*) begin case(NPCOp) `NPC_PLUS4: NPC = PC + 4; // default `NPC_BRANCH: NPC = PC + IMM; // branch `NPC_JUMP: NPC = PC + IMM; // jal `NPC_JALR: NPC = aluout; // jalr default: NPC = PC + 4; endcaseendendmodulectrl
module ctrl( input [6:0] Op, input [6:0] Funct7, input [2:0] Funct3, input Zero, output RegWrite, output MemWrite, output [5:0] EXTOp, output [4:0] ALUOp, output [2:0] NPCOp, output ALUSrc, output [2:0] DMType, output [1:0] WDSel // MemtoReg);// R_type 10条wire rtype = ~Op[6] & Op[5] & Op[4] & ~Op[3] & ~Op[2] & Op[1] & Op[0]; //0110011wire i_add = rtype & ~Funct3[2] & ~Funct3[1] & ~Funct3[0] & ~Funct7[5]; // add 0000000 000wire i_sub = rtype & ~Funct3[2] & ~Funct3[1] & ~Funct3[0] & Funct7[5]; // sub 0100000 000wire i_sll = rtype & ~Funct3[2] & ~Funct3[1] & Funct3[0]; // sll 0000000 001wire i_slt = rtype & ~Funct3[2] & Funct3[1] & ~Funct3[0]; // slt 0000000 010wire i_sltu = rtype & ~Funct3[2] & Funct3[1] & Funct3[0]; // sltu 0000000 011wire i_xor = rtype & Funct3[2] & ~Funct3[1] & ~Funct3[0]; // xor 0000000 100wire i_srl = rtype & Funct3[2] & ~Funct3[1] & Funct3[0] & ~Funct7[5]; // srl 0000000 101wire i_sra = rtype & Funct3[2] & ~Funct3[1] & Funct3[0] & Funct7[5]; // sra 0100000 101wire i_or = rtype & Funct3[2] & Funct3[1] & ~Funct3[0]; // or 0000000 110wire i_and = rtype & Funct3[2] & Funct3[1] & Funct3[0]; // and 0000000 111
// i_l type load 5条wire itype_l = ~Op[6] & ~Op[5] & ~Op[4] & ~Op[3] & ~Op[2] & Op[1] & Op[0]; //0000011wire i_lb = itype_l & ~Funct3[2] & ~Funct3[1] & ~Funct3[0]; //lb 000wire i_lh = itype_l & ~Funct3[2] & ~Funct3[1] & Funct3[0]; //lh 001wire i_lw = itype_l & ~Funct3[2] & Funct3[1] & ~Funct3[0]; //lw 010wire i_lbu = itype_l & Funct3[2] & ~Funct3[1] & ~Funct3[0]; //lbu 100wire i_lhu = itype_l & Funct3[2] & ~Funct3[1] & Funct3[0]; //lh 101
// i_r type 涉及Reg与imm运算,ALU with immediate 10条wire itype_r = ~Op[6] & ~Op[5] & Op[4] & ~Op[3] & ~Op[2] & Op[1] & Op[0]; //0010011wire i_addi = itype_r & ~Funct3[2] & ~Funct3[1] & ~Funct3[0]; // addi 000 func3wire i_slti = itype_r & ~Funct3[2] & Funct3[1] & ~Funct3[0]; // slti 010 func3wire i_sltiu = itype_r & ~Funct3[2] & Funct3[1] & Funct3[0]; // sltiu 011 func3
wire i_slli = itype_r & ~Funct3[2] & ~Funct3[1] & Funct3[0]; // slli 001wire i_srli = itype_r & Funct3[2] & ~Funct3[1] & Funct3[0] & ~Funct7[5]; // srli 101 0000000wire i_srai = itype_r & Funct3[2] & ~Funct3[1] & Funct3[0] & Funct7[5]; // srai 101 0100000wire itype_shamt = i_slli | i_srli | i_srai;
// jalrwire i_jalr = Op[6] & Op[5] & ~Op[4] & ~Op[3] & Op[2] & Op[1] & Op[0]; //1100111
// s format store 3条wire stype = ~Op[6] & Op[5] & ~Op[4] & ~Op[3] & ~Op[2] & Op[1] & Op[0];//0100011wire i_sb = stype & ~Funct3[2] & ~Funct3[1] & ~Funct3[0]; // sb 000wire i_sh = stype & ~Funct3[2] & ~Funct3[1] & Funct3[0]; // sh 001wire i_sw = stype & ~Funct3[2] & Funct3[1] & ~Funct3[0]; // sw 010
// B_type 6条wire btype = Op[6] & Op[5] & ~Op[4] & ~Op[3] & ~Op[2] & Op[1] & Op[0]; //1100011wire i_beq = btype & ~Funct3[2] & ~Funct3[1] & ~Funct3[0]; // beq 000wire i_bne = btype & ~Funct3[2] & ~Funct3[1] & Funct3[0]; // bne 001wire i_blt = btype & Funct3[2] & ~Funct3[1] & ~Funct3[0]; // blt 100wire i_bge = btype & Funct3[2] & ~Funct3[1] & Funct3[0]; // bge 101wire i_bltu = btype & Funct3[2] & Funct3[1] & ~Funct3[0]; // bltu 110wire i_bgeu = btype & Funct3[2] & Funct3[1] & Funct3[0]; // bgeu 111
// J_type 1条wire jtype = Op[6] & Op[5] & ~Op[4] & Op[3] & Op[2] & Op[1] & Op[0]; //1101111wire i_jal = jtype; // jal
// U_type 2条wire utype = ~Op[6] & Op[4] & ~Op[3] & Op[2] & Op[1] & Op[0]; //0X10111wire i_lui = utype & Op[5]; // lui 0110111wire i_auipc = utype & ~Op[5]; // auipc 0010111
assign RegWrite = rtype | itype_r | itype_l | i_jal | i_jalr; // register write (含跳转返回地址)assign MemWrite = stype; // memory write
//`define EXT_CTRL_ITYPE_SHAMT 6'b100000//`define EXT_CTRL_ITYPE 6'b010000//`define EXT_CTRL_STYPE 6'b001000//`define EXT_CTRL_BTYPE 6'b000100//`define EXT_CTRL_UTYPE 6'b000010//`define EXT_CTRL_JTYPE 6'b000001assign EXTOp[5] = itype_shamt;assign EXTOp[4] = itype_l | (itype_r & ~itype_shamt) | i_jalr;assign EXTOp[3] = stype;assign EXTOp[2] = btype;assign EXTOp[1] = i_lui | i_auipc;assign EXTOp[0] = i_jal;
//`define ALUOp_nop 5'b00000
//`define ALUOp_sll 5'b00001//`define ALUOp_srl 5'b00010//`define ALUOp_sra 5'b00101
//`define ALUOp_add 5'b00011
//`define ALUOp_beq 5'b00100//`define ALUOp_bne 5'b01000//`define ALUOp_blt 5'b01100//`define ALUOp_bge 5'b10000//`define ALUOp_bltu 5'b10100//`define ALUOp_bgeu 5'b11000assign ALUOp[0] = i_add | i_addi | stype | itype_l | i_jalr | i_sll | i_sra | i_slli | i_srai;assign ALUOp[1] = i_add | i_addi | stype | itype_l | i_jalr | i_srl | i_srli;assign ALUOp[2] = i_beq | i_blt | i_bltu | i_sra | i_srai;assign ALUOp[3] = i_bne | i_blt | i_bgeu;assign ALUOp[4] = i_bge | i_bltu | i_bgeu;
//`define NPC_PLUS4 3'b000//`define NPC_BRANCH 3'b001//`define NPC_JUMP 3'b010//`define NPC_JALR 3'b100assign NPCOp[0] = btype & Zero;assign NPCOp[1] = i_jal;assign NPCOp[2] = i_jalr;
assign ALUSrc = itype_r | itype_l | stype | i_jal | i_jalr; // ALU B is from instruction immediate
// ALU_DM->RF RF_WD// WDSel FromALU 2'b00// WDSel FromMEM 2'b01// WDSel FromPC 2'b10assign WDSel[0] = itype_l;assign WDSel[1] = i_jal | i_jalr;
// dm_word 3'b000// dm_halfword 3'b001// dm_halfword_unsigned 3'b010// dm_byte 3'b011// dm_byte_unsigned 3'b100assign DMType[2] = i_lbu; // buassign DMType[1] = i_lb | i_sb | i_lhu; // hu和bassign DMType[0] = i_lh | i_sh | i_lb | i_sb; // h和b
endmodulealu
`define ALUOp_nop 5'b00000
`define ALUOp_sll 5'b00001`define ALUOp_srl 5'b00010`define ALUOp_sra 5'b00101
`define ALUOp_add 5'b00011
`define ALUOp_beq 5'b00100`define ALUOp_bne 5'b01000`define ALUOp_blt 5'b01100`define ALUOp_bge 5'b10000`define ALUOp_bltu 5'b10100`define ALUOp_bgeu 5'b11000
module alu( input signed [31:0] A,B, input [4:0] ALUOp, output reg signed [31:0] C, output reg Zero);always @(*) begin C = 32'b0; case(ALUOp) `ALUOp_sll: C = A << B[4:0]; `ALUOp_srl: C = A >> B[4:0]; `ALUOp_sra: C = A >>> B[4:0]; `ALUOp_add: C = A + B; `ALUOp_beq: C = {31'b0,(A!=B)}; `ALUOp_bne: C = {31'b0,{A==B}}; `ALUOp_blt: C = {31'b0,(A>=B)}; `ALUOp_bge: C = {31'b0,(A<B)}; `ALUOp_bltu: C = {31'b0,($unsigned(A)>=$unsigned(B))}; `ALUOp_bgeu: C = {31'b0,{$unsigned(A)<$unsigned(B)}}; default:C = 32'b0; endcase Zero = (C == 0)?1:0; // 阻塞赋值,需等C算出来,而不是同步endendmoduleEXT
// 立即数扩展`define EXT_CTRL_ITYPE_SHAMT 6'b100000`define EXT_CTRL_ITYPE 6'b010000`define EXT_CTRL_STYPE 6'b001000`define EXT_CTRL_BTYPE 6'b000100`define EXT_CTRL_UTYPE 6'b000010`define EXT_CTRL_JTYPE 6'b000001
module EXT( input [4:0] iimm_shamt, input [11:0] iimm, input [11:0] simm, input [11:0] bimm, input [19:0] uimm, input [19:0] jimm, input [5:0] EXTOp, output reg [31:0] immout);always @(*) begin case (EXTOp) `EXT_CTRL_ITYPE_SHAMT: immout <= {27'b0,iimm_shamt[4:0]}; // I-type 立即数 (用于 slli/srli/srai) `EXT_CTRL_ITYPE: immout <= {{20{iimm[11]}}, iimm[11:0]}; // I-type 立即数 (用于 addi, lw, jalr 等) `EXT_CTRL_STYPE: immout <= {{20{simm[11]}}, simm[11:0]}; // S-type 立即数 (用于 sw 等) `EXT_CTRL_BTYPE: immout<= {{19{bimm[11]}},bimm[11:0],1'b0}; // B-type 立即数 (用于 beq 等) `EXT_CTRL_UTYPE: immout <= {uimm[19:0], 12'b0}; // U-type 立即数 (用于 lui, auipc) `EXT_CTRL_JTYPE: immout<= {{11{jimm[19]}},jimm[19:0],1'b0}; // J-type 立即数 (用于 jal) default: immout <= 32'b0; endcaseend
endmodule次要代码
seg7x16
module seg7x16( input clk, input rstn, input disp_mode, input [63:0] i_data, output [7:0] disp_seg_o, output [7:0] disp_an_o);// 2^15分频reg [14:0] cnt;wire seg7_clk;
always @(posedge clk or negedge rstn) begin if(!rstn) cnt <= 0; else cnt <= cnt + 1'b1;end
assign seg7_clk = cnt[14];
// 8选1reg [2:0] seg7_addr;
always @(posedge seg7_clk or negedge rstn) begin if(!rstn) seg7_addr <= 0; else seg7_addr <= seg7_addr + 1'b1; end
// 选中的数码管使能信号 reg [7:0] o_sel_r; always @(*) begin case(seg7_addr) 7 : o_sel_r = 8'b01111111; 6 : o_sel_r = 8'b10111111; 5 : o_sel_r = 8'b11011111; 4 : o_sel_r = 8'b11101111; 3 : o_sel_r = 8'b11110111; 2 : o_sel_r = 8'b11111011; 1 : o_sel_r = 8'b11111101; 0 : o_sel_r = 8'b11111110; endcase end
// reg [63:0] i_data_store; always @(posedge clk or negedge rstn) begin if(!rstn) i_data_store <= 0; else i_data_store <= i_data; end
reg [7:0] seg_data_r; always @(*) begin if(disp_mode == 1'b0) begin // 字符显示模式 case(seg7_addr) 0 : seg_data_r = i_data_store[3:0]; 1 : seg_data_r = i_data_store[7:4]; 2 : seg_data_r = i_data_store[11:8]; 3 : seg_data_r = i_data_store[15:12]; 4 : seg_data_r = i_data_store[19:16]; 5 : seg_data_r = i_data_store[23:20]; 6 : seg_data_r = i_data_store[27:24]; 7 : seg_data_r = i_data_store[31:28]; default: seg_data_r = 8'hFF; // 默认全空,防止latch endcase end else begin // 图形显示模式 case(seg7_addr) 0 : seg_data_r = i_data_store[7:0]; 1 : seg_data_r = i_data_store[15:8]; 2 : seg_data_r = i_data_store[23:16]; 3 : seg_data_r = i_data_store[31:24]; 4 : seg_data_r = i_data_store[39:32]; 5 : seg_data_r = i_data_store[47:40]; 6 : seg_data_r = i_data_store[55:48]; 7 : seg_data_r = i_data_store[63:56]; default: seg_data_r = 8'hFF; // 默认全空,防止latch endcase end end
reg [7:0] o_seg_r; always @(posedge clk or negedge rstn) begin if(!rstn) o_seg_r <= 8'hFF; else if(disp_mode == 1'b0) begin // 字符模式 case(seg_data_r) 4'h0 : o_seg_r <= 8'hC0; 4'h1 : o_seg_r <= 8'hF9; 4'h2 : o_seg_r <= 8'hA4; 4'h3 : o_seg_r <= 8'hB0; 4'h4 : o_seg_r <= 8'h99; 4'h5 : o_seg_r <= 8'h92; 4'h6 : o_seg_r <= 8'h82; 4'h7 : o_seg_r <= 8'hF8; 4'h8 : o_seg_r <= 8'h80; 4'h9 : o_seg_r <= 8'h90; 4'hA : o_seg_r <= 8'h88; 4'hB : o_seg_r <= 8'h83; 4'hC : o_seg_r <= 8'hC6; 4'hD : o_seg_r <= 8'hA1; 4'hE : o_seg_r <= 8'h86; 4'hF : o_seg_r <= 8'h8E; default : o_seg_r <= 8'hFF; endcase end else o_seg_r <= seg_data_r; end
assign disp_an_o = o_sel_r; assign disp_seg_o = o_seg_r;endmoduleRF
module RF( input clk, input rstn, input RFWr, input [15:0] sw_i, input [4:0] A1,A2,A3, input [31:0] WD, output [31:0] RD1,RD2);reg [31:0] rf[31:0]; // reg [31:0]为数据类型,rf[31:0]为数组,32位宽,32个寄存器
integer i;always @(posedge clk or negedge rstn) begin if(!rstn) begin for(i=0;i<32;i=i+1) rf[i] <= i; end else if(RFWr && (!sw_i[1]) && (A3 != 5'd0)) rf[A3] <= WD; // 正常模式下且RegWrite有效,写rdend
// 读rs1和rs2assign RD1 = (A1 != 0)?rf[A1]:0;assign RD2 = (A2 != 0)?rf[A2]:0;
endmoduledm
`define dm_word 3'b000`define dm_halfword 3'b001`define dm_halfword_unsigned 3'b010`define dm_byte 3'b011`define dm_byte_unsigned 3'b100
module dm( input clk, input DMWr, input [5:0] addr, input [31:0] din, input [2:0] DMType, output reg [31:0] dout);reg [7:0] dmem[6:0]; // 8位宽数据,7个单元,reg [7:0]为数据类型,dmem[6:0]为数组integer i;initial begin for(i=0;i<7;i=i+1) dmem[i] = 8'h00;end
// 写操作always @(posedge clk) begin if(DMWr) begin case(DMType) `dm_byte:dmem[addr] <= din[7:0]; `dm_halfword:begin dmem[addr] <= din[7:0]; dmem[addr+1] <= din[15:8]; end `dm_word:begin dmem[addr] <= din[7:0]; dmem[addr+1] <= din[15:8]; dmem[addr+2] <= din[23:16]; dmem[addr+3] <= din[31:24]; end endcase endend
// 读操作always @(*) begin case(DMType) `dm_byte:dout = {{24{dmem[addr][7]}},dmem[addr][7:0]}; `dm_byte_unsigned:dout = {24'b0,dmem[addr][7:0]}; `dm_halfword:dout = {{16{dmem[addr+1][7]}},dmem[addr+1][7:0],dmem[addr][7:0]}; `dm_halfword_unsigned:dout = {16'b0,dmem[addr+1][7:0],dmem[addr][7:0]}; `dm_word:dout = {dmem[addr+3][7:0],dmem[addr+2][7:0],dmem[addr+1][7:0],dmem[addr][7:0]}; default:dout = {dmem[addr+3][7:0],dmem[addr+2][7:0],dmem[addr+1][7:0],dmem[addr][7:0]}; endcaseendendmodule