牛客网 VL1 四选一多路器
多路器一般考虑用三目运算符=A?B:C;超过2路的考虑用基本两路复用器级联
timescale 1ns/1ns
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output[1:0]mux_out
);
//*************code***********//
wire [1:0] mux_out1,mux_out2;
assign mux_out=sel[1]?mux_out1:mux_out2;
assign mux_out1=sel[0]?d0:d1;
assign mux_out2=sel[0]?d2:d3;
//*************code***********//
endmodule`
牛客网 VL2 异步复位的串连T触发器
这题需要注意的是串连的是T触发器而不是D触发器,审题很重要
同时不要忘记阻塞赋值的习惯
`timescale 1ns/1ns
module Tff_2 (
input wire data, clk, rst,
output reg q
);
//*************code***********//
reg q_mid;
always@(posedge clk,negedge rst)
if(!rst)
q_mid<=0;
else
if(data==1)
q_mid<=~q_mid;
else
q_mid<=q_mid;
always@(posedge clk,negedge rst)
if(!rst)
q<=0;
else
if(q_mid==1)
q<=~q;
else
q<=q;
//*************code***********//
endmodule
牛客网 VL3 奇偶校验
本题难在1.审题,sel的功能是当sel为0时输出check取反
2.奇偶校验本质上是一个数按位异或^bus
原理 只有1 xor 0=1因此当1 xor 0 时不变号,忽略0在xor中的作用。当1遇到奇数个1互相xor时结果为1,而1xor 偶数个1时结果为0,而中间遇到多少个0并不影响结果。
`timescale 1ns/1ns
module odd_sel(
input [31:0] bus,
input sel,
output check
);
//*************code***********//
wire check_mid;
assign check_mid=^bus;
assign check=sel?check_mid:~check_mid;
//*************code***********//
endmodule
牛客网 VL4 移位运算与乘法
由于这题状态转换并不复杂,因此仅仅设立单状态mini_state,而不用状态转换模型。
需要注意的是每次时钟脉冲到来时,判断的是前一瞬间的值。
`timescale 1ns/1ns
module multi_sel(
input [7:0]d ,
input clk,
input rst,
output reg input_grant,
output reg [10:0]out,
output reg [1:0] mini_state
);
//*************code***********//
reg [7:0]data;
always@(posedge clk,negedge rst)
if(!rst)
mini_state<=2'b00;
else
mini_state<=mini_state+1;//时钟上升沿到来状态+1
always@(posedge clk)
if(mini_state==2'b00)
data<=d;//锁存输入数据
always@(posedge clk,negedge rst)
if(!rst)
begin
out<=10'b00_0000_0000;
input_grant<=0;
end
else
case(mini_state)
2'b00:
begin
out<=d;
input_grant<=1;
end
2'b01:
begin
out<=data*3;
input_grant<=0;
end
2'b10:
begin
out<=data*7;
input_grant<=0;
end
2'b11:
begin
out<=data*8;
input_grant<=0;
end
endcase
//*************code***********//
endmodule
牛客网 VL5 位拆分与运算
观察题目波形,本题异步性较强,观察到输出out随输入sel同时改变,因此主要通过assign语句实现组合逻辑,然后用always语句实现输入锁存的时序逻辑。
`timescale 1ns/1ns
module data_cal(
input clk,
input rst,
input [15:0]d,
input [1:0]sel,
output [4:0]out,
output validout
);
//*************code***********//
reg [15:0]d_lock;//锁存输入
wire [15:0]d1,d2,d3,out1,out2;
assign d1=d_lock[3:0]+d_lock[7:4];
assign d2=d_lock[3:0]+d_lock[11:8];
assign d3=d_lock[3:0]+d_lock[15:12];
assign validout=sel[0]|sel[1];
assign out1=sel[0]?d1:0;
assign out2=sel[0]?d3:d2;
assign out=sel[1]?out2:out1;
always@(posedge clk,negedge rst)
if(~rst)
d_lock<=d_lock;//复位操作
else
begin
if(~(sel[0]|sel[1]))
d_lock<=d;//锁存
end
//*************code***********//
endmodule
牛客网 VL9 使用子模块实现三输入大小比较
需要注意的是,由于子模块是时序逻辑电路,因此每次比较都会延时。例如ab比较的结果c1是基于第一个时钟脉冲到来之前一瞬间的a,b值。如果直接将c1与c再进行比较的话,就会产生a,b,c三个信号的同步问题 。因为这样的话,c如果在第二个时钟上升沿到来之前变化时,结果d也会相应变化。也就是说,大小比较不满足同时性,比较的是前一个时钟的a,b和后一个时钟的c,因此为了同步需要为c加一个锁存器进行延时,让锁存器输出的也是前一个时钟脉冲的c值。
`timescale 1ns/1ns
module main_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
input [7:0]c,
output [7:0]d
);
wire [7:0]c1,c2;
son_mod S1(.clk(clk),.rst_n(rst_n),.a(a),.b(b),.c(c1));
D_delay D1(c,clk,c2);
son_mod S2(clk,rst_n,c2,c1,d);
endmodule
module son_mod(
input clk,
input rst_n,
input [7:0]a,
input [7:0]b,
output [7:0]c
);
reg [7:0]c_mid;
always@(posedge clk,negedge rst_n)
if(!rst_n)
c_mid<=0;
else
begin
if(a>=b)
c_mid<=b;
else
c_mid<=a;
end
assign c=c_mid;
endmodule
module D_delay(
input [7:0] d,
input clk,
output[7:0] q);
reg [7:0] q_mid;
always@(posedge clk)
q_mid<=d;
assign q=q_mid;
endmodule