blob: df76de380926a29bb1a30fcfec54fae57869bf36 [file] [log] [blame]
`timescale 1ns / 1ps
/*
* Double (and single) error decoding
* Output starts at N + 3 clock cycles and ends and N + 3 + K
*
* SEC sigma(x) = 1 + S_1 * x
* No error if S_1 = 0
*
* DEC simga(x) = 1 + signma_1 * x + sigma_2 * x^2 =
* 1 + S_1 * x + (S_1^2 + S_3 * S_1^-1) * x^2
* No error if S_1 = 0, S_3 = 0
* one error if S_1 != 0, S_3 = S_1^3
* two errors if S_1 != 0, S_3 != S_1^3
* >2 errors if S_1 = 0, S_3 != 0
* The below may be a better choice for large circuits (cycles tradeoff)
* sigma_1(x) = S_1 + S_1^2 * x + (S_1^3 + S_3) * x^2
*
* Takes input for N cycles, then produces output for K cycles.
* Output cycle and input cycle can happen simultaneously.
*/
module dec_decode #(
parameter N = 15,
parameter K = 5,
parameter T = 2 /* Correctable errors */
) (
input clk,
input start,
input data_in,
output reg output_valid = 0,
output reg data_out = 0
);
`include "bch.vh"
localparam TCQ = 1;
localparam M = n2m(N);
localparam LAST = lfsr_count(M, K-1);
wire [2*T*M-1:M] synN;
wire [M-1:0] ch1;
wire [M-1:0] ch1_flipped;
reg first = 0; /* First output cycle */
wire err; /* The current output bit needs to be flipped */
reg next_output_valid = 0;
reg chien_ready = 0;
reg [N+1:0] buf_ = 0;
wire [M-1:0] chien_count;
wire output_last;
wire [M-1:0] ch3;
wire [M-1:0] ch3_flipped;
wire [M-1:0] power;
reg [1:0] errors_last = 0;
wire [1:0] errors;
wire syn_done;
if (T > 1) begin
/* For each cycle, try flipping the bit */
assign ch1_flipped = ch1 ^ !first;
assign ch3_flipped = ch3 ^ !first;
/*
* If flipping reduced the number of errors,
* then we found an error
*/
assign err = errors_last > errors;
end else
assign err = ch1 == 1;
/* sN dsynN */
bch_syndrome #(M, T) u_bch_syndrome(
.clk(clk),
.ce(1'b1),
.start(start),
.done(syn_done),
.data_in(data_in),
.out(synN)
);
dch #(M, 1) u_dch1(
.clk(clk),
.err(err),
.ce(1'b1),
.start(syn_done),
.in(synN[1*M+:M]),
.out(ch1)
);
if (T > 1) begin
assign errors = |ch1_flipped ?
(power == ch3_flipped ? 1 : 2) :
(|ch3_flipped ? 3 : 0);
dch #(M, 3) u_dch3(
.clk(clk),
.err(err),
.ce(1'b1),
.start(syn_done),
.in(synN[3*M+:M]),
.out(ch3)
);
pow3 #(M) u_pow3(
.in(ch1_flipped),
.out(power)
);
end
lfsr_counter #(M) u_chien_counter(
.clk(clk),
.reset(syn_done),
.ce(1'b1),
.count(chien_count)
);
always @(posedge clk) begin
if (chien_ready)
next_output_valid <= #TCQ 1;
else if (chien_count == LAST)
next_output_valid <= #TCQ 0;
chien_ready <= #TCQ syn_done;
output_valid <= #TCQ next_output_valid;
if (T > 1) begin
first <= #TCQ start;
/*
* Load the new error count on cycle zero or when
* we find an error
*/
if (first || err)
errors_last <= #TCQ errors;
end
/* buf dbuf */
buf_ <= #TCQ {buf_[N:0], data_in};
data_out <= #TCQ (buf_[N+1] ^ err) && next_output_valid;
end
endmodule