RISC存儲程序機的設計與綜合
RISC存儲程序機
精簡指令集計算機(RISC)指令集小,時鐘週期短,每條指令的執行週期數少。RISC機優化後可以實現高效的指令流水線操作。本節將構建一個簡單地RISC機。
RISC_SPM是一個RISC架構的存儲程序機(SPM,Stored-Program Machine)——其指令包含在存儲器的程序裏。
該電路包括三個功能單元:處理器(數據通路)、控制器、存儲器。程序指令及數據存放在存儲器中。程序執行時同步地進行指令讀取、譯碼和執行:
1)對ALU中的數據進行操作;
2)修改寄存器的內容;
3)修改程序計數器(PC)、指令寄存器(IR)、和地址寄存器(ADD_R)的內容;
4)修改存儲單元的內容;
5)獲取存儲器中的數據和指令;
6)控制系統總線上的數據傳送。
其中,指令寄存器(IR)用於存放當前正在執行的指令,程序計數器(PC)用於存放下一條將要執行的指令的存儲地址,而地址寄存器(ADD_R)則用於保存下一個將要讀/寫的存儲單元地址。
1、RISC_SPM:處理器
處理器包括寄存器、數據通路、控制信號和ALU。ALU能根據指令寄存器中存放的操作碼對操作數進行算數、邏輯運算。
多路複用器Mux_1決定送往Bus_1的數據源,多路複用器Mux_2決定送往Bus_2的數據源。
Mux_1的輸入來自四個內部通用寄存器(R0、R1、R2、R3)和程序計數器(PC)。
Bus_1上的內容可以被傳送至ALU、存儲器或Bus_2(經由Mux_2)。
Mux_2的輸入來自ALU、Mux_1和存儲單元。
這樣,從存儲器中取出的指令可以經由Bus_2裝入指令寄存器;從存儲器中取出的數據在送入ALU進行操作之前可以先存入;通用寄存器或操作數寄存器(Reg_Y)算術邏輯運算的結果可以經由Bus_2裝入寄存器,再寫入存儲器中。專用寄存器(Reg_Z)用於便是ALU的操作結果是否爲0(該功能可以用於監控循環次數)。
2、RISC_SPM:ALU
本例中,ALU有兩個操作數(數據通路)——data_1和data_2,且指令集包含的內容如下:
指令 | 操作 |
---|---|
ADD | 加 |
SUB | 減 |
AND | 相與 |
NOT | 按位求反 |
3、RISC_SPM:控制器
RISC機所有動作時序都有控制器決定。控制器根據當前指令把數據送到合適的目的地。因此,控制器的設計嚴重依賴於ALU性能、數據通路資源和可用時鐘方案。本例將使用單時鐘,並只在時鐘的某個邊沿(如上升沿)開始操作。控制器監控處理器狀態和執行的指令,並決定控制信號的值。控制器的輸入是指令字和ALU的零標識。
控制器的輸入信號定義如下:
控制器的作用包括:
- 決定何時裝載寄存器
- 控制多路複用器選擇數據通道
- 決定何時將數據寫入存儲器
- 控制三態總線
4、RISC_SPM:指令集
RISC機由存儲器中的由指令序列組成的機器語言程序控制。因此,除了機器架構,控制器的設計還依賴於處理器指令集(即程序執行的指令)。機器語言程序由8位(字節)的存儲序列構成。RISC_ SPM的指令可長可短,由可執行的操作決定。
短指令格式如圖7.11(a)所示。每條短指令需要1個字節存儲。該字節包括4位操作碼、2位源寄存器地址和2位目的寄存器地址。而長指令需要2個字節存儲:第1個字節包含4位操作碼,餘下4位用來指定源和目的寄存器的地址,由指令決定;第2個字節用於存放指令所需存儲器操作數的地址。圖7.11(b)給出了2字節格式的長指令。
程序計數器PC用於保存將要執行的下一條指令的地址。當外部復位有效時,PC被清0,這表示第一條將要執行的指令存放在存儲器底部。對單週期指令來說,在時鐘有效沿PC所指存儲單元中的指令將裝人IR且PC加1。指令譯碼器決定了數據通路和ALU的最終動作。兩字節長指令的執行需要一個額外的時鐘週期,PC所指存儲單元中的第2個(指令)字節在第2個執行週期被讀人後,才能完成該指令的執行。在雙週期執行過程中,ALU中的暫存數據無意義。
5、RISC_SPM:控制器設計
控制器可以設計成FSM,在給定設計的架構、指令集及時鐘方案後,還必須定義狀態。這可以通過確定指令執行時必須完成什麼樣的動作來實現。下 面將使用ASM圖來描述ISC_ SPM機的動作,並清晰地說明在指令支配下狀態機怎樣進行操作。
狀態機有三個操作階段:取指、譯碼和執行。取指階段負責從存儲器中獲取指令,譯碼階段負責解釋指令、控制數據通路和加載寄存器。執行階段則將產生指令結果。取指階段需要兩個時鐘週期,一個時鐘週期用來加載地址寄存器,另一個時鐘週期用來從存儲器中得到給定地址的數據。譯碼階段在一個時鐘週期內完成。執行階段根據所執行的指令的不同可能需要0、1或2個額外的時鐘週期: NOT指令的執行可在譯碼週期內同時完成;單字節指令,如ADD,需要用一個時鐘週期來執行並將結果寫人目的寄存器,源寄存器則在譯碼階段進行加載;2字節指令(如RD)的執行需要兩個時鐘週期一個時鐘週期把指令的第2字節載入地址寄存器,另一個時鐘週期用來從該地址指定的存儲器中得到數據,並將其載人目的寄存器。RISC_ SPM的控制器有11個狀態。各狀態中產生的控制行爲如下所列。
RISC_SPM控制部分的ASM如圖7.12所示,爲了清楚可見,對狀態進行了編號。完成ASM圖的創建後,設計者可以根據給定架構編寫整個RISC機的verilog描述。
該過程按下列步驟展開:首先根據RISC機劃分對各功能單元進行聲明;接着定義端口和變量,並進行語法檢查;然後對各個單元進行描述、調試和驗證;最後整合設計並進行功能驗證。
頂層模塊RISC_SPM
最先給出的是verilog的頂層模塊RISC_SPM,對圖7.10中各個模塊進行整合。實例化三個模塊 Processing_Unit 、 Control_Unit 、Memory_Unit 實例名爲M0_Processor、M1_Controller、M2_SRAM,這三個結構/功能單元之間的數據通路結構(尺寸)參數也在層次裏的這個階段進行聲明。
//Verilog HDL
module RISC_SPM (clk, rst);
parameter word_size = 8;
parameter Sel1_size = 3;
parameter Sel2_size = 2;
wire [Sel1_size-1: 0] Sel_Bus_1_Mux;
wire [Sel2_size-1: 0] Sel_Bus_2_Mux;
input clk, rst;
// Data Nets
wire zero;
wire [word_size-1: 0] instruction, address, Bus_1, mem_word;
// Control Nets
wire Load_R0, Load_R1, Load_R2, Load_R3, Load_PC, Inc_PC, Load_IR;
wire Load_Add_R, Load_Reg_Y, Load_Reg_Z;
wire write;
Processing_Unit M0_Processor
(instruction, zero, address, Bus_1, mem_word, Load_R0, Load_R1,
Load_R2, Load_R3, Load_PC, Inc_PC, Sel_Bus_1_Mux, Load_IR,
Load_Add_R, Load_Reg_Y,
Load_Reg_Z, Sel_Bus_2_Mux, clk, rst);
Control_Unit M1_Controller (Load_R0, Load_R1, Load_R2, Load_R3, Load_PC, Inc_PC,
Sel_Bus_1_Mux, Sel_Bus_2_Mux , Load_IR, Load_Add_R, Load_Reg_Y, Load_Reg_Z,
write, instruction, zero, clk, rst);
Memory_Unit M2_SRAM (
.data_out(mem_word),
.data_in(Bus_1),
.address(address),
.clk(clk),
.write(write) );
endmodule
處理器
處理器的verilog模型描述圖7.10所示的功能單元的結構、寄存器操作和數據通路操作。該處理器例化的其他幾個模塊也必須加以聲明。
//Verilog HDL
module Processing_Unit (instruction, Zflag, address, Bus_1, mem_word, Load_R0, Load_R1, Load_R2,
Load_R3, Load_PC, Inc_PC, Sel_Bus_1_Mux, Load_IR, Load_Add_R, Load_Reg_Y, Load_Reg_Z,
Sel_Bus_2_Mux, clk, rst);
parameter word_size = 8;
parameter op_size = 4;
parameter Sel1_size = 3;
parameter Sel2_size = 2;
output [word_size-1: 0] instruction, address, Bus_1;
output Zflag;
input [word_size-1: 0] mem_word;
input Load_R0, Load_R1, Load_R2, Load_R3, Load_PC, Inc_PC;
input [Sel1_size-1: 0] Sel_Bus_1_Mux;
input [Sel2_size-1: 0] Sel_Bus_2_Mux;
input Load_IR, Load_Add_R, Load_Reg_Y, Load_Reg_Z;
input clk, rst;
wire Load_R0, Load_R1, Load_R2, Load_R3;
wire [word_size-1: 0] Bus_2;
wire [word_size-1: 0] R0_out, R1_out, R2_out, R3_out;
wire [word_size-1: 0] PC_count, Y_value, alu_out;
wire alu_zero_flag;
wire [op_size-1 : 0] opcode = instruction [word_size-1: word_size-op_size];
Register_Unit R0 (R0_out, Bus_2, Load_R0, clk, rst);
Register_Unit R1 (R1_out, Bus_2, Load_R1, clk, rst);
Register_Unit R2 (R2_out, Bus_2, Load_R2, clk, rst);
Register_Unit R3 (R3_out, Bus_2, Load_R3, clk, rst);
Register_Unit Reg_Y (Y_value, Bus_2, Load_Reg_Y, clk, rst);
D_flop Reg_Z (Zflag, alu_zero_flag, Load_Reg_Z, clk, rst);
Address_Register Add_R (address, Bus_2, Load_Add_R, clk, rst);
Instruction_Register IR (instruction, Bus_2, Load_IR, clk, rst);
Program_Counter PC (PC_count, Bus_2, Load_PC, Inc_PC, clk, rst);
Multiplexer_5ch Mux_1 (Bus_1, R0_out, R1_out, R2_out, R3_out, PC_count, Sel_Bus_1_Mux);
Multiplexer_3ch Mux_2 (Bus_2, alu_out, Bus_1, mem_word, Sel_Bus_2_Mux);
Alu_RISC ALU (alu_zero_flag, alu_out, Y_value, Bus_1, opcode);
endmodule
module Register_Unit (data_out, data_in, load, clk, rst);
parameter word_size = 8;
output [word_size-1: 0] data_out;
input [word_size-1: 0] data_in;
input load;
input clk, rst;
reg [word_size-1: 0] data_out;
always @ (posedge clk or negedge rst)
if (rst == 0) data_out <= 0; else if (load) data_out <= data_in;
endmodule
module D_flop (data_out, data_in, load, clk, rst);
output data_out;
input data_in;
input load;
input clk, rst;
reg data_out;
always @ (posedge clk or negedge rst)
if (rst == 0) data_out <= 0; else if (load == 1)data_out <= data_in;
endmodule
module Address_Register (data_out, data_in, load, clk, rst);
parameter word_size = 8;
output [word_size-1: 0] data_out;
input [word_size-1: 0] data_in;
input load, clk, rst;
reg [word_size-1: 0] data_out;
always @ (posedge clk or negedge rst)
if (rst == 0) data_out <= 0; else if (load) data_out <= data_in;
endmodule
module Instruction_Register (data_out, data_in, load, clk, rst);
parameter word_size = 8;
output [word_size-1: 0] data_out;
input [word_size-1: 0] data_in;
input load;
input clk, rst;
reg [word_size-1: 0] data_out;
always @ (posedge clk or negedge rst)
if (rst == 0) data_out <= 0; else if (load) data_out <= data_in;
endmodule
module Program_Counter (count, data_in, Load_PC, Inc_PC, clk, rst);
parameter word_size = 8;
output [word_size-1: 0] count;
input [word_size-1: 0] data_in;
input Load_PC, Inc_PC;
input clk, rst;
reg [word_size-1: 0] count;
always @ (posedge clk or negedge rst)
if (rst == 0) count <= 0; else if (Load_PC) count <= data_in; else if (Inc_PC) count <= count +1;
endmodule
module Multiplexer_5ch (mux_out, data_a, data_b, data_c, data_d, data_e, sel);
parameter word_size = 8;
output [word_size-1: 0] mux_out;
input [word_size-1: 0] data_a, data_b, data_c, data_d, data_e;
input [2: 0] sel;
assign mux_out = (sel == 0)
? data_a: (sel == 1)
? data_b : (sel == 2)
? data_c: (sel == 3)
? data_d : (sel == 4)
? data_e : 'bx;
endmodule
module Multiplexer_3ch (mux_out, data_a, data_b, data_c, sel);
parameter word_size = 8;
output [word_size-1: 0] mux_out;
input [word_size-1: 0] data_a, data_b, data_c;
input [1: 0] sel;
assign mux_out = (sel == 0) ? data_a: (sel == 1) ? data_b : (sel == 2) ? data_c: 'bx;
endmodule
ALU
ALU被描述爲電平敏感的組合邏輯,這個週期操作只要數據通路或選擇總線發生變化就會被激活。使用參數可以增強可讀性,並減少代碼編寫錯誤的可能性。
//Verilog HDL
/*ALU Instruction Action
ADD Adds the datapaths to form data_1 + data_2.
SUB Subtracts the datapaths to form data_1 - data_2.
AND Takes the bitwise-and of the datapaths, data_1 & data_2.
NOT Takes the bitwise Boolean complement of data_1.
*/
// Note: the carries are ignored in this model.
module Alu_RISC (alu_zero_flag, alu_out, data_1, data_2, sel);
parameter word_size = 8;
parameter op_size = 4;
// Opcodes
parameter NOP = 4'b0000;
parameter ADD = 4'b0001;
parameter SUB = 4'b0010;
parameter AND = 4'b0011;
parameter NOT = 4'b0100;
parameter RD = 4'b0101;
parameter WR = 4'b0110;
parameter BR = 4'b0111;
parameter BRZ = 4'b1000;
output alu_zero_flag;
output [word_size-1: 0] alu_out;
input [word_size-1: 0] data_1, data_2;
input [op_size-1: 0] sel;
reg [word_size-1: 0] alu_out;
assign alu_zero_flag = ~|alu_out;
always @ (sel or data_1 or data_2)
case (sel)
NOP: alu_out = 0;
ADD: alu_out = data_1 + data_2; // Reg_Y + Bus_1
SUB: alu_out = data_2 - data_1;
AND: alu_out = data_1 & data_2;
NOT: alu_out = ~ data_2; // Gets data from Bus_1
default: alu_out = 0;
endcase
endmodule
控制器
規模龐大的控制器可以根據圖7.12所示的ASM圖進行簡單設計。首先要聲明端口和變量,然後使用由條件操作代碼(?..:)表示的嵌套連續賦值語句來描述多路複用。這裏使用了兩種週期行爲:電平敏感行爲來描述輸出信號和下一狀態的組合邏輯,邊沿敏感行爲用來同步時鐘變化。
//Verilog HDL
module Control_Unit (
Load_R0, Load_R1,
Load_R2, Load_R3,
Load_PC, Inc_PC,
Sel_Bus_1_Mux, Sel_Bus_2_Mux,
Load_IR, Load_Add_R, Load_Reg_Y, Load_Reg_Z,
write, instruction, zero, clk, rst);
parameter word_size = 8, op_size = 4, state_size = 4;
parameter src_size = 2, dest_size = 2, Sel1_size = 3, Sel2_size = 2;
// State Codes
parameter S_idle = 0, S_fet1 = 1, S_fet2 = 2, S_dec = 3;
parameter S_ex1 = 4, S_rd1 = 5, S_rd2 = 6;
parameter S_wr1 = 7, S_wr2 = 8, S_br1 = 9, S_br2 = 10, S_halt = 11;
// Opcodes
parameter NOP = 0, ADD = 1, SUB = 2, AND = 3, NOT = 4;
parameter RD = 5, WR = 6, BR = 7, BRZ = 8;
// Source and Destination Codes
parameter R0 = 0, R1 = 1, R2 = 2, R3 = 3;
output Load_R0, Load_R1, Load_R2, Load_R3;
output Load_PC, Inc_PC;
output [Sel1_size-1: 0] Sel_Bus_1_Mux;
output Load_IR, Load_Add_R;
output Load_Reg_Y, Load_Reg_Z;
output [Sel2_size-1: 0] Sel_Bus_2_Mux;
output write;
input [word_size-1: 0] instruction;
input zero;
input clk, rst;
reg [state_size-1: 0] state, next_state;
reg Load_R0, Load_R1, Load_R2, Load_R3, Load_PC, Inc_PC;
reg Load_IR, Load_Add_R, Load_Reg_Y;
reg Sel_ALU, Sel_Bus_1, Sel_Mem;
reg Sel_R0, Sel_R1, Sel_R2, Sel_R3, Sel_PC;
reg Load_Reg_Z, write;
reg err_flag;
wire [op_size-1: 0] opcode = instruction [word_size-1: word_size - op_size];
wire [src_size-1: 0] src = instruction [src_size + dest_size -1: dest_size];
wire [dest_size-1: 0] dest = instruction [dest_size -1: 0];
// Mux selectors
assign Sel_Bus_1_Mux[Sel1_size-1: 0] = Sel_R0 ? 0:
Sel_R1 ? 1:
Sel_R2 ? 2:
Sel_R3 ? 3:
Sel_PC ? 4: 3'bx; // 3-bits, sized number
assign Sel_Bus_2_Mux[Sel2_size-1: 0] = Sel_ALU ? 0:
Sel_Bus_1 ? 1:
Sel_Mem ? 2: 2'bx;
always @ (posedge clk or negedge rst) begin: State_transitions
if (rst == 0) state <= S_idle; else state <= next_state; end
/* always @ (state or instruction or zero) begin: Output_and_next_state
Note: The above event control expression leads to incorrect operation. The state transition causes the activity to be evaluated once, then the resulting instruction change causes it to be evaluated again, but with the residual value of opcode. On the second pass the value seen is the value opcode had before the state change, which results in Sel_PC = 0 in state 3, which will cause a return to state 1 at the next clock. Finally, opcode is changed, but this does not trigger a re-evaluation because it is not in the event control expression. So, the caution is to be sure to use opcode in the event control expression. That way, the final execution of the behavior uses the value of opcode that results from the state change, and leads to the correct value of Sel_PC.
說明:上述敏感列表將導致錯誤操作。狀態轉移觸發語旬執行,接着指令(instruction)的變化會再次觸發語句執行,但此時opcode的值不變。這樣第二次看起米opcode仍保持state變化前的值,這使得狀態3下的Sel_ PC=0,於是下一時鐘會返回到狀態1。最後opcode發生變化,但因其不在事件控制表達式中,不會再次觸發語句執行。因此注意必須保證opeode在敏感列表中。這樣最終動作將依據狀態變化後的opcode值,並能得到正確的Sel_PC值。
*/
always @ (state or opcode or src or dest or zero) begin: Output_and_next_state
Sel_R0 = 0; Sel_R1 = 0; Sel_R2 = 0; Sel_R3 = 0; Sel_PC = 0;
Load_R0 = 0; Load_R1 = 0; Load_R2 = 0; Load_R3 = 0; Load_PC = 0;
Load_IR = 0; Load_Add_R = 0; Load_Reg_Y = 0; Load_Reg_Z = 0;
Inc_PC = 0;
Sel_Bus_1 = 0;
Sel_ALU = 0;
Sel_Mem = 0;
write = 0;
err_flag = 0; // Used for de-bug in simulation
next_state = state;
case (state) S_idle: next_state = S_fet1;
S_fet1: begin
next_state = S_fet2;
Sel_PC = 1;
Sel_Bus_1 = 1;
Load_Add_R = 1;
end
S_fet2: begin
next_state = S_dec;
Sel_Mem = 1;
Load_IR = 1;
Inc_PC = 1;
end
S_dec: case (opcode)
NOP: next_state = S_fet1;
ADD, SUB, AND: begin
next_state = S_ex1;
Sel_Bus_1 = 1;
Load_Reg_Y = 1;
case (src)
R0: Sel_R0 = 1;
R1: Sel_R1 = 1;
R2: Sel_R2 = 1;
R3: Sel_R3 = 1;
default : err_flag = 1;
endcase
end // ADD, SUB, AND
NOT: begin
next_state = S_fet1;
Load_Reg_Z = 1;
Sel_Bus_1 = 1;
Sel_ALU = 1;
case (src)
R0: Sel_R0 = 1;
R1: Sel_R1 = 1;
R2: Sel_R2 = 1;
R3: Sel_R3 = 1;
default : err_flag = 1;
endcase
case (dest)
R0: Load_R0 = 1;
R1: Load_R1 = 1;
R2: Load_R2 = 1;
R3: Load_R3 = 1;
default: err_flag = 1;
endcase
end // NOT
RD: begin
next_state = S_rd1;
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
end // RD
WR: begin
next_state = S_wr1;
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
end // WR
BR: begin
next_state = S_br1;
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
end // BR
BRZ: if (zero == 1) begin
next_state = S_br1;
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
end // BRZ
else begin
next_state = S_fet1;
Inc_PC = 1;
end
default : next_state = S_halt;
endcase // (opcode)
S_ex1: begin
next_state = S_fet1;
Load_Reg_Z = 1;
Sel_ALU = 1;
case (dest)
R0: begin Sel_R0 = 1; Load_R0 = 1; end
R1: begin Sel_R1 = 1; Load_R1 = 1; end
R2: begin Sel_R2 = 1; Load_R2 = 1; end
R3: begin Sel_R3 = 1; Load_R3 = 1; end
default : err_flag = 1;
endcase
end
S_rd1: begin
next_state = S_rd2;
Sel_Mem = 1;
Load_Add_R = 1;
Inc_PC = 1;
end
S_wr1: begin
next_state = S_wr2;
Sel_Mem = 1;
Load_Add_R = 1;
Inc_PC = 1;
end
S_rd2: begin
next_state = S_fet1;
Sel_Mem = 1;
case (dest)
R0: Load_R0 = 1;
R1: Load_R1 = 1;
R2: Load_R2 = 1;
R3: Load_R3 = 1;
default : err_flag = 1;
endcase
end
S_wr2: begin
next_state = S_fet1;
write = 1;
case (src)
R0: Sel_R0 = 1;
R1: Sel_R1 = 1;
R2: Sel_R2 = 1;
R3: Sel_R3 = 1;
default : err_flag = 1;
endcase
end
S_br1: begin next_state = S_br2; Sel_Mem = 1; Load_Add_R = 1; end
S_br2: begin next_state = S_fet1; Sel_Mem = 1; Load_PC = 1; end
S_halt: next_state = S_halt;
default: next_state = S_idle;
endcase
end
endmodule
爲了簡單起見,存儲單元用D觸發器陣列描述。另一種方法是採用外部SRAM
//Verilog HDL
module Memory_Unit (data_out, data_in, address, clk, write);
parameter word_size = 8;
parameter memory_size = 256;
output [word_size-1: 0] data_out;
input [word_size-1: 0] data_in;
input [word_size-1: 0] address;
input clk, write;
reg [word_size-1: 0] memory [memory_size-1: 0];
assign data_out = memory[address];
always @ (posedge clk)
if (write) memory[address] = data_in;
endmodule
6、RISC_SPM:程序執行
下面給出RISC_SPM程序執行的驗證平臺。lest_RISC_SPM定義了用來顯示存儲器字數據的指針,使用一次性操作(initial)刷新存儲器,並將小段程序和數據加載到存儲器不同區域。該程序可執行以下操作:(1)讀存儲器並把數據加載到處理器的寄存器中;(2)執行減法修改循環計數; (3)在循環過程中將寄存器內容相加;(4)當循環指針爲0時停止( halt狀態)。程序執行結果如圖7.13所示。
testbench文件代碼:
//Verilog HDL
module test_RISC_SPM ();
reg rst;
wire clk;
parameter word_size = 8;
reg [8: 0] k;
Clock_Unit M1 (clk);
RISC_SPM M2 (clk, rst);
// define probes
wire [word_size-1: 0] word0, word1, word2, word3, word4, word5, word6;
wire [word_size-1: 0] word7, word8, word9, word10, word11, word12, word13;
wire [word_size-1: 0] word14;
wire [word_size-1: 0] word128, word129, word130, word131, word132, word255;
wire [word_size-1: 0] word133, word134, word135, word136, word137;
wire [word_size-1: 0] word138, word139, word140;
assign word0 = M2.M2_SRAM.memory[0];
assign word1 = M2.M2_SRAM.memory[1];
assign word2 = M2.M2_SRAM.memory[2];
assign word3 = M2.M2_SRAM.memory[3];
assign word4 = M2.M2_SRAM.memory[4];
assign word5 = M2.M2_SRAM.memory[5];
assign word6 = M2.M2_SRAM.memory[6];
assign word7 = M2.M2_SRAM.memory[7];
assign word8 = M2.M2_SRAM.memory[8];
assign word9 = M2.M2_SRAM.memory[9];
assign word10 = M2.M2_SRAM.memory[10];
assign word11 = M2.M2_SRAM.memory[11];
assign word12 = M2.M2_SRAM.memory[12];
assign word13 = M2.M2_SRAM.memory[13];
assign word14 = M2.M2_SRAM.memory[14];
assign word128 = M2.M2_SRAM.memory[128];
assign word129 = M2.M2_SRAM.memory[129];
assign word130 = M2.M2_SRAM.memory[130];
assign word131 = M2.M2_SRAM.memory[131];
assign word132 = M2.M2_SRAM.memory[132];
assign word133 = M2.M2_SRAM.memory[133];
assign word134 = M2.M2_SRAM.memory[134];
assign word135 = M2.M2_SRAM.memory[135];
assign word136 = M2.M2_SRAM.memory[136];
assign word137 = M2.M2_SRAM.memory[137];
assign word138 = M2.M2_SRAM.memory[138];
assign word139 = M2.M2_SRAM.memory[139];
assign word140 = M2.M2_SRAM.memory[140];
assign word255 = M2.M2_SRAM.memory[255];
initial #2800 $finish;
//Flush Memory
initial begin: Flush_Memory
#2 rst = 0; for (k=0; k<=255; k=k+1)M2.M2_SRAM.memory[k] = 0; #10 rst = 1;
end
initial begin: Load_program
#5
// opcode_src_dest
M2.M2_SRAM.memory[0] = 8'b0000_00_00; // NOP
M2.M2_SRAM.memory[1] = 8'b0101_00_10; // Read 130 to R2
M2.M2_SRAM.memory[2] = 130;
M2.M2_SRAM.memory[3] = 8'b0101_00_11; // Read 131 to R3
M2.M2_SRAM.memory[4] = 131;
M2.M2_SRAM.memory[5] = 8'b0101_00_01; // Read 128 to R1
M2.M2_SRAM.memory[6] = 128;
M2.M2_SRAM.memory[7] = 8'b0101_00_00; // Read 129 to R0
M2.M2_SRAM.memory[8] = 129;
M2.M2_SRAM.memory[9] = 8'b0010_00_01; // Sub R1-R0 to R1
M2.M2_SRAM.memory[10] = 8'b1000_00_00; // BRZ
M2.M2_SRAM.memory[11] = 134; // Holds address for BRZ
M2.M2_SRAM.memory[12] = 8'b0001_10_11; // Add R2+R3 to R3
M2.M2_SRAM.memory[13] = 8'b0111_00_11; // BR
M2.M2_SRAM.memory[14] = 140;
// Load data
M2.M2_SRAM.memory[128] = 6;
M2.M2_SRAM.memory[129] = 1;
M2.M2_SRAM.memory[130] = 2;
M2.M2_SRAM.memory[131] = 0;
M2.M2_SRAM.memory[134] = 139;
//M2.M2_SRAM.memory[135] = 0;
M2.M2_SRAM.memory[139] = 8'b1111_00_00; // HALT
M2.M2_SRAM.memory[140] = 9; // Recycle
end
endmodule
module Clock_Unit(output reg clock);
parameter delay = 0;
parameter half_cycle = 10;
initial begin
#delay clock = 0;
forever #half_cycle clock = ~clock;
end
endmodule
仿真結果: