]> cloudbase.mooo.com Git - avrcpm.git/blob - avrcpm/avr/z80.asm
minor dram_read optimizations
[avrcpm.git] / avrcpm / avr / z80.asm
1 ; Z80 emulator with CP/M support. The Z80-specific instructions themselves actually aren't
2 ; implemented yet, making this more of an i8080 emulator.
3 ;
4 ; Copyright (C) 2010 Sprite_tm
5 ;
6 ; This program is free software: you can redistribute it and/or modify
7 ; it under the terms of the GNU General Public License as published by
8 ; the Free Software Foundation, either version 3 of the License, or
9 ; (at your option) any later version.
10 ;
11 ; This program is distributed in the hope that it will be useful,
12 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ; GNU General Public License for more details.
15 ;
16 ; You should have received a copy of the GNU General Public License
17 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 ;.nolist
20 #if defined atmega8
21 .include "m8def.inc"
22 #elif defined atmega168
23 .include "m168def.inc"
24 #else /* default */
25 .include "m88def.inc"
26 ;FUSE_H=0xDF
27 ;FUSE_L=0xF7
28 #endif
29 .list
30
31 .listmac
32
33 #ifndef DRAM_DQ_ORDER /* If this is set to 1, the portbits */
34 #define DRAM_DQ_ORDER 0 /* for DRAM D1 and WE are swapped. */
35 #endif
36
37
38 #ifndef F_CPU
39 #define F_CPU 20000000 /* system clock in Hz; defaults to 20MHz */
40 #endif
41 #ifndef BAUD
42 #define BAUD 38400 /* console baud rate */
43 #endif
44
45
46 #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) /* clever rounding */
47
48 #define RXBUFSIZE 64 /* USART recieve buffer size. Must be power of 2 */
49
50 #define REFR_RATE 64000 /* dram refresh rate in cycles/s. */
51 /* Most drams need 1/15.6µs. */
52 #define REFR_PRE 8 /* timer prescale factor */
53 #define REFR_CS 0x02 /* timer clock select for 1/8 */
54 #define REFR_CNT F_CPU / REFR_RATE / REFR_PRE
55
56
57 #if defined __ATmega8__
58 .equ refr_vect = OC2addr
59 #else
60 .equ refr_vect = OC2Aaddr
61 #endif
62
63
64 #define EM_Z80 0 /* we don't have any z80 instructions yet */
65
66 .equ MMC_DEBUG = 0
67 .equ INS_DEBUG = 0
68 .equ MEMTEST = 1
69 .equ BOOTWAIT = 1
70 .equ PORT_DEBUG = 0
71 .equ DISK_DEBUG = 0
72 .equ MEMFILL_CB = 1
73 .equ STACK_DBG = 0
74 .equ PRINT_PC = 0
75
76 ;Port declarations
77
78 ; Port D
79 .equ rxd = 0
80 .equ txd = 1
81 .equ ram_oe = 2
82 .equ ram_a8 = 3
83 .equ mmc_cs = 4
84 .equ ram_a5 = 5
85 .equ ram_a6 = 6
86 .equ ram_a7 = 7
87 .equ P_OE = PORTD
88
89 .equ RAM_AH_MASK = 0xE0 ; ram_a[7..5]
90 .equ PD_OUTPUT_MASK = 0xFE
91
92
93 ;Port B
94 .equ ram_a4 = 0
95 .equ ram_a3 = 1
96 .equ ram_a2 = 2
97 .equ ram_a1 = 3
98 .equ mmc_mosi = 3
99 .equ ram_a0 = 4
100 .equ mmc_miso = 4
101 .equ ram_ras = 5
102 .equ mmc_sck = 5
103 .equ P_RAS = PORTB
104
105 .equ RAM_AL_MASK = 0x1F ; ram_a[4..0]
106 .equ PB_OUTPUT_MASK = 0x3F
107
108 ;Port C
109 #if DRAM_DQ_ORDER == 1
110 .equ ram_d1 = 1
111 .equ ram_w = 4
112 #else /* original */
113 .equ ram_d1 = 4
114 .equ ram_w = 1
115 #endif
116 .equ ram_d0 = 0
117 .equ ram_d2 = 2
118 .equ ram_d3 = 3
119 .equ ram_cas= 5
120 .equ P_W = PORTC
121 .equ P_CAS = PORTC
122
123 .equ RAM_DQ_MASK = (1<<ram_d3)|(1<<ram_d2)|(1<<ram_d1)|(1<<ram_d0)
124 .equ PC_OUTPUT_MASK = (1<<ram_cas)|(1<<ram_w)
125
126
127 ;Flag bits in z_flags
128 .equ ZFL_S = 7
129 .equ ZFL_Z = 6
130 .equ ZFL_H = 4
131 .equ ZFL_P = 2
132 .equ ZFL_N = 1
133 .equ ZFL_C = 0
134
135 ;Register definitions
136 .def z_a = r2
137 .def z_b = r3
138 .def z_c = r4
139 .def z_d = r5
140 .def z_e = r6
141 .def z_l = r7
142 .def z_h = r8
143 .def z_spl = r9
144 .def z_sph = r10
145
146 .def dsk_trk = r11
147 .def dsk_sec = r12
148 .def dsk_dmah = r13
149 .def dsk_dmal = r14
150
151 ;.def parityb = r15
152
153 .def temp = R16 ;The temp register
154 .def temp2 = R17 ;Second temp register
155 .def trace = r18
156 .def opl = r19
157 .def oph = r20
158 .def adrl = r21
159 .def adrh = r22
160 .def insdecl = r23
161 .def z_pcl = r24
162 .def z_pch = r25
163 .undef xl
164 .undef xh
165 .def insdech = r26
166 .def z_flags = r27
167
168
169 ; This is the base z80 port address for clock access
170 #define TIMERPORT 0x40
171 #define TIMER_CTL TIMERPORT
172 #define TIMER_MSECS TIMERPORT+1
173 #define TIMER_SECS TIMER_MSECS+2
174
175 #define starttimercmd 1
176 #define quitTimerCmd 2
177 #define printTimerCmd 15
178 #define uptimeCmd 16
179
180
181
182 ;SRAM
183 .dseg
184
185 ;Sector buffer for 512 byte reads/writes from/to SD-card
186
187 sectbuff:
188 .byte 512
189
190
191 .cseg
192 .org 0
193 rjmp start ; reset vector
194 .org refr_vect
195 rjmp refrint ; tim2cmpa
196 .org OC1Aaddr ; Timer/Counter1 Compare Match A
197 rjmp sysclockint ; 1ms system timer
198 .org URXCaddr
199 rjmp rxint ; USART receive int.
200 ;.org UDREaddr
201 ; rjmp txint
202
203 .org INT_VECTORS_SIZE
204
205 start:
206 ldi temp,low(RAMEND) ; top of memory
207 out SPL,temp ; init stack pointer
208 ldi temp,high(RAMEND) ; top of memory
209 out SPH,temp ; init stack pointer
210
211 ; - Kill wdt
212 wdr
213 #if defined __ATmega8__
214 ldi temp,0
215 out MCUCSR,temp
216
217 ldi temp,(1<<WDCE) | (1<<WDE)
218 out WDTCSR,temp
219 ldi temp,(1<<WDCE)
220 out WDTCSR,temp
221 #else
222 ldi temp,0
223 out MCUSR,temp
224
225 ldi temp,(1<<WDCE) | (1<<WDE)
226 sts WDTCSR,temp
227 ldi temp,(1<<WDCE)
228 sts WDTCSR,temp
229 #endif
230
231 ; - Setup Ports
232 ldi temp,PB_OUTPUT_MASK
233 out DDRB,temp
234 ldi temp,PD_OUTPUT_MASK
235 out DDRD,temp
236 ldi temp,PC_OUTPUT_MASK
237 out DDRC,temp
238
239 sbi PORTC,ram_w
240 sbi PORTC,ram_cas
241 sbi PORTB,ram_ras
242 sbi PORTD,ram_oe
243 sbi PORTD,mmc_cs
244
245
246 ; - Init serial port
247
248 ldi temp,0 ; reset receive buffer
249 sts rxcount,temp
250 sts rxidx_r,temp
251 sts rxidx_w,temp
252
253
254 #if defined __ATmega8__
255 ldi temp, (1<<TXEN) | (1<<RXEN) | (1<<RXCIE)
256 out UCSRB,temp
257 ldi temp, (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0)
258 out UCSRC,temp
259 ldi temp, HIGH(UBRR_VAL)
260 out UBRRH,temp
261 ldi temp, LOW(UBRR_VAL)
262 out UBRRL,temp
263 #else
264 ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
265 sts UCSR0B,temp
266 ldi temp, (1<<UCSZ01) | (1<<UCSZ00)
267 sts UCSR0C,temp
268 ldi temp, HIGH(UBRR_VAL)
269 sts UBRR0H,temp
270 ldi temp, LOW(UBRR_VAL)
271 sts UBRR0L,temp
272 #endif
273
274 ;Init timer2. Refresh-call should happen every (8ms/512)=312 cycles.
275
276 #ifdef __ATmega8__
277 ldi temp,REFR_CNT*2 ; 2 cycles per int
278 out OCR2,temp
279 ldi temp,(1<<WGM21) | REFR_CS ;CTC, clk/REFR_PRE
280 out TCCR2,temp
281 ldi temp, (1<<OCIE2)
282 out TIMSK,temp
283 #else
284 ldi temp,REFR_CNT ;=312 cycles
285 sts OCR2A,temp
286 ldi temp, (1<<WGM21)
287 sts TCCR2A,temp
288 ldi temp, REFR_CS ;clk/REFR_PRE
289 sts TCCR2B,temp
290 ldi temp,(1<<OCIE2A)
291 sts TIMSK2,temp
292 #endif
293
294
295 ; Init clock/timer system
296
297 ldi zl,low(timer_base)
298 ldi zh,high(timer_base)
299 ldi temp,0
300 ldi temp2,timer_size
301 ti_loop:
302 st z+,temp
303 dec temp2
304 brne ti_loop
305
306 ; Init timer 1 as 1 ms system clock tick.
307
308 #ifdef __ATmega8__
309 ldi temp,high(F_CPU/1000)
310 out OCR1AH,temp
311 ldi temp,low(F_CPU/1000)
312 out OCR1AL,temp
313 ldi temp,(1<<WGM12) | (1<<CS10) ;CTC, clk/1
314 out TCCR1B,temp
315 in temp,TIMSK
316 ori temp,(1<<OCIE1A)
317 out TIMSK,temp
318 #else
319 ldi temp,high(F_CPU/1000)
320 sts OCR1AH,temp
321 ldi temp,low(F_CPU/1000)
322 sts OCR1AL,temp
323 ldi temp,(1<<WGM12) | (1<<CS10) ;CTC, clk/1
324 sts TCCR1B,temp
325 lds temp,TIMSK1
326 ori temp,(1<<OCIE1A)
327 sts TIMSK1,temp
328 #endif
329 sei
330
331
332 .if BOOTWAIT
333 ldi temp,10
334 rcall delay_ms
335
336 .endif
337
338 rcall printstr
339 .db "CPM on an AVR, v1.0",13,0,0
340
341
342 rcall printstr
343 .db "Initing mmc...",13,0
344 rcall mmcInit
345
346
347 .if MEMTEST
348 rcall printstr
349 .db "Testing RAM: fill...",0,0
350
351 ;Fill RAM
352 ldi adrl,0
353 ldi adrh,0
354 ramtestw:
355 mov temp,adrh
356 eor temp,adrl
357 rcall memwritebyte
358 ldi temp,1
359 ldi temp2,0
360 add adrl,temp
361 adc adrh,temp2
362 brcc ramtestw
363 rcall printstr
364 .db "wait...",0
365
366 ldi temp2,8
367 ramtestwl:
368 ldi temp,255
369 rcall delay_ms
370 dec temp2
371 brne ramtestwl
372
373 rcall printstr
374 .db "reread...",13,0,0
375
376 ;re-read RAM
377 ldi adrl,0
378 ldi adrh,0
379 ramtestr:
380 rcall memreadbyte
381 mov temp2,adrh
382 eor temp2,adrl
383 cp temp,temp2
384 breq ramtestrok
385 rcall printhex
386 ldi temp,'<'
387 rcall uartPutc
388 mov temp,adrh
389 eor temp,adrl
390 rcall printhex
391 ldi temp,'@'
392 rcall uartPutc
393 mov temp,adrh
394 rcall printhex
395 mov temp,adrl
396 rcall printhex
397 ldi temp,13
398 rcall uartPutc
399 ramtestrok:
400 ldi temp,1
401 ldi temp2,0
402 add adrl,temp
403 adc adrh,temp2
404 brcc ramtestr
405
406 .endif
407
408 .if MEMFILL_CB
409 ;Fill ram with cbs, which (for now) will trigger an invalid opcode error.
410 ldi adrl,0
411 ldi adrh,0
412 ramfillw:
413 ldi temp,0xcb
414 rcall memwritebyte
415 ldi temp,1
416 ldi temp2,0
417 add adrl,temp
418 adc adrh,temp2
419 brcc ramfillw
420 .endif
421
422
423
424 ;Load initial sector from MMC (512 bytes)
425 ldi adrh,0
426 ldi adrl,0
427 rcall mmcReadSect
428
429 ;Save to Z80 RAM (only 128 bytes because that's retro)
430 ldi zl,low(sectbuff)
431 ldi zh,high(sectbuff)
432 ldi adrh,0x20
433 ldi adrl,0x00
434 iplwriteloop:
435 ld temp,z+
436 push zh
437 push zl
438 rcall memWriteByte
439 pop zl
440 pop zh
441 ldi temp,1
442 ldi temp2,0
443 add adrl,temp
444 adc adrh,temp2
445 cpi zl,low(sectbuff+128)
446 brne iplwriteloop
447 cpi zh,high(sectbuff+128)
448 brne iplwriteloop
449
450
451
452 ;Init z80
453 ldi temp,0x00
454 mov z_pcl,temp
455 ldi temp,0x20
456 mov z_pch,temp
457
458 ldi trace,0
459 rcall printstr
460 .db 13,"Ok, CPU is live!",13,0,0
461
462 main:
463 ldi trace,0
464 cpi z_pch,1
465 brlo notraceon
466 cpi z_pch,$dc
467 brsh notraceon
468 ldi trace,1
469 notraceon:
470
471
472 .if PRINT_PC
473 cpi z_pch,1
474 brlo noprintpc
475 cpi z_pch,0xdc
476 brsh noprintpc
477
478 rcall printstr
479 .db "PC=",0
480 mov temp,z_pch
481 rcall printhex
482 mov temp,z_pcl
483 rcall printhex
484 ldi temp,10
485 rcall uartputc
486 noprintpc:
487 .endif
488
489 ; *** Stage 1: Fetch next opcode
490 mov adrl,z_pcl
491 mov adrh,z_pch
492 rcall memReadByte
493 adiw z_pcl,1
494
495
496 .if INS_DEBUG
497 cpi trace,0
498 breq notrace1
499 rcall printstr
500 .db "PC=",0
501 push temp
502 mov temp,adrh
503 rcall printhex
504 mov temp,adrl
505 rcall printhex
506 pop temp
507 rcall printstr
508 .db ", opcode=",0
509 rcall printhex
510 notrace1:
511 .endif
512
513 ; *** Stage 2: Decode it using the ins_table.
514 ldi temp2,0
515 ldi zl,low(inst_table*2)
516 ldi zh,high(inst_table*2)
517 add zl,temp
518 adc zh,temp2
519 add zl,temp
520 adc zh,temp2
521 lpm insdecl,Z+
522 lpm insdech,Z
523
524 .if INS_DEBUG
525 cpi trace,0
526 breq notrace2
527 rcall printstr
528 .db ", decoded=",0
529 mov temp,insdech
530 rcall printhex
531 mov temp,insdecl
532 rcall printhex
533 rcall printstr
534 .db ".",13,0
535 notrace2:
536 .endif
537
538 ; *** Stage 3: Fetch operand. Use the fetch jumptable for this.
539 mov temp,insdecl
540 andi temp,0x1F
541 cpi temp,0
542 breq nofetch
543 ldi temp2,0
544 lsl temp
545 ldi zl,low(fetchjumps*2)
546 ldi zh,high(fetchjumps*2)
547 add zl,temp
548 adc zh,temp2
549 lpm temp,Z+
550 lpm temp2,Z
551 mov zl,temp
552 mov zh,temp2
553 icall
554
555 .if INS_DEBUG
556 cpi trace,0
557 breq notrace3
558 rcall printstr
559 .db "pre: oph:l=",0
560 mov temp,oph
561 rcall printhex
562 mov temp,opl
563 rcall printhex
564 rcall printstr
565 .db " -- ",0
566 notrace3:
567 .endif
568
569 nofetch:
570 ; *** Stage 4: Execute operation :) Use the op jumptable for this.
571 mov temp,insdech
572 andi temp,0xFC
573 lsr temp
574 cpi temp,0
575 breq nooper
576 ldi zl,low(opjumps*2)
577 ldi zh,high(opjumps*2)
578 ldi temp2,0
579 add zl,temp
580 adc zh,temp2
581 lpm temp,Z+
582 lpm temp2,Z
583 mov zl,temp
584 mov zh,temp2
585 icall
586
587 .if INS_DEBUG
588 cpi trace,0
589 breq notrace4
590 rcall printstr
591 .db ",post:oph:l=",0
592 mov temp,oph
593 rcall printhex
594 mov temp,opl
595 rcall printhex
596 notrace4:
597 .endif
598
599 nooper:
600 ; *** Stage 5: Store operand. Use the store jumptable for this.
601 swap insdecl
602 swap insdech
603 mov temp,insdecl
604 andi temp,0x0E
605 andi insdech,0x30
606 or temp,insdech
607 breq nostore
608 ldi zl,low(storejumps*2)
609 ldi zh,high(storejumps*2)
610 ldi temp2,0
611 add zl,temp
612 adc zh,temp2
613 lpm temp,Z+
614 lpm temp2,Z
615 mov zl,temp
616 mov zh,temp2
617 icall
618
619 .if INS_DEBUG
620 cpi trace,0
621 breq notrace5
622 rcall printstr
623 .db ", stored.",0
624 notrace5:
625 .endif
626
627 nostore:
628
629 .if INS_DEBUG
630 cpi trace,0
631 breq notrace6
632 rcall printstr
633 .db 13,0
634 notrace6:
635 .endif
636
637 ;All done. Neeeext!
638 rjmp main
639
640
641 ; ----------------Virtual peripherial interface ------
642
643 ;The hw is modelled to make writing a CPM BIOS easier.
644 ;Ports:
645 ;0 - Con status. Returns 0xFF if the UART has a byte, 0 otherwise.
646 ;1 - Console input, aka UDR.
647 ;2 - Console output
648 ;16 - Track select
649 ;18 - Sector select
650 ;20 - Write addr l
651 ;21 - Write addr h
652 ;22 - Trigger - write 1 to read, 2 to write a sector using the above info.
653 ; This will automatically move track, sector and dma addr to the next sector.
654
655 ;Called with port in temp2. Should return value in temp.
656 portRead:
657 cpi temp2,0
658 breq conStatus
659 cpi temp2,1
660 breq conInp
661
662 cpi temp2,TIMER_MSECS
663 brlo pr_noclock
664 cpi temp2,TIMER_MSECS+6
665 brsh pr_noclock
666 rjmp clockget
667
668 pr_noclock:
669 ldi temp,0xFF
670 ret
671
672 ;Called with port in temp2 and value in temp.
673 portWrite:
674 cpi temp2,0
675 breq dbgOut
676 cpi temp2,2
677 breq conOut
678 cpi temp2,16
679 breq dskTrackSel
680 cpi temp2,18
681 breq dskSecSel
682 cpi temp2,20
683 breq dskDmaL
684 cpi temp2,21
685 breq dskDmaH
686 cpi temp2,22
687 breq dskDoIt
688
689 cpi temp2,TIMERPORT
690 brlo pw_noclock
691 cpi temp2,TIMER_MSECS+6
692 brsh pw_noclock
693 rjmp clockput
694
695 pw_noclock:
696 ret
697
698
699 conStatus:
700
701 lds temp,rxcount
702 tst temp
703 breq PC+2
704 ldi temp,0xff
705 ret
706
707 conInp:
708 rcall uartGetc
709 ret
710
711 dbgOut:
712 rcall printstr
713 .db "Debug: ",0
714 rcall printhex
715 rcall printstr
716 .db 13,0
717 ret
718
719 conOut:
720 rcall uartputc
721 ret
722
723
724
725 dskTrackSel:
726 mov dsk_trk,temp
727 ret
728
729 dskSecSel:
730 mov dsk_sec,temp
731 ret
732
733 dskDmal:
734 mov dsk_dmal,temp
735 ret
736
737 dskDmah:
738 mov dsk_dmah,temp
739 ret
740
741 dskDoIt:
742 .if DISK_DEBUG
743 push temp
744 rcall printstr
745 .db "Disk read: track ",0
746 mov temp,dsk_trk
747 rcall printhex
748 rcall printstr
749 .db " sector ",0
750 mov temp,dsk_sec
751 rcall printhex
752 rcall printstr
753 .db " dma-addr ",0
754 mov temp,dsk_dmah
755 rcall printhex
756 mov temp,dsk_dmal
757 rcall printhex
758 rcall printstr
759 .db ".",13,0
760 pop temp
761 .endif
762
763 ;First, convert track/sector to an LBA address (in 128byte blocks)
764 push temp
765 mov adrl,dsk_sec
766 ldi adrh,0
767 mov temp2,dsk_trk
768 dskXlateLoop:
769 cpi temp2,0
770 breq dskXlateLoopEnd
771 ldi temp,26
772 add adrl,temp
773 ldi temp,0
774 adc adrh,temp
775 dec temp2
776 rjmp dskXlateLoop
777 dskXlateLoopEnd:
778 pop temp
779
780 ;Now, see what has to be done.
781 cpi temp,1
782 breq dskDoItRead
783 cpi temp,2
784 breq dskDoItWrite
785
786 dskDoItRead:
787 push adrl
788 ;Convert from 128-byte LBA blocks to 512-byte LBA blocks
789 lsr adrh
790 ror adrl
791 lsr adrh
792 ror adrl
793 ;Read 512-byte sector
794 rcall mmcReadSect
795 pop adrl
796
797 ;Now, move the correct portion of the sector from AVR ram to Z80 ram
798 ldi zl,low(sectbuff)
799 ldi zh,high(sectbuff)
800 ldi temp,128
801 ldi temp2,0
802 sbrc adrl,0
803 add zl,temp
804 sbrc adrl,0
805 adc zh,temp2
806 sbrc adrl,1
807 inc zh
808
809 mov adrh,dsk_dmah
810 mov adrl,dsk_dmal
811
812 ldi temp2,128
813 dskDoItReadMemLoop:
814 push temp2
815 ld temp,z+
816 push zh
817 push zl
818 rcall memWriteByte
819 pop zl
820 pop zh
821 ldi temp,1
822 ldi temp2,0
823 add adrl,temp
824 adc adrh,temp2
825 pop temp2
826 dec temp2
827 brne dskDoItReadMemLoop
828 ret
829
830 dskDoItWrite:
831 ;The write routines is a bit naive: it'll read the 512-byte sector the 128byte CPM-sector
832 ;resides in into memory, will overwrite the needed 128 byte with the Z80s memory buffer
833 ;and will then write it back to disk. In theory, this would mean that every 512 bytes
834 ;written will take 4 write cycles, while theoretically the writes could be deferred so we
835 ;would only have to do one write cycle.
836
837 .if DISK_DEBUG
838 push temp
839 rcall printstr
840 .db "Disk write: track ",0
841 mov temp,dsk_trk
842 rcall printhex
843 rcall printstr
844 .db " sector ",0
845 mov temp,dsk_sec
846 rcall printhex
847 rcall printstr
848 .db " dma-addr ",0
849 mov temp,dsk_dmah
850 rcall printhex
851 mov temp,dsk_dmal
852 rcall printhex
853 rcall printstr
854 .db ".",13,0
855 pop temp
856 .endif
857
858
859 push adrl
860 push adrh
861 ;Convert from 128-byte LBA blocks to 512-byte LBA blocks
862 lsr adrh
863 ror adrl
864 lsr adrh
865 ror adrl
866 ;Read 512-byte sector
867 rcall mmcReadSect
868 pop adrh
869 pop adrl
870
871 push adrl
872 push adrh
873
874 ;Copy the data from the Z80 DMA buffer in external memory to the right place in the
875 ;sector buffer.
876 ;Now, move the correct portion of the sector from AVR ram to Z80 ram
877 ldi zl,low(sectbuff)
878 ldi zh,high(sectbuff)
879 ldi temp,128
880 ldi temp2,0
881 sbrc adrl,0
882 add zl,temp
883 sbrc adrl,0
884 adc zh,temp2
885 sbrc adrl,1
886 inc zh
887 mov adrh,dsk_dmah
888 mov adrl,dsk_dmal
889 ldi temp2,128
890 dskDoItWriteMemLoop:
891 push temp2
892
893 push zh
894 push zl
895 rcall memReadByte
896 pop zl
897 pop zh
898 st z+,temp
899 ldi temp,1
900 ldi temp2,0
901 add adrl,temp
902 adc adrh,temp2
903
904 pop temp2
905 dec temp2
906 brne dskDoItWriteMemLoop
907
908 pop adrh
909 pop adrl
910
911 ;Convert from 128-byte LBA blocks to 512-byte LBA blocks
912 lsr adrh
913 ror adrl
914 lsr adrh
915 ror adrl
916 ;Write the sector back.
917 rcall mmcWriteSect
918
919 ;All done :)
920 ret
921
922
923 ; ----------------- MMC/SD routines ------------------
924
925 mmcByteNoSend:
926 ldi temp,0xff
927 mmcByte:
928
929 .if MMC_DEBUG
930 push zl
931 push zh
932 rcall printstr
933 .db "MMC: <--",0
934 rcall printhex
935 .endif
936
937 out SPDR,temp
938 mmcWrByteW:
939 in temp,SPSR
940 sbrs temp,7
941 rjmp mmcWrByteW
942 in temp,SPDR
943
944 .if MMC_DEBUG
945 push temp
946 rcall printstr
947 .db ", -->",0
948 rcall printhex
949 rcall printstr
950 .db ".",13,0
951 pop temp
952 pop zh
953 pop zl
954 .endif
955 ret
956
957
958 ;Wait till the mmc answers with the response in temp2, or till a timeout happens.
959 mmcWaitResp:
960 ldi zl,0
961 ldi zh,0
962 mmcWaitResploop:
963 rcall mmcByteNoSend
964 cpi temp,0xff
965 brne mmcWaitResploopEnd
966 adiw zl,1
967 cpi zh,255
968 breq mmcWaitErr
969 rjmp mmcWaitResploop
970 mmcWaitResploopEnd:
971 ret
972
973
974 mmcWaitErr:
975 mov temp,temp2
976 rcall printhex
977 rcall printstr
978 .db ": Error: MMC resp timeout!",13,0
979 rjmp resetAVR
980
981 mmcInit:
982 ldi temp,0x53
983 out SPCR,temp
984
985 ;Init start: send 80 clocks with cs disabled
986 sbi PORTD,mmc_cs
987
988 ldi temp2,20
989 mmcInitLoop:
990 mov temp,temp2
991 rcall mmcByte
992 dec temp2
993 brne mmcInitLoop
994
995 cbi PORTD,mmc_cs
996 rcall mmcByteNoSend
997 rcall mmcByteNoSend
998 rcall mmcByteNoSend
999 rcall mmcByteNoSend
1000 rcall mmcByteNoSend
1001 rcall mmcByteNoSend
1002 sbi PORTD,mmc_cs
1003 rcall mmcByteNoSend
1004 rcall mmcByteNoSend
1005 rcall mmcByteNoSend
1006 rcall mmcByteNoSend
1007
1008 ;Send init command
1009 cbi PORTD,mmc_cs
1010 ldi temp,0xff ;dummy
1011 rcall mmcByte
1012 ldi temp,0xff ;dummy
1013 rcall mmcByte
1014 ldi temp,0x40 ;cmd
1015 rcall mmcByte
1016 ldi temp,0 ;pxh
1017 rcall mmcByte
1018 ldi temp,0 ;pxl
1019 rcall mmcByte
1020 ldi temp,0 ;pyh
1021 rcall mmcByte
1022 ldi temp,0 ;pyl
1023 rcall mmcByte
1024 ldi temp,0x95 ;crc
1025 rcall mmcByte
1026 ldi temp,0xff ;return byte
1027 rcall mmcByte
1028
1029 ldi temp2,0
1030 rcall mmcWaitResp
1031
1032 sbi PORTD,mmc_cs
1033 rcall mmcByteNoSend
1034
1035
1036 ;Read OCR till card is ready
1037 ldi temp2,150
1038 mmcInitOcrLoop:
1039 push temp2
1040
1041 cbi PORTD,mmc_cs
1042 ldi temp,0xff ;dummy
1043 rcall mmcByte
1044 ldi temp,0x41 ;cmd
1045 rcall mmcByte
1046 ldi temp,0 ;pxh
1047 rcall mmcByte
1048 ldi temp,0 ;pxl
1049 rcall mmcByte
1050 ldi temp,0 ;pyh
1051 rcall mmcByte
1052 ldi temp,0 ;pyl
1053 rcall mmcByte
1054 ldi temp,0x95 ;crc
1055 rcall mmcByte
1056 rcall mmcByteNoSend
1057
1058 ldi temp2,1
1059 rcall mmcWaitResp
1060 cpi temp,0
1061 breq mmcInitOcrLoopDone
1062
1063 sbi PORTD,mmc_cs
1064 rcall mmcByteNoSend
1065
1066 pop temp2
1067 dec temp2
1068 cpi temp2,0
1069 brne mmcInitOcrLoop
1070
1071 ldi temp,4
1072 rjmp mmcWaitErr
1073
1074 mmcInitOcrLoopDone:
1075 pop temp2
1076 sbi PORTD,mmc_cs
1077 rcall mmcByteNoSend
1078
1079 ldi temp,0
1080 out SPCR,temp
1081 ret
1082
1083
1084 ;Call this with adrh:adrl = sector number
1085 ;16bit lba address means a max reach of 32M.
1086 mmcReadSect:
1087 ldi temp,0x50
1088 out SPCR,temp
1089
1090 cbi PORTD,mmc_cs
1091 rcall mmcByteNoSend
1092 ldi temp,0x51 ;cmd (read sector)
1093 rcall mmcByte
1094 ldi temp,0
1095 lsl adrl
1096 rol adrh
1097 rol temp
1098 rcall mmcByte
1099 mov temp,adrh ;pxl
1100 rcall mmcByte
1101 mov temp,adrl ;pyh
1102 rcall mmcByte
1103 ldi temp,0 ;pyl
1104 rcall mmcByte
1105 ldi temp,0x95 ;crc
1106 rcall mmcByte
1107 ldi temp,0xff ;return byte
1108 rcall mmcByte
1109
1110 ;resp
1111 ldi temp2,2
1112 rcall mmcWaitResp
1113
1114 ;data token
1115 ldi temp2,3
1116 rcall mmcWaitResp
1117
1118 ;Read sector to AVR RAM
1119 ldi zl,low(sectbuff)
1120 ldi zh,high(sectbuff)
1121 mmcreadloop:
1122 rcall mmcByteNoSend
1123 st z+,temp
1124 cpi zl,low(sectbuff+512)
1125 brne mmcreadloop
1126 cpi zh,high(sectbuff+512)
1127 brne mmcreadloop
1128
1129 ;CRC
1130 rcall mmcByteNoSend
1131 rcall mmcByteNoSend
1132
1133 sbi PORTD,mmc_cs
1134 rcall mmcByteNoSend
1135
1136 ldi temp,0
1137 out SPCR,temp
1138 ret
1139
1140
1141 ;Call this with adrh:adrl = sector number
1142 ;16bit lba address means a max reach of 32M.
1143 mmcWriteSect:
1144 ldi temp,0x50
1145 out SPCR,temp
1146
1147 cbi PORTD,mmc_cs
1148 rcall mmcByteNoSend
1149
1150 ldi temp,0x58 ;cmd (write sector)
1151 rcall mmcByte
1152 ldi temp,0
1153 lsl adrl
1154 rol adrh
1155 rol temp
1156 rcall mmcByte
1157 mov temp,adrh ;pxl
1158 rcall mmcByte
1159 mov temp,adrl ;pyh
1160 rcall mmcByte
1161 ldi temp,0 ;pyl
1162 rcall mmcByte
1163 ldi temp,0x95 ;crc
1164 rcall mmcByte
1165 ldi temp,0xff ;return byte
1166 rcall mmcByte
1167
1168 ;resp
1169 ldi temp2,1
1170 rcall mmcWaitResp
1171
1172 ;Send data token
1173 ldi temp,0xfe
1174 rcall mmcByte
1175
1176 ;Write sector from AVR RAM
1177 ldi zl,low(sectbuff)
1178 ldi zh,high(sectbuff)
1179 mmcwriteloop:
1180 ld temp,z+
1181 rcall mmcByte
1182 cpi zl,low(sectbuff+512)
1183 brne mmcwriteloop
1184 cpi zh,high(sectbuff+512)
1185 brne mmcwriteloop
1186
1187 ;CRC
1188 rcall mmcByteNoSend
1189 rcall mmcByteNoSend
1190
1191 ;Status. Ignored for now.
1192 rcall mmcByteNoSend
1193
1194 ;Wait till the mmc has written everything
1195 mmcwaitwritten:
1196 rcall mmcByteNoSend
1197 cpi temp,0xff
1198 brne mmcwaitwritten
1199
1200 sbi PORTD,mmc_cs
1201 rcall mmcByteNoSend
1202
1203 ldi temp,0
1204 out SPCR,temp
1205 ret
1206
1207
1208 ;Set up wdt to time out after 1 sec.
1209 resetAVR:
1210 cli
1211 #if defined __ATmega8__
1212 ldi temp,(1<<WDCE)
1213 out WDTCSR,temp
1214 ldi temp,(1<<WDCE) | (1<<WDE) | (110<<WDP0)
1215 out WDTCSR,temp
1216 #else
1217 ldi temp,(1<<WDCE)
1218 sts WDTCSR,temp
1219 ldi temp,(1<<WDCE) | (1<<WDE) | (110<<WDP0)
1220 sts WDTCSR,temp
1221 #endif
1222 resetwait:
1223 rjmp resetwait
1224
1225
1226 ; ------------------ DRAM routines -------------
1227
1228 ; TODO:
1229
1230 #if DRAM_DQ_ORDER == 1
1231 #define CLASSIC_DRAM 0
1232 #else
1233 #define CLASSIC_DRAM 1 /* Change manualy, if you want new hw w/ old sw */
1234 #endif
1235
1236
1237 #if DRAM_DQ_ORDER == 0
1238 #if CLASSIC_DRAM == 1
1239 #error "Old harware can not work with new software!"
1240 #endif
1241 #endif
1242
1243 ; ****************************************************************************
1244
1245 #if CLASSIC_DRAM
1246
1247 ; ********************** DRAM routines from Sprite_tm ************************
1248
1249 ;Sends the address in zh:zl to the ram
1250 dram_setaddr:
1251 push temp
1252 in temp,portd
1253 andi temp,0x17
1254 out portd,temp
1255 in temp,portb
1256 andi temp,0xE0
1257 out portb,temp
1258 sbrc zl,0
1259 sbi portb,ram_a0
1260 sbrc zl,1
1261 sbi portb,ram_a1
1262 sbrc zl,2
1263 sbi portb,ram_a2
1264 sbrc zl,3
1265 sbi portb,ram_a3
1266 sbrc zl,4
1267 sbi portb,ram_a4
1268 sbrc zl,5
1269 sbi portd,ram_a5
1270 sbrc zl,6
1271 sbi portd,ram_a6
1272 sbrc zl,7
1273 sbi portd,ram_a7
1274 sbrc zh,0
1275 sbi portd,ram_a8
1276 pop temp
1277 ret
1278
1279 dram_getnibble:
1280 andi temp,0xf0
1281 sbic pinc,ram_d0
1282 ori temp,0x1
1283 sbic pinc,ram_d1
1284 ori temp,0x2
1285 sbic pinc,ram_d2
1286 ori temp,0x4
1287 sbic pinc,ram_d3
1288 ori temp,0x8
1289 ret
1290
1291 dram_sendnibble:
1292 push temp2
1293 in temp2,portc
1294 andi temp2,~RAM_DQ_MASK
1295
1296 sbrc temp,0
1297 ori temp2,(1<<ram_d0)
1298 sbrc temp,1
1299 ori temp2,(1<<ram_d1)
1300 sbrc temp,2
1301 ori temp2,(1<<ram_d2)
1302 sbrc temp,3
1303 ori temp2,(1<<ram_d3)
1304
1305 out portc,temp2
1306 pop temp2
1307 ret
1308
1309
1310 ;Loads the byte on address adrh:adrl into temp.
1311 dram_read:
1312 cli
1313 mov zl,adrh
1314 ldi zh,0
1315 mov temp2,adrl
1316 lsl temp2
1317 rol zl
1318 rol zh
1319 ;z=addr[15-7]
1320 rcall dram_setaddr
1321 cbi portb,ram_ras
1322
1323 ldi zh,0
1324 mov zl,adrl
1325 andi zl,0x7F
1326 rcall dram_setaddr
1327 nop
1328 cbi portc,ram_cas
1329 nop
1330 nop
1331 cbi portd,ram_oe
1332 nop
1333 rcall dram_getnibble
1334 sbi portd,ram_oe
1335 swap temp
1336 sbi portc,ram_cas
1337
1338 ldi zh,0
1339 mov zl,adrl
1340 ori zl,0x80
1341 rcall dram_setaddr
1342 nop
1343 cbi portc,ram_cas
1344 nop
1345 cbi portd,ram_oe
1346 nop
1347 nop
1348 rcall dram_getnibble
1349
1350 sbi portd,ram_oe
1351 sbi portc,ram_cas
1352 sbi portb,ram_ras
1353 sei
1354 ret
1355
1356 ;Writes the byte in temp to adrh:adrl
1357 dram_write:
1358 cli
1359
1360 in temp2,ddrc
1361 ori temp2,RAM_DQ_MASK
1362 out ddrc,temp2
1363
1364 rcall dram_sendnibble
1365
1366 mov zl,adrh
1367 ldi zh,0
1368 mov temp2,adrl
1369 lsl temp2
1370 rol zl
1371 rol zh
1372 ;z=addr[15-7]
1373 rcall dram_setaddr
1374 nop
1375 nop
1376 cbi portb,ram_ras
1377
1378 ldi zh,0
1379 mov zl,adrl
1380 ori zl,0x80
1381 rcall dram_setaddr
1382 nop
1383 nop
1384 cbi portc,ram_cas
1385 nop
1386 nop
1387 cbi portc,ram_w
1388 nop
1389 nop
1390 nop
1391 sbi portc,ram_w
1392 sbi portc,ram_cas
1393
1394
1395 ldi zh,0
1396 mov zl,adrl
1397 andi zl,0x7F
1398 rcall dram_setaddr
1399 swap temp
1400 rcall dram_sendnibble
1401 cbi portc,ram_cas
1402 nop
1403 nop
1404 cbi portc,ram_w
1405 nop
1406 nop
1407 sbi portc,ram_w
1408 nop
1409 nop
1410 sbi portc,ram_cas
1411 sbi portb,ram_ras
1412
1413 in temp,ddrc
1414 andi temp,~RAM_DQ_MASK
1415 out ddrc,temp
1416 in temp,portc
1417 andi temp,~RAM_DQ_MASK
1418 out portc,temp
1419 sei
1420 ret
1421 #endif /* CLASSIC_DRAM == 1 */
1422
1423 ; ****************************************************************************
1424
1425 #if ! CLASSIC_DRAM
1426
1427 ; ***************************** New DRAM routines ****************************
1428
1429 ; Defines how the dram nibbles are arganized.
1430 ; RAMORG == 0 : A7 == 0: low nibble, A7 == 1: high nibble (Original Sprite_tm design)
1431 ; RAMORG == 1 : A8 == 0: low nibble, A8 == 1: high nibble (faster)
1432 ;
1433 #define RAMORG 1
1434
1435 #if RAMORG == 0
1436 ;Sends the address in zh:zl to the ram
1437 dram_setaddr:
1438 push temp
1439 in temp,PORTB
1440 andi temp,~RAM_AL_MASK
1441 sbrc zl,0
1442 ori temp,(1<<ram_a0)
1443 sbrc zl,1
1444 ori temp,(1<<ram_a1)
1445 sbrc zl,2
1446 ori temp,(1<<ram_a2)
1447 sbrc zl,3
1448 ori temp,(1<<ram_a3)
1449 sbrc zl,4
1450 ori temp,(1<<ram_a4)
1451 out PORTB,temp
1452
1453 in temp,PORTD
1454 andi temp,~RAM_AH_MASK
1455 sbrc zl,5
1456 ori temp,(1<<ram_a5)
1457 sbrc zl,6
1458 ori temp,(1<<ram_a6)
1459 sbrc zl,7
1460 ori temp,(1<<ram_a7)
1461 sbrc zh,0
1462 ori temp,(1<<ram_a8)
1463 out PORTD,temp
1464 pop temp
1465 #else /* RAMORG == 1 */
1466 .macro DRAM_SETADDR
1467 push temp
1468 in temp,PORTB
1469 andi temp,~RAM_AL_MASK
1470 sbrc @0,0
1471 ori temp,(1<<ram_a0)
1472 sbrc @0,1
1473 ori temp,(1<<ram_a1)
1474 sbrc @0,2
1475 ori temp,(1<<ram_a2)
1476 sbrc @0,3
1477 ori temp,(1<<ram_a3)
1478 sbrc @0,4
1479 ori temp,(1<<ram_a4)
1480 out PORTB,temp
1481
1482 in temp,PORTD
1483 andi temp,~RAM_AH_MASK
1484 sbrc @0,5
1485 ori temp,(1<<ram_a5)
1486 sbrc @0,6
1487 ori temp,(1<<ram_a6)
1488 sbrc @0,7
1489 ori temp,(1<<ram_a7)
1490 out PORTD,temp
1491 pop temp
1492 .endm
1493 ret
1494 #endif /* RAMORG */
1495
1496 .macro DRAM_SENDNIBBLE
1497 in temp2,PORTC
1498 andi temp2,~RAM_DQ_MASK
1499 andi temp,RAM_DQ_MASK
1500 or temp2,temp
1501 out PORTC,temp2
1502 .endm
1503
1504
1505 ;Loads the byte on address adrh:adrl into temp.
1506 ;must not alter adrh:adrl
1507
1508 dram_read:
1509 cli
1510 #if RAMORG == 0
1511 mov zl,adrh
1512 ldi zh,0
1513 mov temp2,adrl
1514 lsl temp2
1515 rol zl
1516 rol zh
1517 ;z=addr[15-7]
1518 rcall dram_setaddr
1519 cbi PORTB,ram_ras
1520
1521 ldi zh,0
1522 mov zl,adrl
1523 andi zl,0x7F
1524 rcall dram_setaddr
1525 cbi PORTC,ram_cas
1526 cbi PORTD,ram_oe
1527 ldi zh,0
1528 in temp,PINC
1529 andi temp,0x0f
1530 swap temp
1531 sbi PORTC,ram_cas
1532
1533 mov zl,adrl
1534 ori zl,0x80
1535 rcall dram_setaddr
1536 cbi PORTC,ram_cas
1537 nop
1538 in temp2,PINC
1539 andi temp2,0x0f
1540 or temp,temp2
1541
1542 sbi PORTD,ram_oe
1543 sbi PORTC,ram_cas
1544 sbi PORTB,ram_ras
1545 #else
1546 cbi PORTD,ram_a8
1547 DRAM_SETADDR adrh
1548 cbi PORTB,ram_ras
1549
1550 DRAM_SETADDR adrl
1551 cbi PORTD,ram_oe
1552 cbi PORTC,ram_cas
1553 nop
1554 nop
1555 in temp,PINC
1556 sbi PORTC,ram_cas
1557
1558 sbi PORTD,ram_a8
1559 cbi PORTC,ram_cas
1560 andi temp,0x0f
1561 swap temp
1562 in temp2,PINC
1563 andi temp2,0x0f
1564 or temp,temp2
1565 swap temp
1566
1567 sbi PORTD,ram_oe
1568 sbi PORTC,ram_cas
1569 sbi PORTB,ram_ras
1570 #endif
1571 sei
1572 ret
1573
1574
1575 ;Writes the byte in temp to adrh:adrl
1576 ;must not alter adrh:adrl
1577
1578 dram_write:
1579 cli
1580 #if RAMORG == 0
1581 in temp2,DDRC ;DRAM data ports as outputs
1582 ori temp2,RAM_DQ_MASK
1583 out DDRC,temp2
1584
1585 push temp
1586 DRAM_SENDNIBBLE
1587 pop temp
1588
1589 mov zl,adrh
1590 ldi zh,0
1591 mov temp2,adrl
1592 lsl temp2
1593 rol zl
1594 rol zh
1595 ;z=addr[15-7]
1596 rcall dram_setaddr
1597 cbi PORTB,ram_ras
1598
1599 ldi zh,0
1600 mov zl,adrl
1601 ori zl,0x80
1602 cbi PORTC,ram_w ;early write
1603 rcall dram_setaddr
1604 cbi PORTC,ram_cas
1605 sbi PORTC,ram_cas
1606
1607 ldi zh,0
1608 mov zl,adrl
1609 andi zl,0x7F
1610 rcall dram_setaddr
1611 swap temp
1612
1613 DRAM_SENDNIBBLE
1614
1615 cbi PORTC,ram_cas
1616 sbi PORTC,ram_cas
1617 sbi PORTC,ram_w
1618 sbi PORTB,ram_ras
1619
1620 in temp,DDRC
1621 andi temp,~RAM_DQ_MASK
1622 out DDRC,temp
1623 in temp,PORTC
1624 andi temp,~RAM_DQ_MASK
1625 out PORTC,temp
1626 #else /* RAMORG == 1 */
1627 in temp2,DDRC ;DRAM data ports as outputs
1628 ori temp2,RAM_DQ_MASK
1629 out DDRC,temp2
1630
1631 push temp
1632 DRAM_SENDNIBBLE
1633 pop temp
1634
1635 cbi PORTD,ram_a8
1636 DRAM_SETADDR adrh
1637 cbi PORTB,ram_ras
1638
1639 cbi PORTC,ram_w ;early write
1640 DRAM_SETADDR adrl
1641 cbi PORTC,ram_cas
1642 sbi PORTC,ram_cas
1643
1644 sbi PORTD,ram_a8
1645 swap temp
1646
1647 DRAM_SENDNIBBLE
1648
1649 cbi PORTC,ram_cas
1650 sbi PORTC,ram_cas
1651 sbi PORTC,ram_w
1652 sbi PORTB,ram_ras
1653
1654 in temp,DDRC
1655 andi temp,~RAM_DQ_MASK
1656 out DDRC,temp
1657 in temp,PORTC
1658 andi temp,~RAM_DQ_MASK
1659 out PORTC,temp
1660 #endif /* RAMORG */
1661 sei
1662 ret
1663
1664 #endif /* CLASSIC_DRAM == 0 */
1665
1666 ; ****************************************************************************
1667
1668 ; refresh interupt; exec 2 cbr cycles
1669 refrint:
1670 ;4 CAS RAS
1671 cbi P_CAS,ram_cas ;2 1| 1|
1672 ; 1| 1|
1673 cbi P_RAS,ram_ras ;2 |0 1|
1674 ; |0 1|
1675 nop ;1 |0 |0
1676 ; nop ;1 |0 |0
1677 sbi P_RAS,ram_ras ;2 |0 |0
1678 ; |0 |0
1679 ; nop ;1 |0 |0
1680 cbi P_RAS,ram_ras ;2 |0 1|
1681 ; |0 1|
1682 sbi P_CAS,ram_cas ;2 |0 |0
1683 ; |0 |0
1684 sbi P_RAS,ram_ras ;2 1| |0
1685 ; 1| 1|
1686 reti ;4 --> 21 cycles
1687
1688 ; ****************************************************************************
1689
1690 ; ------------- system timer 10ms ---------------
1691 .dseg
1692
1693 delay_timer:
1694 .byte 1
1695 timer_base:
1696 timer_ms:
1697 .byte 2
1698 timer_s:
1699 .byte 4
1700 ; don't change order here, clock put/get depends on it.
1701 cntms_out: ; register for ms
1702 .byte 2
1703 utime_io: ; register for uptime.
1704 .byte 4
1705 cnt_1ms:
1706 .byte 2
1707 uptime:
1708 .byte 4
1709 timer_top:
1710 .equ timer_size = timer_top - timer_base
1711
1712 .equ clkofs = cnt_1ms-cntms_out
1713 .equ timerofs = cnt_1ms-timer_ms
1714
1715 .cseg
1716 sysclockint:
1717 push zl
1718 in zl,SREG
1719 push zl
1720 push zh
1721
1722 lds zl,delay_timer
1723 subi zl,1
1724 brcs syscl1
1725 sts delay_timer,zl
1726 syscl1:
1727 lds zl,cnt_1ms
1728 lds zh,cnt_1ms+1
1729 adiw z,1
1730
1731 sts cnt_1ms,zl
1732 sts cnt_1ms+1,zh
1733 cpi zl,low(1000)
1734 ldi zl,high(1000) ;doesn't change flags
1735 cpc zh,zl
1736 brlo syscl_end
1737
1738 ldi zl,0
1739 sts cnt_1ms,zl
1740 sts cnt_1ms+1,zl
1741
1742 lds zl,uptime+0
1743 inc zl
1744 sts uptime+0,zl
1745 brne syscl_end
1746 lds zl,uptime+1
1747 inc zl
1748 sts uptime+1,zl
1749 brne syscl_end
1750 lds zl,uptime+2
1751 inc zl
1752 sts uptime+2,zl
1753 brne syscl_end
1754 lds zl,uptime+3
1755 inc zl
1756 sts uptime+3,zl
1757
1758 syscl_end:
1759 pop zh
1760 pop zl
1761 out SREG,zl
1762 pop zl
1763 reti
1764
1765 ; wait for temp ms
1766
1767 delay_ms:
1768 sts delay_timer,temp
1769 dly_loop:
1770 lds temp,delay_timer
1771 cpi temp,0
1772 brne dly_loop
1773 ret
1774
1775 ;
1776
1777 clockget:
1778 ldi temp,0xFF
1779 subi temp2,TIMER_MSECS
1780 brcs clkget_end ;Port number in range?
1781 ldi zl,low(cntms_out)
1782 ldi zh,high(cntms_out)
1783 breq clkget_copy ;lowest byte requestet, latch clock
1784 cpi temp2,6
1785 brsh clkget_end ;Port number to high?
1786
1787 add zl,temp2
1788 brcc PC+2
1789 inc zh
1790 ld temp,z
1791 clkget_end:
1792 ret
1793
1794
1795
1796 clkget_copy:
1797 ldi temp2,6
1798 cli
1799 clkget_l:
1800 ldd temp,z+clkofs
1801 st z+,temp
1802 dec temp2
1803 brne clkget_l
1804 sei
1805 lds temp,cntms_out
1806 ;req. byte in temp
1807 ret
1808
1809 clockput:
1810 subi temp2,TIMERPORT
1811 brcs clkput_end ;Port number in range?
1812 brne clkput_1
1813
1814 ; clock control
1815
1816 cpi temp,starttimercmd
1817 breq timer_start
1818 cpi temp,quitTimerCmd
1819 breq timer_quit
1820 cpi temp,printTimerCmd
1821 breq timer_print
1822 cpi temp,uptimeCmd
1823 brne cp_ex
1824 rjmp uptime_print
1825 cp_ex:
1826 ret
1827
1828 timer_quit:
1829 rcall timer_print
1830 rjmp timer_start
1831
1832 clkput_1:
1833 dec temp2
1834 ldi zl,low(cntms_out)
1835 ldi zh,high(cntms_out)
1836 breq clkput_copy ;lowest byte requestet, latch clock
1837 cpi temp2,6
1838 brsh clkput_end ;Port number to high?
1839
1840 add zl,temp2
1841 brcc PC+2
1842 inc zh
1843 st z,temp
1844 clkput_end:
1845 ret
1846
1847 clkput_copy:
1848 st z,temp
1849 adiw z,5
1850 ldi temp2,6
1851 cli
1852 clkput_l:
1853 ldd temp,z+clkofs
1854 st z+,temp
1855 dec temp2
1856 brne clkput_l
1857 sei
1858 ret
1859
1860 ; start/reset timer
1861 ;
1862 timer_start:
1863 ldi zl,low(timer_ms)
1864 ldi zh,high(timer_ms)
1865 ldi temp2,6
1866 cli
1867 ts_loop:
1868 ldd temp,z+timerofs
1869 st z+,temp
1870 dec temp2
1871 brne ts_loop
1872 sei
1873 ret
1874
1875
1876 ; print timer
1877 ;
1878
1879 timer_print:
1880 push adrh
1881 push adrl
1882 push oph
1883 push opl
1884 ldi zl,low(timer_ms)
1885 ldi zh,high(timer_ms)
1886
1887 ; put ms on stack (16 bit)
1888
1889 cli
1890 ldd adrl,z+timerofs
1891 ld temp2,z+
1892 sub adrl,temp2
1893 ldd adrh,z+timerofs
1894 ld temp2,z+
1895 sbc adrh,temp2
1896 brsh tp_s
1897
1898 subi adrl,low(-1000)
1899 sbci adrh,high(-1000)
1900 sec
1901 tp_s:
1902 push adrh
1903 push adrl
1904
1905 ;
1906
1907 ldd temp,z+timerofs
1908 ld adrl,z+
1909 sbc temp,adrl
1910
1911 ldd temp2,z+timerofs
1912 ld adrh,z+
1913 sbc temp2,adrh
1914
1915 ldd opl,z+timerofs
1916 ld adrl,z+
1917 sbc opl,adrl
1918
1919 sei
1920 ldd oph,z+timerofs
1921 ld adrh,z+
1922 sbc oph,adrh
1923
1924 rcall printstr
1925 .db 13,"Timer running. Elapsed: ",0
1926 rcall print_ultoa
1927
1928 rcall printstr
1929 .db ",",0
1930 ldi opl,0
1931 ldi oph,0
1932 pop temp
1933 pop temp2
1934 rcall print_ultoa
1935 rcall printstr
1936 .db "s.",0,0
1937
1938 pop opl
1939 pop oph
1940 pop adrl
1941 pop adrh
1942 ret
1943
1944 uptime_print:
1945
1946 push oph
1947 push opl
1948 ldi zl,low(cnt_1ms)
1949 ldi zh,high(cnt_1ms)
1950
1951 cli
1952 ld temp,z+
1953 push temp
1954 ld temp,z+
1955 push temp
1956
1957 ld temp,z+
1958 ld temp2,z+
1959 ld opl,z+
1960 sei
1961 ld oph,z+
1962
1963 rcall printstr
1964 .db 13,"Uptime: ",0
1965
1966 rcall print_ultoa
1967 rcall printstr
1968 .db ",",0
1969
1970 ldi opl,0
1971 ldi oph,0
1972 pop temp2
1973 pop temp
1974 rcall print_ultoa
1975 rcall printstr
1976 .db "s.",0,0
1977
1978 pop opl
1979 pop oph
1980 ret
1981
1982
1983
1984 ; --------------- Debugging stuff ---------------
1985
1986 ;Print a unsigned lonng value to the uart
1987 ; oph:opl:temp2:temp = value
1988
1989 print_ultoa:
1990 push adrh
1991 push adrl
1992 push insdech
1993
1994 clr adrl ;adrl = stack level
1995
1996 ultoa1: ldi insdech, 32 ;adrh = oph:temp % 10
1997 clr adrh ;oph:temp /= 10
1998 ultoa2: lsl temp
1999 rol temp2
2000 rol opl
2001 rol oph
2002 rol adrh
2003 cpi adrh,10
2004 brcs ultoa3
2005 subi adrh,10
2006 inc temp
2007 ultoa3: dec insdech
2008 brne ultoa2
2009 cpi adrh, 10 ;adrh is a numeral digit '0'-'9'
2010 subi adrh, -'0'
2011 push adrh ;Stack it
2012 inc adrl
2013 ldi insdech,0
2014 cp temp,insdech ;Repeat until oph:temp gets zero
2015 cpc temp2,insdech
2016 cpc opl,insdech
2017 cpc oph,insdech
2018 brne ultoa1
2019
2020 ldi temp, '0'
2021 ultoa5: cpi adrl,3 ; at least 3 digits (ms)
2022 brge ultoa6
2023 push temp
2024 inc adrl
2025 rjmp ultoa5
2026
2027 ultoa6: pop temp ;Flush stacked digits
2028 rcall uartputc
2029 dec adrl
2030 brne ultoa6
2031
2032 pop insdech
2033 pop adrl
2034 pop adrh
2035 ret
2036
2037
2038 ;Prints the lower nibble of temp in hex to the uart
2039 printhexn:
2040 push temp
2041 andi temp,0xf
2042 cpi temp,0xA
2043 brlo printhexn_isno
2044 subi temp,-('A'-10)
2045 rcall uartputc
2046 pop temp
2047 ret
2048 printhexn_isno:
2049 subi temp,-'0'
2050 rcall uartputc
2051 pop temp
2052 ret
2053
2054 ;Prints temp in hex to the uart
2055 printhex:
2056 swap temp
2057 rcall printhexn
2058 swap temp
2059 rcall printhexn
2060 ret
2061
2062 ;Prints the zero-terminated string following the call statement. WARNING: Destroys temp.
2063 printstr:
2064 pop zh
2065 pop zl
2066 push temp
2067
2068 lsl zl
2069 rol zh
2070
2071 printstr_loop:
2072 lpm temp,z+
2073 cpi temp,0
2074 breq printstr_end
2075 rcall uartputc
2076 cpi temp,13
2077 brne printstr_loop
2078 ldi temp,10
2079 rcall uartputc
2080 rjmp printstr_loop
2081
2082 printstr_end:
2083 adiw zl,1
2084 lsr zh
2085 ror zl
2086
2087 pop temp
2088 push zl
2089 push zh
2090 ret
2091
2092
2093 ; --------------- AVR HW <-> Z80 periph stuff ------------------
2094
2095 .equ memReadByte = dram_read
2096 .equ memWriteByte = dram_write
2097
2098 ; --------------------------------------------------------------
2099
2100 .dseg
2101
2102 #define RXBUFMASK RXBUFSIZE-1
2103
2104 rxcount:
2105 .byte 1
2106 rxidx_w:
2107 .byte 1
2108 rxidx_r:
2109 .byte 1
2110 rxfifo:
2111 .byte RXBUFSIZE
2112 .byte 0
2113
2114 .cseg
2115
2116 ; Save received character in a circular buffer. Do nothing if buffer overflows.
2117
2118 rxint:
2119 push temp
2120 in temp,sreg
2121 push temp
2122 push zh
2123 push zl
2124 #ifdef __ATmega8__
2125 in temp,UDR
2126 #else
2127 lds temp,UDR0
2128 #endif
2129 lds zh,rxcount ;if rxcount < RXBUFSIZE
2130 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
2131 brsh rxi_ov ;
2132 inc zh ;
2133 sts rxcount,zh ; rxcount++
2134
2135 ldi zl,low(rxfifo) ;
2136 lds zh,rxidx_w ;
2137 add zl,zh ;
2138 inc zh ;
2139 andi zh,RXBUFMASK ;
2140 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
2141 ldi zh,high(rxfifo) ;
2142 brcc PC+2 ;
2143 inc zh ;
2144 st z,temp ; rxfifo[rxidx_w] = char
2145 rxi_ov: ;endif
2146 pop zl
2147 pop zh
2148 pop temp
2149 out sreg,temp
2150 pop temp
2151 reti
2152
2153
2154 ;Fetches a char from the buffer to temp. If none available, waits till one is.
2155
2156 uartgetc:
2157 lds temp,rxcount ; Number of characters in buffer
2158 tst temp
2159 breq uartgetc
2160
2161 push zh
2162 push zl
2163 ldi zl,low(rxfifo)
2164 ldi zh,high(rxfifo)
2165 lds temp,rxidx_r
2166 add zl,temp
2167 brcc PC+2
2168 inc zh
2169 inc temp
2170 andi temp,RXBUFMASK
2171 sts rxidx_r,temp
2172 cli
2173 lds temp,rxcount
2174 dec temp
2175 sts rxcount,temp
2176 sei
2177 ld temp,z ;don't forget to get the char
2178 pop zl
2179 pop zh
2180 ret
2181
2182
2183
2184 ;Sends a char from temp to the uart.
2185 uartputc:
2186 #if defined __ATmega8__
2187 uartputc_l:
2188 sbis UCSRA,UDRE
2189 rjmp uartputc_l
2190 out UDR,temp
2191 #else
2192 push temp
2193 uartputc_l:
2194 lds temp,UCSR0A
2195 sbrs temp,UDRE0
2196 rjmp uartputc_l
2197 pop temp
2198 sts UDR0,temp
2199 #endif
2200 ret
2201
2202 ; ------------ Fetch phase stuff -----------------
2203
2204 .equ FETCH_NOP = (0<<0)
2205 .equ FETCH_A = (1<<0)
2206 .equ FETCH_B = (2<<0)
2207 .equ FETCH_C = (3<<0)
2208 .equ FETCH_D = (4<<0)
2209 .equ FETCH_E = (5<<0)
2210 .equ FETCH_H = (6<<0)
2211 .equ FETCH_L = (7<<0)
2212 .equ FETCH_AF = (8<<0)
2213 .equ FETCH_BC = (9<<0)
2214 .equ FETCH_DE = (10<<0)
2215 .equ FETCH_HL = (11<<0)
2216 .equ FETCH_SP = (12<<0)
2217 .equ FETCH_MBC = (13<<0)
2218 .equ FETCH_MDE = (14<<0)
2219 .equ FETCH_MHL = (15<<0)
2220 .equ FETCH_MSP = (16<<0)
2221 .equ FETCH_DIR8 = (17<<0)
2222 .equ FETCH_DIR16= (18<<0)
2223 .equ FETCH_RST = (19<<0)
2224
2225
2226 ;Jump table for fetch routines. Make sure to keep this in sync with the .equs!
2227 fetchjumps:
2228 .dw do_fetch_nop
2229 .dw do_fetch_a
2230 .dw do_fetch_b
2231 .dw do_fetch_c
2232 .dw do_fetch_d
2233 .dw do_fetch_e
2234 .dw do_fetch_h
2235 .dw do_fetch_l
2236 .dw do_fetch_af
2237 .dw do_fetch_bc
2238 .dw do_fetch_de
2239 .dw do_fetch_hl
2240 .dw do_fetch_sp
2241 .dw do_fetch_mbc
2242 .dw do_fetch_mde
2243 .dw do_fetch_mhl
2244 .dw do_fetch_msp
2245 .dw do_fetch_dir8
2246 .dw do_fetch_dir16
2247 .dw do_fetch_rst
2248
2249 do_fetch_nop:
2250 ret
2251
2252 do_fetch_a:
2253 mov opl,z_a
2254 ret
2255
2256 do_fetch_b:
2257 mov opl,z_b
2258 ret
2259
2260 do_fetch_c:
2261 mov opl,z_c
2262 ret
2263
2264 do_fetch_d:
2265 mov opl,z_d
2266 ret
2267
2268 do_fetch_e:
2269 mov opl,z_e
2270 ret
2271
2272 do_fetch_h:
2273 mov opl,z_h
2274 ret
2275
2276 do_fetch_l:
2277 mov opl,z_l
2278 ret
2279
2280 do_fetch_af:
2281 mov opl,z_flags
2282 mov oph,z_a
2283 ret
2284
2285 do_fetch_bc:
2286 mov opl,z_c
2287 mov oph,z_b
2288 ret
2289
2290 do_fetch_de:
2291 mov opl,z_e
2292 mov oph,z_d
2293 ret
2294
2295 do_fetch_hl:
2296 mov opl,z_l
2297 mov oph,z_h
2298 ret
2299
2300 do_fetch_sp:
2301 mov opl,z_spl
2302 mov oph,z_sph
2303 ret
2304
2305 do_fetch_mbc:
2306 mov adrh,z_b
2307 mov adrl,z_c
2308 rcall memReadByte
2309 mov opl,temp
2310 ret
2311
2312 do_fetch_mde:
2313 mov adrh,z_d
2314 mov adrl,z_e
2315 rcall memReadByte
2316 mov opl,temp
2317 ret
2318
2319 do_fetch_mhl:
2320 mov adrh,z_h
2321 mov adrl,z_l
2322 rcall memReadByte
2323 mov opl,temp
2324 ret
2325
2326 do_fetch_msp:
2327 mov adrh,z_sph
2328 mov adrl,z_spl
2329 rcall memReadByte
2330 mov opl,temp
2331
2332 ldi temp,1
2333 ldi temp2,0
2334 add adrl,temp
2335 adc adrh,temp2
2336 rcall memReadByte
2337 mov oph,temp
2338 ret
2339
2340 do_fetch_dir8:
2341 mov adrl,z_pcl
2342 mov adrh,z_pch
2343 rcall memReadByte
2344 adiw z_pcl,1
2345 mov opl,temp
2346 ret
2347
2348 do_fetch_dir16:
2349 mov adrl,z_pcl
2350 mov adrh,z_pch
2351 rcall memReadByte
2352 mov opl,temp
2353 adiw z_pcl,1
2354 mov adrl,z_pcl
2355 mov adrh,z_pch
2356 rcall memReadByte
2357 adiw z_pcl,1
2358 mov oph,temp
2359 ret
2360
2361 do_fetch_rst:
2362 mov adrl,z_pcl
2363 mov adrh,z_pch
2364 subi adrl,1
2365 sbci adrh,0
2366 rcall memReadByte
2367 andi temp,0x38
2368 ldi oph,0
2369 mov opl,temp
2370 ret
2371
2372
2373
2374 ; ------------ Store phase stuff -----------------
2375
2376 .equ STORE_NOP = (0<<5)
2377 .equ STORE_A = (1<<5)
2378 .equ STORE_B = (2<<5)
2379 .equ STORE_C = (3<<5)
2380 .equ STORE_D = (4<<5)
2381 .equ STORE_E = (5<<5)
2382 .equ STORE_H = (6<<5)
2383 .equ STORE_L = (7<<5)
2384 .equ STORE_AF = (8<<5)
2385 .equ STORE_BC = (9<<5)
2386 .equ STORE_DE = (10<<5)
2387 .equ STORE_HL = (11<<5)
2388 .equ STORE_SP = (12<<5)
2389 .equ STORE_PC = (13<<5)
2390 .equ STORE_MBC = (14<<5)
2391 .equ STORE_MDE = (15<<5)
2392 .equ STORE_MHL = (16<<5)
2393 .equ STORE_MSP = (17<<5)
2394 .equ STORE_RET = (18<<5)
2395 .equ STORE_CALL = (19<<5)
2396 .equ STORE_AM = (20<<5)
2397
2398 ;Jump table for store routines. Make sure to keep this in sync with the .equs!
2399 storejumps:
2400 .dw do_store_nop
2401 .dw do_store_a
2402 .dw do_store_b
2403 .dw do_store_c
2404 .dw do_store_d
2405 .dw do_store_e
2406 .dw do_store_h
2407 .dw do_store_l
2408 .dw do_store_af
2409 .dw do_store_bc
2410 .dw do_store_de
2411 .dw do_store_hl
2412 .dw do_store_sp
2413 .dw do_store_pc
2414 .dw do_store_mbc
2415 .dw do_store_mde
2416 .dw do_store_mhl
2417 .dw do_store_msp
2418 .dw do_store_ret
2419 .dw do_store_call
2420 .dw do_store_am
2421
2422
2423 do_store_nop:
2424 ret
2425
2426 do_store_a:
2427 mov z_a,opl
2428 ret
2429
2430 do_store_b:
2431 mov z_b,opl
2432 ret
2433
2434 do_store_c:
2435 mov z_c,opl
2436 ret
2437
2438 do_store_d:
2439 mov z_d,opl
2440 ret
2441
2442 do_store_e:
2443 mov z_e,opl
2444 ret
2445
2446 do_store_h:
2447 mov z_h,opl
2448 ret
2449
2450 do_store_l:
2451 mov z_l,opl
2452 ret
2453
2454 do_store_af:
2455 mov z_a,oph
2456 mov z_flags,opl
2457 ret
2458
2459 do_store_bc:
2460 mov z_b,oph
2461 mov z_c,opl
2462 ret
2463
2464 do_store_de:
2465 mov z_d,oph
2466 mov z_e,opl
2467 ret
2468
2469 do_store_hl:
2470 mov z_h,oph
2471 mov z_l,opl
2472 ret
2473
2474 do_store_mbc:
2475 mov adrh,z_b
2476 mov adrl,z_c
2477 mov temp,opl
2478 rcall memWriteByte
2479 ret
2480
2481 do_store_mde:
2482 mov adrh,z_d
2483 mov adrl,z_e
2484 mov temp,opl
2485 rcall memWriteByte
2486 ret
2487
2488 do_store_mhl:
2489 mov adrh,z_h
2490 mov adrl,z_l
2491 mov temp,opl
2492 rcall memWriteByte
2493 ret
2494
2495 do_store_msp:
2496 mov adrh,z_sph
2497 mov adrl,z_spl
2498 mov temp,opl
2499 rcall memWriteByte
2500
2501 ldi temp,1
2502 ldi temp2,0
2503 add adrl,temp
2504 adc adrh,temp2
2505 mov temp,oph
2506 rcall memWriteByte
2507
2508 ret
2509
2510 do_store_sp:
2511 mov z_sph,oph
2512 mov z_spl,opl
2513 ret
2514
2515 do_store_pc:
2516 mov z_pch,oph
2517 mov z_pcl,opl
2518 ret
2519
2520 do_store_ret:
2521 rcall do_op_pop16
2522 mov z_pcl,opl
2523 mov z_pch,oph
2524 ret
2525
2526 do_store_call:
2527 push opl
2528 push oph
2529 mov opl,z_pcl
2530 mov oph,z_pch
2531 rcall do_op_push16
2532 pop z_pch
2533 pop z_pcl
2534 ret
2535
2536 do_store_am:
2537 mov adrh,oph
2538 mov adrl,opl
2539 mov temp,z_a
2540 rcall memWriteByte
2541 ret
2542
2543
2544 ; ------------ Operation phase stuff -----------------
2545
2546
2547 .equ OP_NOP = (0<<10)
2548 .equ OP_INC = (1<<10)
2549 .equ OP_DEC = (2<<10)
2550 .equ OP_INC16 = (3<<10)
2551 .equ OP_DEC16 = (4<<10)
2552 .equ OP_RLC = (5<<10)
2553 .equ OP_RRC = (6<<10)
2554 .equ OP_RR = (7<<10)
2555 .equ OP_RL = (8<<10)
2556 .equ OP_ADDA = (9<<10)
2557 .equ OP_ADCA = (10<<10)
2558 .equ OP_SUBFA = (11<<10)
2559 .equ OP_SBCFA = (12<<10)
2560 .equ OP_ANDA = (13<<10)
2561 .equ OP_ORA = (14<<10)
2562 .equ OP_XORA = (15<<10)
2563 .equ OP_ADDHL = (16<<10)
2564 .equ OP_STHL = (17<<10) ;store HL in fetched address
2565 .equ OP_RMEM16 = (18<<10) ;read mem at fetched address
2566 .equ OP_RMEM8 = (19<<10) ;read mem at fetched address
2567 .equ OP_DA = (20<<10)
2568 .equ OP_SCF = (21<<10)
2569 .equ OP_CPL = (22<<10)
2570 .equ OP_CCF = (23<<10)
2571 .equ OP_POP16 = (24<<10)
2572 .equ OP_PUSH16 = (25<<10)
2573 .equ OP_IFNZ = (26<<10)
2574 .equ OP_IFZ = (27<<10)
2575 .equ OP_IFNC = (28<<10)
2576 .equ OP_IFC = (29<<10)
2577 .equ OP_IFPO = (30<<10)
2578 .equ OP_IFPE = (31<<10)
2579 .equ OP_IFP = (32<<10)
2580 .equ OP_IFM = (33<<10)
2581 .equ OP_OUTA = (34<<10)
2582 .equ OP_IN = (35<<10)
2583 .equ OP_EXHL = (36<<10)
2584 .equ OP_DI = (37<<10)
2585 .equ OP_EI = (38<<10)
2586 .equ OP_INV = (39<<10)
2587
2588 opjumps:
2589 .dw do_op_nop
2590 .dw do_op_inc
2591 .dw do_op_dec
2592 .dw do_op_inc16
2593 .dw do_op_dec16
2594 .dw do_op_rlc
2595 .dw do_op_rrc
2596 .dw do_op_rr
2597 .dw do_op_rl
2598 .dw do_op_adda
2599 .dw do_op_adca
2600 .dw do_op_subfa
2601 .dw do_op_sbcfa
2602 .dw do_op_anda
2603 .dw do_op_ora
2604 .dw do_op_xora
2605 .dw do_op_addhl
2606 .dw do_op_sthl
2607 .dw do_op_rmem16
2608 .dw do_op_rmem8
2609 .dw do_op_da
2610 .dw do_op_scf
2611 .dw do_op_cpl
2612 .dw do_op_ccf
2613 .dw do_op_pop16
2614 .dw do_op_push16
2615 .dw do_op_ifnz
2616 .dw do_op_ifz
2617 .dw do_op_ifnc
2618 .dw do_op_ifc
2619 .dw do_op_ifpo
2620 .dw do_op_ifpe
2621 .dw do_op_ifp
2622 .dw do_op_ifm
2623 .dw do_op_outa
2624 .dw do_op_in
2625 .dw do_op_exhl
2626 .dw do_op_di
2627 .dw do_op_ei
2628 .dw do_op_inv
2629
2630
2631 ;How the flags are supposed to work:
2632 ;7 ZFL_S - Sign flag (=MSBit of result)
2633 ;6 ZFL_Z - Zero flag. Is 1 when the result is 0
2634 ;4 ZFL_H - Half-carry (carry from bit 3 to 4)
2635 ;2 ZFL_P - Parity/2-complement Overflow
2636 ;1 ZFL_N - Subtract - set if last op was a subtract
2637 ;0 ZFL_C - Carry
2638 ;
2639 ;I sure hope I got the mapping between flags and instructions correct...
2640
2641 ;----------------------------------------------------------------
2642 ;| |
2643 ;| Zilog |
2644 ;| |
2645 ;| ZZZZZZZ 88888 000 |
2646 ;| Z 8 8 0 0 |
2647 ;| Z 8 8 0 0 0 |
2648 ;| Z 88888 0 0 0 |
2649 ;| Z 8 8 0 0 0 |
2650 ;| Z 8 8 0 0 |
2651 ;| ZZZZZZZ 88888 000 |
2652 ;| |
2653 ;| Z80 MICROPROCESSOR Instruction Set Summary |
2654 ;| |
2655 ;----------------------------------------------------------------
2656 ;----------------------------------------------------------------
2657 ;|Mnemonic |SZHPNC|Description |Notes |
2658 ;|----------+------+---------------------+----------------------|
2659 ;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
2660 ;|ADC HL,ss |**?V0*|Add with Carry |HL=HL+ss+CY |
2661 ;|ADD A,s |***V0*|Add |A=A+s |
2662 ;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
2663 ;|ADD IX,pp |--?-0*|Add |IX=IX+pp |
2664 ;|ADD IY,rr |--?-0*|Add |IY=IY+rr |
2665 ;|AND s |**1P00|Logical AND |A=A&s |
2666 ;|BIT b,m |?*1?0-|Test Bit |m&{2^b} |
2667 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
2668 ;|CALL nn |------|Unconditional Call |-[SP]=PC,PC=nn |
2669 ;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
2670 ;|CP s |***V1*|Compare |A-s |
2671 ;|CPD |****1-|Compare and Decrement|A-[HL],HL=HL-1,BC=BC-1|
2672 ;|CPDR |****1-|Compare, Dec., Repeat|CPD till A=[HL]or BC=0|
2673 ;|CPI |****1-|Compare and Increment|A-[HL],HL=HL+1,BC=BC-1|
2674 ;|CPIR |****1-|Compare, Inc., Repeat|CPI till A=[HL]or BC=0|
2675 ;|CPL |--1-1-|Complement |A=~A |
2676 ;|DAA |***P-*|Decimal Adjust Acc. |A=BCD format |
2677 ;|DEC s |***V1-|Decrement |s=s-1 |
2678 ;|DEC xx |------|Decrement |xx=xx-1 |
2679 ;|DEC ss |------|Decrement |ss=ss-1 |
2680 ;|DI |------|Disable Interrupts | |
2681 ;|DJNZ e |------|Dec., Jump Non-Zero |B=B-1 till B=0 |
2682 ;|EI |------|Enable Interrupts | |
2683 ;|EX [SP],HL|------|Exchange |[SP]<->HL |
2684 ;|EX [SP],xx|------|Exchange |[SP]<->xx |
2685 ;|EX AF,AF' |------|Exchange |AF<->AF' |
2686 ;|EX DE,HL |------|Exchange |DE<->HL |
2687 ;|EXX |------|Exchange |qq<->qq' (except AF)|
2688 ;|HALT |------|Halt | |
2689 ;|IM n |------|Interrupt Mode | (n=0,1,2)|
2690 ;|IN A,[n] |------|Input |A=[n] |
2691 ;|IN r,[C] |***P0-|Input |r=[C] |
2692 ;|INC r |***V0-|Increment |r=r+1 |
2693 ;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
2694 ;|INC xx |------|Increment |xx=xx+1 |
2695 ;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
2696 ;|INC ss |------|Increment |ss=ss+1 |
2697 ;|IND |?*??1-|Input and Decrement |[HL]=[C],HL=HL-1,B=B-1|
2698 ;|INDR |?1??1-|Input, Dec., Repeat |IND till B=0 |
2699 ;|INI |?*??1-|Input and Increment |[HL]=[C],HL=HL+1,B=B-1|
2700 ;|INIR |?1??1-|Input, Inc., Repeat |INI till B=0 |
2701 ;|JP [HL] |------|Unconditional Jump |PC=[HL] |
2702 ;|JP [xx] |------|Unconditional Jump |PC=[xx] |
2703 ;|JP nn |------|Unconditional Jump |PC=nn |
2704 ;|JP cc,nn |------|Conditional Jump |If cc JP |
2705 ;|JR e |------|Unconditional Jump |PC=PC+e |
2706 ;|JR cc,e |------|Conditional Jump |If cc JR(cc=C,NC,NZ,Z)|
2707 ;|LD dst,src|------|Load |dst=src |
2708 ;|LD A,i |**0*0-|Load |A=i (i=I,R)|
2709 ;|LDD |--0*0-|Load and Decrement |[DE]=[HL],HL=HL-1,# |
2710 ;|LDDR |--000-|Load, Dec., Repeat |LDD till BC=0 |
2711 ;|LDI |--0*0-|Load and Increment |[DE]=[HL],HL=HL+1,# |
2712 ;|LDIR |--000-|Load, Inc., Repeat |LDI till BC=0 |
2713 ;|NEG |***V1*|Negate |A=-A |
2714 ;|NOP |------|No Operation | |
2715 ;|OR s |**0P00|Logical inclusive OR |A=Avs |
2716 ;|OTDR |?1??1-|Output, Dec., Repeat |OUTD till B=0 |
2717 ;|OTIR |?1??1-|Output, Inc., Repeat |OUTI till B=0 |
2718 ;|OUT [C],r |------|Output |[C]=r |
2719 ;|OUT [n],A |------|Output |[n]=A |
2720 ;|OUTD |?*??1-|Output and Decrement |[C]=[HL],HL=HL-1,B=B-1|
2721 ;|OUTI |?*??1-|Output and Increment |[C]=[HL],HL=HL+1,B=B-1|
2722 ;|POP xx |------|Pop |xx=[SP]+ |
2723 ;|POP qq |------|Pop |qq=[SP]+ |
2724 ;|PUSH xx |------|Push |-[SP]=xx |
2725 ;|PUSH qq |------|Push |-[SP]=qq |
2726 ;|RES b,m |------|Reset bit |m=m&{~2^b} |
2727 ;|RET |------|Return |PC=[SP]+ |
2728 ;|RET cc |------|Conditional Return |If cc RET |
2729 ;|RETI |------|Return from Interrupt|PC=[SP]+ |
2730 ;|RETN |------|Return from NMI |PC=[SP]+ |
2731 ;|RL m |**0P0*|Rotate Left |m={CY,m}<- |
2732 ;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
2733 ;|RLC m |**0P0*|Rotate Left Circular |m=m<- |
2734 ;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
2735 ;|RLD |**0P0-|Rotate Left 4 bits |{A,[HL]}={A,[HL]}<- ##|
2736 ;|RR m |**0P0*|Rotate Right |m=->{CY,m} |
2737 ;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
2738 ;|RRC m |**0P0*|Rotate Right Circular|m=->m |
2739 ;|RRCA |--0-0*|Rotate Right Circular|A=->A |
2740 ;|RRD |**0P0-|Rotate Right 4 bits |{A,[HL]}=->{A,[HL]} ##|
2741 ;|RST p |------|Restart | (p=0H,8H,10H,...,38H)|
2742 ;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
2743 ;|SBC HL,ss |**?V1*|Subtract with Carry |HL=HL-ss-CY |
2744 ;|SCF |--0-01|Set Carry Flag |CY=1 |
2745 ;|SET b,m |------|Set bit |m=mv{2^b} |
2746 ;|SLA m |**0P0*|Shift Left Arithmetic|m=m*2 |
2747 ;|SRA m |**0P0*|Shift Right Arith. |m=m/2 |
2748 ;|SRL m |**0P0*|Shift Right Logical |m=->{0,m,CY} |
2749 ;|SUB s |***V1*|Subtract |A=A-s |
2750 ;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
2751 ;|----------+------+--------------------------------------------|
2752
2753
2754 .equ AVR_T = 6
2755 .equ AVR_H = 5
2756 .equ AVR_S = 4
2757 .equ AVR_V = 3
2758 .equ AVR_N = 2
2759 .equ AVR_Z = 1
2760 .equ AVR_C = 0
2761
2762 ;------------------------------------------------;
2763 ; Move single bit between two registers
2764 ;
2765 ; bmov dstreg,dstbit,srcreg.srcbit
2766
2767 .macro bmov
2768 bst @2,@3
2769 bld @0,@1
2770 .endm
2771
2772
2773 ;------------------------------------------------;
2774 ; Load table value from flash indexed by source reg.
2775 ;
2776 ; ldpmx dstreg,tablebase,indexreg
2777 ;
2778 ; (6 words, 8 cycles)
2779
2780 .macro ldpmx
2781 ldi zl,low (@1*2)
2782 ldi zh,high(@1*2)
2783 add zl,@2
2784 brcc PC+2
2785 inc zh
2786 lpm @0,z
2787 .endm
2788
2789 .macro do_z80_flags_HP
2790 #if EM_Z80
2791 bmov z_flags, ZFL_P, temp, AVR_V
2792 bmov z_flags, ZFL_H, temp, AVR_H
2793 #endif
2794 .endm
2795
2796 .macro do_z80_flags_set_N
2797 #if EM_Z80
2798 ori z_flags, (1<<ZFL_N) ; Negation auf 1
2799 #endif
2800 .endm
2801
2802 .macro do_z80_flags_set_HN
2803 #if EM_Z80
2804 ori z_flags,(1<<ZFL_N)|(1<<ZFL_H)
2805 #endif
2806 .endm
2807
2808 .macro do_z80_flags_clear_N
2809 #if EM_Z80
2810 andi z_flags,~(1<<ZFL_N)
2811 #endif
2812 .endm
2813
2814 .macro do_z80_flags_op_rotate
2815 ; must not change avr carry flag!
2816 #if EM_Z80
2817 andi z_flags, ~( (1<<ZFL_H) | (1<<ZFL_N) | (1<<ZFL_C) )
2818 #else
2819 andi z_flags, ~( (1<<ZFL_C) )
2820 #endif
2821 .endm
2822
2823 .macro do_z80_flags_op_and
2824 #if EM_Z80
2825 ori z_flags,(1<<ZFL_H)
2826 #else
2827 ori z_flags,(1<<ZFL_H)
2828 #endif
2829 .endm
2830
2831 .macro do_z80_flags_op_or
2832 #if EM_Z80
2833 #endif
2834 .endm
2835
2836
2837 do_op_nop:
2838 ret
2839
2840 ;----------------------------------------------------------------
2841 ;|Mnemonic |SZHPNC|Description |Notes |
2842 ;----------------------------------------------------------------
2843 ;|INC r |***V0-|Increment |r=r+1 |
2844 ;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
2845 ;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
2846 ;|----------|SZHP C|---------- 8080 ----------------------------|
2847 ;|INC r |**-P0-|Increment |r=r+1 |
2848 ;|INC [HL] |**-P0-|Increment |[HL]=[HL]+1 |
2849 ;
2850 ;
2851 do_op_inc:
2852 ldi temp,1
2853 add opl,temp
2854 in temp, sreg
2855 andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
2856 ldpmx temp2, sz53p_tab, opl
2857 or z_flags,temp2 ;
2858 do_z80_flags_HP
2859 ret
2860
2861 ;----------------------------------------------------------------
2862 ;|Mnemonic |SZHPNC|Description |Notes |
2863 ;----------------------------------------------------------------
2864 ;|DEC r |***V1-|Decrement |s=s-1 |
2865 ;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
2866 ;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
2867 ;|----------|SZHP C|---------- 8080 ----------------------------|
2868 ;|DEC r |**-P -|Increment |r=r+1 |
2869 ;|DEC [HL] |**-P -|Increment |[HL]=[HL]+1 |
2870 ;
2871 ;
2872 do_op_dec:
2873 subi opl,1
2874 in temp, sreg
2875 andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
2876 ldpmx temp2, sz53p_tab, opl
2877 or z_flags,temp2 ;
2878 do_z80_flags_HP
2879 do_z80_flags_set_N
2880 ret
2881
2882
2883 ;----------------------------------------------------------------
2884 ;|Mnemonic |SZHPNC|Description |Notes |
2885 ;----------------------------------------------------------------
2886 ;|INC xx |------|Increment |xx=xx+1 |
2887 ;|INC ss |------|Increment |ss=ss+1 |
2888 ;
2889 ;
2890 do_op_inc16:
2891 inc opl
2892 brne op_i16x
2893 inc oph
2894 op_i16x:
2895 ret
2896
2897 ;----------------------------------------------------------------
2898 ;|Mnemonic |SZHPNC|Description |Notes |
2899 ;----------------------------------------------------------------
2900 ;|DEC xx |------|Decrement |xx=xx-1 |
2901 ;|DEC ss |------|Decrement |ss=ss-1 |
2902 ;
2903 ;
2904 do_op_dec16:
2905 subi opl, 1
2906 sbci oph, 0
2907 ret
2908
2909 ;----------------------------------------------------------------
2910 ;|Mnemonic |SZHPNC|Description |Notes |
2911 ;----------------------------------------------------------------
2912 ;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
2913 ;|----------|SZHP C|---------- 8080 ----------------------------|
2914 ;|RLCA |---- *|Rotate Left Circular |A=A<- |
2915 ;
2916 ;
2917 do_op_rlc:
2918 ;Rotate Left Cyclical. All bits move 1 to the
2919 ;left, the msb becomes c and lsb.
2920 do_z80_flags_op_rotate
2921 lsl opl
2922 brcc do_op_rlc_noc
2923 ori opl, 1
2924 ori z_flags, (1<<ZFL_C)
2925 do_op_rlc_noc:
2926 ret
2927
2928 ;----------------------------------------------------------------
2929 ;|Mnemonic |SZHPNC|Description |Notes |
2930 ;----------------------------------------------------------------
2931 ;|RRCA |--0-0*|Rotate Right Circular|A=->A |
2932 ;|----------|SZHP C|---------- 8080 ----------------------------|
2933 ;|RRCA |---- *|Rotate Right Circular|A=->A |
2934 ;
2935 ;
2936 do_op_rrc:
2937 ;Rotate Right Cyclical. All bits move 1 to the
2938 ;right, the lsb becomes c and msb.
2939 do_z80_flags_op_rotate
2940 lsr opl
2941 brcc do_op_rrc_noc
2942 ori opl, 0x80
2943 ori z_flags, (1<<ZFL_C)
2944 do_op_rrc_noc:
2945 ret
2946
2947 ;----------------------------------------------------------------
2948 ;|Mnemonic |SZHPNC|Description |Notes |
2949 ;----------------------------------------------------------------
2950 ;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
2951 ;|----------|SZHP C|---------- 8080 ----------------------------|
2952 ;|RRA |---- *|Rotate Right Acc. |A=->{CY,A} |
2953 ;
2954 ;
2955 do_op_rr:
2956 ;Rotate Right. All bits move 1 to the right, the lsb
2957 ;becomes c, c becomes msb.
2958 clc ; get z80 carry to avr carry
2959 sbrc z_flags,ZFL_C
2960 sec
2961 do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
2962 bmov z_flags,ZFL_C, opl,0 ; Bit 0 --> CY
2963 ror opl
2964 ret
2965
2966 ;----------------------------------------------------------------
2967 ;|Mnemonic |SZHPNC|Description |Notes |
2968 ;----------------------------------------------------------------
2969 ;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
2970 ;|----------|SZHP C|---------- 8080 ----------------------------|
2971 ;|RLA |---- *|Rotate Left Acc. |A={CY,A}<- |
2972 ;
2973 ;
2974 do_op_rl:
2975 ;Rotate Left. All bits move 1 to the left, the msb
2976 ;becomes c, c becomes lsb.
2977 clc
2978 sbrc z_flags,ZFL_C
2979 sec
2980 do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
2981 bmov z_flags,ZFL_C, opl,7 ; Bit 7 --> CY
2982 rol opl
2983 ret
2984
2985 ;----------------------------------------------------------------
2986 ;|Mnemonic |SZHPNC|Description |Notes |
2987 ;----------------------------------------------------------------
2988 ;|ADD A,s |***V0*|Add |A=A+s |
2989 ;|----------|SZHP C|---------- 8080 ----------------------------|
2990 ;|ADD A,s |***P *|Add |A=A+s |
2991 ;
2992 ;
2993 do_op_adda:
2994 add opl,z_a
2995 in temp,sreg
2996 ldpmx z_flags,sz53p_tab,opl ;S,Z,P flag
2997 bmov z_flags,ZFL_C, temp,AVR_C
2998 do_z80_flags_HP
2999 ret
3000
3001 ;----------------------------------------------------------------
3002 ;|Mnemonic |SZHPNC|Description |Notes |
3003 ;----------------------------------------------------------------
3004 ;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
3005 ;|----------|SZHP C|---------- 8080 ----------------------------|
3006 ;|ADC A,s |***P *|Add with Carry |A=A+s+CY |
3007 ;
3008 ;
3009 do_op_adca:
3010 clc
3011 sbrc z_flags,ZFL_C
3012 sec
3013 adc opl,z_a
3014 in temp,sreg
3015 ldpmx z_flags,sz53p_tab,opl ;S,Z,P
3016 bmov z_flags,ZFL_C, temp,AVR_C
3017 do_z80_flags_HP
3018 ret
3019
3020 ;----------------------------------------------------------------
3021 ;|Mnemonic |SZHPNC|Description |Notes |
3022 ;----------------------------------------------------------------
3023 ;|SUB s |***V1*|Subtract |A=A-s |
3024 ;|CP s |***V1*|Compare |A-s |
3025 ;|----------|SZHP C|---------- 8080 ----------------------------|
3026 ;|SUB s |***P *|Subtract |A=A-s |
3027 ;|CP s |***P *|Compare |A-s |
3028
3029 ;
3030 do_op_subfa:
3031 mov temp,z_a
3032 sub temp,opl
3033 mov opl,temp
3034 in temp,sreg
3035 ldpmx z_flags,sz53p_tab,opl ;S,Z,P
3036 bmov z_flags,ZFL_C, temp,AVR_C
3037 do_z80_flags_HP
3038 do_z80_flags_set_N
3039 ret
3040
3041 ;----------------------------------------------------------------
3042 ;|Mnemonic |SZHPNC|Description |Notes |
3043 ;----------------------------------------------------------------
3044 ;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
3045 ;|----------|SZHP C|---------- 8080 ----------------------------|
3046 ;|SBC A,s |***P *|Subtract with Carry |A=A-s-CY |
3047 ;
3048 ;
3049 do_op_sbcfa:
3050 mov temp,z_a
3051 clc
3052 sbrc z_flags,ZFL_C
3053 sec
3054 sbc temp,opl
3055 mov opl,temp
3056 in temp,sreg
3057 ldpmx z_flags,sz53p_tab,opl ;S,Z,P
3058 bmov z_flags,ZFL_C, temp,AVR_C
3059 do_z80_flags_HP
3060 do_z80_flags_set_N
3061 ret
3062
3063 ;----------------------------------------------------------------
3064 ;|Mnemonic |SZHPNC|Description |Notes |
3065 ;----------------------------------------------------------------
3066 ;|AND s |**1P00|Logical AND |A=A&s |
3067 ;|----------|SZHP C|---------- 8080 ----------------------------|
3068 ;|AND s |**-P 0|Logical AND |A=A&s |
3069 ;
3070 ; TODO H-Flag
3071 do_op_anda:
3072 and opl,z_a ;
3073 ldpmx z_flags,sz53p_tab,opl ;S,Z,P,N,C
3074 do_z80_flags_op_and
3075 ret
3076
3077
3078 ;----------------------------------------------------------------
3079 ;|Mnemonic |SZHPNC|Description |Notes |
3080 ;----------------------------------------------------------------
3081 ;|OR s |**0P00|Logical inclusive OR |A=Avs |
3082 ;|----------|SZHP C|---------- 8080 ----------------------------|
3083 ;|OR s |**-P00|Logical inclusive OR |A=Avs |
3084 ;
3085 ; TODO: H-Flag
3086 do_op_ora:
3087 or opl,z_a
3088 ldpmx z_flags,sz53p_tab,opl ;S,Z,H,P,N,C
3089 do_z80_flags_op_or
3090 ret
3091
3092 ;----------------------------------------------------------------
3093 ;|Mnemonic |SZHPNC|Description |Notes |
3094 ;----------------------------------------------------------------
3095 ;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
3096 ;|----------|SZHP C|---------- 8080 ----------------------------|
3097 ;|XOR s |**-P 0|Logical Exclusive OR |A=Axs |
3098 ;
3099 ; TODO: H-Flag
3100 do_op_xora:
3101 eor opl,z_a
3102 ldpmx z_flags,sz53p_tab,opl ;S,Z,H,P,N,C
3103 do_z80_flags_op_or
3104 ret
3105
3106 ;----------------------------------------------------------------
3107 ;|Mnemonic |SZHPNC|Description |Notes |
3108 ;----------------------------------------------------------------
3109 ;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
3110 ;|----------|SZHP C|---------- 8080 ----------------------------|
3111 ;|ADD HL,ss |---- *|Add |HL=HL+ss |
3112 ;
3113 ;
3114 do_op_addhl:
3115 add opl,z_l
3116 adc oph,z_h
3117 in temp,sreg
3118 bmov z_flags,ZFL_H, temp,AVR_H
3119 bmov z_flags,ZFL_C, temp,AVR_C
3120 do_z80_flags_clear_N
3121 ret
3122
3123 ;----------------------------------------------------------------
3124 ;|Mnemonic |SZHPNC|Description |Notes |
3125 ;----------------------------------------------------------------
3126 ;|LD dst,src|------|Load |dst=src |
3127 ;
3128 ;
3129 do_op_sthl: ;store hl to mem loc in opl:h
3130 mov adrl,opl
3131 mov adrh,oph
3132 mov temp,z_l
3133 rcall memWriteByte
3134
3135 inc opl
3136 brne op_sthlx
3137 inc oph
3138 op_sthlx:
3139 mov adrl,opl
3140 mov adrh,oph
3141 mov temp,z_h
3142 rcall memWriteByte
3143
3144 ret
3145
3146 ;----------------------------------------------------------------
3147 ;|Mnemonic |SZHPNC|Description |Notes |
3148 ;----------------------------------------------------------------
3149 ;|LD dst,src|------|Load |dst=src |
3150 ;
3151 ;
3152 do_op_rmem16:
3153 mov adrl,opl
3154 mov adrh,oph
3155 rcall memReadByte
3156 mov opl,temp
3157 ldi temp,1
3158 add adrl,temp
3159 ldi temp,0
3160 adc adrh,temp
3161 rcall memReadByte
3162 mov oph,temp
3163 ret
3164
3165 ;----------------------------------------------------------------
3166 ;|Mnemonic |SZHPNC|Description |Notes |
3167 ;----------------------------------------------------------------
3168 ;|LD dst,src|------|Load |dst=src |
3169 ;
3170 ;
3171 do_op_rmem8:
3172 mov adrl,opl
3173 mov adrh,oph
3174 rcall memReadByte
3175 mov opl,temp
3176 ret
3177
3178 ;----------------------------------------------------------------
3179 ;|Mnemonic |SZHPNC|Description |Notes |
3180 ;----------------------------------------------------------------
3181 ;|DAA |***P-*|Decimal Adjust Acc. | |
3182 ;|----------|SZHP C|---------- 8080 ----------------------------|
3183 ;
3184 ; Not yet checked
3185
3186 ; Description (http://www.z80.info/z80syntx.htm#DAA):
3187 ; This instruction conditionally adjusts the accumulator for BCD addition
3188 ; and subtraction operations. For addition (ADD, ADC, INC) or subtraction
3189 ; (SUB, SBC, DEC, NEC), the following table indicates the operation performed:
3190 ;
3191 ; -------------------------------------------------------------------------------
3192 ; | | C Flag | HEX value in | H Flag | HEX value in | Number | C flag|
3193 ; | Operation| Before | upper digit | Before | lower digit | added | After |
3194 ; | | DAA | (bit 7-4) | DAA | (bit 3-0) | to byte | DAA |
3195 ; |-----------------------------------------------------------------------------|
3196 ; | | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
3197 ; | ADD | 0 | 0-8 | 0 | A-F | 06 | 0 |
3198 ; | | 0 | 0-9 | 1 | 0-3 | 06 | 0 |
3199 ; | ADC | 0 | A-F | 0 | 0-9 | 60 | 1 |
3200 ; | | 0 | 9-F | 0 | A-F | 66 | 1 |
3201 ; | INC | 0 | A-F | 1 | 0-3 | 66 | 1 |
3202 ; | | 1 | 0-2 | 0 | 0-9 | 60 | 1 |
3203 ; | | 1 | 0-2 | 0 | A-F | 66 | 1 |
3204 ; | | 1 | 0-3 | 1 | 0-3 | 66 | 1 |
3205 ; |-----------------------------------------------------------------------------|
3206 ; | SUB | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
3207 ; | SBC | 0 | 0-8 | 1 | 6-F | FA | 0 |
3208 ; | DEC | 1 | 7-F | 0 | 0-9 | A0 | 1 |
3209 ; | NEG | 1 | 6-F | 1 | 6-F | 9A | 1 |
3210 ; |-----------------------------------------------------------------------------|
3211 ;
3212 ; Flags:
3213 ; C: See instruction.
3214 ; N: Unaffected.
3215 ; P/V: Set if Acc. is even parity after operation, reset otherwise.
3216 ; H: See instruction.
3217 ; Z: Set if Acc. is Zero after operation, reset otherwise.
3218 ; S: Set if most significant bit of Acc. is 1 after operation, reset otherwise.
3219
3220
3221
3222 #if 1
3223 do_op_da:
3224 ldi oph,0 ; what to add
3225 sbrc z_flags,ZFL_H ; if H-Flag
3226 rjmp op_da_06
3227 mov temp,opl
3228 andi temp,0x0f ; ... or lower digit > 9
3229 cpi temp,0x0a
3230 brlo op_da_06n
3231 op_da_06:
3232 ori oph,0x06
3233 op_da_06n:
3234 sbrc z_flags,(1<<ZFL_C)
3235 rjmp op_da_60
3236 cpi opl,0xa0
3237 brlo op_da_60n
3238 op_da_60:
3239 ori oph,0x60
3240 op_da_60n:
3241 cpi opl,0x9a
3242 brlo op_da_99n
3243 ori z_flags,(1<<ZFL_C); set C
3244 op_da_99n:
3245 sbrs z_flags,ZFL_N ; if sub-op
3246 rjmp op_da_add ; then
3247 sub opl,oph
3248 rjmp op_da_ex
3249 op_da_add: ; else add-op
3250 cpi opl,0x91
3251 brlo op_da_60n2
3252 mov temp,opl
3253 andi temp,0x0f
3254 cpi temp,0x0a
3255 brlo op_da_60n2
3256 ori oph,0x60
3257 op_da_60n2:
3258 add opl,oph
3259 op_da_ex:
3260 in temp,SREG
3261 sbrc temp,AVR_H
3262 ori z_flags,(1<<ZFL_C)
3263 andi z_flags,(1<<ZFL_N)|(1<<ZFL_C) ; preserve C,N
3264 ldpmx temp2, sz53p_tab, opl ; get S,Z,P
3265 or z_flags,temp2
3266 bmov z_flags,ZFL_H, temp,AVR_H ; H (?)
3267 ret
3268 #else
3269
3270 do_op_da:
3271 sbrc z_flags,ZFL_N ; if add-op
3272 rjmp do_op_da_sub ; then
3273 ldi temp2,0 ;
3274 mov temp,opl ;
3275 andi temp,0x0f ;
3276 cpi temp,0x0a ; if lower digit > 9
3277 brlo do_op_da_h ;
3278 ori temp2,0x06 ; add 6 to lower digit
3279 do_op_da_h: ;
3280 sbrc z_flags,ZFL_H ; ... or H-Flag
3281 ori temp2,0x06 ;
3282 add opl,temp2 ;
3283
3284 ldi temp2,0 ;
3285 mov temp,opl ;
3286 andi temp,0xf0 ;
3287 cpi temp,0xa0 ;
3288 brlo do_op_da_c ;
3289 ori temp2,0x60 ;
3290 do_op_da_c: ; else sub-op
3291 sbrc z_flags,ZFL_C ;
3292 ori temp2,0x60 ;
3293 andi z_flags, ~( (1<<ZFL_S) | (1<<ZFL_Z) | (1<<ZFL_H) )
3294 add opl,temp2 ;
3295 in temp,SREG ;
3296 bst temp,AVR_Z ;Z-Flag
3297 bld z_flags,ZFL_Z ;
3298 bst temp,AVR_N ;S-Flag
3299 bst z_flags,ZFL_S ;
3300 sbrc temp2,5 ;C-Flag, set if 0x06 added
3301 ori z_flags,(1<<ZFL_C) ;
3302 ;H-Flag?
3303 ret
3304
3305 do_op_da_sub: ;TODO:
3306 rcall do_op_inv
3307 ret
3308 #endif
3309
3310 ;----------------------------------------------------------------
3311 ;|Mnemonic |SZHPNC|Description |Notes |
3312 ;----------------------------------------------------------------
3313 ;|SCF |--0-01|Set Carry Flag |CY=1 |
3314 ;|----------|SZHP C|---------- 8080 ----------------------------|
3315 ;
3316 ;
3317 do_op_scf:
3318 andi z_flags,~((1<<ZFL_H)|(1<<ZFL_N))
3319 ori z_flags,(1<<ZFL_C)
3320 ret
3321
3322 ;----------------------------------------------------------------
3323 ;|Mnemonic |SZHPNC|Description |Notes |
3324 ;----------------------------------------------------------------
3325 ;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
3326 ;|----------|SZHP C|---------- 8080 ----------------------------|
3327 ;|SCF |---- 1|Set Carry Flag |CY=1 |
3328 ;
3329 ;TODO: H-Flag
3330 do_op_ccf:
3331 do_z80_flags_clear_N
3332 ldi temp,(1<<ZFL_C)
3333 eor z_flags,temp
3334 ret
3335
3336 ;----------------------------------------------------------------
3337 ;|Mnemonic |SZHPNC|Description |Notes |
3338 ;----------------------------------------------------------------
3339 ;|CPL |--1-1-|Complement |A=~A |
3340 ;|----------|SZHP C|---------- 8080 ----------------------------|
3341 ;|CPL |---- -|Complement |A=~A |
3342 ;
3343 ;
3344 do_op_cpl:
3345 com opl
3346 do_z80_flags_set_HN
3347 ret
3348
3349
3350 ;----------------------------------------------------------------
3351 ;|Mnemonic |SZHPNC|Description |Notes |
3352 ;----------------------------------------------------------------
3353 ;|PUSH xx |------|Push |-[SP]=xx |
3354 ;|PUSH qq |------|Push |-[SP]=qq |
3355 ;
3356 ;
3357 do_op_push16:
3358 #if 1
3359 ldi temp,1
3360 ldi temp2,0
3361 sub z_spl,temp
3362 sbc z_sph,temp2
3363
3364 mov adrl,z_spl
3365 mov adrh,z_sph
3366 mov temp,oph
3367 rcall memWriteByte
3368
3369 ldi temp,1
3370 ldi temp2,0
3371 sub z_spl,temp
3372 sbc z_sph,temp2
3373
3374 mov adrl,z_spl
3375 mov adrh,z_sph
3376 mov temp,opl
3377 rcall memWriteByte
3378 #else
3379 subi z_spl,1
3380 sbci z_sph,0
3381
3382 mov adrl,z_spl
3383 mov adrh,z_sph
3384 mov temp,oph
3385 rcall memWriteByte
3386
3387 subi z_spl,1
3388 sbci z_sph,0
3389
3390 mov adrl,z_spl
3391 mov adrh,z_sph
3392 mov temp,opl
3393 rcall memWriteByte
3394 #endif
3395
3396 .if STACK_DBG
3397 rcall printstr
3398 .db "Stack push ",0
3399 mov temp,oph
3400 rcall printhex
3401 mov temp,opl
3402 rcall printhex
3403 rcall printstr
3404 .db ", SP is now ",0
3405 mov temp,z_sph
3406 rcall printhex
3407 mov temp,z_spl
3408 rcall printhex
3409 rcall printstr
3410 .db ".",13,0
3411 .endif
3412
3413 ret
3414
3415 ;----------------------------------------------------------------
3416 ;|Mnemonic |SZHPNC|Description |Notes |
3417 ;----------------------------------------------------------------
3418 ;|POP xx |------|Pop |xx=[SP]+ |
3419 ;|POP qq |------|Pop |qq=[SP]+ |
3420 ;
3421 ;
3422 do_op_pop16:
3423 mov adrl,z_spl
3424 mov adrh,z_sph
3425 rcall memReadByte
3426 mov opl,temp
3427
3428 ldi temp,1
3429 ldi temp2,0
3430 add z_spl,temp
3431 adc z_sph,temp2
3432
3433 mov adrl,z_spl
3434 mov adrh,z_sph
3435 rcall memReadByte
3436 mov oph,temp
3437
3438 ldi temp,1
3439 ldi temp2,0
3440 add z_spl,temp
3441 adc z_sph,temp2
3442
3443 .if STACK_DBG
3444 rcall printstr
3445 .db "Stack pop: val ",0
3446 mov temp,oph
3447 rcall printhex
3448 mov temp,opl
3449 rcall printhex
3450 rcall printstr
3451 .db ", SP is now",0
3452 mov temp,z_sph
3453 rcall printhex
3454 mov temp,z_spl
3455 rcall printhex
3456 rcall printstr
3457 .db ".",13,0
3458 .endif
3459 ret
3460
3461 ;----------------------------------------------------------------
3462 ;|Mnemonic |SZHPNC|Description |Notes |
3463 ;----------------------------------------------------------------
3464 ;|EX [SP],HL|------|Exchange |[SP]<->HL |
3465 ;|EX DE,HL |------|Exchange |DE<->HL |
3466 ;
3467 ;
3468 do_op_exhl:
3469 mov temp,z_h
3470 mov z_h,oph
3471 mov oph,temp
3472 mov temp,z_l
3473 mov z_l,opl
3474 mov opl,temp
3475 ret
3476
3477 ;----------------------------------------------------------------
3478 ;|Mnemonic |SZHPNC|Description |Notes |
3479 ;----------------------------------------------------------------
3480 ;
3481 ; TODO: Implement IFF1, IFF2
3482 do_op_di:
3483 ret
3484
3485 ;----------------------------------------------------------------
3486 ;|Mnemonic |SZHPNC|Description |Notes |
3487 ;----------------------------------------------------------------
3488 ;
3489 ; TODO: Implement IFF1, IFF2
3490 do_op_ei:
3491 ret
3492
3493 ;----------------------------------------------------------------
3494 ;|Mnemonic |SZHPNC|Description |Notes |
3495 ;----------------------------------------------------------------
3496 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3497 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3498 ;|RET cc |------|Conditional Return |If cc RET |
3499 ;
3500 ;
3501 do_op_ifnz:
3502 sbrs z_flags, ZFL_Z
3503 ret
3504 ldi insdech, 0
3505 ldi insdecl, 0
3506 ret
3507
3508 ;----------------------------------------------------------------
3509 ;|Mnemonic |SZHPNC|Description |Notes |
3510 ;----------------------------------------------------------------
3511 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3512 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3513 ;|RET cc |------|Conditional Return |If cc RET |
3514 ;
3515 ;
3516 do_op_ifz:
3517 sbrc z_flags, ZFL_Z
3518 ret
3519 ldi insdech, 0
3520 ldi insdecl, 0
3521 ret
3522
3523 ;----------------------------------------------------------------
3524 ;|Mnemonic |SZHPNC|Description |Notes |
3525 ;----------------------------------------------------------------
3526 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3527 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3528 ;|RET cc |------|Conditional Return |If cc RET |
3529 ;
3530 ;
3531 do_op_ifnc:
3532 sbrs z_flags, ZFL_C
3533 ret
3534 ldi insdech, 0
3535 ldi insdecl, 0
3536 ret
3537
3538 ;----------------------------------------------------------------
3539 ;|Mnemonic |SZHPNC|Description |Notes |
3540 ;----------------------------------------------------------------
3541 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3542 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3543 ;|RET cc |------|Conditional Return |If cc RET |
3544 ;
3545 ;
3546 do_op_ifc:
3547 sbrc z_flags, ZFL_C
3548 ret
3549 ldi insdech, 0
3550 ldi insdecl, 0
3551 ret
3552
3553 ;----------------------------------------------------------------
3554 ;|Mnemonic |SZHPNC|Description |Notes |
3555 ;----------------------------------------------------------------
3556 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3557 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3558 ;|RET cc |------|Conditional Return |If cc RET |
3559 ;
3560 ;
3561 do_op_ifpo:
3562 sbrs z_flags, ZFL_P
3563 ret
3564 ldi insdech, 0
3565 ldi insdecl, 0
3566 ret
3567
3568 ;----------------------------------------------------------------
3569 ;|Mnemonic |SZHPNC|Description |Notes |
3570 ;----------------------------------------------------------------
3571 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3572 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3573 ;|RET cc |------|Conditional Return |If cc RET |
3574 ;
3575 ;
3576 do_op_ifpe:
3577 sbrc z_flags, ZFL_P
3578 ret
3579 ldi insdech, 0
3580 ldi insdecl, 0
3581 ret
3582
3583 ;----------------------------------------------------------------
3584 ;|Mnemonic |SZHPNC|Description |Notes |
3585 ;----------------------------------------------------------------
3586 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3587 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3588 ;|RET cc |------|Conditional Return |If cc RET |
3589 ;
3590 ;
3591 do_op_ifp: ;sign positive, aka s=0
3592 sbrs z_flags, ZFL_S
3593 ret
3594 ldi insdech,0
3595 ldi insdecl,0
3596 ret
3597
3598 ;----------------------------------------------------------------
3599 ;|Mnemonic |SZHPNC|Description |Notes |
3600 ;----------------------------------------------------------------
3601 ;|CALL cc,nn|------|Conditional Call |If cc CALL |
3602 ;|JP cc,nn |------|Conditional Jump |If cc JP |
3603 ;|RET cc |------|Conditional Return |If cc RET |
3604 ;
3605 ;
3606 do_op_ifm: ;sign negative, aka s=1
3607 sbrc z_flags, ZFL_S
3608 ret
3609 ldi insdech, 0
3610 ldi insdecl, 0
3611 ret
3612
3613 ;----------------------------------------------------------------
3614 ;|Mnemonic |SZHPNC|Description |Notes |
3615 ;----------------------------------------------------------------
3616 ;|OUT [n],A |------|Output |[n]=A |
3617 ;
3618 ;
3619 ;Interface with peripherials goes here :)
3620 do_op_outa: ; out (opl),a
3621 .if PORT_DEBUG
3622 rcall printstr
3623 .db 13,"Port write: ",0
3624 mov temp,z_a
3625 rcall printhex
3626 rcall printstr
3627 .db " -> (",0
3628 mov temp,opl
3629 rcall printhex
3630 rcall printstr
3631 .db ")",13,0
3632 .endif
3633 mov temp,z_a
3634 mov temp2,opl
3635 rcall portWrite
3636 ret
3637
3638 ;----------------------------------------------------------------
3639 ;|Mnemonic |SZHPNC|Description |Notes |
3640 ;----------------------------------------------------------------
3641 ;|IN A,[n] |------|Input |A=[n] |
3642 ;
3643 ;
3644 do_op_in: ; in a,(opl)
3645 .if PORT_DEBUG
3646 rcall printstr
3647 .db 13,"Port read: (",0
3648 mov temp,opl
3649 rcall printhex
3650 rcall printstr
3651 .db ") -> ",0
3652 .endif
3653
3654 mov temp2,opl
3655 rcall portRead
3656 mov opl,temp
3657
3658 .if PORT_DEBUG
3659 rcall printhex
3660 rcall printstr
3661 .db 13,0
3662 .endif
3663 ret
3664
3665 ;----------------------------------------------------------------
3666
3667 #if 0
3668 do_op_calcparity:
3669 ldi temp2,1
3670 sbrc parityb,0
3671 inc temp2
3672 sbrc parityb,1
3673 inc temp2
3674 sbrc parityb,2
3675 inc temp2
3676 sbrc parityb,3
3677 inc temp2
3678 sbrc parityb,4
3679 inc temp2
3680 sbrc parityb,5
3681 inc temp2
3682 sbrc parityb,6
3683 inc temp2
3684 sbrc parityb,7
3685 inc temp2
3686 andi temp2,1
3687 ret
3688 #endif
3689
3690 ;----------------------------------------------------------------
3691 do_op_inv:
3692 rcall printstr
3693 .db "Invalid opcode @ PC=",0,0
3694 mov temp,z_pch
3695 rcall printhex
3696 mov temp,z_pcl
3697 rcall printhex
3698
3699 ;----------------------------------------------------------------
3700 haltinv:
3701 rjmp haltinv
3702
3703 ;----------------------------------------------------------------
3704 ; Lookup table, stolen from z80ex, Z80 emulation library.
3705 ; http://z80ex.sourceforge.net/
3706
3707 ; The S, Z, 5 and 3 bits and the parity of the lookup value
3708 sz53p_tab:
3709 .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
3710 .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
3711 .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
3712 .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
3713 .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
3714 .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
3715 .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
3716 .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
3717 .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
3718 .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
3719 .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
3720 .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
3721 .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
3722 .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
3723 .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
3724 .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
3725 .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
3726 .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
3727 .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
3728 .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
3729 .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
3730 .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
3731 .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
3732 .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
3733 .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
3734 .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
3735 .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
3736 .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
3737 .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
3738 .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
3739 .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
3740 .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
3741
3742
3743 ; ----------------------- Opcode decoding -------------------------
3744
3745 ; Lookup table for Z80 opcodes. Translates the first byte of the instruction word into three
3746 ; operations: fetch, do something, store.
3747 ; The table is made of 256 words. These 16-bit words consist of
3748 ; the fetch operation (bit 0-4), the processing operation (bit 10-16) and the store
3749 ; operation (bit 5-9).
3750
3751 inst_table:
3752 .dw (FETCH_NOP | OP_NOP | STORE_NOP) ; 00 NOP
3753 .dw (FETCH_DIR16| OP_NOP | STORE_BC ) ; 01 nn nn LD BC,nn
3754 .dw (FETCH_A | OP_NOP | STORE_MBC ) ; 02 LD (BC),A
3755 .dw (FETCH_BC | OP_INC16 | STORE_BC ) ; 03 INC BC
3756 .dw (FETCH_B | OP_INC | STORE_B ) ; 04 INC B
3757 .dw (FETCH_B | OP_DEC | STORE_B ) ; 05 DEC B
3758 .dw (FETCH_DIR8 | OP_NOP | STORE_B ) ; 06 nn LD B,n
3759 .dw (FETCH_A | OP_RLC | STORE_A ) ; 07 RLCA
3760 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 08 EX AF,AF' (Z80)
3761 .dw (FETCH_BC | OP_ADDHL | STORE_HL ) ; 09 ADD HL,BC
3762 .dw (FETCH_MBC | OP_NOP | STORE_A ) ; 0A LD A,(BC)
3763 .dw (FETCH_BC | OP_DEC16 | STORE_BC ) ; 0B DEC BC
3764 .dw (FETCH_C | OP_INC | STORE_C ) ; 0C INC C
3765 .dw (FETCH_C | OP_DEC | STORE_C ) ; 0D DEC C
3766 .dw (FETCH_DIR8 | OP_NOP | STORE_C ) ; 0E nn LD C,n
3767 .dw (FETCH_A | OP_RRC | STORE_A ) ; 0F RRCA
3768 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 10 oo DJNZ o (Z80)
3769 .dw (FETCH_DIR16| OP_NOP | STORE_DE ) ; 11 nn nn LD DE,nn
3770 .dw (FETCH_A | OP_NOP | STORE_MDE) ; 12 LD (DE),A
3771 .dw (FETCH_DE | OP_INC16 | STORE_DE ) ; 13 INC DE
3772 .dw (FETCH_D | OP_INC | STORE_D ) ; 14 INC D
3773 .dw (FETCH_D | OP_DEC | STORE_D ) ; 15 DEC D
3774 .dw (FETCH_DIR8 | OP_NOP | STORE_D ) ; 16 nn LD D,n
3775 .dw (FETCH_A | OP_RL | STORE_A ) ; 17 RLA
3776 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 18 oo JR o (Z80)
3777 .dw (FETCH_DE | OP_ADDHL | STORE_HL ) ; 19 ADD HL,DE
3778 .dw (FETCH_MDE | OP_NOP | STORE_A ) ; 1A LD A,(DE)
3779 .dw (FETCH_DE | OP_DEC16 | STORE_DE ) ; 1B DEC DE
3780 .dw (FETCH_E | OP_INC | STORE_E ) ; 1C INC E
3781 .dw (FETCH_E | OP_DEC | STORE_E ) ; 1D DEC E
3782 .dw (FETCH_DIR8 | OP_NOP | STORE_E ) ; 1E nn LD E,n
3783 .dw (FETCH_A | OP_RR | STORE_A ) ; 1F RRA
3784 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 20 oo JR NZ,o (Z80)
3785 .dw (FETCH_DIR16| OP_NOP | STORE_HL ) ; 21 nn nn LD HL,nn
3786 .dw (FETCH_DIR16| OP_STHL | STORE_NOP) ; 22 nn nn LD (nn),HL
3787 .dw (FETCH_HL | OP_INC16 | STORE_HL ) ; 23 INC HL
3788 .dw (FETCH_H | OP_INC | STORE_H ) ; 24 INC H
3789 .dw (FETCH_H | OP_DEC | STORE_H ) ; 25 DEC H
3790 .dw (FETCH_DIR8 | OP_NOP | STORE_H ) ; 26 nn LD H,n
3791 .dw (FETCH_A | OP_DA | STORE_A ) ; 27 DAA
3792 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 28 oo JR Z,o (Z80)
3793 .dw (FETCH_HL | OP_ADDHL | STORE_HL ) ; 29 ADD HL,HL
3794 .dw (FETCH_DIR16| OP_RMEM16 | STORE_HL ) ; 2A nn nn LD HL,(nn)
3795 .dw (FETCH_HL | OP_DEC16 | STORE_HL ) ; 2B DEC HL
3796 .dw (FETCH_L | OP_INC | STORE_L ) ; 2C INC L
3797 .dw (FETCH_L | OP_DEC | STORE_L ) ; 2D DEC L
3798 .dw (FETCH_DIR8 | OP_NOP | STORE_L ) ; 2E nn LD L,n
3799 .dw (FETCH_A | OP_CPL | STORE_A ) ; 2F CPL
3800 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 30 oo JR NC,o (Z80)
3801 .dw (FETCH_DIR16| OP_NOP | STORE_SP ) ; 31 nn nn LD SP,nn
3802 .dw (FETCH_DIR16| OP_NOP | STORE_AM ) ; 32 nn nn LD (nn),A
3803 .dw (FETCH_SP | OP_INC16 | STORE_SP ) ; 33 INC SP
3804 .dw (FETCH_MHL | OP_INC | STORE_MHL) ; 34 INC (HL)
3805 .dw (FETCH_MHL | OP_DEC | STORE_MHL) ; 35 DEC (HL)
3806 .dw (FETCH_DIR8 | OP_NOP | STORE_MHL) ; 36 nn LD (HL),n
3807 .dw (FETCH_NOP | OP_SCF | STORE_NOP) ; 37 SCF
3808 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; 38 oo JR C,o (Z80)
3809 .dw (FETCH_SP | OP_ADDHL | STORE_HL ) ; 39 ADD HL,SP
3810 .dw (FETCH_DIR16| OP_RMEM8 | STORE_A ) ; 3A nn nn LD A,(nn)
3811 .dw (FETCH_SP | OP_DEC16 | STORE_SP ) ; 3B DEC SP
3812 .dw (FETCH_A | OP_INC | STORE_A ) ; 3C INC A
3813 .dw (FETCH_A | OP_DEC | STORE_A ) ; 3D DEC A
3814 .dw (FETCH_DIR8 | OP_NOP | STORE_A ) ; 3E nn LD A,n
3815 .dw (FETCH_NOP | OP_CCF | STORE_NOP) ; 3F CCF (Complement Carry Flag, gvd)
3816 .dw (FETCH_B | OP_NOP | STORE_B ) ; 40 LD B,r
3817 .dw (FETCH_C | OP_NOP | STORE_B ) ; 41 LD B,r
3818 .dw (FETCH_D | OP_NOP | STORE_B ) ; 42 LD B,r
3819 .dw (FETCH_E | OP_NOP | STORE_B ) ; 43 LD B,r
3820 .dw (FETCH_H | OP_NOP | STORE_B ) ; 44 LD B,r
3821 .dw (FETCH_L | OP_NOP | STORE_B ) ; 45 LD B,r
3822 .dw (FETCH_MHL | OP_NOP | STORE_B ) ; 46 LD B,r
3823 .dw (FETCH_A | OP_NOP | STORE_B ) ; 47 LD B,r
3824 .dw (FETCH_B | OP_NOP | STORE_C ) ; 48 LD C,r
3825 .dw (FETCH_C | OP_NOP | STORE_C ) ; 49 LD C,r
3826 .dw (FETCH_D | OP_NOP | STORE_C ) ; 4A LD C,r
3827 .dw (FETCH_E | OP_NOP | STORE_C ) ; 4B LD C,r
3828 .dw (FETCH_H | OP_NOP | STORE_C ) ; 4C LD C,r
3829 .dw (FETCH_L | OP_NOP | STORE_C ) ; 4D LD C,r
3830 .dw (FETCH_MHL | OP_NOP | STORE_C ) ; 4E LD C,r
3831 .dw (FETCH_A | OP_NOP | STORE_C ) ; 4F LD C,r
3832 .dw (FETCH_B | OP_NOP | STORE_D ) ; 50 LD D,r
3833 .dw (FETCH_C | OP_NOP | STORE_D ) ; 51 LD D,r
3834 .dw (FETCH_D | OP_NOP | STORE_D ) ; 52 LD D,r
3835 .dw (FETCH_E | OP_NOP | STORE_D ) ; 53 LD D,r
3836 .dw (FETCH_H | OP_NOP | STORE_D ) ; 54 LD D,r
3837 .dw (FETCH_L | OP_NOP | STORE_D ) ; 55 LD D,r
3838 .dw (FETCH_MHL | OP_NOP | STORE_D ) ; 56 LD D,r
3839 .dw (FETCH_A | OP_NOP | STORE_D ) ; 57 LD D,r
3840 .dw (FETCH_B | OP_NOP | STORE_E ) ; 58 LD E,r
3841 .dw (FETCH_C | OP_NOP | STORE_E ) ; 59 LD E,r
3842 .dw (FETCH_D | OP_NOP | STORE_E ) ; 5A LD E,r
3843 .dw (FETCH_E | OP_NOP | STORE_E ) ; 5B LD E,r
3844 .dw (FETCH_H | OP_NOP | STORE_E ) ; 5C LD E,r
3845 .dw (FETCH_L | OP_NOP | STORE_E ) ; 5D LD E,r
3846 .dw (FETCH_MHL | OP_NOP | STORE_E ) ; 5E LD E,r
3847 .dw (FETCH_A | OP_NOP | STORE_E ) ; 5F LD E,r
3848 .dw (FETCH_B | OP_NOP | STORE_H ) ; 60 LD H,r
3849 .dw (FETCH_C | OP_NOP | STORE_H ) ; 61 LD H,r
3850 .dw (FETCH_D | OP_NOP | STORE_H ) ; 62 LD H,r
3851 .dw (FETCH_E | OP_NOP | STORE_H ) ; 63 LD H,r
3852 .dw (FETCH_H | OP_NOP | STORE_H ) ; 64 LD H,r
3853 .dw (FETCH_L | OP_NOP | STORE_H ) ; 65 LD H,r
3854 .dw (FETCH_MHL | OP_NOP | STORE_H ) ; 66 LD H,r
3855 .dw (FETCH_A | OP_NOP | STORE_H ) ; 67 LD H,r
3856 .dw (FETCH_B | OP_NOP | STORE_L ) ; 68 LD L,r
3857 .dw (FETCH_C | OP_NOP | STORE_L ) ; 69 LD L,r
3858 .dw (FETCH_D | OP_NOP | STORE_L ) ; 6A LD L,r
3859 .dw (FETCH_E | OP_NOP | STORE_L ) ; 6B LD L,r
3860 .dw (FETCH_H | OP_NOP | STORE_L ) ; 6C LD L,r
3861 .dw (FETCH_L | OP_NOP | STORE_L ) ; 6D LD L,r
3862 .dw (FETCH_MHL | OP_NOP | STORE_L ) ; 6E LD L,r
3863 .dw (FETCH_A | OP_NOP | STORE_L ) ; 6F LD L,r
3864 .dw (FETCH_B | OP_NOP | STORE_MHL) ; 70 LD (HL),r
3865 .dw (FETCH_C | OP_NOP | STORE_MHL) ; 71 LD (HL),r
3866 .dw (FETCH_D | OP_NOP | STORE_MHL) ; 72 LD (HL),r
3867 .dw (FETCH_E | OP_NOP | STORE_MHL) ; 73 LD (HL),r
3868 .dw (FETCH_H | OP_NOP | STORE_MHL) ; 74 LD (HL),r
3869 .dw (FETCH_L | OP_NOP | STORE_MHL) ; 75 LD (HL),r
3870 .dw (FETCH_NOP | OP_NOP | STORE_NOP) ; 76 HALT
3871 .dw (FETCH_A | OP_NOP | STORE_MHL) ; 77 LD (HL),r
3872 .dw (FETCH_B | OP_NOP | STORE_A ) ; 78 LD A,r
3873 .dw (FETCH_C | OP_NOP | STORE_A ) ; 79 LD A,r
3874 .dw (FETCH_D | OP_NOP | STORE_A ) ; 7A LD A,r
3875 .dw (FETCH_E | OP_NOP | STORE_A ) ; 7B LD A,r
3876 .dw (FETCH_H | OP_NOP | STORE_A ) ; 7C LD A,r
3877 .dw (FETCH_L | OP_NOP | STORE_A ) ; 7D LD A,r
3878 .dw (FETCH_MHL | OP_NOP | STORE_A ) ; 7E LD A,r
3879 .dw (FETCH_A | OP_NOP | STORE_A ) ; 7F LD A,r
3880 .dw (FETCH_B | OP_ADDA | STORE_A ) ; 80 ADD A,r
3881 .dw (FETCH_C | OP_ADDA | STORE_A ) ; 81 ADD A,r
3882 .dw (FETCH_D | OP_ADDA | STORE_A ) ; 82 ADD A,r
3883 .dw (FETCH_E | OP_ADDA | STORE_A ) ; 83 ADD A,r
3884 .dw (FETCH_H | OP_ADDA | STORE_A ) ; 84 ADD A,r
3885 .dw (FETCH_L | OP_ADDA | STORE_A ) ; 85 ADD A,r
3886 .dw (FETCH_MHL | OP_ADDA | STORE_A ) ; 86 ADD A,r
3887 .dw (FETCH_A | OP_ADDA | STORE_A ) ; 87 ADD A,r
3888 .dw (FETCH_B | OP_ADCA | STORE_A ) ; 88 ADC A,r
3889 .dw (FETCH_C | OP_ADCA | STORE_A ) ; 89 ADC A,r
3890 .dw (FETCH_D | OP_ADCA | STORE_A ) ; 8A ADC A,r
3891 .dw (FETCH_E | OP_ADCA | STORE_A ) ; 8B ADC A,r
3892 .dw (FETCH_H | OP_ADCA | STORE_A ) ; 8C ADC A,r
3893 .dw (FETCH_L | OP_ADCA | STORE_A ) ; 8D ADC A,r
3894 .dw (FETCH_MHL | OP_ADCA | STORE_A ) ; 8E ADC A,r
3895 .dw (FETCH_A | OP_ADCA | STORE_A ) ; 8F ADC A,r
3896 .dw (FETCH_B | OP_SUBFA | STORE_A ) ; 90 SUB A,r
3897 .dw (FETCH_C | OP_SUBFA | STORE_A ) ; 91 SUB A,r
3898 .dw (FETCH_D | OP_SUBFA | STORE_A ) ; 92 SUB A,r
3899 .dw (FETCH_E | OP_SUBFA | STORE_A ) ; 93 SUB A,r
3900 .dw (FETCH_H | OP_SUBFA | STORE_A ) ; 94 SUB A,r
3901 .dw (FETCH_L | OP_SUBFA | STORE_A ) ; 95 SUB A,r
3902 .dw (FETCH_MHL | OP_SUBFA | STORE_A ) ; 96 SUB A,r
3903 .dw (FETCH_A | OP_SUBFA | STORE_A ) ; 97 SUB A,r
3904 .dw (FETCH_B | OP_SBCFA | STORE_A ) ; 98 SBC A,r
3905 .dw (FETCH_C | OP_SBCFA | STORE_A ) ; 99 SBC A,r
3906 .dw (FETCH_D | OP_SBCFA | STORE_A ) ; 9A SBC A,r
3907 .dw (FETCH_E | OP_SBCFA | STORE_A ) ; 9B SBC A,r
3908 .dw (FETCH_H | OP_SBCFA | STORE_A ) ; 9C SBC A,r
3909 .dw (FETCH_L | OP_SBCFA | STORE_A ) ; 9D SBC A,r
3910 .dw (FETCH_MHL | OP_SBCFA | STORE_A ) ; 9E SBC A,r
3911 .dw (FETCH_A | OP_SBCFA | STORE_A ) ; 9F SBC A,r
3912 .dw (FETCH_B | OP_ANDA | STORE_A ) ; A0 AND A,r
3913 .dw (FETCH_C | OP_ANDA | STORE_A ) ; A1 AND A,r
3914 .dw (FETCH_D | OP_ANDA | STORE_A ) ; A2 AND A,r
3915 .dw (FETCH_E | OP_ANDA | STORE_A ) ; A3 AND A,r
3916 .dw (FETCH_H | OP_ANDA | STORE_A ) ; A4 AND A,r
3917 .dw (FETCH_L | OP_ANDA | STORE_A ) ; A5 AND A,r
3918 .dw (FETCH_MHL | OP_ANDA | STORE_A ) ; A6 AND A,r
3919 .dw (FETCH_A | OP_ANDA | STORE_A ) ; A7 AND A,r
3920 .dw (FETCH_B | OP_XORA | STORE_A ) ; A8 XOR A,r
3921 .dw (FETCH_C | OP_XORA | STORE_A ) ; A9 XOR A,r
3922 .dw (FETCH_D | OP_XORA | STORE_A ) ; AA XOR A,r
3923 .dw (FETCH_E | OP_XORA | STORE_A ) ; AB XOR A,r
3924 .dw (FETCH_H | OP_XORA | STORE_A ) ; AC XOR A,r
3925 .dw (FETCH_L | OP_XORA | STORE_A ) ; AD XOR A,r
3926 .dw (FETCH_MHL | OP_XORA | STORE_A ) ; AE XOR A,r
3927 .dw (FETCH_A | OP_XORA | STORE_A ) ; AF XOR A,r
3928 .dw (FETCH_B | OP_ORA | STORE_A ) ; B0 OR A,r
3929 .dw (FETCH_C | OP_ORA | STORE_A ) ; B1 OR A,r
3930 .dw (FETCH_D | OP_ORA | STORE_A ) ; B2 OR A,r
3931 .dw (FETCH_E | OP_ORA | STORE_A ) ; B3 OR A,r
3932 .dw (FETCH_H | OP_ORA | STORE_A ) ; B4 OR A,r
3933 .dw (FETCH_L | OP_ORA | STORE_A ) ; B5 OR A,r
3934 .dw (FETCH_MHL | OP_ORA | STORE_A ) ; B6 OR A,r
3935 .dw (FETCH_A | OP_ORA | STORE_A ) ; B7 OR A,r
3936 .dw (FETCH_B | OP_SUBFA | STORE_NOP) ; B8 CP A,r
3937 .dw (FETCH_C | OP_SUBFA | STORE_NOP) ; B9 CP A,r
3938 .dw (FETCH_D | OP_SUBFA | STORE_NOP) ; BA CP A,r
3939 .dw (FETCH_E | OP_SUBFA | STORE_NOP) ; BB CP A,r
3940 .dw (FETCH_H | OP_SUBFA | STORE_NOP) ; BC CP A,r
3941 .dw (FETCH_L | OP_SUBFA | STORE_NOP) ; BD CP A,r
3942 .dw (FETCH_MHL | OP_SUBFA | STORE_NOP) ; BE CP A,r
3943 .dw (FETCH_A | OP_SUBFA | STORE_NOP) ; BF CP A,r
3944 .dw (FETCH_NOP | OP_IFNZ | STORE_RET) ; C0 RET NZ
3945 .dw (FETCH_NOP | OP_POP16 | STORE_BC ) ; C1 POP BC
3946 .dw (FETCH_DIR16| OP_IFNZ | STORE_PC ) ; C2 nn nn JP NZ,nn
3947 .dw (FETCH_DIR16| OP_NOP | STORE_PC ) ; C3 nn nn JP nn
3948 .dw (FETCH_DIR16| OP_IFNZ | STORE_CALL) ; C4 nn nn CALL NZ,nn
3949 .dw (FETCH_BC | OP_PUSH16 | STORE_NOP) ; C5 PUSH BC
3950 .dw (FETCH_DIR8 | OP_ADDA | STORE_A ) ; C6 nn ADD A,n
3951 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; C7 RST 0
3952 .dw (FETCH_NOP | OP_IFZ | STORE_RET) ; C8 RET Z
3953 .dw (FETCH_NOP | OP_NOP | STORE_RET) ; C9 RET
3954 .dw (FETCH_DIR16| OP_IFZ | STORE_PC ) ; CA nn nn JP Z,nn
3955 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; CB (Z80 specific)
3956 .dw (FETCH_DIR16| OP_IFZ | STORE_CALL) ; CC nn nn CALL Z,nn
3957 .dw (FETCH_DIR16| OP_NOP | STORE_CALL) ; CD nn nn CALL nn
3958 .dw (FETCH_DIR8 | OP_ADCA | STORE_A ) ; CE nn ADC A,n
3959 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; CF RST 8H
3960 .dw (FETCH_NOP | OP_IFNC | STORE_RET) ; D0 RET NC
3961 .dw (FETCH_NOP | OP_POP16 | STORE_DE ) ; D1 POP DE
3962 .dw (FETCH_DIR16| OP_IFNC | STORE_PC ) ; D2 nn nn JP NC,nn
3963 .dw (FETCH_DIR8 | OP_OUTA | STORE_NOP) ; D3 nn OUT (n),A
3964 .dw (FETCH_DIR16| OP_IFNC | STORE_CALL) ; D4 nn nn CALL NC,nn
3965 .dw (FETCH_DE | OP_PUSH16 | STORE_NOP) ; D5 PUSH DE
3966 .dw (FETCH_DIR8 | OP_SUBFA | STORE_A ) ; D6 nn SUB n
3967 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; D7 RST 10H
3968 .dw (FETCH_NOP | OP_IFC | STORE_RET) ; D8 RET C
3969 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; D9 EXX (Z80)
3970 .dw (FETCH_DIR16| OP_IFC | STORE_PC ) ; DA nn nn JP C,nn
3971 .dw (FETCH_DIR8 | OP_IN | STORE_A ) ; DB nn IN A,(n)
3972 .dw (FETCH_DIR16| OP_IFC | STORE_CALL) ; DC nn nn CALL C,nn
3973 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; DD (Z80)
3974 .dw (FETCH_DIR8 | OP_SBCFA | STORE_A ) ; DE nn SBC A,n
3975 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; DF RST 18H
3976 .dw (FETCH_NOP | OP_IFPO | STORE_RET) ; E0 RET PO
3977 .dw (FETCH_NOP | OP_POP16 | STORE_HL ) ; E1 POP HL
3978 .dw (FETCH_DIR16| OP_IFPO | STORE_PC ) ; E2 nn nn JP PO,nn
3979 .dw (FETCH_MSP | OP_EXHL | STORE_MSP) ; E3 EX (SP),HL
3980 .dw (FETCH_DIR16| OP_IFPO | STORE_CALL) ; E4 nn nn CALL PO,nn
3981 .dw (FETCH_HL | OP_PUSH16 | STORE_NOP) ; E5 PUSH HL
3982 .dw (FETCH_DIR8 | OP_ANDA | STORE_A ) ; E6 nn AND n
3983 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; E7 RST 20H
3984 .dw (FETCH_NOP | OP_IFPE | STORE_RET) ; E8 RET PE
3985 .dw (FETCH_HL | OP_NOP | STORE_PC ) ; E9 JP (HL)
3986 .dw (FETCH_DIR16| OP_IFPE | STORE_PC ) ; EA nn nn JP PE,nn
3987 .dw (FETCH_DE | OP_EXHL | STORE_DE ) ; EB EX DE,HL
3988 .dw (FETCH_DIR16| OP_IFPE | STORE_CALL) ; EC nn nn CALL PE,nn
3989 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; ED (Z80 specific)
3990 .dw (FETCH_DIR8 | OP_XORA | STORE_A ) ; EE nn XOR n
3991 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; EF RST 28H
3992 .dw (FETCH_NOP | OP_IFP | STORE_RET) ; F0 RET P
3993 .dw (FETCH_NOP | OP_POP16 | STORE_AF ) ; F1 POP AF
3994 .dw (FETCH_DIR16| OP_IFP | STORE_PC ) ; F2 nn nn JP P,nn
3995 .dw (FETCH_NOP | OP_DI | STORE_NOP) ; F3 DI
3996 .dw (FETCH_DIR16| OP_IFP | STORE_CALL) ; F4 nn nn CALL P,nn
3997 .dw (FETCH_AF | OP_PUSH16 | STORE_NOP) ; F5 PUSH AF
3998 .dw (FETCH_DIR8 | OP_ORA | STORE_A ) ; F6 nn OR n
3999 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; F7 RST 30H
4000 .dw (FETCH_NOP | OP_IFM | STORE_RET) ; F8 RET M
4001 .dw (FETCH_HL | OP_NOP | STORE_SP ) ; F9 LD SP,HL
4002 .dw (FETCH_DIR16| OP_IFM | STORE_PC ) ; FA nn nn JP M,nn
4003 .dw (FETCH_NOP | OP_EI | STORE_NOP) ; FB EI
4004 .dw (FETCH_DIR16| OP_IFM | STORE_CALL) ; FC nn nn CALL M,nn
4005 .dw (FETCH_NOP | OP_INV | STORE_NOP) ; FD (Z80 specific)
4006 .dw (FETCH_DIR8 | OP_SUBFA | STORE_NOP) ; FE nn CP n
4007 .dw (FETCH_RST | OP_NOP | STORE_CALL) ; FF RST 38H
4008
4009 ; vim:set ts=8 noet nowrap
4010