第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
casex(state) //先高字节,后低字节 1’b0: begin
opc_iraddr[15:8]<=data; state<=1; end 1’b1: begin
opc_iraddr[7:0]<=data; state<=0; end
default: begin
opc_iraddr[15:0]<=16'bxxxxxxxxxxxxxxxx; state<=1'bx; end
endcase end else
state<=1'b0; end end
endmodule
//--------------------------------------------------------
8.2.3.累加器
ACCUMULATORALU_OUT[7:0]DATA[7:0]LOAD_ACCENACLK1RSTCLK1RSTACCUM[7:0]ACCUM[7:0]ACCUMULATOR
累加器用于存放当前的结果,它也是双目运算其中一个数据来源。复位后,累加器的值是零。当累加器通过ena口收到来自CPU状态控制器load_acc信号时,在clk1时钟正跳沿时就收到来自于数据总线的数据。
其VerilogHDL 程序见下面的模块:
//--------------------------------------------------------------
module accum( accum, data, ena, clk1, rst); output[7:0]accum; input[7:0]data;
input ena,clk1,rst; reg[7:0]accum;
always@(posedge clk1) begin
if(rst)
176
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
accum<=8'b0000_0000; //Reset else
if(ena) //当CPU状态控制器发出load_acc信号 accum<=data; //Accumulate
end
endmodule
8.2.4.算术运算器
DATA[7:0]DATA[7:0] ZEROZEROALUALU_OUT[7:0]ALU_OUT[7:0]ACCUM[7:0]ACCUM[7:0]ALU_CLOCKOPCODE[2:0]ALU_CLOCKOPCODE[2:0]
算术逻辑运算单元 根据输入的8种不同操作码分别实现相应的加、与、异或、跳转等8种基本操作运算。利用这几种基本运算可以实现很多种其它运算以及逻辑判断等操作。
其VerilogHDL 程序见下面的模块:
//------------------------------------------------------------------------------
module alu (alu_out, zero, data, accum, alu_clk, opcode); output [7:0]alu_out; output zero;
input [7:0] data, accum; input [2:0] opcode; input alu_clk;
reg [7:0] alu_out;
parameter HLT =3’b000,
SKZ =3’b001, ADD =3’b010, ANDD =3’b011, XORR =3’b100, LDA =3’b101, STO =3’b110, JMP =3’b111;
assign zero = !accum; always @(posedgealu_clk)
begin //操作码来自指令寄存器的输出opc_iaddr<15..0>的低3位 casex (opcode)
HLT: alu_out<=accum; SKZ: alu_out<=accum;
177
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
ADD: alu_out<=data+accum; ANDD: alu_out<=data&accum; XORR: alu_out<=data^accum; LDA: alu_out<=data; STO: alu_out<=accum; JMP: alu_out<=accum;
default: alu_out<=8'bxxxx_xxxx; endcase end endmodule
//----------------------------------------------------------------------------
8.2.5.数据控制器
数据控制器的作用是控制累加器数据输出,由于数据总线是各种操作时传送数据的公共通道,
DATACTLALU_OUT[7:0]IN[7:0]DATA[7:0]DATACTL_ENADATA[7:0]DATA_ENA
不同的情况下传送不同的内容。有时要传输指令,有时要传送RAM区或接口的数据。累加器的数据只有在需要往RAM区或端口写时才允许输出,否则应呈现高阻态,以允许其它部件使用数据总线。 所以任何部件往总线上输出数据时,都需要一控制信号。而此控制信号的启、停,则由CPU状态控制器输出的各信号控制决定。数据控制器何时输出累加器的数据则由状态控制器输出的控制信号datactl_ena决定。
其VerilogHDL 程序见下面的模块:
//--------------------------------------------------------------------
module datactl (data,in,data_ena);
output [7:0]data; input [7:0]in; input data_ena;
assign data = (data_ena)? In : 8'bzzzz_zzzz;
endmodule
//--------------------------------------------------------------------
178
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
8.2.6.地址多路器
PC_ADDR[12 : 0]ADDRPC_ADDR[12 : 0]ADDR[12 : 0]ADDR[12 : 0]IR_ADDR[12 : 0] IR_ADDR[12 : 0] FETCHFETCH
地址多路器用于选择输出的地址是PC(程序计数)地址还是数据/端口地址。每个指令周期的前4个时钟周期用于从ROM中读取指令,输出的应是PC地址。后4个时钟周期用于对RAM或端口的读写,该地址由指令中给出。地址的选择输出信号由时钟信号的8分频信号fetch提供。
其VerilogHDL 程序见下面的模块:
//------------------------------------------------------------------------------
module adr(addr,fetch,ir_addr,pc_addr); output [12:0] addr;
input [12:0] ir_addr, pc_addr; input fetch;
assign addr = fetch? pc_addr : ir_addr;
endmodule
//------------------------------------------------------------------------------
8.2.7.程序计数器
程序计数器用于提供指令地址。以便读取指令,指令按地址顺序存放在存储器中。有两种途径可形成指令地址:其一是顺序执行的情况,其二是遇到要改变顺序执行程序的情况,例如执行JMP指令后,需要形成新的指令地址。下面就来详细说明PC地址是如何建立的。
COUNTERIR_ADDR[12 : 0]IR_ADDR[12 : 0]LOADPC_ADDR[12 : 0]CLOCKRESETLOAD_PCINC_PCPC_ADDR[12 : 0]RST
复位后,指令指针为零,即每次CPU重新启动将从ROM的零地址开始读取指令并执行。每条指令执行完需2个时钟,这时pc_addr已被增2,指向下一条指令。(因为每条指令占两个字节。)如果正执行的指令是跳转语句,这时CPU状态控制器将会输出load_pc信号,通过load口进入程序计数器。程序计数器(pc_addr)将装入目标地址(ir_addr),而不是增2。
179
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
其VerilogHDL 程序见下面的模块:
//------------------------------------------------------------------------------
module counter ( pc_addr, ir_addr, load, clock, rst); output [12:0] pc_addr; input [12:0] ir_addr; input load, clock, rst; reg [12:0] pc_addr;
always @( posedge clock or posedge rst ) begin
if(rst)
pc_addr<=13'b0_0000_0000_0000; else
if(load)
pc_addr<=ir_addr; else
pc_addr <= pc_addr + 1;
end endmodule
//------------------------------------------------------------------------------
180