FPGA: RS译码仿真过程

FPGA: RS译码仿真过程

在上一篇中记录了在FPGA中利用RS编码IP核完成信道编码的仿真过程,这篇记录利用译码IP核进行RS解码的仿真过程,带有程序和结果。

1. 开始准备

在进行解码的过程时,同时利用上一篇中的MATLAB仿真程序和编码过程,IP核的下载是同样的地址。解码过程中的参数设置正好对应编码的过程。对0-15的自然数通过RS编码得到的数据进行解码,其中m=4,n=15,k=3,ploy=19

2. RS译码IP核

RS译码IP核全名Reed-Solomon Decoder,具体细节可以参照PDF技术文档,首先看IP核参数设置。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R32PpUta-1692190030739)(1.png “rs解码IP核设置1”)]

已经通过RS编码IP核完成了编码的仿真过程,并且通过MATLAB对比对结果进行了验证,所以这个第一个页码的参数直接参照如图设置就可以,与编码是一一对应的,没有什么需要特别的说明。
在下面的Variable Check Symbol Options不需要勾选。

在这里插入图片描述

在第二个参数设置界面,都不需要勾选,勾选的话译码输出的结果会带有校验的数据。

在这里插入图片描述

在第三个参数设置界面中,把Reset选项勾选上。

在这里插入图片描述

完成这个IP核的设置。

补充

为了方便利用仿真过程中的译码过程,在之前完成编码过程后添加了一个fifo方便进行数据处理和信号控制,其中的fifoIP核的参数设置为如下。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这个fifo根据需要设置即可,主要是为了编码之后的数据和译码过程使用控制方便。

3. 代码编写

译码过程是在编码基础上添加的,编码过程的参数没有变化,对0-15的数据进行编码,然后再进行译码,在编码和译码过程中间有一个fifo,其中fifo的读控制信号利用empty信号和译码IP的s_ready信号,fifo的写信号编码信号的输出valid信号。详细的逻辑看代码。

代码如下rs_test.v

