计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集

单周期CPU实验:
完成本次实验最重要的策略是参考CPU的流程图:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第1张图片

通过流程图,我们可以发现一共要实现五个部分,并且流程图给出了关键电线的定义。
电线的定义:
 与寄存器接口有关的:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第2张图片

在原本提供的三个接口中,添加四根交互的电线。
 与译码阶段有关的:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第3张图片

按照mips手册提供的指令,将instruction拆分,方便后续获得所需要的部分。
Control Unit:
对于单周期CPU,Load指令和MemtoReg始终相当,所以其电平高低始终和MemRead指令一样,因此可以舍去着一根电线。

电线含义:

  1. RegDst信号用来区分RF_waddr是rt还是rd。
  2. Branch信号用来指示是否存在一个跳转信号。
  3. Condition信号代表在所有跳转类指令中总有成立条件,Branch指令高电平代表条件成立。
  4. MemRead信号在Load指令高电平。
  5. MemWrite信号在Store指令高电平。
  6. ALU_conrol信号用来操控ALU。
  7. ALUsrc信号代表那些计算过程中需要利用扩展数的指令。
     与加法器、移位器有关的:
    计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第4张图片

 与取址阶段有关的:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第5张图片

 与Load和Store阶段有关的:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第6张图片

  1. Vaddr代表在Load过程中运算得到的Address值的末两位,其用来决定最后读入寄存器堆的值是哪一块。
  2. l_mask代表掩码,其用来选数。
     用来判断opcode的一些电线:

 一些用于符号拓展的电线:
在这里插入图片描述

前两条电线设计的分别是无符号和有符号数拓展,第三条是针对lui指令的特别设计,最后一条是为了ITYPE的branch指令设计的扩展。
取址阶段:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第7张图片

