HDLBits学习记录(circuits)

一、Combinational logic

Gates
out_anotb a与b非
Truthtable1
Gatesv100

用assign实现两个向量逐位对比:

 assign out_both = in[98:0]&in[99:1];

也要注意向量拼接后和前面运算的向量长度是否相同

Mux256to1v

 assign out = in[2*sel+3:2*sel];verilog中这样的写法是错误的 ,verilog中要求向量下标可以是变量,但是位宽必须是常量,而上式无法证明位宽是常量。assign out = in[sel]是对的。

cin是前一轮的进位 cout是下一轮的进位

 assign sum = a^b^cin;
 assign cout = a&b|a&cin|b&cin;

Adder3

全加器实例化法1

 genvar i;
    generate 
            for(i=0;i<3;i=i+1)
            begin:add
                if(i==0)
                    begin//不加要出现begin对应错误
                   assign sum[0]=a[0]^b[0]^cin;
                   assign cout[0]=a[0]&b[0]|a[0]&cin|b[0]&cin;
                    end
            else
                begin
                   assign sum[i]=a[i]^b[i]^cout[i-1];
                    assign cout[i]=a[i]&b[i]|a[i]&cout[i-1]|b[i]&cout[i-1];
                end
            end
    endgenerate

signed addition overflow

溢出:当两个正数相加产生负结果或两个负数相加产生正结果时,会发生有符号溢出。有几种检测溢出的方法:可以通过比较输入和输出数的符号来计算,或者从位 n 和 n-1 的进位推导出

 assign overflow = (a[7]^s[7])&(b[7]^s[7]);

assign overflow = (a[7]&b[7]&~s[7])|(~a[7]&~b[7]&s[7])

Kmap2

卡曼图解法

二、Sequential Logic

Detect an edge(上升沿检测)

输入信号din和打一拍(寄存器寄存延迟一个时钟周期输出)信号进行组合逻辑运算来获得边沿检测

assign up_edge   = ~din_r & din;//上边沿
assign down_edge = din_r & ~din;//下边沿
assign both_edge = din_r ^ din;//双边沿

http://t.csdn.cn/7oCTI

要实现边沿检测,最直接的想法是用两级寄存器,第二级寄存器锁存住某个时钟上升沿到来时的输入电平,第一级寄存器锁存住下一个时钟沿到来时的输入电平,如果这两个寄存器锁存住的电平信号不同,就说明检测到了边沿,具体是上升沿还是下降沿可以通过组合逻辑来实现。

module top_module (
    input clk,
    input [7:0] in,
    output [7:0] pedge
);
    reg [7:0]in_d;
    always@(posedge clk)
        begin
            in_d<=in;
            pedge <= ~in_d&in;
        end
endmodule
Edge capture register

边沿检测后还要维持的话

 reg [31:0]one;
    always@(posedge clk)
        begin
            one<=in;//in_delay要在刚开始就进行 否则和赋值语句同步执行就没有delay效果了

            if(reset)
                begin
                out <= 32'b0;
                end
            else
               // one<=in;           
               out<=one&~in|out;//不光下降沿判断 判断完还保存
        end
Dualedge

非阻塞赋值只能用于寄存器型变量,只能在initial块和always块中使用。阻塞赋值既可以用于寄存器型变量,也可以用于线网型变量

所以块外的assign语句要用阻塞赋值 他没有时序逻辑是组合逻辑

Counter1-12

设计一个1-12的计数器,有以下输入和输出:
Reset同步active-high复位,强制计数器到1
Enable设置high,计数器运行Clk正向边缘触发时钟输入
Q[3:0]计数器的输出
c_enable, c_load, c_d[3:0]控制信号到达提供的4位计数器,因此可以验证正确的操作。
您有以下可用的组件:
下面的4位二进制计数器(count4),它具有Enable和同步并行负载输入(load优先级高于Enable)。count4模块提供给您。在你的电路中实例化它

