/* m68k_sys.c: assembler/disassembler/misc simfuncs for generic m68k_cpu | |
Copyright (c) 2009, Holger Veit | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
Holger Veit BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
Except as contained in this notice, the name of Holger Veit et al shall not be | |
used in advertising or otherwise to promote the sale, use or other dealings | |
in this Software without prior written authorization from Holger Veit et al. | |
04-Oct-09 HV Initial version | |
15-Mar-10 HV fix 2nd arg bug in disassembling btst | |
24-Apr-10 HV fix _fsymea for jsr.l | |
27-Apr-10 HV fix stop instr | |
27-Jun-10 HV improve error handling in Motorola S0 reader | |
20-Jul-10 HV fix disassemble error for LINK | |
*/ | |
#include "m68k_cpu.h" | |
#include <ctype.h> | |
#include <string.h> | |
#if defined(_WIN32) | |
#include <windows.h> | |
#else | |
#include <unistd.h> | |
#endif | |
t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc) | |
{ | |
DEVICE* dptr; | |
PNP_INFO* pnp; | |
t_stat rc; | |
uint16 newbase; | |
if (!cptr) return SCPE_ARG; | |
if (!uptr) return SCPE_IERR; | |
if (!(dptr = find_dev_from_unit(uptr))) return SCPE_IERR; | |
if (!(pnp = (PNP_INFO*)dptr->ctxt)) return SCPE_IERR; | |
newbase = get_uint (cptr, 16, 0xFF, &rc); | |
if (rc != SCPE_OK) return rc; | |
if (dptr->flags & DEV_DIS) { | |
printf("Device not enabled yet.\n"); | |
pnp->io_base = newbase; | |
} else { | |
dptr->flags |= DEV_DIS; | |
dptr->reset(dptr); | |
pnp->io_base = newbase; | |
dptr->flags &= ~DEV_DIS; | |
dptr->reset(dptr); | |
} | |
return SCPE_OK; | |
} | |
t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, CONST void *desc) | |
{ | |
DEVICE *dptr; | |
PNP_INFO *pnp; | |
if (!uptr) return SCPE_IERR; | |
if (!(dptr = find_dev_from_unit(uptr))) return SCPE_IERR; | |
if (!(pnp = (PNP_INFO *) dptr->ctxt)) return SCPE_IERR; | |
fprintf(st, "I/O=0x%02X-0x%02X", pnp->io_base, pnp->io_base + pnp->io_size - pnp->io_incr); | |
return SCPE_OK; | |
} | |
t_stat m68k_set_cpu(UNIT *uptr, int32 value, CONST char *cptr, void *desc) | |
{ | |
if (value < 0 || value > CPU_TYPE_68030) | |
return SCPE_ARG; | |
cputype = (value & UNIT_CPUTYPE_MASK) >> UNIT_CPU_V_TYPE; | |
uptr->flags &= ~UNIT_CPUTYPE_MASK; | |
uptr->flags |= value; | |
return SCPE_OK; | |
} | |
t_stat m68k_show_cpu(FILE* st,UNIT *uptr, int32 value, CONST void *desc) | |
{ | |
fprintf(st,"TYPE=%s",(const char *)desc); | |
return SCPE_OK; | |
} | |
t_stat m68k_alloc_mem() | |
{ | |
if (M == NULL) | |
M = (uint8*)calloc(MEMORYSIZE, 1); | |
else | |
M = (uint8*)realloc(M, MEMORYSIZE); | |
return M == NULL ? SCPE_MEM : SCPE_OK; | |
} | |
t_stat m68k_set_size(UNIT *uptr, int32 value, CONST char *cptr, void *desc) | |
{ | |
t_stat rc; | |
uptr->capac = value; | |
if ((rc=m68k_alloc_mem()) != SCPE_OK) return rc; | |
return SCPE_OK; | |
} | |
t_stat m68k_set_fpu(UNIT *uptr, int32 value, CONST char *cptr, void *desc) | |
{ | |
uptr->flags |= value; | |
return SCPE_OK; | |
} | |
t_stat m68k_set_nofpu(UNIT *uptr, int32 value, CONST char *cptr, void *desc) | |
{ | |
uptr->flags |= value; | |
return SCPE_OK; | |
} | |
t_stat m68kcpu_set_flag(UNIT *uptr, int32 value, CONST char *cptr, void *desc) | |
{ | |
uptr->flags |= value; | |
return SCPE_OK; | |
} | |
t_stat m68kcpu_set_noflag(UNIT *uptr, int32 value, CONST char *cptr, void *desc) | |
{ | |
uptr->flags &= ~value; | |
return SCPE_OK; | |
} | |
t_stat m68kcpu_ex(t_value* eval_array, t_addr addr, UNIT* uptr, int32 sw) | |
{ | |
uint32 val = 0; | |
t_stat rc = (sw & SWMASK('V')) ? ReadVW(addr,&val) : ReadPW(addr,&val); | |
if (rc==SCPE_OK) *eval_array = val; | |
return rc; | |
} | |
t_stat m68kcpu_dep(t_value value, t_addr addr, UNIT* uptr, int32 sw) | |
{ | |
return (sw & SWMASK('V')) ? WriteVW(addr,value) : WritePW(addr,value); | |
} | |
static int getHex(FILE* fptr,int* chksum) | |
{ | |
char buf[3]; | |
int c; | |
if ((c = fgetc(fptr))==EOF) return EOF; | |
buf[0] = c; | |
if ((c = fgetc(fptr))==EOF) return EOF; | |
buf[1] = c; | |
buf[2] = 0; | |
return strtol(buf,0,16); | |
} | |
/* Motorola S-Record reader | |
* Format: | |
* type 2 Bytes (S0, S1, S2, S3, S5, S7, S8, S9) | |
* reclength 2 Bytes | |
* address 4,6,8 Bytes | |
* data 0...2n | |
* checksum 2 Bytes (lsb of 1'comp of fields reclength-data | |
*/ | |
static t_stat m68k_sread(FILE* fptr) | |
{ | |
int typ; | |
t_addr addr=0, a; | |
int d, len, chksum, i; | |
int end = FALSE; | |
int line = 0; | |
fseek(fptr,0l,SEEK_SET); | |
for(;;) { | |
while ((i = fgetc(fptr)) == '\r' || i == '\n'); | |
line++; | |
if (end && i == EOF) return SCPE_OK; | |
if (i != 'S') { printf("Line %d: expected S but did not find one (found %x)\n",line,i); return SCPE_FMT; } | |
typ = fgetc(fptr); | |
chksum = 0; | |
len = getHex(fptr,&chksum); | |
addr = getHex(fptr,&chksum); | |
a = getHex(fptr,&chksum); | |
if (len==EOF || addr==EOF || a==EOF) { typ = 'X'; goto error; } | |
addr = (addr << 8) | a; | |
i = 3; | |
switch (typ) { | |
case '0': | |
for (i=2; i<len; i++) (void)getHex(fptr,&chksum); | |
break; | |
case '1': | |
i = 2; | |
goto dread; | |
case '3': | |
if ((a = getHex(fptr,&chksum))==EOF) goto error; | |
addr = (addr << 8) | a; | |
i = 4; | |
/*fallthru*/ | |
case '2': | |
if ((a = getHex(fptr,&chksum))==EOF) goto error; | |
addr = (addr << 8) | a; | |
dread: | |
for (; i<len; i++) { d = getHex(fptr,&chksum); WritePB(addr,d); addr++; } | |
break; | |
case '7': | |
if ((a = getHex(fptr,&chksum))==EOF) goto error; | |
addr = (addr << 8) | a; | |
/*fallthru*/ | |
case '8': | |
if ((a = getHex(fptr,&chksum))==EOF) goto error; | |
addr = (addr << 8) | a; | |
/*fallthru*/ | |
case '9': | |
end = TRUE; | |
/*fallthru*/ | |
case '5': | |
if((d = getHex(fptr,&chksum))==EOF) goto error; | |
break; | |
} | |
if ((chksum & 0xff) != 0) return SCPE_CSUM; | |
saved_PC = addr; | |
} | |
error: | |
printf("S%c at line %d: Unexpected EOF/Invalid character\n",typ,line); | |
return SCPE_FMT; | |
} | |
t_stat sim_load(FILE* fptr, CONST char* cptr, CONST char* fnam, t_bool flag) | |
{ | |
int i,len,rc; | |
uint16 data; | |
uint8 s; | |
int32 addr = saved_PC; | |
/* no dump */ | |
if (*cptr != 0 || flag != 0) return SCPE_ARG; | |
/* check whether Motorola S-Record format was presented */ | |
fseek(fptr,0L,SEEK_SET); | |
if (fread(&s,sizeof(uint8),1,fptr) == 1) { | |
if (s == 'S') { | |
/* asssume S record format */ | |
if (m68k_sread(fptr) == SCPE_OK) return SCPE_OK; | |
} | |
} | |
/* assume plain octet word stream */ | |
fseek(fptr,0L,SEEK_END); | |
len = ftell(fptr); | |
if (len & 1) return SCPE_FMT; | |
fseek(fptr,0L,SEEK_SET); | |
for (i=0; i<len; i+=2) { | |
if (fread(&data,sizeof(uint16),1,fptr) != 1) return SCPE_FMT; | |
if ((rc=WritePW(addr,data)) != SCPE_OK) return rc; | |
addr += 2; | |
} | |
return SCPE_OK; | |
} | |
const char *sim_stop_messages[] = { | |
"---", | |
"PC Breakpoint", | |
"MEM Breakpoint", | |
"Invalid Opcode", | |
"Invalid I/O address", | |
"Invalid Mem access", | |
"Not yet implemented!", | |
"(internal: IO dispatch)", | |
"(internal: nonexisting memory)", | |
"PC at I/O address", | |
"Privilege Violation", | |
"Trace trap", | |
"STOP instruction", | |
"Double Bus Fault", | |
"Printer Offline", | |
}; | |
#define ONERR_QUIT() if (rc==SCPE_ARG) { printf("??\n\t"); return SCPE_ARG; } | |
#define REG0_FIELD(inst) (inst&7) | |
#define REG0_CHAR(inst) (inst&7) + '0' | |
#define REG9_CHAR(inst) ((inst>>9)&7) + '0' | |
#define OPLEN_FIELD(inst) (inst>>6)&3 | |
#define EA_FIELD(inst) inst&077 | |
#define EAMOD_FIELD(inst) inst & 070 | |
#define BWL_CHAR(oplen) (oplen==0) ? 'b' : ((oplen==1) ? 'w' : 'l') | |
#define DATA_B(x) (x&0xff) | |
#define DATA_W(x) (x&0xffff) | |
/* Use scp.c provided fprintf function */ | |
#define fprintf Fprintf | |
#define fputs(_s,f) Fprintf(f,"%s",_s) | |
#define fputc(_c,f) Fprintf(f,"%c",_c) | |
static t_stat _fsymea(FILE* of,t_addr addr,int ea, int oplen,t_value* rest) | |
{ | |
int eamod = EAMOD_FIELD(ea); | |
char eareg = REG0_CHAR(ea); | |
t_value offb = DATA_B(rest[0]); | |
t_value offw = DATA_W(rest[0]); | |
t_value offw2 = DATA_W(rest[1]); | |
char da = (rest[0] & 0x8000)? 'a' : 'd'; | |
char xreg = ((rest[0]>>12) & 7) + '0'; | |
char wl = (rest[0] & 0x800) ? 'l' : 'w'; | |
switch (eamod) { | |
case 000: fprintf(of,"d%c",eareg); return 0; | |
case 010: fprintf(of,"a%c",eareg); return 0; | |
case 020: fprintf(of,"(a%c)",eareg); return 0; | |
case 030: fprintf(of,"(a%c)+",eareg); return 0; | |
case 040: fprintf(of,"-(a%c)",eareg); return 0; | |
case 050: fprintf(of,"($%x,a%c)",offw,eareg); return -2; | |
case 060: | |
if (offb) | |
fprintf(of,"($%x,a%c,%c%c.%c)",offb,eareg,da,xreg,wl); | |
else | |
fprintf(of,"(a%c,%c%c.%c)",eareg,da,xreg,wl); | |
return -2; | |
case 070: | |
switch (eareg) { | |
case '0': fprintf(of,"($%x).w",(uint32)((uint16)offw)); return -2; | |
case '1': | |
if (offw) | |
fprintf(of,"($%x%04x).l",offw,offw2); | |
else | |
fprintf(of,"($%x).l",offw2); | |
return -4; | |
case '2': //fprintf(of,"($%x,pc)",offw); | |
if (offw & 0x8000) offw |= 0xffff0000; | |
fprintf(of,"$%x",addr+offw+2); | |
return -2; | |
case '3': | |
if (offb) | |
fprintf(of,"($%x,pc,%c%c.%c)",offb,da,xreg,wl); | |
else | |
fprintf(of,"(pc,%c%c.%c)",da,xreg,wl); | |
return -2; | |
case '4': | |
switch(oplen) { | |
case 0: fprintf(of,"#$%x",offb); return -2; | |
case 1: fprintf(of,"#$%x",offw); return -2; | |
case 2: | |
if (offw) | |
fprintf(of,"#$%x%04x",offw,offw2); | |
else | |
fprintf(of,"#$%x",offw2); | |
return -4; | |
case 3: fprintf(of,"ccr"); return 0; | |
case 4: fprintf(of,"sr"); return 0; | |
default: return SCPE_ARG; | |
} | |
default: return SCPE_ARG; | |
} | |
default: return SCPE_ARG; | |
} | |
} | |
static t_stat _fsymead(FILE* of,int dir,char reg9,t_addr addr,int ea,int oplen,t_value* rest) | |
{ | |
int rc; | |
if (dir) { | |
fprintf(of,"d%c,",reg9); rc = _fsymea(of,addr,ea,oplen,rest); | |
} else { | |
rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); fprintf(of,",d%c",reg9); | |
} | |
return rc-1; | |
} | |
static t_stat _fsymimm(FILE* of,int oplen,t_value* rest) | |
{ | |
t_value offb = rest[0] & 0xff; | |
t_value offw = rest[0] & 0xffff; | |
t_value offw2 = rest[1] & 0xffff; | |
switch(oplen) { | |
case 0: fprintf(of,"#$%x",offb); return 1; | |
case 1: fprintf(of,"#$%x",offw); return 1; | |
case 2: fprintf(of,"#$%x%04x",offw,offw2); return 2; | |
default: return SCPE_ARG; | |
} | |
} | |
static t_stat _fsym0(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
int rc; | |
int oplen = OPLEN_FIELD(inst); | |
char bwl = BWL_CHAR(oplen); | |
char reg9 = REG9_CHAR(inst); | |
char reg0 = REG0_CHAR(inst); | |
int bitnum= DATA_B(rest[0]); | |
int ea = EA_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
const char* s = 0; | |
switch (inst & 000700) { | |
case 000400: | |
if (eamod==010) { | |
fprintf(of,"movep.w $%x(a%c),d%c",rest[0],reg0,reg9); return -3; | |
} else s = "btst"; | |
break; | |
case 000500: | |
if (eamod==010) { | |
fprintf(of,"movep.l $%x(a%c),d%c",rest[0],reg0,reg9); return -3; | |
} else s = "bchg"; | |
break; | |
case 000600: | |
if (eamod==010) { | |
fprintf(of,"movep.w d%c,$%x(a%c)",reg9,rest[0],reg0); return -3; | |
} else s = "bclr"; | |
break; | |
case 000700: | |
if (eamod==010) { | |
fprintf(of,"movep.l d%c,$%x(a%c)",reg9,rest[0],reg0); return -3; | |
} else s = "bset"; | |
break; | |
} | |
if (s) { | |
fprintf(of,"%s d%c,",s,reg9); rc = _fsymea(of,addr,ea,3,rest); ONERR_QUIT(); return rc-1; | |
} | |
switch (inst & 007000) { | |
case 000000: | |
s = "ori"; break; | |
case 001000: | |
s = "andi"; break; | |
case 002000: | |
s = "subi"; break; | |
case 003000: | |
s = "addi"; break; | |
case 004000: | |
switch (inst & 000700) { | |
case 000000: | |
s = "btst"; break; | |
case 000100: | |
s = "bchg"; break; | |
case 000200: | |
s = "bclr"; break; | |
case 000300: | |
s = "bset"; break; | |
default: | |
return SCPE_ARG; | |
} | |
fprintf(of,"%s #%x,",s,bitnum); rc = _fsymea(of,addr,ea,0,rest+1); ONERR_QUIT(); return rc-3; | |
case 005000: | |
s = "eori"; break; | |
case 006000: | |
s = "cmpi"; break; | |
default: | |
return SCPE_ARG; | |
} | |
fprintf(of,"%s.%c ",s,bwl); rc = _fsymimm(of,oplen,rest); ONERR_QUIT(); | |
fputc(',',of); rc = _fsymea(of,addr,ea,oplen+3,rest+rc); | |
return rc - 3 - ((oplen==2) ? 2 : 0); | |
} | |
static t_stat _fsym123(FILE* of,t_value inst,t_addr addr,t_value* rest,char w,int oplen) | |
{ | |
int rc, rc2; | |
int eas = inst & 077; | |
int eat = ((inst>>9)&7)|((inst&0700)>>3); | |
const char *s = ((eat&070)==010) ? "movea" : "move"; | |
fprintf(of,"%s.%c ",s,w); | |
rc = _fsymea(of,addr,eas,oplen,rest); ONERR_QUIT(); rc2 = rc; | |
fputc(',',of); | |
rc = _fsymea(of,addr,eat,oplen,rest-rc2/2); ONERR_QUIT(); | |
return rc2 + rc -1; | |
} | |
static const char* moveregs[] = { | |
"d0","d1","d2","d3","d4","d5","d6","d7","a0","a1","a2","a3","a4","a5","a6","a7" | |
}; | |
static const char* moveregsp[] = { | |
"a7","a6","a5","a4","a3","a2","a1","a0","d7","d6","d5","d4","d3","d2","d1","d0" | |
}; | |
#define BITEMIT() if (sl) fputc('/',of); sl = 1; \ | |
if (hi==lo) fprintf(of,"%s",regs[lo]); \ | |
else if (ispredec) fprintf(of,"%s-%s",regs[hi],regs[lo]); \ | |
else fprintf(of,"%s-%s",regs[lo],regs[hi]); \ | |
lo = hi = -1; | |
#define BITSEQ() bit = regset & 1; regset >>= 1; \ | |
if (bit && lo == -1) lo = i; \ | |
if (bit == 0 && lo != -1) { hi = i-1; BITEMIT(); } | |
static void _fsymregs(FILE* of, int regset,int ispredec) | |
{ | |
int lo, hi, bit, sl, i; | |
const char** regs = ispredec ? moveregsp : moveregs; | |
//printf("regset=%x\n",regset); | |
sl = 0; | |
bit = lo = hi = -1; | |
for (i=0; i<8; i++) { BITSEQ(); } | |
if (lo != -1) { hi = 7; BITEMIT(); } | |
bit = -1; | |
for (i=8; i<16; i++) { BITSEQ(); } | |
if (lo != -1) { hi = 15; BITEMIT(); } | |
} | |
static t_stat _fsym4(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
t_stat rc; | |
char reg9 = REG9_CHAR(inst); | |
int ea = EA_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
char reg0 = REG0_CHAR(inst); | |
int oplen = OPLEN_FIELD(inst); | |
const char* s; | |
switch (inst & 000700) { | |
case 000600: | |
fprintf(of,"chk "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); | |
fprintf(of,",d%c",reg9); return rc-1; | |
case 000700: | |
fprintf(of,"lea "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9); return rc-1; | |
case 000000: | |
switch (inst & 007000) { | |
case 000000: | |
s = "negx.b "; break; | |
case 001000: | |
s = "clr.b "; break; | |
case 002000: | |
s = "neg.b "; break; | |
case 003000: | |
s = "not.b "; break; | |
case 004000: | |
s = "nbcd "; break; | |
case 005000: | |
s = "tst.b "; break; | |
default: | |
return SCPE_ARG; | |
} | |
fputs(s,of); rc = _fsymea(of,addr,ea,0,rest); ONERR_QUIT(); return rc-1; | |
case 000100: | |
switch (inst & 007000) { | |
case 007000: | |
switch (inst & 000070) { | |
case 000000: | |
case 000010: | |
fprintf(of,"trap #$%x",inst & 0xf); return -1; | |
case 000020: | |
fprintf(of,"link a%c,#$%x",reg0,rest[0]); return -3; | |
case 000030: | |
fprintf(of,"unlk a%c",reg0); return -1; | |
case 000040: | |
fprintf(of,"move a%c,usp",reg0); return -1; | |
case 000050: | |
fprintf(of,"move usp,a%c",reg0); return -1; | |
case 000060: | |
switch (inst & 000007) { | |
case 000000: | |
s = "reset"; break; | |
case 000001: | |
s = "nop"; break; | |
case 000002: | |
fprintf(of,"stop #%x",DATA_W(rest[0])); return -3; | |
case 000003: | |
s = "rte"; break; | |
case 000005: | |
s = "rts"; break; | |
case 000006: | |
s = "trapv"; break; | |
case 000007: | |
s = "rtr"; break; | |
default: | |
return SCPE_ARG; | |
} | |
fputs(s,of); return -1; | |
default: | |
return SCPE_ARG; | |
} | |
case 000000: | |
s = "negx.w "; break; | |
case 001000: | |
s = "clr.w "; break; | |
case 002000: | |
s = "neg.w "; break; | |
case 003000: | |
s = "not.w "; break; | |
case 005000: | |
s = "tst.w "; break; | |
case 004000: | |
if (eamod==0) { | |
fprintf(of,"swap d%c",reg0); return -1; | |
} else { | |
fputs("pea ",of); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); return rc-1; | |
} | |
default: | |
return SCPE_ARG; | |
} | |
fputs(s,of); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); return rc-1; | |
case 000200: | |
switch (inst & 007000) { | |
case 000000: | |
s = "negx.l "; break; | |
case 001000: | |
s = "clr.l "; break; | |
case 002000: | |
s = "neg.l "; break; | |
case 003000: | |
s = "not.l "; break; | |
case 004000: | |
if (eamod==0) { | |
fprintf(of,"ext.w d%c",reg0); return -1; | |
} else { | |
fprintf(of,"movem.w "); _fsymregs(of,rest[0],eamod==040); | |
fputc(',',of); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); return rc-3; | |
} | |
case 005000: | |
s = "tst.l "; break; | |
case 006000: | |
fprintf(of,"movem.w "); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); | |
fputc(',',of); _fsymregs(of,rest[0],0); return rc-3; | |
case 007000: | |
s = "jsr "; break; | |
default: | |
return SCPE_ARG; | |
} | |
fputs(s,of); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); return rc-1; | |
case 000300: | |
switch (inst & 007000) { | |
case 000000: | |
fprintf(of,"move sr,"); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); return rc-1; | |
case 003000: | |
fprintf(of,"move "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); fputs(",sr",of); return rc-1; | |
case 002000: | |
fprintf(of,"move "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); fputs(",ccr",of); return rc-1; | |
case 004000: | |
if (eamod==0) { | |
fprintf(of,"ext.l d%c",reg0); return -1; | |
} else { | |
fprintf(of,"movem.l "); _fsymregs(of,rest[0],eamod==040); | |
fputc(',',of); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); return rc-3; | |
} | |
case 005000: | |
switch (inst & 000077) { | |
case 000074: | |
fputs("illegal",of); return -1; | |
default: | |
fprintf(of,"tas "); rc = _fsymea(of,addr,ea,0,rest); return rc-1; | |
} | |
case 006000: | |
fprintf(of,"movem.l "); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); | |
fputc(',',of); _fsymregs(of,rest[0],0); return rc-3; | |
case 007000: | |
fputs("jmp ",of); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); return rc-1; | |
default: | |
return SCPE_ARG; | |
} | |
default: | |
return SCPE_ARG; | |
} | |
} | |
static const char* conds[] = { "ra","sr","hi","ls","cc","cs","ne","eq","vc","vs","pl","mi","ge","lt","gt","le" }; | |
static const char* conds2[] = { "t", "f","hi","ls","cc","cs","ne","eq","vc","vs","pl","mi","ge","lt","gt","le" }; | |
static t_stat _fsym5(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
t_stat rc; | |
int ea = EA_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
int reg0 = REG0_CHAR(inst); | |
int oplen = OPLEN_FIELD(inst); | |
char bwl = BWL_CHAR(oplen); | |
t_addr a; | |
if (oplen==3) { | |
const char* cond = conds2[(inst>>8)&0xf]; | |
if (eamod==010) { | |
a = rest[0] & 0xffff; | |
if (a & 0x8000) a |= 0xffff0000; | |
//printf("addr=%x a=%x sum=%x\n",addr,a,addr+a+2); | |
fprintf(of,"db%s d%c,$%x",cond,reg0,addr+a+2); | |
return -3; | |
} else { | |
fprintf(of,"s%s ",cond); rc = _fsymea(of,addr,ea,0,rest); return rc-3; | |
} | |
} else { | |
int data = (inst>>9) & 07; | |
const char *s = (inst & 0x0100) ? "subq" : "addq"; | |
if (data==0) data = 8; | |
fprintf(of,"%s.%c #%d,",s,bwl,data); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); return rc-1; | |
} | |
} | |
static t_stat _fsym6(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
const char* cond = conds[(inst>>8)&0xf]; | |
t_addr a = inst & 0xff; | |
if (a) { | |
if (a & 0x80) a |= 0xffffff00; | |
fprintf(of,"b%s.s $%x",cond,addr+a+2); return -1; | |
} else { | |
a = rest[0] & 0xffff; | |
if (a & 0x8000) a |= 0xffff0000; | |
fprintf(of,"b%s.w $%x",cond,addr+a+2); return -3; | |
} | |
} | |
static t_stat _fsym7(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
int reg9 = REG9_CHAR(inst); | |
switch (inst & 000400) { | |
case 000000: | |
fprintf(of,"moveq #$%x,d%c",(int32)((int8)(inst&0xff)),reg9); return -1; | |
default: | |
return SCPE_ARG; | |
} | |
} | |
static t_stat _fsym8(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
t_stat rc; | |
int oplen = OPLEN_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
int ea = EA_FIELD(inst); | |
char reg9 = REG9_CHAR(inst); | |
char reg0 = REG0_CHAR(inst); | |
char bwl = BWL_CHAR(oplen); | |
switch (inst & 000700) { | |
case 000000: | |
case 000100: | |
case 000200: | |
fprintf(of,"or.%c ",bwl); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); | |
fprintf(of,",d%c",reg9); return rc-1; | |
case 000300: | |
fprintf(of,"divu.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); | |
fprintf(of,",d%c",reg9); return rc-1; | |
case 000400: | |
switch (eamod) { | |
case 000: | |
fprintf(of,"sbcd d%c,d%c",reg0,reg9); return -1; | |
case 010: | |
fprintf(of,"sbcd -(a%c),-(a%c)",reg0,reg9); return -1; | |
default: | |
fprintf(of,"or.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); | |
return rc-1; | |
} | |
case 000500: | |
case 000600: | |
fprintf(of,"or.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); | |
return rc-1; | |
case 000700: | |
fprintf(of,"divs.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); | |
fprintf(of,",d%c",reg9); return rc-1; | |
} | |
return SCPE_ARG; /* Not reached, but silence agressive compiler warnings */ | |
} | |
static t_stat _fsym9(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
t_stat rc; | |
int oplen = OPLEN_FIELD(inst); | |
char reg9 = REG9_CHAR(inst); | |
char reg0 = REG0_CHAR(inst); | |
char bwl = BWL_CHAR(oplen); | |
int ea = EA_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
switch (inst & 000700) { | |
case 000000: | |
case 000100: | |
case 000200: | |
fprintf(of,"sub.%c ",bwl); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); | |
fprintf(of,",d%c",reg9);return rc-1; | |
case 000300: | |
fprintf(of,"suba.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9);return rc-1; | |
case 000400: | |
switch (eamod) { | |
case 000: | |
fprintf(of,"subx.%c d%c,d%c",bwl,reg9,reg0); return -1; | |
case 001: | |
fprintf(of,"subx.%c d%c,d%c",bwl,reg9,reg0); return -1; | |
default: | |
fprintf(of,"sub.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); return rc-1; | |
} | |
case 000500: | |
case 000600: | |
fprintf(of,"sub.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); return rc-1; | |
case 000700: | |
fprintf(of,"suba.l "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9);return rc-1; | |
default: | |
return SCPE_ARG; | |
} | |
} | |
static t_stat _fsyma(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
fprintf(of,"trapa #$%x",inst&0xfff); return -1; | |
} | |
static t_stat _fsymb(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
int rc; | |
char reg9 = REG9_CHAR(inst); | |
char reg0 = REG0_CHAR(inst); | |
int ea = EA_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
int oplen = OPLEN_FIELD(inst); | |
char bwl = BWL_CHAR(oplen); | |
switch (inst & 000700) { | |
case 000000: | |
case 000100: | |
case 000200: | |
fprintf(of,"cmp.%c ",bwl); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); | |
fprintf(of,",d%c",reg9); return rc-1; | |
case 000300: | |
fprintf(of,"cmpa.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9); return rc-1; | |
case 000400: | |
case 000500: | |
case 000600: | |
if (eamod==010) { | |
fprintf(of,"cmpm.%c (a%c)+,(a%c)+",bwl,reg0,reg9); return -1; | |
} else { | |
fprintf(of,"eor.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); | |
return rc-1; | |
} | |
case 000700: | |
fprintf(of,"cmpa.l "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9); return rc-1; | |
default: | |
return SCPE_ARG; | |
} | |
} | |
static t_stat _fsymc(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
char reg9 = REG9_CHAR(inst); | |
int ea = EA_FIELD(inst); | |
int reg0 = REG0_CHAR(inst); | |
int oplen = OPLEN_FIELD(inst); | |
char bwl = BWL_CHAR(oplen); | |
switch (inst & 0000770) { | |
case 0000500: | |
fprintf(of,"exg d%c,d%c",reg9,reg0); return -1; | |
case 0000510: | |
fprintf(of,"exg a%c,a%c",reg9,reg0); return -1; | |
case 0000610: | |
fprintf(of,"exg d%c,a%c",reg9,reg0); return -1; | |
case 0000400: | |
fprintf(of,"abcd d%c,d%c",reg9,reg0); return -1; | |
case 0000410: | |
fprintf(of,"abcd -(a%c),-(a%c)",reg9,reg0); return -1; | |
default: | |
break; | |
} | |
switch (inst & 0000700) { | |
case 0000400: | |
fprintf(of,"and.%c ",bwl); return _fsymead(of,1,reg9,addr,ea,oplen,rest); | |
case 0000000: | |
case 0000100: | |
case 0000200: | |
fprintf(of,"and.%c ",bwl); return _fsymead(of,0,reg9,addr,ea,oplen,rest); | |
case 0000300: | |
fprintf(of,"mulu.w "); return _fsymead(of,0,reg9,addr,ea,1,rest); | |
case 0000700: | |
fprintf(of,"muls.w "); return _fsymead(of,0,reg9,addr,ea,1,rest); | |
default: | |
return SCPE_ARG; | |
} | |
} | |
static t_stat _fsymd(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
int rc; | |
char reg9 = REG9_CHAR(inst); | |
char reg0 = REG0_CHAR(inst); | |
int ea = EA_FIELD(inst); | |
int eamod = EAMOD_FIELD(inst); | |
int oplen = OPLEN_FIELD(inst); | |
char bwl = BWL_CHAR(oplen); | |
switch (inst & 000700) { | |
case 000000: | |
case 000100: | |
case 000200: | |
fprintf(of,"add.%c ",bwl); return _fsymead(of,0,reg9,addr,ea,oplen,rest); | |
case 000300: | |
fprintf(of,"adda.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9); return rc-1; | |
case 000400: | |
switch (eamod) { | |
case 000: | |
fprintf(of,"addx.%c d%c,d%c",bwl,reg9,reg0); return -1; | |
case 001: | |
fprintf(of,"addx.%c d%c,d%c",bwl,reg9,reg0); return -1; | |
default: | |
fprintf(of,"add.%c ",bwl); return _fsymead(of,1,reg9,addr,ea,oplen,rest); | |
} | |
case 000500: | |
case 000600: | |
fprintf(of,"add.%c ",bwl); return _fsymead(of,1,reg9,addr,ea,oplen,rest); | |
case 000700: | |
fprintf(of,"adda.l "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); | |
fprintf(of,",a%c",reg9); return rc-1; | |
} | |
return SCPE_ARG; /* Not reached, but silence agressive compiler warnings */ | |
} | |
static t_stat _fsyme(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
int rc; | |
int oplen = OPLEN_FIELD(inst); | |
char bwl = BWL_CHAR(oplen); | |
int op = (oplen==3 ? (inst>>9) : (inst>>3)) & 3; | |
char dir = (inst&0x100) ? 'l' : 'r'; | |
int ir = inst & 0x20; | |
int ea = EA_FIELD(inst); | |
char reg9 = REG9_CHAR(inst); | |
char reg0 = REG0_CHAR(inst); | |
const char *s; | |
switch (op) { | |
case 0: s = "as"; break; | |
case 1: s = "ls"; break; | |
case 2: s = "rox"; break; | |
case 3: s = "ro"; break; | |
default: s = "??"; break; | |
} | |
fprintf(of,"%s%c",s,dir); | |
if (oplen<3) { | |
fprintf(of,".%c ",bwl); | |
if (ir) | |
fprintf(of,"d%c,d%c",reg9,reg0); | |
else { | |
if (reg9=='0') reg9 = '8'; | |
fprintf(of,"#%d,d%c",reg9-'0',reg0); | |
} | |
return -1; | |
} else { | |
fputc(' ',of); | |
rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); return rc-1; | |
} | |
} | |
static t_stat _fsymf(FILE* of,t_value inst,t_addr addr,t_value* rest) | |
{ | |
fprintf(of,"trapf #$%x",inst&0xfff); return -1; | |
} | |
t_stat fprint_sym(FILE* of, t_addr addr, t_value* val, UNIT* uptr, int32 sw) | |
{ | |
int32 c1, c2, inst; | |
c1 = (val[0] >> 8) & 0177; | |
c2 = val[0] & 0177; | |
if (sw & SWMASK ('A')) { | |
fprintf (of, (c2 < 040)? "<%02x>": "%c", c2); | |
return SCPE_OK; | |
} | |
if (sw & SWMASK ('C')) { | |
fprintf (of, (c1 < 040)? "<%02x>": "%c", c1); | |
fprintf (of, (c2 < 040)? "<%02x>": "%c", c2); | |
return -1; | |
} | |
if (!(sw & SWMASK ('M'))) return SCPE_ARG; | |
inst = val[0]; | |
switch ((inst>>12) & 0xf) { | |
case 0x0: return _fsym0(of,inst,addr,val+1); | |
case 0x1: return _fsym123(of,inst,addr,val+1,'b',0); | |
case 0x2: return _fsym123(of,inst,addr,val+1,'l',2); | |
case 0x3: return _fsym123(of,inst,addr,val+1,'w',1); | |
case 0x4: return _fsym4(of,inst,addr,val+1); | |
case 0x5: return _fsym5(of,inst,addr,val+1); | |
case 0x6: return _fsym6(of,inst,addr,val+1); | |
case 0x7: return _fsym7(of,inst,addr,val+1); | |
case 0x8: return _fsym8(of,inst,addr,val+1); | |
case 0x9: return _fsym9(of,inst,addr,val+1); | |
case 0xa: return _fsyma(of,inst,addr,val+1); | |
case 0xb: return _fsymb(of,inst,addr,val+1); | |
case 0xc: return _fsymc(of,inst,addr,val+1); | |
case 0xd: return _fsymd(of,inst,addr,val+1); | |
case 0xe: return _fsyme(of,inst,addr,val+1); | |
case 0xf: return _fsymf(of,inst,addr,val+1); | |
} | |
return SCPE_OK; | |
} |