---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2007
--
-- Filename: SimCtrl002.vhd
-- Language: VHDL '93
-- Project:  NDTS2100
--
-- Design Description:
-- Simulation Control file to test System Monitor
---------------------------------------------------------------------------


library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;
use std.textio.all;

library work;
use work.LocalBusModelPkg.all;
use work.AdcModelPkg.all;


architecture Test of SimCtrl is

  -- Define some system register addresses
  constant cSysCheckReg           : integer := 16#00300000#;
  constant cSysMonCtrlReg         : integer := 16#00300010#;
  constant cUnderRangeFlagsReg    : integer := 16#00300014#;
  constant cOverRangeFlagsReg     : integer := 16#00300018#;
  constant cUnderRangeDLedEnReg   : integer := 16#0030001C#;  -- 5 registers
  constant cOverRangeDLedEnReg    : integer := 16#00300030#;  -- 5 registers
  constant cUnderRangeOKLedEnReg  : integer := 16#00300044#;
  constant cOverRangeOKLedEnReg   : integer := 16#00300048#;
  constant cSysMonitorADCValReg   : integer := 16#00300080#;  -- 24 registers
  constant cSysMonitorTempValReg  : integer := 16#003000E0#;
  constant cSysMonitorADCMinReg   : integer := 16#00300100#;  -- 24 registers
  constant cSysMonitorTempMinReg  : integer := 16#00300160#;
  constant cSysMonitorADCMaxReg   : integer := 16#00300180#;  -- 24 registers
  constant cSysMonitorTempMaxReg  : integer := 16#003001E0#;

