精简指令集计算机(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)则用于保存下一个将要读/写的存储单元地址。
处理器包括寄存器、数据通路、控制信号和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(该功能可以用于监控循环次数)。
本例中,ALU有两个操作数(数据通路)——data_1和data_2,且指令集包含的内容如下:
指令 | 操作 |
---|---|
ADD | 加 |
SUB | 减 |
AND | 相与 |
NOT | 按位求反 |
RISC机所有动作时序都有控制器决定。控制器根据当前指令把数据送到合适的目的地。因此,控制器的设计严重依赖于ALU性能、数据通路资源和可用时钟方案。本例将使用单时钟,并只在时钟的某个边沿(如上升沿)开始操作。控制器监控处理器状态和执行的指令,并决定控制信号的值。控制器的输入是指令字和ALU的零标识。
控制器的输入信号定义如下:
控制器的作用包括:
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中的暂存数据无意义。
控制器可以设计成FSM,在给定设计的架构、指令集及时钟方案后,还必须定义状态。这可以通过确定指令执行时必须完成什么样的动作来实现。下 面将使用ASM图来描述ISC_ SPM机的动作,并清晰地说明在指令支配下状态机怎样进行操作。
状态机有三个操作阶段:取指、译码和执行。取指阶段负责从存储器中获取指令,译码阶段负责解释指令、控制数据通路和加载寄存器。执行阶段则将产生指令结果。取指阶段需要两个时钟周期,一个时钟周期用来加载地址寄存器,另一个时钟周期用来从存储器中得到给定地址的数据。译码阶段在一个时钟周期内完成。执行阶段根据所执行的指令的不同可能需要0、1或2个额外的时钟周期: NOT指令的执行可在译码周期内同时完成;单字节指令,如ADD,需要用一个时钟周期来执行并将结果写人目的寄存器,源寄存器则在译码阶段进行加载;2字节指令(如RD)的执行需要两个时钟周期一个时钟周期把指令的第2字节载入地址寄存器,另一个时钟周期用来从该地址指定的存储器中得到数据,并将其载人目的寄存器。RISC_ SPM的控制器有11个状态。各状态中产生的控制行为如下所列。
RISC_SPM控制部分的ASM如图7.12所示,为了清楚可见,对状态进行了编号。完成ASM图的创建后,设计者可以根据给定架构编写整个RISC机的verilog描述。
该过程按下列步骤展开:首先根据RISC机划分对各功能单元进行声明;接着定义端口和变量,并进行语法检查;然后对各个单元进行描述、调试和验证;最后整合设计并进行功能验证。
最先给出的是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被描述为电平敏感的组合逻辑,这个周期操作只要数据通路或选择总线发生变化就会被激活。使用参数可以增强可读性,并减少代码编写错误的可能性。
//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
下面给出RISC_SPM程序执行的验证平台。lest_RISC_SPM定义了用来显示存储器字数据的指针,使用一次性操作(initial)刷新存储器,并将小段程序和数据加载到存储器不同区域。该程序可执行以下操作:(1)读存储器并把数据加载到处理器的寄存器中;(2)执行减法修改循环计数; (3)在循环过程中将寄存器内容相加;(4)当循环指针为0时停止( halt状态)。程序执行结果如图7.13所示。
//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