一些Verilog的小东西
常用小模块
- 奇数次分频
module fdiv5(input clk,output k_or,k1,k2);
reg [2:0] c1,c2;
reg M1,M2;
always @ (posedge clk )
begin
if(c1 == 4) c1<=0 ; else c1<=c1+1;
if(c1 == 1) M1<=~M1; else if(c1 ==3) M1<=~M1;
end
always @ (negedge clk )
begin
if(c2 == 4) c2<=0; else c2 <=c2+1;
if(c2 == 1) M2<=~M2 ; else if (c2 == 3) M2<=~M2;
end
assign k1 = M1; assign k2=M2;
assign k_or = k1|k2;
endmodule
- 未完待续
状态机
这里给两种比较常见的写法
a.
module fsm(
input x,
input rst,
input clk,
output reg [1:0] y
);
parameter state_A = 3'd0 , state_B = 3'd1 ,
state_C = 3'd2 , state_D = 3'd3 ,
state_E = 3'd4 ;
reg [2:0] state;
always @(posedge clk or posedge rst)
begin
if(rst)
begin
state <= state_A;
y <= 2'b00;
end
else
case(state)
state_A : begin
if(!x) state <= state_B; else state <= state_C;
y <= 2'b00;
end
state_B : begin
if(!x) state <= state_D; else state <= state_C;
y <= 2'b00;
end
state_C : begin
if(!x) state <= state_E; else state <= state_B;
y <= 2'b00;
end
state_D : begin
if(!x) state <= state_D; else state <= state_C;
y <= 2'b01;
end
state_E : begin
if(!x) state <= state_B; else state <= state_E;
y <= 2'b10;
end
default : begin
state <= state_A; y <= 2'b00;
end
endcase
end
endmodule
b.
module fsm2(
input [3:0] row,
input srow,
input reset,
input clk,
output reg [3:0] col
);
parameter S0 = 3'd0 , S1 = 3'd1 ,
S2 = 3'd2 , S3 = 3'd3 ,
S4 = 3'd4 , S5 = 3'd5 ;
reg [3:0] current_state , next_state;
always @(posedge clk or posedge reset)
begin
if(reset)
current_state <= S0;
else
current_state <= next_state;
end
always @(*)
begin
case(current_state)
S0:begin
next_state = (srow==1'b1) ? S1 : S0;
col = 4'd15;
end
S1:begin
next_state = (row==4'd0) ? S2 : S5;
col = 4'd1;
end
S2:begin
next_state =(row==4'd0) ? S3 : S5;
col = 4'd2;
end
S3:begin
next_state = (row==4'd0) ? S4 : S5;
col = 4'd3;
end
S4:begin
next_state = (row==4'd0) ? S0 : S5;
col = 4'd4;
end
S5:begin
next_state = S5;
col = 4'd5;
end
endcase
end
endmodule
懂的人自然都懂.建议用quartus写,然后看看RTL会贴心地给出状态描述图
仿真的 $display $monitor $strobe的区别
-
$display
相当于c语言的printf,一旦程序触发到就立即显示 -
$monitor
一直以一个格式在追踪某几个变量或者表达式的变化
一个程序里面只能有一个monitor在跑
- $strobe
用于观察非阻塞赋值,在所在的always块结束后才会改变
task 和function的区别
这里也是给上一个功能一样,但是分别用task和function实现的代码
- task_test
module task_test(data_in,data_out);
output reg [3:0] data_out;
input [3:0] data_in;
task BCD2Access3;
output [3:0] data_out;
input [3:0] data_in;
data_out = data_in + 4'd3;
endtask
always @(data_in)
begin
if(data_in >= 4'd10) data_out = 4'b0000;
else BCD2Access3(data_out,data_in);
end
endmodule
- function_test
module function_test(data_in,data_out);
output reg [3:0] data_out;
input [3:0] data_in;
function BCD2Access3;
input [3:0] data_in;
BCD2Access3 = data_in + 4'd3;
endfunction
always @(data_in)
begin
if(data_in >= 4'd10) data_out = 4'b0000;
else data_out = BCD2Access3(data_in);
end
endmodule
务必要注意两点:
1. task可以有很多输入输出,但是例化的顺序和task里面写的input,output顺序是一致的,不能搞反
2. function虽说看起来很C语言,但是要注意返回值就是他的名字(,剩下的都是输入
结语
先用来应付一下考查课,顺便查漏补缺一下自己的Verilog基础
距离 频率计发布到现在才4个月,最近博客的阅读量又翻了翻…但是如果csdn再不对verilog进行markdown支持的话,就搬迁到简书了,谢谢大家