HDLBits刷题Day04

博客围绕Verilog的Always块展开,介绍了可综合出电路硬件的综合逻辑和时序逻辑两种Always块,还提及Verilog的三种赋值方法及适用场景。此外,讲解了if、case语句在过程块的使用,以及优先编码器、锁存器等电路设计要点,强调设计时要避免锁存器问题。


强烈建议大家去看看HDLBits 中文导学,原文在知乎
链接: link.

28.Always blocks

简单的always块的介绍,

有两种always块是可以综合出电路硬件的:
1.综合逻辑:always @(*)
2.时序逻辑:always @(posedge clk)

always @(*) out_alwaysblock=a&b;
综合逻辑中“ * ”号,我理解的是默认全部变量,挨个去写的话,容易遗漏。

29.Always blocks2

always @(posedge clk)
时序逻辑会在生成的组合电路之后,添加一个触发器或者寄存器,在下一个时钟的上升沿才会触发。
Blocking vs. Non-Blocking Assignment(阻塞/非阻塞赋值)

Verilog三种赋值方法:

  1. 连续赋值:assign x = y,能用于过程块;
  2. 阻塞赋值:x = y,只能用在过程块中;
  3. 非阻塞赋值:x <= y,只能用于过程块;

一般的,组合always块中,使用阻塞性赋值。在时序always块中,使用非阻塞性赋值;

30.Always_if

if语句只能在过程块使用,一般用来表示一个2选1选择器;

always @(*) begin
   if (condition) begin
       out = x;
   end
   else begin
       out = y;
   end
end

其功能和c语言中的条件赋值语句类似

assign out = (condition) ? x : y;
 assign out_assign=(sel_b1&sel_b2)?b:a;
 
    always@(*) begin
        if(sel_b1&sel_b2) begin
            out_always=b;
        end
        else begin
            out_always=a;
        end
    end
        

31.Always if2–latch(锁存器)

这边大概的意思:首先,设计电路时不要急功近利,要自底向上一层层的去实现,再然后就是,可能你的电路设计出来,在没有触发器的情况下,在收到某些输入之后,输出可能保持不变,电路的输出要想保持不变就需要锁存器,当你没有时就会报错

Warning (10240): ... inferring latch(es)

即便你的Verilog代码没有语法上的错误这不代表着你的电路就是完全正确的;

 always @(*) begin
        if (cpu_overheated) begin
           shut_off_computer = 1;
    end
    else begin
           shut_off_computer = 0;
    end
    
    end

    always @(*) begin
        if (~arrived&& ~gas_tank_empty)begin //既没有到达并且还有油;
           keep_driving = 1;
    end 
    else begin
         keep_driving = 0;
    end
    end
 

32 Always case

case语句

always @(*) begin     // This is a combinational circuit
    case (in)
      1'b1: begin 
               out = 1'b1;  // begin-end if >1 statement
            end
      1'b0:    out = 1'b0;
      default: out = 1'bx;
    endcase
end
  1. 每条选择语句case开头,冒号结束;
  2. 一般一个case一个语句,多于一个的时候就要加上begin and;
  3. 允许重复的case ,优先执行第一条
 always@(*) begin  // This is a combinational circuit
        case(sel)//sel 选择信号,3位2进制
            3'b000: out=data0;
            3'b001:out=data1;
            3'b010: out=data2;
            3'b011: out=data3;
            3'b100: out=data4;
            3'b101: out=data5;
            default: out = 4'b0000;
        endcase
    end

33.Always case-priority encoder(优先编码器)

优先编码器:输出从右边往左的第一个1的位置;
简单译码器: 输入只能有一个1。出现多个1的时候视不同情况有不同的处理方式。

always@(*)
     case(in)
        4'b0000:pos=2'b00;//4'h0: pos = 2'h0;
        4'b0001:pos=2'b00;//4'h1: pos = 2'h0;
        4'b0010:pos=2'b01;//4'h2: pos = 2'h1;
        4'b0011:pos=2'b00;//4'h3: pos = 2'h0;
        4'b0100:pos=2'b10;//...
        4'b0101:pos=2'b00;
        4'b0110:pos=2'b01;
        4'b0111:pos=2'b00;
        4'b1000:pos=2'b11;
        4'b1001:pos=2'b00;
        4'b1010:pos=2'b01;//4'ha: pos = 2'h1;
        4'b1011:pos=2'b00;//...
        4'b1100:pos=2'b10;
        4'b1101:pos=2'b00;
        4'b1110:pos=2'b01;
        4'b1111:pos=2'b00;
       default: pos = 2'b00;//可以不写因为所有的16个数全都包含了;
    //用16进制写更加方便不用写4位二进制数;
        endcase

