// tb_storage.cpp - Verilator C++ testbench for storage (sd_bram top)
//
// Reads test vectors from +VECTOR_FILE= hex file.
// Format: "ADDR DATA" per line (addr in 2-char hex, data in 12-char hex).
// Writes values via sd_bram, reads back, prints "RESULT: VAL_HEX".
// s_bram is compiled as rtl_dep.
//
// Clock: 10ns period. W=48, D=64, A=6 (default sd_bram parameters).

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <cstdint>
#include "Vsd_bram.h"
#include "verilated.h"

#define CLK_HALF_PS 5000

static vluint64_t main_time = 0;

double sc_time_stamp() {
    return (double)main_time / 1000.0;
}

static void tick(Vsd_bram* dut) {
    dut->clk = 1;
    main_time += CLK_HALF_PS;
    dut->eval();
    dut->clk = 0;
    main_time += CLK_HALF_PS;
    dut->eval();
}

int main(int argc, char** argv) {
    Verilated::commandArgs(argc, argv);

    const char* vector_file = NULL;
    for (int i = 1; i < argc; i++) {
        std::string arg(argv[i]);
        if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
            vector_file = argv[i] + 13;
            break;
        }
    }

    if (!vector_file) {
        std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
        return 1;
    }

    std::ifstream infile(vector_file);
    if (!infile.is_open()) {
        std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
        return 1;
    }

    struct Vec { int addr; uint64_t data; };
    std::vector<Vec> vectors;

    std::string line;
    while (std::getline(infile, line)) {
        if (line.empty() || line[0] == '#') continue;
        std::istringstream iss(line);
        int a;
        uint64_t d;
        if (!(iss >> std::hex >> a >> d)) continue;
        if (a < 0 || a > 63) continue;
        vectors.push_back({a, d & 0xFFFFFFFFFFFFULL});
    }
    infile.close();

    if (vectors.empty()) {
        std::cerr << "ERROR: No valid vectors in file" << std::endl;
        return 1;
    }

    Vsd_bram* dut = new Vsd_bram;

    dut->clk     = 0;
    dut->rd_addr = 0;
    dut->wr_en   = 0;
    dut->wr_addr = 0;
    dut->wr_data = 0;
    dut->eval();
    main_time += CLK_HALF_PS;
    dut->eval();

    // --- WRITE PHASE ---
    for (size_t i = 0; i < vectors.size(); i++) {
        dut->wr_en   = 1;
        dut->wr_addr = vectors[i].addr & 0x3F;
        dut->wr_data = vectors[i].data & 0xFFFFFFFFFFFFULL;
        tick(dut);
    }
    dut->wr_en   = 0;
    dut->wr_addr = 0;
    dut->wr_data = 0;
    tick(dut);

    // --- READ PHASE ---
    for (size_t i = 0; i < vectors.size(); i++) {
        dut->rd_addr = vectors[i].addr & 0x3F;
        tick(dut);
        printf("RESULT: %012lX\n", (unsigned long)(dut->rd_data & 0xFFFFFFFFFFFFULL));
    }

    delete dut;
    return 0;
}
