aboutsummaryrefslogtreecommitdiff
path: root/u.s
diff options
context:
space:
mode:
Diffstat (limited to 'u.s')
-rw-r--r--u.s199
1 files changed, 199 insertions, 0 deletions
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
+ ldx #>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