1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
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
|