// Copyright 2007 Altera Corporation. All rights reserved. // Altera products are protected under numerous U.S. and foreign patents, // maskwork rights, copyrights and other intellectual property laws. // // This reference design file, and your use thereof, is subject to and governed // by the terms and conditions of the applicable Altera Reference Design // License Agreement (either as signed by you or found at www.altera.com). By // using this reference design file, you indicate your acceptance of such terms // and conditions between you and Altera Corporation. In the event that you do // not agree with such terms and conditions, you may not use the reference // design file and please promptly destroy any copies you have made. // // This reference design file is being provided on an "as-is" basis and as an // accommodation and therefore all warranties, representations or guarantees of // any kind (whether express, implied or statutory) including, without // limitation, warranties of merchantability, non-infringement, or fitness for // a particular purpose, are specifically disclaimed. By making this reference // design file available, Altera expressly does not recommend, suggest or // require that this reference design file be used in combination with any // other product not provided by Altera. ///////////////////////////////////////////////////////////////////////////// // baeckler - 07-06-2006 // reved to be more parameterized 08-25-2006 // // Build verilog factored XORs for error correction encode // matrix. Not very fancy because there isn't any good reuse // to be had on the depth 2 6-LUT solution. Needs a bit of // hand balancing to reflect smaller luts being cheaper. // // And then the decoder and appropriate helper modules. Variable // latency controlled by parameters. #include // 64 -> 72 (8) // 32 -> 39 (7) // 16 -> 22 (6) // 8 -> 13 (5) int const DATA_BITS = 8; int const SYN_BITS = 5; int const TOTAL_BITS = DATA_BITS + SYN_BITS; unsigned char matrix[64][72+1] = { "11100000000000000000000000000000000000000000000000000000000000000000000", "10011000000000000000000000000000000000000000000000000000000000000000000", "01010100000000000000000000000000000000000000000000000000000000000000000", "11010010000000000000000000000000000000000000000000000000000000000000000", "10000001100000000000000000000000000000000000000000000000000000000000000", "01000001010000000000000000000000000000000000000000000000000000000000000", "11000001001000000000000000000000000000000000000000000000000000000000000", "00010001000100000000000000000000000000000000000000000000000000000000000", "10010001000010000000000000000000000000000000000000000000000000000000000", "01010001000001000000000000000000000000000000000000000000000000000000000", "11010001000000100000000000000000000000000000000000000000000000000000000", "10000000000000011000000000000000000000000000000000000000000000000000000", "01000000000000010100000000000000000000000000000000000000000000000000000", "11000000000000010010000000000000000000000000000000000000000000000000000", "00010000000000010001000000000000000000000000000000000000000000000000000", "10010000000000010000100000000000000000000000000000000000000000000000000", "01010000000000010000010000000000000000000000000000000000000000000000000", "11010000000000010000001000000000000000000000000000000000000000000000000", "00000001000000010000000100000000000000000000000000000000000000000000000", "10000001000000010000000010000000000000000000000000000000000000000000000", "01000001000000010000000001000000000000000000000000000000000000000000000", "11000001000000010000000000100000000000000000000000000000000000000000000", "00010001000000010000000000010000000000000000000000000000000000000000000", "10010001000000010000000000001000000000000000000000000000000000000000000", "01010001000000010000000000000100000000000000000000000000000000000000000", "11010001000000010000000000000010000000000000000000000000000000000000000", "10000000000000000000000000000001100000000000000000000000000000000000000", "01000000000000000000000000000001010000000000000000000000000000000000000", "11000000000000000000000000000001001000000000000000000000000000000000000", "00010000000000000000000000000001000100000000000000000000000000000000000", "10010000000000000000000000000001000010000000000000000000000000000000000", "01010000000000000000000000000001000001000000000000000000000000000000000", "11010000000000000000000000000001000000100000000000000000000000000000000", "00000001000000000000000000000001000000010000000000000000000000000000000", "10000001000000000000000000000001000000001000000000000000000000000000000", "01000001000000000000000000000001000000000100000000000000000000000000000", "11000001000000000000000000000001000000000010000000000000000000000000000", "00010001000000000000000000000001000000000001000000000000000000000000000", "10010001000000000000000000000001000000000000100000000000000000000000000", "01010001000000000000000000000001000000000000010000000000000000000000000", "11010001000000000000000000000001000000000000001000000000000000000000000", "00000000000000010000000000000001000000000000000100000000000000000000000", "10000000000000010000000000000001000000000000000010000000000000000000000", "01000000000000010000000000000001000000000000000001000000000000000000000", "11000000000000010000000000000001000000000000000000100000000000000000000", "00010000000000010000000000000001000000000000000000010000000000000000000", "10010000000000010000000000000001000000000000000000001000000000000000000", "01010000000000010000000000000001000000000000000000000100000000000000000", "11010000000000010000000000000001000000000000000000000010000000000000000", "00000001000000010000000000000001000000000000000000000001000000000000000", "10000001000000010000000000000001000000000000000000000000100000000000000", "01000001000000010000000000000001000000000000000000000000010000000000000", "11000001000000010000000000000001000000000000000000000000001000000000000", "00010001000000010000000000000001000000000000000000000000000100000000000", "10010001000000010000000000000001000000000000000000000000000010000000000", "01010001000000010000000000000001000000000000000000000000000001000000000", "11010001000000010000000000000001000000000000000000000000000000100000000", "10000000000000000000000000000000000000000000000000000000000000011000000", "01000000000000000000000000000000000000000000000000000000000000010100000", "11000000000000000000000000000000000000000000000000000000000000010010000", "00010000000000000000000000000000000000000000000000000000000000010001000", "10010000000000000000000000000000000000000000000000000000000000010000100", "01010000000000000000000000000000000000000000000000000000000000010000010", "11010000000000000000000000000000000000000000000000000000000000010000001" }; void dump_ecc_coder (FILE * f) { int x=0,y=0; int num_terms = 0; int lutsize = 6; int n=0,i=0,num_helpers=0,num_ins_this_helper=0; fprintf (f,"// baeckler - 08-25-2006 \n\n"); fprintf (f,"//////////////////////////////////////////\n"); fprintf (f,"// %d bit to %d bit ECC encoder\n",DATA_BITS,TOTAL_BITS); fprintf (f,"//////////////////////////////////////////\n\n"); fprintf (f,"module ecc_encode_%dbit (d,c);\n\n",DATA_BITS); fprintf (f,"input [%d:0] d;\n",DATA_BITS-1); fprintf (f,"output [%d:0] c;\n",TOTAL_BITS-1); fprintf (f,"wire [%d:0] c;\n\n",TOTAL_BITS-1); // the MSB of the code is the parity of the other code outs. // re-express it in terms of the data inputs in the MSB postion // of the matrix. for (y=0; y=0;n--) { fprintf (f,"dw[%d] & %ss[6] & !fatal_s6_%s", bit_syndrome[n] & 0x3f, ((bit_syndrome[n] & 0x40) != 0 ? "" : "!"), ((bit_syndrome[n] & 0x40) != 0 ? "hot" : "cold")); if (n!=0) fprintf (f,","); if ((n%4) == 0) fprintf (f,"\n "); } fprintf (f,"};\n\n"); } else { //////////////////////////////////////////////////////// // non - 64 bit decoder //////////////////////////////////////////////////////// fprintf (f," // decode the syndrome\n"); fprintf (f," reg [%d:0] d;\n",4*DATA_BITS-1); fprintf (f," wire [%d:0] dw /* synthesis keep */;\n",4*DATA_BITS-1); fprintf (f," always @(s) begin\n"); fprintf (f," d = %d'b0;\n",4*DATA_BITS); fprintf (f," d[{!s[%d],s[%d:0]}] = 1'b1;\n",SYN_BITS-1,SYN_BITS-2); fprintf (f," end\n"); fprintf (f," assign dw = d;\n\n"); fprintf (f," // Identify uncorrectable errors\n"); fprintf (f," wire fatal = (|s[%d:0]) & !s[%d] /* synthesis keep */;\n", SYN_BITS-2,SYN_BITS-1); fprintf (f," assign e = {\n "); for (n=DATA_BITS-1;n>=0;n--) { fprintf (f,"dw[%d]", bit_syndrome[n] & ((1<=0;n--) { fprintf (f,"c[%d]",bit_syndrome[n]-1); if (n!=0) fprintf (f,","); if ((n%8) == 0) fprintf (f,"\n "); } fprintf (f,"};\n\n"); fprintf (f," // conditional output register\n"); fprintf (f," generate\n"); fprintf (f," if (REGISTER) begin\n"); fprintf (f," always @(posedge clk or posedge rst) begin\n"); fprintf (f," if (rst) d <= 0;\n"); fprintf (f," else d <= d_int;\n"); fprintf (f," end\n"); fprintf (f," end else begin\n"); fprintf (f," always @(d_int) begin\n"); fprintf (f," d <= d_int;\n"); fprintf (f," end\n"); fprintf (f," end\n"); fprintf (f," endgenerate\n\n"); fprintf (f,"endmodule\n\n"); fprintf (f,"//////////////////////////////////////////\n"); fprintf (f,"// %d bit to %d bit ECC decoder\n",TOTAL_BITS,DATA_BITS); fprintf (f,"//////////////////////////////////////////\n\n"); fprintf (f,"module ecc_decode_%dbit (clk,rst,c,d,no_err,err_corrected,err_fatal);\n\n",DATA_BITS); fprintf (f,"// optional pipeline registers at the halfway\n"); fprintf (f,"// point and on the outputs\n"); fprintf (f,"parameter MIDDLE_REG = 0;\n"); fprintf (f,"parameter OUTPUT_REG = 0;\n\n"); fprintf (f,"input clk,rst;\n"); fprintf (f,"input [%d:0] c;\n",TOTAL_BITS-1); fprintf (f,"output [%d:0] d;\n",DATA_BITS-1); fprintf (f,"output no_err, err_corrected, err_fatal;\n\n"); fprintf (f,"reg [%d:0] d;\n",DATA_BITS-1); fprintf (f,"reg no_err, err_corrected, err_fatal;\n\n"); fprintf (f," // Pull the raw (uncorrected) data from the codeword\n"); fprintf (f," wire [%d:0] raw_bits;\n",DATA_BITS-1); fprintf (f," ecc_raw_data_%dbit raw (.clk(clk),.rst(rst),.c(c),.d(raw_bits));\n\n",DATA_BITS); fprintf (f," defparam raw .REGISTER = MIDDLE_REG;\n"); fprintf (f," // Build syndrome, which will be 0 for correct\n"); fprintf (f," // correct codewords, otherwise a pointer to the\n"); fprintf (f," // error.\n"); fprintf (f," wire [%d:0] syndrome;\n",SYN_BITS-1); fprintf (f," ecc_syndrome_%dbit syn (.clk(clk),.rst(rst),.c(c),.s(syndrome));\n",DATA_BITS); fprintf (f," defparam syn .REGISTER = MIDDLE_REG;\n\n"); fprintf (f," // Use the the syndrome to find a correction, or 0 for no correction\n"); fprintf (f," wire [%d:0] err_flip;\n",DATA_BITS-1); fprintf (f," wire fatal;\n"); fprintf (f," ecc_correction_%dbit cor (.s(syndrome),.e(err_flip),.fatal(fatal));\n\n",DATA_BITS); fprintf (f," // Classify error types and correct data as appropriate\n"); fprintf (f," // If there is a multibit error take care not to make \n"); fprintf (f," // the data worse.\n"); fprintf (f," generate\n"); fprintf (f," if (OUTPUT_REG) begin\n"); fprintf (f," always @(posedge clk or posedge rst) begin\n"); fprintf (f," if (rst) begin\n"); fprintf (f," no_err <= 1'b0;\n"); fprintf (f," err_corrected <= 1'b0;\n"); fprintf (f," err_fatal <= 1'b0;\n"); fprintf (f," d <= 1'b0;\n"); fprintf (f," end else begin\n"); fprintf (f," no_err <= ~| syndrome;\n"); fprintf (f," err_corrected <= syndrome[%d];\n",SYN_BITS-1); fprintf (f," err_fatal <= fatal;\n\n"); fprintf (f," d <= err_flip ^ raw_bits;\n"); fprintf (f," end\n"); fprintf (f," end\n"); fprintf (f," end else begin\n"); fprintf (f," always @(*) begin\n"); fprintf (f," no_err = ~| syndrome;\n"); fprintf (f," err_corrected = syndrome[%d];\n",SYN_BITS-1); fprintf (f," err_fatal = fatal;\n\n"); fprintf (f," d = err_flip ^ raw_bits;\n"); fprintf (f," end\n"); fprintf (f," end\n"); fprintf (f," endgenerate\n\n"); fprintf (f,"endmodule\n\n"); } //////////////////////////////////////////////////////////// void dump_ecc_ram (FILE * f) { fprintf (f,"// baeckler - 07-10-2006\n"); fprintf (f,"// %d-%d ECC internal RAM\n",DATA_BITS,TOTAL_BITS); fprintf (f,"//\n"); fprintf (f,"module soft_ecc_ram_%dbit (\n",DATA_BITS); fprintf (f," rst,\n"); fprintf (f," address_a,\n"); fprintf (f," address_b,\n"); fprintf (f," clock_a,\n"); fprintf (f," clock_b,\n"); fprintf (f," data_a,\n"); fprintf (f," data_b,\n"); fprintf (f," wren_a,\n"); fprintf (f," wren_b,\n"); fprintf (f," q_a,\n"); fprintf (f," q_b,\n"); fprintf (f," err_a,\n"); fprintf (f," err_b\n"); fprintf (f,");\n"); fprintf (f,"\n"); fprintf (f,"`include \"log2.inc\"\n"); fprintf (f,"\n"); fprintf (f,"// Number of %d bit data words (stored as %d bit words internally)\n",DATA_BITS,TOTAL_BITS); fprintf (f,"parameter NUM_WORDS = 512;\n"); fprintf (f,"localparam ADDR_WIDTH = log2(NUM_WORDS-1);\n"); fprintf (f,"\n"); fprintf (f,"// For testing error detection / correction\n"); fprintf (f,"// a 1 bit indicates inversion of the corresponding code bit\n"); fprintf (f,"// on the encoded RAM output.\n"); fprintf (f,"parameter PORT_A_ERROR_INJECT = %d'b0;\n",TOTAL_BITS); fprintf (f,"parameter PORT_B_ERROR_INJECT = %d'b0;\n",TOTAL_BITS); fprintf (f,"\n"); fprintf (f," input rst;\n"); fprintf (f," input [ADDR_WIDTH-1:0] address_a;\n"); fprintf (f," input [ADDR_WIDTH-1:0] address_b;\n"); fprintf (f," input clock_a;\n"); fprintf (f," input clock_b;\n"); fprintf (f," input [%d:0] data_a;\n",DATA_BITS-1); fprintf (f," input [%d:0] data_b;\n",DATA_BITS-1); fprintf (f," input wren_a;\n"); fprintf (f," input wren_b;\n"); fprintf (f," output [%d:0] q_a;\n",DATA_BITS-1); fprintf (f," output [%d:0] q_b;\n",DATA_BITS-1); fprintf (f," output [2:0] err_a;\n"); fprintf (f," output [2:0] err_b;\n"); fprintf (f,"\n"); fprintf (f,"\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"// port A encoder\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"reg [%d:0] data_a_reg;\n",DATA_BITS-1); fprintf (f,"always @(posedge clock_a or posedge rst) begin\n"); fprintf (f," if (rst) data_a_reg <= %d'b0;\n",DATA_BITS); fprintf (f," else data_a_reg <= data_a;\n"); fprintf (f,"end\n"); fprintf (f,"wire [%d:0] data_a_code;\n",TOTAL_BITS-1); fprintf (f,"ecc_encode_%dbit enc_a (.d(data_a_reg),.c(data_a_code));\n",DATA_BITS); fprintf (f,"\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"// port B encoder\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"reg [%d:0] data_b_reg;\n",DATA_BITS-1); fprintf (f,"always @(posedge clock_b or posedge rst) begin\n"); fprintf (f," if (rst) data_b_reg <= %d'b0;\n",DATA_BITS); fprintf (f," else data_b_reg <= data_b;\n"); fprintf (f,"end\n"); fprintf (f,"wire [%d:0] data_b_code;\n",TOTAL_BITS-1); fprintf (f,"ecc_encode_%dbit enc_b (.d(data_b_reg),.c(data_b_code));\n",DATA_BITS); fprintf (f,"\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"// RAM block (%d bit words)\n",TOTAL_BITS); fprintf (f,"///////////////////////\n"); fprintf (f,"wire [%d:0] q_a_code;\n",TOTAL_BITS-1); fprintf (f,"wire [%d:0] q_b_code;\n",TOTAL_BITS-1); fprintf (f,"ram_block ram (\n"); fprintf (f," .aclr_a(rst),\n"); fprintf (f," .aclr_b(rst),\n"); fprintf (f," .address_a(address_a),\n"); fprintf (f," .address_b(address_b),\n"); fprintf (f," .clock_a(clock_a),\n"); fprintf (f," .clock_b(clock_b),\n"); fprintf (f," .data_a(data_a_code),\n"); fprintf (f," .data_b(data_b_code),\n"); fprintf (f," .wren_a(wren_a),\n"); fprintf (f," .wren_b(wren_b),\n"); fprintf (f," .q_a(q_a_code),\n"); fprintf (f," .q_b(q_b_code)\n"); fprintf (f,");\n"); fprintf (f,"defparam ram .NUM_WORDS = NUM_WORDS;\n"); fprintf (f,"defparam ram .DAT_WIDTH = %d;\n",TOTAL_BITS); fprintf (f,"\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"// port A decoder\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"ecc_decode_%dbit dec_a (\n",DATA_BITS); fprintf (f," .clk(clock_a),\n"); fprintf (f," .rst(rst),\n"); fprintf (f," .c(q_a_code ^ PORT_A_ERROR_INJECT),\n"); fprintf (f," .d(q_a),\n"); fprintf (f," .no_err(err_a[0]),\n"); fprintf (f," .err_corrected(err_a[1]),\n"); fprintf (f," .err_fatal(err_a[2]));\n"); fprintf (f,"\n"); fprintf (f,"defparam dec_a .OUTPUT_REG = 1;\n"); fprintf (f,"defparam dec_a .MIDDLE_REG = 1;\n"); fprintf (f,"\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"// port B decoder\n"); fprintf (f,"///////////////////////\n"); fprintf (f,"ecc_decode_%dbit dec_b (\n",DATA_BITS); fprintf (f," .clk(clock_b),\n"); fprintf (f," .rst(rst),\n"); fprintf (f," .c(q_b_code ^ PORT_B_ERROR_INJECT),\n"); fprintf (f," .d(q_b),\n"); fprintf (f," .no_err(err_b[0]),\n"); fprintf (f," .err_corrected(err_b[1]),\n"); fprintf (f," .err_fatal(err_b[2]));\n"); fprintf (f,"\n"); fprintf (f,"defparam dec_b .OUTPUT_REG = 1;\n"); fprintf (f,"defparam dec_b .MIDDLE_REG = 1;\n"); fprintf (f,"\n"); fprintf (f,"endmodule\n"); } int main (void) { char buffer [255]; FILE * f = NULL; //////////////// // build the encode and decode functions sprintf (buffer,"ecc_matrix_%dbit.v",DATA_BITS); f = fopen (buffer,"wt"); if (!f) { fprintf (stdout,"ERROR : Unable to write file %s\n",buffer); return (1); } dump_ecc_coder (f); fclose (f); //////////////// // build a soft RAM with 2 enc/dec ports sprintf (buffer,"soft_ecc_ram_%dbit.v",DATA_BITS); f = fopen (buffer,"wt"); if (!f) { fprintf (stdout,"ERROR : Unable to write file %s\n",buffer); return (1); } dump_ecc_ram (f); fclose (f); return (0); }