# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# The RNBIP Emulator
# This Multi threaded module 1: 1 emulates the operation of the RNBIP Micro - Controller
# Author::@CommandPaul(Paul George)# Junior Year 2016 - 17
# Shiv Nadar University
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
#   This Python Script is hierarchially seperated into the original modulles of
#   the architecture, all original signals have been preserved the encoded data
#   can be visualised in VedantCJ(Vedant Chakravarty `s) Visualisation module
#   Developed in C++ using the QT Framework , The input to this file should be
#   in the format output by the Pn337(Prasanna Natarajan) Assembler .
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

# ---- Fixit Comments Remove from final
# Re-Write this in cpp
# ---- End of Fixit Comments

#   Note :: The killthr flag is negative logic

#   Import Libraries
import time
from multiprocessing import Process, Value, Queue, Array, Barrier
from ctypes import c_ubyte, c_char, c_int
import ctypes
import multiprocessing
import logging
import random
import pdb
import os
import datetime
import platform
import re
import sys
# import importlib

from rnbip_emulator.rnbip_isa import Architectural_state, Microarchitectural_state
# if platform.system == "Linux":
#   from emulator_io import IO_Interface
# Block Design
# process declarition with all shared variables
# Procces tasks on current mmachine state
# process essentially creates a copy of all write affect control bits for that cycle # Write schedule protect
# Process state is recorded :D # essentially as an outcome of the previous state
# process Wait at Barrier for Synchronous
# Process executes Synchronous functions
# All mem writes are performed prep for next set of control siglanls is done
# wait for Kill Signal
# barrier 2

'''def Proc(StateVariableA,StateVariableB,Kill,Barrier1,Barrier2):
    
    # The design is assumed to be completly synchronous to an implict clock
    # Barriers are used as an analogue to Standard HDL Event Regions, 
    # which help us split the design simulation into independent phases 
    # helping us avoid race conditions on our lock free state variables

    < Initialization Phase >
    StateVariableA.set(0)
    StateVariableB.set(0)

    Barrier2.wait()
    a = StateVariableA.get()+1
    
    while(1):
      StateVariableB.put(a)
      Barrier1.wait()
    
      a = StateVariableA.get()+1
      StateVariableB.put(a)
      Barrier2.wait()
      if(Kill.value == 1 ):
        return
  '''


