1. 程式人生 > >中山大學16級計算機組成與設計實驗——單週期CPU設計與實現

中山大學16級計算機組成與設計實驗——單週期CPU設計與實現

實驗二 : 單週期CPU設計與實現

一.相關原理詳解

關於單週期CPU的設計思路和相關原理分析可以參看個人的另一篇部落格,部落格連結如下:
單週期CPU設計與實現原理分析

二.實驗目的

  1. 掌握單週期CPU資料通路圖的構成、原理及其設計方法;
  2. 掌握單週期CPU的實現方法,程式碼實現方法;
  3. 認識和掌握指令與CPU的關係;
  4. 掌握測試單週期CPU的方法;
  5. 掌握單週期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)sll rd, rt,sa

011000 未用 rt(5位) rd(5位) sa reserved

功能:rd<-rt<<(zero-extend)sa, 左移sa位 ,(zero-extend)sa

==>比較指令

(8)slti rt, rs,immediate 帶符號

011011 rs(5位) rt(5位) immediate(16位)

功能:if (rs <(sign-extend)immediate) rt =1 else rt=0, 具體請看錶2 ALU運算功能表,帶符號

==> 儲存器讀/寫指令

(9)sw rt ,immediate(rs) 寫儲存器

100110 rs(5位) rt(5位) immediate(16位)

功能:memory[rs+ (sign-extend)immediate]←rt; immediate符號擴充套件再相加。即將rt暫存器的內容儲存到rs暫存器內容和立即數符號擴充套件後的數相加作為地址的記憶體單元中。

(10) lw rt , immediate(rs) 讀儲存器

100111rs(5位) rt(5位) immediate(16位)

功能:rt ← memory[rs + (sign-extend)immediate]; immediate符號擴充套件再相加。即讀取rs暫存器內容和立即數符號擴充套件後的數相加作為地址的記憶體單元中的數,然後儲存到rt暫存器中。

==> 分支指令

(11)beq rs,rt,immediate

110000 rs(5位) rt(5位) immediate(16位)

功能:if(rs=rt) pc←pc + 4 + (sign-extend)immediate <<2 else pc ←pc + 4
特別說明:immediate是從PC+4地址開始和轉移到的指令之間指令條數。immediate符號擴充套件之後左移2位再相加。為什麼要左移2位?由於跳轉到的指令地址肯定是4的倍數(每條指令佔4個位元組),最低兩位是“00”,因此將immediate放進指令碼中的時候,是右移了2位的,也就是以上說的“指令之間指令條數”。

(12)bne rs,rt,immediate

110001 rs(5位) rt(5位) immediate

功能:if(rs!=rt) pc←pc + 4 + (sign-extend)immediate <<2 else pc ←pc + 4
特別說明:與beq不同點是,不等時轉移,相等時順序執行。

==>跳轉指令

(13)j addr

111000 addr[27..2]

功能:pc <-{(pc+4)[31…28],addr[27…2],2{0}}, 無條件跳轉。
特別說明:由於MIPS32的指令程式碼長度佔4個位元組,所以指令地址二進位制數最低2位均為0,將指令地址放進指令程式碼中時,可省掉!這樣,除了最高6位操作碼外,還有26位可用於存放地址,事實上,可存放28位地址了,剩下最高4位由pc+4最高4位拼接上。

==> 停機指令

(14)halt

111111 00000000000000000000000000(26位)

功能:停機; 不改變PC的值,PC保持不變。

四.實驗原理