`timescale 1ns / 1ps

module rs_test(
    input clk,          //时钟
    input rst_n         // 复位  高电平复位
//    input [7:0] data_in,  // 输入的待编码数据
//    output [7:0] dataout      // 输出的解码数据
    );

wire rs_encode_input_tready;  // 编码输入准备信号
reg rs_encode_input_tvalid_reg;  // 编码输入有效信号
reg rs_encode_input_tready_reg;
wire rs_encode_input_tlast;
reg rs_encode_input_tlast_reg;
wire[7:0] rs_encode_data;
wire rs_encode_output_tvalid;
wire rs_encode_output_tlast;
wire rs_enocde_output_tready;
reg rs_enocde_output_tready_reg;

parameter K = 3;   //  对应MATLAB仿真中的k和n的值,这个在IP核设置中已经有体现
parameter N = 4;   //
parameter L = 15;  // 编码之后的数据长度

reg [3:0] datain_num; // 每一组编码的原始数据个数
reg [5:0] dataout_num;  //输出编码数据的个数

wire fifo_full; // fifo 满信号

// 设计输入数据
reg [3:0] datain;
always@(posedge clk)begin
    if(~rst_n)begin
        datain <= 4'b0;
        rs_encode_input_tready_reg <= 1'b0;
        rs_encode_input_tvalid_reg <= 1'b0;
        rs_encode_input_tlast_reg <= 1'b0;
        rs_enocde_output_tready_reg <= 1'b0;
        datain_num <= 4'b0;
    end
    else begin
        rs_encode_input_tready_reg <= rs_encode_input_tready;
        if(fifo_full==1'b1)begin
            rs_encode_input_tvalid_reg <= 1'b0;
        end
        else begin
            rs_encode_input_tvalid_reg <= 1'b1;
        end
        
        if(rs_encode_input_tready == 1'b1 && rs_encode_input_tvalid_reg == 1'b1)begin // 在ready 和valid信号都有效的时候才开始编码数据,可以在这里计数编码的个数。
            datain <= datain + 4'b1;
            datain_num <= 4'b1 + datain_num;
            rs_enocde_output_tready_reg <= 1'b1;
        end
        else begin
        end
    end
end

// 根据每一组编码的组数来确定数据顺序 控制最后一个tlast信号。
always@(posedge clk)begin
    if(~rst_n)begin
        rs_encode_input_tlast_reg <= 1'b0; // 这个信号是需要在一组中的最后一个数据时候信号处于高电平 和k的大小对应
    end
    else begin
        if(datain_num >= K)begin
            rs_encode_input_tlast_reg <= 1'b1;
        end
        else begin
            rs_encode_input_tlast_reg <= 1'b0;  //然后重新置零
        end
    end
end

wire [3:0] data_in;
assign data_in = datain;

rs_encoder_0 rs_encoder_0_ins (   //latency 5clk
  .aclk(clk),                                                      // input wire aclk
  .aresetn(rst_n),                                                // input wire aresetn
  .s_axis_input_tdata(data_in),                          // input wire [7 : 0] s_axis_input_tdata
  .s_axis_input_tvalid(rs_encode_input_tvalid_reg),                        // input wire s_axis_input_tvalid
  .s_axis_input_tready(rs_encode_input_tready),                        // output wire s_axis_input_tready
  .s_axis_input_tlast(rs_encode_input_tlast_reg),                          // input wire s_axis_input_tlast
  .m_axis_output_tdata(rs_encode_data),                        // output wire [7 : 0] m_axis_output_tdata
  .m_axis_output_tvalid(rs_encode_output_tvalid),                      // output wire m_axis_output_tvalid
  .m_axis_output_tready(rs_enocde_output_tready_reg),                      // input wire m_axis_output_tready
  .m_axis_output_tlast(rs_encode_output_tlast)                       // output wire m_axis_output_tlast
);

// 通过编码模块输出的valid信号和ready信号来记录输出数据的个数
always@(posedge clk)begin
    if(~rst_n)begin
        dataout_num <= 6'b0;
    end
    else begin
        if(rs_encode_output_tvalid==1'b1 && rs_enocde_output_tready_reg==1'b1)begin
            dataout_num <= dataout_num + 6'b1;
            if(dataout_num >= 6'd15)begin
                dataout_num <= 6'b0;
            end
        end
        else begin
            
        end
    end
end

// rs 译码过程
// 在编码之后的数据添加一个fifo  方便管理valid信号和ready信号,减少耦合同时可以比配位宽
wire fifo_empty;
wire fifo_rd_en;

wire[3:0] fifo_data;
reg fifo_flag;  // 这个是用来标致第一次从fifo中读取数据的过程

wire [7:0] rs_decode_data_temp;
wire [3:0] rs_decode_data;
//in
wire rs_decode_data_s_ready;
wire rs_decode_data_s_valid;
reg rs_decode_data_s_valid_reg;  // 去掉fifo 输出的一个时钟延迟
reg rs_decode_data_s_tlast_reg;
assign fifo_rd_en = rs_decode_data_s_ready && (!fifo_empty);
// out
wire rs_decode_data_m_valid;
wire rs_decode_data_m_tlast;
wire rs_decode_data_m_ready;
// stat
wire [7:0] rs_decode_stat_data;
//wire rs_decode_stat_ready;
wire rs_decode_stat_valid;

always@(posedge clk)begin
    if(~rst_n)begin
        fifo_flag <= 1'b0;
    end
    else begin
        if(fifo_rd_en==1'b1)begin
            fifo_flag <= 1'b1;
        end
    end
end

always@(posedge clk)begin
    if(~rst_n)begin
        rs_decode_data_s_valid_reg <= 1'b0;
    end
    else begin
        rs_decode_data_s_valid_reg <= fifo_rd_en;
    end
end

fifo_generator_0 fifo_ins( // 这个输出有1clk延迟
  .clk(clk),      // input wire clk
  .srst(~rst_n),    // input wire srst
  .din(rs_encode_data[3:0]),      // input wire [3 : 0] din
  .wr_en(rs_encode_output_tvalid),  // input wire wr_en
  .rd_en(fifo_rd_en),  // input wire rd_en
  .dout(fifo_data),    // output wire [3 : 0] dout  
  .full(fifo_full),    // output wire full
  .empty(fifo_empty)  // output wire empty
);
// 输入编码中的有效信号
assign rs_decode_data_s_valid = (fifo_flag==1'b1)?fifo_rd_en:rs_decode_data_s_valid_reg; // 在第一次读取的时候 信号跟随reg信号,之后跟随en信号
reg[5:0] decode_num;
always@(posedge clk)begin
    if(~rst_n)begin
        decode_num = 6'b1;
    end
    else begin
        if(rs_decode_data_s_valid==1'b1)begin
            decode_num <= decode_num + 6'b1;
            if(decode_num >= 6'd14)begin
                decode_num <= 6'b0;
            end
        end
    end
end
// 控制tlast信号
always@(posedge clk)begin
    if(~rst_n)begin
        rs_decode_data_s_tlast_reg <= 1'b0;
    end
    else begin //当解码输入进入的数据为一组时,拉高tlast信号;
        if(decode_num >= 6'd14)begin
            rs_decode_data_s_tlast_reg <= 1'b1;
        end
        else begin
            rs_decode_data_s_tlast_reg <= 1'b0;
        end
    end
end

rs_decoder_0 rs_decoder_0_ins (
  .aclk(clk),                                                      // input wire aclk
  .aresetn(rst_n),                                                // input wire aresetn
  .s_axis_input_tdata(fifo_data),                          // input wire [7 : 0] s_axis_input_tdata
  .s_axis_input_tvalid(rs_decode_data_s_valid),                        // input wire s_axis_input_tvalid
  .s_axis_input_tlast(rs_decode_data_s_tlast_reg),                          // input wire s_axis_input_tlast
  .s_axis_input_tready(rs_decode_data_s_ready),                        // output wire s_axis_input_tready
  .m_axis_output_tdata(rs_decode_data_temp),                        // output wire [7 : 0] m_axis_output_tdata
  .m_axis_output_tvalid(rs_decode_data_m_valid),                      // output wire m_axis_output_tvalid
  .m_axis_output_tready(1'b1),                      // input wire m_axis_output_tready
  .m_axis_output_tlast(rs_decode_data_m_tlast),                        // output wire m_axis_output_tlast
  .m_axis_stat_tdata(rs_decode_stat_data),                            // output wire [7 : 0] m_axis_stat_tdata
  .m_axis_stat_tvalid(rs_decode_stat_valid),                          // output wire m_axis_stat_tvalid
  .m_axis_stat_tready(1'b1)                          // input wire m_axis_stat_tready
);

assign rs_decode_data = rs_decode_data_temp[3:0];

endmodule

4. 仿真测试

测试程序的testbench文件和之前保持一致,只需要把实例化的模块名字更改即可。

`timescale 1ns / 1ps
module rs_tb();

