赞
踩
这里看的时候并不能理解,找了几篇别人的文章综合看完才想明白原理。
1.原理:首先明确的是,任何一个数除以3只能得到3个余数,0,1,2。此时的数字表示为
3a+b=c,b是余数,c是被除数。
检测完c后,序列向左移动,进来一个新的数如果是0,此时c变成了2c!
(这里可以这样理解:如果c是十进制的2,左移1位后就变成20=2*10,因为十进制是缝10进位,多1位就多1个进制的倍数,原来的个位2相当于被进了一次位变成了十位,而个位由新进来的0补上,所以二进制的假设为01进位10,1变成了2^1位,新进来的0为2^0位,c就变成了2c。)
序列向左移动,进来一个新的数如果是1,此时c变成了3a+b+1,也就是原来的余数再+1。
那么,假设新进来的是0:
当b=0,原来的3a*2=2c,依然可以被整除,所以余数还是0,输出1。
当b=1,新的数变成3a*2+1*2=2c,相当于余数翻倍变成2,输出0.
当b=2,新的数变成3a*2+2*2=2c,相当于余数翻倍变成4,新的余数是1,输出0.
那么,假设新进来的是1:
当b=0,原来的3a*2=2c+1,余数变成1,输出0。
当b=1,新的数变成3a*2+1*2+1=2c+1,余数变成0,输出1.
当b=2,新的数变成3a+2*2+1=2c+1,余数2变成5,新的余数是2,输出0.
总结成表格如下,当前余数用state,新的余数用nextstate
当前余数 | 对应状态 | 输出 | 输入的数a | 新的余数 | 对应状态 | 新的输出 |
0 | zero | 1 | 0 | 0 | zero | 1 |
1 | one | 0 | 0 | 2 | two | 0 |
2 | two | 0 | 0 | 4(1) | one | 0 |
0 | zero | 1 | 1 | 1 | one | 0 |
1 | one | 0 | 1 | 0 | zero | 1 |
2 | two | 0 | 1 | 5(2) | two | 0 |
画成状态图为 |
- //模三检测器
- //目的:判断输入序列能否被三整除,能的时候输出1,不能的时候输出0
- //逻辑:不管一个数是多少位都对应一个十进制整数,任何数除以3必然可以得到3个余数。整除时得到的余数是0,不能整除时得到的余数是1或2,
- module mo3 (clk,rst,a,result);
-
- input clk,rst,a;
- output result;
- reg [2:0] state,nextstate;
-
- //定义状态
- parameter idle=3'd0,one=3'd1,two=3'd2,zero=3'd3;
- //先写每个时钟沿产生一次可能的状态变化
- always@ (posedge clk or negedge rst)
- if(!rst)
- state<=idle;
- else state<=nextstate;
- //产生下一个状态的组合逻辑
- always@(*)
- begin
- case(state)
- idle: nextstate= a? one:zero;
- one: nextstate= a? zero:two;
- two: nextstate= a? two:one;
- zero: nextstate= a? one:zero;
- default state<=3'dx;
- endcase
- end
- assign result= (state==one)? 1:0;
- endmodule
-
- `timescale 1ns/1ps
-
- module mo3test;
- reg clk,rst;
- reg a;
- wire result;
-
- mo3 t1(.clk(clk), .rst(rst), .a(a), .result(result));
-
- always #5 clk=~clk;
-
- always #9.99 a=$random;
- initial
- begin
- clk=0;rst=1;
- #5 rst=0;
- #10 rst=1;
- #1000 $stop;
- end
-
- endmodule
到点了,感觉不太对。先回家,女朋友等了一晚上。
——————————————————————————————————————————
感谢华为树枝江哥的指导,记录在此,作为接下来的准则。
1,if后和always块都要用begin end
2,输出的信号一般用reg,就是寄存器打一拍,这样给其他模块,降低组合逻辑,时序会好很多,
3,default不要写x态,不确定,让他会到idle状态就好了,状态机保证异常条件下不会挂死,能跳出异常回到idle既可
4,default信号名错了,组合逻辑是用阻塞写法
5,定义一个信号定义一行,不要写一齐
6,代码尽量对齐
7,组合逻辑用阻塞赋值=,时序逻辑用非阻塞赋值<=
8,这种inital task function都是仿真的,逻辑代码不要出现,你代码想要信号有初始值,把他写在复位的分支里面就可以
9,一个alway块里面放一个信号就好,不然很容易出错,代码可读信差,conut一个always,clk2r一个always,然后把clk2r放在复位的分支里,就有初始值了
10,default,是去操作你always块的信号的,不用去操作你case的条件的
___________________________________________________________________________
第二天仔细检查后发现,还是一开始的逻辑不对,算错了,真值表和状态图也跟着错,就是rst置1后连续采到两个1不会输出1。
修改后的结果图为
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。