' Digirule2 Source Code Version 1.0
' By Bradley Slattery 09 September 2018
'
' The Digirule2 is an open source 8-bit binary computer built into a PCB Ruler
' see bradsprojects.com for more details

' Setup type of chip and tell compiler the clock speed in Mhz
Device = 18F45K20           
Clock = 8

' Setup config options                      
Config FOSC = INTIO67   ' internal oscillator, I/O on PORTA pins 6 and 7       
Config MCLRE = OFF      ' disable external reset
Config boren = off      ' turn brown out detection

' write block size for the K20 (this is used for writing directly to program memory in the MemoryAccess.bas library)
#option ROM_BLOCK_SIZE = 16

' import library's                  
Include "MemoryAccess.bas"

'Port Setup  
Dim DataLEDs As PORTA  
Dim AddressLEDs As PORTD 
Dim DataInputButtons As PORTB                           
Dim ProgramCounterNextButton As PORTE.3 
Dim ProgramCounterPrevButton As PORTE.2 
Dim GotoAddressButton As PORTE.0
Dim RunStopButton As PORTC.0                
Dim RunStopLED As PORTC.3                 
Dim SaveGotoNextButton As PORTE.1
Dim EEPROMSaveButton As PORTC.4
Dim EEPROMLoadButton As PORTC.5

' Global Variables
Dim Stack As Byte                               
Dim CPUSpeed As Byte
Dim DataButtonsState As Byte
Dim OldDataButtonsState   As Byte 
Dim ButtonDelay As Word
Dim DataButtonAlreadyPressed As Byte
Dim ProgramCounterNextDelay As Word
Dim ProgramCounterPrevDelay As Word
Dim SaveGotoNextButtonPressDelay As Word
Dim ProgramCounter As Byte
Dim Accumulator As Byte
Dim StepProgramCounter As Boolean
Dim ShowDataAtAddress As Boolean
Dim ShowDataButtonStatus As Boolean
Dim RunProgramButtonAlreadyPressed As Boolean
Dim GotoAddressbuttonPressed As Boolean
Dim CPURunning As Boolean
Dim EEPROMLoadButtonIsPressed As Boolean 
Dim EEPROMSaveButtonIsPressed As Boolean
Dim ShowAddressLEDs As Boolean
Dim LedScannerPosition As Byte
Dim LedScannerGoingLeft As Boolean
Dim LedScannerSpeed As Byte

' Global Constants
Const ZeroFlag = 0
Const CarryFlag = 1
Const AddressLEDModeFlag = 2
Const StatusRegister = 252      ' bit 0 = zero flag, bit 1 = carry flag, bit 2 = function of address LED's
Const ButtonRegister = 253
Const AddressLEDRegister = 254
Const DataLEDRegister = 255

' Global Variable Arrays
Dim RAM(256) As Byte    ' Instructions and data are stored within this array

' Sub Routines
Sub CheckForZero(CheckThisNumber As Byte)   ' check if the number stored within a veriable is zero (or not) update the zero flag within the status register
    If CheckThisNumber = 0 Then
        RAM(StatusRegister).bits(ZeroFlag) = 1
    Else
        RAM(StatusRegister).bits(ZeroFlag) = 0
    EndIf
End Sub

Sub LEDScanner()    ' this is used when one of the EEPROM buttons is pressed - it will scan the ADDRESS and DATA LEDs left and right
    Dim Index As Byte
    For Index = 0 To 7
        If Index = LedScannerPosition Then
            DataLEDs.bits(Index) = 1
        Else
            DataLEDs.bits(Index) = 0     
        EndIf
    Next
    
    If LedScannerSpeed <> 0 Then
        Dec(LedScannerSpeed)
    Else 
        LedScannerSpeed = 50
        If LedScannerGoingLeft = true Then
            Inc(LedScannerPosition)
            If LedScannerPosition = 7 Then
                LedScannerGoingLeft = false
            EndIf
        Else
            Dec(LedScannerPosition)
            If LedScannerPosition = 0 Then
                LedScannerGoingLeft = true
            EndIf
        EndIf
    EndIf
