From 2c420394ee7a5d177e2485828c4fdb4dd35a28f8 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sat, 10 Dec 2022 18:08:27 -0500 Subject: Initial commit. --- u.s | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 u.s (limited to 'u.s') diff --git a/u.s b/u.s new file mode 100644 index 0000000..f9e91c4 --- /dev/null +++ b/u.s @@ -0,0 +1,199 @@ +; Tool for controlling tf_hh's SRAM upgrade (512K v4.5, or 576K v2 for 600XL). + +; Gets built with various defines, see README.txt. Non-coldstart +; builds can be prepended to another .xex file to set the upgrade's +; mode automatically when that .xex is loaded. + +; Reverse-engineered by disassembling setmem.xex. + +; Note that the upgrade's mode can *only* be changed while the +; Start key is held down, so this can't be 100% non-interactive. + + .include "atari.inc" + .include "xex.inc" + + .include "ver.s" + + .ifndef magic_value + .error "You must define magic_value to 0, 1, or 2." + .endif + + .define rambo_msg "for 512K/RAMBO mode" + .define compy_msg "for 256K/Compy mode" + .define disable_msg "to disable memory upgrade" + + .if magic_value = 0 + .ifdef reverse_logic + .define mode_msg compy_msg + .define xex_name "U256R" + .else + .define mode_msg rambo_msg + .define xex_name "U512" + .endif + .else + .if magic_value = 1 + .define mode_msg disable_msg + .define xex_name "UOFF" + .else + .if magic_value = 2 + .ifdef reverse_logic + .define mode_msg rambo_msg + .define xex_name "U512R" + .else + .define mode_msg compy_msg + .define xex_name "U256" + .endif + .else + .error .sprintf("Invalid magic_value (must be 0, 1, or 2, not %d)", magic_value) + .endif + .endif + .endif + + .out .sprintf("Using magic_value %d, message '%s'", magic_value, mode_msg) + + loadaddr = $8000 + + magic_register = $d3f3 + + xex_org loadaddr + + ; runaddr is fake (just an RTS), put here so the tool can be run + ; standalone under "smart" DOSes like SDX that want to jump to the + ; load address. +runaddr: rts + +magic_bits: .byte magic_value + +prompt_msg: + .byte xex_name + .ifdef coldstart + .byte "X" + .endif + .byte " v", VERSION, " by Urchlay", $9b, $9b, "Press Start ", mode_msg + .ifdef coldstart + .byte $9b, "The Atari will reboot!", $9b + .byte "Press any other key to abort.", $9b + .endif + .byte 0 + +;;; subroutines + +printchr: ; print character in A register. + tay ; save A (character to print). + lda ICPTH ; set up stack, so it looks like a JSR to the + pha ; put-one-byte address for E:, + lda ICPTL ; which the OS has conveniently stashed + pha ; in IOCB #0. + tya ; restore A (put-one-byte argument). + rts ; "return" to put-one-byte, which will return to printchr's caller. + +printmsg: ; print message pointed to by A/X + sta FR0 + stx FR0+1 + lda #0 + sta FR0+2 +pmloop: + ldy FR0+2 + lda (FR0),y + beq pmdone + jsr printchr + inc FR0+2 + bne pmloop +pmdone: + rts + +; wait for CONSOL to equal A +waitconsol: + cmp CONSOL + bne waitconsol + ; a bit of debouncing... + sta WSYNC + sta WSYNC + sta WSYNC + sta WSYNC + cmp CONSOL + bne waitconsol + rts + +;;; main program + +entrypoint: + ; print our prompt + lda #prompt_msg + jsr printmsg + +.if 0 + ; no idea why setmem.xex clicks the console speaker... + lda #8 + sta CONSOL +.endif + + ; just in case: make sure Start's not being held down. + lda #7 + jsr waitconsol + + ; save previous contents of PBCTL and PORTB. diddling $d3f3 + ; affects PBCTL whether Start is held down or not... and + ; changing PBCTL crashes SpartaDOS X. + ldx PBCTL + ldy PORTB + + ; wait for the user to press Start. can't skip this, the magic + ; register can only be updated when Start is pressed. +.ifdef coldstart + ; if the user presses any regular key, exit the program without + ; changing modes or rebooting. + lda #$ff + sta CH +waitkey: + lda CH + cmp #$ff + beq wk_chkstart + lda #$ff + sta CH + rts +wk_chkstart: + lda CONSOL + cmp #6 + bne waitkey +.else + lda #6 + jsr waitconsol +.endif + + ; disable both IRQ and NMI interrupts. + sei + lda #0 + sta NMIEN + + ; update the magic, the same way setmem.xex does. + lda magic_register + and #$fc + ora magic_bits + sta magic_register + + ; original code waits for the user to release the Start key before + ; re-enabling interrupts. I don't think this matters, but I'll do it. + lda #7 + jsr waitconsol + + ; restore previous PIA contents. + stx PBCTL + sty PORTB + + ; re-enable interrupts and exit. + lda #$40 + sta NMIEN + cli + +.ifdef coldstart + jmp COLDSV +.else + rts +.endif + + xex_run runaddr + + ; the real work gets done by an init routine. + xex_init entrypoint -- cgit v1.2.3