在单周期CPU,每一次上升沿都应当将PC寄存器变化为下一拍的值,其中有四个可能的情况:
  1. Rst高电平,对PC复位
  2. 一般情况下,PC下一拍就是PC+4
  3. 对于当前拍是一个Branch指令,而且这个Branch指令符合了其所被需求的条件,则下一拍跳转至PC_4+shift_sign_extend。
  4. 对于当前拍是一个跳转指令,分两种可能:
    对于R_Type的,直接跳转到寄存器堆读出的指定位置;
    对于J_Type的,跳转到
{PC_4[31:28],Instruction[25:0],2'b00};

译码阶段:
Control Unit
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第8张图片

  1. RegDst信号在R_Type指令中高电平,写位置为rd否则为rt,当jal类指令时,写在第31号寄存器处。
  2. RF_wen信号代表write enable信号,在所有计算类信号、移位信号、满足条件的移 动信号、Store信号和需要向31号位写的情况下全部都是高电平。
    执行阶段:
    增加了更多功能的ALU:
    计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第9张图片

本ALU修改时比较简单,添加了sltu/xor/nor,其中 sltu和Carryout的电平高低是一样的,因为定义是相同的,xor和nor则直接算好了选数就行了。
自行设计的shifter:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第10张图片

由于直接使用了移位指令,因此shifter直接算出结果再进行选数即可,唯一要注意的是算术右移最好做到先把A转为有符号数,免得出现一些因为被误认为是无符号数而显得吊诡的波形。
ALU的端口信号设计:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第11张图片

 ALUcontrol较为好设计:以下是电路示意图
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第12张图片

对于ITYPE和RTYPE的计算信号,除开lui需要单独设计之外,全部调用对应的ALUcontrol模块即可。
对于Load和Store信号,需要利用加法计算得到Address,因此ALUcontrol为ADD。
对于movz/movn/beq/bne指令,前者是【rt】和0比较是否相等,后者是【rs】/【rt】比较是否相等,因此利用减法,利用Zero这根电线判断即可。
对于bltz/bgez/blez/bgtz我选择使用slt操作判断【rs】和零的关系。这里有一个思考:
对于bltz和bgez,需要把A设置为【rs】B设置为0,对于blez和bgtz,需要把A设置为0B设置【rs】,这样利用slt的定义,就可以直接判断结果是否满足了。

 Extend选数设计:
基本上除了ITYPE的andi/ori/xori,其余全是有符号扩展,MUX选数即可。
 ALU的A/B赋值:
对于A,大部分操作它应当被复制为【rs】但是在movz/movn操作中,其应当为0,对于blez/bgtz前文已解释其为0。
对于B,大部分操作它应当被复制为【rt】,但对与Load/Store操作其应该被赋值为扩展后的立即数,对于ITYPE也是如此。对于blez和bgtz前文已经提及,应当被赋值为【rs】。
Shift端口信号设计:
在这里插入图片描述
Shifter端口非常方便设计,对于因为func的末两位和shiftop是一致的,对于shiftB按照不同指令选数即可。
Store指令:

计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第13张图片

按照mips指令要求,Address的返回值末两位为0,末两位的信息利用掩码反馈。
我选择的设计是算出所有的MemWrite指令的掩码和返回值,然后选数。
 Write_strb掩码设计:
最好设计的掩码是sw指令的掩码,因为它一定是1111。
对于sb指令的掩码,根据3-4’b1000,2-4’b0100……直接设计。
对于sh指令的掩码,如果高位为1,为4’b1100,否则为低位,为4’b0011。
对于swl和swr指令,必须注意到这是一个小根端CPU,按照mips指令参考手册的指示,即可写出对应的掩码。
随后进行按照指令选数即可。
 Write_data返回值设计:
根据掩码的定义,掩码为1所在的位,代表这一字节需要被存入内存,因此按照掩码指示设计拼接然后补零即可。
对于sw数据,由于直接是RF_data2,可以不用单独设计选出这个数。
Load指令设计:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第14张图片

虽然未作要求,但是同样设计一条掩码会比较方便,因为在原本的电路中2bit才能确定是哪一位,但先求出掩码,就只需要1bit找到是哪一位了。
在求得mask后,可以直接利用mask选数,从而得到每一种指令需要的值,最后在寄存器取值时选数即可。
RF_Wdata设计:
计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第15张图片

除开lui指令和shift指令需要单独设计之外,所有计算指令的结果就存在ALU_result。
对于其他指令:

  1. 对于jal/jalr指令,需要将下一拍PC值存在【31】即PC+8.
  2. 对于shift指令,结果存在shift_result。
  3. 对于lui指令,直接选取预先算好的lui即可。
  4. 对于load指令,需要扩展的按照指令要求,相应的符号或者无符号扩展即可。
    多周期CPU实验:
    多周期CPU状态转移图:
    计算机组成原理实验项目2 简单功能型处理器设计 —— 基于MIPS 32位指令集_第16张图片

多周期CPU自动机代码:

always @(*)begin
    case(current_state)
        `state_IF : begin
            next_state = `state_ID;
        end
        `state_ID : begin
            if(op_EX == 1'b1)
                next_state = `state_EX;
            else 
                next_state = `state_IF;
        end
        `state_EX : begin
            if(op_REGIMM|op_I_Type_branch|op_j)
                next_state = `state_IF;
            else 
                if(op_R_Type|op_jal|op_I_Type_cal)
                    next_state = `state_WB;
                else if(Load|Store)
                        next_state = `state_MEM;
                    else
                        next_state = `state_EX;
        end
        `state_MEM: begin
            if(Load)
                next_state = `state_WB;
            else 
                if(Store)
                    next_state = `state_IF;
                else 
                    next_state = `state_MEM; 
        end
        `state_WB : begin
            next_state = `state_IF;
        end 
    default:
        next_state = `state_IF;
    endcase
end

多周期CPU的核心是添加一个自动机模块,按照CPU设计的五个阶段,定义相应的状态,在这里我使用one-hot编码:

`define state_NOP 9'b000000001
`define state_IF  9'b000000010
`define state_ID  9'b000000100
`define state_EX  9'b000001000
`define state_MEM 9'b000010000
`define state_WB  9'b000100000

对于状态转移过程,总的来讲,按照转移图设计代码,即可,但是值得注意的的是,为避免形成锁存器,这个组合逻辑所有的if结构必须要保有else,因此如果本状态所有状态选择完毕后,要将不合逻辑的输入状态保留在原本的状态位置,也就是自己的下个状态仍然是自己。
除此之外PC的时序逻辑也需要修改:

    always@(posedge clk)begin
        if(rst)begin
            PC<=32'b0;
        end
        else begin
            if(current_state == `state_IF )
                PC<=PC+4;
            else 
                if(current_state == `state_EX && (op_jump|(Branch&condition)))
                    if(op_jump)
                        PC<=PC_jump;
                    else 
                        PC<=PC_branch;
        end
    end

对于PC来讲,在取址阶段其一定会正常加4,对于branch指令在执行阶段跳转。由于mips指令集存在一种被称为延迟槽的技术,因此对于branch指令的PC+4得到的那条多余的指令其实是一个nop指令,因此不会执行。
寄存器:

    always@(posedge clk)begin
        if(current_state == `state_IF)begin
            PC_temp<=PC;
        end
    end

    always@(posedge clk)begin
        if(current_state == `state_IF)begin
            Instruction_temp<= Instruction;     
        end
    end

    always@(posedge clk)begin
        if(MemRead == 1'b1)begin
            Read_data_temp<=Read_data;
        end
    end

多周期CPU设计了三种寄存器,分别是PC/Instruction/Read_data,对于前两者,由于在译码阶段PC会改变,所以需要存储上一拍PC和Instruction的值,对于后一个,则只有在MemRead拉高时才有值,因此需要用寄存器存储。

`timescale 10ns / 1ns

`define DATA_WIDTH 32
`define ADDR_WIDTH 5

`define ADD 3'b010
`define SUB 3'b110
`define AND 3'b000
`define OR  3'b001
`define XOR 3'b100
`define NOR 3'b101
`define SLT 3'b111
`define SLTU 3'b011

`define beq 6'b000100
`define bne 6'b000101
`define blez 6'b000110 
`define bgtz 6'b000111 

`define sb 6'b101000
`define sh 6'b101001
`define sw 6'b101011
`define swl 6'b101010
`define swr 6'b101110

`define lui 6'b001111
`define lb  6'b100000
`define lbu 6'b100100
`define lh  6'b100001
`define lhu 6'b100101
`define lw  6'b100011
`define lwl 6'b100010
`define lwr 6'b100110

module simple_cpu(
	input             clk,
	input             rst,

	output reg [31:0]     PC,
	input  [31:0]     Instruction,

	output [31:0]     Address,
	output            MemWrite,
	output [31:0]     Write_data,
	output [ 3:0]     Write_strb,

	input  [31:0]     Read_data,
	output            MemRead
);
	// THESE THREE SIGNALS ARE USED IN OUR TESTBENCH
	// PLEASE DO NOT MODIFY SIGNAL NAMES
	// AND PLEASE USE THEM TO CONNECT PORTS
	// OF YOUR INSTANTIATION OF THE REGISTER FILE MODULE
	wire			RF_wen;
	wire [4:0]		RF_waddr;
	wire [31:0]		RF_wdata;

	wire [4:0]      RF_raddr1;
	wire [4:0]      RF_raddr2;
	wire [31:0]     RF_rdata1;
	wire [31:0]     RF_rdata2;


	wire [5:0]  opcode;// = Instruction[31:26];
	wire [4:0]  rs    ;// = Instruction[25:21];
	wire [4:0]  rt    ;// = Instruction[20:16];
	wire [4:0]  rd    ;// = Instruction[15:11];
	wire [4:0]  sa    ;// = Instruction[10:6];
	wire [5:0]  func  ;// = Instruction[5:0];
	wire [15:0] imm   ;// = Instruction[15:0];
	wire [25:0] instr_index;
	
	assign opcode = Instruction[31:26];
	assign rs     = Instruction[25:21];
	assign rt     = Instruction[20:16];
	assign rd     = Instruction[15:11];
	assign sa     = Instruction[10:6];
	assign func   = Instruction[5:0];
	assign imm    = Instruction[15:0];
	assign instr_indx = Instruction[25:0];
	//wire for control unit
	wire RegDst;//determine write register is rt/rd
	wire Branch;/*branch has two types, the first one is whether it is a branch order 
									and the second one is wheter it meets the conditon*/
	wire condition;//condition in branch

	assign MemRead  = opcode[5] & (~opcode[3]);
	/*
	lwr:
    对于大端:从所指位置(地址)向低地址方向取数直至地址对齐,且按从低地址至高地址的顺序将数据排序,将排序好的数据存放在寄存器的低位。
       对于小端:从所指位置(地址)向高低址方向取数直至地址对齐,且按从高地址至低地址的顺序将数据排序,将排序好的数据存放在寄存器的低位。

	lwl:
    对于大端:从所指位置(地址)向高地址方向取数直至地址对齐,且按从低地址至高地址的顺序将数据排序,将排序好的数据存放在寄存器的高位。
       对于小端:从所指位置(地址)向低地址方向取数直至地址对齐,且按从高地址至低地址的顺序将数据排序,将排序好的数据存放在寄存器的高位。
	*/
	assign MemWrite = opcode[5] & opcode[3];
	wire MemtoReg;//write back flag
	wire [2:0] ALU_control;//the order of ALU;
	wire ALUsrc;
	/*
		a wire that tells you whether the extension required
	*/
	wire [31:0] extend;//in case MR/MW/I_Type_cal extend number is required
	wire [31:0] ALU_A;
	wire [31:0] ALU_B;
	wire [31:0] ALU_result;
	wire Zero;/*
		case 1 bltz,bgez,movz,movn,blez,bgtz needs zero wire to get the condtion
		which means judge the value of rs
	*/
	//wire for shift
	wire [31:0] shift_A;
	wire [4:0]  shift_B;
	wire [1:0]  shift_control;
	wire [31:0] shift_result;
	//wire for PC
	wire [31:0] PC_4;//normally PC + 4
	wire [31:0] PC_branch;//PC_4 + offset (imm) bltz/bgez/beq/bne/blez/bgtz
	wire [31:0] PC_jump;
	/*
		case 1 R_type jump to (rs)
		case 2 J_Type jump to (PC+4)[31:28]+Instr_index+00
	*/
	assign PC_4 = PC+4;//can be replaced by a alu

	wire [31:0] sign_extend = {{16{Instruction[15]}},Instruction[15:0]};
	wire [31:0] zero_extend = {16'b0,Instruction[15:0]};
	wire [31:0] lui_extend  = {Instruction[15:0],16'b0};
	wire [31:0] shift_sign_extend ={{14{Instruction[15]}},Instruction[15:0],2'b00};//for I-Type branch PC_4+ signed_extend(imm+00)
	wire [1:0]  vaddr;
	wire [7:0]  load_byte;
	wire [15:0] load_half;
	wire [31:0] load_lwl;
	wire [31:0] load_lwr;
	wire [3:0]  write_sb;//byte
	wire [3:0]  write_sh;//half
	wire [3:0]  write_sw;//word just 4'b1111
	wire [3:0]  write_swl;
	wire [3:0]  write_swr;
	wire [3:0] 	l_mask;
	wire [31:0] result_sb;
	wire [31:0] result_sh;
	wire [31:0] result_sw;
	wire [31:0] result_swl;
	wire [31:0] result_swr;

	wire op_sb  = opcode ==`sb;
	wire op_sh  = opcode ==`sh;
	wire op_sw  = opcode ==`sw;
	wire op_swl = opcode ==`swl;
	wire op_swr = opcode ==`swr;
	wire op_beq = opcode ==`beq;
	wire op_bne = opcode ==`bne;
	wire op_blez= opcode ==`blez;
	wire op_bgtz= opcode ==`bgtz;

	wire op_R_Type = opcode == 6'b000000;
	wire op_R_Type_cal = op_R_Type&func[5];
	wire op_REGIMM = opcode == 6'b000001;
	wire op_J_Type = opcode[5:1] == 5'b00001;
	wire op_I_Type_branch = opcode[5:2] == 4'b0001;
	wire op_I_Type_cal    = opcode[5:3] == 3'b001;
	wire op_jal    = opcode == 6'b000011;
	wire op_jalr   = op_R_Type & (func == 6'b001001);
	wire op_cal    = op_R_Type&(func[5] == 1'b1)|op_I_Type_cal;
	wire op_shift  = op_R_Type&(func[5:3] == 3'b000);
	wire op_jump   = op_R_Type&({func[5:3],func[1]}==4'b0010)|op_J_Type;
	wire op_mov    = op_R_Type&({func[5:3],func[1]}==4'b0011);
	wire op_PC_jump = (op_R_Type&({func[5:3],func[1]}==4'b0010));//for PC_jump to (rs)

	assign RegDst = op_R_Type ? 1 : 0;
	assign Branch = op_I_Type_branch|op_REGIMM;
	assign ALUsrc = op_I_Type_cal|MemRead|MemWrite;
	assign RF_wen = op_cal|op_shift|(op_mov&(Zero^func[0]))|MemRead|op_jal|op_jalr;
	assign RF_raddr1 = rs;
	assign RF_raddr2 = rt;
	assign RF_waddr  = op_jal?31:(RegDst?rd:rt);
	assign RF_wdata  = {32{op_jal|op_jalr}}& (PC+8)|
					   {32{op_shift}}& shift_result|
					   {32{op_mov&(Zero^func[0])}}& RF_rdata1|
					   {32{opcode==`lui}}& lui_extend|
					   {32{opcode==`lb }}& {{24{load_byte[7]}},load_byte}|
					   {32{opcode==`lbu}}& {{24{1'b0}},load_byte}|
					   {32{opcode==`lh }}& {{16{load_half[15]}},load_half}|
					   {32{opcode==`lhu}}& {{16{1'b0}},load_half}|
					   {32{opcode==`lw }}& Read_data|
					   {32{opcode==`lwl}}& load_lwl|
					   {32{opcode==`lwr}}& load_lwr|
					   {32{op_cal&~(opcode==`lui)}}& ALU_result
					   ;	

	assign vaddr = ALU_result[1:0];
	assign l_mask = {vaddr[1]&vaddr[0],vaddr[1]&~vaddr[0],~vaddr[1]&vaddr[0],~vaddr[1]&~vaddr[0]};
	assign load_byte = { 8{l_mask[3]}}&Read_data[31:24]|
					   { 8{l_mask[2]}}&Read_data[23:16]|
					   { 8{l_mask[1]}}&Read_data[15: 8]|
					   { 8{l_mask[0]}}&Read_data[ 7: 0];

	assign load_half = {16{l_mask[0]}}&Read_data[15: 0]|
					   {16{l_mask[2]}}&Read_data[31:16];
	
	assign load_lwl  = {32{l_mask[3]}}&Read_data[31: 0]|
					   {32{l_mask[2]}}&{Read_data[23:0],RF_rdata2[ 7:0]}|
					   {32{l_mask[1]}}&{Read_data[15:0],RF_rdata2[15:0]}|
					   {32{l_mask[0]}}&{Read_data[ 7:0],RF_rdata2[23:0]};

	assign load_lwr  = {32{l_mask[3]}}&{RF_rdata2[31: 8],Read_data[31:24]}|
					   {32{l_mask[2]}}&{RF_rdata2[31:16],Read_data[31:16]}|
					   {32{l_mask[1]}}&{RF_rdata2[31:24],Read_data[31: 8]}|
					   {32{l_mask[0]}}&Read_data[31:0];

	assign ALU_control  = {3{op_R_Type_cal&(func[3:2]==2'b00)}}&{func[1],2'b10}|
						  {3{op_R_Type_cal&(func[3:2]==2'b01)}}&{func[1],1'b0,func[0]}|
						  {3{op_R_Type_cal&(func[3:2]==2'b10)}}&{~func[0],2'b11}|
						  {3{op_I_Type_cal&(opcode[2:1]==2'b00)}}&{opcode[1],2'b10}|
						  {3{op_I_Type_cal& opcode[2]}}&{opcode[1],1'b0,opcode[0]}|
						  {3{op_I_Type_cal&(opcode[2:1]==2'b01)}}&{~opcode[0],2'b11}|
						  {3{MemRead|MemWrite}}&`ADD|
						  {3{op_mov|op_beq|op_bne}}&`SUB| //sub rs-rt in beq/bne sub rs-0 in movz/movn
						  {3{op_REGIMM|op_blez|op_bgtz}}&`SLT//in mov A=(rs) B=0, in blez A=0,B=(rs)
						  ;
	assign extend = (op_I_Type_cal&opcode[2])?zero_extend:sign_extend;//(op_I_Type_cal&~opcode[2]|MemRead|MemWrite)
	assign condition = ((op_beq)&&Zero)|((op_bne)&&~Zero)|
					   ((op_blez)&&Zero)|((op_bgtz)&&~Zero)|
					   (op_REGIMM&~rt[0]&~Zero)|(op_REGIMM&rt[0]&Zero); 
	
	assign ALU_A = RF_rdata1&{32{~(op_mov|(op_blez)|(op_bgtz))}};
	assign ALU_B = {32{ALUsrc}}&extend|{32{((op_blez)|(op_bgtz))}}&RF_rdata1|{32{~(ALUsrc|((op_blez)|(op_bgtz))|op_REGIMM)}}&RF_rdata2;
	
	//model for shift R_Type 
	assign shift_control= func[1:0];
	assign shift_A = RF_rdata2;
	assign shift_B = (func[2])?RF_rdata1[4:0]:sa;

	assign PC_branch = PC_4+shift_sign_extend;

	always@(posedge clk)begin
		if(rst)begin
			PC<=32'b0;
		end
		else begin
			PC<=op_jump?PC_jump:((Branch&condition)?PC_branch:PC_4);
		end
	end
	reg_file ren_data(
		.clk(clk),
		.waddr(RF_waddr),
		.raddr1(RF_raddr1),
		.raddr2(RF_raddr2),
		.wen(RF_wen),
		.wdata(RF_wdata),
		.rdata1(RF_rdata1),
		.rdata2(RF_rdata2)
	);
	//model for shift operation
	shifter EX_shift(
		.A(shift_A),
		.B(shift_B),
		.Shiftop(shift_control),
		.Result(shift_result)
	);
	//model for calculation operation and for calculating the
	alu EX_alu(
		.A(ALU_A),
		.B(ALU_B),
		.ALUop(ALU_control),
		.Overflow(),
		.CarryOut(),
		.Zero(Zero),
		.Result(ALU_result)
	);

	assign Address = {ALU_result[31:2],2'b00};
	/*Aligned.The effective address must be naturally-aligned. 
	If either of the 2 least-significant bits of the address is non-zero, an Address Error exception occurs.*/
	assign write_sw = 4'b1111;
	assign write_sb = {{ALU_result[1:0]==2'b11},{ALU_result[1:0]==2'b10},{ALU_result[1:0]==2'b01},{ALU_result[1:0]==2'b00}};//3-4'b1000/2-4'b0100
	//4'b1000>>(~ALU_result[1:0]);
	assign write_sh = {4{ALU_result[1]}}&4'b1100|{4{~ALU_result[1]}}&4'b0011;
	assign write_swl = {ALU_result[1]&ALU_result[0],ALU_result[1],ALU_result[1]|ALU_result[0],1'b1};//0,4'b0001 1,4'b0011 2,4'b0111 3,4'b1111
	assign write_swr = {1'b1,~ALU_result[1]|~ALU_result[0],~ALU_result[1],~ALU_result[1]&~ALU_result[0]};

	assign Write_strb = {4{op_sb}}&write_sb|{4{op_sh}}&write_sh|{4{op_sw}}&write_sw|{4{op_swl}}&write_swl|{4{op_swr}}&write_swr;

	assign result_sb  = {{8{write_sb [3]}}&RF_rdata2[ 7: 0],{8{write_sb [2]}}&RF_rdata2[ 7: 0],{8{write_sb [1]}}&RF_rdata2[ 7:0],{8{write_sb [0]}}&RF_rdata2[7:0]};
	assign result_sh  = {{16{write_sh[3]}}&RF_rdata2[15: 0],{16{write_sh[1]}}&RF_rdata2[15: 0]};
	assign result_swl =  {32{(write_swl==4'b0001)}} & {{24{1'b0}},RF_rdata2[31:24]} |
						 {32{(write_swl==4'b0011)}} & {{16{1'b0}},RF_rdata2[31:16]} |
						 {32{(write_swl==4'b0111)}} & {{ 8{1'b0}},RF_rdata2[31:8]};
	assign result_swr =  {32{(write_swr==4'b1110)}} & {RF_rdata2[23:0],{ 8{1'b0}}} |
						 {32{(write_swr==4'b1100)}} & {RF_rdata2[15:0],{16{1'b0}}} |
						 {32{(write_swr==4'b1000)}} & {RF_rdata2[ 7:0],{24{1'b0}}};
	
	assign Write_data = {32{op_sb}}&result_sb|{32{op_sh}}&result_sh|{32{op_swl}}&result_swl|{32{op_swr}}&result_swr|{32{~(MemWrite)|op_sw}}&RF_rdata2;
					
	assign PC_jump= {32{op_PC_jump}}&RF_rdata1|{32{~op_PC_jump}}&{PC_4[31:28],Instruction[25:0],2'b00};
	
endmodule 
`timescale 10ns / 1ns

`define state_NOP 9'b000000001
`define state_IF  9'b000000010
`define state_ID  9'b000000100
`define state_EX  9'b000001000
`define state_MEM 9'b000010000
`define state_WB  9'b000100000

`define DATA_WIDTH 32
`define ADDR_WIDTH 5

`define ADD 3'b010
`define SUB 3'b110
`define AND 3'b000
`define OR  3'b001
`define XOR 3'b100
`define NOR 3'b101
`define SLT 3'b111
`define SLTU 3'b011

`define beq 6'b000100
`define bne 6'b000101
`define blez 6'b000110 
`define bgtz 6'b000111 

`define sb 6'b101000
`define sh 6'b101001
`define sw 6'b101011
`define swl 6'b101010
`define swr 6'b101110

`define lui 6'b001111
`define lb  6'b100000
`define lbu 6'b100100
`define lh  6'b100001
`define lhu 6'b100101
`define lw  6'b100011
`define lwl 6'b100010
`define lwr 6'b100110

module simple_cpu(
	input             clk,
	input             rst,

	output reg [31:0]     PC,
	input  [31:0]     Instruction,

	output [31:0]     Address,
	output            MemWrite,
	output [31:0]     Write_data,
	output [ 3:0]     Write_strb,

	input  [31:0]     Read_data,
	output            MemRead
);
	// THESE THREE SIGNALS ARE USED IN OUR TESTBENCH
	// PLEASE DO NOT MODIFY SIGNAL NAMES
	// AND PLEASE USE THEM TO CONNECT PORTS
	// OF YOUR INSTANTIATION OF THE REGISTER FILE MODULE
	wire			RF_wen;
	wire [ 4:0]		RF_waddr;
	wire [31:0]		RF_wdata;
	wire [ 4:0]     RF_raddr1;//it is easily to be misused between raddr and rdata
	wire [ 4:0]     RF_raddr2;
	wire [31:0]     RF_rdata1;
	wire [31:0]     RF_rdata2;

	reg  [ 8:0] 	current_state;
	reg  [ 8:0] 	next_state;
	reg  [31:0] 	Read_data_reg;

	reg  [31:0] 	Instruction_reg;
	reg  [31:0] 	PC_reg;
	wire [ 5:0]  	opcode;// = Instruction[31:26];
	wire [ 4:0]  	rs    ;// = Instruction[25:21];
	wire [ 4:0]  	rt    ;// = Instruction[20:16];
	wire [ 4:0]  	rd    ;// = Instruction[15:11];
	wire [ 4:0] 	sa    ;// = Instruction[10:6];
	wire [ 5:0]  	func  ;// = Instruction[5:0];
	wire [15:0] 	imm   ;// = Instruction[15:0];
	wire [25:0] 	instr_index;
	
	assign opcode = Instruction_reg[31:26];
	assign rs     = Instruction_reg[25:21];
	assign rt     = Instruction_reg[20:16];
	assign rd     = Instruction_reg[15:11];
	assign sa     = Instruction_reg[10:6];
	assign func   = Instruction_reg[5:0];
	assign imm    = Instruction_reg[15:0];
	assign instr_indx = Instruction_reg[25:0];
	//wire for control unit
	wire RegDst;//determine write register is rt/rd
	wire Branch;/*branch has two types, the first one is whether it is a branch order 
									and the second one is wheter it meets the conditon*/
	wire condition;//condition in branch

	wire Load = opcode[5] & (~opcode[3]);
	assign MemRead  = (current_state == `state_MEM) ? Load : 0;
	/*
	lwr:
    对于大端:从所指位置(地址)向低地址方向取数直至地址对齐,且按从低地址至高地址的顺序将数据排序,将排序好的数据存放在寄存器的低位。
       对于小端:从所指位置(地址)向高低址方向取数直至地址对齐,且按从高地址至低地址的顺序将数据排序,将排序好的数据存放在寄存器的低位。

	lwl:
    对于大端:从所指位置(地址)向高地址方向取数直至地址对齐,且按从低地址至高地址的顺序将数据排序,将排序好的数据存放在寄存器的高位。
       对于小端:从所指位置(地址)向低地址方向取数直至地址对齐,且按从高地址至低地址的顺序将数据排序,将排序好的数据存放在寄存器的高位。
	*/
	wire Store = opcode[5] & opcode[3];
	assign MemWrite = (current_state == `state_MEM) ? Store : 0;

	wire MemtoReg;//write back flag
	wire [2:0] ALU_control;//the order of ALU;
	wire ALUsrc;
	/*
		a wire that tells you whether the extension required
	*/
	wire [31:0] extend;//in case MR/MW/I_Type_cal extend number is required
	wire [31:0] ALU_A;
	wire [31:0] ALU_B;
	wire [31:0] ALU_result;
	wire Zero;/*
		case 1 bltz,bgez,movz,movn,blez,bgtz needs zero wire to get the condtion
		which means judge the value of rs
	*/
	//wire for shift
	wire [31:0] shift_A;
	wire [4:0]  shift_B;
	wire [1:0]  shift_control;
	wire [31:0] shift_result;
	//wire for PC
	wire [31:0] PC_4;//normally PC + 4
	wire [31:0] PC_branch;//PC_4 + offset (imm) bltz/bgez/beq/bne/blez/bgtz
	wire [31:0] PC_jump;
	/*
		case 1 R_type jump to (rs)
		case 2 J_Type jump to (PC+4)[31:28]+Instr_index+00
	*/
	assign PC_4 = PC_reg+4;//can be replaced by a alu

	wire [31:0] sign_extend = {{16{Instruction_reg[15]}},Instruction_reg[15:0]};
	wire [31:0] zero_extend = {16'b0,Instruction_reg[15:0]};
	wire [31:0] lui_extend  = {Instruction_reg[15:0],16'b0};
	wire [31:0] shift_sign_extend ={{14{Instruction_reg[15]}},Instruction_reg[15:0],2'b00};//for I-Type branch PC_4+ signed_extend(imm+00)
	wire [1:0]  vaddr;
	wire [3:0]  l_mask;
	wire [7:0]  load_byte;
	wire [15:0] load_half;
	wire [31:0] load_lwl;
	wire [31:0] load_lwr;
	wire [3:0]  write_sb;//byte
	wire [3:0]  write_sh;//half
	wire [3:0]  write_sw;//word just 4'b1111
	wire [3:0]  write_swl;
	wire [3:0]  write_swr;

	wire [31:0] result_sb;
	wire [31:0] result_sh;
	wire [31:0] result_sw;
	wire [31:0] result_swl;
	wire [31:0] result_swr;

	wire op_sb  = opcode ==`sb;
	wire op_sh  = opcode ==`sh;
	wire op_sw  = opcode ==`sw;
	wire op_swl = opcode ==`swl;
	wire op_swr = opcode ==`swr;


	wire op_R_Type = opcode == 6'b000000;
	wire op_R_Type_cal = op_R_Type&func[5];
	wire op_R_Type_jump= op_R_Type&({func[5:3],func[1]}==4'b0010);
	wire op_REGIMM = opcode == 6'b000001;
	wire op_J_Type = opcode[5:1] == 5'b00001;
	wire op_I_Type_branch = opcode[5:2] == 4'b0001;
	wire op_I_Type_cal    = opcode[5:3] == 3'b001;
	wire op_j	   = opcode == 6'b000010;
	wire op_jal    = opcode == 6'b000011;
	wire op_jalr   = op_R_Type & (func == 6'b001001);
	wire op_cal    = op_R_Type&(func[5] == 1'b1)|op_I_Type_cal;
	wire op_shift  = op_R_Type&(func[5:3] == 3'b000);
	wire op_jump   = op_R_Type&({func[5:3],func[1]}==4'b0010)|op_J_Type;
	wire op_mov    = op_R_Type&({func[5:3],func[1]}==4'b0011);
	wire op_PC_jump = (op_R_Type&({func[5:3],func[1]}==4'b0010));//for PC_jump to (rs)
	
	wire op_EX     = op_R_Type&~(Instruction_reg == {32{1'b0}})|op_REGIMM|op_J_Type|op_I_Type_branch|op_I_Type_cal|(opcode[5]&(~opcode[3]))|(opcode[5]&opcode[3]);

	assign RegDst = op_R_Type ? 1 : 0;
	assign Branch = op_I_Type_branch|op_REGIMM;
	assign ALUsrc = op_I_Type_cal|Load|Store;
	assign RF_wen = (current_state == `state_WB)&(op_cal|op_shift|(op_mov&(Zero^func[0]))|Load|op_jal|op_jalr);
	assign RF_raddr1 = rs;
	assign RF_raddr2 = rt;
	assign RF_waddr  = op_jal?31:(RegDst?rd:rt);
	assign RF_wdata  = {32{op_jal|op_jalr}}& (PC_reg+8)|
					   {32{op_shift}}& shift_result|
					   {32{op_mov&(Zero^func[0])}}& RF_rdata1|
					   {32{opcode==`lui}}& lui_extend|
					   {32{opcode==`lb }}& {{24{load_byte[7]}},load_byte}|
					   {32{opcode==`lbu}}& {{24{1'b0}},load_byte}|
					   {32{opcode==`lh }}& {{16{load_half[15]}},load_half}|
					   {32{opcode==`lhu}}& {{16{1'b0}},load_half}|
					   {32{opcode==`lw }}& Read_data_reg|
					   {32{opcode==`lwl}}& load_lwl|
					   {32{opcode==`lwr}}& load_lwr|
					   {32{op_cal&~(opcode==`lui)}}& ALU_result
					   ;	
	//using mask for coding
	assign vaddr = ALU_result[1:0];
	assign l_mask = {vaddr[1]&vaddr[0],vaddr[1]&~vaddr[0],~vaddr[1]&vaddr[0],~vaddr[1]&~vaddr[0]};
	assign load_byte = { 8{l_mask[3]}}&Read_data_reg[31:24]|
					   { 8{l_mask[2]}}&Read_data_reg[23:16]|
					   { 8{l_mask[1]}}&Read_data_reg[15: 8]|
					   { 8{l_mask[0]}}&Read_data_reg[ 7: 0];

	assign load_half = {16{l_mask[0]}}&Read_data_reg[15: 0]|
					   {16{l_mask[2]}}&Read_data_reg[31:16];
	
	assign load_lwl  = {32{l_mask[3]}}&Read_data_reg[31: 0]|
					   {32{l_mask[2]}}&{Read_data_reg[23:0],RF_rdata2[ 7:0]}|
					   {32{l_mask[1]}}&{Read_data_reg[15:0],RF_rdata2[15:0]}|
					   {32{l_mask[0]}}&{Read_data_reg[ 7:0],RF_rdata2[23:0]};

	assign load_lwr  = {32{l_mask[3]}}&{RF_rdata2[31: 8],Read_data_reg[31:24]}|
					   {32{l_mask[2]}}&{RF_rdata2[31:16],Read_data_reg[31:16]}|
					   {32{l_mask[1]}}&{RF_rdata2[31:24],Read_data_reg[31: 8]}|
					   {32{l_mask[0]}}&Read_data_reg[31:0];

	assign ALU_control  = {3{op_R_Type_cal&(func[3:2]==2'b00)}}&{func[1],2'b10}|
						  {3{op_R_Type_cal&(func[3:2]==2'b01)}}&{func[1],1'b0,func[0]}|
						  {3{op_R_Type_cal&(func[3:2]==2'b10)}}&{~func[0],2'b11}|
						  {3{op_I_Type_cal&(opcode[2:1]==2'b00)}}&{opcode[1],2'b10}|
						  {3{op_I_Type_cal& opcode[2]}}&{opcode[1],1'b0,opcode[0]}|
						  {3{op_I_Type_cal&(opcode[2:1]==2'b01)}}&{~opcode[0],2'b11}|
						  {3{Load|Store}}&`ADD|
						  {3{op_mov|opcode==`beq|opcode==`bne}}&`SUB| //sub rs-rt in beq/bne sub rs-0 in movz/movn
						  {3{op_REGIMM|opcode==`blez|opcode==`bgtz}}&`SLT//in mov A=(rs) B=0, in blez A=0,B=(rs)
						  ;
	assign extend = (op_I_Type_cal&opcode[2])?zero_extend:sign_extend;//(op_I_Type_cal&~opcode[2]|MemRead|MemWrite)
	assign condition = ((opcode==`beq)&&Zero)|((opcode==`bne)&&~Zero)|((opcode==`blez)&&~ALU_result[0])|((opcode==`bgtz)&&ALU_result[0])|
					   (op_mov&~func[0]&Zero)|(op_mov&func[0]&~Zero)|(op_REGIMM&~rt[0]&ALU_result[0])|(op_REGIMM&rt[0]&~ALU_result[0]); 
	
	assign ALU_A = RF_rdata1&{32{~(op_mov|(opcode==`blez)|(opcode==`bgtz))}};
	assign ALU_B = {32{ALUsrc}}&extend|{32{((opcode==`blez)|(opcode==`bgtz))}}&RF_rdata1|{32{~(ALUsrc|((opcode==`blez)|(opcode==`bgtz))|op_REGIMM)}}&RF_rdata2;
	
	//model for shift R_Type 
	assign shift_control= func[1:0];
	assign shift_A = RF_rdata2;
	assign shift_B = (func[2])?RF_rdata1[4:0]:sa;

	assign PC_branch = PC_4+shift_sign_extend;

	reg_file ren_data(
		.clk(clk),
		.waddr(RF_waddr),
		.raddr1(RF_raddr1),
		.raddr2(RF_raddr2),
		.wen(RF_wen),
		.wdata(RF_wdata),
		.rdata1(RF_rdata1),
		.rdata2(RF_rdata2)
	);
	//model for shift operation
	shifter EX_shift(
		.A(shift_A),
		.B(shift_B),
		.Shiftop(shift_control),
		.Result(shift_result)
	);
	//model for calculation operation and for calculating the
	alu EX_alu(
		.A(ALU_A),
		.B(ALU_B),
		.ALUop(ALU_control),
		.Overflow(),
		.CarryOut(),
		.Zero(Zero),
		.Result(ALU_result)
	);

	assign Address = {ALU_result[31:2],2'b00};
	/*Aligned.The effective address must be naturally-aligned. 
	If either of the 2 least-significant bits of the address is non-zero, an Address Error exception occurs.*/
	assign write_sw = 4'b1111;
	assign write_sb = {{ALU_result[1:0]==2'b11},{ALU_result[1:0]==2'b10},{ALU_result[1:0]==2'b01},{ALU_result[1:0]==2'b00}};//3-4'b1000/2-4'b0100

	assign write_sh = {4{ALU_result[1]}}&4'b1100|{4{~ALU_result[1]}}&4'b0011;
	assign write_swl = {ALU_result[1]&ALU_result[0],ALU_result[1],ALU_result[1]|ALU_result[0],1'b1};//0,4'b0001 1,4'b0011 2,4'b0111 3,4'b1111
	assign write_swr = {1'b1,~ALU_result[1]|~ALU_result[0],~ALU_result[1],~ALU_result[1]&~ALU_result[0]};

	assign Write_strb = {4{op_sb}}&write_sb|{4{op_sh}}&write_sh|{4{op_sw}}&write_sw|{4{op_swl}}&write_swl|{4{op_swr}}&write_swr;

	assign result_sb  = {{8{write_sb [3]}}&RF_rdata2[ 7: 0],{8{write_sb [2]}}&RF_rdata2[ 7: 0],{8{write_sb [1]}}&RF_rdata2[ 7:0],{8{write_sb [0]}}&RF_rdata2[7:0]};
	assign result_sh  = {{16{write_sh[3]}}&RF_rdata2[15: 0],{16{write_sh[1]}}&RF_rdata2[15: 0]};
	assign result_swl =  {32{(write_swl==4'b0001)}} & {{24{1'b0}},RF_rdata2[31:24]} |
						 {32{(write_swl==4'b0011)}} & {{16{1'b0}},RF_rdata2[31:16]} |
						 {32{(write_swl==4'b0111)}} & {{ 8{1'b0}},RF_rdata2[31: 8]};
	assign result_swr =  {32{(write_swr==4'b1110)}} & {RF_rdata2[23:0],{ 8{1'b0}}} |
						 {32{(write_swr==4'b1100)}} & {RF_rdata2[15:0],{16{1'b0}}} |
						 {32{(write_swr==4'b1000)}} & {RF_rdata2[ 7:0],{24{1'b0}}};
	
	assign Write_data = {32{op_sb}}&result_sb|{32{op_sh}}&result_sh|{32{op_swl}}&result_swl|{32{op_swr}}&result_swr|{32{~(Store)|op_sw}}&RF_rdata2;
					
	assign PC_jump= {32{op_PC_jump}}&RF_rdata1|{32{~op_PC_jump}}&{PC_4[31:28],Instruction_reg[25:0],2'b00};

	always@(posedge clk)begin
		if(rst)begin
			PC<=32'b0;
		end
		else begin
			if(current_state == `state_IF )
				PC<=PC+4;
			else 
				if(current_state == `state_EX && (op_jump|(Branch&condition)))
					if(op_jump)
						PC<=PC_jump;
					else 
						PC<=PC_branch;
		end
	end

	always@(posedge clk)begin
		if(current_state == `state_IF)begin
			PC_reg<=PC;
		end
	end

    always@(posedge clk)begin
		if(current_state == `state_IF)begin
			Instruction_reg<= Instruction;		
		end
    end

	always@(posedge clk)begin
		if(MemRead == 1'b1)begin
			Read_data_reg<=Read_data;
		end
	end

	always @(posedge clk)begin
		if(rst == 1'b1)begin
			current_state<=`state_IF;
		end
		else begin
			current_state<=next_state;
		end
	end

	always @(*)begin
		case(current_state)
			`state_IF : begin
				next_state = `state_ID;
			end
			`state_ID : begin
				if(op_EX == 1'b1)
					next_state = `state_EX;
				else 
					next_state = `state_IF;
			end
			`state_EX : begin
				if(op_REGIMM|op_I_Type_branch|op_j)
					next_state = `state_IF;
				else 
					if(op_R_Type|op_jal|op_I_Type_cal)
						next_state = `state_WB;
					else if(Load|Store)
							next_state = `state_MEM;
						else
							next_state = `state_EX;
			end
			`state_MEM: begin
				if(Load)
					next_state = `state_WB;
				else 
					if(Store)
						next_state = `state_IF;
					else 
						next_state = `state_MEM; 
			end
			`state_WB : begin
				next_state = `state_IF;
			end 
		default:
			next_state = `state_IF;
		endcase
	end

endmodule 

你可能感兴趣的:(单片机,c语言,嵌入式硬件)