一、Combinational logic
Gates
out_anotb a与b非
Truthtable1
Gatesv100
用assign实现两个向量逐位对比:
assign out_both = in[98:0]&in[99:1];
也要注意向量拼接后和前面运算的向量长度是否相同
Mux256to1v
assign out = in[2*sel+3:2*sel];verilog中这样的写法是错误的 ,verilog中要求向量下标可以是变量,但是位宽必须是常量,而上式无法证明位宽是常量。assign out = in[sel]是对的。
cin是前一轮的进位 cout是下一轮的进位
assign sum = a^b^cin;
assign cout = a&b|a&cin|b&cin;
Adder3
全加器实例化法1
genvar i;
generate
for(i=0;i<3;i=i+1)
begin:add
if(i==0)
begin//不加要出现begin对应错误
assign sum[0]=a[0]^b[0]^cin;
assign cout[0]=a[0]&b[0]|a[0]&cin|b[0]&cin;
end
else
begin
assign sum[i]=a[i]^b[i]^cout[i-1];
assign cout[i]=a[i]&b[i]|a[i]&cout[i-1]|b[i]&cout[i-1];
end
end
endgenerate
signed addition overflow
溢出:当两个正数相加产生负结果或两个负数相加产生正结果时,会发生有符号溢出。有几种检测溢出的方法:可以通过比较输入和输出数的符号来计算,或者从位 n 和 n-1 的进位推导出
assign overflow = (a[7]^s[7])&(b[7]^s[7]);
assign overflow = (a[7]&b[7]&~s[7])|(~a[7]&~b[7]&s[7])
Kmap2
卡曼图解法
二、Sequential Logic
Detect an edge(上升沿检测)
输入信号din和打一拍(寄存器寄存延迟一个时钟周期输出)信号进行组合逻辑运算来获得边沿检测
assign up_edge = ~din_r & din;//上边沿
assign down_edge = din_r & ~din;//下边沿
assign both_edge = din_r ^ din;//双边沿
要实现边沿检测,最直接的想法是用两级寄存器,第二级寄存器锁存住某个时钟上升沿到来时的输入电平,第一级寄存器锁存住下一个时钟沿到来时的输入电平,如果这两个寄存器锁存住的电平信号不同,就说明检测到了边沿,具体是上升沿还是下降沿可以通过组合逻辑来实现。
module top_module (
input clk,
input [7:0] in,
output [7:0] pedge
);
reg [7:0]in_d;
always@(posedge clk)
begin
in_d<=in;
pedge <= ~in_d∈
end
endmodule
Edge capture register
边沿检测后还要维持的话
reg [31:0]one;
always@(posedge clk)
begin
one<=in;//in_delay要在刚开始就进行 否则和赋值语句同步执行就没有delay效果了
if(reset)
begin
out <= 32'b0;
end
else
// one<=in;
out<=one&~in|out;//不光下降沿判断 判断完还保存
end
Dualedge
非阻塞赋值只能用于寄存器型变量,只能在initial块和always块中使用。阻塞赋值既可以用于寄存器型变量,也可以用于线网型变量
所以块外的assign语句要用阻塞赋值 他没有时序逻辑是组合逻辑
Counter1-12
设计一个1-12的计数器,有以下输入和输出:
Reset同步active-high复位,强制计数器到1
Enable设置high,计数器运行Clk正向边缘触发时钟输入
Q[3:0]计数器的输出
c_enable, c_load, c_d[3:0]控制信号到达提供的4位计数器,因此可以验证正确的操作。
您有以下可用的组件:
下面的4位二进制计数器(count4),它具有Enable和同步并行负载输入(load优先级高于Enable)。count4模块提供给您。在你的电路中实例化它
module top_module (
input clk,
input reset,
input enable,
output [3:0] Q,
output c_enable,
output c_load,
output [3:0] c_d
); //
assign c_enable=enable;
assign c_load=reset|((enable==1)&&(Q==4'd12));//等待
assign c_d=(c_load)?4'd1:4'd0;//计数器 复位和记到12强制为1
count4 the_counter (clk, c_enable, c_load, c_d ,Q);
endmodule
Counter 1000
从 1000 Hz 时钟导出一个称为OneHertz的 1 Hz 信号,该信号可用于驱动一组小时/分钟/秒计数器的启用信号,以创建数字挂钟。由于我们希望时钟每秒计数一次,因此OneHertz信号必须每秒准确地断言一个周期。使用模 10 (BCD) 计数器和尽可能少的其他门构建分频器。还要从您使用的每个 BCD 计数器输出使能信号(c_enable[0] 为最快的计数器,c_enable[2] 为最慢的)。为您提供以下 BCD 计数器。Enable必须为高电平才能使计数器运行。复位是同步的并设置为高以强制计数器为零。电路中的所有计数器必须直接使用相同的 1000 Hz 信号。
这题提供的是一个1000hz的时钟 我们要转化成1hz时钟的话 只有1000hz运行一个周期才能得到一个1hz,所以我们要让三个bcd分别代表个位十位百位 每位均取9得到999让onehertz输出为1
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
);
wire [3:0]one,ten,hundred;
assign OneHertz=(one==4'd9&&ten==4'd9&&hundred==4'd9);
assign c_enable={one==4'd9&&ten==4'd9,one==4'd9,1'd1};
bcdcount bcdcount_one (clk, reset, c_enable[0],one);
bcdcount bcdcount_ten (clk, reset, c_enable[1],ten);
bcdcount bcdcount_hun(clk, reset, c_enable[2],hundred);
endmodule
Countbcd
构建一个 4 位 BCD(二进制编码的十进制)计数器。每个十进制数字使用 4 位编码:q[3:0] 是个位,q[7:4] 是十位等。对于数字 [3:1],还输出一个使能信号,指示个位,十位,百位何时应加1。
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
assign ena[1]=(q[3:0]==4'b1001);//只在进位时候取一 一般都置0
assign ena[2]=(q[3:0]==4'b1001&&q[7:4]==4'b1001);
assign ena[3]=(q[3:0]==4'b1001&&q[7:4]==4'b1001&&q[11:8]==4'b1001);
BCD_count one(clk,1'd1,reset,q[3:0]);
BCD_count ten(clk,ena[1],reset,q[7:4]);
BCD_count hur(clk,ena[2],reset,q[11:8]);
BCD_count tho(clk,ena[3],reset,q[15:12]);
endmodule
module BCD_count(
input clk,
input enable,
input reset,
output [3:0]Q
//output c_enable
);
always@(posedge clk)
begin
if(reset)
begin
Q<=4'b0;
end
else if(Q==4'b1001&&enable==1)//要即等于9又有ena信号才能置0,否则高位一等于9就置0没办法保持一个计数周期
begin
Q<=4'b0;
end
else if(enable)
begin
Q<=Q+4'b0001;
end
end
endmodule
三、Shift Registers
32-bit LFSR
Build a 32-bit Galois LFSR with taps at bit positions 32, 22, 2, and 1
右移:>>
哪位有抽头就异或他和p[0]
Shift register
置0要把每一个过度变量都置0,要不然过几个周期不为0的输出了会出错
Shift register
创建一个模块然后引用
module MUXDFF (
input clk,
input E,
input L,
input W,
input R,
output q);
wire a;
always@(posedge clk)
begin
a=(E)?W:q;//阻塞赋值
q=(L)?R:a;
// q <= (L)?R:((E)?W:q);
end
endmodule
这里要用阻塞赋值 因为如果非阻塞的话 这里的q取得是上个时钟的a 不是刚才更新的a
3-input LUT
module top_module (
input clk,
input enable,
input S,
input A, B, C,
output Z );
reg [7:0]q;
always@(posedge clk)
begin
if(enable)
begin
q<={{q[6:0]},S};//q[0]为S 前面为移位寄存器一步一步移位,即为q的0-6位
end
else
q<=q;
end
assign Z=q[{A,B,C}];//可以不写case直接这么写
endmodule
四、More Circuits
Rule 90
一次一次异或的原理
always @(posedge clk)
begin
if(load)begin
q <= data;
end
else begin
q <= {1'b0,q[511:1]}^{q[510:0],1'b0};//补齐最高位和最低位
end
五、Finite State Machines
Fsm1
状态机:
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:
第一类,若输出只和状态有关而与输入无关,则称为Moore状态机
第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机
原文链接:https://blog.csdn.net/m0_67839421/article/details/127217631
parameter A=0, B=1;
reg state, next_state;
always @(*) begin // This is a combinational always block 描述状态寄存器
case(in)
1: next_state<=state;
0:next_state<=(state)?A:B;
endcase
end
always @(posedge clk, posedge areset) begin // This is a sequential always block组合逻辑输出
if(areset)
state<=B;
else
state<=next_state;
end
// Output logic
assign out = (state == B);//通过逻辑判断输出
最后使用组合逻辑对结果进行判断,但组合逻辑容易产生毛刺等不稳定因素。
Simple one-hot state transitions 3
独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。通常,在通信网络协议栈中,使用八位或者十六位状态的独热码,且系统占用其中一个状态码,余下的可以供用户使用。
例如,有6个状态的独热码状态编码为:000001,000010,000100,001000,010000,100000。
parameter A=0, B=1, C=2, D=3;
assign next_state[A] = (state[A]&~in)|(state[C]&~in);
assign next_state[B] = (state[A]&in)|(state[B]&in)|(state[D]&in);
assign next_state[C] = (state[B]&~in)|(state[D]&~in);
assign next_state[D] = (state[C]&in);
assign out = (state[D]);
Simple FSM 3
和上一个对比着看吧
parameter A=0,B=1,C=2,D=3;
reg[1:0] state,next_state;
always@(*)
begin
case(state)
A:next_state = (in)?B:A;
B:next_state = (in)?B:C;
C:next_state = (in)?D:A;
D:next_state = (in)?B:C;
endcase
end
// State transition logic
always@(posedge clk or posedge areset)
begin
if(areset)
state<=A;
else state<=next_state;
end
// State flip-flops with asynchronous reset
assign out = (state==D);
// Output logic
Lemmings1
parameter LEFT=0, RIGHT=1;
reg state, next_state;
always @(*) begin
// State transition logic
case(state)//判断变化没有 没有就维持原样 刚开始if的写法没有维持原样
LEFT:next_state<=bump_left?RIGHT:LEFT;
RIGHT:next_state<=bump_right?LEFT:RIGHT;
endcase
end
always @(posedge clk, posedge areset) begin
// State flip-flops with asynchronous reset
if(areset)
begin
state<=LEFT;
end
else
state<=next_state;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
Lemmings2
增加两个状态 往左走掉下去和往右走时候掉下去
parameter LEFT=2'b00,RIGHT=2'b01,fallr=2'b11,falll=2'b10;
reg [1:0]state,next_state;
always@(*)
begin
case(state)
LEFT:
begin
if(ground)
begin
next_state<=bump_left?RIGHT:LEFT;
end
else
begin
next_state<=falll;
end
end
RIGHT:
begin
if(ground)
begin
next_state<=bump_right?LEFT:RIGHT;
end
else
begin
next_state<=fallr;
end
end
falll:
if(!ground)
begin
next_state<=falll;
end
else
begin
next_state<=LEFT;
end
fallr:
if(!ground)
begin
next_state<=fallr;
end
else
begin
next_state<=RIGHT;
end
endcase
end
always@(posedge clk,posedge areset)
begin
if(areset)
begin
state<=LEFT;
end
else
begin
state<=next_state;
end
end
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
assign aaah=(state==fallr)|(state==falll);
Lemmings3
digl://dig优先级高于转向 开始挖了就一直挖直到地塌陷
begin
if(!ground)
begin
next_state<=falll;
end
/* else if(dig)
begin
next_state<=digl;
end*/
else
begin
next_state<=digl;
end
end
digr:
begin
if(!ground)
begin
next_state<=fallr;
end
else
begin
next_state<=digr;
end
/* else
begin
next_state<=right;
end*/
end
one-hot FSM
题目会给非onehot编码来验证 所以他希望用状态机来写不是case的default归于一个值
Serial receiver
always@(*)begin
case(state)//增加一个等待和初始状态 等到信号开始start
start:next_state<=one;
one:next_state<=two;
two:next_state<=thr;
thr:next_state<=fou;
fou:next_state<=fiv;
fiv:next_state<=six;
six:next_state<=sev;
sev:next_state<=eig;
eig:begin
if(in)
next_state<=stop;
else
next_state<=waitt;
end
stop:begin
if(in)
next_state<=fir;
else
next_state<=start;
end
waitt:begin
if(in)
next_state<=fir;
else
next_state<=waitt;
end
fir:begin
if(!in)
next_state<=start;
else
next_state<=fir;
end
endcase
Iteration limit 5000 reached at time 0 ps
出现这个错误的原因是:代码中的组合逻辑存在回环,也就是说对敏感列表中的变量进行赋值,造成回环,在仿真的时候modelsim对电路中的回环不断迭代,直到超出了迭代界限。
方法:修改代码中的组合逻辑,注意不要对敏感列表中的变量赋值,或者将组合逻辑写成时序逻辑。modelsim error:iteration limit reached at time xxx ns._薛定谔的bug~的博客-CSDN博客
Serial receiver and datapath
这边的第一个有效位指的是start而不是d1,再done的时候输出整个序列
Serial receiver with pariting checking
不太懂为什么 暂存问题
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter start=4'd0,D1=4'd1,D2=4'd2,D3=4'd3,D4=4'd4,D5=4'd5,D6=4'd6,D7=4'd7,D8=4'd8,stop=4'd9,idle=4'd10,WAIT=4'd11,par=4'd12;
reg [4:0] state,next_state;
reg [7:0] temp_in;
wire odd;
//wire[3:0]count=4'd0;
always @(*)
begin
case(state)
start: begin next_state = D1; temp_in[0] = in; end
D1: begin next_state = D2; temp_in[1] = in; end
D2: begin next_state = D3; temp_in[2] = in; end
D3: begin next_state = D4; temp_in[3] = in; end
D4: begin next_state = D5; temp_in[4] = in; end
D5: begin next_state = D6; temp_in[5] = in; end
D6: begin next_state = D7; temp_in[6] = in; end
D7: begin next_state = D8; temp_in[7] = in; end
D8:begin
if(in)
next_state = par;
else
next_state = WAIT;
end
par:begin
if(in)
next_state = stop;
else
next_state = WAIT;
end
stop:begin
if(in)
next_state = idle;
else
next_state = start;
end
idle:begin
if(in)
next_state = idle;
else
next_state = start;
end
WAIT:begin
if(in)
next_state = idle;
else
next_state = WAIT;
end
default:next_state = idle;
endcase
end
always@(posedge clk)begin
if(reset)
state<=idle;
else
state<=next_state;
end
always@(posedge clk)begin
if(reset)
done<=1'd0;
else if((next_state == stop)&&(odd==1))
done<=1'd1;
else
done<=1'd0;
end
always@(posedge clk)begin
if(reset)
out_byte<=8'b0;
else if((next_state == stop)&&(odd==1))
out_byte<=temp_in;
else
out_byte<=8'b0;
end
//assign done = (next_state == stop)&&(odd==1);
// assign out_byte = done?temp_in:8'b0;
wire reseta;
assign reseta=(reset==1)||(next_state==start);
parity one(clk,reseta,in,odd);
endmodule
Design a Mealy FSM
错误提示:Error (10200): Verilog HDL Conditional Statement error at ……: cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct
这是因为,“always@(posedge clk or negedge r_est)”表明在clk上升沿或r_est下降沿这两个敏感事件发生时always语句块得以触发;而always中的if条件语句必须至少有一个条件指向其中一个敏感事件(边界标识符);所以写成“if(r_est)...else...”就会出错。
把“always@(posedge clk or negedge r_est)”改为“always@(posedge clk or posedge r_est)”再编译试试,就没问题了。
两种状态机:
1:输出只和当前状态有关而与输入无关,则称为摩尔(Moore)状态机;
2:输出不仅和当前状态有关而且和输入有关,则称为米利(Mealy)状态机;
always@(*)begin
case(state)
s1:begin
next_state<=x?s2:s1;
end
s2:begin
next_state<=x?s2:s3;//如果s2不为0不回初始状态而是等下一个0
end
s3:begin
next_state<=x?s2:s1;//s3是1的话就回s2等下一个1
end
default:next_state<=s1;
endcase
end
补码:计算数N的补码,所要做的就是将X的每一位取反,然后将取反结果加1 Q3a:FSM
parameter A=0,B=1;
reg [1:0]tcount,wcount;//搭配两个计数器 一个计有几个一 一个计时钟012012循环
reg[1:0]state,next_state;
always@(*)begin
case(state)
A:next_state<=s?B:A;
B:next_state<=B;
default:next_state<=A;
endcase
end
always@(posedge clk)begin
if(reset)
state<=A;
else
state<=next_state;
end
always@(posedge clk)begin
if(reset)
tcount<=2'd0;
else if(state==B)begin
if(tcount==2'd2)
begin
tcount<=2'd0;
end
else
tcount<=tcount+1;
end
else
begin
tcount<=2'd0;
end
end
always@(posedge clk)begin
if(reset)
wcount<=2'd0;
else if(state==B)begin
if(tcount==2'd0)begin
wcount<=w?2'd1:2'd0;
end
else if(w==1)begin
wcount<=wcount+1;
end
else
wcount<=wcount;
end
else
wcount<=2'd0;
end
always@(*)begin
case(state)
A:z<=0;
B:z<=(tcount==2'd0)&&(wcount==2'd2);//一个周期结束并且计数到两个
endcase
end
Q6c:FSM one-hot next-state log
假设您触发器和hot码显示此 FSM 的状态分配表。导出触发器y[2]和y[4]的下一个状态表达式。
parameter A=3'd1,B=3'd2,C=3'd3,D=3'd4,E=3'd5,F=3'd6;
reg[6:0]next_state;
always@(*)begin
case(y)
A:next_state<=w?A:B;
B:next_state<=w?D:C;
C:next_state<=w?D:E;
D:next_state<=w?A:F;
E:next_state<=w?D:E;
F:next_state<=w?D:C;
endcase
end
assign Y2=~w&y[A];
assign Y4=w&(y[B]|y[C]|y[E]|y[F]);//用当前状态写下一个状态
Q2b:Another FSM
parameter A=4'd0,B=4'd1,C=4'd2,D=4'd3,E=4'd4,F=4'd5,FONE=4'd6,FZERO=4'd7,G=4'd8;
reg[3:0]state,next_state;
always@(*)begin
case(state)
A:next_state<=B;
B:next_state<=C;
C:next_state<=x?D:C;
D:next_state<=x?D:E;
E:next_state<=x?F:C;
F:next_state<=y?FONE:G;
G:next_state<=y?FONE:FZERO;
FONE:next_state<=FONE;
FZERO:next_state<=FZERO;
default:next_state<=A;
endcase
end
always@(posedge clk)begin
if(!resetn)
state<=A;
else
state<=next_state;
end
assign f=(state==B);
assign g=(state==F)||(state==G)||(state==FONE);