Saturday, October 27, 2018

Debugging commands

This leaves us with only two commands remaining. The BRK is a software interrupt, while the NOP command does nothing. Doing nothing is a handy thing as we will discuss shortly.
As mentioned in the previous article, when an IRQ happens, the processor stops what it is doing and executes the interrupt handler. BRK issues an IRQ but unlike a normal IRQ this one is not maskable so will always occur. This results in the code continuing execution at the address that is stored in $FFFE-$FFFF. On early computer systems this was set up to be a special machine language debugging program called a monitor. This allowed the programmer to scatter BRK statements through their code which would trigger the monitor when they were reached. The monitor would display status information about the program and let the programmer issue debugging commands for doing things such as changing the values in memory, changing the execution address, or continuing the program right after the break point.

When a programmer was finished with a specific BRK statement, they would simply replace the value at that location with $EA which is the OPCode for NOP. In other words, in the early days break points were coded into a program!

As if removing break points from a program wasn’t a good enough reason to have the NOP command, it also takes two cycles to execute. This means that if you have timing critical parts of your program you can use NOP instructions as padding to get the right timing. With the 2600, timing is very important so this is not something to be taken for granted.

Testing was a bit tricky for implementing these instructions. Making sure that the NOP was timing correctly probably didn’t need testing as that is handled by the emulator but as the operation of the TIA chip requires precise timing making sure cycles are working important so for these tests run until a cycle is reached instead of until a break is reached. This is kind of required as testing the break does require that the break command actually get executed!

Address Mode
Decimal OPCode
Hexadecimal OpCode
Flags affected: I
Usage: Triggers the Break interrupt causing the program to start executing code from the address stored at $FFFE-$FFFF. Used for debugging with the IRQ address set to a monitor program.
Test Code:
; BRK  -> requires IRQ set to 512, cycles = 71
            LDX #255 ; 2
            TXS     ; 4
loop: BRK        ; 11, 33, 55, END
            ; start here with 22, 44, 66
            INX ; 24, 46, 68
            JMP loop   ;27, 49, 71
.ORG 512
            ; reach here at 11, 33, 55
            TAY  ; 13, 35, 57
            TXA  ; 15, 37, 59
            RTI ; 22, 44, 66
            ;x=2, y = 0, A = 1

pushByteOnStack((state.ipNext / 256) and 255)
pushByteOnStack(state.ipNext and 255)
pushByteOnStack(state.flags or BREAK_FLAG or INTERRUPT_FLAG)
state.ipNext = findAbsoluteAddress(0xfffd)

NOPNo OPeration
Address Mode
Decimal OPCode
Hexadecimal OpCode
Flags affected: None
Usage: This command tends to be used for debugging to replace BRK instructions. It can be used in timing sensitive programs as a 2 cycle delay.
Test Code:
; NOP -> run for 32 cycles
            LDX #0            ;2
            loop: NOP  ; 4, 15, 26
            NOP                ; 6, 17, 28
            NOP                ; 8, 19, 30
            INX                  ; 10, 21, 32
            BNE loop   ;13, 24
            ; expect at 32 cycles for x=3

No comments:

Post a Comment