單周期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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM