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 | ; Now that we got the system out of the way, map the ROM
|
---|
49 | ; (we stay in mode 1)
|
---|
50 | LD BC, 0x7F85
|
---|
51 | OUT (C),C
|
---|
52 |
|
---|
53 | ; TODO get the ROM number to burn somehow ?
|
---|
54 | ; (we can get it as a CALL parameter)
|
---|
55 |
|
---|
56 | CALL ERASE
|
---|
57 | CALL CHECKBLANK
|
---|
58 |
|
---|
59 | ; Load the "erase error" message. If erase actually succeded, we will go
|
---|
60 | ; to the write function which will set something else.
|
---|
61 | ; DE holds the error address
|
---|
62 | EX DE,HL
|
---|
63 | LD HL,MSG_ERASE_ERR
|
---|
64 | LD (status),HL
|
---|
65 | CALL Z,WRITE
|
---|
66 |
|
---|
67 | ; Disconnect the Megaflash
|
---|
68 | LD BC,0xDFFF
|
---|
69 | OUT (C),C
|
---|
70 |
|
---|
71 | ; Restore the firmware in working order now that we are done
|
---|
72 | LD SP,(stack)
|
---|
73 | LD HL,(inthandle)
|
---|
74 | LD (0x38),HL
|
---|
75 | EI
|
---|
76 |
|
---|
77 | ; Tell firmware to draw the screen at &4000 (so we don't erase the
|
---|
78 | ; ROM with the next message...)
|
---|
79 | LD A,0x40
|
---|
80 | CALL screenmem
|
---|
81 |
|
---|
82 | ; TODO clear screen
|
---|
83 |
|
---|
84 | ; Print the error/success message
|
---|
85 | LD HL,(status)
|
---|
86 | CALL puts
|
---|
87 |
|
---|
88 | ; Print DE so we know where the problem was
|
---|
89 | LD A,D
|
---|
90 | CALL PRNHEX2
|
---|
91 | LD A,E
|
---|
92 | CALL PRNHEX2
|
---|
93 |
|
---|
94 | ; Now user can safely disconnect the ROM
|
---|
95 | LD HL,MSG_WRITE_END
|
---|
96 | CALL puts
|
---|
97 | ; Wait for key
|
---|
98 | CALL 0xBB06
|
---|
99 |
|
---|
100 | ; Put screen back at normal address
|
---|
101 | LD A,0xC0
|
---|
102 | CALL screenmem
|
---|
103 |
|
---|
104 | ; TODO clear screen
|
---|
105 | LD HL,0xC000
|
---|
106 | CALL DUMP
|
---|
107 | CALL 0xBB06
|
---|
108 |
|
---|
109 | LD HL, 0xD000
|
---|
110 | CALL DUMP
|
---|
111 | CALL 0xBB06
|
---|
112 |
|
---|
113 | LD HL, 0xE000
|
---|
114 | CALL DUMP
|
---|
115 | CALL 0xBB06
|
---|
116 |
|
---|
117 | LD HL,0xF000
|
---|
118 | CALL DUMP
|
---|
119 | CALL 0xBB06
|
---|
120 |
|
---|
121 | ; TODO cleanly get out (and handle both calls by RUN and CALL)
|
---|
122 | JR $
|
---|
123 |
|
---|
124 |
|
---|
125 | ; Erase a 16K ROM. Input:
|
---|
126 | ; A - ROM number to erase (TODO)
|
---|
127 | ; Assumes we are in write mode, interrupts disabled.
|
---|
128 | ERASE
|
---|
129 | LD B,4
|
---|
130 | eraseloop
|
---|
131 | PUSH BC
|
---|
132 |
|
---|
133 | LD A, 0x80 ; ERASE
|
---|
134 | CALL send_command
|
---|
135 |
|
---|
136 | CALL prepare_command
|
---|
137 |
|
---|
138 | LD B,0xDF
|
---|
139 | LD C,5 ; ROM number to write (FIXME get it as a RSX param)
|
---|
140 | OUT (C),C
|
---|
141 |
|
---|
142 | ; Compute address near start of sector
|
---|
143 | POP BC
|
---|
144 |
|
---|
145 | LD HL, addrmap-1
|
---|
146 | LD D,0
|
---|
147 | LD E,B
|
---|
148 | ADD HL,DE
|
---|
149 | LD A,(HL)
|
---|
150 |
|
---|
151 | LD H,A
|
---|
152 | LD L,0
|
---|
153 |
|
---|
154 | ; Sector erase command
|
---|
155 | LD E, 0x30
|
---|
156 | LD (HL), E
|
---|
157 |
|
---|
158 | ; This will delay long enough - we need at least 20ms
|
---|
159 | EI
|
---|
160 | HALT
|
---|
161 | HALT
|
---|
162 | HALT
|
---|
163 | HALT
|
---|
164 | HALT
|
---|
165 | HALT
|
---|
166 | HALT
|
---|
167 | DI
|
---|
168 |
|
---|
169 | DJNZ eraseloop
|
---|
170 |
|
---|
171 | RET
|
---|
172 |
|
---|
173 | addrmap defb 0xC0, 0xD0, 0xE0, 0xF0
|
---|
174 |
|
---|
175 | ; Write a 16K ROM
|
---|
176 | ; IN: A - ROM number to write (TODO)
|
---|
177 | ; &2000 - Data to copy (TODO let the caller put that in IX maybe ?)
|
---|
178 | ; Assumes we are in write-enabled mode (TODO)
|
---|
179 | WRITE
|
---|
180 | ; Ok, now that we erased the 4 sectors we needed, we can write data to them
|
---|
181 | LD HL, 0xC000
|
---|
182 | LD IX, 0x2000
|
---|
183 | PROGRAM
|
---|
184 | PUSH HL
|
---|
185 |
|
---|
186 | LD A, 0xA0 ; BYTE PROGRAM
|
---|
187 | CALL send_command
|
---|
188 |
|
---|
189 | POP HL
|
---|
190 |
|
---|
191 | LD B,0xDF
|
---|
192 | LD C,5 ; ROM number to write (FIXME get it as a RSX param)
|
---|
193 | OUT (C),C
|
---|
194 |
|
---|
195 | LD A,(IX + 0)
|
---|
196 | LD (HL),A ; Write occurs here. Need to wait 20 NOPs before next
|
---|
197 | ; operation on ROM. Our code is slow enough already !
|
---|
198 |
|
---|
199 | INC IX
|
---|
200 | INC HL
|
---|
201 |
|
---|
202 | ; As INC HL doesn't update the flags, check if we overflowed yet
|
---|
203 | LD A,H
|
---|
204 | OR L
|
---|
205 |
|
---|
206 | JR NZ, PROGRAM
|
---|
207 |
|
---|
208 | LD HL,MSG_WRITE_OK
|
---|
209 | LD (status),HL
|
---|
210 | RET
|
---|
211 |
|
---|
212 |
|
---|
213 | ; Check if the ROM was erased properly and contains all FF bytes.
|
---|
214 | ; Input: upper ROM is connected
|
---|
215 | ; Output: Z flag set if all ok, else HL points to error
|
---|
216 | CHECKBLANK
|
---|
217 | ; TODO select the right ROM
|
---|
218 | LD BC,0xDF05
|
---|
219 | OUT (C),C
|
---|
220 |
|
---|
221 | LD HL, 0xC000
|
---|
222 | .checkbyte
|
---|
223 | LD A,(HL)
|
---|
224 |
|
---|
225 | CP 0xFF
|
---|
226 | RET NZ
|
---|
227 |
|
---|
228 | INC HL
|
---|
229 | LD A,H
|
---|
230 | OR A
|
---|
231 | RET Z
|
---|
232 | JR .checkbyte
|
---|
233 | ; Helper routines -----------------------------------------------------
|
---|
234 |
|
---|
235 | ; Send a command to the ROM. The available commands are :
|
---|
236 | ;ERASE equ 0x80
|
---|
237 | IDENTIFY equ 0x90
|
---|
238 | BYTEPROG equ 0xA0
|
---|
239 | RESET equ 0xF0
|
---|
240 |
|
---|
241 | ; Input: Commend to send in A register
|
---|
242 | send_command:
|
---|
243 | ; That code is shared with sector erase which has some tricks
|
---|
244 | call prepare_command
|
---|
245 |
|
---|
246 | ; Select ROM 1 again and write the command to address 0xEAAA
|
---|
247 | DEC C
|
---|
248 | OUT (C),C
|
---|
249 | EX DE,HL
|
---|
250 | LD (HL), A
|
---|
251 |
|
---|
252 | ; Select ROM 0xFF, which basically prevents future accesses to get to the
|
---|
253 | ; Flash chip.
|
---|
254 | DEC C
|
---|
255 | DEC C
|
---|
256 | OUT (C),C
|
---|
257 |
|
---|
258 | RET
|
---|
259 |
|
---|
260 | prepare_command:
|
---|
261 | ; Select ROM 1
|
---|
262 | LD BC,0xDF01
|
---|
263 | LD HL,0xD555
|
---|
264 | LD DE,0xEAAA
|
---|
265 |
|
---|
266 | ; Select ROM 1 and write 0xAA to address 0xD555
|
---|
267 | OUT (C),C
|
---|
268 | LD (HL),E
|
---|
269 |
|
---|
270 | ; Select ROM 2 and write 0x55 to address 0xEAAA
|
---|
271 | INC C
|
---|
272 | OUT (C),C
|
---|
273 | EX DE,HL
|
---|
274 | LD (HL), E
|
---|
275 |
|
---|
276 | RET
|
---|
277 |
|
---|
278 |
|
---|
279 | ; Write message pointed by HL to screen
|
---|
280 | puts
|
---|
281 | LD A,(HL)
|
---|
282 | INC HL
|
---|
283 | CALL &BB5A
|
---|
284 | OR A
|
---|
285 | JR NZ,puts
|
---|
286 | RET
|
---|
287 |
|
---|
288 | ; Print A value as hexadecimal
|
---|
289 | ; AF is corrupt
|
---|
290 | PRNHEX2
|
---|
291 | PUSH AF
|
---|
292 | RRA
|
---|
293 | RRA
|
---|
294 | RRA
|
---|
295 | RRA ;divise A par 8
|
---|
296 | CALL PRNHEX1 ;affiche le premier morceau
|
---|
297 | POP AF ;r{cup la valeur originale pour la suit
|
---|
298 | PRNHEX1 ;affiche la valeur de A sur 1 chiffre
|
---|
299 | ;affiche A sur 1 chiffre en Hexa
|
---|
300 | AND 0xF ;ne prend que les unit{s
|
---|
301 | OR A
|
---|
302 | DAA ;convertit en d{cimal
|
---|
303 | ADD A,0xF0 ;ajoute 240
|
---|
304 | ADC A,0x40 ;ajoute 64+le carry (si >15)
|
---|
305 | ;on a le code ascii du chiffre @ afficher
|
---|
306 | JP 0xBB5A ;call-ret
|
---|
307 |
|
---|
308 |
|
---|
309 | ; Dump some bytes from beginning of ROM 5
|
---|
310 | DUMP
|
---|
311 | DI
|
---|
312 |
|
---|
313 | ; Map the ROM in (stay in mode 1 and get system rom out)
|
---|
314 | LD BC, 0x7F85
|
---|
315 | OUT (C),C
|
---|
316 |
|
---|
317 | LD BC,0xDF05
|
---|
318 | OUT (C),C
|
---|
319 |
|
---|
320 | ; Copy the ROM to RAM
|
---|
321 | LD DE, 0x4000
|
---|
322 | LD BC, 0x4000
|
---|
323 | LDIR
|
---|
324 |
|
---|
325 | EI
|
---|
326 |
|
---|
327 | ; Dump the RAM (we're safe if the system maps another ROM this way)
|
---|
328 | LD HL,0x4000
|
---|
329 | plop
|
---|
330 | LD A,(HL)
|
---|
331 | INC HL
|
---|
332 | CALL PRNHEX2
|
---|
333 | DJNZ plop
|
---|
334 |
|
---|
335 | ; Wait for next command
|
---|
336 | RET
|
---|
337 |
|
---|
338 |
|
---|
339 | ; -----------------------------------------------------------------------------
|
---|
340 | ; Messages
|
---|
341 | MSG_WRITE_START string "Turn write switch ON and press a key...\r\n"
|
---|
342 | MSG_WRITE_END string "Turn write switch OFF and press a key...\r\n"
|
---|
343 | MSG_ERASE_ERR string "Erasing memory failed at address "
|
---|
344 | MSG_WRITE_OK string "Success!\r\n"
|
---|
345 |
|
---|
346 | ; -----------------------------------------------------------------------------
|
---|
347 | SECTION .uninit,"urw"
|
---|
348 |
|
---|
349 | stack DEFW 1
|
---|
350 | inthandle DEFW 1
|
---|
351 | status DEFW 1
|
---|
352 |
|
---|
353 | end
|
---|
354 | ; END END END END END END END END END END END END END END END END END END END
|
---|
355 |
|
---|
356 | ; Very basic command prompt/monitor stuff for testing
|
---|
357 | ; Print prompt
|
---|
358 | LD A,'?'
|
---|
359 | CALL 0xBB5A
|
---|
360 | ; Wait for key
|
---|
361 | CALL 0xBB06
|
---|
362 | ; Parse commands
|
---|
363 | CP A,'d'
|
---|
364 | JP Z,DUMP
|
---|
365 | CP A,'e'
|
---|
366 | JP Z,ERASE
|
---|
367 | CP A,'w'
|
---|
368 | JP Z,WRITE
|
---|
369 |
|
---|
370 | ; Unhandled command
|
---|
371 | LD A,'X'
|
---|
372 | CALL 0xBB5A
|
---|
373 |
|
---|
374 | ; Start over
|
---|
375 | JR _start
|
---|
376 |
|
---|
377 |
|
---|