1. 一个16位信号in包含四个四位数[3:0]a[3:0]b[3:0]c[3:0]d,将它们顺序倒置为dcba输出,输出out
module top_module(
input in,
output out
);
assign out = {in[3:0],in[7:4],in[11:8],in[15:12]};
endmodule
module top_module(
input in,
output out
);
wire [3:0]a,b,c,d;
assign {a,b,c,d}=in;
assign out = {d,c,b,a};
endmodule
以 上写法适用于in位数较少的时候,当in位数较多时需要考虑用到generate...for语句。
当同一模块需要多次例化,或同一赋值语句需要多次执行时使用。
genvar i;
generater
for(i=0;i<10;i=i+1)begin
out[15-i]=in[i];
end
endgenerate
(A)generate-for循环必须使用genvar关键字定义循环变量;
(B)generate-for循环中的内容必须使用begin-end包括起来,哪怕只有一句;
(C)generate-for循环begin后的名字不可以省略;
(D)generate-for循环同一个模块内的begin-end块名字不能一样。
module top_module(
input [15:0] in,
output [15:0] out
);
genvar i;
generate
for(i=0;i<4;i=i+1)begin
assign out[4*(3-i)+3:4*(3-i)]=in[4*i+3:4*i];
end
endgenerate
向量的部分选择:
2. 用verilog实现两个串联的异步复位的T触发器的逻辑,结构如图:
T ff:输入是1 输出取反(在上一个ff时); 输入是0,输出保持
图中是两个T FF,可以一级一级写。
module tolp_module(
input clk,
input rst,
input data,
output q
);
reg q1;
always@(posedge clk or negedge rst)
if(!rst)
q1 <= 1'b0;
else
if(data)
q1<=~q1;
else
q1<=q1;
always@(posedge clk or negedge rst)
if(!rst)
q <= 1'b0;
else
if(q1)
q<=~q;
else
q<=q;
3.现在需要对输入的32位数据进行奇偶校验,根据sel输出校验结果(1输出奇校验,0输出偶校验)
单目运算符:
假设d=3'b100;
则
①e=&d 检测全为1(是否含0)
②f=^d 奇偶校验 (检测1的个数是奇数还是偶数,奇数个1 结果为1 偶数个1 结果为0)
③g=|d 检测全为0(是否含1)
使用异或就可以完成奇偶校验
module top_module(
input [31:0] bus,
input sel,
input clk,
output check
);
wire bus_tmp;
assign bus_tmp = ^bus;
assign check = sel ? bus_tmp: ~bus_tmp;
4. 已知d为一个8位数,请在每个时钟周期分别输出该数乘1/3/7/8,并输出一个信号通知此时刻输入的d有效(d给出的信号的上升沿表示写入有效)
输入在6的时候很特殊,只持续了一个时钟周期,但是out 给6乘1、3、7、8需要四个时钟周期,说明不能利用d的实时变化去算out的实时变化,所以在第一个input_grant的时候把d寄存起来。就可以利用计数器 作为FSM,cnt=0 d*1;...cnt=1 d*3...
module top_module(
input clk,
input rst,
input [7:0] d,
output input_grant,
output [10:0] out
);
reg [1:0] count;
always@(posedge clk or negedge rst)
if(~rst)
count <= 2'b0;
else
count <= count;
always@(posedge clk or negedge rst)
if(~rst)begin
input_grant <= 1'b0;
out<= 'd0;
d_reg <= 'd0;
end
else begin
case(count)
2'b00:begin
input_grant <= 1'b1;
d_reg <= d;
out <= d;
end
2'b01:begin
input_grant <= 1'b0;
out <= d_reg + {d_reg,1'b0};
end
2'b00:begin
input_grant <= 1'b=;
out <= d_reg + {d_reg,1'b0} + {d_reg,2'b0};
end
2'b00:begin
input_grant <= 1'b0;
out <= {d_reg,3'b0};
end
end
移位运算与乘法
移位运算符<< >> 移位可以实现乘法,和 无符号数的除法,有符号数的除法就不行了!!
<<低位补零 乘法
>> 无符号数除法
假设d=4'b1110;(-6)
f=d>>1 = 3'b0111(6) (高位补零 错 负数成了正数)
可以使用位拼接!!!
对于乘法来说,都是在低位补零,不需要考虑符号位;
如果是有符号除法,需要在最前面补符号位
5. 在数字芯片设计中,经常把实现特定功能的模块编写成函数,在需要的时候再在主模块中调用,以提高代码的复用性和提高设计的层次,分别后续的修改。
请用函数实现一个4bit数据大小端转换的功能。实现对两个不同的输入分别转换并输出
`timescale 1ns/1ns
module function_mod(
input clk,
input rst_n,
input [3:0]a,
input [3:0]b,
output [3:0]c,
output [3:0]d
);
function [3:0] begin_end; //输出
input [3:0] data_in;
begin
begin_end[0] = data_in[3];
begin_end[1] = data_in[2];
begin_end[2] = data_in[1];
begin_end[3] = data_in[0];
end
endfunction
assign c = begin_end(a); //函数调用
assign d = begin_end(b);
endmodule
在Verilog HDL中,函数的声明由关键字function开始,endfunction结束。对于函数中的语句需要用begin…end包含,即使只有一句。函数的声明模板如下:
function [range-1:0] function_name ;
input_declaration ;
other_declaration ;
begin
procedural_statement ;
end
endfunction
函数只能描述组合逻辑,函数必须有一个返回值