
// -----------------------------------------------------------------------------
//  Framework for ternary simulation in Verilator
// -----------------------------------------------------------------------------

#include <stdio.h>
#include "Vternary.h"
#include "Vternary___024root.h"
#include "verilated_vcd_c.h"

// -----------------------------------------------------------------------------
//  Internal trit representation definition. Hardwired, do not change.
// -----------------------------------------------------------------------------

#define Z 0
#define P 1
#define N 2
#define X 3

// -----------------------------------------------------------------------------
//  Conversion between binary and ternary numbers
// -----------------------------------------------------------------------------

uint32_t bits2trits(int32_t bits)
{
  uint32_t trits = 0;
  uint32_t shift = 0;

  if (bits)
    while(bits)
    {
      int32_t rem = bits % 3; bits /= 3;

      if (rem == -2) {trits |= P << shift; bits--;}
      if (rem == -1) {trits |= N << shift;        }
      if (rem ==  0) {trits |= Z << shift;        }
      if (rem ==  1) {trits |= P << shift;        }
      if (rem ==  2) {trits |= N << shift; bits++;}

      shift += 2;
    }
    else trits = Z;

    return(trits);
}

int32_t trits2bits(uint32_t trits)
{
  int32_t binary = 0;
  int32_t power3 = 1;

  while (trits)
  {
    uint32_t t = trits & 3; trits = trits >> 2;
    if (t == P) binary += power3;
    if (t == N) binary -= power3;
    power3 *= 3;
  }

  return(binary);
}

// -----------------------------------------------------------------------------
//  Simulation
// -----------------------------------------------------------------------------

int main(int argc, char **argv)
{
    Verilated::commandArgs(argc, argv);
    Vternary* top = new Vternary;
    int i;

    top->serial_valid = 1;   // Pretend to always have a character waiting
    top->serial_busy = 0;   // Pretend to never be busy

    top->resetq = 0;
    top->eval();
    top->resetq = 1;

    int data = 0;

    for (i = 0; ; i++)
    {

      top->serial_rdata = data;

      top->clk = 1;
      top->eval();
      top->clk = 0;
      top->eval();

      if (top->serial_wr)
      {
        putchar(top->serial_wdata);
      }

      if (top->serial_rd)
      {
        data=getchar();
        if (data ==  27) break;
        if (data == EOF) break;
        if (data == 127) { data=8; } // Replace DEL with Backspace
      }

    }

    printf("Simulation ended after %d cycles\n", i);

    FILE *fcoredump;
    fcoredump = fopen("coredump.hex", "w");
    if(fcoredump == NULL) exit(-1);

    for (i = 0; i < 8192; i++)
    {
      fprintf(fcoredump, "%06X\n", top->rootp->v__DOT__processor__DOT__mem[i]);
    }

    fclose(fcoredump);

    delete top;
    exit(0);
}
