The VICE monitor - part IV: Program execution and changing registers
By Spiro Trikaliotis on Saturday, October 6 2007, 15:53 - VICE - Permalink
Being able to read and write memory contents, disassembling and using lables is a good thing when it comes to use a monitor. Anyhow, in many cases, you want to change the execution of a program. This is what a debugger is really like, and how you do this is covered in this part.
This part will also cover how to specify and convert numbers in different number systems (decimal, hexadecimal, octal, binary).
First of all, I must apologize for not writing for so long. I was short on time, thus, I was not able to do this before. I am trying to write more articles as time permits. This is the first one of more to come.
Starting execution at a memory address
The go (g) command is the easiest of the ones I will describe in this part of the sequel. It is used when you want to execute your own program. its help text looks like follows:
(C:$e5d4) ? g Syntax: goto <address> Abbreviation: g Change the PC to ADDRESS and continue execution (C:$e5d4)
It's easy, isn't it? You might remember the good old "SYS 64738" command which seems to reset your C64. You can use this command from the BASIC command line, or you can enter it in the monitor.
Assume you have some program loading which does not return to the BASIC command-line. To reset it, you can do the following: Enter the monitor (Alt+M in the Windows version of VICE), and enter:
(C:$e5d4) ? g +64738
The monitor will immediately exit, and you will see the left and rights borders of the C64 screen getting smaller for some seconds. Afterwards, your emulated C64 will look as if it was just started.
Of course, you could also have used the (virtual) RESET button of VICE to reset the machine (Alt+R on the Windows version of VICE), but this was not the point of this blog entry.
You might have noticed the "+" in the command-line above. This tells the VICE monitor that the number afterwards is written in decimal, not in hexadecimal. Normally, all numbers are given in hexadecimal, unless specified otherwise. The "+" specifies otherwise, in this case, decimal.
Thus, you could have achieved the same effect with the command
(C:$e5d4) ? g fce2
as $FCE2 is the same 64738. You are not convinced? You can let the monitor do the conversion for you:
(C:$e5cf) ~ +64738 +64738 $fce2 0176342 11111100 11100010 (C:$e5cf)
Here, the monitor outputs the number you have given (64738 in decimal) into all number systems it knows about: Decimal (+), hexadecimal ($), octal, and binary. The key to this conversion is the command ").
Of course, if I convert the hexadecimal value FCE2, I get the same output:
(C:$e5cf) ~ fce2 +64738 $fce2 0176342 11111100 11100010 (C:$e5cf)
Note that the command, the monitor tells you how to specify decimal numbers: With the plus (+) sign.
Modifying registers
Now, we know how to start a program at a given location. Sometimes, you also want to be able to change some register values before this. This can be done with the registers command. Its online help is as follows:
(C:$fd83) ? r Syntax: registers <reg_name> = <number> [, <reg_name> = <number>*] Abbreviation: r Assign respective registers. With no parameters, display register values. (C:$fd83)
So, we have two ways to use it: "registers" without any parameter just outputs the current register values:
(C:$fd83) registers ADDR AC XR YR SP 00 01 NV-BDIZC LIN CYC .;fd83 ff ff fe fd 2f 37 10100101 000 000 (C:$fd83)
So, we see that currently, the Accu is $FF, X is $FF, Y is $FE, the stack pointer (SP) is $FD, and the flags. The VICE monitor also outputs additional information. I will skip these additional values "00", "01", "LIN" and "CYC", which are not present with most other monitors, here.
Now, assume we want to change the value of a register. For this, we can use the registers command and assign a value to the register we want. For example, we can change the value of the accu (AC) to $46 by issuing
(C:$fd83) r A=46
That's all! You can verify that the change took effect by having a look at the registers again:
(C:$fd83) r ADDR AC XR YR SP 00 01 NV-BDIZC LIN CYC .;fd83 46 ff fe fd 2f 37 10100101 000 000 (C:$fd83)
You see that AC has changed its value.
Oh... Now, you are surprised? You used the name "A" in the command, but the output is "AC"? Yes, this is an inconsistency, and I do not like it, either. But that's the way it is currently.
Even worse, it is not always obvious which name to use to assign a register a value. You must use other names that are output. As I am searching for the names myself quite a lot (by having a look into the VICE sources!), I made a list for you:
- the accu (AC) is "A"
- the X register (XR) is "X"
- the Y register (YR) is "Y"
- the program counter (ADDR) is "PC"
- the stack pointer (SP) is "SP"
You see, only the stack pointer has the abbreviation that is output by the registers command itself! Furthermore, notice that you can not change the status registers (at least, not that I know of - and I have looked at the sources)
Of course, with this info, it is easy to mimic the effect of "g fce2":
(C:$fd83) r PC=fce2 (C:$fd83) r ADDR AC XR YR SP 00 01 NV-BDIZC LIN CYC .;fce2 46 ff fe fd 2f 37 10100101 000 000 (C:$fd83) x
As with "g fce2", the C64 is reset with this sequence of commands.
Ok, can we do something more interesting than resetting the machine with these commands? Yes, we can. You might know the following BASIC command sequence to output something to a given position on the screen:
POKE 214,Y:POKE 211,X:SYS 58732
We can mimic this behaviour without problems. First, let's have a look into the routine at +58732:
(C:$e595) d +58732 .C:e56c A6 D6 LDX $D6 .C:e56e A5 D3 LDA $D3 .C:e570 B4 D9 LDY $D9,X .C:e572 30 08 BMI $E57C .C:e574 18 CLC .C:e575 69 28 ADC #$28 .C:e577 85 D3 STA $D3 .C:e579 CA DEX
Wow... It directly performs some calculations. While the routine is not very hard to understand, it is out of the scope of this blog entry here. Of course, we could write the Y position into +214 ($D6) and the X position into +211 ($D3), but this way, I would not be able to tell you how to use the registers command. Instead, let's have a look into the KERNAL routine (PLOT, $FFF0) which calls our routine at $E56C (58732) at some time:
(C:$0019) d fff0 .C:fff0 4C 0A E5 JMP $E50A
... Ok, it jumps directly to $E50A, so let's have a look there:
(C:$fff3) d e50a .C:e50a B0 07 BCS $E513 .C:e50c 86 D6 STX $D6 .C:e50e 84 D3 STY $D3 .C:e510 20 6C E5 JSR $E56C .C:e513 A6 D6 LDX $D6 .C:e515 A4 D3 LDY $D3 .C:e517 60 RTS
What is the BCS for? The PLOT kernal routine can be used for two purposes: If the Carry flag is set, it reads out the current position (and the X position is given in Y, and the Y position in X (sic!)). If the carry flag is not set, the current position is changed to the position given by the X register and the Y register. The BCS in $E50A distinguished between both uses. It is a scheme found rather commonly in the Commodore KERNAL.
As I already told, I do not know how to clear the carry flag. Thus, to be sure, we will just jump to $E50C with the X and the Y register properly set:
(C:$e534) r X=5 (C:$e534) r Y=7 (C:$e534) g e50c
But what is this? When you execute these lines, your C64 will NOT position the cursor to line 5, column 7. Instead, it output a screen that looks like you have pressed Run/STOP+Restore:

Why does this happen? Don't the commands work as I told you?
I can assure you, they work as advertised. The problem is another one, we will try to find it out and the next part of this sequel...
Comments
What are the LIN and CYC registers for? Maybe you can explain them in one of the next articles?
thx
-Darkstar