End Sub

Sub UpdateLEDs()
    If EEPROMLoadButtonIsPressed = true Or EEPROMSaveButtonIsPressed = true Then    ' Load the scanner LED animation if one of the EEPROM buttons is pressed
        LEDScanner
    Else    ' otherwise, continue with showing the LEDs as normal depending on the CPU mode of operation
        If ShowAddressLEDs = true Then  ' we either show the program counter or the data stored within the AddressLEDRegister depending on the status of the AddressLEDModeFlag in the StatusRegister 
            If RAM(StatusRegister).bits(AddressLEDModeFlag) = 0 Or CPURunning = false Then
                AddressLEDs = ProgramCounter    
            Else
                AddressLEDs = RAM(AddressLEDRegister)
            EndIf
        Else    ' this is mainly used for the POV programs where you only want to see the DATA LED's showing any data - otherwise the image will not draw correctly
            AddressLEDs = 0
        EndIf
        
        If ShowDataAtAddress = true Then    ' we either show the data contained within the current program memory location OR we show the data containted within the DataLEDRegister
            If ShowDataButtonStatus = true Then
                DataLEDs = DataButtonsState
            Else
                DataLEDs = RAM(ProgramCounter)
            EndIf
        Else
            DataLEDs = RAM(DataLEDRegister)         
        EndIf
    EndIf
End Sub

Sub IncrementProgramCounter()
    UpdateLEDs 
    Inc(ProgramCounter)
    If CPUSpeed.bits(7) = 0 Then
        DelayUS(CPUSpeed * 7)
    Else
        DelayMS((CPUSpeed - 128) * 7)
    EndIf
End Sub

Sub SaveCodeToRAM()
    If SaveGotoNextButtonPressDelay <> 0 Then
        Dec(SaveGotoNextButtonPressDelay)
    Else
        If SaveGotoNextButton = 0 Then  
            ShowDataButtonStatus = false
            SaveGotoNextButtonPressDelay = 500
            RAM(ProgramCounter) = DataButtonsState
            Inc(ProgramCounter) 
            DataButtonsState = RAM(ProgramCounter)
        EndIf
    EndIf                 
End Sub

Sub WriteToProgramMemory(BlockToSave As Word)
    Dim Address As Word
    Dim MyIndex As Byte
   
    Address = $1500 + BlockToSave
    EraseBlock(Address)
    EraseBlock(Address + 64)
    EraseBlock(Address + 128)
    EraseBlock(Address + 192)
   
    For MyIndex = 0 To 255
        WriteAt(Address + MyIndex, RAM(MyIndex))
    Next
End Sub

Sub ReadFromProgramMemory(BlockToRead As Word)
    Dim Address As Word
    Dim MyIndex As Byte
   
    Address = $1500 + BlockToRead
    For MyIndex = 0 To 255
        RAM(MyIndex) = ReadByte(address + MyIndex)
    Next
End Sub


Sub HALT() ' Instruction 0 
    ShowDataAtAddress = true
    ShowAddressLEDs = true
    CPURunning = false 
    RunStopLED = 0        
    DataButtonsState = RAM(ProgramCounter)
End Sub  

Sub NOP() ' Instruction 1
    IncrementProgramCounter    
End Sub

Sub SPEED() ' Instruction 2
    IncrementProgramCounter
    CPUSpeed = RAM(ProgramCounter)
    IncrementProgramCounter
End Sub

Sub COPYLR() ' Instruction 3
    Dim TempByte As Byte
    IncrementProgramCounter
    TempByte = RAM(ProgramCounter)
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)) = TempByte
    IncrementProgramCounter
End Sub

Sub COPYLA() ' Instruction 4
    IncrementProgramCounter           
    Accumulator = RAM(ProgramCounter)                                                     
    IncrementProgramCounter            
End Sub

