第四章 RTL概念与RTL建模 安排常用的设计实例,对RTL建模有感性的认识
第五章 重点讨论RTL级的编码风格和各种设计原则
第六章 讨论RTL级设计的FSM(有限状态机)的描述技巧
主要内容如下:
RTL与综合的概念
RTL级设计的基本要素和步骤
常用的RTL级建模
实例
1.HDL语言的层次:
系统级(system level)
功能模块级(function model level)
行为级(behavior level)
寄存器传输级(RTL,Register Transfer Level)
门级(Gate Level)
2.RTL级概念:
不关注寄存器和组合逻辑的细节,
通过描述寄存器到寄存器之间的逻辑功能描述电路的HDL层次。
3.RTL级综合:
将RTL级源代码翻译并优化为门级网表
在可编程器件(PLD,主要是指FPGA和CPLD)设计领域,最重要的设计层次就是RTL级
1.典型的RTL级设计包含三部分:
时钟域描述
时序逻辑描述(寄存器描述):
根据时钟沿的变换,描述寄存器之间的数据传输方式
组合逻辑描述:
描述电平敏感信号的逻辑组合方式和逻辑功能
2.全局时钟资源的特点是几乎没有Clock Skew(时钟偏斜),有一定的Clock Delay(时钟延时);
第二全局时钟资源的特点是具有娇羞奥的Clock Skew和Clock Delay,时钟驱动能力较强。
设置异步复位信号“reset_”为低有效信号(下降沿开始复位):
reg [3:0] cnt_reg;
always @ (posedge clock or negedge reset_)
if ( !reset_ )
cnt_reg<= 4'b0000;
else
begin
......
end
always的敏感列表中仅有时钟沿信号,仅当时钟沿猜到同步复位的有效电平时,才会在时钟沿到达时刻进行复位/置位的操作。
reg [3:0] cnt_reg;
always @ (posedge clock)
if(!reset_)
cnt_reg <= 4'b0000;
else
begin
......
end
在时钟的上升沿和下降沿到达时,对寄存器电路都进行相应的操作。这个双沿电路相当于使用了原时钟的倍频时钟的单沿操作电路。在PLD设计中,不推荐使用该方式。
always模块的敏感表为电平敏感信号的电路
使用阻塞赋值“=”,因为最后实现的不是寄存器使用阻塞赋值“=”,因为最后实现的不是寄存器
2.assign等关键字描述的组合逻辑电路
用于表示相对简单的电路,信号一般被定义为wire型
除了直接赋值外,还可以使用? 语句
举例:利用?表达式描述一个2选1的Mux
wire mux_out;
assign mux_out=(en)?a:b;
举例:利用case描述一个4选1的Mux
reg mux_out;
always @(en or a or bor c or d)
case(en)
2'b00: mux_out = a;
2'b01: mux_out = b;
2'b10: mux_out = c;
2'b11: mux_out = d;
endcase
定义一个数据位宽为 8 bit,地址为 63 位的RAM8x64:
reg [7:0] RAM8x64 [0:63]
使用存储单元时,不能直接引用存储器某地址的某比特位值
正确的操作为,现将存储单元赋值给某个寄存器,然后对寄存器的某位进行操作
举例:将 8 bit 位宽,64 位地址RAM的读写电路,在读的时候,先将RAM某地址的数据读到“mem_data”寄存器中,然后即可对寄存器的任意bit位进行相关操作:
reg [7:0] RAM8x64 [0:63];
reg [7:0] mem_data;
always @(posedge clk)
if(WR&&CS) // WRite
RAM8x64[addr] <= data_in [7:0];
else if(~WR&&CS) // read
mem_data <= RAM8x64 [addr];
对PLD设计而言,大多数FPGA都有内嵌的RAM资源,所以不推荐使用Verilog直接建模RAM。
FPGA内嵌的RAM资源大致分为两类:
没有内嵌PLL/DLL的时钟电路中,或内嵌的资源不能满足时钟关系的处理方式:(PLD的主要时钟处理为分频和移相)
例:对200kHZ的时钟做2分频,4分频,8分频,要求分频之后的时钟同相。
一般PLD内嵌的PLL的输入频率下限都在MHz级,因此无法使用PLL完成分频和相位调整要求。
对于低速时钟的分频,一般使用计数器。
reg [2:0] cnt;
always @ (posedge clk_200K or negedge rst)
if(!rst)
cnt <= 3'b000;
else
cnt <= cnt + 1;
assign clk_100K = ~cnt [0];//直接偶数分频后的相位与原相位相反
assign clk_50K = ~cnt [1];
assign clk_25K = ~cnt [2];
例:对源时钟做3分频,要求3分频时钟占空比为50%。
reg [1:0] state;
reg clk1;
always @(posedge clk or negedge reset)
if(!reset)
state <= 2'b00;
else
case(state)
2'b00 : state <= 2'b01;
2'b01 : state <= 2'b11;
2'b11 : state <= 2'b00;
default : state <= 2'b00;
endcase
always @(negedge clk or negedge restt)
if(!reset)
clk1 <= 1'b0;
else
clk1 <= state[0];
assign clk_out = state[0] & clk1;
见4-21的syn_wr包:
top.v
module top (clk_cpu, rst, CS_, OE_, WR_, Addr, data_bus);
input clk_cpu, rst;
input CS_, OE_, WR_;
input [7:0] Addr;
inout [7:0] data_bus;
wire [7:0] data_in;
wire [7:0] data_out;
wire my_wr, my_rd;
wire CS_reg1, CS_reg2, CS_reg3; // the register selection
wire [7:0] reg1, reg2, reg3; // the register to be read and written
assign data_in = data_bus;
decode decode_u1 (.CS_(CS_),
.OE_(OE_),
.WR_(WR_),
.Addr(Addr),
.my_wr(my_wr),
.my_rd(my_rd),
.CS_reg1(CS_reg1),
.CS_reg2(CS_reg2),
.CS_reg3(CS_reg3)
);
write_reg write_reg_u1 ( .clk(clk_cpu),
.rst(rst),
.data_in(data_in),
.my_wr(my_wr),
.CS_reg1(CS_reg1),
.CS_reg2(CS_reg2),
.CS_reg3(CS_reg3),
.reg1(reg1),
.reg2(reg2),
.reg3(reg3)
);
read_reg read_reg_u1 ( .clk(clk_cpu),
.rst(rst),
.data_out(data_out),
.my_rd(my_rd),
.CS_reg1(CS_reg1),
.CS_reg2(CS_reg2),
.CS_reg3(CS_reg3),
.reg1(reg1),
.reg2(reg2),
.reg3(reg3)
);
assign data_bus = ((!CS_) && (!OE_))? data_out : 8'bZZZZZZZZ;
endmodule
decode:译码电路
module decode (CS_, OE_, WR_, Addr, my_wr, my_rd, CS_reg1, CS_reg2, CS_reg3);
input CS_, OE_, WR_;
input [7:0] Addr;
output my_wr, my_rd;
output CS_reg1, CS_reg2, CS_reg3;
reg CS_reg1, CS_reg2, CS_reg3;
assign my_wr = (!WR_) && (!CS_) && (!OE_);
assign my_rd = (WR_) && (!CS_) && (!OE_);
always @ (Addr or CS_)
if (!CS_)
begin
case (Addr)
8'b 11110000: CS_reg1 <= 1'b1;
8'b 00001111: CS_reg2 <= 1'b1;
8'b 10100010: CS_reg3 <= 1'b1;
default: begin
CS_reg1 <= 1'b0;
CS_reg2 <= 1'b0;
CS_reg3 <= 1'b0;
end
endcase
end
endmodule
write_reg: 写寄存器
module read_reg (clk, rst, data_out, my_rd, CS_reg1, CS_reg2, CS_reg3, reg1, reg2, reg3);
input clk, rst, my_rd, CS_reg1, CS_reg2, CS_reg3;
input [7:0] reg1, reg2, reg3;
output [7:0] data_out;
reg [7:0] data_out;
always @ (posedge clk or negedge rst)
if (!rst)
data_out <= 8'b0;
else
begin
if (my_rd)
begin
if (CS_reg1)
data_out <= reg1;
else if (CS_reg2)
data_out <= reg2;
else if (CS_reg3)
data_out <= reg3;
end
else
data_out <= 8'b0;
end
endmodule
write_reg: 写寄存器
module write_reg (clk, rst, data_in, my_wr, CS_reg1, CS_reg2, CS_reg3, reg1, reg2, reg3);
input clk, rst, my_wr, CS_reg1, CS_reg2, CS_reg3;
input [7:0] data_in;
output [7:0] reg1, reg2, reg3;
reg [7:0] reg1, reg2, reg3;
always @ (posedge clk or negedge rst)
if (!rst)
begin
reg1 <= 8'b0;
reg2 <= 8'b0;
reg3 <= 8'b0;
end
else
begin
if (my_wr)
begin
if (CS_reg1)
reg1 <= data_in;
else if (CS_reg2)
reg2 <= data_in;
else if (CS_reg3)
reg3 <= data_in;
end
else
begin
reg1 <= reg1;
reg2 <= reg2;
reg3 <= reg3;
end
end
endmodule