单周期CPU设计

终于有点时间了,恰好多周期的设计也已经完成,其实只想写写多周期的,无奈单周期补上才好,哈哈哈~

—————+—————黄金分割线—————+—————  

首先要理解什么叫单周期CPU(与后面多周期CPU对比)单周期CPU指的是一条指令的执行在一个时钟周期内完成,然后开始下一条指令的执行,即一条指令用一个时钟周期完成。  

单周期CPU的功能:能够实现一些指令功能操作。需设计的指令与格式如下:

==>算术运算指令

(1)add rd , rs, rt  (说明:以助记符表示,是汇编指令;以代码表示,是机器指令

   000000   

   rs(5位)   

   rt(5位)   

  rd(5位)   

  reserved  

功能:rd←rs + rt。reserved为预留部分,即未用,一般填“0”。

(2)addi rt , rs ,immediate 

   000001   

   rs(5位)   

   rt(5位)   

   immediate(16位)   

功能:rt←rs + (sign-extend)immediate;immediate符号扩展再参加“加”运算。

    (3)sub rd , rs , rt

   000010  

  rs(5位)    

    rt(5位)   

   rd(5位)   

   reserved  

完成功能:rd←rs - rt

    ==> 逻辑运算指令

(4)ori rt , rs ,immediate 

   010000  

   rs(5位)  

  rt(5位)  

   immediate(16位)        

功能:rt←rs | (zero-extend)immediate;immediate做“0”扩展再参加“或”运算。

(5)and rd , rs , rt

  010001  

  rs(5位)   

   rt(5位)  

   rd(5位)  

    reserved    

功能:rd←rs & rt;逻辑与运算。

    (6)or rd , rs , rt

   010010  

  rs(5位)  

  rt(5位)   

  rd(5位)   

   reserved    

功能:rd←rs | rt;逻辑或运算。

    ==> 传送指令

    (7)move  rd , rs  

   100000  

   rs(5位)  

  00000   

  rd(5位)   

   reserved   

功能:rd←rs + $0 ;$0=$zero=0。

==> 存储器读/写指令

(8)sw rt ,immediate(rs) 写存储器

  100110  

  rs(5位)  

   rt(5位)   

    immediate(16位)      

    功能:memory[rs+ (sign-extend)immediate]←rt;immediate符号扩展再相加。

(9) lw  rt , immediate(rs)读存储器

   100111  

  rs(5位)  

  rt(5位)  

    immediate(16位)       

功能:rt ← memory[rs + (sign-extend)immediate];immediate符号扩展再相加。

 ==> 分支指令

    (10)beq rs,rt,immediate     

  110000  

   rs(5位)  

  rt(5位)  

immediate(位移量,16位)

功能:if(rs=rt) pc←pc +4 + (sign-extend)immediate <<2;

特别说明:immediate是从PC+4地址开始和转移到的指令之间指令条数。immediate符号扩展之后左移2位再相加。为什么要左移2位?由于跳转到的指令地址肯定是4的倍数(每条指令占4个字节),最低两位是“00”,因此将immediate放进指令码中的时候,是右移了2位的,也就是以上说的“指令之间指令条数”。

==>停机指令

(11)halt

  111111  

 00000000000000000000000000(26位)  

功能:停机;不改变PC的值,PC保持不变。

 设计原理

 

CPU在处理指令时,一般需要经过以下几个步骤:

   (1) 取指令(IF):根据程序计数器PC中的指令地址,从存储器中取出一条指令,同时,PC根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令时,则控制器把“转移地址”送入PC,当然得到的“地址”需要做些变换才送入PC。

   (2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。

   (3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。

   (4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得到数据地址单元中的数据。

   (5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。

   单周期CPU,是在一个时钟周期内完成这五个阶段的处理。

MIPS32的指令的三种格式:

R类型:

31       26 25       21 20      16 15       11 10        6 5       0

       op             

          rs            

         rt            

          rd            

        sa            

       func    

  6位         5位       5位       5位        5位        6位

I类型:

31        26 25         21 20        16 15                       0

        op              

          rs              

           rt              

              immediate                 

6位         5位          5位                16位

J类型:

31        26 25                                                0

          op           

                         address                                                

6位                            26位

其中,

op:为操作码;

rs:为第1个源操作数寄存器,寄存器地址(编号)是00000~11111,00~1F;

rt:为第2个源操作数寄存器,或目的操作数寄存器,寄存器地址(同上);

rd:为目的操作数寄存器,寄存器地址(同上);

sa:为位移量(shift amt),移位指令用于指定移多少位;

func:为功能码,在寄存器类型指令中(R类型)用来指定指令的功能;

immediate:为16位立即数,用作无符号的逻辑操作数、有符号的算术操作数、数据加载(Laod)/数据保存(Store)指令的数据地址字节偏移量和分支指令中相对程序计数器(PC)的有符号偏移量;

address:为地址。

 

图2是一个简单的基本上能够在单周期上完成所要求设计的指令功能的数据通路和必要的控制线路图。其中指令和数据各存储在不同存储器中,即有指令存储器和数据存储器。访问存储器时,先给出地址,然后由读/写信号控制(1-写,0-读。当然,也可以由时钟信号控制,但必须在图上标出)。对于寄存器组,读操作时,先给出地址,输出端就直接输出相应数据;而在写操作时,在 WE使能信号为1时,在时钟边沿触发写入。图中控制信号作用如表1所示,表2是ALU运算功能表。

表1 控制信号的作用

控制信号名

状态“0”

状态“1”

PCWre

PC不更改,相关指令:halt

PC更改,相关指令:除指令halt外

ALUSrcB

来自寄存器堆data2输出,相关指令:add、sub、or、and、move、beq

来自sign或zero扩展的立即数,相关指令:addi、ori、sw、lw

ALUM2Reg

来自ALU运算结果的输出,相关指令:add、addi、sub、ori、or、and、move

来自数据存储器(Data MEM)的输出,相关指令:lw

RegWre

无写寄存器组寄存器,相关指令:

sw、halt

寄存器组写使能,相关指令:add、addi、sub、ori、or、and、move、lw

InsMemRW

读指令存储器(Ins. Data),初始化为0

写指令存储器

DataMemRW

读数据存储器,相关指令:lw

写数据存储器,相关指令:sw

ExtSel

相关指令:ori,(zero-extend)immediate(0扩展

相关指令:addi、sw、lw、beq,

(sign-extend)immediate(符号扩展

PCSrc

PC←PC+4,相关指令:add、sub、ori、or、and、move、sw、lw、beq(zero=0)

PC←PC+4+(sign-extend)immediate,同时zero=1,相关指令:beq

RegOut

写寄存器组寄存器的地址,来自rt字段,相关指令:addi、ori、lw

写寄存器组寄存器的地址,来自rd字段,相关指令:add、sub、and、or、move

ALUOp[2..0]

ALU 8种运算功能选择(000-111),看功能表

相关部件及引脚说明:

InstructionMemory指令存储器

        Iaddr,指令存储器地址输入端口

        IDataIn,指令存储器数据输入端口(指令代码输入端口)

        IDataOut,指令存储器数据输出端口(指令代码输出端口)

        RW,指令存储器读写控制信号,为1写,为0读

DataMemory数据存储器

        Daddr,数据存储器地址输入端口

        DataIn,数据存储器数据输入端口

        DataOut,数据存储器数据输出端口

        RW,数据存储器读写控制信号,为1写,为0读

RegisterFile:(寄存器组)

        Read Reg1,rs寄存器地址输入端口

        Read Reg2,rt寄存器地址输入端口

        Write Reg,将数据写入的寄存器端口,其地址来源rt或rd字段

        Write Data,写入寄存器的数据输入端口

        Read Data1,rs寄存器数据输出端口

        Read Data2,rt寄存器数据输出端口

        WE,写使能信号,为1时,在时钟上升沿写入

ALU

        result,ALU运算结果

        zero,运算结果标志,结果为0输出1,否则输出0

表2 ALU运算功能表       

ALUOp[2..0]

功能

描述

000

A + B

001

A – B

010

B – A

011

A ∨ B

100

A ∧ B

101

/A ∧ B

A非与B

110

A Å B

异或

111

A ⊙ B

同或

需要说明的是根据要实现的指令功能要求画出以上数据通路图,和确定ALU的运算功能(当然,以上指令没有完全用到提供的ALU所有功能,但至少必须能实现以上指令功能操作)。从数据通路图上可以看出控制单元部分需要产生各种控制信号,当然,也有些信号必须要传送给控制单元。从指令功能要求和数据通路图的关系得出以上表1,这样,从表1可以看出各控制信号与相应指令之间的相互关系,根据这种关系就可以得出控制信号与指令之间的关系表(如下),再根据关系表可以写出各控制信号的逻辑表达式,这样控制单元部分就可实现了。

表3 控制信号与指令的关系表

控制信号

指令

z

PCWre

ALUSrcB

ALUM2Reg

RegWre

InsMemRW

DataMemRW

ExtSel

PCSrc

RegOut

ALUOp[2..0]

add

x

1

0

0

1

0

x

x

0

1

000

addi

x

1

1

0

1

0

x

1

0

0

000

sub

x

1

0

0

1

0

x

x

0

1

001

ori

x

1

1

0

1

0

x

0

0

0

011

and

x

1

0

0

1

0

x

x

0

1

100

or

x

1

0

0

1

0

x

x

0

1

011

move

x

1

0

0

1

0

x

x

0

1

000

sw

x

1

1

x

0

0

1

1

0

x

000

lw

x

1

1

1

1

0

0

1

0

0

000

beq

0

1

0

x

0

0

x

1

0

x

001

1

1

0

x

0

0

x

1

1

x

001

halt

x

0

x

x

x

0

x

x

x

x

xxx


 

分析与设计

 

根据实验原理中的单周期CPU数据通路和控制线路图,我们可以清楚的知道单周期CPU的设计应包括controlUnit,RegisterFile, ALU, DataMemory, instructionMemory, PC, signZeroExtend这几个模块,其中为了运行整个CPU还需要加入一个顶层模块(singleCycleCPU)来调用这七个模块,所以自然地,这七个模块为顶层模块的子模块。设计流程逻辑图如下:

 

 1、控制单元(controlUnit.v)

根据数据通路图可以知道,控制单元的功能是接收一个6位的操作码(opCode)和一个标志符(zero)作为输入,输出PCWre、ALUSrcB等控制信号,各控制信号的作用见实验原理的控制信号作用表(表1),从而达到控制各指令的目的。其中模块内部实现则根据实验原理中控制信号与指令的关系表(表3)列出各信号的逻辑表达式从而实现各信号的输出。比如:

ALUOp的表达式为:ALUOp[2]=i_and

ALUOp[1]=i_ori | i_or

ALUOp[0]=i_sub | i_ori | i_or | i_beq

所以其实现为:assignALUOp[2] = (opCode == 6'b010001)? 1 : 0;

              assignALUOp[1] = (opCode == 6'b010000 || opCode == 6'b010010)? 1 : 0;

            assign ALUOp[0] = (opCode == 6'b000010 || opCode == 6'b010000|| opCode == 6'b010010 || opCode == 6'b110000)? 1 : 0;

整个模块设计如下:

[plain] view plain copy
 
  1. </pre><pre name="code" class="plain">`timescale 1ns / 1ps  
  2.   
  3. module controlUnit(opCode, zero, PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut, ALUOp);  
  4.     input [5:0] opCode;  
  5.      input zero;  
  6.      output PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut;  
  7.      output[2:0] ALUOp;  
  8.        
  9.      assign PCWre = (opCode == 6'b111111)? 0 : 1;  
  10.      assign ALUSrcB = (opCode == 6'b000001 || opCode == 6'b010000 || opCode == 6'b100110 || opCode == 6'b100111)? 1 : 0;  
  11.      assign ALUM2Reg = (opCode == 6'b100111)? 1 : 0;  
  12.      assign RegWre = (opCode == 6'b100110 || opCode == 6'b111111)? 0 : 1;  
  13.      assign InsMemRW = 0;  
  14.      assign DataMemRW = (opCode == 6'b100111)? 0 : 1;  
  15.      assign ExtSel = (opCode == 6'b010000)? 0 : 1;  
  16.      assign PCSrc = (opCode == 6'b110000 && zero == 1)? 1 : 0;  
  17.      assign RegOut = (opCode == 6'b000001 || opCode == 6'b010000 || opCode == 6'b100111)? 0 : 1;  
  18.      assign ALUOp[2] = (opCode == 6'b010001)? 1 : 0;  
  19.      assign ALUOp[1] = (opCode == 6'b010000 || opCode == 6'b010010)? 1 : 0;  
  20.      assign ALUOp[0] = (opCode == 6'b000010 || opCode == 6'b010000 || opCode == 6'b010010 || opCode == 6'b110000)? 1 : 0;   
  21.        
  22. endmodule  
 
2、算术运算单元(ALU.v)
模块ALU接收寄存器的数据和控制信号作为输入,将结果输出,具体设计如下:
[html] view plain copy
 
  1. `timescale 1ns / 1ps  
  2.   
  3. module ALU(ReadData1, ReadData2, inExt, ALUSrcB, ALUOp, zero, result);  
  4.     input [31:0] ReadData1, ReadData2, inExt;  
  5.      input ALUSrcB;  
  6.      input [2:0] ALUOp;  
  7.      output zero;  
  8.      output [31:0] result;  
  9.        
  10.      reg zero;  
  11.      reg [31:0] result;  
  12.      wire [31:0] B;  
  13.      assign B = ALUSrcB? inExt : ReadData2;  
  14.        
  15.      always @(ReadData1 or ReadData2 or inExt or ALUSrcB or ALUOp or B)  
  16.          begin  
  17.               case(ALUOp)  
  18.                     // A + B  
  19.                      3'b000: begin  
  20.                          result = ReadData1 + B;  
  21.                           zero = (result == 0)? 1 : 0;  
  22.                      end  
  23.                      // A - B  
  24.                      3'b001: begin  
  25.                          result = ReadData1 - B;  
  26.                           zero = (result == 0)? 1 : 0;  
  27.                      end  
  28.                      // B - A  
  29.                      3'b010: begin  
  30.                          result = B - ReadData1;  
  31.                           zero = (result == 0)? 1 : 0;  
  32.                      end  
  33.                      // A ∨ B  
  34.                      3'b011: begin  
  35.                          result = ReadData1 | B;  
  36.                           zero = (result == 0)? 1 : 0;  
  37.                      end  
  38.                      // A ∧ B  
  39.                      3'b100: begin  
  40.                          result = ReadData1 & B;  
  41.                           zero = (result == 0)? 1 : 0;  
  42.                      end  
  43.                      // /A ∧ B  
  44.                      3'b101: begin  
  45.                          result = (~ReadData1) & B;  
  46.                           zero = (result == 0)? 1 : 0;  
  47.                      end  
  48.                      // A ⊕ B  
  49.                      3'b110: begin  
  50.                          result = ReadData1 ^ B;  
  51.                           zero = (result == 0)? 1 : 0;  
  52.                      end  
  53.                      // A ⊙ B  
  54.                      3'b111: begin  
  55.                          result = ReadData1 ^~ B;  
  56.                           zero = (result == 0)? 1 : 0;  
  57.                      end  
  58.               endcase  
  59.           end  
  60. endmodule  

3、PC单元(PC.v)

PC单元以时钟信号clk、重置标志Reset、立即数以及PCWreck和PCSrc两个信号控制为输入,输出当前PC地址,具体设计如下:

[html] view plain copy
 
  1. `timescale 1ns / 1ps  
  2.   
  3. module PC(clk, Reset, PCWre, PCSrc, immediate, Address);  
  4.     input clk, Reset, PCWre, PCSrc;  
  5.      input [31:0] immediate;  
  6.      output [31:0] Address;  
  7.      reg [31:0] Address;  
  8.        
  9.      /*initial begin  
  10.          Address = 0;  
  11.      end*/  
  12.        
  13.      always @(posedge clk or negedge Reset)  
  14.          begin  
  15.               if (Reset == 0) begin  
  16.                     Address = 0;  
  17.                 end  
  18.                 else if (PCWre) begin  
  19.                     if (PCSrc) Address = Address + 4 + immediate*4;  
  20.                      else Address = Address + 4;  
  21.                 end  
  22.           end  
  23.   
  24. endmodule  


4、 扩展单元(signZeroExtend.v)

扩展单元的设计比较简单,其功能就是将一个16位的立即数扩展到32位,具体模块设计如下:

[html] view plain copy
 
  1. `timescale 1ns / 1ps  
  2.   
  3. module signZeroExtend(immediate, ExtSel, out);  
  4.     input [15:0] immediate;  
  5.      input ExtSel;  
  6.      output [31:0] out;  
  7.        
  8.      assign out[15:0] = immediate;  
  9.      assign out[31:16] = ExtSel? (immediate[15]? 16'hffff : 16'h0000) : 16'h0000;  
  10.   
  11. endmodule  


5、数据存储单元(DataMemory.v)

数据存储单元的功能是读取数据,根据数据通路图可以有如下模块设计:

[html] view plain copy
 
  1. `timescale 1ns / 1ps  
  2.   
  3. module dataMemory(DAddr, DataIn, DataMemRW, DataOut);  
  4.     input [31:0] DAddr, DataIn;  
  5.      input DataMemRW;  
  6.      output reg [31:0] DataOut;  
  7.      reg [31:0] memory[0:31];  
  8.        
  9.      // read data  
  10.      always @(DataMemRW) begin  
  11.      if (DataMemRW == 0) assign DataOut = memory[DAddr];  
  12.      end  
  13.        
  14.        
  15.      // write data  
  16.      integer i;  
  17.      initial begin  
  18.          for (i = 0; i 32; i = i+1) memory[i] <= 0;  
  19.      end  
  20.      always @(DataMemRW or DAddr or DataIn)  
  21.          begin  
  22.               if (DataMemRW) memory[DAddr] = DataIn;  
  23.           end  
  24.   
  25. endmodule  


6、指令存储单元(instructionMemory.v)

根据当前的PC地址得到对应的op,rs,rt,rd以及immediate.

内部实现:

将需要测试的汇编指令程序转化为指令代码,当然,每个人都可以有自己的测试指令,能正确转化为指令代码就好。为了书写的简便,我们可以将32位的二进制指令代码转化为16进制。具体测试表设计如下:

地址

汇编程序

指令代码

op(6)

rs(5)

rt(5)

rd(5)/immediate (16)

16进制数代码

0x00000004

addi  $1,$0,8

000001

00000

00001

0000 0000 0000 1000

=

04010008

0x00000008

ori  $2,$0,12

010000

00000

00010

0000 0000 0000 1100

=

4002000C

0x0000000C

add  $3,$1,$2

000000

00001

00010

00011 00000000000

=

00221800

0x00000010

sub  $4,$2,$1

000010

00010

00001

00100 00000000000

=

08412000

0x00000014

and  $5,$1,$2

010001

00001

00010

00101 00000000000

=

44222800

0x00000018

or  $6,$1,$2

010010

00001

00010

00110 00000000000

=

48223000

0x0000001C

beq  $1,$2,4 (转030)

110000

00001

00010

0000 0000 0000 0100

=

C0220004

0x00000020

move  $7,$1

100000

00001

00000

00111 00000000000

=

80203800

0x00000024

sw  $1,1($7)

100110

00111

00001

0000 0000 0000 0001

=

98E10001

0x00000028

lw  $2,0($1)

100111

00001

00010

0000 0000 0000 0000

=

9C220000

0x0000002C

beq $2,$7,-5 (转01C)

110000

00010

00111

1111 1111 1111 1011

=

C047FFFB

0x00000030

halt

111111

00000

00000

0000000000000000

=

FC000000

其次,为了存储这些指令代码,可以申请一个32位的二进制数组来存储它们,最后根据PC地址得到对应的op,rs,rt,immediate等,具体模块设计如下:

[html] view plain copy
 
  1. `timescale 1ns / 1ps  
  2.   
  3. module instructionMemory(  
  4.     input [31:0] pc,  
  5.     input InsMemRW,  
  6.      output [5:0] op,   
  7.      output [4:0] rs, rt, rd,  
  8.      output [15:0] immediate);  
  9.        
  10.      wire [31:0] mem[0:15];  
  11.        
  12.      assign mem[0] = 32'h00000000;  
  13.     // addi  $1,$0,8  
  14.      assign mem[1] = 32'h04010008;  
  15.      // ori  $2,$0,12  
  16.      assign mem[2] = 32'h4002000C;  
  17.      // add  $3,$1,$2  
  18.      assign mem[3] = 32'h00221800;  
  19.      // sub  $4,$2,$1  
  20.      assign mem[4] = 32'h08412000;  
  21.      // and  $5,$1,$2  
  22.      assign mem[5] = 32'h44222800;  
  23.      // or  $6,$1,$2  
  24.      assign mem[6] = 32'h48223000;  
  25.      // beq  $1,$2,4 (转030)  
  26.      assign mem[7] = 32'hC0220004;  
  27.      // move  $7,$1  
  28.      assign mem[8] = 32'h80203800;  
  29.      // sw  $1,1($7)  
  30.      assign mem[9] = 32'h98E10001;  
  31.      // lw  $2,0($1)  
  32.      assign mem[10] = 32'h9C220000;  
  33.      // beq $2,$7,-5 (转01C)  
  34.      assign mem[11] = 32'hC047FFFB;  
  35.      // halt  
  36.      assign mem[12] = 32'hFC000000;  
  37.        
  38.      assign mem[13] = 32'h00000000;  
  39.      assign mem[14] = 32'h00000000;  
  40.      assign mem[15] = 32'h00000000;  
  41.        
  42.      // output  
  43.      assign op = mem[pc[5:2]][31:26];  
  44.      assign rs = mem[pc[5:2]][25:21];  
  45.      assign rt = mem[pc[5:2]][20:16];  
  46.      assign rd = mem[pc[5:2]][15:11];  
  47.      assign immediate = mem[pc[5:2]][15:0];  
  48.   
  49. endmodule  


7、寄存器文件单元(registerFile.v)

寄存器文件单元的功能是接收instructionMemory中的rs,rt,rd作为输入,输出对应寄存器的数据,从而达到取寄存器里的数据的目的。需要注意的是,在其内部实现的过程中,为了防止0号寄存器写入数据需要在writeReg的时候多加入一个判断条件,即writeReg不等于0时写入数据。具体设计如下:

[html] view plain copy
 
  1. `timescale 1ns / 1ps  
  2.   
  3. module registerFile(clk, RegWre, RegOut, rs, rt, rd, ALUM2Reg, dataFromALU, dataFromRW, Data1, Data2);  
  4.     input clk, RegOut, RegWre, ALUM2Reg;  
  5.      input [4:0] rs, rt, rd;  
  6.      input [31:0] dataFromALU, dataFromRW;  
  7.      output [31:0] Data1, Data2;  
  8.        
  9.      wire [4:0] writeReg;  
  10.      wire [31:0] writeData;  
  11.      assign writeReg = RegOut? rd : rt;  
  12.      assign writeData = ALUM2Reg? dataFromRW : dataFromALU;  
  13.        
  14.      reg [31:0] register[0:31];  
  15.      integer i;  
  16.      initial begin  
  17.          for (i = 0; i 32; i = i+1) register[i] <= 0;  
  18.      end  
  19.        
  20.      // output  
  21.      assign Data1 = register[rs];  
  22.      assign Data2 = register[rt];  
  23.        
  24.      // Write Reg  
  25.      always @(posedge clk or RegOut or RegWre or ALUM2Reg or writeReg or writeData) begin  
  26.          if (RegWre && writeReg) register[writeReg] = writeData;  // 防止数据写入0号寄存器  
  27.      end  
  28.   
  29. endmodule  


8、顶层模块(singleStyleCPU)

顶层模块(singleStyleCPU)是整个CPU的控制模块,通过连接各个子模块来达到运行CPU的目的,整个模块设计可以如下:

[html] view plain copy
 
  1. `include "controlUnit.v"  
  2. `include "dataMemory.v"  
  3. `include "ALU.v"  
  4. `include "instructionMemory.v"  
  5. `include "registerFile.v"  
  6. `include "signZeroExtend.v"  
  7. `include "PC.v"  
  8. `timescale 1ns / 1ps  
  9.   
  10. module SingleCycleCPU(  
  11.     input clk, Reset,  
  12.      output wire [5:0] opCode,  
  13.      output wire [31:0] Out1, Out2, curPC, Result);  
  14.        
  15.      wire [2:0] ALUOp;  
  16.      wire [31:0] ExtOut, DMOut;  
  17.      wire [15:0] immediate;  
  18.      wire [4:0] rs, rt, rd;  
  19.      wire zero, PCWre, PCSrc, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, RegOut;  
  20.        
  21.      // module ALU(ReadData1, ReadData2, inExt, ALUSrcB, ALUOp, zero, result);  
  22.      ALU alu(Out1, Out2, ExtOut, ALUSrcB, ALUOp, zero, Result);  
  23.      // module PC(clk, Reset, PCWre, PCSrc, immediate, Address);  
  24.      PC pc(clk, Reset, PCWre, PCSrc, ExtOut, curPC);  
  25.      // module controlUnit(opCode, zero, PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut, ALUOp);  
  26.      controlUnit control(opCode, zero, PCWre, ALUSrcB, ALUM2Reg, RegWre, InsMemRW, DataMemRW, ExtSel, PCSrc, RegOut, ALUOp);  
  27.      // module dataMemory(DAddr, DataIn, DataMemRW, DataOut);  
  28.      dataMemory datamemory(Result, Out2, DataMemRW, DMOut);  
  29.      /* module instructionMemory(  
  30.     input [31:0] pc,  
  31.     input InsMemRW,  
  32.      input [5:0] op,   
  33.      input [4:0] rs, rt, rd,  
  34.      output [15:0] immediate);*/  
  35.      instructionMemory ins(curPC, InsMemRW, opCode, rs, rt, rd, immediate);  
  36.      // module registerFile(clk, RegWre, RegOut, rs, rt, rd, ALUM2Reg, dataFromALU, dataFromRW, Data1, Data2);  
  37.      registerFile registerfile(clk, RegWre, RegOut, rs, rt, rd, ALUM2Reg, Result, DMOut, Out1, Out2);  
  38.     // module signZeroExtend(immediate, ExtSel, out);  
  39.      signZeroExtend ext(immediate, ExtSel, ExtOut);  
  40.   
  41.   
  42. endmodule  


[html] view plain copy
 
  1.   
最后就是测试程序(testSCPU.v)

从顶层模块中可以看出整个CPU的输入只有时钟信号clk和重置信号Reset,所以测试程序代码比较简单。(说明:下面是在测试文件中额外加的,因为其他初始化数据ISE已经自动生成,点赞)

Reset = 1; //初始化PC地址,为0

        forever #100 clk = ~clk;



 一个简单的单周期就设计完成了,重点是要学会其中涉及到的模块化思想,这中模块化的分解思想应用极其广泛,所以,最好学会熟练使用。

表脸粘一下仿真结果好了:

单周期CPU卒,见多周期CPU,2333~

 原文:http://blog.csdn.net/zhaokx3/article/details/51493842

原文地址:https://www.cnblogs.com/Ph-one/p/7423252.html