reg l_clk;
reg rst_n;

rs_test rs_test_ins(
    .clk(l_clk),          //时钟
    .rst_n(rst_n)         // 复位  高电平复位
    );
initial l_clk = 1;
always #5 l_clk= !l_clk;  //15.625   

initial begin
    rst_n <= 0;
    #40;
    rst_n <= 1;
    #320;
    //#50000000;
    #320;
//    $stop;
end
endmodule

然后进入仿真过程,对照时序查看结果。

在这里插入图片描述

首先看试验大图,其中的蓝色线是解码之后的数据,从数据结果中可以看出每个数据间隔3,正好是编码之前的结果,拉开蓝色线就可以看到具体的数值。因为译码也是存在延时的,所以看起来数据会滞后,蓝色数据线的m_valid信号对应输出数据有效信号。

这里面有需要注意的地方,首先看仿真结果的前面部分。

在这里插入图片描述

这是fifo_rd_en有效的第一段,由于有1个clk的时钟延迟,所以把有效信号rs_decode_data_s_valid信号需要延迟一个clk,然后看接下来的fifo_rd_en第二个周期,需要把rs_decode_data_s_valid信号和fifo_rd_en信号对齐,否则会丢一个数据,后面的和第二个周期相同,只有第一个需要延迟一个周期,这个在程序中通过fifo_flag判断是不是第一个周期。

