第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------ 状态机和状态机控制器组成了状态控制器。它们之间的连接关系很简单。见本小节的图8.2.8。
8.2.9.外围模块
为了对RISC_CPU进行测试,需要有存储测试程序的ROM和装载数据的RAM、地址译码器。下面来简单介绍一下:
地址译码器
module addr_decode( addr, rom_sel, ram_sel); output rom_sel, ram_sel; input [12:0] addr; reg rom_sel, ram_sel;
always @( addr ) begin
casex(addr)
13'b1_1xxx_xxxx_xxxx:{rom_sel,ram_sel}<=2'b01; 13'b0_xxxx_xxxx_xxxx:{rom_sel,ram_sel}<=2'b10; 13'b1_0xxx_xxxx_xxxx:{rom_sel,ram_sel}<=2'b10; default:{rom_sel,ram_sel}<=2'b00; endcase end
endmodule
地址译码器用于产生选通信号,选通ROM或RAM。
FFFFH---1800H RAM 1800H---0000H ROM
2.RAM和ROM
module ram( data, addr, ena, read, write ); inout [7:0] data; input [9:0] addr; input ena;
input read, write;
reg [7:0] ram [10'h3ff:0];
assign data = ( read && ena )? ram[addr] : 8'hzz;
always @(posedge write) begin
ram[addr]<=data; end endmodule
module rom( data, addr, read, ena ); output [7:0] data; input [12:0] addr;
186
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
input read, ena;
reg [7:0] memory [13'h1fff:0]; wire [7:0] data;
assign data= ( read && ena )? memory[addr] : 8'bzzzzzzzz;
endmodule
ROM用于装载测试程序,可读不可写。RAM用于存放数据,可读可写。
8.3. RISC_CPU 操作和时序
一个微机系统为了完成自身的功能,需要CPU执行许多操作。以下是RISC_CPU的主要操作: 系统的复位和启动操作 总线读操作 总线写操作
下面详细介绍一下每个操作:
8.3.1.系统的复位和启动操作
RISC_CPU的复位和启动操作是通过rst引脚的信号触发执行的。当rst信号一进入高电平,RISC_CPU就会结束现行操作,并且只要rst停留在高电平状态,CPU就维持在复位状态。在复位状态,CPU各内部寄存器都被设为初值,全部为零。数据总线为高阻态,地址总线为0000H,所有控制信号均为无效状态。rst回到低电平后,接着到来的第一个fetch上升沿将启动RISC_CPU开始工作,从ROM的000处开始读取指令并执行相应操作。波形图见8.3.1。虚线标志处为RISC_CPU启动工作的时刻。
8.3.2.总线读操作
RISC_CPU的复位和启动操作波形
187
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
每个指令周期的前0--3个时钟周期用于读指令,在状态控制器一节中已详细讲述,这里就不再重复。第3.5个周期处,存储器或端口地址就输出到地址总线上,第4--6个时钟周期,读信号rd有效,数据送到数据总线上,以备累加器锁存,或参与算术、逻辑运算。第7个时钟周期,读信号无效,第7.5个周期,地址总线输出PC地址,为下一个指令做好准备。
CPU从存储器或端口读取数据的时序
8.3.3写总线操作
每个指令周期的第3.5个时钟周期处,写的地址就建立了,第4个时钟周期输出数据,第5个时钟周期输出写信号。至第6个时钟结束,数据无效,第7.5时钟地址输出为PC地址,为下一个指令周期做好准备。
CPU对存储器或端口写数据的时序
8.4.RISC_CPU寻址方式和指令系统
RISC_CPU的指令格式一律为:
188
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0指令 地址
它的指令系统仅由8条指令组成。
1) HLT 停机操作。该操作将空一个指令周期,即8个时钟周期。 2) SKZ 为零跳过下一条语句。该操作先判断当前alu中的结果是否为零,若是零就跳过下
一条语句,否则继续执行。 3) ADD 相加。该操作将累加器中的值与地址所指的存储器或端口的数据相加,结果仍送回累
加器中。 4) AND 相与。该操作将累加器的值与地址所指的存储器或端口的数据相与,结果仍送回累加
器中。 5) XOR 异或。该操作将累加器的值与指令中给出地址的数据异或,结果仍送回累加器中。 6) LDA 读数据。该操作将指令中给出地址的数据放入累加器。 7) STO 写数据。该操作将累加器的数据放入指令中给出的地址。 8) JMP 无条件跳转语句。该操作将跳转至指令给出的目的地址,继续执行。
RISC_CPU是8位微处理器,一律采用直接寻址方式,即数据总是放在存储器中,寻址单元的地址由指令直接给出。这是最简单的寻址方式。
8.5. RISC_CPU模块的调试
8.5.1. RISC_CPU模块的前仿真
为了对所设计的RISC_CPU模型进行验证,需要把RISC_CPU包装在一个模块下,这样其内部连线就隐蔽起来,从系统的角度看就显得简洁,见图8.5.2。还需要建立一些必要的外围器件模型,例如储存程序用的ROM模型、储存数据用的RAM和地址译码器等。这些模型都可以用VerilogHDL描述,由于不需要综合成具体的电路只要保证功能和接口信号正确就能用于仿真。也就是说,用虚拟器件来代替真实的器件对所设计的RISC_CPU模型进行验证,检查各条指令是否执行正确,与外围电路的数据交换是否正常。这种模块是很容易编写的,上面8.2.9节中的ROM和RAM模块就是简化的虚拟器件的例子,可在下面的仿真中来代替真实的器件,用于验证RISC_CPU模型是否能正确地运行装入ROM和RAM的程序。在RISC_CPU的电路图上加上这些外围电路把有关的电路接通,见图8.5.1;也可以用VerilogHDL模块调用的方法把这些外围电路的模块连接上,这跟用真实的电路器件调试情况很类似,
189
第八章 可综合的Verilog HDL设计实例
----------------------------------------------------------------------------------------------------------------------
DATA<7..0> CLK CLK DATA<7..0> RST HALT ADDR<9..0> addr<9..0> data<7..0> HALT RST read RD RSC RD WR write WR ram ADDR<12..0> ADDR<12..0> ena addr<12..0> addr<12..0> ram_sel data<7..0> read addr_decode rom rom_sel ena RISC_CPU和它的外围电路
下面介绍的是在modelsim 5.4 下进行调试的仿真测试程序cputop.v。可用于对以上所设计的RISCCPU进行仿真测试,下面是前仿真的测试程序cputop.v。它的作用是按模块的要求执行仿真,并显示仿真的结果,测试模块cputop.v中的$display和$monitor等系统调用能在计算机的显示屏幕上显示部分测试结果,可以同时用波型观察器观察有关信号的波形。
`include \`include \
`include \`include \
`timescale 1ns / 100ps
`define PERIOD 100 // matches clk_gen.v module t;
reg reset_req,clock; integer test;
reg [(3*8):0] mnemonic; //array that holds 3 8-bit ASCII characters reg [12:0] PC_addr,IR_addr; wire [7:0] data; wire [12:0] addr;
wire rd,wr,halt,ram_sel,rom_sel;
//---------------------------------------------------------------------------- cpu t_cpu (.clk(clock),.reset(reset_req),.halt(halt),.rd(rd),
.wr(wr),.addr(addr),.data(data));
ram t_ram (.addr(addr[9:0]),.read(rd),.write(wr),.ena(ram_sel),.data(data));
rom t_rom (.addr(addr),.read(rd),.ena(rom_sel),.data(data));
190