HDB3 的编码 ②(Verilog 语言实现)2021-9-12

文章目录


前言

在上一篇有关hdb3 的编码和译码的介绍中,简单介绍了hdb3的编码规则,以及使用MATLAB进行了仿真实验。感兴趣的朋友可以去看一下。HDB3 的编码与译码 ①(MATLAB 实现)2021-9-11。仿真实验过后,就要在FPGA中实现,通过这次学习也是对FPGA的相关知识有了进一步的了解。下面也是介绍了相关部分的设计,主要的参考资料是:HDB3码编码器及解码器verilog代码编程及实现这个课件给出了详细的设计流程,编码设计主要参考了这个课件的介绍。
本篇文章也是介绍了编码的实现过程。译码过程在下一篇文章中介绍。


一、实现HDB3编码步骤

梳理好完善逻辑就是成功的一半,要实现的HDB3的编码不可操之过急。上述课件中,给出了详细的过程以及相应的代码。
在来哦哦饥饿这个编程最初,我一直也不是很理解hdb3编码中的V还有B要用什么代替,以及最后的正负极性,要如何处理?这些问题都在课件中给出了相应的解释。
跟做MATLAB的仿真一样,在编码之中一共有四中符号:1,0,B,V。那就用一个两位的寄存器来分别表示就可以了。
0:00
1:01
B:10
V:11
这就是开始的“原材料”准备。下面开始分模块。
主要的流程有三个:
第一步:插入符号V。
第二步:插入符号B。
第三步整体统一改变极性。并且将代表各符号的值统一成0,+1和-1。
分好了模块,就可以一个模块一个模块的进行设计。

1. 插入V模块

第一个模块是插V模块。在这个模块中,要将输入进来的单极性信号转变为两位的信号,同时在固定格式下插上V。那么固定格式是什么格式那?在HDB3的编码规则中,不允许有超过三个0连续,如果有就将第四个0转变成V那么这第四个零就是要插V的位置了。
首先先来完成逻辑框图。
HDB3 的编码 ②(Verilog 语言实现)2021-9-12

整体的逻辑就是进行判断分类,再分类。

