HDLbits一刷还愿,记录一些有价值的内容。
一、例化数组(举例说明)
- 对于模块:
module add1(
input a,
input b,
output out
);
assign out = a + b;
endmodule
- 除使用
generate/endgenerate
+for循环方式对重复例化模块进行赋值操作外:
module top(
input [1:0]a,
input [1:0]b,
output [1:0]out
);
genvar i;
generate
for(i = 0;i <= 1;i = i + 1)begin:uut1
add1 uut2(.a(a[i]),.b(b[i]),.out(out[i]));
//add1 uut2(a[i],b[i],out[i]);//必须按照模块端口定义顺序连接
end
endgenerate
endmodule
- 还可以使用例化数组的方法:
module top(
input [1:0]a,
input [1:0]b,
output [1:0]out
);
add1 uut[1:0](.a(a),.b(b),.out(out));
endmodule
其中uut[0]代表第一个例化,对应连接a[0]、b[0]、out[0],依次类推。
二、casez(举例说明)
- casez的匹配是
从上向下
匹配的,不关心的位可以设置为z
以减少代码量(下面代码功能和多级if/else类似)。
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*)begin
casez(in)
8'bzzzzzzz1: pos <= 3'd0;
8'bzzzzzz10: pos <= 3'd1;
8'bzzzzz100: pos <= 3'd2;
8'bzzzz1000: pos <= 3'd3;
8'bzzz10000: pos <= 3'd4;
8'bzz100000: pos <= 3'd5;
8'bz1000000: pos <= 3'd6;
8'b10000000: pos <= 3'd7;
default:pos <= 'x;//不定态
endcase
end
endmodule
三、initial语句
在FPGA中给reg赋初值可以综合(编译器预处理),ASIC设计则不可综合。
四、上升下降双边沿触发器
- 使用两个触发器实现
module top_module(
input clk,
input d,
output q);
reg p, n;
// A positive-edge triggered flip-flop
always @(posedge clk)
p <= d ^ n;
// A negative-edge triggered flip-flop
always @(negedge clk)
n <= d ^ p;
assign q = p ^ n;
endmodule
五、拼接符: {}(举例说明)
{{4{a[0]}},a[3:1]}
//以上表示a[0]重复4次后组成高4位,和a[3:1]所示的低3位组成7bit数据
注意上文大括号的使用位置,重复次数’4‘内外层都需要添加。
六、独热码编码的状态机
使用独热码编码的状态机,状态转移可以对状态对应的bit位分别独立赋值,赋值使用的状态也使用对应bit位代表,对输出赋值类似。
- 下例
Fsm3onehot
展示了在状态使用独热编码时对应的状态转移和输出表示:
module top_module(
input in,
input [3:0] state,
output [3:0] next_state,
output out); //
parameter A=0, B=1, C=2, D=3;
// State transition logic: Derive an equation for each state flip-flop.
assign next_state[A] = (state[0] & (~in)) | (state[2] & (~in));
assign next_state[B] = (state[0] & in) | (state[1] & in) | (state[3] & in);
assign next_state[C] = (state[1] & (~in)) | (state[3] & (~in));
assign next_state[D] = (state[2] & in);
// Output logic:
assign out = state[3];
endmodule
七、Conveylife
- 作为HDLbits有难度的题目之一,这里给出实现方法。
module top_module(
input clk,
input load,
input [255:0] data,
output reg [255:0] q );
//这里自下而上,从右到左排列data内的数据(从低位开始排列)
wire [255:0]right,left,up,down,left_up,right_up,left_down,right_down;
//right表示相对于原来数据右侧的数据组成的新数据阵列以下类似。
assign right = {q[254-:15],q[255],q[238-:15],q[239],q[222-:15],q[223],q[206-:15],q[207],
q[190-:15],q[191],q[174-:15],q[175],q[158-:15],q[159],q[142-:15],q[143],
q[126-:15],q[127],q[110-:15],q[111],q[94-:15],q[95], q[78-:15],q[79],
q[62-:15],q[63], q[46-:15], q[47], q[30-:15],q[31], q[14-:15],q[15]};
assign left = {q[240],q[255-:15],q[224],q[239-:15],q[208],q[223-:15],q[192],q[207-:15],
q[176],q[191-:15],q[160],q[175-:15],q[144],q[159-:15],q[128],q[143-:15],
q[112],q[127-:15],q[96], q[111-:15],q[80], q[95-:15],q[64], q[79-:15] ,
q[48], q[63-:15],q[32], q[47-:15], q[16], q[31-:15],q[0], q[15-:15]};
assign up = {q[15:0], q[255:16]};
assign down = {q[239:0],q[255:240]};
assign left_up = {left[15:0], left[255:16]};
assign right_up = {right[15:0], right[255:16]};
assign left_down = {left[239:0],left[255:240]};
assign right_down= {right[239:0],right[255:240]};
//数据相加和判决
wire [3:0]sum;
wire [255:0]q_next;
integer i;
always @(*)begin
for(i=0;i<=255;i=i+1)begin
sum = right[i] + left[i] + up[i] + down[i] + left_up[i] + right_up[i] + left_down[i] + right_down[i];
q_next[i] = (sum == 4'd2) ? (q[i]) : ( (sum == 4'd3) ? (1'b1) : (1'b0) );
end
end
always @(posedge clk)begin
if(load)
q <= data;
else begin
q <= q_next;
end
end
endmodule