【Verilog】汉明码

文章目录

      • 汉明码
        • 定义
        • 校验位个数
        • 编码规则
        • 一个例子
          • 编码
          • 解码
        • C++实现
          • 功能编写
          • 测试结果
        • Verilog实现
          • .v功能代码
          • testbench
          • 波形

汉明码

定义

  • 在传输的信息流中插入验证码,侦测单一比特错误
  • 只能发现和修正一位错误,对于两位或两位以上的错误无法发现与修正

校验位个数

  • 2r ≥ k + r + 1
  • 其中:
    • k为数据位
    • r为校验位

编码规则

  • 在新的编码的2(k - 1)( k >= 0)位上填入0(即校验位),把新的编码的其余位把源码按原顺序填入
  • 校验位的编码方式为:
    • 第k位校验码从则从新的编码的第2(k - 1)位开始,每计算2(k - 1)位的异或,跳2(k - 1)位,再计算下一组2(k - 1)位的异或,填入2(k - 1)
    • 比如:
      • 第1位校验码位于新的编码的第1位(2 (1-1) == 1)(汉明码从1位开始),计算1,3,5,7,9,11,13,15,…位的异或,填入新的编码的第1位
      • 第2位校验码位于新的编码的第2位(2 (2-1) == 2),计算2,3,6,7,10,11,14,15,…位的异或,填入新的编码的第2位
      • 第3位校验码位于新的编码的第4位(2 (3-1) == 4),计算4,5,6,7,12,13,14,15,20,21,22,23,…位的异或,填入新的编码的第4位
      • 第4位校验码位于新的编码的第8位(2 (4-1) == 8),计算8-15,24-31,40-47,…位的异或,填入新的编码的第8位
      • 第5位校验码位于新的编码的第16位(2 (5-1) == 16),计算16-31,48-63,80-95,…位的异或,填入新的编码的第16位

一个例子

  • 以10101编码为例,创建一个汉明码编码的空间,并且需要将原本数据位的校验位放置于对应位置中
  • 计算校验位数
    • 23 < 5 + 3 + 1
    • 24 ≥ 5 + 4 + 1
    • r = 4
  • 数据位记为P1~P5 = 10101
  • 校验位记为C1~C4
  • 数据输出为:C1C2P1C3P2P3P4C4P5
编码
  • 计算校验位
    • C1 = P1 ^ P2 ^ P4 ^ P5 = 1 ^ 0 ^ 0 ^ 1 = 0
    • C2 = P1 ^ P3 ^ P4 = 1 ^ 1 ^ 0 = 0
    • C3 = P2 ^ P3 ^ P4 = 0 ^ 1 ^ 0 = 1
    • C4 = P5 = 1
  • 插入校验位
    • C1C2P1C3P2P3P4C4P5 = 001101011
解码
  • 假设收到的编码数据为:001101001
  • 计算校验位数
    • 23 < 5 + 3 + 1
    • 24 ≥ 5 + 4 + 1
    • r = 4
  • 2(k - 1)(k = 1, 2, 3, 4)为校验位位置
  • 校验
    • C1 ^ P1 ^ P2 ^ P4 ^ P5 = 0 ^ 1 ^ 0 ^ 0 ^ 1 = 0
    • C2 ^ P1 ^ P3 ^ P4 = 0 ^ 1 ^ 1 ^ 0 = 0
    • C3 ^ P2 ^ P3 ^ P4 = 1 ^ 0 ^ 1 ^ 0 = 0
    • C4 ^ P5 = 0 ^ 1 = 1
  • 将各校验结果逆序排列 = 2’b1000 = 1’d8
  • 则第8位出错,纠正后 = 001101001 -> 001101011

C++实现

功能编写
  • 计算编码校验位
// calculate the number of check digits for encode
auto cal(size_t sz) -> decltype(auto)
{
  decltype(sz) k = 0;
  decltype(sz) cur = 1;
  while (cur - 1 < sz + k)
  {
    cur <<= 1;
    k++;
  }
  return k;
}
  • 编码