begin

  -- Main Simulation Control process
  Main: process
    variable vRData: integer;
    variable vWData: integer;
    variable vTData: integer;
    variable vTestFail: boolean;
    variable vLine: Line;
    variable vDone: boolean;
    variable vBurstData: tBurstData;
    variable vReadBurstData: tBurstData;

  begin

    -- Initialise the test fail flag
    vTestFail := false;

    -- Setup some values on System monitor ADC inputs
    for i in 0 to 23 loop
      ToSysMonAdc(i) <= (i+1) * 7;
    end loop;  
    ToSysMonTemp <= +22; -- deg C

    -- Initialise the Bus Model (bus clock = 66 MHz)
    BusInit(15.152 ns, ToBusModel, FromBusModel);

    -- Write description of test to output
    write (vLine, string'("Testbench: Testing System Monitor Registers"));
    writeline (OUTPUT, vLine);

    -- check enabled by default
    LBusRead(cSysMonCtrlReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 16#0000001# then
      write (vLine, string'("Testbench: Error - Expected 0x00000001 from System Monitor Control register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    -- Check under/over-range LED enable bits
    vWData := 16#AAAA5555#;
    for i in 0 to 4 loop
      LBusWrite(cUnderRangeDLedEnReg+(i*4), vWData, ToBusModel, FromBusModel);
      vWData := vWData / 2;
    end loop;  
    vTData := 16#AAAA5555#;
    for i in 0 to 4 loop
      LBusRead(cUnderRangeDLedEnReg+(i*4), vRData, ToBusModel, FromBusModel);
      if vRData /= (vTData and 16#01FFFFFF#) then
        write (vLine, string'("Testbench: Error - Expected "));
        write (vLine, string'(Int2HexString(vTData, 8)));
        write (vLine, string'(" from UnderRange LED enable register"));
        writeline (OUTPUT, vLine);
        vTestFail := true;
      end if;
      vTData := vTData / 2;
    end loop;  

    vWData := 16#5555AAAA#;
    for i in 0 to 4 loop
      LBusWrite(cOverRangeDLedEnReg+(i*4), vWData, ToBusModel, FromBusModel);
      vWData := vWData / 2;
    end loop;  
    vTData := 16#5555AAAA#;
    for i in 0 to 4 loop
      LBusRead(cOverRangeDLedEnReg+(i*4), vRData, ToBusModel, FromBusModel);
      if vRData /= (vTData and 16#01FFFFFF#) then
        write (vLine, string'("Testbench: Error - Expected "));
        write (vLine, string'(Int2HexString(vTData, 8)));
        write (vLine, string'(" from OverRange LED enable register"));
        writeline (OUTPUT, vLine);
        vTestFail := true;
      end if;
      vTData := vTData / 2;
    end loop;  

    LBusWrite(cUnderRangeOKLedEnReg, 16#BBBB6666#, ToBusModel, FromBusModel);
    LBusWrite(cOverRangeOKLedEnReg, 16#6666BBBB#, ToBusModel, FromBusModel);
    LBusRead(cUnderRangeOKLedEnReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 16#01BB6666# then
      write (vLine, string'("Testbench: Error - Expected 0x01BB6666 from OK LED UnderRange enable register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;
    LBusRead(cOverRangeOKLedEnReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 16#0066BBBB# then
      write (vLine, string'("Testbench: Error - Expected 0x0066BBBB from OK LED OverRange enable register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    write (vLine, string'("Testbench: System Monitor Register tests complete"));
    writeline (OUTPUT, vLine);

    -- Write description of test to output
    write (vLine, string'("Testbench: Testing System Monitor operation"));
    writeline (OUTPUT, vLine);

    -- wait for System Monitor to go round once
    wait for 250 us;

    for i in 0 to 23 loop
      vTData := (i+1) * 7;
      LBusRead(cSysMonitorADCValReg+(i*4), vRData, ToBusModel, FromBusModel);
      if vRData /= vTData then
        write (vLine, string'("Testbench: Error - Expected "));
        write (vLine, vTData);
        write (vLine, string'(" from ADC value register at "));
        write (vLine, string'(Int2HexString(cSysMonitorADCValReg+(i*4), 8)));
        writeline (OUTPUT, vLine);
        vTestFail := true;
      end if;
    end loop;  

    -- wait for System Monitor to go round again before temperature is valid
    wait for 250 us;

    LBusRead(cSysMonitorTempValReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 16#00000058# then
      write (vLine, string'("Testbench: Error - Expected 0x00000058 from temperature value register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    -- set min and max registers
    for i in 0 to 23 loop
      LBusWrite(cSysMonitorADCMinReg+(i*4), 0, ToBusModel, FromBusModel);
      LBusWrite(cSysMonitorADCMaxReg+(i*4), 256, ToBusModel, FromBusModel);
    end loop;  
    LBusWrite(cSysMonitorTempMinReg, 10*4, ToBusModel, FromBusModel);
    LBusWrite(cSysMonitorTempMaxReg, 40*4, ToBusModel, FromBusModel);

    for i in 0 to 23 loop
      LBusRead(cSysMonitorADCMinReg+(i*4), vRData, ToBusModel, FromBusModel);
      if vRData /= 0 then
        write (vLine, string'("Testbench: Error - Expected 0 from ADC Min register"));
        writeline (OUTPUT, vLine);
        vTestFail := true;
      end if;
      LBusRead(cSysMonitorADCMaxReg+(i*4), vRData, ToBusModel, FromBusModel);
      if vRData /= 256 then
        write (vLine, string'("Testbench: Error - Expected 256 from ADC Min register"));
        writeline (OUTPUT, vLine);
        vTestFail := true;
      end if;
    end loop;  
    LBusRead(cSysMonitorTempMinReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 10*4 then
      write (vLine, string'("Testbench: Error - Expected 40 from Temp Min register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;
    LBusRead(cSysMonitorTempMaxReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 40*4 then
      write (vLine, string'("Testbench: Error - Expected 160 from Temp Max register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    -- clear under/over-range LED enable registers
    for i in 0 to 4 loop
      LBusWrite(cUnderRangeDLedEnReg+(i*4), 0, ToBusModel, FromBusModel);
      LBusWrite(cOverRangeDLedEnReg+(i*4), 0, ToBusModel, FromBusModel);
    end loop;  
    LBusWrite(cUnderRangeOKLedEnReg, 16#01FFFFFF#, ToBusModel, FromBusModel);
    LBusWrite(cOverRangeOKLedEnReg, 16#01FFFFFF#, ToBusModel, FromBusModel);

    -- wait for System Monitor to go round once more
    wait for 250 us;

    -- Check no under/over-range flags set yet
    LBusRead(cUnderRangeFlagsReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 0 then
      write (vLine, string'("Testbench: Error - Expected 0 from UnderRange flags register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    LBusRead(cOverRangeFlagsReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 0 then
      write (vLine, string'("Testbench: Error - Expected 0 from OverRange flags register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;
    -- Also LED outputs
    if SysMonD /= "11111" or SysMonOK /= '1' then
      write (vLine, string'("Testbench: Error - LED outputs on when not expected"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    -- channel 0 is 7, so make min 10
    LBusWrite(cSysMonitorADCMinReg+(0*4), 10, ToBusModel, FromBusModel);

    -- channel 2 is 21, so make max 15
    LBusWrite(cSysMonitorADCMaxReg+(2*4), 15, ToBusModel, FromBusModel);

    -- enable channel 0 under-range on led 0, channel 2 over-range on led 2
    LBusWrite(cUnderRangeDLedEnReg+(0*4), 16#00000001#, ToBusModel, FromBusModel);
    LBusWrite(cOverRangeDLedEnReg+(2*4), 16#00000004#, ToBusModel, FromBusModel);

    -- wait for System Monitor to go round once more
    wait for 250 us;

    -- Check under/over-range flags now set
    LBusRead(cUnderRangeFlagsReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 16#00000001# then
      write (vLine, string'("Testbench: Error - Expected 0x0000001 from UnderRange flags register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    LBusRead(cOverRangeFlagsReg, vRData, ToBusModel, FromBusModel);
    if vRData /= 16#00000004# then
      write (vLine, string'("Testbench: Error - Expected 0x0000004 from OverRange flags register"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;

    -- check LED outputs
    if SysMonD /= "11010" or SysMonOK /= '0' then
      write (vLine, string'("Testbench: Error - LED outputs not on when expected"));
      writeline (OUTPUT, vLine);
      vTestFail := true;
    end if;


    write (vLine, string'("Testbench: System Monitor test complete"));
    writeline (OUTPUT, vLine);

    wait for 100 ns;

    -- Stop the simulation and report pass/fail
    if vTestFail then
      report "Testbench: Simulation 002 completed - FAIL"
      severity failure;
    else
      report "Testbench: Simulation 002 completed - PASS"
      severity failure;
    end if;

    wait;

  end process main;


end architecture Test;