diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /sim/ucsim/xa.src/xa.cc | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'sim/ucsim/xa.src/xa.cc')
| -rw-r--r-- | sim/ucsim/xa.src/xa.cc | 1190 |
1 files changed, 1190 insertions, 0 deletions
diff --git a/sim/ucsim/xa.src/xa.cc b/sim/ucsim/xa.src/xa.cc new file mode 100644 index 0000000..92452ba --- /dev/null +++ b/sim/ucsim/xa.src/xa.cc @@ -0,0 +1,1190 @@ +/* + * Simulator of microcontrollers (xa.cc) + * + * Copyright (C) 1999,2002 Drotos Daniel, Talker Bt. + * + * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu + * Other contributors include: + * Karl Bongers karl@turbobit.com, + * Johan Knol johan.knol@iduna.nl + */ + +/* This file is part of microcontroller simulator: ucsim. + +UCSIM is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +UCSIM is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with UCSIM; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ +/*@1@*/ + +#include "ddconfig.h" + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "i_string.h" + +// prj +#include "pobjcl.h" + +// sim +#include "simcl.h" + +// local +#include "xacl.h" +#include "glob.h" +#include "regsxa.h" + + +/* + * Names of SFRs + */ + +static struct name_entry sfr_tabXA51[]= +{ + //#include "xa_sfr.cc" + {CPU_XA, 0x400, "PSW"}, /* Program status word */ + {CPU_XA, 0x400, "PSWL"}, /* Program status word (low byte) */ + {CPU_XA, 0x401, "PSWH"}, /* Program status word (high byte) */ + {CPU_XA, 0x402, "PSW51"}, /* 80C51 compatible PSW */ + {CPU_XA, 0x403, "SSEL"}, /* Segment selection register */ + {CPU_XA, 0x404, "PCON"}, /* Power control register */ + {CPU_XA, 0x410, "TCON"}, /* Timer 0 and 1 control register */ + {CPU_XA, 0x411, "TSTAT"}, /* Timer 0 and 1 extended status */ + {CPU_XA, 0x418, "T2CON"}, /* Timer 2 control register */ + {CPU_XA, 0x419, "T2MOD"}, /* Timer 2 mode control */ + {CPU_XA, 0x41F, "WDCON"}, /* Watchdog control register */ + {CPU_XA, 0x420, "S0CON"}, /* Serial port 0 control register */ + {CPU_XA, 0x421, "S0STAT"}, /* Serial port 0 extended status */ + {CPU_XA, 0x424, "S1CON"}, /* Serial port 1 control register */ + {CPU_XA, 0x425, "S1STAT"}, /* Serial port 1 extended status */ + {CPU_XA, 0x426, "IEL"}, /* Interrupt enable low byte */ + {CPU_XA, 0x427, "IEH"}, /* Interrupt enable high byte */ + {CPU_XA, 0x42A, "SWR"}, /* Software Interrupt Request */ + {CPU_XA, 0x430, "P0"}, /* Port 0 */ + {CPU_XA, 0x431, "P1"}, /* Port 1 */ + {CPU_XA, 0x432, "P2"}, /* Port 2 */ + {CPU_XA, 0x433, "P3"}, /* Port3 */ + {CPU_XA, 0x440, "SCR"}, /* System configuration register */ + {CPU_XA, 0x441, "DS"}, /* Data segment */ + {CPU_XA, 0x442, "ES"}, /* Extra segment */ + {CPU_XA, 0x443, "CS"}, /* Code segment */ + {CPU_XA, 0x450, "TL0"}, /* Timer 0 low byte */ + {CPU_XA, 0x451, "TH0"}, /* Timer 0 high byte */ + {CPU_XA, 0x452, "TL1"}, /* Timer 1 low byte */ + {CPU_XA, 0x453, "TH1"}, /* Timer 1 high byte */ + {CPU_XA, 0x454, "RTL0"}, /* Timer 0 extended reload, low byte */ + {CPU_XA, 0x455, "RTH0"}, /* Timer 0 extended reload, high byte */ + {CPU_XA, 0x456, "RTL1"}, /* Timer 1 extended reload, low byte */ + {CPU_XA, 0x457, "RTH1"}, /* Timer 1 extended reload, high byte */ + {CPU_XA, 0x458, "TL2"}, /* Timer 2 low byte */ + {CPU_XA, 0x459, "TH2"}, /* Timer 2 high byte */ + {CPU_XA, 0x45A, "T2CAPL"}, /* Timer 2 capture register, low byte */ + {CPU_XA, 0x45B, "T2CAPH"}, /* Timer 2 capture register, high byte */ + {CPU_XA, 0x45C, "TMOD"}, /* Timer 0 and 1 mode register */ + {CPU_XA, 0x45D, "WFEED1"}, /* Watchdog feed 1 */ + {CPU_XA, 0x45E, "WFEED2"}, /* Watchdog feed 2 */ + {CPU_XA, 0x45F, "WDL"}, /* Watchdog timer reload */ + {CPU_XA, 0x460, "S0BUF"}, /* Serial port 0 buffer register */ + {CPU_XA, 0x461, "S0ADDR"}, /* Serial port 0 address register */ + {CPU_XA, 0x462, "S0ADEN"}, /* Serial port 0 address enable register */ + {CPU_XA, 0x464, "S1BUF"}, /* Serial port 1 buffer register */ + {CPU_XA, 0x465, "S1ADDR"}, /* Serial port 1 address register */ + {CPU_XA, 0x466, "S1ADEN"}, /* Serial port 1 address enable register */ + {CPU_XA, 0x468, "BTRL"}, /* Bus timing register high byte */ + {CPU_XA, 0x469, "BTRH"}, /* Bus timing register low byte */ + {CPU_XA, 0x46A, "BCR"}, /* Bus configuration register */ + {CPU_XA, 0x470, "P0CFGA"}, /* Port 0 configuration A */ + {CPU_XA, 0x471, "P1CFGA"}, /* Port 1 configuration A */ + {CPU_XA, 0x472, "P2CFGA"}, /* Port 2 configuration A */ + {CPU_XA, 0x473, "P3CFGA"}, /* Port 3 configuration A */ + {CPU_XA, 0x47A, "SWE"}, /* Software Interrupt Enable */ + {CPU_XA, 0x4A0, "IPA0"}, /* Interrupt priority 0 */ + {CPU_XA, 0x4A1, "IPA1"}, /* Interrupt priority 1 */ + {CPU_XA, 0x4A2, "IPA2"}, /* Interrupt priority 2 */ + {CPU_XA, 0x4A4, "IPA4"}, /* Interrupt priority 4 */ + {CPU_XA, 0x4A5, "IPA5"}, /* Interrupt priority 5 */ + {CPU_XA, 0x4F0, "P0CFGB"}, /* Port 0 configuration B */ + {CPU_XA, 0x4F1, "P1CFGB"}, /* Port 1 configuration B */ + {CPU_XA, 0x4F2, "P2CFGB"}, /* Port 2 configuration B */ + {CPU_XA, 0x4F3, "P3CFGB"}, /* Port 3 configuration B */ + { 0, 0, NULL } +}; + +/* + * Names of SBITs + */ + +static struct name_entry bit_tabXA51[]= +{ + //#include "xa_bit.cc" + {CPU_XA, 0x33B, "ETI1"}, /* TX interrupt enable 1 */ + {CPU_XA, 0x33A, "ERI1"}, /* RX interrupt enable 1 */ + {CPU_XA, 0x339, "ETI0"}, /* TX interrupt enable 0 */ + {CPU_XA, 0x338, "ERI0"}, /* RX interrupt enable 0 */ + {CPU_XA, 0x337, "EA"}, /* global int. enable */ + {CPU_XA, 0x334, "ET2"}, /* timer 2 interrupt */ + {CPU_XA, 0x333, "ET1"}, /* timer 1 interrupt */ + {CPU_XA, 0x332, "EX1"}, /* external interrupt 1 */ + {CPU_XA, 0x331, "ET0"}, /* timer 0 interrupt */ + {CPU_XA, 0x330, "EX0"}, /* external interrupt 0 */ + {CPU_XA, 0x221, "PD"}, /* power down */ + {CPU_XA, 0x220, "IDL"}, + {CPU_XA, 0x20F, "SM"}, + {CPU_XA, 0x20E, "TM"}, + {CPU_XA, 0x20D, "RS1"}, + {CPU_XA, 0x20C, "RS0"}, + {CPU_XA, 0x20B, "IM3"}, + {CPU_XA, 0x20A, "IM2"}, + {CPU_XA, 0x209, "IM1"}, + {CPU_XA, 0x208, "IM0"}, + {CPU_XA, 0x307, "S0M0"}, + {CPU_XA, 0x306, "S0M1"}, + {CPU_XA, 0x305, "S0M2"}, + {CPU_XA, 0x304, "R0EN"}, + {CPU_XA, 0x303, "T0B8"}, + {CPU_XA, 0x302, "R0B8"}, + {CPU_XA, 0x301, "TI0"}, /* serial port 0 tx ready */ + {CPU_XA, 0x300, "RI0"}, /* serial port 0 rx ready */ + {CPU_XA, 0x30B, "FE0"}, + {CPU_XA, 0x30A, "BR0"}, + {CPU_XA, 0x309, "OE0"}, + {CPU_XA, 0x308, "STINT0"}, + {CPU_XA, 0x327, "S1M0"}, + {CPU_XA, 0x326, "S1M1"}, + {CPU_XA, 0x325, "S1M2"}, + {CPU_XA, 0x324, "R1EN"}, + {CPU_XA, 0x323, "T1B8"}, + {CPU_XA, 0x322, "R1B8"}, + {CPU_XA, 0x321, "TI1"}, /* serial port 0 tx ready */ + {CPU_XA, 0x320, "RI1"}, /* serial port 0 rx ready */ + {CPU_XA, 0x32B, "FE1"}, + {CPU_XA, 0x32A, "BR1"}, + {CPU_XA, 0x329, "OE1"}, + {CPU_XA, 0x328, "STINT1"}, + {CPU_XA, 0x356, "SWR7"}, + {CPU_XA, 0x355, "SWR6"}, + {CPU_XA, 0x354, "SWR5"}, + {CPU_XA, 0x353, "SWR4"}, + {CPU_XA, 0x352, "SWR3"}, + {CPU_XA, 0x351, "SWR2"}, + {CPU_XA, 0x350, "SWR1"}, + {CPU_XA, 0x2C7, "TF2"}, + {CPU_XA, 0x2C6, "EXF2"}, + {CPU_XA, 0x2C5, "RCLK0"}, + {CPU_XA, 0x2C4, "TCLK0"}, + {CPU_XA, 0x2CD, "RCLK1"}, + {CPU_XA, 0x2CC, "TCLK1"}, + {CPU_XA, 0x2C3, "EXEN2"}, + {CPU_XA, 0x2C2, "TR2"}, + {CPU_XA, 0x2C1, "CT2"}, + {CPU_XA, 0x2C0, "CPRL2"}, + {CPU_XA, 0x2C9, "T2OE"}, + {CPU_XA, 0x2C8, "DCEN"}, + {CPU_XA, 0x287, "TF1"}, + {CPU_XA, 0x286, "TR1"}, + {CPU_XA, 0x285, "TF0"}, + {CPU_XA, 0x284, "TR0"}, + {CPU_XA, 0x283, "IE1"}, + {CPU_XA, 0x282, "IT1"}, + {CPU_XA, 0x281, "IE0"}, + {CPU_XA, 0x280, "IT0"}, + {CPU_XA, 0x28A, "T1OE"}, + {CPU_XA, 0x288, "T0OE"}, + {CPU_XA, 0x2FF, "PRE2"}, + {CPU_XA, 0x2FE, "PRE1"}, + {CPU_XA, 0x2FD, "PRE0"}, + {CPU_XA, 0x2FA, "WDRUN"}, + {CPU_XA, 0x2F9, "WDTOF"}, + {CPU_XA, 0x2F8, "WDMOD"}, + {CPU_XA, 0x388, "WR1"}, + {CPU_XA, 0x38F, "T2EX"}, + {CPU_XA, 0x38C, "RXD1"}, + {CPU_XA, 0x38D, "TXD1"}, + {CPU_XA, 0x398, "RXD0"}, + {CPU_XA, 0x399, "TXD0"}, + {CPU_XA, 0x39A, "INT0"}, + {CPU_XA, 0x39B, "INT1"}, + {CPU_XA, 0x39C, "T0"}, + {CPU_XA, 0x39D, "T1"}, + {CPU_XA, 0x39E, "WR"}, + {CPU_XA, 0x39F, "RD"}, + { 0, 0, NULL } +}; + + +/* + * Base type of xa controllers + */ + +cl_xa::cl_xa(class cl_sim *asim): + cl_uc(asim) +{ + type= (struct cpu_entry *)malloc(sizeof(struct cpu_entry)); + type->type= CPU_XA; +} + +int +cl_xa::init(void) +{ + cl_uc::init(); /* Memories now exist */ + + /* set SCR to osc/4, native XA mode, flat 24 */ + set_scr(0); + /* initialize SP to 100H */ + set_reg2(7, 0x100); + /* set PSW from reset vector */ + set_psw(getcode2(0)); + /* set PC from reset vector */ + PC = getcode2(2); + + printf("The XA Simulator is in development, UNSTABLE, DEVELOPERS ONLY!\n"); + + int i; + for (i= 0; sfr_tabXA51[i].name != NULL; i++) + { + if (type->type & sfr_tabXA51[i].cpu_type) + { + class cl_var *v; + vars->add(v= new cl_var(chars(sfr_tabXA51[i].name), + sfr, + sfr_tabXA51[i].addr, "")); + v->init(); + } + } + for (i= 0; bit_tabXA51[i].name != NULL; i++) + { + if (type->type & bit_tabXA51[i].cpu_type) + { + class cl_var *v; + t_addr a= bit_tabXA51[i].addr; + int bitnr, offset= 0; + if (a >= 0x200) + { + a-= 0x200; + offset= 0x400; + } + bitnr= a%8; + a= offset + a/8; + vars->add(v= new cl_var(chars(bit_tabXA51[i].name), + sfr, + a, "", bitnr)); + v->init(); + } + } + return(0); +} + + +char * +cl_xa::id_string(void) +{ + return((char*)"unspecified XA"); +} + + +/* + * Making elements of the controller + */ + +void +cl_xa::mk_hw_elements(void) +{ + //class cl_base *o; + cl_uc::mk_hw_elements(); +} + +void +cl_xa::make_memories(void) +{ + class cl_address_space *as; + + as= rom= new cl_address_space("rom", 0, 0x10000, 8); + as->init(); + address_spaces->add(as); + as= iram= new cl_address_space("iram", 0, 0x2000, 8); + as->init(); + address_spaces->add(as); + as= sfr= new cl_address_space("sfr", 0x0, 0x2000, 8); + as->init(); + address_spaces->add(as); + as= ram= new cl_address_space("xram", 0, 0x10000, 8); + as->init(); + address_spaces->add(as); + + class cl_address_decoder *ad; + class cl_memory_chip *chip; + + chip= new cl_memory_chip("rom_chip", 0x10000, 8); + chip->init(); + memchips->add(chip); + ad= new cl_address_decoder(as= address_space("rom"), chip, 0, 0xffff, 0); + ad->init(); + as->decoders->add(ad); + ad->activate(0); + + chip= new cl_memory_chip("iram_chip", 0x2000, 8); + chip->init(); + memchips->add(chip); + ad= new cl_address_decoder(as= address_space("iram"), chip, 0, 0x1fff, 0); + ad->init(); + as->decoders->add(ad); + ad->activate(0); + + chip= new cl_memory_chip("xram_chip", 0x10000, 8); + chip->init(); + memchips->add(chip); + ad= new cl_address_decoder(as= address_space("xram"), chip, 0, 0xffff, 0); + ad->init(); + as->decoders->add(ad); + ad->activate(0); + + chip= new cl_memory_chip("sfr_chip", 0x2000, 8); + chip->init(); + memchips->add(chip); + ad= new cl_address_decoder(as= address_space("sfr"), chip, 0x0, 0x1fff, 0); + ad->init(); + as->decoders->add(ad); + ad->activate(0); +} + + +/* + * Help command interpreter + */ + +struct dis_entry * +cl_xa::dis_tbl(void) +{ + // this should be unused, we need to make main prog code + // independent of any array thing. + printf("ERROR - Using disass[] table in XA sim code!\n"); + return(glob_disass_xa); +} + +struct name_entry *cl_xa::sfr_tbl(void) +{ + return(sfr_tabXA51); +} + +struct name_entry *cl_xa::bit_tbl(void) +{ + return(bit_tabXA51); +} + +int +cl_xa::inst_length(t_addr addr) +{ + int len = 0; + + get_disasm_info(addr, &len, NULL, NULL, NULL, NULL); + + return len; +} + +int +cl_xa::inst_branch(t_addr addr) +{ + int b; + + get_disasm_info(addr, NULL, &b, NULL, NULL, NULL); + + return b; +} + +int +cl_xa::longest_inst(void) +{ + return 6; +} + +static char dir_name[64]; +char *cl_xa::get_dir_name(short addr) { + if (!/*get*/addr_name(addr, sfr/*_tbl()*/, dir_name)) { + sprintf (dir_name, "0x%03x", addr); + } + return dir_name; +} + +static char bit_name[64]; +char *cl_xa::get_bit_name(short addr) { + t_addr a= addr; int offset= 0, bitnr= addr%8; + if (a >= 0x200) { a-= 0x200; offset= 0x400; } + a= offset+a/8; + if (!/*get*/addr_name(a/*ddr*/, sfr/*bit_tbl()*/, bitnr, bit_name)) { + sprintf (bit_name, "0x%03x", addr); + } + return bit_name; +} + +/*-------------------------------------------------------------------- +get_disasm_info - Given an address, return information about the opcode + which resides there. + addr - address of opcode we want information on. + ret_len - return length of opcode. + ret_branch - return a character which indicates if we are + a branching opcode. Used by main app to implement "Next" + function which steps over functions. + immed_offset - return a number which represents the number of bytes + offset to where any immediate data is(tail end of opcode). Used + for printing disassembly. + operands - return a key indicating the form of the operands, + used for printing the disassembly. + mnemonic - return a key indicating the mnemonic of the instruction. + + Return value: Return the operand code formed by either the single + byte opcode or 2 bytes of the opcode for multi-byte opcodes. + + Note: Any of the return pointer parameters can be set to NULL to + indicate the caller does not want the information. +|--------------------------------------------------------------------*/ +int +cl_xa::get_disasm_info(t_addr addr, + int *ret_len, + int *ret_branch, + int *immed_offset, + int *parms, + int *mnemonic) +{ + uint code; + //int len = 0; + int immed_n = 0; + int i; + int start_addr = addr; + + code= rom->get(addr++); + if (code == 0x00) { + i= 0; + while (disass_xa[i].mnemonic != NOP) + i++; + } else { + //len = 2; + code = (code << 8) | rom->get(addr++); + i= 0; + while ((code & disass_xa[i].mask) != disass_xa[i].code && + disass_xa[i].mnemonic != BAD_OPCODE) + i++; + } + + if (ret_len) + *ret_len = disass_xa[i].length; + if (ret_branch) + *ret_branch = disass_xa[i].branch; + if (immed_offset) { + if (immed_n > 0) + *immed_offset = immed_n; + else *immed_offset = (addr - start_addr); + } + if (parms) { + *parms = disass_xa[i].operands; + } + if (mnemonic) { + *mnemonic = disass_xa[i].mnemonic; + } + + return code; +} + +static const char *w_reg_strs[] = { + "R0", "R1", + "R2", "R3", + "R4", "R5", + "R6", "R7", + "R8", "R9", + "R10", "R11", + "R12", "R13", + "R14", "R15"}; + +static const char *b_reg_strs[] = { + "R0l", "R0h", + "R1l", "R1h", + "R2l", "R2h", + "R3l", "R3h", + "R4l", "R4h", + "R5l", "R5h", + "R6l", "R6h", + "R7l", "R7h"}; + +/*-------------------------------------------------------------------- +disass - Disassemble an opcode. + addr - address of opcode to disassemble/print. + sep - optionally points to string(tab) to use as separator. +|--------------------------------------------------------------------*/ +char * +cl_xa::disass(t_addr addr, const char *sep) +{ + char work[256], parm_str[40]; + char *buf, *p, *b; + int code; + int len = 0; + int immed_offset = 0; + int operands; + int mnemonic; + const char **reg_strs; + + p= work; + + code = get_disasm_info(addr, &len, NULL, &immed_offset, &operands, &mnemonic); + + if (mnemonic == BAD_OPCODE) { + buf= (char*)malloc(30); + strcpy(buf, "UNKNOWN/INVALID"); + return(buf); + } + + if (code & 0x0800) + reg_strs = w_reg_strs; + else + reg_strs = b_reg_strs; + + switch(operands) { + // the repeating common parameter encoding for ADD, ADDC, SUB, AND... + case REG_REG : + sprintf(parm_str, "%s,%s", + reg_strs[((code >> 4) & 0xf)], + reg_strs[(code & 0xf)]); + break; + case REG_IREG : + sprintf(parm_str, "%s,[%s]", + reg_strs[((code >> 4) & 0xf)], + w_reg_strs[(code & 0xf)]); + break; + case IREG_REG : + sprintf(parm_str, "[%s],%s", + w_reg_strs[(code & 0x7)], + reg_strs[((code >> 4) & 0xf)] ); + break; + case REG_IREGOFF8 : + sprintf(parm_str, "%s,[%s+%02x]", + reg_strs[((code >> 4) & 0xf)], + w_reg_strs[(code & 0x7)], + rom->get(addr+immed_offset)); + ++immed_offset; + break; + case IREGOFF8_REG : + sprintf(parm_str, "[%s+%02x],%s", + w_reg_strs[(code & 0x7)], + rom->get(addr+immed_offset), + reg_strs[((code >> 4) & 0xf)] ); + ++immed_offset; + break; + case REG_IREGOFF16 : + sprintf(parm_str, "%s,[%s+%04x]", + reg_strs[((code >> 4) & 0xf)], + w_reg_strs[(code & 0x7)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset)<<8)) ); + ++immed_offset; + ++immed_offset; + break; + case IREGOFF16_REG : + sprintf(parm_str, "[%s+%04x],%s", + w_reg_strs[(code & 0x7)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset)<<8)), + reg_strs[((code >> 4) & 0xf)] ); + ++immed_offset; + ++immed_offset; + break; + case REG_IREGINC : + sprintf(parm_str, "%s,[%s+]", + reg_strs[((code >> 4) & 0xf)], + w_reg_strs[(code & 0xf)]); + break; + case IREGINC_REG : + sprintf(parm_str, "[%s+],%s", + w_reg_strs[(code & 0x7)], + reg_strs[((code >> 4) & 0xf)] ); + break; + case DIRECT_REG : + sprintf(parm_str, "%s,%s", + get_dir_name(((code & 0x7) << 8) | + rom->get(addr+immed_offset)), + reg_strs[((code >> 4) & 0xf)] ); + ++immed_offset; + break; + case REG_DIRECT : + sprintf(parm_str, "%s,%s", + reg_strs[((code >> 4) & 0xf)], + get_dir_name(((code & 0x7) << 8) | + rom->get(addr+immed_offset))); + ++immed_offset; + break; + case REG_DATA8 : + sprintf(parm_str, "%s,#0x%02x", + b_reg_strs[((code >> 4) & 0xf)], + rom->get(addr+immed_offset) ); + ++immed_offset; + break; + case REG_DATA16 : + sprintf(parm_str, "%s,#0x%04x", + reg_strs[((code >> 4) & 0xf)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset)<<8)) ); + ++immed_offset; + ++immed_offset; + break; + case IREG_DATA8 : + sprintf(parm_str, "[%s], 0x%02x", + w_reg_strs[((code >> 4) & 0x7)], + rom->get(addr+immed_offset) ); + ++immed_offset; + break; + case IREG_DATA16 : + sprintf(parm_str, "[%s], 0x%04x", + w_reg_strs[((code >> 4) & 0x7)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset)<<8)) ); + ++immed_offset; + ++immed_offset; + break; + case IREGINC_DATA8 : + sprintf(parm_str, "[%s+], 0x%02x", + w_reg_strs[((code >> 4) & 0x7)], + rom->get(addr+immed_offset) ); + ++immed_offset; + break; + case IREGINC_DATA16 : + sprintf(parm_str, "[%s+], 0x%04x", + w_reg_strs[((code >> 4) & 0x7)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset)<<8)) ); + ++immed_offset; + ++immed_offset; + break; + case IREGOFF8_DATA8 : + sprintf(parm_str, "[%s+%02x], 0x%02x", + w_reg_strs[((code >> 4) & 0x7)], + rom->get(addr+immed_offset), + rom->get(addr+immed_offset+1) ); + immed_offset += 2; + break; + case IREGOFF8_DATA16 : + sprintf(parm_str, "[%s+%02x], 0x%04x", + w_reg_strs[((code >> 4) & 0x7)], + rom->get(addr+immed_offset), + (short)((rom->get(addr+immed_offset+2)) | + (rom->get(addr+immed_offset+1)<<8)) ); + immed_offset += 3; + break; + case IREGOFF16_DATA8 : + sprintf(parm_str, "[%s+%04x], 0x%02x", + w_reg_strs[((code >> 4) & 0x7)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset+0)<<8)), + rom->get(addr+immed_offset+2) ); + immed_offset += 3; + break; + case IREGOFF16_DATA16 : + sprintf(parm_str, "[%s+%04x], 0x%04x", + w_reg_strs[((code >> 4) & 0x7)], + (short)((rom->get(addr+immed_offset+1)) | + (rom->get(addr+immed_offset+0)<<8)), + (short)((rom->get(addr+immed_offset+3)) | + (rom->get(addr+immed_offset+2)<<8)) ); + immed_offset += 4; + break; + case DIRECT_DATA8 : + sprintf(parm_str, "%s,#0x%02x", + get_dir_name(((code & 0x0070) << 4) | + rom->get(addr+immed_offset)), + rom->get(addr+immed_offset+1)); + immed_offset += 3; + break; + case DIRECT_DATA16 : + sprintf(parm_str, "%s,#0x%04x", + get_dir_name(((code & 0x0070) << 4) | + rom->get(addr+immed_offset)), + rom->get(addr+immed_offset+2) + + (rom->get(addr+immed_offset+1)<<8)); + immed_offset += 3; + break; + +// odd-ball ones + case NO_OPERANDS : // for NOP + strcpy(parm_str, ""); + break; + case CY_BIT : + sprintf(parm_str, "C,%s", + get_bit_name(((code&0x0003)<<8) + rom->get(addr+2))); + break; + case BIT_CY : + sprintf(parm_str, "%s,C", + get_bit_name(((code&0x0003)<<8) + rom->get(addr+2))); + break; + case REG_DATA4 : + strcpy(parm_str, "REG_DATA4"); + break; + case REG_DATA5 : + strcpy(parm_str, "REG_DATA5"); + break; + case IREG_DATA4 : + strcpy(parm_str, "IREG_DATA4"); + break; + case IREGINC_DATA4 : + strcpy(parm_str, "IREGINC_DATA4"); + break; + case IREGOFF8_DATA4 : + strcpy(parm_str, "IREGOFF8_DATA4"); + break; + case IREGOFF16_DATA4 : + strcpy(parm_str, "IREGOFF16_DATA4"); + break; + case DIRECT_DATA4 : + sprintf(parm_str, "%s,#0x%x", + get_dir_name(((code & 0x70)<<4) | + rom->get(addr+2)), + code&0x0f); + break; + case DIRECT : + sprintf(parm_str, "%s", + get_dir_name(((code & 0x007) << 4) + + rom->get(addr+2))); + break; + case REG : + sprintf(parm_str, "%s", + reg_strs[((code >> 4) & 0xf)] ); + break; + case IREG : + sprintf(parm_str, "[%s]", + reg_strs[((code >> 4) & 0xf)] ); + break; + case BIT_ALONE : + sprintf(parm_str, "%s", + get_bit_name(((code&0x0003)<<8) + rom->get(addr+2))); + break; + case BIT_REL8 : + sprintf(parm_str, "%s,0x%04lx", + get_bit_name((code&0x0003)<<8) + rom->get(addr+2), + (long)(((signed char)rom->get(addr+3)*2+addr+len)&0xfffe)); + break; + case DATA4: + sprintf(parm_str, "#0x%02x", code&0x0f); + break; + case ADDR24 : + sprintf(parm_str, "0x%06x", + (rom->get(addr+3)<<16) + + (rom->get(addr+1)<<8) + + rom->get(addr+2)); + break; + break; + case REG_REL8 : + sprintf(parm_str, "%s,0x%04lx", + reg_strs[(code>>4) & 0xf], + (long)(((signed char)rom->get(addr+2)*2+addr+len)&0xfffe)); + break; + case DIRECT_REL8 : + sprintf(parm_str, "%s,0x%04lx", + get_dir_name(((code&0x07)<<8) + + rom->get(addr+2)), + (long)(((signed char)rom->get(addr+2)*2+addr+len)&0xfffe)); + break; + case REG_USP: + sprintf(parm_str, "REG_USP"); + break; + case USP_REG: + sprintf(parm_str, "USP_REG"); + break; + case REL8 : + sprintf(parm_str, "0x%04lx", + (long)(((signed char)rom->get(addr+1)*2+addr+len)&0xfffe)); + break; + case REL16 : + sprintf(parm_str, "0x%04lx", + (long)(((signed short)((rom->get(addr+1)<<8) + rom->get(addr+2))*2+addr+len)&0xfffe)); + break; + + case RLIST : { + /* TODO: the list should be comma reperated + and maybe for POP the list should be reversed */ + unsigned char rlist=code&0xff; + parm_str[0]='\0'; + if (code&0x0800) { // word list + if (code&0x4000) { // R8-R15 + if (rlist&0x80) strcat (parm_str, "R15 "); + if (rlist&0x40) strcat (parm_str, "R14"); + if (rlist&0x20) strcat (parm_str, "R13 "); + if (rlist&0x10) strcat (parm_str, "R12 "); + if (rlist&0x08) strcat (parm_str, "R11 "); + if (rlist&0x04) strcat (parm_str, "R10 "); + if (rlist&0x02) strcat (parm_str, "R9 "); + if (rlist&0x01) strcat (parm_str, "R8 "); + } else { // R7-R0 + if (rlist&0x80) strcat (parm_str, "R7 "); + if (rlist&0x40) strcat (parm_str, "R6 "); + if (rlist&0x20) strcat (parm_str, "R5 "); + if (rlist&0x10) strcat (parm_str, "R4 "); + if (rlist&0x08) strcat (parm_str, "R3 "); + if (rlist&0x04) strcat (parm_str, "R2 "); + if (rlist&0x02) strcat (parm_str, "R1 "); + if (rlist&0x01) strcat (parm_str, "R0 "); + } + } else { // byte list + if (code&0x4000) { //R7h-R4l + if (rlist&0x80) strcat (parm_str, "R7h "); + if (rlist&0x40) strcat (parm_str, "R7l "); + if (rlist&0x20) strcat (parm_str, "R6h "); + if (rlist&0x10) strcat (parm_str, "R6l "); + if (rlist&0x08) strcat (parm_str, "R5h "); + if (rlist&0x04) strcat (parm_str, "R5l "); + if (rlist&0x02) strcat (parm_str, "R4h "); + if (rlist&0x01) strcat (parm_str, "R4l "); + } else { // R3h-R0l + if (rlist&0x80) strcat (parm_str, "R3h "); + if (rlist&0x40) strcat (parm_str, "R3l "); + if (rlist&0x20) strcat (parm_str, "R2h "); + if (rlist&0x10) strcat (parm_str, "R2l "); + if (rlist&0x08) strcat (parm_str, "R1h "); + if (rlist&0x04) strcat (parm_str, "R1l "); + if (rlist&0x02) strcat (parm_str, "R0h "); + if (rlist&0x01) strcat (parm_str, "R0l "); + } + } + } + break; + + case REG_DIRECT_REL8 : + sprintf(parm_str, "%s,%s,0x%02x", + reg_strs[((code >> 4) & 0xf)], + get_dir_name(((code & 0x7) << 8) + + rom->get(addr+immed_offset)), + ((signed char) rom->get(addr+immed_offset+1) * 2) & 0xfffe ); + break; + case REG_DATA8_REL8 : + sprintf(parm_str, "%s,#0x%02x,0x%02x", + reg_strs[((code >> 4) & 0xf)], + rom->get(addr+immed_offset+1), + ((signed char)rom->get(addr+immed_offset) * 2) & 0xfffe ); + break; + case REG_DATA16_REL8 : + sprintf(parm_str, "%s,#0x%04x,0x%02x", + w_reg_strs[(code >> 4) & 0xf], + rom->get(addr+immed_offset+2) + + (rom->get(addr+immed_offset+1)<<8), + ((signed char)rom->get(addr+immed_offset) * 2) & 0xfffe ); + break; + case IREG_DATA8_REL8 : + sprintf(parm_str, "[%s],#0x%02x,0x%02x", + reg_strs[((code >> 4) & 0x7)], + rom->get(addr+immed_offset+1), + ((signed char)rom->get(addr+immed_offset) * 2) & 0xfffe ); + break; + case IREG_DATA16_REL8 : + sprintf(parm_str, "[%s],#0x%04x,0x%02x", + w_reg_strs[(code >> 4) & 0x7], + rom->get(addr+immed_offset+2) + + (rom->get(addr+immed_offset+1)<<8), + ((signed char)rom->get(addr+immed_offset) * 2) & 0xfffe ); + break; + + case A_APLUSDPTR : + strcpy(parm_str, "A, [A+DPTR]"); + break; + + case A_APLUSPC : + strcpy(parm_str, "A, [A+PC]"); + break; + + case REG_REGOFF8 : + sprintf(parm_str, "%s,%s+0x%02x", + w_reg_strs[(code >> 4) & 0x7], + w_reg_strs[code & 0x7], + rom->get(addr+immed_offset)); + break; + + case REG_REGOFF16 : + sprintf(parm_str, "%s,%s+0x%02x", + w_reg_strs[(code >> 4) & 0x7], + w_reg_strs[code & 0x7], + rom->get(addr+immed_offset+1) + + (rom->get(addr+immed_offset+0)<<8)); + break; + + case A_PLUSDPTR : + strcpy(parm_str, "[A+DPTR]"); + break; + + case IIREG : + sprintf(parm_str, "[[%s]]", + w_reg_strs[(code & 0x7)]); + break; + + default: + strcpy(parm_str, "???"); + break; + } + + sprintf(work, "%s %s", + op_mnemonic_str[ mnemonic ], + parm_str); + + p= strchr(work, ' '); + if (!p) + { + buf= strdup(work); + return(buf); + } + if (sep == NULL) + buf= (char *)malloc(6+strlen(p)+1); + else + buf= (char *)malloc((p-work)+strlen(sep)+strlen(p)+1); + + for (p= work, b= buf; *p != ' '; p++, b++) + *b= *p; + p++; + *b= '\0'; + if (sep == NULL) + { + while (strlen(buf) < 6) + strcat(buf, " "); + } + else + strcat(buf, sep); + strcat(buf, p); + return(buf); +} + +/*-------------------------------------------------------------------- + print_regs - Print the registers, flags and other useful information. + Used to print a status line while stepping through the code. +|--------------------------------------------------------------------*/ +void +cl_xa::print_regs(class cl_console_base *con) +{ + unsigned char flags; + + flags = get_psw(); + con->dd_printf("CA---VNZ | ", flags); + con->dd_printf("R0:%04x R1:%04x R2:%04x R3:%04x\n", + reg2(0), reg2(1), reg2(2), reg2(3)); + + con->dd_printf("%c%c---%c%c%c | ", + (flags & BIT_C)?'1':'0', + (flags & BIT_AC)?'1':'0', + (flags & BIT_V)?'1':'0', + (flags & BIT_N)?'1':'0', + (flags & BIT_Z)?'1':'0'); + + con->dd_printf("R4:%04x R5:%04x R6:%04x SP:%04x ES:%04x DS:%04x\n", + reg2(4), reg2(5), reg2(6), reg2(7), 0, 0); + + print_disass(PC, con); +} + + +/*-------------------------------------------------------------------- + exec_inst - Called to implement simulator execution of 1 instruction + at the current PC(program counter) address. +|--------------------------------------------------------------------*/ +int cl_xa::exec_inst(void) +{ + t_mem code1; + uint code; + int i; + int operands; + + instPC= PC; + + if (fetch(&code1)) + return(resBREAKPOINT); + tick(1); + +/* the following lookups make for a slow simulation, we will + figure out how to make it fast later... */ + + /* scan to see if its a 1 byte-opcode */ + code = (code1 << 8); + i= 0; + while ( ((code & disass_xa[i].mask) != disass_xa[i].code || + (!disass_xa[i].is1byte)) /* not a one byte op code */ + && + disass_xa[i].mnemonic != BAD_OPCODE) + i++; + + if (disass_xa[i].mnemonic == BAD_OPCODE) { + /* hit the end of the list, must be a 2 or more byte opcode */ + /* fetch another code byte and search the list again */ + //if (fetch(&code2)) ?not sure if break allowed in middle of opcode? + // return(resBREAKPOINT); + code |= fetch(); /* add 2nd opcode */ + + i= 0; + while ((code & disass_xa[i].mask) != disass_xa[i].code && + disass_xa[i].mnemonic != BAD_OPCODE) + i++; + /* we should have found the opcode by now, if not invalid entry at eol */ + } + + operands = (int)(disass_xa[i].operands); + switch (disass_xa[i].mnemonic) + { + case ADD: + return inst_ADD(code, operands); + case ADDC: + return inst_ADDC(code, operands); + case ADDS: + return inst_ADDS(code, operands); + case AND: + return inst_AND(code, operands); + case ANL: + return inst_ANL(code, operands); + case ASL: + return inst_ASL(code, operands); + case ASR: + return inst_ASR(code, operands); + case BCC: + return inst_BCC(code, operands); + case BCS: + return inst_BCS(code, operands); + case BEQ: + return inst_BEQ(code, operands); + case BG: + return inst_BG(code, operands); + case BGE: + return inst_BGE(code, operands); + case BGT: + return inst_BGT(code, operands); + case BKPT: + return inst_BKPT(code, operands); + case BL: + return inst_BL(code, operands); + case BLE: + return inst_BLE(code, operands); + case BLT: + return inst_BLT(code, operands); + case BMI: + return inst_BMI(code, operands); + case BNE: + return inst_BNE(code, operands); + case BNV: + return inst_BNV(code, operands); + case BOV: + return inst_BOV(code, operands); + case BPL: + return inst_BPL(code, operands); + case BR: + return inst_BR(code, operands); + case CALL: + return inst_CALL(code, operands); + case CJNE: + return inst_CJNE(code, operands); + case CLR: + return inst_CLR(code, operands); + case CMP: + return inst_CMP(code, operands); + case CPL: + return inst_CPL(code, operands); + case DA: + return inst_DA(code, operands); + case DIV_w : + case DIV_d : + case DIVU_b: + case DIVU_w: + case DIVU_d: + return inst_DIV(code, operands); + case DJNZ: + return inst_DJNZ(code, operands); + case FCALL: + return inst_FCALL(code, operands); + case FJMP: + return inst_FJMP(code, operands); + case JB: + return inst_JB(code, operands); + case JBC: + return inst_JBC(code, operands); + case JMP: + return inst_JMP(code, operands); + case JNB: + return inst_JNB(code, operands); + case JNZ: + return inst_JNZ(code, operands); + case JZ: + return inst_JZ(code, operands); + case LEA: + return inst_LEA(code, operands); + case LSR: + return inst_LSR(code, operands); + case MOV: + return inst_MOV(code, operands); + case MOVC: + return inst_MOVC(code, operands); + case MOVS: + return inst_MOVS(code, operands); + case MOVX: + return inst_MOVX(code, operands); + case MUL_w: + case MULU_b: + case MULU_w: + return inst_MUL(code, operands); + case NEG: + return inst_NEG(code, operands); + case NOP: + return inst_NOP(code, operands); + case NORM: + return inst_NORM(code, operands); + case OR: + return inst_OR(code, operands); + case ORL: + return inst_ORL(code, operands); + case POP: + case POPU: + return inst_POP(code, operands); + case PUSH: + case PUSHU: + return inst_PUSH(code, operands); + case RESET: + return inst_RESET(code, operands); + case RET: + return inst_RET(code, operands); + case RETI: + return inst_RETI(code, operands); + case RL: + return inst_RL(code, operands); + case RLC: + return inst_RLC(code, operands); + case RR: + return inst_RR(code, operands); + case RRC: + return inst_RRC(code, operands); + case SETB: + return inst_SETB(code, operands); + case SEXT: + return inst_SEXT(code, operands); + case SUB: + return inst_SUB(code, operands); + case SUBB: + return inst_SUBB(code, operands); + case TRAP: + return inst_TRAP(code, operands); + case XCH: + return inst_XCH(code, operands); + case XOR: + return inst_XOR(code, operands); + + case BAD_OPCODE: + default: + break; + } + + /*if (PC) + PC--; + else + PC= get_mem_size(MEM_ROM_ID)-1;*/ + PC= rom->inc_address(PC, -1); + //tick(-clock_per_cycle()); + sim->stop(resINV_INST); + return(resINV_INST); +} + + +/* End of xa.src/xa.cc */ |