class single_bus_emulator:

    # RNBIP Architectural State
    ProgramCounter = Value(c_ubyte, 0, lock=False)
    StackPointer = Value(c_ubyte, 0, lock=False)
    RegisterArray = Array(c_ubyte, [1, 2, 3, 4, 5, 6, 7, 8], lock=False)
    FlagRegister = Array(c_ubyte, [1, 0, 0, 1, 1, 0, 0, 1], lock=False)
    Memory = Array(c_ubyte, 256, lock=False)
    IO_In = Array(c_ubyte, [0, 0, 0, 0, 0, 0, 0, 0], lock=False)
    IO_Out = Array(c_ubyte, [0, 0, 0, 0, 0, 0, 0, 0], lock=False)

    # RNBIP MicroArchitectural State
    DataBus = Queue()
    IR_CCG = Queue()
    #SelectedFlag = Queue()
    # make this a queue and put values spl case of no SAL for ClC case
    AluOut = Value(c_ubyte, 0, lock=False)
    #AluOut = Value(c_ubyte, 0, lock=False)
    AluOpcode = Value(c_ubyte, 0, lock=False)
    CarryIn = Value(c_ubyte, 0, lock=False)
    InstructionRegister = Value(c_ubyte, 0, lock=False)
    OperandRegister = Value(c_ubyte, 0, lock=False)
    State = Value(c_ubyte, 0, lock=False)
    ControlBits = Array(c_char, b'1010010000100000000000',
                        lock=False)  # needs to be Cached

    # Model specific Variables
    Ncyc = 20
    Kill = Value(c_ubyte, 0, lock=False)
    # RegSel = Value(c_ubyte, 0, lock=False)#needs Cacheing

    # Multi Processing and Synchronization State
    ThrCCG = Process()
    ThrIR = Process()
    ThrPC = Process()
    ThrMEM = Process()
    ThrRegArr = Process()
    ThrALU = Process()
    ThrSPtr = Process()
    ThrOpReg = Process()
    ThrIO = Process()
    Barrier1 = Barrier(10)  # dont forget ot update :P
    Barrier2 = Barrier(10)

    # Trace Vector
    TraceVector = []

    # Housekeeping static members
    @staticmethod
    def parityOf(number):
        parity = 0
        int_type = number
        while (int_type > 0):
            parity = ~parity
            int_type = int_type & (int_type - 1)
        return(parity + 1)

    @staticmethod
    def file_len(fname):
        i = 0
        with fname as f:
            for i, l in enumerate(f):
                pass
        return i + 1

    # State machine static member functions

    @staticmethod
    def RegisterArrayModule(ControlBits, DataBus, RegisterArr, InstructionRegister, AluOut, Kill, Barrier1, Barrier2):
        # initialisation read from file
        RegisterArray = [0, 1, 2, 3, 4, 5, 6, 7]
        for k in range(0, 8):
            RegisterArray[k] = random.randint(0, 255)
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            LR0 = ControlBits[18]  # cached for Synchronous Protection
            LRN = ControlBits[20]  # cached for Synchronous Protection
            SAL = ControlBits[17]  # cached for Synchronous Protection
            REGSEL = InstructionRegister.value % 8
            # print(LR0,LRN,SAL,REGSEL)

            if(ControlBits[19] == b'1'):
                DataBus.put(RegisterArray[0])

            if(ControlBits[21] == b'1'):
                DataBus.put(RegisterArray[REGSEL])

            Barrier1.wait()
            # Synchronous Here after
            if(LR0 == b'1' and LRN == b'1'):
                RegisterArray = [0, 0, 0, 0, 0, 0, 0, 0]
            # a = AluOut.get() # a useless pop to clear the queue
            elif(LR0 == b'1' and SAL == b'0'):
                # .value requirement ? Not Required :)
                RegisterArray[0] = DataBus.get()
            elif(LRN == b'1' and SAL == b'0'):
                # .value requirement ? Not Required :)
                RegisterArray[REGSEL] = DataBus.get()
            elif(LR0 == b'1' and SAL == b'1'):
                # .value requirement ? Not Required :)
                RegisterArray[0] = AluOut.value
            elif(LRN == b'1' and SAL == b'1'):
                # .value requirement ? Not Required :)
                RegisterArray[REGSEL] = AluOut.value
            for k in range(0, 8):
                RegisterArr[k] = RegisterArray[k]
            # print(RegisterArray)

            Barrier2.wait()
            if(Kill.value == 1):
                #           print("Bye - Reg Arr")
                return
        return

    # Additions for Prof. Biswas`s Requested Realtime IO Request Feature

        # IO_Interface_Update(IO_In,IO_Out,master)
    # End of Additions - CommandPaul

    @staticmethod
    def IOModule(ControlBits, InstructionRegister, IO_In, IO_Out, DataBus, Kill, Barrier1, Barrier2):
        # initialisation
        IO_In = [1, 3, 5, 7, 9, 11, 13, 15]
        IO_Out = [2, 4, 6, 8, 10, 12, 14, 16]
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            LOP = ControlBits[14]  # cached for Synchronous Protection
            REGSEL = InstructionRegister.value % 8  # cached for Synchronous Protection
            if(ControlBits[13] == b'1'):
                # Tkinter Code Here
                # interface = IO_Interface(IO_In,IO_Out)
                # interface.mainloop()
                # print(IO_In)
                DataBus.put(IO_In[REGSEL])  # IOs are Effectively Looped Back
            Barrier1.wait()
            # Synchronous Here after
            if(LOP == b'1'):
                # .value requirement ? Not Required :)
                IO_Out[REGSEL] = DataBus.get()
                #interface = IO_Interface(IO_In,IO_Out)
                # interface.mainloop()
                # print(IO_Out)
            Barrier2.wait()
            if(Kill.value == 1):
                return
        return

    @staticmethod
    def OperandRegisterModule(ControlBits, OperandRegister, DataBus, Kill, Barrier1, Barrier2):
        # initialisation
        OperandRegister.value = 0
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            LOR = ControlBits[16]  # cached for Synchronous Protection
            if(ControlBits[15] == b'1'):
                DataBus.put(OperandRegister.value)
            Barrier1.wait()
            # Synchronous Here after
            if(LOR == b'1'):
                # .value requirement ? Not Required :)
                OperandRegister.value = DataBus.get()
            Barrier2.wait()
            if(Kill.value == 1):
                return
        return

    @staticmethod
    def ALU_Module(ControlBits, DataBus, OperandRegister, InstructionRegister, CarryIn, AluOut, FlagRegister, Kill, Barrier1, Barrier2):
        # initialisation
        OperandRegister.value = 0
        ALU_imOut = c_int(0)
        FR = [1, 0, 0, 1, 1, 0, 0, 1]
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            SAL = ControlBits[17]  # cached for Synchronous Protection
            OpCode = InstructionRegister.value >> 4  # for faster Switch below :|
            # print(OpCode)
            if(SAL == b'1'):
                if (OpCode == 0):
                    ALU_imOut = 0
                else:
                    dataBus = DataBus.get()
                    OperandReg = OperandRegister.value
                    CarryIn = FR[2]
                    if (OpCode == 1):
                        ALU_imOut = dataBus
                    elif (OpCode == 2):
                        # the 1FF is maintainance of a design descision
                        ALU_imOut = (~dataBus & 0x1FF)
                    elif (OpCode == 3):
                        ALU_imOut = OperandReg
                    elif (OpCode == 4):
                        ALU_imOut = dataBus+1
                    elif (OpCode == 5):
                        ALU_imOut = dataBus-1
                    elif (OpCode == 6):
                        ALU_imOut = ((dataBus << 1)+CarryIn)
                    elif (OpCode == 7):
                        ALU_imOut = (((dataBus % 2) << 8) +
                                     (CarryIn << 7)+(dataBus >> 1))
                    elif (OpCode == 8):
                        ALU_imOut = dataBus+OperandReg
                    elif (OpCode == 9):
                        ALU_imOut = OperandReg-dataBus
                    elif (OpCode == 10):
                        ALU_imOut = dataBus+OperandReg+CarryIn
                    elif (OpCode == 11):
                        ALU_imOut = OperandReg-dataBus-CarryIn
                    elif (OpCode == 12):
                        ALU_imOut = dataBus & OperandReg
                    elif (OpCode == 13):
                        ALU_imOut = dataBus | OperandReg
                    elif (OpCode == 14):
                        ALU_imOut = dataBus ^ OperandReg
                    elif (OpCode == 15):
                        # the 1FF is maintainance of a design descision
                        ALU_imOut = ~(dataBus ^ OperandReg) & 0x1FF
                AluOut.value = ALU_imOut % 256
                ALU_imOut = ALU_imOut % 512

                # print(AluOut.value)
                # Flag Register Update #consoder making the flag pipe a queue
                #ALU_imOut = int(ALU_imOut)
                FR = [(ALU_imOut % 256 == 0), (ALU_imOut % 256 != 0), (ALU_imOut >= 256), not (ALU_imOut >= 256), ((((ALU_imOut % 256) & (1 << 7)) >> 7) == 0), ((
                    (~(ALU_imOut % 256) & (1 << 7)) >> 7) == 0), (single_bus_emulator.parityOf(ALU_imOut % 256) == 0), (single_bus_emulator.parityOf(ALU_imOut % 256) == 1)]
                for k in range(0, 8):
                    FlagRegister[k] = FR[k]
                # print("FLags")
                #print(FlagRegister[4],end = " ")
                # print(FlagRegister[5])
                #print("ALU OUT  == = == ",end = " ")
                #print(FR,end = " ")
                # print(ALU_imOut)
                #print([chr(ALU_imOut / 256), ~chr(ALU_imOut / 256), (ALU_imOut == 0), ~(ALU_imOut == 0),~(ALU_imOut & (1 << 7)), (~ALU_imOut & (1 << 7)), (parityof(ALU_imOut)),~(parityof(ALU_imOut))])
            Barrier1.wait()
            # Synchronous Here after
            # no regs and synchronous activity in the ALU module ?
            Barrier2.wait()
            if(Kill.value == 1):
                return
        return

    @staticmethod
    def StackPointerModule(ControlBits, DataBus, StackPointer, ProgramCounter, Kill, Barrier1, Barrier2):
        # initialisation read from file
        StackPointer.value = 0
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            DSP = ControlBits[8]  # cached for Synchronous Protection
            ISP = ControlBits[9]  # cached for Synchronous Protection
            # i deleted ESP when removing EPC
            if(ControlBits[7] == b'1'):
                DataBus.put(StackPointer.value)
            Barrier1.wait()
            # Synchronous Here after
            if(DSP == b'1' and ISP == b'0'):
                # .value requirement ? Not Required :)
                StackPointer.value = (StackPointer.value - 1) % 256
            if(ISP == b'1' and DSP == b'0'):
                # .value requirement ? Not Required :)
                StackPointer.value = (StackPointer.value + 1) % 256
            if(ISP == b'1' and DSP == b'1'):
                StackPointer.value = DataBus.get()
            Barrier2.wait()
            if(Kill.value == 1):
                return
        return

    @staticmethod
    def MemoryModule(ControlBits, ProgramCounter, RegisterArray, StackPointer, DataBus, Memory, Kill, Barrier1, Barrier2):
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            DSP = ControlBits[8]
            WR = ControlBits[1]  # cached for Synchronous Protection
            if(ControlBits[2] == b'1'):
                address = ProgramCounter.value
            elif(ControlBits[3] == b'1'):
                address = StackPointer.value if (
                    DSP == b'0') else (StackPointer.value - 1) % 256
            else:
                address = RegisterArray[0]
            if(ControlBits[0] == b'1'):
                DataBus.put(Memory[address])
            Barrier1.wait()
            # Synchronous Here after
            if(WR == b'1'):
                # value requirement ? Not Required :)
                Memory[address] = DataBus.get()
            Barrier2.wait()
            if(Kill.value == 1):
                # while(counter<256): # Persist Memory state at the end of the smulation This needs the correct operation of the step function
                #   outFile = open("memory.bin","w")
                #   output = bin(Memory[counter])[2:].zfill(8)
                #   outFile.write(output+"\n");
                #   counter = counter+1
                return
        return

    @staticmethod
    def ProgramCounterModule(ControlBits, ProgramCounter, OperandRegister, DataBus, Kill, Barrier1, Barrier2):
        # initialisation read from file
        ProgramCounter.value = 0
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            LPC = ControlBits[6]  # cached for Synchronous Protection
            IPC = ControlBits[5]  # cached for Synchronous Protection
            if(ControlBits[4] == b'1'):
                DataBus.put(ProgramCounter.value)
            Barrier1.wait()
            # Synchronous Here after
            if (LPC == b'1' and IPC == b'0'):
                # pdb.set_trace()
                # print(DataBus.get())
                # .value requirement ? Not Required :)
                ProgramCounter.value = DataBus.get()
            # print(ProgramCounter.value)
            elif(LPC == b'0' and IPC == b'1'):
                # .value requirement ? Not Required :)
                ProgramCounter.value = (ProgramCounter.value + 1) % 256
            elif(LPC == b'1' and IPC == b'1'):
                # .value requirement ? Not Required :)
                ProgramCounter.value = OperandRegister.value
            Barrier2.wait()
            #print("ProgramCounter ",end=" ")
            # print(ProgramCounter.value)
            if(Kill.value == 1):
                # print("Bye - pc")
                return
        return

    @staticmethod
    def InstructionRegister_Module(ControlBits, InstructionRegister, DataBus, IR_CCG, Kill, Barrier1, Barrier2):
        InstructionRegister.value = 0
        counter = 0  # Diagnostic For runtime counting
        Barrier2.wait()
        while(1):
            L_IR = ControlBits[10]  # cached for Synchronous Protection
            Barrier1.wait()
            if(L_IR == b'1'):
                InstructionRegister.value = DataBus.get()
                IR_CCG.put(InstructionRegister.value)
            Barrier2.wait()
            counter = counter + 1
            if(Kill.value == 1):
                #print("bye - ir")
                # print(counter)
                return
        return

    @staticmethod
    def ControlCodeGenerator(ControlBits, IR_CCG, FlagRegister, State, Kill, Barrier1, Barrier2):
        # initialisation read from file

        counter = 0
        IR = 0
        CCG_LUT = []
        FL = False
        # importlib.resources.path
        path = os.path.dirname(os.path.abspath(__file__))
        CCGConfFile = open(os.path.join(path, 'machCode.bin'))
        while(counter < 512):
            line = CCGConfFile.readline()
            Temp_Pointer = ctypes.create_string_buffer(line.encode())
            # (int(line,2)) # control bit arr append and read subsequent # Computationally less expensive eats memory :P
            CCG_LUT.append(Temp_Pointer)
            counter = counter+1

        # looks good :)
        State.value = 0
        ctypes.memmove(ControlBits, ctypes.create_string_buffer(
            b'1010010000100000000000'), 23)  # Essentially Initialise for fetch
        # print("CCG Init Complete")
        Barrier2.wait()
        # Setup Main Loop
        while(1):
            #print("0  , 1 , 2  , 3  , 4  , 5  , 6  , 7  , 8  , 9  , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 ")
            #print("RD , WR ,S_PC,S_SP,E_PC,I_PC,L_PC,E_SP,D_SP,I_SP,L_IR,E_FL,S_IF,E_IP,L_OP,E_OR,L_OR,S_AL,L_R0,E_R0,L_RN,E_RN")
            # for i in range(0,22):
            #   print(ControlBits[i],end=" ")
            # print(".")
            # cache existing control bbits and start acting on the same
            L_IR = ControlBits[10]  # cached for synchronousnous Protection
            E_FL = ControlBits[11]  # cached for Synchronous Protection
            S_IF = ControlBits[12]  # cached for Synchronous Protection
            # Selected Flag :P
            # Fetch Logic (FL + E FL ) * S IF = 1. Selected FLAg  ?
            # print(S_IF)
            if (E_FL == b'1'):
                FL = FlagRegister[IR % 8]

            FETCH = ((S_IF == b'1') and (
                (not (E_FL == b'1') or not(FL == True))))
            Barrier1.wait()
            # if fetch condition detected then wait on the queue to read form IR   Reset State and push th bits for fetch
            # else issue
            if(FETCH == 1):
                # print("Fetch")
                State.value = 0
                ctypes.memmove(ControlBits, ctypes.create_string_buffer(
                    b'1010010000100000000000'), 23)  # eqv of checking the CCG LUT for Space 0 :P
            else:
                # print("No_Fetch")
                if (L_IR == b'1'):
                    IR = IR_CCG.get()
                ctypes.memmove(ControlBits, CCG_LUT[IR*2 + State.value], 23)
                State.value = (State.value + 1) % 3

            Barrier2.wait()
            if(Kill.value == 1):
                # print("Bye - ccg")
                return
        return
    # opens control Code generator csv aand line by line reads the machine states
    # it then moves through the state machien and issues control codes on the
    #  0, 1 ,2  , 3  , 4  , 5  , 6  , 7  , 8  , 9  , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21
    # RD,WR,S_PC,S_SP,E_PC,I_PC,L_PC,E_SP,D_SP,I_SP,L_IR,E_FL,S_IF,E_IP,L_OP,E_OR,L_OR,S+_AL,L_R0,E_R0,L_RN,E_RN

    def __init__(self):
        counter = 0
        while(counter < 256):
            self.Memory[counter] = (int("00000000", 2))
            counter = counter+1
        # print("emulator instantiated")

    def load_memory(self, memory_bin):
        counter = 0
        self.memory_bin = memory_bin
        for line in self.memory_bin.splitlines():
            self.Memory[counter] = (int(line, 2))
            counter = counter+1
        while(counter < 256):
            self.Memory[counter] = (int("00000000", 2))
            counter = counter+1

    def start(self):
        # Thread Instantiation
        self.ThrCCG = Process(target=single_bus_emulator.ControlCodeGenerator, args=(
            self.ControlBits, self.IR_CCG, self.FlagRegister, self.State, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrIR = Process(target=single_bus_emulator.InstructionRegister_Module, args=(
            self.ControlBits, self.InstructionRegister, self.DataBus, self.IR_CCG, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrPC = Process(target=single_bus_emulator.ProgramCounterModule, args=(
            self.ControlBits, self.ProgramCounter, self.OperandRegister, self.DataBus, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrMEM = Process(target=single_bus_emulator.MemoryModule, args=(self.ControlBits, self.ProgramCounter,
                              self.RegisterArray, self.StackPointer, self.DataBus, self.Memory, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrRegArr = Process(target=single_bus_emulator.RegisterArrayModule, args=(
            self.ControlBits, self.DataBus, self.RegisterArray, self.InstructionRegister, self.AluOut, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrALU = Process(target=single_bus_emulator.ALU_Module, args=(self.ControlBits, self.DataBus, self.OperandRegister,
                              self.InstructionRegister, self.CarryIn, self.AluOut, self.FlagRegister, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrSPtr = Process(target=single_bus_emulator.StackPointerModule, args=(
            self.ControlBits, self.DataBus, self.StackPointer, self.ProgramCounter, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrOpReg = Process(target=single_bus_emulator.OperandRegisterModule, args=(
            self.ControlBits, self.OperandRegister, self.DataBus, self.Kill, self.Barrier1, self.Barrier2))
        self.ThrIO = Process(target=single_bus_emulator.IOModule, args=(self.ControlBits, self.InstructionRegister, self.IO_In,
                             self.IO_Out, self.DataBus, self.Kill, self.Barrier1, self.Barrier2))  # EDIT Regsel was not wired to the I0 Module

        # Reset Global State
        self.TraceVector.clear()
        self.Kill.value = 0
        self.ProgramCounter.value = 0
        self.StackPointer.value = 0
        for k in range(0, 8):
            self.RegisterArray[k] = random.randint(0, 255)
            self.IO_In[k] = 0
            self.IO_Out[k] = 0

        self.FlagRegister[0] = 1
        self.FlagRegister[1] = 0
        self.FlagRegister[2] = 0
        self.FlagRegister[3] = 1
        self.FlagRegister[4] = 1
        self.FlagRegister[5] = 0
        self.FlagRegister[6] = 0
        self.FlagRegister[7] = 1

        # RNBIP MicroArchitectural State
        self.DataBus = Queue()
        self.IR_CCG = Queue()
        #SelectedFlag = Queue()
        self.AluOut.value = 0
        self.AluOpcode.value = 0
        self.CarryIn.value = 0
        self.InstructionRegister.value = 0
        self.OperandRegister.value = 0
        self.State.value = 0
        ctypes.memmove(self.ControlBits, ctypes.create_string_buffer(
            b'1010010000100000000000'), 23)

        # Thread Start
        self.ThrCCG.start()
        self.ThrIR.start()
        self.ThrPC.start()
        self.ThrMEM.start()
        self.ThrRegArr.start()
        self.ThrALU.start()
        self.ThrSPtr.start()
        self.ThrOpReg.start()
        self.ThrIO.start()

    def trace_vector_append(self):
        # Arch State
        words = []
        flags = []
        regs = []
        IO_OUTPUT = []
        IO_INPUT = []
        for word in self.Memory:
            words.append(word)
        for flag in self.FlagRegister:  # ctype unpacking
            flags.append(flag == 1)
        for reg in self.RegisterArray:  # ctype unpacking
            regs.append(reg)
        for io_inB in self.IO_In:  # ctype unpacking
            IO_INPUT.append(io_inB)
        for io_outB in self.IO_Out:  # ctype unpacking
            IO_OUTPUT.append(io_outB)

        arch = Architectural_state(
            PC=self.ProgramCounter.value,
            SP=self.StackPointer.value,
            Registers=regs.copy(),
            Flags=flags.copy(),
            Memory=words.copy(),
            IO_In=IO_INPUT.copy(),
            IO_Out=IO_OUTPUT.copy())

        del words, flags, regs, IO_INPUT, IO_OUTPUT

        # March State
        control_bits = []
        for cbit in self.ControlBits:  # ctype unpacking
            control_bits.append(cbit == b'1')

        march = Microarchitectural_state(
            AluOut=self.AluOut.value,
            AluOpcode=self.AluOpcode.value,
            CarryIn=self.CarryIn.value,
            InstructionRegister=self.InstructionRegister.value,
            OperandRegister=self.OperandRegister.value,
            State=self.State.value,
            ControlBits=control_bits.copy())

        del control_bits

        self.TraceVector.append((arch, march))

    def step_n(self, Ncyc):
        N = Ncyc
        while(N > 0):
            self.Barrier2.wait()
            self.trace_vector_append()
            self.Barrier1.wait()
            N = N-1
        # self.Kill.value  = 1
        # print(self.Barrier2.n_waiting)
        # self.Barrier2.wait()
        # Barrier2.wait()
        #print("End Cycle")

    def end_emulation(self):
        self.Kill.value = 1
        self.Barrier2.wait()
        # Join threads and Prepare for Exit
        self.ThrCCG.join()
        self.ThrIR.join()
        self.ThrPC.join()
        self.ThrMEM.join()
        self.ThrRegArr.join()
        self.ThrALU.join()
        self.ThrSPtr.join()
        self.ThrOpReg.join()
        self.ThrIO.join()

        # self.DataBus.close()
        while(not self.DataBus.empty()):
            self.DataBus.get()
        # self.DataBus.join_thread()

        # self.IR_CCG.close()
        while(not self.IR_CCG.empty()):
            self.IR_CCG.get()
        # self.IR_CCG.join_thread()

        #print("No issue in init :D")
        # print (self.TraceVector)