Sub COPYAR() ' Instruction 5
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)) = Accumulator
    IncrementProgramCounter
End Sub

Sub COPYRA() ' Instruction 6
    IncrementProgramCounter                    
    Accumulator = RAM(RAM(ProgramCounter))     
    CheckForZero(Accumulator)
    IncrementProgramCounter                      
End Sub

Sub COPYRR() ' Instruction 7
    Dim TempByte As Byte                    
    IncrementProgramCounter                    
    TempByte = RAM(RAM(ProgramCounter))     
    IncrementProgramCounter                 
    RAM(RAM(ProgramCounter)) = TempByte      
    CheckForZero(RAM(RAM(ProgramCounter)))  
    IncrementProgramCounter                 
End Sub

Sub ADDLA() ' Instruction 8
    IncrementProgramCounter                            
    If Accumulator + RAM(ProgramCounter) > 255 Then    
        RAM(StatusRegister).bits(CarryFlag) = 1
    Else
        RAM(StatusRegister).bits(CarryFlag) = 0
    EndIf
    Accumulator = Accumulator + RAM(ProgramCounter)
    CheckForZero(Accumulator)
    IncrementProgramCounter
End Sub

Sub ADDRA() ' Instruction 9     
    IncrementProgramCounter                     
    If Accumulator + RAM(RAM(ProgramCounter)) > 255 Then  
        RAM(StatusRegister).bits(CarryFlag) = 1
    Else
        RAM(StatusRegister).bits(CarryFlag) = 0
    EndIf
    Accumulator = Accumulator + RAM(RAM(ProgramCounter))   
    CheckForZero(Accumulator)
    IncrementProgramCounter                            
End Sub

Sub SUBLA() ' Instruction 10
    IncrementProgramCounter                            
    If RAM(ProgramCounter) > Accumulator  Then    
        RAM(StatusRegister).bits(CarryFlag) = 1
    Else
        RAM(StatusRegister).bits(CarryFlag) = 0
    EndIf
    Accumulator = Accumulator - RAM(ProgramCounter)   
    CheckForZero(Accumulator)
    IncrementProgramCounter                           
End Sub

Sub SUBRA() ' Instruction 11
    IncrementProgramCounter                             
    If RAM(RAM(ProgramCounter)) > Accumulator Then    
        RAM(StatusRegister).bits(CarryFlag) = 1
    Else
        RAM(StatusRegister).bits(CarryFlag) = 0
    EndIf
    Accumulator = Accumulator - RAM(RAM(ProgramCounter))   
    CheckForZero(Accumulator)
    IncrementProgramCounter                             
End Sub

Sub ANDLA() ' Instruction 12
    IncrementProgramCounter                            
    Accumulator = Accumulator And RAM(ProgramCounter)
    CheckForZero(Accumulator)
    IncrementProgramCounter
End Sub

Sub ANDRA() ' Instruction 13
    IncrementProgramCounter                           
    Accumulator = Accumulator And RAM(RAM(ProgramCounter))     
    CheckForZero(Accumulator)
    IncrementProgramCounter                              
End Sub

Sub ORLA() ' Instruction 14
    IncrementProgramCounter                               
    Accumulator = Accumulator Or RAM(ProgramCounter)      
    CheckForZero(Accumulator)
    IncrementProgramCounter
End Sub

Sub ORRA() ' Instruction 15
    IncrementProgramCounter                            
    Accumulator = Accumulator Or RAM(RAM(ProgramCounter))    
    CheckForZero(Accumulator)
    IncrementProgramCounter
End Sub

Sub XORLA() ' Instruction 16
    IncrementProgramCounter                           
    Accumulator = Accumulator Xor RAM(ProgramCounter)  
    CheckForZero(Accumulator)
    IncrementProgramCounter                            
End Sub

Sub XORRA() ' Instruction 17
    IncrementProgramCounter                            
    Accumulator = Accumulator Xor RAM(RAM(ProgramCounter))   
    CheckForZero(Accumulator)
    IncrementProgramCounter                         
