P1做题记录

pigKiller

本次的三道题目主要考插入了组合逻辑中的乘法、moore状态机和状态机。

分享一下自己的做法,欢迎大家批评指正。

向量乘法

本题的要求是将ver_aver_b两个32位向量数进行逐位相乘,再把每一位的结果加起来作为输出。

可以把这道题分为两个部分:

  1. 逐位相乘
  2. 相加

首先,对于逐位相乘。1位二进制数的乘法和与操作等价,故可以把ver_aver_b进行与操作,这样便捷地实现了逐位相乘的效果。

其次,对于诸位相加,我采用的方法是使用for循环实现,在verilogfor循环只能在always块(或initial块)中使用。而本题是一道组合逻辑的题目,故采用always @(*),实现组合逻辑。

由于位数不是特别多,本题的另一种方法是Ctrl cv大法,万一以后有更大规模的数据,全面准备吧()

代码框架为:

1
2
3
4
assign ver=ver_a&ver_b;
//i也可以是integer型变量
for(i=0;i<32;i++) begin
sum=sum+ver[i];

筛子涂色问题

这道题是一道moore型状态机问题,根据当前状态的输入(涂色),进行状态转移(涂色后目前的颜色是什么)。但是需要注意的是,尽管是moore型状态机,但是错误信息需要在当前周期就进行输出。

我的思路是这样的,一共四个状态:初始状态S0、红S1、蓝S2、绿S3。再使用一个寄存器保存了当前颜色出现了多少次。

如果红和绿相遇了,或者当前的颜色出现到第三次,按照题意,清除上一次的输入,故只需要将输出置1,并不需要进行状态转移

展示一个状态的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
//...
if(status==`Red) begin
if(in==`red) begin
if(count==2) Is_Error;
else Is_good;
end
else if(in==`green) Is_error;
else begin
count=1;
//balabala
end
end

个人觉得,相比更面向硬件的logisimverilog很好的一点就是状态转移的一大部分用一个else就可以。

随着见到了越来越多的检查型的状态机题目,不少是一个不符合就需要扔到初始状态或者垃圾桶状态logisim中的线路连接很烦,但是verilog只需要一个else

异步复位问题

另外这一题值得一说的就是异步复位问题,在之前的课下中,我们所见过的复位都是高电平有效,而这道题目的异步复位信号是低电平有效

先来看下这段代码:

1
2
3
4
5
6
7
8
9
always @(rst_n) begin
if(rst_n==0) begin
//reset
end
end

always @(posedge clk) begin
//balabala...
end

这段代码是不能实现异步复位操作的,为何:

  1. always模块是响应信号变化,如果rst_n一直是低电平,则只有最初的由高电平转为低电平的那个下降沿会被always响应。如果后续一直是低电平,则无法响应
    • 如果想要实现操作,则应该在下面一个always块中加上if(rst_n==0),但是这样此拆分成两个always块就显得有些多次一举了
  2. 这样写还有一个规范问题,那就是reset会无可避免地修改状态量,在两个always模块中都对变量进行赋值,这是不符合规范的,应该避免

正确的异步复位操作可以是这样的:

1
2
3
4
5
6
always @(posedge clk or negedge rst_n) begin
if(rst_n==0)
//reset
else
//balabala...
end
  • 如果rst_n一直是低电平,则会在时钟沿被识别进行同步复位。

  • 如果rst_n是由高电平变为低电平,则必然有一个下降沿过程,可以用negedge进行识别信号

数字上升下降匹配

这道题有两种做法,一种是设计具有6个状态的状态机,在读入时进行状态转移和匹配;另一种的做法更为普遍,是识别数据的上升下降,如果匹配了上升下降+数量匹配,则输出。

状态机

输入只有1-5,故可以设计一个6状态状态机,记录当前序列到哪里了。

如果连续输入的数是奇数个(分析见下),则顺利转移到下一个状态,否则报错。

这里状态机的书写并不难,就略去状态转移图和代码了。

上升下降匹配

这是一种更为普遍的做法。本体的数据输入只有1-5,还可以用状态机解决,但是如果大胆一点,把输入扩展到1-100,手写101种状态的状态机显然是不太显示,这时候这种方法依然能解决,具有较强的适应性。

分析题目:

  1. 对于数据,上升下降必须是相邻的,n的下一个输出只能是n-1或n+1,并且上升下降性质必须不变
  2. 同一个数字在上升下降中分别出现奇数次
    1. 这道题需要解决的就是12233221并不匹配,因为两个2完成了“贪婪匹配”,3并不包在序列中,像一个俄罗斯方块一样,只要同一个数字相邻出现偶数次就相消了:12223321123321相比,如果是正确的数字,重复的数字必须在相邻处完成匹配。
    2. 实际上这个问题相当好解决,只需要检查一侧的正确性,如果一个数,重复出现了奇数次,相当于只出现了一次;重复出现了偶数次,则相当于没出现。
    3. 用一个寄存器存下当前数字相邻出现了几次,在下一个更大数/更小数来临时,则可以判断是否是正确的序列

给出部分伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
if(IsDown) begin
if(number==num_now+1 && cnt%2==1) begin
cnt<=1;
end
else if(number==num_now) begin
cnt<=cnt+1;
end
else if(number==num_now-1) begin
IsDown=1;
cnt<=cnt+1;
end
num_now<=number;
end

廖鹏飞

同学你好,看了你关于异步复位部分的讲解,我有很多收获。之前我对于异步复位的理解仅限于代码实现方式上(只会写不会解释),通过这篇详细的总结,我完全理解了异步复位的各种细节。

但是,我还有一个问题,这样的实现方式对下降沿(上升沿)敏感,但要是rst_n一开始就是0这种情况如何正确对状态置初值呢?或者说如果rst_n一直保持0,如何正确实现清零操作?


朱雄伟 回复 廖鹏飞

rst_n一直为0的话,当clk上升沿到来时,也会执行reset操作,希望能帮到你


fysszlr 回复 廖鹏飞

同学你好,一般来说题目会保证在数据到来前清零,所以不需要担心类似的情况,希望能帮到你~

0%