目前牛客网上面“基础语法”部分都已经完成了, 都是已经验证通过了的,代码链接如下:
FPGA刷题P1:4选1多路选择器、异步复位的串联T触发器、奇偶校验、移位拼接乘法_居安士的博客-CSDN博客
FPGA刷题P2:多功能数据处理器、求两个数的差值、使用generate...for语句简化代码、使用子模块实现三输入数的大小比较、使用函数实现数据大小端转化_居安士的博客-CSDN博客
个人的感觉,就算不是为了find work,用这些题目练习一下编程思维也是不错的 !下面就书接上文,开始“组合逻辑”的部分~~
目录
4位数值比较器电路
根据真值表output部分,给Y2=1和Y1=1时input要满足的条件,就可以实现了,这里没有Y0,我们可以理解为Y0是非Y1非Y2,需要注意的是,对于这种多个条件与或非,最好乖乖加括号,不然就需要特别熟悉符合的优先级,代码如下:
module comparator_4(
input [3:0] A ,
input [3:0] B ,
output wire Y2 , //A>B
output wire Y1 , //A=B
output wire Y0 //A<B
);
assign Y2=(A[3]>B[3]) || ((A[3]==B[3])&&(A[2]>B[2]))||((A[3]==B[3])&&(A[2]==B[2])&&(A[1]>B[1])||(A[3]==B[3])&&(A[2]==B[2])&&(A[1]==B[1])&&(A[0]>B[0]));
assign Y1=((A[3]==B[3])&&(A[2]==B[2])&&(A[1]==B[1])&&(A[0]==B[0]));
assign Y0=(~Y1)&&(~Y2);
endmodule
4bit超前进位加法器电路
这一题给出来了逻辑表达式,叫用Verilog语言去描述:
⊙是同或运算符~^,⊕是异或运算符^,&&是乘法,||是加法
公式里面的 i 指的是每一位
module lca_4(
input [3:0] A_in ,
input [3:0] B_in ,
input C_1 ,
output wire CO ,
output wire [3:0] S
);
wire [3:0] G;
wire [3:0] P;
wire [3:0] C;
assign G[0]=A_in[0] && B_in[0];//乘是与
assign G[1]=A_in[1] && B_in[1];
assign G[2]=A_in[2] && B_in[2];
assign G[3]=A_in[3] && B_in[3];
assign P[0]=A_in[0] ^ B_in[0];//圆圈加号是异或
assign P[1]=A_in[1] ^ B_in[1];
assign P[2]=A_in[2] ^ B_in[2];
assign P[3]=A_in[3] ^ B_in[3];
assign C[0]=G[0]|| P[0]&&C_1;//视为-1
assign C[1]=G[1]|| P[1]&&C[0];//加号是或
assign C[2]=G[2]|| P[2]&&C[1];
assign C[3]=G[3]|| P[3]&&C[2];
assign S[0]=P[0] ^ C_1;//视为-1
assign S[1]=P[1] ^ C[0];
assign S[2]=P[2] ^ C[1];
assign S[3]=P[3] ^ C[2];
assign CO=C[3];//输出C的高位作为进位
endmodule
优先编码器电路
真值表中x代表不知道是0还是1,就需要用到casex语句
casex语句可以识别出x和z的情况,使用方法和case没有区别,只是多加了x
casex(条件):
条件值:语句;
endcase
module encoder_0(
input [8:0] I_n ,
output reg [3:0] Y_n
);
always@(*)begin
casex(I_n)
9'b111111111:Y_n=4'b1111;
9'b0xxxxxxxx:Y_n=4'b0110;
9'b10xxxxxxx:Y_n=4'b0111;
9'b110xxxxxx:Y_n=4'b1000;
9'b1110xxxxx:Y_n=4'b1001;
9'b11110xxxx:Y_n=4'b1010;
9'b111110xxx:Y_n=4'b1011;
9'b1111110xx:Y_n=4'b1100;
9'b11111110x:Y_n=4'b1101;
9'b111111110:Y_n=4'b1110;
default: Y_n=4'b1111;
endcase
end
endmodule
用优先编码器实现键盘编码电路
这一题是在上一题的基础之上,真值表和上一题相同
这个题要求按键输出为8421BCD码,根据目前真值表的输出Y,不难发现非Y就是8421BCD码的0~9
(8421BCD码:是指从高到低的4位分别为 8 4 2 1,用着4位数可以表示十进制的0~9,例如5的8421BCD码就是 0101)
此外,还要求有工作状态标志位,没有按键按下,Y输出为1111;按键0对应输入的0位,按下是低电平,因此只有按键0按下,0位=0
module encoder_0(
input [8:0] I_n ,
output reg [3:0] Y_n
);
always @(*)begin
casex(I_n)
9'b111111111 : Y_n = 4'b1111;
9'b0xxxxxxxx : Y_n = 4'b0110;
9'b10xxxxxxx : Y_n = 4'b0111;
9'b110xxxxxx : Y_n = 4'b1000;
9'b1110xxxxx : Y_n = 4'b1001;
9'b11110xxxx : Y_n = 4'b1010;
9'b111110xxx : Y_n = 4'b1011;
9'b1111110xx : Y_n = 4'b1100;
9'b11111110x : Y_n = 4'b1101;
9'b111111110 : Y_n = 4'b1110;
default : Y_n = 4'b1111;
endcase
end
endmodule
module key_encoder(
input [9:0] S_n , //输入按键 I_n
output wire[3:0] L ,//按键输出Y_n
output wire GS //是否有按键按下
);
//例化
wire [3:0] L1;
encoder_0 inst_encoder_0(
.I_n (S_n[9:1]),
.Y_n (L1)
);
assign L=~L1;//8421BCD码恰好是Y_n的非
assign GS=((L1==4'b1111) && (S_n[0]==1))? 0:1; //没有按键按下=0,按键0没按下=1
endmodule
优先编码器
表格非常长!给了一个巨长的真值表要求实现
和以往不同的是,这次的输入相当于给了一个复位信号E
module encoder_83(
input [7:0] I ,
input EI ,
output wire [2:0] Y ,
output wire GS ,
output wire EO
);
reg [2:0] y;
reg gs;
reg eo;
always@(*)begin
if(~EI)begin
y =3'b0;
gs =1'b0;
eo =1'b0;
end
else begin
casex(I)
8'b00000000 : begin
y = 3'b000;
gs = 1'b0;
eo = 1'b1;
end
8'b1xxxxxxx : begin
y = 3'b111;
gs = 1'b1;
eo = 1'b0;
end
8'b01xxxxxx : begin
y = 3'b110;
gs = 1'b1;
eo = 1'b0;
end
8'b001xxxxx : begin
y = 3'b101;
gs = 1'b1;
eo = 1'b0;
end
8'b0001xxxx : begin
y = 3'b100;
gs = 1'b1;
eo = 1'b0;
end
8'b00001xxx : begin
y = 3'b011;
gs = 1'b1;
eo = 1'b0;
end
8'b000001xx : begin
y = 3'b010;
gs = 1'b1;
eo = 1'b0;
end
8'b0000001x : begin
y = 3'b001;
gs = 1'b1;
eo = 1'b0;
end
8'b00000001 : begin
y = 3'b000;
gs = 1'b1;
eo = 1'b0;
end
default : begin
y = 3'b000;
gs = 1'b0;
eo = 1'b0;
end
endcase
end
end
assign Y = y;
assign GS = gs;
assign EO = eo;
endmodule