End Sub

Sub DECR()  ' Instruction 18
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)) = RAM(RAM(ProgramCounter)) - 1
    CheckForZero(RAM(RAM(ProgramCounter))) 
    IncrementProgramCounter       
End Sub

Sub INCR() ' Instruction 19
    IncrementProgramCounter 
    RAM(RAM(ProgramCounter)) = RAM(RAM(ProgramCounter)) + 1
    CheckForZero(RAM(RAM(ProgramCounter))) 
    IncrementProgramCounter       
End Sub

Sub DECRJZ() ' Instruction 20
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)) = RAM(RAM(ProgramCounter)) - 1
    CheckForZero(RAM(RAM(ProgramCounter)))
    If RAM(StatusRegister).bits(ZeroFlag) = 1 Then 
        ProgramCounter = ProgramCounter + 3
    Else
        IncrementProgramCounter
    EndIf              
End Sub

Sub INCRJZ() ' Instruction 21
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)) = RAM(RAM(ProgramCounter)) + 1
    CheckForZero(RAM(RAM(ProgramCounter)))
    If RAM(StatusRegister).bits(ZeroFlag) = 1 Then   
        ProgramCounter = ProgramCounter + 3
    Else
        IncrementProgramCounter
    EndIf        
End Sub

Sub SHIFTRL() ' Instruction 22
    Dim TempBit As Bit
    Dim TempByte As Byte
    IncrementProgramCounter
    TempByte = RAM(RAM(ProgramCounter)) 
    TempBit = TempByte.bits(7)
    RAM(RAM(ProgramCounter)) = TempByte << 1
    RAM(RAM(ProgramCounter)).bits(0) = RAM(StatusRegister).bits(CarryFlag)
    RAM(StatusRegister).bits(CarryFlag) = TempBit
    IncrementProgramCounter            
End Sub

Sub SHIFTRR() ' Instruction 23
    Dim TempBit As Bit
    Dim TempByte As Byte
    IncrementProgramCounter
    TempByte = RAM(RAM(ProgramCounter)) 
    TempBit = TempByte.bits(0)
    RAM(RAM(ProgramCounter)) = TempByte >> 1
    RAM(RAM(ProgramCounter)).bits(7) = RAM(StatusRegister).bits(CarryFlag)
    RAM(StatusRegister).bits(CarryFlag) = TempBit
    IncrementProgramCounter           
End Sub

Sub CBR()   ' Instruction 24
    Dim TempByte As Byte
    IncrementProgramCounter
    TempByte = RAM(ProgramCounter)
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)).bits(TempByte) = 0
    IncrementProgramCounter
End Sub

Sub SBR()   ' Instruction 25
    Dim TempByte As Byte
    IncrementProgramCounter
    TempByte = RAM(ProgramCounter)
    IncrementProgramCounter
    RAM(RAM(ProgramCounter)).bits(TempByte) = 1
    IncrementProgramCounter
End Sub

Sub BCRSC() ' Instruction 26
    Dim TempByte1 As Byte
    Dim TempByte2 As Byte
    IncrementProgramCounter
    TempByte1 = RAM(ProgramCounter)
    IncrementProgramCounter
    TempByte2 = RAM(RAM(ProgramCounter))
    IncrementProgramCounter
    If TempByte2.bits(TempByte1) = 0 Then
        IncrementProgramCounter
        IncrementProgramCounter
    EndIf
End Sub

Sub BCRSS() ' Instruction 27
    Dim TempByte1 As Byte
    Dim TempByte2 As Byte
    IncrementProgramCounter
    TempByte1 = RAM(ProgramCounter)
    IncrementProgramCounter
    TempByte2 = RAM(RAM(ProgramCounter))
    IncrementProgramCounter
    If TempByte2.bits(TempByte1) = 1 Then
        IncrementProgramCounter
        IncrementProgramCounter
    EndIf
End Sub

Sub JUMP() ' Instruction 28
    IncrementProgramCounter                
    ProgramCounter = RAM(ProgramCounter) 