module add_v
(
	Clk,Rstn_,
	DataIn,DataOut
);

	input Clk;
	input Rstn_;
	
	input DataIn;
	
	output [1:0] DataOut;
	
	reg [1:0] DataOut;
	
	reg [1:0] count; //连“0”计数器 最多就会有4个 0
	
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin
			count <= 2'd0;
			DataOut <= 2'b00;
		end
		else
		begin
			if (DataIn == 1'b1)  //如果收到的是 1 
				begin
					count <= 2'd0;
					DataOut <= 2'b01;  //先不考虑极性
				end
			else
			begin
				count <= count + 1'b1;
				if (count == 2'd3) // 连 0 达到 4个 输出 “V” 11
				begin
					count <= 2'd0;
					DataOut <= 2'b11;
				end
				else
					DataOut <= 2'b00; //连 0 未达到 4个 输出 00 
			end
		end				
endmodule

简单看一下仿真结果:
HDB3 的编码 ②(Verilog 语言实现)2021-9-12
可以看到在仿真结果图中,开始端的01前面有一小段00,那是因为在时钟的上升沿手到达之前,编码的值就是00。从而可以的出一个结论,在实际使用hdb3编码模块的时候应当加一个使能位,使用的顺序应当是先给好数据,随后快速地使能模块,再进行编码,这样保证整体的编码质量。

2. 插入B模块

插入B模块可以说是整个编码的核心了,还是一样捋一下逻辑。什么时候才会插入B那?当两个V之间的1的个数为偶数个时,就需要将后面那个V前面的三个0中的第一个0转变成B。
这其中有几个很重要的点:
第一个点就是要检测V,同时转变的是V之后的第四个值,所以要设计一个四位的移位寄存器。这样才能保证,既能看到前面又能变后面。
第二个点就是偶数这个问题要怎么处理,如何判断1的个数是奇数还是偶数那?这里的解决方案非常牛逼,我们是不知道两个V之间是会有多少个1的,有可能很多,也有可能很少,所以不可能将每一个1都计上去,这里就利用了寄存器会溢出的特性。
定义一个一位的寄存器,有一个奇数个1,寄存器的值就是1。有偶数个1,寄存器的值就是0;

/**
 时间:2021年9月9日 
 文件名:add_B.v
 所属项目:hdb3 编解码
 顶层模块:hdb3.v
 模块名称及其描述:hdb3 编码过程中实现插入 “B” 的操作
 修改记录:无
*/
module add_B
(
	Clk,Rstn_,
	DataIn_B,DataOut_B
);

	input Clk;
	input Rstn_;
	
	input [1:0] DataIn_B;
	
	output [1:0] DataOut_B;
	
	
	
	/****************V和1的计数器设计************************/	
	
	reg count_1;  //对 “1” 的计数器
	
	reg [1:0] count_V;  //对 “V” 的计数器
	
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin
			count_1 <= 1'b0;
			count_V <= 1'b0;
		end
		else
		begin
			if(data[0] == 2'b11)  //输入进来的是 V 将1的计数器清零,同时将V的计数器+1
			begin
				count_1 <= 1'b0; 
				count_V  = count_V + 1'b1;
			end
			else if(data[0] == 2'b01) //输入进来的是 1  //1的计数器加1 
			begin
				count_1 <= count_1 + 1'b1;
				if(count_V  == 2'd2)//当这个V当过后边的V时,重新将它变成前面的V
					count_V <= 1'b1;
			end
			else			//输入进来的是 0 
			begin
				if(count_V  == 2'd2)//当这个V当过后边的V时,重新将它变成前面的V
					count_V <= 1'b1;
			end
		end
		
		
	/****************四位的移位寄存器************************/	
	
	reg [1:0] data[3:0];
	reg [1:0] i;
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin
		//	for (i=0; i<3; i=i+1)
		//		data[i] <= 2'b0;
		end
		else
		begin
			data[3] <= data[2];
			data[2] <= data[1];
			data[1] <= data[0];
			data[0] <= DataIn_B;
		end

		
	/***************数据输出端口的设计*************************/	
	
	//count_1==0 && count_V==1 表示 1的个数是偶数个 
	//data[0]==2'b11 表示偶数个的个数是在两个 V 之间数出来的 
	assign DataOut_B = (count_1==0)&&(count_V==1)&&(data[0]==2'b11)? 2'b10:data[3];
	
	
endmodule

前文给出的资料中,PPT中的例程代码是有一个小小的bug在这里做了订正。他的bug是,如果源码的开始是110000…也就是开始就会有偶数个1。那么他也会在第一个V的前面加上B,这是不合理的。这里给出了修正。
现在来分析一下每个计数器的工作逻辑。
HDB3 的编码 ②(Verilog 语言实现)2021-9-12
可以看到只有在两个V之间1的个数为偶数个的时候才会插入一个B。
看一下仿真的结果:
HDB3 的编码 ②(Verilog 语言实现)2021-9-12
由于四位移位寄存器的存在,所以输出会滞后四个钟。同时还要注意的是,第一个B应该是0,也是PPT中的bug。

3. 整理极性

通过前两部的整理,信号源码已经整理成,00,01,10,11了,也就是0,1,B,V。这里开始整理极性,同时在整理完极性之后的输出应该整理为0,+1,-1。这里用00来代表0,用01来代表+1,用10来代表-1;
极性的变化规则是:
1.1和 B看成一组,正负交替变化,一般第一个1的极性是负号。
2.V的极性看成一组,正负交替变化,第一个V的极性和前一个非0符号的极性相同。
这里对B模块输入进来的数据进行判断整理即可。还是简单的画一个逻辑图。
HDB3 的编码 ②(Verilog 语言实现)2021-9-12
极性的整体统一还有另一个功能,就是产生脉冲,当然输出的数据两位也可以当做正负脉冲来使用,这里还是使用了两个端口来产生正负脉冲。
整体的代码:


module polar
(
	Clk,Rstn_,
	DataOut_B,PolarOut,
	BP,BN
);

	input Clk;
	input Rstn_;
	
	input [1:0] DataOut_B;
	
	output [1:0] PolarOut;
	
	//设计正脉冲和负脉冲
	output BP;  // 正脉冲
	output BN;  // 负脉冲
	
	reg [1:0] PolarOut;
	
	reg BP;  
	reg BN;
	
	/****************极性翻转************************/
	
	reg even = 0;

	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin

		end
		else 
		begin
			if( (DataOut_B == 2'b01) || (DataOut_B == 2'b10) ) //输入为 1 或者 B 两者翻转
			begin
				if(even == 1) //将初始位设计成 -1
					PolarOut <= 2'b01;
				else  
					PolarOut <= 2'b10;  
				even <= ~even; //将标识位翻转
			end
			else if(DataOut_B == 2'b11) //输入进来的是 V
			begin
				if(even == 1)
					PolarOut <= 2'b10;
				else
					PolarOut <= 2'b01;
			end
			else  //输入为 00 
				PolarOut <= 2'b00;
		end
		
		
	/****************极性翻转************************/		
	
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin

		end	
		else
		begin
			if(PolarOut == 2'b01) //输入为 +1
			begin
				BP <= 1'b1;
				BN <= 1'b0;
			end
			else if(PolarOut == 2'b10)  //输入为 -1
			begin
				BP <= 1'b0;
				BN <= 1'b1;
			end			
			else
			begin
				BP <= 1'b0;
				BN <= 1'b0;
			end			
			
		end
endmodule

其中主要注意的点就是1和V的极性,他们各自是交替变化,但同时第一个V的极性又和前一个1的极性有关系(这里的1包含B),这里就是用一个寄存器even来控制整体的极性。来看一下仿真结果。
HDB3 的编码 ②(Verilog 语言实现)2021-9-12
和自己手算的结果比较一下,可以得出相应的结果。


二、 总结

通过对hdb3的编码,通过这个小课题使得自己认识到,基本还是比较差,另外也产生另一个问题,就是不会使用相应的仿真工具也就是ModelSim,之前使用的一直是逻辑分析仪,没有使用过这种,数据量的仿真,都是跑跑时序,现阶段也是总结出来最适合我的开发方法,如果要调试时序类的程序,跑跑时序什么的有条件就可以用逻辑分析仪,要是处理数据编码什么的 程序还是需要到仿真环境ModelSim。积累吧,积累多了自然就会了。

上一篇:【Verilog】子模块连接相关问题


下一篇:Verilog HDL语法基础