前言
本次是一次作业内容,本意是要用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