Verilog实现HDB3编码译码


前言

本次是一次作业内容,本意是要用Simulink中的门电路和寄存器来进行搭建电路完成HDB3编码和译码,但是既然可以用门电路实现,那么就可以用Verilog代码编程然后进行综合自动生成门电路,下面进行介绍。


一、使用的软件

Verilog编程用的Quartus II,仿真用Modelsim。有关Verilog语法问题,仿真步骤和HDB3编译码相关的问题很多博客都写的很详细了,这里就不再叙述。

二、具体实现

1.模块介绍

顶层模块(top.bdf):
在这里插入图片描述
解释:
clk:时钟信号
rst_n:复位信号
start:数据有效信号
code_in:输入待编码数据
code:HDB3编码输出信号
binary:HDB3译码后的数据
out_flag:输出译码信号有效位

v_coder:用来对输入数据进行处理,只在需要加V和-V的地方进行处理。
b_coder1:用来对输入的数据进行加B00V和-B00V处理。
b_coder2:由于加B00V和-B00V处理之后,原有的1的符号也要进行该改变,总之使为了纠正加B00V之后1的符号没有进行改变的情况。
decoder:译码模块。

2.模块的.V文件

v_coder.v

module v_coder(
	input clk,
	input rst_n,
	input start,      //高电平有效,须维持 
	input code_in,

	output reg[2:0] codeout_v   //000->0  001->1  010->-1  011->+V前面+B  100->+V  101->-V前面加—B  110->-V  111->无效
);

reg count1;
reg start_flag;

always @ ( posedge clk or negedge rst_n )
begin
if(!rst_n)
	begin
		count1 <= 1'b0;
	end
