1.输入序列连续的序列检测
- 题面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k6Je97EX-1690946333718)(https://s2.loli.net/2023/07/26/HJPXR2mhbaVCG6d.png)] - 思路
对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。
状态机法的过程类似于:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。
序列缓存对比法,则是将八个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后将数组和目标序列对比,如果数组和目标序列相等,则说明出现目标序列。
序列缓存对比法在实现上比较简单。首先声明一个数组,缓存八个时刻的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
2.含有无关项的序列检测
- 题面
- 思路
序列缓存对比法,则是将九个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后截取数组的前三位和目标序列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
- 解法2
`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
- 解法3
`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
3. 不重叠序列检测
- 题意
题目描写错误,应该是001110,而题目是011100,差评。 - 思路
使用数选器选择出来对应的位,再做同或与最后做与运算,资源用的也很少。
- 代码
`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
4. 简易秒表
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
5. 可置位计数器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
6. 加减计数器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
7.RAM的简单实现
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
8. 单端口RAM
-
题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
9. 4位数比较器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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]));
- 解法2
````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
- 解法3
`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
10.4bit超前进位加法器电路
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
11.优先编码器电路①
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
12. 用优先编码器实现键盘编码电路
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
13. 8线-3线优先编码器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
14. 使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-US4MapYw-1690946333729)(https://s2.loli.net/2023/07/27/YAJa9xIWkbRDE6l.png)]
- 思路
电路连接图
当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
15.实现3-8译码器①
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
16. 用3-8译码器实现全减器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
17 数据选择器实现逻辑电路
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
企业真题
【哲库】
1. 根据RTL图编写Verilog程序
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
2. 自动售卖机
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
3. 序列发生器
-
题意
-
思路
用一个数据存储序列,不断移位,然后一直发送某一位,感觉代码更简单一点。
- 代码
`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
【华为】
1. VL63 并串转换
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
2. VL67 十六进制计数器
- 题意
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
3. 同步FIFO
- 题意
- 思路
待补
4. 状态机与时钟分频
- 题意
-
思路
-
代码
`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
- 解法2
`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
5. 超前进位加法器
- 题意
- 思路
一级加法器进位信号如下
这里‘+’ ‘·’符号不是‘加’和‘乘’,是‘或’和 ‘与’
则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
【阿里】
1. 求最小公倍数
- 题意
- 思路
待补
- 代码
2.任意奇数倍时钟分频
- 题意
- 思路
实现偶数倍的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