| |
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 |
|
... 5 posts hidden. Click here to view all posts.... |
| |
tlr
Registered: Sep 2003 Posts: 1787 |
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: 1787 |
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: 1787 |
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 ;) |
| |
Pex Mahoney Tufvesson
Registered: Sep 2003 Posts: 52 |
Your slideshow is awesome, simply awesome! Congratulations on a world's first in 2013! This is one for the history books! :-D
---
Have a noise night!
http://mahoney.c64.org |
| |
tlr
Registered: Sep 2003 Posts: 1787 |
Hehe, thanks! :)
I'm sure something more radical could be done with similar techniques. |
| |
Zyron
Registered: Jan 2002 Posts: 2381 |
So much new amazing things still happening in the world of c64 coding it's insane! |
| |
Mr. SID
Registered: Jan 2003 Posts: 424 |
Awesome idea! |
| |
tlr
Registered: Sep 2003 Posts: 1787 |
@mahoney: Perhaps you should try to define your original rules a bit more stringenly?
It would be fun to try to do something more flexible. :)
Your original rules aren't too bad as is actually. Executing BASIC code is actually implicitly disallowed via the code execution restriction because it relies on executing CHRGET/CHRGOT at $0073 in zp.
The main thing that is unclear is what piece of RAM you may modify.
You could say $0000-$0400 but that is a bit harsh restriction on e.g screen mem.
You could say that ROM, e.g $ffd2, may modify RAM outside $0000-$0400 but that is kind of pointless because all code executed is ROM code.
How about allowing read/write to all RAM?
If the $0000-$0400 RAM write restriction is to be kept, can the initial LOAD still load any amount of RAM? |
Previous - 1 | 2 - Next |