在这里插入图片描述

至此完成了译码的过程。

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
++++++++++++++++++++++++++ RS Decoder (31,19,6) v1.1 ++++++++++++++++++++++++++ This project consists of 8 verilog files including a testbench file. The files are: - RSDecoder.v : contains description of top module of the decoder. It combines 5 modules of typical RS Decoder building blocks. - scblock.v : contains description of the SC (Syndrome Computation) block and its submodules. - kesblock.v : KES (Key Equation Solver) block and its submodules. - cseeblock.v : CSEE (Chien Search and Error Evaluator) block and parallel invers multiplier module. CSEE is the only block in the decoder that use invers multiplier to compute error magnitude using Fourney Formula. - controller.v : describes controller module. It consists of 2 FSMs and 2 counters. - fifo_register.v : a FIFO register consists of 31 registers to store received word and a register to synchronize outputted data with CSEE block. - common_modules.v: this file contains basic modules that used by other higher modules. It behaves like a library for the project. - testbench.v : the testbench contains 3 different received word vectors. First received word contains no error symbol. Second word contains 6 error symbols and the last word contains 8 error symbols. Limitations in this version: Despite its high data rates, the decoder has some limitations that must be considered. - It flags decoding failure at the end of outputted word. So, other block outside the decoder cannot differentiate between uncorrected word and corrected word until it receive decoding failure flag at the end of the word. - Decoding failure is detected when degree of error location polynomial and number of its roots is not equal. It means the error location polynomial doesn't have roots in the underlying GF(2^5). To determine the roots, decoder must activate CSEE block first. H
Viterbi译码器是一种重要的误码纠正方法,它在通信、多媒体等领域有着广泛的应用。FPGA(现场可程门阵列)作为一种可重构计算平台,可以快速构建硬件电路,提高系统的运行效率和性能。因此,在FPGA上实现Viterbi译码器成为一种比较常见的选择。但是,为了保证电路的正确性和稳定性,在设计和实现过程中需要进行仿真FPGA仿真是指通过软件模拟FPGA的硬件逻辑,来验证、测试电路的正确性和性能的过程。与实际的硬件电路相比,FPGA仿真可以在更短的时间内模拟出电路的运行状态,方便进行调试和测试。特别是对于Viterbi译码器这样的复杂电路,通过仿真可以有效地减少设计缺陷和问题,提高电路的可靠性和正确性。 在进行FPGA仿真时,我们需要先进行源代码的写和仿真环境的设置。针对Viterbi译码器,我们可以选择Verilog或VHDL等硬件描述语言进行写。在代码写完成后,需要使用EDA工具(如ModelSim)进行仿真环境的搭建和调试。这个过程中,需要先完成电路的功能验证,再进行性能测试和时序分析,最终输出仿真结果。 需要注意的是,FPGA仿真可以发现并解决电路的设计问题,但仍需要进一步的验证和测试。实际的硬件电路可能会受到不同的电器因素和物理影响,因此在进行设计和实现之前还需要进行实验验证和性能测试,以确保电路的稳定性和正确性。 总之,FPGA仿真是一种重要的电路设计和实现方法,特别适用于复杂的Viterbi译码器等电路。通过仿真,可以有效地发现和解决设计问题,提高电路的可靠性和正确性,同时也能够简化电路设计和实现的过程
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一支绝命钩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值