赞
踩
对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。
状态机法的过程类似于:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。
序列缓存对比法,则是将八个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后将数组和目标序列对比,如果数组和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单。首先声明一个数组,缓存八个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[6:0]表示截取a_tem的低7位,{a_tem[6:0],a}表示把a_tem[6:0]和新输入的数值a拼接,a位于低位。
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input a, output reg match ); reg [7:0] a_tem; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin match <=1'b0; end else if (a_tem == 8'b0111_0001) begin match <= 1'b1; end else begin match <= 1'b0; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin a_tem <= 8'b0; end else begin a_tem <= {a_tem[6:0],a}; end end endmodule
序列缓存对比法,则是将九个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后截取数组的前三位和目标序列011对比,截取数组的后三位和目标序列110对比,如果两段数组都和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单,本题采用该方法实现。首先声明一个数组,缓存九个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[7:0]表示截取a_tem的低7位,{a_tem[7:0],a}表示把a_tem[7:0]和新输入的数值a拼接,a位于低位。
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input a, output match ); reg [8:0] a_tem; reg match_f; reg match_b; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin match_f <=1'b0; end else if (a_tem[8:6] == 3'b011) begin match_f <= 1'b1; end else begin match_f <= 1'b0; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin match_b <= 1'b0; end else if (a_tem[2:0] == 3'b110) begin match_b <= 1'b1; end else begin match_b <= 1'b0; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin a_tem <= 9'b0; end else begin a_tem <= {a_tem[7:0],a}; end end assign match = match_b && match_f; endmodule
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input a, output reg match ); reg [8:0] sequence; always @(posedge clk or negedge rst_n) begin if (~rst_n) begin sequence <= 9'b0; end else begin sequence <= {sequence[7:0],a}; end end always @(posedge clk or negedge rst_n) begin if (~rst_n) begin match <= 0; end else if (sequence[8:6] == 3'b011 && sequence[2:0] == 3'b110) begin match <= 1; end else begin match <= 0; end end endmodule
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input a, output reg match ); reg [8:0] val; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin val <= 9'b0; end else begin val <= {val[7:0],a}; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin match <= 1'b0; end else begin casex (val) 9'b011xxx110 : match <= 1'b1; default : match <= 1'b0; endcase end end endmodule
使用数选器选择出来对应的位,再做同或与最后做与运算,资源用的也很少。
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input data, output reg match, output reg not_match ); reg [2:0] cnt; reg cmp; reg detect_cmp; parameter detect = 6'b011100; always@(posedge clk or negedge rst_n)begin if(! rst_n) cnt <= 3'd0; else if(cnt == 3'd5) cnt <= 3'd0; else cnt <= cnt + 3'd1; end always@(*)begin case(cnt) 3'd0: cmp = 1'd0; 3'd1: cmp = 1'd1; 3'd2: cmp = 1'd1; 3'd3: cmp = 1'd1; 3'd4: cmp = 1'd0; 3'd5: cmp = 1'd0; default: cmp = 1'd0; endcase end always@(posedge clk or negedge rst_n) begin if(! rst_n) detect_cmp <= 1'd1; else if(cnt == 3'd5) detect_cmp <= 1'd1; else detect_cmp <= detect_cmp && (~( cmp^ data)); end always@(posedge clk or negedge rst_n) begin if(! rst_n) match <= 1'd0; else if((detect_cmp )&&(cnt == 3'd5)) match <= 1'd1; else match <= 1'd0; end always@(posedge clk or negedge rst_n) begin if(! rst_n) not_match <= 1'd0; else if((!detect_cmp)&&(cnt == 3'd5)) not_match <= 1'd1; else not_match <= 1'd0; end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kY64tO5e-1690946333720)(https://s2.loli.net/2023/07/26/Zylt2eT9h3uGEWO.png)]
首先确定second的取值逻辑:当minute=60时停止计数,即保持second为0;当second=60时,下一个周期second置为1。其余情况second 等于前一时刻的值加一。 然后明确minute的取值逻辑:当second=60,minute等于前一时刻的值加一。其余情况,minute保持不变。
`timescale 1ns/1ns module count_module( input clk, input rst_n, output reg [5:0]second, output reg [5:0]minute ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin minute <= 6'd0; end else if (second == 6'd60) begin minute <= minute + 1; end else begin minute <= minute; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin second <= 6'd0; end else if (second == 6'd60) begin second <= 6'd1; end else if (minute == 60) begin second <=0; end else second <= second + 1'd1; end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6mrVnCX-1690946333720)(https://s2.loli.net/2023/07/26/dg8SMpxfuBGT97Q.png)]
首先明确number的取值逻辑,声明number变量为4位无符号数,数值每个时钟加一,则每次数值达到15,下一个时钟因为位宽的限制,自动变为1,可以实现十六进制计数。当set信号为1时,将set_num的值赋给number。
然后确定zero的取值逻辑,在默认情况下为0,当number=0时,zero值为1。
因为判断number4’d0需要一个时钟,zero信号为1,总是滞后number0一个时钟周期。所以可以考虑将number延迟一个时钟再输出。使用num变量代替上述的number,再通过以下语句实现number延迟一个时钟输出。【因为number是寄存器类型,无法通过组合逻辑进行阻塞赋值同时匹配。 如果直接使用number进行zero的判断来说,zero肯定是比number过“0”时刻慢一拍的; 所以不妨使用num_reg,进行延迟; 因为zero肯定是比num_reg慢一拍的,所以再通过num_reg延迟一拍给number,则number与zero同步输出匹配;】
`timescale 1ns/1ns module count_module( input clk, input rst_n, input set, input [3:0] set_num, output reg [3:0]number, output reg zero ); reg [3:0] num; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin zero = 1'd0; end else if (num == 4'd0) begin zero <= 1'b1; end else begin zero <= 1'b0; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin num <= 4'b0; end else if (set) begin num <= set_num; end else begin num <= num + 1'd1; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin number <= 1'd0; end else begin number <= num; end end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tgHdRB9I-1690946333721)(https://s2.loli.net/2023/07/26/sOD1nVqmpaLbWyC.png)]
首先确定zero的取值逻辑,在默认情况下为0,当number=0时,zero值为1。 always @(posedge clk or negedge rst_n)
然后将mode的值作为if-else的判断条件,当mode为1时,number每个时钟周期加一,当mode为0时,number每个时钟周期减一。
按照以上代码,因为判断number4’d0需要一个时钟,zero信号为1,总是滞后number0一个时钟周期。所以可以考虑将number延迟一个时钟再输出。使用num变量代替上述的number,再通过以下语句实现number延迟一个时钟输出。
`timescale 1ns/1ns module count_module( input clk, input rst_n, input mode, output reg [3:0]number, output reg zero ); reg [3:0] num; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin zero <= 1'd0; end else if (num == 4'd0) begin zero <= 1'b1; end else begin zero <= 1'b0; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin num <= 4'b0; end else if (mode) begin if (num == 9) num <= 0; else num <= num + 1'd1; end else if (!mode) begin if (num == 0) num <= 9; else num <= num - 1'd1; end else num <= num ; end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin number <= 4'd0; end else begin number <= num; end end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOXdfKjA-1690946333722)(https://s2.loli.net/2023/07/26/5AKM8VZ72XdDgCm.png)]
要实现RAM,首先要声明数据的存储空间,例如:[3:0] rom [7:0];变量名称ram之前的[3:0]表示每个数据具有多少位,指位宽;变量名称ram之后的[7:0]表示需要多少个数据,指深度,注意这里深度为8,应该是使用[7:0],而不是[2:0];
声明存储变量之后,需要对ram进行初始化,写入数据,当write_en有效,向write_addr写入write_data,当read_en有效,根据输入的read_addr输出read_data。需要注意的是,题目要求实现真双端口RAM,即可以同时写入和读出,所以需要使用两个always语句块实现写入和读出逻辑,不可以在同一个always块中使用if-else if-else if结果。
`timescale 1ns/1ns module ram_mod( input clk, input rst_n, input write_en, input [7:0]write_addr, input [3:0]write_data, input read_en, input [7:0]read_addr, output reg [3:0]read_data ); reg [3:0] myRAM [7:0]; reg [8:0] i; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin for (i = 0;i < 256;i = i+1) myRAM[i] = 0; end else begin myRAM[write_addr] <= write_en ? write_data:myRAM[write_addr]; end end always @(posedge clk or negedge rst_n) begin if (~rst_n) begin read_data <= 0; end else read_data <= read_en?myRAM[read_addr]:read_data; end endmodule
题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLXVUwhb-1690946333723)(https://s2.loli.net/2023/07/27/anzKjiMc1mdbe5x.png)]
思路
建立一个reg的数组,将数据存储进来,进行的是读、写互不干扰的读写机制,即要么读要么写。这个时侯需要设置enb,进行读写的开关控制。需要注意的是,写是对寄存器进行写,因此必须有时序电路构成。
`timescale 1ns/1ns module RAM_1port( input clk, input rst, input enb, input [6:0]addr, input [3:0]w_data, output wire [3:0]r_data ); //*************code***********// reg [6:0] mem[127:0]; integer i; always @(posedge clk or negedge rst) begin if (!rst) begin for (i = 0;i < 127;i ++) begin mem[i] <= 1'b0; end end else if (enb) begin mem[addr] <= w_data; end end assign r_data = (!enb)?mem[addr]:1'b0; //*************code***********// endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFYF9HxO-1690946333723)(https://s2.loli.net/2023/07/27/4BLiHUldXDCq3yV.png)]
门级描述,无非就是将<,>,==三个符号用门级电路来表示,然后根据行为级描述进行替换。
a == b --> ~(a^b)
a > b --> (a^b)&a
a < b --> (a^b)&b
assign Y1 = ~(A[0]^B[0]) & ~(A[1]^B[1]) & ~(A[2]^B[2]) & ~(A[3]^B[3]);
assign Y2 = ((A[3]^B[3])&A[3]) |
(~(A[3]^B[3]) & ((A[2]^B[2])&A[2])) |
(~(A[3]^B[3]) & ~(A[2]^B[2]) & ((A[1]^B[1])&A[1])) |
(~(A[3]^B[3]) & ~(A[2]^B[2]) & ~(A[1]^B[1]) & ((A[0]^B[0])&A[0]));
assign Y0 = ((A[3]^B[3])&B[3]) |
(~(A[3]^B[3]) & ((A[2]^B[2])&B[2])) |
(~(A[3]^B[3]) & ~(A[2]^B[2]) & ((A[1]^B[1])&B[1])) |
(~(A[3]^B[3]) & ~(A[2]^B[2]) & ~(A[1]^B[1]) & ((A[0]^B[0])&B[0]));
````timescale 1ns/1ns module comparator_4( input [3:0] A , input [3:0] B , output reg Y2 , //A>B output reg Y1 , //A=B output reg Y0 //A<B ); always @ (A or B) begin if(A>B) begin Y2=1; Y1=0; Y0=0; end else if (A<B) begin Y2=0; Y1=0; Y0=1; end else begin Y2=0; Y1=1; Y0=0; end end endmodule
`timescale 1ns/1ns 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>B)?1:0; assign Y1 = (A==B)?1:0; assign Y0 = (A<B)?1:0; endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IGGLnOKB-1690946333724)(https://s2.loli.net/2023/07/27/EtzQDw8syVqelcb.png)]
`timescale 1ns/1ns 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] C; assign S[0] = A_in[0] ^ B_in[0] ^ C_1; assign S[1] = A_in[1] ^ B_in[1] ^ C[0]; assign S[2] = A_in[2] ^ B_in[2] ^ C[1]; assign S[3] = A_in[3] ^ B_in[3] ^ C[2]; assign C[0] = (A_in[0] & B_in[0]) || ((A_in[0] ^ B_in[0]) & C_1); assign C[1] = (A_in[1] & B_in[1]) || ((A_in[1] ^ B_in[1]) & C[0]); assign C[2] = (A_in[2] & B_in[2]) || ((A_in[2] ^ B_in[2]) & C[1]); assign C[3] = (A_in[3] & B_in[3]) || ((A_in[3] ^ B_in[3]) & C[2]); assign CO = C[3]; endmodule
半加器是最简单的加法器。它不考虑进位输入。其中A
和B
是两个加数,S
是和,C_o
是进位输出。
assign S = A ^ B;
assign C_out = A & B;
全加器是多bit加法器的基础。 C i C_i Ci 是进位输入。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L2C3EKBe-1690946333725)(https://s2.loli.net/2023/07/27/Gnh5cNXWHxsbqvC.png)]
下图中红色路径是全加器的关键路径。
module full_adder(
input A,
input B,
input C_i,
output S,
output C_o
);
assign S = A ^ B ^ C_i;
assign C_o = A & B | C_i&(a^b);
// assign C_o = A & B | A & C_i | B & C_i; // 也可以
endmodule
Ripple-carry adder, RCA
。将全加器串联起来。 虽然 RCA
结构简单易于理解,但容易看出,每一位的运算结果
S
k
S_k
Sk 都要依赖进位
C
k
C_k
Ck 才能得出。如下图所示,这会使得 RCA
的关键路径变得很长,而长关键路径会让电路难以满足时序要求。
module rca #( parameter width = 4 )( input [width-1:0] A, input [width-1:0] B, output [width-1:0] S, input C_i, output C_o ); wire [width:0] C; genvar i; generate for (i=0; i<width; i=i+1)begin full_adder myadder( .A (A[i]), .B (B[i]), .C_i (C[i]), .S (S[i]), .C_o (C[i+1]), ); end endgenerate assign C[0] = C_i; assign C_o = C[width]; endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeVmcbZM-1690946333727)(https://s2.loli.net/2023/07/27/C1BrOihzMQSmJFg.png)]
关于case
、casez
和casex
参考这篇文章。简单地说,三者都是可以综合的。case
进行全等匹配,casez
忽略?
或z
对应的位进行匹配,casex
忽略x
、?
或z
对应的位进行匹配。
`timescale 1ns/1ns module encoder_0( input [8:0] I_n , output reg [3:0] Y_n ); always@(*) begin casez (I_n) 9'b1_1111_1111: Y_n = 4'b1111; 9'b0_????_????: Y_n = 4'b0110; 9'b1_0???_????: Y_n = 4'b0111; 9'b1_10??_????: Y_n = 4'b1000; 9'b1_110?_????: Y_n = 4'b1001; 9'b1_1110_????: Y_n = 4'b1010; 9'b1_1111_0???: Y_n = 4'b1011; 9'b1_1111_10??: Y_n = 4'b1100; 9'b1_1111_110?: Y_n = 4'b1101; 9'b1_1111_1110: Y_n = 4'b1110; default: Y_n = 4'b0000; endcase end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-saeMgwuv-1690946333728)(https://s2.loli.net/2023/07/27/3pl9vBh6UWKTrIt.png)]
首先确定电路输出L是8421BCD码,即是高电平有效的,而题目中给出的优先编码器输出Y_n是低电平有效的,故应当明确L和Y_n两者的状态是恰好相反的;
注意:键盘有10个按键,而所给的优先编码器是只有9个输入的;
此题关键在于着重理解: “键盘编码电路要有工作状态标志,以区分没有按键按下和按键0按下两种情况。” : 这句话的潜台词是 按键按下和按键0按下时,电路的输出L的状态是一样的,因此在这种情况下可以通过GS信号来区分键盘是否处在工作状态,对应的真值表如下;
键盘状态 | S[9:0] | L[3:0] | GS |
---|---|---|---|
无按键按下 | 1_1111_1111 | 0000 | 0 |
按键0按下 | 1_1111_1110 | 0000 | 1 |
`timescale 1ns/1ns 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 , output wire[3:0] L , output wire GS ); wire [3:0] L_temp; encoder_0 encoder (S_n[9:1], L_temp); assign GS = ~((&(~L)) & S_n[0]); assign L = ~L_temp; endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PtVldSbG-1690946333728)(https://s2.loli.net/2023/07/27/3I4Kt8oDlPBugAq.png)]
分析编码器的功能表:
当El=1时,编码器工作:而当E1=0时,禁止编码器工作,此时不论8个输入端为何种状态,3个输出端均为低电平,且GS和EO均为低电平。
只有在EI为1,且所有输入端都为0时,EO输出为1.它可与另一片编码器的EI连接,以便组成更多输入端的优先编码器。
GS的功能是,当EI为1,且至少有一个输入端有高电平信号输入时,GS为1.表明编码器处于工作状态,否则GS为0,由此可以区分当电路所有输入端均无高电平输人,或者只有I[0]输入端有高电平时,Y[2:0]均为000的情况
根据功能表推导出各输出端的逻辑表达式为
Y[2] = EI(I[7]+I[6]+I[5]+I[4]);
Y[1] = EI(I[7]+I[6]+~I[5]~I[4] I[3] +~I[5]~I[4] I[2]);
Y[0] = EI(I[7]+~I[6] I[5]+ ~I[6]~I[4] I[3]+ ~I[6]~I[4]~ I[2]I[1]);
EO=EI(~I[7] ~I[6] ~I[5] ~I[4] ~I[3] ~I[2] ~I[1] ~I[0]);
GS=EI(I[7]+ I[6]+ I[5]+ I[4]+ I[3]+ I[2]+ I[1]+ I[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]); //assign GS = EI&(| I); endmodule
电路连接图
当EI1=0时、U1禁止编码,其输出端Y为000,GS1、EO1均为0。同时EO1使EI0=0,U0也禁止编码,其输出端及GS0、EO0均为0。由电路图可知GS=GS1+GS0=0,表示此时电路输出端的代码L=0000是非编码输出。
当E=1时,U1允许编码,若A[15:8]均无有效电平输人,则EO1=1,使EI0=1,从而允许U0编码,因此U1的优先级高于U0。
此时A[15:8]没有有效电平输入,U1的输出均为0。使4个或门都打开,L[2:0]取决于U0的输出,而L[3]=GS1总是等于0,所以输出代码在0000-0111之间变化。若只有A[0]有高电平输入,输出为0000,若A[7]及其他输入同时有高电平输人,则输出为0111。A[0]的优先级别最低。
(3)当EI1=1且A[15:8]中至少有一个为高电平输人时,EO1=0,使EI0=0,U0禁止编码,此时L[3]=GS1=1,L[2:0]取决于U1的输出,输出代码在1000~1111之间变化,并且A的优先级别最高。
`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]); //assign GS = EI&(| I); endmodule module encoder_164( input [15:0] A , input EI , output wire [3:0] L , output wire GS , output wire EO ); wire EO1; wire [2:0] Y0; wire [2:0] Y1; wire GS0; encoder_83 U0( .I (A[7:0]), .EI (EO1), .Y (Y0), .GS (GS0), .EO (EO) ); encoder_83 U1( .I (A[15:8]), .EI (EI), .Y (Y1), .GS (GS1), .EO (EO1) ); assign L[3] = GS1; assign L[2] = Y1[2] | Y0[2]; assign L[1] = Y1[1] | Y0[1]; assign L[0] = Y1[0] | Y0[0]; assign GS = GS1 | GS0; endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5JEeRDnZ-1690946333731)(https://s2.loli.net/2023/07/27/CjKxLaqU6RMSuPV.png)]
根据该电路的真值表,可列出逻辑表达式,最简结果如下。
Y0_n = (E·(A2)·(A1)·(A0));
Y1_n = (E·(A2)·(~A1)·(A0));
Y2_n = (E·(A2)·(A1)·(~A0));
Y3_n = (E·(A2)·(A1)·(A0));
Y4_n = (E·(A2)·(A1)·(~A0));
Y5_n = (E·(A2)·(A1)·(A0));
Y6_n = (E·(A2)·(A1)·(A0));
Y7_n = ~(E·(A2)·(A1)·(A0));
`timescale 1ns/1ns module decoder_38( input E1_n , input E2_n , input E3 , input A0 , input A1 , input A2 , output wire Y0_n , output wire Y1_n , output wire Y2_n , output wire Y3_n , output wire Y4_n , output wire Y5_n , output wire Y6_n , output wire 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
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5mAbG1HI-1690946333732)(https://s2.loli.net/2023/07/27/AhT9Ru4ybsMHzZ8.png)]
3-8译码器代码如下,可将参考代码添加并例化到本题答案中。
module decoder_38( input E , input A0 , input A1 , input A2 , output reg Y0n , output reg Y1n , output reg Y2n , output reg Y3n , output reg Y4n , output reg Y5n , output reg Y6n , output reg Y7n ); always @(*)begin if(!E)begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end else begin case({A2,A1,A0}) 3'b000 : begin Y0n = 1'b0; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b001 : begin Y0n = 1'b1; Y1n = 1'b0; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b010 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b0; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b011 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b0; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b100 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b0; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b101 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b0; Y6n = 1'b1; Y7n = 1'b1; end 3'b110 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b0; Y7n = 1'b1; end 3'b111 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b0; end default: begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end endcase end end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GGh3L5uV-1690946333734)(https://s2.loli.net/2023/07/27/DPCKUNFBeAGVaR3.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06WTo0xb-1690946333735)(https://s2.loli.net/2023/07/27/SMrKPcTlye3GxoI.png)]
`timescale 1ns/1ns module decoder_38( input E , input A0 , input A1 , input A2 , output reg Y0n , output reg Y1n , output reg Y2n , output reg Y3n , output reg Y4n , output reg Y5n , output reg Y6n , output reg Y7n ); always @(*)begin if(!E)begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end else begin case({A2,A1,A0}) 3'b000 : begin Y0n = 1'b0; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b001 : begin Y0n = 1'b1; Y1n = 1'b0; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b010 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b0; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b011 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b0; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b100 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b0; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end 3'b101 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b0; Y6n = 1'b1; Y7n = 1'b1; end 3'b110 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b0; Y7n = 1'b1; end 3'b111 : begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b0; end default: begin Y0n = 1'b1; Y1n = 1'b1; Y2n = 1'b1; Y3n = 1'b1; Y4n = 1'b1; Y5n = 1'b1; Y6n = 1'b1; Y7n = 1'b1; end endcase end end endmodule module decoder1( input wire A, input wire B, input wire Ci, output wire D, output wire Co ); wire [7:0] Y; assign D = ~Y[1] + ~Y[2] + ~Y[4] + ~Y[7]; assign Co = ~Y[1] + ~Y[4] + ~Y[5] + ~Y[7]; decoder_38 myDecoder( .E (1 ), .A0 (B ), .A1 (A ), .A2 (Ci ), .Y0n(Y[0]), .Y1n(Y[1]), .Y2n(Y[2]), .Y3n(Y[3]), .Y4n(Y[4]), .Y5n(Y[5]), .Y6n(Y[6]), .Y7n(Y[7]) ); endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBsifET9-1690946333736)(https://s2.loli.net/2023/07/27/OFbBh2nZo1m7ayd.png)]
数据选择器代码如下,可在本题答案中添加并例化此数据选择器。
module data_sel(
input S0 ,
input S1 ,
input D0 ,
input D1 ,
input D2 ,
input D3 ,
output wire Y
);
assign Y = ~S1 & (~S0&D0 | S0&D1) | S1&(~S0&D2 | S0&D3);
endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUAIEJ9Q-1690946333737)(https://s2.loli.net/2023/07/27/skfPxvhXZoJRNYq.png)]
将变量A、B接入4选1数据选择器选择输入端S0 S1。将变量C分配在数据输入端。从表中可以看出输出L与变量C的关系。
当AB=00时选通D0而此时L=0,所以数据端D0接0:当AB=01时选通D1,由真值表得此时L=C,即D1应接C:当AB为10和11时,D2和D3分别接~C和1。A接S1,B接S0。
`timescale 1ns/1ns module data_sel( input S0 , input S1 , input D0 , input D1 , input D2 , input D3 , output wire Y ); assign Y = ~S1 & (~S0&D0 | S0&D1) | S1&(~S0&D2 | S0&D3); endmodule module sel_exp( input A , input B , input C , output wire L ); data_sel U0( .S0 (B), .S1 (A), .D0 (0), .D1 (C), .D2 (~C), .D3 (1), .Y (L) ); endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6qOQbV5-1690946333738)(https://s2.loli.net/2023/07/27/xnOm7qFpTzUVHSc.png)]
观察题目给出的RTL图,主要的器件是两个D触发器,一个与门。D触发器含有异步复位信号,且为低电平有效。data_in输入到D触发器,D触发器的输出Q是前一时刻的data_in,即data_in打一拍得到data_in_reg。与门表示data_out = data_in && !data_in_reg。再通过一个D触发器输出,这样子处理使data_in上升沿出现的时候,data_out保持一个时钟的高电平。由此可见,RTL实现了求data_in上升沿的功能。
`timescale 1ns/1ns module RTL( input clk, input rst_n, input data_in, output reg data_out ); reg data_in_reg; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_in_reg <= 1'b0; end else begin data_in_reg <= data_in; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_out <= 1'b0; end else if (data_in && !data_in_reg) begin data_out <= 1'b1; end else begin data_out <= 1'b0; end end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dGl074sc-1690946333739)(https://s2.loli.net/2023/07/28/6rKeuFZvcXfGJCW.png)]
思路
代码
`timescale 1ns/1ns module sale( input clk , input rst_n , input sel ,//sel=0,5$dranks,sel=1,10&=$drinks input [1:0] din ,//din=1,input 5$,din=2,input 10$ output reg [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks output reg change_out ); reg [1:0] temp; wire [1:0] total = din+temp; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin drinks_out <= 2'd0; change_out <= 1'd0; end else begin case ({sel,total}) 3'd111: begin drinks_out <= 2'd2; change_out <= 1'd1; end 3'd110: begin drinks_out <= 2'd2; change_out <= 1'd0; end 3'd010: begin drinks_out <= 2'd1; change_out <= 1'd0; end 3'd001: begin drinks_out <= 2'd1; change_out <= 1'd0; end endcase end end always @(posedge clk or drinks_out) begin if (!rst_n) begin temp <= 2'd0; end else begin if (drinks_out) begin temp <= 2'd0; end else begin temp <= din; end end end endmodule
题意
思路
用一个数据存储序列,不断移位,然后一直发送某一位,感觉代码更简单一点。
`timescale 1ns/1ns module sequence_generator( input clk, input rst_n, output reg data ); reg [5:0] q; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin q <= 6'b001011; end else begin q <= {q[4:0],q[5]}; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data <= 1'd0; end else begin data <= q[5]; end end endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BL9P2cKb-1690946333741)(https://s2.loli.net/2023/07/31/AStcHjgieDW9zay.png)]
核心思想就是移位。串转并就是把1位的输入放到N位reg的最低位,然后N位reg左移一位,在把1位输入放到左移后的reg的最低位,这样循环,就可以得到,以最高位开始传输,最低位传输完成的N位数据了;并转串就是把并行的N位数据的最高位给1位输出,然后类似的循环左移就可以了。
`timescale 1ns/1ns module huawei5( input wire clk , input wire rst , input wire [3:0]d , output wire valid_in , output wire dout ); //*************code***********// reg [3:0] data = 'd0; reg [1:0] cnt; reg valid; assign dout = data[3]; assign valid_in = valid; always @(posedge clk or negedge rst) begin if (!rst) begin data <= 'd0; cnt <= 'd0; valid <= 'd0; end else begin if (cnt == 'd3) begin data <= d; cnt <= 'd0; valid <= 1; end else begin cnt <= cnt + 'd1; valid <= 0; data <= {data[2:0],data[3]}; end end end //*************code***********// endmodule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EQHnrQev-1690946333741)(https://s2.loli.net/2023/07/31/XZYiT1OchPKQ4BC.png)]
自动溢出。Q属于是4bit
`timescale 1ns/1ns module counter_16( input clk , input rst_n , output reg [3:0] Q ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin Q <= 4'b0; end else begin Q <= Q +1'b1; end end endmodule
待补
思路
代码
`timescale 1ns/1ns module huawei7( input wire clk , input wire rst , output reg clk_out ); //*************code***********// parameter [1:0] s0 = 2'b00, s1 = 2'b01, s2 = 2'b10, s3 = 2'b11; reg [1:0] state,next_state; always @(posedge clk or negedge rst) begin if (!rst) begin state <= s0; end else begin state <= next_state; end end always @(state) begin case(state) s0:begin next_state <= s1; clk_out <= 1'b0; end s1:begin next_state <= s2; clk_out <= 1'b1; end s2:begin next_state <= s3; clk_out <= 1'b0; end s3: begin next_state <= s0; end default:begin next_state <= s0; clk_out <= 1'b0; end endcase end //*************code***********// endmodule
`timescale 1ns/1ns module huawei7( input wire clk , input wire rst , output reg clk_out ); //*************code***********// reg[1:0] cnt; always@(posedge clk or negedge rst) if(!rst) cnt <= 0; else cnt <= cnt+1; always@(*) clk_out = cnt==1; //*************code***********// endmodule
一级加法器进位信号如下
这里‘+’ ‘·’符号不是‘加’和‘乘’,是‘或’和 ‘与’
则4级可以表示为如下,这里P和G是传播信号和生成信号:
因此,应该得到两个子模块:一位运算和四位逻辑
`timescale 1ns/1ns module huawei8//四位超前进位加法器 ( input wire [3:0]A, input wire [3:0]B, output wire [4:0]OUT ); //*************code***********// wire [3:0] G; wire [3:0] P; wire [3:0] F; wire [4:1] C; Add1 u1 ( .a(A[0]), .b(B[0]), .C_in(1'b0), .f(F[0]), .g(G[0]), .p(P[0]) ); Add1 u2 ( .a(A[1]), .b(B[1]), .C_in(C[1]), .f(F[1]), .g(G[1]), .p(P[1]) ); Add1 u3 ( .a(A[2]), .b(B[2]), .C_in(C[2]), .f(F[2]), .g(G[2]), .p(P[2]) ); Add1 u4 ( .a(A[3]), .b(B[3]), .C_in(C[3]), .f(F[3]), .g(G[3]), .p(P[3]) ); CLA_4 uut ( .P(P), .G(G), .C_in(1'b0), .Ci(C), .Gm(), .Pm() ); assign OUT={C[4],F}; //*************code***********// endmodule //下面是两个子模块 module Add1 ( input a, input b, input C_in, output f, output g, output p ); assign f = a^b^C_in; assign g = a&b; assign p = a|b; endmodule module CLA_4( input [3:0]P, input [3:0]G, input C_in, output [4:1]Ci, output Gm, output Pm ); assign Ci[1] = G[0]|P[0]&C_in; assign Ci[2] = G[1]|P[1]&G[0]|P[1]&P[0]&C_in; assign Ci[3] = G[2]|P[2]&G[1]|P[2]&P[1]&G[0]|P[2]&P[1]&P[0]&C_in; assign Ci[4] = G[3]|P[3]&G[2]|P[3]&P[2]&G[1]|P[3]&P[2]&P[1]&G[0]|P[3]&P[2]&P[1]&P[0]&C_in; assign Gm = G[3]|P[3]&G[2]|P[3]&P[2]&G[1]|P[3]&P[2]&P[1]&G[0]; assign Pm = P[3]&P[2]&P[1]&P[0]; endmodule
待补
实现偶数倍的n分频时,每当计数器从0计数到n/2 - 1时,输出时钟信号跳变,同时计数器归零从新开始计数。
题目要求的是奇数倍分频,且要求占空比为50%,则需要稍加调整:以五分频为例,需要输出时钟信号保持2.5个输入时钟的1,然后保持2.5个时钟的0。比如在第一个时钟的上升沿跳变为1,则在第三个时钟的下降沿跳变为0,在第六个时钟的上升沿再一次跳变为1。即需要对上升/下降两个时钟沿的进行计数。
由此得出实现奇数倍数分频的方法:加入两个中间信号flag_1,flag_2,分别使用输入时钟信号的上升/下降沿驱动。以五分频为例,flag_1的变化由上升沿驱动,flag_2的变化由下降沿驱动。当计数器计数到(n-1)/2=2和(n-1)=4时,flag_1、flag_2发生跳变(即取反)。再将flag_1,flag_2相或即可得到分频之后的时钟信号。
如下图所示。红色框分别为flag_1,flag_2,持续两个时钟,相或得到蓝色部分刚好占2.5个时钟,实现五分频。
`timescale 1ns/1ns module clk_divider #(parameter dividor = 5) ( input clk_in, input rst_n, output clk_out ); //定义计数器的位宽,$clog2()为取对数操作,在编译过程中执行完成。因此在模块运行过程中CNT_WIDTH是一个确定的数值。 parameter CNT_WIDTH = $clog2(dividor-1); reg flag_1; reg flag_2; reg [CNT_WIDTH :0] cnt; always @(posedge clk_in or negedge rst_n) if (!rst_n) cnt <= 0; else if(cnt == dividor-1) cnt <= 0; else cnt <= cnt + 1'd1; always @(posedge clk_in or negedge rst_n) if (!rst_n) flag_1 <= 0; else if(cnt == (dividor-1>>1)) flag_1 <= ~flag_1; else if(cnt == dividor-1) flag_1 <= ~flag_1; else flag_1 <= flag_1; always @(negedge clk_in or negedge rst_n) if (!rst_n) flag_2 <= 0; else if(cnt == (dividor-1 >>1)) flag_2 <= ~flag_2; else if(cnt == dividor-1) flag_2 <= ~flag_2; else flag_2 <= flag_2; assign clk_out = flag_1 || flag_2; endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。