End Sub

Sub CALL() ' Instruction 29
    IncrementProgramCounter
    Stack = ProgramCounter + 1
    ProgramCounter = RAM(ProgramCounter)
End Sub

Sub RETLA() ' Instruction 30
    IncrementProgramCounter
    Accumulator = RAM(ProgramCounter)
    ProgramCounter = Stack
End Sub

Sub RETURN() ' Instruction 31
    ProgramCounter = Stack
End Sub

Sub ADDRPC() ' Instruction 32
    ProgramCounter = ProgramCounter + RAM(RAM(ProgramCounter + 1))
End Sub

Sub CPULoop()
    Select RAM(ProgramCounter)
        Case 0 HALT           ' Stop the CPU from running - performs the same function as pressing the run/stop button (1 byte)
        Case 1 NOP            ' No operation (1 byte)
        Case 2 SPEED          ' Set the CPU speed - the higher the number the SLOWER the CPU speed (2 bytes)
        Case 3 COPYLR         ' Copy literal value to register (3 bytes)
        Case 4 COPYLA         ' Copy literal value to accumulator (2 bytes)
        Case 5 COPYAR         ' Copy contents of accumulator to register (2 bytes)  
        Case 6 COPYRA         ' Copy contents of register to accumulator (2 bytes) 
        Case 7 COPYRR         ' Copy contents of register to register (2 bytes) 
        Case 8 ADDLA          ' Add literal value to accumulator and store result in accumulator (2 bytes)
        Case 9 ADDRA          ' Add contents of register to accumulator and store result in accumulator (2 bytes)     
        Case 10 SUBLA         ' Subtract literal value from accumulator and store result in accumulator (2 bytes)
        Case 11 SUBRA         ' Subtract contents of register from accumulator and store result in accumulator (2 bytes)  
        Case 12 ANDLA         ' AND literal value with accumulator and store result in accumulator (2 bytes)     
        Case 13 ANDRA         ' AND contents of register with accumulator and store result in accumulator (2 bytes)   
        Case 14 ORLA          ' OR literal value with accumulator and store result in accumulator (2 bytes)     
        Case 15 ORRA          ' OR contents of register with accumulator and store result in accumulator (2 bytes)   
        Case 16 XORLA         ' Exclusive OR literal value with accumulator and store result in accumulator (2 bytes) 
        Case 17 XORRA         ' Exclusive contents of register with accumulator and store result in accumulator (2 bytes)
        Case 18 DECR          ' Decrement the contents of register (2 bytes)       
        Case 19 INCR          ' Increment the contents of register (2 bytes)
        Case 20 DECRJZ        ' Decrement the contents of register and then skip the next two lines of code IF the result is ZERO (3 bytes)
        Case 21 INCRJZ        ' Increment the contents of register and then skip the next two lines of code IF the result is ZERO (3 bytes)
        Case 22 SHIFTRL       ' Shift contents of register left by one (2 bytes)
        Case 23 SHIFTRR       ' Shift contents of register right by one (2 bytes)
        Case 24 CBR           ' Clear specific bit within register (3 bytes)
        Case 25 SBR           ' Set specific bit within register (3 bytes)
        Case 26 BCRSC         ' Check specific bit within register and skip the next two lines of code IF the bit is a ZERO (3 bytes) 
        Case 27 BCRSS         ' Check specific bit within register and skip the next two lines of code IF the bit is a ONE (3 bytes) 
        Case 28 JUMP          ' Jump to specific line of code (2 bytes)
        Case 29 CALL          ' Jump to specific line of code, then return once that code is completed (2 bytes)
        Case 30 RETLA         ' Return from a call instruction with 1 byte of data stored in the accumulator (2 bytes)
        Case 31 RETURN        ' Return from a call instruction (1 byte)
        Case 32 ADDRPC        ' Add the number contained within a register to the program counter  (2 bytes)          
    EndSelect        
End Sub

