| %{ | |
| /* m68k_parse.c: line assembler for generic m68k_cpu | |
| Copyright (c) 2009-2010, Holger Veit | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| HOLGER VEIT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of Holger Veit et al shall not be | |
| used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from Holger Veit et al. | |
| 04-Oct-09 HV Initial version | |
| */ | |
| #include "m68k_cpu.h" | |
| #include <ctype.h> | |
| #include <string.h> | |
| #if defined(_WIN32) | |
| #include <windows.h> | |
| #else | |
| #include <unistd.h> | |
| #endif | |
| struct _ea { | |
| int ea; | |
| int cnt; | |
| t_value arg[10]; | |
| }; | |
| struct _rea { | |
| int reg; | |
| struct _ea ea; | |
| }; | |
| struct _mask { | |
| int x; | |
| int d; | |
| }; | |
| struct _brop { | |
| int opc; | |
| int len; | |
| }; | |
| static int oplen; | |
| static int movemx[] = { 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, | |
| 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080 }; | |
| static int movemd[] = { 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001, | |
| 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100 }; | |
| static int yyrc; | |
| static int yyerrc; | |
| extern int yylex(); | |
| static int _genop(t_value arg); | |
| static int _genea(struct _ea arg); | |
| static int _genbr(t_value arg,t_value,int); | |
| static void yyerror(char* s); | |
| #define YYDEBUG 1 | |
| %} | |
| %union { | |
| int rc; | |
| int reg; | |
| int wl; | |
| int opc; | |
| struct _ea ea; | |
| t_value num; | |
| struct _rea rea; | |
| struct _mask mask; | |
| struct _brop brop; | |
| } | |
| %token A0 A1 A2 A3 A4 A5 A6 A7 D0 D1 D2 D3 D4 D5 D6 D7 | |
| %token CCR SR USP PC | |
| %token <num> NUMBER | |
| %token ABCD ADD ADDA ADDI ADDQ ADDX AND ANDI OR ORI SBCD SUB SUBA SUBI SUBQ SUBX | |
| %token ASL ASR LSL LSR ROL ROR ROXL ROXR | |
| %token BCC BCS BEQ BGE BGT BHI BLE BLS BLT BMI BNE BPL BVC BVS BSR BRA | |
| %token BCLR BSET BCHG BTST CHK CMP CMPA CMPI CMPM EOR EORI EXG EXT | |
| %token DIVU DIVS MULU MULS | |
| %token DBCC DBCS DBEQ DBF DBGE DBGT DBHI DBLE DBLS DBLT DBMI DBNE DBPL DBT DBVC DBVS | |
| %token SCC SCS SEQ SF SGE SGT SHI SLE SLS SLT SMI SNE SPL ST SVC SVS | |
| %token ILLEGAL NOP RESET RTE RTR RTS TRAPV | |
| %token JMP JSR LEA LINK MOVE MOVEA MOVEM MOVEP MOVEQ | |
| %token CLR NEG NEGX NBCD NOT PEA STOP TAS SWAP TRAP TST UNLK | |
| %token PREDEC POSTINC BSIZE WSIZE LSIZE SSIZE | |
| %start stmt | |
| %type <opc> bcdop bcdarg dualop immop qop immop2 shftarg monop btop | |
| %type <opc> mdop dbop jop arop | |
| %type <opc> direct | |
| %type <brop> brop | |
| %type <rea> dualarg shftop | |
| %type <reg> dreg areg | |
| %type <ea> ea0 ea1 ea2 ea3 ea4 ea5 ea6 ea70 ea72 ea73 ea74 eama eaa eaall eada eadas easr ead eac eacad eacai | |
| %type <wl> szwl szbwl szmv szm szs | |
| %type <mask> regs reglist | |
| %% | |
| stmt: | |
| bcdop bcdarg { _genop($1 | $2); yyrc = -1; } | |
| | dualop dualarg { _genop($1 | $2.reg | $2.ea.ea); yyrc = _genea($2.ea) -1; } | |
| | immop '#' NUMBER ',' eada { _genop($1 | $5.ea); if (oplen==0) { _genop($3 & 0xff); yyrc = _genea($5) - 3; } | |
| else if (oplen==1) { _genop($3); yyrc = _genea($5) - 3; } else { _genop($3>>16); _genop($3 & 0xffff); yyrc = _genea($5)-5; } } | |
| | qop '#' NUMBER ',' eaa { _genop($1 | (($3&7)<<9) | $5.ea); yyrc = _genea($5) - 1; } | |
| | immop2 '#' NUMBER ',' eadas { _genop($1 | $5.ea); if (oplen==0) { _genop($3 & 0xff); yyrc = _genea($5) - 3; } | |
| else if (oplen==1) { _genop($3); yyrc = _genea($5) - 3; } else { _genop($3>>16); _genop($3 & 0xffff); yyrc = _genea($5)-5; } } | |
| | shftop { _genop($1.reg); if (($1.reg&0xc0)==0xc0) yyrc = _genea($1.ea) - 1; else { yyrc = -1; } } | |
| | brop NUMBER { yyrc = _genbr($1.opc,$2,$1.len) - 1; } | |
| | btop dreg ',' eada { _genop($1 | ($2<<9) | 0x100 | $4.ea); yyrc = _genea($4) - 1; } | |
| | btop '#' NUMBER ',' eada { _genop($1 | 0x0800 | $5.ea); _genop($3); yyrc = _genea($5) - 3; } | |
| | CHK ead ',' dreg { _genop(0x4180 | ($4<<9) | $2.ea); yyrc = _genea($2) - 1; } | |
| | monop eada { _genop($1 | $2.ea); yyrc = _genea($2) - 1; } | |
| | CMP szbwl eaall ',' dreg { _genop(0xb000 | ($2<<6) | ($5<<9) | $3.ea); yyrc = _genea($3) - 1; } | |
| | mdop ead ',' dreg { _genop($1 | ($4<<9) | $2.ea); yyrc = _genea($2) - 1; } | |
| | CMPA szwl eaall ',' areg { _genop(0xb0c0 | ($2<<8) | ($5<<9) | $3.ea); yyrc = _genea($3) - 1; } | |
| | CMPM szbwl ea3 ',' ea3 { _genop(0xb108 | ($5.ea<<9) | ($2<<6) | $3.ea); yyrc = -1; } | |
| | dbop dreg ',' NUMBER { yyrc = _genbr($1 | $2, $4, 1) - 1; } | |
| | EOR szbwl dreg ',' eada { _genop(0xb000 | ($2 << 6) | 0x100 | $5.ea); yyrc = _genea($5) - 1; } | |
| | EXG dreg ',' dreg { _genop(0xc140 | ($2<<9) | $4); yyrc = -1; } | |
| | EXG areg ',' areg { _genop(0xc148 | ($2<<9) | $4); yyrc = -1; } | |
| | EXG areg ',' dreg { _genop(0xc188 | ($4<<9) | $2); yyrc = -1; } | |
| | EXG dreg ',' areg { _genop(0xc188 | ($2<<9) | $4); yyrc = -1; } | |
| | EXT szwl dreg { _genop(0x4840 | ($2<<6) | $3); yyrc = -1; } | |
| | direct { _genop($1); yyrc = -1; } | |
| | jop eac { _genop($1 | $2.ea); yyrc = _genea($2) -1; } | |
| | LEA eac ',' areg { _genop(0x41c0 | $2.ea); yyrc = _genea($2) - 1; } | |
| | LINK areg ',' '#' NUMBER { _genop(0x4e50 | $2); _genop($5); yyrc = -3; } | |
| | MOVE szmv eaall ',' eadas { if ($5.ea==074) { _genop(0x44c0 | ($5.cnt==1?0x0200:0x0000) | $3.ea); yyrc = _genea($3) - 1; } | |
| else { int tmp = (($5.ea&070)>>3)|(($5.ea&7)<<3); _genop(0x0000 | ($2<<12) | (tmp<<6) | $3.ea); | |
| yyrc = _genea($3) - 1; yyrc += _genea($5); } } | |
| | MOVE SR ',' eada { _genop(0x40c0 | $4.ea); yyrc = _genea($4) - 1; } | |
| | MOVE USP ',' areg { _genop(0x4e68 | $4); yyrc = -1; } | |
| | MOVE areg ',' USP { _genop(0x4e60 | $2); yyrc = -1; } | |
| | MOVEA szm eada ',' areg { _genop(0x0040 | ($2<<12) | ($5<<9) | $3.ea); yyrc = _genea($3) - 1; } | |
| | MOVEM szwl reglist ',' eacad { _genop(0x4880 | ($2<<6) | $5.ea); _genop(($5.ea&070)==040 ? $3.d : $3.x); yyrc = _genea($5) - 3; } | |
| | MOVEM szwl eacai ',' reglist { _genop(0x4c80 | ($2<<6) | $3.ea); _genop($5.x); yyrc = _genea($3) - 3; } | |
| | MOVEP szwl dreg ',' ea5 { _genop(0x0108 | ($3<<9) | ($2<<6) | ($5.ea & 7)); yyrc = _genea($5) - 1; } | |
| | MOVEP szwl ea5 ',' dreg { _genop(0x0188 | ($5<<9) | ($2<<6) | ($3.ea & 7)); yyrc = _genea($3) - 1; } | |
| | MOVEQ '#' NUMBER ',' dreg { _genop(0x7000 | ($5<<9) | ($3&0xff)); yyrc = -1; } | |
| | STOP '#' NUMBER { _genop(0x4e72); yyrc = _genop($3&0xffff) - 1; } | |
| | arop szwl eaall ',' areg { _genop($1 | ($5<<9) | ($2<<8) | $3.ea); yyrc = _genea($3) - 1; } | |
| | SWAP dreg { _genop(0x4840 | $2); yyrc = -1; } | |
| | TRAP '#' NUMBER { _genop(0x4e40 | ($3 & 0x0f)); yyrc = -1; } | |
| | UNLK areg { _genop(0x4e58 | $2); yyrc = -1; } | |
| ; | |
| arop: | |
| ADDA { $$ = 0xd0c0; } | |
| | SUBA { $$ = 0x90c0; }; | |
| bcdop: | |
| ABCD { $$ = 0xc100; } | |
| | ADDX szbwl { $$ = 0xd100 | ($2<<6); } | |
| | SBCD { $$ = 0x8100; } | |
| | SUBX szbwl { $$ = 0x9100 | ($2<<6); } | |
| ; | |
| dualop: | |
| ADD szbwl { $$ = 0xd000 | ($2<<6); } | |
| | AND szbwl { $$ = 0xc000 | ($2<<6); } | |
| | OR szbwl { $$ = 0x8000 | ($2<<6); } | |
| | SUB szbwl { $$ = 0x9000 | ($2<<6); } | |
| ; | |
| immop: | |
| ADDI szbwl { $$ = 0x0600 | ($2<<6); } | |
| | CMPI szbwl { $$ = 0x0c00 | ($2<<6); } | |
| | SUBI szbwl { $$ = 0x0400 | ($2<<6); } | |
| ; | |
| immop2: | |
| ANDI szbwl { $$ = 0x0200 | ($2<<6); } | |
| | EORI szbwl { $$ = 0x0a00 | ($2<<6); } | |
| | ORI szbwl { $$ = 0x0000 | ($2<<6); } | |
| ; | |
| qop: | |
| ADDQ szbwl { $$ = 0x5000 | ($2<<6); } | |
| | SUBQ szbwl { $$ = 0x5100 | ($2<<6); } | |
| ; | |
| shftop: | |
| ASL eama { $$.reg = 0xe1c0 | $2.ea; $$.ea = $2; } | |
| | ASL szbwl shftarg { $$.reg = 0xe100 | ($2<<6) | $3; } | |
| | ASR eama { $$.reg = 0xe0c0 | $2.ea; $$.ea = $2; } | |
| | ASR szbwl shftarg { $$.reg = 0xe000 | ($2<<6) | $3; } | |
| | LSL eama { $$.reg = 0xe3c0 | $2.ea; $$.ea = $2; } | |
| | LSL szbwl shftarg { $$.reg = 0xe108 | ($2<<6) | $3; } | |
| | LSR eama { $$.reg = 0xe2c0 | $2.ea; $$.ea = $2; } | |
| | LSR szbwl shftarg { $$.reg = 0xe008 | ($2<<6) | $3; } | |
| | ROL eama { $$.reg = 0xe7c0 | $2.ea; $$.ea = $2; } | |
| | ROL szbwl shftarg { $$.reg = 0xe118 | ($2<<6) | $3; } | |
| | ROR eama { $$.reg = 0xe6c0 | $2.ea; $$.ea = $2; } | |
| | ROR szbwl shftarg { $$.reg = 0xe018 | ($2<<6) | $3; } | |
| | ROXL eama { $$.reg = 0xe5c0 | $2.ea; $$.ea = $2; } | |
| | ROXL szbwl shftarg { $$.reg = 0xe100 | ($2<<6) | $3; } | |
| | ROXR eama { $$.reg = 0xe4c0 | $2.ea; $$.ea = $2; } | |
| | ROXR szbwl shftarg { $$.reg = 0xe000 | ($2<<6) | $3; } | |
| ; | |
| brop: | |
| BCC { $$.opc = 0x6400; $$.len = 1; } | |
| | BCS { $$.opc = 0x6500; $$.len = 1; } | |
| | BEQ { $$.opc = 0x6700; $$.len = 1; } | |
| | BGE { $$.opc = 0x6c00; $$.len = 1; } | |
| | BGT { $$.opc = 0x6e00; $$.len = 1; } | |
| | BHI { $$.opc = 0x6200; $$.len = 1; } | |
| | BLE { $$.opc = 0x6f00; $$.len = 1; } | |
| | BLS { $$.opc = 0x6300; $$.len = 1; } | |
| | BLT { $$.opc = 0x6d00; $$.len = 1; } | |
| | BMI { $$.opc = 0x6b00; $$.len = 1; } | |
| | BNE { $$.opc = 0x6600; $$.len = 1; } | |
| | BPL { $$.opc = 0x6a00; $$.len = 1; } | |
| | BVC { $$.opc = 0x6800; $$.len = 1; } | |
| | BVS { $$.opc = 0x6900; $$.len = 1; } | |
| | BSR { $$.opc = 0x6100; $$.len = 1; } | |
| | BRA { $$.opc = 0x6000; $$.len = 1; } | |
| | BCC szs { $$.opc = 0x6400; $$.len = 0; } | |
| | BCS szs { $$.opc = 0x6500; $$.len = 0; } | |
| | BEQ szs { $$.opc = 0x6700; $$.len = 0; } | |
| | BGE szs { $$.opc = 0x6c00; $$.len = 0; } | |
| | BGT szs { $$.opc = 0x6e00; $$.len = 0; } | |
| | BHI szs { $$.opc = 0x6200; $$.len = 0; } | |
| | BLE szs { $$.opc = 0x6f00; $$.len = 0; } | |
| | BLS szs { $$.opc = 0x6300; $$.len = 0; } | |
| | BLT szs { $$.opc = 0x6d00; $$.len = 0; } | |
| | BMI szs { $$.opc = 0x6b00; $$.len = 0; } | |
| | BNE szs { $$.opc = 0x6600; $$.len = 0; } | |
| | BPL szs { $$.opc = 0x6a00; $$.len = 0; } | |
| | BVC szs { $$.opc = 0x6800; $$.len = 0; } | |
| | BVS szs { $$.opc = 0x6900; $$.len = 0; } | |
| | BSR szs { $$.opc = 0x6100; $$.len = 0; } | |
| | BRA szs { $$.opc = 0x6000; $$.len = 0; } | |
| ; | |
| btop: | |
| BCHG { $$ = 0x0040; } | |
| | BCLR { $$ = 0x0080; } | |
| | BSET { $$ = 0x00c0; } | |
| | BTST { $$ = 0x0000; } | |
| ; | |
| monop: | |
| CLR szbwl { $$ = 0x4200 | ($2<<6); } | |
| | NBCD { $$ = 0x4800; } | |
| | NEG szbwl { $$ = 0x4400 | ($2<<6); } | |
| | NEGX szbwl { $$ = 0x4000 | ($2<<6); } | |
| | NOT szbwl { $$ = 0x4600 | ($2<<6); } | |
| | SCC { $$ = 0x54c0; } | |
| | SCS { $$ = 0x55c0; } | |
| | SEQ { $$ = 0x57c0; } | |
| | SF { $$ = 0x51c0; } | |
| | SGE { $$ = 0x5cc0; } | |
| | SGT { $$ = 0x5ec0; } | |
| | SHI { $$ = 0x52c0; } | |
| | SLE { $$ = 0x5fc0; } | |
| | SLS { $$ = 0x53c0; } | |
| | SLT { $$ = 0x5dc0; } | |
| | SMI { $$ = 0x5bc0; } | |
| | SNE { $$ = 0x56c0; } | |
| | SPL { $$ = 0x5ac0; } | |
| | ST { $$ = 0x50c0; } | |
| | SVC { $$ = 0x58c0; } | |
| | SVS { $$ = 0x59c0; } | |
| | TAS { $$ = 0x4ac0; } | |
| | TST szbwl { $$ = 0x4a00 | ($2<<6); } | |
| ; | |
| mdop: | |
| DIVS { $$ = 0x81c0; } | |
| | DIVU { $$ = 0x80c0; } | |
| | MULS { $$ = 0xc1c0; } | |
| | MULU { $$ = 0xc0c0; } | |
| ; | |
| dbop: | |
| DBCC { $$ = 0x54c8; } | |
| | DBCS { $$ = 0x55c8; } | |
| | DBEQ { $$ = 0x57c8; } | |
| | DBGE { $$ = 0x5cc8; } | |
| | DBGT { $$ = 0x5ec8; } | |
| | DBHI { $$ = 0x52c8; } | |
| | DBLE { $$ = 0x5fc8; } | |
| | DBLS { $$ = 0x53c8; } | |
| | DBLT { $$ = 0x5dc8; } | |
| | DBMI { $$ = 0x5bc8; } | |
| | DBNE { $$ = 0x56c8; } | |
| | DBPL { $$ = 0x5ac8; } | |
| | DBVC { $$ = 0x58c8; } | |
| | DBVS { $$ = 0x59c8; } | |
| | DBF { $$ = 0x51c8; } | |
| | DBT { $$ = 0x50c8; } | |
| ; | |
| direct: | |
| ILLEGAL { $$ = 0x4afc; } | |
| | NOP { $$ = 0x4e71; } | |
| | RESET { $$ = 0x4e70; } | |
| | RTE { $$ = 0x4e73; } | |
| | RTR { $$ = 0x4e77; } | |
| | RTS { $$ = 0x4e75; } | |
| | TRAPV { $$ = 0x4e76; } | |
| ; | |
| jop: | |
| JMP { $$ = 0x4ec0; } | |
| | JSR { $$ = 0x4e80; } | |
| | PEA { $$ = 0x4840; }; | |
| shftarg: | |
| dreg ',' dreg { $$ = ($1<<9) | 0x20 | $3; } | |
| | '#' NUMBER ',' dreg { $$ = (($2 & 7)<<9) | $4; }; | |
| bcdarg: | |
| ea0 ',' ea0 { $$ = (($1.ea & 7) << 9) | ($3.ea & 7); } | |
| | ea4 ',' ea4 { $$ = (($1.ea & 7) << 9) | 0x0008 | ($3.ea & 7); }; | |
| dualarg: | |
| dreg ',' eaa { if (($3.ea & 070)==0) { /* dx,dy must be swapped */ | |
| $$.reg = ($3.ea & 7)<<9; $3.ea = $1 & 7; $$.ea = $3; } | |
| else { $$.reg = ($1<<9) | 0x100; $$.ea = $3; } } | |
| | eama ',' dreg { $$.reg = ($3<<9); $$.ea = $1; }; | |
| areg: | |
| A0 { $$=0; } | |
| | A1 { $$=1; } | |
| | A2 { $$=2; } | |
| | A3 { $$=3; } | |
| | A4 { $$=4; } | |
| | A5 { $$=5; } | |
| | A6 { $$=6; } | |
| | A7 { $$=7; }; | |
| dreg: | |
| D0 { $$=0; } | |
| | D1 { $$=1; } | |
| | D2 { $$=2; } | |
| | D3 { $$=3; } | |
| | D4 { $$=4; } | |
| | D5 { $$=5; } | |
| | D6 { $$=6; } | |
| | D7 { $$=7; }; | |
| szs: | |
| SSIZE { $$ = 1; oplen = 0; } | |
| szwl: | |
| WSIZE { $$ = 0; oplen = 1; } | |
| | LSIZE { $$ = 1; oplen = 2; }; | |
| szbwl: | |
| BSIZE { $$ = 0; oplen = 0; } | |
| | WSIZE { $$ = 1; oplen = 1; } | |
| | LSIZE { $$ = 2; oplen = 2; }; | |
| szmv: | |
| BSIZE { $$ = 1; oplen = 0; } | |
| | WSIZE { $$ = 3; oplen = 1; } | |
| | LSIZE { $$ = 2; oplen = 2; }; | |
| szm: | |
| WSIZE { $$ = 3; oplen = 1; } | |
| | LSIZE { $$ = 2; oplen = 2; }; | |
| reglist: | |
| regs { $$ = $1; } | |
| | regs '/' reglist { $$.x = $1.x | $3.x; $$.d = $1.d | $3.d; }; | |
| regs: | |
| areg { $$.x = movemx[$1]; $$.d = movemd[$1]; } | |
| | dreg { $$.x = movemx[$1+8]; $$.d = movemd[$1+8]; } | |
| | areg '-' areg { int i,l=$1,h=$3; if (l>h) { l=$3; h=$1; } $$.x = $$.d = 0; | |
| for (i=l; i<=h; i++) { $$.d |= movemx[i]; $$.d |= movemd[i]; } } | |
| | dreg '-' dreg { int i,l=$1,h=$3; if (l>h) { l=$3; h=$1; } $$.x = $$.d = 0; | |
| for (i=l; i<=h; i++) { $$.x |= movemx[i+8]; $$.d |= movemd[i+8]; } } | |
| ; | |
| eama: ea1 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70 | ea72 | ea73 | ea74; | |
| eaa: ea0 | ea1 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70; | |
| ead: ea0 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70 | ea72 | ea73 | ea74; | |
| eaall: ea0 | eama; | |
| eada: ea0 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70; | |
| eadas: eada | easr; | |
| eac: ea2 | ea5 | ea6 | ea70 | ea72 | ea73; | |
| eacai: ea2 | ea3 | ea5 | ea6 | ea70; | |
| eacad: ea2 | ea4 | ea5 | ea6 | ea70; | |
| ea0: | |
| dreg { $$.ea = $1; $$.cnt = 0; }; | |
| ea1: | |
| areg { $$.ea = 010 | $1; $$.cnt = 0; }; | |
| ea2: | |
| '(' areg ')' { $$.ea = 020 | $2; $$.cnt = 0; }; | |
| ea3: | |
| '(' areg POSTINC { $$.ea = 030 | $2; $$.cnt = 0; }; | |
| ea4: | |
| PREDEC areg ')' { $$.ea = 040 | $2; $$.cnt = 0; }; | |
| ea5: | |
| '(' NUMBER ',' areg ')' { $$.ea = 050 | $4; $$.cnt = 1; $$.arg[0] = $2; }; | |
| ea6: | |
| '(' NUMBER ',' areg ',' dreg szwl ')' | |
| { $$.ea = 060 | $4; $$.cnt = 1; $$.arg[0] = 0x8000 | ($6<<12) | ($7<<11) | ($2 & 0xff); } | |
| | '(' NUMBER ',' areg ',' areg szwl ')' | |
| { $$.ea = 060 | $4; $$.cnt = 1; $$.arg[0] = ($6<<12) | ($7<<11) | ($2 & 0xff); }; | |
| ea70: | |
| '(' NUMBER ')' szwl { if ($4==0) { $$.ea = 070; $$.cnt = 1; $$.arg[0] = $2; } | |
| else { $$.ea = 071; $$.cnt = 2; $$.arg[0] = $2 >> 16; $$.arg[1] = $2 & 0xffff; } } | |
| | '(' NUMBER ')' { int tmp = ($2>>15) & 0x1ffff; if (tmp==0 || tmp==0x1ffff) { $$.ea = 070; $$.cnt = 1; $$.arg[0] = $2; } | |
| else { $$.ea = 070; $$.cnt = 2; $$.arg[0] = $2 >> 16; $$.arg[1] = $2 & 0xffff; } }; | |
| ea72: | |
| '(' NUMBER ',' PC ')' { $$.ea = 072; $$.cnt = 1; $$.arg[0] = $2; } | |
| | NUMBER { $$.ea = 072; $$.cnt = 1; $$.arg[0] = $1; }; | |
| ea73: | |
| '(' NUMBER ',' PC ',' dreg szwl ')' | |
| { $$.ea = 073; $$.cnt = 1; $$.arg[0] = 0x8000 | ($6<<12) | ($7<<11) | ($2 & 0xff); } | |
| | '(' NUMBER ',' PC ',' areg szwl ')' | |
| { $$.ea = 073; $$.cnt = 1; $$.arg[0] = ($6<<12) | ($7<<11) | ($2 & 0xff); }; | |
| ea74: | |
| '#' NUMBER { $$.ea = 074; if (oplen==0) { $$.cnt = 1; $$.arg[0] = $2 & 0xff; } | |
| else if (oplen==1) { $$.cnt = 1; $$.arg[0] = $2 & 0xffff; } | |
| else { $$.cnt = 2; $$.arg[0] = $2 >> 16; $$.arg[1] = $2 & 0xffff; } }; | |
| easr: | |
| CCR { $$.ea = 074; $$.cnt = 0; } | |
| | SR { $$.ea = 074; $$.cnt = 1; }; | |
| %% | |
| static void yyerror(char* s) | |
| { | |
| /* do not emit anything, but set error flag */ | |
| yyerrc = 1; | |
| } | |
| struct _optable { | |
| char* mnem; | |
| int token; | |
| }; | |
| static struct _optable ops[] = { | |
| { "abcd", ABCD }, { "add", ADD }, { "adda", ADDA }, { "addi", ADDI }, | |
| { "addq", ADDQ }, { "addx", ADDX }, { "and", AND }, { "andi", ANDI }, | |
| { "asl", ASL }, { "asr", ASR }, { "bcc", BCC }, { "bcs", BCS }, | |
| { "beq", BEQ }, { "bge", BGE }, { "bgt", BGT }, { "bhi", BHI }, | |
| { "ble", BLE }, { "bls", BLS }, { "blt", BLT }, { "bmi", BMI }, | |
| { "bne", BNE }, { "bpl", BPL }, { "bvc", BVC }, { "bvs", BVS }, | |
| { "bchg", BCHG }, { "bclr", BCLR }, { "bra", BRA }, { "bset", BSET }, | |
| { "bsr", BSR }, { "btst", BTST }, { "chk", CHK }, { "clr", CLR }, | |
| { "cmp", CMP }, { "cmpa", CMPA }, { "cmpi", CMPI }, { "cmpm", CMPM }, | |
| { "dbcc", DBCC }, { "dbcs", DBCS }, { "dbeq", DBEQ }, { "dbf", DBF }, | |
| { "dbge", DBGE }, { "dbgt", DBGT }, { "dbhi", DBHI }, { "dble", DBLE }, | |
| { "dbls", DBLS }, { "dblt", DBLT }, { "dbmi", DBMI }, { "dbne", DBNE }, | |
| { "dbpl", DBPL }, { "dbt", DBT }, { "dbvc", DBVC }, { "dbvs", DBVS }, | |
| { "divs", DIVS }, { "divu", DIVU }, { "eor", EOR }, { "eori", EORI }, | |
| { "exg", EXG }, { "ext", EXT }, { "illegal",ILLEGAL }, { "jmp", JMP }, | |
| { "jsr", JSR }, { "lea", LEA }, { "link", LINK }, { "lsl", LSL }, | |
| { "lsr", LSR }, { "move", MOVE }, { "movea", MOVEA }, { "movem", MOVEM }, | |
| { "movep", MOVEP }, { "moveq", MOVEQ }, { "muls", MULS }, { "mulu", MULU }, | |
| { "nbcd", NBCD }, { "neg", NEG }, { "negx", NEGX }, { "nop", NOP }, | |
| { "not", NOT }, { "or", OR }, { "ori", ORI }, { "pea", PEA }, | |
| { "reset", RESET }, { "rol", ROL }, { "ror", ROR }, { "roxl", ROXL }, | |
| { "roxr", ROXR }, { "rte", RTE }, { "rtr", RTR }, | |
| { "rts", RTS }, { "scc", SCC }, { "scs", SCS }, { "seq", SEQ }, | |
| { "sf", SF }, { "sge", SGE }, { "sgt", SGT }, { "shi", SHI }, | |
| { "sle", SLE }, { "sls", SLS }, { "slt", SLT }, { "smi", SMI }, | |
| { "sne", SNE }, { "spl", SPL }, { "st", ST }, { "svc", SVC }, | |
| { "svs", SVS }, { "stop", STOP }, { "sub", SUB }, { "suba", SUBA }, | |
| { "subi", SUBI }, { "subq", SUBQ }, { "subx", SUBX }, { "swap", SWAP }, | |
| { "tas", TAS }, { "trap", TRAP }, { "trapv", TRAPV }, { "tst", TST }, | |
| { "unlk", UNLK }, { "a0", A0 }, { "a1", A1 }, { "a2", A2 }, | |
| { "a3", A3 }, { "a4", A4 }, { "a5", A5 }, { "a6", A6 }, | |
| { "a7", A7 }, { "d0", D0 }, { "d1", D1 }, { "d2", D2 }, | |
| { "d3", D3 }, { "d4", D4 }, { "d5", D5 }, { "d6", D6 }, | |
| { "d7", D7 }, { "ccr", CCR }, { "sr", SR }, { "usp", USP }, | |
| { "pc", PC }, | |
| { 0, 0 } | |
| }; | |
| typedef struct _ophash { | |
| struct _ophash* next; | |
| struct _optable* op; | |
| } OPHASH; | |
| #define OPHASHSIZE 97 | |
| static OPHASH **ophash = 0; | |
| static int getophash(const char* s) | |
| { | |
| int h = 0; | |
| while (*s++) h += (int)*s; | |
| return h % OPHASHSIZE; | |
| } | |
| static int oplookup(const char* s) | |
| { | |
| int idx = getophash(s); | |
| OPHASH* oph = ophash[idx]; | |
| if (oph) { | |
| if (oph->next) { | |
| while (oph) { | |
| if (!strcmp(s,oph->op->mnem)) return oph->op->token; | |
| oph = oph->next; | |
| } | |
| return 0; | |
| } | |
| return oph->op->token; | |
| } | |
| return 0; | |
| } | |
| static void init_ophash() | |
| { | |
| struct _optable* op = ops; | |
| OPHASH* oph; | |
| ophash = (OPHASH**)calloc(sizeof(OPHASH*),OPHASHSIZE); | |
| while (op->mnem) { | |
| int idx = getophash(op->mnem); | |
| oph = (OPHASH*)malloc(sizeof(OPHASH)); | |
| oph->next = ophash[idx]; | |
| oph->op = op; | |
| ophash[idx] = oph; | |
| op++; | |
| } | |
| } | |
| static char* yystream; | |
| int yylex() | |
| { | |
| char ident[30]; | |
| char *p = ident; | |
| char c = yystream[0]; | |
| while (c != 0 && (c=='\t' || c==' ')) { | |
| c = *++yystream; | |
| } | |
| if (c==0) return EOF; | |
| if (isalpha(c)) { | |
| while (isalnum(c) && (p-ident)<28) { | |
| *p++ = tolower(c); c = *++yystream; | |
| } | |
| *p = 0; | |
| if (p>ident) { return oplookup(ident); } | |
| return EOF; | |
| } else if (isdigit(c)) { | |
| *p++ = c; | |
| if (yystream[1]=='x' || yystream[1]=='X') { *p++ = 'x'; yystream++; } | |
| c = *++yystream; | |
| while ((isdigit(c) || isxdigit(c)) && (p-ident)<28) { | |
| *p++ = c; c = *++yystream; | |
| } | |
| *p = 0; | |
| yylval.num = strtol(ident,0,0); | |
| return NUMBER; | |
| } else if (c=='$') { | |
| if (isdigit(yystream[1]) || isxdigit(yystream[1])) { | |
| c = *++yystream; | |
| while ((isdigit(c) || isxdigit(c)) && (p-ident)<28) { | |
| *p++ = c; c = *++yystream; | |
| } | |
| *p = 0; | |
| yylval.num = strtol(ident,0,16); | |
| return NUMBER; | |
| } else return '$'; | |
| } else if (c == '-' && yystream[1] == '(') { | |
| yystream += 2; return PREDEC; | |
| } else if (c == ')' && yystream[1] == '+') { | |
| yystream += 2; return POSTINC; | |
| } else if (c == '.') { | |
| switch (yystream[1]) { | |
| case 'b': yystream += 2; return BSIZE; | |
| case 'w': yystream += 2; return WSIZE; | |
| case 'l': yystream += 2; return LSIZE; | |
| case 's': yystream += 2; return SSIZE; | |
| default: yystream++; return '.'; | |
| } | |
| } else { | |
| ++yystream; return c; | |
| } | |
| } | |
| static t_value *yyvalptr; | |
| static t_addr yyaddr; | |
| t_stat parse_sym(char* c, t_addr a, UNIT* u, t_value* val, int32 sw) | |
| { | |
| char ch; | |
| if (!ophash) init_ophash(); | |
| yyvalptr = val; | |
| yyaddr = a; | |
| yystream = c; | |
| yyerrc = 0; | |
| ch = *yystream; | |
| while (ch != 0 && (ch=='\t' || ch==' ')) { | |
| ch = *++yystream; | |
| } | |
| if (ch == 0) return 0; | |
| if (sw & SWMASK('Y')) yydebug = 1 - yydebug; | |
| if ((sw & SWMASK('A')) || ch=='\'') { | |
| if ((ch = yystream[1])) { | |
| val[0] = (uint32)ch; | |
| return SCPE_OK; | |
| } else return SCPE_ARG; | |
| } | |
| if ((sw & SWMASK('C')) || ch=='"') { | |
| if ((ch = yystream[1])) { | |
| val[0] = ((uint32)ch << 8) | (uint32)yystream[1]; | |
| return SCPE_OK; | |
| } else return SCPE_ARG; | |
| } | |
| yyparse(); | |
| printf("rc=%d\n",yyrc); | |
| if (yyerrc) return SCPE_ARG; | |
| return yyrc; | |
| } | |
| static int _genop(t_value arg) | |
| { | |
| // printf("_genop(%x)@%x\n",arg,(int)yyvalptr); | |
| *yyvalptr = arg; | |
| yyvalptr++; | |
| return -1; | |
| } | |
| static int _genea(struct _ea arg) | |
| { | |
| int i; | |
| for (i=0; i<arg.cnt; i++) _genop(arg.arg[i]); | |
| return -(arg.cnt*2)-1; | |
| } | |
| static int _genbr(t_value arg,t_addr tgt,int len) | |
| { | |
| t_addr a = tgt - yyaddr -2; | |
| if (len==1) { | |
| _genop(arg); | |
| _genop(a & 0xffff); | |
| a &= 0xffff8000; | |
| if (a != 0x00000000 && a != 0xffff8000) return SCPE_ARG; | |
| return -3; | |
| } else { | |
| _genop(arg | (a&0xff)); | |
| a &= 0xffffff80; | |
| if (a != 0x00000000 && a != 0xffffff80) return SCPE_ARG; | |
| return -1; | |
| } | |
| } |