8-to-10 Encoder in Verilog and VHDL — Complete Code, Testbenches, and Waveforms
An 8-to-10 encoder converts an 8-bit data word into a 10-bit codeword by appending two error-detection (check) bits. This post gives a complete, working design — all 256 inputs covered — in both Verilog and VHDL, with full testbenches, expected console output, and waveforms you can view in GTKWave.
default), and the two extra
bits were a constant prefix (111110), so they carried no information and could not
detect errors. Here the check bits are computed from the data, so every input gets a unique
codeword and every single-bit error is detectable.
1. Design Idea
The 10-bit output is formed as {chk_high, chk_low, data_in}:
chk_high— XOR (parity) of the upper nibbledata_in[7:4]chk_low— XOR (parity) of the lower nibbledata_in[3:0]
If any single bit (data or check bit) flips during transmission, at least one
recomputed check bit will mismatch, and the decoder raises an error flag.
Example encodings:
| data_in (binary) | chk_high | chk_low | data_out (10 bits) |
|---|---|---|---|
| 00000000 | 0 | 0 | 00 0000 0000 |
| 00000001 | 0 | 1 | 01 0000 0001 |
| 10110010 | 1 | 1 | 11 1011 0010 |
| 11111111 | 0 | 0 | 00 1111 1111 |
2. Verilog Code
2.1 Encoder — encoder_8to10.v
module encoder_8to10 (
input [7:0] data_in, // 8-bit input data
output [9:0] data_out // 10-bit encoded output
);
// Two check bits: parity of each nibble.
// Every one of the 256 inputs gets a unique encoding.
wire chk_high = ^data_in[7:4];
wire chk_low = ^data_in[3:0];
assign data_out = {chk_high, chk_low, data_in};
endmodule
2.2 Decoder — decoder_10to8.v
module decoder_10to8 (
input [9:0] data_in, // received 10-bit codeword
output [7:0] data_out, // recovered 8-bit data
output error // '1' = single-bit error detected
);
assign data_out = data_in[7:0];
// Recompute the check bits and compare with the received ones
assign error = (data_in[9:8] != {^data_in[7:4], ^data_in[3:0]});
endmodule
3. Verilog Testbench — tb_encoder_8to10.v
The testbench does three things: (1) exhaustively checks all 256 input encodings and the round-trip through the decoder, (2) injects a single-bit error at each of the 10 bit positions and confirms it is always detected, and (3) demonstrates a double-bit error that slips through (a known limitation of 2 check bits).
`timescale 1ns / 1ps
module tb_encoder_8to10;
// ---------------------------------------------------------
// Signals
// ---------------------------------------------------------
reg [7:0] data_in;
wire [9:0] data_out;
reg [9:0] corrupted_out; // word fed to decoder (may be corrupted)
wire [7:0] decoded_data;
wire decoded_error;
integer i;
integer b;
integer error_count;
// ---------------------------------------------------------
// DUTs
// ---------------------------------------------------------
encoder_8to10 uut_enc (
.data_in (data_in),
.data_out (data_out)
);
decoder_10to8 uut_dec (
.data_in (corrupted_out),
.data_out (decoded_data),
.error (decoded_error)
);
// ---------------------------------------------------------
// Task: corrupt one bit of the current codeword
// ---------------------------------------------------------
task inject_error(input integer pos);
begin
corrupted_out = data_out ^ (10'b1 << pos);
end
endtask
// ---------------------------------------------------------
// Stimulus
// ---------------------------------------------------------
initial begin
error_count = 0;
// ---- Part 1: exhaustive test of all 256 inputs ----
for (i = 0; i < 256; i = i + 1) begin
data_in = i[7:0];
#10; // let the encoder settle
corrupted_out = data_out; // clean word to the decoder
#10;
// Check the encoder against the expected value
if (data_out !== {^data_in[7:4], ^data_in[3:0], data_in}) begin
$display("ERROR: encoding mismatch for data_in = %b", data_in);
error_count = error_count + 1;
end
// A clean word must never raise the error flag
if (decoded_error !== 1'b0) begin
$display("ERROR: false error flag for data_in = %b", data_in);
error_count = error_count + 1;
end
end
$display("Exhaustive test complete. Errors = %0d", error_count);
// ---- Part 2: single-bit error injection (all 10 positions) ----
data_in = 8'b10110010;
#10;
for (b = 0; b < 10; b = b + 1) begin
inject_error(b);
#10;
if (decoded_error === 1'b1)
$display("Bit %0d corrupted -> detected. data=%b err=%b",
b, decoded_data, decoded_error);
else begin
$display("BUG: bit %0d corruption NOT detected!", b);
error_count = error_count + 1;
end
end
// ---- Part 3: double-bit error (may pass undetected) ----
corrupted_out = data_out ^ 10'b0000000011; // flip bits 1 and 0
#10;
$display("Double-bit flip: decoded=%b error_flag=%b (0 = undetected, expected for 2 check bits)",
decoded_data, decoded_error);
$display("Testbench finished. Total mismatches = %0d", error_count);
$finish;
end
// ---------------------------------------------------------
// Dump waveform for GTKWave
// ---------------------------------------------------------
initial begin
$dumpfile("encoder_8to10.vcd");
$dumpvars(0, tb_encoder_8to10);
end
endmodule
4. VHDL Code
4.1 Encoder — encoder_8to10.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity encoder_8to10 is
Port ( data_in : in STD_LOGIC_VECTOR(7 downto 0);
data_out : out STD_LOGIC_VECTOR(9 downto 0) );
end encoder_8to10;
architecture Behavioral of encoder_8to10 is
signal chk_high : STD_LOGIC;
signal chk_low : STD_LOGIC;
begin
-- Parity of each nibble (VHDL-93 compatible)
chk_high <= data_in(7) xor data_in(6) xor data_in(5) xor data_in(4);
chk_low <= data_in(3) xor data_in(2) xor data_in(1) xor data_in(0);
-- 2 check bits + 8 data bits = 10-bit output
data_out <= chk_high & chk_low & data_in;
end Behavioral;
4.2 Decoder — decoder_10to8.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity decoder_10to8 is
Port ( data_in : in STD_LOGIC_VECTOR(9 downto 0);
data_out : out STD_LOGIC_VECTOR(7 downto 0);
error : out STD_LOGIC );
end decoder_10to8;
architecture Behavioral of decoder_10to8 is
signal chk_high, chk_low : STD_LOGIC;
begin
-- Recompute the check bits from the received data
chk_high <= data_in(7) xor data_in(6) xor data_in(5) xor data_in(4);
chk_low <= data_in(3) xor data_in(2) xor data_in(1) xor data_in(0);
data_out <= data_in(7 downto 0);
-- Error if stored check bits do not match the recomputed ones
error <= '1' when (data_in(9) /= chk_high) or (data_in(8) /= chk_low)
else '0';
end Behavioral;
5. VHDL Testbench — tb_encoder_8to10.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity tb_encoder_8to10 is
end tb_encoder_8to10;
architecture sim of tb_encoder_8to10 is
signal data_in : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
signal data_out : STD_LOGIC_VECTOR(9 downto 0);
signal corrupted_out : STD_LOGIC_VECTOR(9 downto 0) := (others => '0');
signal decoded_data : STD_LOGIC_VECTOR(7 downto 0);
signal decoded_error : STD_LOGIC;
begin
uut_enc: entity work.encoder_8to10
port map ( data_in => data_in, data_out => data_out );
uut_dec: entity work.decoder_10to8
port map ( data_in => corrupted_out,
data_out => decoded_data,
error => decoded_error );
stim: process
variable error_count : integer := 0;
variable expected : STD_LOGIC_VECTOR(9 downto 0);
variable err_vec : STD_LOGIC_VECTOR(9 downto 0);
begin
-- Part 1: exhaustive test of all 256 inputs
for i in 0 to 255 loop
data_in <= STD_LOGIC_VECTOR(to_unsigned(i, 8));
wait for 10 ns;
corrupted_out <= data_out; -- clean word to the decoder
wait for 10 ns;
expected(9) := data_in(7) xor data_in(6)
xor data_in(5) xor data_in(4);
expected(8) := data_in(3) xor data_in(2)
xor data_in(1) xor data_in(0);
expected(7 downto 0) := data_in;
if data_out /= expected then
report "Encoding mismatch for input " & integer'image(i)
severity error;
error_count := error_count + 1;
end if;
if decoded_error /= '0' then
report "False error flag for input " & integer'image(i)
severity error;
error_count := error_count + 1;
end if;
end loop;
report "Exhaustive test complete. Errors = " & integer'image(error_count);
-- Part 2: single-bit error injection (all 10 positions)
data_in <= "10110010";
wait for 10 ns;
for b in 0 to 9 loop
err_vec := (others => '0');
err_vec(b) := '1';
corrupted_out <= data_out xor err_vec;
wait for 10 ns;
if decoded_error = '1' then
report "Bit " & integer'image(b) & " corrupted -> detected OK";
else
report "BUG: bit " & integer'image(b)
& " corruption NOT detected!" severity error;
error_count := error_count + 1;
end if;
end loop;
-- Part 3: double-bit error (may pass undetected)
corrupted_out <= data_out xor "0000000011"; -- flip bits 1 and 0
wait for 10 ns;
report "Double-bit flip: error flag = " & STD_LOGIC'image(decoded_error)
& " (0 = undetected, expected for 2 check bits)";
report "Testbench finished. Total errors = " & integer'image(error_count);
wait; -- stop the simulation
end process;
end architecture sim;
6. How to Simulate
# Verilog (Icarus Verilog)
iverilog -o enc_tb.vvp encoder_8to10.v decoder_10to8.v tb_encoder_8to10.v
vvp enc_tb.vvp
gtkwave encoder_8to10.vcd # view the waveform
# VHDL (GHDL)
ghdl -a encoder_8to10.vhd decoder_10to8.vhd tb_encoder_8to10.vhd
ghdl -e tb_encoder_8to10
ghdl -r tb_encoder_8to10 --wave=wave.ghw
gtkwave wave.ghw # view the waveform
7. Expected Console Output
Exhaustive test complete. Errors = 0
Bit 0 corrupted -> detected. data=10110011 err=1
Bit 1 corrupted -> detected. data=10110000 err=1
Bit 2 corrupted -> detected. data=10110110 err=1
Bit 3 corrupted -> detected. data=10111010 err=1
...
Bit 8 corrupted -> detected. data=10110010 err=1
Bit 9 corrupted -> detected. data=10110010 err=1
Double-bit flip: decoded=10110001 error_flag=0 (0 = undetected, expected for 2 check bits)
Testbench finished. Total mismatches = 0
Note the last result: flipping two bits inside the same nibble leaves the parity unchanged, so the double-bit error passes undetected. That is the expected behavior of 2 check bits — they guarantee detection of all single-bit errors only.
8. Waveform
Example transaction: input A5 → output 0A5, input 01 →
output 101, then a corrupted word 100 arrives (one bit flipped) and the
decoder raises error for exactly one clock period, then input FF →
output 0FF.
Text version of the same waveform:
0ns 20ns 40ns 60ns 80ns
| | | | |
data_in <--A5--><--01--><--A5--><--FF-->
data_out <-0A5-><-101-><-100*><-0FF-> (* corrupted word)
error ________/▔▔▔▔▔▔▔▔▔\________________
The Verilog testbench writes encoder_8to10.vcd via $dumpfile /
$dumpvars, and the GHDL run produces wave.ghw — open either file in
GTKWave to see this exact waveform.
9. Notes and Limitations
- All 256 input combinations are encoded — no ambiguous
default/otherscase is needed. - All 10 single-bit errors (8 data bits + 2 check bits) are detected, verified exhaustively by the testbenches.
- Some double-bit errors are undetectable with 2 parity bits (demonstrated in Part 3 of the testbenches). For stronger protection you would need a proper Hamming or CRC code.
- This scheme adds error detection only, not correction, and it is not DC-balanced. For serial links that need run-length and disparity control, use the industry-standard 8b/10b encoding, which tracks running disparity and is a sequential (state-dependent) design rather than a simple lookup.
No comments:
Post a Comment