From: Shamus Hammons Date: Sat, 23 Jun 2018 16:57:21 +0000 (-0500) Subject: Cleanup of codebase and initial commit of 56K assembler by ggn. X-Git-Tag: v2.1.0~68 X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=commitdiff_plain;h=30a208654896284b50e7b362e97d3e63ec717b96 Cleanup of codebase and initial commit of 56K assembler by ggn. There's still a ways to go before this will work properly as we need to add proper fixup handling and origin (".org") bookkeeping. As it is now, the addition of all the miscellaneous bits and bobs to support the main 56K assembler are in place but they don't cause any regressions to the existing assemblers already present in RMAC. Stay tuned for Round 2! --- diff --git a/.gitignore b/.gitignore index 52dc3f7..f229d61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ 68kgen 68kgen.o 68ktab.h -68kmn +68k.tab 6502kw.h opkw.h *.o diff --git a/6502.c b/6502.c index 5978240..55c6048 100644 --- a/6502.c +++ b/6502.c @@ -21,6 +21,9 @@ #include "sect.h" #include "token.h" +#define DEF_KW +#include "kwtab.h" + #define UPSEG_SIZE 0x10010L // size of 6502 code buffer, 64K+16bytes // Internal vars @@ -50,83 +53,83 @@ char strtoa8[128]; // ASCII to Atari 800 internal conversion table #define A65_IMMEDH 12 #define A65_IMMEDL 13 -#define NMACHOPS 56 // Number of machine ops -#define NMODES 14 // Number of addressing modes -#define NOP 0xEA // 6502 NOP instruction -#define ILLEGAL 0xFF // 'Illegal instr' marker -#define END65 0xFF // End-of-an-instr-list +#define NMACHOPS 56 // Number of machine ops +#define NMODES 14 // Number of addressing modes +#define NOP 0xEA // 6502 NOP instruction +#define ILLEGAL 0xFF // 'Illegal instr' marker +#define END65 0xFF // End-of-an-instr-list static char imodes[] = { - A65_IMMED, 0x69, A65_ABS, 0x6d, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71, - A65_ZPX, 0x75, A65_ABSX, 0x7d, A65_ABSY, 0x79, END65, - A65_IMMED, 0x29, A65_ABS, 0x2d, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31, - A65_ZPX, 0x35, A65_ABSX, 0x3d, A65_ABSY, 0x39, END65, - A65_ABS, 0x0e, A65_ZP, 0x06, A65_IMPL, 0x0a, A65_ZPX, 0x16, A65_ABSX, - 0x1e, END65, + A65_IMMED, 0x69, A65_ABS, 0x6D, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71, + A65_ZPX, 0x75, A65_ABSX, 0x7D, A65_ABSY, 0x79, END65, + A65_IMMED, 0x29, A65_ABS, 0x2D, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31, + A65_ZPX, 0x35, A65_ABSX, 0x3D, A65_ABSY, 0x39, END65, + A65_ABS, 0x0E, A65_ZP, 0x06, A65_IMPL, 0x0A, A65_ZPX, 0x16, A65_ABSX, + 0x1E, END65, A65_REL, 0x90, END65, - A65_REL, 0xb0, END65, - A65_REL, 0xf0, END65, - A65_REL, 0xd0, END65, + A65_REL, 0xB0, END65, + A65_REL, 0xF0, END65, + A65_REL, 0xD0, END65, A65_REL, 0x30, END65, A65_REL, 0x10, END65, A65_REL, 0x50, END65, A65_REL, 0x70, END65, - A65_ABS, 0x2c, A65_ZP, 0x24, END65, + A65_ABS, 0x2C, A65_ZP, 0x24, END65, A65_IMPL, 0x00, END65, A65_IMPL, 0x18, END65, - A65_IMPL, 0xd8, END65, + A65_IMPL, 0xD8, END65, A65_IMPL, 0x58, END65, - A65_IMPL, 0xb8, END65, - A65_IMMED, 0xc9, A65_ABS, 0xcd, A65_ZP, 0xc5, A65_INDX, 0xc1, A65_INDY, 0xd1, - A65_ZPX, 0xd5, A65_ABSX, 0xdd, A65_ABSY, 0xd9, END65, - A65_IMMED, 0xe0, A65_ABS, 0xec, A65_ZP, 0xe4, END65, - A65_IMMED, 0xc0, A65_ABS, 0xcc, A65_ZP, 0xc4, END65, - A65_ABS, 0xce, A65_ZP, 0xc6, A65_ZPX, 0xd6, A65_ABSX, 0xde, END65, - A65_IMPL, 0xca, END65, + A65_IMPL, 0xB8, END65, + A65_IMMED, 0xC9, A65_ABS, 0xCD, A65_ZP, 0xC5, A65_INDX, 0xC1, A65_INDY, 0xD1, + A65_ZPX, 0xD5, A65_ABSX, 0xDD, A65_ABSY, 0xD9, END65, + A65_IMMED, 0xE0, A65_ABS, 0xEC, A65_ZP, 0xE4, END65, + A65_IMMED, 0xC0, A65_ABS, 0xCC, A65_ZP, 0xC4, END65, + A65_ABS, 0xCE, A65_ZP, 0xC6, A65_ZPX, 0xD6, A65_ABSX, 0xDE, END65, + A65_IMPL, 0xCA, END65, A65_IMPL, 0x88, END65, - A65_IMMED, 0x49, A65_ABS, 0x4d, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51, - A65_ZPX, 0x55, A65_ABSX, 0x5d, A65_ABSY, 0x59, END65, - A65_ABS, 0xee, A65_ZP, 0xe6, A65_ZPX, 0xf6, A65_ABSX, 0xfe, END65, - A65_IMPL, 0xe8, END65, - A65_IMPL, 0xc8, END65, - A65_ABS, 0x4c, A65_IND, 0x6c, END65, + A65_IMMED, 0x49, A65_ABS, 0x4D, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51, + A65_ZPX, 0x55, A65_ABSX, 0x5D, A65_ABSY, 0x59, END65, + A65_ABS, 0xEE, A65_ZP, 0xE6, A65_ZPX, 0xF6, A65_ABSX, 0xFE, END65, + A65_IMPL, 0xE8, END65, + A65_IMPL, 0xC8, END65, + A65_ABS, 0x4C, A65_IND, 0x6C, END65, A65_ABS, 0x20, END65, - A65_IMMED, 0xa9, A65_ABS, 0xad, A65_ZP, 0xa5, A65_INDX, 0xa1, A65_INDY, 0xb1, - A65_ZPX, 0xb5, A65_ABSX, 0xbd, A65_ABSY, 0xb9, A65_IMMEDH, 0xa9, A65_IMMEDL, 0xa9, END65, - A65_IMMED, 0xa2, A65_ABS, 0xae, A65_ZP, 0xa6, A65_ABSY, 0xbe, - A65_ZPY, 0xb6, A65_IMMEDH, 0xa2, A65_IMMEDL, 0xa2, END65, - A65_IMMED, 0xa0, A65_ABS, 0xac, A65_ZP, 0xa4, A65_ZPX, 0xb4, - A65_ABSX, 0xbc, A65_IMMEDH, 0xa0, A65_IMMEDL, 0xa0, END65, - A65_ABS, 0x4e, A65_ZP, 0x46, A65_IMPL, 0x4a, A65_ZPX, 0x56, - A65_ABSX, 0x5e, END65, - A65_IMPL, 0xea, END65, - A65_IMMED, 0x09, A65_ABS, 0x0d, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11, - A65_ZPX, 0x15, A65_ABSX, 0x1d, A65_ABSY, 0x19, END65, + A65_IMMED, 0xA9, A65_ABS, 0xAD, A65_ZP, 0xA5, A65_INDX, 0xA1, A65_INDY, 0xB1, + A65_ZPX, 0xB5, A65_ABSX, 0xBD, A65_ABSY, 0xB9, A65_IMMEDH, 0xA9, A65_IMMEDL, 0xA9, END65, + A65_IMMED, 0xA2, A65_ABS, 0xAE, A65_ZP, 0xA6, A65_ABSY, 0xBE, + A65_ZPY, 0xB6, A65_IMMEDH, 0xA2, A65_IMMEDL, 0xA2, END65, + A65_IMMED, 0xA0, A65_ABS, 0xAC, A65_ZP, 0xA4, A65_ZPX, 0xB4, + A65_ABSX, 0xBC, A65_IMMEDH, 0xA0, A65_IMMEDL, 0xA0, END65, + A65_ABS, 0x4E, A65_ZP, 0x46, A65_IMPL, 0x4A, A65_ZPX, 0x56, + A65_ABSX, 0x5E, END65, + A65_IMPL, 0xEA, END65, + A65_IMMED, 0x09, A65_ABS, 0x0D, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11, + A65_ZPX, 0x15, A65_ABSX, 0x1D, A65_ABSY, 0x19, END65, A65_IMPL, 0x48, END65, A65_IMPL, 0x08, END65, A65_IMPL, 0x68, END65, A65_IMPL, 0x28, END65, - A65_ABS, 0x2e, A65_ZP, 0x26, A65_IMPL, 0x2a, A65_ZPX, 0x36, - A65_ABSX, 0x3e, END65, - A65_ABS, 0x6e, A65_ZP, 0x66, A65_IMPL, 0x6a, A65_ZPX, 0x76, - A65_ABSX, 0x7e, END65, + A65_ABS, 0x2E, A65_ZP, 0x26, A65_IMPL, 0x2A, A65_ZPX, 0x36, + A65_ABSX, 0x3E, END65, + A65_ABS, 0x6E, A65_ZP, 0x66, A65_IMPL, 0x6A, A65_ZPX, 0x76, + A65_ABSX, 0x7E, END65, A65_IMPL, 0x40, END65, A65_IMPL, 0x60, END65, - A65_IMMED, 0xe9, A65_ABS, 0xed, A65_ZP, 0xe5, A65_INDX, 0xe1, A65_INDY, 0xf1, - A65_ZPX, 0xf5, A65_ABSX, 0xfd, A65_ABSY, 0xf9, END65, + A65_IMMED, 0xE9, A65_ABS, 0xED, A65_ZP, 0xE5, A65_INDX, 0xE1, A65_INDY, 0xF1, + A65_ZPX, 0xF5, A65_ABSX, 0xFD, A65_ABSY, 0xF9, END65, A65_IMPL, 0x38, END65, - A65_IMPL, 0xf8, END65, + A65_IMPL, 0xF8, END65, A65_IMPL, 0x78, END65, - A65_ABS, 0x8d, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95, - A65_ABSX, 0x9d, A65_ABSY, 0x99, END65, - A65_ABS, 0x8e, A65_ZP, 0x86, A65_ZPY, 0x96, END65, - A65_ABS, 0x8c, A65_ZP, 0x84, A65_ZPX, 0x94, END65, - A65_IMPL, 0xaa, END65, - A65_IMPL, 0xa8, END65, - A65_IMPL, 0xba, END65, - A65_IMPL, 0x8a, END65, - A65_IMPL, 0x9a, END65, + A65_ABS, 0x8D, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95, + A65_ABSX, 0x9D, A65_ABSY, 0x99, END65, + A65_ABS, 0x8E, A65_ZP, 0x86, A65_ZPY, 0x96, END65, + A65_ABS, 0x8C, A65_ZP, 0x84, A65_ZPX, 0x94, END65, + A65_IMPL, 0xAA, END65, + A65_IMPL, 0xA8, END65, + A65_IMPL, 0xBA, END65, + A65_IMPL, 0x8A, END65, + A65_IMPL, 0x9A, END65, A65_IMPL, 0x98, END65 }; @@ -264,6 +267,14 @@ void m6502cg(int op) amode = A65_IMPL; break; + case KW_A: + if (tok[1] != EOL) + goto badmode; + + amode = A65_IMPL; + tok++; + break; + case '#': tok++; @@ -307,6 +318,7 @@ void m6502cg(int op) { // (foo),y tok++; +#if 0 p = string[tok[1]]; // Sleazo tolower() -----------------vvvvvvvvvvv @@ -315,6 +327,15 @@ void m6502cg(int op) tok += 2; amode = A65_INDY; +#else + if (tok[0] == KW_Y) + amode = A65_INDY; + + if (tok[1] != EOL) + goto badmode; + + tok++; +#endif } else amode = A65_IND; @@ -421,6 +442,7 @@ not_coinop: else if (*tok == ',') { tok++; +#if 0 p = string[tok[1]]; if (*tok != SYMBOL || p[1] != EOS) @@ -441,6 +463,21 @@ not_coinop: amode = A65_ABSY; else goto badmode; +#else + if (tok[0] == KW_X) + { + amode = A65_ABSX; + tok++; + } + else if (tok[0] == KW_Y) + { + amode = A65_ABSY; + tok++; + } + + if (tok[0] != EOL) + goto badmode; +#endif } else goto badmode; @@ -568,9 +605,9 @@ badmode: D_rword(eval); break; - // - // Deposit 3 NOPs for illegal things - // + // + // Deposit 3 NOPs for illegal things (why 3? why not 30? or zero?) + // default: case ILLEGAL: for(i=0; i<3; i++) @@ -583,6 +620,7 @@ badmode: if (sloc > 0x10000L) fatal("6502 code pointer > 64K"); +//Now why use this instead of at_eol()? if (*tok != EOL) error(extra_stuff); } @@ -609,6 +647,9 @@ void m6502obj(int ofd) for(uint16_t * l=&orgmap[0][0]; l 0xFFFF) return error(range_error); @@ -251,9 +252,12 @@ int d_org(void) chptr = scode->chptr + address; orgaddr = address; orgactive = 1; - at_eol(); + } + else if (dsp56001) + { } + at_eol(); return 0; } @@ -290,25 +294,39 @@ int d_print(void) case '/': formatting = 1; - if (tok[1] != SYMBOL) + // "X" & "L" get tokenized now... :-/ Probably should look into preventing this kind of thing from happening (was added with DSP56K code) + if ((tok[1] != SYMBOL) && (tok[1] != KW_L) && (tok[1] != KW_X)) goto token_err; -// strcpy(prntstr, (char *)tok[2]); - strcpy(prntstr, string[tok[2]]); - - switch(prntstr[0]) + if (tok[1] == KW_L) { - case 'l': case 'L': wordlong = 1; break; - case 'w': case 'W': wordlong = 0; break; - case 'x': case 'X': outtype = 0; break; - case 'd': case 'D': outtype = 1; break; - case 'u': case 'U': outtype = 2; break; - default: - error("unknown print format flag"); - return ERROR; + wordlong = 1; + tok += 2; + } + else if (tok[1] == KW_X) + { + outtype = 0; + tok += 2; + } + else + { + strcpy(prntstr, string[tok[2]]); + + switch(prntstr[0]) + { + case 'l': case 'L': wordlong = 1; break; + case 'w': case 'W': wordlong = 0; break; + case 'x': case 'X': outtype = 0; break; + case 'd': case 'D': outtype = 1; break; + case 'u': case 'U': outtype = 2; break; + default: + error("unknown print format flag"); + return ERROR; + } + + tok += 3; } - tok += 3; break; case ',': tok++; @@ -349,7 +367,7 @@ int d_print(void) return 0; token_err: - error("illegal print token"); + error("illegal print token [@ '%s']", prntstr); return ERROR; } @@ -958,7 +976,7 @@ int d_ds(WORD siz) uint64_t eval; - if (cursect != M6502) + if ((cursect & (M6502 | M56KPXYL)) == 0) { if ((siz != SIZB) && (sloc & 1)) // Automatic .even auto_even(); @@ -1036,7 +1054,7 @@ int d_dc(WORD siz) for(p=string[tok[1]]; *p!=EOS; p++) D_byte(*p); } - else if(*tok == STRINGA8) + else if (*tok == STRINGA8) { for(p=string[tok[1]]; *p!=EOS; p++) D_byte(strtoa8[*p]); @@ -1496,7 +1514,7 @@ int d_nlist(void) // int d_68000(void) { - rgpu = rdsp = robjproc = 0; + rgpu = rdsp = robjproc = dsp56001 = 0; // Switching from gpu/dsp sections should reset any ORG'd Address orgactive = 0; orgwarning = 0; @@ -1586,11 +1604,18 @@ int d_nofpu(void) // -// DSP56001 +// .56001 - Switch to DSP56001 assembler // int d_56001(void) { - return error("Not yet, child. Be patient."); + dsp56001 = 1; + rgpu = rdsp = robjproc = 0; + SaveSection(); + + if (obj_format == LOD || obj_format == P56) + SwitchSection(M56001P); + + return 0; } @@ -1615,6 +1640,7 @@ int d_gpu(void) rgpu = 1; // Set GPU assembly rdsp = 0; // Unset DSP assembly robjproc = 0; // Unset OP assembly + dsp56001 = 0; // Unset 56001 assembly regbank = BANK_N; // Set no default register bank return 0; } @@ -1641,6 +1667,7 @@ int d_dsp(void) rdsp = 1; // Set DSP assembly rgpu = 0; // Unset GPU assembly robjproc = 0; // Unset OP assembly + dsp56001 = 0; // Unset 56001 assembly regbank = BANK_N; // Set no default register bank return 0; } @@ -1913,6 +1940,7 @@ int d_objproc(void) robjproc = 1; // Set OP assembly rgpu = 0; // Unset GPU assembly rdsp = 0; // Unset DSP assembly + dsp56001 = 0; // Unset 56001 assembly return OK; } diff --git a/mntab b/direct.tab similarity index 100% rename from mntab rename to direct.tab diff --git a/dsp56k.c b/dsp56k.c new file mode 100644 index 0000000..50e8601 --- /dev/null +++ b/dsp56k.c @@ -0,0 +1,15 @@ +// +// RMAC - Reboot's Macro Assembler for all Atari computers +// DSP56K.C - General DSP56001 routines +// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#include "rmac.h" +#include "dsp56k.h" + +DSP_ORG dsp_orgmap[1024]; // Mark all 56001 org changes +DSP_ORG * dsp_currentorg = &dsp_orgmap[0]; +int dsp_written_data_in_current_org = 0; + diff --git a/dsp56k.h b/dsp56k.h new file mode 100644 index 0000000..c73e99e --- /dev/null +++ b/dsp56k.h @@ -0,0 +1,42 @@ +// +// RMAC - Reboot's Macro Assembler for all Atari computers +// DSP56K.H - General DSP56001 routines +// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#pragma once + +#include "rmac.h" +#include "sect.h" + +// Exported variables. +#define DSP_MAX_RAM (32*3*1024) // 32k 24-bit words +#define DSP_ORG struct dsp56001_orgentry + +enum MEMTYPES +{ + ORG_P, + ORG_X, + ORG_Y, + ORG_L +} ; + +DSP_ORG +{ + enum MEMTYPES memtype; + uint8_t * start; + uint8_t * end; + uint32_t orgadr; + CHUNK * chunk; +}; + +extern DSP_ORG dsp_orgmap[1024]; // Mark all 56001 org changes +extern DSP_ORG * dsp_currentorg; +extern int dsp_written_data_in_current_org; + +#define dprintf(...) p_buf += sprintf(p_buf, __VA_ARGS__) + +// Exported functions + diff --git a/dsp56k.mch b/dsp56k.mch new file mode 100644 index 0000000..c73ecaf --- /dev/null +++ b/dsp56k.mch @@ -0,0 +1,336 @@ +abs M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0010d110 dsp_ab d=(a=0, b=1) +asl M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0011d010 dsp_ab d=(a=0, b=1) +asr M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0010d010 dsp_ab d=(a=0, b=1) +clr M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0001d011 dsp_ab d=(a=0, b=1) +lsl M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0011d011 dsp_ab d=(a=0, b=1) +lsr M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0010d011 dsp_ab d=(a=0, b=1) +not M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0001d111 dsp_ab d=(a=0, b=1) +addl M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0001d010 dsp_baab d=(b,a=0, a,b=1) +addr M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0000d010 dsp_baab d=(b,a=0, a,b=1) +add M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0001d000 dsp_baab + d=(a=0, b=1) +- M_ALL48 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0jjjd000 dsp_acc48 jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1) +cmp M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0000d101 dsp_baab + d=(a=0, b=1) +- M_ALU24 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0jjjd101 dsp_acc48 jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1) +cmpm M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0000d111 dsp_baab + d=(a=0, b=1) +- M_ALU24 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0jjjd111 dsp_acc48 jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1) +sub M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0001d100 dsp_baab + d=(a=0, b=1) +- M_ALL48 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0jjjd100 dsp_acc48 jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1) +tfr M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0000d001 dsp_baab + d=(a=0, b=1) +- M_ALU24 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0jjjd001 dsp_acc48 jjj=(x=2, y=3, x0=4, y0=5, x1=6, y1=7), d=(a=0, b=1) +rnd M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0001d001 dsp_ab d=(a=0, b=1) +rol M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0011d111 dsp_ab d=(a=0, b=1) +ror M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0010d111 dsp_ab d=(a=0, b=1) +subl M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0001d110 dsp_baab d=(b,a=0, a,b=1) +subr M_ACC56 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm0000d110 dsp_baab d=(b,a=0, a,b=1) +tst M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0000d011 dsp_ab d=(a=0, b=1) +enddo M_AM_NONE M_AM_NONE NOPARMO %000000000000000010001100 dsp_self +illegal M_AM_NONE M_AM_NONE NOPARMO %000000000000000000000101 dsp_self +nop M_AM_NONE M_AM_NONE NOPARMO %000000000000000000000000 dsp_self +reset M_AM_NONE M_AM_NONE NOPARMO %000000000000000010000100 dsp_self +rti M_AM_NONE M_AM_NONE NOPARMO %000000000000000000000100 dsp_self +rts M_AM_NONE M_AM_NONE NOPARMO %000000000000000000001100 dsp_self +stop M_AM_NONE M_AM_NONE NOPARMO %000000000000000010000111 dsp_self +swi M_AM_NONE M_AM_NONE NOPARMO %000000000000000000000110 dsp_self +wait M_AM_NONE M_AM_NONE NOPARMO %000000000000000010000110 dsp_self +adc M_INP48 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm001jd001 dsp_xyab j=(x=0, y=1), d=(a=0, b=1) +sbc M_INP48 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm001jd101 dsp_xyab s1 (j)=(x=0,y=1),s2 (d)=(a=0,b=1) +and M_ALU24 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm01jjd110 dsp_x0y0ab jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1) +eor M_ALU24 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm01jjd011 dsp_x0y0ab jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1) +div M_ALU24 M_ACC56 NOPARMO %000000011000000001jjd000 dsp_x0y0ab jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1) +or M_ALU24 M_ACC56 PARMOVE %mmmmmmmmmmmmmmmm01jjd010 dsp_x0y0ab jj=(x0=0, x1=2, y0=1, y1=3), d=(a=0, b=1) +andi M_DSPIM8 M_DSPPCU NOPARMO %00000000iiiiiiii101110ee dsp_immcr ee=(mr=0, ccr=1, omr=2) +ori M_DSPIM8 M_DSPPCU NOPARMO %00000000iiiiiiii111110ee dsp_immcr ee=(mr=0, ccr=1, omr=2) +tcc M_ACC56 M_ACC56 NOPARMO %00000010000000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010000000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +ths M_ACC56 M_ACC56 NOPARMO %00000010000000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010000000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tcs M_ACC56 M_ACC56 NOPARMO %00000010100000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010100000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tlo M_ACC56 M_ACC56 NOPARMO %00000010100000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010100000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tec M_ACC56 M_ACC56 NOPARMO %00000010010100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010010100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +teq M_ACC56 M_ACC56 NOPARMO %00000010101000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010101000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tes M_ACC56 M_ACC56 NOPARMO %00000010110100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010110100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tge M_ACC56 M_ACC56 NOPARMO %00000010000100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010000100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tgt M_ACC56 M_ACC56 NOPARMO %00000010011100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010011100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tlc M_ACC56 M_ACC56 NOPARMO %00000010011000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010011000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tle M_ACC56 M_ACC56 NOPARMO %00000010111100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010111100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tls M_ACC56 M_ACC56 NOPARMO %00000010111000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010111000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tlt M_ACC56 M_ACC56 NOPARMO %00000010100100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010100100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tmi M_ACC56 M_ACC56 NOPARMO %00000010101100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010101100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tne M_ACC56 M_ACC56 NOPARMO %00000010001000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010001000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tnr M_ACC56 M_ACC56 NOPARMO %00000010110000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010110000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tpl M_ACC56 M_ACC56 NOPARMO %00000010001100000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010001100000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +tnn M_ACC56 M_ACC56 NOPARMO %00000010010000000jjjd000 dsp_baab + s1,d1 [s2,d2] +- M_ALL48 M_ACC56 NOPARMO %00000010010000000jjjd000 dsp_tcc2 s1,d1 [s2,d2] +jcc M_DSPABS12 M_AM_NONE NOPARMO %000011100000aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100000 dsp_ea Jcc ea mmmrrr=ea +jhs M_DSPABS12 M_AM_NONE NOPARMO %000011100000aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100000 dsp_ea Jcc ea mmmrrr=ea +jcs M_DSPABS12 M_AM_NONE NOPARMO %000011101000aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101000 dsp_ea Jcc ea mmmrrr=ea +jlo M_DSPABS12 M_AM_NONE NOPARMO %000011101000aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101000 dsp_ea Jcc ea mmmrrr=ea +jec M_DSPABS12 M_AM_NONE NOPARMO %000011100101aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100101 dsp_ea Jcc ea mmmrrr=ea +jeq M_DSPABS12 M_AM_NONE NOPARMO %000011101010aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101010 dsp_ea Jcc ea mmmrrr=ea +jes M_DSPABS12 M_AM_NONE NOPARMO %000011101101aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101101 dsp_ea Jcc ea mmmrrr=ea +jge M_DSPABS12 M_AM_NONE NOPARMO %000011100001aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100001 dsp_ea Jcc ea mmmrrr=ea +jgt M_DSPABS12 M_AM_NONE NOPARMO %000011100111aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100111 dsp_ea Jcc ea mmmrrr=ea +jge M_DSPABS12 M_AM_NONE NOPARMO %000011100001aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100001 dsp_ea Jcc ea mmmrrr=ea +jlc M_DSPABS12 M_AM_NONE NOPARMO %000011100110aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100110 dsp_ea Jcc ea mmmrrr=ea +jle M_DSPABS12 M_AM_NONE NOPARMO %000011101111aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101111 dsp_ea Jcc ea mmmrrr=ea +jls M_DSPABS12 M_AM_NONE NOPARMO %000011101110aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101110 dsp_ea Jcc ea mmmrrr=ea +jlt M_DSPABS12 M_AM_NONE NOPARMO %000011101001aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101001 dsp_ea Jcc ea mmmrrr=ea +jmi M_DSPABS12 M_AM_NONE NOPARMO %000011101011aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101011 dsp_ea Jcc ea mmmrrr=ea +jne M_DSPABS12 M_AM_NONE NOPARMO %000011100010aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100010 dsp_ea Jcc ea mmmrrr=ea +jnr M_DSPABS12 M_AM_NONE NOPARMO %000011101100aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10101100 dsp_ea Jcc ea mmmrrr=ea +jpl M_DSPABS12 M_AM_NONE NOPARMO %000011100011aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100011 dsp_ea Jcc ea mmmrrr=ea +jnn M_DSPABS12 M_AM_NONE NOPARMO %000011100100aaaaaaaaaaaa dsp_abs12 + Jcc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10100100 dsp_ea Jcc ea mmmrrr=ea +jmp M_DSPABS12 M_AM_NONE NOPARMO %000011000000aaaaaaaaaaaa dsp_abs12 + JMP xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101011mmmrrr10000000 dsp_ea JMP ea (+optional 24bit address) +jscc M_DSPABS12 M_AM_NONE NOPARMO %000011110000aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100000 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jshs M_DSPABS12 M_AM_NONE NOPARMO %000011110000aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100000 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jscs M_DSPABS12 M_AM_NONE NOPARMO %000011111000aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101000 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jslo M_DSPABS12 M_AM_NONE NOPARMO %000011111000aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101000 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsec M_DSPABS12 M_AM_NONE NOPARMO %000011110101aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100101 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jseq M_DSPABS12 M_AM_NONE NOPARMO %000011111010aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101010 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jses M_DSPABS12 M_AM_NONE NOPARMO %000011111101aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101101 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsge M_DSPABS12 M_AM_NONE NOPARMO %000011110001aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100001 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsgt M_DSPABS12 M_AM_NONE NOPARMO %000011110111aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100111 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jslc M_DSPABS12 M_AM_NONE NOPARMO %000011110110aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100110 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsle M_DSPABS12 M_AM_NONE NOPARMO %000011111111aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101111 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsls M_DSPABS12 M_AM_NONE NOPARMO %000011111110aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101110 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jslt M_DSPABS12 M_AM_NONE NOPARMO %000011111001aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101001 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsmi M_DSPABS12 M_AM_NONE NOPARMO %000011111011aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101011 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsne M_DSPABS12 M_AM_NONE NOPARMO %000011110010aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100010 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsnr M_DSPABS12 M_AM_NONE NOPARMO %000011111100aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10101100 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jspl M_DSPABS12 M_AM_NONE NOPARMO %000011110011aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100011 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsnn M_DSPABS12 M_AM_NONE NOPARMO %000011110100aaaaaaaaaaaa dsp_abs12 + JScc xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10100100 dsp_ea JScc ea mmmrrr=ea (+optional 24bit address) +jsr M_DSPABS12 M_AM_NONE NOPARMO %000011010000aaaaaaaaaaaa dsp_abs12 + JSR xxx aaaaaaaaaaaa=12bit address +- C_DSPABSEA M_AM_NONE NOPARMO %0000101111mmmrrr10000000 dsp_ea JSR ea mmmrrr=ea (+optional 24bit address) +neg M_ACC56 M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm0011d110 dsp_ab d=(a=0, b=1) +bchg C_DSPIM M_DSPEA NOPARMO %0000101101mmmrrr0s0bbbbb dsp_ea_imm5 + bchg #n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31 +- C_DSPIM M_DSPAA NOPARMO %0000101100aaaaaa0s0bbbbb dsp_ea_imm5 + bchg #n,X:aa / bchg #n,Y:aa +- C_DSPIM M_DSPPP NOPARMO %0000101110pppppp0s0bbbbb dsp_ea_imm5 + bchg #n,X:pp / bchg #n,Y:pp +- C_DSPIM C_DD NOPARMO %00001011110001dd010bbbbb dsp_reg_imm5 + bchg #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DDD NOPARMO %0000101111001ddd010bbbbb dsp_reg_imm5 + bchg #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101111010ddd010bbbbb dsp_reg_imm5 + bchg #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101111011ddd010bbbbb dsp_reg_imm5 + bchg #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101111100ddd010bbbbb dsp_reg_imm5 + bchg #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101111111ddd010bbbbb dsp_reg_imm5 bchg #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +bclr C_DSPIM M_DSPEA NOPARMO %0000101001mmmrrr0s0bbbbb dsp_ea_imm5 + bclr #n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31 +- C_DSPIM M_DSPAA NOPARMO %0000101000aaaaaa0s0bbbbb dsp_ea_imm5 + bclr #n,X:aa / bclr #n,Y:aa +- C_DSPIM M_DSPPP NOPARMO %0000101010pppppp0s0bbbbb dsp_ea_imm5 + bclr #n,X:pp / bclr #n,Y:pp +- C_DSPIM C_DDD NOPARMO %0000101011001ddd010bbbbb dsp_reg_imm5 + bclr #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DD NOPARMO %00001010110001dd010bbbbb dsp_reg_imm5 + bclr #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101011010ddd010bbbbb dsp_reg_imm5 + bclr #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101011011ddd010bbbbb dsp_reg_imm5 + bclr #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101011100ddd010bbbbb dsp_reg_imm5 + bclr #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101011111ddd010bbbbb dsp_reg_imm5 bclr #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +bset C_DSPIM M_DSPEA NOPARMO %0000101001mmmrrr0s1bbbbb dsp_ea_imm5 + bset #n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31 +- C_DSPIM M_DSPAA NOPARMO %0000101000aaaaaa0s1bbbbb dsp_ea_imm5 + bset #n,X:aa / bset #n,Y:aa +- C_DSPIM M_DSPPP NOPARMO %0000101010pppppp0s1bbbbb dsp_ea_imm5 + bset #n,X:pp / bset #n,Y:pp +- C_DSPIM C_DD NOPARMO %00001010110001dd011bbbbb dsp_reg_imm5 + bset #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DDD NOPARMO %0000101011001ddd011bbbbb dsp_reg_imm5 + bset #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101011010ddd011bbbbb dsp_reg_imm5 + bset #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101011011ddd011bbbbb dsp_reg_imm5 + bset #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101011100ddd011bbbbb dsp_reg_imm5 + bset #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101011111ddd011bbbbb dsp_reg_imm5 bset #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +btst C_DSPIM M_DSPEA NOPARMO %0000101101mmmrrr0s1bbbbb dsp_ea_imm5 + btst#n,X:ea / #n,Y:ea mmmrrr=ea, s=(X=0, Y=1), bbbbb=0-31 +- C_DSPIM M_DSPAA NOPARMO %0000101100aaaaaa0s1bbbbb dsp_ea_imm5 + btst #n,X:aa / btst #n,Y:aa +- C_DSPIM M_DSPPP NOPARMO %0000101110pppppp0s1bbbbb dsp_ea_imm5 + btst #n,X:pp / btst #n,Y:pp +- C_DSPIM C_DDD NOPARMO %0000101111001ddd011bbbbb dsp_reg_imm5 + btst #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DD NOPARMO %00001011110001dd011bbbbb dsp_reg_imm5 + btst #n,D DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101111010ddd011bbbbb dsp_reg_imm5 + btst #n,D TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101111011ddd011bbbbb dsp_reg_imm5 + btst #n,D NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101111100ddd011bbbbb dsp_reg_imm5 + btst #n,D FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101111111ddd011bbbbb dsp_reg_imm5 btst #n,D GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +do M_DSPEA C_DSPABS24 NOPARMO %0000011001mmmrrr0s000000 dsp_ea_abs16 + DO X:ea,expr / DO Y:ea,expr mmmrrr=ea, s=(X=0, Y=1), expr=16bit in extension word +- M_DSPAA C_DSPABS24 NOPARMO %0000011000aaaaaa0s000000 dsp_ea_abs16 + DO X:aa,expr / DO Y:aa,expr aaaaaa=aa, s=(X=0, Y=1), expr=16bit in extension word +- C_DSPIM C_DSPABS24 NOPARMO %00000110iiiiiiii1000hhhh dsp_imm12_abs16 + DO #xxx,expr hhhhiiiiiiii=12bit immediate, expr=16bit in extension word +- M_ALU24 C_DSPABS24 NOPARMO %0000011011000ddd00000000 dsp_alu24_abs16 + DO S,expr x0, x1, y0, y1 +- C_DDD C_DSPABS24 NOPARMO %0000011011001ddd00000000 dsp_reg_abs16 + DO S,expr DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_TTT C_DSPABS24 NOPARMO %0000011011010ddd00000000 dsp_reg_abs16 + DO S,expr TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_NNN C_DSPABS24 NOPARMO %0000011011011ddd00000000 dsp_reg_abs16 + DO S,expr NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_FFF C_DSPABS24 NOPARMO %0000011011100ddd00000000 dsp_reg_abs16 + DO S,expr FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_GGG C_DSPABS24 NOPARMO %0000011011111ddd00000000 dsp_reg_abs16 DO S,expr GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +rep C_DSPIM M_AM_NONE NOPARMO %00000110iiiiiiii1010hhhh dsp_imm12 + rep #xx +- M_DSPEA M_AM_NONE NOPARMO %0000011001mmmrrr0s100000 dsp_ea + rep x:ea / y:ea +- M_DSPAA M_AM_NONE NOPARMO %0000011000aaaaaa0s100000 dsp_ea + rep x:aa / y:aa +- M_ALU24 M_AM_NONE NOPARMO %0000011011000ddd00100000 dsp_alu24 + rep S,expr x0, x1, y0, y1 +- C_DDD M_AM_NONE NOPARMO %0000011011001ddd00100000 dsp_reg + rep S DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_TTT M_AM_NONE NOPARMO %0000011011010ddd00100000 dsp_reg + rep S TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_NNN M_AM_NONE NOPARMO %0000011011011ddd00100000 dsp_reg + rep S NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_FFF M_AM_NONE NOPARMO %0000011011100ddd00100000 dsp_reg + rep S FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_GGG M_AM_NONE NOPARMO %0000011011111ddd00100000 dsp_reg rep S GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +jsclr C_DSPIM M_DSPEA NOPARMO %0000101101mmmrrr1s0bbbbb dsp_ea_imm5_abs16 + JSCLR #n,X:ea,xxxx / #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1) +- C_DSPIM M_DSPAA NOPARMO %0000101100aaaaaa1s0bbbbb dsp_ea_imm5_abs16 + JSCLR #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1) +- C_DSPIM M_DSPPP NOPARMO %0000101110pppppp1s0bbbbb dsp_ea_imm5_abs16 + JSCLR #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1) +- C_DSPIM C_DD NOPARMO %00001011110001dd000bbbbb dsp_reg_imm5_abs16 + JSCLR #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DDD NOPARMO %0000101111001ddd000bbbbb dsp_reg_imm5_abs16 + JSCLR #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101111010ddd000bbbbb dsp_reg_imm5_abs16 + JSCLR #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101111011ddd000bbbbb dsp_reg_imm5_abs16 + JSCLR #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101111100ddd000bbbbb dsp_reg_imm5_abs16 + JSCLR #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101111101ddd000bbbbb dsp_reg_imm5_abs16 JSCLR #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +jset C_DSPIM M_DSPEA NOPARMO %0000101001mmmrrr1s1bbbbb dsp_ea_imm5_abs16 + JSET #n,X:ea,xxxx / #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1) +- C_DSPIM M_DSPAA NOPARMO %0000101000aaaaaa1s1bbbbb dsp_ea_imm5_abs16 + JSET #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1) +- C_DSPIM M_DSPPP NOPARMO %0000101010pppppp1s1bbbbb dsp_ea_imm5_abs16 + JSET #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1) +- C_DSPIM C_DD NOPARMO %00001010110001dd001bbbbb dsp_reg_imm5_abs16 + JSET #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DDD NOPARMO %0000101011001ddd001bbbbb dsp_reg_imm5_abs16 + JSET #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101011010ddd001bbbbb dsp_reg_imm5_abs16 + JSET #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101011011ddd001bbbbb dsp_reg_imm5_abs16 + JSET #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101011100ddd001bbbbb dsp_reg_imm5_abs16 + JSET #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101011101ddd001bbbbb dsp_reg_imm5_abs16 JSET #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +jsset C_DSPIM M_DSPEA NOPARMO %0000101101mmmrrr1s1bbbbb dsp_ea_imm5_abs16 + JSSET #n,X:ea,xxxx / JSSET #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1) +- C_DSPIM M_DSPAA NOPARMO %0000101100aaaaaa1s1bbbbb dsp_ea_imm5_abs16 + JSSET #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1) +- C_DSPIM M_DSPPP NOPARMO %0000101110pppppp1s1bbbbb dsp_ea_imm5_abs16 + JSSET #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1) +- C_DSPIM C_DD NOPARMO %00001011110001dd001bbbbb dsp_reg_imm5_abs16 + JSSET #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DDD NOPARMO %0000101111001ddd001bbbbb dsp_reg_imm5_abs16 + JSSET #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101111010ddd001bbbbb dsp_reg_imm5_abs16 + JSSET #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101111011ddd001bbbbb dsp_reg_imm5_abs16 + JSSET #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101111100ddd001bbbbb dsp_reg_imm5_abs16 + JSSET #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101111101ddd001bbbbb dsp_reg_imm5_abs16 JSSET #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +jclr C_DSPIM M_DSPEA NOPARMO %0000101001mmmrrr1s0bbbbb dsp_ea_imm5_abs16 + JCLR #n,X:ea,xxxx / #n,Y:ea,xxxx n=bbbbb=0-31, ea=mmmrrr, xxxx=16bit extension, s=(X=0, Y=1) +- C_DSPIM M_DSPAA NOPARMO %0000101000aaaaaa1s0bbbbb dsp_ea_imm5_abs16 + JCLR #n,X:aa,xxxx / #n,Y:aa,xxxx n=bbbbb=0-31, aa=aaaaaa=short address, s=(X=0, Y=1) +- C_DSPIM M_DSPPP NOPARMO %0000101010pppppp1s0bbbbb dsp_ea_imm5_abs16 + JCLR #n,X:pp,xxxx / #n,Y:pp,xxxx n=bbbbb=0-31, pp=pppppp=short i/o address, s=(X=0, Y=1) +- C_DSPIM C_DD NOPARMO %00001010110001dd000bbbbb dsp_reg_imm5_abs16 + JCLR #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_DDD NOPARMO %0000101011001ddd000bbbbb dsp_reg_imm5_abs16 + JCLR #n,S,xxxx DDD See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_TTT NOPARMO %0000101011010ddd000bbbbb dsp_reg_imm5_abs16 + JCLR #n,S,xxxx TTT See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_NNN NOPARMO %0000101011011ddd000bbbbb dsp_reg_imm5_abs16 + JCLR #n,S,xxxx NNN See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_FFF NOPARMO %0000101011100ddd000bbbbb dsp_reg_imm5_abs16 + JCLR #n,S,xxxx FFF See A.9 Instruction Encoding and Table A-18 for specific register encodings. +- C_DSPIM C_GGG NOPARMO %0000101011101ddd000bbbbb dsp_reg_imm5_abs16 JCLR #n,S,xxxx GGG See A.9 Instruction Encoding and Table A-18 for specific register encodings. +lua M_DSPEA C_LUADST NOPARMO %00000100010mmrrr0001dddd dsp_ea_lua mmrrr=ea (subset), dddd=(bit 3=(0=Rn, 1=Nn), bits 2-0=0-7) +norm M_DSPR M_ACC56 NOPARMO %0000000111011rrr0001d101 dsp_ab_rn norm Rn,D D=(a=0, b=1) +move M_AM_NONE M_AM_NONE PARMOVE %mmmmmmmmmmmmmmmm00000000 dsp_self +movec M_DSPIM8 C_MOVEC NOPARMO %00000101iiiiiiii101ddddd dsp_immmovec + move(c) #xx,d1 +- M_DSPEA C_MOVEC NOPARMO %0000010111mmmrrr0s1ddddd dsp_movec_ea + move(c) x:ea,d1 / y:ea,d1 +- C_MOVEC M_DSPEA NOPARMO %0000010101mmmrrr0s1ddddd dsp_movec_ea + move(c) s1,x:ea / s1,y:ea +- C_DSPIM C_MOVEC NOPARMO %0000010111110100001ddddd dsp_movec_ea + move(c) #xxxx,d1 +- M_DSPAA C_MOVEC NOPARMO %0000010110aaaaaa0s1ddddd dsp_movec_aa + move(c) x:aa,d1 / y:aa,d1 +- C_MOVEC M_DSPAA NOPARMO %0000010100aaaaaa0s1ddddd dsp_movec_aa + move(c) s1,x:aa / s1,y:aa +- C_MOVEC M_ALU24 NOPARMO %0000010001000eee101ddddd dsp_movec_reg + move(c) s1,d2 +- C_MOVEC C_DDD NOPARMO %0000010001001eee101ddddd dsp_movec_reg + move(c) s1,d2 +- C_MOVEC C_TTT NOPARMO %0000010001010eee101ddddd dsp_movec_reg + move(c) s1,d2 +- C_MOVEC C_NNN NOPARMO %0000010001011eee101ddddd dsp_movec_reg + move(c) s1,d2 +- C_MOVEC C_FFF NOPARMO %0000010001100eee101ddddd dsp_movec_reg + move(c) s1,d2 +- C_MOVEC C_GGG NOPARMO %0000010001111eee101ddddd dsp_movec_reg + move(c) s1,d2 +- M_ALU24 C_MOVEC NOPARMO %0000010011000eee101ddddd dsp_movec_reg + move(c) s2,d1 +- C_DDD C_MOVEC NOPARMO %0000010011001eee101ddddd dsp_movec_reg + move(c) s2,d1 +- C_TTT C_MOVEC NOPARMO %0000010011010eee101ddddd dsp_movec_reg + move(c) s2,d1 +- C_NNN C_MOVEC NOPARMO %0000010011011eee101ddddd dsp_movec_reg + move(c) s2,d1 +- C_FFF C_MOVEC NOPARMO %0000010011100eee101ddddd dsp_movec_reg + move(c) s2,d1 +- C_GGG C_MOVEC NOPARMO %0000010011111eee101ddddd dsp_movec_reg move(c) s2,d1 +movem M_ALU24 M_DSPEA NOPARMO %0000011101mmmrrr10000ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- C_DDD M_DSPEA NOPARMO %0000011101mmmrrr10001ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- C_TTT M_DSPEA NOPARMO %0000011101mmmrrr10010ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- C_NNN M_DSPEA NOPARMO %0000011101mmmrrr10011ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- C_FFF M_DSPEA NOPARMO %0000011101mmmrrr10100ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- C_GGG M_DSPEA NOPARMO %0000011101mmmrrr10111ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_DSPEA M_ALU24 NOPARMO %0000011111mmmrrr10000ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_DSPEA C_DDD NOPARMO %0000011111mmmrrr10001ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_DSPEA C_TTT NOPARMO %0000011111mmmrrr10010ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_DSPEA C_NNN NOPARMO %0000011111mmmrrr10011ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_DSPEA C_FFF NOPARMO %0000011111mmmrrr10100ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_DSPEA C_GGG NOPARMO %0000011111mmmrrr10111ddd dsp_movem_ea + move(m) s,p:ea / p:ea,d +- M_ALU24 M_DSPAA NOPARMO %0000011100aaaaaa00000ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- C_DDD M_DSPAA NOPARMO %0000011100aaaaaa00001ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- C_TTT M_DSPAA NOPARMO %0000011100aaaaaa00010ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- C_NNN M_DSPAA NOPARMO %0000011100aaaaaa00011ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- C_FFF M_DSPAA NOPARMO %0000011100aaaaaa00100ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- C_GGG M_DSPAA NOPARMO %0000011100aaaaaa00111ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- M_DSPAA M_ALU24 NOPARMO %0000011110aaaaaa00000ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- M_DSPAA C_DDD NOPARMO %0000011110aaaaaa00001ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- M_DSPAA C_TTT NOPARMO %0000011110aaaaaa00010ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- M_DSPAA C_NNN NOPARMO %0000011110aaaaaa00011ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- M_DSPAA C_FFF NOPARMO %0000011110aaaaaa00100ddd dsp_movem_aa + move(m) s,p:aa / p:aa,d +- M_DSPAA C_GGG NOPARMO %0000011110aaaaaa00111ddd dsp_movem_aa move(m) s,p:aa / p:aa,d +mac M_ALU24 M_ALU24 PARMOVE %mmmmmmmmmmmmmmmm1qqqdk10 dsp_mult mac -+s1,s2,d / mac -+s2,s1,d +macr M_ALU24 M_ALU24 PARMOVE %mmmmmmmmmmmmmmmm1qqqdk11 dsp_mult macr -+s1,s2,d / macr -+s2,s1,d +mpy M_ALU24 M_ALU24 PARMOVE %mmmmmmmmmmmmmmmm1qqqdk00 dsp_mult mpy -+s1,d2,d / -+s2,s1,d +mpyr M_ALU24 M_ALU24 PARMOVE %mmmmmmmmmmmmmmmm1qqqdk01 dsp_mult mpyr -+s1,d2,d / -+s2,s1,d +movep M_DSPEA M_DSPPP NOPARMO %0000100s11mmmrrr1spppppp dsp_movep_ea + movep p:ea,x:pp / p:ea,y:pp +- M_DSPAA M_DSPPP NOPARMO %0000100s11mmmrrr1spppppp dsp_movep_ea + movep p:aa,x:pp / p:aa,y:pp +- M_DSPPP M_DSPEA NOPARMO %0000100s01mmmrrr1spppppp dsp_movep_ea + x:pp,p:ea / y:pp,p:ea +- M_DSPPP M_DSPPP NOPARMO %0000100s01mmmrrr1spppppp dsp_movep_ea + x:pp,p:ea / y:pp,p:ea +- M_DSPPP M_DSPAA NOPARMO %0000100s01mmmrrr1spppppp dsp_movep_ea + x:pp,p:aa / y:pp,p:aa +- C_DSPIM M_DSPPP NOPARMO %0000100s111101001spppppp dsp_movep_ea + #xxxxxx,x:pp / #xxxxxx,y:pp +- C_DSPIM M_DSPEA NOPARMO %0000100s111101001spppppp dsp_movep_ea + #xxxxxx,x:pp / #xxxxxx,y:pp +- M_ALU24 M_DSPPP NOPARMO %0000100s11000ddd0spppppp dsp_movep_reg + movep s,x:pp / s,y:pp +- C_DDD M_DSPPP NOPARMO %0000100s11001ddd0spppppp dsp_movep_reg + movep s,x:pp / s,y:pp +- C_TTT M_DSPPP NOPARMO %0000100s11010ddd0spppppp dsp_movep_reg + movep s,x:pp / s,y:pp +- C_NNN M_DSPPP NOPARMO %0000100s11011ddd0spppppp dsp_movep_reg + movep s,x:pp / s,y:pp +- C_FFF M_DSPPP NOPARMO %0000100s11100ddd0spppppp dsp_movep_reg + movep s,x:pp / s,y:pp +- C_GGG M_DSPPP NOPARMO %0000100s11111ddd0spppppp dsp_movep_reg + movep s,x:pp / s,y:pp +- M_DSPPP M_ALU24 NOPARMO %0000100s01000ddd0spppppp dsp_movep_reg + movep x:pp,d / y:pp,d +- M_DSPPP C_DDD NOPARMO %0000100s01001ddd0spppppp dsp_movep_reg + movep x:pp,d / y:pp,d +- M_DSPPP C_TTT NOPARMO %0000100s01010ddd0spppppp dsp_movep_reg + movep x:pp,d / y:pp,d +- M_DSPPP C_NNN NOPARMO %0000100s01011ddd0spppppp dsp_movep_reg + movep x:pp,d / y:pp,d +- M_DSPPP C_FFF NOPARMO %0000100s01100ddd0spppppp dsp_movep_reg + movep x:pp,d / y:pp,d +- M_DSPPP C_GGG NOPARMO %0000100s01111ddd0spppppp dsp_movep_reg movep x:pp,d / y:pp,d +debug M_AM_NONE M_AM_NONE NOPARMO %000000000000001000000000 dsp_self +debugcc M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000000 dsp_self +debughs M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000000 dsp_self +debugcs M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001000 dsp_self +debuglo M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001000 dsp_self +debugec M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000101 dsp_self +debugeq M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001010 dsp_self +debuges M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001101 dsp_self +debugge M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000001 dsp_self +debuggt M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000111 dsp_self +debuglc M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000110 dsp_self +debugle M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001111 dsp_self +debugls M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001110 dsp_self +debuglt M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001001 dsp_self +debugmi M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001011 dsp_self +debugne M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000010 dsp_self +debugnr M_AM_NONE M_AM_NONE NOPARMO %000000000000001100001100 dsp_self +debugpl M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000011 dsp_self +debugnn M_AM_NONE M_AM_NONE NOPARMO %000000000000001100000100 dsp_self + + diff --git a/dsp56k_amode.c b/dsp56k_amode.c new file mode 100644 index 0000000..c5644cc --- /dev/null +++ b/dsp56k_amode.c @@ -0,0 +1,2806 @@ +// +// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// AMODE.C - DSP 56001 Addressing Modes +// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#include "dsp56k_amode.h" +#include "error.h" +#include "token.h" +#include "expr.h" +#include "rmac.h" +#include "procln.h" +#include "sect.h" +#include "math.h" + +#define DEF_KW +#include "kwtab.h" +#define DEF_MN +#include "mntab.h" + +// Address-mode information +int nmodes; // Number of addr'ing modes found +int dsp_am0; // Addressing mode +int dsp_a0reg; // Register +TOKEN dsp_a0expr[EXPRSIZE]; // Expression +uint64_t dsp_a0exval; // Expression's value +WORD dsp_a0exattr; // Expression's attribute +LONG dsp_a0memspace; // Addressing mode's memory space (P, X, Y) +SYM * dsp_a0esym; // External symbol involved in expr + +int dsp_am1; // Addressing mode +int dsp_a1reg; // Register +TOKEN dsp_a1expr[EXPRSIZE]; // Expression +uint64_t dsp_a1exval; // Expression's value +WORD dsp_a1exattr; // Expression's attribute +LONG dsp_a1memspace; // Addressing mode's memory space (P, X, Y) +SYM * dsp_a1esym; // External symbol involved in expr + +int dsp_am2; // Addressing mode +int dsp_a2reg; // Register +TOKEN dsp_a2expr[EXPRSIZE]; // Expression +uint64_t dsp_a2exval; // Expression's value +WORD dsp_a2exattr; // Expression's attribute +SYM * dsp_a2esym; // External symbol involved in expr + +int dsp_am3; // Addressing mode +int dsp_a3reg; // Register +TOKEN dsp_a3expr[EXPRSIZE]; // Expression +uint64_t dsp_a3exval; // Expression's value +WORD dsp_a3exattr; // Expression's attribute +SYM * dsp_a3esym; // External symbol involved in expr + +TOKEN dspImmedEXPR[EXPRSIZE]; // Expression +uint64_t dspImmedEXVAL; // Expression's value +WORD dspImmedEXATTR; // Expression's attribute +SYM * dspImmedESYM; // External symbol involved in expr +int deposit_extra_ea; // Optional effective address extension +TOKEN dspaaEXPR[EXPRSIZE]; // Expression +uint64_t dspaaEXVAL; // Expression's value +WORD dspaaEXATTR; // Expression's attribute +SYM * dspaaESYM; // External symbol involved in expr + +int dsp_k; // Multiplications sign + +static inline LONG checkea(const uint32_t termchar, const int strings); + +// ea checking error strings put into a table because I'm not sure there's an easy way to do otherwise +// (the messages start getting differerent in many places so it will get awkward to code those in) +// (I'd rather burn some RAM in order to have more helpful error messages than the other way round) + +#define X_ERRORS 0 +#define Y_ERRORS 1 +#define L_ERRORS 2 +#define P_ERRORS 3 + +const char *ea_errors[][12] = { + // X: + { + "unrecognised X: parallel move syntax: expected '(' after 'X:-'", // 0 + "unrecognised X: parallel move syntax: expected ')' after 'X:-(Rn'", // 1 + "unrecognised X: parallel move syntax: expected R0-R7 after 'X:-('", // 2 + "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn+'", // 3 + "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn+Nn)'", // 4 + "unrecognised X: parallel move syntax: expected ')' after 'X:(Rn+Nn'", // 5 + "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)+Nn'", // 6 + "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)+'", // 7 + "unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)-Nn'", // 8 + "unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)-'", // 9 + "unrecognised X: parallel move syntax: expected '+', '-' or ',' after 'X:(Rn)'", // 10 + "unrecognised X: parallel move syntax: expected '+' or ')' after 'X:(Rn'", // 11 + }, + // Y: + { + "unrecognised Y: parallel move syntax: expected '(' after 'Y:-'", // 0 + "unrecognised Y: parallel move syntax: expected ')' after 'Y:-(Rn'", // 1 + "unrecognised Y: parallel move syntax: expected R0-R7 after 'Y:-('", // 2 + "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn+'", // 3 + "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn+Nn)'", // 4 + "unrecognised Y: parallel move syntax: expected ')' after 'Y:(Rn+Nn'", // 5 + "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)+Nn'", // 6 + "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)+'", // 7 + "unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)-Nn'", // 8 + "unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)-'", // 9 + "unrecognised Y: parallel move syntax: expected '+', '-' or ',' after 'Y:(Rn)'", // 10 + "unrecognised Y: parallel move syntax: expected '+' or ')' after 'Y:(Rn'", // 11 + }, + // L: + { + "unrecognised L: parallel move syntax: expected '(' after 'L:-'", // 0 + "unrecognised L: parallel move syntax: expected ')' after 'L:-(Rn'", // 1 + "unrecognised L: parallel move syntax: expected R0-R7 after 'L:-('", // 2 + "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn+'", // 3 + "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn+Nn)'", // 4 + "unrecognised L: parallel move syntax: expected ')' after 'L:(Rn+Nn'", // 5 + "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)+Nn'", // 6 + "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)+'", // 7 + "unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)-Nn'", // 8 + "unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)-'", // 9 + "unrecognised L: parallel move syntax: expected '+', '-' or ',' after 'L:(Rn)'", // 10 + "unrecognised L: parallel move syntax: expected '+' or ')' after 'L:(Rn'", // 11 + }, + // P: + { + "unrecognised P: effective address syntax: expected '(' after 'P:-'", // 0 + "unrecognised P: effective address syntax: expected ')' after 'P:-(Rn'", // 1 + "unrecognised P: effective address syntax: expected R0-R7 after 'P:-('", // 2 + "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn+'", // 3 + "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn+Nn)'", // 4 + "unrecognised P: effective address syntax: expected ')' after 'P:(Rn+Nn'", // 5 + "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)+Nn'", // 6 + "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)+'", // 7 + "unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)-Nn'", // 8 + "unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)-'", // 9 + "unrecognised P: effective address syntax: expected '+', '-' or ',' after 'P:(Rn)'", // 10 + "unrecognised P: effective address syntax: expected '+' or ')' after 'P:(Rn'", // 11 + } +}; + +enum +{ + NUM_NORMAL = 0, + NUM_FORCE_LONG = 1, + NUM_FORCE_SHORT = 2 +}; + +// +// Parse a single addressing mode +// +static inline int dsp_parmode(int *am, int *areg, TOKEN * AnEXPR, uint64_t * AnEXVAL, WORD * AnEXATTR, SYM ** AnESYM, LONG *memspace, LONG *perspace, const int operand) +{ + if (*tok == KW_A || *tok == KW_B) + { + *am = M_ACC56; + *areg = *tok++; + return OK; + } + else if (*tok == '#') + { + tok++; + + if (*tok == '<') + { + // Immediate Short Addressing Mode Force Operator + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXVAL > 0xfff && *AnEXVAL<-4096) + return error("immediate short addressing mode forced but address is bigger than $fff"); + if ((int32_t)*AnEXVAL <= 0xff && (int32_t)*AnEXVAL>-0x100) + { + *am = M_DSPIM8; + return OK; + } + *am = M_DSPIM12; + return OK; + } + else if (*tok == '>') + { + // Immediate Long Addressing Mode Force Operator + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if ((int32_t)*AnEXVAL > 0xffffff || (int32_t)*AnEXVAL < -0xffffff) + return error("long immediate is bigger than $ffffff"); + *am = M_DSPIM; + return OK; + } + + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + if (*AnEXATTR & DEFINED) + { + if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100) + { + *AnEXVAL &= 0xff; + *am = M_DSPIM8; + } + else if (*AnEXVAL < 0x1000) + *am = M_DSPIM12; + else + *am = M_DSPIM; + } + else + { + // We have no clue what size our immediate will be + // so we have to assume the worst + *am = M_DSPIM; + } + return OK; + } + else if (*tok >= KW_X0 && *tok <= KW_Y1) + { + *am = M_ALU24; + *areg = *tok++; + return OK; + } + else if (*tok == KW_X && *(tok + 1) == ':') + { + tok = tok + 2; + if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + *memspace = 0 << 6; // Mark we're on X memory space + + // Check if value is between $ffc0 and $ffff, AKA X:pp + { + uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits + if ((temp >= 0xffffffc0 /* Check for 32bit sign extended number */ + && ((int32_t)*AnEXVAL<0)) /* Check if 32bit signed number is negative*/ + ||(*AnEXVAL<0xffff && *AnEXVAL>=0x8000)) /* Check if 16bit number is negative*/ + { + *AnEXVAL = temp; + *am = M_DSPPP; + *memspace = 0 << 6; // Mark we're on X memory space + *perspace = 0 << 16; // Mark we're on X peripheral space + *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + + } + + // If the symbol/expression is defined then check for valid range. + // Otherwise the value had better fit or Fixups will bark! + if (*AnEXVAL > 0x3f) + { + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + else + { + *am = M_DSPAA; + } + } + else + { + // Assume the worst + *memspace = 0 << 6; // Mark we're on X memory space + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + return OK; + } + else if (*tok == '<') + { + // X:aa + // Short Addressing Mode Force Operator in the case of '<' + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + // If the symbol/expression is defined then check for valid range. + // Otherwise the value had better fit or Fixups will bark! + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0x3f) + return error("short addressing mode forced but address is bigger than $3f"); + } + else + { + // Mark it as a fixup + deposit_extra_ea = DEPOSIT_EXTRA_FIXUP; + } + *am = M_DSPAA; + *memspace = 0 << 6; // Mark we're on X memory space + *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + else if (*tok == '>') + { + // Long Addressing Mode Force Operator + tok++; + + if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXATTR&DEFINED) + { + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + *memspace = 0 << 6; // Mark we're on X memory space + + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + else + { + // Assume the worst + *memspace = 0 << 6; // Mark we're on X memory space + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + return OK; + } + } + else if (*tok == SHL) // '<<' + { + // I/O Short Addressing Mode Force Operator + // X:pp + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + // If the symbol/expression is defined then check for valid range. + // Otherwise the value had better fit or Fixups will bark! + if (*AnEXATTR & DEFINED) + { + *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits + if (*AnEXVAL < 0xffffffc0) + return error("I/O Short Addressing Mode addresses must be between $ffc0 and $ffff"); + } + *am = M_DSPPP; + *memspace = 0 << 6; // Mark we're on X memory space + *perspace = 0 << 16; // Mark we're on X peripheral space + *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + + if ((*areg = checkea(0, X_ERRORS)) != ERROR) + { + // TODO: what if we need M_DSPAA here???? + *memspace = 0 << 6; // Mark we're on X memory space + *am = M_DSPEA; + return OK; + } + else + return ERROR; + + } + else if (*tok == KW_Y && *(tok + 1) == ':') + { + tok = tok + 2; + + if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + *memspace = 1 << 6; // Mark we're on Y memory space + + // Check if value is between $ffc0 and $ffff, AKA Y:pp + { + uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits + if ((temp >= 0xffffffc0 /* Check for 32bit sign extended number */ + && ((int32_t)*AnEXVAL<0)) /* Check if 32bit signed number is negative*/ + || (*AnEXVAL<0xffff && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/ + { + *AnEXVAL = temp; + *am = M_DSPPP; + *perspace = 1 << 16; // Mark we're on X peripheral space + *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + + } + + // If the symbol/expression is defined then check for valid range. + // Otherwise the value had better fit or Fixups will bark! + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0x3f) + { + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + else + { + *am = M_DSPAA; + } + } + else + { + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + + return OK; + } + else if (*tok == '<') + { + // Y:aa + // Short Addressing Mode Force Operator in the case of '<' + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + // If the symbol/expression is defined then check for valid range. + // Otherwise the value had better fit or Fixups will bark! + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0x3f) + { + warn("short addressing mode forced but address is bigger than $3f - switching to long"); + *am = M_DSPEA; + *memspace = 1 << 6; // Mark we're on Y memory space + *areg = DSP_EA_ABS; + return OK; + } + } + else + { + // Mark it as a fixup + deposit_extra_ea = DEPOSIT_EXTRA_FIXUP; + } + + *am = M_DSPAA; + *memspace = 1 << 6; // Mark we're on Y memory space + *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + else if (*tok == '>') + { + // Long Addressing Mode Force Operator + tok++; + + if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXATTR&DEFINED) + { + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + *memspace = 1 << 6; // Mark we're on Y memory space + + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + else + { + // Assume the worst + *memspace = 1 << 6; // Mark we're on Y memory space + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + return OK; + } + } + else if (*tok == SHL) // '<<' + { + // I/O Short Addressing Mode Force Operator + // Y:pp + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + // If the symbol/expression is defined then check for valid range. + // Otherwise the value had better fit or Fixups will bark! + if (*AnEXATTR & DEFINED) + { + *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6)); // Sign extend 6 to 32 bits + if (*AnEXVAL < 0xffffffc0) + return error("I/O Short Addressing Mode addresses must be between $ffe0 and $1f"); + } + *am = M_DSPPP; + *memspace = 1 << 6; // Mark we're on Y memory space + *perspace = 1 << 16; // Mark we're on Y peripheral space + *areg = *AnEXVAL & 0x3f; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + + if ((*areg = checkea(0, X_ERRORS)) != ERROR) + { + *memspace = 1 << 6; // Mark we're on Y memory space + *am = M_DSPEA; + return OK; + } + else + return ERROR; + // TODO: add absolute address checks + + } + else if (*tok >= KW_X&&*tok <= KW_Y) + { + *am = M_INP48; + *areg = *tok++; + return OK; + } + else if (*tok >= KW_M0 && *tok <= KW_M7) + { + *am = M_DSPM; + *areg = (*tok++) & 7; + return OK; + } + else if (*tok >= KW_R0 && *tok <= KW_R7) + { + *am = M_DSPR; + *areg = (*tok++) - KW_R0; + return OK; + } + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + *am = M_DSPN; + *areg = (*tok++) & 7; + return OK; + } + else if (*tok == KW_A0 || *tok == KW_A1 || *tok == KW_B0 || *tok == KW_B1) + { + *am = M_ACC24; + *areg = *tok++; + return OK; + } + else if (*tok == KW_A2 || *tok == KW_B2) + { + *am = M_ACC8; + *areg = *tok++; + return OK; + } + else if (*tok == '-' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1)) + { + // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications + tok++; + + // Check to see if this is the first operand + if (operand != 0) + return error("-x0/-x1/-y0/-y1 only allowed in the first operand"); + + *am = M_ALU24; + *areg = *tok++; + dsp_k = 1 << 2; + return OK; + } + else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1)) + { + // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications + tok++; + + // Check to see if this is the first operand + if (operand != 0) + return error("+x0/+x1/+y0/+y1 only allowed in the first operand"); + + *am = M_ALU24; + *areg = *tok++; + dsp_k = 0 << 2; + return OK; + } + else if (*tok == '(' || *tok == '-') + { + // Could be either an expression or ea mode + if (*tok + 1 == SYMBOL) + { + tok++; + + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + *am = M_DSPIM; + return OK; + } + if ((*areg = checkea(0, P_ERRORS)) != ERROR) + { + *am = M_DSPEA; + return OK; + } + else + return ERROR; + // TODO: add absolute address checks + return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!"); + } + else if (*tok == KW_P && *(tok + 1) == ':') + { + tok = tok + 2; + if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + // Address + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + if (*AnEXVAL > 0x3f) + { + *am = M_DSPEA; + *areg = DSP_EA_ABS; + } + else + { + *areg = (int)*AnEXVAL; // Lame, but what the hell + *am = M_DSPAA; + } + return OK; + } + else if (*tok == '<') + { + // X:aa + // Short Addressing Mode Force Operator in the case of '<' + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXVAL > 0x3f) + return error("short addressing mode forced but address is bigger than $3f"); + *am = M_DSPAA; + *areg = (int)*AnEXVAL; // Since this is only going to get used in dsp_ea_imm5... + return OK; + } + else if (*tok == '>') + { + // Long Addressing Mode Force Operator + tok++; + // Immediate Short Addressing Mode Force Operator + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + } + *am = M_DSPEA; + *areg = DSP_EA_ABS; + return OK; + } + + if ((*areg = checkea(0, P_ERRORS)) != ERROR) + { + *am = M_DSPEA; + return OK; + } + else + return ERROR; + + } + else if (*tok == SHL) + { + // I/O Short Addressing Mode Force Operator + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXVAL > 0xfff) + return error("I/O short addressing mode forced but address is bigger than $fff"); + *am = M_DSPABS06; + return OK; + } + else if (*tok == '<') + { + // Short Addressing Mode Force Operator + tok++; + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0xfff) + return error("short addressing mode forced but address is bigger than $fff"); + } + *am = M_DSPABS12; + return OK; + } + else if (*tok == '>') + { + // Long Addressing Mode Force Operator + tok++; + // Immediate Short Addressing Mode Force Operator + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + if (*AnEXATTR & DEFINED) + { + if (*AnEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + } + *am = M_DSPEA; + *areg = DSP_EA_ABS; + return OK; + } + + else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS)) + { + *areg = *tok++; + *am = M_DSPPCU; + return OK; + } + // expr + else + { + if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK) + return ERROR; + + // We'll store M_DSPEA_ABS in areg and if we have + // any extra info, it'll go in am + if (*AnEXATTR & DEFINED) + { + *areg = DSP_EA_ABS; + if (*AnEXVAL < 0x1000) + *am = M_DSPABS12; + else if (*AnEXVAL < 0x10000) + *am = M_DSPABS16; + else if (*AnEXVAL < 0x1000000) + *am = M_DSPABS24; + else + return error("address must be smaller than $1000000"); + return OK; + } + else + { + // Well, we have no opinion on the expression's size, so let's assume the worst + *areg = DSP_EA_ABS; + *am = M_DSPABS24; + return OK; + } + } + return error("internal assembler error: Please report this error message: 'reached the end of dsp_parmode' with the line of code that caused it. Thanks, and sorry for the inconvenience"); // Something bad happened +} + +// +// Parse all addressing modes except parallel moves +// +int dsp_amode(int maxea) +{ + LONG dummy; + // Initialize global return values + nmodes = dsp_a0reg = dsp_a1reg = 0; + dsp_am0 = dsp_am1 = M_AM_NONE; + dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR; + dsp_a0exval = 0; + dsp_a1exval = 0; + dsp_a0exattr = dsp_a1exattr = 0; + dsp_a0esym = dsp_a1esym = (SYM *)NULL; + dsp_a0memspace = dsp_a1memspace = -1; + dsp_a0perspace = dsp_a1perspace = -1; + dsp_k = 0; + + // If at EOL, then no addr modes at all + if (*tok == EOL) + return 0; + + if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR) + return ERROR; + + + // If caller wants only one mode, return just one (ignore comma); + // If there is no second addressing mode (no comma), then return just one anyway. + nmodes = 1; + + if (*tok != ',') + { + if (dsp_k != 0) + return error("-x0/-x1/-y0/-y1 only allowed in multiply operations"); + + return 1; + } + + // Eat the comma + tok++; + + // Parse second addressing mode + if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR) + return ERROR; + + if (maxea == 2 || *tok == EOL) + { + if (dsp_k != 0) + return error("-x0/-x1/-y0/-y1 only allowed in multiply operations"); + + nmodes = 2; + return 2; + } + + if (*tok == ',') + { + // Only MAC-like or jsset/clr/tst/chg instructions here + tok++; + if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR) + return ERROR; + if (maxea == 3) + return 3; + if (*tok != EOL) + return error(extra_stuff); + nmodes = 3; + return 3; + + } + + // Only Tcc instructions here, and then only those that accept 4 operands + + if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR) + return ERROR; + + if (*tok++ != ',') + return error("expected 4 parameters"); + + if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR) + return ERROR; + + if (*tok == EOL) + { + if (dsp_k != 0) + return error("-x0/-x1/-y0/-y1 only allowed in multiply operations"); + + nmodes = 4; + return 4; + } + else + { + // Tcc instructions do not support parallel moves, so any remaining tokens are garbage + return error(extra_stuff); + } + + return error("internal assembler error: Please report this error message: 'reached the end of dsp_amode' with the line of code that caused it. Thanks, and sorry for the inconvenience"); //Something bad happened + +} + + +// +// Helper function which gives us the encoding of a DSP register +// +static inline int SDreg(int reg) +{ + if (reg >= KW_X0 && reg <= KW_N7) + return reg & 0xff; + else if (reg >= KW_A0&® <= KW_A2) + return (8 >> (reg & 7)) | 8; + else //if (reg>=KW_R0&®<=KW_R7) + return reg - KW_R0 + 16; + // Handy map for the above: + // (values are of course taken from keytab) + // Register | Value | Return value + // x0 | 260 | 4 + // x1 | 261 | 5 + // y0 | 262 | 6 + // y1 | 263 | 7 + // b0 | 265 | 8 + // b2 | 267 | 9 + // b1 | 269 | 10 + // a | 270 | 14 + // b | 271 | 15 + // n0 | 280 | 24 + // n1 | 281 | 25 + // n2 | 282 | 26 + // n3 | 283 | 27 + // n4 | 284 | 28 + // n5 | 285 | 29 + // n6 | 286 | 30 + // n7 | 287 | 31 + // a0 | 136 | 0 + // a1 | 137 | 1 + // a2 | 138 | 2 + // r0 | 151 | 16 + // r1 | 152 | 17 + // r2 | 153 | 18 + // r3 | 154 | 19 + // r4 | 155 | 20 + // r5 | 156 | 21 + // r6 | 157 | 22 + // r7 | 158 | 23 +} + + +// +// Check for X:Y: parallel mode syntax +// +static inline LONG check_x_y(LONG ea1, LONG S1) +{ + LONG inst; + LONG eax_temp, eay_temp; + LONG D1, D2, S2, ea2; + LONG K_D1, K_D2; + LONG w = 1 << 7; // S1=0, D1=1<<14 + if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 || + (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD) + { + + switch (ea1 & 0x38) + { + case DSP_EA_POSTINC: ea1 = (ea1&(~0x38)) | 0x8;break; + case DSP_EA_POSTINC1: ea1 = (ea1&(~0x38)) | 0x18;break; + case DSP_EA_POSTDEC1: ea1 = (ea1&(~0x38)) | 0x10;break; + case DSP_EA_NOUPD: ea1 = (ea1&(~0x38)) | 0x00;break; + } + + if (S1 == 0) + { + // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' + // Check for D1 + switch (K_D1 = *tok++) + { + case KW_X0: D1 = 0 << 10; break; + case KW_X1: D1 = 1 << 10; break; + case KW_A: D1 = 2 << 10; break; + case KW_B: D1 = 3 << 10; break; + default: return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'"); + } + } + else + { + // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay' + w = 0; + switch (S1) + { + case 4: D1 = 0 << 10; break; + case 5: D1 = 1 << 10; break; + case 14: D1 = 2 << 10; break; + case 15: D1 = 3 << 10; break; + default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'"); + } + } + + if (*tok == KW_Y) + { + tok++; + // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2' + if (*tok++ != ':') + return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'"); + if (*tok++ == '(') + { + if (*tok >= KW_R0 && *tok <= KW_R7) + { + ea2 = (*tok++ - KW_R0); + if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4)) + return error("unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea Y:eay,D2'"); + } + else + return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('"); + // If eax register is r0-r3 then eay register is r4-r7. + // Encode that to 2 bits (i.e. eay value is 0-3) + eax_temp = (ea2 & 3) << 5; // Store register temporarily + if (*tok++ != ')') + return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'"); + if (*tok == '+') + { + tok++; + if (*tok == ',') + { + // (Rn)+ + ea2 = 3 << 12; + tok++; + } + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)+Nn + if ((*tok++ & 7) != ea2) + return error("unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea Y:(Rn)+Nn,D')"); + ea2 = 1 << 12; + if (*tok++ != ',') + return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'"); + } + else + return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'"); + + } + else if (*tok == '-') + { + // (Rn)- + ea2 = 2 << 12; + tok++; + if (*tok++ != ',') + return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'"); + } + else if (*tok++ == ',') + { + // (Rn) + ea2 = 0 << 12; + } + else + return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'"); + + ea2 |= eax_temp; // OR eay back from temp + + switch (K_D2 = *tok++) + { + case KW_Y0: D2 = 0 << 8; break; + case KW_Y1: D2 = 1 << 8; break; + case KW_A: D2 = 2 << 8; break; + case KW_B: D2 = 3 << 8; break; + default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'"); + } + + if (*tok != EOL) + return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'"); + + if (S1 == 0) + if (K_D1 == K_D2) + return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'"); + + inst = B16(11000000, 00000000) | w; + inst |= ea1 | D1 | ea2 | D2; + return inst; + } + else + return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'"); + } + else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B) + { + // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay' + switch (*tok++) + { + case KW_Y0: S2 = 0 << 8; break; + case KW_Y1: S2 = 1 << 8; break; + case KW_A: S2 = 2 << 8; break; + case KW_B: S2 = 3 << 8; break; + default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'"); + } + + if (*tok++ != ',') + return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'"); + + if (*tok++ == KW_Y) + { + // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2' + if (*tok++ != ':') + return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'"); + if (*tok++ == '(') + { + if (*tok >= KW_R0 && *tok <= KW_R7) + { + ea2 = (*tok++ - KW_R0); + if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4)) + return error("unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea S2,Y:eay'"); + } + else + return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('"); + // If eax register is r0-r3 then eay register is r4-r7. + // Encode that to 2 bits (i.e. eay value is 0-3) + eay_temp = (ea2 & 3) << 5; //Store register temporarily + if (*tok++ != ')') + return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'"); + if (*tok == '+') + { + tok++; + if (*tok == EOL) + // (Rn)+ + ea2 = 3 << 12; + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)+Nn + if ((*tok++ & 7) != ea2) + return error("unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn')"); + ea2 = 1 << 12; + if (*tok != EOL) + return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'"); + } + else + return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'"); + + } + else if (*tok == '-') + { + // (Rn)- + ea2 = 2 << 12; + tok++; + if (*tok != EOL) + return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'"); + } + else if (*tok == EOL) + { + // (Rn) + ea2 = 0 << 12; + } + else + return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'"); + + ea2 |= eay_temp; //OR eay back from temp + + inst = B16(10000000, 00000000) | w; + inst |= (ea1 & 0x1f) | D1 | S2 | ea2; + return inst; + } + else + return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'"); + + } + else + return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'"); + } + else + return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'"); + + + } + return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'"); +} + +// +// Parse X: addressing space parallel moves +// +static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y) +{ + int immreg; // Immediate register destination + LONG S2, D1, D2; // Source and Destinations + LONG ea1; // ea bitfields + uint32_t termchar = ','; // Termination character for ea checks + int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>') + ea1 = -1; // initialise e1 (useful for some code paths) + if (W == 0) + termchar = EOL; + if (*tok == '-') + { + if (tok[1] == CONST || tok[1] == FCONST) + { + tok++; + dspImmedEXVAL = *tok++; + goto x_check_immed; + } + // This could be either -(Rn), -aa or -ea. Check for immediate first + if (tok[1] == SYMBOL) + { + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK) + { + if (S1 != 0) + { + x_checkea_right: + + // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B', 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay' + if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A) + { + // 'A,X:ea X0,A' + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + if (S1 != 14) + return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'"); + if (ea1 == -1) + return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'"); + if (ea1 == B8(00110100)) + return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'"); + inst = B16(00001000, 00000000) | ea1 | (0 << 8); + return inst; + } + else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B) + { + // 'B,X:ea X0,B' + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + if (S1 != 15) + return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'"); + if (ea1 == -1) + return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'"); + if (ea1 == B8(00110100)) + return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'"); + inst = B16(00001001, 00000000) | ea1 | (1 << 8); + return inst; + } + else if (*tok == KW_A || *tok == KW_B) + { + // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay' + + switch (S1) + { + case 4: D1 = 0 << 10; break; + case 5: D1 = 1 << 10; break; + case 14: D1 = 2 << 10; break; + case 15: D1 = 3 << 10; break; + default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'"); + } + + if (tok[1] == ',' && tok[2] == KW_Y) + { + // 'S1,X:eax S2,Y:eay' + return check_x_y(ea1, S1); + } + + // 'S1,X:ea S2,D2' + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + switch (*tok++) + { + case KW_A: S2 = 0 << 9; break; + case KW_B: S2 = 1 << 9; break; + default: return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'"); + } + if (*tok++ != ',') + return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'"); + + if (*tok == KW_Y0 || *tok == KW_Y1) + { + if (*tok++ == KW_Y0) + D2 = 0 << 8; + else + D2 = 1 << 8; + + if (*tok != EOL) + return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'"); + + inst = B16(00010000, 00000000) | (0 << 7); + inst |= ea1 | D1 | S2 | D2; + return inst; + } + else + return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'"); + + } + else if (*tok == KW_Y) + { + // 'S1,X:eax Y:eay,D2' + return check_x_y(ea1, S1); + } + else if (*tok == KW_Y0 || *tok == KW_Y1) + { + // 'S1,X:eax S2,Y:eay' + return check_x_y(ea1, S1); + } + else + return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1"); + } + else + { + // Only check for aa if we have a defined number in our hands or we've + // been asked to use a short number format. The former case we'll just test + // it to see if it's small enough. The later - it's the programmer's call + // so he'd better have a small address or the fixups will bite him/her in the arse! + if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT) + { + + // It's an immediate, so ea or eax is probably an absolute address + // (unless it's aa if the immediate is small enough) + // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay' + x_check_immed: + // Check for aa (which is 6 bits zero extended) + if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG) + { + if (W == 1) + { + // It might be X:aa but we're not 100% sure yet. + // If it is, the only possible syntax here is 'X:aa,D'. + // So check ahead to see if EOL follows D, then we're good to go. + if (*tok == ',' && ((*(tok + 1) >= KW_X0 && *(tok + 1) <= KW_N7) || (*(tok + 1) >= KW_R0 && *(tok + 1) <= KW_R7) || (*(tok + 1) >= KW_A0 && *(tok + 1) <= KW_A2)) && *(tok + 2) == EOL) + { + // Yup, we're good to go - 'X:aa,D' it is + tok++; + immreg = SDreg(*tok++); + inst = inst | (uint32_t)dspImmedEXVAL; + inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8); + inst |= 1 << 7; // W + return inst; + } + } + else + { + if (*tok == EOL) + { + // 'S,X:aa' + inst = inst | (uint32_t)dspImmedEXVAL; + inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8); + return inst; + } + else + { + // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B', + // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay' + ea1 = DSP_EA_ABS; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + goto x_checkea_right; + } + } + } + } + + // Well, that settles it - we do have an ea in our hands + if (W == 1) + { + // 'X:ea,D' [... S2,d2] + if (*tok++ != ',') + return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'"); + if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) + { + D1 = SDreg(*tok++); + if (*tok == EOL) + { + // 'X:ea,D' + inst = inst | B8(01000000) | (1 << 7); + inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8); + inst |= ea1; + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + return inst; + } + else + { + // 'X:ea,D1 S2,D2' + if (*tok == KW_A || *tok == KW_B) + { + S2 = SDreg(*tok++); + if (*tok++ != ',') + return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2"); + if (*tok == KW_Y0 || *tok == KW_Y1) + { + D2 = SDreg(*tok++); + if (*tok != EOL) + return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2"); + inst = B16(00010000, 00000000) | (1 << 7); + inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10); + inst |= (S2 & 1) << 9; + inst |= (D2 & 1) << 8; + inst |= ea1; + return inst; + } + else + return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,"); + } + else + return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1"); + } + } + else + return error("unrecognised X: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'X:ea,'"); + } + else + { + if (*tok == EOL) + { + // 'S,X:ea' + inst = inst | B8(01000000) | (0 << 7); + inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8); + inst |= ea1; + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + return inst; + } + else + { + // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B', + // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay' + goto x_checkea_right; + } + } + + } + } + } + else + { + // It's not an immediate, check for '-(Rn)' + ea1 = checkea(termchar, X_ERRORS); + + if (ea1 == ERROR) + return ERROR; + + goto x_gotea1; + + } + } + else if (*tok == '#') + { + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + // Okay so we have immediate data - mark it down + ea1 = DSP_EA_IMM; + // Now, proceed to the main code for this branch + goto x_gotea1; + } + else if (*tok == '(') + { + // Maybe we got an expression here, check for it + if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING) + { + // Evaluate the expression and go to immediate code path + expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM); + goto x_check_immed; + } + + // Nope, let's check for ea then + ea1 = checkea(termchar, X_ERRORS); + if (ea1 == ERROR) + return ERROR; + + x_gotea1: + if (W == 1) + { + if (*tok++ != ',') + return error("Comma expected after 'X:(Rn)')"); + + // It might be 'X:(Rn..)..,D' but we're not 100% sure yet. + // If it is, the only possible syntax here is 'X:ea,D'. + // So check ahead to see if EOL follows D, then we're good to go. + if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL) + { + //'X:ea,D' + D1 = SDreg(*tok++); + + inst = inst | B8(01000000) | (1 << 7); + inst |= ea1; + inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8); + return inst; + } + } + else + { + if (*tok == EOL) + { + //'S,X:ea' + inst = inst | B8(01000000) | (0 << 7); + inst |= ea1; + inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8); + return inst; + } + else + { + goto x_checkea_right; + } + } + // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2' + // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2' + if ((*tok == KW_X0 || *tok == KW_X1 || *tok == KW_A || *tok == KW_B) && (*(tok + 1) == KW_A || *(tok + 1) == KW_B) && (*(tok + 2) == ',') && (*(tok + 3) == KW_Y0 || (*(tok + 3) == KW_Y1))) + { + // 'X:ea,D1 S2,D2' + // Check if D1 is x0, x1, a or b + switch (*tok++) + { + case KW_X0: D1 = 0 << 10; break; + case KW_X1: D1 = 1 << 10; break; + case KW_A: D1 = 2 << 10; break; + case KW_B: D1 = 3 << 10; break; + default: return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'"); + } + + switch (*tok++) + { + case KW_A: S2 = 0 << 9; break; + case KW_B: S2 = 1 << 9; break; + default: return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '"); + } + + if (*tok++ != ',') + return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'"); + + if (*tok == KW_Y0 || *tok == KW_Y1) + { + if (*tok++ == KW_Y0) + D2 = 0 << 8; + else + D2 = 1 << 8; + + if (*tok != EOL) + return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'"); + + inst = B16(00010000, 00000000) | (W << 7); + inst |= ea1 | D1 | S2 | D2; + return inst; + } + else + return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'"); + + } + + // Check to see if we got eax (which is a subset of ea) + if (check_for_x_y) + { + if ((inst = check_x_y(ea1, 0)) != 0) + return inst; + else + { + // Rewind pointer as it might be an expression and check for it + tok--; + if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK) + return ERROR; + // Yes, we have an expression, so we now check for + // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay' + goto x_check_immed; + } + } + } + else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + // Check for immediate address + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + + // We set ea1 here - if it's aa instead of ea + // then it won't be used anyway + ea1 = DSP_EA_ABS; + if (!(dspImmedEXATTR&DEFINED)) + { + force_imm = NUM_FORCE_LONG; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + } + + goto x_check_immed; + } + else if (*tok == '>') + { + // Check for immediate address forced long + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + if (dspImmedEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + force_imm = NUM_FORCE_LONG; + ea1 = DSP_EA_ABS; + goto x_check_immed; + } + else if (*tok == '<') + { + // Check for immediate address forced short + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + force_imm = NUM_FORCE_SHORT; + if (dspImmedEXATTR & DEFINED) + { + if (dspImmedEXVAL > 0x3f) + { + warn("short addressing mode forced but address is bigger than $3f - switching to long"); + force_imm = NUM_FORCE_LONG; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + ea1 = DSP_EA_ABS; + } + } + else + { + // This might end up as something like 'move Y:') + if (*tok == '-') + { + if (tok[1] == CONST || tok[1] == FCONST) + { + tok++; + dspImmedEXVAL = *tok++; + goto y_check_immed; + } + // This could be either -(Rn), -aa or -ea. Check for immediate first + if (*tok == SYMBOL || tok[1] == SYMBOL) + { + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK) + { + // Only check for aa if we have a defined number in our hands or we've + // been asked to use a short number format. The former case we'll just test + // it to see if it's small enough. The later - it's the programmer's call + // so he'd better have a small address or the fixups will bite him/her in the arse! + if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT) + { + // It's an immediate, so ea is probably an absolute address + // (unless it's aa if the immediate is small enough) + // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa' + y_check_immed: + // Check for aa (which is 6 bits zero extended) + if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG) + { + // It might be Y:aa but we're not 100% sure yet. + // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'. + // So check ahead to see if EOL follows D, then we're good to go. + if (*tok == EOL && S1 != 0) + { + // 'S,Y:aa' + inst = B16(01001000, 00000000); + inst |= dspImmedEXVAL; + inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8); + return inst; + } + if (*tok == ',' && ((*(tok + 1) >= KW_X0 && *(tok + 1) <= KW_N7) || (*(tok + 1) >= KW_R0 && *(tok + 1) <= KW_R7) || (*(tok + 1) >= KW_A0 && *(tok + 1) <= KW_A2)) && *(tok + 2) == EOL) + { + // Yup, we're good to go - 'Y:aa,D' it is + tok++; + immreg = SDreg(*tok++); + inst |= dspImmedEXVAL; + inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8); + return inst; + } + } + } + // Well, that settles it - we do have a ea in our hands + if (*tok == EOL && S1 != 0) + { + // 'S,Y:ea' + inst = B16(01001000, 01110000); + inst |= ea1; + inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8); + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + return inst; + } + if (*tok++ != ',') + return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'"); + if (D1 == 0 && S1 == 0) + { + // 'Y:ea,D' + if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) + { + D1 = SDreg(*tok++); + if (*tok != EOL) + return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'"); + inst |= B16(00000000, 01110000); + inst |= ea1; + inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8); + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + return inst; + } + else + return error("unrecognised Y: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'Y:ea,'"); + } + else + { + // 'S1,D1 Y:ea,D2' + if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1) + { + D2 = SDreg(*tok++); + inst |= ea1; + inst |= 1 << 7; + inst |= (S1 & 1) << 11; + inst |= (D1 & 1) << 10; + inst |= (D2 & 8) << (9 - 3); + inst |= (D2 & 1) << 8; + return inst; + } + else + return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'"); + } + } + else + return ERROR; + } + else + { + // It's not an immediate, check for '-(Rn)' + ea1 = checkea(',', Y_ERRORS); + + if (ea1 == ERROR) + return ERROR; + + goto y_gotea1; + + } + } + else if (*tok == '#') + { + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + // Okay so we have immediate data - mark it down + ea1 = DSP_EA_IMM; + // Now, proceed to the main code for this branch + goto y_gotea1; + } + else if (*tok == '(') + { + // Maybe we got an expression here, check for it + if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING) + { + // Evaluate the expression and go to immediate code path + expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM); + goto y_check_immed; + } + + // Nope, let's check for ea then + if (S1 == 0 || (S1 != 0 && D1 != 0)) + ea1 = checkea(',', Y_ERRORS); + else + ea1 = checkea(EOL, Y_ERRORS); + + if (ea1 == ERROR) + return ERROR; + + y_gotea1: + if (S1 != 0 && *tok == EOL) + { + // 'S,Y:ea' + inst = B16(01001000, 01000000); + inst |= ea1; + inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8); + return inst; + } + else if (S1 != 0 && D1 != 0 && S2 == 0) + { + // 'S1,D1 Y:ea,D2' + switch (S1) + { + case 14: S1 = 0 << 11; break; // A + case 15: S1 = 1 << 11; break; // B + default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break; + } + switch (D1) + { + case 4: D1 = 0 << 10; break; // X0 + case 5: D1 = 1 << 10; break; // X1 + default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break; + } + if (*tok++ != ',') + return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'"); + switch (*tok++) + { + case KW_Y0: D2 = 0 << 8; break; + case KW_Y1: D2 = 1 << 8; break; + case KW_A: D2 = 2 << 8; break; + case KW_B: D2 = 3 << 8; break; + default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'"); + } + inst = B16(00010000, 11000000); + inst |= S1 | D1 | D2; + inst |= ea1; + return inst; + } + if (*tok++ != ',') + return error("Comma expected after 'Y:(Rn)')"); + // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet. + // If it is, the only possible syntax here is 'Y:ea,D'. + // So check ahead to see if EOL follows D, then we're good to go. + if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL) + { + //'Y:ea,D' + D1 = SDreg(*tok++); + inst |= B16(00000000, 01000000); + inst |= ea1; + inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8); + return inst; + } + } + else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + // Check for immediate address + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + + // Yes, we have an expression, so we now check for + // 'Y:ea,D' or 'Y:aa,D' + ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct + if (!(dspImmedEXATTR&DEFINED)) + { + force_imm = NUM_FORCE_LONG; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + } + + goto y_check_immed; + } + else if (*tok == '>') + { + // Check for immediate address forced long + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + if (dspImmedEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + force_imm = NUM_FORCE_LONG; + ea1 = DSP_EA_ABS; + goto y_check_immed; + } + else if (*tok == '<') + { + tok++; + if (S1 != 0 && D1 != 0) + { + // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea' + // there's no Y:aa mode here, so we'll force long + warn("forced short addressing in R:Y mode is not allowed - switching to long"); + + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + + ea1 = DSP_EA_ABS; + + force_imm = NUM_FORCE_LONG; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + goto y_check_immed; + } + else + { + // Check for immediate address forced short + ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct + + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + force_imm = NUM_FORCE_SHORT; + if (dspImmedEXATTR & DEFINED) + { + if (dspImmedEXVAL > 0xfff) + { + warn("short addressing mode forced but address is bigger than $fff - switching to long"); + ea1 = DSP_EA_ABS; + force_imm = NUM_FORCE_LONG; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + } + } + else + { + // This might end up as something like 'move Y:') + if (*tok == '-') + { + if (*tok == CONST || tok[1] == FCONST) + { + tok++; + dspImmedEXVAL = *tok++; + goto l_check_immed; + } + // This could be either -(Rn), -aa or -ea. Check for immediate first + // Maybe we got an expression here, check for it + if (*tok == SYMBOL || tok[1] == SYMBOL) + { + // Evaluate the expression and go to immediate code path + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK) + { + // Only check for aa if we have a defined number in our hands or we've + // been asked to use a short number format. The former case we'll just test + // it to see if it's small enough. The later - it's the programmer's call + // so he'd better have a small address or the fixups will bite him/her in the arse! + if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT) + { + // It's an immediate, so ea is probably an absolute address + // (unless it's aa if the immediate is small enough) + // 'L:ea,D' or 'L:aa,D' + l_check_immed: + // Check for aa (which is 6 bits zero extended) + if (*tok == EOL) + { + // 'S,L:aa' + if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG) + { + // 'S,L:aa' + if (S1 == KW_A) + S1 = 4; + else if (S1 == KW_B) + S1 = 5; + else + S1 &= 7; + + inst = B16(01000000, 00000000); + inst |= dspImmedEXVAL; + inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8); + return inst; + } + else + { + // 'S,L:ea' + if (S1 == KW_A) + S1 = 4; + else if (S1 == KW_B) + S1 = 5; + else + S1 &= 7; + + if (ea1 == DSP_EA_ABS) + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + inst |= B16(01000000, 01110000); + inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8); + inst |= ea1; + return inst; + } + + } + if (*tok++ != ',') + return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'"); + // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba) + if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B))) + return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'"); + + if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED)) + { + // 'L:aa,D' + l_aa: + immreg = *tok++; + if (immreg == KW_A) + immreg = 4; + else if (immreg == KW_B) + immreg = 5; + else + immreg &= 7; + + if (*tok != EOL) + return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D"); + + inst &= B16(11111111, 10111111); + inst |= dspImmedEXVAL; + inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8); + return inst; + } + } + + if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP) + { + // Hang on, we've got a L:= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL) + { + //'L:ea,D' + D1 = *tok++; + if (D1 == KW_A) + D1 = 4; + else if (D1 == KW_B) + D1 = 5; + else + D1 &= 7; + + inst |= ea1; + inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8); + return inst; + } + } + else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + // Check for immediate address + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + + // We set ea1 here - if it's aa instead of ea + // then it won't be used anyway + ea1 = DSP_EA_ABS; + if (!(dspImmedEXATTR & DEFINED)) + { + force_imm = NUM_FORCE_LONG; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + } + else if (dspImmedEXVAL > 0x3f) + { + // Definitely no aa material, so it's going to be a long + // Mark that we need to deposit an extra word + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + } + + // Yes, we have an expression, so we now check for + // 'L:ea,D' or 'L:aa,D' + goto l_check_immed; + } + else if (*tok == '>') + { + // Check for immediate address forced long + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + if (dspImmedEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + force_imm = NUM_FORCE_LONG; + goto l_check_immed; + } + else if (*tok == '<') + { + // Check for immediate address forced short + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + { + if (dspImmedEXVAL > 0xfff) + return error("short addressing mode forced but address is bigger than $fff"); + } + else + { + // This might end up as something like 'move Y:= KW_R0 && *tok <= KW_R7) + { + // We got '-(Rn' so mark it down + ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0); + if (*tok++ != ')') + return error(ea_errors[strings][1]); + // Now, proceed to the main code for this branch + return ea; + } + else + return error(ea_errors[strings][2]); + } + else if (*tok == '(') + { + // Checking for ea of type (Rn) + tok++; + if (*tok >= KW_R0 && *tok <= KW_R7) + { + // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay' + ea = *tok++ - KW_R0; + if (*tok == '+') + { + // '(Rn+Nn)' + tok++; + if (*tok < KW_N0 || *tok > KW_N7) + return error(ea_errors[strings][3]); + if ((*tok++ & 7) != ea) + return error(ea_errors[strings][4]); + ea |= DSP_EA_INDEX; + if (*tok++ != ')') + return error(ea_errors[strings][5]); + return ea; + } + else if (*tok == ')') + { + // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)' + tok++; + if (*tok == '+') + { + tok++; + if (termchar == ',') + { + if (*tok == ',') + { + // (Rn)+ + ea |= DSP_EA_POSTINC1; + return ea; + } + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)+Nn + if ((*tok++ & 7) != ea) + return error(ea_errors[strings][6]); + ea |= DSP_EA_POSTINC; + return ea; + } + else + return error(ea_errors[strings][7]); + } + else + { + if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)+Nn + if ((*tok++ & 7) != ea) + return error(ea_errors[strings][6]); + ea |= DSP_EA_POSTINC; + return ea; + } + else + { + // (Rn)+ + ea |= DSP_EA_POSTINC1; + return ea; + } + } + } + else if (*tok == '-') + { + tok++; + if (termchar == ',') + { + if (*tok == ',') + { + // (Rn)- + ea |= DSP_EA_POSTDEC1; + return ea; + } + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)-Nn + if ((*tok++ & 7) != ea) + return error(ea_errors[strings][8]); + ea |= DSP_EA_POSTDEC; + return ea; + } + else + return error(ea_errors[strings][9]); + } + else + { + if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)-Nn + if ((*tok++ & 7) != ea) + return error(ea_errors[strings][8]); + ea |= DSP_EA_POSTDEC; + return ea; + } + else + { + // (Rn)- + ea |= DSP_EA_POSTDEC1; + return ea; + } + } + } + else if (termchar == ',') + { + if (*tok == ',') + { + // (Rn) + ea |= DSP_EA_NOUPD; + return ea; + } + else + return error(ea_errors[strings][10]); + } + else + { + // (Rn) + ea |= DSP_EA_NOUPD; + return ea; + } + } + else + return error(ea_errors[strings][11]); + } + } + return error("internal assembler error: Please report this error message: 'reached the end of checkea' with the line of code that caused it. Thanks, and sorry for the inconvenience"); +} + + +// +// Checks for all ea cases, i.e. all addressing modes that checkea handles +// plus immediate addresses included forced short/long ones. +// In other words this is a superset of checkea (and in fact calls checkea). +// +LONG checkea_full(const uint32_t termchar, const int strings) +{ + LONG ea1; + + if (*tok == CONST || *tok == FCONST || *tok == SYMBOL) + { + // Check for immediate address + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + // Yes, we have an expression + return DSP_EA_ABS; + } + else if (*tok == '>') + { + // Check for immediate address forced long + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + if (dspImmedEXVAL > 0xffffff) + return error("long address is bigger than $ffffff"); + + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + + // Yes, we have an expression + return DSP_EA_ABS; + } + else if (*tok == '<') + { + // Check for immediate address forced short + tok++; + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + if (dspImmedEXVAL > 0xfff) + return error("short addressing mode forced but address is bigger than $fff"); + + // Yes, we have an expression + return DSP_EA_ABS; + } + else + { + ea1 = checkea(termchar, strings); + if (ea1 == ERROR) + return ERROR; + else + return ea1; + } + +} + +// +// Main routine to check parallel move modes. +// It's quite complex so it's split into a few procedures (in fact most of the above ones). +// A big effort was made so this can be managable and not too hacky, however one look at +// the 56001 manual regarding parallel moves and you'll know that this is not an easy +// problem to deal with! +// dest=destination register from the main opcode. This must not be the same as D1 or D2 +// and that even goes for stuff like dest=A, D1=A0/1/2!!! +// +LONG parmoves(WORD dest) +{ + int force_imm; // Addressing mode force operator + int immreg; // Immediate register destination + LONG inst; // 16 bit bitfield that has the parallel move opcode + LONG S1, S2, D1, D2; // Source and Destinations + LONG ea1; // ea bitfields + + if (*tok == EOL) + { + // No parallel move + return B16(00100000, 00000000); + } + if (*tok == '#') + { + // '#xxxxxx,D', '#xx,D' + tok++; + force_imm = NUM_NORMAL; + if (*tok == '>') + { + force_imm = NUM_FORCE_LONG; + tok++; + } + else if (*tok == '<') + { + force_imm = NUM_FORCE_SHORT; + tok++; + } + + if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK) + return ERROR; + + if (*tok++ != ',') + return error("expected comma"); + + if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))) + return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate"); + immreg = SDreg(*tok++); + + if (*tok == EOL) + { + if (!(dspImmedEXATTR & FLOAT)) + { + if (dspImmedEXATTR & DEFINED) + { + // From I parallel move: + // "If the destination register D is X0, X1, Y0, Y1, A, or B, the 8-bit immediate short operand + // is interpreted as a signed fraction and is stored in the specified destination register. + // That is, the 8 - bit data is stored in the eight MS bits of the destination operand, and the + // remaining bits of the destination operand D are zeroed." + // The funny bit is that Motorola assembler can parse something like 'move #$FF0000,b' into an + // I (immediate short move) - so let's do that as well then... + if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG) + { + if ((dspImmedEXVAL & 0xffff) == 0) + { + dspImmedEXVAL >>= 16; + } + } + if (force_imm == NUM_FORCE_SHORT) + { + if (dspImmedEXVAL<0xff && (int32_t)dspImmedEXVAL>-0x100) + { + // '#xx,D' + // value fits in 8 bits - immediate move + inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL; + return inst; + } + else + { + warn("forced short immediate value doesn't fit in 8 bits - switching to long"); + force_imm = NUM_FORCE_LONG; + } + } + if (force_imm == NUM_FORCE_LONG) + { + // '#xxxxxx,D' + // it can either be + // X or Y Data move. I don't think it matters much + // which of the two it will be, so let's use X. + deposit_immediate_long_with_register: + inst = B16(01000000, 11110100); + inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8); + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + return inst; + } + if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100)) + { + // value fits in 8 bits - immediate move + deposit_immediate_short_with_register: + inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL; + return inst; + } + else + { + // value doesn't fit in 8 bits, so it can either be + // X or Y Data move. I don't think it matters much + // which of the two it will be, so let's use X:. + // TODO: if we're just goto'ing perhaps the logic can be simplified + goto deposit_immediate_long_with_register; + } + } + else + { + if (force_imm != NUM_FORCE_SHORT) + { + // '#xxxxxx,D' + // TODO: if we're just goto'ing perhaps the logic can be simplified + goto deposit_immediate_long_with_register; + } + else + { + // '#xx,D' - I mode + // No visibility of the number so let's add a fixup for this + AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR); + inst = B16(00100000, 00000000); + inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8); + return inst; + } + + } + } + else + { + // Float constant + if (dspImmedEXATTR & DEFINED) + { + + double f = *(double *)&dspImmedEXVAL; + // Check direct.c for ossom comments regarding conversion! + dspImmedEXVAL = ((uint32_t)(int32_t)round(f*(1 << 23))) & 0xffffff; + double g; + g = f*(1 << 23); + g = round(g); + + if ((dspImmedEXVAL & 0xffff) == 0) + { + // Value's 16 lower bits are not set so the value can fit in a single byte + // (check parallel I move quoted above) + warn("Immediate value fits inside 8 bits, so using instruction short format"); + dspImmedEXVAL >>= 16; + goto deposit_immediate_short_with_register; + } + + if (force_imm == NUM_FORCE_SHORT) + { + if ((dspImmedEXVAL & 0xffff) != 0) + { + warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format"); + goto deposit_immediate_long_with_register; + } + return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!"); + } + // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long. + goto deposit_immediate_long_with_register; + } + else + { + if (force_imm == NUM_FORCE_SHORT) + { + goto deposit_immediate_short_with_register; + } + else + { + // Just deposit a float fixup + AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR); + inst = B16(00100000, 00000000); + inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8); + return inst; + } + } + } + } + else + { + // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I) + + switch (immreg) + { + case 4: D1 = 0 << 10;break; // X0 + case 5: D1 = 1 << 10;break; // X1 + case 14: D1 = 2 << 10;break; // A + case 15: D1 = 3 << 10;break; // B + default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break; + } + + switch (*tok++) + { + case KW_A: S2 = 0 << 9; break; + case KW_B: S2 = 1 << 9; break; + default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break; + } + + if (*tok++ != ',') + return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'"); + + switch (*tok++) + { + case KW_Y0: D2 = 0 << 8; break; + case KW_Y1: D2 = 1 << 8; break; + default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break; + } + + if (*tok != EOL) + return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'"); + + inst = B16(00010000, 10110100) | D1 | S2 | D2; + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + return inst; + } + } + else if (*tok == KW_X) + { + if (tok[1] == ',') + // Hey look, it's just the register X and not the addressing mode - fall through to general case + goto parse_everything_else; + + tok++; + + if (*tok++ != ':') + return error("expected ':' after 'X' in parallel move (i.e. X:)"); + + // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay' + return parse_x(1, B16(01000000, 00000000), 0, 1); + } + else if (*tok == KW_Y) + { + if (tok[1] == ',') + // Hey look, it's just the register y and not the addressing mode - fall through to general case + goto parse_everything_else; + + tok++; + if (*tok++ != ':') + return error("expected ':' after 'Y' in parallel move (i.e. Y:)"); + + // 'Y:ea,D' or 'Y:aa,D' + return parse_y(B16(01001000, 10000000), 0, 0, 0); + } + else if (*tok == KW_L) + { + // 'L:ea,D' or 'L:aa,D' + tok++; + if (*tok++ != ':') + return error("expected ':' after 'L' in parallel move (i.e. L:)"); + + return parse_l(1, B16(01000000, 11000000), 0); + } + else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2) || (*tok >= KW_A10 && *tok <= KW_BA)) + { + // Everything else - brace for impact! + // R: 'S,D' + // X: 'S,X:ea' 'S,X:aa' + // X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B' + // Y: 'S,Y:ea' 'S,Y:aa' + // R:Y: 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 #xxxxxx,D2' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' + // L: 'S,L:ea' 'S,L:aa' + LONG L_S1; +parse_everything_else: + L_S1 = *tok++; + S1 = SDreg(L_S1); + + if (*tok++ != ',') + return error("Comma expected after 'S')"); + + if (*tok == KW_X) + { + // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay' + // 'A,X:ea X0,A' 'B,X:ea X0,B' + tok++; + if (*tok++ != ':') + return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'"); + return parse_x(0, B16(01000000, 00000000), S1, 1); + } + else if (*tok == KW_Y) + { + // 'S,Y:ea' 'S,Y:aa' + tok++; + if (*tok++ != ':') + return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'"); + return parse_y(B16(0000000, 00000000), S1, 0, 0); + } + else if (*tok == KW_L) + { + // 'S,L:ea' 'S,L:aa' + tok++; + if (*tok++ != ':') + return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'"); + return parse_l(1, B16(00000000, 00000000), L_S1); + } + else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) + { + // 'S,D' + // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2' + // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' + D1 = SDreg(*tok++); + if (*tok == EOL) + { + // R 'S,D' + inst = B16(00100000, 00000000); + inst |= (S1 << 5) | (D1); + return inst; + } + else if (*tok == KW_Y) + { + // 'S1,D1 Y:ea,D2' + tok++; + if (*tok++ != ':') + return error("expected ':' after 'Y' in parallel move (i.e. Y:)"); + return parse_y(B16(00010000, 01000000), S1, D1, 0); + + } + else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1) + { + // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea' + S2 = SDreg(*tok++); + if (S1 == 6 && D1 == 14 && S2 == 14) + { + // 'Y0,A A,Y:ea' + if (*tok++ != ',') + return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A"); + if (*tok++ != KW_Y) + return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,"); + if (*tok++ != ':') + return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y"); + ea1 = checkea_full(EOL, Y_ERRORS); + if (ea1 == ERROR) + return ERROR; + inst = B16(00001000, 10000000); + inst |= 0 << 8; + inst |= ea1; + return inst; + } + else if (S1 == 6 && D1 == 15 && S2 == 15) + { + // 'Y0,B B,Y:ea' + if (*tok++ != ',') + return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B"); + if (*tok++ != KW_Y) + return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,"); + if (*tok++ != ':') + return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y"); + ea1 = checkea_full(EOL, Y_ERRORS); + if (ea1 == ERROR) + return ERROR; + inst = B16(00001000, 10000000); + inst |= 1 << 8; + inst |= ea1; + return inst; + } + else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15)) + { + //'S1,D1 S2,Y:ea' + if (*tok++ != ',') + return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2"); + if (*tok++ != KW_Y) + return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,"); + if (*tok++ != ':') + return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y"); + ea1 = checkea_full(EOL, Y_ERRORS); + if (ea1 == ERROR) + return ERROR; + inst = B16(00010000, 01000000); + inst |= (S1 & 1) << 11; + inst |= (D1 & 1) << 10; + inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8); + inst |= ea1; + return inst; + } + else + return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'"); + // Check for Y: + } + else if (*tok == '#') + { + // R:Y: 'S1,D1 #xxxxxx,D2' + tok++; + if (*tok == '>') + { + // Well, forcing an immediate to be 24 bits is legal here + // but then it's the only available option so my guess is that this + // is simply superfluous. So let's just eat the character + tok++; + } + if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK) + return ERROR; + if (dspImmedEXATTR & DEFINED) + if (dspImmedEXVAL > 0xffffff) + return error("immediate is bigger than $ffffff"); + deposit_extra_ea = DEPOSIT_EXTRA_WORD; + if (*tok++ != ',') + return error("Comma expected after 'S1,D1 #xxxxxx')"); + // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b + switch (*tok++) + { + case KW_Y0: D2 = 0 << 8; break; + case KW_Y1: D2 = 1 << 8; break; + case KW_A: D2 = 2 << 8; break; + case KW_B: D2 = 3 << 8; break; + default: return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'"); + } + + if (S1 == 14 || S1 == 15) + { + if (D1 == 4 || D1 == 5) + { + inst = B16(00010000, 11110100); + inst |= (S1 & 1) << 11; + inst |= (D1 & 1) << 10; + inst |= D2; + dspImmedEXVAL = dspaaEXVAL; + return inst; + } + else + return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'"); + } + else + return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'"); + } + else + return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'"); + } + else + return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'"); + } + else if (*tok == '(') + { + // U: 'ea' + // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+' + tok++; + if (*tok >= KW_R0 && *tok <= KW_R7) + { + ea1 = (*tok++ - KW_R0); + } + else + return error("unrecognised U parallel move syntax: expected 'Rn' after '('"); + if (*tok++ != ')') + return error("unrecognised U parallel move syntax: expected ')' after '(Rn'"); + if (*tok == '+') + { + tok++; + if (*tok == EOL) + // (Rn)+ + ea1 |= 3 << 3; + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)+Nn + if ((*tok++ & 7) != ea1) + return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')"); + ea1 |= 1 << 3; + if (*tok != EOL) + return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'"); + } + else + return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'"); + + } + else if (*tok == '-') + { + tok++; + if (*tok == EOL) + { + // (Rn)- + ea1 |= 2 << 3; + tok++; + } + else if (*tok >= KW_N0 && *tok <= KW_N7) + { + // (Rn)-Nn + if ((*tok++ & 7) != ea1) + return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')"); + ea1 |= 0 << 3; + if (*tok != EOL) + return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'"); + } + } + + inst = B16(00100000, 01000000); + inst |= ea1; + return inst; + } + else + return error("extra (unexpected) text found"); + + return OK; +} + diff --git a/dsp56k_amode.h b/dsp56k_amode.h new file mode 100644 index 0000000..03ae962 --- /dev/null +++ b/dsp56k_amode.h @@ -0,0 +1,149 @@ +// +// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// DSP56K_AMODE.H - Addressing Modes for Motorola DSP56001 +// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#ifndef __DSP56K_AMODE_H__ +#define __DSP56K_AMODE_H__ + +#include "rmac.h" +#include "amode.h" + +// Addressing-mode masks + +#define M_ACC56 0x00000001L // Accumulators A=A2:A1:A0 and B=B2:B1:B0 +#define M_ACC48 0x00000002L // Accumulators AB=A1:B1, BA=B1:A1, A10=A1:A0, B10=B1:B0 +#define M_ACC24 0x00000004L // Accumulators A0, A1, B0 and B1 +#define M_ACC8 0x00000008L // Accumulators A2 and B2 +#define M_INP48 0x00000010L // Input registers X=X1:X0 and Y=Y1:Y0 +#define M_ALU24 0x00000020L // Data ALU input registers X1, X0, Y1, Y0 +#define M_DSPIM 0x00000040L // #data +#define M_DSPIM12 0x00000080L // #data +//#define M_DSPIM24 0x0000010 // #data +#define M_DSPPCU 0x00000200L // Program control unit registers PC, MR, CCR, SR, OMR, LA, LC, SP, SS, SSH, SSL +#define M_DSPEA 0x00000400L // Effective addressing modes (Rn)-Nn, (Rn)+Nn, (Rn)-, (Rn)+, (Rn), (Rn+Nn), -(Rn), +#define M_DSPAA 0x00000800L // 6-bit Absolute Short Address +#define M_DSPPP 0x00001000L // 6-bit I/O Short Address +#define M_DSPM 0x00002000L // Modifier registers M0-M7 +#define M_DSPR 0x00004000L // Address registers R0-R7 +#define M_DSPN 0x00008000L // Address offset registers N0-N7 +#define M_DSPABS12 0x00010000L // xxx.12bit +#define M_DSPABS24 0x00020000L // xxx.24bit +#define M_DSPABS06 0x00040000L // xxx.6bit +#define M_DSPABS16 0x00080000L // xxx.16bit +#define M_DSPIM8 0x00100000L // #data + +#define M_ALL48 (M_ACC56|M_INP48|M_ALU24) // Input registers X=X1:X0, Y=Y1:Y0, A=A2:A1:A0, B=B2:B1:B0, X0, X1, Y0, Y1 + +#define C_DD (M_ALU24) // 4 registers in data ALU: x0, x1, y0, y1 +#define C_DDD (M_ACC56|M_ACC24|M_ACC8) // 8 accumulators in data ALU: a0, b0, a2, b2, a1, b1, a, b +#define C_LLL (M_ACC56|M_ACC48|M_INP48) // 8 extended-precision registers in data ALU: a10, b10, x, y, a, b, ab, ba +#define C_FFF (M_DSPM) // 8 address modifier registers in address ALU: m0-m7 +#define C_NNN (M_DSPN) // 8 address offset registers in address ALU: n0-n7 +#define C_TTT (M_DSPR) // 8 address registers in address: r0-r7 +#define C_GGG (M_DSPPCU) // 8 program controller registers: sr, omr, sp, ssh, la, lc +#define C_A18 (M_ALU24|C_DDD|C_LLL|C_FFF|C_NNN|C_TTT|C_GGG) // All of the above registers + +#define C_DSPABS24 (M_DSPABS06|M_DSPABS12|M_DSPABS16|M_DSPABS24) // Everything up to 24-bit addresses +#define C_DSPABSEA (C_DSPABS24|M_DSPEA) // All absolute addresses and all other ea addressing modes +#define C_DSPABS16 (M_DSPABS06|M_DSPABS12|M_DSPABS16) // Everything up to 16-bit addresses +#define C_LUADST (M_DSPR|M_DSPN) // Mask for LUA instruction destination +#define C_MOVEC (M_DSPM|M_DSPPCU) // M0-M7 and SR, OMR, LA, LC, SP, SS, SSH, SSL +#define C_DSPIM (M_DSPIM8 | M_DSPIM | M_DSPIM12) // All the immmediate sizes we want to alias + +// Xn Input Register X1 or X0 (24 Bits) +// Yn Input Register Y1 or Y0 (24 Bits) +// An Accumulator Registers A2, A1, A0 (A2 — 8 Bits, A1 and A0 — 24 Bits) +// Bn Accumulator Registers B2, B1, B0 (B2 — 8 Bits, B1 and B0 — 24 Bits) +// X Input Register X = X1: X0 (48 Bits) +// Y Input Register Y = Y1: Y0 (48 Bits) +// A Accumulator A = A2: A1: A0 (56 Bits)* +// B Accumulator B = B2: B1: B0 (56 BIts)* +// AB Accumulators A and B = A1: B1 (48 Bits)* +// BA Accumulators B and A = B1: A1 (48 Bits)* +// A10 Accumulator A = A1: A0 (48 Bits) +// B10 Accumulator B= B1:B0 (48 bits) + +// Attribute masks +#define PARMOVE 0x00000001L +#define NOPARMO 0x00000000L + +// DSP EA modes + +#define DSP_EA_POSTDEC B8(00000000) +#define DSP_EA_POSTINC B8(00001000) +#define DSP_EA_POSTDEC1 B8(00010000) +#define DSP_EA_POSTINC1 B8(00011000) +#define DSP_EA_NOUPD B8(00100000) +#define DSP_EA_INDEX B8(00101000) +#define DSP_EA_PREDEC1 B8(00111000) +#define DSP_EA_ABS B8(00110000) +#define DSP_EA_IMM B8(00110100) + + +// Mnemonic table structure +#define MNTABDSP struct _mntabdsp +MNTABDSP { + LONG mn0, mn1; // Addressing modes + WORD mnattr; // Attributes (PARMOVE, ...) + LONG mninst; // Instruction mask + WORD mncont; // Continuation (or -1) + int (* mnfunc)(LONG); // Mnemonic builder +}; + +// Addressing mode variables, output of dsp_amode() +int dsp_am0; // Addressing mode +int dsp_a0reg; // Register +int dsp_am1; // Addressing mode +int dsp_a1reg; // Register +int dsp_am2; // Addressing mode +int dsp_a2reg; // Register +int dsp_am3; // Addressing mode +int dsp_a3reg; // Register + +TOKEN dsp_a0expr[EXPRSIZE]; // Expression +uint64_t dsp_a0exval; // Expression's value +WORD dsp_a0exattr; // Expression's attribute +SYM * dsp_a0esym; // External symbol involved in expr +LONG dsp_a0memspace; // Addressing mode's memory space (P, X, Y) +LONG dsp_a0perspace; // Peripheral space (X, Y - used in movep) +TOKEN dsp_a1expr[EXPRSIZE]; // Expression +uint64_t dsp_a1exval; // Expression's value +WORD dsp_a1exattr; // Expression's attribute +SYM * dsp_a1esym; // External symbol involved in expr +LONG dsp_a1memspace; // Addressing mode's memory space (P, X, Y) +LONG dsp_a1perspace; // Peripheral space (X, Y - used in movep) +TOKEN dsp_a2expr[EXPRSIZE]; // Expression +uint64_t dsp_a2exval; // Expression's value +WORD dsp_a2exattr; // Expression's attribute +SYM * dsp_a2esym; // External symbol involved in expr +TOKEN dsp_a3expr[EXPRSIZE]; // Expression +uint64_t dsp_a3exval; // Expression's value +WORD dsp_a3exattr; // Expression's attribute +SYM * dsp_a3esym; // External symbol involved in expr +int dsp_k; // Multiplications sign +TOKEN dspImmedEXPR[EXPRSIZE]; // Expression +uint64_t dspImmedEXVAL; // Expression's value +WORD dspImmedEXATTR; // Expression's attribute +SYM * dspImmedESYM; // External symbol involved in expr +int deposit_extra_ea; // Optional effective address extension + + +// Extra ea deposit modes +enum +{ + DEPOSIT_EXTRA_WORD = 1, + DEPOSIT_EXTRA_FIXUP = 2, +}; + + +// Prototypes +int dsp_amode(int maxea); +LONG parmoves(WORD dest); +int dsp_tcc4(LONG inst); + +#endif // __DSP56K_AMODE_H__ + diff --git a/dsp56k_mach.c b/dsp56k_mach.c new file mode 100644 index 0000000..20fc07a --- /dev/null +++ b/dsp56k_mach.c @@ -0,0 +1,1460 @@ +// +// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// DSP56L_MACH.C - Code Generation for Motorola DSP56001 +// Copyright (C) 199x Landon Dyer, 2011-2018 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#include "dsp56k_mach.h" +#include "direct.h" +#include "dsp56k.h" +#include "error.h" +#include "rmac.h" +#include "sect.h" +#include "token.h" + +#define DEF_KW +#include "kwtab.h" + + +// Globals +unsigned int dsp_orgaddr; // DSP 56001 ORG address +unsigned int dsp_orgseg; // DSP 56001 ORG segment + + +// Fucntion prototypes +int m_unimp(WORD, WORD), m_badmode(WORD, WORD); +int dsp_ab(LONG); +int dsp_baab(LONG inst); +int dsp_acc48(LONG inst); +int dsp_self(LONG inst); +int dsp_xyab(LONG inst); +int dsp_x0y0ab(LONG inst); +int dsp_immcr(LONG inst); +int dsp_immmovec(LONG inst); +int dsp_imm12(LONG inst); +int dsp_tcc2(LONG inst); +int dsp_tcc4(LONG inst); +int dsp_ea(LONG inst); +int dsp_ea_imm5(LONG inst); +int dsp_abs12(LONG inst); +int dsp_reg_imm5(LONG inst); +int dsp_ea_abs16(LONG inst); +int dsp_reg_abs16(LONG inst); +int dsp_imm12_abs16(LONG inst); +int dsp_alu24_abs16(LONG inst); +int dsp_reg(LONG inst); +int dsp_alu24(LONG inst); +int dsp_reg_imm5_abs16(LONG inst); +int dsp_ea_imm5_abs16(LONG inst); +int dsp_ea_lua(LONG inst); +int dsp_ab_rn(LONG inst); +int dsp_movec_ea(LONG inst); +int dsp_movec_aa(LONG inst); +int dsp_movec_reg(LONG inst); +int dsp_mult(LONG inst); +int dsp_movem_ea(LONG inst); +int dsp_movem_aa(LONG inst); +int dsp_movep_ea(LONG inst); +int dsp_movep_reg(LONG inst); + + +// Common error messages + + +// Include code tables +MNTABDSP dsp56k_machtab[] = { + { 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0x0000, 0, (int (*)(LONG))m_badmode }, // 0 + #include "dsp56ktab.h" + { 0L, 0L, 0x0000, 0x0000, 0, (int (*)(LONG))m_unimp } // Last entry +}; + + +static inline int dsp_extra_ea() +{ + if (deposit_extra_ea == DEPOSIT_EXTRA_WORD) + { + if (!(dspImmedEXATTR&FLOAT)) + { + if (dspImmedEXATTR & DEFINED) + { + D_dsp(dspImmedEXVAL); + } + else + { + // TODO: what if it's an address and not an immediate? Does it matter at all? + AddFixup(FU_DSPIMM24, sloc, dspImmedEXPR); + D_dsp(0); + } + } + else + { + if (dspImmedEXATTR & DEFINED) + { + D_dsp(dspImmedEXVAL); + } + else + { + // TODO: what if it's an address and not an immediate? Does it matter at all? + AddFixup(FU_DSPIMMFL24, sloc, dspImmedEXPR); + D_dsp(0); + } + } + } + else if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP) + { + // Probably superfluous check (we're not likely to land here with a + // known aa) but oh well + if (!(dspImmedEXATTR & DEFINED)) + { + // Since we already deposited the word to be fixup'd we need to + // subtract 1 from sloc + chptr -= 3; + AddFixup(FU_DSPADR06, sloc - 1, dspImmedEXPR); + chptr += 3; + } + } + + return OK; +} + + +int dsp_ab(LONG inst) +{ + inst |= (dsp_a0reg & 1) << 3; + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + return OK; +} + + +int dsp_baab(LONG inst) +{ + if (dsp_a0reg == dsp_a1reg) + return error("source and destination registers must not be the same"); + + inst |= ((dsp_a0reg + 1) & 1) << 3; + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + + return OK; +} + + +int dsp_acc48(LONG inst) +{ + if (dsp_a0reg == dsp_a1reg) + return error("source and destination registers must not be the same"); + + inst |= (dsp_a1reg & 1) << 3; + + switch (dsp_a0reg) + { + case KW_X: inst |= 2 << 4; break; + case KW_Y: inst |= 3 << 4; break; + case KW_X0: inst |= 4 << 4;break; + case KW_Y0: inst |= 5 << 4;break; + case KW_X1: inst |= 6 << 4;break; + case KW_Y1: inst |= 7 << 4;break; + default: return error("dsp_acc48: shouldn't reach here!"); + } + + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + + return OK; +} + + +int dsp_self(LONG inst) +{ + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + + return OK; +} + + +int dsp_xyab(LONG inst) +{ + if (dsp_a0reg == dsp_a1reg) + return error("source and destination registers must not be the same"); + + inst |= (dsp_a0reg & 1) << 4; + inst |= (dsp_a1reg & 1) << 3; + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + + return OK; +} + + +int dsp_x0y0ab(LONG inst) +{ + if (dsp_a0reg == dsp_a1reg) + return error("source and destination registers must not be the same"); + + int inverse = (dsp_a0reg & 3); + inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1); + inst |= inverse << 4; + inst |= (dsp_a1reg & 1) << 3; + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + + return OK; +} + + +int dsp_immcr(LONG inst) +{ + switch (dsp_a1reg) + { + case KW_CCR: inst |= 1; break; + case KW_MR:inst |= 0; break; + case KW_OMR:inst |= 2; break; + default: return error("invalid destination register (only ccr, mr, omr allowed"); + } + + if (dsp_a0exattr & DEFINED) + { + inst |= dsp_a0exval << 8; + D_dsp(inst); + } + else + { + AddFixup(FU_DSPIMM8, sloc, dsp_a0expr); + D_dsp(inst); + } + + return OK; +} + + +int dsp_immmovec(LONG inst) +{ + switch (dsp_a1reg) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: inst |= dsp_a1reg; break; // M0-M7 + case KW_SR: inst |= 25; break; + case KW_OMR: inst |= 26; break; + case KW_SP: inst |= 27; break; + case KW_SSH: inst |= 28; break; + case KW_SSL: inst |= 29; break; + case KW_LA: inst |= 30; break; + case KW_LC: inst |= 31; break; + default: return error("invalid destination register (only m0-m7, SR, OMR, SP, SSH, SSL, LA, LC allowed"); + } + + if (dsp_a0exattr & DEFINED) + { + inst |= (dsp_a0exval & 0xff) << 8; + D_dsp(inst); + } + else + { + AddFixup(FU_DSPIMM8, sloc, dsp_a0expr); + D_dsp(inst); + } + + return OK; +} + + +int dsp_imm12(LONG inst) +{ + if (dsp_a0exattr & DEFINED) + { + if ((dsp_am0 & (M_DSPIM12 | M_DSPIM8)) == 0) + return error("immediate out of range ($000-$fff)"); + inst |= ((dsp_a0exval & 0x0ff) << 8) | ((dsp_a0exval & 0xf00) >> 8); + D_dsp(inst); + } + else + { + AddFixup(FU_DSPIMM12, sloc, dsp_a0expr); + D_dsp(inst); + } + + return OK; +} + + +// Tcc instructions with 2 operands (48bit) +int dsp_tcc2(LONG inst) +{ + if (dsp_a0reg == dsp_a1reg) + return error("First pair of source and destination registers must not be the same"); + + int inverse; + inverse = (dsp_a0reg & 7); + inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1) | (inverse & 4); + inst |= inverse << 4; + inst |= ((dsp_a1reg) & 1) << 3; + D_dsp(inst); + + return OK; +} + + +// Tcc instructions with 4 operands +int dsp_tcc4(LONG inst) +{ + if (dsp_a0reg == dsp_a1reg) + return error("First pair of source and destination registers must not be the same"); + + if (dsp_am2 != M_DSPR || dsp_am3 != M_DSPR) + return error("Second pair of source and destination registers must be R0-R7"); + + if (dsp_am0 == M_ACC56 && dsp_am1 == M_ACC56) + { + inst |= ((dsp_a0reg + 1) & 1) << 3; + } + else + { + int inverse; + inverse = (dsp_a0reg & 7); + inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1) | (inverse & 4); + inst |= inverse << 4; + inst |= ((dsp_a1reg) & 1) << 3; + } + + inst |= 1 << 16; + inst |= (dsp_a2reg << 8) | (dsp_a3reg); + D_dsp(inst); + + return OK; +} + + +// Just store ea +int dsp_ea(LONG inst) +{ + inst |= dsp_a0reg << 8; + + if (dsp_a0memspace != -1) + inst |= dsp_a0memspace; + + if (dsp_am0 == M_DSPAA) + inst |= ((dsp_a0exval & 0x3f) << 8); + + D_dsp(inst); + + if (dsp_a0reg == DSP_EA_ABS) + { + if (dsp_a0exattr & DEFINED) + { + D_dsp(dsp_a0exval); + } + else + { + AddFixup(FU_DSPADR24, sloc, dsp_a0expr); + D_dsp(0); + } + } + + return OK; +} + + +// Store ea and 5-bit constant +int dsp_ea_imm5(LONG inst) +{ + if (dsp_a1memspace == -1) + return error("Only X: or Y: memory space allowed"); + + if (dsp_a0exattr & DEFINED) + { + int v = (int)dsp_a0exval; + + if (v < 0 || v > 23) + return error("immediate value must be between 0 and 23"); + + if (dsp_a1reg == DSP_EA_ABS) + { + inst |= (v | dsp_a1memspace | (dsp_a1reg << 8)); + } + else + { + inst |= ((dsp_a1exval & 0x3F) << 8) | v | dsp_a1memspace | (dsp_a1reg << 8); + } + + D_dsp(inst); + + if (dsp_a1reg == DSP_EA_ABS) + { + if (dsp_a1exattr & DEFINED) + { + D_dsp(dsp_a1exval); + } + else + { + AddFixup(FU_DSPADR24, sloc, dsp_a1expr); + D_dsp(0); + } + } + } + else + { + if (dsp_a1reg == DSP_EA_ABS) + { + inst |= dsp_a1memspace | (dsp_a1reg << 8); + } + else + { + inst |= ((dsp_a1exval & 0x3F) << 8) | dsp_a1memspace | (dsp_a1reg << 8); + } + + AddFixup(FU_DSPIMM5, sloc, dsp_a0expr); + D_dsp(inst); + + if (dsp_a1reg == DSP_EA_ABS) + { + if (dsp_a1exattr & DEFINED) + { + D_dsp(dsp_a1exval); + } + else + { + AddFixup(FU_DSPADR24, sloc, dsp_a1expr); + D_dsp(0); + } + } + } + + return OK; +} + + +// Processes the input register according to table A-18 of the Motorola DSP +// manual and returns the correct encoding. +// Note: returns only the 3 lower bits of the table. The rest is handled in +// dsp56ktab. +static inline LONG tab_A18(int *am, int *reg) +{ + switch (*am) + { + case M_ALU24: + return (*reg & 7); + case M_DSPM: + case M_DSPN: + case M_DSPR: + return *reg; + break; + case M_ACC56: + case M_ACC24: + case M_ACC8: + if (*reg == KW_A1) + return 4; + else + return (*reg & 7); + + break; + case M_DSPPCU: + switch (*reg) + { + case KW_SR: return 1; break; + case KW_OMR: return 2; break; + case KW_SP: return 3; break; + case KW_SSH: return 4; break; + case KW_SSL: return 5; break; + case KW_LA: return 6; break; + case KW_LC: return 7; break; + default: + return error("specified control register not allowed as destination"); + break; + } + + break; + default: + return error("reached at the end of tab_A18 - shouldn't happen!"); + } +} + + +// Store register (table A-18 in the motorola manual) and 5-bit constant +int dsp_reg_imm5(LONG inst) +{ + LONG reg; + + if ((reg = tab_A18(&dsp_am1, &dsp_a1reg)) == ERROR) + return ERROR; + + inst |= (reg << 8); + + if (dsp_a0exattr & DEFINED) + { + int v = (int)dsp_a0exval; + + if (v < 0 || v > 23) + return error("immediate value must be between 0 and 23"); + + inst |= v; + D_dsp(inst); + } + else + { + AddFixup(FU_DSPIMM5, sloc, dsp_a0expr); + D_dsp(inst); + } + + return OK; +} + + +// Store 12-bit address +int dsp_abs12(LONG inst) +{ + if (dsp_a0exattr & DEFINED) + { + int v = (int)dsp_a0exval; + + if (v < 0 || v > 0xFFF) + return error("immediate out of range ($000-$FFF)"); + + inst |= v; + D_dsp(inst); + } + else + { + AddFixup(FU_DSPADR12, sloc, dsp_a0expr); + D_dsp(inst); + } + + return OK; +} + + +// Manipulate expr to append a '-1'. Used specifically for DO. +void append_minus_1(TOKEN * expr) +{ + // Find where the end of expression is + while (*expr != ENDEXPR) + { + if (*expr == SYMBOL || *expr == CONST || *expr == FCONST) + expr++; + else if (*expr == ACONST) + expr += 3; + + expr++; + } + + // Overwrite ENDEXPR and append '-1' + *expr++ = CONST; + uint64_t *expr64 = (uint64_t *)expr; + *expr64++ = 1; + expr = (uint32_t *)expr64; + *expr++ = '-'; + *expr = ENDEXPR; +} + + +// Store a 12bit immediate and 16bit address. +// Note: This function is specifically handling DO. DO has a requirement of +// storing the address of a label minus 1! Quoting the manual: +// "Note: The assembler calculates the end-of-loop address to be loaded +// into LA (the absolute address extension word) by evaluating the end +// -of-loop expression and subtracting one. This is done to +// accommodate the case where the last word in the DO loop is a two-word +// instruction. Thus, the end-of-loop expression in the source +// code must represent the address of the instruction AFTER the last +// instruction in the loop as shown in the example." +// This is fine if we know the address already, but a problem when we +// don't. +int dsp_imm12_abs16(LONG inst) +{ + if (dsp_a0exattr & DEFINED) + { + if ((dsp_am0 & (M_DSPIM12 | M_DSPIM8)) == 0) + return error("immediate out of range ($000-$FFF)"); + + inst |= ((dsp_a0exval & 0x0FF) << 8) | ((dsp_a0exval & 0xF00) >> 8); + D_dsp(inst); + } + else + { + AddFixup(FU_DSPIMM12, sloc, dsp_a0expr); + D_dsp(inst); + } + + if (dsp_a1exattr & DEFINED) + { + D_dsp((a1exval - 1)); + } + else + { + append_minus_1(dsp_a1expr); + AddFixup(FU_DSPADR16, sloc, dsp_a1expr); + D_dsp(0); + } + + return OK; +} + + +// Just store ea and 16bit address +// Note: this function is specifically handling DO. +// The same notes as dsp_imm12_abs16 apply here. +int dsp_ea_abs16(LONG inst) +{ + if ((dsp_a0reg == DSP_EA_ABS && dsp_a0memspace == -1) || dsp_a1reg == DSP_EA_IMM) + return error("immediate values > 31 or absolute values not allowed"); + + if (dsp_a0exattr & DEFINED) + { + if (dsp_a0exval > 31) + return error("absolute address (aa) bigger than $1F"); + + inst |= dsp_a0exval << 8; + } + + inst |= dsp_a0reg << 8; + + if (dsp_a0memspace == -1) + return error("only X:, Y: address spaces allowed"); + + if ((deposit_extra_ea == DEPOSIT_EXTRA_FIXUP) || (dsp_a0reg == DSP_EA_ABS && dsp_am0 == M_DSPEA)) + { + // Change instruction to aa instead of ea. TODO: check if this is true + // for all cases + inst = 0x060000; + inst |= dsp_a0memspace; + + // Probably superfluous check (we're not likely to land here with a + // known aa) but oh well + if (!(dsp_a0exattr & DEFINED)) + { + AddFixup(FU_DSPADR06, sloc, dsp_a0expr); + D_dsp(inst); + } + else + { + D_dsp(inst); + } + } + else + { + inst |= dsp_a0memspace; + D_dsp(inst); + } + + if (dsp_a1exattr & DEFINED) + { + D_dsp((dsp_a1exval - 1)); + } + else + { + append_minus_1(dsp_a1expr); + AddFixup(FU_DSPADR16, sloc, dsp_a1expr); + D_dsp(0); + } + + return OK; +} + + +// Store register (table A-18 in the motorola manual) 5-bit constant and 16bit address +// Note: this function is specifically handling DO. +// The same notes as dsp_imm12_abs16 apply here. +int dsp_reg_abs16(LONG inst) +{ + LONG reg; + + if ((reg = tab_A18(&dsp_am0, &dsp_a0reg)) == ERROR) + return ERROR; + + inst |= reg << 8; + + if (dsp_a1exattr & DEFINED) + { + int v = (int)dsp_a1exval - 1; + D_dsp(inst); + D_dsp(v); + } + else + { + D_dsp(inst); + append_minus_1(dsp_a1expr); + AddFixup(FU_DSPADR16, sloc, dsp_a1expr); + D_dsp(0); + } + + return OK; +} + + +// Store ALU24 register and 16bit address +// Note: this function is specifically handling DO. +// The same notes as dsp_imm12_abs16 apply here. +int dsp_alu24_abs16(LONG inst) +{ + inst |= (dsp_a0reg & 7) << 8; + + if (dsp_a1exattr & DEFINED) + { + int v = (int)dsp_a1exval - 1; + D_dsp(inst); + D_dsp(v); + } + else + { + D_dsp(inst); + append_minus_1(dsp_a1expr); + AddFixup(FU_DSPADR16, sloc, dsp_a1expr); + D_dsp(0); + } + + return OK; +} + + +// Store register (table A-18 in the motorola manual) +int dsp_reg(LONG inst) +{ + LONG reg; + + if ((reg = tab_A18(&dsp_am0, &dsp_a0reg)) == ERROR) + return ERROR; + + inst |= reg << 8; + D_dsp(inst); + + return OK; +} + + +int dsp_alu24(LONG inst) +{ + inst |= (dsp_a0reg & 7) << 8; + D_dsp(inst); + + return OK; +} + + +// Store register (table A-18 in the motorola manual) and 5-bit constant +int dsp_reg_imm5_abs16(LONG inst) +{ + LONG reg; + + // First, check that we have at best an 16bit absolute address in + // operand 3 since we don't check that anywhere else + if (dsp_a2exattr & DEFINED) + { + if ((dsp_am2 & C_DSPABS16) == 0) + return error("expected 16-bit address as third operand."); + } + + if ((reg = tab_A18(&dsp_am1, &dsp_a1reg)) == ERROR) + return ERROR; + + inst |= reg << 8; + + if (dsp_a0exattr & DEFINED) + { + int v = (int)dsp_a0exval; + + if (v < 0 || v > 23) + return error("immediate value must be between 0 and 23"); + + inst |= v; + D_dsp(inst); + + if (dsp_a2exattr & DEFINED) + { + int v = (int)dsp_a2exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR16, sloc, dsp_a2expr); + D_dsp(0); + } + } + else + { + AddFixup(FU_DSPIMM5, sloc, dsp_a0expr); + D_dsp(inst); + + if (dsp_a2exattr & DEFINED) + { + int v = (int)dsp_a2exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR16, sloc, dsp_a2expr); + D_dsp(0); + } + } + + return OK; +} + + +// Store ea, 5-bit constant and 16-bit address in the extension word +int dsp_ea_imm5_abs16(LONG inst) +{ + // First, check that we have at best an 16bit absolute address in + // operand 3 since we don't check that anywhere else + if (dsp_a2exattr&DEFINED) + { + if ((dsp_am2&C_DSPABS16) == 0) + return error("expected 16-bit address as third operand."); + } + + if (dsp_a1memspace == -1) + return error("Only X: or Y: memory space allowed"); + + if (dsp_am1 == M_DSPAA) + { + if (dsp_a1exattr & DEFINED) + inst |= (dsp_a1exval & 0x3F) << 8; + else + AddFixup(FU_DSPADR06, sloc, dsp_a1expr); + } + + if (dsp_am1 == M_DSPPP) + { + if (dsp_a1exattr & DEFINED) + inst |= (dsp_a1exval & 0x3f) << 8; + else + AddFixup(FU_DSPPP06, sloc, dsp_a1expr); + } + + if (dsp_a0exattr & DEFINED) + { + int v = (int)dsp_a0exval; + + if (v < 0 || v > 23) + return error("immediate value must be between 0 and 23"); + + inst |= (dsp_a1reg << 8) | v | dsp_a1memspace; + D_dsp(inst); + + if (dsp_a2exattr & DEFINED) + { + int v = (int)dsp_a2exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR16, sloc, dsp_a2expr); + D_dsp(0); + } + } + else + { + inst |= (dsp_a1reg << 8) | dsp_a1memspace; + AddFixup(FU_DSPIMM5, sloc, dsp_a0expr); + D_dsp(inst); + + if (dsp_a2exattr & DEFINED) + { + int v = (int)dsp_a2exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR16, sloc, dsp_a2expr); + D_dsp(0); + } + } + + return OK; +} + + +int dsp_ea_lua(LONG inst) +{ + int am = dsp_a0reg & 0x38; + + if (am != DSP_EA_POSTDEC && am != DSP_EA_POSTINC && + am != DSP_EA_POSTDEC1 && am != DSP_EA_POSTINC1) + return error("addressing mode not allowed"); + + inst |= dsp_a0reg << 8; + + if (dsp_am1 == M_DSPN) + inst |= 1 << 3; + + inst |= dsp_a1reg; + D_dsp(inst); + + return OK; +} + + +int dsp_ab_rn(LONG inst) +{ + inst |= (dsp_a1reg & 1) << 3; + inst |= (dsp_a0reg) << 8; + D_dsp(inst); + + return OK; +} + + +int dsp_movec_ea(LONG inst) +{ + int ea = dsp_a1reg; + int memspace = dsp_a1memspace; + WORD exattr = dsp_a1exattr; + LONG exval = (uint32_t)dsp_a1exval; + TOKEN * expr = dsp_a1expr; + int reg = dsp_a0reg; + int am = dsp_am0; + int reg2 = dsp_a1reg; + + if (dsp_am0 == M_DSPEA || (dsp_am0 & C_DSPIM)) + { + ea = dsp_a0reg; + exattr = dsp_a0exattr; + exval = (uint32_t)dsp_a0exval; + memspace = dsp_a0memspace; + expr = dsp_a0expr; + reg = dsp_a1reg; + reg2 = dsp_a0reg; + am = dsp_am1; + } + + // Abort if unsupported registers are requested + if (reg == KW_PC || reg == KW_MR || reg == KW_CCR) + return error("illegal registers for instruction."); + + if (dsp_am0 & C_DSPIM) + memspace = 0; + + if (memspace == -1) + return error("only x: or y: memory spaces allowed."); + + // No memspace required when loading an immediate + if (dsp_am0 & C_DSPIM) + memspace = 0; + + reg = tab_A18(&am, ®); + inst |= (ea << 8) | memspace | reg; + + if (am == M_DSPPCU) + inst |= 3 << 3; + + D_dsp(inst); + + if (reg2 == DSP_EA_ABS || (dsp_am0 & C_DSPIM)) + { + if (exattr & DEFINED) + { + int v = exval; + D_dsp(v); + } + else + { + if (dsp_am0 == M_DSPIM) + { + AddFixup(FU_DSPIMM24, sloc, expr); + D_dsp(0); + } + else + { + AddFixup(FU_DSPADR24, sloc, expr); + D_dsp(0); + } + } + } + + return OK; +} + + +int dsp_movec_aa(LONG inst) +{ + int ea = dsp_a1reg; + int memspace = dsp_a1memspace; + WORD exattr = dsp_a1exattr; + LONG exval = (uint32_t)dsp_a1exval; + TOKEN * expr = dsp_a1expr; + int reg = dsp_a0reg; + int am = dsp_am0; + int reg2 = dsp_a1reg; + + if (dsp_am0 == M_DSPAA) + { + ea = dsp_a0reg; + exattr = dsp_a0exattr; + exval = (uint32_t)dsp_a0exval; + memspace = dsp_a0memspace; + expr = dsp_a0expr; + reg = dsp_a1reg; + reg2 = dsp_a0reg; + am = dsp_am1; + } + + // Abort if unsupported registers are requested + if (reg == KW_PC || reg == KW_MR || reg == KW_CCR) + return error("PC, MR, CCR are illegal registers for this instruction."); + + if (memspace == -1) + return error("only x: or y: memory spaces allowed."); + + reg = tab_A18(&am, ®); + inst |= (ea << 8) | memspace | reg; + + if (am == M_DSPPCU) + inst |= 3 << 3; + + if (exattr & DEFINED) + { + inst |= exval << 8; + D_dsp(inst); + } + else + { + AddFixup(FU_DSPADR06, sloc, expr); + D_dsp(inst); + } + + return OK; +} + + +int dsp_movec_reg(LONG inst) +{ + int am0 = dsp_am0; + int am1 = dsp_am1; + + // Abort if unsupported registers are requested + if (dsp_a0reg == KW_PC || dsp_a0reg == KW_MR || dsp_a0reg == KW_CCR || + dsp_a1reg == KW_PC || dsp_a1reg == KW_MR || dsp_a1reg == KW_CCR) + return error("PC, MR, CCR are illegal registers for this instruction."); + + int reg1 = tab_A18(&dsp_am0, &dsp_a0reg); + int reg2 = tab_A18(&dsp_am1, &dsp_a1reg); + + if (inst & (1 << 15)) + { + // S1,D2 + } + else + { + // S2,D1 + int temp = am0; + am0 = am1; + am1 = temp; + temp = reg1; + reg1 = reg2; + reg2 = temp; + } + + switch (am0) + { + case M_ALU24: reg1 |= 0x00; break; + case M_ACC8: + case M_ACC24: reg1 |= 0x08; break; + case M_ACC56: reg1 |= 0x0E; break; + case M_DSPR: reg1 |= 0x10; break; + case M_DSPN: reg1 |= 0x18; break; + case M_DSPM: reg1 |= 0x20; break; + case M_DSPPCU: reg1 |= 0x38; break; + default: + return error("reached the end of dsp_movec_reg case 1 - should not happen!"); + } + + switch (am1) + { + case M_DSPM: reg2 |= 0x00; break; + case M_DSPPCU: reg2 |= 0x18; break; + default: + return error("reached the end of dsp_movec_reg case 2 - should not happen!"); + } + + inst |= (reg1 << 8) | reg2; + D_dsp(inst); + + return OK; +} + + +int dsp_mult(LONG inst) +{ + if (dsp_am2 != M_ACC56) + return error("only A or B allowed as third operand."); + + switch (((dsp_a0reg & 3) << 2) + (dsp_a1reg & 3)) + { + case (0 << 2) + 0: inst |= 0 << 4; break; // x0 x0 + case (2 << 2) + 2: inst |= 1 << 4; break; // y0 y0 + case (1 << 2) + 0: inst |= 2 << 4; break; // x1 x0 + case (0 << 2) + 1: inst |= 2 << 4; break; // x0 x1 + case (3 << 2) + 2: inst |= 3 << 4; break; // y1 y0 + case (2 << 2) + 3: inst |= 3 << 4; break; // y0 y1 + case (0 << 2) + 3: inst |= 4 << 4; break; // x0 y1 + case (3 << 2) + 0: inst |= 4 << 4; break; // y1 x0 + case (2 << 2) + 0: inst |= 5 << 4; break; // y0 x0 + case (0 << 2) + 2: inst |= 5 << 4; break; // x0 y0 + case (1 << 2) + 2: inst |= 6 << 4; break; // x1 y0 + case (2 << 2) + 1: inst |= 6 << 4; break; // y0 x1 + case (3 << 2) + 1: inst |= 7 << 4; break; // y1 x1 + case (1 << 2) + 3: inst |= 7 << 4; break; // x1 y1 + default: + return error("x0/y0/x1/y1 combination not allowed for multiplication."); + } + + if (dsp_a2reg == KW_B) + inst |= 1 << 3; + + inst |= dsp_k; + D_dsp(inst); + dsp_extra_ea(); // Deposit effective address if needed + + return OK; +} + + +int dsp_movem_ea(LONG inst) +{ + int ea = dsp_a1reg; + int memspace = dsp_a0memspace; + WORD exattr = dsp_a1exattr; + LONG exval = (uint32_t)dsp_a1exval; + TOKEN * expr = dsp_a1expr; + int reg = dsp_a0reg; + int am = dsp_am0; + int reg2 = dsp_a1reg; + + if (dsp_am0 == M_DSPEA || dsp_am0 == M_DSPIM) + { + ea = dsp_a0reg; + exattr = dsp_a0exattr; + exval = (uint32_t)dsp_a0exval; + memspace = dsp_a0memspace; + expr = dsp_a0expr; + reg = dsp_a1reg; + reg2 = dsp_a0reg; + am = dsp_am1; + inst |= 1 << 15; + } + + // Abort if unsupported registers are requested + if (reg == KW_PC || reg == KW_MR || reg == KW_CCR) + return error("illegal registers for instruction."); + + if (memspace != -1) + return error("only p: memory space allowed."); + + reg = tab_A18(&am, ®); + inst |= (ea << 8) | reg; + + if (am == M_DSPPCU) + inst |= 3 << 3; + + D_dsp(inst); + + if (reg2 == DSP_EA_ABS || dsp_am0 == M_DSPIM) + { + if (exattr & DEFINED) + { + int v = exval; + D_dsp(v); + } + else + { + if (dsp_am0 == M_DSPIM) + { + AddFixup(FU_DSPIMM24, sloc, expr); + D_dsp(0); + } + else + { + AddFixup(FU_DSPADR24, sloc, expr); + D_dsp(0); + } + } + } + + return OK; +} + + +int dsp_movem_aa(LONG inst) +{ + int ea = dsp_a1reg; + int memspace = dsp_a1memspace; + WORD exattr = dsp_a1exattr; + LONG exval = (uint32_t)dsp_a1exval; + TOKEN * expr = dsp_a1expr; + int reg = dsp_a0reg; + int am = dsp_am0; + int reg2 = dsp_a1reg; + + if (dsp_am0 == M_DSPAA) + { + ea = dsp_a0reg; + exattr = dsp_a0exattr; + exval = (uint32_t)dsp_a0exval; + memspace = dsp_a0memspace; + expr = dsp_a0expr; + reg = dsp_a1reg; + reg2 = dsp_a0reg; + am = dsp_am1; + } + + // Abort if unsupported registers are requested + if (reg == KW_PC || reg == KW_MR || reg == KW_CCR) + return error("PC, MR, CCR are illegal registers for this instruction."); + + if (memspace != -1) + return error("only p: memory space allowed."); + + reg = tab_A18(&am, ®); + inst |= (ea << 8) | reg; + + if (am == M_DSPPCU) + inst |= 3 << 3; + + if (exattr & DEFINED) + { + inst |= exval << 8; + D_dsp(inst); + } + else + { + AddFixup(FU_DSPADR06, sloc, expr); + D_dsp(inst); + } + + return OK; +} + + +int dsp_movep_ea(LONG inst) +{ + // movep doesn't allow any aa modes but we might detect this during amode + // detection. No worries, just change it to ea with extra address instead + if (dsp_am0 == M_DSPAA) + { + dsp_a0reg = DSP_EA_ABS; + dsp_a1reg = 0; + } + if (dsp_am1 == M_DSPAA) + { + dsp_a0reg = 0; + dsp_a1reg = DSP_EA_ABS; + } + + // So we might encounter something like 'movep x:pp,x:pp' which we + // obviously flagged as M_DSPPP during ea parsing. In this case we give up + // and declare the second term as a classic absolute address (we chop off + // the high bits too) and let the routine treat is as such. At least that's + // what Motorola's assembler seems to be doing. + if (dsp_am0 == M_DSPPP && dsp_am1 == M_DSPPP) + { + dsp_am1 = DSP_EA_ABS; + dsp_a1reg = DSP_EA_ABS; + dsp_a1exval &= 0xFFFF; + } + + // Assume first operand is :pp + int ea = dsp_a1reg; + int memspace = dsp_a1memspace; + int perspace = dsp_a0perspace; + WORD exattr = dsp_a1exattr; + WORD exattr2 = dsp_a0exattr; + LONG exval = (uint32_t)dsp_a1exval; + LONG exval2 = (uint32_t)dsp_a0exval; + TOKEN * expr = dsp_a1expr; + TOKEN * expr2 = dsp_a0expr; + int reg = dsp_a0reg; + int am = dsp_am0; + int reg2 = dsp_a1reg; + + if (dsp_am1 == M_DSPPP) + { + ea = dsp_a0reg; + exattr = dsp_a0exattr; + exattr2 = dsp_a1exattr; + exval = (uint32_t)dsp_a0exval; + exval2 = (uint32_t)dsp_a1exval; + memspace = dsp_a0memspace; + perspace = dsp_a1perspace; + expr = dsp_a0expr; + expr2 = dsp_a1expr; + reg = dsp_a1reg; + reg2 = dsp_a0reg; + am = dsp_am1; + } + + if (dsp_a0perspace == -1 && dsp_a1perspace == -1) + { + // Ok, so now we have to guess which of the two parameters is X:pp or + // Y:pp. This happened because we didn't get a << marker in any of the + // addressing modes + if (((dsp_a0exattr | dsp_a1exattr) & DEFINED) == 0) + // You have got to be shitting me... + // One way to deal with this (for example X:ea,X:pp / X:pp,X:ea + // aliasing would be to check number ranges and see which one is + // negative. ...unless one of the two isn't known during this phase + return error("internal assembler error: could not deduce movep syntax"); + + if (dsp_a0exattr & DEFINED) + { + if (dsp_a0exval >= 0xFFC0 && dsp_a0exval <= 0xFFFF) + { + // First operand is :pp - do nothing + perspace = dsp_a0memspace << 10; + // When the source contains a << then we bolt on the :pp + // address during ea parsing, but since we couldn't recognise + // the addressing mode in this case let's just insert it right + // now... + reg |= (dsp_a0exval & 0x3F); + } + } + + if (dsp_a1exattr & DEFINED) + { + if (dsp_a1exval >= 0xFFC0 && dsp_a1exval <= 0xFFFF) + { + ea = dsp_a0reg; + exattr = dsp_a0exattr; + exval = (uint32_t)dsp_a0exval; + memspace = dsp_a0memspace; + perspace = dsp_a1memspace << 10; + expr = dsp_a0expr; + reg = dsp_a0reg; + reg2 = dsp_a1reg; + am = dsp_am1; + // See above + reg |= (dsp_a1exval & 0x3F); + } + } + + if (perspace == -1) + // You have got to be shitting me (twice)... + return error("internal assembler error: could not deduce movep syntax"); + } + + inst |= reg | (ea << 8) | perspace; // reg contains memory space + + if ((dsp_am0 & (M_DSPIM | M_DSPIM8 | M_DSPIM12)) == 0) + { + if (memspace == -1) + { + inst &= ~(1 << 7); + inst |= 1 << 6; + } + else + inst |= memspace; + } + + if (am == M_DSPPP) + { + if (exattr2&DEFINED) + { + inst |= (exval2 & 0x3F); + D_dsp(inst); + } + else + { + AddFixup(FU_DSPIMM5, sloc, expr2); + D_dsp(inst); + } + } + else + { + D_dsp(inst); + } + + if (dsp_am0 & (M_DSPIM | M_DSPIM8 | M_DSPIM12)) + { + if (dsp_a0exattr & DEFINED) + { + int v = (int)dsp_a0exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR16, sloc, dsp_a0expr); + D_dsp(0); + } + } + else if (reg2 == DSP_EA_ABS) + { + if (exattr & DEFINED) + { + int v = exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR24, sloc, expr); + D_dsp(0); + } + } + + return OK; +} + + +int dsp_movep_reg(LONG inst) +{ + // Assume first operand is :pp + int ea = dsp_a0reg; + int memspace = dsp_a0memspace; + int perspace = dsp_a0perspace; + WORD exattr = dsp_a1exattr; + LONG exval = (uint32_t)dsp_a1exval; + TOKEN * expr = dsp_a1expr; + int reg = dsp_a0reg; + int am = dsp_am1; + int reg2 = dsp_a1reg; + + if (dsp_am1 == M_DSPPP) + { + ea = dsp_a1reg; + exattr = dsp_a0exattr; + exval = (uint32_t)dsp_a0exval; + memspace = dsp_a1memspace; + perspace = dsp_a1perspace; + expr = dsp_a0expr; + reg = dsp_a1reg; + reg2 = dsp_a0reg; + am = dsp_am0; + } + + // Abort if unsupported registers are requested + if (reg == KW_PC || reg == KW_MR || reg == KW_CCR) + return error("illegal registers for instruction."); + + reg2 = tab_A18(&am, ®2); + inst |= (reg2 << 8) | reg; + + if (perspace == -1) + return error("only x: or y: memory space allowed."); + else + inst |= perspace; + + D_dsp(inst); + + if (reg2 == DSP_EA_ABS) + { + if (exattr & DEFINED) + { + int v = exval; + D_dsp(v); + } + else + { + AddFixup(FU_DSPADR24, sloc, expr); + D_dsp(0); + } + } + + return OK; +} + diff --git a/dsp56k_mach.h b/dsp56k_mach.h new file mode 100644 index 0000000..593ff9a --- /dev/null +++ b/dsp56k_mach.h @@ -0,0 +1,24 @@ +// +// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// DSP56L_MACH.C - Code Generation for Motorola DSP56001 +// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#ifndef __DSP56KMACH_H__ +#define __DSP56KMACH_H__ + +#include "rmac.h" +#include "dsp56k_amode.h" + +// Exported variables +extern MNTABDSP dsp56k_machtab[]; +extern unsigned int dsp_orgaddr; +extern unsigned int dsp_orgseg; + +// Exported functions +extern int dsp_mult(LONG inst); + +#endif // __DSP56KMACH_H__ + diff --git a/dsp56kgen.c b/dsp56kgen.c new file mode 100644 index 0000000..3f263ad --- /dev/null +++ b/dsp56kgen.c @@ -0,0 +1,134 @@ +// +// RMAC - Reboot's Macro Assembler for all Atari computers +// 68KGEN.C - Tool to Generate 68000 Opcode Table +// Copyright (C) 199x Landon Dyer, 2011-2018 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer +// + +#include +#include +#include + + +#define EOS '\0' + +int kwnum = 1; /* current op# for kwgen output */ +FILE * kfp; /* keyword file */ +int lineno = 0; + +// Function prototypes +void error(char *, char *); +void procln(int, char **); + + +int main(int argc, char ** argv) +{ + char * namv[256]; + char * s; + int namcnt; + char ln[256]; + + if ((argc == 2) && ((kfp = fopen(argv[1], "w")) == NULL)) + error("Cannot create: %s", argv[1]); + + while (fgets(ln, 256, stdin) != NULL) + { + lineno++; /* bump line# */ + + if (*ln == '#') /* ignore comments */ + continue; + + /* + * Tokenize line (like the way "argc, argv" works) + * and pass it to the parser. + */ + namcnt = 0; + s = ln; + + while (*s) + { + if (isspace(*s)) + ++s; + else + { + namv[namcnt++] = s; + + while (*s && !isspace(*s)) + s++; + + if (isspace(*s)) + *s++ = EOS; + } + } + + if (namcnt) + procln(namcnt, namv); + } + + return 0; +} + + +// +// Parse line +// +void procln(int namc, char ** namv) +{ + int i, j; + + // alias for previous entry + if (namc == 1) + { + fprintf(kfp, "%s\t%d\n", namv[0], kwnum - 1 + 2000); + return; + } + + if (namc < 5) + { + fprintf(stderr, "%d: missing fields\n", lineno); + exit(1); + } + + // output keyword name + if (*namv[0] != '-') + fprintf(kfp, "%s\t%d\n", namv[0], kwnum + 2000); + + printf("/*%4d %-6s*/ {", kwnum, namv[0]); + + printf("%s, %s, %s, ", namv[1], namv[2], namv[3]); + + // enforce little fascist percent signs + if (*namv[4] == '%') + { + for(i=1, j=0; i<25; i++) + { + j <<= 1; + + if (namv[4][i] == '1' || isupper(namv[4][i])) + j++; + } + + printf("0x%06x, ", j); + } + else + printf("%s, ", namv[4]); + + if (namc >= 7 && *namv[6] == '+') + printf("%d, ", kwnum + 1); + else + printf("0, "); + + printf("%s},\n", namv[5]); + + kwnum++; +} + + +void error(char * s, char * s1) +{ + fprintf(stderr, s, s1); + fprintf(stderr, "\n"); + exit(1); +} + diff --git a/expr.c b/expr.c index 4318aa7..6db7435 100644 --- a/expr.c +++ b/expr.c @@ -36,7 +36,7 @@ char itokcl[] = { CR_STREQ, CR_MACDEF, CR_DATE, CR_TIME, CR_ABSCOUNT, 0, - '!', '~', UNMINUS, 0, // UNARY + '!', '~', UNMINUS, UNLT, UNGT, 0, // UNARY '*', '/', '%', 0, // MULT '+', '-', 0, // ADD SHL, SHR, 0, // SHIFT @@ -49,6 +49,7 @@ char itokcl[] = { const char missym_error[] = "missing symbol"; const char str_error[] = "missing symbol or string"; +const char noflt_error[] = "operator not usable with float"; // Convert expression to postfix static PTR evalTokenBuffer; // Deposit tokens here (this is really a @@ -125,23 +126,24 @@ int expr0(void) // int expr1(void) { - TOKEN t; - SYM * sy; - char * p, * p2; + char * p; WORD w; - int j; int class = tokenClass[*tok]; - if (*tok == '-' || *tok == '+' || class == UNARY) + if (*tok == '-' || *tok == '+' || *tok == '<' || *tok == '>' || class == UNARY) { - t = *tok++; + TOKEN t = *tok++; if (expr2() != OK) return ERROR; if (t == '-') t = UNMINUS; + else if (t == '<') + t = UNLT; + else if (t == '>') + t = UNGT; // With leading + we don't have to deposit anything to the buffer // because there's no unary '+' nor we have to do anything about it @@ -183,8 +185,9 @@ getsym: return error(missym_error); p = string[*tok++]; - j = (*p == '.' ? curenv : 0); - w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0); + int j = (*p == '.' ? curenv : 0); + SYM * sy = lookup(p, LABEL, j); + w = ((sy != NULL) && (sy->sattr & w ? 1 : 0)); *evalTokenBuffer.u32++ = CONST; *evalTokenBuffer.u64++ = (uint64_t)w; break; @@ -201,7 +204,7 @@ getsym: if (*tok != SYMBOL && *tok != STRING) return error(str_error); - p2 = string[tok[1]]; + char * p2 = string[tok[1]]; tok += 2; w = (WORD)(!strcmp(p, p2)); @@ -222,9 +225,6 @@ getsym: // int expr2(void) { - char * p; - SYM * sy; - int j; PTR ptk; switch (*tok++) @@ -242,9 +242,10 @@ int expr2(void) tok = ptk.u32; break; case SYMBOL: - p = string[*tok++]; - j = (*p == '.' ? curenv : 0); - sy = lookup(p, LABEL, j); + { + char * p = string[*tok++]; + int j = (*p == '.' ? curenv : 0); + SYM * sy = lookup(p, LABEL, j); if (sy == NULL) sy = NewSymbol(p, LABEL, j); @@ -264,6 +265,7 @@ int expr2(void) symbolPtr[symbolNum] = sy; symbolNum++; break; + } case STRING: *evalTokenBuffer.u32++ = CONST; *evalTokenBuffer.u64++ = str_value(string[*tok++]); @@ -494,10 +496,15 @@ thrown away right here. What the hell is it for? tok += 2; } + // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!! + else if (m6502) + { + *evalTokenBuffer.u32++ = *tok++; + } else { // Unknown type here... Alert the user!, - error("undefined RISC register in expression"); + error("undefined RISC register in expression [token=$%X]", *tok); // Prevent spurious error reporting... tok++; return ERROR; @@ -691,6 +698,30 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); break; + case UNLT: // Unary < (get the low byte of a word) +//printf("evexpr(): UNLT\n"); + if (*sattr & TDB) + return error(seg_error); + + if (*sattr & FLOAT) + return error(noflt_error); + + *sval = (int64_t)((*sval) & 0x00FF); + *sattr = ABS | DEFINED; // Expr becomes absolute + break; + + case UNGT: // Unary > (get the high byte of a word) +//printf("evexpr(): UNGT\n"); + if (*sattr & TDB) + return error(seg_error); + + if (*sattr & FLOAT) + return error(noflt_error); + + *sval = (int64_t)(((*sval) >> 8) & 0x00FF); + *sattr = ABS | DEFINED; // Expr becomes absolute + break; + case '!': //printf("evexpr(): !\n"); if (*sattr & TDB) diff --git a/kwtab b/kw.tab similarity index 73% rename from kwtab rename to kw.tab index 249eb47..cde9337 100644 --- a/kwtab +++ b/kw.tab @@ -68,13 +68,6 @@ fp4 228 fp5 229 fp6 230 fp7 231 -mr 272 -omr 273 -la 274 -lc 275 -ssh 276 -ssl 277 -ss 278 .equ 61 equ 61 @@ -128,4 +121,46 @@ time 120 date 121 abscount 122 +x0 260 +x1 261 +y0 262 +y1 263 +b0 265 +b2 267 +b1 269 +a 270 +b 271 +n0 280 +n1 281 +n2 282 +n3 283 +n4 284 +n5 285 +n6 286 +n7 287 +m0 288 +m1 289 +m2 290 +m3 291 +m4 292 +m5 293 +m6 294 +m7 295 +mr 304 +omr 305 +la 306 +lc 307 +ssh 308 +ssl 309 +ss 310 + +l 302 +p 303 + +a10 312 +b10 313 +x 314 +y 315 +ab 318 +ba 319 diff --git a/makefile b/makefile index a1ffcc8..b69348f 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ # -# RMAC - Reboot's Macro Assembler for the Atari Jaguar -# Copyright (C) 199x Landon Dyer, 2011 Reboot & Friends +# RMAC - Reboot's Macro Assembler for all Atari computers +# Copyright (C) 199x Landon Dyer, 2011-2018 Reboot & Friends # MAKEFILE for *nix # @@ -20,22 +20,21 @@ STD := gnu99 endif -rm = /bin/rm -f +RM = /bin/rm -f CC = $(CROSS)gcc HOSTCC = gcc #CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2 -MMD CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2 -SRCS = 6502.c amode.c debug.c direct.c eagen.c error.c expr.c fltpoint.c listing.c mach.c macro.c mark.c object.c op.c procln.c riscasm.c rmac.c sect.c symbol.c token.c - -OBJS = 6502.o amode.o debug.o direct.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o op.o procln.o riscasm.o rmac.o sect.o symbol.o token.o +OBJS = 6502.o amode.o debug.o direct.o dsp56k.o dsp56k_amode.o dsp56k_mach.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o op.o procln.o riscasm.o rmac.o sect.o symbol.o token.o # # Build everything # -all : mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h rmac +#all: mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h dsp56ktab.h rmac +all: rmac @echo @echo "Don't forget to bump the version number before commiting!" @echo @@ -45,106 +44,48 @@ all : mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h rmac # definitions # -mntab.h : mntab 68kmn kwgen - cat mntab 68kmn | ./kwgen mn >mntab.h +68ktab.h 68k.tab: 68k.mch 68kgen + ./68kgen 68k.tab <68k.mch >68ktab.h + +dsp56ktab.h dsp56k.tab: dsp56k.mch dsp56kgen + ./dsp56kgen dsp56k.tab dsp56ktab.h -68ktab.h 68kmn : 68ktab 68ktab 68kgen - ./68kgen 68kmn <68ktab >68ktab.h +mntab.h: direct.tab 68k.tab kwgen + cat direct.tab 68k.tab | ./kwgen mn >mntab.h -kwtab.h : kwtab kwgen - ./kwgen kw kwtab.h +kwtab.h: kw.tab kwgen + ./kwgen kw kwtab.h -6502kw.h : 6502.tbl kwgen - ./kwgen mp <6502.tbl >6502kw.h +6502kw.h: 6502.tab kwgen + ./kwgen mp <6502.tab >6502kw.h -risckw.h : kwtab kwgen - ./kwgen mr risckw.h +risckw.h: risc.tab kwgen + ./kwgen mr risckw.h -opkw.h : op.tab kwgen +opkw.h: op.tab kwgen ./kwgen mo opkw.h +# Looks like this is not needed... +dsp56kkw.h: dsp56k.tab kwgen + ./kwgen dsp dsp56kkw.h + # # Build tools # -kwgen.o : kwgen.c - $(HOSTCC) $(CFLAGS) -c kwgen.c - -kwgen : kwgen.o - $(HOSTCC) $(CFLAGS) -o kwgen kwgen.o - -68kgen.o : 68kgen.c - $(HOSTCC) $(CFLAGS) -c 68kgen.c - -68kgen : 68kgen.o - $(HOSTCC) $(CFLAGS) -o 68kgen 68kgen.o +%gen: %gen.c + $(HOSTCC) $(CFLAGS) -c $< + $(HOSTCC) $(CFLAGS) -o $*gen $< # # Build RMAC executable # -6502.o : 6502.c 6502.h - $(CC) $(CFLAGS) -c 6502.c - -amode.o : amode.c amode.h - $(CC) $(CFLAGS) -c amode.c - -debug.o : debug.c debug.h - $(CC) $(CFLAGS) -c debug.c - -direct.o : direct.c direct.h - $(CC) $(CFLAGS) -c direct.c - -eagen.o : eagen.c eagen.h eagen0.c - $(CC) $(CFLAGS) -c eagen.c - -error.o : error.c error.h - $(CC) $(CFLAGS) -c error.c - -expr.o : expr.c expr.h - $(CC) $(CFLAGS) -c expr.c - -fltpoint.o : fltpoint.c fltpoint.h - $(CC) $(CFLAGS) -c fltpoint.c - -listing.o : listing.c listing.h - $(CC) $(CFLAGS) -c listing.c - -mach.o : mach.c mach.h - $(CC) $(CFLAGS) -c mach.c - -macro.o : macro.c macro.h - $(CC) $(CFLAGS) -c macro.c - -mark.o : mark.c mark.h - $(CC) $(CFLAGS) -c mark.c - -object.o : object.c object.h - $(CC) $(CFLAGS) -c object.c - -op.o : op.c op.h - $(CC) $(CFLAGS) -c op.c - -procln.o : procln.c procln.h - $(CC) $(CFLAGS) -c procln.c - -riscasm.o : riscasm.c riscasm.h - $(CC) $(CFLAGS) -c riscasm.c - -rmac.o : rmac.c rmac.h - $(CC) $(CFLAGS) -c rmac.c - -sect.o : sect.c sect.h - $(CC) $(CFLAGS) -c sect.c - -symbol.o : symbol.c symbol.h - $(CC) $(CFLAGS) -c symbol.c - -token.o : token.c token.h - $(CC) $(CFLAGS) -c token.c +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< -rmac : $(OBJS) +rmac: $(OBJS) $(CC) $(CFLAGS) -o rmac $(OBJS) -lm # @@ -152,30 +93,37 @@ rmac : $(OBJS) # clean: - $(rm) $(OBJS) kwgen.o 68kgen.o rmac kwgen 68kgen kwtab.h 68ktab.h mntab.h risckw.h 6502kw.h opkw.h + $(RM) $(OBJS) kwgen.o 68kgen.o rmac kwgen 68kgen 68k.tab kwtab.h 68ktab.h mntab.h risckw.h 6502kw.h opkw.h dsp56kgen dsp56kgen.o dsp56k.tab dsp56kkw.h dsp56ktab.h # # Dependencies # 6502.o: 6502.c direct.h rmac.h symbol.h token.h expr.h error.h mach.h \ - procln.h riscasm.h sect.h -68kgen.o: 68kgen.c + procln.h riscasm.h sect.h kwtab.h +68kgen: 68kgen.c amode.o: amode.c amode.h rmac.h symbol.h error.h expr.h mach.h procln.h \ - token.h sect.h kwtab.h mntab.h parmode.h + token.h sect.h riscasm.h kwtab.h mntab.h parmode.h debug.o: debug.c debug.h rmac.h symbol.h amode.h direct.h token.h expr.h \ - mark.h sect.h + mark.h sect.h riscasm.h direct.o: direct.c direct.h rmac.h symbol.h token.h 6502.h amode.h \ error.h expr.h fltpoint.h listing.h mach.h macro.h mark.h procln.h \ riscasm.h sect.h kwtab.h +dsp56k.o: dsp56k.c rmac.h symbol.h dsp56k.h sect.h riscasm.h +dsp56k_amode.o: dsp56k_amode.c dsp56k_amode.h rmac.h symbol.h amode.h \ + error.h token.h expr.h procln.h sect.h riscasm.h kwtab.h mntab.h +dsp56k_mach.o: dsp56k_mach.c dsp56k_mach.h rmac.h symbol.h dsp56k_amode.h \ + amode.h direct.h token.h dsp56k.h sect.h riscasm.h error.h kwtab.h \ + dsp56ktab.h +dsp56kgen: dsp56kgen.c eagen.o: eagen.c eagen.h rmac.h symbol.h amode.h error.h fltpoint.h \ mach.h mark.h riscasm.h sect.h token.h eagen0.c error.o: error.c error.h rmac.h symbol.h listing.h token.h expr.o: expr.c expr.h rmac.h symbol.h direct.h token.h error.h listing.h \ mach.h procln.h riscasm.h sect.h kwtab.h fltpoint.o: fltpoint.c fltpoint.h -kwgen.o: kwgen.c +kwgen: kwgen.c listing.o: listing.c listing.h rmac.h symbol.h error.h procln.h token.h \ - sect.h version.h + sect.h riscasm.h version.h mach.o: mach.c mach.h rmac.h symbol.h amode.h direct.h token.h eagen.h \ error.h expr.h procln.h riscasm.h sect.h kwtab.h 68ktab.h macro.o: macro.c macro.h rmac.h symbol.h debug.h direct.h token.h error.h \ @@ -183,20 +131,20 @@ macro.o: macro.c macro.h rmac.h symbol.h debug.h direct.h token.h error.h \ mark.o: mark.c mark.h rmac.h symbol.h error.h object.h riscasm.h sect.h object.o: object.c object.h rmac.h symbol.h 6502.h direct.h token.h \ error.h mark.h riscasm.h sect.h -op.o: op.c op.h rmac.h symbol.h direct.h token.h error.h expr.h \ - fltpoint.h mark.h procln.h riscasm.h sect.h +op.o: op.c op.h direct.h rmac.h symbol.h token.h error.h expr.h \ + fltpoint.h mark.h procln.h riscasm.h sect.h opkw.h procln.o: procln.c procln.h rmac.h symbol.h token.h 6502.h amode.h \ - direct.h error.h expr.h listing.h mach.h macro.h op.h riscasm.h sect.h \ - kwtab.h mntab.h risckw.h 6502kw.h opkw.h + direct.h dsp56kkw.h error.h expr.h listing.h mach.h macro.h op.h riscasm.h \ + sect.h kwtab.h mntab.h risckw.h 6502kw.h opkw.h riscasm.o: riscasm.c riscasm.h rmac.h symbol.h amode.h direct.h token.h \ error.h expr.h mark.h procln.h sect.h risckw.h kwtab.h rmac.o: rmac.c rmac.h symbol.h 6502.h debug.h direct.h token.h error.h \ expr.h listing.h mark.h macro.h object.h procln.h riscasm.h sect.h \ version.h -sect.o: sect.c sect.h rmac.h symbol.h 6502.h direct.h token.h error.h \ - expr.h listing.h mach.h mark.h riscasm.h +sect.o: sect.c sect.h rmac.h symbol.h riscasm.h 6502.h direct.h token.h \ + error.h expr.h listing.h mach.h mark.h symbol.o: symbol.c symbol.h error.h rmac.h listing.h object.h procln.h \ token.h token.o: token.c token.h rmac.h symbol.h direct.h error.h macro.h \ - procln.h sect.h kwtab.h + procln.h sect.h riscasm.h kwtab.h diff --git a/procln.c b/procln.c index eb74281..d7bf53c 100644 --- a/procln.c +++ b/procln.c @@ -10,6 +10,8 @@ #include "6502.h" #include "amode.h" #include "direct.h" +#include "dsp56k_amode.h" +#include "dsp56k_mach.h" #include "error.h" #include "expr.h" #include "listing.h" @@ -39,6 +41,11 @@ #define DECL_MO // Include OP keyword state machine tables #include "opkw.h" +#define DEF_DSP // Include DSP56K keywords definitions +#define DECL_DSP // Include DSP56K keyword state machine tables +#include "dsp56kkw.h" + + IFENT * ifent; // Current ifent static IFENT ifent0; // Root ifent IFENT * f_ifent; // Freelist of ifents @@ -696,6 +703,93 @@ When checking to see if it's already been equated, issue a warning. } } + // If we are in 56K mode and still in need of a mnemonic then search for one + if (dsp56001 && ((state < 0) || (state >= 1000))) + { + for(state=0, p=opname; state>=0;) + { + j = dspbase[state] + (int)tolowertab[*p]; + + // Reject, character doesn't match + if (dspcheck[j] != state) + { + state = -1; // No match + break; + } + + // Must accept or reject at EOS + if (!*++p) + { + state = dspaccept[j]; // (-1 on no terminal match) + break; + } + + state = dsptab[j]; + } + + // Call DSP code generator if we found a mnemonic + if (state >= 2000) + { + LONG parcode; + int operands; + MNTABDSP * md = &dsp56k_machtab[state - 2000]; + deposit_extra_ea = 0; // Assume no extra word needed + + if (md->mnfunc == dsp_mult) + { + // Special case for multiplication instructions: they require + // 3 operands + if ((operands = dsp_amode(3)) == ERROR) + goto loop; + } + else if ((md->mnattr & PARMOVE) && md->mn0 != M_AM_NONE) + { + if (dsp_amode(2) == ERROR) + goto loop; + } + else if ((md->mnattr & PARMOVE) && md->mn0 == M_AM_NONE) + { + // Instructions that have parallel moves but use no operands + // (probably only move). In this case, don't parse addressing + // modes--just go straight to parallel parse + dsp_am0 = dsp_am1 = M_AM_NONE; + } + else + { + // Non parallel move instructions can have up to 4 parameters + // (well, only tcc instructions really) + if ((operands = dsp_amode(4)) == ERROR) + goto loop; + + if (operands == 4) + { + dsp_tcc4(md->mninst); + goto loop; + } + } + + if (md->mnattr & PARMOVE) + { + // Check for parallel moves + if ((parcode = parmoves(dsp_a1reg)) == ERROR) + goto loop; + } + else + { + if (*tok != EOL) + error("parallel moves not allowed with this instruction"); + + parcode = 0; + } + + while ((dsp_am0 & md->mn0) == 0 || (dsp_am1 & md->mn1) == 0) + md = &dsp56k_machtab[md->mncont]; + + (*md->mnfunc)(md->mninst | (parcode << 8)); + goto loop; + } + } + // Invoke macro or complain about bad mnemonic if (state < 0) { @@ -760,16 +854,11 @@ When checking to see if it's already been equated, issue a warning. // Keep a backup of chptr (used for optimisations during codegen) chptr_opcode = chptr; - for(;;) - { - if ((m->mnattr & siz) && (amsk0 & m->mn0) != 0 && (amsk1 & m->mn1) != 0) - { - (*m->mnfunc)(m->mninst, siz); - goto loop; - } - + while ((m->mnattr & siz) && (amsk0 & m->mn0) == 0 || (amsk1 & m->mn1) == 0) m = &machtab[m->mncont]; - } + + (*m->mnfunc)(m->mninst, siz); + goto loop; } diff --git a/risctab b/risc.tab similarity index 100% rename from risctab rename to risc.tab diff --git a/rmac.h b/rmac.h index f282460..cf8aabc 100644 --- a/rmac.h +++ b/rmac.h @@ -219,7 +219,12 @@ PTR #define DATA 0x0002 // Relative to data #define BSS 0x0004 // Relative to BSS #define M6502 0x0008 // 6502/microprocessor (absolute) +#define M56001P 0x0010 // DSP 56001 Program RAM +#define M56001X 0x0020 // DSP 56001 X RAM +#define M56001Y 0x0040 // DSP 56001 Y RAM +#define M56001L 0x0080 // DSP 56001 L RAM #define TDB (TEXT|DATA|BSS) // Mask for text+data+bss +#define M56KPXYL (M56001P|M56001X|M56001Y|M56001L) // Mask for 56K stuff // Sizes #define SIZB 0x0001 // .b diff --git a/sect.c b/sect.c index 59f7977..b076ca6 100644 --- a/sect.c +++ b/sect.c @@ -91,12 +91,12 @@ void InitSection(void) // void MakeSection(int sno, uint16_t attr) { - SECT * p = §[sno]; - p->scattr = attr; - p->sloc = 0; - p->orgaddr = 0; - p->scode = p->sfcode = NULL; - p->sfix = p->sffix = NULL; + SECT * sp = §[sno]; + sp->scattr = attr; + sp->sloc = 0; + sp->orgaddr = 0; + sp->scode = sp->sfcode = NULL; + sp->sfix = sp->sffix = NULL; } @@ -108,15 +108,15 @@ void SwitchSection(int sno) { CHUNK * cp; cursect = sno; - SECT * p = §[sno]; + SECT * sp = §[sno]; m6502 = (sno == M6502); // Set 6502-mode flag // Copy section vars - scattr = p->scattr; - sloc = p->sloc; - scode = p->scode; - orgaddr = p->orgaddr; + scattr = sp->scattr; + sloc = sp->sloc; + scode = sp->scode; + orgaddr = sp->orgaddr; // Copy code chunk vars if ((cp = scode) != NULL) @@ -126,6 +126,12 @@ void SwitchSection(int sno) chptr = cp->chptr + ch_size; // For 6502 mode, add the last org'd address +// Why? +/* +Because the way this is set up it treats the 6502 assembly space as a single 64K space (+ 16 bytes, for some reason) and just bobbles around inside that space and uses a stack of org "pointers" to show where the data ended up. + +This is a piss poor way to handle things, and for fucks sake, we can do better than this! +*/ if (m6502) chptr = cp->chptr + orgaddr; } @@ -139,11 +145,11 @@ void SwitchSection(int sno) // void SaveSection(void) { - SECT * p = §[cursect]; + SECT * sp = §[cursect]; - p->scattr = scattr; // Bailout section vars - p->sloc = sloc; - p->orgaddr = orgaddr; + sp->scattr = scattr; // Bailout section vars + sp->sloc = sloc; + sp->orgaddr = orgaddr; if (scode != NULL) // Bailout code chunk scode->ch_size = ch_size; @@ -711,7 +717,6 @@ int ResolveFixups(int sno) if (fup->orgaddr) addr = fup->orgaddr; - eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21); } else if (w & FU_OBJDATA) diff --git a/sect.h b/sect.h index 11ddfd4..83bc7b5 100644 --- a/sect.h +++ b/sect.h @@ -10,6 +10,7 @@ #define __SECT_H__ #include "rmac.h" +#include "riscasm.h" // Macros to deposit code in the current section (in Big Endian) #define D_byte(b) {chcheck(1);*chptr++=(uint8_t)(b); sloc++; ch_size++; \ @@ -38,7 +39,7 @@ sloc+=2; ch_size+=2;if(orgactive) orgaddr += 2;} // Macro for the 56001. Word size on this device is 24 bits wide. I hope that -// orgaddr += 1 means that the addresses in the device reflect this. +// orgaddr += 1 means that the addresses in the device reflect this. [A: Yes.] #define D_dsp(w) {chcheck(3);*chptr++=(uint8_t)(w>>16); \ *chptr++=(uint8_t)(w>>8); *chptr++=(uint8_t)w; \ sloc+=1; ch_size += 3; if(orgactive) orgaddr += 1; \ @@ -77,6 +78,8 @@ #define FU_BYTEH 0x0008 // Fixup 6502 high byte of immediate word #define FU_BYTEL 0x0009 // Fixup 6502 low byte of immediate word #define FU_QUAD 0x000A // Fixup quad-word (8 bytes) +#define FU_56001 0x000B // Generic fixup code for all 56001 modes +#define FU_56001_B 0x000C // Generic fixup code for all 56001 modes (ggn: I have no shame) #define FU_SEXT 0x0010 // Ok to sign extend #define FU_PCREL 0x0020 // Subtract PC first @@ -99,14 +102,34 @@ #define FU_DONE 0x8000 // Fixup has been done // FPU fixups -#define FU_FLOATSING 0x000B // Fixup 32-bit float -#define FU_FLOATDOUB 0x000C // Fixup 64-bit float -#define FU_FLOATEXT 0x000D // Fixup 96-bit float +#define FU_FLOATSING 0x000D // Fixup 32-bit float +#define FU_FLOATDOUB 0x000E // Fixup 64-bit float +#define FU_FLOATEXT 0x000F // Fixup 96-bit float // OP fixups #define FU_OBJLINK 0x10000 // Fixup OL link addr (bits 24-42, drop last 3) #define FU_OBJDATA 0x20000 // Fixup OL data addr (bits 43-63, drop last 3) +// DSP56001 fixups +// TODO: Sadly we don't have any spare bits left inside a 16-bit word +// so we use the 2nd nibble as control code and +// stick $B or $C in the lower nibble - then it's picked up as +// FU_56001 by the fixup routine and then a second switch +// selects fixup mode. Since we now have 32 bits, we can fix this! +// [N.B.: This isn't true anymore, we now have 32 bits! :-P] +#define FU_DSPIMM5 0x090B // Fixup 5-bit immediate +#define FU_DSPADR12 0x0A0B // Fixup 12-bit address +#define FU_DSPADR24 0x0B0B // Fixup 24-bit address +#define FU_DSPADR16 0x0C0B // Fixup 24-bit address +#define FU_DSPIMM12 0x0D0B // Fixup 12-bit immediate +#define FU_DSPIMM24 0x0E0B // Fixup 24-bit immediate +#define FU_DSPIMM8 0x0F0B // Fixup 8-bit immediate +#define FU_DSPADR06 0x090C // Fixup 6-bit address +#define FU_DSPPP06 0x0A0C // Fixup 6 bit pp address +#define FU_DSPIMMFL8 0x0B0C // Fixup 8-bit immediate float +#define FU_DSPIMMFL16 0x0C0C // Fixup 16-bit immediate float +#define FU_DSPIMMFL24 0x0D0C // Fixup 24-bit immediate float + // Chunks are used to hold generated code and fixup records #define CHUNK struct _chunk diff --git a/token.h b/token.h index e20402b..59e6ff5 100644 --- a/token.h +++ b/token.h @@ -63,6 +63,8 @@ #define DOTQ 'Q' // .q or .Q (essentially an alias for P) #define DOTS 'S' // .s or .S (FPU Single) #define ENDEXPR 'E' // End of expression +#define UNLT 0x81 // Unary '<' (low byte) +#define UNGT 0x82 // Unary '>' (high byte) // ^^ operators #define CR_DEFINED 'p' // ^^defined - is symbol defined?