Sub CheckButtons()
    Dim Index As Byte
    Dim Index2 As Byte
    
    ' check the run/stop button
    If RunStopButton = 0 Then
        If RunProgramButtonAlreadyPressed = false Then
            RunProgramButtonAlreadyPressed = true
            If CPURunning = false Then
                RAM(DataLEDRegister) = 0    
                ShowDataAtAddress = false
                CPURunning = true
                RunStopLED = 1
            Else
                HALT
            EndIf
        EndIf
    Else
        RunProgramButtonAlreadyPressed = false
    EndIf
    
    ' check the goto button to toggle the showaddressled flag
    If CPURunning = true Then
        If GotoAddressButton = 0 Then
            If GotoAddressbuttonPressed = false Then
                GotoAddressbuttonPressed = true
                If ShowAddressLEDs = true Then
                    ShowAddressLEDs = false
                Else
                    ShowAddressLEDs = true
                EndIf
            EndIf
        Else
            GotoAddressbuttonPressed = false
        EndIf
        
        ' copy the state of the input buttons to the ButtonRegister (we XOR it ith %11111111 because the button is a zero when it is pressed, but we want the button register to hold one's to indicate a pressed button
        RAM(ButtonRegister) = DataInputButtons Xor %11111111
    Else    ' if the CPU is not running - we will check all of these other buttons
    
        ' check data buttons - they will toggle when pressed
        If ButtonDelay <> 0 Then
            Dec(ButtonDelay)
        Else
            For Index = 0 To 7
                If DataInputButtons.bits(Index) = 0 Then
                    ButtonDelay = 500
                    If DataButtonAlreadyPressed.bits(Index) = 0 Then
                        ShowDataButtonStatus = true
                        DataButtonAlreadyPressed.bits(Index) = 1
                        DataButtonsState.bits(Index) = DataButtonsState.bits(Index) Xor %1
                    EndIf
                Else
                    DataButtonAlreadyPressed.bits(Index) = 0    
                EndIf
            Next
        EndIf
        
        ' check goto button
        If GotoAddressButton = 0 Then
            If GotoAddressbuttonPressed = false Then
                GotoAddressbuttonPressed = true
                ShowDataButtonStatus = false
                ProgramCounter = DataButtonsState
                DataButtonsState = RAM(ProgramCounter)
            EndIf
        Else
            GotoAddressbuttonPressed = false    
        EndIf
    
        ' check the increment and decrement buttons
        If ProgramCounterNextDelay <> 0 Then
            Dec(ProgramCounterNextDelay)
        Else
            If ProgramCounterNextButton = 0 Then
                ShowDataButtonStatus = false
                ProgramCounterNextDelay = 500
                Inc(ProgramCounter)         
                DataButtonsState = RAM(ProgramCounter)
            EndIf
        EndIf
        If ProgramCounterPrevDelay <> 0 Then
            Dec(ProgramCounterPrevDelay)
        Else
            If ProgramCounterPrevButton = 0 Then
                ShowDataButtonStatus = false
                ProgramCounterPrevDelay = 500
                Dec(ProgramCounter)     
                DataButtonsState = RAM(ProgramCounter)
            EndIf
        EndIf
        
        ' now check the save / load eeprom buttons (there are four seperate blocks for saving and loading eeprom data (4 blocks of 256 bytes) these are set by switch 0 and 1
        If EEPROMLoadButton = 0 Then
            EEPROMLoadButtonIsPressed = true
            For Index = 0 To 7
                If DataInputButtons.bits(Index) = 0 Then
                    ReadFromProgramMemory(Index * 256) ' we multiply by 256 here because we store data in 256 byte blocks
                    DataLEDs = 0
                    For Index2 = 0 To 7
                        DataLEDs.bits(Index) = 1
                        DelayMS(100)
                        DataLEDs.bits(Index) = 0
                        DelayMS(100)
                    Next
                    DataButtonsState = RAM(ProgramCounter)    
                EndIf
            Next
        Else
            EEPROMLoadButtonIsPressed = False
        EndIf 
        
        If EEPROMSaveButton = 0 Then
            EEPROMSaveButtonIsPressed = true
            For Index = 0 To 7
                If DataInputButtons.bits(Index) = 0 Then
                    WriteToProgramMemory(Index * 256) ' we multiply by 256 here because we store data in 256 byte blocks
                    DataLEDs = 0
                    For Index2 = 0 To 7
                        DataLEDs.bits(Index) = 1
                        DelayMS(100)
                        DataLEDs.bits(Index) = 0
                        DelayMS(100)
                    Next
                    DataButtonsState = RAM(ProgramCounter)    
                EndIf
            Next 
        Else
            EEPROMSaveButtonIsPressed = False
        EndIf      
    EndIf 
