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 -68ktab.h 68kmn : 68ktab 68ktab 68kgen - ./68kgen 68kmn <68ktab >68ktab.h +dsp56ktab.h dsp56k.tab: dsp56k.mch dsp56kgen + ./dsp56kgen dsp56k.tab dsp56ktab.h -kwtab.h : kwtab kwgen - ./kwgen kw kwtab.h +mntab.h: direct.tab 68k.tab kwgen + cat direct.tab 68k.tab | ./kwgen mn >mntab.h -6502kw.h : 6502.tbl kwgen - ./kwgen mp <6502.tbl >6502kw.h +kwtab.h: kw.tab kwgen + ./kwgen kw kwtab.h -risckw.h : kwtab kwgen - ./kwgen mr risckw.h +6502kw.h: 6502.tab kwgen + ./kwgen mp <6502.tab >6502kw.h -opkw.h : op.tab kwgen +risckw.h: risc.tab kwgen + ./kwgen mr risckw.h + +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 +%.o: %.c %.h + $(CC) $(CFLAGS) -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 - -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?