一个有趣的异步时序逻辑电路设计实例 ——MFM调制模块设计笔记
本文从本人的163博客搬迁至此。
MFM是改进型频率调制的缩写,其本质是一种非归零码,是用于磁介质硬盘存储的一种调制方式。调制规则有两句话,即两个翻转条件:
1、为1的码元在每个码元的正中进行一次翻转;为0的码元不翻转。
2、对连续两个为0的码元,则在第一个为0的码元结束时翻转一次;单个的0码元不翻转。
设计过程:
若码元的同步时钟为CLK,不失一般性,假设CLK的上升沿开始产生新的码元,下降沿为该码元的正中。则MFM调制信号有可能在时钟的上升沿,也有可能在时钟的下降沿发生电平翻转。由于一个触发器不会在两个边沿都翻转,也就不可能由单个触发器的输出作为MFM调制的输出。一种合理的思路是分别由一个上升沿和一个下降沿触发器分别在上升沿和下降沿翻转,然后用它们的输出相异或的结果作为总输出。特别值得注意的是,异或具有如下的属性:参与异或的两个数,不论其中一个为0或1,只要另一个发生翻转,异或的结果一定会翻转。下面分别来实现MFM调制规则的两个条件,即在满足条件1时翻转的电路——设其输出为Dout1,和满足条件2时翻转的电路——设其输出为Dout2,再将它们异或为最终的MFM调制结果Dout。
条件1要求在为1的码元的正中进行一次翻转,比较容易实现,使用受控的触发器时钟即可。条件2较难实现,原因在于其对应的触发器需要在第二个码元为0的还没有到来之前,先就对是否存在两个连续为0的码元做出判断,并在第二个为0的码元开始出现的上升沿就先翻转。由于我们的电路不可能“未卜先知”地知道上升沿出现后的码元是否为0,只能让判断条件2的电路延迟(潜伏)一个时钟(CLK)周期后再发生翻转。当然由于条件2翻转的触发器电路,需要延迟一个CLK,条件1翻转的触发器电路也必须随之延迟一个时钟周期,以同步于条件2翻转的电路。图1中的DinD就是延迟一个时钟周期后的输入被调制信号。

图1 MFM调制电路及其时序
满足条件1的电路,应该由两部分构成。第一个部分在上升沿动作,完成延迟一个时钟周期。第二部分则在下降沿动作,当码元为1时在下降沿翻转Dout1,为一个T'触发器。
满足条件2的电路,也由两部分组成。第一个部分是一组下降沿移位寄存器,该移位寄存器有两个D触发器构成,负责保存最近两个下降沿时刻码元的值,当两个触发器同时为0时输出允许Dout2翻转的信号。第二个部分是在第一部分允许的条件下,在上升沿翻转的T'触发器,其输出就是Dout2。
从图中可以看到,本电路是一个典型的异步时序逻辑电路,为了在连续的一个/组下降沿和上升沿之间不间断地动作,满足条件1的电路和满足条件2的电路的前后两个部分所使用的时钟边沿都不相同。使用硬件描述语言时,需要分别使用两个always模块来对应上升沿和下降沿电路。由于上升沿电路和下降沿电路交叉出现在两个always模块中,这段VerilogHDL不太容易直接看懂。
module MFM(
input CLK, //产生被调制信号的时钟,其周期等于被调制信号一个码元的宽度
input Din, //被调制信号
input rst, //复位信号
output DinD, //延迟了一个clk周期的被调制信号
output Dout1, //为1的码元在码元正中翻转的信号
output Dout2, //连续两个为0的码元,在两个码元之间翻转的信号
output MFM_Dout //Dout1和Dout2异或的结果,也就是DOUT1和Dout2翻转时都翻转的信号。
);
reg DinD_reg;//这个寄存器的值将输入延迟了一个时钟周期
reg Dout1_reg;//Dout1对应的寄存器
reg Dout2_reg;//Dout2对应的寄存器
reg[:] D_reg_n; //在下降沿缓冲两级输入,以判断是否是连续两个0
assign DinD = DinD_reg;
assign Dout1 = Dout1_reg;
assign Dout2 = Dout2_reg;
assign MFM_Dout = Dout1^Dout2;
//异或的属性就是不论第一个自变量为0还是1,只要第二个自变量变化,结果都会跟着变化,因此MFM_Dout可以在DOUT1和Dout2翻转时都翻转
always @(posedge CLK or posedge rst)
begin
if(rst)
begin
DinD_reg <= ;
Dout2_reg <= ;
end
else begin
DinD_reg <= Din;
if(~(D_reg_n[]|D_reg_n[]))
//如果D_reg_n[0]和D_reg_n[1]都为0则翻转Dout2
Dout2_reg <= ~Dout2_reg;
end
end
always @(negedge CLK or posedge rst)
begin
if(rst)
begin
Dout1_reg <= ;
D_reg_n[:] <= 'b11;
end
else begin
if (DinD == )
Dout1_reg <= ~Dout1_reg;
D_reg_n[:] <= {D_reg_n[],Din};
//缓冲两个下降沿时的输出,如果都为0,则需要在下一个上升沿翻转Dout2
end
end
endmodule
上述代码在Vivado中综合后,得到下图所示的Schematic。