End Sub

Sub Setup()
    Dim Index As Byte
    ' Oscillator setup
    OSCCON = %01100000          ' device enters sleep on IDLE, 8Mhz Clock,   
    OSCTUNE = %00000000         ' Internal oscillator low freq comes from 31Khz clock from LFINTOSC, PLL disabled
    
    ' Analog / Digital pins setup
    ANSEL = %00000000          ' disable all analog inputs 
    ANSELH = %00000000         ' disable all analog inputs 
    
    ' setup weak pullups on PORTB (which is the only port with weak pullups)
    INTCON2.bits(7) = 0 ' this must be a 0 to enable the weak pullups in DataInputButtons
    WPUB = %11111111    ' now that we have enabled pullups in intcon2, we have to specify which ones using wpub register
    
    ' Tristate setup
    TRISA = %00000000
    TRISB = %11111111
    TRISC = %11110111
    TRISD = %00000000
    TRISE = %0111  ' TRISE bit 4 is used to select between standard I/O and parallel port mode. Since we want pins 0, 1 and 2 to be standard - we need bit 4 to be a logic 0

    ' variable setup
    For Index = 0 To Bound(RAM)
        RAM(Index) = 0
    Next
    ProgramCounter = 0
    DataButtonAlreadyPressed = 0
    ButtonDelay = 500
    ProgramCounterNextDelay = 500
    ProgramCounterPrevDelay = 500
    SaveGotoNextButtonPressDelay = 500
    DataButtonsState = 0
    OldDataButtonsState = DataButtonsState
    DataLEDs = 0
    AddressLEDs = 0
    RunStopLED = 0
    DataButtonsState = 0
    DataButtonsState = 0
    ShowDataAtAddress = true  
    StepProgramCounter = false  
    CPURunning = false        
    ShowDataButtonStatus = false  
    RunProgramButtonAlreadyPressed = false 
    GotoAddressbuttonPressed = false
    CPUSpeed = 1
    EEPROMLoadButtonIsPressed = false
    EEPROMSaveButtonIsPressed = false
    CPUSpeed = 0
    ShowAddressLEDs = true
    Stack = 0
    Accumulator = 0
    LedScannerPosition = 0
    LedScannerGoingLeft = true
    LedScannerSpeed = 100
    
    ' startup animation
    For Index = 0 To 7
        DataLEDs.bits(Index) = 1
        AddressLEDs.bits(7 - Index) = 1
        DelayMS(100)
        DataLEDs.bits(Index) = 0
        AddressLEDs.bits(7 - Index) = 0
    Next
    For Index = 7 To 0 Step -1
        DataLEDs.bits(Index) = 1
        AddressLEDs.bits(7 - Index) = 1
        DelayMS(100)
        DataLEDs.bits(Index) = 0
        AddressLEDs.bits(7 - Index) = 0
    Next
End Sub 

' Start Of Program - this is where we setup everything before getting into the main loop
Setup

' Main Loop
While true
    If CPURunning = true Then   ' code to run if the CPU is running
        CPULoop 
        CheckButtons
    Else                        ' code to run if the CPU is not running
        CheckButtons
        SaveCodeToRAM  
    EndIf
    UpdateLEDs
Wend 
 
