赞
踩
全部答案汇总:刷完这套题,我才发现Verilog原来如此简单----HDLBits答案汇总
今天更新Circuits章节中的Building Larger Circuits
【题目】:
设计一个从0-999(1000个周期)的计数器。同步复位,复位值0。
【个人思路】:
经典的计数器,数字电路、FPGA的基础应用之一。计数器首先复位清零,当计数器计数到最大值999时清零,没计数到最大值则每个周期+1。
- module top_module (
- input clk ,
- input reset ,
- output [9:0] q
- );
-
- //计数器:0-999
- always @(posedge clk)begin
- if(reset)
- q <= 10'd0; //同步复位清零
- else if(q == 10'd999)
- q <= 10'd0; //计数到最大值清零
- else
- q <= q + 1'b1; //其他时候每个时钟周期+1
- end
-
- endmodule
【题目】:
设计一个四位移位寄存器,也作为一个下行计数器。当shift_ena为1时,数据会先以最高有效位移位。当前移位寄存器中的数字在count_ena为1时递减。系统不会出现两种使能信号同时为高的情况,所以不存在优先级问题。
【个人思路】:
当shift_ena有效时,数据开始循环移位,当count_ena为1时,该移位寄存器做递减器。
- module top_module (
- input clk,
- input shift_ena,
- input count_ena,
- input data,
- output [3:0] q);
-
- always@(posedge clk)begin
- case({shift_ena,count_ena})
- 2'b01: q <= q -1'b1;
- 2'b10: q <= {q[2:0],data};
- default:;
- endcase
- end
-
- endmodule
【题目】:
设计一个有限状态机FSM,从输入码流中找出“1101”序列,当1101被找到后,永远的拉高start_shifting信号,直到复位才拉低。
【个人思路】
经典的序列检测问题,笔试常见,一定要掌握。可以参考我的这篇博文:‘10010’序列检测器的两种实现方法(有限状态机、移位寄存器)
设计的有限状态机状态转移图如下:
- module top_module (
- input clk ,
- input reset ,
- input data ,
- output start_shifting
- );
-
- parameter S0 = 5'b00001,
- S1 = 5'b00010,
- S2 = 5'b00100,
- S3 = 5'b01000,
- S4 = 5'b10000;
- reg [4:0] cur_state , //定义现态寄存器
- next_state ; //定义次态寄存器
- //三段式状态机第一段:同步时序描述状态转移
- always @(posedge clk)begin
- if(reset)
- cur_state <= S0;
- else
- cur_state <= next_state;
- end
- //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
- always@(*)begin
- next_state = S0;
- case(cur_state)
- S0:
- if(data) //检测到1101的第1个1
- next_state = S1;
- else
- next_state = S0; //没有检测到1101的第1个1
- S1:
- if(data) //检测到1101的第2个1
- next_state = S2;
- else
- next_state = S0; //没有检测到1101的第2个1
- S2:
- if(!data) //检测到1101的0
- next_state = S3;
- else
- next_state = S2; //没有检测到1101的0,此时为111,后面两个11可以视为检测到了1101的11
- S3:
- if(data) //检测到1101的最后的1,检测完成
- next_state = S4;
- else
- next_state = S0; //没有检测到第一个字节(1100)则跳转到S0
- S4:
- next_state = S4; //永远保持在这个状态,因为start_shifting永远为1,只检测一次
- default:next_state = S0;
- endcase
- end
- //三段式状态机第三段:时序逻辑描述输出
- always @(posedge clk)begin
- if(reset)
- start_shifting <= 1'b0;
- else
- case(next_state)
- S0,S1,S2,S3:
- start_shifting <= 1'b0;
- S4:
- start_shifting <= 1'b1;
- default:start_shifting <= 1'b0;
- endcase
- end
- endmodule
【题目】:
作为控制移位寄存器的FSM的一部分,我们希望能够在检测到合适的位模式时,使移位寄存器精确地为4个时钟周期。我们在Exams/review2015_fsmseq中处理序列检测,所以FSM的这部分只处理4个周期的移位寄存器启用。
当FSM被重置时,置位shift_ena 4个周期,然后0永远(直到重置)。
【个人思路】
这道题的意思是,如果复位信号有效,shift_ena信号就为1;当复位信号撤销以后,shift_ena信号保持4个周期高电平后变为0。
使用一个计数器计数,reset该计数器复位到0,shift_ena高电平期间计数(在此期间计数0-3),计数到3后计数器清零。
shift_ena在复位有效后拉高,在计数器计数到3后拉低。
预期波形图如下:
- module top_module (
- input clk,
- input reset, // Synchronous reset
- output shift_ena);
-
- reg [2:0] cnt;
-
- always @(posedge clk)begin
- if(reset)
- shift_ena <= 1'b1; //复位拉高shift_ena
- else if(cnt == 3'd3)
- shift_ena <= 1'b0; //计数器到3说明维持了4个周期,shift_ena拉低
- else
- shift_ena <= shift_ena; //其他时候不变
- end
- //计数器:0-3
- always @(posedge clk)begin
- if(reset)
- cnt <= 3'd0; //复位清零
- else if(shift_ena)
- cnt <= cnt + 1'd1; //shift_ena有效时递增1
- else
- cnt <= cnt; //其他时候不变
- end
-
- endmodule
FSM式解法:
- module top_module (
- input clk,
- input reset, // Synchronous reset
- output shift_ena);
-
- parameter S0 = 5'b00001,
- S1 = 5'b00010,
- S2 = 5'b00100,
- S3 = 5'b01000,
- S4 = 5'b10000;
-
- reg [4:0] cur_state , //定义现态寄存器
- next_state ; //定义次态寄存器
- //三段式状态机第一段:同步时序描述状态转移
- always @(posedge clk)begin
- if(reset)
- cur_state <= S0;
- else
- cur_state <= next_state;
- end
- //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
- always@(*)begin
- next_state = S0;
- case(cur_state)
- S0: next_state = S1; //维持第1个时钟周期
- S1: next_state = S2; //维持第2个时钟周期
- S2: next_state = S3; //维持第3个时钟周期
- S3: next_state = S4; //维持第4个时钟周期
- S4: next_state = S4; //保持在这个状态,直到下一次复位
- default: next_state = S0;
- endcase
- end
-
- assign shift_ena = (cur_state == S0 || cur_state == S1 || cur_state == S2 || cur_state == S3);
- //三段式状态机第三段:时序逻辑描述输出
- /*always @(posedge clk)begin
- if(reset)
- shift_ena <= 1'b0;
- else
- case(next_state)
- S0,S1,S2,S3:
- shift_ena <= 1'b1;
- S4:
- shift_ena <= 1'b0;
- default:shift_ena <= 1'b0;
- endcase
- end */
-
- endmodule
【题目】:
首先检测序列“1101”,检测到后停止检测,拉高shift_ena4个时钟周期,然后拉高counting直到输入done_counting为1,然后拉高done直到输入ack为1。
【个人思路】:
这题目是前面几道题的结合,状态转移图如下:
- module top_module (
- input clk,
- input reset, // Synchronous reset
- input data,
- input ack,
- input done_counting,
-
- output shift_ena,
- output counting,
- output done
- );
-
- parameter S = 4'd0,
- S1 = 4'd1,
- S11 = 4'd2,
- S110 = 4'd3,
- B0 = 4'd4,
- B1 = 4'd5,
- B2 = 4'd6,
- B3 = 4'd7,
- COUNT = 4'd8,
- WAIT = 4'd9;
-
- reg [3:0] cur_state , //定义现态寄存器
- next_state ; //定义次态寄存器
-
- //三段式状态机第一段:同步时序描述状态转移
- always @(posedge clk)begin
- if(reset)
- cur_state <= S;
- else
- cur_state <= next_state;
- end
- //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
- always@(*)begin
- //next_state = S;
- case(cur_state)
- S :
- if(data)
- next_state = S1;
- else
- next_state = S;
- S1 :
- if(data)
- next_state = S11;
- else
- next_state = S;
- S11 :
- if(!data)
- next_state = S110;
- else
- next_state = S11;
- S110 :
- if(data)
- next_state = B0;
- else
- next_state = S;
- B0 :
- next_state = B1;
- B1 :
- next_state = B2;
- B2 :
- next_state = B3;
- B3 :
- next_state = COUNT;
- COUNT:
- if(done_counting)
- next_state = WAIT;
- else
- next_state = COUNT;
- WAIT :
- if(ack)
- next_state = S;
- else
- next_state = WAIT;
- default: next_state = S;
- endcase
- end
- /*
- assign shift_ena = (cur_state == B0 || cur_state == B1 || cur_state == B2 || cur_state == B3);
- assign counting = (cur_state == COUNT);
- assign done = (cur_state == WAIT);
- */
- //三段式状态机第三段:时序逻辑描述输出
- always @(posedge clk)begin
- if(reset)begin
- shift_ena <= 1'b0;
- counting <= 1'b0;
- done <= 1'b0;
- end
- else
- case(next_state)
- B0,B1,B2,B3:begin
- shift_ena <= 1'b1;
- counting <= 1'b0;
- done <= 1'b0;
- end
- COUNT:begin
- shift_ena <= 1'b0;
- counting <= 1'b1;
- done <= 1'b0;
- end
- WAIT:begin
- shift_ena <= 1'b0;
- counting <= 1'b0;
- done <= 1'b1;
- end
- default:begin
- shift_ena <= 1'b0;
- counting <= 1'b0;
- done <= 1'b0;
- end
- endcase
- end
-
- endmodule
【题目】:
在数据流中检测到序列 1101 后,电路需要将接下来的 4bit 数据移入移位寄存器。4bit 数据决定了计数器的计数周期,称为 delay[3:0]。首先到达的比特作为数据的高位。之后,状态机置高 counting 信号,表示其正在等待计数器完成计数。在 FSM 中增加计数器状态,计数周期为 (delay[3:0] + 1 )* 1000 个时钟周期。比如 delay = 0 时,计数值为 1000 个周期。delay = 5 代表 6000 个周期。同时输出 count 当前剩余的计数周期,输出当前剩余计数周期的千位(比如,还剩1000个周期输出 1,还剩 999 个周期时输出 0)。当计数停止后,count 的输出可以为任意数。
当计数完成后,电路置高 done 信号通知上层应用计数器计数完成,等待 ack 信号置高后,状态机清除 done 信号,返回空闲状态等待捕获下一个 1101 序列。
本题给出了一个期望输入输出的例子。图中的斜线代表当前信号为 'X', 表示状态机不关心该信号当前的值。比如图例中,一旦 FSM 检测到 1101 序列并读取 delay[3:0] 后,在此次计数器事件完成前,对于当前的数据流不再关心。
在图例中,电路计数周期为 2000 ,因为 delay[3:0] 数值为 4'b0001 。在后续的第二个计数周期中,因为 delay[3:0] = 4‘b1110,所以计数周期为 15000。
【个人思路】:
首先需要找到序列“1101”,接下来的码流输出的4个数据(高位在前)+1,再乘以1000,就是接下来要延时的时间。延时完成后,拉高done,直到ack拉高(响应了),再重新开始新一轮。count输出的是计数的千位数,比如计数器还是1999,那么输出为1。
设计状态转移如下图:
再贴几张写的仿真的仿真结果,方便理解:
- module top_module (
- input clk,
- input reset,
- input data,
- input ack,
-
- output [3:0] count,
- output counting,
- output done
- );
-
- parameter S = 4'd0,
- S1 = 4'd1,
- S11 = 4'd2,
- S110 = 4'd3,
- DELAY = 4'd4,
- COUNT = 4'd5,
- WAIT = 4'd6;
-
- reg [3:0] cur_state , //定义现态寄存器
- next_state ; //定义次态寄存器
-
- reg [1:0] cnt_delay ; //用来接收码流的计数器
- reg [15:0] cnt ;
- reg [3:0] delay ;
- //三段式状态机第一段:同步时序描述状态转移
- always @(posedge clk)begin
- if(reset)
- cur_state <= S;
- else
- cur_state <= next_state;
- end
- //三段式状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
- always@(*)begin
- //next_state = S;
- case(cur_state)
- S :
- if(data)
- next_state = S1;
- else
- next_state = S;
- S1 :
- if(data)
- next_state = S11;
- else
- next_state = S;
- S11 :
- if(!data)
- next_state = S110;
- else
- next_state = S11;
- S110 :
- if(data)
- next_state = DELAY;
- else
- next_state = S;
- DELAY:
- if(cnt_delay == 2'd3)
- next_state = COUNT;
- else
- next_state = DELAY;
- COUNT:
- if(cnt == 16'd0)
- next_state = WAIT;
- else
- next_state = COUNT;
- WAIT :
- if(ack)
- next_state = S;
- else
- next_state = WAIT;
- default: next_state = S;
- endcase
- end
- //三段式状态机第三段:描述输出
- assign count = cnt/1000;
- assign counting = (cur_state == COUNT);
- assign done = (cur_state == WAIT);
- //延时计数器,计数4个时钟,来接收delay数据
- always @(posedge clk)begin
- if(reset)
- cnt_delay <= 2'd0;
- else if(cur_state == DELAY)begin
- cnt_delay <= cnt_delay + 1'b1;
- end
- else
- cnt_delay <= cnt_delay;
- end
- //根据接收到的delay数据进行计数延时
- always @(posedge clk)begin
- if(reset)
- cnt <= 16'd0;
- else if(cur_state == DELAY)
- cnt <= (delay+1'b1) * 1000-1'd1;
- else if(cur_state == COUNT)
- cnt <= cnt - 1'd1;
- else
- cnt <= cnt;
- end
- //接收delay数据
- always@(*)begin
- if(cur_state == DELAY)
- case(cnt_delay)
- 2'd0: delay[3] = data;
- 2'd1: delay[2] = data;
- 2'd2: delay[1] = data;
- 2'd3: delay[0] = data;
- default:;
- endcase
- else
- delay = 4'b0000;
- end
-
- endmodule
【题目】:本题给出了一个具有 3 输入,3 输出以及 10 个状态的 FSM 的状态转移图。仅需要实现状态转移和输出逻辑的组合逻辑,tb 会检测是否按照要求使用了独热码。
【个人思路】:
使用独热码进行输出,跟之前有类似的题,就直接做了。
- module top_module(
- input d,
- input done_counting,
- input ack,
- input [9:0] state, // 10-bit one-hot current state
- output B3_next,
- output S_next,
- output S1_next,
- output Count_next,
- output Wait_next,
- output done,
- output counting,
- output shift_ena
- ); //
-
- parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;
-
- assign B3_next = state[B2];
- assign S_next = ~d & state[S] | ~d & state[S1] | ~d & state[S110] | ack & state[Wait];
- assign S1_next = d & state[S];
- assign Count_next = state[B3] | ~done_counting & state[Count];
- assign Wait_next = done_counting & state[Count] | ~ack & state[Wait];
- assign done = state[Wait];
- assign counting = state[Count];
- assign shift_ena = state[B0] | state[B1] | state[B2] |state[B3];
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。