4 * Copyright (C) 1989-2021 Alan R. Baldwin
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.
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.
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/>.
26 * xerr messages Copyright (C) 1989-2021 Alan R. Baldwin
28 * Things missing that exist in 5.40:
34 * Extensions: P. Felber
41 /* Gameboy mods by Roger Ivie (ivie at cc dot usu dot edu); see gb.h for more info
47 char *cpu
= "GameBoy";
50 char imtab
[3] = { 0x46, 0x56, 0x5E };
53 * Opcode Cycle Definitions
55 #define OPCY_SDP ((char) (0xFF))
56 #define OPCY_ERR ((char) (0xFE))
58 /* OPCY_NONE ((char) (0x80)) */
59 /* OPCY_MASK ((char) (0x7F)) */
61 #define UN ((char) (OPCY_NONE | 0x00))
62 #define P2 ((char) (OPCY_NONE | 0x01))
65 * GB Opcode Cycle Pages
68 static char gbpg1
[256] = {
69 /*--*--* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
70 /*--*--* - - - - - - - - - - - - - - - - */
71 /*00*/ 4,12, 8, 8, 4, 4, 8, 4,20, 8, 8, 8, 4, 4, 8, 4,
72 /*10*/ 4,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,
73 /*20*/ 12,12, 8, 8, 4, 4, 8, 4,12, 8, 8, 8, 4, 4, 8, 4,
74 /*30*/ 12,12, 8, 8,12,12,12, 4,12, 8, 8, 8, 4, 4, 8, 4,
75 /*40*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
76 /*50*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
77 /*60*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
78 /*70*/ 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
79 /*80*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
80 /*90*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
81 /*A0*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
82 /*B0*/ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
83 /*C0*/ 20,12,16,16,24,16, 8,16,20,16,16,P2
,24,24, 8,16,
84 /*D0*/ 20,12,16,UN
,24,16, 8,16,20,16,16,UN
,24,UN
, 8,16,
85 /*E0*/ 12,12, 8,UN
,UN
,16, 8,16,16, 4,16,UN
,UN
,UN
, 8,16,
86 /*F0*/ 12,12, 8, 4,UN
,16, 8,16,12, 8,16, 4,UN
,UN
, 8,16
89 static char gbpg2
[256] = { /* P2 == CB */
90 /*--*--* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
91 /*--*--* - - - - - - - - - - - - - - - - */
92 /*00*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
93 /*10*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
94 /*20*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
95 /*30*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
96 /*40*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
97 /*50*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
98 /*60*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
99 /*70*/ 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
100 /*80*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
101 /*90*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
102 /*A0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
103 /*B0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
104 /*C0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
105 /*D0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
106 /*E0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8,
107 /*F0*/ 8, 8, 8, 8, 8, 8,16, 8, 8, 8, 8, 8, 8, 8,16, 8
110 static char *gbPage
[2] = {
115 * Process a machine op.
124 int d
,c
,i
,th
,tl
,oops
; /* for dealing with .tile */
128 op
= (int) mp
->m_valu
;
138 if ((v1
= admode(CND
)) != 0) {
141 xerr('q', "Condition codes are NZ, Z, NC, and C.");
153 if ((v1
= admode(R16
)) != 0 && (v1
&= 0xFF) != SP
) {
157 xerr('a', "Register SP is invalid.");
161 v1
= (int) absexpr();
163 xerr('a', "Valid values are N * 0x08, N = 0 -> 7.");
173 xerr('a', "Valid values are 0 -> 2.");
177 outab(imtab
[(int) e1
.e_addr
]);
183 v1
= (int) e1
.e_addr
;
192 if (genop(0xCB, op
, &e2
, 0) || t1
)
193 xerr('a', "Invalid Addressing Mode.");
200 if ((t2
!= S_R8
) || (e2
.e_addr
!= A
))
206 if (genop(0xCB, op
, &e2
, 0) || t1
)
207 xerr('a', "Invalid Addressing Mode.");
210 /* TODO: where is S_SWAP? */
217 if ((t2
!= S_R8
) || (e2
.e_addr
!= A
))
223 if (genop(0, op
, &e2
, 1) || t1
)
224 xerr('a', "Invalid Addressing Mode.");
236 if (genop(0, op
, &e1
, 1))
237 xerr('a', "Invalid Addressing Mode.");
240 if ((t1
== S_R8
) && (e1
.e_addr
== A
)) {
241 if (genop(0, op
, &e2
, 1))
242 xerr('a', "Invalid Addressing Mode.");
245 xerr('a', "Invalid Addressing Mode.");
256 if (genop(0, op
, &e1
, 1))
257 xerr('a', "Invalid Addressing Mode.");
260 if ((t1
== S_R8
) && (e1
.e_addr
== A
)) {
261 if (genop(0, op
, &e2
, 1))
262 xerr('a', "Invalid Addressing Mode.");
265 if ((t1
== S_R16
) && (t2
== S_R16
)) {
268 v1
= (int) e1
.e_addr
;
269 v2
= (int) e2
.e_addr
;
270 if ((v1
== HL
) && (v2
<= SP
)) {
271 outab(op
| (v2
<< 4));
279 if ((t1
== S_R16
) && (t2
== S_IMMED
)) {
281 xerr('a', "ADC, SUB, and SBC are invalid.");
284 if( e1
.e_addr
== SP
) {
290 xerr('a', "Invalid Addressing Mode.");
299 v1
= (int) (e1
.e_addr
<<3);
300 if (genop(0, op
| v1
, &e2
, 0) == 0)
309 v1
= (int) e1
.e_addr
;
310 v2
= (int) e2
.e_addr
;
312 if ((t1
== S_R16
) && (t2
== S_IMMED
)) {
313 outab(0x01 | (v1
<<4));
317 if ((t2
== S_R8
) && (t1
== S_IDHL
)) {
323 if ((t2
== S_IMMED
) && (t1
== S_IDHL
)) {
330 if ((t1
== S_R16
) && (v1
== SP
)) {
331 if ((t2
== S_R16
) && (v2
== HL
)) {
336 if ((t1
== S_R8
) && (v1
== A
)) {
337 if ((t2
== S_IDBC
) || (t2
== S_IDDE
)) {
338 outab(0x0A | ((t2
-S_INDR
)<<4));
342 if ((t2
== S_R8
) && (v2
== A
)) {
343 if ((t1
== S_IDBC
) || (t1
== S_IDDE
)) {
344 outab(0x02 | ((t1
-S_INDR
)<<4));
351 if ((t1
== S_INDM
) && (t2
== S_R16
) && (v2
== SP
)) {
360 if ((t1
== S_INDM
) && (t2
== S_R8
) && (v2
== A
)) {
365 if ((t2
== S_INDM
) && (t1
== S_R8
) && (v1
== A
)) {
374 if ((t1
== S_R8
) && (v1
== A
) && (t2
== S_IDHLD
)) {
378 if ((t2
== S_R8
) && (v2
== A
) && (t1
== S_IDHLD
)) {
386 if ((t1
== S_R8
) && (v1
== A
) && (t2
== S_IDHLI
)) {
390 if ((t2
== S_R8
) && (v2
== A
) && (t1
== S_IDHLI
)) {
394 xerr('a', "Invalid Addressing Mode.");
397 /* TODO: find out where this handled in upstream */
398 case S_STOP
: /* 0x10 */
406 case S_LDA
: /* 0xE8 */ /* extension */
408 * 0xE8 : LDA SP,#n(SP)
409 * 0xF8 : LDA HL,#n(SP)
414 if ((t1
== S_R16
) && (e1
.e_addr
== SP
) && (t2
== S_INDR
+SP
)) {
419 if ((t1
== S_R16
) && (e1
.e_addr
== HL
) && (t2
== S_INDR
+SP
)) {
424 xerr('a', "Invalid Addressing Mode.");
427 case S_LDHL
: /* 0xF8 */ /* extension */
434 if ((t1
== S_R16
) && (e1
.e_addr
== SP
) && (t2
== S_IMMED
)) {
439 xerr('a', "Invalid Addressing Mode.");
445 v1
= (int) e1
.e_addr
;
464 xerr('a', "Invalid Addressing Mode.");
468 if ((v1
= admode(CND
)) != 0 ) {
469 if ((v1
&= 0xFF) <= 0x03) {
472 xerr('q', "Condition codes are NZ, Z, NC, and C.");
479 v2
= (int) (e2
.e_addr
- dot
.s_addr
- 1);
480 if (pass
== 2 && ((v2
< -128) || (v2
> 127)))
481 xerr('a', "Branching Range Exceeded.");
486 if (e2
.e_mode
!= S_USER
)
491 if ((v1
= admode(CND
)) != 0) {
503 if ((v1
= admode(CND
)) != 0) {
517 if ((e1
.e_addr
== 0) && (t1
== S_IDHL
)) {
521 xerr('a', "Invalid Addressing Mode.");
526 * 0xE0 : LDH (n),A = LD ($FF00+n),A
527 * 0xE2 : LDH (C),A = LD ($FF00+C),A
528 * 0xF0 : LDH A,(n) = LD A,($FF00+n)
529 * 0xF2 : LDH A,(C) = LD A,($FF00+C)
535 v1
= (int) e1
.e_addr
;
536 v2
= (int) e2
.e_addr
;
538 if ((t1
== S_R8
) && (v1
== A
) && (t2
== S_INDM
)) {
543 if ((t2
== S_R8
) && (v2
== A
) && (t1
== S_INDM
)) {
548 if ((t1
== S_R8
) && (v1
== A
) && (t2
== S_IDC
)) {
552 if ((t2
== S_R8
) && (v2
== A
) && (t1
== S_IDC
)) {
556 xerr('a', "Invalid Addressing Mode.");
560 /* Ported from ASXXXX 5.40 */
561 /* The .tile pseudo-op. It generates two bytes from
562 * an 8-character ASCII string to represent a line of
563 * pixels in a Gameboy character.
566 /* Like .ASCII, the first character after .TILE is used
567 * as the string delimiter. Get it.
570 if ((d
= getnb()) == '^') {
574 xerr('q', "TILE is a chunk of 8 characters.");
577 /* .tile deals with chunks of 8 characters. We need to
578 * generate an error if we get fewer than 8 characters in
579 * chunk, so we have a modulo-8 counter to keep track of
580 * how many characters we've processed. We also need to
581 * generate an error if we see a character we don't
582 * recognize; this can be done either with a goto
583 * or an 'oops' flag. Although I normally lean towards
584 * goto implementations, since I didn't design _all_
585 * of this code that would be ugly; so we need to
586 * initialize the oops flag. We also need to initialize
587 * the variables we'll be using to collect the bits.
591 c
= get(); /* Prime the pump */
596 /* Process characters until we find one we don't
597 * understand, encounter the delimiter, or run into
601 while( ( oops
== 0 ) && ( c
!= d
) && ( c
!= 0 ) ) {
631 /* Spit out the tile data.
643 /* Figure out whether we left the while loop early. If so,
648 xerr('a', "Invalid character or terminated without 8 characters.");
652 /* Make sure we have the delimiter next. This should
653 * already have been fetched by the end of the while().
654 * What this primarily buys us that the check for
655 * the modulo-8 counter does not is detecting a string
656 * which ended with an end-of-line rather than a
661 xerr('q', "Missing TILE terminator.");
668 xerr('o', "Internal Opcode Error.");
672 if (opcycles
== OPCY_NONE
) {
673 opcycles
= gbpg1
[cb
[0] & 0xFF];
674 if ((opcycles
& OPCY_NONE
) && (opcycles
& OPCY_MASK
)) {
675 opcycles
= gbPage
[opcycles
& OPCY_MASK
][cb
[1] & 0xFF];
681 * general addressing evaluation
682 * return(0) if general addressing mode output, else
683 * return(esp->e_mode)
686 genop(pop
, op
, esp
, f
)
692 if ((t1
= esp
->e_mode
) == S_R8
) {
695 outab(op
|esp
->e_addr
);
704 if ((t1
== S_IMMED
) && (f
)) {
715 * Branch/Jump PCR Mode Check
721 if (esp
->e_base
.e_ap
== dot
.s_area
) {
724 if (esp
->e_flag
==0 && esp
->e_base
.e_ap
==NULL
) {
726 * Absolute Destination
728 * Use the global symbol '.__.ABS.'
729 * of value zero and force the assembler
730 * to use this absolute constant as the
731 * base value for the relocation.
734 esp
->e_base
.e_sp
= &sym
[1];
740 * Machine dependent initialization