├── EXE.v ├── EXT.v ├── ID.v ├── MEM.v ├── PC.v ├── README.md ├── RF.v ├── WB.v ├── alu.v ├── ctrl.v ├── ctrl_encode_def.v ├── dm.v ├── im.v ├── mipstest_pipelinedloop.asm ├── mipstest_pipelinedloop.dat ├── mux.v ├── sccomp.v ├── sccomp_tb.v ├── sccpu.v ├── studentnosorting.asm └── studentnosorting.dat /EXE.v: -------------------------------------------------------------------------------- 1 | module EXE (clk,rst,ID_RegWrite,ID_mem_to_reg,ID_memwrite,ID_aluOp, ID_jal,ID_alua,ID_alub,ID_PC,ID_A,ID_B,ID_IMM32,ID_writereg_num, 2 | EXE_RegWrite,EXE_mem_to_reg,EXE_memwrite,EXE_aluOp, EXE_jal,EXE_alua,EXE_alub,EXE_PC,EXE_A,EXE_B,EXE_IMM32,EXE_writereg_num 3 | ); 4 | input clk,rst,ID_RegWrite,ID_mem_to_reg,ID_memwrite,ID_jal,ID_alua,ID_alub; 5 | input [4:0] ID_writereg_num; 6 | input [3:0] ID_aluOp; 7 | input [31:0] ID_PC,ID_A,ID_B,ID_IMM32; 8 | 9 | output reg EXE_RegWrite,EXE_mem_to_reg,EXE_memwrite,EXE_jal,EXE_alua,EXE_alub; 10 | output reg [4:0] EXE_writereg_num; 11 | output reg [3:0] EXE_aluOp; 12 | output reg [31:0] EXE_PC,EXE_A,EXE_B,EXE_IMM32; 13 | 14 | always @(posedge clk,posedge rst) 15 | begin 16 | if(rst) begin 17 | EXE_A=0; 18 | EXE_B=0; 19 | EXE_IMM32=0; 20 | EXE_PC=0; 21 | EXE_RegWrite=0; 22 | EXE_aluOp=0; 23 | EXE_alua=0; 24 | EXE_alub=0; 25 | EXE_jal=0; 26 | EXE_mem_to_reg=0; 27 | EXE_memwrite=0; 28 | EXE_writereg_num=0; 29 | end 30 | else begin 31 | EXE_A=ID_A; 32 | EXE_B=ID_B; 33 | EXE_IMM32=ID_IMM32; 34 | EXE_PC=ID_PC+4; 35 | EXE_RegWrite=ID_RegWrite; 36 | EXE_aluOp=ID_aluOp; 37 | EXE_alua=ID_alua; 38 | EXE_alub=ID_alub; 39 | EXE_jal=ID_jal; 40 | EXE_mem_to_reg=ID_mem_to_reg; 41 | EXE_memwrite=ID_memwrite; 42 | EXE_writereg_num=ID_writereg_num; 43 | end 44 | end 45 | endmodule 46 | //EXE级流水线更新数据模块,类似闸门的作用 47 | //此模块仅仅起到更新数据的用途,流水线CPU的基本要求就是一个周期仅更新一次基本信号量,以此保证将一条指令分成五个周期进行 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /EXT.v: -------------------------------------------------------------------------------- 1 | module EXT( Imm16, EXTOp, Imm32 ); 2 | 3 | input [15:0] Imm16; 4 | input EXTOp; 5 | output [31:0] Imm32; 6 | 7 | assign Imm32 = (EXTOp) ? {{16{Imm16[15]}}, Imm16} : {16'd0, Imm16}; 8 | 9 | endmodule 10 | //默认情况下是进行高位补0 的立即数拓展 11 | //在有符号数的情况下进行最高位的拓展 -------------------------------------------------------------------------------- /ID.v: -------------------------------------------------------------------------------- 1 | module ID(clk,rst,ID_nostall,IF_INS,ID_INS,IF_PC,ID_PC); 2 | 3 | input clk,rst,ID_nostall; 4 | input [31:0] IF_INS,IF_PC; 5 | output reg [31:0] ID_INS,ID_PC; 6 | 7 | always@(posedge clk,posedge rst) 8 | begin 9 | if(rst) 10 | ID_INS =32'b0; 11 | else if(ID_nostall) 12 | begin 13 | ID_INS = IF_INS; 14 | ID_PC=IF_PC+4; 15 | end 16 | end 17 | endmodule 18 | //ID级流水线更新数据模块,类似闸门的作用 19 | //此模块仅仅起到更新数据的用途,流水线CPU的基本要求就是一个周期仅更新一次基本信号量,以此保证将一条指令分成五个周期进行 -------------------------------------------------------------------------------- /MEM.v: -------------------------------------------------------------------------------- 1 | module MEM(clk,rst,EXE_C,EXE_RegWrite,EXE_mem_to_reg,EXE_memwrite,EXE_B,EXE_writereg_num, 2 | MEM_C,MEM_RegWrite,MEM_mem_to_reg,MEM_memwrite,MEM_B,MEM_writereg_num, 3 | ); 4 | input clk,rst,EXE_RegWrite,EXE_mem_to_reg,EXE_memwrite; 5 | input [31:0] EXE_B,EXE_C; 6 | input [4:0] EXE_writereg_num; 7 | 8 | output reg MEM_RegWrite,MEM_mem_to_reg,MEM_memwrite; 9 | output reg [31:0] MEM_B,MEM_C; 10 | output reg [4:0] MEM_writereg_num; 11 | 12 | always @(posedge clk,posedge rst) 13 | begin 14 | if(rst) 15 | begin 16 | MEM_B=0; 17 | MEM_C=0; 18 | MEM_RegWrite=0; 19 | MEM_mem_to_reg=0; 20 | MEM_memwrite=0; 21 | MEM_writereg_num=0; 22 | end 23 | else begin 24 | MEM_B=EXE_B; 25 | MEM_C=EXE_C; 26 | MEM_RegWrite=EXE_RegWrite; 27 | MEM_mem_to_reg=EXE_mem_to_reg; 28 | MEM_memwrite=EXE_memwrite; 29 | MEM_writereg_num=EXE_writereg_num; 30 | end 31 | end 32 | endmodule 33 | //MEM级流水线更新数据模块,类似闸门的作用 34 | //此模块仅仅起到更新数据的用途,流水线CPU的基本要求就是一个周期仅更新一次基本信号量,以此保证将一条指令分成五个周期进行 -------------------------------------------------------------------------------- /PC.v: -------------------------------------------------------------------------------- 1 | module PC( clk, rst, NPC, IF_PC ,ID_nostall); 2 | 3 | input clk; 4 | input rst,ID_nostall; 5 | input [31:0] NPC; 6 | output reg [31:0] IF_PC; 7 | 8 | always @(posedge clk, posedge rst) 9 | if (rst) 10 | IF_PC <= 32'h0000_0000; 11 | else if(ID_nostall) 12 | IF_PC <= NPC; 13 | 14 | endmodule 15 | //ID_nostall :根据ID级的控制器决定是否锁定PC,暂停一个周期 16 | //IF级流水线更新数据模块,类似闸门的作用 17 | //此模块仅仅起到更新数据的用途,流水线CPU的基本要求就是一个周期仅更新一次基本信号量,以此保证将一条指令分成五个周期进行 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 五级流水线CPU 2 | *** 3 | 4 | 5 | 1. > **语言** 6 | 7 | verilong HDL。 8 | 9 | 2. > **软件** 10 | 11 | Modelsim 12 | 13 | 3. > **流水线分级** 14 | 15 | IF ID EXE MEM WB。 16 | 17 | 4. > 数据冒险: 18 | 19 | 一般的数据冒险通过旁路(forward)解决; 20 | lw型的数据冒险通过阻塞一个周期加旁路解决。 21 | 22 | 5. > 控制冒险的处理 23 | 24 | 在所有的跳转指令之后加入nop指令,实现在ID级判断之后进行跳转, 25 | 26 | 6. > 动态的分支预测 27 | 28 | 无 29 | 30 | 7. > 异常处理模块 31 | 32 | 无 33 | 34 | | 文件名 | 功能 | 35 | | :-----| :---- | 36 | | sccomp_tb.v | 信号激励文件,是整个CPU的入口 | 37 | | sccomp.v | 与内部CPU和外部指令寄存器和内存打交道的入口 | 38 | | sccpu.v | 是整个工程的核心,执行CPU的所有事务 | 39 | | ctrl.v | 控制器 | 40 | | alu.v | 运算器 | 41 | | PC.v ID.v EXE.v MEM.v WB.v | 控制五级流水线信号的更新部件,一个周期运行一次 | 42 | | EXT.v | 立即数的拓展文件 | 43 | | ctrl_encode_def.v | 类似C语言的一些宏的东西 | 44 | | dm.v | 外部内存ROM文件 | 45 | | im.v | 指令存储器 | 46 | | mux.v | 多路选择器 | 47 | | mipstest_pipelinedloop.asm | 测试文件的MIPS指令 | 48 | | mipstest_pipelinedloop.dat | 测试文件汇编之后的机器码 | 49 | | studentnosorting.asm | 学号排序测试文件的MIPS指令 | 50 | | studentnosorting.dat | 学号排序测试文件汇编之后的机器码 | 51 | 52 | 作者邮箱:`1059024691@qq.com` 53 | 54 | -------------------------------------------------------------------------------- /RF.v: -------------------------------------------------------------------------------- 1 | 2 | module RF( input clk, 3 | input rst, 4 | input RFWr, 5 | input [4:0] A1, A2, A3, 6 | input [31:0] WD, 7 | output [31:0] RD1, RD2, 8 | input [4:0] reg_sel, 9 | output [31:0] reg_data); 10 | 11 | reg [31:0] rf[31:0]; 12 | 13 | integer i; 14 | //目前暂定为时钟的下降沿写入数据,上升沿复位 15 | always @(negedge clk, posedge rst) 16 | if (rst) begin // reset 17 | for (i=1; i<32; i=i+1) 18 | rf[i] <= 0; // i; 19 | end 20 | 21 | else 22 | if (RFWr) begin 23 | rf[A3] <= WD; 24 | end 25 | 26 | 27 | assign RD1 = (A1 != 0) ? rf[A1] : 0; 28 | assign RD2 = (A2 != 0) ? rf[A2] : 0; 29 | assign reg_data = (reg_sel != 0) ? rf[reg_sel] : 0; 30 | 31 | endmodule 32 | //指令寄存器,一直读,时钟下降沿和写使能信号写入数据 -------------------------------------------------------------------------------- /WB.v: -------------------------------------------------------------------------------- 1 | module WB(clk,rst,MEM_RegWrite,MEM_mem_to_reg,MEM_read,MEM_C,MEM_writereg_num, 2 | WB_RegWrite,WB_mem_to_reg,WB_read,WB_C,WB_writereg_num 3 | ); 4 | input clk,rst,MEM_RegWrite,MEM_mem_to_reg; 5 | input [31:0] MEM_C,MEM_read; 6 | input [4:0] MEM_writereg_num; 7 | 8 | output reg WB_RegWrite,WB_mem_to_reg; 9 | output reg [31:0] WB_C,WB_read; 10 | output reg [4:0] WB_writereg_num; 11 | 12 | always @(posedge clk,posedge rst) 13 | begin 14 | if(rst) 15 | begin 16 | WB_C=0; 17 | WB_RegWrite=0; 18 | WB_mem_to_reg=0; 19 | WB_read=0; 20 | WB_writereg_num=0; 21 | end 22 | else begin 23 | WB_C=MEM_C; 24 | WB_RegWrite=MEM_RegWrite; 25 | WB_mem_to_reg=MEM_mem_to_reg; 26 | WB_read=MEM_read; 27 | WB_writereg_num=MEM_writereg_num; 28 | end 29 | end 30 | endmodule 31 | //WB级流水线更新数据模块,类似闸门的作用 32 | //此模块仅仅起到更新数据的用途,流水线CPU的基本要求就是一个周期仅更新一次基本信号量,以此保证将一条指令分成五个周期进行 -------------------------------------------------------------------------------- /alu.v: -------------------------------------------------------------------------------- 1 | `include "ctrl_encode_def.v" 2 | 3 | module alu(A, B, ALUOp, C); 4 | //定义端口输入输出 5 | input signed [31:0] A, B; 6 | input [3:0] ALUOp; 7 | output signed [31:0] C; 8 | 9 | reg [31:0] C; 10 | integer i; 11 | 12 | always @( * ) 13 | begin 14 | case ( ALUOp) 15 | `ALU_NOP: C = A; // NOP 16 | `ALU_ADD: C = A + B; // ADD 17 | `ALU_SUB: C = A - B; // SUB 18 | `ALU_AND: C = A & B; // AND/ANDI 19 | `ALU_OR: C = A | B; // OR/ORI 20 | `ALU_SLT: C = (A < B) ? 32'd1 : 32'd0; // SLT/SLTI 21 | `ALU_SLTU: C = ({1'b0, A} < {1'b0, B}) ? 32'd1 : 32'd0; //SLTU 22 | `ALU_SLL: C = B << A[10:6]; //SLL 23 | `ALU_SLLV: C = B << A[4:0]; //SLLV 24 | `ALU_SRL: C = B >> A[10:6]; //SRL 25 | `ALU_SRLV: C = B >> A[4:0]; //SRLV 26 | `ALU_NOR: C = ~(A|B) ; //NOR 27 | `ALU_LUI: C = B << 16; 28 | default: C = A; // Undefined 29 | endcase 30 | end // end always 31 | 32 | 33 | endmodule 34 | 35 | -------------------------------------------------------------------------------- /ctrl.v: -------------------------------------------------------------------------------- 1 | // `include "ctrl_encode_def.v" 2 | 3 | module ctrl(ID_Op, ID_Funct,ID_rs,ID_rt,ID_Zero, 4 | EXE_RegWrite,MEM_RegWrite,EXE_mem_to_reg,MEM_mem_to_reg,EXE_writereg_num,MEM_writereg_num, 5 | ID_RegWrite,ID_mem_to_reg,ID_writereg_to_rt,ID_memwrite, 6 | ID_extOp, ID_aluOp, ID_npcOp,ID_jal,ID_alua,ID_alub,ID_nostall,ID_forwarda,ID_forwardb, 7 | ); 8 | 9 | 10 | input [5:0] ID_Op, ID_Funct; 11 | input [4:0] ID_rs,ID_rt,EXE_writereg_num,MEM_writereg_num; 12 | input ID_Zero,EXE_RegWrite,MEM_RegWrite,EXE_mem_to_reg,MEM_mem_to_reg; 13 | 14 | output ID_RegWrite,ID_mem_to_reg,ID_memwrite,ID_jal,ID_extOp,ID_alua,ID_alub,ID_nostall; 15 | output [1:0] ID_npcOp,ID_forwarda,ID_forwardb,ID_writereg_to_rt; 16 | output [3:0] ID_aluOp; 17 | 18 | reg [1:0] ID_forwarda,ID_forwardb; 19 | 20 | // r format 21 | wire rtype = ~|ID_Op; 22 | wire i_add = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&~ID_Funct[2]&~ID_Funct[1]&~ID_Funct[0]; // add 23 | wire i_sub = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&~ID_Funct[2]& ID_Funct[1]&~ID_Funct[0]; // sub 24 | wire i_and = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]& ID_Funct[2]&~ID_Funct[1]&~ID_Funct[0]; // and 25 | wire i_or = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]& ID_Funct[2]&~ID_Funct[1]& ID_Funct[0]; // or 26 | wire i_slt = rtype& ID_Funct[5]&~ID_Funct[4]& ID_Funct[3]&~ID_Funct[2]& ID_Funct[1]&~ID_Funct[0]; // slt 27 | wire i_sltu = rtype& ID_Funct[5]&~ID_Funct[4]& ID_Funct[3]&~ID_Funct[2]& ID_Funct[1]& ID_Funct[0]; // sltu 28 | wire i_addu = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&~ID_Funct[2]&~ID_Funct[1]& ID_Funct[0]; // addu 29 | wire i_subu = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&~ID_Funct[2]& ID_Funct[1]& ID_Funct[0]; // subu 30 | 31 | //刘大进补充 32 | wire i_sll = rtype& ~ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&~ID_Funct[2]& ~ID_Funct[1]& ~ID_Funct[0]; 33 | wire i_srl = rtype& ~ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&~ID_Funct[2]& ID_Funct[1]& ~ID_Funct[0]; 34 | wire i_jalr = rtype& ~ID_Funct[5]&~ID_Funct[4]&ID_Funct[3]&~ID_Funct[2]& ~ID_Funct[1]& ID_Funct[0]; 35 | wire i_jr = rtype& ~ID_Funct[5]&~ID_Funct[4]&ID_Funct[3]&~ID_Funct[2]& ~ID_Funct[1]& ~ID_Funct[0]; 36 | wire i_nor = rtype& ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&ID_Funct[2]& ID_Funct[1]& ID_Funct[0]; 37 | wire i_sllv = rtype& ~ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&ID_Funct[2]& ~ID_Funct[1]& ~ID_Funct[0]; 38 | wire i_srlv = rtype& ~ID_Funct[5]&~ID_Funct[4]&~ID_Funct[3]&ID_Funct[2]& ID_Funct[1]& ~ID_Funct[0]; 39 | // i format 40 | wire i_addi = ~ID_Op[5]&~ID_Op[4]& ID_Op[3]&~ID_Op[2]&~ID_Op[1]&~ID_Op[0]; // addi 41 | wire i_ori = ~ID_Op[5]&~ID_Op[4]& ID_Op[3]& ID_Op[2]&~ID_Op[1]& ID_Op[0]; // ori 42 | wire i_lw = ID_Op[5]&~ID_Op[4]&~ID_Op[3]&~ID_Op[2]& ID_Op[1]& ID_Op[0]; // lw 43 | wire i_sw = ID_Op[5]&~ID_Op[4]& ID_Op[3]&~ID_Op[2]& ID_Op[1]& ID_Op[0]; // sw 44 | wire i_beq = ~ID_Op[5]&~ID_Op[4]&~ID_Op[3]& ID_Op[2]&~ID_Op[1]&~ID_Op[0]; // beq 45 | wire i_lui = ~ID_Op[5]&~ID_Op[4]&ID_Op[3]& ID_Op[2]&ID_Op[1]&ID_Op[0];//lui 46 | wire i_slti = ~ID_Op[5]&~ID_Op[4]&ID_Op[3]& ~ID_Op[2]&ID_Op[1]&~ID_Op[0];//slti 47 | wire i_bne = ~ID_Op[5]&~ID_Op[4]&~ID_Op[3]& ID_Op[2]&~ID_Op[1]&ID_Op[0];//bne 48 | wire i_andi = ~ID_Op[5]&~ID_Op[4]&ID_Op[3]& ID_Op[2]&~ID_Op[1]&~ID_Op[0];//andi 49 | // j format 50 | wire i_j = ~ID_Op[5]&~ID_Op[4]&~ID_Op[3]&~ID_Op[2]& ID_Op[1]&~ID_Op[0]; // j 51 | wire i_jal = ~ID_Op[5]&~ID_Op[4]&~ID_Op[3]&~ID_Op[2]& ID_Op[1]& ID_Op[0]; // jal 52 | 53 | 54 | //用于检测lw冒险的时候lw的下一条指令是否使用rs,rt寄存器。 55 | wire i_rs = i_add | i_sub | i_and |i_or | i_slt | i_sltu | i_addu | i_subu | i_jalr | i_jr | i_nor | i_sllv | i_srlv | i_addi | i_ori | i_lw | i_sw | i_beq | i_slti | i_bne | i_andi; 56 | wire i_rt = i_add | i_sub | i_and |i_or | i_slt | i_sltu | i_addu | i_subu | i_sll | i_srl | i_nor | i_sllv | i_srlv | i_beq | i_bne | i_sw; 57 | //允许写寄存器 58 | assign ID_RegWrite = (i_add |i_sub| i_and|i_or|i_slt|i_sltu|i_addu|i_subu| i_lw | i_addi | i_ori | i_jal | i_lui | i_slti | i_sll | i_srl | i_jalr| i_andi | i_nor | i_sllv | i_srlv) & ID_nostall; // register write 59 | 60 | //允许写ROM 61 | assign ID_memwrite = i_sw & ID_nostall; // memory write 62 | 63 | //写入寄存器的来源是内存中读出来的,否则就是从alu中读出来的 64 | assign ID_mem_to_reg = i_lw; 65 | 66 | //lw/sw型数据冒险,停止后序指令一个周期 67 | assign ID_nostall = ~(EXE_RegWrite & EXE_mem_to_reg & (EXE_writereg_num !=0) & ( i_rs & (EXE_writereg_num == ID_rs) | i_rt & (EXE_writereg_num == ID_rt))); 68 | 69 | //默认情况下指令的写是写到rd寄存器,但是在一些立即数包括lw的运算上是写到rt上的 70 | //更奇怪的是jal是写到31号寄存器的,但是却没有31号寄存器的标识!! 71 | assign ID_writereg_to_rt [0] = i_lw | i_addi | i_ori | i_lui | i_slti | i_andi; 72 | assign ID_writereg_to_rt [1] = i_jal; 73 | //默认情况下往寄存器中写的是数,但在jal和jalr的情况下,往31号寄存中写的是PC地址 74 | assign ID_jal = i_jal | i_jalr; 75 | 76 | //正常进行高位填充0进行符号拓展,但是在有符号数的情况下就是填充最高位进行拓展 77 | assign ID_extOp = i_addi | i_lw | i_sw | i_bne | i_beq; 78 | 79 | //正常情况下alua是来自forwarda信号控制的多路选择器的,也就是寄存器的,但在sll,srl却是来自shamt字段的,此时就要传递符号拓展后的立即数然后切片的 80 | assign ID_alua = i_sll | i_srl; 81 | 82 | //正常情况下alub是来自forwardb信号控制的多路选择器的,也就是寄存器的,但是在addi等的情况下却来自拓展后的立即数 83 | assign ID_alub = i_addi | i_andi | i_ori | i_lw | i_sw | i_lui | i_slti; 84 | 85 | //默认情况下是进行pc+4,只有出现跳转指令时 86 | //我们定义01 bpc就是立即数+地址跳转 87 | //10 npc寄存器跳转 典型的有jr jalr 88 | //11 jpc就是指令跳转,典型的有j,jal; 89 | assign ID_npcOp[1] = i_jr | i_jalr | i_j | i_jal; 90 | assign ID_npcOp[0] = i_beq & ID_Zero | i_bne & ~ID_Zero | i_j | i_jal; 91 | 92 | //旁路 93 | always @ (ID_rs,ID_rt,EXE_RegWrite,EXE_mem_to_reg,EXE_writereg_num,MEM_RegWrite,MEM_mem_to_reg,MEM_writereg_num) 94 | begin 95 | 96 | ID_forwarda = 2'b00;//默认没有冒险 97 | if(EXE_RegWrite & (EXE_writereg_num!=0) &(EXE_writereg_num ==ID_rs) & ~EXE_mem_to_reg) 98 | begin 99 | ID_forwarda = 2'b01;//发生EXE-ID级R型冒险 100 | end 101 | else if(MEM_RegWrite & (MEM_writereg_num!=0) &(MEM_writereg_num ==ID_rs) &~MEM_mem_to_reg) 102 | begin 103 | ID_forwarda = 2'b10;//发生MEM-ID级冒险 104 | end 105 | else if(MEM_RegWrite & (MEM_writereg_num!=0) & (MEM_writereg_num==ID_rs) & MEM_mem_to_reg) 106 | begin 107 | ID_forwarda = 2'b11;//发生lw型的冒险 108 | end 109 | 110 | ID_forwardb = 2'b00;//默认没有冒险 111 | if(EXE_RegWrite & (EXE_writereg_num!=0) &(EXE_writereg_num ==ID_rt) & ~EXE_mem_to_reg) 112 | begin 113 | ID_forwardb = 2'b01;//发生EXE-ID级R型冒险 114 | end 115 | else if(MEM_RegWrite & (MEM_writereg_num!=0) &(MEM_writereg_num ==ID_rt) &~MEM_mem_to_reg) 116 | begin 117 | ID_forwardb = 2'b10;//发生MEM-ID级冒险 118 | end 119 | else if(MEM_RegWrite & (MEM_writereg_num!=0) & (MEM_writereg_num==ID_rt) & MEM_mem_to_reg) 120 | begin 121 | ID_forwardb = 2'b11;//发生lw型的冒险 122 | end 123 | end 124 | 125 | //执行ALU指令 126 | assign ID_aluOp[0] = i_add | i_lw | i_sw | i_addi | i_and | i_slt | i_addu | i_sll | i_andi | i_nor |i_srlv; 127 | assign ID_aluOp[1] = i_sub | i_beq | i_and | i_sltu | i_subu | i_sll | i_slti | i_bne | i_andi | i_sllv|i_srlv; 128 | assign ID_aluOp[2] = i_or | i_ori | i_slt | i_sltu | i_sll | i_slti | i_lui ; 129 | assign ID_aluOp[3] = i_srl | i_nor |i_sllv|i_srlv | i_lui; 130 | 131 | endmodule 132 | -------------------------------------------------------------------------------- /ctrl_encode_def.v: -------------------------------------------------------------------------------- 1 | // NPC control signal 2 | `define NPC_PLUS4 2'b00 3 | `define NPC_BPC 2'b01 4 | `define NPC_JPC 2'b10 5 | `define NPC_RPC 2'b11 6 | 7 | // ALU control signal 8 | `define ALU_NOP 4'b0000 9 | `define ALU_ADD 4'b0001 10 | `define ALU_SUB 4'b0010 11 | `define ALU_AND 4'b0011 12 | `define ALU_OR 4'b0100 13 | `define ALU_SLT 4'b0101 14 | `define ALU_SLTU 4'b0110 15 | `define ALU_SLL 4'b0111 16 | `define ALU_SRL 4'b1000 17 | `define ALU_NOR 4'b1001 18 | `define ALU_SLLV 4'b1010 19 | `define ALU_SRLV 4'b1011 20 | `define ALU_LUI 4'b1100 21 | -------------------------------------------------------------------------------- /dm.v: -------------------------------------------------------------------------------- 1 | 2 | // data memory 3 | module dm(clk, DMWr, addr, din, dout); 4 | input clk; 5 | input DMWr; 6 | input [8:2] addr; 7 | input [31:0] din; 8 | output [31:0] dout; 9 | 10 | reg [31:0] dmem[127:0]; 11 | 12 | always @(posedge clk) 13 | if (DMWr) begin 14 | dmem[addr[8:2]] <= din; 15 | $display("dmem[0x%8X] = 0x%8X,", addr << 2, din); 16 | end 17 | assign dout = dmem[addr[8:2]]; 18 | 19 | endmodule 20 | //始终读取ROM存储器中的数据,仅当有写信号且有时钟之时才将数据写入ROM -------------------------------------------------------------------------------- /im.v: -------------------------------------------------------------------------------- 1 | 2 | // 指令寄存器,用于根据PC读取指令 3 | module im(input [8:2] addr, 4 | output [31:0] dout ); 5 | 6 | reg [31:0] ROM[127:0]; 7 | 8 | assign dout = ROM[addr]; 9 | endmodule 10 | -------------------------------------------------------------------------------- /mipstest_pipelinedloop.asm: -------------------------------------------------------------------------------- 1 | # mipstest_pipelined.asm 2 | # 2017202110132@whu.edu.cn 25 March 2018 3 | # add, sub, and, or, slt, addi, lw, sw, beq, j have been done in mipstest.asm 4 | # sll, lui, bne, jal, ori, addu, subu, jr, srl have been done in mipstest_extended.asm 5 | # sltu, nor are added in this test. 6 | ### Make sure the following Settings : 7 | # Settings -> Memory Configuration -> Compact, Text at address 0 8 | # You could use it to test if there is data hazard and control hazard. 9 | # If successful, it should write value 12 to address 80 and 84, and register $7 should be 12 10 | 11 | # Assembly Description Address Machine 12 | # Test if there is data hazard 13 | main: addi $2, $0, 5 # initialize $2 = 5 00 20020005 14 | ori $3, $0, 12 # initialize $3 = 12 04 3403000c 15 | subu $1, $3, $2 # $1 = 12 - 5 = 7 08 00620823 16 | srl $7, $1, 1 # $7 = 7 >> 1 = 3 0c 00013842 17 | call_a: j a # jump to a 10 08000019 18 | nop 14 00000000 19 | or $4, $7, $2 # $4 = (3 or 5) = 7 18 00e22025 20 | and $5, $3, $4 # $5 = (12 and 7) = 4 1c 00642824 21 | add $5, $5, $4 # $5 = 4 + 7 = 11 20 00a42820 22 | beq $5, $7, end # should not be taken 24 10a7001f 23 | nop # 28 00000000 24 | sltu $4, $3, $4 # $4 = (12 < 7) = 0 2c 0064202b 25 | #Test if there is control hazard 26 | beq $4, $0, around # should be taken 30 10800004 27 | nop # 34 00000000 28 | addi $5, $0, 0 # should not happen 38 20050000 29 | addi $5, $0, 0 # should not happen 3c 20050000 30 | addi $5, $0, 0 # should not happen 40 20050000 31 | around: slt $4, $7, $2 # $4 = 3 < 5 = 1 44 00e2202a 32 | addu $7, $4, $5 # $7 = 1 + 11 = 12 48 00853821 33 | sub $7, $7, $2 # $7 = 12 - 5 = 7 4c 00e23822 34 | sw $7, 68($3) # [80] = 7 50 ac670044 101011 00011 00111 0000000001000100 35 | lw $2, 80($0) # $2 = [80] = 7 54 8c020050 36 | j end # should be taken 58 08000029 37 | nop # 5c 00000000 38 | addi $2, $0, 1 # should not happen 60 20020001 39 | a: sll $7, $7, 2 # $7 = 3 << 2 = 12 64 00073880 40 | call_b: jal b # jump to b 68 0c00001f 41 | nop # 6c 00000000 42 | addi $31,$0,24 # $31 <= 20 70 201f0018 43 | jr $31 # return to call_a 74 03e00008 44 | nop # 78 00000000 45 | b: lui $1, 0xFFAA # $1 <= 0xFFAA0000 7c 3c01ffaa 46 | slt $1, $7, $1 # $1 <= 0 80 00e1082a 47 | bne $1, $0, end # should not be taken 84 14200007 48 | nop # 88 00000000 49 | sub $7, $7, $2 # $7 = 12 - 5 = 7 8c 00e23822 50 | srl $7, $7, 1 # $7 = 7 >> 1 = 3 90 00073842 51 | nor $1, $7, $1 # $1 = 0xFFFFFFFC 94 00e10827 52 | sltu $1, $1, $7 # $1 <= 0 98 0027082b 53 | jr $31 # return to call_b 9c 03e00008 54 | nop # a0 00000000 55 | # Test if there is load use hazard 56 | end: sw $3, 84($0) # [84] = 12 a4 ac030054 57 | lw $7, 72($3) # $7 = [84] = 12 a8 8c670048 58 | 59 | sw $7, 68($3) # [80] = 12 ac ac670044 60 | lw $6, 68($3) # $6 = [80] = 12 b0 8c660044 61 | 62 | add $6, $6, $5 # $6 = 12 + 11 = 23 b4 00c53020 63 | loop: j loop # dead loop b8 0800002e 64 | nop # bc 00000000 65 | 66 | 67 | # $0 = 0 # $1 = 0 # $2 = 7 # $3 = c 68 | # $4 = 1 # $5 = b # $6 = 17h # $7 = c 69 | # $31 = 18h -------------------------------------------------------------------------------- /mipstest_pipelinedloop.dat: -------------------------------------------------------------------------------- 1 | 20020005 2 | 3403000c 3 | 00620823 4 | 00013842 5 | 08000019 6 | 00000000 7 | 00e22025 8 | 00642824 9 | 00a42820 10 | 10a7001f 11 | 00000000 12 | 0064202b 13 | 10800004 14 | 00000000 15 | 20050000 16 | 20050000 17 | 20050000 18 | 00e2202a 19 | 00853821 20 | 00e23822 21 | ac670044 22 | 8c020050 23 | 08000029 24 | 00000000 25 | 20020001 26 | 00073880 27 | 0c00001f 28 | 00000000 29 | 201f0018 30 | 03e00008 31 | 00000000 32 | 3c01ffaa 33 | 00e1082a 34 | 14200007 35 | 00000000 36 | 00e23822 37 | 00073842 38 | 00e10827 39 | 0027082b 40 | 03e00008 41 | 00000000 42 | ac030054 43 | 8c670048 44 | ac670044 45 | 8c660044 46 | 00c53020 47 | 0800002e 48 | 00000000 49 | -------------------------------------------------------------------------------- /mux.v: -------------------------------------------------------------------------------- 1 | //2,4,8,16.四种模式的的多路选择器 2 | 3 | // mux2 4 | module mux2 #(parameter WIDTH = 8) 5 | (d0, d1, 6 | s, y); 7 | 8 | input [WIDTH-1:0] d0, d1; 9 | input s; 10 | output [WIDTH-1:0] y; 11 | 12 | assign y = ( s == 1'b1 ) ? d1:d0; 13 | 14 | endmodule 15 | 16 | // mux4 17 | module mux4 #(parameter WIDTH = 8) 18 | (d0, d1, d2, d3, 19 | s, y); 20 | 21 | input [WIDTH-1:0] d0, d1, d2, d3; 22 | input [1:0] s; 23 | output [WIDTH-1:0] y; 24 | 25 | reg [WIDTH-1:0] y_r; 26 | 27 | always @( * ) begin 28 | case ( s ) 29 | 2'b00: y_r = d0; 30 | 2'b01: y_r = d1; 31 | 2'b10: y_r = d2; 32 | 2'b11: y_r = d3; 33 | default: ; 34 | endcase 35 | end // end always 36 | 37 | assign y = y_r; 38 | 39 | endmodule 40 | 41 | // mux8 42 | module mux8 #(parameter WIDTH = 8) 43 | (d0, d1, d2, d3, 44 | d4, d5, d6, d7, 45 | s, y); 46 | 47 | input [WIDTH-1:0] d0, d1, d2, d3; 48 | input [WIDTH-1:0] d4, d5, d6, d7; 49 | input [2:0] s; 50 | output [WIDTH-1:0] y; 51 | 52 | reg [WIDTH-1:0] y_r; 53 | 54 | always @( * ) begin 55 | case ( s ) 56 | 3'd0: y_r = d0; 57 | 3'd1: y_r = d1; 58 | 3'd2: y_r = d2; 59 | 3'd3: y_r = d3; 60 | 3'd4: y_r = d4; 61 | 3'd5: y_r = d5; 62 | 3'd6: y_r = d6; 63 | 3'd7: y_r = d7; 64 | default: ; 65 | endcase 66 | end // end always 67 | 68 | assign y = y_r; 69 | 70 | endmodule 71 | 72 | // mux16 73 | module mux16 #(parameter WIDTH = 8) 74 | (d0, d1, d2, d3, 75 | d4, d5, d6, d7, 76 | d8, d9, d10, d11, 77 | d12, d13, d14, d15, 78 | s, y); 79 | 80 | input [WIDTH-1:0] d0, d1, d2, d3; 81 | input [WIDTH-1:0] d4, d5, d6, d7; 82 | input [WIDTH-1:0] d8, d9, d10, d11; 83 | input [WIDTH-1:0] d12, d13, d14, d15; 84 | input [3:0] s; 85 | output [WIDTH-1:0] y; 86 | 87 | reg [WIDTH-1:0] y_r; 88 | 89 | always @( * ) begin 90 | case ( s ) 91 | 4'd0: y_r = d0; 92 | 4'd1: y_r = d1; 93 | 4'd2: y_r = d2; 94 | 4'd3: y_r = d3; 95 | 4'd4: y_r = d4; 96 | 4'd5: y_r = d5; 97 | 4'd6: y_r = d6; 98 | 4'd7: y_r = d7; 99 | 4'd8: y_r = d8; 100 | 4'd9: y_r = d9; 101 | 4'd10: y_r = d10; 102 | 4'd11: y_r = d11; 103 | 4'd12: y_r = d12; 104 | 4'd13: y_r = d13; 105 | 4'd14: y_r = d14; 106 | 4'd15: y_r = d15; 107 | default: ; 108 | endcase 109 | end // end always 110 | 111 | assign y = y_r; 112 | 113 | endmodule 114 | -------------------------------------------------------------------------------- /sccomp.v: -------------------------------------------------------------------------------- 1 | //顶层文件 2 | module sccomp(clk, rstn, reg_sel, reg_data); 3 | input clk; 4 | input rstn; 5 | input [4:0] reg_sel; 6 | output [31:0] reg_data; 7 | 8 | wire [31:0] instr; 9 | wire [31:0] PC; 10 | wire MemWrite; 11 | wire [31:0] dm_addr, dm_din, dm_dout; 12 | 13 | wire rst = ~rstn; 14 | 15 | // instantiation of single-cycle CPU 16 | sccpu U_SCCPU( 17 | .clk(clk), // input: cpu clock 18 | .rst(rst), // input: reset 19 | .instr(instr), // input: instruction 20 | .readdata(dm_dout), // input: data to cpu 21 | .MemWrite(MemWrite), // output: memory write signal 22 | .PC(PC), // output: PC 23 | .aluout(dm_addr), // output: address from cpu to memory 24 | .writedata(dm_din), // output: data from cpu to memory 25 | .reg_sel(reg_sel), // input: register selection 26 | .reg_data(reg_data) // output: register data 27 | ); 28 | 29 | // instantiation of data memory 30 | dm U_DM( 31 | .clk(clk), // input: cpu clock 32 | .DMWr(MemWrite), // input: ram write 33 | .addr(dm_addr[8:2]), // input: ram address 34 | .din(dm_din), // input: data to ram 35 | .dout(dm_dout) // output: data from ram 36 | ); 37 | 38 | // instantiation of intruction memory (used for simulation) 39 | im U_IM ( 40 | .addr(PC[8:2]), // input: rom address 41 | .dout(instr) // output: instruction 42 | ); 43 | 44 | endmodule 45 | 46 | -------------------------------------------------------------------------------- /sccomp_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | // 测试文件 3 | module sccomp_tb(); 4 | //定义输入输出端口 5 | reg clk, rstn; 6 | reg [4:0] reg_sel; 7 | wire [31:0] reg_data; 8 | 9 | 10 | //实例化顶层文件 11 | sccomp U_SCCOMP( 12 | .clk(clk), .rstn(rstn), .reg_sel(reg_sel), .reg_data(reg_data) 13 | ); 14 | 15 | //初始化信号量并加载指令存储器,将指令添加到存储器中 16 | initial 17 | begin 18 | $readmemh( "mipstest_pipelinedloop.dat" , U_SCCOMP.U_IM.ROM); // load instructions into instruction memory 19 | clk = 1; 20 | rstn = 1; 21 | #5 ; 22 | rstn = 0; 23 | #20 ; 24 | rstn = 1; 25 | #1000 ; 26 | reg_sel = 7; 27 | end 28 | //50ns一次时钟翻转 29 | always 30 | begin 31 | #(50) clk = ~clk; 32 | end 33 | endmodule 34 | -------------------------------------------------------------------------------- /sccpu.v: -------------------------------------------------------------------------------- 1 | 2 | //流水线CPU核心模块 3 | module sccpu( clk, rst, instr, readdata,PC, MemWrite, aluout, writedata, reg_sel, reg_data); 4 | input clk; 5 | input rst; // reset 6 | 7 | input [31:0] instr; // instruction 8 | input [31:0] readdata; // data from data memory 9 | 10 | output [31:0] PC; // PC address 11 | output MemWrite; // memory write 12 | output [31:0] aluout; // ALU output 13 | output [31:0] writedata; // data to data memory 14 | 15 | input [4:0] reg_sel; // register selection (for debug use) 16 | output [31:0] reg_data; // selected register data (for debug use) 17 | 18 | 19 | 20 | wire [15:0] ID_IMM16; 21 | wire [31:0] ID_IMM32,EXE_IMM32; 22 | wire [31:0] NPC; 23 | wire [31:0] jpc,npc,bpc; 24 | wire [31:0] ID_INS; 25 | wire [31:0] ID_PC; 26 | wire [31:0] ID_A,ID_B; 27 | wire [31:0] ID_reada,ID_readb; 28 | wire [4:0] ID_writereg_num; 29 | 30 | wire [31:0] WB_writereg;//写向寄存器的数据 31 | wire [5:0] ID_Op, ID_Funct; 32 | wire [4:0] ID_rs,ID_rt,ID_rd,EXE_writereg_num,MEM_writereg_num; 33 | wire ID_Zero,EXE_RegWrite,MEM_RegWrite,EXE_mem_to_reg,MEM_mem_to_reg; 34 | 35 | wire ID_RegWrite,ID_mem_to_reg,ID_memwrite,ID_jal,ID_extOp,ID_alua,ID_alub,ID_nostall; 36 | wire [1:0] ID_npcOp,ID_forwarda,ID_forwardb,ID_writereg_to_rt; 37 | wire [3:0] ID_aluOp; 38 | 39 | 40 | wire EXE_memwrite,EXE_jal,EXE_alua,EXE_alub; 41 | wire [3:0] EXE_aluOp; 42 | wire [31:0] EXE_PC,EXE_A,EXE_B,EXE_C; 43 | 44 | 45 | wire WB_RegWrite,WB_mem_to_reg; 46 | wire [31:0] WB_C,WB_read; 47 | wire [4:0] WB_writereg_num; 48 | 49 | wire [31:0] ALU_A,ALU_B,ALU_C; 50 | //用于更新PC,IF级作用 51 | PC U_PC(.rst(rst), .IF_PC(PC),.clk(clk),.NPC(NPC),.ID_nostall(ID_nostall)); 52 | //此时将jal,和j指令集合到了一起。但是j是跳转指令低26,而jal仅仅16位,但是此次试验PC地址不会太大,故此处可暂时将 53 | assign jpc={ID_PC[31:18],ID_INS[15:0],2'b00}; 54 | //用于寄存器跳转,主要有jalr,jr 55 | assign npc=ID_A; 56 | //用于bne,beq跳转 57 | assign bpc=ID_PC+{14'b0,ID_IMM16,2'b00}; 58 | 59 | //切分指令段 60 | assign ID_Op=ID_INS[31:26]; 61 | assign ID_Funct=ID_INS[5:0]; 62 | assign ID_rs=ID_INS[25:21]; 63 | assign ID_rt=ID_INS[20:16]; 64 | assign ID_rd=ID_INS[15:11]; 65 | assign ID_IMM16=ID_INS[15:0]; 66 | //用于bne,beq的ID级判断 67 | assign ID_Zero=(ID_A ==ID_B)?1'b1:1'b0; 68 | //ID级更新作用 69 | ID U_ID(.clk(clk),.rst(rst),.IF_INS(instr),.IF_PC(PC),.ID_INS(ID_INS),.ID_PC(ID_PC),.ID_nostall(ID_nostall)); 70 | 71 | //控制器,核心部件 72 | ctrl U_CTRL(.ID_Op(ID_Op), .ID_Funct(ID_Funct),.ID_rs(ID_rs),.ID_rt(ID_rt),.ID_Zero(ID_Zero), 73 | .EXE_RegWrite(EXE_RegWrite),.MEM_RegWrite(MEM_RegWrite),.EXE_mem_to_reg(EXE_mem_to_reg),.MEM_mem_to_reg(MEM_mem_to_reg),.EXE_writereg_num(EXE_writereg_num),.MEM_writereg_num(MEM_writereg_num), 74 | .ID_RegWrite(ID_RegWrite),.ID_mem_to_reg(ID_mem_to_reg),.ID_writereg_to_rt(ID_writereg_to_rt),.ID_memwrite(ID_memwrite), 75 | .ID_extOp(ID_extOp), .ID_aluOp(ID_aluOp), .ID_npcOp(ID_npcOp),.ID_jal(ID_jal),.ID_alua(ID_alua),.ID_alub(ID_alub),.ID_nostall(ID_nostall),.ID_forwarda(ID_forwarda),.ID_forwardb(ID_forwardb) 76 | ); 77 | //决定下一个pc信号,取决于控制器器的输出 78 | mux4 #(32) U_MUX4_NPC (.d0(PC+4),.d1(bpc),.d2(npc),.d3(jpc),.s(ID_npcOp),.y(NPC)); 79 | //决定是否进行立即数的有符号数的拓展 80 | EXT U_EXT(.Imm16(ID_IMM16),.EXTOp(ID_extOp),.Imm32(ID_IMM32)); 81 | //决定是否进行旁路,进行旁路进行什么旁路 82 | mux4 #(32) U_MUX4_FOEWARDA (.d0(ID_reada),.d1(EXE_C),.d2(aluout),.d3(readdata),.s(ID_forwarda),.y(ID_A)); 83 | //决定是否进行旁路,进行旁路进行什么旁路 84 | mux4 #(32) U_MUX4_FOEWARDB (.d0(ID_readb),.d1(EXE_C),.d2(aluout),.d3(readdata),.s(ID_forwardb),.y(ID_B)); 85 | 86 | //决定写入寄存器的内容的来源,是EXE级计算出的,还是MEM级读出来的 87 | mux2 #(32) U_MUX2_WRITEREG (.d0(WB_C),.d1(WB_read), .s(WB_mem_to_reg), .y(WB_writereg)); 88 | 89 | //寄存器模块 90 | RF U_RF(.clk(clk),.rst(rst),.RFWr(WB_RegWrite),.A1(ID_rs),.A2(ID_rt),.A3(WB_writereg_num),.WD(WB_writereg),.RD1(ID_reada),.RD2(ID_readb),.reg_sel(reg_sel),.reg_data(reg_data)); 91 | //决定写入的寄存器号的来源,31号还是rd段或者rt段 92 | mux4 #(5) U_MUX4_RT_RD (.d0(ID_rd),.d1(ID_rt),.d2(5'b11111),.d3(5'b0),.s(ID_writereg_to_rt),.y(ID_writereg_num)); 93 | 94 | 95 | 96 | //EXE级更新作用 97 | EXE U_EXE(.clk(clk),.rst(rst),.ID_RegWrite(ID_RegWrite),.ID_mem_to_reg(ID_mem_to_reg),.ID_memwrite(ID_memwrite),.ID_aluOp(ID_aluOp),. ID_jal( ID_jal),.ID_alua(ID_alua),.ID_alub(ID_alub),.ID_PC(ID_PC),.ID_A(ID_A),.ID_B(ID_B),.ID_IMM32(ID_IMM32),.ID_writereg_num(ID_writereg_num), 98 | .EXE_RegWrite(EXE_RegWrite),.EXE_mem_to_reg(EXE_mem_to_reg),.EXE_memwrite(EXE_memwrite),.EXE_aluOp(EXE_aluOp),.EXE_jal(EXE_jal),.EXE_alua(EXE_alua),.EXE_alub(EXE_alub),.EXE_PC(EXE_PC),.EXE_A(EXE_A),.EXE_B(EXE_B),.EXE_IMM32(EXE_IMM32),.EXE_writereg_num(EXE_writereg_num) 99 | ); 100 | //MEM级更新作用 101 | MEM U_MEM(.clk(clk),.rst(rst),.EXE_C(EXE_C),.EXE_RegWrite(EXE_RegWrite),.EXE_mem_to_reg(EXE_mem_to_reg),.EXE_memwrite(EXE_memwrite),.EXE_B(EXE_B),.EXE_writereg_num(EXE_writereg_num), 102 | .MEM_C(aluout),.MEM_RegWrite(MEM_RegWrite),.MEM_mem_to_reg(MEM_mem_to_reg),.MEM_memwrite(MemWrite),.MEM_B(writedata),.MEM_writereg_num(MEM_writereg_num) 103 | ); 104 | //WB级更新作用 105 | WB U_WB(.clk(clk),.rst(rst),.MEM_RegWrite(MEM_RegWrite),.MEM_mem_to_reg(MEM_mem_to_reg),.MEM_read(readdata),.MEM_C(aluout),.MEM_writereg_num(MEM_writereg_num), 106 | .WB_RegWrite(WB_RegWrite),.WB_mem_to_reg(WB_mem_to_reg),.WB_read(WB_read),.WB_C(WB_C),.WB_writereg_num(WB_writereg_num) 107 | ); 108 | //决定ALUC是来自PC还是来自ALU计算的结果 109 | mux2 #(32) U_MUX2_ALUC (.d0(ALU_C),.d1(EXE_PC),.s(EXE_jal),.y(EXE_C)); 110 | //决定ALUa是来自ID级的旁路选择器的结果还是来自立即数 111 | mux2 #(32) U_MUX2_ALUA (.d0(EXE_A),.d1(EXE_IMM32),.s(EXE_alua),.y(ALU_A)); 112 | //决定ALUb是来自ID级的旁路选择器的结果还是来自立即数 113 | mux2 #(32) U_MUX2_ALUB (.d0(EXE_B),.d1(EXE_IMM32),.s(EXE_alub),.y(ALU_B)); 114 | //进行ALU运算 115 | alu U_ALU(.A(ALU_A),.B(ALU_B),.ALUOp(EXE_aluOp),.C(ALU_C)); 116 | 117 | endmodule -------------------------------------------------------------------------------- /studentnosorting.asm: -------------------------------------------------------------------------------- 1 | ############################################# 2 | # C program for sorting the student no. 3 | ############################################# 4 | # sortedstuno = stuno; 5 | # mask0 = 0x0f; 6 | # for (int i= 0; i < 8; i++) { 7 | # a = sortedstuno & mask0; 8 | # a = a >> (4 * i); 9 | # mask1 = mask0 << 4; 10 | # bestj = i; 11 | # tmpMax = a; 12 | # for (int j = i + 1; j < 8) { 13 | # b = sortedstuno & mask1; 14 | # b = b >> (4 * j); 15 | # if (tmpMax < b) { 16 | # tmpMax = b; 17 | # bestj = j; 18 | # } 19 | # mask1 = mask1 << 4; 20 | # } 21 | # if (a < tmpMax) { 22 | # mask1 = 0x0f; 23 | # bestj4 = bestj << 2; 24 | # mask1 = mask1 << bestj4 25 | # mask2 = mask0 | mask1; 26 | # mask2 = ~mask2; 27 | # sortedstuno = sortedstuno & mask2; 28 | # tmpMax = tmpMax << (4 * i); 29 | # sortedstuno = sortedstuno | tmpMax; 30 | # a = a << bestj4; 31 | # sortedstuno = sortedstuno | a; 32 | # } 33 | # mask0 = mask0 << 4; 34 | # } 35 | ############################################# 36 | # the uasge of the registers 37 | ############################################# 38 | # mem[0], student no. 39 | # mem[4], sorted student no 40 | # $1, partially sorted student number / the address of switch 41 | # $2, the outer loop variable i / the address of seg7 42 | # $3, the inner loop variable j / the switch input 43 | # $4, mask0 44 | # $5, mask1 45 | # $6, mask2 46 | # $7, a 47 | # $8, b 48 | # $9, 4 * i 49 | # $10, 4 * j 50 | # $11, N = 8 51 | # $12, bestj 52 | # $13, tmpMax 53 | # $14, compare result 54 | ############################################# 55 | # MIPS assembly language program for sorting the student no. 56 | # The following instructions are used. 57 | # add and nor or sll sllv srlv slt 58 | # addi andi ori lui 59 | # beq bne 60 | # j jal jr 61 | # lw sw 62 | ######################################################################################################################### instr.(H) ####### addr.(H) 63 | lui $2, 0x0150 # high halfword the student no (last 8 digitals), use your own student no. instead! # 0 0 64 | ori $2, $2, 0x0196 # low halfword of the student no (last 8 digitals) # 1 4 65 | sw $2, 0($0) # store the original stuno at data memory # 2 8 66 | addi $11, $0, 8 # the size of stuno, N = 8 # 3 C 67 | lw $1, 0x0($0) # $1 = [0x0] = stuno # 4 10 68 | add $2, $0, $0 # the outer loop variable initilization, i = 0, # 5 14 69 | addi $4, $0, 0x0f # mask0 = 0xf # 6 18 70 | loop1: 71 | and $7, $1, $4 # a = sortedstuno & mask0, get the BCD to be processed # 7 1C 72 | sll $9, $2, 2 # (4 * i) # 8 20 73 | srlv $7, $7, $9 # a = a >> (4 * i), shift the BCD to the LSB 4 bits # 9 24 74 | sll $5, $4, 4 # mask1 = mask0 << 4 # A 28 75 | add $12, $2, $0 # bestj = i, remmember the position of the largest BCD in this loop # B 2C 76 | add $13, $7, $0 # tmpMax = a, remember the last BCD in this loop # C 30 77 | addi $3, $2, 1 # j = i + 1, the inner loop variable initilization, j = i + 1 # D 34 78 | loop2: 79 | beq $3, $11, checkswap # to check if j == 8 # E 38 80 | nop 81 | and $8, $1, $5 # b = sortedstuno & mask1 # F 3C 82 | sll $10, $3, 2 # (4 * j) # 10 40 83 | srlv $8, $8, $10 # b = b >> (4 * j), shift the BCD to the LSB 4 bits # 11 44 84 | slt $14, $13, $8 # # 12 48 85 | beq $14, $0, incrLoop2 # if (tmpMax >= b), increase j # 13 4C 86 | nop 87 | add $13, $8, $0 # tmpMax = b, remember the last BCD in this loop # 14 50 88 | add $12, $3, $0 # bestj = j, remmember the position of the largest BCD in this loop # 15 54 89 | incrLoop2: 90 | sll $5, $5, 4 # mask1 = mask1 << 4 # 16 58 91 | addi $3, $3, 1 # j = j + 1 # 17 5C 92 | j loop2 # 18 60 93 | nop 94 | checkswap: 95 | slt $14, $2, $12 # to check if the position of the largest BCD in the this loop has been changed # 19 64 96 | beq $14, $0, incrLoop1 # 1A 68 97 | nop 98 | jal swap # 1B 6C 99 | nop 100 | incrLoop1: 101 | sll $4, $4, 4 # mask0 = mask0 << 4 # 1C 70 102 | addi $2, $2, 1 # i = i + 1 # 1D 74 103 | bne $2, $11, loop1 # to check if i <> 8 # 1E 78 104 | nop 105 | 106 | result: 107 | sw $1, 0x04($0) # [0x04] = sortedstuno # 1F 7C 108 | 109 | lui $2, 0xffff # $1 = 0xffff0000 # 20 80 110 | ori $1, $2, 0x0004 # $1 = 0xffff0004 # switch as input # 21 84 111 | ori $2, $2, 0x000c # $2 = 0xffff000c # seg7 as output # 22 88 112 | 113 | display: 114 | lw $3, 0x00($1) # 23 8C 115 | andi $3, $3, 0x100 # test if bit 8 is 1 # 24 90 116 | beq $3, $0, dispstuno # if bit 8 = 0, display the original stu no. if bit 8 = 1, display the sorted stu no. # 25 94 117 | nop 118 | dispsortedstuno: 119 | lw $3, 0x04($0) # load the sorted student no. # 26 98 120 | j displayseg7label # 27 9C 121 | nop 122 | dispstuno: 123 | lw $3, 0x00($0) # load the orginal student no. # 28 A0 124 | displayseg7label: 125 | sw $3, 0x00($2) # output to seg7 # 29 A4 126 | j display # 2A A8 127 | nop 128 | 129 | swap: # change the nibble at i with the nibble at bestj 130 | addi $5, $0, 0x0f # 2B AC 131 | sll $10, $12, 2 # 4 * bestj # 2C B0 132 | sllv $5, $5, $10 # mask1 = mask (4 * bestj) # 2D B4 133 | or $6, $4, $5 # mask2 = mask0 | mask1 # 2E B8 134 | nor $6, $6, $0 # mask2 = ~mask2 # 2F BC 135 | and $1, $1, $6 # sortedstuno = sortedstuno & mask2 # 30 C0 136 | sllv $8, $13,$9 # tmpmax = tmpmax << (4*i) # 31 C4 137 | or $1, $1, $8 # sortedstuno = sortedstuno | tmpmax # 32 C8 138 | sllv $7, $7, $10 # a = a << (4 * bestj) # 33 CC 139 | or $1, $1, $7 # sortedstuno = sortedstuno | a # 34 D0 140 | jr $31 # 35 D4 141 | nop 142 | -------------------------------------------------------------------------------- /studentnosorting.dat: -------------------------------------------------------------------------------- 1 | 3c020150 2 | 34420196 3 | ac020000 4 | 200b0008 5 | 8c010000 6 | 00001020 7 | 2004000f 8 | 00243824 9 | 00024880 10 | 01273806 11 | 00042900 12 | 00406020 13 | 00e06820 14 | 20430001 15 | 106b000d 16 | 00000000 17 | 00254024 18 | 00035080 19 | 01484006 20 | 01a8702a 21 | 11c00003 22 | 00000000 23 | 01006820 24 | 00606020 25 | 00052900 26 | 20630001 27 | 0800000e 28 | 00000000 29 | 004c702a 30 | 11c00003 31 | 00000000 32 | 0c000034 33 | 00000000 34 | 00042100 35 | 20420001 36 | 144bffe3 37 | 00000000 38 | ac010004 39 | 3c02ffff 40 | 34410004 41 | 3442000c 42 | 8c230000 43 | 30630100 44 | 10600004 45 | 00000000 46 | 8c030004 47 | 08000031 48 | 00000000 49 | 8c030000 50 | ac430000 51 | 08000029 52 | 00000000 53 | 2005000f 54 | 000c5080 55 | 01452804 56 | 00853025 57 | 00c03027 58 | 00260824 59 | 012d4004 60 | 00280825 61 | 01473804 62 | 00270825 63 | 03e00008 64 | 00000000 65 | --------------------------------------------------------------------------------