單週期CPU指的是一條指令的執行在一個時鐘週期內完成,然後開始下一條指令的執行,即一條指令用一個時鐘週期完成。電平從低到高變化的瞬間稱為時鐘上升沿,兩個相鄰時鐘上升沿之間的時間間隔稱為一個時鐘週期。時鐘週期一般也稱振盪週期(如果晶振的輸出沒有經過分頻就直接作為CPU的工作時鐘,則時鐘週期就等於振盪週期。若振盪週期經二分頻後形成時鐘脈衝訊號作為CPU的工作時鐘,這樣,時鐘週期就是振盪週期的兩倍。

CPU在處理指令時,一般需要經過以下幾個步驟:
(1) 取指令(IF):根據程式計數器PC中的指令地址,從儲存器中取出一條指令,同時,PC根據指令字長度自動遞增產生下一條指令所需要的指令地址,但遇到“地址轉移”指令時,則控制器把“轉移地址”送入PC,當然得到的“地址”需要做些變換才送入PC。
(2) 指令譯碼(ID):對取指令操作中得到的指令進行分析並譯碼,確定這條指令需要完成的操作,從而產生相應的操作控制訊號,用於驅動執行狀態中的各種操作。
(3) 指令執行(EXE):根據指令譯碼得到的操作控制訊號,具體地執行指令動作,然後轉移到結果寫回狀態。
(4) 儲存器訪問(MEM):所有需要訪問儲存器的操作都將在這個步驟中執行,該步驟給出儲存器的資料地址,把資料寫入到儲存器中資料地址所指定的儲存單元或者從儲存器中得到資料地址單元中的資料。
(5) 結果寫回(WB):指令執行的結果或者訪問儲存器中得到的資料寫回相應的目的暫存器中。
單週期CPU,是在一個時鐘週期內完成這五個階段的處理

單週期CPU指令處理過程

MIPS指令的三種格式

MIPS指令的三種格式
其中,
op:為操作碼;
rs:只讀。為第1個源運算元暫存器,暫存器地址(編號)是0000011111,001F;
rt:可讀可寫。為第2個源運算元暫存器,或目的運算元暫存器,暫存器地址(同上);
rd:只寫。為目的運算元暫存器,暫存器地址(同上);
sa:為位移量(shift amt),移位指令用於指定移多少位;
funct:為功能碼,在暫存器型別指令中(R型別)用來指定指令的功能與操作碼配合使用;
immediate:為16位立即數,用作無符號的邏輯運算元、有符號的算術運算元、資料載入(Load)/資料儲存(Store)指令的資料地址位元組偏移量和分支指令中相對程式計數器(PC)的有符號偏移量;
address:為地址。
 單週期CPU資料通路和控制線路圖
:

圖2 單週期CPU資料通路和控制線路圖

圖2是一個簡單的基本上能夠在單週期CPU上完成所要求設計的指令功能的資料通路和必要的控制線路圖。其中指令和資料各儲存在不同儲存器中,即有指令儲存器和資料儲存器。訪問儲存器時,先給出記憶體地址,然後由讀或寫訊號控制操作。對於暫存器組,先給出暫存器地址,讀操作時,輸出端就直接輸出相應資料;而在寫操作時,在 WE使能訊號為1時,在時鐘邊沿觸發將資料寫入暫存器。圖中控制訊號作用如表1所示,表2是ALU運算功能表。
表1 控制訊號的作用
控制訊號名 狀態“0” 狀態“1”
Reset 初始化PC為0 PC接收新地址
PCWre PC不更改,相關指令:halt PC更改,相關指令:除指令halt外
ALUSrcA 來自暫存器堆data1輸出,相關指令:add、sub、addi、or、and、ori、beq、bne、slti、sw、lw 來自移位數sa,同時,進行(zero-extend)sa,即 {{27{0}},sa},相關指令:sll
ALUSrcB 來自暫存器堆data2輸出,相關指令:add、sub、or、and、sll、beq、bne 來自sign或zero擴充套件的立即數,相關指令:addi、ori、slti、sw、lw
DBDataSrc 來自ALU運算結果的輸出,相關指令:add、addi、sub、ori、or、and、slti、sll 來自資料儲存器(Data MEM)的輸出,相關指令:lw
RegWre 無寫暫存器組暫存器,相關指令:beq、bne、sw、halt、j 暫存器組寫使能,相關指令:add、addi、sub、ori、or、and、slti、sll、lw
InsMemRW 寫指令儲存器 讀指令儲存器(Ins. Data)
mRD 輸出高阻態 讀資料儲存器,相關指令:lw
mWR 無操作 寫資料儲存器,相關指令:sw
RegDst 寫暫存器組暫存器的地址,來自rt欄位,相關指令:addi、ori、lw、slti 寫暫存器組暫存器的地址,來自rd欄位,相關指令:add、sub、and、or、sll
ExtSel (zero-extend)immediate(0擴充套件),相關指令:ori (sign-extend)immediate(符號擴充套件),相關指令:addi、slti、sw、lw、beq、bne
PCSrc[1..0] 00:pc←pc+4,相關指令:add、addi、sub、or、ori、and、slti、sll、sw、lw、beq(zero=0)、bne(zero=1);
01:pc←pc+4+(sign-extend)immediate,相關指令:beq(zero=1)、bne(zero=0);
10:pc←{(pc+4)[31:28],addr[27:2],2{0}},相關指令:j;
11:未用
ALUOp[2..0] ALU 8種運算功能選擇(000-111),看功能表

1.相關部件及引腳說明(根據個人設計有所修改):

Instruction Memory:指令儲存器(單個模組)

Iaddr:指令儲存器地址輸入埠
IDataOut:指令儲存器資料輸出埠(指令程式碼輸出埠)
RW:指令儲存器讀寫控制訊號,為0寫,為1讀

PC:程式計數器(兩個模組)

①PC地址計數模組:
CLK: CPU時鐘,當CLK上升沿到來時PC值可以發生變化,為輸入埠
Reset:重置訊號輸入埠,Reset為0時重置當前PC地址為0,為1時正常執行
PCWre:判定PC地址是否需要發生變化,0時不更改,1時更改,為輸入埠
newAddress:下一個指令地址,為輸入埠
PCAddr:PC當前的指令地址,為輸出埠

②指令跳轉控制模組:
PCSrc:用於判斷下一條指令地址的跳轉方式(具體功能見上表),為輸入埠
CurPC:PC模組輸出的當前地址,為輸入埠
Immediat:從I型指令中讀取的16-bit位寬立即數,為輸入埠
addr:從J型指令中讀取的26-bit位寬地址偏移量,為輸入埠
newAddress:通過PCSrc確定的跳轉方式得到的下一個指令地址,為輸出埠

Data Memory:資料儲存器(單個模組)

DAddr:資料儲存器地址輸入埠
CLK:CPU時鐘,當CLK的下降沿到來時才會將資料寫入資料儲存器中,為輸入埠
mRD:資料儲存器讀控制訊號,為0讀
mWR:資料儲存器寫控制訊號,為0寫
DataIn:資料儲存器資料輸入埠
DataOut:資料儲存器資料輸出埠

Register File:暫存器組(三個模組)

①rt,rd暫存器地址選擇輸入模組:
Select:選擇訊號輸入埠,R、I型別指令時用以選擇傳入rt或rd暫存器地址
DataIn1:rt暫存器地址,為輸入埠
DataIn2:rd暫存器地址,為輸入埠
DataOut:選擇要寫入資料的暫存器地址,為輸出埠

②暫存器值輸入模組:
Select:選擇訊號輸入埠,呼叫lw指令時選擇從資料儲存器讀取對應資料
DataIn1:ALU模組輸出值,為輸入埠
DataIn2:資料儲存器記憶體儲的對應位置的值,為輸入埠
DataOut:選擇要寫入暫存器的值,為輸出埠

③暫存器管理模組:
WE:寫使能訊號,為1時,在時鐘邊沿觸發寫入,為輸入埠
CLK:CPU時鐘,當CLK的下降沿到來時才會將資料寫入暫存器組中,為輸入埠
ReadReg1:rs暫存器地址輸入埠
ReadReg2:rt暫存器地址輸入埠
WriteReg:將資料寫入的暫存器埠,其地址來源rt或rd欄位,為輸入埠 WriteData:暫存器的資料輸入埠,資料來源ALU模組輸出或者資料儲存器取值
ReadData1:rs暫存器資料輸出埠
ReadData2:rt暫存器資料輸出埠

ALU:算術邏輯單元(三個模組)

①A操作值輸入選擇模組:
Select:選擇訊號輸入埠,來自ControlUnit模組,用以確定A操作值
DataIn1:來自暫存器組輸出的32-bit位寬的rs暫存器值,為輸入埠
sa:來自指令儲存器輸出的sa值,用作ALU功能中左移的左移量,為輸入埠
DataOut:選擇輸入ALU模組的A運算元的值,為輸出埠

②B操作值輸入選擇模組:
Select:選擇訊號輸入埠,來自ControlUnit模組,用以確定B操作值
DataIn1:來自暫存器組輸出的32-bit位寬的rt暫存器值,為輸入埠
DataIn2:來自位寬擴充套件單元輸出的一個32-bit位寬的立即數擴充套件值,為輸入埠
DataOut:選擇輸入ALU模組的B運算元的值,為輸出埠

③ALU邏輯操作模組:
A:A運算元,來源A操作值輸入選擇模組輸出,為輸入埠
B:B運算元,來源B操作值輸入選擇模組輸出,為輸入埠
ALUOp:ALU算術邏輯單元的操作選擇訊號輸入端,來自控制單元ControlUnit
result:ALU模組運算結果,為輸出埠
zero:運算結果標誌,結果為0,則zero=1;否則zero=0,為輸出埠

Sign_Zero_Extend:資料擴充套件單元(單個模組)

Imm_Number:用作擴充套件操作的16-bit位寬立即數,為輸入埠
ExtSel:擴充套件選擇訊號輸入端,用作判斷擴充套件方式為帶符號擴充套件或者無符號擴充套件
Result:32-bit位寬的擴充套件結果,為輸出埠

ControlUnit:算術邏輯單元(單個模組)

opCode:指令前六位的6-bit位寬的運算元,來自指令儲存器,為輸入埠
zero:ALU算術邏輯單元計算結果的零標誌位,來自ALU,為輸入埠
ExtSel,PCWre,InsMemRW,RegDst,RegWre,ALUOp,PCSrc,ALUSrcA,ALUSrcB,RD,WR,DBDataSrc:根據執行指令得到的CPU各模組的控制訊號,具體功能見上表,為輸出埠

表2 ALU運算功能表
ALUOp[2…0] 功能 描述
000 Y = A + B
001 Y = A – B
010 Y = B << A B左移A位
011 Y = A ∨ B
100 Y = A ∧ B
101 Y=(A < B)?1: 0 比較A與B
不帶符號
110 Y=(((rega < regb) && (rega[31] == regb[31] )) || ( ( rega[31] ==1 && regb[31] == 0))) ? 1:0 比較A與B
帶符號
111 Y = A⊕B 異或
表3 指令訊號表

指令訊號表
從指令功能要求和資料通路圖的關係得出以上表3,這樣,從表3可以看出各控制訊號與相應指令之間的相互關係,根據關係表可以寫出各控制訊號的邏輯表示式,這樣控制單元部分就可實現了。

2.FPGA板的埠與功能設計:

在此次試驗中Basys3板用作單週期CPU結果、PC值、rs,rt暫存器地址和資料的輸出。輸出內容是通過7端數碼管實現。數碼管通過使能端的高低電平控制亮和滅(Basys3為共陽,所以低電平有效)。通過控制4個7端數碼管相對應使能端按順序快速地高低變化,實現肉眼可見的同時輸出結果。

其中,Basys板設定四個開關,SW15,SW14,T17與V17,其中SW15與SW14作為顯示內容的選擇,T17用作CPU按鍵輸入,V17用作Reset重置訊號輸入。指令執行採用單步(按鍵控制)執行方式,由T17按鍵提供單個的CPU時鐘週期,開關(SW15、SW14)控制選擇檢視數碼管上的相關資訊,地址和資料。

地址或資料的輸出經以下模組程式碼轉換後接到數碼管上。其中:
SW_in = 00:顯示 當前 PC值:下條指令PC值
SW_in = 01:顯示 RS暫存器地址:RS暫存器資料
SW_in = 10:顯示 RT暫存器地址:RT暫存器資料
SW_in = 11:顯示 ALU結果輸出 :DB匯流排資料。

五.實驗器材

電腦一臺,Xilinx Vivado 軟體一套,Basys3板一塊。

六.模擬程式碼實現

1.單週期CPU模組程式碼

PC.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 01:43:15
// Design Name: 
// Module Name: PC
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module PC(
    input CLK, 
    input Reset, 
    input PCWre, 
    input [31:0] newAddress,
    output reg [31:0] PCAddr
    );
    
    initial begin  
        PCAddr = 0;  
    end
    
    always @(posedge CLK or negedge Reset) begin  
        if (Reset == 0) begin  
            PCAddr = 0;  
        end  
        else if (PCWre) begin 
            PCAddr = newAddress;
        end  
    end     
    
endmodule

InstructionMemory.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 01:28:02
// Design Name: 
// Module Name: InstructionMemory
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module InstructionMemory(
    input [31:0] IAddr,
    input RW,
    output reg [31:0] IDataOut
    );
    
    reg [7:0] InstMemory [255:0];
    
    initial begin
        $readmemb("F:/test.txt", InstMemory);
    end

    [email protected](IAddr or RW) begin
        if (RW == 1) begin
            IDataOut = { InstMemory[IAddr], InstMemory[IAddr + 1], InstMemory[IAddr + 2], InstMemory[IAddr + 3] };
        end
        $display("InstMem PC", IAddr, " INST: ", IDataOut);
    end  
      
endmodule

RegisterFile.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 01:35:43
// Design Name: 
// Module Name: RegisterFile
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module RegisterFile(
    input WE,
    input CLK,
    input [4:0] ReadReg1, ReadReg2,
    input [4:0] WriteReg,
    input [31:0] WriteData,
    output [31:0] ReadData1, ReadData2
    );
    
    reg [31:0] registers[1:31];
    
    assign ReadData1 = ( ReadReg1 == 0 ) ? 0 : registers[ReadReg1];
    assign ReadData2 = ( ReadReg2 == 0 ) ? 0 : registers[ReadReg2];

    [email protected]( negedge CLK ) begin // д²Ù×÷
        if (( WriteReg != 0 ) && ( WE == 1 )) begin
            $display("WriteData: ", WriteData, " WriteReg: ", WriteReg);
            registers[WriteReg] <= WriteData;
        end
    end
    
endmodule

Sign_Zero_Extend.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 01:34:37
// Design Name: 
// Module Name: Sign_Zero_Extend
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Sign_Zero_Extend(
    input [15 :0] Imm_Number,
    input ExtSel,
    output reg [31:0] Result
    );
    
    [email protected]( Imm_Number or ExtSel) begin
        if (ExtSel == 0 || Imm_Number[15] == 0)
            Result = { 16'b0000000000000000, Imm_Number };
        else
            Result = { 16'b1111111111111111, Imm_Number };
    end
    
endmodule

ALU.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 01:51:09
// Design Name: 
// Module Name: ALU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module ALU(
    input [31:0] A,
    input [31:0] B,
    input [2:0] ALUOp,
    output reg [31:0] result,
    output zero
    );
    
    assign zero = ( result == 0 ) ? 1 : 0;
    
   [email protected]( ALUOp or A or B ) begin
       case (ALUOp)
          3'b000 : result = A + B; // Y = A + B
          3'b001 : result = A - B; // Y = A - B
          3'b010 : result = B << A; // Y = B << A
          3'b011 : result = A | B; // Y = A | B
          3'b100 : result = A & B; // Y = A & B
          3'b101 : result = (A < B) ? 1 : 0; // Y=£¨A < B£©? 1 : 0
          3'b110 : result = (((A < B) && (A[31] == B[31])) || ((A[31] ==1 && B[31] == 0))) ? 1:0; // Y=(((A<B) && (A[31] == B[31] )) ||( ( A[31] ==1 && B[31] == 0))) ? 1:0
          3'b111 : result = A ^ B; // Y = A ^ B
      endcase
    end
endmodule

DataMemory.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 01:40:45
// Design Name: 
// Module Name: DataMemory
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module DataMemory(
    input [31:0] DAddr,
    input CLK,
    input mRD,
    input mWR,
    input [31:0] DataIn,
    output reg [31:0] DataOut
    );
    
    reg [7:0] dataMemory [255:0];
    
    [email protected]( mRD or DAddr ) begin 
        if (mRD == 1) begin
            DataOut[7:0] = dataMemory[DAddr + 3];
            DataOut[15:8] = dataMemory[DAddr + 2];
            DataOut[23:16] = dataMemory[DAddr + 1];
            DataOut[31:24] = dataMemory[DAddr];
        end
    end

    [email protected]( negedge CLK ) begin //總是在時鐘下降沿到來時觸發
        if (mWR == 1) begin
            dataMemory[DAddr + 3] <= DataIn[7:0];
            dataMemory[DAddr + 2] <= DataIn[15:8];
            dataMemory[DAddr + 1] <= DataIn[23:16];
            dataMemory[DAddr] <= DataIn[31:24];
        end
    end
    
endmodule

ControlUnit.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 02:13:34
// Design Name: 
// Module Name: ControlUnit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module ControlUnit(
    output ExtSel,
    output PCWre,
    output InsMemRW,
    output RegDst,
    output RegWre,
    output [2:0] ALUOp,
    output [1:0] PCSrc,
    output ALUSrcA,
    output ALUSrcB,
    output RD,
    output WR,
    output DBDataSrc,
    input [5:0] opCode,
    input zero
    );
    
    assign ExtSel = (opCode == 6'b010000 || opCode == 6'b011000) ? 0 : 1;
    assign PCWre = (opCode == 6'b111111) ? 0 : 1;
    assign InsMemRW = 0;
    assign RegDst = (opCode == 6'b000001 || opCode == 6'b010000 || opCode == 6'b100111 || opCode == 6'b011011) ? 0 : 1;
    assign RegWre = (opCode == 6'b100110 || opCode == 6'b110000 || opCode == 6'b110001 || opCode == 6'b111000) ? 0 : 1;
    assign PCSrc[0] = ((opCode == 6'b110000 && zero == 1) || (opCode == 6'b110001 && zero == 0)) ? 1 : 0;
    assign PCSrc[1] = (opCode == 6'b111000) ? 1 : 0;
    assign ALUSrcA = (opCode == 6'b011000) ? 1 : 0;
    assign ALUSrcB = (opCode == 6'b000001 || opCode == 6'b010000 || opCode == 6'b011011 || opCode == 6'b100110 || opCode == 6'b100111) ? 1 : 0;
    assign RD = (opCode == 6'b100111) ? 1 : 0;
    assign WR = (opCode == 6'b100110) ? 1 : 0;
    assign DBDataSrc = (opCode == 6'b100111) ? 1 : 0;
    assign ALUOp[0] = (opCode == 6'b000010 || opCode == 6'b010000 || opCode == 6'b010010 || opCode == 6'b110000 || opCode == 6'b110001) ? 1: 0;
    assign ALUOp[1] = (opCode == 6'b010000 || opCode == 6'b010010 || opCode == 6'b011000 || opCode == 6'b011011) ? 1 : 0;
    assign ALUOp[2] = (opCode == 6'b010001 || opCode == 6'b011011) ? 1 : 0;
    
endmodule

Mux_ThreeToOne.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/26 10:18:34
// Design Name: 
// Module Name: Mux_ThreeToOne
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Mux_ThreeToOne(
    input [1:0] PCSrc,
    input [31:0] CurPC,
    input [31:0] immediate,
    input [27:2] addr,
    output reg [31:0] newAddress
    );
    
    wire [31:0] PCAddr4 = CurPC + 4;
    
    [email protected]( PCSrc or CurPC or addr or immediate ) begin
    if ( PCSrc == 2'b00 )
        newAddress = PCAddr4;
    else if ( PCSrc == 2'b01 )
        newAddress = PCAddr4 + immediate * 4;
    else if ( PCSrc == 2'b10 )
        newAddress = {PCAddr4[31:28], addr[27:2],2'b00};
    end
endmodule

Mux_TwoToOne.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 02:11:51
// Design Name: 
// Module Name: Mux_TwoToOne
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Mux_TwoToOne(
    input Select,
    input [31:0] DataIn1,
    input [31:0] DataIn2,
    output reg [31:0] DataOut
    );
    
    [email protected]( Select or DataIn1 or DataIn2 ) begin
        if ( Select == 0 )
            DataOut = DataIn1;
        else
            DataOut = DataIn2;
    end
        
endmodule

Mux_TwoToOne_A.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 02:08:52
// Design Name: 
// Module Name: Mux_TwoToOne_A
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Mux_TwoToOne_A(
    input Select,
    input [31:0] DataIn1,
    input [4:0] sa,
    output reg [31:0] DataOut
    );
    
     [email protected]( Select or DataIn1 or sa ) begin
        if ( Select == 0 )
            DataOut = DataIn1;
        else
            DataOut = { 27'b000000000000000000000000000, sa }; // 對sa進行擴充套件
    end   
endmodule

Mux_TwoToOne_Reg.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 02:10:46
// Design Name: 
// Module Name: Mux_TwoToOne_Reg
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Mux_TwoToOne_Reg(
    input Select,
    input [4:0] DataIn1,
    input [4:0] DataIn2,
    output reg [4:0] DataOut
    );
    
    [email protected]( Select or DataIn1 or DataIn2 ) begin
        if ( Select == 0 )
            DataOut = DataIn1;
        else
            DataOut = DataIn2;
    end
       
endmodule

SCPU.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 02:44:32
// Design Name: 
// Module Name: SCPU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module SCPU(
    input CLK, // 時鐘訊號
    input Reset, // 置零訊號
    output [31:0] CurPC, // 當前指令地址
    output [31:0] newaddress, // 下一個指令地址
    output [31:0] instcode, // rs,rt暫存器所在指令
    output [31:0] Reg1Out, // 暫存器組rs暫存器的值 
    output [31:0] Reg2Out, // 暫存器組rt暫存器的值
    output [31:0] ALU_Out, // ALU的result輸出值
    output [31:0] WriteData // DB匯流排值
    );
        
        wire ExtSel; // 位擴充套件訊號,1為符號擴充套件,0為0擴充套件
        wire PCWre; // PC工作訊號,0不更改,1更改
        wire InsMemRW; // 指令暫存器訊號,0為寫,1為讀
        wire RegDst; // 指令讀取時判斷是rt還是rd進入暫存器組的寫資料端,0為rt,1為rd
        wire RegWre; // 暫存器組是否需要寫功能,0為無寫功能,1為些功能
        wire [2:0] ALUOp; // ALU8種運算功能選擇
        wire [1:0] PCSrc; // PC正常+4還是要跳轉,0為正常+4,1為跳轉
        wire ALUSrcA; // 暫存器組Data1的輸出,0為暫存器本身輸出,1為指令碼的最後16位立即數
        wire ALUSrcB; // 暫存器組Data2的輸出,0位本身的輸出,1為擴充套件後的立即數
        wire RD; // 讀資料儲存器功能,0時讀取
        wire WR; // 寫資料儲存器功能,1時寫
        wire DBDataSrc; // 決定將什麼資料傳入暫存器組Write Data端,0為ALU結果,1為儲存器
        wire [4:0] WriteRegAddr; // 暫存器組Write Reg輸入端
        wire [31:0] ALU_Input_A; // ALU的A輸入端
        wire [31:0] ALU_Input_B; // ALU的B輸入端
        wire zero; // ALU的zero輸出
        wire [31:0] MemOut; // 儲存器的輸出
        wire [31:0] Ext_Imm; // 位擴充套件後的立即數
        
        // Mux_ThreeToOne( PCSrc, CurPC, immediate, addr, newAddress)
        Mux_ThreeToOne my_Mux_ThreeToOne( PCSrc, CurPC, Ext_Imm, instcode[25:0], newaddress );
       
        // PC( CLK, Reset, PCWre, newAddress, PCAddr )
        PC my_PC( CLK, Reset, PCWre, newaddress, CurPC );
    
        // ALU( Reg1, Reg2, ALUOp, result, zero )
        ALU my_ALU( ALU_Input_A, ALU_Input_B, ALUOp, ALU_Out, zero );
    
        // DataMemory( DAddr, CLK, RD, WR, DataIn, DataOut)
        DataMemory my_DataMemory( ALU_Out, CLK, RD, WR, Reg2Out, MemOut );
    
        // Sign_Zero_Extend( Imm_Number, ExtSel, Result )
        Sign_Zero_Extend my_Sign_Zero_Extend( instcode[15:0], ExtSel, Ext_Imm );
    
        // Mux_TwoToOneReg( Select, DataIn1, DataIn2, DataOut )
        Mux_TwoToOne_Reg my_Mux_TwoToOneReg( RegDst, instcode[20:16], instcode[15:11], WriteRegAddr );
    
        // Mux_TwoToOne( Select, DataIn1, DataIn2, DataOut )
        Mux_TwoToOne_A my_Mux_TwoToOne_For_ALU_InputA( ALUSrcA, Reg1Out, instcode[10:6], ALU_Input_A );
    
        Mux_TwoToOne my_Mux_TwoToOne_For_ALU_InputB( ALUSrcB, Reg2Out, Ext_Imm, ALU_Input_B );
    
        Mux_TwoToOne my_Mux_TwoToOne_For_RegisterFile_WriteData( DBDataSrc, ALU_Out, MemOut, WriteData );
    
        // RegisterFile( RegWre, CLK, Reg1, Reg2, WriteReg, WriteData, DataOut1, DataOut2 )
        RegisterFile my_RegisterFile( RegWre, CLK, instcode[25:21], instcode[20:16], WriteRegAddr, WriteData, Reg1Out, Reg2Out );
    
        // ControlUnit( ExtSel, PCWre, InsMemRW, RegDst, RegWre, ALUOp, PCSrc, ALUSrcB, RD, WR, DBDataSrc, opCode, zero )
        ControlUnit my_ControlUnit( ExtSel, PCWre, InsMemRW, RegDst, RegWre, ALUOp, PCSrc, ALUSrcA, ALUSrcB, RD, WR, DBDataSrc, instcode[31:26], zero );
    
        // InstructionMemory( CurPC, instMemRW, instcode )
        InstructionMemory my_InstructionMemory( CurPC, InsMemRW, instcode );
endmodule

2.模擬檔案

至此,單週期CPU的所有模組完成,其中SCPU.v是頂層檔案,我們最後寫一個模擬程式碼對單週期CPU進行模擬測試,經檢查已知結果正確,模擬程式碼如下:

SCPU_sim.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/25 02:53:19
// Design Name: 
// Module Name: SCPU_sim
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module SCPU_sim;

    reg CLK; // 時鐘訊號
    reg Reset; // 置零訊號

    SCPU my_SCPU( .CLK(CLK), 
                  .Reset(Reset)
                  );

                  always #30 CLK = !CLK; // 60ns為一週期
                  initial begin
                    CLK = 0;
                    Reset = 0;
                    #90;
                    Reset = 1;
                  end
endmodule

3.測試指令

這裡寫圖片描述

七.Basys3實驗板程式碼實現

本部分是實現在Basys3實驗板上執行的相關程式碼,因為時鐘設定原因(具體原因已在另一篇部落格中進行講解說明),在按鍵控制操作上存在著半個週期的延遲,這一點不影響實驗板實現結果的正確性,但是主觀上會覺得有些彆扭,所以建議大家以參考為主,只要抓住該部分程式碼設計的核心是確定合適的數碼管掃描頻率這一點,相信實現過程並不困難。

SegLED.v(數碼管顯示譯碼模組)

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/27 11:21:21
// Design Name: 
// Module Name: SegLED
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module SegLED(
    input [3:0] Store,
	input Reset,
	output reg [7:0] Out
    );
    
    always @( Store or Reset) begin
        if(Reset == 0) begin
            Out = 8'b11111110;
        end 
        else begin
            case (Store)
                4'b0000 : Out = 8'b10000001; //0£»'0'-ÁÁµÆ£¬'1'-ϨµÆ
                4'b0001 : Out = 8'b11001111; //1
                4'b0010 : Out = 8'b10010010; //2
                4'b0011 : Out = 8'b10000110; //3
                4'b0100 : Out = 8'b11001100; //4
                4'b0101 : Out = 8'b10100100; //5
                4'b0110 : Out = 8'b10100000; //6
                4'b0111 : Out = 8'b10001111; //7
                4'b1000 : Out = 8'b10000000; //8
                4'b1001 : Out = 8'b10000100; //9
                4'b1010 : Out = 8'b10001000; //A
                4'b1011 : Out = 8'b11100000; //b
                4'b1100 : Out = 8'b10110001; //C
                4'b1101 : Out = 8'b11000010; //d
                4'b1110 : Out = 8'b10110000; //E
                4'b1111 : Out = 8'b10111000; //F
                default : Out = 8'b0000_0000; //no light
            endcase
        end
    end
    
endmodule

key_fangdou.v(按鍵消抖模組)

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/27 23:27:49
// Design Name: 
// Module Name: key_fangdou
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module key_fangdou(clk,key_in,key_out);
    parameter SAMPLE_TIME = 5000;
    input clk;
    input key_in;
    output key_out;

    reg [21:0] count_low;
    reg [21:0] count_high;

    reg key_out_reg;

    always @(posedge clk)
    if(key_in ==1'b0)
        count_low <= count_low + 1;
    else
        count_low <= 0;

    always @(posedge clk)
        if(key_in ==1'b1)
            count_high <= count_high + 1;
        else
            count_high <= 0;

    always @(posedge clk)
        if(count_high == SAMPLE_TIME)
            key_out_reg <= 1;
        else if(count_low == SAMPLE_TIME)
            key_out_reg <= 0;

    assign key_out = !key_out_reg;
    
endmodule 

Basys3_Out.v(Basys3頂層模組)

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2018/05/26 13:21:45
// Design Name: 
// Module Name: Basys3_Out
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Basys3_Out(
    input CLK,
    input [1:0] SW, // 選擇輸出訊號
    input Reset, // 重置按鈕
    input Button, // 單脈衝
    output reg[3:0] AN, // 數碼管位選擇訊號
    output [7:0] Out // 數碼管輸入訊號
    );
    
    reg [16:0] showCounter;
    parameter T1MS = 100000;
    wire [31:0] ALU_Out; // ALU的result輸出值
    wire [31:0] CurPC;
    wire [31:0] WriteData; // DB匯流排值
    wire [31:0] Reg1Out; // 暫存器組rs暫存器的值
    wire [31:0] Reg2Out; // 暫存器組rt暫存器的值
    wire [31:0] instcode;
    wire myCLK;
    reg [3:0] store; // 記錄當前要顯示位的值
    wire [31:0] newAddress;
    
    SCPU my_SCPU(myCLK, Reset, CurPC, newAddress, instcode, Reg1Out, Reg2Out, ALU_Out, WriteData);
    
    key_fangdou my_key_fangdou(CLK, Button, myCLK);
    
    initial begin
        showCounter <= 0;
        AN <= 4'b0111;
    end
        
        [email protected] (posedge CLK)
            begin
            if(Reset == 0) begin
              showCounter <= 0;
              AN <= 4'b0000;
            end else begin
                showCounter <= showCounter + 1;
                if(showCounter == T1MS)
                    begin
                        showCounter <= 0;
                        case(AN)
                            4'b1110 : begin
                                AN <= 4'b1101;
                            end
                            4'b1101 : begin
                                AN <= 4'b1011;
                            end
                            4'b1011 : begin
                                AN <= 4'b0111;
                            end
                            4'b0111 : begin
                                AN <= 4'b1110;
                            end
                           4'b0000 : begin
                                AN <= 4'b0111;
                           end
                        endcase
                    end
                end
            end
    
        SegLED led(store, Reset, Out);
        
        [email protected] (myCLK) begin
           case(AN)
                4'b1110 : begin
                    case(SW)
                        2'b00: store <= newAddress[3:0];
                        2'b01: store <= Reg1Out[3:0];
                        2'b10: store <= Reg2Out[3:0];
                        2'b11: store <= WriteData[3:0];
                    endcase
                end
                4'b1101 : begin
                    case(SW)
                        2'b00: store <= newAddress[7:4];
                        2'b01: store <= Reg1Out[7:4];
                        2'b10: store <= Reg2Out[7:4];
                        2'b11: store <= WriteData[7:4];
                    endcase
                end
                4'b1011 : begin
                    case(SW)
                        2'b00: store <= CurPC[3:0];
                        2'b01: store <= instcode[24:21];
                        2'b10: store <= instcode[19:16];
                        2'b11: store <= ALU_Out[3:0];
                    endcase
                end
                4'b0111 : begin
                    case(SW)
                        2'b00: store <= CurPC[7:4];
                        2'b01: store <= { 3'b000,instcode[25]};
                        2'b10: store <= { 3'b000,instcode[20]};
                        2'b11: store <= ALU_Out[7:4];
                    endcase
                end
            endcase
        end
            
endmodule

相關推薦

中山大學16計算機組成設計實驗——週期CPU設計實現

實驗二 : 單週期CPU設計與實現 一.相關原理詳解 關於單週期CPU的設計思路和相關原理分析可以參看個人的另一篇部落格,部落格連結如下: 單週期CPU設計與實現原理分析 二.實驗目的 掌握單週期CPU資料通路圖的構成、原理及其設計方法; 掌握單週期CP

週期cpu設計程式碼解讀

目錄 寫在前面 單週期cpu設計程式碼講解 概念回顧 Verilog程式碼講解 寫在前面 歡迎轉載,轉載請說明出處。 單週期cpu設計程式碼講解 概念回顧 一、

華中科技大學 計算機組成原理 上機實驗1 2018

image 可能 ive debug 區號 分析 pan open 實驗目的 實驗目的 GB2312 區位碼 字模碼 奇偶校驗校 驗位 檢錯 海明碼編解碼電路基本原理 流水數據傳輸機制,流水暫停原理 實驗環境 (以下文字僅

學習彙集地,如果你擅長計算機組成原理,多執行緒,設計模式,jvm,前端或者其他都可以

擅長jvm 多執行緒 設計模式 資料庫 前端 分散式什麼的一起學習共同進步。   目的是大家在自學新的領域的時候有地方可以探討求疑 比如在看到垃圾回收各種收集器中遇到執行緒方面知識的時候 學習設計模式分不清單例和享元的區別,只有書本經驗不知道如何應用到實際開發的時候 學習資料庫系統

計算機組成原理實驗2---週期CPU

實驗目的 實驗內容 設計一個單週期CPU,該CPU至少能實現以下指令功能操作。 必須寫一段測試用的彙編程式,而且必須包含所要求的所有指令,slti指令必須檢查兩種情況:“小於”和“大於等於”;beq、bne:“不等”和“等”。這段彙編程式必須儘量優化且出現在實驗報告中,同時,給出每條指令

計算機組成.就是它在運算.處理器CPU

處理器是要好好複習了,畢竟考試重點 主要的內容感覺還是在指令方面,包括指令的格式、指令集的設計、指令流水線、指令級並行。 東西慢慢整理吧,如果一邊在網上搜索的估計會找到很多資料,但是耗費的時間太多了 國內的教材雖然有一定的侷限性,但是tm的要考試啊 我覺得需要

深入淺出計算機組成原理:通過你的CPU主頻,我們來談談“性能”究竟是什麽?(第3講)

但是 網絡 strong 我們 差異 int 情況下 內核 自己 一、性能到底指的是什麽? 買新電腦的時候,我們會說:"原來的電腦性能跟不上了" 寫程序的時候,我們會說:"這個程序西能需要優化一下" 1、"性能"到底指的是什麽? 在計算機組成原理乃至體系結構中"

設計模式——例模式(C++實現

一、單例模式定義: 保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點,該例項被所有程式模組共享。 二、應用場景: 比如在某個伺服器程式中,該伺服器的配置資訊存放在一個檔案中,這些配置資料由一個單例物件統一讀取,然後服務程序中的其他物件再通過這個單例物件獲取這些配置

設計模式-例模式及多種實現

單例模式 單例模式(Singleton Pattern)是Java中最簡單的設計模式之一,屬於建立型,一般都用於保證唯一性的建立,這也是他最大的特點(保證全域性只有唯一的一個例項),並且提供一個全域性的訪問點。 單例有以下幾種形式 餓漢式 懶漢(存線上程安全問題) 註冊登記式 列舉式 序列化(存線上程安

使用logisim搭建週期CPU新增指令

# 使用logisim搭建單週期CPU與新增指令 ## 搭建 ### 總設計 借用高老闆的圖,我們只需要分別做出PC、NPC、IM、RF、EXT、ALU、DM、Controller模組即可,再按圖連線,最後進行控制訊號的處理,一個CPU就差不多搭完了。目前支援的指令集為{addu、subu、ori、lw

計算機組成系統結構實驗-基於微程式控制的CPU設計

本文章主要是為了通俗的解釋計算機組成實驗的微程式彙編的實現方法:實驗目的在掌握部件單元電路實驗的基礎上,初步瞭解如何基於微程式控制進行CPU設計。實驗軟體Dais-CMStudio實驗要求1、學習教材3.1,3.2節,熟悉聯機方式下的開發環境。2、完成以下內容:任務1:用匯編

計算機組成設計 有意思的句子

前言 我們能體驗的最美好的東西是神祕的事物。他是所有真正藝術和科學的來源。 ——阿爾伯特·愛因斯坦 《我的世界觀》,1930 第1章 計算機概念和技術 增多我們不加思索就能完成的重要工作的數量,文明便是如此進步的。 ——Alfred North Whitehead,An Introducti

計算機組成設計(二)——算術邏輯運

 算術運算 計算機結構的簡化模型(模型機)     演示例項一 以add $8,$9,$10(格式被Latex強行改變,不知道怎麼辦555。。。)演示加法運算 1、首先取指令,即得到得到指令的編碼 查指令編碼表知opcode = 0,function =

計算機組成設計(三)—— 門電路的基本原理

http 計算機 都是 計算機組成 tor uri font 同時 get 集體管 現在集成電路中常使用MOS集體管:Metal-Oxide-Semiconductor(金屬-氧化物-半導體) 晶體管有兩種類型:N型和P型,由NMOS和PMOS共同構成的互補型MOS集成

計算機組成設計(四)—— 加法和減法的實現

二進位制加法 半加器(Half Adder) 半加器的功能是將兩個1位二進位制數相加。輸入埠A、B,輸出埠S(輸出),C(進位)。 其有一個很明顯的缺點:不能將低位的進位參與運算。   全加器(Full Adder) 全加器由兩個半加器構成。輸入埠A、B、Cin,輸出埠S(和)、Co

計算機組成設計(五)—— 加法器的優化

4-bit加法器示例 先看一下上一節得到的加法器實現,可以看出改進的地方。 不難發現整個過程是從右至左依次執行,每一個進位需要等前面的運算全完成,可以在一開始得到所有的進位嗎?   行波進位加法器(Ripple-Carry Adder,RCA) 像上面4-bit加法器這樣實現的加法器被

計算機組成設計(六)—— 乘法器

乘法的運算過程 人們日常習慣的乘法是十進位制,但計算機實現起來不方便。首先,需要記錄9x9乘法表,每次相乘去表中找結果;其次,將豎式相加也不方便。 但二進位制卻十分方便,馮·諾伊曼在《關於ENDVAC的報告草案》中說“二進位制可以極大簡化乘法和除法運算。尤其是對於乘法,不再需要十進位制乘法表,也不需要兩輪

計算機組成設計(七)—— 除法器

除法的運算過程 與乘法相比,除法的實現較為複雜,運算過程如下: 過程: 被除數和餘數:將餘數和被除數視為一個,共享一個暫存器,初始值為被除數 除數:可視為不斷右移,並和被除數相減 商:每個bit依次生成,可視為不斷左移   除法器的工作流程   要注

計算機組成設計(八)—— 週期處理器

處理器的設計步驟 分析指令系統,得出對資料通路的需求 為資料通路選擇合適的元件 連線元件,建立資料通路 分析每條指令的實現,以確定控制訊號 整合控制訊號,完成完整的資料通路   具體設計步驟 (一)分析指令系統 MIPS的所有指令是非常多的,我們只實現其簡化版,包

計算機組成設計(八)—— 周期處理器

uri 處理器 lec zuche 輸入 style 我們 方式 gis 處理器的設計步驟 分析指令系統,得出對數據通路的需求 為數據通路選擇合適的組件 連接組件,建立數據通路 分析每條指令的實現,以確定控制信號 集成控制信號,完成完整的數據通路