ecc_decode.cpp 2.97 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
// SPDX-License-Identifier: Apache-2.0
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>

#include "Vecc_decode.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "ecc.h"

#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <math.h>

// This is a 64-bit integer to reduce wrap over issues and
// allow modulus.  You can also use a double, if you wish.
vluint64_t main_time = 0;

// Called by $time in Verilog
// converts to double, to match
// what SystemC does
double sc_time_stamp () {
    return main_time;
}


int main(int argc, char** argv, char** env) {

    Verilated::commandArgs(argc, argv);
    Vecc_decode* dut = new Vecc_decode;

    int d = 64; // code word length
    int p = calcParityLen(d);  // parity length

    // number of bytes to store the codeword
    int cw_byte = (int) ceil((d + p + 1)/32.0);

    // input word
    uint64_t word = 0x55555555;
    uint8_t codeword [d + p + 1];
    // allocate 8 bit per byt
    uint8_t encoded_word [cw_byte];
    uint8_t parity [d];

    uint8_t single_error, parity_error, double_error;

    Verilated::traceEverOn(true);
    VerilatedVcdC* tfp = new VerilatedVcdC;
    dut->trace(tfp, 99);  // Trace 99 levels of hierarchy
    tfp->open("ecc_decode.vcd");

    while (!Verilated::gotFinish()) {

        ecc_encode(word, d, codeword);

        for (int i = 0; i < cw_byte; i++) encoded_word[i] = 0;

        toByte(encoded_word, codeword, d + p + 1);

        printf("[DUT] input  = %llx\n", word);
        // Apply Input Data
        for (int i = 0; i < cw_byte; i++) {
            dut->data_i[i] = *((unsigned int *) encoded_word + i);
        }

        // randomly inject some errors
        single_error = 0;
        double_error = 0;
        parity_error = 0;

        switch (random() % 10) {
            // inject single error
            case 0:
                printf("Injecting single error\n");
                single_error = 1;
                dut->data_i[random() % (cw_byte - 1)] ^= 0x1 << (random() % 8);
                break;
            // parity error
            case 1:
                printf("Injecting parity error\n");
                parity_error = 1;
                dut->data_i[cw_byte-1] ^= 0x80;
                break;
            // inject double error
            case 2:
                printf("Injecting double error\n");
                double_error = 1;
                dut->data_i[random() % (cw_byte - 1)] ^= 0x3 << (random() % 8);
                break;
        }

        // Eval DUT
        dut->eval();

        printf("[DUT] output = %lx\n", dut->data_o);
        assert (double_error || dut->data_o == word);
        assert (dut->single_error_o == single_error);
        assert (dut->parity_error_o == parity_error);
        assert (dut->double_error_o == double_error);
        // Advance Time
        main_time++;

        word = random() << 32 | random();

        tfp->dump(main_time);

        if (main_time > 100000) break;
    }
    dut->final();
    tfp->close();
    delete dut;
    exit(0);
}