查看: 1459|回复: 1

基于FPGA的汉明码编码解码设计

[复制链接]
  • TA的每日心情
    开心
    2019-11-4 13:48
  • 签到天数: 14 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2020-4-16 09:37:24 | 显示全部楼层 |阅读模式
    分享到:
    基于FPGA的汉明码编码解码设计

    实验简述

            本实验的目的是实现汉明纠错码的编码和解码

    1.1汉明码简介
         汉明码,是在电信领域的一种线性调试码,以发明者理查德 卫斯理 汉明的名字命名。汉明码在传输的消息流中插入验证码,当计算机存储或移动数据时,可能会产生数据位错误,以侦测并更正单一比特错误。由于汉明编码简单,他们被广泛应用于内存。

        与其他的错误校验码类似,汉明码也利用了奇偶校验位的概念,通过在数据位后面增加一些比特,可以验证数据的有效性。利用一个以上的校验位,汉明码不仅可以检验数据是否有效,还能在数据出错的情况下指明错误的位置。(汉明码可以检测两位错误,纠正一位错误)。
    1.2编码规则
        理解汉明码首先要理解奇偶校验,奇校验就是在一串编码里增加一位校验位使这一串编码里的1的个数位奇数。偶校验同理,使编码里1的个数为偶数。

        汉明码的编码位数n与纠错码的位数k的关系:2^k >= n+k+1。这里给出常用的nk的值:

    n
    1
    2-4
    5-11
    12-26
    27-57
    58-120
    k
    2
    3
    4
    5
    6
    7

                我们将纠错码加入到相应的编码里,纠错码的位置必须在2^n位置上。以10101100为例进行编码。这个序列为8位,需要4个纠错码。我们先将序列从18编号

    1
    2
    3
    4
    5
    6
    7
    8
    1
    0
    1
    0
    1
    1
    0
    0

        然后将纠错码(p1,p2,p3,p4)加到这个序列里 的2^n的位置,并用二进制重新编号

    0001
    0010
    0011
    0100
    0101
    0110
    0111
    1000
    1001
    1010
    1011
    1100
    p1
    p2
    1
    p3
    0
    1
    0
    p4
    1
    1
    0
    0
       
        然后我们要求出p1,p2,p3,p4的值,先将上面的序列分组编号为xxx1的分为一组,xx1x 的分为一组,x1xx的分为一组,1xxx的分为一组:
    xxx1p1,1,0,0,1,0
    xx1xp2,1,1,0,1,0
    x1xxp3,0,1,0,0
    1xxxp4,1,1,0,0

       我们采用偶校验,所以p1 = 1,p2 = 1, p3 = 1, p4 = 0。这样我们就得到了10101100的汉明码111101001100
            那么汉明码是如何来纠错的呢?

                我们将p4,p3,p2,p1按这个顺序排列得到0111,这个就是出错的位数,由于是二进制传输,所以就将相应位取反就可以得到正确的序列了。
    1.3FPGA实现
            对于p1,p2,p3,p4的计算在用fpga实现时只需进行按位异或就行。输入数据位8位,需要四个纠错位。
    1.3.1 顶层架构



    信号说明
    信号
    功能
    说明
    clk
    工作时钟
    外部输入
    rst_n
    系统复位
    外部输入
    data
    输入数据
    外部输入
    wren
    写使能
    外部输入
    rden
    读使能
    外部输入
    q
    输出数据
    输出
    hc_out
    经过汉明编码后输出
    输出
    hc_in
    输入的汉明码
    外部输入
    顶层代码

    module humming_coder12_8(clk, rst_n, data, q, rden, wren, hc_out, hc_in);

        input clk, rst_n;
        input [7:0] data;
        output [7:0] q;
        input rden, wren;
        output [11:0] hc_out;
        input [11:0] hc_in;

        hamming_encoder HE(
            .clk(clk),
            .rst_n(rst_n),
            .wren(wren),
            .data(data),
            .hc_out(hc_out)
        );

        hamming_decoder HD(
            .clk(clk),
            .rst_n(rst_n),
            .rden(rden),
            .q(q),
            .hc_in(hc_in)
        );

    endmodule

    1.3.2 编码模块
                编码模块只需将分组之后的每一组数据(不包括p)按位异或后赋值给p就可以
            编码模块代码
    module hamming_encoder(clk, rst_n, wren, data, hc_out);

        input clk, rst_n;
        input wren;
        input [7:0] data;
        output reg [11:0] hc_out;

        wire p0, p1, p2, p3;

        assign p0 = data[6] ^ data[4] ^ data[3] ^ data[1] ^ data[0];
        assign p1 = data[6] ^ data[5] ^ data[3] ^ data[2] ^ data[0];
        assign p2 = data[7] ^ data[3] ^ data[2] ^ data[1];
        assign p3 = data[7] ^ data[6] ^ data[5] ^ data[4];

        always @ (posedge clk or negedge rst_n)begin
            IF(!rst_n)
                hc_out <= 0;
            else if(wren)
                hc_out <= {data[7:4], p3, data[3:1],p2, data[0], p1, p0};
            else   
                hc_out <= 0;
        end

    endmodule

    1.3.3解码模块
        解码模块只需判断哪位出错,然后取反,并将纠错位删除即可
       解码模块代码
    module hamming_decoder(clk, rst_n, rden, q, hc_in);

        input clk, rst_n;
        input rden;
        output reg [7:0] q;
        input [11:0] hc_in;

        wire g0_error, g1_error, g2_error,g3_error;

        assign g0_error = hc_in[10] ^ hc_in[8] ^ hc_in[6] ^ hc_in[4] ^ hc_in[2] ^ hc_in[0];
        assign g1_error = hc_in[10] ^ hc_in[9] ^ hc_in[6] ^ hc_in[5] ^ hc_in[2] ^ hc_in[1];
        assign g2_error = hc_in[11] ^ hc_in[6] ^ hc_in[5] ^ hc_in[4] ^ hc_in[3];
        assign g3_error = hc_in[11] ^ hc_in[10] ^ hc_in[9] ^ hc_in[8] ^ hc_in[7];

        always @ (posedge clk or negedge rst_n)begin
            if(!rst_n)
                q <= 0;
            else if(rden)
                case ({g3_error, g2_error, g1_error, g0_error})
                    4'b0000 :   q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
                    4'b0001 :   q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
                    4'b0010 :   q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
                    4'b0011 :   q <= {hc_in[11:8], hc_in[6:4], ~hc_in[2]};
                    4'b0100 :   q <= {hc_in[11:8], hc_in[6:4], hc_in[2]};
                    4'b0101 :   q <= {hc_in[11:8], hc_in[6:5], ~hc_in[4], hc_in[2]};
                    4'b0110 :   q <= {hc_in[11:8], hc_in[6], ~hc_in[5], hc_in[4], hc_in[2]};
                    4'b0111 :   q <= {hc_in[11:8], ~hc_in[6], hc_in[5], hc_in[4], hc_in[2]};
                    4'b1000 :   q <= {hc_in[11:8], hc_in[6], hc_in[5], hc_in[4], hc_in[2]};
                    4'b1001 :   q <= {hc_in[11:9], ~hc_in[8], hc_in[6:4], hc_in[2]};
                    4'b1010 :   q <= {hc_in[11:10], ~hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};
                    4'b1011 :   q <= {hc_in[11], ~hc_in[10], hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};
                    4'b1100 :   q <= {~hc_in[11], hc_in[10], hc_in[9], hc_in[8], hc_in[6:4], hc_in[2]};
                    default :   q <= 0;
                endcase
            else
                q <= 0;
        end

    endmodule

    仿真验证
        我们用$random系统函数产生的随机数来作为编码模块数据,用$random系统函数产生的随机数来将hc_out的哪一位取反来模拟噪声。并判断输入的数据和输出的数据是否相等,以验证纠错功能。用$display$error系统函数来生成报告。
    测试文件代码
    module humming_coder12_8_tb;

        reg clk, rst_n;
        reg [7:0] data;
        reg rden, wren;
        wire [11:0] hc_out;
        reg [11:0] hc_in;
        wire [7:0] q;

        reg [7:0] temp1, temp2;

        humming_coder12_8 DUT(
            .clk(clk),
            .rst_n(rst_n),
            .data(data),
            .wren(wren),
            .q(q),
            .rden(rden),
            .hc_out(hc_out),
            .hc_in(hc_in)
        );

        integer pn, i;

        initial begin
            pn = 0;
            hc_in = 0;

            forever begin
                @ (posedge clk)
                pn = {$random} %12;
                #1
                for (i=0; i<12; i=i+1) begin
                    if (i!= pn)
                        hc_in = hc_out;
                    else
                        hc_in = ~hc_out;
                end
            end
        end

        always @ (posedge clk)
        begin
            temp1 <= data;
            temp2 <= temp1;
        end
        always @ (*)
        begin
            if (wren) begin
                #1
                if (temp2 == q)
                    $display("OK:time=%0t data=%0d q=%0d", $time, temp2, q);
                else
                    $error("ERROR:time=%0t data=%0d q=%0d", $time, temp2, q);
            end
        end

        initial begin
            clk = 1;
            rst_n = 0;
            data = 0;
            rden = 0;
            wren = 0;

            #200
            @ (posedge clk)
            rst_n = 1;

            #200
            forever begin
                @ (posedge clk)
                wren = 1;
                data = {$random} % 9'b10000_0000;
                @ (posedge clk)
                wren = 1;
                data = {$random} % 9'b10000_0000;
                rden = 1;
            end
        end
        always #10 clk = ~clk;
        initial #5000 $stop;
    endmodule
        生成的报告,我们可以看到错误的数据可以被修改成原来正确的数据,证明我们的编码解码模块功能正确



    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-12-28 02:33 , Processed in 0.132582 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.