图2 在Vivado中综合后产生的Schematic
这个实例再次印证了用硬件描述语言开发硬件电路的那个准则:在开始描述之前,脑中应该先有电路的大概模型,否则不可能综合出满足要求的硬件电路。
一个有趣的异步时序逻辑电路设计实例 ——MFM调制模块设计笔记的更多相关文章
- 一个有趣的小例子,带你入门协程模块-asyncio
一个有趣的小例子,带你入门协程模块-asyncio 上篇文章写了关于yield from的用法,简单的了解异步模式,[https://www.cnblogs.com/c-x-a/p/10106031. ...
- FPGA学习笔记(六)—— 时序逻辑电路设计
用always@(posedge clk)描述 时序逻辑电路的基础——计数器(在每个时钟的上升沿递增1) 例1.四位计数器(同步使能.异步复位) // Module Name: coun ...
- 04-时序逻辑电路设计之计数器——小梅哥FPGA设计思想与验证方法视频教程配套文档
芯航线--普利斯队长精心奉献 实验目的:以计数器为例学会简单的时序逻辑电路设计 实验平台:芯航线FPGA核心板 实验原理: 时序逻辑电路是指电路任何时刻的稳态输出不仅取决于当前的输入,还与前一时刻输入 ...
- verilogHDL设计中的同步时序逻辑
引用自夏宇闻教授 1.同步时序逻辑: 是指表示状态的寄存器组的值只能在唯一确定的触发条件发生改变. 只能由时钟的正跳变沿或者负跳变沿触发的状态机就是一例,always@(posedge clk). 1 ...
- 03-组合逻辑电路设计之译码器——小梅哥FPGA设计思想与验证方法视频教程配套文档
芯航线——普利斯队长精心奉献 课程目标: 1. 再次熟悉Quartus II工程的建立以及完整的FPGA开发流程 2. 以译码器为例学会简单组合逻辑电路设计 实验平台:无 实验原理: 组合逻辑, ...
- 组合逻辑的Glitch与时序逻辑的亚稳态
竞争(Race):一个门的输入有两个及以上的变量发生变化时,由于各个输入的组合路径的延时不同,使得在门级输入的状态改变非同时. 冒险或险象(Hazard):竞争的结果,如毛刺Glitch. 相邻信号间 ...
- 我的 FPGA 学习历程(09)—— 时序逻辑入门
讲到这篇时,组合逻辑就告一段落了,下面是一些总结: 描述组合逻辑时,always 语句中的敏感信号列表中需要列出全部的可能影响输出的变量 描述组合逻辑时,always 语句中的赋值总是使用阻塞赋值符号 ...
- 从头学起Verilog(二):时序逻辑基础与回顾
引言 时序逻辑对于数字电路设计十分重要,本文针对数字电路中的时序逻辑部分进行了系统的回顾. 存储器件 由于时序逻辑的输出不但受当前输入影响,还受之前的输入的影响,所以需要有存储单元对以前的输入进行存储 ...
- 【小贴士】关于transitionEnd/animate的一个有趣故事
前言 在很久之前,我们项目有一个动画功能,功能本身很简单,便是典型的右进左出,并且带动画功能 以当时来说,虽然很简单,但是受限于框架本身的难度,就直接使用了CSS3的方式完成了功能 当时主要使用tra ...
随机推荐
- Oracle中SQL语句转化IP地址到数字
CREATE OR REPLACE FUNCTION ip_num(ipaddress IN VARCHAR2) RETURN NUMBER AS ipnum ; pos1 ; pos2 ; BEGI ...
- JTS基本概念和使用
简介 JTS是加拿大的 Vivid Solutions公司做的一套开放源码的 Java API.它提供了一套空间数据操作的核心算法.为在兼容OGC标准的空间对象模型中进行基础的几何操作提供2D空间谓词 ...
- loadrunner 脚本开发- web_url函数详解
脚本开发- web_url函数详解 by:授客 QQ:1033553122 加载指定url的web页面(GET请求) C语言函数 int web_url( const char *StepName ...
- go语言练习:sha256、sha512哈希算法
package main import ( "fmt" "crypto/sha256") func main() { str:="test hash. ...
- 关于动态加载js
已知一个需要动态加载的js的文件路径数组,动态加载数组里面所有的js文件. 加载分两种情况: 1. 并行加载,不管js的执行顺序. 2. 串行加载,即一个一个加载,上一个加载完再加载下一个,直到最后. ...
- LeetCode题解之 Increasing Order Search Tree
1.题目描述 2/问题分析 利用中序遍历,然后重新构造树. 3.代码 TreeNode* increasingBST(TreeNode* root) { if (root == NULL) retur ...
- http请求工具-OkHttp用法
OKHttp介绍 okhttp是一个第三方类库,用于android中请求网络.这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCan ...
- IAM页面是在统一区分配的还是在混合区分配的?
IAM页面是在统一区分配的还是在混合区分配的? IAM页面的作用这里就不说了,网上的资料很多 文章中用到的工具:查看SQLSERVER内部数据页面的小插件Internals Viewer 先建立四张表 ...
- python常用模块之string
python常用模块string模块,该模块可以帮我们获取字母.数字.特殊符号. import string #打印所有的小写字母 print(string.ascii_lowercase) #打印所 ...
- mysql的又一个让人捉摸不透的bug?
这次就不说很多没有写博客了,因为前几天已经写过了.\^o^/ 昨天我们刚讨论了关于自动化运维工作的实现方式,如果批量执行,中间出错怎么办?突然有人提出mysql支持--force,可以跳过出错继续执行 ...