URL
https://opencores.org/ocsvn/common/common/trunk
Subversion Repositories common
[/] [common/] [trunk/] [encode_8b_10b.v] - Rev 48
Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////////// //// //// //// encode_8b_10b #(N), decode_10b_8b #(N) //// //// //// //// This file is part of the general opencores effort. //// //// <http://www.opencores.org/cores/misc/> //// //// //// //// Module Description: //// //// Example of how to convert 8B data to 10B data. //// //// Example of how to convert 10B data to 8B data. //// //// //// //// NOTE: //// //// The IBM Patent grew up in a world where the Least //// //// Significant Bit of a word was written to the Left. //// //// These modules use the LSB as Bit 0, and it will //// //// typically be written as the Rightmost bit in a field. //// //// //// //// NOTE: //// //// These modules are based on information contained in //// //// "Implementing an 8B/10B Encoder/Decoder for Gigabit //// //// Ethernet" by Daniel Elftmann and Jing Hua Ma of Altera. //// //// The paper was given in the International IC Tiapei //// //// conferance in 1999. //// //// //// //// A second source of information is XAPP336 titled "Design //// //// of a 16B/20B Encoder/Decoder using a Coolrunner CPLD" //// //// found on the Xilinx web sire www.xilinx.com //// //// //// //// The best article describing this is at wildpackets.com //// //// http://www.wildpackets.com/compendium/GB/L1-GbEn.html //// //// //// //// Finally, this is covered in US patent 4,665,517. //// //// Unfortunately the US Patent Office online copy has //// //// missing figures and the tables are un-readable. //// //// //// //// Author(s): //// //// - Anonymous //// //// //// ////////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2000 Anonymous and OPENCORES.ORG //// //// //// //// This source file may be used and distributed without //// //// restriction provided that this copyright statement is not //// //// removed from the file and that any derivative work contains //// //// the original copyright notice and the associated disclaimer. //// //// //// //// This source file is free software; you can redistribute it //// //// and/or modify it under the terms of the GNU Lesser General //// //// Public License as published by the Free Software Foundation; //// //// either version 2.1 of the License, or (at your option) any //// //// later version. //// //// //// //// This source is distributed in the hope that it will be //// //// useful, but WITHOUT ANY WARRANTY; without even the implied //// //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// //// PURPOSE. See the GNU Lesser General Public License for more //// //// details. //// //// //// //// You should have received a copy of the GNU Lesser General //// //// Public License along with this source; if not, download it //// //// from <http://www.opencores.org/lgpl.shtml> //// //// //// ////////////////////////////////////////////////////////////////////// // // $Id: encode_8b_10b.v,v 1.6 2001-11-29 09:22:08 bbeaver Exp $ // // CVS Revision History // // $Log: not supported by cvs2svn $ // Revision 1.19 2001/11/29 09:31:11 Blue Beaver // no message // // Revision 1.18 2001/10/26 10:39:43 Blue Beaver // no message // // Revision 1.17 2001/10/26 10:38:05 Blue Beaver // no message // // Revision 1.16 2001/10/25 11:43:03 Blue Beaver // no message // // Revision 1.14 2001/10/25 11:33:51 Blue Beaver // no message // // Revision 1.13 2001/10/24 11:38:02 Blue Beaver // no message // // Revision 1.12 2001/10/24 09:47:40 Blue Beaver // no message // // Revision 1.11 2001/10/24 08:49:02 Blue Beaver // no message // // Revision 1.10 2001/10/24 07:28:08 Blue Beaver // no message // // Revision 1.9 2001/10/23 10:34:50 Blue Beaver // no message // // Revision 1.8 2001/10/23 08:12:37 Blue Beaver // no message // // Revision 1.7 2001/10/22 12:36:12 Blue Beaver // no message // // Revision 1.6 2001/10/22 11:54:58 Blue Beaver // no message // // Revision 1.5 2001/10/21 11:37:28 Blue Beaver // no message // // Revision 1.4 2001/10/21 10:17:34 Blue Beaver // no message // // Revision 1.3 2001/10/21 03:40:52 Blue Beaver // no message // // Revision 1.2 2001/10/21 02:27:39 Blue Beaver // no message // // Revision 1.1 2001/10/21 01:36:14 Blue Beaver // no message // // // `timescale 1ns/1ps // These are the codes which are valid to use as control codes. // I believe that they have names, but I don't know them. // Note K_28_1, K_28_5, and K_28_7 contain Singular Commas. `define K_28_0 8'b000_11100 `define K_28_1 8'b001_11100 `define K_28_2 8'b010_11100 `define K_28_3 8'b011_11100 `define K_28_4 8'b100_11100 `define K_28_5 8'b101_11100 `define K_28_6 8'b110_11100 `define K_28_7 8'b111_11100 `define K_23_7 8'b111_10111 `define K_27_7 8'b111_11011 `define K_29_7 8'b111_11101 `define K_30_7 8'b111_11110 // Convert 8-bit binary or 8-bit control code to 10-bit code module encode_8b_10b ( eight_bit_data_or_control_in, input_is_control, mess_up_link_disparity, ten_bit_encoded_data_out, invalid_control, clk, reset ); input [7:0] eight_bit_data_or_control_in; input input_is_control; input mess_up_link_disparity; output [9:0] ten_bit_encoded_data_out; output invalid_control; input clk, reset; // Data is treated as 2 fields. The 3 MSB bits are treated as 1 field, and // the 5 LSB bits are treated as another field. // The 5 LSB bits are encoded as 6 bits. The 3 MSB bits are encoded as 4 bits. // The encodings are chosen so that the 10 bits together have either // 1) 5 1's and 5 0's, // 2) 4 1's and 6 0's, // 3 6 1's and 4 0's // There are alternative encodings for the cases that the number of 1's and 0's // are not balanced. The 8B/10B encoder keeps track of the running disparity // between the number of 1's and 0's, and uses alternate encodings to keep // the serial signal balanced with no disparity on average. // // TABLE I 5B/6B ENCODING (NOTE LSB TO LEFT) // NAME ABCDE K D-1 abcdei DO ALTERNATE // ______________________________________ // D.0 00000 0 + 011000 - 100111 // D.1 10000 0 + 100010 - 011101 ! // D.2 01000 0 + 010010 - 101101 ! // D.3 11000 0 x 110001 0 ! // D.4 00100 0 + 001010 - 110101 ! // D.5 10100 0 x 101001 0 ! // D.6 01100 0 x 011001 0 ! // D.7 11100 0 - 111000 0 000111 ! // D.8 00010 0 + 000110 - 111001 ! // D.9 10010 0 x 100101 0 ! // D.10 01010 0 x 010101 0 ! // D.11 11010 0 x 110100 0 ! // D.12 00110 0 x 001101 0 ! // D.13 10110 0 x 101100 0 ! // D.14 01110 0 x 011100 0 ! // D.15 11110 0 + 101000 - 010111 // D.16 00001 0 - 011011 + 100100 // D.17 10001 0 x 100011 0 ! // D.18 01001 0 x 010011 0 ! // D.19 11001 0 x 110010 0 ! // D.20 00101 0 x 001011 0 ! // D.21 10101 0 x 101010 0 ! // D.22 01101 0 x 011010 0 ! // D.23 11101 x - 111010 + 000101 ! // D.24 00011 0 + 001100 - 110011 // D.25 10011 0 x 100110 0 ! // D.26 01011 0 x 010110 0 ! // D.27 11011 x - 110110 + 001001 ! // D.28 00111 0 x 001110 0 ! // D.29 10111 x - 101110 + 010001 ! // D.30 01111 x - 011110 + 100001 ! // D.31 11111 0 - 101011 + 010100 // // K.23 11101 x - 111010 + 000101 ! // K.27 11011 x - 110110 + 001001 ! // K.28 00111 1 - 001111 + 110000 ! // K.29 10111 x - 101110 + 010001 ! // K.30 01111 x - 011110 + 100001 ! // // TABLE II 3B/4B ENCODING (NOTE LSB TO LEFT) // NAME FGH K D-1 fghj DO ALTERNATE // ______________________________________ // D.x.0 000 x + 0100 - 1011 // D.x.1 100 0 x 1001 0 ! // D.x.2 010 0 x 0101 0 ! // D.x.3 110 x - 1100 0 0011 ! // D.x.4 001 x + 0010 - 1101 ! // D.x.5 101 0 x 1010 0 ! // D.x.6 011 0 x 0110 0 ! // D.x.P7 111 0 - 1110 + 0001 ! Primary // D.x.A7 111 x - 0111 + 1000 Alternate // // K.28.0 000 x + 0100 - 1011 // K.28.1 100 1 + 1001 0 0110 ! Singular Comma // K.28.2 010 1 + 0101 0 1010 ! // K.28.3 110 x - 1100 0 0011 ! // K.28.4 001 x + 0010 - 1101 ! // K.28.5 101 1 + 1010 0 0101 ! Singular Comma // K.28.6 011 1 + 0110 0 1001 ! // K.28.7 111 x - 0111 + 1000 Singular Comma // // K.23.7 111 x - 0111 + 1000 // K.27.7 111 x - 0111 + 1000 // K.29.7 111 x - 0111 + 1000 // K.30.7 111 x - 0111 + 1000 // // The alternate Data encoding D.x.A7 is used in the case // that e = i = 1 and negative running disparity, // or e = i = 0 and positive running disparity, // or a Control signal is being sent, // all while encoding 7 in the MSB. // // This exception to the simple rule guarantees that there // aren't a run of 5 1's or 5 0's in the first 6 bits // concatinated with the last 4 bits. // // The special sequence starting at "a" of 2 0's followed by // 5 1's, or 2 1's followed by 5 0's, is called a // "Singular Comma". // A Singular Comma does not occur in any valid code EXCEPT // K.28.1 or K.28.5 or K.28.7. // // The web says K.28.5 is the Fiber Channel Comma Character. // // NOTE that K.28.7 is a bad comma character, because it // can be followed by a FALSE comma character when followed // by any character starting with 2 1's or 0's, like K.11 // The false comma character is part in the K.28.7 and part // in the following data byte. Bad. // // The following info is found in www.wildpackets.com/compendium/GB/L1-GbEn.html, // in a document headed: // "Gigabit Ethernet is Closely Related to Fibre Channel Technology, // going back to 1988!" // // 8B-10B characters are described as Dn.m, where n gives the low order // 5 bits in decimal, and m gives the top 3 bits. // // Configuration data is transferred as an alternating sequence of: // (flips disparity: "C1") K28.5/D21.5/Config_reg[7:0]/Config_reg[15:8] // (leaves disparity: "C2") K28.5/D2.2/Config_reg[7:0]/Config_reg[15:8] // // Idle status is transmitted when ther eis nothing else to send. // The link is left in negative disparity. If it is positive, first // "I1" K28.5/D5.6 is sent, which knocks the displarity to negative // "I2" K28.5/D16.2 is sent repeatitively to maintain the negative disparity // // Start of Packet delimiter "S" K27.7 // End of Packet delimiter "T" K29.7 // Carrier Extend "R" K23.7 // // An End Of Packet consists of either T/R/I or T/R/R // The second is used when a packet follows the previous packet in a burst. // "R" is also sent so that a subsequent "I" follows on an even-numbered // code boundry. // // Error propagation "V" K30.7 // Accumulate the new data. First, calculate ignoring the running disparity; wire [9:0] first_level_encoded_data; // Calculate the values for the 5 -> 6 encoding // Discover important details about the incoming numbers. wire [1:0] LSB_02_Population = eight_bit_data_or_control_in[0] // half adder + eight_bit_data_or_control_in[1]; wire [1:0] LSB_34_Population = eight_bit_data_or_control_in[2] // half adder + eight_bit_data_or_control_in[3]; wire [2:0] LSB_Population = {1'b0, LSB_02_Population[1:0]} + {1'b0, LSB_34_Population[1:0]}; // As can be seen, in many of the LSB encodings the bottom // 4 of the encoded data are identical to the input // data. (These are noted with a trailing "!") // // There are several exceptions to this in the LSB. Decode these. wire LSB_all_zero = (LSB_Population[2:0] == 3'h0); wire LSB_contains_one_one = (LSB_Population[2:0] == 3'h1); wire LSB_contains_two_ones = (LSB_Population[2:0] == 3'h2); wire LSB_contains_three_ones = (LSB_Population[2:0] == 3'h3); wire LSB_all_one = (LSB_Population[2:0] == 3'h4); wire LSB_is_7 = (eight_bit_data_or_control_in[4:0] == 5'h07); // 7 wire LSB_is_24 = (eight_bit_data_or_control_in[4:0] == 5'h18); // 24 wire LSB_is_28 = (eight_bit_data_or_control_in[4:0] == 5'h1C); // 28 wire LSB_is_23_27_29_30 = (eight_bit_data_or_control_in[4:0] == 5'h17) // 23 | (eight_bit_data_or_control_in[4:0] == 5'h1B) // 27 | (eight_bit_data_or_control_in[4:0] == 5'h1D) // 29 | (eight_bit_data_or_control_in[4:0] == 5'h1E); // 30 wire LSB_contains_other_i = (eight_bit_data_or_control_in[3:0] == 4'h0) | (eight_bit_data_or_control_in[3:0] == 4'h1) | (eight_bit_data_or_control_in[3:0] == 4'h2) | (eight_bit_data_or_control_in[3:0] == 4'h4); // Notice that the bottom bit of the encoded LSB data is the same as // the input LSB data. assign first_level_encoded_data[0] = eight_bit_data_or_control_in[0]; // If the bottom 4 bits are 0s, force 0110 (LSB is the left bit) // If the bottom 5 bits are 24, force 0011 (LSB is the left bit) // If the bottom 4 bits are 1s, force 1010 (LSB is the left bit) assign first_level_encoded_data[1] = ( eight_bit_data_or_control_in[1] & ~LSB_all_one) | LSB_all_zero; assign first_level_encoded_data[2] = eight_bit_data_or_control_in[2] | LSB_all_zero | LSB_is_24; assign first_level_encoded_data[3] = ( eight_bit_data_or_control_in[3] & ~LSB_all_one); // Bits "e" and "i" are chosen to guarantee that there are enough transitions, // and to control the disparity caused by each pattern. assign first_level_encoded_data[4] = (LSB_contains_one_one | eight_bit_data_or_control_in[4]) & ~LSB_is_24; assign first_level_encoded_data[5] = (LSB_contains_two_ones & ~eight_bit_data_or_control_in[4]) | ( ( LSB_contains_other_i | LSB_all_one) & eight_bit_data_or_control_in[4]) | (input_is_control & LSB_is_28); // Now calculate the other information needed to produce the LSB output data wire LSB_code_has_positive_disparity = | ( ( LSB_all_zero | LSB_contains_three_ones | LSB_all_one) & (eight_bit_data_or_control_in[4] == 1'b1) ) | (input_is_control & LSB_is_28); wire LSB_code_has_negative_disparity = ( ( LSB_all_zero | LSB_contains_one_one | LSB_all_one) & (eight_bit_data_or_control_in[4] == 1'b0) ) | LSB_is_24; wire invert_LSB_if_input_disparity_is_positive = LSB_code_has_positive_disparity | LSB_is_7; wire invert_LSB_if_input_disparity_is_negative = LSB_code_has_negative_disparity; wire LSB_toggle_running_disparity = LSB_code_has_positive_disparity | LSB_code_has_negative_disparity; // Calculate the values for the 3 -> 4 encoding // An alternate encoding of the MSB for an input of 0x7 is used to // prevent accidental use of a pattern with 5 0's or 1's in a row. // The alternate Data encoding D.x.A7 is used in the case // that e = i = 0 and positive running disparity, // or e = i = 1 and negative running disparity, // or a Control signal is being sent, // all while encoding 7 in the MSB. reg Running_Disparity; // forward reference wire use_alternate_encoding = ( input_is_control | ( (Running_Disparity == 1'b0) & ( (eight_bit_data_or_control_in[4:0] == 5'h11) // 17 | (eight_bit_data_or_control_in[4:0] == 5'h12) // 18 | (eight_bit_data_or_control_in[4:0] == 5'h14) // 20 )) | ( (Running_Disparity == 1'b1) & ( (eight_bit_data_or_control_in[4:0] == 5'h0B) // 11 | (eight_bit_data_or_control_in[4:0] == 5'h0D) // 13 | (eight_bit_data_or_control_in[4:0] == 5'h0E) // 14 )) ) & (eight_bit_data_or_control_in[7:5] == 3'h7); // The low bit of the MSB is a pass-through, except when the alternate // encoding of the value is used to prevent unintentional long runs. assign first_level_encoded_data[6] = eight_bit_data_or_control_in[5] & ~use_alternate_encoding; // The second bit of the MSB is a pass-through except when the input // is all 0's. assign first_level_encoded_data[7] = eight_bit_data_or_control_in[6] | (eight_bit_data_or_control_in[7:5] == 3'h0); // The top bit of the encoded MSB data is the same as the input MSB data. assign first_level_encoded_data[8] = eight_bit_data_or_control_in[7]; // Bit "j" is chosen to guarantee that there are enough transitions, // and to control the disparity caused by each pattern. assign first_level_encoded_data[9] = (eight_bit_data_or_control_in[7:5] == 3'h1) | (eight_bit_data_or_control_in[7:5] == 3'h2) | use_alternate_encoding; // Now calculate the other information needed to produce the MSB output data wire invert_MSB_if_LSB_disparity_is_positive = (eight_bit_data_or_control_in[7:5] == 3'h3) | (eight_bit_data_or_control_in[7:5] == 3'h7); wire invert_MSB_if_LSB_disparity_is_negative = (eight_bit_data_or_control_in[7:5] == 3'h0) | (eight_bit_data_or_control_in[7:5] == 3'h4) | ( input_is_control & ( (eight_bit_data_or_control_in[7:5] == 3'h1) | (eight_bit_data_or_control_in[7:5] == 3'h2) | (eight_bit_data_or_control_in[7:5] == 3'h5) | (eight_bit_data_or_control_in[7:5] == 3'h6) ) ); wire MSB_toggle_running_disparity = (eight_bit_data_or_control_in[7:5] == 3'h0) | (eight_bit_data_or_control_in[7:5] == 3'h4) | (eight_bit_data_or_control_in[7:5] == 3'h7); // Keep track of the running disparity. If 1'b1, the disparity is positive. always @(posedge clk) begin if (reset == 1'b1) begin Running_Disparity <= 1'b0; // start negative end else begin Running_Disparity <= Running_Disparity ^ LSB_toggle_running_disparity ^ MSB_toggle_running_disparity; end end // Decide whether to invert the encoded data; wire Invert_LSB = ( (Running_Disparity == 1'b1) & (invert_LSB_if_input_disparity_is_positive == 1'b1) ) | ( (Running_Disparity == 1'b0) & (invert_LSB_if_input_disparity_is_negative == 1'b1) ); wire Invert_MSB = ( ((Running_Disparity ^ LSB_toggle_running_disparity) == 1'b1) & (invert_MSB_if_LSB_disparity_is_positive == 1'b1) ) | ( ((Running_Disparity ^ LSB_toggle_running_disparity) == 1'b0) & (invert_MSB_if_LSB_disparity_is_negative == 1'b1) ); // Calculate the actual encoded data. reg [9:0] ten_bit_encoded_data_out; reg invalid_control; always @(posedge clk) begin if (reset == 1'b1) begin ten_bit_encoded_data_out[9:0] <= 10'h000; invalid_control <= 1'b0; end else begin ten_bit_encoded_data_out[5:0] <= {6{Invert_LSB}} ^ first_level_encoded_data[5:0]; ten_bit_encoded_data_out[9:6] <= {4{Invert_MSB}} ^ first_level_encoded_data[9:6]; invalid_control <= input_is_control & ~( LSB_is_28 // all MSB bits are valid | ( LSB_is_23_27_29_30 & (eight_bit_data_or_control_in[7:5] == 3'h7) // MSB must be 7 ) ); end end endmodule // Convert 10-bit code to 8-bit binary or 8-bit control code module decode_10b_8b ( ten_bit_encoded_data_in, eight_bit_data_or_control_out, output_is_control, invalid_encoded_data, clk, reset ); input [9:0] ten_bit_encoded_data_in; output [7:0] eight_bit_data_or_control_out; output output_is_control; output invalid_encoded_data; input clk, reset; // Data is encoded as described in the encode_8b_10b module above. // This module tries to extract valid data or control info from the // encoded input data. // // This module depends on the data being correctly 10-bit aligned. // the LSB of the input must be the "a" bit as described above. // // This module tries to detect errors in the code sequence as it arrives. // Errors are when an illegal bit sequence arrives, or when the disparity // of the input data goes beyond 1 bit. This would happen if the sender // did not correctly use alternate encodings of output data. // Accumulate the new data. Calculate ignoring the running disparity; wire [7:0] decoded_data; // Calculate the values for the 6 -> 5 decoding // Discover important details about the incoming numbers. wire [1:0] LSB_02_Population = ten_bit_encoded_data_in[0] // full adder + ten_bit_encoded_data_in[1] + ten_bit_encoded_data_in[2]; wire [1:0] LSB_35_Population = ten_bit_encoded_data_in[3] // full adder + ten_bit_encoded_data_in[4] + ten_bit_encoded_data_in[5]; wire [2:0] LSB_bottom_4_Population = {1'b0, LSB_02_Population[1:0]} + {2'b00, ten_bit_encoded_data_in[3]}; wire [2:0] LSB_Population = {1'b0, LSB_02_Population[1:0]} // allowed: 2, 3, 4 + {1'b0, LSB_35_Population[1:0]}; // illegal: 0, 1, 5, 6 // As can be seen, in many of the LSB encodings the bottom // 4 of the decoded data are identical to the input // data. (These are noted with a trailing "!") // // The bottom 4 bits can be used directly in these cases (which are all cases // where the number of bits in the input are equil to 3 except for 7): // 3 5 6 9 10 11 12 13 14 17 18 19 20 21 22 25 26 28 // The bottom 4 bits must be inverted before use in these cases: (MSB right) // 011101 101101 110101 111001 000101 001001 010001 100001 000111 110000 wire LSB_Invert_Before_Use = ( (ten_bit_encoded_data_in[5:4] == 2'b10) & ( (LSB_bottom_4_Population[2:0] == 3'h1) | (LSB_bottom_4_Population[2:0] == 3'h3) ) ) | (ten_bit_encoded_data_in[5:0] == 6'b111000) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b000011); // Values must be substituted in these cases: wire LSB_is_0_16_a = (ten_bit_encoded_data_in[5:0] == 6'b000110) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b110110); wire LSB_is_0_16_b = (ten_bit_encoded_data_in[5:0] == 6'b111001) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b001001); wire LSB_is_15_31_a = (ten_bit_encoded_data_in[5:0] == 6'b000101) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b110101); wire LSB_is_15_31_b = (ten_bit_encoded_data_in[5:0] == 6'b111010) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b001010); wire LSB_is_24_a = (ten_bit_encoded_data_in[5:0] == 6'b001100); // LSB to right wire LSB_is_24_b = (ten_bit_encoded_data_in[5:0] == 6'b110011); // LSB to right // Notice when these codes occur. They are the only time Alternate D.x.7 data // can be used. This is looked for below to detect errors. wire LSB_is_11_13_14 = (ten_bit_encoded_data_in[5:0] == 6'b001011) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b001101) | (ten_bit_encoded_data_in[5:0] == 6'b001110); wire LSB_is_17_18_20 = (ten_bit_encoded_data_in[5:0] == 6'b110001) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b110010) | (ten_bit_encoded_data_in[5:0] == 6'b110100); // Control signals must be called out when recognized. wire LSB_is_23_27_29_30 = ( (ten_bit_encoded_data_in[5:4] == 2'b01) & (LSB_bottom_4_Population[2:0] == 3'h3) ) | ( (ten_bit_encoded_data_in[5:4] == 2'b10) & (LSB_bottom_4_Population[2:0] == 3'h1) ); wire LSB_is_K28 = (ten_bit_encoded_data_in[5:0] == 6'b111100) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b000011); // calculate the bottom 4 bits of decoded data wire [3:0] LSB_XOR_Term = {4{LSB_Invert_Before_Use}} // invert all signals with alternate values | {1'b0, LSB_is_0_16_a, LSB_is_0_16_a, 1'b0} // make 0, 16 into 0 | {LSB_is_0_16_b, 1'b0, 1'b0, LSB_is_0_16_b} // make 0, 16 into 0 | {LSB_is_15_31_a, 1'b0, LSB_is_15_31_a, 1'b0} // make 15, 31 into 15 | {1'b0, LSB_is_15_31_b, 1'b0, LSB_is_15_31_b} // make 15, 31 into 15 | {1'b0, LSB_is_24_a, 1'b0, 1'b0} // make 24 into 24 | {LSB_is_24_b, 1'b0, LSB_is_24_b, LSB_is_24_b}; // make 24 into 24 assign decoded_data[3:0] = ten_bit_encoded_data_in[3:0] ^ LSB_XOR_Term[3:0]; // The next bit is harder. I don't know if this is minimal assign decoded_data[4] = (ten_bit_encoded_data_in[5:0] == 6'b001001) // LSB to right | (ten_bit_encoded_data_in[5:0] == 6'b001010) | (ten_bit_encoded_data_in[5:0] == 6'b001100) | (ten_bit_encoded_data_in[5:3] == 3'b110) | ( (ten_bit_encoded_data_in[5:4] == 2'b01) & (LSB_bottom_4_Population[2:0] == 3'h2) ) | LSB_is_23_27_29_30 | LSB_is_K28; // Calculate the values for the 4 -> 3 decoding // The bottom 2 bits of the MSB must always be inverted before use in these // cases: (MSB right) 0011, 1101, 0001 // When the LSB indicate that the byte contains a K28, and the bottom 6 bits // have a negative disparity, invert these before using: (MSB right) // 0110, 1010, 0101, 1001 // Only 2 of these are needed to greate singular commas. I don't understand // why they made the other special cases. Very odd wire MSB_Invert_Before_Use = (ten_bit_encoded_data_in[9:6] == 4'b1100) // LSB to right | (ten_bit_encoded_data_in[9:6] == 4'b1011) | (ten_bit_encoded_data_in[9:6] == 4'b1000) | ( (ten_bit_encoded_data_in[5:0] == 6'b000011) & ( (ten_bit_encoded_data_in[9:6] == 4'b0110) | (ten_bit_encoded_data_in[9:6] == 4'b0101) | (ten_bit_encoded_data_in[9:6] == 4'b1010) | (ten_bit_encoded_data_in[9:6] == 4'b1001) ) ); // Values must be substituted in these cases: wire MSB_0_value_a = (ten_bit_encoded_data_in[9:6] == 4'b0010); // LSB to right wire MSB_0_value_b = (ten_bit_encoded_data_in[9:6] == 4'b1101); wire alternate_MSB_a = (ten_bit_encoded_data_in[9:6] == 4'b1110); // LSB to right wire alternate_MSB_b = (ten_bit_encoded_data_in[9:6] == 4'b0001); wire primary_MSB_a = (ten_bit_encoded_data_in[9:6] == 4'b0111); // LSB to right wire primary_MSB_b = (ten_bit_encoded_data_in[9:6] == 4'b1000); wire [2:0] MSB_XOR_Term = {3{MSB_Invert_Before_Use}} | {1'b0, MSB_0_value_a, 1'b0} | {MSB_0_value_b, 1'b0, MSB_0_value_b} | {1'b0, 1'b0, alternate_MSB_a} | {alternate_MSB_b, alternate_MSB_b, 1'b0}; assign decoded_data[7:5] = ten_bit_encoded_data_in[8:6] ^ MSB_XOR_Term[2:0]; wire decoded_control = ( LSB_is_23_27_29_30 & (alternate_MSB_a | alternate_MSB_b)) | LSB_is_K28; // Keep track of the running disparity. If 1'b1, the disparity is positive. wire [1:0] MSB_01_Population = ten_bit_encoded_data_in[6] // half adder + ten_bit_encoded_data_in[7]; wire [1:0] MSB_23_Population = ten_bit_encoded_data_in[8] // half adder + ten_bit_encoded_data_in[9]; wire [2:0] MSB_Population = {1'b0, MSB_01_Population[1:0]} // 1, 2, 3 + {1'b0, MSB_23_Population[1:0]}; wire [3:0] Code_Population = {1'b0, LSB_Population[2:0]} // 4, 5, 6 + {1'b0, MSB_Population[2:0]}; reg Running_Disparity; always @(posedge clk) begin if (reset == 1'b1) begin Running_Disparity <= 1'b0; // start negative end else begin Running_Disparity <= (Code_Population[3:0] == 4'h6) ? 1'b1 : ( (Code_Population[3:0] == 4'h4) ? 1'b0 : Running_Disparity); end end // Detect invalid code values. wire too_many_bits_in_first_nibble = (LSB_bottom_4_Population[2:0] > 3'h3); wire too_few_bits_in_first_nibble = (LSB_bottom_4_Population[2:0] < 3'h1); wire too_many_bits_in_LSB = (LSB_Population[2:0] > 3'h4); wire too_few_bits_in_LSB = (LSB_Population[2:0] < 3'h2); wire too_many_bits_in_MSB = (MSB_Population[2:0] > 3'h3); wire too_few_bits_in_MSB = (LSB_Population[2:0] < 3'h1); wire too_many_bits_in_entire_code = (Code_Population[3:0] > 4'h6); wire too_few_bits_in_entire_code = (Code_Population[3:0] < 4'h4); wire LSB_inconsistent_with_running_disparity = ( (Running_Disparity == 1'b1) & ( (LSB_Population[2:0] == 3'h4) | (ten_bit_encoded_data_in[5:0] == 6'b000111) // X.7 negative disparity ) ) | ( (Running_Disparity == 1'b0) & ( (LSB_Population[2:0] == 3'h2) | (ten_bit_encoded_data_in[5:0] == 6'b111000) // X.7 positive disparity ) ); wire LSB_code_7_positive_but_MSB_inconsistent = (ten_bit_encoded_data_in[5:0] == 6'b111000) // X.7 positive disparity & ( (MSB_Population[2:0] == 3'h3) // too many bits in MSB | (ten_bit_encoded_data_in[9:6] == 4'b0011) // Y.3 negative disparity ); wire LSB_code_7_negative_but_MSB_inconsistent = (ten_bit_encoded_data_in[5:0] == 6'b000111) // X.7 negative disparity & ( (MSB_Population[2:0] == 3'h1) // too few bits in MSB | (ten_bit_encoded_data_in[9:6] == 4'b1100) // Y.3 positive disparity ); wire MSB_code_3_positive_but_LSB_inconsistent = (ten_bit_encoded_data_in[9:6] == 4'b1100) // X.7 positive disparity & (LSB_Population[2:0] == 3'h2); // too few bits in LSB wire MSB_code_3_negative_but_LSB_inconsistent = (ten_bit_encoded_data_in[9:6] == 4'b0011) // X.7 negative disparity & (LSB_Population[2:0] == 3'h4); // too many bits in LSB wire alternate_encoding_not_used_when_required = ((Running_Disparity == 1'b1) & (LSB_is_11_13_14) & primary_MSB_b) | ((Running_Disparity == 1'b0) & (LSB_is_17_18_20) & primary_MSB_a) | (LSB_is_K28 & (primary_MSB_a | primary_MSB_b)); wire primary_encoding_not_used_when_required = ((Running_Disparity == 1'b0) & (LSB_is_11_13_14) & alternate_MSB_b) | ((Running_Disparity == 1'b1) & (LSB_is_17_18_20) & alternate_MSB_a); wire detected_invalid_8b_10b_sequence = too_many_bits_in_first_nibble | too_few_bits_in_first_nibble | too_many_bits_in_LSB | too_few_bits_in_LSB | too_many_bits_in_MSB | too_few_bits_in_MSB | too_many_bits_in_entire_code | too_few_bits_in_entire_code | LSB_inconsistent_with_running_disparity | LSB_code_7_positive_but_MSB_inconsistent | LSB_code_7_negative_but_MSB_inconsistent | MSB_code_3_positive_but_LSB_inconsistent | MSB_code_3_negative_but_LSB_inconsistent | alternate_encoding_not_used_when_required | primary_encoding_not_used_when_required; // Calculate the actual decoded data. reg [7:0] eight_bit_data_or_control_out; reg output_is_control; reg invalid_encoded_data; always @(posedge clk) begin if (reset == 1'b1) begin eight_bit_data_or_control_out[7:0] <= 8'h00; output_is_control <= 1'b0; invalid_encoded_data <= 1'b0; end else begin eight_bit_data_or_control_out[7:0] <= decoded_data[7:0]; output_is_control <= decoded_control; invalid_encoded_data <= detected_invalid_8b_10b_sequence & (ten_bit_encoded_data_in[9:0] != 10'b0000_000000) // NOTE TEMPORARY ; end end endmodule // `define TEST_8B_10B `ifdef TEST_8B_10B // This simulates in between 6 and 7 minutes on a 400 MHz Ultra using verilog XL. // This does not complete before filling up the disk on a 300 MHz K6 using Verilogger PRO. module test_8b_10b; reg [8:0] test_data; reg [8:0] test_data_second; reg [8:0] limit; reg [7:0] control_byte; reg [7:0] control_byte_second; reg test_control; reg [7:0] eight_bit_data_or_control_in; reg input_is_control; reg mess_up_link_disparity; wire [9:0] ten_bit_encoded_data_out; wire invalid_control; wire [7:0] eight_bit_data_or_control_out; wire output_is_control; wire invalid_encoded_data; reg clk, reset; reg found_singular_comma; task set_to_negative_disparity; begin clk = 1'b0; reset = 1'b1; #1; clk = 1'b1; reset = 1'b1; #1; // do reset, setting sender to negative disparity clk = 1'b0; reset = 1'b1; #1; clk = 1'b0; reset = 1'b0; #1; end endtask task set_to_positive_disparity; begin clk = 1'b0; reset = 1'b1; #1; clk = 1'b1; reset = 1'b1; #1; // do reset, setting sender to negative disparity clk = 1'b0; reset = 1'b1; #1; clk = 1'b0; reset = 1'b0; #1; eight_bit_data_or_control_in[7:0] = 8'b111_00011; #1; clk = 1'b1; #1; // switch to a positive running disparity clk = 1'b0; #1; end endtask task check; input disparity; input [7:0] test_data; input do_control; reg [9:0] latched_code; begin if (disparity == 1'b1) set_to_positive_disparity; else set_to_negative_disparity; input_is_control = do_control; eight_bit_data_or_control_in[7:0] = test_data[7:0]; #1; // inputs settle clk = 1'b1; #1; // encoded data available clk = 1'b0; #1; latched_code[9:0] = ten_bit_encoded_data_out[9:0]; input_is_control = 1'b0; eight_bit_data_or_control_in[7:0] = 8'b010_00011; #1; clk = 1'b1; #1; // decoded data available clk = 1'b0; #1; if ( (eight_bit_data_or_control_out[7:0] !== test_data[7:0]) | (output_is_control !== do_control) | (invalid_encoded_data !== 1'b0) ) begin $display ("!!! test data, result %d %d %b_%b %x %d %b %b", test_data[7:5], test_data[4:0], latched_code[9:6], latched_code[5:0], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end endtask function look_for_singular_comma; input [6:0] data; begin if ( (data[0] == data[1]) & (data[0] == ~data[2]) & (data[0] == ~data[3]) & (data[0] == ~data[4]) & (data[0] == ~data[5]) & (data[0] == ~data[6]) ) begin look_for_singular_comma = 1'b1; end else begin look_for_singular_comma = 1'b0; end end endfunction task check_pair; // Data then Data or Control then Data input disparity; input [7:0] test_data; input [7:0] test_data_second; input do_control; input want_singular_comma; reg [9:0] latched_code; reg [19:0] two_bytes_of_codes_back_to_back; begin if (disparity == 1'b1) set_to_positive_disparity; else set_to_negative_disparity; input_is_control = do_control; eight_bit_data_or_control_in[7:0] = test_data[7:0]; #1; // inputs settle clk = 1'b1; #1; // encoded data available clk = 1'b0; #1; latched_code[9:0] = ten_bit_encoded_data_out[9:0]; two_bytes_of_codes_back_to_back[9:0] = ten_bit_encoded_data_out[9:0]; input_is_control = 1'b0; eight_bit_data_or_control_in[7:0] = test_data_second[7:0]; #1; // inputs settle clk = 1'b1; #1; // decoded data available clk = 1'b0; #1; if ( (eight_bit_data_or_control_out[7:0] !== test_data[7:0]) | (output_is_control !== do_control) | (invalid_encoded_data !== 1'b0) ) begin $display ("!!! test data, result %d %d %b_%b %x %d %b %b", test_data[7:5], test_data[4:0], latched_code[9:6], latched_code[5:0], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end latched_code[9:0] = ten_bit_encoded_data_out[9:0]; two_bytes_of_codes_back_to_back[19:10] = ten_bit_encoded_data_out[9:0]; input_is_control = 1'b0; eight_bit_data_or_control_in[7:0] = 8'b010_00011; #1; clk = 1'b1; #1; // decoded data available clk = 1'b0; #1; if ( (eight_bit_data_or_control_out[7:0] !== test_data_second[7:0]) | (output_is_control !== 1'b0) | (invalid_encoded_data !== 1'b0) ) begin $display ("!!! test data second, result %d %d %b_%b %x %d %b %b", test_data_second[7:5], test_data_second[4:0], latched_code[9:6], latched_code[5:0], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end if (~want_singular_comma) begin if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) ) begin $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end else // want a singular comma begin if (!look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0])) begin $display ("!!! missing singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) ) begin $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end end endtask task check_pair_2; // Data followed by Control or Control followed by Control input disparity; input [7:0] test_data; input [7:0] test_data_second; input first_control; input want_first_singular_comma; input second_control; input want_second_singular_comma; reg [9:0] latched_code; reg [19:0] two_bytes_of_codes_back_to_back; begin if (disparity == 1'b1) set_to_positive_disparity; else set_to_negative_disparity; input_is_control = first_control; eight_bit_data_or_control_in[7:0] = test_data[7:0]; #1; // inputs settle clk = 1'b1; #1; // encoded data available clk = 1'b0; #1; latched_code[9:0] = ten_bit_encoded_data_out[9:0]; two_bytes_of_codes_back_to_back[9:0] = ten_bit_encoded_data_out[9:0]; input_is_control = second_control; eight_bit_data_or_control_in[7:0] = test_data_second[7:0]; #1; // inputs settle clk = 1'b1; #1; // decoded data available clk = 1'b0; #1; if ( (eight_bit_data_or_control_out[7:0] !== test_data[7:0]) | (output_is_control !== first_control) | (invalid_encoded_data !== 1'b0) ) begin $display ("!!! test data, result %d %d %b_%b %x %d %b %b", test_data[7:5], test_data[4:0], latched_code[9:6], latched_code[5:0], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end latched_code[9:0] = ten_bit_encoded_data_out[9:0]; two_bytes_of_codes_back_to_back[19:10] = ten_bit_encoded_data_out[9:0]; input_is_control = 1'b0; eight_bit_data_or_control_in[7:0] = 8'b010_00011; #1; clk = 1'b1; #1; // decoded data available clk = 1'b0; #1; if ( (eight_bit_data_or_control_out[7:0] !== test_data_second[7:0]) | (output_is_control !== second_control) | (invalid_encoded_data !== 1'b0) ) begin $display ("!!! test data second, result %d %d %b_%b %x %d %b %b", test_data_second[7:5], test_data_second[4:0], latched_code[9:6], latched_code[5:0], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end if (~want_first_singular_comma) begin if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9]) ) begin $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end else // want a singular comma in the first byte begin if (!look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0])) begin $display ("!!! missing singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9]) ) begin $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end if (~want_second_singular_comma) begin if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) ) begin $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end else // want a singular comma in the second byte begin if (!look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10])) begin $display ("!!! missing singular comma 2, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12]) | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) ) begin $display ("!!! unexpected singular comma 2, result %d %d %b_%b %b_%b %b %b %b %b", test_data[7:0], test_data_second[7:0], two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0], two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10], eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0], output_is_control, invalid_encoded_data); end end end endtask function [7:0] pick_control_byte; input [3:0] index; begin case (index[3:0]) 0: pick_control_byte[7:0] = `K_23_7; 1: pick_control_byte[7:0] = `K_27_7; 2: pick_control_byte[7:0] = `K_28_0; 3: pick_control_byte[7:0] = `K_28_1; 4: pick_control_byte[7:0] = `K_28_2; 5: pick_control_byte[7:0] = `K_28_3; 6: pick_control_byte[7:0] = `K_28_4; 7: pick_control_byte[7:0] = `K_28_5; 8: pick_control_byte[7:0] = `K_28_6; 9: pick_control_byte[7:0] = `K_28_7; 10: pick_control_byte[7:0] = `K_29_7; default: pick_control_byte[7:0] = `K_30_7; endcase end endfunction initial begin mess_up_link_disparity = 1'b0; $display ("test 32 LSB data values starting with negative disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h020; test_data[8:0] = test_data[8:0] + 9'h001) begin check (0, test_data[7:0], 1'b0); end $display ("test 8 MSB data values starting with negative disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (0, (test_data[2:0] << 5) | 5'h03, 1'b0); end $display ("test 8 MSB data values starting with negative disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (0, (test_data[2:0] << 5) | 5'h0B, 1'b0); // 11 end $display ("test 8 MSB data values starting with negative disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (0, (test_data[2:0] << 5) | 5'h11, 1'b0); // 17 end $display ("test control starting with negative disparity"); check (0, `K_23_7, 1'b1); check (0, `K_27_7, 1'b1); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (0, `K_28_0 | (test_data[2:0] << 5), 1'b1); end check (0, `K_29_7, 1'b1); check (0, `K_30_7, 1'b1); // $display ("invalid control character with negative disparity"); // check (0, 8'h0, 1'b1); $display ("test 32 LSB data values starting with positive disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h020; test_data[8:0] = test_data[8:0] + 9'h001) begin check (1, test_data[7:0], 1'b0); end $display ("test 8 MSB data values starting with positive disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (1, (test_data[2:0] << 5) | 5'h03, 1'b0); end $display ("test 8 MSB data values starting with positive disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (1, (test_data[2:0] << 5) | 5'h0B, 1'b0); // 11 end $display ("test 8 MSB data values starting with positive disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (1, (test_data[2:0] << 5) | 5'h11, 1'b0); // 17 end $display ("test control starting with positive disparity"); check (1, `K_23_7, 1'b1); check (1, `K_27_7, 1'b1); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008; test_data[8:0] = test_data[8:0] + 9'h001) begin check (1, `K_28_0 | (test_data[2:0] << 5), 1'b1); end check (1, `K_29_7, 1'b1); check (1, `K_30_7, 1'b1); // $display ("invalid control character with positive disparity"); // check (1, 8'h0, 1'b1); limit[8:0] = 9'h100; # 1; $display ("trying all byte pairs starting with negative disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100; test_data[8:0] = test_data[8:0] + 9'h001) begin for (test_data_second[8:0] = 9'h000; test_data_second[8:0] < limit[8:0]; test_data_second[8:0] = test_data_second[8:0] + 9'h001) begin check_pair (0, test_data[7:0], test_data_second[7:0], 1'b0, 1'b0); end end $display ("trying all controls then bytes with negative disparity"); $display ("This finds 24 unexpected extra singular commas when sending K_28_7"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100; test_data[8:0] = test_data[8:0] + 9'h001) begin for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC; test_data_second[3:0] = test_data_second[3:0] + 4'h1) begin check_pair (0, pick_control_byte(test_data_second[3:0]), test_data[7:0], 1'b1, (test_data_second[3:0] == 4'h3) | (test_data_second[3:0] == 4'h7) | (test_data_second[3:0] == 4'h9) ); end end $display ("trying all bytes then controls with negative disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100; test_data[8:0] = test_data[8:0] + 9'h001) begin for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC; test_data_second[3:0] = test_data_second[3:0] + 4'h1) begin check_pair_2 (0, test_data[7:0], pick_control_byte(test_data_second[3:0]), 1'b0, 1'b0, 1'b1, (test_data_second[3:0] == 4'h3) | (test_data_second[3:0] == 4'h7) | (test_data_second[3:0] == 4'h9) ); end end $display ("trying all controls then controls with negative disparity"); $display ("This finds 8 unexpected extra singular commas when sending K_28_7"); for (test_data[3:0] = 9'h000; test_data[3:0] < 4'hC; test_data[3:0] = test_data[3:0] + 4'h1) begin for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC; test_data_second[3:0] = test_data_second[3:0] + 4'h1) begin check_pair_2 (0, pick_control_byte(test_data[3:0]), pick_control_byte(test_data_second[3:0]), 1'b1, (test_data[3:0] == 4'h3) | (test_data[3:0] == 4'h7) | (test_data[3:0] == 4'h9), 1'b1, (test_data_second[3:0] == 4'h3) | (test_data_second[3:0] == 4'h7) | (test_data_second[3:0] == 4'h9) ); end end $display ("trying all byte pairs starting with positive disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100; test_data[8:0] = test_data[8:0] + 9'h001) begin for (test_data_second[8:0] = 9'h000; test_data_second[8:0] < limit[8:0]; test_data_second[8:0] = test_data_second[8:0] + 9'h001) begin check_pair (1, test_data[7:0], test_data_second[7:0], 1'b0, 1'b0); end end $display ("trying all controls then bytes with positive disparity"); $display ("This finds 24 unexpected extra singular commas when sending K_28_7"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100; test_data[8:0] = test_data[8:0] + 9'h001) begin for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC; test_data_second[3:0] = test_data_second[3:0] + 4'h1) begin check_pair (1, pick_control_byte(test_data_second[3:0]), test_data[7:0], 1'b1, (test_data_second[3:0] == 4'h3) | (test_data_second[3:0] == 4'h7) | (test_data_second[3:0] == 4'h9) ); end end $display ("trying all bytes then controls with positive disparity"); for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100; test_data[8:0] = test_data[8:0] + 9'h001) begin for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC; test_data_second[3:0] = test_data_second[3:0] + 4'h1) begin check_pair_2 (1, test_data[7:0], pick_control_byte(test_data_second[3:0]), 1'b0, 1'b0, 1'b1, (test_data_second[3:0] == 4'h3) | (test_data_second[3:0] == 4'h7) | (test_data_second[3:0] == 4'h9) ); end end $display ("trying all controls then controls with positive disparity"); $display ("This finds 8 unexpected extra singular commas when sending K_28_7"); for (test_data[3:0] = 9'h000; test_data[3:0] < 4'hC; test_data[3:0] = test_data[3:0] + 4'h1) begin for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC; test_data_second[3:0] = test_data_second[3:0] + 4'h1) begin check_pair_2 (1, pick_control_byte(test_data[3:0]), pick_control_byte(test_data_second[3:0]), 1'b1, (test_data[3:0] == 4'h3) | (test_data[3:0] == 4'h7) | (test_data[3:0] == 4'h9), 1'b1, (test_data_second[3:0] == 4'h3) | (test_data_second[3:0] == 4'h7) | (test_data_second[3:0] == 4'h9) ); end end end encode_8b_10b encode_8b_10b ( .eight_bit_data_or_control_in (eight_bit_data_or_control_in[7:0]), .input_is_control (input_is_control), .mess_up_link_disparity (mess_up_link_disparity), .ten_bit_encoded_data_out (ten_bit_encoded_data_out[9:0]), .invalid_control (invalid_control), .clk (clk), .reset (reset) ); decode_10b_8b decode_10b_8b ( .ten_bit_encoded_data_in (ten_bit_encoded_data_out[9:0]), .eight_bit_data_or_control_out (eight_bit_data_or_control_out[7:0]), .output_is_control (output_is_control), .invalid_encoded_data (invalid_encoded_data), .clk (clk), .reset (reset) ); endmodule `endif // TEST_8B_10B // `define DISCOVER_WHICH_CODES_ARE_ILLEGAL `ifdef DISCOVER_WHICH_CODES_ARE_ILLEGAL module figure_out_error_patterns; // NOTE: For the purpose of comparing with the patent, this exploration // module uses the notation that the LEFTMOST BIT is the LSB. // All other modules use the more normal Rightmost Bit == bit 0 == LSB reg [10:0] i; reg [9:0] full_addr; reg [4095:0] valid; // storage reg [4095:0] invalid; // storage task do_one; input [3:0] high_addr; begin full_addr[3:0] = high_addr[3:0]; // note LSB to left valid[full_addr[9:0]] = 1'b1; end endtask task mark_both; begin // both do_one (4'b1001); do_one (4'b0101); do_one (4'b1010); do_one (4'b0110); end endtask // The alternate Data encoding D.x.A7 is used in the case // that e = i = 0 and positive running disparity, // or e = i = 1 and negative running disparity, // or a Control signal is being sent, // all while encoding 7 in the MSB. task mark_positive; begin // positive list do_one (4'b0100); do_one (4'b0011); do_one (4'b0010); if (full_addr[5:4] != 2'b00) do_one (4'b0001); // P else do_one (4'b1000); // A end endtask task mark_negative; begin // negative list do_one (4'b1011); do_one (4'b1100); do_one (4'b1101); if (full_addr[5:4] != 2'b11) do_one (4'b1110); // P else do_one (4'b0111); // A end endtask task mark_all; begin mark_positive; mark_negative; mark_both; end endtask task mark; input [5:0] val; input type; integer type; begin full_addr[9:4] = val[5:0]; // note LSB to left if (type == 0) begin mark_all; end else if (type == 1) begin mark_positive; mark_both; end else begin mark_negative; mark_both; end end endtask initial begin // Clear all bits for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001) begin valid[i[9:0]] = 1'b0; invalid[full_addr[9:0]] = 1'b0; end // Mark patterns which are parts of valid codes mark (6'b110001, 0); mark (6'b101001, 0); mark (6'b011001, 0); mark (6'b100101, 0); mark (6'b010101, 0); mark (6'b110100, 0); mark (6'b001101, 0); mark (6'b101100, 0); mark (6'b011100, 0); mark (6'b100011, 0); mark (6'b010011, 0); mark (6'b110010, 0); mark (6'b001011, 0); mark (6'b101010, 0); mark (6'b011010, 0); mark (6'b100110, 0); mark (6'b010110, 0); mark (6'b001110, 0); mark (6'b011000, -1); mark (6'b100010, -1); mark (6'b010010, -1); mark (6'b001010, -1); mark (6'b111000, -1); mark (6'b000110, -1); mark (6'b101000, -1); mark (6'b100100, -1); mark (6'b000101, -1); mark (6'b001100, -1); mark (6'b001001, -1); mark (6'b010001, -1); mark (6'b100001, -1); mark (6'b010100, -1); mark (6'b100111, +1); mark (6'b011101, +1); mark (6'b101101, +1); mark (6'b110101, +1); mark (6'b000111, +1); mark (6'b111001, +1); mark (6'b010111, +1); mark (6'b011011, +1); mark (6'b111010, +1); mark (6'b110011, +1); mark (6'b110110, +1); mark (6'b101110, +1); mark (6'b011110, +1); mark (6'b101011, +1); // Mark patterns which are control codes. valid[ 10'b111010_1000] = 1'b1; valid[ 10'b110110_1000] = 1'b1; valid[ 10'b101110_1000] = 1'b1; valid[ 10'b011110_1000] = 1'b1; valid[ 10'b001111_0100] = 1'b1; valid[ 10'b001111_1001] = 1'b1; valid[ 10'b001111_0101] = 1'b1; valid[ 10'b001111_0011] = 1'b1; valid[ 10'b001111_0010] = 1'b1; valid[ 10'b001111_1010] = 1'b1; valid[ 10'b001111_0110] = 1'b1; valid[ 10'b001111_1000] = 1'b1; valid[~10'b111010_1000] = 1'b1; valid[~10'b110110_1000] = 1'b1; valid[~10'b101110_1000] = 1'b1; valid[~10'b011110_1000] = 1'b1; valid[~10'b001111_0100] = 1'b1; valid[~10'b001111_1001] = 1'b1; valid[~10'b001111_0101] = 1'b1; valid[~10'b001111_0011] = 1'b1; valid[~10'b001111_0010] = 1'b1; valid[~10'b001111_1010] = 1'b1; valid[~10'b001111_0110] = 1'b1; valid[~10'b001111_1000] = 1'b1; for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001) begin // Get rid of patterns in the 6 LSB with less than 2 or greater than 4 bits set. if ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) < 2) begin invalid[i[9:0]] = 1'b1; end if ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) > 4) begin invalid[i[9:0]] = 1'b1; end // Get rid of patterns in the 4 MSB with less than 1 or greater than 3 bits set. if ((i[3:0] == 4'h0) | (i[3:0] == 4'hF)) begin invalid[i[9:0]] = 1'b1; end // Get rid of total patterns with less than 4 or greater than 6 bits set. if ((i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9]) < 4) begin invalid[i[9:0]] = 1'b1; end if ((i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9]) > 6) begin invalid[i[9:0]] = 1'b1; end // Get rid of patterns with the 4 LSB all 0 or all 1 if ((i[9:6] == 4'b0000) | (i[9:6] == 4'b1111)) begin invalid[i[9:0]] = 1'b1; end // Get rid of patterns which use D.7.y with the wrong disparity. 8 if ((i[9:4] == 6'b111000) & (i[3] + i[2] + i[1] + i[0] == 1)) // minus then minus begin invalid[i[9:0]] = 1'b1; end if ((i[9:4] == 6'b000111) & (i[3] + i[2] + i[1] + i[0] == 3)) // plus then plus begin invalid[i[9:0]] = 1'b1; end // Get rid of patterns which use D.x.3 with the wrong disparity. 28 if ( (i[3:0] == 4'b0011) & ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) == 2)) begin invalid[i[9:0]] = 1'b1; end if ( (i[3:0] == 4'b1100) & ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) == 4)) begin invalid[i[9:0]] = 1'b1; end end // Get rid of case when D.x.3 and D.7.y are used together as D.7.3 valid[10'b111000_0011] = 1'b1; valid[10'b000111_1100] = 1'b1; for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001) begin // Get rid of non-control codes which use alternate encoding inappropriately. 32 // These are all the data items except 23, 27, 29, and 30 which do not end in // 00 or 11 as the MSB. This excludes control codes, which use alternate encoding. if ( (i[9:4] != 6'b111010) & (i[9:4] != 6'b000101) // 23 & (i[9:4] != 6'b110110) & (i[9:4] != 6'b001001) // 27 & (i[9:4] != 6'b101110) & (i[9:4] != 6'b010001) // 29 & (i[9:4] != 6'b011110) & (i[9:4] != 6'b100001) // 30 & (i[9:4] != 6'b001111) & (i[9:4] != 6'b110000) // K28 & (i[9:4] != 6'b110100) // 11 & (i[9:4] != 6'b101100) // 13 & (i[9:4] != 6'b011100) // 14 & (i[9:4] != 6'b100011) // 17 & (i[9:4] != 6'b010011) // 18 & (i[9:4] != 6'b001011) // 20 ) begin if ((i[3:0] == 4'b0111) | (i[3:0] == 4'b1000)) begin invalid[i[9:0]] = 1'b1; // not a candidate for alternate D7 at all end end if ( (i[9:4] == 6'b110000) // K28 | (i[9:4] == 6'b001111) // K28 | (i[9:4] == 6'b110100) // 11 | (i[9:4] == 6'b101100) // 13 | (i[9:4] == 6'b011100) // 14 ) begin if (i[3:0] == 4'b0001) // cant use normal + begin invalid[i[9:0]] = 1'b1; end end if ( (i[9:4] == 6'b100011) // 17 | (i[9:4] == 6'b010011) // 18 | (i[9:4] == 6'b001011) // 20 ) begin if (i[3:0] == 4'b1000) // cant use alternate + begin invalid[i[9:0]] = 1'b1; end end if ( (i[9:4] == 6'b110000) // K28 | (i[9:4] == 6'b001111) // K28 | (i[9:4] == 6'b100011) // 17 | (i[9:4] == 6'b010011) // 18 | (i[9:4] == 6'b001011) // 20 ) begin if (i[3:0] == 4'b1110) // cant use normal - begin invalid[i[9:0]] = 1'b1; end end if ( (i[9:4] == 6'b110100) // 11 | (i[9:4] == 6'b101100) // 13 | (i[9:4] == 6'b011100) // 14 ) begin if (i[3:0] == 4'b0111) // cant use alternate - begin invalid[i[9:0]] = 1'b1; end end end $display ("LSB is to the left"); for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001) begin if ((valid[i[9:0]] !== 1'b1) & (invalid[i[9:0]] !== 1'b1)) begin $display ("not set %b", i[9:0]); end if ((valid[i[9:0]] === 1'b1) & (invalid[i[9:0]] === 1'b1)) begin $display ("both set %b", i[9:0]); end end end endmodule `endif // DISCOVER_WHICH_CODES_ARE_ILLEGAL