else if(start)
	begin
		if(code_in == 1'b1)      //如果有1了,则把0清零
			 count1 <= count1 + 1'b1;
		else 
			count1 <= count1;
	end
else
	begin
		count1<=count1;
	end

end

always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
	codeout_v<=3'b111;
else if(start)
	begin
	if(code_in == 1'b1)
		begin
			if(count1 == 1'b0)      //之前没有1,
				codeout_v<=3'b001;      
			else 
				codeout_v<= 3'b010;    //之前有1了
		end
	else
		codeout_v<=1'b0;
	end
else
	codeout_v <= 3'b111;
end

endmodule

b_coder.v

module b_coder(
input clk,
input rst_n,
input [2:0] input_data,
input start,  //输入有效数据开始   0无效,1有效
output reg [2:0] b_coder
);


reg [2:0]start_reg;
reg [2:0]out_reg;
reg start_state;
reg[2:0] count0;    
reg[15:0] count1; 
reg[11:0] temp_code;
reg count1_flag;
reg one_sign;
reg[2:0] input_reg;
reg break_flag;
reg [7:0]boov_count;

always @(posedge clk or negedge rst_n)     //计算0的个数
begin
	if(!rst_n)
		count0<=3'b0;
	else if(start_state)
		begin
			if(count0 == 3'b011)
				count0 <= 3'b0;
			else if(input_reg==3'b0)
				count0 <= count0 + 1'b1;
			else
				count0 <= 3'b0;
		end
	else
		count0<=3'b0;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		start_reg<=3'b0;
	else
		start_reg<=(start_reg<<1)|start;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		start_state<=1'b0;
	else if( (start_reg&3'b111)!=0 )
		start_state<=1'b1;
	else
		start_state<=1'b0;
end

always @(posedge clk or negedge rst_n)       //先移位到寄存器
begin
	if(!rst_n)
		input_reg<=3'b111;
	else if(start_state)
		input_reg <= input_data;
	else
		input_reg <= 3'b111;
end

always @(posedge clk or negedge rst_n)       //先移位到寄存器
begin
	if(!rst_n)
		begin
			temp_code<=12'b111111111111;
		end
	else if(start_state)
		begin
			if(count0 == 3'b011)
				begin
					temp_code <= (12'b111111111000 | input_data);
				end
			else
				temp_code <= (temp_code<<3) | input_data;
		end
	else
		temp_code <= 12'b111111111111;
end



always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			count1_flag<=1'b0;
			break_flag<=1'b0;
		end
	else if(start_state)
		begin
			if(temp_code[11:0]==11'b0)
				begin
					count1_flag<=1'b1;
					break_flag<=1'b1;
				end
			else
				begin
					count1_flag<=count1_flag;
					break_flag<=break_flag;
				end
		end
	else
		begin
			count1_flag<=count1_flag;
			break_flag<=break_flag;
		end
end
/*
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			count1<=16'b1;     //0代表负,1代表正
		end
	else if(start_state)
		begin
			if(count1_flag==1'b1)
				begin
					if(input_reg==3'b001)
						count1<=count1+1'b1;
					else if(input_reg==3'b010)
						count1<=count1+1'b1
					else
						count1<=count1;
				end
			else
				count1<=count1;
		end
	else
		count1<=count1;
end  */

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			out_reg<=3'b111;
			count1<=16'b0;     //0代表负,1代表正
			one_sign<=1'b0;     //0代表负,1代表正
			boov_count<=8'b0;
		end
	else if(start_state)
		begin
			if(temp_code[11:0]==11'b0 )
				begin
					count1<=16'b0;
					if(count1[0] == 0)   //偶数个
						begin
							if(break_flag==1'b0)  //第一次
								begin
									if(one_sign==0)  //负的
										begin
											out_reg<=3'b110;   //负的V
										end
									else
										begin
											out_reg<=3'b100;  //正的V
										end
								end
							else
								begin
									if(one_sign==0)  //负的
										begin
											out_reg<=3'b011;   //+B00V
											one_sign<=1'b1;  //变为正的
											boov_count<=boov_count+1'b1;
										end
									else	    //正的
										begin
											out_reg<=3'b101;  //-B00V
											one_sign<=1'b0;  //负的
											boov_count<=boov_count+1'b1;
										end
								end
						end
					else
						begin
							if(one_sign==0)  //负的
								out_reg<=3'b110;   //负的V
							else
								out_reg<=3'b100;  //正的V
						end
				end
			else
				begin
					if(count1_flag==1'b1)
						begin
							if(input_reg==3'b001)
								begin
									count1<=count1+1'b1;
										begin
											if(boov_count[0]==1'b0)
												begin
													one_sign<=1'b1;
													out_reg <= 3'b001;
												end
											else
												begin
													one_sign<=1'b0;
													out_reg <= 3'b010;
												end
										end
								end
							else if(input_reg==3'b010)
								begin
									count1<=count1+1'b1;
										begin
											if(boov_count[0]==1'b0)
												begin
													one_sign<=1'b0;
													out_reg <= 3'b010;
												end
											else
												begin
													one_sign<=1'b1;
													out_reg <= 3'b001;
												end
										end
								end
							else if(input_reg==3'b000)
								begin
									out_reg<=3'b000;
								end
							else
								begin
									out_reg <= input_reg;
									count1<=count1;
									one_sign<=one_sign;
								end
						end
					else
						begin
							out_reg <= input_reg;
							count1<=count1;
							begin
								if(input_reg==3'b001)
									one_sign<=1'b1;
								else if(input_reg==3'b010)
									one_sign<=1'b0;
								else
									one_sign<=one_sign;
							end
						end
				end
		end
	else
		begin
			count1<=count1;
			out_reg<=3'b111;
			one_sign<=one_sign;
		end
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		b_coder<=3'b111;
	else if(start_state)
		b_coder<=out_reg;
	else
		b_coder<=3'b111;
end

endmodule

b_coder2.v

module b_coder_2(
input clk,
input rst_n,
input [2:0] in_data,
output reg [1:0] out_data     //00->0     01->1   02->-1  11->无效
);

reg [2:0]in_data_reg;
reg [11:0] out_data_reg;       //000->0  001->1  010->-1  011->+B  100->+V  101->—B  110->-V  111->无效
reg start_flag;
reg [2:0] reg_out;
reg [3:0]out_flag_reg;
reg out_flag;
wire whole_flag;

assign whole_flag=start_flag|out_flag;
		
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out_flag_reg <= 4'b0000;
	else 
		out_flag_reg <= ( (out_flag_reg << 1) | start_flag);
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out_flag <= 1'b0;
	else if(out_flag_reg[3:0]!=0)
		out_flag <= 1'b1;
	else
		out_flag <= 1'b0;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		start_flag <= 1'b0;      //0代表无效
	else if( (in_data_reg==3'b111)&&(in_data!=3'b111) )
		start_flag <= 1'b1;
	else if( (in_data_reg != 3'b111)&&(in_data==3'b111) )
		start_flag <= 1'b0;
	else
		start_flag <= start_flag;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		in_data_reg <= 3'b111;
	else
		in_data_reg <= in_data;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out_data_reg<=12'b111111111111;
	else if(whole_flag)
		begin
			if(in_data_reg[2:0]==3'b011)
				begin
					out_data_reg[11:9] <= 3'b001;
					out_data_reg[2:0] <= 3'b100;
				end
			else if(in_data_reg[2:0] == 3'b101)
				begin
					out_data_reg[11:9] <= 3'b101;
					out_data_reg[2:0] <= 3'b110;
				end
			else
				begin
					out_data_reg <= ((out_data_reg << 3)|in_data_reg);
				end
		end
	else
		out_data_reg<=out_data_reg;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		reg_out<=3'b111;
	else if(out_flag)
		reg_out <= (out_data_reg[11:9]);
	else
		reg_out <= 3'b111;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out_data<=2'b11;
	else 
		begin
			if(reg_out==3'b000)
				out_data <= 2'b00;
			else if( (reg_out==3'b001) ||(reg_out == 3'b011) || (reg_out==3'b100))
				out_data <= 2'b01;
			else if( (reg_out==3'b010) || (reg_out==3'b101) || (reg_out == 3'b110))
				out_data <= 2'b10;
			else 
				out_data <= 2'b11;
		end
end


endmodule

decoder.v

module decoder(
input clk,
input rst_n,
input [1:0]code_in,

output reg out,
output reg out_flag
);


reg start_flag;
reg [1:0]data_in_reg;
reg [1:0] data_in_reg2;
reg [1:0] data_in_reg3;
reg [1:0] data_in_reg4;
reg one_sign;
reg [7:0] count0;
reg [7:0] count01;
reg [1:0] data_out_reg1;
reg [1:0] temp;
reg [3:0] temp1;
reg [2:0] temp_one_sign_reg;
reg one_sign_reg;
reg [2:0] countout;
reg [1:0] out1;

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		temp1 <= 4'b1111;
	else if(start_flag)
		temp1 <= ((temp1<<2)|data_out_reg1);
	else
		temp1 <= temp1;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		data_in_reg3<=2'b11;
	else if(start_flag)
		data_in_reg3<=temp1[3:2];
	else
		data_in_reg3 <= data_in_reg3;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		data_in_reg4<=2'b11;
	else if(start_flag)
		data_in_reg4<=data_in_reg3;
	else
		data_in_reg4 <= data_in_reg4;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		temp<=2'b11;
	else
		temp <= code_in;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		start_flag <= 1'b0;
	else if(code_in != 2'b11)
		start_flag <= 1'b1;
	else
		start_flag <= start_flag;
end



always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		data_in_reg<=2'b11;
	else if(start_flag)
		data_in_reg <= temp;
	else
		data_in_reg <= 2'b11;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		data_in_reg2<=2'b11;
	else if(start_flag)
		data_in_reg2 <= data_in_reg;
	else
		data_in_reg2 <= 2'b11;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		one_sign <= 1'b0;
	else if(start_flag)
		begin
			if(data_in_reg == 2'b01)
				one_sign <= 1'b1;
			else if(data_in_reg==2'b10)
				one_sign <= 1'b0;
			else
				one_sign <= one_sign;
		end
	else
		one_sign <= one_sign;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		temp_one_sign_reg<= 3'b000;
	else if(start_flag)
		temp_one_sign_reg<=((temp_one_sign_reg<<1)|one_sign);
	else
		temp_one_sign_reg <= 3'b000; 
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		one_sign_reg<= 1'b0;
	else if(start_flag)
		one_sign_reg<=temp_one_sign_reg[2];
	else
		one_sign_reg <= 1'b0; 
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		count0 <= 8'b00000000;
	else if(start_flag)
		begin
			if(data_in_reg2 == 2'b00)
				count0 <= count0 + 1'b1;
			else
				count0 <= 8'b00000000;
		end
	else
		count0 <= 8'b00000000;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		count01 <= 8'b00000000;
	else if(start_flag)
		begin
			if(data_out_reg1 == 2'b00)
				count01 <= count01 + 1'b1;
			else
				count01 <= 8'b00000000;
		end
	else
		count01 <= 8'b00000000;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		data_out_reg1<=2'b11;
	else if(count0==8'b00000011)
		begin
			if(one_sign==one_sign_reg)
				data_out_reg1 <= 2'b00;
			else
				data_out_reg1 <= data_in_reg2;
		end
	else
		data_out_reg1 <= data_in_reg2;
end


always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		countout <= 3'b0;
	else if(start_flag)
		begin
			if((data_out_reg1 == data_in_reg3) && (count01==8'b00000010))
				countout<=3'b100;
			else if(countout!=3'b000)
				countout<=countout-1'b1;
			else if(countout==3'b000)
				countout<=countout;
			else
				countout<=countout;
		end
	else
		countout<=countout;
end
	
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out1<=2'b11;
	else if(start_flag)
		begin
			if(countout!=3'b000)
				out1<=2'b00;
			else
				out1<=data_in_reg4;
		end
	else
		out1 <= 2'b11;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out<=1'b0;
	else if(start_flag)
		begin
			if(out1==2'b11)
				out<=1'b0;
			else if((out1 == 2'b01) || (out1 == 2'b10))
				out <= 1'b1;
			else
				out <= 1'b0;
		end
	else
		out<=1'b0;
end

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		out_flag <= 1'b0;
	else if(out1 != 2'b11)
		out_flag <= 1'b1;
	else if(out1 == 2'b11)
		out_flag <= 1'b0;
end
endmodule

代码较长,而且注释很少(编程不喜欢写注释,大家可根据逻辑和仿真结果进行验证)。


三、仿真结果

首先,每个模块的仿真结果就不贴出来了(当时仿真的时候没截图),这里仅进行总模块的仿真。(说明,编写testbench文件时,输入的数据仅在start信号的延迟一个时钟的高电平间有效)。
1,输入为101100001000011000011000011
那么手动编码为 10-11000V-1000-V1-1B00V-11-B00-V1-1 即10-110001-1000-11-11001-11-100-11-1
看结果:
输入:(code_in)
在这里插入图片描述
编码结果:(code)
在这里插入图片描述
其中01代表1,10代表-1,00代表0,11代表无效。可见和手动编码结果一样。
译码结果:(binary)
在这里插入图片描述
完全一致。
2, 输入为000000000000000000000000000
那么手动编码为:000-VB00V-B00-VB00V-B00-VB00V000(设前一个码为V),即000-11001-100-11001-100-11001000
输入:(code_in)(一条直线,没什么好看的)
在这里插入图片描述
编码输出:(code)
在这里插入图片描述
完全一致。
译码结果(binary)
在这里插入图片描述
也是一条直线,编译码正确。
3, 输入为100110000100001100001110000
那么手动编码为:100-11000V-1000-V1-1B00V-11-1000-1, 即100-110001-1000-11-11001-11-1000-1
输入:(code_in)
在这里插入图片描述
编码结果:(code)
在这里插入图片描述
完全一致
译码结果:(binary)
在这里插入图片描述
完全一致。可见是正确的。


四、总结

1.关于编程的结构

对于模块v_coder等简单的模块还好,结构较为清晰。但是最不可忍受的是b_coder模块,中间的always块又臭又长,而且一个always块中竟然有多个信号被幅值。这样的情况当然越少越好,想要修改一个信号则要牵一发而动全身。那么为什么当时我写出来这么臭的代码呢?

对于v_coder等较为简单的逻辑,经过编写程序后不断仿真找逻辑错误,可以慢慢地得到想要的结果。对于b_coder与b_coder2这样的模块,经过不断仿真,然后修改程序也可以得到正确的结果,但我认为可能会出问题。因为输入的数据是随机的,而不断仿真而针对性的修改代码可能会陷入局部最优,即当前数据没问题,而换个输入数据则就出问题。虽然这次编码程序很成功,经过不同输入数据的测试结果也正确,但这种方法总之是不科学的。而由上面的方法,不断调试找错误来修改代码,当然有可能把很多信号写到一个always块中,因为信号是相互关联的,按照上面的方法当然会这样。

那么如何进行改进?
decoder模块是我用新方法编写出来的代码,尽管逻辑也很复杂,但是并没有很长的always块情况,但是代码难懂了些。这是我用Wavedrom按照逻辑提前写好时序图,提前规划好每个信号是什么样子的,怎么样组合才能得到想要的结果。如下图
在这里插入图片描述
可见,每个信号如何变化清晰可见。但是绘制时序图时需要自己取推演每个信号如何变化的,怎么样才是正确的结果,这个过程是很漫长的,反正总比先编完然后调试找错误快多了,而且找错误和修正还搞人心态。不过尽管过程漫长,须耐住性子,但是当你写好时序图,并验证好是正确的时候,那么你的Verilog代码也就出来了。因为Verilog本身就是依靠时序图来编程的,当我把时序图转写为Verilog时,经过仿真一次通过,而且代码也层次分明。然而v_coder,b_coder和b_coder2并没有这样编写,欢迎各位有志之士来按照此方法重新进行改写。

2.收获

之前编写Verilog都是已知时序图,然后进行编写,也就没有思考没有时序图,怎么进行编写的问题。于是前三个模块,我就想瓶子中的苍蝇一样,不断试错搞心态。然而当我真正静下心来取思考它的逻辑,然后画出时序图时,一些都豁然开朗了。编程从来不是一个不断试错修改的过程,而是你的想法实现的过程,千万不要走错了路。总之、关于此次实践,对Verilog编程的思想的改变是我最大的收获。

五、附testbench文件

`timescale 1ns/1ns
module AMI_test;
reg clk;
reg rst_n;
reg start;
reg code_in;

wire[1:0] code;
wire binary;
wire out_flag;
top top_inst_v1(
.clk(clk),
.rst_n(rst_n),
.start(start),
.code_in(code_in),
.code(code),
.out_flag(out_flag),
.binary(binary)
);

initial 
begin
	#0 clk=0;
	#0 rst_n=0;
	#0 start=0;
	#0 code_in=0;
	#1 rst_n = 1;
	#2 start=1;
	#2 code_in = 1;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 1;
	#2 code_in = 1;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 1;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 1;
	#2 code_in = 1;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 1;
	#2 code_in = 1;
	#2 code_in = 1;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#2 code_in = 0;
	#0 start=0;
end

always#1 clk=~clk;
endmodule

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值