Verilog入门
Part one 基础语法
VL1 四选一多路器
// VL1 四选一多路器
// 这一题主要得知道,always块里赋值的话都得是reg型
// 不管是阻塞赋值还是非阻塞赋值
`timescale 1ns/1ns
module mux4_1(
input [1:0]d1,d2,d3,d0,sel,
output reg [1:0]mux_out
);
always @ (*)begin
case(sel)
2'd0: mux_out = d3;
2'd1: mux_out = d2;
2'd2: mux_out = d1;
2'd3: mux_out = d0;
endcase
end
endmodule
VL2 用verilog实现两个串联的异步复位的T触发器
// VL2 用verilog实现两个串联的异步复位的T触发器
// 没太理解那个波形图,但是T触发器就是这种,1翻转0不变
// 学会用if else if else语句
// 然后这个题的复位还是低电平
`timescale 1ns/1ns
module Tff_2 (
input data,clk,rst,
output reg q
);
reg q0;
always @ (posedge clk or negedge rst) begin
if(~rst) q0 <= 1'd0;
else if(data) q0 <= ~q0;
else q0 <= q0;
end
always @ (posedge clk or negedge rst) begin
if(~rst) q <= 1'd0;
else if(q0) q <= ~q;
else q <= q;
end
endmodule
VL3 奇偶校验
// VL3 奇偶校验(该题通过的答案是错的)
// 若有奇数个1,奇校验为0,偶校验为1
// 若有偶数个1,奇校验为1,偶校验为0
// 奇校验:添加校验位后,数位中的1总数是奇数
// 偶校验:添加校验位后,数位中的1总数是偶数
// 思路位对bus按位,异或若有奇数个1则为1,那么奇校验
// 然后结合sel,sel为0是奇校验,
`timescale 1ns/1ns
module odd_sel(
input [31:0] bus,
input sel,
output check
);
assign check = sel ? ^bus : ~(^bus);
// assign check = sel ? ~(^bus) : ^bus; // 真的正确答案
endmodule
VL4 移位运算与乘法
// VL4 移位运算与乘法(稍有不规范)
// 建议是分段式写always块,这里没这么做
// 关于在非阻塞赋值的右侧使用,逻辑判断/三目运算符
// 其实always块以if else判断可以不用begin end
// 这题的测试文件还没写
`timescale 1ns/1ns
module multi_sel(
input [7:0] d,
input clk,rst,
output reg input_grant,
output reg [10:0] out
);
reg [1:0] cnt;
reg [7:0] d0;
always @ (posedge clk or negedge rst)
if(~rst) begin
out <= 11'd0;
d0 <= 8'd0;
cnt <= 2'd0;
input_grant <= 1'd0;
end
else begin
cnt <= cnt + 2'd1;
input_grant <= (cnt==2'd0);
d0 <= (cnt==2'd0) ? d : d0;
case(cnt)
2'd0: out <= d;
2'd1: out <= d0 + {d0,1'd0};
2'd2: out <= d0 + {d0,1'd0} + {d0,2'd0};
2'd3: out <= {d0,3'd0};
endcase
end
endmodule
VL5 位拆分与运算
// VL5 位拆分与运算
// 和上题差不多,更简单点
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0] d,
input [1:0] sel,
output reg [4:0] out,
output reg validout
);
reg [15:0] d0;
always @ (posedge clk or negedge rst)begin
if(~rst)begin
d0 <= 16'd0;
out <= 5'd0;
validout <= 1'd0;
end
else begin
case(sel)
2'd0: begin d0<=d; out<=5'd0; validout<=1'd0; end
2'd1: begin out<=d0[3:0]+d0[7:4]; validout<=1'd1;end
2'd2: begin out<=d0[3:0]+d0[11:8]; validout<=1'd1;end
2'd3: begin out<=d0[3:0]+d0[15:12]; validout<=1'd1;end
endcase
end
end
endmodule
VL6 多功能数据处理器
// VL6 多功能数据处理器
// 和上题差不多,更简单点
`timescale 1ns/1ns
module data_select(
input clk,rst_n,
input signed [7:0] a,b,
input [1:0] select,
output reg signed [8:0] c
);
always @ (posedge clk or negedge rst_n)begin
if(~rst_n)begin
c <= 9'd0;
end
else begin
case(select)
2'd0: c <= a;
2'd1: c <= b;
2'd2: c <= a + b;
2'd3: c <= a - b;
endcase
end
end
endmodule
VL7 求两个数的差值
// VL7 求两个数的差值
// 没啥特别,用if else if代替嵌套if else
`timescale 1ns/1ns
module data_minus(
input clk,rst_n,
input [7:0] a,b,
output reg [8:0] c
);
always @ (posedge clk or negedge rst_n)begin
if(~rst_n) c <= 9'd0;
else if(a>b) c <= a-b;
else c <= b-a;
end
endmodule
VL8 使用generate…for语句简化代码
// VL8 使用generate…for语句简化代码
// generate语法的使用,里边搭配for循环
`timescale 1ns/1ns
module gen_for_module(
input [7:0] data_in,
output [7:0] data_out
);
generate genvar i;
for(i=0;i<8;i=i+1)begin:gen
assign data_out[i]=data_in[7-i];
end
endgenerate
endmodule
VL9 使用子模块实现三输入数的大小比较
// VL9 使用子模块实现三输入数的大小比较
// 使用if else if代替嵌套 if else
// 新的模块例化方式(当知道模块内部信号定义顺序时可以这么写)
// 关于这个题一定要要用三次比较!!!!!
// 如果只用两次比较,由于并行比较,第一级输出和第二级输入不是同clk
`timescale 1ns/1ns
module main_mod(
input clk,rst_n,
input [7:0] a,b,c,
output [7:0] d
);
wire [7:0]i,j;
slave_mod mod1(clk,rst_n,a,b,i);
slave_mod mod2(clk,rst_n,a,c,j);
slave_mod mod3(clk,rst_n,i,j,d);
endmodule
module slave_mod(
input clk,rst_n,
input [7:0] in_1,in_2,
output reg [7:0] out
);
always @ (posedge clk or negedge rst_n)begin
if(~rst_n) out <= 8'd0;
else if(in_1<in_2) out<=in_1;
else out<=in_2;
end
endmodule
VL10 使用函数实现数据的大小端转换
// VL10 使用函数实现数据的大小端转换
// 这里有复位,题目意思就是复位的时候输出的值为0
// 学习function的用法,有时间结合task语法一起学一下!!!!!!
`timescale 1ns/1ns
module function_mod(
input clk,rst_n,
input [3:0] a,b,
output [3:0] c,d
);
function [3:0] f1;
input [3:0] d;
begin
f1[0]=d[3];
f1[1]=d[2];
f1[2]=d[1];
f1[3]=d[0];
end
endfunction
assign c = rst_n ? f1(a) : 4'd0;
assign d = rst_n ? f1(b) : 4'd0;
endmodule
Part two 组合逻辑
VL11 4位数值比较器电路
// VL11 4位数值比较器电路
// 直接比较不就行了
`timescale 1ns/1ns
module comparator_4(
input [3:0] A,B,
output reg Y2,Y1,Y0
);
always @(*) begin Y2=(A>B);Y1=(A==B);Y0=(A<B); end
endmodule
// 根据题目要求,还是要用门级电路来做
module comparator_4(
input [3:0] A,B,
output wire Y2,Y1,Y0
);
reg Da3,Da2,Da1,Da0,De3,De2,De1,De0;
always @ (*) begin
Da3=(A[3]&~B[3]);Da2=(A[2]&~B[2]);Da1=(A[1]&~B[1]);Da0=(A[0]&~B[0]);
De3=~(A[3]^B[3]);De2=~(A[2]^B[2]);De1=~(A[1]^B[1]);De0=(~A[0]^B[0]);
end
assign Y2 = Da3 | De3&Da2 | De3&De2&Da1 | De3&De2&De1&Da0;
assign Y1 = De3&De2&De1&De0;
assign Y0 = ~Y2&~Y1;
endmodule
VL12 4bit超前进位加法器电路
// VL12 4bit超前进位加法器电路
// 用卡诺图化简,分别算出Sum和Cin
// Si=Ai^Bi^Ci 、 Ci+1=AiBi+(Ai+Bi)Ci
`timescale 1ns/1ns
module lca_4(
input [3:0] A_in,B_in,
input C_1,
output reg CO,
output reg [3:0] S
);
reg [3:0] C;
always @ (*) begin
C[0] = C_1;
C[1] = A_in[0]&B_in[0] | (A_in[0]|B_in[0])&C[0];
C[2] = A_in[1]&B_in[1] | (A_in[1]|B_in[1])&C[1];
C[3] = A_in[2]&B_in[2] | (A_in[2]|B_in[2])&C[2];
CO = C[3];
S = A_in^B_in^C;
end
endmodule
VL13 优先编码器电路1
// VL13 优先编码器电路1
// 使用casex语法按照给出的真值表输出对应的结果
`timescale 1ns/1ns
module encoder_0(
input [8:0] I_n ,
output reg [3:0] Y_n
);
always @ (*)begin
casex(I_n)
9'b0xxx_xxxx_x: Y_n = 4'b0110;
9'b10xx_xxxx_x: Y_n = 4'b0111;
9'b110x_xxxx_x: Y_n = 4'b1000;
9'b1110_xxxx_x: Y_n = 4'b1001;
9'b1111_0xxx_x: Y_n = 4'b1010;
9'b1111_10xx_x: Y_n = 4'b1011;
9'b1111_110x_x: Y_n = 4'b1100;
9'b1111_1110_x: Y_n = 4'b1101;
9'b1111_1111_0: Y_n = 4'b1110;
9'b1111_1111_1: Y_n = 4'b1111;
default: Y_n = 4'b1111;
endcase
end
endmodule
VL14 用优先编码器①实现键盘编码电路
// VL14 用优先编码器①实现键盘编码电路
`timescale 1ns/1ns
module encoder(
input [8:0] I_n ,
output reg [3:0] Y_n
);
// 这里都是取反,
always @(*)begin
casex(I_n)
9'b111111111 : Y_n = 4'b1111; // I=9'b000000000 Y=4'b0000 按键0
9'b111111110 : Y_n = 4'b1110; // I=9'b000000001 Y=4'b0001 按键1
9'b11111110x : Y_n = 4'b1101; // I=9'b00000001x Y=4'b0010 按键2
9'b1111110xx : Y_n = 4'b1100; // I=9'b0000001xx Y=4'b0011 按键3
9'b111110xxx : Y_n = 4'b1011; // I=9'b000001xxx Y=4'b0100 按键4
9'b11110xxxx : Y_n = 4'b1010; // I=9'b00001xxxx Y=4'b0101 按键5
9'b1110xxxxx : Y_n = 4'b1001; // I=9'b0001xxxxx Y=4'b0110 按键6
9'b110xxxxxx : Y_n = 4'b1000; // I=9'b001xxxxxx Y=4'b0111 按键7
9'b10xxxxxxx : Y_n = 4'b0111; // I=9'b01xxxxxxx Y=4'b1000 按键8
9'b0xxxxxxxx : Y_n = 4'b0110; // I=9'b1xxxxxxxx Y=4'b1001 按键9
default : Y_n = 4'b1111; // I=9'bxxxxxxxxx Y=4'b0000 按键×
endcase
end
endmodule
// 这题怪就怪在输入的S_n有10位,意思就是把S_n[0]作为判断依据
// 从状态栏可见:S_n全为1时,L_n也全1,表示按键0按下
// 然后关于GS的状态,通过的答案是认为GS=1,代表没按键按下
// 这个也好理解,没按键按下只有一种情况,方便判断,拉高说明空闲了
// 意思就是当Y全为零,同时输入也全为零时,认为按键0,GS=0
// 意思就是当Y全为零,但是输入没有时,认为按键没按下,GS=1
module key_encoder(
input [9:0] S_n ,
output wire [3:0] L ,
output wire GS
);
wire [3:0] L_n; encoder encoder(S_n[9:1],L_n);
assign L = ~L_n;
assign GS = ~(S_n[0]&L_n[0]&L_n[1]&L_n[2]&L_n[3]);
// assign GS = ~((S_n[0]==1'd1)&(L==4'd0));
endmodule
VL15 优先编码器Ⅰ
// VL15 优先编码器Ⅰ
// 没啥特别的,根据真值表来编
`timescale 1ns/1ns
module encoder_83(
input [7:0] I ,
input EI ,
output reg [2:0] Y ,
output reg GS ,
output reg EO
);
always @ (*)begin
if(EI)
casex(I)
8'b0000_0000: begin Y = 3'b000; GS = 1'b0; EO = 1'b1; end
8'b0000_0001: begin Y = 3'b000; GS = 1'b1; EO = 1'b0; end// 1
8'b0000_001x: begin Y = 3'b001; GS = 1'b1; EO = 1'b0; end// 2
8'b0000_01xx: begin Y = 3'b010; GS = 1'b1; EO = 1'b0; end// 3
8'b0000_1xxx: begin Y = 3'b011; GS = 1'b1; EO = 1'b0; end// 4
8'b0001_xxxx: begin Y = 3'b100; GS = 1'b1; EO = 1'b0; end// 5
8'b001x_xxxx: begin Y = 3'b101; GS = 1'b1; EO = 1'b0; end// 6
8'b01xx_xxxx: begin Y = 3'b110; GS = 1'b1; EO = 1'b0; end// 7
8'b1xxx_xxxx: begin Y = 3'b111; GS = 1'b1; EO = 1'b0; end// 8
default : begin Y = 3'b000; GS = 1'b0; EO = 1'b0; end
endcase
else begin Y = 3'b000; GS = 1'b0; EO = 1'b0; end
end
endmodule
VL16 使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器
// VL16 使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器
// 两片级联的方式进行操作,通过对第二块的GS的值进行判断
// GS2=0:Y={0,Y1} GS=GS1 EO=EO1
// GS2=1:Y={1,Y2} GS=1 EO=0
`timescale 1ns/1ns
module encoder_83(
input [7:0] I ,
input EI ,
output wire [2:0] Y ,
output wire GS ,
output wire EO
);
assign Y[2] = EI & (I[7] | I[6] | I[5] | I[4]);
assign Y[1] = EI & (I[7] | I[6] | ~I[5]&~I[4]&I[3] | ~I[5]&~I[4]&I[2]);
assign Y[0] = EI & (I[7] | ~I[6]&I[5] | ~I[6]&~I[4]&I[3] | ~I[6]&~I[4]&~I[2]&I[1]);
assign EO = EI&~I[7]&~I[6]&~I[5]&~I[4]&~I[3]&~I[2]&~I[1]&~I[0];
assign GS = EI&(I[7] | I[6] | I[5] | I[4] | I[3] | I[2] | I[1] | I[0]);
endmodule
module encoder_164(
input [15:0] A ,
input EI ,
output wire [3:0] L ,
output wire GS ,
output wire EO
);
wire GS1,GS2,EO1,EO2;
wire [2:0] Y1,Y2;
encoder_83 encoder_1(A[7 :0],EI,Y1,GS1,EO1);
encoder_83 encoder_2(A[15:8],EI,Y2,GS2,EO2);
assign {L,GS,EO} = GS_2 ? {{1'b1,Y2},1'b1,1'b0} : {{1'b0,Y1},GS1,EO1};
endmodule
VL17 用3-8译码器实现全减器
// VL17 用3-8译码器实现全减器
// 通过画卡诺图的方式先把全减器的逻辑表达式定下来:
// D=A^B^Ci 、 Co=~AB+(~A+B)Ci;
// 然后根据对应的ABC的值,查找对应的译码器输出值
module decoder_38(
input E,
input [2:0] A,
output reg [7:0] Y
);
always @(*)
if(!E) Y = 8'b00000000;
else if(A==3'b000) Y = 8'b00000001;
else if(A==3'b001) Y = 8'b00000010;
else if(A==3'b010) Y = 8'b00000100;
else if(A==3'b011) Y = 8'b00001000;
else if(A==3'b100) Y = 8'b00010000;
else if(A==3'b101) Y = 8'b00100000;
else if(A==3'b110) Y = 8'b01000000;
else if(A==3'b111) Y = 8'b10000000;
else Y = 8'b00000000;
endmodule
module decoder1(
input A,B,Ci,
output D,Co
);
wire [7:0] Y;
decoder_38 decoder_38(1'b1,{A,B,Ci},Y);
assign D = Y[1]|Y[2]|Y[4]|Y[7];
assign Co = Y[1]|Y[2]|Y[3]|Y[7];
endmodule
VL18 实现3-8译码器1 用基础门电路实现
// VL18 实现3-8译码器1 用基础门电路实现
// 根据图片来,输出由输入决定
`timescale 1ns/1ns
module decoder_38(
input E1_n,E2_n,E3,A0,A1,A2,
output Y0_n,Y1_n,Y2_n,Y3_n,Y4_n,Y5_n,Y6_n,Y7_n
);
wire E ;
assign E = E3 & ~E2_n & ~E1_n;
assign Y0_n = ~(E & ~A2 & ~A1 & ~A0);
assign Y1_n = ~(E & ~A2 & ~A1 & A0);
assign Y2_n = ~(E & ~A2 & A1 & ~A0);
assign Y3_n = ~(E & ~A2 & A1 & A0);
assign Y4_n = ~(E & A2 & ~A1 & ~A0);
assign Y5_n = ~(E & A2 & ~A1 & A0);
assign Y6_n = ~(E & A2 & A1 & ~A0);
assign Y7_n = ~(E & A2 & A1 & A0);
endmodule
VL19 使用3-8译码器1实现逻辑函数
// VL19 使用3-8译码器1实现逻辑函数
// 例化时注意顺序
// 根据逻辑表达式发现ABC=1,3,6,7时L为1,然后和对应的Y挂钩即可
`timescale 1ns/1ns
module decoder_38(
input E1_n,E2_n,E3,A0,A1,A2,
output Y0_n,Y1_n,Y2_n,Y3_n,Y4_n,Y5_n,Y6_n,Y7_n
);
wire E ;
assign E = E3 & ~E2_n & ~E1_n;
assign Y0_n = ~(E & ~A2 & ~A1 & ~A0);
assign Y1_n = ~(E & ~A2 & ~A1 & A0);
assign Y2_n = ~(E & ~A2 & A1 & ~A0);
assign Y3_n = ~(E & ~A2 & A1 & A0);
assign Y4_n = ~(E & A2 & ~A1 & ~A0);
assign Y5_n = ~(E & A2 & ~A1 & A0);
assign Y6_n = ~(E & A2 & A1 & ~A0);
assign Y7_n = ~(E & A2 & A1 & A0);
endmodule
module decoder0(
input A,B,C,
output L
);
wire Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7;
decoder_38 decoder_38(1'b0,1'b0,1'b1,C,B,A,Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7);
assign L = ~Y1 | ~Y3 | ~Y6 | ~Y7;
endmodule
VL20 数据选择器实现逻辑电路
// VL20 数据选择器实现逻辑电路
// 这题有意思的就在于对这个选择器的理解上
// 和前面题很像,先确定逻辑表达式,然后分配到输入输出
// L = A&B | A&~C | B&C 以A C作为输入 结果作为输出
`timescale 1ns/1ns
module data_sel(
input S0,S1,D0,D1,D2,D3,
output Y
);
assign Y = ~S1 & (~S0&D0 | S0&D1) | S1&(~S0&D2 | S0&D3);
endmodule
module sel_exp(
input A,B,C,
output L
);
data_sel data_sel(A,C,1'b0,1'b1,B,B,L);
endmodule
Part three 时序逻辑
VL21 根据状态转移表实现时序电路
// VL21 根据状态转移表实现时序电路
// 注意题目给的Y用的是wire型,是想要用组合逻辑来操作Y;
// 这里就比较麻烦,直接在状态机里一起走时序不是更好
// 但这应该是和几段式状态机相关吧,一段放时序,一段放组合
// 常规方案:一开始的思路,就画出状态转移说明
`timescale 1ns/1ns
module seq_circuit(
input A,clk,rst_n,
output Y
);
reg [1:0] state;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
state <= 2'b0;
end
else begin
case(state)
2'b00: if(A) state<=2'b11;else state<=2'b01;
2'b01: if(A) state<=2'b00;else state<=2'b10;
2'b10: if(A) state<=2'b01;else state<=2'b11;
2'b11: if(A) state<=2'b10;else state<=2'b00;
endcase
end
end
assign Y = (state==2'b11);
endmodule
// 方案二:题目是说用D触发器和必要逻辑门实现
// 通过画卡诺图方式化简来操作:(在下一题中比较明显)
`timescale 1ns/1ns
module seq_circuit(
input A,clk,rst_n,
output Y
);
reg Q1,Q0;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
Q1 <= 1'b0;
Q0 <= 1'b0;
end
else begin
Q1 <= A^Q1^Q0;
Q0 <= ~Q0;
end
end
assign Y = Q1&Q0;
endmodule
VL22 根据状态转移图实现时序电路
// VL22 根据状态转移图实现时序电路
// 和上面那个题一样的画卡诺图来解
`timescale 1ns/1ns
module seq_circuit(
input C,clk,rst_n,
output Y
);
reg Q1,Q0;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
Q1 <= 1'b0;
Q0 <= 1'b0;
end
else begin
Q1 <= ~C&Q0 | Q1&Q0 | C&Q1 ;
Q0 <= ~C&Q0 | ~Q1&Q0 | C&~Q1;
end
end
assign Y = Q1&Q0|C&Q1;
endmodule
VL23 ROM的简单实现
//VL23 ROM的简单实现
// 这一题在这边关于这个变量的申明特别有意思!!
`timescale 1ns/1ns
module rom(
input clk,rst_n,
input [7:0] addr,
output wire [3:0] data
);
reg [3:0] rom[7:0];
always @ (posedge clk or negedge rst_n) begin
rom[0] <= 4'd0 ;
rom[1] <= 4'd2 ;
rom[2] <= 4'd4 ;
rom[3] <= 4'd6 ;
rom[4] <= 4'd8 ;
rom[5] <= 4'd10;
rom[6] <= 4'd12;
rom[7] <= 4'd14;
end
assign data = rom[addr];
endmodule
VL24 边沿检测
// VL24 边沿检测
// 通过打一拍的方式获得delay,通过取反相与的方式找到边沿
// 不知道为啥不能直接赋值,说什么会出现不定态,很迷惑??????
`timescale 1ns/1ns
module edge_detect(
input clk,rst_n,a,
output reg rise,down
);
reg delay;
always @ (posedge clk) delay <= a;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin rise <= 1'b0; down <= 1'b0; end
else if(~delay&a) begin rise <= 1'b1; down <= 1'b0; end
else if(~a&delay) begin rise <= 1'b0; down <= 1'b1; end
else begin rise <= 1'b0; down <= 1'b0; end
end
endmodule