// encode
bool encode(const string &data, string &str)
{

  str.clear();
  auto check = cal(data.size());
  str.resize(data.size() + check);

  for (decltype(str.size()) i = 0, j = 0, p = 0; i != str.size(); i++)
  {
    if ((i + 1) == pow(2, p) && p < check)
    {
      str[i] = '0';
      p++;
    }
    else if (data[j] == '0' || data[j] == '1')
    {
      str[i] = data[j++];
    }
    else
    {
      return false;
    }
  }

  for (auto i = 0; i != check; i++)
  {
    int count = 0, index = 1 << i;
    for (auto j = index - 1; j < str.size(); j += index)
    {
      for (auto k = 0; k != index && j < str.size(); k++, j++)
      {
        count ^= str[j] - '0';
      }
      str[index - 1] = '0' + count;
    }
  }

  return true;
}
  • 计算解码校验位
// calculate the number of check digits for decode
auto antical(size_t sz) -> decltype(auto)
{
  decltype(sz) k = 0;
  decltype(sz) cur = 1;
  while (cur < sz)
  {
    cur <<= 1;
    k++;
  }
  return k;
}
  • 解码
// decode
auto decode(string &data, string &str) -> decltype(auto)
{

  data.clear();
  auto check = antical(str.size());
  data.resize(str.size() - check);
  decltype(data.size()) sum = 0;

  for (decltype(check) i = 0; i != check; i++)
  {
    int pAnti = 0;
    decltype(check) index = 1 << i;
    for (decltype(str.size()) j = index - 1; j < str.size(); j += index)
    {
      for (auto k = 0; k < index && j < str.size(); j++, k++)
      {
        pAnti ^= str[j] - '0';
      }
    }
    sum += pAnti << i;
  }

  if (sum != 0)
  {
    str[sum - 1] = (1 - (int)(str[sum - 1] - '0')) + '0';
  }

  for (decltype(str.size()) i = 0, j = 0, k = 0; i != str.size(); i++)
  {
    if ((i + 1) == (1 << j) && j < check)
    {
      j++;
    }
    else
    {
      data[k++] = str[i];
    }
  }

  return sum;
}
测试结果
int main()
{
  string source, dest;
  while (cin >> source)
  {
    if (encode(source, dest))
    {
      cout << "source            : " << source << endl;
      cout << "dest              : " << dest << endl;
    }
    size_t index;
    cout << "input error index : ";
    cin >> index;
    auto check = dest.size();
    if (index != 0 && index <= dest.size())
    {
      dest[index - 1] = (1 - (int)(dest[index - 1] - '0')) + '0';
    }
    cout << "code              : " << dest << endl;
    auto ret = decode(source, dest);
    if (ret == 0)
    {
      cout << "source            : " << source << endl;
      cout << "dest              : " << dest << endl;
    }
    else
    {
      cout << "error index       : " << ret << endl;
      cout << "corret source     : " << source << endl;
      cout << "corret dest       : " << dest << endl;
    }
    cout << endl;
  }
  return 0;
}
  • 结果
    【Verilog】汉明码_第1张图片

Verilog实现

.v功能代码
  • 编码
module ham_encoder(
  input  wire        clk,
  input  wire        rst_n,
  input  wire        data_v,
  input  wire [ 7:0] data_in,
  output reg         encode,
  output reg  [11:0] data_out
);

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

always @ (posedge clk or negedge rst_n) begin
  if (!rst_n) begin
    data_out <= 12'b0;
  end else if (data_v) begin
    data_out[11:4] <= data_in[7:0];
    data_out[3]    <= data_in[7]^data_in[5]^data_in[3]^data_in[2];
    data_out[2]    <= data_in[7]^data_in[6]^data_in[4]^data_in[2]^data_in[1];
    data_out[1]    <= data_in[7]^data_in[6]^data_in[5]^data_in[3]^data_in[1]^data_in[0];
    data_out[0]    <= data_in[6]^data_in[4]^data_in[3]^data_in[0];
  end else begin
    data_out <= 12'b0;
  end
end

endmodule
  • 解码
module	ham_decoder(
	input	 wire			   clk,
	input	 wire			   rst_n,
	input	 wire		     data_v,
	input	 wire	[11:0] data_in,
	output reg	[ 7:0] data_out,
	output reg				 decode
);

wire [ 3:0] checkout;
wire [11:0]	data;

always @ (posedge clk or negedge rst_n) begin
  if(!rst_n) begin 
    decode <= 1'd0;
  end else begin
    decode <= 1'b1;
  end
