import java.io.*;
import byucc.jhdl.base.*;
import byucc.jhdl.Logic.*;

/**
 *  tb_fsmMemCtl - Testbench for memory controller FSM example.
 *
 */
public class tb_fsmMemCtl
  extends Logic
  implements TestBench
{

  // These are the wires which will be passed into FSM
  Wire clr;
  Wire wReq;
  Wire rReq;
  Wire latchAddr;
  Wire rw_;
  Wire ack;

  // Verbosity level
  private static boolean verbose = true;

  // The constructor for the testbench
  public tb_fsmMemCtl (Node parent)
  {
    super (parent, "tb_fsmMemCtl");


    // Instance all wires in this design
    clr       = Logic.wire(this, "clr");
    wReq      = Logic.wire(this, "wReq");
    rReq      = Logic.wire(this, "rReq");
    latchAddr = Logic.wire(this, "latchAddr");
    rw_       = Logic.wire(this, "rw_");
    ack       = Logic.wire(this, "ack");

    // Turn on Fsm verbosity (Only for JHDL versions LATER than 0.3.9):
    byucc.jhdl.Fsm.Fsm.setVerbose( verbose );
    // Build the FSM
    fsmMemCtl f = new fsmMemCtl (this, clr, wReq, rReq, latchAddr, rw_, ack,
				 "fsmMemCtl.fsm");

  }

  // This routine gets called on initialization
  public void reset()
  {
    msgln("Resetting the memory control FSM");
    clr.put(this, 1);
    wReq.put(this, 0);
    rReq.put(this, 0);
    clkCnt = 0;
    stpCnt = 0;
    ttlStp = 0;
  }

  // Here are the inputs which will be driven into the circuit each cycle
  static String inputs[] = {
    //step0 step1 // cycle
    "100", "100", // 00
    "000", "000", // 01
    "010", "010", // 02
    "000", "000", // 03
    "000", "000", // 04
    "000", "000", // 05
    "011", "011", // 06
    "000", "000", // 07
    "000", "000", // 08
    "000", "000", // 09
    "000", "000", // 10
    "001", "001", // 11
    "000", "000", // 12
    "000", "000", // 13
    "000", "000", // 14
  };

  // Here are the input/output combinations we expect to get back out
  static String results[] = {
    "100 010", // reset the circuit
    "100 010",
    "100 010",
    "000 010",
    "000 010",
    "010 110", // Write request arrived, assert latchAddr
    "010 010",
    "000 010",
    "000 001", // Strobe rw_ signal and assert ack, step 0
    "000 001", // Strobe rw_ signal and assert ack, step 1
    "000 010",
    "000 010",
    "000 010",
    "011 110", // Write request takes priority over read request
    "011 010", // Write request takes priority over read request
    "000 010",
    "000 001", // Strobe rw_ signal and assert ack, step 0
    "000 001", // Strobe rw_ signal and assert ack, step 1
    "000 010",
    "000 010",
    "000 010",
    "000 010",
    "000 010",
    "001 110", // Read request arrived, assert latchAddr
    "001 011", // Assert ack, step 0
    "000 011", // Assert ack, step 1
    "000 010", // Back to initial state
    "000 010",
    "000 010",
    "000 010",
  };

  // Global flag to signal a simulation error occured
  static boolean simError = false;

  // Count number of clock cycles
  int clkCnt = 0;
  int stpCnt = 0;
  int ttlStp = 0;

  // This routine gets called each cycle.  Will check outputs and
  // assert new inputs.
  public void clock() {
    String s;

    // Build results string
    s = "" + clr.get(this)+ wReq.get(this)+ rReq.get(this) + " ";
    s += "" + latchAddr.get(this)+ rw_.get(this) + ack.get(this);
    msg("Cycle " + clkCnt +
	", Step " + stpCnt + ":\t");
    msgln(s);

    // See if we got the right answer
    String expected = results[ttlStp % results.length];
    if (!s.equals(expected)){
      simError = true;
      System.err.println("   Error in cycle " + clkCnt +
			 ", step " + stpCnt +
			 " - expected \"" + expected +
			 "\" , got \"" + s + "\" instead.");
    }

    // Get new inputs to drive out and assign them
    s = inputs[ttlStp % inputs.length];

    clr.put(this, s.charAt(0) - '0');
    wReq.put(this, s.charAt(1) - '0');
    rReq.put(this, s.charAt(2) - '0');

    // Increment the cycle and total step counts and toggle the step.
    ttlStp++;
    if ( 1 == stpCnt ) {
      clkCnt++;
      stpCnt = 0;
    } else {
      stpCnt = 1;
    }
  }

  private static void msg(String msg)
  {
    if ( verbose )
      System.out.print(msg);
  }
  private static void msgln(String msg)
  {
    if ( verbose )
      System.out.println(msg);
  }

  // Main routine.  Build testbench and execute it.  Tell user if
  // error occured.
  public static void main (String[] args)
  {
    // See if user wants quiet output
    if ( 0 < args.length && args[0].equals("-q") )
      verbose = false;

    msgln("fsmMemCtl Test");

    HWSystem system = new HWSystem();
    new tb_fsmMemCtl (system);
    msgln("Everything is built....");

    system.step(inputs.length);
    if (!simError)
      System.out.println("***** Simulation OK *****");
  }
}
