Berlekamp算法 Verilog hdl
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第11章数字通信与控制设计实例
11.9 RS编码器、译码器设计实例
RS编码器是Reed Solomon编码器的简称,它是目前最有效、应用最广泛的差错控制编码方法之一。
它是1960年由Iring
Reed和Gus
Solomon首先构造出来的一种BCH码,既能纠错随机误码又能纠错突发性误码,在数据通信、电视传输、数据存储等领域得到广泛应用。
11.9.1 RS编码器的设计
下面简要介绍RS编码的基本原理,并以RS(63,45)为例,介绍RS编码的Verilog HDL语言设计过程。
1. RS编码的代数知识
数据的多项式表示:可以把二进制数表示为一个多项式。
例如,二进制数“110010”,可以表示为以下多项式:
(11-48)
表11-11 部分本原多项式
<DIV align=center>m本原多项式P(X)
2
3
4
5
6
7
8
</DIV>
以m=6为例,GF()的全部符号的求法如表11-12所示。
表11-12 伽罗华域符号的求法
由于篇幅有限,表11-12只列出了部分的符号,其余求法类似。
GF()的生成多项式为式(11-49):
(11-49)
展开式(11-49),合并同类项,并运用伽罗华四则运算化简得到式(11-50):(11-50)
根据式(11-50)画出RS编码的电路图,如图11-71所示。
图11-71 RS编码的电路图
2. RS编码的乘法器
根据伽罗华域运算规则设计乘法器。
当系数为0时,乘法器的Verilog HDL代码如下:
module mula_0(a,c);
input [5:0] a;
output [5:0] c;
reg [5:0] c;
always @(a)
begin
c[5]<=a[5];
c[4]<=a[4];
c[3]<=a[3];
c[2]<=a[2];
c[1]<=a[1];
c[0]<=a[0];
end
endmodule
代码分析:
由于伽罗华域的加法是作异或运算,当系数为0时,乘积即为本身。
当系数为1时,乘法器的Verilog HDL 代码如下:
module mula_1(a,c);
input [5:0] a;
output [5:0] c;
reg [5:0] c;
always @(a)
begin
c[5]<=a[4];
c[4]<=a[3];
c[3]<=a[2];
c[2]<=a[1];
c[1]<=a[5] ^ a[0];
c[0]<=a[5];
end
endmodule
代码分析:
假设乘数为,它乘以x,得到式(11-51):
(11-51)
化简得到式(11-52):
(11-52)
上面代码中的c[1]<=a[5] ^
a[0],当系数为其他值时,按此方法类似求得。
由于篇幅有限,这里不一一列出所有代码,具体的请参考光盘内容。
3. RS编码的Verilog HDL实现
根据图11-1<A language=JavaScript class=msocomanchor id=_anchor_1
onmouseover="msoCommentShow('_anchor_1','_com_1')"
onmouseout="msoCommentHide('_com_1')"
href="/manage/read/ShowSection.asp?ChapterID=1000000244#_msoc om_1"
name=_msoanchor_1>[G7] ,组合RS编码的乘法器,设计Verilog HDL代码如下:
module rscode(clk, clr, start, datavalid, x, y);
input clk;
input clr;
input start;
input datavalid;
input [5:0] x;
output [5:0] y;
reg [5:0] y;
wire [5:0] mul0, mul1, mul2, mul3, mul4, mul5;
wire [5:0] mul6, mul7, mul8, mul9, mul10, mul11;
wire [5:0] mul12, mul13, mul14, mul15, mul16, mul17;
reg [5:0] r0, r1, r2, r3, r4, r5;
reg [5:9] r6, r7, r8, r9, r10, r11;
reg [5:0] r12, r13, r14, r15, r16, r17;
reg [5:0] databack;
//调用乘法器
mula_45 g0(.a(databack), .c(mul0));
mula_48 g1(.a(databack), .c(mul1));
mula_3 g2(.a(databack), .c(mul2));
mula_51 g3(.a(databack), .c(mul3));
mula_35 g4(.a(databack), .c(mul4));
mula_11 g5(.a(databack), .c(mul5));
mula_32 g6(.a(databack), .c(mul6));
mula_59 g7(.a(databack), .c(mul7));
mula_25 g8(.a(databack), .c(mul8));
mula_31 g9(.a(databack), .c(mul9));
mula_6 g10(.a(databack), .c(mul10));
mula_21 g11(.a(databack), .c(mul11)); mula_38 g12(.a(databack), .c(mul12)); mula_61 g13(.a(databack), .c(mul13)); mula_3 g14(.a(databack), .c(mul14)); mula_0 g15(.a(databack), .c(mul15)); mula_59 g16(.a(databack), .c(mul16)); mula_22 g17(.a(databack), .c(mul17));
always @(posedge clk)
begin
if(clr == 1'b0)
begin
r0 <= 6'd0;
r1 <= 6'd0;
r2 <= 6'd0;
r3 <= 6'd0;
r4 <= 6'd0;
r5 <= 6'd0;
r6 <= 6'd0;
r7 <= 6'd0;
r8 <= 6'd0;
r9 <= 6'd0;
r10 <= 6'd0;
r11 <= 6'd0;
r12 <= 6'd0;
r13 <= 6'd0;
r14 <= 6'd0;
r15 <= 6'd0;
r16 <= 6'd0;
r17 <= 6'd0;
end
else if(start == 1'b1) //作异或运算begin
r0 <= mul0;
r1 <= r0 ^ mul1;
r2 <= r1 ^ mul2;
r3 <= r2 ^ mul1;
r4 <= r3 ^ mul1;
r5 <= r4 ^ mul1;
r6 <= r5 ^ mul1;
r7 <= r6 ^ mul1;
r8 <= r7 ^ mul1;
r9 <= r8 ^ mul1;
r10 <= r9 ^ mul1;
r11 <= r10 ^ mul1;
r12 <= r11 ^ mul1;
r13 <= r12 ^ mul1;
r14 <= r13 ^ mul1;
r15 <= r14 ^ mul1;
r16 <= r15 ^ mul1;
r17 <= r16 ^ mul1;
end
end
always @(datavalid or x or r17)
begin
if(datavalid == 1'b1)
begin
databack <= x ^ r17;
end
else
begin
databack <= 6'd0;
end
end
always @(datavalid or x or r17)
begin
if(datavalid == 1'b1) //输出数据
begin
y <= x;
end
else //输出检验码
begin
y <= r17;
end
end
endmodule
保存代码为rscode.v,并设为顶层文件,编译工程,编译无误后单击Processing →Generate Functional
Simulation
Netlist,产生功能仿真网表。
新建波形仿真文件,加入输入输出信号,设置系统时钟信号clk的周期为10ns,单击输入信号clr,设置为前20ns为低有效,后面的为高无效;单击输入信号start,设置为前20ns低无效,后面的为高有效;单击输入信号datavalid,设置为20~470ns为高有效,其他时间为低无效;单击输入信号x,设置从20ns开始,每隔10ns加“1”。
保存波形文件为
rscode.vwf,单击按钮进行RS编码器的波形仿真,波形仿真报告如图11-72
所示。
图11-72 RS编码器的波形仿真报告
波形仿真报告说明:
在信号datavalid为高时,输出信号y就是输入数据x;当信号datavalid为低时,输出信号y是18个校验码。
11.9.2 RS(204, 188)译码器的设计
RS码在通信系统、数字电视和计算机存储系统中应用很广泛。
例如,DVB(数字电视)标准中信道编/解码采用RS(204,
188);A TM网络中使用RS(128, 124)作为前向纠错编码(Forward Error Correcting, FEC)。
本节将以DVB标准中定义的RS(204,
188)译码器为例,详细介绍基于改进的BM迭代算法、pipeline结构的译码的所有技术细节。
考虑到译码器的可扩展性、可维护性,实例中尽可能地使用参数化、模块化的设计。
读者可在实例代码基础上作很小的改动,就能实现不同需要的RS译码器。
1. 应用背景
在数字通信、数字电视中,信道编码的使用提高了数据传输的质量。
虽然增加了传输带宽,但信道编码减小了数据传输出现误码的概率,同时也减小了所需要的信噪比(signal-to-noise
rate)。
在大多数应用中,将RS码与卷积码级联使用进行纠错。
在自信源至接收的过程中,数字电视信号的编码包括信源编码、信道编码及加密。
信道编码又称做前向纠错编码,其目的是提高信息传送或传输的可靠性,当传输差错在一定范围内,接收机都能将误码纠正过来。
必须指出,信道编码并非指信号经上变频发送出去后,在传输信道中(有线、卫星或地面)进行编码,而是指经过编码后便匹配信道传输和减少差错。
因此,自信源编码后的所有编码包括能量随机化扰码、卷积、交织、Reed-Solomon编码等都可划为信道编码。
典型的数字电视信道编码如图11-73所示。
<DIV>
TS流
</DIV>
<DIV>
MPEG-2
</DIV>
<DIV>
复用匹配与能量扩散
</DIV>
<DIV>
交织
</DIV>
<DIV>
信道
调制
</DIV>
<DIV>
外码
编码
</DIV>
<DIV>
内码
编码
</DIV>
<DIV>
基带
形成
</DIV>
图11-73 数字电视信道编码的一般结构框图
在图11-73中,外编码多为具有很强突发纠错能力的RS(n, k,
t)编码,n为(缩短)码长,k为信息位,t为能纠正误码的最大的码位,且RS外码编码的特点是纠正与本组有关的误码,尤其对纠正突发性的误码最有效。
通常,n、k、t分别为204、188和8。
如图11-74所示为“EN 300 429”有线数字电视(DVB-C)标准规定的发送端(Cable
Head-end)框图,其中包括了数据帧结构(Framing structure)、信道编码及调制。
可以看到,使用了RS(204,
188)编码。
图11-74 DVB-C前端框图
2. 理论算法
RS译码主要有时域译码和频域译码,时域译码通常采用BM迭代算法或者欧式算法(Euclid’s
Algorithm)。
本文主要介绍BM迭代算法原理及以此算法为基础的RS译码器的FPGA实现。
RS译码可分为4步:第一步由接收到的码组计算伴随式;第二步求解关键方程;第三步计算出错误图样;最后由错误图样和接收码组计算出可能发送的码字。
图11-75给出了RS译码器的一般步骤框图。
图11-75 RS译码器的一般步骤框图
RS译码的关键在于求解错误位置多项式Λ(x),1966年伯利坎普(Berlekamp)提出了可以由伴随式计算错误位置多项式的迭代译码算法,这极大地加快了求解错误位置多项式的速度,该方法简单且易于实现,从而从工程上解决了RS译码的问题;1969年梅西(Massey)指出了该算法与序列的最短线性移位寄存器综合之间的关系,并进行了简化,因此,此译码算法就称为BM迭代译码算法。
(1)Reed-Solomon码基本概念
RS循环码是广泛用于数字电视传输系统中的前向纠错码的重要组成,是一个符号取自有限域GF(q),长度为n,信息位长为k的(n,
k)线性分组码。
其中的任何码矢C = (Cn-1,…, C1, C0),可用码字多项式表示为:
…(11-53)
如果F是包含阶数为n的元素a的有限域,r是1到n之间的固定的整数,F 域中的所有矢量C = (C0, C1,…, Cn-1)满足下式:
j = 0,1,…,r-1 (11-54)
那么,这样的矢量集就称做在有限域F上的长度为n冗余为r的Reed-Solomon 码。
其中,b0为任意整数,通常取1,但在DVB标准中b0=0。
矢量C称做该码的码字(codeword)。
RS码是特殊的BCH码,其码字C和生成多项式g(x)均在同一个有限域内。
对于本源BCH码,分组长度n = qm –
1,其生成多项式g(x)的根在扩展域GF(qm)内。
BCH码的g(x)可表示为:
…(11-55)
其中,LCM表示多项式的最小公倍数。
mai表示GF(qm)域中的本原元ai在GF(q)中的最小多项式(minimal
polynomial)。
d 称做码设计间距(design distance),且3≤d≤n。
如果取m = 1,则n = q –
1,此时就得到了标准的RS码。
因为最小多项式和本原元均在GF(q)中,则最小多项式的次数(degress)为1,形式为(x -
ai),所以RS码的生成多项式简化为:
…(11-56)
对于RS码,n –k = d-1。
因为是特殊的BCH码,所以其最小码间距dmin ≥d。
又因为所有的线性码的码间距只能小于等于n –k
+ 1,所以
dmin = n –k + 1 (11-57)
为了便于理解RS码的译码原理,由式(11-54)的定义可得出下面重要性质。
设RS码的码矢为C = (Cn-1,…, C1,
C0),其对应的码字多项式C(x)如式(11-53)所示,则C(x)有由本原元a为底连续的从b0到(b0 +d - 2) 为幂的d -
1个根。
即:
,i = 0, 1,…,d-2 (11-58)
此外,还可以从频域的角度进行分析。
有限域的N点DFT(离散傅里叶变换)定义为:
,i = 0, 1,…, N-1 (11-59)
其中,x = (x0, x1,…, xN-1)是来自GF(q)、长度为N的序列。
a是来自GF(qm),阶数(order)为N,即aN =
1。
如果令m = 1(如RS码),则DFT变换对应的序列x和X均属于同一个域GF(q)。
同理,DFT的逆变换IDFT定义为:
…(11-60)
设RS码的码字为C = (Cn-1,…, C1,
C0),码字多项式为C(x)如式(11-53)所示。
若其对应的DFT变换序列为,则由式(11-53)和式(11-59)有:
,i = 0, 1,…, N-1 (11-61)
由式(11-61)的定义可知,RS码的码字的DFT序列从b0, b0+1,…, b0+d -2位置连续的d-1个系数均为0。
(2)RS译码与关键方程
在介绍RS译码的关键方程之前,先给出下面的定义及定理。
对于给定一个矢量V,其支持集(support set)I定义为:
(11-62)
定义矢量V的位置多项式(locator polynomial)为:
(11-63)
定义矢量V的第i个点的位置多项式(punctured locator polynomial)为:
(11-64)
最后,定义矢量V的计算多项式(evaluator polynomial)为:
(11-65)
定理11.1的推论1表明,使用式(11-68),矢量V的时域坐标可以由σV(x)和ωV(x)恢复出来。
下面开始讨论RS译码的具体问题。
假设C = (C0, C1,…, Cn-1)为纠错能力为t 的RS(n, k)
码的码字。
码字C发送后经过有噪声信道,接收端收到的码字为R = (R0, R1,…, Rn-1)。
设传输过程中加入的错误图样(error
pattern)矢量为E = (E0, E1,…, En-1) = R –C。
定义伴随式(syndrome)Sj 为:
(3)BM及其改进算法求解关键方程
1966年伯利坎普(Berlekamp)提出了可以由伴随式计算错误位置多项式的迭代译码算法,这极大地加快了求解错误位置多项式的速度,该方法简单且易于实现,从而从工程上解决了RS译码的问题;1969年梅西(Massey)指出了该算法与序列的最短线性移位寄存器综合之间的关系,并进行了简化,因此,此译码算法就称为BM迭代译码算法。
在VLSI设计中,RS解码时的关键方程求解比较复杂,主要有以下三种方法:Berlekamp-Massey(BM)算法、Euclidean算法、PGZ
算法。
当错误个数(t>3)值较大时,一般认为BM算法占用最少的面积和时间及相对小的结构复杂度。
但是,BM算法涉及到有限域元素求逆(inverse),这是个很复杂、很耗时的运算。
而本文的RS(204,
188)译码器关键方程求解采用了改进的BM算法,算法迭代时无需求解有限域元素逆(inversionless)。
下面首先详细介绍BM算法。
设纠错能力为t的RS(n, k)码的错误位置多项式为…,d≤t由式(11-66)可知:
(11-77)
因此,对于任意的j(0≤j≤n-1),下式成立:
,j = d, d+1, 2t-1 (11-78)
其中,d为误码的个数。
式(11-78)可以用图11-76的移位寄存器描述。
图11-76 移位寄存器描述的关键方程
BM算法可以得到最小次数多项式(即最短的移位寄存器),用于确定错误位置多项式。
该算法逐渐增加移位寄存器的长度,从0开始直到等于实际错误的个数。
若式(11-78)不成立,则要么改变si系数,要么增加移位寄存器长度。
例如,有差值(discrepancy)
dn为:
(11-79)
如果dn不为零,则新的移位寄存器系数在上次改变值的基础上加上当前值。
上次的系数按照移位寄存器的方向移动,直到与伴随式相对应。
随后,相同的差值dn使得移位寄存器长度改变。
新的错误位置多项式由下式给出:
(11-80)
其中,n –
m为移位次数(长度),dn为新的差值,dm为上一次长度改变时的差值。
只有当dn≠0并且2Ln≤n时,才会引起长度的改变。
在介绍改进的BM算法前,先给出完整的BM算法的流程。
(1)初始化
(2)下面的步骤从式(11-81)到式(11-85)循环迭代,直到k=d -1。
(11-81)
(11-82)
(11-83)
(11-84)
(11-85)
其中,为错误位置多项式,即式(11-76)中的。
在上面的BM算法中,式(11-83)求B(x)中用到有限域元素求逆运算,即[(k)]-1。
因为有限域求逆(除法)运算很复杂,下面给出改进的BM算法,无需求逆。
改进的BM算法如下。
(1)初始化:
(2)下面的步骤从式(11-86)到式(11-91)循环迭代,直到k=d -1。
(11-86)
(11-87)
(11-88)
(11-89)
(11-90)
(11-91)
其中,为错误位置多项式。
在上面改进的BM算法中,整个过程没有用到有限域元素求逆运算。
通过比较两种算法,可以有下面的结论:
(11-92)
(11-93)
(11-94)
特别地,
(11-95)
其中,k为常数,。
所以,和有相同的根,并且都能作为错误位置多项式。
二者最大的区别是:σ(x)多项式的最小次数项系数为1;而
(x)的最小次数项系数可为非0的任意数。
(4)Chien搜索和Forney算法
在算出错误位置多项式Λ(x)后,就可以结合关键方程求出错误图样。
结合式(11-95)及s(x)的定义:
则有:
(11-96)
其中,I={i:Ei≠0}。
所以,通过将有限域元素的倒数(即s(x)的根)代入错误位置多项式,就可以找到错误所在的位置,这就是Chien搜索的原理。
具体做法是:将有限域元素
…逐次代入,若,则接收到的第i个码出现误码。
在s(x)和S(x)均已知的情况下,通过式(11-76)的BCH/RS关键方程可求出错误计算多项式w(x)。
即:
(11-97)
用(x)替换s(x),用(x)替换w(x),则有下式:
(11-98)
在确定了误码的位置后,可以使用Forney算法求出该位置的错误样值。
用交织的错误矢量…替换定理11.1的推论1中的矢量V,即用代替
,可得:
(11-99)
其中,i∈I。
在式(11-99)中,因为并且,所以Forney算法也可改写为:
(11-100)
最后,利用C=R-E就可得到纠正后的正确的码字。
3. RS(204, 188)译码器建模
这里以具体的DVB标准中定义的RS(204, 188)码为例,详细讨论其实现的FPGA/VLSI硬件模型。
在DVB标准中,RS(204,
188)码定义如下:
码生成多项式:…(11-101)
域生成多项式:(11-102)
由定义可知:n=204,t=8,d=2t+1=17,b0=0。
(1)伴随式计算模块
回顾前面Sj的定义,…。
其中:
…, 对于Sj的计算,下面给出一个高效的算法——Horner准则,采用嵌套的乘累加运算:
……(11-103)
将n=204,b0=0代入,则有:
… … … … ……
… …
式(11-100)的运算可以用流水线结构硬件实现,如图11-77所示为通用伴随式计算框图。
图中“D”代表寄存器,“+”代表有限域加法,“×”代表有限域乘法。
初始
化时,所有寄存器置0。
经过204个时钟周期,接收完所有的204个符号后,就可以得到全部16个伴随式。
图11-77 通用伴随式计算框图
(2)改进的BM算法模块
当2t个伴随式都求出以后,就可以通过改进的BM算法求错误位置多项式σ(x),即BM算法中的(x)。
在此回顾式(11-86):
很显然,是与的卷积求和运算。
为了实现流水线处理,可以采用FIR滤波器技术来实现。
如图11-78所示为FIR滤波器计算。
初始化时,所有寄存器置0,然后每个时钟周期,依次将S1, S2,…, S2t移入移位寄存器。
滤波器系数i也在每个时钟周期更新一次。
图11-78 FIR滤波器计算此外,简要提一下,在改进的BM算法中,式(11-87)求L(x)。
因为L(x)是多项式,即求L(x)的多项式系数。
所以,式(11-87)分解成t+1个运算。
即:
(11-104)
从式(11-104)可以看出,在循环迭代过程中L(x)的系数除L0(仅1个乘法器)外,各需要2个乘法器和1个加法器(除L0外)实现。
(3)Chien搜索模块
由式(11-96)可知,L(x)可用来搜索错误位置,方法是:依次将…代入L(x),若L(a-i) =
0,则在该位置出现误码。
等效的实现框图如图11-79所示。
图11-79 Chien搜索模块框图
(4)Forney算法模块
在求出等价的错误位置多项式L(x)后,可以利用式(11-98)等价的错误计算多项式W(x),即:
因为W(x)的结果为mod x2t,所以W(x)的最高次数为2t-1。
因此,W(x)可表示为:
(11-105)
式(11-105)中,W(x)的系数可分别表示为:
(11-106)
从式(11-106)可以看出,两个多项式的相乘其实质是两个多项式对应的系数卷积求和。
因此,式(11-106)运算也可采用FIR滤波器技术来实现,对应的原理框图如图11-80所示。
初始化时,所有寄存器置0。
然后在每个时钟周期,伴随式从S1,…,
S2t依次移入移位寄存器,生成的Wi依次经过移位寄存器。
最终,2t个Wi 移位寄存器的内容从左到右依次为:W2t-1,…, W1, W0。
图11-80 FIR实现的W (x)计算框图
下面介绍错误位置多项式L(x)的导数L'(x)计算。
设L(x)表示如下:
则按照导数的定义有:
(11-107)
在通常情况下,用到的RS码都是基于GF(2m)域的。
根据有限域的知识,域GF(pm)的特征(characteristic)为p,即域中的任一元素累加p次的和为0。
故对于式(11-107)有,2L2=0,3L3=L3,依此类推,式(11-107)可以简化为:
(11-108)
其中,m为≤t的最大奇数。
若以RS(204, 188)码为例,其t=8,则有:
硬件结构框图如图11-81所示。
图11-81 t=8时的L'(x)硬件结构框图
再次回顾式(11-100)的Forney算法如下:
大多数的RS码b0=1,所以a的幂项为1。
但是,在DVB标准中,b0=0,所以式(11-100)可以写成:
(11-109)
式(11-109)的硬件实现框图如图11-82所示。
图11-82 Forney算法及误码校正硬件实现框图
在图11-82中,“Pow”模块表示生成根ai的幂次i,“Exp”表示查表求ai的幂,“Inv”用查找表求L´(a-i)的逆。
4. 程序说明
本部分将给出RS(204, 188)译码器的Verilog HDL程序代码,其中RS码的生成多项式g(x)为:
该程序代码已经仿真、验证,能够纠正不大于8个的误码,完全实现流水线结构,伴随式计算、关键方程求解、Forney算法、Chien搜索等模块并行工作。
在经过243个字节的固有延时后,每个时钟周期都能连续输出经校正的码字。
同时,与前端及后续电路的接口简单,无需额外的握手控制信号。
考虑到文章篇幅,此处仅给出几个关键模块的代码,在随书光盘中有完整的程序代码,请读者参阅。
下面首先给出伴随式计算模块程序,如下所示。
module SCalculate(clk, init, sc_done, r, s_out);
parameter t = 8, //t—纠错能力
N = 204, //N—RS码长度
m = 8; //m—GF(2m)扩展域
input clk, init;
input [m-1:0] r;
output[m-1:0] s_out;
output sc_done; //伴随式计算完成信号
reg [m-1:0] s[t*2:1], s_latched[t*2:1];
wire [m-1:0] r_a[t*2-1:0];
integer counter;
always @(posedge clk)begin:SC_BLOCK
integer j;
if((init) || (counter==N))begin
for(j=1; j<=t*2; j=j+1) //锁存上一帧数据的伴随式,开始新的计算
s_latched[j] <= s[j];
for(j=1; j<=t*2; j=j+1)
s[j] <= r;
counter <= 1;
end
else if(counter<=N-1)begin
for(j=1; j<=t*2; j=j+1)
s[j] <= r ^ r_a[j-1];
counter <= counter + 1;
end
end
/* 下面是有限域的常数乘法器的例化*/
ff_const_mul r_x_a0(.din(s[1]), .dout(r_a[0])); //a^0
ff_const_mul r_x_a1(.din(s[2]), .dout(r_a[1])); //a^1
ff_const_mul r_x_a2(.din(s[3]), .dout(r_a[2])); //a^2
ff_const_mul r_x_a3(.din(s[4]), .dout(r_a[3])); // a^3
ff_const_mul r_x_a4(.din(s[5]), .dout(r_a[4])); // a^4
ff_const_mul r_x_a5(.din(s[6]), .dout(r_a[5])); // a^5
ff_const_mul r_x_a6(.din(s[7]), .dout(r_a[6])); // a^6
ff_const_mul r_x_a7(.din(s[8]), .dout(r_a[7])); // a^7
ff_const_mul r_x_a8(.din(s[9]), .dout(r_a[8])); // a^8
ff_const_mul r_x_a9(.din(s[10]), .dout(r_a[9])); // a^9
ff_const_mul r_x_a10(.din(s[11]), .dout(r_a[10])); // a^10
ff_const_mul r_x_a11(.din(s[12]), .dout(r_a[11])); // a^11
ff_const_mul r_x_a12(.din(s[13]), .dout(r_a[12])); // a^12
ff_const_mul r_x_a13(.din(s[14]), .dout(r_a[13])); // a^13
ff_const_mul r_x_a14(.din(s[15]), .dout(r_a[14])); // a^14
ff_const_mul r_x_a15(.din(s[16]), .dout(r_a[15])); // a^15
defparam r_x_a0.CONST = 15'h4405, r_x_a1.CONST = 15'h6202,
r_x_a2.CONST = 15'h7101, r_x_a3.CONST =
15'h3880, r_x_a4.CONST = 15'h1C40,
r_x_a5.CONST = 15'h0E20, r_x_a6.CONST = 15'h4710, r_x_a7.CONST = 15'h2388,
r_x_a8.CONST = 15'h11C4, r_x_a9.CONST = 15'h48E2,
r_x_a10.CONST = 15'h2471, r_x_a11.CONST = 15'h5238,
r_x_a12.CONST = 15'h691C, r_x_a13.CONST =
15'h748E, r_x_a14.CONST = 15'h3A47,
r_x_a15.CONST = 15'h1D23;
/* 输出sc_done信号,指示后续电路进行新的计算*/
reg sc_done;
integer shift_count;
always @(posedge clk)begin
if(counter == N)begin
sc_done <= 1;
shift_count <= 1;
end
else begin
sc_done <= 0;
if((0<shift_count) && (shift_count <= t*2))begin
shift_count <= shift_count + 1;
end
else
shift_count <= 0;
end
end
//移位输出伴随式
reg [m-1:0] s_out;
always @(shift_count)begin
if((0<shift_count) &&(shift_count <= t*2))
s_out = s_latched[shift_count];
else
s_out = 0;
end
endmodule
对上面的程序有如下的说明。
(1)“init”信号是一个包(码的长度如204)的起始标志,通常称做“同步”信号。
(2)因为RS码的b0 = 0,所以在求伴随式Sj时,a的幂从0开始直到15依次代入式(11-71)。
即:
(3)因为整个译码器采用流水线结构,所以在伴随式计算完后,产生一个时钟周期有效的“sc_done”信号,用以启动后续电路进行新的计算。
(4)由于在BM算法中,用到了L(x)和S(x)的卷积求和,因此本模块将计算出的伴随式序列Sj串行输出。
接下来,给出BM算法求错误位置多项式L(x)的程序代码。
//*****************************************
// 改进的BM算法
//*****************************************
module BMA (S, clk, kes_init, kes_done,
Lmd0, Lmd1, Lmd2, Lmd3, Lmd4, Lmd5, Lmd6, Lmd7, Lmd8, L, s_out);
parameter t = 8, N = 204, m = 8;
input clk, kes_init;
input [m-1:0] S;
output [m-1:0] L, Lmd0, Lmd1, Lmd2, Lmd3, Lmd4, Lmd5, Lmd6, Lmd7,
Lmd8; output [m-1:0] s_out;
output kes_done;
reg [m-1:0] L;
reg [m-1:0] B[t:0]; //B(x)即所求的错误多项式
reg [m-1:0] T[t:0], gamma, delta, k;
reg [m-1:0] SSR[t*2:1];
wire [m-1:0] S_B[t:0]; // Product of (S*B)
integer counter;
reg [m-1:0] s_latched[t*2:1];
reg comput, kes_done;
always @(posedge clk)begin:BM_BLOCK
integer j;
if(kes_init)begin //初始化变量
delta <= 0;
for(j=2; j<=t*2; j=j+1)
SSR[j] <= 0;
SSR[1] <= S;
counter <= 0;
end
else if(counter == t*2-1)begin
delta <= ((S_B[0]^S_B[1])^(S_B[2]^S_B[3]))^((S_B[4]^S_B[5])
^(S_B[6]^S_B[7]))^S_B[8]; //更新Δ的值for(j=1; j<=t*2-1; j=j+1)
SSR[j+1] <= SSR[j];
SSR[1] <= S;
for(j=1; j<=t*2; j=j+1) //锁存输入的伴随式序列
s_latched[j] <= SSR[j];
counter <= counter + 1;
end
else if(counter <= t*2)begin
delta <= ((S_B[0]^S_B[1])^(S_B[2]^S_B[3]))^((S_B[4]^S_B[5])
^(S_B[6]^S_B[7]))^S_B[8]; //更新Δ的值for(j=1; j<=t*2-1; j=j+1)
SSR[j+1] <= SSR[j];
SSR[1] <= S;
counter <= counter + 1;
end
end
//计算S(x)*B(x)
FF_Mul S_x_B0(.B(SSR[1]), .A(B[0]), .P(S_B[0]));
FF_Mul S_x_B1(.B(SSR[2]), .A(B[1]), .P(S_B[1]));
FF_Mul S_x_B2(.B(SSR[3]), .A(B[2]), .P(S_B[2]));
FF_Mul S_x_B3(.B(SSR[4]), .A(B[3]), .P(S_B[3]));
FF_Mul S_x_B4(.B(SSR[5]), .A(B[4]), .P(S_B[4]));
FF_Mul S_x_B5(.B(SSR[6]), .A(B[5]), .P(S_B[5]));
FF_Mul S_x_B6(.B(SSR[7]), .A(B[6]), .P(S_B[6]));
FF_Mul S_x_B7(.B(SSR[8]), .A(B[7]), .P(S_B[7]));
FF_Mul S_x_B8(.B(SSR[9]), .A(B[8]), .P(S_B[8]));
wire [m-1:0] gamma_B[t:0]; //Product of γ*B(x)
wire [m-1:0] delta_T[t-1:0]; //Product of Δ*T(x)
always @(negedge clk)begin:LABLE
integer j;
if(kes_init)begin
for(j=1; j<=t; j=j+1)begin
B[j] <= 0; T[j] <= 0;
end
B[0] <= 1; T[0] <= 1;
L <= 0; k <= 0; gamma <= 1;
end
else if(comput)begin
B[0] <= gamma_B[0]; //更新B(x)多项式系数for(j=0; j<t; j=j+1)
B[j+1] <= gamma_B[j+1] ^ delta_T[j];
if((delta) && ((L<<1)<= k))begin //Condition 2
for(j=0; j<=t; j=j+1)
T[j] <= B[j]; //T[x] = B[x]
L <= k + 1 - L;
gamma <= delta; //γ = Δ
end
else begin
for(j=0; j<t; j=j+1)begin
T[j+1] <= T[j]; //T[x] = x * T[x];
end
T[0] <= 0;
end
k <= k + 1;
end
end
//计算γ*B(x)
FF_Mul gamma_x_B0(.A(gamma), .B(B[0]), .P(gamma_B[0])); FF_Mul gamma_x_B1(.A(gamma), .B(B[1]), .P(gamma_B[1])); FF_Mul gamma_x_B2(.A(gamma), .B(B[2]), .P(gamma_B[2])); FF_Mul gamma_x_B3(.A(gamma), .B(B[3]), .P(gamma_B[3])); FF_Mul gamma_x_B4(.A(gamma), .B(B[4]), .P(gamma_B[4])); FF_Mul gamma_x_B5(.A(gamma), .B(B[5]), .P(gamma_B[5])); FF_Mul gamma_x_B6(.A(gamma), .B(B[6]), .P(gamma_B[6])); FF_Mul gamma_x_B7(.A(gamma), .B(B[7]), .P(gamma_B[7])); FF_Mul gamma_x_B8(.A(gamma), .B(B[8]), .P(gamma_B[8]));
//计算Δ*T(x)
FF_Mul delta_x_T0(.A(delta), .B(T[0]), .P(delta_T[0]));
FF_Mul delta_x_T1(.A(delta), .B(T[1]), .P(delta_T[1]));
FF_Mul delta_x_T2(.A(delta), .B(T[2]), .P(delta_T[2]));
FF_Mul delta_x_T3(.A(delta), .B(T[3]), .P(delta_T[3]));
FF_Mul delta_x_T4(.A(delta), .B(T[4]), .P(delta_T[4])); FF_Mul delta_x_T5(.A(delta), .B(T[5]), .P(delta_T[5])); FF_Mul delta_x_T6(.A(delta), .B(T[6]), .P(delta_T[6])); FF_Mul delta_x_T7(.A(delta), .B(T[7]), .P(delta_T[7]));
always @(counter)begin
if((0<counter)&&(counter<=t*2))
comput = 1;
else
comput = 0;
end
integer shift_count;
always @(posedge clk)begin
if(counter == t*2-1)begin
kes_done <= 1;
shift_count <= 1;
end
else begin
kes_done <= 0;
if((0<shift_count) && (shift_count <= t*2))begin
shift_count <= shift_count + 1;
end
else
shift_count <= 0;
end
end
reg [m-1:0] s_out;
always @(shift_count)begin
if((0<shift_count) &&(shift_count <= t*2))
s_out = s_latched[t*2-shift_count+1];
else
s_out = 0;
end
assign Lmd0 = B[0];
assign Lmd1 = B[1];
assign Lmd2 = B[2];
assign Lmd3 = B[3];
assign Lmd4 = B[4];
assign Lmd5 = B[5];
assign Lmd6 = B[6];
assign Lmd7 = B[7];
assign Lmd8 = B[8];
endmodule
关于改进的BM算法,对程序说明如下。
(1)回顾一下L(x)的计算公式:
为了在求出值后,能马上用于计算L(k+1),程序中用到了反相时钟,即在时钟上升沿计算,在时钟下降沿计算L(k+1)。
(2)同样,BM模块也是串行输出伴随式序列,以便后面的卷积求和。
下面的程序代码完成了Forney算法,包括错误计算多项式W(x)的计算。
//******************************************
// 计算:Ei = α^i*Ω(α^-I)/Λ`(α^-i)^2
//******************************************
module error_valuator(clk, init, s,
Lmd0, Lmd1, Lmd2, Lmd3, Lmd4, Lmd5, Lmd6, Lmd7, Lmd8,
ErrorValue);
parameter t = 8, N = 204, m = 8;
input clk, init;
input [m-1:0] s, Lmd0, Lmd1, Lmd2, Lmd3, Lmd4, Lmd5, Lmd6, Lmd7,
Lmd8;
output [m-1:0] ErrorValue;
/* 计算:Ω(x) = Λ(x)*S(x) (mod x^2t) */
reg [m-1:0] OmegaC[t*2-1:0], SyndromeSR[t+1:1], LmdC[t:0];
wire[m-1:0] sLmdC[t:0];
integer counter1;
always @(posedge clk)begin:OMEGA_COEEFICIENT
integer j;
if(init)begin
for(j=2; j<=t+1; j=j+1) //加载伴随式序列(从1到2t)
SyndromeSR[j] <= 0;
SyndromeSR[1] <= s;
//加载错误位置多项式Λ(x)的系数
LmdC[0] <= Lmd0; LmdC[1] <= Lmd1; LmdC[2] <= Lmd2;
LmdC[3] <= Lmd3; LmdC[4] <= Lmd4; LmdC[5] <= Lmd5;
LmdC[6] <= Lmd6; LmdC[7] <= Lmd7; LmdC[8] <= Lmd8;
for(j=0; j<=t*2-1; j=j+1) //初始化OmegaC[j]寄存器
OmegaC[j] <= 0;
counter1 <= 1;
end
else if((0<counter1) && (counter1 <= t*2))begin
for(j=1; j<=t; j=j+1)
SyndromeSR[j+1] <= SyndromeSR[j];
SyndromeSR[1] <= s;
for(j=0; j<t*2-1; j=j+1)
OmegaC[j] <= OmegaC[j+1];
OmegaC[t*2-1] <= (sLmdC[0]^sLmdC[1])^(sLmdC[2]^sLmdC[3])
^(sLmdC[4]^sLmdC[5])^(sLmdC[6]^sLmdC[7])^sLmdC[8];
counter1 <= counter1 + 1;
end
else
counter1 <= 0;
end
FF_Mul s_x_Lmdc0(.A(SyndromeSR[1]), .B(LmdC[0]), .P(sLmdC[0]));
FF_Mul s_x_Lmdc1(.A(SyndromeSR[2]), .B(LmdC[1]), .P(sLmdC[1]));
FF_Mul s_x_Lmdc2(.A(SyndromeSR[3]), .B(LmdC[2]), .P(sLmdC[2]));
FF_Mul s_x_Lmdc3(.A(SyndromeSR[4]), .B(LmdC[3]), .P(sLmdC[3]));
FF_Mul s_x_Lmdc4(.A(SyndromeSR[5]), .B(LmdC[4]), .P(sLmdC[4]));
FF_Mul s_x_Lmdc5(.A(SyndromeSR[6]), .B(LmdC[5]), .P(sLmdC[5]));
FF_Mul s_x_Lmdc6(.A(SyndromeSR[7]), .B(LmdC[6]), .P(sLmdC[6]));
FF_Mul s_x_Lmdc7(.A(SyndromeSR[8]), .B(LmdC[7]), .P(sLmdC[7]));
FF_Mul s_x_Lmdc8(.A(SyndromeSR[9]), .B(LmdC[8]), .P(sLmdC[8]));
reg Comput_Err; //启动Ω(a^-i)计算的控制信号
always @(counter1)begin
if(counter1 == (t*2+1) )Comput_Err = 1;
else Comput_Err = 0;
end
//依次计算Ω(a^-i),i从203~0
reg [m-1:0] OmegaIR[t*2-1:0], OmegaA;
wire[m-1:0] aOmegaIR[t*2-1:1], a52OmegaC[t*2-1:1];
always @(posedge clk)begin:OMEGA_ALPHA
integer j;
if(Comput_Err)begin
for(j=1; j<=t*2-1; j=j+1) //加载OmegaIR[j]迭代寄存器
OmegaIR[j] <= a52OmegaC[j];
OmegaIR[0] <= OmegaC[0];
end
else begin //计算Ω(a^-i)
for(j=1; j<=t*2-1; j=j+1)
OmegaIR[j] <= aOmegaIR[j];
OmegaIR[0] <= OmegaIR[0];
end
end
ff_const_mul a1_x_OmegaIR1(.din(OmegaIR[1]),
.dout(aOmegaIR[1])); // a^1*Ω1 ff_const_mul a2_x_OmegaIR2(.din(OmegaIR[2]),
.dout(aOmegaIR[2])); //
a^2*Ω2
ff_const_mul a3_x_OmegaIR3(.din(OmegaIR[3]),
.dout(aOmegaIR[3])); // a^3*Ω3
ff_const_mul a4_x_OmegaIR4(.din(OmegaIR[4]),
.dout(aOmegaIR[4])); // a^4*Ω4
ff_const_mul a5_x_OmegaIR5(.din(OmegaIR[5]),
.dout(aOmegaIR[5])); // a^5*Ω5
ff_const_mul a6_x_OmegaIR6(.din(OmegaIR[6]),
.dout(aOmegaIR[6])); // a^6*Ω6
ff_const_mul a7_x_OmegaIR7(.din(OmegaIR[7]),
.dout(aOmegaIR[7])); // a^7*Ω7
ff_const_mul a8_x_OmegaIR8(.din(OmegaIR[8]),
.dout(aOmegaIR[8])); // a^8*Ω8
ff_const_mul a9_x_OmegaIR9(.din(OmegaIR[9]),
.dout(aOmegaIR[9])); // a^9*Ω9
ff_const_mul a10_x_OmegaIR10(.din(OmegaIR[10]),
.dout(aOmegaIR[10])); // a^10*Ω10
ff_const_mul a11_x_OmegaIR11(.din(OmegaIR[11]),
.dout(aOmegaIR[11])); // a^11*Ω11
ff_const_mul a12_x_OmegaIR12(.din(OmegaIR[12]),
.dout(aOmegaIR[12])); // a^12*Ω12
ff_const_mul a13_x_OmegaIR13(.din(OmegaIR[13]),
.dout(aOmegaIR[13])); // a^13*Ω13
ff_const_mul a14_x_OmegaIR14(.din(OmegaIR[14]),
.dout(aOmegaIR[14])); // a^14*Ω14
ff_const_mul a15_x_OmegaIR15(.din(OmegaIR[15]),
.dout(aOmegaIR[15])); // a^15*Ω15
defparam
a1_x_OmegaIR1.CONST = 15'h6202,
a2_x_OmegaIR2.CONST=15'h7101,
a3_x_OmegaIR3.CONST =
15'h3880,a4_x_OmegaIR4.CONST=15'h1C40,
a5_x_OmegaIR5.CONST =
15'h0E20,a6_x_OmegaIR6.CONST=15'h4710,
a7_x_OmegaIR7.CONST =
15'h2388,a8_x_OmegaIR8.CONST=15'h11C4,
a9_x_OmegaIR9.CONST =
15'h48E2,a10_x_OmegaIR10.CONST=15'h2471,
a11_x_OmegaIR11.CONST =
15'h5238,a12_x_OmegaIR12.CONST=15'h691C,
a13_x_OmegaIR13.CONST =
15'h748E,a14_x_OmegaIR14.CONST=15'h3A47,
a15_x_OmegaIR15.CONST = 15'h1D23;
ff_const_mul a52_x_OmegaC1(.din(OmegaC[1]),
.dout(a52OmegaC[1])); // a^52*Ω1
ff_const_mul a52_x_OmegaC2(.din(OmegaC[2]),
.dout(a52OmegaC[2])); // a^104*Ω2
ff_const_mul a52_x_OmegaC3(.din(OmegaC[3]),
.dout(a52OmegaC[3])); // a^156*Ω3
ff_const_mul a52_x_OmegaC4(.din(OmegaC[4]),
.dout(a52OmegaC[4])); // a^208*Ω4
ff_const_mul a52_x_OmegaC5(.din(OmegaC[5]),
.dout(a52OmegaC[5])); // a^260*Ω5
ff_const_mul a52_x_OmegaC6(.din(OmegaC[6]),
.dout(a52OmegaC[6])); // a^312*Ω6
ff_const_mul a52_x_OmegaC7(.din(OmegaC[7]),
.dout(a52OmegaC[7])); // a^364*Ω7
ff_const_mul a52_x_OmegaC8(.din(OmegaC[8]),
.dout(a52OmegaC[8])); // a^416*Ω8
ff_const_mul a52_x_OmegaC9(.din(OmegaC[9]),
.dout(a52OmegaC[9])); // a^468*Ω9
ff_const_mul a52_x_OmegaC10(.din(OmegaC[10]),
.dout(a52OmegaC[10])); // a^520*Ω10
ff_const_mul a52_x_OmegaC11(.din(OmegaC[11]),
.dout(a52OmegaC[11])); //
a^572*Ω11
ff_const_mul a52_x_OmegaC12(.din(OmegaC[12]),
.dout(a52OmegaC[12])); //
a^624*Ω12
ff_const_mul a52_x_OmegaC13(.din(OmegaC[13]),
.dout(a52OmegaC[13])); //
a^676*Ω13
ff_const_mul a52_x_OmegaC14(.din(OmegaC[14]),
.dout(a52OmegaC[14])); //
a^728*Ω14
ff_const_mul a52_x_OmegaC15(.din(OmegaC[15]),
.dout(a52OmegaC[15])); //
a^780*Ω15
defparam
a52_x_OmegaC1.CONST = 15'h6D41, a52_x_OmegaC2.CONST = 15'h0D84,
a52_x_OmegaC3.CONST = 15'h1BB9, a52_x_OmegaC4.CONST = 15'h1F55,
a52_x_OmegaC5.CONST = 15'h0E20, a52_x_OmegaC6.CONST = 15'h6B6A,
a52_x_OmegaC7.CONST = 15'h3C6C, a52_x_OmegaC8.CONST = 15'h3CDD,
a52_x_OmegaC9.CONST = 15'h14FA, a52_x_OmegaC10.CONST = 15'h2471,
a52_x_OmegaC11.CONST = 15'h535B, a52_x_OmegaC12.CONST =
15'h39E3,
a52_x_OmegaC13.CONST = 15'h7DE6, a52_x_OmegaC14.CONST =
15'h10A7,
a52_x_OmegaC15.CONST = 15'h1D23;
/* 计算:Λ’(α^-i) */
reg [m-1:0] DifLmdIR[3:0], DifLmdA;
wire[m-1:0] aDifLmdIR[3:1], a52LmdC[3:1];
always @(posedge clk)begin
if(Comput_Err)begin //计算Λ'(x)的系数
DifLmdIR[0] <= LmdC[1]; DifLmdIR[1] <= a52LmdC[1];
DifLmdIR[2] <= a52LmdC[2]; DifLmdIR[3] <= a52LmdC[3];
end
else begin //计算Λ’(α^-i)
DifLmdIR[1] <= aDifLmdIR[1];
DifLmdIR[2] <= aDifLmdIR[2];
DifLmdIR[3] <= aDifLmdIR[3];
end
end
ff_const_mul a2_x_DifLmdIR1(.din(DifLmdIR[1]),
.dout(aDifLmdIR[1])); //
a^2*Ω1
ff_const_mul a4_x_DifLmdIR2(.din(DifLmdIR[2]),
.dout(aDifLmdIR[2])); //
a^4*Ω1
ff_const_mul a6_x_DifLmdIR3(.din(DifLmdIR[3]),
.dout(aDifLmdIR[3])); // a^6*Ω1 defparam
a2_x_DifLmdIR1.CONST = 15'h7101, a4_x_DifLmdIR2.CONST = 15'h1C40,
a6_x_DifLmdIR3.CONST = 15'h4710;
ff_const_mul a52_x_LmdC3(.din(LmdC[3]),
.dout(a52LmdC[1])); // a^104*Ω1
ff_const_mul a52_x_LmdC5(.din(LmdC[5]),
.dout(a52LmdC[2])); // a^208*Ω2
ff_const_mul a52_x_LmdC7(.din(LmdC[7]),
.dout(a52LmdC[3])); // a^312*Ω3
defparam
a52_x_LmdC3.CONST = 15'h0D84, a52_x_LmdC5.CONST = 15'h1F55,
a52_x_LmdC7.CONST = 15'h6B6A;
/* 生成α^i的幂次i */
reg [m-1:0] ExpIndex;
always @(posedge clk)begin
if(Comput_Err) ExpIndex <= N - 1;
else ExpIndex <= ExpIndex - 1;
end
always @(posedge clk)begin
OmegaA <= (OmegaIR[0] ^ OmegaIR[1]) ^ (OmegaIR[2] ^ OmegaIR[3])
^(OmegaIR[4] ^ OmegaIR[5]) ^ (OmegaIR[6] ^ OmegaIR[7])
^(OmegaIR[8] ^ OmegaIR[9]) ^ (OmegaIR[10]^ OmegaIR[11])
^(OmegaIR[12]^ OmegaIR[13])^ (OmegaIR[14]^ OmegaIR[15]);。