Vic Wolf
Moderator: Moderators
- Kweepa
- Vic 20 Scientist
- Posts: 1315
- Joined: Fri Jan 04, 2008 5:11 pm
- Location: Austin, Texas
- Occupation: Game maker
It's not so much what's missing, just how clunky it is.Kananga wrote:What's missing from VICE's debugger that you urgently need?
Importing symbols. I don't even know how to do it, or if it's possible with output from CBM Prg Studio.
Setting and clearing breakpoints is not a one click/one keypress operation. Setting initial breakpoints when the game starts is very irritating, unless I've missed that in the docs.
There isn't an "auto/locals" window (which would display whatever memory the nearby instructions are operating on).
Code: Select all
lda $20 [$20 = 0xfe / 254]
[A = 0xf7 / 248]
ldx ($88),y [$88/9 = 0x1e00]
[Y = 0x02 / 2 / 'B']
[$1e02 = 0x01 / 1 / 'A']
[X = 0x60 / 96 / '+']
The biggest problem I have is that I am using callbacks and pushing the return address on the stack manually. VICE's step over function matches JSR and RTS calls, rather than just setting a temporary breakpoint on the return address, so if I try to step over a function that uses the callback, the debugger stops after the callback's RTS. I can work around it by rewriting the code to JMP to the return address at the end of the callback instead of using RTS, but it's a pain.
Code: Select all
callbackfn:
lda #40
sta $1e00,x
rts
funcwithcallback:
ldx #100
loop:
lda #<returnaddress-1
pha
lda #>returnaddress-1
pha
jmp (callbackfnaddress)
returnaddress:
dex
bne loop
rts
...
lda #<callbackfn
sta callbackfnaddress
lda #>callbackfn
sta callbackfnaddress+1
jsr funcwithcallback // can't step over this - the PC ends up at returnaddress
...
- Mike
- Herr VC
- Posts: 4845
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
How about using the following construct instead? By the way, what you're using is a vectored function call, not a callback. Callbacks are done by the OS on exit of an interrupt or kernal call in case a non-reentrant routine is necessary to perform work requested within an interrupt server. That also means the routine called back is usually at the same hierarchy level than the foreground process, which is clearly not the case with your 'callbackfn' - it is still two levels below the main function.Kweepa wrote:Code: Select all
callbackfn: lda #40 sta $1e00,x rts funcwithcallback: ldx #100 loop: lda #<returnaddress-1 pha lda #>returnaddress-1 pha jmp (callbackfnaddress) returnaddress: dex bne loop rts ... lda #<callbackfn sta callbackfnaddress lda #>callbackfn sta callbackfnaddress+1 jsr funcwithcallback // can't step over this - the PC ends up at returnaddress
Code: Select all
vectoredfn:
lda #40
sta $1e00,x
rts
funcwithvectoredfn:
ldx #100
loop:
jsr trampoline
dex
bne loop
rts
trampoline:
jmp (fnvector)
...
lda #<vectoredfn
sta fnvector
lda #>vectoredfn
sta fnvector+1
jsr funcwithvectoredfn
Greetings,
Michael
- Kweepa
- Vic 20 Scientist
- Posts: 1315
- Joined: Fri Jan 04, 2008 5:11 pm
- Location: Austin, Texas
- Occupation: Game maker
Tomato, tomatoe
http://en.wikipedia.org/wiki/Callback_% ... ramming%29
If callback is redefined by the kernal, then phooey to it.
Thanks for the suggestion! I'll just self-modify the inner JSR, to avoid the trampoline. Saves a couple of bytes and a few cycles
http://en.wikipedia.org/wiki/Callback_% ... ramming%29
If callback is redefined by the kernal, then phooey to it.
Thanks for the suggestion! I'll just self-modify the inner JSR, to avoid the trampoline. Saves a couple of bytes and a few cycles
- Mike
- Herr VC
- Posts: 4845
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
As long as there is only one JSR into the sub-routine you can do that, of course. The trampoline allows for several 'users' of the vectored sub-routine, and you can have the vector in RAM, while the code is in ROM.I'll just self-modify the inner JSR, to avoid the trampoline.
Actually, the spelling of kern_a_l in my posting above was a typo - I really meant kern_e_l as the core of an OS in general, and not only the CBM one. Again, Callbacks are issued by the kernel or an interrupt routine to do work which requires the kernel has been threaded out before, so there are no issues with non re-entrant routines.
That mechanism requires that the kernel knows exactly when it is about to re-enter the user program, with enabled interrupts, and nothing in the stack still amounts to kernel processing. In that situation, and when a callback is requested, the kernel jumps to the callback routine first, which itself now is able to do operations on the same hierarchy level than the user program, and which then handles control over to the user program by popping its address off stack and jumping to that again. The CPU should feature privileged modes, and the kernel needs to hold a semaphor to implement this efficiently.
And here is one more construct I've used myself when setup time is significant (for example executing virtual machine instructions where the actual function does very little). It loses its advantage if you often call the same function repeatedly.Mike wrote:How about using the following construct instead?
Code: Select all
vectoredfn:
lda #40
sta $1e00,x
rts
...
lda #VFN0_ID
jsr trampolineA ; call function defined in register A
...
jsr trampoline ; call function defined earlier
...
trampolineA
sta trampoline+1
trampoline:
jmp (fntable)
fntable:
dc.w vectoredfn, vectoredfn2, ...
The above is ROMable if you copy trampoline code to RAM, 5 or 6 bytes depending on whether you can sacrifice 5 zero page locations or not.
- Kweepa
- Vic 20 Scientist
- Posts: 1315
- Joined: Fri Jan 04, 2008 5:11 pm
- Location: Austin, Texas
- Occupation: Game maker
Very interesting, thanks!
I'm not sure it works as coded here - there seems to be something missing in trampolineA. [EDIT] Ok, I understand now. Durrr. [/EDIT]
I considered using a table of functions too, although like this:
Obviously this would only be a size saving if I call funcwithcallback several times. I currently have two different funcwithcallbacks, one called 3 times, and one 4, so it's a marginal saving.
I'm not sure it works as coded here - there seems to be something missing in trampolineA. [EDIT] Ok, I understand now. Durrr. [/EDIT]
I considered using a table of functions too, although like this:
Code: Select all
callbackfn1:
lda #40
sta $1e00,x
rts
funcwithcallback:
lda functable,y
sta loop+1
lda functable+1,y
sta loop+2
ldx #100
loop:
jsr $1000
dex
bne loop
rts
...
ldy #(2*funcindex)
jsr funcwithcallback
...
functable:
word callbackfn1, callbackfn2, ...