1 fpga内部的存储器资源
FPGA内部有两种存储器资源,一种是BLOCK RAM,另一种是LUT查找表配置成的内部存储器,也就是分布式RAM。
2 时钟抖动 时钟偏斜
时钟抖动: jitter
由于晶振本身的稳定性,电源以及温度变化等原因造成了时钟频率的变化,相对于理想时钟产生的不随时间积累的,时而超前,时而滞后的偏移。 时钟周期在不同的周期上可能加长或缩短,它是一个平均值为0的平均变量。
时钟偏移:skew
指同样的时钟产生的多个子时钟信号之间的延时差异,skew时钟偏斜通常是时钟相位上的不确定。由于时钟域到达不同寄存器所经历路径的驱动和负载不同,时钟边沿的位置有所差异,因此带来了skew。
3 FPGA对时钟的使用
FPGA芯片有固定的时钟路由,这些路由可以减少时钟抖动和偏差。需要对时钟进行相位移动或者变频时候,一般不允许对时钟进行逻辑操作,这样不仅会增加时钟的偏差和抖动,还会使时钟带上毛刺。 一般的处理方法是采用FPGA芯片自带的时钟管理单元PLL、DLL,或者把逻辑转换为触发器的D输入。
4 查找表的原理和结构
查找表LUT,本质是一个RAM。目前FPGA中多使用4输入的LUT,每一个LUT可以看成4位地址线的16x1的RAM。当用户描述逻辑电路后,FPGA开发软件会自动计算逻辑电路的所有可能的结果,并把结果事先写入RAM,这样每输入一个信号进行逻辑运算就等于输入一个地址进行查表,找出地址对应的内容,然后输出即可。
自动饮料贩卖机
请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。
电路的接口如下图所示。sel信号会先于din信号有效,且在购买一种饮料时值不变。 sel为选择信号,用来选择购买饮料的种类,sel=0,表示购买A饮料,sel=1,表示购买B饮料; din表示投币输入,din=0表示未投币,din=1表示投币5元,
- din=2表示投币10元,不会出现din=3的情况;
- drinks_out表示饮料输出,drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,不出现drinks_out =3的情况,输出有效仅保持一个时钟周期;
- change_out表示找零输出,change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。
接口电路图如下:
经典三段式状态机,第一段采用同步时序描述状态转移。state<=next_state.第二段采用组合逻辑判断状态转移条件.第三段描述状态输出(这里采用时序电路输出)都可以case语句使用阻塞和非阻塞都行。
****mealy状态机的输出不仅与当前状态值有关,而且与当前输入有关。
moore状态机的输出仅与当前状态值有关,而与此时的输入无关
我们使用mealy型状态机 减少状态数
module sale(
input clk ,
input rst_n ,
input sel ,//sel=0,5$dranks,sel=1,10&=$drinks
input [1:0] din ,//din=1,input 5$,din=2,input 10$
output reg [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
output reg change_out
);
//两个状态,饮料机空闲和饮料机输出饮料B但只投了五块钱
//声明状态变量 使用mealy型状态机减少状态数
reg [1:0]state,next_state;
parameter IDLE = 2'b01,
S_Five = 2'b10;
always@(posedge clk or negedge rst_n)
if(!rst_n)
state <= IDLE;
else
state <= next_state;
always@(*)
case(state)
//空闲状态 ,只有在sel为1购买b饮料,且din=1只有5元挑战状态
IDLE:next_state = sel ? (din == 1 ? S_Five : IDLE) : IDLE;
//din =0 ,没钱,不跳转状态。有钱就可以跳转空闲,再做判断
S_Five: next_state = din==0?S_Five:IDLE;
default: next_state = IDLE;
endcase
always@(posedge clk or negedge rst_n)
if(!rst_n)
drinks_out <= 2'd0;
// sel为0表示购买A饮料5元,IDLE表示空闲状态。din=1为5元,din=2为10元
else if(!sel)begin
if((state == IDLE&&din==1) || (state==IDLE&&din==2))
drinks_out <= 2'd1;
else
drinks_out <= 2'd0;
end
// 购买B饮料需要10元
else begin
if((state == IDLE && din==2)||(state==S_Five&&din==1)||(state == S_Five&&din==2))
drinks_out <= 2'd2;
else
drinks_out <= 2'd0;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
change_out <= 1'b0;
//买A饮料输入10元 买B饮料在第二个状态再输入10元
else if((sel==1'b0&&state==IDLE &&din==2)||(sel&&state==S_Five&&din==2))
change_out <= 1'b1;
else
change_out <= 1'b0;
endmodule
```