v0.2 - Boot Agent for UART flash is back?
[wj-unilink2.git] / wjuni2.asm
1                 title   "PIC16F876A Unilink Interface by Werner Johansson (c) 2004-2005"\r
2                 subtitl "Definitions"\r
3                 list    c=132,P=16F876a,R=DEC,F=inhx8m\r
4         include "p16f876a.inc"            ; Standard equates & Macros\r
5         ERRORLEVEL 1,-302               ; Get rid of those annoying 302 msgs!\r
6 \r
7 ;----------------------------------------------------------------\r
8 ;  The Configuration Word\r
9       __CONFIG _HS_OSC&_WDT_OFF&_PWRTE_OFF&_BODEN_ON&_LVP_OFF&_CPD_OFF&_WRT_OFF&_DEBUG_OFF&_CP_OFF\r
10 \r
11 ;----------------------------------------------------------------\r
12 ;       HISTORY\r
13 ;----------------------------------------------------------------\r
14 ;  Version\r
15 ;\r
16 ;  0.0  Very first "Fucking No Work!" version\r
17 ;  0.1  Some receiving works with the new MCU using HW SPI, yay!\r
18 ;  0.2  Boot Agent for UART flash is back?\r
19 ;\r
20 ;----------------------------------------------------------------\r
21 \r
22 ; Unilink BUSON IN (blue) connected to RA4C2/T0CKI\r
23 ; Unilink DATA (green) connected to RC4(SDI), RC5(SDO) via open collector driver (HW USART)\r
24 ; Unilink BUSON OUT (blue) connected to RA5 via 100R resistor (this is for daisy-chaining)\r
25 ; Unilink CLK (yellow) connected to RC3(SCK) (USART CLK)\r
26 ; Unilink RST (lilac) connected to RB0(INT)\r
27 ; RS-232 TX from computer connected to RC7/RX\r
28 ; RS-232 RX to computer connected to RC6/TX\r
29 ; RS-232 RTS from computer connected to RC2\r
30 ; RS-232 RI and CTS to computer connected to RC1\r
31 ; RS-232 INVALID signal from MAX connected to RC0\r
32 \r
33 ; Pin mapping as follows:\r
34 \r
35 ; RA0 Voltage sense (A/D in 0)\r
36 ; RA1 Amp sense 1 (A/D in 1)\r
37 ; RA2 Early-Startup sense/Blue LED drive (active low) (RA2 and RA3 have been reversed from the PCB layout!)\r
38 ; RA3 Amp sense 2 (A/D in 3)\r
39 ; RA4/T0CKI BUSON IN from Head Unit (can trigger interrupt on clocking?)\r
40 ; RA5 BUSON OUT to cascade\r
41 \r
42 ; RB0 UNI RST in (interrupt triggered)\r
43 ; RB1 Enable-PWR output to SEPIC converter\r
44 ; RB2 Disable-AMP output\r
45 ; RB3 Enable-AUX output to trigger analog switch relay\r
46 ; RB4 Sign output from Amp sense 1/Red LED drive, active low\r
47 ; RB5 Sign output from Amp sense 2/Green LED drive, active low\r
48 ; RB6 ICSP/ICD reserved\r
49 ; RB7 ICSP/ICD reserved\r
50 \r
51 ; RC0 INVALID input from MAX3235\r
52 ; RC1 CTS and RI output\r
53 ; RC2 RTS input\r
54 ; RC3 Unilink clock input\r
55 ; RC4 Unilink data input\r
56 ; RC5 Unilink data output (drives inverted!)\r
57 ; RC6 TX output\r
58 ; RC7 RX input\r
59 \r
60 ;----------------------------------------------------------------\r
61 ; File register usage\r
62 \r
63 ; Memory from 20h to  7fh (BANK 0 96 bytes)\r
64 ;             a0h to  efh (BANK 1 80 bytes)\r
65 ;            110h to 16fh (BANK 2 96 bytes)\r
66 ;            190h to 1efh (BANK 3 96 bytes)\r
67 ; 70-7fh, f0-ffh, 170-17fh and 1f0-1ffh share the same 16 bytes, for ISR!)\r
68 \r
69 Dcount  equ     20h\r
70 e_LEN   equ     21h\r
71 Icount  equ   2Dh   ; Offset of string to print\r
72 TxTemp  equ   2Eh   ; blahblah\r
73 TxTemp2 equ   2Fh   ; Blahblah2\r
74 \r
75 ; Start of code - four instructions fit before the IRQ handler\r
76                 org     0\r
77                 nop                                             ; Leave the first location as NOP, just in case (required for ICD use)\r
78                 call    Bootstrap               ; Call Flash Load routine at top of flash\r
79                 call    IRQInit                 ; Set up and start the IRQ handler\r
80                 goto    Main                    ; Run the main program loop (skip the IRQ handler)\r
81 \r
82                 subtitl "IRQ Handler"\r
83 ;----------------------------------------------------------------\r
84 ; Interrupt handler always starts at addr 4.\r
85 ; Let the entire handler stay here instead of branching away\r
86 \r
87                 org     4                                       ; Must be on Address 4!\r
88                 retfie                  ; Interrupt return\r
89 \r
90                 subtitl "IRQ Initialization code"\r
91 ;----------------------------------------------------------------\r
92 ; Initializes the interrupt handler and registers.\r
93 \r
94 IRQInit\r
95                 return\r
96 \r
97                 subtitl "Main loop"\r
98                 page\r
99 \r
100                 org     100h\r
101 Main\r
102         clrf    PORTA\r
103         clrf    PORTB\r
104         clrf    PORTC\r
105         bsf     STATUS,RP0      ; Hi Bank\r
106         movlw   04h             ; AD mode 4h, 3 ad inputs AN0, 1 and 3, not 2 (!) fix pcb.. :(\r
107         movwf   ADCON1\r
108        movlw   0dfh            ; RA5 should be outputs...\r
109 ;        movlw   0dbh            ; RA2 & RA5 should be outputs...\r
110 ;        movlw   0fbh            ; RA2 should be output...\r
111         movwf   TRISA           ; Yep.\r
112         movlw   0c1h            ; RB0, 6 & 7 are inputs.\r
113         movwf   TRISB           ; Yep\r
114                 movlw   9dh                             ; RC0, 2, 3, 4, 7 are inputs\r
115 ;               movlw   0bdh                            ; RC0, 2, 3, 4, 7 are inputs\r
116                 movwf   TRISC\r
117         bcf     OPTION_REG,NOT_RBPU     ; Turn on port B pull-up\r
118         bcf     STATUS,RP0      ; Restore Lo Bank\r
119 \r
120         bsf     PORTB,1                 ; Turn on SEPIC\r
121 ;       bsf PORTA,5                     ; test ss shit\r
122 \r
123         bsf     STATUS,RP0              ; Access bank 1\r
124         bsf     TXSTA,TXEN              ; Enable UART TX\r
125         movlw   31                      ; Divisor for 9k6 @ 20MHz Fosc\r
126         movwf   SPBRG                   ; Store\r
127         bcf     STATUS,RP0              ; Back to bank 0\r
128 \r
129         bsf     RCSTA,SPEN              ; Enable serial port\r
130         bsf     RCSTA,CREN              ; Enable UART RX\r
131 \r
132 ;               movlw 'W'\r
133 ;               movwf   TXREG   ; Test transmission\r
134 \r
135                 \r
136 ;WaitRSTHigh\r
137 ;               call    UpdateLEDS\r
138 ;               btfss   PORTB,0         ; Test RST bit\r
139 ;               goto    WaitRSTHigh\r
140 \r
141 ;        bsf     STATUS,RP0      ; Hi Bank\r
142 ;               bsf             TRISA,2         ; RA2 back as input (turn off blue led)\r
143 ;        bcf     STATUS,RP0      ; Lo Bank\r
144 \r
145 RestartCrap\r
146                 bcf             SSPCON,SSPEN    ;disable ssp\r
147 \r
148 WaitRSTLow\r
149                 call    UpdateLEDS\r
150 ;b WaitRSTLow\r
151                 btfsc   PORTB,0         ; Test RST bit\r
152                 goto    WaitRSTLow              \r
153 \r
154 WaitBUSONHigh\r
155                 call    UpdateLEDS\r
156                 btfss   PORTA,4         ; Test BUSON bit\r
157                 goto    WaitBUSONHigh           \r
158 \r
159                 bsf             STATUS,RP0\r
160 ;               movlw   40h                     ; Latch on active-to-idle edge (needs ss crap?)\r
161                 movlw   00h                     ; Transfer on idle-to-active edge (and latch on active-to-idle)\r
162                 movwf   SSPSTAT\r
163                 bcf             STATUS,RP0\r
164 \r
165 WaitCLKLow\r
166                 call    UpdateLEDS\r
167                 btfsc   PORTC,3         ; SCK input must be low before enabling SSP according to errata sheet (!)\r
168                 goto    WaitCLKLow\r
169                 movlw   25h\r
170 ;               movlw   34h                     ; fuxx0red ss mode crap\r
171                 movwf   SSPCON          ; Enable SPI slave mode with SCK IDLE low, no _SS control\r
172                 clrw\r
173                 movwf   SSPBUF\r
174 \r
175 OnceMore\r
176 WaitForByte\r
177                 call    UpdateLEDS\r
178 \r
179                 btfsc   PORTB,0         ; Test RST bit\r
180                 goto    RestartCrap\r
181 \r
182                 btfss   PORTA,4         ; Test BUSON bit\r
183                 goto    RestartCrap\r
184 \r
185                 bsf             STATUS,RP0\r
186                 btfss   SSPSTAT,BF      ; Test for buffer complete\r
187                 goto    WaitForByte\r
188                 bcf             STATUS,RP0\r
189                 movf    SSPBUF,w\r
190                 xorlw   0ffh            ; Invert received data\r
191                 movwf   TXREG           ; Send it out to Async serial\r
192                 clrw\r
193                 movwf   SSPBUF\r
194                 goto    OnceMore\r
195 \r
196 meck\r
197         b meck\r
198 \r
199 UpdateLEDS\r
200 ; NOTE!!!! This is wrong, never drive the led outputs high as there are other open-collector drivers on these pins!!!\r
201 ; This is just for debugging, must be removed when hooking things up to the board!!!\r
202                 bcf     STATUS,RP0\r
203 ; IO is inverted logic (active low)\r
204 ;               btfsc   PORTA,4         ; test buson\r
205                 btfss   PORTC,4         ; test IO\r
206                 bcf     PORTB,5         ; turn on green led\r
207 ;               btfss   PORTA,4         ; test buson clear\r
208                 btfsc   PORTC,4         ; test IO\r
209                 bsf     PORTB,5         ; turn off green led\r
210 \r
211 ; CLK is true logic (active high)\r
212 ;               btfsc   PORTB,0         ; Test RST bit\r
213                 btfsc   PORTC,3         ; test clk\r
214                 bcf     PORTB,4         ; turn on red led if RST high\r
215 ;               btfss   PORTB,0         ; Test RST bit\r
216                 btfss   PORTC,3         ; test clk\r
217                 bsf     PORTB,4         ; turn off red led if RST low\r
218 \r
219                 return\r
220 \r
221         subtitl "Bootstrap/Bootloader code"\r
222         page\r
223 \r
224 ;----------------------------------------------------------------------\r
225 ; Bootstrap code - Allows PIC to flash itself with data from the async port.\r
226 ; Accepts a standard INHX8 encoded file as input, the only caveat is that the code is slow when writing to memory\r
227 ; (we have to wait for the flash to complete), and therefore care has to be taken not to overflow the RS232 receiver\r
228 ; (one good way of solving that is to wait for the echo from the PIC before sending anything else)\r
229 ; Both program memory and Data EEPROM memory can be programmed, but due to hardware contraints the configuration\r
230 ; register can't be programmed. That means that any references to the config register in the hex file will be ignored.\r
231 ;\r
232 ; Startup @9600bps\r
233 \r
234 ; RAM usage for the bootstrap code\r
235 \r
236 BootBits        equ     7eh             ; bit0 1=write 0=read, bit1 1=PGM 0=EE, bit2 0=normal 1=no-op when prog\r
237 BootAddrL       equ     7dh\r
238 BootAddrH       equ     7ch\r
239 BootDataL       equ     7bh\r
240 BootDataH       equ     7ah\r
241 BootTimerL      equ     79h\r
242 BootTimerM      equ     78h\r
243 BootTimerH      equ     77h\r
244 BootNumBytes    equ     76h\r
245 BootDataVL      equ     75h\r
246 BootDataVH      equ     74h\r
247 BootHEXTemp     equ     73h\r
248 \r
249         org     72eh                    ; Place the boot code at the top of memory page 0\r
250 \r
251 Bootstrap\r
252         bsf     STATUS,RP0              ; Access bank 1\r
253         bsf     TXSTA,TXEN              ; Enable UART TX\r
254         movlw   31                      ; Divisor for 9k6 @ 20MHz Fosc\r
255         movwf   SPBRG                   ; Store\r
256         bcf     STATUS,RP0              ; Back to bank 0\r
257 \r
258         bsf     RCSTA,SPEN              ; Enable serial port\r
259         bsf     RCSTA,CREN              ; Enable UART RX\r
260 \r
261         movlw   low BootStartText       ; Send boot banner to the serial port\r
262         call    BootTXStr\r
263 \r
264         movlw   0e8h                    ; Initialize timeout timer (e8 is about 3 secs)\r
265 ;       movlw   0fdh                    ; Initialize timeout timer (fd is short enough to get the headunit to recognize us)\r
266         movwf   BootTimerL\r
267         movwf   BootTimerM\r
268         movwf   BootTimerH\r
269 \r
270 BootTimeout\r
271         incf    BootTimerL,f            ; A 24-bit counter\r
272         skpnz\r
273         incf    BootTimerM,f\r
274         skpnz\r
275         incf    BootTimerH,f\r
276         skpnz                           ; When overflowing here..\r
277         goto    BootReturn              ; ..Exit boot loader, no keypress within timeout period, resume program\r
278         btfss   PIR1,RCIF               ; Wait for RX to complete\r
279         goto    BootTimeout\r
280         call    BootRXB\r
281         xorlw   27                      ; ESC\r
282         skpz\r
283         goto    BootTimeout             ; If it wasn't ESC, wait for another key\r
284 \r
285 BootFlash\r
286         movlw   low BootFlashText       ; OK, flashing it is, send "start" text to serial port\r
287         call    BootTXStr\r
288 \r
289         bsf     BootBits,1\r
290         clrf    BootAddrL\r
291         clrf    BootAddrH\r
292 \r
293 BootLoop\r
294         call    BootRXB                 ; First find the ':'\r
295         xorlw   ':'\r
296         skpz\r
297         goto    BootLoop                ; Loop until we find it!\r
298 \r
299         call    BootRXHEX               ; Get one ASCII encoded byte (two chars)\r
300         movwf   BootNumBytes            ; This is the number of bytes to be programmed on the line\r
301 ; Maybe clear cary here?\r
302         rrf     BootNumBytes,f          ; Right shift because we're double addressing this 8-bit format\r
303 \r
304 ; Note carry should be clear here as there cannot be odd number of bytes in this format\r
305 \r
306         call    BootRXHEX               ; Receive AddrH\r
307         movwf   BootAddrH\r
308         call    BootRXHEX               ; Receive AddrL\r
309         movwf   BootAddrL\r
310         rrf     BootAddrH,f             ; Fix the addressing again\r
311         rrf     BootAddrL,f\r
312 \r
313         bcf     BootBits,2              ; Assume we should program\r
314         bsf     BootBits,1              ; And assume we should program flash not ee\r
315 \r
316         movf    BootAddrH,w\r
317         xorlw   020h                    ; Check if it's configuration, which we can't program\r
318         skpnz                           ; Skip the bit set if it was false alarm\r
319         bsf     BootBits,2              ; No programming for this line\r
320 \r
321         xorlw   001h                    ; Also check if it's EEPROM memory (first xor 20h then 1 =21h)\r
322         skpnz                           ; Skip the bit set instr if not EE data address\r
323         bcf     BootBits,1              ; We should program EE, will ignore the AddrH\r
324 \r
325         call    BootRXHEX               ; Receive Record Type (must be 0 for real records)\r
326         skpz                            ; Check if zero\r
327         goto    BootFlashComplete\r
328 \r
329 BootLineLoop\r
330         call    BootRXHEX               ; Receive low-byte of data word\r
331         movwf   BootDataVL\r
332         call    BootRXHEX               ; Receive high-byte of data word\r
333         movwf   BootDataVH\r
334         \r
335         btfsc   BootBits,2              ; Check whether this line should be programmed at all\r
336         goto    BootWriteSkip\r
337 \r
338         bcf     BootBits,0              ; Read mode first, verify if we actually have to write\r
339         call    BootEE\r
340         movf    BootDataVL,w\r
341         xorwf   BootDataL,f             ; Compare and destroy DataL\r
342         movwf   BootDataL               ; Write new data to DataL\r
343         skpz                            ; Skip if no difference, have to check high byte as well\r
344         goto    BootWrite               ; Jump directly to write\r
345 \r
346         movf    BootDataVH,w\r
347         xorwf   BootDataH,f             ; Compare\r
348         skpnz                           ; Skip if no difference, no programming necessary\r
349         goto    BootWriteSkip\r
350 \r
351 BootWrite\r
352         movf    BootDataVH,w\r
353         movwf   BootDataH               ; Have to put the new H byte data in as well\r
354 \r
355         bsf     BootBits,0\r
356         call    BootEE                  ; Write directly into program mem\r
357 \r
358 ; Here a verify can take place, the read-back results are now in DataL/H\r
359 \r
360 BootWriteSkip\r
361 \r
362         incf    BootAddrL,f             ; Advance counter to next addr\r
363         skpnz\r
364         incf    BootAddrH,f             ; And add to high byte if needed\r
365 \r
366         decfsz  BootNumBytes,f\r
367         goto    BootLineLoop\r
368 \r
369         goto    BootLoop\r
370 \r
371 BootFlashComplete\r
372         \r
373 BootReturn\r
374         movlw   low BootRunText\r
375         call    BootTXStr\r
376 \r
377         bsf     STATUS,RP0              ; Reg bank 1\r
378 BootReturnWait\r
379         btfss   TXSTA,TRMT              ; Wait for last things to flush\r
380         goto    BootReturnWait\r
381         bcf     TXSTA,TXEN              ; Disable UART TX\r
382         bcf     STATUS,RP0              ; Back to bank 0\r
383 \r
384         bcf     RCSTA,SPEN              ; Disable serial port\r
385         bcf     RCSTA,CREN              ; Disable UART RX\r
386 \r
387         return                          ; Return to code        \r
388 \r
389 ;----------------------------------------------------------------------\r
390 ; BootTXB - Sends one byte to the UART, waits for transmitter to become\r
391 ;  free before sending\r
392 \r
393 BootTXB\r
394 BootTXW1\r
395         btfss   PIR1,TXIF               ; Wait for TX to empty\r
396         goto    BootTXW1\r
397         movwf   TXREG                   ; Send the byte\r
398         return\r
399 \r
400 ;----------------------------------------------------------------------\r
401 ; BootTXStr - Sends ASCII string pointed to by W, zero terminated\r
402 \r
403 BootTXStr\r
404         movwf   BootAddrL               ; Store LSB of text pointer\r
405         movlw   07h                     ; MSB of pointer to the text (0700h in this boot loader)\r
406         movwf   BootAddrH\r
407         movlw   02h                     ; Select "Read Program Memory" operation\r
408         movwf   BootBits        \r
409 BootTXStrLoop\r
410         call    BootEE                  ; Lookup char (actually two packed into one word)\r
411         rlf     BootDataL,w             ; Shift the MSB out into carry (that's the 2nd char LSB)\r
412         rlf     BootDataH,w             ; Shift it into 2nd char\r
413         call    BootTXB                 ; Send the high byte first\r
414         movf    BootDataL,w             ; Get the low byte\r
415         andlw   07fh                    ; Mask of the highest bit\r
416         skpnz                           ; Stop if zero\r
417         return\r
418         call    BootTXB                 ; Send char\r
419         incf    BootAddrL,f             ; Increment pointer\r
420         goto    BootTXStrLoop\r
421 \r
422 ;----------------------------------------------------------------------\r
423 ; BootRXB - Receives one byte from the UART, waits if nothing available\r
424 \r
425 BootRXB\r
426 BootRXW1\r
427         btfss   PIR1,RCIF               ; Wait for RX to complete\r
428         goto    BootRXW1\r
429         movf    RCREG,w                 ; Get the recvd byte\r
430         call    BootTXB                 ; Echo to terminal\r
431         return\r
432 \r
433 ;----------------------------------------------------------------------\r
434 ; BootRXHEXNibble - Receives one byte and converts it from ASCII HEX to binary\r
435 \r
436 BootRXHEXNibble\r
437         call    BootRXB                 ; Receive nibble\r
438 \r
439 ; This code is from piclist.com, really neat!\r
440 \r
441         addlw   -'A'                    ; Convert from BCD to binary nibble\r
442         skpc                            ; Test if if was 0-9 or A-F, skip if A-F\r
443         addlw  'A' - 10 - '0'           ; It was numeric '0'\r
444         addlw   10                      ; Add 10 (A get to be 0ah etc.)\r
445 \r
446         return\r
447 \r
448 ;----------------------------------------------------------------------\r
449 ; BootRXHEX - Receives two bytes from the UART, waits if nothing available\r
450 ;  Decodes the bytes as ASCII hex and returns a single byte in W\r
451 \r
452 BootRXHEX\r
453         call    BootRXHEXNibble\r
454         movwf   BootHEXTemp\r
455         swapf   BootHEXTemp,f           ; Swap it up to the high nibble\r
456 \r
457         call    BootRXHEXNibble\r
458         addwf   BootHEXTemp,w           ; And add the two nibbles together\r
459         return\r
460 \r
461 ;----------------------------------------------------------------------\r
462 ; BootEE - Reads or writes EE or Flash memory, BootBits specify the\r
463 ;  exact action to take. BootAddrL and BootAddrH has to be initialized\r
464 ;  to the address of choice (0000-00ffh for EE and 0000h-1fffh for flash.\r
465 ;  The data to be written has to be put in BootDataL and BootDataH, and\r
466 ;  data will be written to the same place when read back\r
467 \r
468 BootEE\r
469         bsf     STATUS,RP1              ; Select bank 2 (RP0 must be 0)\r
470 \r
471         movf    BootAddrH,w             ; Load desired address\r
472         movwf   EEADRH\r
473         movf    BootAddrL,w\r
474         movwf   EEADR\r
475         movf    BootDataH,w             ; And load the data (only used when writing)\r
476         movwf   EEDATH\r
477         movf    BootDataL,w\r
478         movwf   EEDATA\r
479 \r
480         bsf     STATUS,RP0              ; Go to bank 3\r
481 \r
482         bsf     EECON1,EEPGD            ; Point to Program Flash mem\r
483         btfss   BootBits,1              ; Test if that was correct or if we have to clear again\r
484         bcf     EECON1,EEPGD            ; Point to EE DATA mem\r
485 \r
486         btfss   BootBits,0              ; Check from read or write\r
487         goto    BootEERD                ; Skip the WR if we were going for a read\r
488 \r
489         bsf     EECON1,WREN             ; Enable writes\r
490         movlw   55h\r
491         movwf   EECON2\r
492         movlw   0AAh\r
493         movwf   EECON2                  ; Unlock write operation\r
494         bsf     EECON1,WR               ; And start a write cycle\r
495 BootWRLoop\r
496         btfsc   EECON1,WR               ; This executes for EE only not flash, waits for WR to finish\r
497         goto    BootWRLoop              ; These two instructions gets NOPed when flashing program memory\r
498 \r
499         bcf     EECON1,WREN             ; Finally disable writes again\r
500                                         ; Here we read the data back again, can be used as verify\r
501 BootEERD\r
502         bsf     EECON1,RD               ; Start a read cycle\r
503         nop                             ; Only necessary for flash read, same thing as when writing above\r
504         nop                             ; Except I could use the two words for something useful there.. :)\r
505 \r
506 BootEEX\r
507         bcf     STATUS,RP0              ; Back to bank 2\r
508         movf    EEDATA,w                ; Store our EE-data\r
509         movwf   BootDataL\r
510         movf    EEDATH,w\r
511         movwf   BootDataH\r
512         bcf     STATUS,RP1              ; And finally back to bank 0\r
513 \r
514         return\r
515 \r
516 ; To produce compact code the end zero byte has to be in the LSB (that means an even number of chars in every string)\r
517 BootStartText\r
518         DA      "WJ PIC16F876A Boot Loader - press ESC to flash...\x00"\r
519 \r
520 BootFlashText\r
521         DA      "\r\nSend INHX8 file now...\r\x00"\r
522 \r
523 BootRunText\r
524         DA      "\r\nExiting loader\r\x00"\r
525 \r
526 ;----------------------------------------------------------------------\r
527 ; EE Data (256 bytes), located at 2100h\r
528 \r
529         org 2100h\r
530 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
531 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
532 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
533 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
534 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
535 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
536 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
537 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
538 \r
539 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
540 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
541 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
542 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
543 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
544 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
545 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
546 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
547 \r
548 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
549 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
550 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
551 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
552 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
553 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
554 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
555 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
556 \r
557 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
558 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
559 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
560 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
561 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
562 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
563 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
564 ;       de      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh\r
565 \r
566         END\r