end

assign checkout[3] = data_in[11]^data_in[ 9]^data_in[7]^data_in[6]^data_in[3];
assign checkout[2] = data_in[11]^data_in[10]^data_in[8]^data_in[6]^data_in[5]^data_in[2];
assign checkout[1] = data_in[11]^data_in[10]^data_in[9]^data_in[7]^data_in[5]^data_in[4]^data_in[1];
assign checkout[0] = data_in[10]^data_in[ 8]^data_in[7]^data_in[4]^data_in[0];

assign	data[11] = data_in[11]^( checkout[3]& checkout[2]& checkout[1]&~checkout[0]); 
assign	data[10] = data_in[10]^(~checkout[3]& checkout[2]& checkout[1]& checkout[0]);
assign	data[ 9] = data_in[ 9]^( checkout[3]&~checkout[2]& checkout[1]&~checkout[0]);  
assign	data[ 8] = data_in[ 8]^(~checkout[3]& checkout[2]&~checkout[1]& checkout[0]);   
assign	data[ 7] = data_in[ 7]^( checkout[3]&~checkout[2]& checkout[1]& checkout[0]);   
assign	data[ 6] = data_in[ 6]^( checkout[3]& checkout[2]&~checkout[1]&~checkout[0]);  
assign	data[ 5] = data_in[ 5]^(~checkout[3]& checkout[2]& checkout[1]&~checkout[0]); 
assign	data[ 4] = data_in[ 4]^(~checkout[3]&~checkout[2]& checkout[1]& checkout[0]);  
assign	data[ 3] = data_in[ 3]^( checkout[3]&~checkout[2]&~checkout[1]&~checkout[0]); 
assign	data[ 2] = data_in[ 2]^(~checkout[3]& checkout[2]&~checkout[1]&~checkout[0]); 
assign	data[ 1] = data_in[ 1]^(~checkout[3]&~checkout[2]& checkout[1]&~checkout[0]);
assign	data[ 0] = data_in[ 0]^(~checkout[3]&~checkout[2]&~checkout[1]& checkout[0]);

always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		data_out<= 12'b0;
  end else if(decode) begin
		data_out <= data[11:4];
  end else begin
		data_out <= 12'b0;
  end
end

endmodule

testbench
`timescale  1ns / 1ps
`include "ham_encoder.v"
`include "ham_decoder.v"

module tb_ham;

// edge_detect Parameters
parameter PERIOD  = 10;


// Inputs
reg         clk                                  = 0 ;
reg         rst_n                                = 0 ;
reg         data_v                               = 0 ;
reg  [ 7:0] data_in                                  ;

// Output
wire [11:0] encoder                                  ;
wire        encode                                   ;
wire [ 7:0] decoder                                  ;
wire        decode                                   ;

initial begin
  forever begin
    #(PERIOD) clk = ~clk;
  end
end

initial begin
  #(PERIOD*2) rst_n = ~rst_n;
end

initial begin
  #(PERIOD*2)
  @ (posedge clk)
  data_in = 8'h35;
  data_v  = 1'b1;

  #(PERIOD*2)
  data_in = 8'h0;
  data_v  = 1'b0;
 
end


initial
begin
    $dumpfile("./build/ham.vcd");
    $dumpvars;

    #1000
    $finish;
end

ham_encoder  u_ham_encoder (
    .clk                     ( clk                         ),
    .rst_n                   ( rst_n                       ),
    .data_v                  ( data_v                      ),
    .data_in                 ( data_in   [ 7:0]            ),

    .encode                  ( encode                      ),
    .data_out                ( encoder                     )
);

wire [11:0] err_encoder;
assign err_encoder = {encoder[11:1], ~encoder[0]};

ham_decoder  u_ham_decoder (
    .clk                     ( clk                         ),
    .rst_n                   ( rst_n                       ),
    .data_v                  ( encode                      ),
    .data_in                 ( err_encoder                 ),

    .data_out                ( decoder[ 7:0]               ),
    .decode                  ( decode                      )
);


endmodule
波形

【Verilog】汉明码_第2张图片

你可能感兴趣的:(数字芯片研发,#,Verilog,c++,Verilog,汉明码,编码与解码)