1 | ; FLASH GORDON driver
|
---|
2 | ; Copyright 2012, Adrien Destugues <pulkomandy@gmail.com>
|
---|
3 | ; This program is distributed under the terms of the MIT licence
|
---|
4 |
|
---|
5 | GLOBAL _start
|
---|
6 |
|
---|
7 | ; Friendly firmware functions
|
---|
8 | getc EQU 0xBB06
|
---|
9 | putc EQU 0xBB5A
|
---|
10 | screenmem EQU 0xBC08
|
---|
11 |
|
---|
12 |
|
---|
13 | ; FIXME the plan is to have the same file behave both as a ROM and as an
|
---|
14 | ; executable, so it can bootstrap itself into the megaflash. So we should start
|
---|
15 | ; with a standard ROM header. RSXs to expose are :
|
---|
16 | ; |BURN,"file",n (load file to &4000, then copy it to ROM n)
|
---|
17 | ; |HIDE,n (write a FF as first byte in ROM to hide it from firmware)
|
---|
18 | ; |HIDE (hides all ROMs)
|
---|
19 | ; |SHOW,n (restore ROM n to visible state
|
---|
20 | ; |SHOW (shows all ROMs)
|
---|
21 | ; |KILL,n (erases ROM n)
|
---|
22 |
|
---|
23 | ; This is the entry point when running as a standalone file
|
---|
24 | _start
|
---|
25 | ; Ask the user to allow us to write to the flash memory
|
---|
26 | LD HL,MSG_WRITE_START
|
---|
27 | CALL puts
|
---|
28 | CALL getc
|
---|
29 | ; From there on, writing is enabled. This is ok as long as we don't
|
---|
30 | ; connect a writable ROM ! When we do, we have to make sure NOTHING
|
---|
31 | ; is read written from 8000-FFFF because the MegaFlash hardware
|
---|
32 | ; doesn't decode A14 and will answer for the whole 32k range. This
|
---|
33 | ; means, no use of firmware jumpblocks, and the stack needs to be
|
---|
34 | ; moved elsewhere
|
---|
35 |
|
---|
36 | DI
|
---|
37 | ; Move the stack away from the $8000-$FFFF area, since any write there
|
---|
38 | ; will be intercepted by the Megaflash (it does not decode A14).
|
---|
39 | LD (stack),SP
|
---|
40 | LD SP,0x7FFF
|
---|
41 |
|
---|
42 | ; Save the interrupt vector and replace it with EI/RET
|
---|
43 | LD HL,(0x38)
|
---|
44 | LD (inthandle),HL
|
---|
45 | LD HL,0xC9FB
|
---|
46 | LD (0x38),HL
|
---|
47 |
|
---|
48 | ; TODO get the ROM number to burn somehow ?
|
---|
49 | ; (we can get it as a CALL parameter)
|
---|
50 |
|
---|
51 | CALL ERASE
|
---|
52 | CALL WRITE
|
---|
53 |
|
---|
54 | ; Disconnect the Megaflash
|
---|
55 | LD BC,0xDFFF
|
---|
56 | OUT (C),C
|
---|
57 |
|
---|
58 | ; Restore the firmware in working order now that we are done
|
---|
59 | LD SP,(stack)
|
---|
60 | LD HL,(inthandle)
|
---|
61 | LD (0x38),HL
|
---|
62 | EI
|
---|
63 |
|
---|
64 | ; Tell firmware to draw the screen at &4000 (so we don't erase the
|
---|
65 | ; ROM with the next message...)
|
---|
66 | LD A,0x40
|
---|
67 | CALL screenmem
|
---|
68 |
|
---|
69 | LD HL,MSG_WRITE_END
|
---|
70 | CALL puts
|
---|
71 | ; Wait for key
|
---|
72 | CALL 0xBB06
|
---|
73 |
|
---|
74 | ; Put screen back at normal address
|
---|
75 | LD A,0xC0
|
---|
76 | CALL screenmem
|
---|
77 |
|
---|
78 | ; TODO cleanly get out (and handle both calls by RUN and CALL)
|
---|
79 | JR $
|
---|
80 |
|
---|
81 | ; Erase a 16K ROM. Input:
|
---|
82 | ; A - ROM number to erase (TODO)
|
---|
83 | ; Assumes we are in write mode, interrupts disabled.
|
---|
84 | ERASE
|
---|
85 | LD B,4
|
---|
86 | eraseloop
|
---|
87 | PUSH BC
|
---|
88 |
|
---|
89 | LD A, 0x80 ; ERASE
|
---|
90 | CALL send_command
|
---|
91 |
|
---|
92 | CALL prepare_command
|
---|
93 |
|
---|
94 | LD B,0xDF
|
---|
95 | LD C,5 ; ROM number to write (FIXME get it as a RSX param)
|
---|
96 | OUT (C),C
|
---|
97 |
|
---|
98 | ; Compute address near start of sector
|
---|
99 | POP BC
|
---|
100 | LD A,B
|
---|
101 | DEC A
|
---|
102 | SLA A
|
---|
103 | SLA A
|
---|
104 |
|
---|
105 | ADD 0xC0
|
---|
106 |
|
---|
107 | LD H,A
|
---|
108 | LD L,0
|
---|
109 |
|
---|
110 | ; Sector erase command
|
---|
111 | LD E, 0x30
|
---|
112 | LD (HL), E
|
---|
113 |
|
---|
114 | ; This will delay long enough - we need at least 20ms
|
---|
115 | EI
|
---|
116 | HALT
|
---|
117 | HALT
|
---|
118 | HALT
|
---|
119 | HALT
|
---|
120 | HALT
|
---|
121 | HALT
|
---|
122 | HALT
|
---|
123 | DI
|
---|
124 |
|
---|
125 | DJNZ eraseloop
|
---|
126 |
|
---|
127 | RET
|
---|
128 |
|
---|
129 |
|
---|
130 | ; Write a 16K ROM
|
---|
131 | ; IN: A - ROM number to write (TODO)
|
---|
132 | ; &2000 - Data to copy (TODO let the caller put that in IX maybe ?)
|
---|
133 | ; Assumes we are in write-enabled mode (TODO)
|
---|
134 | WRITE
|
---|
135 | ; Ok, now that we erased the 4 sectors we needed, we can write data to them
|
---|
136 | LD HL, 0xC000
|
---|
137 | LD IX, 0x2000
|
---|
138 | PROGRAM
|
---|
139 | PUSH HL
|
---|
140 |
|
---|
141 | LD A, 0xA0 ; BYTE PROGRAM
|
---|
142 | CALL send_command
|
---|
143 |
|
---|
144 | POP HL
|
---|
145 |
|
---|
146 | LD B,0xDF
|
---|
147 | LD C,5 ; ROM number to write (FIXME get it as a RSX param)
|
---|
148 | OUT (C),C
|
---|
149 |
|
---|
150 | LD A,(IX + 0)
|
---|
151 | LD (HL),A ; Write occurs here. Need to wait 20 NOPs before next
|
---|
152 | ; operation on ROM. Our code is slow enough already !
|
---|
153 |
|
---|
154 | INC IX
|
---|
155 | INC HL
|
---|
156 |
|
---|
157 | ; As INC HL doesn't update the flags, check if we overflowed yet
|
---|
158 | LD A,H
|
---|
159 | OR L
|
---|
160 |
|
---|
161 | JR NZ, PROGRAM
|
---|
162 |
|
---|
163 | RET
|
---|
164 |
|
---|
165 | ; Helper routines -----------------------------------------------------
|
---|
166 |
|
---|
167 | ; Send a command to the ROM. The available commands are :
|
---|
168 | ;ERASE equ 0x80
|
---|
169 | IDENTIFY equ 0x90
|
---|
170 | BYTEPROG equ 0xA0
|
---|
171 | RESET equ 0xF0
|
---|
172 |
|
---|
173 | ; Input: Commend to send in A register
|
---|
174 | send_command:
|
---|
175 | ; That code is shared with sector erase which has some tricks
|
---|
176 | call prepare_command
|
---|
177 |
|
---|
178 | ; Select ROM 1 again and write the command to address 0xEAAA
|
---|
179 | DEC C
|
---|
180 | OUT (C),C
|
---|
181 | EX DE,HL
|
---|
182 | LD (HL), A
|
---|
183 |
|
---|
184 | ; Select ROM 0xFF, which basically prevents future accesses to get to the
|
---|
185 | ; Flash chip.
|
---|
186 | DEC C
|
---|
187 | DEC C
|
---|
188 | OUT (C),C
|
---|
189 |
|
---|
190 | RET
|
---|
191 |
|
---|
192 | prepare_command:
|
---|
193 | ; Select ROM 1
|
---|
194 | LD BC,0xDF01
|
---|
195 | LD HL,0xD555
|
---|
196 | LD DE,0xEAAA
|
---|
197 |
|
---|
198 | ; Select ROM 1 and write 0xAA to address 0xD555
|
---|
199 | OUT (C),C
|
---|
200 | LD (HL),E
|
---|
201 |
|
---|
202 | ; Select ROM 2 and write 0x55 to address 0xEAAA
|
---|
203 | INC C
|
---|
204 | OUT (C),C
|
---|
205 | EX DE,HL
|
---|
206 | LD (HL), E
|
---|
207 |
|
---|
208 | RET
|
---|
209 |
|
---|
210 |
|
---|
211 | ; Write message pointed by HL to screen
|
---|
212 | puts
|
---|
213 | LD A,(HL)
|
---|
214 | INC HL
|
---|
215 | CALL &BB5A
|
---|
216 | OR A
|
---|
217 | JR NZ,puts
|
---|
218 | RET
|
---|
219 |
|
---|
220 | ; -----------------------------------------------------------------------------
|
---|
221 | ; Messages
|
---|
222 | MSG_WRITE_START string "Turn write switch ON and press a key...\r\n"
|
---|
223 | MSG_WRITE_END string "Turn write switch OFF and press a key...\r\n"
|
---|
224 |
|
---|
225 | ; -----------------------------------------------------------------------------
|
---|
226 | SECTION .uninit,"urw"
|
---|
227 |
|
---|
228 | stack DEFW 1
|
---|
229 | inthandle DEFW 1
|
---|
230 |
|
---|
231 | end
|
---|
232 |
|
---|
233 | ; Very basic command prompt/monitor stuff for testing
|
---|
234 | ; Print prompt
|
---|
235 | LD A,'?'
|
---|
236 | CALL 0xBB5A
|
---|
237 | ; Wait for key
|
---|
238 | CALL 0xBB06
|
---|
239 | ; Parse commands
|
---|
240 | CP A,'d'
|
---|
241 | JP Z,DUMP
|
---|
242 | CP A,'e'
|
---|
243 | JP Z,ERASE
|
---|
244 | CP A,'w'
|
---|
245 | JP Z,WRITE
|
---|
246 |
|
---|
247 | ; Unhandled command
|
---|
248 | LD A,'X'
|
---|
249 | CALL 0xBB5A
|
---|
250 |
|
---|
251 | ; Start over
|
---|
252 | JR _start
|
---|
253 |
|
---|
254 |
|
---|
255 | ; Dump some bytes from beginning of ROM 5
|
---|
256 | DUMP
|
---|
257 | DI
|
---|
258 |
|
---|
259 | ; Map the ROM in (stay in mode 1 and get system rom out)
|
---|
260 | LD BC, 0x7F85
|
---|
261 | OUT (C),C
|
---|
262 |
|
---|
263 | LD BC,0xDF05
|
---|
264 | OUT (C),C
|
---|
265 |
|
---|
266 | ; Copy the ROM to RAM
|
---|
267 | LD DE, 0x4000
|
---|
268 | LD BC, 0x4000
|
---|
269 | LD HL, 0xC000
|
---|
270 | LDIR
|
---|
271 |
|
---|
272 | EI
|
---|
273 |
|
---|
274 | ; Dump the RAM (we're safe if the system maps another ROM this way)
|
---|
275 | LD HL,0x4000
|
---|
276 | plop
|
---|
277 | LD A,(HL)
|
---|
278 | INC HL
|
---|
279 | CALL PRNHEX2
|
---|
280 | DJNZ plop
|
---|
281 |
|
---|
282 | ; Wait for next command
|
---|
283 | JP _start
|
---|
284 |
|
---|
285 |
|
---|
286 | PRNHEX2 ;affiche la valeur de A sur 2 chiffres
|
---|
287 | ; en hexad{cimal
|
---|
288 | PUSH AF
|
---|
289 | RRA
|
---|
290 | RRA
|
---|
291 | RRA
|
---|
292 | RRA ;divise A par 8
|
---|
293 | CALL PRNHEX1 ;affiche le premier morceau
|
---|
294 | POP AF ;r{cup la valeur originale pour la suit
|
---|
295 | PRNHEX1 ;affiche la valeur de A sur 1 chiffre
|
---|
296 | ;affiche A sur 1 chiffre en Hexa
|
---|
297 | AND 0xF ;ne prend que les unit{s
|
---|
298 | OR A
|
---|
299 | DAA ;convertit en d{cimal
|
---|
300 | ADD A,0xF0 ;ajoute 240
|
---|
301 | ADC A,0x40 ;ajoute 64+le carry (si >15)
|
---|
302 | ;on a le code ascii du chiffre @ afficher
|
---|
303 | JP 0xBB5A ;call-ret
|
---|
304 |
|
---|
305 |
|
---|
306 | PRNHEX2 ;affiche la valeur de A sur 2 chiffres
|
---|
307 | ; en hexad{cimal
|
---|
308 | PUSH AF
|
---|
309 | RRA
|
---|
310 | RRA
|
---|
311 | RRA
|
---|
312 | RRA ;divise A par 8
|
---|
313 | CALL PRNHEX1 ;affiche le premier morceau
|
---|
314 | POP AF ;r{cup la valeur originale pour la suit
|
---|
315 | PRNHEX1 ;affiche la valeur de A sur 1 chiffre
|
---|
316 | ;affiche A sur 1 chiffre en Hexa
|
---|
317 | AND 0xF ;ne prend que les unit{s
|
---|
318 | OR A
|
---|
319 | DAA ;convertit en d{cimal
|
---|
320 | ADD A,0xF0 ;ajoute 240
|
---|
321 | ADC A,0x40 ;ajoute 64+le carry (si >15)
|
---|
322 | ;on a le code ascii du chiffre @ afficher
|
---|
323 | JP 0xBB5A ;call-ret
|
---|
324 |
|
---|
325 |
|
---|