| |
Paulko64
Registered: Jul 2010 Posts: 24 |
How to correctly use KERNAL routines from a cartridge?
Hi there,
The last couple of days I've been struggling heavily to get the Kernal SCNKEY routine to work correctly when called from a cartridge build. I think I maybe missed something crucial in the memory init or something, but I can't figure out what I'm doing wrong. Perhaps somebody here can help me.
My cartridge starts with:
.word launcher
.word launcher
.byte $c3 ;c
.byte $c2 ;b
.byte $cd ;m
.byte $38 ;8
.byte $30 ;0
launcher sei
cld
ldx #$ff
txs
jsr $ff84 ;init I/O
ldx #$17
lda #$00
lp1 sta $d400,x ;clear SID registers
dex
bpl lp1
tay ;(A still contains zero)
lp2 sta $0002,y
sta $0200,y
sta $0300,y ;clear a bunch of low-memory locations
iny
bne lp2
tax
ldy #$a0
jsr $fd8c ;init system constants (without the ram-test)
jsr $ff8a ;restore kernal vectors
jsr $ff81 ;init screen editor
cli
ldx #$fb
txs
Then I copy all my code to RAM, disable the cartridge, and start my game from RAM. The above is enough to get my game running. However, when I try to access the kernal with the following part, it does not register any keys pressed:
lda #%00110110 ;enable kernal
sta $01
jsr SCNKEY ;read keyboard
lda #%00110101 ;disable kernal
sta $01
It should put the current key pressed in $0277, but there is nothing there. When starting the SAME build from the prompt, i.e. without copying first from cartridge it works correctly!
I already checked that all relevant ZP and $02XX adresses are set correctly. So I'm kind of lost here, maybe someone has some ideas?
Thanks,
Paul |
|
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Your code works here, i only added a copy-to-ram loop, a cli before the jsr SCNKEY, an sei after it, and a jmp back to the kernal enable.
Pressing a few keys will fill the keyboard buffer at $0277 just fine.
I suspect the error to be somewhere in the game code.
So maybe your game changes things to the worse only when run from cartridge.
Can you provide a minimal non-working cartridge image? |
| |
6R6
Registered: Feb 2002 Posts: 245 |
At the end of the source you change zeropage $01 to 35. That turns off basic+kernal rom and will trigger the irq vector at $fffe/$ffff. And if that vector has not been properly set up you should get a break crash or a jam.
[edit] Krill's suggestion works, but by setting up the $fffe vector you dont have to use sei and cli when changing $01. |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
I suspect the game is already in a state advanced enough to tell a crash from a non-working subroutine. :) |
| |
Paulko64
Registered: Jul 2010 Posts: 24 |
Thanks for the suggestions. After commenting out some routines I found the problem.
After the above memory-setup routine and before copying the game to RAM I had also included a logo with a colorram fill routine. I didn't nicely end filling the collorram at $dbff, but I went some bytes beyond it, probably corrupting some CIA adresses. Now the game itself does not use any CIA stuff, except for the keyboard read part!
Somehow I always end up with these bugs were one routine corrupts another routine which is not used untill much later, so that I never suspect that they are correlated :(
Anyway, back to coding again.
Thanks again! |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: Thanks for the suggestions. After commenting out some routines I found the problem.
After the above memory-setup routine and before copying the game to RAM I had also included a logo with a colorram fill routine. I didn't nicely end filling the collorram at $dbff, but I went some bytes beyond it, probably corrupting some CIA adresses. Now the game itself does not use any CIA stuff, except for the keyboard read part!
Somehow I always end up with these bugs were one routine corrupts another routine which is not used untill much later, so that I never suspect that they are correlated :(
Anyway, back to coding again.
Thanks again!
That's life without an MMU and an OS that creates non-writable executable pages for you... :) Otoh you get the powah' of self modifying code! :D |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
Quoting JackAsserThat's life without an MMU and an OS that creates non-writable executable pages for you... :) Otoh you get the powah' of self modifying code! :D
An MMU isn't really guaranteed to save you at the hardware register level though. If you're lucky you could guard different pieces of hardware from each other but it's not going to be funny to switch contexts inside timed 6502 code. ;) |
| |
Pex Mahoney Tufvesson
Registered: Sep 2003 Posts: 52 |
MMU destroys most of the fun there is in hacking. I'm thinking of making a return-oriented programming demo contest on the c64 aka "iOS jailbreak demo compo" - something for Gubbdata 2013, maybe? :-D
Rules:
1. You're not allowed to execute any assembly code or BASIC program from RAM. (read: execution prevention bit).
2. You're not allowed to modify any RAM address from your code (read: MMU + sandbox) - except the stack & HW/OS registers.
3. You must find a kernel bug that allows you to run a "demo" anyway.
4. Jailbreak may be initiated with LOAD "demo",8,1 - nothing else.
Yes, it can be done. The title of this discussion thread is a hint for you.
---
Have a noise night!
http://mahoney.c64.org |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
Quoting Pex Mahoney TufvessonRules:
1. You're not allowed to execute any assembly code or BASIC program from RAM. (read: execution prevention bit).
2. You're not allowed to modify any RAM address from your code (read: MMU + sandbox) - except the stack & HW/OS registers.
3. You must find a kernel bug that allows you to run a "demo" anyway.
4. Jailbreak may be initiated with LOAD "demo",8,1 - nothing else.
So what you are saying is execution must be done by letting some rom code (e.g kernal) be an unintentional interpreter, but specifically disallowing the built in basic functionality? In addition it may only write ram in the area $0000-$0333? (minus $02a7-$02ff?) + I/O regs.
I guess it should be possible but the rules need to be much more strictly defined for a compo to make sense.
|
| |
Pex Mahoney Tufvesson
Registered: Sep 2003 Posts: 52 |
Sure, these rules are not strict enough - you're right, tlr.
By overwriting the return address from the loader in the stack, you can "jump" to any place in basic/kernal. And when that piece of code is done, you better have another "RTS" or "RTI" address ready for what piece of ROM code to execute.
I've almost completed a "set the border colour to black" routine this way. Printing something to the screen is probably easier that writing to D000-registers, though.
$01ed-$01f7 are overwritten/trashed by the disk loader.
$01f8 and $01f9 contains the return address when loading is done. Direct this to your kernel rom code of choice.
$01fa and $01fb will be the next RTS address, if the code you jumped to does RTS at the end.
Fortunately, the stack wraps when it is empty, so there an astonishing 200 bytes left for return addresses! :-D
---
Have a noise night!
http://mahoney.c64.org |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
You can do an "IFFL" slideshow by loading $cc00-$ffff, then wrapping to $0000 upto $ae/$af where you overwrite your pointer to go back to $cbb0... et voila.
explanation:
1. load screen ram at $cc00 to $cfe8
2. setup $d000 regs for bitmap display
2.5 optionally setup wrooam sound as you pass $d400.
3. load $d800 color ram.
4. load $dd00 to set vbank.
5. load $e000-$ff40 bitmap
6. wrap to overwrite $ae/$af -> $cbb0
7. go to 1.
Of course you need to pay attention not to destructively change the value of any I/O registers you pass.
It would even allow to set up a few sprites according on what combination you can make the IEC loader tolerate.
Pretty slow though. :)
EDIT: couldn't resist it, there: Nocode-slide ;) |
... 5 posts hidden. Click here to view all posts.... |
Previous - 1 | 2 - Next |