Scott Robison Posted April 19, 2021 Share Posted April 19, 2021 Is it just me, or is finding good samples of ca65 syntax really difficult? But I have, after a few hours, figured out how to write a 65c02 hello world application that uses JSRFAR to call the kernal, assembled it as a ROM image, appended it to the "stock roms", and poked a 7 byte stub at $0400, and used SYS 1024 to run my "ROM". Yay! Now to do something "useful" with this... 2 Quote Link to comment Share on other sites More sharing options...
evlthecat Posted April 19, 2021 Share Posted April 19, 2021 Congrats on the success! Quote Link to comment Share on other sites More sharing options...
SlithyMatt Posted April 19, 2021 Share Posted April 19, 2021 I just yesterday created a new macro to simplify JSRFAR on ca65: Quote JSRFAR_kernal_addr = $FF6E .macro JSRFAR far_sr_addr, bank jsr JSRFAR_kernal_addr .addr far_sr_addr .byte bank .endmacro Then you can just call JSRFAR like a function in your code, where $ABCD is the subroutine address and it sits in bank 42: Quote JSRFAR $ABCD, 42 2 1 Quote Link to comment Share on other sites More sharing options...
ZeroByte Posted April 19, 2021 Share Posted April 19, 2021 (edited) 31 minutes ago, SlithyMatt said: JSRFAR_kernal_addr = $FF6E .macro JSRFAR far_sr_addr, bank jsr JSRFAR_kernal_addr .addr far_sr_addr .byte bank .endmacro I've seen this kind of construct go by in several people's code lately. Just want to make sure my understanding of what's going on is correct: Normally, jsr pushes the PC onto the stack - which would be PC-> .addr far_sr_addr - but the code in JSRFAR (or any routine doing this trick) will at some point pull the PC off of the stack, use that as the address to read some arguments from, bump this value up by however many bytes of arguments were read (in this case, 3) and then push the new value back on the stack as if it were the original value pushed by JSR. This way, whenever the routine called by JSRFAR executes RTS, it doesn't come back and try to execute the .addr far_sr_addr as a command. Essentially, this is a "pass by value" way to pass parameters to a function - it's "by value" because the values are copied to a new location and those copies are used. In this case, the new location happens to be right in the middle of the code, and the values are a pointer (to a function) and an unsigned char. Is that about right? Edited April 19, 2021 by ZeroByte 1 Quote Link to comment Share on other sites More sharing options...
SlithyMatt Posted April 19, 2021 Share Posted April 19, 2021 2 minutes ago, ZeroByte said: Is that about right? Yes, that's correct. It's a bit of stack manipulation in the kernal JSRFAR subroutine -- so don't try to do additional stack manipulation unless you know what you're doing! 1 Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 19, 2021 Author Share Posted April 19, 2021 2 hours ago, SlithyMatt said: I just yesterday created a new macro to simplify JSRFAR on ca65: Then you can just call JSRFAR like a function in your code, where $ABCD is the subroutine address and it sits in bank 42: Since my code is executing out of a ROM, I can't JSRFAR into the kernal (I don't think) directly, so I copied the bjsrfar stub from the BASIC ROM so that I had my own entry point in my own ROM space. Really, most of my time was spent puzzling out how to get the right ca65 syntax for segments and configuration file. I have years of experience with assembly language on 6502 & x86, just not ca65. I do look forward to utilizing the macro features Real Soon Now(TM). Quote Link to comment Share on other sites More sharing options...
SlithyMatt Posted April 19, 2021 Share Posted April 19, 2021 (edited) 2 minutes ago, Scott Robison said: I can't JSRFAR into the kernal (I don't think) directly Correct, JSRFAR only works with the RAM banks. My repo here shows you how to do some other config magic, and it's going to be the subject of my next vlog coming out Thursday. Edited April 19, 2021 by SlithyMatt 1 Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 19, 2021 Author Share Posted April 19, 2021 1 minute ago, SlithyMatt said: Correct, JSRFAR only works with the RAM banks. My repo here shows you how to do some other config magic, and it's going to be the subject of my next vlog coming out Thursday. JSRFAR seems like it works for ROM, there is just a chicken and egg problem. JSRFAR is a kernal routine at $FF6E (which I have memorized for the moment after typing it in multiple times over the last 12 hours). Kernal is in ROM bank 0. My Hello World ROM is in ROM bank 7. I can't change the ROM bank while my code is executing in ROM without bad things happening, so I need a little helper function in my own ROM to get to the RAM entry point. My (almost completely worthless) code is below: .pc02 .code ldx #0 loop: lda message,x bne print rts print: jsr xjsrfar .word $FFD2 .byte 0 inx bra loop ; ----------------------------------------------------------------------------- ; code borrowed from BASIC ROM to support jsrfar to kernal ram_bank = 0 rom_bank = 1 .include "c:/dev/x16/x16-rom/inc/banks.inc" .export xjsrfar xjsrfar: .include "c:/dev/x16/x16-rom/inc/jsrfar.inc" ; ----------------------------------------------------------------------------- .rodata message: .asciiz "HELLO WORLD" Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 19, 2021 Author Share Posted April 19, 2021 2 hours ago, evlthecat said: Congrats on the success! Thanks! I'm debating several project ideas. 1. An "advanced" (for some concept of advanced) BASIC-like interpreter that supports a more structured language than Commodore BASIC 2. An emulator of some other computer. I feel like basic emulation of some 40 year old computers should be possible with 2+ MB of RAM and 16 KB of ROM 2 Quote Link to comment Share on other sites More sharing options...
ZeroByte Posted April 19, 2021 Share Posted April 19, 2021 You get the inception award if you can emulate a VIC-II + SID and C64 Kernal+BASIC on an X16, especially if it correctly runs any demoscene demos. 1 Quote Link to comment Share on other sites More sharing options...
rje Posted April 19, 2021 Share Posted April 19, 2021 (edited) What was going thru my head were earlier, simpler systems. KIM-1? Or something more exotic out of the 1970s. Would it be possible to emulate a PDP-8? Completely alien architecture... 4096 "words" of memory, where a "word" is 12 bits... strange... only 8 opcodes... eeek no, wrong direction by FAR too painfully simple. I think I'll read up on the Wikipedia entry for the PDP-11. Edited April 19, 2021 by rje Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 19, 2021 Author Share Posted April 19, 2021 1 hour ago, ZeroByte said: You get the inception award if you can emulate a VIC-II + SID and C64 Kernal+BASIC on an X16, especially if it correctly runs any demoscene demos. No way will I be trying for that level of emulation. My thought was to emulate an 8086 with simple INT interfaces that would allow a DOS COM file to be executed that didn't try for any fancy direct hardware access. Or a Timex Sinclair 1000. Strictly instruction level emulation of a CPU, no cycle accurate emulation. 1 Quote Link to comment Share on other sites More sharing options...
rje Posted April 19, 2021 Share Posted April 19, 2021 Ooooooh, an 8086/8088. Amusing!! And also a "neat" to the Sinclair. Quote Link to comment Share on other sites More sharing options...
Ed Minchau Posted April 19, 2021 Share Posted April 19, 2021 There is a bug in the JSRFAR subroutine. It works fine for ROM, but for RAM banks it returns the RAM bank number in the processor status register rather than the flags. 1 Quote Link to comment Share on other sites More sharing options...
Lorin Millsap Posted April 19, 2021 Share Posted April 19, 2021 There is a bug in the JSRFAR subroutine. It works fine for ROM, but for RAM banks it returns the RAM bank number in the processor status register rather than the flags.Good to know. Has anyone filed an official bug report for this?Sent from my iPhone using Tapatalk Quote Link to comment Share on other sites More sharing options...
Stefan Posted April 19, 2021 Share Posted April 19, 2021 Nice work! The thing I struggled the most with was proper interrupt handling. In a hello world that exits very quickly, chances are that you never have an interrupt during the ROM code execution. After all, there are 155,555 cycles per VBLANK at 8 Mhz. If your program runs for a longer period of time, you would, however, not want the interrupt vector in $fffe-ffff point to outer space, but to some code that handles interrupts. The solution is quite easy. Let $fffe-ffff in your ROM bank point to the KERNAL RAM code banked_irq. That is located at address $038b. Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 19, 2021 Author Share Posted April 19, 2021 12 minutes ago, Stefan said: Nice work! The thing I struggled the most with was proper interrupt handling. In a hello world that exits very quickly, chances are that you never have an interrupt during the ROM code execution. After all, there are 155,555 cycles per VBLANK at 8 Mhz. If your program runs for a longer period of time, you would, however, not want the interrupt vector in $fffe-ffff point to outer space, but to some code that handles interrupts. The solution is quite easy. Let $fffe-ffff in your ROM bank point to the KERNAL RAM code banked_irq. That is located at address $038b. Agreed. This was just to make sure I could write some "legitimate" asm, assemble it, link it, append it to the "blessed" roms, and do a JSRFAR into my bank. Now the real work begins. Like picking what project I want to work on. Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 19, 2021 Author Share Posted April 19, 2021 (edited) 2 hours ago, Lorin Millsap said: Good to know. Has anyone filed an official bug report for this? I just filed an issue, and am working on a PR. Edit: PR created and linked. Edited April 19, 2021 by Scott Robison Quote Link to comment Share on other sites More sharing options...
Ed Minchau Posted April 19, 2021 Share Posted April 19, 2021 4 hours ago, Lorin Millsap said: Good to know. Has anyone filed an official bug report for this? Sent from my iPhone using Tapatalk Yes, I filed a report a while ago. I don't see it getting fixed until Rev 39 is officially released. 1 Quote Link to comment Share on other sites More sharing options...
Scott Robison Posted April 20, 2021 Author Share Posted April 20, 2021 11 hours ago, rje said: What was going thru my head were earlier, simpler systems. KIM-1? Or something more exotic out of the 1970s. Would it be possible to emulate a PDP-8? Completely alien architecture... 4096 "words" of memory, where a "word" is 12 bits... strange... only 8 opcodes... eeek no, wrong direction by FAR too painfully simple. I think I'll read up on the Wikipedia entry for the PDP-11. Perhaps a 4004 emulator. That should be "easy". Quote Link to comment Share on other sites More sharing options...
ZeroByte Posted April 20, 2021 Share Posted April 20, 2021 (edited) Yaknow, Atari2600 might be doable because of how Stella worked. You’d have to be a mad genius of cycle exact coding though, because the 2600 was all about timing your code. Edited April 20, 2021 by ZeroByte Quote Link to comment Share on other sites More sharing options...
SlithyMatt Posted April 20, 2021 Share Posted April 20, 2021 1 hour ago, ZeroByte said: Yaknow, Atari2600 might be doable because of how Stella worked. You’d have to be a mad genius of cycle exact coding though, because the 2600 was all about timing your code. Not at full speed, but you could get some kind of emulation. Might work better to have the X16 transpile the 2600 ROM into a more native format -- convert all the TIA and RIOT load/stores to library subroutine calls. 1 Quote Link to comment Share on other sites More sharing options...
ZeroByte Posted April 20, 2021 Share Posted April 20, 2021 1 hour ago, SlithyMatt said: Might work better to have the X16 transpile the 2600 ROM into a more native format -- That's exactly what I was thinking. Make the loader go through and modify addresses as needed, etc. One thing I'd thought of would be to load the ROM to BANKRAM so that any carts which do bank swapping would actually behave the same way w/o any real work on the part of the X16. I hadn't thought of hooking TIA/RIOT with subroutine calls. That's a clever idea. I was thinking that since there're only a few graphic primatives that pretty much only exist in X coordinate space in TIA, it might be doable by using layers and scroll registers to set the X location... Quote Link to comment Share on other sites More sharing options...
SlithyMatt Posted April 20, 2021 Share Posted April 20, 2021 12 minutes ago, ZeroByte said: scroll registers to set the X location scroll registers won't help with the X location, that just going to have to be sprite placement. You can't have multiple scroll X-coordinates on the same line. This will be the hardest part -- converting the delays for X positioning. You'd have to analyze the code to determine when those X-placement TIA writes relative to the last known line start, then convert that into sprite X coordinates. Same with the Y -- count the lines for TIA writes and convert that into Y positioning and row data. Doing all this conversion on the X16 would be intense, but doable if you're patient for the transpiler to spend some time doing its conversion before running the ROM. If you just did the conversion on a modern PC, it would be instantaneous and you would have an X16 program that you could just load and run. Quote Link to comment Share on other sites More sharing options...
ZeroByte Posted April 20, 2021 Share Posted April 20, 2021 49 minutes ago, SlithyMatt said: You can't have multiple scroll X-coordinates on the same line. True, but I was thinking something along the lines of using both layers where L0 = sprite0 and L1 = sprite1, having only one tile in the top-left of each layer's tilemap, and writes to the sprite data register just re-write the first byte of the tile pixel map (which, conveniently, is just a single write because it's 1bpp) - not saying this is the best way at all - it's just what the idea was floating around in my head. Doubling or tripling sprites would just amount to putting 1 into a couple more tile slots (unless the spacing is variable, which I think it isn't). I'd use sprites for the ball and missiles - but thinking of it now, it seems using VERA sprites for the TIA sprites is the way to go anyway, because the tilemap is much more suited to emulating the playfield. It's crazy to think about writing a general-purpose algorithm to analyze a VCS game's kernal(s) and generate code that "just shows it" on VERA, but that's probably the best way to go. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.