34.priority encoder–caseZ

我就说上一题为啥要这么写,没有模糊选项吗,它来了;

  always@(*)
        casez(in)
         8'bzzzzzzz1:pos=3'h0;
         8'bzzzzzz1z:pos=3'h1;
         8'bzzzzz1zz:pos=3'h2;
         8'bzzzz1zzz:pos=3'h3;
         8'bzzz1zzzz:pos=3'h4;
         8'bzz1zzzzz:pos=3'h5;
         8'bz1zzzzzz:pos=3'h6;
         8'b1zzzzzzz:pos=3'h7;
            default : pos=3'h0;
            //解析里pos直接等于1,2,3...不知道为啥可以;
        endcase

35.Always nolatches

有时候输入可能很多,但是我们某些时候只用得到其中的一些,为了前面的不加锁存器原则,必须给那些用不到的也赋值默认值;

    always@(*) 
    
    casez(scancode)
        16'he06b: begin 
        up = 1'b0; 
        down = 1'b0;
        left = 1'b1;
        right = 1'b0; 
          end
        16'he072: begin 
        up = 1'b0; 
        down = 1'b1; 
        left = 1'b0; 
        right = 1'b0;
         end
        16'he074: begin 
        up = 1'b0; 
        down = 1'b0; 
        left = 1'b0; 
        right = 1'b1; 
          end
        16'he075: begin 
        up = 1'b1; 
        down = 1'b0; 
        left = 1'b0; 
        right = 1'b0;
          end
        default:  begin 
         up = 1'b0; 
         down = 1'b0; 
         left = 1'b0; 
         right = 1'b0;
           end
    endcase
endmodule

赋值默认值之后;

always@(*)
begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    casez(scancode)
        16'he06b: left = 1'b1;
        16'he072: down = 1'b1;
        16'he074: right = 1'b1; 
        16'he075: up = 1'b1;
    endcase
end
### 关于蓝桥杯竞赛中的C语言回文字符串练习及其解法 对于蓝桥杯竞赛中涉及的回文字符串问,在C语言环境下可以通过多种方式实现。下面提供一种常见的解决方案,该方案不仅适用于比赛环境下的快速编写需求,同时也能够帮助理解如何高效处理此类逻辑。 #### 定义与初步准备 首先定义什么是回文串——即正读反读均相同的序列。为了简化输入输出过程并提高程序可移植性,这里假设已经通过标准输入获取了一个不含空白符的纯字母数字组成的字符串[^1]。 #### 实现思路 核心在于构建两个指针分别指向待检测字符串首尾两端并向中间靠拢比较对应位置上的字符是否相等直到相遇为止;如果过程中遇到不匹配的情况则立即返回不是回文的结果;反之当循环结束仍未发现差异时说明给定字符串确实构成回文特性。 ```c #include <stdio.h> #include <string.h> int isPalindrome(char str[]) { int i = 0; int j = strlen(str) - 1; // 获取字符串长度减去终止符'\0'的位置 while(i < j){ if(str[i++] != str[j--]) return 0; // 若有任意一对不同,则非回文 } return 1; // 所有对比项相同视为回文 } void main(){ char testStr[]="level"; if(isPalindrome(testStr)){ printf("%s 是回文。\n",testStr); }else{ printf("%s 不是回文。\n",testStr); } } ``` 上述代码展示了基本框架以及具体操作细节,其中`isPalindrome()`函数负责执行实际判定工作而`main()`部分用于测试验证目的。 #### 进一步优化建议 考虑到可能存在的大小写字母混杂情况或是其他特殊符号干扰因素,在正式比赛中应当先对原始数据做适当预处理比如统一转换成小写形式或者忽略掉所有非字母字符后再进行后续分析以确保准确性[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值