aboutsummaryrefslogtreecommitdiff
path: root/u.s
blob: f9e91c45c8c68a343af31862b618e8fae23638db (plain)
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