module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
); //
	assign c_enable=enable;
    assign c_load=reset|((enable==1)&&(Q==4'd12));//等待
    assign c_d=(c_load)?4'd1:4'd0;//计数器 复位和记到12强制为1
        count4 the_counter (clk, c_enable, c_load, c_d ,Q);

endmodule
Counter 1000

从 1000 Hz 时钟导出一个称为OneHertz的 1 Hz 信号,该信号可用于驱动一组小时/分钟/秒计数器的启用信号,以创建数字挂钟。由于我们希望时钟每秒计数一次,因此OneHertz信号必须每秒准确地断言一个周期。使用模 10 (BCD) 计数器和尽可能少的其他门构建分频器。还要从您使用的每个 BCD 计数器输出使能信号(c_enable[0] 为最快的计数器,c_enable[2] 为最慢的)。为您提供以下 BCD 计数器。Enable必须为高电平才能使计数器运行。复位是同步的并设置为高以强制计数器为零。电路中的所有计数器必须直接使用相同的 1000 Hz 信号。

这题提供的是一个1000hz的时钟 我们要转化成1hz时钟的话 只有1000hz运行一个周期才能得到一个1hz,所以我们要让三个bcd分别代表个位十位百位 每位均取9得到999让onehertz输出为1

module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); 
    wire [3:0]one,ten,hundred;
    assign OneHertz=(one==4'd9&&ten==4'd9&&hundred==4'd9);
    assign c_enable={one==4'd9&&ten==4'd9,one==4'd9,1'd1};
    bcdcount bcdcount_one (clk, reset, c_enable[0],one);
    bcdcount bcdcount_ten (clk, reset, c_enable[1],ten);
    bcdcount bcdcount_hun(clk, reset, c_enable[2],hundred);
endmodule
Countbcd

构建一个 4 位 BCD(二进制编码的十进制)计数器。每个十进制数字使用 4 位编码:q[3:0] 是个位,q[7:4] 是十位等。对于数字 [3:1],还输出一个使能信号,指示个位,十位,百位何时应加1。

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    assign ena[1]=(q[3:0]==4'b1001);//只在进位时候取一 一般都置0
    assign ena[2]=(q[3:0]==4'b1001&&q[7:4]==4'b1001);
    assign ena[3]=(q[3:0]==4'b1001&&q[7:4]==4'b1001&&q[11:8]==4'b1001);
    BCD_count one(clk,1'd1,reset,q[3:0]);
    BCD_count ten(clk,ena[1],reset,q[7:4]);
    BCD_count hur(clk,ena[2],reset,q[11:8]);
    BCD_count tho(clk,ena[3],reset,q[15:12]);
endmodule

module BCD_count(
    input clk,
    input enable,
    input reset,
    output [3:0]Q
    //output c_enable
);
    always@(posedge clk)
        begin
        if(reset)
            begin
            Q<=4'b0;
            end
            else if(Q==4'b1001&&enable==1)//要即等于9又有ena信号才能置0,否则高位一等于9就置0没办法保持一个计数周期
                begin
                 Q<=4'b0;
                end
            else if(enable)
                begin
                Q<=Q+4'b0001;
                end
        end
endmodule

三、Shift Registers

32-bit LFSR

Build a 32-bit Galois LFSR with taps at bit positions 32, 22, 2, and 1

右移:>>

哪位有抽头就异或他和p[0]

Shift register

置0要把每一个过度变量都置0,要不然过几个周期不为0的输出了会出错

Shift register

创建一个模块然后引用

module MUXDFF (
    input clk,
    input E,
    input L,
    input W,
    input R,
    output q);
    wire a;
    always@(posedge clk)
        begin
            a=(E)?W:q;//阻塞赋值
            q=(L)?R:a;
          //  q <= (L)?R:((E)?W:q);
        end
endmodule

这里要用阻塞赋值 因为如果非阻塞的话 这里的q取得是上个时钟的a 不是刚才更新的a

3-input LUT
module top_module (
    input clk,
    input enable,
    input S,
    input A, B, C,
    output Z ); 
    reg [7:0]q;
    always@(posedge clk)
        begin
            if(enable)
              begin
                  q<={{q[6:0]},S};//q[0]为S 前面为移位寄存器一步一步移位,即为q的0-6位
              end
            else
                q<=q;
        end
    assign Z=q[{A,B,C}];//可以不写case直接这么写
                  
  
endmodule

四、More Circuits

Rule 90

一次一次异或的原理

always @(posedge clk)
        begin
            if(load)begin
                q <= data;
            end
            else begin
                q <= {1'b0,q[511:1]}^{q[510:0],1'b0};//补齐最高位和最低位
            end

五、Finite State Machines

Fsm1

状态机:
        状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:

第一类,若输出只和状态有关而与输入无关,则称为Moore状态机

第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机

原文链接:https://blog.csdn.net/m0_67839421/article/details/127217631

 parameter A=0, B=1; 
    reg state, next_state;

    always @(*) begin    // This is a combinational always block 描述状态寄存器
       case(in)
          1: next_state<=state;
           0:next_state<=(state)?A:B;
       endcase
    end

    always @(posedge clk, posedge areset) begin    // This is a sequential always block组合逻辑输出
        if(areset)
            state<=B;
        else
            state<=next_state;
    end

    // Output logic
    assign out = (state == B);//通过逻辑判断输出

最后使用组合逻辑对结果进行判断,但组合逻辑容易产生毛刺等不稳定因素。 

Simple one-hot state transitions 3

独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。通常,在通信网络协议栈中,使用八位或者十六位状态的独热码,且系统占用其中一个状态码,余下的可以供用户使用。 

例如,有6个状态的独热码状态编码为:000001,000010,000100,001000,010000,100000。

parameter A=0, B=1, C=2, D=3;
    assign next_state[A] = (state[A]&~in)|(state[C]&~in);
    assign next_state[B] = (state[A]&in)|(state[B]&in)|(state[D]&in);
    assign next_state[C] = (state[B]&~in)|(state[D]&~in);
    assign next_state[D] = (state[C]&in);
    assign out = (state[D]);
Simple FSM 3

和上一个对比着看吧

  parameter A=0,B=1,C=2,D=3;
    reg[1:0] state,next_state;
    
    always@(*)
        begin
            case(state)
                A:next_state = (in)?B:A;
                B:next_state = (in)?B:C;
                C:next_state = (in)?D:A;
                D:next_state = (in)?B:C;
            endcase
        end
    // State transition logic

    always@(posedge clk or posedge areset)
        begin
            if(areset)
                state<=A;
            else state<=next_state;
        end
    // State flip-flops with asynchronous reset
    assign out = (state==D);
    // Output logic
Lemmings1
  parameter LEFT=0, RIGHT=1;
    reg state, next_state;

    always @(*) begin
        // State transition logic
        case(state)//判断变化没有 没有就维持原样 刚开始if的写法没有维持原样
            LEFT:next_state<=bump_left?RIGHT:LEFT;
            RIGHT:next_state<=bump_right?LEFT:RIGHT;
        endcase
    end

    always @(posedge clk, posedge areset) begin
        // State flip-flops with asynchronous reset
        if(areset)
            begin
               state<=LEFT;
            end
        else
            state<=next_state;   
    end

    // Output logic
    assign walk_left = (state == LEFT);
     assign walk_right = (state == RIGHT);
Lemmings2

增加两个状态 往左走掉下去和往右走时候掉下去

 parameter LEFT=2'b00,RIGHT=2'b01,fallr=2'b11,falll=2'b10;
    reg [1:0]state,next_state;
    always@(*)
        begin
            case(state)
            LEFT:
                begin
                    if(ground)
                        begin
                   next_state<=bump_left?RIGHT:LEFT;
                        end
                    else
                        begin
                        next_state<=falll;
                        end
                end        
            RIGHT:
                begin
                    if(ground)
                        begin
                        next_state<=bump_right?LEFT:RIGHT;
                        end
                    else
                        begin
                             next_state<=fallr;
                        end
                end
                falll:
                    if(!ground)
                        begin
                            next_state<=falll;
                        end
                else
                    begin
                        next_state<=LEFT;
                    end
                fallr:
                    if(!ground)
                        begin
                            next_state<=fallr;
                        end
                else
                    begin
                        next_state<=RIGHT;
                    end
            endcase
        end
    always@(posedge clk,posedge areset)
        begin
            if(areset)
                begin
                    state<=LEFT;
                end
           
            else
                begin
                state<=next_state;
                end
          
        end
      assign walk_left = (state == LEFT);
     assign walk_right = (state == RIGHT);
    assign aaah=(state==fallr)|(state==falll);
Lemmings3
  digl://dig优先级高于转向 开始挖了就一直挖直到地塌陷
                        begin
                          if(!ground)
                            begin
                               next_state<=falll;
                            end
                               /* else if(dig)
                                    begin
                                        next_state<=digl;
                                    end*/
                            else
                                begin
                               next_state<=digl;
                                end
                        end 
                    digr:
                         begin
                        if(!ground)
                            begin
                               next_state<=fallr;
                            end
                                else 
                                    begin
                                        next_state<=digr;
                                    end
                           /* else
                                begin
                               next_state<=right;
                                end*/
                        end
one-hot FSM

题目会给非onehot编码来验证 所以他希望用状态机来写不是case的default归于一个值

Serial receiver
 always@(*)begin
        case(state)//增加一个等待和初始状态 等到信号开始start
            start:next_state<=one;
            one:next_state<=two;
            two:next_state<=thr;
            thr:next_state<=fou;
            fou:next_state<=fiv;
            fiv:next_state<=six;
            six:next_state<=sev;
            sev:next_state<=eig;
            eig:begin
                if(in)
                    next_state<=stop;
            	else
                next_state<=waitt;
            end
            stop:begin
                if(in)
                     next_state<=fir;
                else
                     next_state<=start;
            end
            waitt:begin
                if(in)
                    next_state<=fir;
                    else
                       next_state<=waitt;
            end
            fir:begin
                if(!in)
                    next_state<=start;
                else
                    next_state<=fir;
            end
        endcase

Iteration limit 5000 reached at time 0 ps

出现这个错误的原因是:代码中的组合逻辑存在回环,也就是说对敏感列表中的变量进行赋值,造成回环,在仿真的时候modelsim对电路中的回环不断迭代,直到超出了迭代界限。
方法:修改代码中的组合逻辑,注意不要对敏感列表中的变量赋值,或者将组合逻辑写成时序逻辑。modelsim error:iteration limit reached at time xxx ns._薛定谔的bug~的博客-CSDN博客

Serial receiver and datapath

这边的第一个有效位指的是start而不是d1,再done的时候输出整个序列

Serial receiver with pariting checking

不太懂为什么 暂存问题

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //

    parameter start=4'd0,D1=4'd1,D2=4'd2,D3=4'd3,D4=4'd4,D5=4'd5,D6=4'd6,D7=4'd7,D8=4'd8,stop=4'd9,idle=4'd10,WAIT=4'd11,par=4'd12;
    reg [4:0] state,next_state;
    reg [7:0] temp_in;
    wire odd;
    //wire[3:0]count=4'd0;
    always @(*)
        begin
            case(state)
                start: begin next_state = D1; temp_in[0] = in; end
                D1: begin next_state = D2; temp_in[1] = in; end
                D2: begin next_state = D3; temp_in[2] = in; end
                D3: begin next_state = D4; temp_in[3] = in; end
                D4: begin next_state = D5; temp_in[4] = in; end
                D5: begin next_state = D6; temp_in[5] = in; end
                D6: begin next_state = D7; temp_in[6] = in; end
                D7: begin next_state = D8; temp_in[7] = in; end
                D8:begin
                    if(in)
                        next_state = par;
                    else
                        next_state = WAIT;
                end
                par:begin
                    if(in)
                        next_state = stop;
                    else
                        next_state = WAIT;
                end
                stop:begin
                    if(in)
                        next_state = idle;
                    else
                        next_state = start;
                end
                idle:begin
                    if(in)
                        next_state = idle;
                    else
                        next_state = start;
                end
                WAIT:begin
                    if(in)
                        next_state = idle;
                    else
                        next_state = WAIT;
                end
                default:next_state = idle;
            endcase
        end
    
      always@(posedge clk)begin
          if(reset)
              state<=idle;  
          else
              state<=next_state;
        end
       always@(posedge clk)begin
          if(reset)
              done<=1'd0;         	  
          else if((next_state == stop)&&(odd==1))
              done<=1'd1;
              else
               done<=1'd0;
        end      
    always@(posedge clk)begin
          if(reset)
             out_byte<=8'b0;         	  
          else if((next_state == stop)&&(odd==1))
              out_byte<=temp_in;
              else
               out_byte<=8'b0;
        end     
    //assign done = (next_state == stop)&&(odd==1);
   // assign out_byte = done?temp_in:8'b0;
	wire reseta;
    assign reseta=(reset==1)||(next_state==start);
    parity one(clk,reseta,in,odd);
endmodule
Design a Mealy FSM

错误提示:Error (10200): Verilog HDL Conditional Statement error at ……: cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct
这是因为,“always@(posedge clk or negedge r_est)”表明在clk上升沿或r_est下降沿这两个敏感事件发生时always语句块得以触发;而always中的if条件语句必须至少有一个条件指向其中一个敏感事件(边界标识符);所以写成“if(r_est)...else...”就会出错。
把“always@(posedge clk or negedge r_est)”改为“always@(posedge clk or posedge r_est)”再编译试试,就没问题了。

两种状态机:

1:输出只和当前状态有关而与输入无关,则称为摩尔(Moore)状态机;

2:输出不仅和当前状态有关而且和输入有关,则称为米利(Mealy)状态机;

 always@(*)begin
        case(state)
            s1:begin
                next_state<=x?s2:s1;
            end
            s2:begin
                next_state<=x?s2:s3;//如果s2不为0不回初始状态而是等下一个0
            end
            s3:begin
                next_state<=x?s2:s1;//s3是1的话就回s2等下一个1
            end
            default:next_state<=s1;
        endcase
        end
补码:计算数N的补码,所要做的就是将X的每一位取反,然后将取反结果加1 Q3a:FSM

 parameter A=0,B=1;
    reg [1:0]tcount,wcount;//搭配两个计数器 一个计有几个一 一个计时钟012012循环
    reg[1:0]state,next_state;
    always@(*)begin
        case(state)
        A:next_state<=s?B:A;
        B:next_state<=B;
            default:next_state<=A;
    endcase
    end
    always@(posedge clk)begin
        if(reset)
            state<=A;
        else
            state<=next_state;
    end
    
     always@(posedge clk)begin
        if(reset)
            tcount<=2'd0;
         else if(state==B)begin
             if(tcount==2'd2)
                 begin
            	tcount<=2'd0;
                 end
             else
                tcount<=tcount+1;
         end
         else 
             begin
             tcount<=2'd0;
             end
    end
    
    always@(posedge clk)begin
        if(reset)
            wcount<=2'd0;
        else if(state==B)begin
            if(tcount==2'd0)begin
                wcount<=w?2'd1:2'd0;
            end
            else if(w==1)begin
                wcount<=wcount+1;
            end
            else
                wcount<=wcount;
        end
        else
             wcount<=2'd0;
    end
    always@(*)begin
        case(state)
        A:z<=0;
            B:z<=(tcount==2'd0)&&(wcount==2'd2);//一个周期结束并且计数到两个
    endcase
    end
Q6c:FSM one-hot next-state log

假设您触发器和hot码显示此 FSM 的状态分配表。导出触发器y[2]和y[4]的下一个状态表达式。

parameter A=3'd1,B=3'd2,C=3'd3,D=3'd4,E=3'd5,F=3'd6;
    reg[6:0]next_state;
    always@(*)begin
        case(y)
            A:next_state<=w?A:B;
            B:next_state<=w?D:C;
            C:next_state<=w?D:E;
            D:next_state<=w?A:F;
            E:next_state<=w?D:E;
            F:next_state<=w?D:C;
        endcase
    end
    assign Y2=~w&y[A];
    assign Y4=w&(y[B]|y[C]|y[E]|y[F]);//用当前状态写下一个状态

Q2b:Another FSM

parameter A=4'd0,B=4'd1,C=4'd2,D=4'd3,E=4'd4,F=4'd5,FONE=4'd6,FZERO=4'd7,G=4'd8;
    reg[3:0]state,next_state;
    always@(*)begin
        case(state)
            A:next_state<=B;
            B:next_state<=C;
            C:next_state<=x?D:C;
            D:next_state<=x?D:E;
            E:next_state<=x?F:C;
            F:next_state<=y?FONE:G;
            G:next_state<=y?FONE:FZERO;
            FONE:next_state<=FONE;
            FZERO:next_state<=FZERO;
            default:next_state<=A;
        endcase
    end
    always@(posedge clk)begin
        if(!resetn)
            state<=A;
        else
            state<=next_state;
    end
    assign f=(state==B);
    assign g=(state==F)||(state==G)||(state==FONE);

六、 Building Large Circuits

NAND

Sequential cricuit 8
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值