diff --git a/Dasm6301.cpp b/Dasm6301.cpp new file mode 100644 index 0000000..c18478d --- /dev/null +++ b/Dasm6301.cpp @@ -0,0 +1,261 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6301.cpp : 6301 disassembler classes implementation */ +/*****************************************************************************/ + +#include "Dasm6301.h" + +/*****************************************************************************/ +/* Create6301 : create a 6301 disassembler */ +/*****************************************************************************/ + +static Disassembler *Create6301() +{ +Disassembler *pDasm = new Dasm6301; +if (pDasm) pDasm->Setup(); +return pDasm; +} + +/*****************************************************************************/ +/* Auto-registration */ +/*****************************************************************************/ + +static bool bRegistered[] = + { + RegisterDisassembler("6301", Create6301), + RegisterDisassembler("6303", Create6301), + }; + + +/*===========================================================================*/ +/* Dasm6301 class members */ +/*===========================================================================*/ + +/*****************************************************************************/ +/* m6301_codes : table of all 6301 instruction bytes and types */ +/*****************************************************************************/ + +uint8_t Dasm6301::h6301_codes[512] = + { + _ill ,_nom, _nop ,_imp, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _lsrd ,_imp, _asld ,_imp, _tap ,_imp, _tpa ,_imp, /* 04..07 */ + _inx ,_imp, _dex ,_imp, _clv ,_imp, _sev ,_imp, /* 08..0B */ + _clc ,_imp, _sec ,_imp, _cli ,_imp, _sei ,_imp, /* 0C..0F */ + _sba ,_imp, _cba ,_imp, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _tab ,_imp, _tba ,_imp, /* 14..17 */ + _xgdx ,_imp, _daa ,_imp, _slp ,_imp, _aba ,_imp, /* 18..1B: extra 0x18/xgdx, 0x1a/slp */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _bra ,_reb, _brn ,_reb, _bhi ,_reb, _bls ,_reb, /* 20..23 */ + _bcc ,_reb, _bcs ,_reb, _bne ,_reb, _beq ,_reb, /* 24..27 */ + _bvc ,_reb, _bvs ,_reb, _bpl ,_reb, _bmi ,_reb, /* 28..2B */ + _bge ,_reb, _blt ,_reb, _bgt ,_reb, _ble ,_reb, /* 2C..2F */ + _tsx ,_imp, _ins ,_imp, _pula ,_imp, _pulb ,_imp, /* 30..33 */ + _des ,_imp, _txs ,_imp, _psha ,_imp, _pshb ,_imp, /* 34..37 */ + _pulx ,_imp, _rts ,_imp, _abx ,_imp, _rti ,_imp, /* 38..3B */ + _pshx ,_imp, _mul ,_imp, _wai ,_imp, _swi ,_imp, /* 3C..3F */ + _nega ,_imp, _ill ,_nom, _ill ,_nom, _coma ,_imp, /* 40..43 */ + _lsra ,_imp, _ill ,_nom, _rora ,_imp, _asra ,_imp, /* 44..47 */ + _asla ,_imp, _rola ,_imp, _deca ,_imp, _ill ,_nom, /* 48..4B */ + _inca ,_imp, _tsta ,_imp, _ill ,_nom, _clra ,_imp, /* 4C..4F */ + _negb ,_imp, _ill ,_nom, _ill ,_nom, _comb ,_imp, /* 50..53 */ + _lsrb ,_imp, _ill ,_nom, _rorb ,_imp, _asrb ,_imp, /* 54..57 */ + _aslb ,_imp, _rolb ,_imp, _decb ,_imp, _ill ,_nom, /* 58..5B */ + _incb ,_imp, _tstb ,_imp, _ill ,_nom, _clrb ,_imp, /* 5C..5F */ + _neg ,_ix8, _aim ,_bi, _oim ,_bi, _com ,_ix8, /* 60..63: extra 0x62/aim, 0x63/oim */ + _lsr ,_ix8, _eim ,_bi, _ror ,_ix8, _asr ,_ix8, /* 64..67: extra 0x65/eim */ + _asl ,_ix8, _rol ,_ix8, _dec ,_ix8, _tim ,_bi, /* 68..6B: extra 0x6b/tim */ + _inc ,_ix8, _tst ,_ix8, _jmp ,_ix8, _clr ,_ix8, /* 6C..6F */ + _neg ,_ext, _aim ,_bd, _oim ,_bd, _com ,_ext, /* 70..73: extra 0x72/aim, 0x73/oim */ + _lsr ,_ext, _eim ,_bd, _ror ,_ext, _asr ,_ext, /* 74..77: extra 0x75/eim */ + _asl ,_ext, _rol ,_ext, _dec ,_ext, _tim ,_bd, /* 78..7B: extra 0x7b/tim */ + _inc ,_ext, _tst ,_ext, _jmp ,_ext, _clr ,_ext, /* 7C..7F */ + _suba ,_imb, _cmpa ,_imb, _sbca ,_imb, _subd ,_imw, /* 80..83 */ + _anda ,_imb, _bita ,_imb, _lda ,_imb, _ill ,_nom, /* 84..87 */ + _eora ,_imb, _adca ,_imb, _ora ,_imb, _adda ,_imb, /* 88..8B */ + _cpx ,_imw, _bsr ,_reb, _lds ,_imw, _ill ,_nom, /* 8C..8F */ + _suba ,_dir, _cmpa ,_dir, _sbca ,_dir, _subd ,_dir, /* 90..93 */ + _anda ,_dir, _bita ,_dir, _lda ,_dir, _sta ,_dir, /* 94..97 */ + _eora ,_dir, _adca ,_dir, _ora ,_dir, _adda ,_dir, /* 98..9B */ + _cpx ,_dir, _jsr ,_dir, _lds ,_dir, _sts ,_dir, /* 9C..9F */ + _suba ,_ix8, _cmpa ,_ix8, _sbca ,_ix8, _subd ,_ix8, /* A0..A3 */ + _anda ,_ix8, _bita ,_ix8, _lda ,_ix8, _sta ,_ix8, /* A4..A7 */ + _eora ,_ix8, _adca ,_ix8, _ora ,_ix8, _adda ,_ix8, /* A8..AB */ + _cpx ,_ix8, _jsr ,_ix8, _lds ,_ix8, _sts ,_ix8, /* AC..AF */ + _suba ,_ext, _cmpa ,_ext, _sbca ,_ext, _subd ,_ext, /* B0..B3 */ + _anda ,_ext, _bita ,_ext, _lda ,_ext, _sta ,_ext, /* B4..B7 */ + _eora ,_ext, _adca ,_ext, _ora ,_ext, _adda ,_ext, /* B8..BB */ + _cpx ,_ext, _jsr ,_ext, _lds ,_ext, _sts ,_ext, /* BC..BF */ + _subb ,_imb, _cmpb ,_imb, _sbcb ,_imb, _addd ,_imw, /* C0..C3 */ + _andb ,_imb, _bitb ,_imb, _ldb ,_imb, _ill ,_nom, /* C4..C7 */ + _eorb ,_imb, _adcb ,_imb, _orb ,_imb, _addb ,_imb, /* C8..CB */ + _ldd ,_imw, _ill ,_nom, _ldx ,_imw, _ill ,_nom, /* CC..CF */ + _subb ,_dir, _cmpb ,_dir, _sbcb ,_dir, _addd ,_dir, /* D0..D3 */ + _andb ,_dir, _bitb ,_dir, _ldb ,_dir, _stb ,_dir, /* D4..D7 */ + _eorb ,_dir, _adcb ,_dir, _orb ,_dir, _addb ,_dir, /* D8..DB */ + _ldd ,_dir, _std ,_dir, _ldx ,_dir, _stx ,_dir, /* DC..DF */ + _subb ,_ix8, _cmpb ,_ix8, _sbcb ,_ix8, _addd ,_ix8, /* E0..E3 */ + _andb ,_ix8, _bitb ,_ix8, _ldb ,_ix8, _stb ,_ix8, /* E4..E7 */ + _eorb ,_ix8, _adcb ,_ix8, _orb ,_ix8, _addb ,_ix8, /* E8..EB */ + _ldd ,_ix8, _std ,_ix8, _ldx ,_ix8, _stx ,_ix8, /* EC..EF */ + _subb ,_ext, _cmpb ,_ext, _sbcb ,_ext, _addd ,_ext, /* F0..F3 */ + _andb ,_ext, _bitb ,_ext, _ldb ,_ext, _stb ,_ext, /* F4..F7 */ + _eorb ,_ext, _adcb ,_ext, _orb ,_ext, _addb ,_ext, /* F8..FB */ + _ldd ,_ext, _std ,_ext, _ldx ,_ext, _stx ,_ext, /* FC..FF */ + }; + +/*****************************************************************************/ +/* opcodes : additional opcodes over 6800 */ +/*****************************************************************************/ + +OpCode Dasm6301::opcodes[mnemo6301_count - mnemo6801_count] = + { + { "AIM", Data }, /* _aim */ + { "EIM", Data }, /* _eim */ + { "OIM", Data }, /* _oim */ + { "TIM", Data }, /* _tim */ + { "SLP", Data }, /* _slp */ + { "XGDX", Data }, /* _xgdx */ + }; + +/*****************************************************************************/ +/* Dasm6301 : constructor */ +/*****************************************************************************/ + +Dasm6301::Dasm6301(void) +{ +codes = h6301_codes; +mnemo.resize(mnemo6301_count); /* set up additional mnemonics */ +for (int i = 0; i < mnemo6301_count - mnemo6801_count; i++) + mnemo[mnemo6801_count + i] = opcodes[i]; +} + +/*****************************************************************************/ +/* ~Dasm6301 : destructor */ +/*****************************************************************************/ + +Dasm6301::~Dasm6301(void) +{ +} + +/*****************************************************************************/ +/* ParseCode : parse instruction at given memory address for labels */ +/*****************************************************************************/ + +addr_t Dasm6301::ParseCode + ( + addr_t addr, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +int MI; +const char *I; +addr_t PC = addr; +bool bSetLabel; + +O = T = GetUByte(PC++); +I = mnemo[T].mne; +W = (uint16_t)(T * 2); +MI = T = codes[W++]; +M = codes[W]; + +switch (M) /* which mode is this ? */ + { + case _bi : /* Bit Manipulation indexed */ + PC += 2; + break; + case _bd : /* Bit Manipulation direct */ + T = GetUByte(PC++); + bSetLabel = !IsConst(PC); + W = GetUByte(PC++); + if (bSetLabel) + { + W = (uint16_t)PhaseInner(W, PC - 1); + AddLabel(W, mnemo[MI].memType, "", true); + } + break; + default : /* anything else is handled by base */ + return Dasm6801::ParseCode(addr, bDataBus); + } +return PC - addr; /* pass back # processed bytes */ +} + +/*****************************************************************************/ +/* DisassembleCode : disassemble code instruction at given memory address */ +/*****************************************************************************/ + +addr_t Dasm6301::DisassembleCode + ( + addr_t addr, + std::string &smnemo, + std::string &sparm, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +addr_t Wrel; +const char *I; +addr_t PC = addr; +bool bGetLabel; + +O = T = GetUByte(PC++); +W = (uint16_t)(T * 2); +T = codes[W++]; +I = mnemo[T].mne; +M = codes[W]; + +smnemo = I; /* initialize mnemonic */ + +switch (M) /* which mode is this? */ + { + case _bi : /* Bit Manipulation indexed */ + T = GetUByte(PC++); + sparm = Number2String(T, 2, PC - 1) + ","; + bGetLabel = !IsConst(PC); + T = GetUByte(PC++); + Wrel = GetRelative(PC - 1); + if (Wrel) + { + W = (int)((unsigned char)T) + (uint16_t)Wrel; + sparm += Label2String((addr_t)((int)((unsigned char)T)), bGetLabel, PC - 1) + ",X"; + } + else if (!T && !showIndexedModeZeroOperand) + sparm += ",X"; /* omit '$00', unless the user has set the 'showzero' option */ + else + sparm += Number2String(T, 2, PC - 1) + ",X"; + break; + case _bd : /* Bit Manipulation direct */ + M = GetUByte(PC++); + bGetLabel = !IsConst(PC); + W = GetUByte(PC); + if (bGetLabel) + W = (uint16_t)PhaseInner(W, PC); + PC++; + sparm = sformat("#%s,%s", + Number2String(M, 2, PC - 2).c_str(), + Label2String(W, bGetLabel, PC - 1).c_str()); + break; + default : /* anything else is handled by base */ + return Dasm6801::DisassembleCode(addr, smnemo, sparm, bDataBus); + } +return PC - addr; /* pass back # processed bytes */ +} diff --git a/Dasm6301.h b/Dasm6301.h new file mode 100644 index 0000000..a393501 --- /dev/null +++ b/Dasm6301.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6801.h : definition of the Dasm6801 class */ +/*****************************************************************************/ + +#ifndef __Dasm6301_h_defined__ +#define __Dasm6301_h_defined__ + +#include "Dasm6801.h" + +/*****************************************************************************/ +/* Dasm6301 : class for a Hitachi 6301 Processor */ +/*****************************************************************************/ + +class Dasm6301 : public Dasm6801 + { + public: + Dasm6301(void); + virtual ~Dasm6301(void); + + // Overrides + public: + // return processor long name + virtual std::string GetName() { return "Hitachi 6301"; } + + protected: + // parse instruction at given memory address for labels + virtual addr_t ParseCode(addr_t addr, bool bDataBus = false); + // disassemble instruction at given memory address + virtual addr_t DisassembleCode(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false); + + protected: + // additional 6309 addressing modes + enum AddrMode6301 + { + _bi = addrmodes6800_count, /* Bit Manipulation index */ + _bd , /* Bit Manipulation direct */ + }; + // additional 6301 mnemonics + enum Mnemonics6301 + { + _aim = mnemo6801_count, + _eim, + _oim, + _tim, + _slp, + _xgdx, + + mnemo6301_count + }; + + + static uint8_t h6301_codes[512]; + static OpCode opcodes[mnemo6301_count - mnemo6801_count]; + }; + +#endif // __Dasm6301_h_defined__ diff --git a/Dasm6309.cpp b/Dasm6309.cpp new file mode 100644 index 0000000..a06b118 --- /dev/null +++ b/Dasm6309.cpp @@ -0,0 +1,824 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6309.cpp : 6309 disassembler classes implementation */ +/*****************************************************************************/ + +#include "Dasm6309.h" + +/*****************************************************************************/ +/* Create6309 : create a 6309 processor handler */ +/*****************************************************************************/ + +static Disassembler *Create6309() +{ +Disassembler *pDasm = new Dasm6309; +if (pDasm) pDasm->Setup(); +return pDasm; +} + +/*****************************************************************************/ +/* Auto-registration */ +/*****************************************************************************/ + +static bool bRegistered = RegisterDisassembler("6309", Create6309); + + +/*===========================================================================*/ +/* Dasm6309 class members */ +/*===========================================================================*/ + +/*****************************************************************************/ +/* m6309_codes : table of all 6309 instruction bytes and types */ +/*****************************************************************************/ + +uint8_t Dasm6309::h6309_codes[512] = + { + _neg ,_dir, _oim ,_bd , _aim ,_bd , _com ,_dir, /* 00..03 */ + _lsr ,_dir, _eim ,_bd , _ror ,_dir, _asr ,_dir, /* 04..07 */ + _asl ,_dir, _rol ,_dir, _dec ,_dir, _tim ,_bd , /* 08..0B */ + _inc ,_dir, _tst ,_dir, _jmp ,_dir, _clr ,_dir, /* 0C..0F */ + _ill ,_nom, _ill ,_nom, _nop ,_imp, _sync ,_imp, /* 10..13 */ + _sexw ,_imp, _ill ,_nom, _lbra ,_rew, _lbsr ,_rew, /* 14..17 */ + _ill ,_nom, _daa ,_imp, _orcc ,_imb, _ill ,_nom, /* 18..1B */ + _andcc,_imb, _sex ,_imp, _exg ,_r1 , _tfr ,_r1 , /* 1C..1F */ + _bra ,_reb, _brn ,_reb, _bhi ,_reb, _bls ,_reb, /* 20..23 */ + _bcc ,_reb, _bcs ,_reb, _bne ,_reb, _beq ,_reb, /* 24..27 */ + _bvc ,_reb, _bvs ,_reb, _bpl ,_reb, _bmi ,_reb, /* 28..2B */ + _bge ,_reb, _blt ,_reb, _bgt ,_reb, _ble ,_reb, /* 2C..2F */ + _leax ,_ind, _leay ,_ind, _leas ,_ind, _leau ,_ind, /* 30..33 */ + _pshs ,_r2 , _puls ,_r2 , _pshu ,_r3 , _pulu ,_r3 , /* 34..37 */ + _ill ,_nom, _rts ,_imp, _abx ,_imp, _rti ,_imp, /* 38..3B */ + _cwai ,_imb, _mul ,_imp, _reset,_imp, _swi ,_imp, /* 3C..3F */ + _nega ,_imp, _ill ,_nom, _ill ,_nom, _coma ,_imp, /* 40..43 */ + _lsra ,_imp, _ill ,_nom, _rora ,_imp, _asra ,_imp, /* 44..47 */ + _asla ,_imp, _rola ,_imp, _deca ,_imp, _ill ,_nom, /* 48..4B */ + _inca ,_imp, _tsta ,_imp, _ill ,_nom, _clra ,_imp, /* 4C..4F */ + _negb ,_imp, _ill ,_nom, _ill ,_nom, _comb ,_imp, /* 50..53 */ + _lsrb ,_imp, _ill ,_nom, _rorb ,_imp, _asrb ,_imp, /* 54..57 */ + _aslb ,_imp, _rolb ,_imp, _decb ,_imp, _ill ,_nom, /* 58..5B */ + _incb ,_imp, _tstb ,_imp, _ill ,_nom, _clrb ,_imp, /* 5C..5F */ + _neg ,_ind, _oim ,_bi , _aim ,_bi , _com ,_ind, /* 60..63 */ + _lsr ,_ind, _eim ,_bi , _ror ,_ind, _asr ,_ind, /* 64..67 */ + _asl ,_ind, _rol ,_ind, _dec ,_ind, _tim ,_bi , /* 68..6B */ + _inc ,_ind, _tst ,_ind, _jmp ,_ind, _clr ,_ind, /* 6C..6F */ + _neg ,_ext, _oim ,_be , _aim ,_be , _com ,_ext, /* 70..73 */ + _lsr ,_ext, _eim ,_be , _ror ,_ext, _asr ,_ext, /* 74..77 */ + _asl ,_ext, _rol ,_ext, _dec ,_ext, _tim ,_be , /* 78..7B */ + _inc ,_ext, _tst ,_ext, _jmp ,_ext, _clr ,_ext, /* 7C..7F */ + _suba ,_imb, _cmpa ,_imb, _sbca ,_imb, _subd ,_imw, /* 80..83 */ + _anda ,_imb, _bita ,_imb, _lda ,_imb, _ill ,_nom, /* 84..87 */ + _eora ,_imb, _adca ,_imb, _ora ,_imb, _adda ,_imb, /* 88..8B */ + _cmpx ,_imw, _bsr ,_reb, _ldx ,_imw, _ill ,_nom, /* 8C..8F */ + _suba ,_dir, _cmpa ,_dir, _sbca ,_dir, _subd ,_dir, /* 90..93 */ + _anda ,_dir, _bita ,_dir, _lda ,_dir, _sta ,_dir, /* 94..97 */ + _eora ,_dir, _adca ,_dir, _ora ,_dir, _adda ,_dir, /* 98..9B */ + _cmpx ,_dir, _jsr ,_dir, _ldx ,_dir, _stx ,_dir, /* 9C..9F */ + _suba ,_ind, _cmpa ,_ind, _sbca ,_ind, _subd ,_ind, /* A0..A3 */ + _anda ,_ind, _bita ,_ind, _lda ,_ind, _sta ,_ind, /* A4..A7 */ + _eora ,_ind, _adca ,_ind, _ora ,_ind, _adda ,_ind, /* A8..AB */ + _cmpx ,_ind, _jsr ,_ind, _ldx ,_ind, _stx ,_ind, /* AC..AF */ + _suba ,_ext, _cmpa ,_ext, _sbca ,_ext, _subd ,_ext, /* B0..B3 */ + _anda ,_ext, _bita ,_ext, _lda ,_ext, _sta ,_ext, /* B4..B7 */ + _eora ,_ext, _adca ,_ext, _ora ,_ext, _adda ,_ext, /* B8..BB */ + _cmpx ,_ext, _jsr ,_ext, _ldx ,_ext, _stx ,_ext, /* BC..BF */ + _subb ,_imb, _cmpb ,_imb, _sbcb ,_imb, _addd ,_imw, /* C0..C3 */ + _andb ,_imb, _bitb ,_imb, _ldb ,_imb, _ill ,_nom, /* C4..C7 */ + _eorb ,_imb, _adcb ,_imb, _orb ,_imb, _addb ,_imb, /* C8..CB */ + _ldd ,_imw, _ldq ,_iml, _ldu ,_imw, _ill ,_nom, /* CC..CF */ + _subb ,_dir, _cmpb ,_dir, _sbcb ,_dir, _addd ,_dir, /* D0..D3 */ + _andb ,_dir, _bitb ,_dir, _ldb ,_dir, _stb ,_dir, /* D4..D7 */ + _eorb ,_dir, _adcb ,_dir, _orb ,_dir, _addb ,_dir, /* D8..DB */ + _ldd ,_dir, _std ,_dir, _ldu ,_dir, _stu ,_dir, /* DC..DF */ + _subb ,_ind, _cmpb ,_ind, _sbcb ,_ind, _addd ,_ind, /* E0..E3 */ + _andb ,_ind, _bitb ,_ind, _ldb ,_ind, _stb ,_ind, /* E4..E7 */ + _eorb ,_ind, _adcb ,_ind, _orb ,_ind, _addb ,_ind, /* E8..EB */ + _ldd ,_ind, _std ,_ind, _ldu ,_ind, _stu ,_ind, /* EC..EF */ + _subb ,_ext, _cmpb ,_ext, _sbcb ,_ext, _addd ,_ext, /* F0..F3 */ + _andb ,_ext, _bitb ,_ext, _ldb ,_ext, _stb ,_ext, /* F4..F7 */ + _eorb ,_ext, _adcb ,_ext, _orb ,_ext, _addb ,_ext, /* F8..FB */ + _ldd ,_ext, _std ,_ext, _ldu ,_ext, _stu ,_ext, /* FC..FF */ + }; + +/*****************************************************************************/ +/*hm6309_codes10 : $10 extended instruction 2nd byte */ +/*****************************************************************************/ + +uint8_t Dasm6309::h6309_codes10[512] = + { + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 04..07 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 08..0B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 0C..0F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 14..17 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 18..1B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _ill ,_nom, _lbrn ,_rew, _lbhi ,_rew, _lbls ,_rew, /* 20..23 */ + _lbcc ,_rew, _lbcs ,_rew, _lbne ,_rew, _lbeq ,_rew, /* 24..27 */ + _lbvc ,_rew, _lbvs ,_rew, _lbpl ,_rew, _lbmi ,_rew, /* 28..2B */ + _lbge ,_rew, _lblt ,_rew, _lbgt ,_rew, _lble ,_rew, /* 2C..2F */ + _addr ,_r1 , _adcr ,_r1 , _subr ,_r1 , _sbcr ,_r1 , /* 30..33 */ + _andr ,_r1 , _orr ,_r1 , _eorr ,_r1 , _cmpr ,_r1 , /* 34..37 */ + _pshsw,_imp, _pulsw,_imp, _pshuw,_imp, _puluw,_imp, /* 38..3B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _swi2 ,_imp, /* 3C..3F */ + _negd ,_imp, _ill ,_nom, _ill ,_nom, _comd ,_imp, /* 40..43 */ + _lsrd ,_imp, _ill ,_nom, _rord ,_imp, _asrd ,_imp, /* 44..47 */ + _asld ,_imp, _rold ,_imp, _decd ,_imp, _ill ,_nom, /* 48..4B */ + _incd ,_imp, _tstd ,_imp, _ill ,_nom, _clrd ,_imp, /* 4C..4F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _comw ,_imp, /* 50..53 */ + _lsrw ,_imp, _ill ,_nom, _rorw ,_imp, _ill ,_nom, /* 54..57 */ + _ill ,_nom, _rolw ,_imp, _decw ,_imp, _ill ,_nom, /* 58..5B */ + _incw ,_imp, _tstw ,_imp, _ill ,_nom, _clrw ,_imp, /* 5C..5F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 60..63 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 64..67 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 68..6B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 6C..6F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 70..73 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 74..77 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 78..7B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 7C..7F */ + _subw ,_imw, _cmpw ,_imw, _sbcd ,_imw, _cmpd ,_imw, /* 80..83 */ + _andd ,_imw, _bitd ,_imw, _ldw ,_imw, _ill ,_nom, /* 84..87 */ + _eord ,_imw, _adcd ,_imw, _ord ,_imw, _addw ,_imw, /* 88..8B */ + _cmpy ,_imw, _ill ,_nom, _ldy ,_imw, _ill ,_nom, /* 8C..8F */ + _subw ,_dir, _cmpw ,_dir, _sbcd ,_dir, _cmpd ,_dir, /* 90..93 */ + _andd ,_dir, _bitd ,_dir, _ldw ,_dir, _stw ,_dir, /* 94..97 */ + _eord ,_dir, _adcd ,_dir, _ord ,_dir, _addw ,_dir, /* 98..9B */ + _cmpy ,_dir, _ill ,_nom, _ldy ,_dir, _sty ,_dir, /* 9C..9F */ + _subw ,_ind, _cmpw ,_ind, _sbcd ,_ind, _cmpd ,_ind, /* A0..A3 */ + _andd ,_ind, _bitd ,_ind, _ldw ,_ind, _stw ,_ind, /* A4..A7 */ + _eord ,_ind, _adcd ,_ind, _ord ,_ind, _addw ,_ind, /* A8..AB */ + _cmpy ,_ind, _ill ,_nom, _ldy ,_ind, _sty ,_ind, /* AC..AF */ + _subw ,_ext, _cmpw ,_ext, _sbcd ,_ext, _cmpd ,_ext, /* B0..B3 */ + _andd ,_ext, _bitd ,_ext, _ldw ,_ext, _stw ,_ext, /* B4..B7 */ + _eord ,_ext, _adcd ,_ext, _ord ,_ext, _addw ,_ext, /* B8..BB */ + _cmpy ,_ext, _ill ,_nom, _ldy ,_ext, _sty ,_ext, /* BC..BF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C0..C3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C4..C7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C8..CB */ + _ill ,_nom, _ill ,_nom, _lds ,_imw, _ill ,_nom, /* CC..CF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D0..D3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D4..D7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D8..DB */ + _ldq ,_dir, _stq ,_dir, _lds ,_dir, _sts ,_dir, /* DC..DF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E0..E3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E4..E7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E8..EB */ + _ldq ,_ind, _stq ,_ind, _lds ,_ind, _sts ,_ind, /* EC..EF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F0..F3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F4..F7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F8..FB */ + _ldq ,_ext, _stq ,_ext, _lds ,_ext, _sts ,_ext, /* FC..FF */ + }; + +/*****************************************************************************/ +/* h6309_codes11 : $11 extended instruction 2nd byte */ +/*****************************************************************************/ + +uint8_t Dasm6309::h6309_codes11[512] = + { + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 04..07 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 08..0B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 0C..0F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 14..17 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 18..1B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 20..23 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 24..27 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 28..2B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 2C..2F */ + _band ,_bt , _biand,_bt , _bor ,_bt , _bior ,_bt , /* 30..33 */ + _beor ,_bt , _bieor,_bt , _ldbt ,_bt , _stbt ,_bt , /* 34..37 */ + _tfm ,_t1 , _tfm ,_t2 , _tfm ,_t3 , _tfm ,_t4 , /* 38..3B */ + _bitmd,_imb, _ldmd ,_imb, _ill ,_nom, _swi3 ,_imp, /* 3C..3F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _come ,_imp, /* 40..43 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 44..47 */ + _ill ,_nom, _ill ,_nom, _dece ,_imp, _ill ,_nom, /* 48..4B */ + _ince ,_imp, _tste ,_imp, _ill ,_nom, _clre ,_imp, /* 4C..4F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _comf ,_imp, /* 50..53 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 54..57 */ + _ill ,_nom, _ill ,_nom, _decf ,_imp, _ill ,_nom, /* 58..5B */ + _incf ,_imp, _tstf ,_imp, _ill ,_nom, _clrf ,_imp, /* 5C..5F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 60..63 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 64..67 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 68..6B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 6C..6F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 70..73 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 74..77 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 78..7B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 7C..7F */ + _sube ,_imb, _cmpe ,_imb, _ill ,_nom, _cmpu ,_imw, /* 80..83 */ + _ill ,_nom, _ill ,_nom, _lde ,_imb, _ill ,_nom, /* 84..87 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _adde ,_imb, /* 88..8B */ + _cmps ,_imw, _divd ,_imb, _divq ,_imw, _muld ,_imw, /* 8C..8F */ + _sube ,_dir, _cmpe ,_dir, _ill ,_nom, _cmpu ,_dir, /* 90..93 */ + _ill ,_nom, _ill ,_nom, _lde ,_dir, _ste ,_dir, /* 94..97 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _adde ,_dir, /* 98..9B */ + _cmps ,_dir, _divd ,_dir, _divq ,_dir, _muld ,_dir, /* 9C..9F */ + _sube ,_ind, _cmpe ,_ind, _ill ,_nom, _cmpu ,_ind, /* A0..A3 */ + _ill ,_nom, _ill ,_nom, _lde ,_ind, _ste ,_ind, /* A4..A7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _adde ,_ind, /* A8..AB */ + _cmps ,_ind, _divd ,_ind, _divq ,_ind, _muld ,_ind, /* AC..AF */ + _sube ,_ext, _cmpe ,_ext, _ill ,_nom, _cmpu ,_ext, /* B0..B3 */ + _ill ,_nom, _ill ,_nom, _lde ,_ext, _ste ,_ext, /* B4..B7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _adde ,_ext, /* B8..BB */ + _cmps ,_ext, _divd ,_ext, _divq ,_ext, _muld ,_ext, /* BC..BF */ + _subf ,_imb, _cmpf ,_imb, _ill ,_nom, _ill ,_nom, /* C0..C3 */ + _ill ,_nom, _ill ,_nom, _ldf ,_imb, _ill ,_nom, /* C4..C7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _addf ,_imb, /* C8..CB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* CC..CF */ + _subf ,_dir, _cmpf ,_dir, _ill ,_nom, _ill ,_nom, /* D0..D3 */ + _ill ,_nom, _ill ,_nom, _ldf ,_dir, _stf ,_dir, /* D4..D7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _addf ,_dir, /* D8..DB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* DC..DF */ + _subf ,_ind, _cmpf ,_ind, _ill ,_nom, _ill ,_nom, /* E0..E3 */ + _ill ,_nom, _ill ,_nom, _ldf ,_ind, _stf ,_ind, /* E4..E7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _addf ,_ind, /* E8..EB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* EC..EF */ + _subf ,_ext, _cmpf ,_ext, _ill ,_nom, _ill ,_nom, /* F0..F3 */ + _ill ,_nom, _ill ,_nom, _ldf ,_ext, _stf ,_ext, /* F4..F7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _addf ,_ext, /* F8..FB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* FC..FF */ + }; + +static char *h6309_exg_tfr[] = + { + "D", "X", "Y", "U", "S", "PC","W" ,"V", + "A", "B", "CC","DP","0", "0", "E", "F" + }; + +/*****************************************************************************/ +/* opcodes : additional opcodes over 6809 */ +/*****************************************************************************/ + +OpCode Dasm6309::opcodes[mnemo6309_count - mnemo6809_count] = + { + { "AIM", Data }, /* _aim */ + { "EIM", Data }, /* _eim */ + { "OIM", Data }, /* _oim */ + { "TIM", Data }, /* _tim */ + { "BAND", Data }, /* _band */ + { "BIAND", Data }, /* _biand */ + { "BOR", Data }, /* _bor */ + { "BIOR", Data }, /* _bior */ + { "BEOR", Data }, /* _beor */ + { "BIEOR", Data }, /* _bieor */ + { "LDBT", Data }, /* _ldbt */ + { "STBT", Data }, /* _stbt */ + { "TFM", Data }, /* _tfm */ + { "ADCD", Data }, /* _adcd */ + { "ADCR", Data }, /* _adcr */ + { "ADDE", Data }, /* _adde */ + { "ADDF", Data }, /* _addf */ + { "ADDW", Data }, /* _addw */ + { "ADDR", Data }, /* _addr */ + { "ANDD", Data }, /* _andd */ + { "ANDR", Data }, /* _andr */ + { "ASRD", Data }, /* _asrd */ + { "BITD", Data }, /* _bitd */ + { "BITMD", Data }, /* _bitmd */ + { "CLRD", Data }, /* _clrd */ + { "CLRE", Data }, /* _clre */ + { "CLRF", Data }, /* _clrf */ + { "CLRW", Data }, /* _clrw */ + { "CMPE", Data }, /* _cmpe */ + { "CMPF", Data }, /* _cmpf */ + { "CMPW", Data }, /* _cmpw */ + { "CMPR", Data }, /* _cmpr */ + { "COMD", Data }, /* _comd */ + { "COME", Data }, /* _come */ + { "COMF", Data }, /* _comf */ + { "COMW", Data }, /* _comw */ + { "DECD", Data }, /* _dedc */ + { "DECE", Data }, /* _dece */ + { "DECF", Data }, /* _decf */ + { "DECW", Data }, /* _decw */ + { "DIVD", Data }, /* _divd */ + { "DIVQ", Data }, /* _divq */ + { "EORD", Data }, /* _eord */ + { "EORR", Data }, /* _eorr */ + { "INCD", Data }, /* _incd */ + { "INCE", Data }, /* _ince */ + { "INCF", Data }, /* _incf */ + { "INCW", Data }, /* _incw */ + { "LDE", Data }, /* _lde */ + { "LDF", Data }, /* _ldf */ + { "LDQ", Data }, /* _ldq */ + { "LDW", Data }, /* _ldw */ + { "LDMD", Data }, /* _ldmd */ + { "LSRW", Data }, /* _lsrw */ + { "MULD", Data }, /* _muld */ + { "NEGD", Data }, /* _negd */ + { "ORD", Data }, /* _ord */ + { "ORR", Data }, /* _orr */ + { "PSHSW", Data }, /* _pshsw */ + { "PSHUW", Data }, /* _pshuw */ + { "PULSW", Data }, /* _pulsw */ + { "PULUW", Data }, /* _puluw */ + { "ROLD", Data }, /* _rold */ + { "ROLW", Data }, /* _rolw */ + { "RORD", Data }, /* _rord */ + { "RORW", Data }, /* _rorw */ + { "SBCD", Data }, /* _sbcd */ + { "SBCR", Data }, /* _sbcr */ + { "SEXW", Data }, /* _sexw */ + { "STE", Data }, /* _ste */ + { "STF", Data }, /* _stf */ + { "STQ", Data }, /* _stq */ + { "STW", Data }, /* _stw */ + { "SUBE", Data }, /* _sube */ + { "SUBF", Data }, /* _subf */ + { "SUBW", Data }, /* _subw */ + { "SUBR", Data }, /* _subr */ + { "TSTD", Data }, /* _tstd */ + { "TSTE", Data }, /* _tste */ + { "TSTF", Data }, /* _tstf */ + { "TSTW", Data }, /* _tstw */ + }; + +/*****************************************************************************/ +/* Dasm6309 : constructor */ +/*****************************************************************************/ + +Dasm6309::Dasm6309(void) +{ +codes = h6309_codes; +codes10 = h6309_codes10; +codes11 = h6309_codes11; +exg_tfr = h6309_exg_tfr; + +mnemo.resize(mnemo6309_count); /* set up additional mnemonics */ +for (int i = 0; i < mnemo6309_count - mnemo6809_count; i++) + mnemo[mnemo6809_count + i] = opcodes[i]; +} + +/*****************************************************************************/ +/* ~Dasm6309 : destructor */ +/*****************************************************************************/ + +Dasm6309::~Dasm6309(void) +{ +} + +/*****************************************************************************/ +/* InitParse : initialize parsing */ +/*****************************************************************************/ + +bool Dasm6309::InitParse(bool bDataBus) +{ +if (!bDataBus) + { + if (useFlex) + AddFlexLabels(); + + // set up DIV0 system vector + addr_t addr = 0xfff0; + if (GetMemType(addr) != Untyped) /* if system vector loaded */ + { + SetMemType(addr, Data); /* that's a data word */ + SetCellSize(addr, 2); + addr_t tgtaddr = GetUWord(addr); /* look whether it points to loaded */ + if (GetMemType(tgtaddr) != Untyped) + { /* if so, */ + SetMemType(tgtaddr, Code); /* that's code there */ + AddLabel(tgtaddr, Code, /* and it got a predefined label */ + sformat("vec_%s", "DIV0"), + true); + } + } + } +return Dasm6809::InitParse(bDataBus); +} + +/*****************************************************************************/ +/* IndexParse : parses index for labels */ +/*****************************************************************************/ + +addr_t Dasm6309::IndexParse(int MI, addr_t pc) +{ +uint8_t T; +uint16_t W; +char R; +addr_t PC = pc; +bool bSetLabel = true; + +T = GetUByte(PC++); +R = reg[(T >> 5) & 0x03]; + +if (T & 0x80) + { + switch(T & 0x1F) + { + case 0x07: + case 0x17: + case 0x0A: + case 0x1A: + case 0x0E: + case 0x1E: + return PC; + default: + switch (T) + { + case 0xAF: + case 0xB0: + bSetLabel = !IsConst(PC); + W = GetUWord(PC); PC += 2; + if (bSetLabel) + AddLabel(W, mnemo[MI].memType, "", true); + return PC; + } + break; + } + } +return Dasm6809::IndexParse(MI, pc); +} + +/*****************************************************************************/ +/* IndexString : converts index to string */ +/*****************************************************************************/ + +std::string Dasm6309::IndexString(addr_t &pc) +{ +uint8_t T; +uint16_t W; +char R; +std::string buf; +addr_t PC = pc; +bool bGetLabel; + +T = GetUByte(PC++); +R = reg[(T >> 5) & 0x03]; + +if (T & 0x80) + { + switch (T & 0x1F) + { + case 0x07: + buf = sformat("E,%c", R); + break; + case 0x17: + buf = sformat("[E,%c]", R); + break; + case 0x0A: + buf = sformat("F,%c",R); + break; + case 0x1A: + buf = sformat("[F,%c]",R); + break; + case 0x0E: + buf = sformat("W,%c",R); + break; + case 0x1E: + buf = sformat("[W,%c]",R); + break; + default: + switch (T) + { + case 0x8F: + buf = sformat(",W"); + break; + case 0x90: + buf = sformat("[,W]"); + break; + case 0xAF: + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + buf = sformat("%s,W", Label2String(W, bGetLabel, PC - 2).c_str()); + break; + case 0xB0: + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + buf = sformat("[%s,W]", Label2String(W, bGetLabel, PC - 2).c_str()); + break; + case 0xCF: + buf = sformat(",W++"); + break; + case 0xD0: + buf = sformat("[,W++]"); + break; + case 0xEF: + buf = sformat(",--W"); + break; + case 0xF0: + buf = sformat("[,--W]"); + break; + default: + return Dasm6809::IndexString(pc); + } + break; + } + pc = PC; + return buf; + } + +return Dasm6809::IndexString(pc); +} + +/*****************************************************************************/ +/* ParseCode : parse instruction at given memory address for labels */ +/*****************************************************************************/ + +addr_t Dasm6309::ParseCode + ( + addr_t addr, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +int MI; +const char *I; +addr_t PC = addr; +bool bSetLabel; +addr_t dp = GetDirectPage(addr); + + +O = T = GetUByte(PC++); +if (T == 0x10) + { + T = GetUByte(PC++); + W = T * 2; + MI = T = codes10[W++]; + I = mnemo[T].mne; + M = codes10[W]; + + if ((T == _swi2) && os9Patch) + return (PC + 1 - addr); + } +else if (T == 0x11) + { + T = GetUByte(PC++); + W = T * 2; + MI = T = codes11[W++]; + I = mnemo[T].mne; + M = codes11[W]; + } +else + { + W = T * 2; + MI = T = codes[W++]; + I = mnemo[T].mne; + M = codes[W]; + } + +switch (M) /* which mode is this ? */ + { + case _bd: /* Bit Manipulation direct */ + M = GetUByte(PC++); + bSetLabel = !IsConst(PC); + T = GetUByte(PC++); + if (dp >= 0) + { + W = (uint16_t)dp | T; + if (bSetLabel) + { + W = (uint16_t)PhaseInner(W, PC - 1); + AddLabel(W, mnemo[MI].memType, "", true); + } + } + break; + + case _bi: /* Bit Manipulation index */ + T = GetUByte(PC++); + PC = IndexParse(MI, PC); + break; + + case _be: /* Bit Manipulation extended */ + T = GetUByte(PC++); + bSetLabel = !IsConst(PC); + if (bSetLabel) + { + W = (uint16_t)PhaseInner(GetUWord(PC), PC); + AddLabel(W, mnemo[MI].memType, "", true); + } + PC += 2; + break; + + case _bt: /* Bit Transfers direct */ + PC += 2; + break; + + case _t1: /* Block Transfer r0+,r1+ */ + case _t2: /* Block Transfer r0-,r1- */ + case _t3: /* Block Transfer r0+,r1 */ + case _t4: /* Block Transfer r0,r1+ */ + PC++; + break; + + case _iml: /* immediate 32-bit */ + PC += 4; + break; + + default : /* anything else is handled by base */ + return Dasm6809::ParseCode(addr, bDataBus); + } +return PC - addr; /* pass back # processed bytes */ +} + +/*****************************************************************************/ +/* DisassembleData : disassemble data area at given memory address */ +/*****************************************************************************/ + +addr_t Dasm6309::DisassembleData + ( + addr_t addr, + addr_t end, + uint32_t flags, + std::string &smnemo, + std::string &sparm, + int maxparmlen, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +if (!(flags & SHMF_RMB) && /* if display necessary */ + ((flags & 0xff) == 3)) /* and dword-sized */ + { + addr_t done; + + smnemo = "FQB"; + /* assemble as many as possible */ + for (done = addr; done < end; done += 4) + { + // these are constants in any case. + std::string s = Number2String(GetUWord(done), 8, done); + if (sparm.size()) /* if already something there */ + { /* if this would become too long */ + if (sparm.size() + s.size() + 1 >= (std::string::size_type)maxparmlen) + break; /* terminate the loop */ + sparm += ','; /* add separator */ + } + sparm += s; /* append the byte's representation */ + } + return done - addr; + } +// anything else is done by base class +return Dasm6809::DisassembleData(addr, end, flags, smnemo, sparm, maxparmlen, bDataBus); +} + +/*****************************************************************************/ +/* DisassembleCode : disassemble code instruction at given memory address */ +/*****************************************************************************/ + +addr_t Dasm6309::DisassembleCode + ( + addr_t addr, + std::string &smnemo, + std::string &sparm, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +const char *I; +addr_t PC = addr; +bool bGetLabel; +addr_t dp = GetDirectPage(addr); + +O = T = GetUByte(PC++); +if (T == 0x10) + { + T = GetUByte(PC++); + W = T * 2; + T = codes10[W++]; + I = mnemo[T].mne; + M = codes10[W]; + + if ((T == _swi2) && os9Patch) + { + T = GetUByte(PC++); + smnemo = "OS9"; + sparm = os9_codes[T]; + return PC - addr; + } + } +else if (T == 0x11) + { + T = GetUByte(PC++); + W = T * 2; + T = codes11[W++]; + I = mnemo[T].mne; + M = codes11[W]; + } +else + { + W = T * 2; + T = codes[W++]; + I = mnemo[T].mne; + M = codes[W]; + } + +smnemo = I; /* initialize mnemonic */ + +switch (M) /* which mode is this? */ + { + case _imp: /* inherent/implied */ + // override 6800 code, since the convenience mnemonics LSRD and ASLD + // are real opcodes on a 6309! + break; + + case _bd: /* Bit Manipulation direct */ + M = GetUByte(PC++); + bGetLabel = !IsConst(PC); + T = GetUByte(PC++); + if (dp != NO_ADDRESS) + { + W = (uint16_t)dp | T; + if (bGetLabel) + W = (uint16_t)PhaseInner(W, PC - 1); + sparm = sformat("#%s,%s", + Number2String(M, 2, PC - 2).c_str(), + Label2String(W, bGetLabel, PC - 1)); + } + else + { + sparm = sformat("#%s,<%s", + Number2String(M, 2, PC - 2).c_str(), + Number2String(T, 2, PC - 1).c_str()); + } + break; + + case _bi: /* Bit Manipulation index */ + T = GetUByte(PC++); + sparm = sformat("#%s,", I, Number2String(T, 2, PC - 1).c_str()); + sparm += IndexString(PC); + break; + + case _be: /* Bit Manipulation extended */ + T = GetUByte(PC++); + bGetLabel = !IsConst(PC); + if (bGetLabel) + W = (uint16_t)PhaseInner(GetUWord(PC), addr); + PC += 2; + if ((dp != NO_ADDRESS) && + ((W & (uint16_t)0xff00) == (uint16_t)dp) && + (forceExtendedAddr)) + sparm = sformat("#%s,>%s", + Number2String(T, 2, PC - 3).c_str(), + Label2String(W, bGetLabel, PC - 2).c_str()); + else + sparm = sformat("#%s,%s", + Number2String(T, 2, PC - 3).c_str(), + Label2String(W, bGetLabel, PC - 2).c_str()); + break; + + case _bt: /* Bit Transfers direct */ + M = GetUByte(PC++); + T = GetUByte(PC++); + sparm = sformat("%s,%d,%d,%s%s", + bit_r[M >> 6], + (M >> 3) & 7, + M & 7, + forceDirectAddr ? "<" : "", + Number2String(T, 2, PC - 1).c_str()); + break; + + case _t1: /* Block Transfer r0+,r1+ */ + T = GetUByte(PC++); + sparm = sformat("%s+,%s+", I, block_r[T >> 4], block_r[T & 0xF]); + break; + + case _t2: /* Block Transfer r0-,r1- */ + T = GetUByte(PC++); + sparm = sformat("%s-,%s-", I, block_r[T >> 4], block_r[T & 0xF]); + break; + + case _t3: /* Block Transfer r0+,r1 */ + T = GetUByte(PC++); + sparm = sformat("%s+,%s", I, block_r[T >> 4], block_r[T & 0xF]); + break; + + case _t4: /* Block Transfer r0,r1+ */ + T = GetUByte(PC++); + sparm = sformat("%-7s %s,%s+", I, block_r[T >> 4], block_r[T & 0xF]); + break; + + case _iml: /* immediate 32-bit */ + sparm = sformat("#$%08X", GetUDWord(PC)); PC += 4; + break; + + default : /* anything else is handled by base */ + return Dasm6809::DisassembleCode(addr, smnemo, sparm, bDataBus); + } +return PC - addr; /* pass back # processed bytes */ +} diff --git a/Dasm6309.h b/Dasm6309.h new file mode 100644 index 0000000..4c61a44 --- /dev/null +++ b/Dasm6309.h @@ -0,0 +1,169 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6309.h : definition of the Dasm6309 class */ +/*****************************************************************************/ + +#ifndef __Dasm6309_h_defined__ +#define __Dasm6309_h_defined__ + +#include "Dasm6809.h" + +/*****************************************************************************/ +/* Dasm6309 : class for a Hitachi 6309 disassembler */ +/*****************************************************************************/ + +class Dasm6309 : public Dasm6809 + { + public: + Dasm6309(void); + virtual ~Dasm6309(void); + + // Overrides + public: + // return processor long name + virtual std::string GetName() { return "Hitachi 6309"; } + + // Initialize parsing + virtual bool InitParse(bool bDataBus = false); + + protected: + // parse instruction at given memory address for labels + virtual addr_t ParseCode(addr_t addr, bool bDataBus = false); + // disassemble data area at given memory address + virtual addr_t DisassembleData(addr_t addr, addr_t end, uint32_t flags, std::string &smnemo, std::string &sparm, int maxparmlen, bool bDataBus = false); + // disassemble instruction at given memory address + virtual addr_t DisassembleCode(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false); + + protected: + // additional 6309 addressing modes + enum AddrMode6309 + { + _bd = addrmodes6809_count, /* Bit Manipulation direct */ + _bi , /* Bit Manipulation index */ + _be , /* Bit Manipulation extended */ + _bt , /* Bit Transfers direct */ + _t1 , /* Block Transfer r0+,r1+ */ + _t2 , /* Block Transfer r0-,r1- */ + _t3 , /* Block Transfer r0+,r1 */ + _t4 , /* Block Transfer r0,r1+ */ + _iml, /* immediate 32-bit */ + + addrmodes6309_count + }; + + // additional 6309 mnemonics + enum Mnemonics6309 + { + _aim = mnemo6809_count, + _eim, + _oim, + _tim, + _band, + _biand, + _bor, + _bior, + _beor, + _bieor, + _ldbt, + _stbt, + _tfm, + _adcd, + _adcr, + _adde, + _addf, + _addw, + _addr, + _andd, + _andr, + _asrd, + _bitd, + _bitmd, + _clrd, + _clre, + _clrf, + _clrw, + _cmpe, + _cmpf, + _cmpw, + _cmpr, + _comd, + _come, + _comf, + _comw, + _decd, + _dece, + _decf, + _decw, + _divd, + _divq, + _eord, + _eorr, + _incd, + _ince, + _incf, + _incw, + _lde, + _ldf, + _ldq, + _ldw, + _ldmd, + _lsrw, + _muld, + _negd, + _ord, + _orr, + _pshsw, + _pshuw, + _pulsw, + _puluw, + _rold, + _rolw, + _rord, + _rorw, + _sbcd, + _sbcr, + _sexw, + _ste, + _stf, + _stq, + _stw, + _sube, + _subf, + _subw, + _subr, + _tstd, + _tste, + _tstf, + _tstw, + + mnemo6309_count + }; + + static uint8_t h6309_codes[512]; + static uint8_t h6309_codes10[512]; + static uint8_t h6309_codes11[512]; + static OpCode opcodes[mnemo6309_count - mnemo6809_count]; + + protected: + virtual addr_t IndexParse(int MI, addr_t pc); + virtual std::string IndexString(addr_t &pc); + }; + +#endif // __Dasm6309_h_defined__ diff --git a/Dasm6800.cpp b/Dasm6800.cpp new file mode 100644 index 0000000..fc909c1 --- /dev/null +++ b/Dasm6800.cpp @@ -0,0 +1,1022 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6800.cpp : 6800 disassembler implementation */ +/*****************************************************************************/ + +#include "Dasm6800.h" + +/*****************************************************************************/ +/* Create6800 : create an 6800 processor handler */ +/*****************************************************************************/ + +static Disassembler *Create6800() +{ +Disassembler *pDasm = new Dasm6800; +if (pDasm) pDasm->Setup(); +return pDasm; +} + +/*****************************************************************************/ +/* Auto-registration */ +/*****************************************************************************/ + +static bool bRegistered[] = + { + RegisterDisassembler("6800", Create6800), + RegisterDisassembler("6802", Create6800), + RegisterDisassembler("6808", Create6800), + }; + + +/*===========================================================================*/ +/* Dasm6800 class members */ +/*===========================================================================*/ + +/*****************************************************************************/ +/* m6800_codes : table of all 6800 instruction bytes and types */ +/*****************************************************************************/ + +uint8_t Dasm6800::m6800_codes[512] = + { + _ill ,_nom, _nop ,_imp, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _ill ,_nom, _ill ,_nom, _tap ,_imp, _tpa ,_imp, /* 04..07 */ + _inx ,_imp, _dex ,_imp, _clv ,_imp, _sev ,_imp, /* 08..0B */ + _clc ,_imp, _sec ,_imp, _cli ,_imp, _sei ,_imp, /* 0C..0F */ + _sba ,_imp, _cba ,_imp, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _tab ,_imp, _tba ,_imp, /* 14..17 */ + _ill ,_nom, _daa ,_imp, _ill ,_nom, _aba ,_imp, /* 18..1B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _bra ,_reb, _ill ,_nom, _bhi ,_reb, _bls ,_reb, /* 20..23 */ + _bcc ,_reb, _bcs ,_reb, _bne ,_reb, _beq ,_reb, /* 24..27 */ + _bvc ,_reb, _bvs ,_reb, _bpl ,_reb, _bmi ,_reb, /* 28..2B */ + _bge ,_reb, _blt ,_reb, _bgt ,_reb, _ble ,_reb, /* 2C..2F */ + _tsx ,_imp, _ins ,_imp, _pula ,_imp, _pulb ,_imp, /* 30..33 */ + _des ,_imp, _txs ,_imp, _psha ,_imp, _pshb ,_imp, /* 34..37 */ + _ill ,_nom, _rts ,_imp, _ill ,_nom, _rti ,_imp, /* 38..3B */ + _ill ,_nom, _ill ,_nom, _wai ,_imp, _swi ,_imp, /* 3C..3F */ + _nega ,_imp, _ill ,_nom, _ill ,_nom, _coma ,_imp, /* 40..43 */ + _lsra ,_imp, _ill ,_nom, _rora ,_imp, _asra ,_imp, /* 44..47 */ + _asla ,_imp, _rola ,_imp, _deca ,_imp, _ill ,_nom, /* 48..4B */ + _inca ,_imp, _tsta ,_imp, _ill ,_nom, _clra ,_imp, /* 4C..4F */ + _negb ,_imp, _ill ,_nom, _ill ,_nom, _comb ,_imp, /* 50..53 */ + _lsrb ,_imp, _ill ,_nom, _rorb ,_imp, _asrb ,_imp, /* 54..57 */ + _aslb ,_imp, _rolb ,_imp, _decb ,_imp, _ill ,_nom, /* 58..5B */ + _incb ,_imp, _tstb ,_imp, _ill ,_nom, _clrb ,_imp, /* 5C..5F */ + _neg ,_ix8, _ill ,_nom, _ill ,_nom, _com ,_ix8, /* 60..63 */ + _lsr ,_ix8, _ill ,_nom, _ror ,_ix8, _asr ,_ix8, /* 64..67 */ + _asl ,_ix8, _rol ,_ix8, _dec ,_ix8, _ill ,_nom, /* 68..6B */ + _inc ,_ix8, _tst ,_ix8, _jmp ,_ix8, _clr ,_ix8, /* 6C..6F */ + _neg ,_ext, _ill ,_nom, _ill ,_nom, _com ,_ext, /* 70..73 */ + _lsr ,_ext, _ill ,_nom, _ror ,_ext, _asr ,_ext, /* 74..77 */ + _asl ,_ext, _rol ,_ext, _dec ,_ext, _ill ,_nom, /* 78..7B */ + _inc ,_ext, _tst ,_ext, _jmp ,_ext, _clr ,_ext, /* 7C..7F */ + _suba ,_imb, _cmpa ,_imb, _sbca ,_imb, _ill ,_nom, /* 80..83 */ + _anda ,_imb, _bita ,_imb, _lda ,_imb, _ill ,_nom, /* 84..87 */ + _eora ,_imb, _adca ,_imb, _ora ,_imb, _adda ,_imb, /* 88..8B */ + _cpx ,_imw, _bsr ,_reb, _lds ,_imw, _ill ,_nom, /* 8C..8F */ + _suba ,_dir, _cmpa ,_dir, _sbca ,_dir, _ill ,_nom, /* 90..93 */ + _anda ,_dir, _bita ,_dir, _lda ,_dir, _sta ,_dir, /* 94..97 */ + _eora ,_dir, _adca ,_dir, _ora ,_dir, _adda ,_dir, /* 98..9B */ + _cpx ,_dir, _ill ,_nom, _lds ,_dir, _sts ,_dir, /* 9C..9F */ + _suba ,_ix8, _cmpa ,_ix8, _sbca ,_ix8, _ill ,_nom, /* A0..A3 */ + _anda ,_ix8, _bita ,_ix8, _lda ,_ix8, _sta ,_ix8, /* A4..A7 */ + _eora ,_ix8, _adca ,_ix8, _ora ,_ix8, _adda ,_ix8, /* A8..AB */ + _cpx ,_ix8, _jsr ,_ix8, _lds ,_ix8, _sts ,_ix8, /* AC..AF */ + _suba ,_ext, _cmpa ,_ext, _sbca ,_ext, _ill ,_nom, /* B0..B3 */ + _anda ,_ext, _bita ,_ext, _lda ,_ext, _sta ,_ext, /* B4..B7 */ + _eora ,_ext, _adca ,_ext, _ora ,_ext, _adda ,_ext, /* B8..BB */ + _cpx ,_ext, _jsr ,_ext, _lds ,_ext, _sts ,_ext, /* BC..BF */ + _subb ,_imb, _cmpb ,_imb, _sbcb ,_imb, _ill ,_nom, /* C0..C3 */ + _andb ,_imb, _bitb ,_imb, _ldb ,_imb, _ill ,_nom, /* C4..C7 */ + _eorb ,_imb, _adcb ,_imb, _orb ,_imb, _addb ,_imb, /* C8..CB */ + _ill ,_nom, _ill ,_nom, _ldx ,_imw, _ill ,_nom, /* CC..CF */ + _subb ,_dir, _cmpb ,_dir, _sbcb ,_dir, _ill ,_nom, /* D0..D3 */ + _andb ,_dir, _bitb ,_dir, _ldb ,_dir, _stb ,_dir, /* D4..D7 */ + _eorb ,_dir, _adcb ,_dir, _orb ,_dir, _addb ,_dir, /* D8..DB */ + _ill ,_nom, _ill ,_nom, _ldx ,_dir, _stx ,_dir, /* DC..DF */ + _subb ,_ix8, _cmpb ,_ix8, _sbcb ,_ix8, _ill ,_nom, /* E0..E3 */ + _andb ,_ix8, _bitb ,_ix8, _ldb ,_ix8, _stb ,_ix8, /* E4..E7 */ + _eorb ,_ix8, _adcb ,_ix8, _orb ,_ix8, _addb ,_ix8, /* E8..EB */ + _ill ,_nom, _ill ,_nom, _ldx ,_ix8, _stx ,_ix8, /* EC..EF */ + _subb ,_ext, _cmpb ,_ext, _sbcb ,_ext, _ill ,_nom, /* F0..F3 */ + _andb ,_ext, _bitb ,_ext, _ldb ,_ext, _stb ,_ext, /* F4..F7 */ + _eorb ,_ext, _adcb ,_ext, _orb ,_ext, _addb ,_ext, /* F8..FB */ + _ill ,_nom, _ill ,_nom, _ldx ,_ext, _stx ,_ext, /* FC..FF */ + }; + +char *Dasm6800::bit_r[] = {"CC","A","B","??"}; + +char *Dasm6800::block_r[] = + { + "D","X","Y","U","S","?","?","?","?","?","?","?","?","?","?","?" + }; + +/*****************************************************************************/ +/* opcodes : 6800 opcodes array for initialization */ +/*****************************************************************************/ + +OpCode Dasm6800::opcodes[mnemo6800_count] = + { + { "???", Data }, /* _ill */ + { "ABA", Data }, /* _aba */ + { "ADCA", Data }, /* _adca */ + { "ADCB", Data }, /* _adcb */ + { "ADDA", Data }, /* _adda */ + { "ADDB", Data }, /* _addb */ + { "ANDA", Data }, /* _anda */ + { "ANDB", Data }, /* _andb */ + { "ASLA", Data }, /* _asla */ + { "ASLB", Data }, /* _aslb */ + { "ASL", Data }, /* _asl */ + { "ASRA", Data }, /* _asra */ + { "ASRB", Data }, /* _asrb */ + { "ASR", Data }, /* _asr */ + { "BCC", Code }, /* _bcc */ + { "BCS", Code }, /* _bcs */ + { "BEQ", Code }, /* _beq */ + { "BGE", Code }, /* _bge */ + { "BGT", Code }, /* _bgt */ + { "BHI", Code }, /* _bhi */ + { "BITA", Data }, /* _bita */ + { "BITB", Data }, /* _bitb */ + { "BLE", Code }, /* _ble */ + { "BLS", Code }, /* _bls */ + { "BLT", Code }, /* _blt */ + { "BMI", Code }, /* _bmi */ + { "BNE", Code }, /* _bne */ + { "BPL", Code }, /* _bpl */ + { "BRA", Code }, /* _bra */ + { "BSR", Code }, /* _bsr */ + { "BVC", Code }, /* _bvc */ + { "BVS", Code }, /* _bvs */ + { "CBA", Data }, /* _cba */ + { "CLI", Data }, /* _cli */ + { "CLRA", Data }, /* _clra */ + { "CLRB", Data }, /* _clrb */ + { "CLR", Data }, /* _clr */ + { "CLC", Data }, /* _clc */ + { "CLV", Data }, /* _clv */ + { "CMPA", Data }, /* _cmpa */ + { "CMPB", Data }, /* _cmpb */ + { "COMA", Data }, /* _coma */ + { "COMB", Data }, /* _comb */ + { "COM", Data }, /* _com */ + { "CPX", Data }, /* _cpx */ + { "DAA", Data }, /* _daa */ + { "DECA", Data }, /* _deca */ + { "DECB", Data }, /* _decb */ + { "DEC", Data }, /* _dec */ + { "DES", Data }, /* _des */ + { "DEX", Data }, /* _dex */ + { "EORA", Data }, /* _eora */ + { "EORB", Data }, /* _eorb */ + { "INCA", Data }, /* _inca */ + { "INCB", Data }, /* _incb */ + { "INC", Data }, /* _inc */ + { "INS", Data }, /* _ins */ + { "INX", Data }, /* _inx */ + { "JMP", Code }, /* _jmp */ + { "JSR", Code }, /* _jsr */ + { "LDAA", Data }, /* _lda */ + { "LDAB", Data }, /* _ldb */ + { "LDS", Data }, /* _lds */ + { "LDX", Data }, /* _ldx */ + { "LSRA", Data }, /* _lsra */ + { "LSRB", Data }, /* _lsrb */ + { "LSR", Data }, /* _lsr */ + { "NEGA", Data }, /* _nega */ + { "NEGB", Data }, /* _negb */ + { "NEG", Data }, /* _neg */ + { "NOP", Data }, /* _nop */ + { "ORAA", Data }, /* _ora */ + { "ORAB", Data }, /* _orb */ + { "PSHA", Data }, /* _psha */ + { "PSHB", Data }, /* _pshb */ + { "PULA", Data }, /* _pula */ + { "PULB", Data }, /* _pulb */ + { "ROLA", Data }, /* _rola */ + { "ROLB", Data }, /* _rolb */ + { "ROL", Data }, /* _rol */ + { "RORA", Data }, /* _rora */ + { "RORB", Data }, /* _rorb */ + { "ROR", Data }, /* _ror */ + { "RTI", Data }, /* _rti */ + { "RTS", Data }, /* _rts */ + { "SBA", Data }, /* _sba */ + { "SBCA", Data }, /* _sbca */ + { "SBCB", Data }, /* _sbcb */ + { "SEC", Data }, /* _sec */ + { "SEI", Data }, /* _sei */ + { "SEV", Data }, /* _sev */ + { "STAA", Data }, /* _sta */ + { "STAB", Data }, /* _stb */ + { "STS", Data }, /* _sts */ + { "STX", Data }, /* _stx */ + { "SUBA", Data }, /* _suba */ + { "SUBB", Data }, /* _subb */ + { "SWI", Data }, /* _swi */ + { "TAB", Data }, /* _tab */ + { "TAP", Data }, /* _tap */ + { "TBA", Data }, /* _tba */ + { "TPA", Data }, /* _tpa */ + { "TSTA", Data }, /* _tsta */ + { "TSTB", Data }, /* _tstb */ + { "TST", Data }, /* _tst */ + { "TSX", Data }, /* _tsx */ + { "TXS", Data }, /* _txs */ + { "WAI", Data }, /* _wai */ + // Convenience mnemonics + { "ASLD", Data }, /* _asld */ + { "LSRD", Data }, /* _lsrd */ + }; + +/*****************************************************************************/ +/* Dasm6800 : constructor */ +/*****************************************************************************/ + +Dasm6800::Dasm6800(void) +{ +codes = m6800_codes; +useConvenience = true; +showIndexedModeZeroOperand = false; +useFCC = true; +#if RB_VARIANT +forceExtendedAddr = false; +forceDirectAddr = false; +closeCC = true; +#else +forceExtendedAddr = true; +forceDirectAddr = true; +closeCC = false; +commentStart = "*"; +#endif + +mnemo.resize(mnemo6800_count); /* set up mnemonics table */ +for (int i = 0; i < mnemo6800_count; i++) + mnemo[i] = opcodes[i]; + +// set up options table +// class uses one generic option setter/getter pair (not mandatory) +AddOption("conv", "{off|on}\tUse convenience macros", + static_cast(&Dasm6800::Set6800Option), + static_cast(&Dasm6800::Get6800Option)); +AddOption("showzero", "{off|on}\tdo not omit indexed-mode operands of $00", + static_cast(&Dasm6800::Set6800Option), + static_cast(&Dasm6800::Get6800Option)); +AddOption("closecc", "{off|on}\tadd closing delimiter to char constants", + static_cast(&Dasm6800::Set6800Option), + static_cast(&Dasm6800::Get6800Option)); +AddOption("fcc", "{off|on}\tuse FCC to define data", + static_cast(&Dasm6800::Set6800Option), + static_cast(&Dasm6800::Get6800Option)); +} + +/*****************************************************************************/ +/* ~Dasm6800 : destructor */ +/*****************************************************************************/ + +Dasm6800::~Dasm6800(void) +{ +} + +/*****************************************************************************/ +/* Set6800Option : sets a disassembler option */ +/*****************************************************************************/ + +int Dasm6800::Set6800Option(std::string lname, std::string value) +{ +std::string lvalue(lowercase(value)); +int bnvalue = (lvalue == "off") ? 0 : (lvalue == "on") ? 1 : atoi(value.c_str()); + +if (lname.substr(0, 2) == "no") /* obviously a boolean negation */ + { + lname = lname.substr(2); /* skip the "no" */ + bnvalue = !bnvalue; /* and invert the value */ + } +if (lname == "conv") + useConvenience = !!bnvalue; +else if (lname == "showzero") + showIndexedModeZeroOperand = !!bnvalue; +else if (lname == "closecc") + closeCC = !!bnvalue; +else if (lname == "fcc") + useFCC = !!bnvalue; +else + return 0; /* only name consumed */ +return 1; /* name and value consumed */ +} + +/*****************************************************************************/ +/* Get6800Option : retrieves a disassembler option */ +/*****************************************************************************/ + +std::string Dasm6800::Get6800Option(std::string lname) +{ +if (lname == "conv") + return useConvenience ? "on" : "off"; +else if (lname == "showzero") + return showIndexedModeZeroOperand ? "on" : "off"; +else if (lname == "closecc") + return closeCC ? "on" : "off"; +else if (lname == "fcc") + return useFCC ? "on" : "off"; + +return ""; +} + +/*****************************************************************************/ +/* SFlexRecord : a record in a binary FLEX(9) disk file */ +/*****************************************************************************/ + +#pragma pack(1) +struct SFlexRecord + { + uint8_t bSOI; /* start of record indicator */ + uint8_t bLoadAddress[2]; /* Hi/Lo byte of load address */ + uint8_t bDataLen; /* length of data record */ + uint8_t bData[255]; /* data record */ + + int IsTransferAddress() { return (bSOI == 0x16); } + int IsRecord() { return (bSOI == 0x02); } + int GetSize() { return bDataLen; } + addr_t GetLoadAddress() { return (((addr_t)(bLoadAddress[0])) << 8) | bLoadAddress[1]; } + uint8_t *GetData() { return bData; } + }; +#pragma pack() + +/*****************************************************************************/ +/* ReadFlexRecord : read one record of a FLEX9 binary */ +/*****************************************************************************/ + +static bool ReadFlexRecord(FILE *f, SFlexRecord *pRecord) +{ +int nCurPos = ftell(f); +uint8_t bCur = 0; +int i; + +while (!bCur) /* read 1st byte, skipping 0 bytes */ + if (!fread(&bCur, 1, 1, f)) + return false; +switch (bCur) /* OK, so what's that? */ + { + case 0x02 : /* Start of Record Indicator ? */ + { + pRecord->bSOI = bCur; + if ((!fread(pRecord->bLoadAddress, 2, 1, f)) || + (!fread(&pRecord->bDataLen, 1, 1, f))) + return false; + for (i = 0; i < pRecord->bDataLen; i++) + if (!fread(&pRecord->bData[i], 1, 1, f)) + return false; + } + break; + case 0x16 : /* Transfer Address ? */ + pRecord->bSOI = bCur; + if (!fread(pRecord->bLoadAddress, 2, 1, f)) + return false; + break; + default : + fseek(f, nCurPos, SEEK_SET); /* seek back */ + return false; + } +return true; +} + +/*****************************************************************************/ +/* LoadFlex : loads a FLEX(9) binary executable */ +/*****************************************************************************/ + +bool Dasm6800::LoadFlex(FILE *f, std::string &sLoadType) +{ +struct SFlexRecord rec; +int nCurPos = ftell(f); +int nRecs = 0; +bool bExecutable = false; +addr_t fbegin = GetHighestCodeAddr(), fend = GetLowestCodeAddr(); +addr_t i; + +while (ReadFlexRecord(f, &rec)) + { + addr_t nStart = rec.GetLoadAddress(); + addr_t nEnd = nStart + rec.GetSize() - 1; + + nRecs++; + if (nStart < fbegin) + fbegin = nStart; + if (nEnd > fend) + fend = nEnd; + if (rec.IsRecord() && rec.GetSize()) + { + AddMemory(nStart, rec.GetSize(), Code, rec.GetData()); + for (i = nStart; i <= nEnd; i++) /* mark area as used */ + { + SetCellUsed(i); + SetDisplay(i, defaultDisplay); + } + } + else if (rec.IsTransferAddress()) + { + bExecutable = true; + load = rec.GetLoadAddress(); + } + } + +if (fgetc(f) != EOF) /* if not read through the whole file*/ + { + for (i = fbegin; i <= fend; i++) /* mark area as UNused */ + SetCellUsed(i, false); + nRecs = 0; /* this ain't no valid FLEX file */ + } + +fseek(f, nCurPos, SEEK_SET); /* reset position for next filetype */ +if (nRecs > 0) + { + if (fbegin < begin) + begin = fbegin; + if (fend > end) + end = fend; + sLoadType = "FLEX"; + } +return (nRecs > 0); +} + +/*****************************************************************************/ +/* LoadFile : loads an opened file */ +/*****************************************************************************/ + +bool Dasm6800::LoadFile(std::string filename, FILE *f, std::string &sLoadType, int interleave) +{ +return LoadFlex(f, sLoadType) || // FLEX9 files need no interleave + Disassembler::LoadFile(filename, f, sLoadType, interleave); +} + +/*****************************************************************************/ +/* String2Number : convert a string to a number in all known formats */ +/*****************************************************************************/ + +bool Dasm6800::String2Number(std::string s, addr_t &value) +{ +/* Standard formats for known 680x assemblers : + - a character has a leading ' + and may be followed by a (n unchecked) closing ' + - a binary has a leading % + - an octal constant has a leading @ + - a hex constant has a leading $ +*/ +if (s[0] == '$') + return (sscanf(s.substr(1).c_str(), "%x", &value) == 1); +else if (s[0] == '@') + return (sscanf(s.substr(1).c_str(), "%o", &value) == 1); +else if (s[0] == '\'' && s.size() > 1) + { + value = s[1]; + return true; + } +else if (s[0] == '%') + { + for (std::string::size_type i = 1; i < s.size(); i++) + { + char c = s[i]; + if (c >= '0' && c <= '1') + value = (value << 1) + (c - '0'); + else + return false; + } + } + +// allow base class to check for others +return Disassembler::String2Number(s, value); +} + +/*****************************************************************************/ +/* Number2String : converts a number to a string in a variety of formats */ +/*****************************************************************************/ + +std::string Dasm6800::Number2String(addr_t value, int nDigits, addr_t addr, bool bDataBus) +{ +std::string s; + +/* Standard formats for known 680x assemblers : + - a character has a leading ' + and may be followed by a (n unchecked) closing ' + - a binary has a leading % + - an octal constant has a leading @ + - a hex constant has a leading $ +*/ + +MemoryType memType = GetMemType(addr); +MemAttribute::Display disp; +bool bSigned = false; +if (memType == MemAttribute::CellUntyped) + { +#pragma message("Define default type!") + disp = MemAttribute::Hex; + } +else + { + disp = GetDisplay(addr); + bSigned = IsSigned(addr); + } + +if ((nDigits == 2) && /* if 2-digit value */ + (disp == MemAttribute::Char)) /* and character output requested */ + { + if (isprint(value)) + s = sformat("'%c%s", value, closeCC ? "'" : ""); + else + s = sformat("$%02x", value); + } +else if (disp == MemAttribute::Binary) /* if a binary */ + { + int nBit; + + nDigits *= 4; /* convert from digits to bits */ + s = '%'; /* prepare a binary value */ + /* now do for all bits */ + for (nBit = nDigits - 1; nBit >= 0; nBit--) + s.push_back('0' + (!!(value & (1 << nBit)))); + } +else if (disp == MemAttribute::Hex) /* if hex */ + s = sformat("$%0*X", nDigits, value); /* prepare a hex value */ +else if (disp == MemAttribute::Octal) /* if octal display */ + s = sformat("@%0*o", (nDigits * 4) + 2 / 3, value); +else /* otherwise */ + { + if (bSigned) + { + int32_t sval; // sign extension, simple way + if (nDigits == 2) sval = (int32_t)((int8_t)value); + else if (nDigits == 4) sval = (int32_t)((int16_t)value); + else sval = (int32_t)value; + s = sformat("%d", sval); /* prepare signed decimal value */ + } + else + s = sformat("%u", value); /* prepare unsigned decimal value */ + } +return s; /* pass back generated string */ +} + +/*****************************************************************************/ +/* InitParse : initialize parsing */ +/*****************************************************************************/ + +bool Dasm6800::InitParse(bool bDataBus) +{ +if (!bDataBus) + { + // set up IRQ-RST system vectors + static const char *vectbl[] = + { + "IRQ", /* fff8 */ + "SWI", /* fffa */ + "NMI", /* fffc */ + "RST" /* fffe */ + }; + for (addr_t addr = 0xfff8; addr <= GetHighestCodeAddr(); addr+= 2) + { + if (GetMemType(addr) != Untyped) /* if system vector loaded */ + { + SetMemType(addr, Data); /* that's a data word */ + SetCellSize(addr, 2); + addr_t tgtaddr = GetUWord(addr); /* look whether it points to loaded */ + if (GetMemType(tgtaddr) != Untyped) + { /* if so, */ + SetMemType(tgtaddr, Code); /* that's code there */ + AddLabel(tgtaddr, Code, /* and it got a predefined label */ + sformat("vec_%s", vectbl[(addr - 0xfff8) / 2]), + true); + } + } + } + } +return Disassembler::InitParse(bDataBus); +} + +/*****************************************************************************/ +/* ParseData : parse data at given memory address for labels */ +/*****************************************************************************/ + +addr_t Dasm6800::ParseData + ( + addr_t addr, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +int csz = GetCellSize(addr); +if (csz == 2) /* if WORD data */ + { + if (!IsConst(addr)) + { + addr_t wo = GetUWord(addr); + Label *pLabel = FindLabel(wo); /* if there's a label for the addr */ + if (pLabel) + pLabel->SetUsed(); /* mark it as used */ + } + } +return csz; +} + +/*****************************************************************************/ +/* ParseCode : parse instruction at given memory address for labels */ +/*****************************************************************************/ + +addr_t Dasm6800::ParseCode + ( + addr_t addr, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +int MI; +const char *I; +addr_t PC = addr; +bool bSetLabel; + +O = T = GetUByte(PC++); +W = (uint16_t)(T * 2); +MI = T = codes[W++]; +I = mnemo[T].mne; +M = codes[W]; + +switch (M) /* which mode is this ? */ + { + case _nom: /* no mode */ + PC = addr + 1; + break; + + case _imp: /* inherent/implied */ + break; + + case _imb: /* immediate byte */ + PC++; + break; + + case _imw: /* immediate word */ + bSetLabel = !IsConst(PC); + W = GetUWord(PC); + if (bSetLabel) + { + W = (uint16_t)PhaseInner(W, PC); + AddLabel(W, mnemo[MI].memType, "", true); + } + PC += 2; + break; + + case _dir: /* direct */ + bSetLabel = !IsConst(PC); + T = GetUByte(PC); + if (bSetLabel) + { + W = T; // on 6800, dp=0 + W = (uint16_t)PhaseInner(W, PC); + AddLabel(W, mnemo[MI].memType, "", true); + } + PC++; + break; + + case _ext: /* extended */ + bSetLabel = !IsConst(PC); + if (bSetLabel) + { + uint16_t ow = GetUWord(PC); + W = (uint16_t)PhaseInner(ow, PC); + AddLabel(W, mnemo[MI].memType, "", true); + } + PC += 2; + break; + + case _ix8: /* indexed for 6800 (unsigned) */ + PC++; + break; + + case _reb: /* relative byte */ + bSetLabel = !IsConst(PC); + T = GetUByte(PC); PC++; + W = (uint16_t)(PC + (signed char)T); + if (bSetLabel) + { + W = (uint16_t)DephaseOuter(W, PC - 1); + AddLabel(W, mnemo[MI].memType, "", true); + } + break; + + } + +return PC - addr; /* pass back # processed bytes */ +} + +/*****************************************************************************/ +/* DisassembleLabel : disassemble used external labels */ +/*****************************************************************************/ + +bool Dasm6800::DisassembleLabel + ( + addr_t addr, + std::string &smnemo, + std::string &sparm, + bool bDataBus + ) +{ +Label *pLabel; +std::string s; + +if (/* !IsCellUsed(addr) && */ // to be done externally! + (pLabel = FindLabel(addr)) != NULL && + pLabel->IsUsed() && + pLabel->GetText().find_first_of("+-") == std::string::npos) + { + smnemo = "EQU"; + sparm = sformat("$%04X", addr); + return true; + } +return false; +} + +/*****************************************************************************/ +/* DisassembleData : disassemble data area at given memory address */ +/*****************************************************************************/ + +addr_t Dasm6800::DisassembleData + ( + addr_t addr, + addr_t end, + uint32_t flags, + std::string &smnemo, + std::string &sparm, + int maxparmlen, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +std::string::size_type max = 24; //(nComment ? 24 : 52); +addr_t done; + +if (flags & SHMF_RMB) /* if reserved memory block */ + { + done = end; /* remember it's done completely */ + smnemo = "RMB"; + sparm = Number2String(end - addr, 4, addr); + } +else if (useFCC && (flags & SHMF_TXT)) /* if FCC (text) allowed */ + { + smnemo = "FCC"; + sparm = '"'; /* start the game */ + for (done = addr; done < end; done++) /* assemble as many as possible */ + { /* if this would become too long */ + if (sparm.size() + 2 > (std::string::size_type)maxparmlen) + break; /* terminate the loop */ + sparm += *getat(done); + } + sparm += '"'; /* append delimiter */ + } +else if (flags & 0xff) /* if not byte-sized */ + { + // 680x can ony do byte and word, so assume word entities + smnemo = "FDB"; + /* assemble as many as possible */ + for (done = addr; done < end; done += 2) + { + std::string s = Label2String(GetUWord(done), !IsConst(done), done); + if (sparm.size()) /* if already something there */ + { /* if this would become too long */ + if (sparm.size() + s.size() + 1 > (std::string::size_type)maxparmlen) + break; /* terminate the loop */ + sparm += ','; /* add separator */ + } + sparm += s; /* append the byte's representation */ + } + } +else /* if FCB (hex or binary) */ + { + smnemo = "FCB"; + /* assemble as many as possible */ + for (done = addr; done < end; done++) + { + std::string s = Number2String(*getat(done), 2, done); + if (sparm.size()) /* if already something there */ + { /* if this would become too long */ + if (sparm.size() + s.size() + 1 > (std::string::size_type)maxparmlen) + break; /* terminate the loop */ + sparm += ','; /* add separator */ + } + sparm += s; /* append the byte's representation */ + } + } + +return done - addr; +} + +/*****************************************************************************/ +/* DisassembleCode : disassemble code instruction at given memory address */ +/*****************************************************************************/ + +addr_t Dasm6800::DisassembleCode + ( + addr_t addr, + std::string &smnemo, + std::string &sparm, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +addr_t Wrel; +const char *I; +addr_t PC = addr; +bool bGetLabel; + +O = T = GetUByte(PC++); +W = (uint16_t)(T * 2); +T = codes[W++]; +I = mnemo[T].mne; +M = codes[W]; + +smnemo = I; /* initialize mnemonic */ + +switch (M) /* which mode is this? */ + { + case _nom: /* no mode */ + smnemo = "FCB"; + sparm = Number2String(O, 2, PC++); + break; + + case _imp: /* inherent/implied */ + if (useConvenience && + !IsLabel(PC)) /* not if 2nd byte has a label! */ + { + switch ((uint16_t)(O << 8) | GetUByte(PC)) + { + case 0x4456 : /* LSRA + RORB -> LSRD */ + smnemo = mnemo[_lsrd].mne; PC++; + break; + case 0x5849 : /* ASLB + ROLA -> ASLD */ + smnemo = mnemo[_asld].mne; PC++; + break; + } + } + break; + + case _imb: /* immediate byte */ + T = GetUByte(PC++); + sparm = "#" + Number2String(T, 2, PC - 1); + break; + + case _imw: /* immediate word */ + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + if (bGetLabel) + W = (uint16_t)PhaseInner(W, PC - 2); + sparm = "#" + Label2String(W, bGetLabel, PC - 2); + break; + + case _dir: /* direct */ + bGetLabel = !IsConst(PC); + T = GetUByte(PC++); + W = (uint16_t)T; + if (bGetLabel) + W = (uint16_t)PhaseInner(W, PC - 1); + sparm = Label2String(W, bGetLabel, PC - 1); + break; + + case _ext: /* extended */ + bGetLabel = !IsConst(PC); + W = (uint16_t)PhaseInner(GetUWord(PC), PC); + PC += 2; + if (forceExtendedAddr && (W & (uint16_t)0xff00) == 0) + sparm = ">" + Label2String(W, bGetLabel, PC - 2); + else + sparm = Label2String(W, bGetLabel, PC - 2); + break; + + case _ix8: /* indexed for 6800 (unsigned) */ + bGetLabel = !IsConst(PC); + T = GetUByte(PC++); + Wrel = GetRelative(PC - 1); + if (Wrel) + { + W = (int)((unsigned char)T) + (uint16_t)Wrel; + sparm = Label2String((addr_t)((int)((unsigned char)T)), bGetLabel, PC - 1) + ",X"; + } + else if (!T && !showIndexedModeZeroOperand) + sparm = ",X"; /* omit '$00', unless the user has set the 'showzero' option */ + else + sparm = Number2String(T, 2, PC - 1) + ",X"; + break; + + case _reb: /* relative byte */ + bGetLabel = !IsConst(PC); + T = GetUByte(PC++); + if (bGetLabel) + { + W = (uint16_t)(PC + (int8_t)T); + W = (uint16_t)DephaseOuter(W, PC - 1); + sparm = Label2String(W, bGetLabel, PC - 1); + } + else + { + int nDiff = (int)(int8_t)T; + sparm = "*"; + if (nDiff >= 0) + sparm += "+"; + sparm += SignedNumber2String(nDiff + 2, 2, PC - 1); + } + break; + } +return PC - addr; /* pass back # processed bytes */ +} + +/*****************************************************************************/ +/* DisassembleChanges : report dasm-specific state changes before/after addr */ +/*****************************************************************************/ + +bool Dasm6800::DisassembleChanges + ( + addr_t addr, + addr_t prevaddr, + addr_t prevsz, + bool bAfterLine, + std::vector &changes, + bool bDataBus + ) +{ +// init / exit +if (addr == NO_ADDRESS && prevaddr == NO_ADDRESS) + { + if (!bAfterLine) /* start of disassembly output */ + { + } + else /* end of disassembly output */ + { + LineChange chg; + changes.push_back(chg); /* append empty line before END */ + chg.smnemo = "END"; + if (load != NO_ADDRESS && /* if entry point address given */ + bLoadLabel) /* and labelling wanted */ + chg.sparm = Label2String(load, true, load); + changes.push_back(chg); + } + } +else if (!bDataBus) /* no Harvard architecture here. */ + { + addr_t org = DephaseOuter(addr, addr); + addr_t prevorg = DephaseOuter(prevaddr, prevaddr); + if (addr != prevaddr + prevsz) + { + if (!bAfterLine) + { + TMemory *curPhArea = FindPhase(addr); + TMemory *prevPhArea = FindPhase(prevaddr); + + addr_t prevphase = prevPhArea ? prevPhArea->GetType() : NO_ADDRESS; + addr_t prevphstart = prevPhArea ? prevPhArea->GetStart() : NO_ADDRESS; + addr_t curphase = curPhArea ? curPhArea->GetType() : NO_ADDRESS; + addr_t curphstart = curPhArea ? curPhArea->GetStart() : NO_ADDRESS; + LineChange chg; + changes.push_back(chg); + if (prevphase != NO_ADDRESS && prevphstart != curphstart) + { + chg.smnemo = "DEPHASE"; + changes.push_back(chg); + changes.push_back(LineChange()); + } + if (addr != NO_ADDRESS) + { + chg.smnemo = "ORG"; + chg.sparm = Number2String(addr, 4, NO_ADDRESS); + changes.push_back(chg); + if (curphase != NO_ADDRESS && + prevphstart != curphstart +// uncomment this to remove superfluous PHASE statements +// && curphase != addr + ) + { + chg.smnemo = "PHASE"; + chg.sparm = Number2String(curphase, 4, NO_ADDRESS); + changes.push_back(chg); + } + changes.push_back(LineChange()); + } + } + } + } + +return Disassembler::DisassembleChanges(addr, prevaddr, prevsz, bAfterLine, changes, bDataBus); +} diff --git a/Dasm6800.h b/Dasm6800.h new file mode 100644 index 0000000..e492a5f --- /dev/null +++ b/Dasm6800.h @@ -0,0 +1,255 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6800.h : definition of the Dasm6800 class */ +/*****************************************************************************/ + +#ifndef __Dasm6800_h_defined__ +#define __Dasm6800_h_defined__ + +#include "Disassembler.h" + +/* + * Copied from f9dasm ... + * There's a variant "1.61-RB" available at + * https://github.com/gordonjcp/f9dasm + * (based on my V1.60) which contains some interesting changes by Rainer Buchty. + * Unfortunately, I only saw that by chance in summer 2015, 6 versions later. + * Rainer customized it to his own taste, so I didn't directly add his changes + * to my code, which defaults to TSC Assembler compatible output; + * you can, however, create a "Rainer Buchty compatible variant" by either + * 1) setting the -DRB_VARIANT compiler flag or + * 2) setting the following definition to anything other than 0. +*/ + +#ifndef RB_VARIANT + #define RB_VARIANT 0 +#endif + + +/*****************************************************************************/ +/* Dasm6800 : class for a Motorola 6800 processor */ +/*****************************************************************************/ + +class Dasm6800 : + public Disassembler + { + public: + Dasm6800(void); + virtual ~Dasm6800(void); + + // Overrides + public: + // return processor long name + virtual std::string GetName() { return "Motorola 6800"; } + // return whether big- or little-endian + virtual Endian GetEndianness() { return BigEndian; } + // return code bits + virtual int GetCodeBits() { return 16; } + // return code pointer size in bytes + virtual int GetCodePtrSize() { return 2; } + // return highest possible code address + virtual caddr_t GetHighestCodeAddr() { return 0xffff; } + // return data bits + virtual int GetDataBits() { return 8; } + // return data pointer size in bytes + virtual int GetDataPtrSize() { return 2; } + // return highest possible data address + virtual daddr_t GetHighestDataAddr() { return 0xffff; } + + // Options handler + protected: + int Set6800Option(std::string name, std::string value); + std::string Get6800Option(std::string name); + + protected: + // parse data area for labels + virtual addr_t ParseData(addr_t addr, bool bDataBus = false); + // parse instruction at given memory address for labels + virtual addr_t ParseCode(addr_t addr, bool bDataBus = false); + // pass back correct mnemonic and parameters for a label + virtual bool DisassembleLabel(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false); + // disassemble data area at given memory address + virtual addr_t DisassembleData(addr_t addr, addr_t end, uint32_t flags, std::string &smnemo, std::string &sparm, int maxparmlen, bool bDataBus = false); + // disassemble instruction at given memory address + virtual addr_t DisassembleCode(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false); + public: + // Initialize parsing + virtual bool InitParse(bool bDataBus = false); + // pass back disassembler-specific state changes before/after a disassembly line + virtual bool DisassembleChanges(addr_t addr, addr_t prevaddr, addr_t prevsz, bool bAfterLine, std::vector &changes, bool bDataBus = false); + + + protected: + bool LoadFlex(FILE *f, std::string &sLoadType); + virtual bool LoadFile(std::string filename, FILE *f, std::string &sLoadType, int interleave = 1); + virtual bool String2Number(std::string s, addr_t &value); + virtual std::string Number2String(addr_t value, int nDigits, addr_t addr, bool bDataBus = false); + + protected: + // 6800 addressing modes + enum AddrMode6800 + { + _nom, /* no mode */ + _imp, /* inherent/implied */ + _imb, /* immediate byte */ + _imw, /* immediate word */ + _dir, /* direct */ + _ext, /* extended */ + _ix8, /* indexed for 6800 (unsigned) */ + _reb, /* relative byte */ + + addrmodes6800_count + }; + + // 6800 mnemonics + enum Mnemonics6800 + { + _ill, /* illegal */ + _aba, + _adca, + _adcb, + _adda, + _addb, + _anda, + _andb, + _asla, + _aslb, + _asl, + _asra, + _asrb, + _asr, + _bcc, + _bcs, + _beq, + _bge, + _bgt, + _bhi, + _bita, + _bitb, + _ble, + _bls, + _blt, + _bmi, + _bne, + _bpl, + _bra, + _bsr, + _bvc, + _bvs, + _cba, + _cli, + _clra, + _clrb, + _clr, + _clc, + _clv, + _cmpa, + _cmpb, + _coma, + _comb, + _com, + _cpx, + _daa, + _deca, + _decb, + _dec, + _des, + _dex, + _eora, + _eorb, + _inca, + _incb, + _inc, + _ins, + _inx, + _jmp, + _jsr, + _lda, + _ldb, + _lds, + _ldx, + _lsra, + _lsrb, + _lsr, + _nega, + _negb, + _neg, + _nop, + _ora, + _orb, + _psha, + _pshb, + _pula, + _pulb, + _rola, + _rolb, + _rol, + _rora, + _rorb, + _ror, + _rti, + _rts, + _sba, + _sbca, + _sbcb, + _sec, + _sei, + _sev, + _sta, + _stb, + _sts, + _stx, + _suba, + _subb, + _swi, + _tab, + _tap, + _tba, + _tpa, + _tsta, + _tstb, + _tst, + _tsx, + _txs, + _wai, + // convenience mnemonics + _asld, + _lsrd, + + mnemo6800_count + }; + + static uint8_t m6800_codes[512]; + + uint8_t *codes; + static char *bit_r[]; + static char *block_r[]; + static OpCode opcodes[mnemo6800_count]; + + bool useConvenience; + bool useFCC; + bool showIndexedModeZeroOperand; + bool closeCC; + bool forceExtendedAddr; + bool forceDirectAddr; + }; + + +#endif // __Dasm6800_h_defined__ diff --git a/Dasm6801.cpp b/Dasm6801.cpp new file mode 100644 index 0000000..099d963 --- /dev/null +++ b/Dasm6801.cpp @@ -0,0 +1,177 @@ +#include "Dasm6801.h" + +/*****************************************************************************/ +/* Create6801 : create an 6801 disassembler */ +/*****************************************************************************/ + +static Disassembler *Create6801() +{ +Disassembler *pDasm = new Dasm6801; +if (pDasm) pDasm->Setup(); +return pDasm; +} + +/*****************************************************************************/ +/* Auto-registration */ +/*****************************************************************************/ + +static bool bRegistered[] = + { + RegisterDisassembler("6801", Create6801), + RegisterDisassembler("6803", Create6801), + }; + + +/*===========================================================================*/ +/* Dasm6801 class members */ +/*===========================================================================*/ + +/*****************************************************************************/ +/* m6801_codes : table of all 6801 instruction bytes and types */ +/*****************************************************************************/ + +uint8_t Dasm6801::m6801_codes[512] = + { + _ill ,_nom, _nop ,_imp, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _lsrd ,_imp, _asld ,_imp, _tap ,_imp, _tpa ,_imp, /* 04..07 */ + _inx ,_imp, _dex ,_imp, _clv ,_imp, _sev ,_imp, /* 08..0B */ + _clc ,_imp, _sec ,_imp, _cli ,_imp, _sei ,_imp, /* 0C..0F */ + _sba ,_imp, _cba ,_imp, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _tab ,_imp, _tba ,_imp, /* 14..17 */ + _ill ,_nom, _daa ,_imp, _ill ,_nom, _aba ,_imp, /* 18..1B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _bra ,_reb, _brn ,_reb, _bhi ,_reb, _bls ,_reb, /* 20..23 */ + _bcc ,_reb, _bcs ,_reb, _bne ,_reb, _beq ,_reb, /* 24..27 */ + _bvc ,_reb, _bvs ,_reb, _bpl ,_reb, _bmi ,_reb, /* 28..2B */ + _bge ,_reb, _blt ,_reb, _bgt ,_reb, _ble ,_reb, /* 2C..2F */ + _tsx ,_imp, _ins ,_imp, _pula ,_imp, _pulb ,_imp, /* 30..33 */ + _des ,_imp, _txs ,_imp, _psha ,_imp, _pshb ,_imp, /* 34..37 */ + _pulx ,_imp, _rts ,_imp, _abx ,_imp, _rti ,_imp, /* 38..3B */ + _pshx ,_imp, _mul ,_imp, _wai ,_imp, _swi ,_imp, /* 3C..3F */ + _nega ,_imp, _ill ,_nom, _ill ,_nom, _coma ,_imp, /* 40..43 */ + _lsra ,_imp, _ill ,_nom, _rora ,_imp, _asra ,_imp, /* 44..47 */ + _asla ,_imp, _rola ,_imp, _deca ,_imp, _ill ,_nom, /* 48..4B */ + _inca ,_imp, _tsta ,_imp, _ill ,_nom, _clra ,_imp, /* 4C..4F */ + _negb ,_imp, _ill ,_nom, _ill ,_nom, _comb ,_imp, /* 50..53 */ + _lsrb ,_imp, _ill ,_nom, _rorb ,_imp, _asrb ,_imp, /* 54..57 */ + _aslb ,_imp, _rolb ,_imp, _decb ,_imp, _ill ,_nom, /* 58..5B */ + _incb ,_imp, _tstb ,_imp, _ill ,_nom, _clrb ,_imp, /* 5C..5F */ + _neg ,_ix8, _ill ,_nom, _ill ,_nom, _com ,_ix8, /* 60..63 */ + _lsr ,_ix8, _ill ,_nom, _ror ,_ix8, _asr ,_ix8, /* 64..67 */ + _asl ,_ix8, _rol ,_ix8, _dec ,_ix8, _ill ,_nom, /* 68..6B */ + _inc ,_ix8, _tst ,_ix8, _jmp ,_ix8, _clr ,_ix8, /* 6C..6F */ + _neg ,_ext, _ill ,_nom, _ill ,_nom, _com ,_ext, /* 70..73 */ + _lsr ,_ext, _ill ,_nom, _ror ,_ext, _asr ,_ext, /* 74..77 */ + _asl ,_ext, _rol ,_ext, _dec ,_ext, _ill ,_nom, /* 78..7B */ + _inc ,_ext, _tst ,_ext, _jmp ,_ext, _clr ,_ext, /* 7C..7F */ + _suba ,_imb, _cmpa ,_imb, _sbca ,_imb, _subd ,_imw, /* 80..83 */ + _anda ,_imb, _bita ,_imb, _lda ,_imb, _ill ,_nom, /* 84..87 */ + _eora ,_imb, _adca ,_imb, _ora ,_imb, _adda ,_imb, /* 88..8B */ + _cpx ,_imw, _bsr ,_reb, _lds ,_imw, _ill ,_nom, /* 8C..8F */ + _suba ,_dir, _cmpa ,_dir, _sbca ,_dir, _subd ,_dir, /* 90..93 */ + _anda ,_dir, _bita ,_dir, _lda ,_dir, _sta ,_dir, /* 94..97 */ + _eora ,_dir, _adca ,_dir, _ora ,_dir, _adda ,_dir, /* 98..9B */ + _cpx ,_dir, _jsr ,_dir, _lds ,_dir, _sts ,_dir, /* 9C..9F */ + _suba ,_ix8, _cmpa ,_ix8, _sbca ,_ix8, _subd ,_ix8, /* A0..A3 */ + _anda ,_ix8, _bita ,_ix8, _lda ,_ix8, _sta ,_ix8, /* A4..A7 */ + _eora ,_ix8, _adca ,_ix8, _ora ,_ix8, _adda ,_ix8, /* A8..AB */ + _cpx ,_ix8, _jsr ,_ix8, _lds ,_ix8, _sts ,_ix8, /* AC..AF */ + _suba ,_ext, _cmpa ,_ext, _sbca ,_ext, _subd ,_ext, /* B0..B3 */ + _anda ,_ext, _bita ,_ext, _lda ,_ext, _sta ,_ext, /* B4..B7 */ + _eora ,_ext, _adca ,_ext, _ora ,_ext, _adda ,_ext, /* B8..BB */ + _cpx ,_ext, _jsr ,_ext, _lds ,_ext, _sts ,_ext, /* BC..BF */ + _subb ,_imb, _cmpb ,_imb, _sbcb ,_imb, _addd ,_imw, /* C0..C3 */ + _andb ,_imb, _bitb ,_imb, _ldb ,_imb, _ill ,_nom, /* C4..C7 */ + _eorb ,_imb, _adcb ,_imb, _orb ,_imb, _addb ,_imb, /* C8..CB */ + _ldd ,_imw, _ill ,_nom, _ldx ,_imw, _ill ,_nom, /* CC..CF */ + _subb ,_dir, _cmpb ,_dir, _sbcb ,_dir, _addd ,_dir, /* D0..D3 */ + _andb ,_dir, _bitb ,_dir, _ldb ,_dir, _stb ,_dir, /* D4..D7 */ + _eorb ,_dir, _adcb ,_dir, _orb ,_dir, _addb ,_dir, /* D8..DB */ + _ldd ,_dir, _std ,_dir, _ldx ,_dir, _stx ,_dir, /* DC..DF */ + _subb ,_ix8, _cmpb ,_ix8, _sbcb ,_ix8, _addd ,_ix8, /* E0..E3 */ + _andb ,_ix8, _bitb ,_ix8, _ldb ,_ix8, _stb ,_ix8, /* E4..E7 */ + _eorb ,_ix8, _adcb ,_ix8, _orb ,_ix8, _addb ,_ix8, /* E8..EB */ + _ldd ,_ix8, _std ,_ix8, _ldx ,_ix8, _stx ,_ix8, /* EC..EF */ + _subb ,_ext, _cmpb ,_ext, _sbcb ,_ext, _addd ,_ext, /* F0..F3 */ + _andb ,_ext, _bitb ,_ext, _ldb ,_ext, _stb ,_ext, /* F4..F7 */ + _eorb ,_ext, _adcb ,_ext, _orb ,_ext, _addb ,_ext, /* F8..FB */ + _ldd ,_ext, _std ,_ext, _ldx ,_ext, _stx ,_ext, /* FC..FF */ + }; + +/*****************************************************************************/ +/* opcodes : additional opcodes over 6800 */ +/*****************************************************************************/ + +OpCode Dasm6801::opcodes[mnemo6801_count - mnemo6800_count] = + { + { "ABX", Data }, /* _abx */ + { "ADDD", Data }, /* _addd */ + { "BRN", Code }, /* _brn */ + { "LDD", Data }, /* _ldd */ + { "MUL", Data }, /* _mul */ + { "PULX", Data }, /* _pulx */ + { "PSHX", Data }, /* _pshx */ + { "STD", Data }, /* _std */ + { "SUBD", Data }, /* _subd */ + }; + +/*****************************************************************************/ +/* Dasm6801 : constructor */ +/*****************************************************************************/ + +Dasm6801::Dasm6801(void) +{ +codes = m6801_codes; +mnemo.resize(mnemo6801_count); /* set up additional mnemonics */ +for (int i = 0; i < mnemo6801_count - mnemo6800_count; i++) + mnemo[mnemo6800_count + i] = opcodes[i]; +} + +/*****************************************************************************/ +/* ~Dasm6801 : destructor */ +/*****************************************************************************/ + +Dasm6801::~Dasm6801(void) +{ +} + +/*****************************************************************************/ +/* InitParse : initialize parsing */ +/*****************************************************************************/ + +bool Dasm6801::InitParse(bool bDataBus) +{ +Dasm6800::InitParse(bDataBus); /* let 6800 init go first */ +if (!bDataBus) + { + static const char *vectbl[] = + { + "IRQ_SCI", /* fff0 */ + "IRQ_T0F", /* fff2 */ + "IRQ_OCF", /* fff4 */ + "IRQ_ICF", /* fff6 */ + "IRQ_EXT", /* fff8 */ + "SWI", /* fffa */ + "NMI", /* fffc */ + "RST" /* fffe */ + }; + for (addr_t addr = 0xfff0; addr <= GetHighestCodeAddr(); addr += 2) + { + if (GetMemType(addr) != Untyped) /* if system vector loaded */ + { + SetMemType(addr, Data); /* that's a data word */ + SetCellSize(addr, 2); + addr_t tgtaddr = GetUWord(addr); /* look whether it points to loaded */ + if (GetMemType(tgtaddr) != Untyped) + { /* if so, */ + SetMemType(tgtaddr, Code); /* that's code there */ + AddLabel(tgtaddr, Code, /* and it got a predefined label */ + sformat("vec_%s", vectbl[(addr - 0xfff0) / 2]), + true); + } + } + } + } +return true; +} + diff --git a/Dasm6801.h b/Dasm6801.h new file mode 100644 index 0000000..2aa6c44 --- /dev/null +++ b/Dasm6801.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6801.h : definition of the Dasm6801 class */ +/*****************************************************************************/ + +#ifndef __Dasm6801_h_defined__ +#define __Dasm6801_h_defined__ + +#include "Dasm6800.h" + +/*****************************************************************************/ +/* Dasm6801 : class for a Motorola 6801 Processor */ +/*****************************************************************************/ + +class Dasm6801 : public Dasm6800 + { + public: + Dasm6801(void); + virtual ~Dasm6801(void); + + // Overrides + public: + // return processor long name + virtual std::string GetName() { return "Motorola 6801"; } + + // Initialize parsing + virtual bool InitParse(bool bDataBus = false); + + protected: + // additional 6801 mnemonics + enum Mnemonics6801 + { + _abx = mnemo6800_count, + _addd, + _brn, + _ldd, + _mul, + _pulx, + _pshx, + _std, + _subd, + + mnemo6801_count + }; + + + static uint8_t m6801_codes[512]; + static OpCode opcodes[mnemo6801_count - mnemo6800_count]; + }; + +#endif // __Dasm6801_h_defined__ diff --git a/Dasm6809.cpp b/Dasm6809.cpp new file mode 100644 index 0000000..c3f8485 --- /dev/null +++ b/Dasm6809.cpp @@ -0,0 +1,1488 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6809.cpp : 6809 disassembler implementation */ +/*****************************************************************************/ + +#include "Dasm6809.h" + +/*****************************************************************************/ +/* Create6809 : create an 6809 disassembler */ +/*****************************************************************************/ + +static Disassembler *Create6809() +{ +Disassembler *pDasm = new Dasm6809; +if (pDasm) pDasm->Setup(); +return pDasm; +} + +/*****************************************************************************/ +/* Auto-registration */ +/*****************************************************************************/ + +static bool bRegistered = RegisterDisassembler("6809", Create6809); + + +/*****************************************************************************/ +/* os9_codes : OS/9 entry points */ +/*****************************************************************************/ + +char *Dasm6809::os9_codes[0x100] = + { + "F$Link", "F$Load", "F$UnLink", "F$Fork", /* 00..03 */ + "F$Wait", "F$Chain", "F$Exit", "F$Mem", /* 04..07 */ + "F$Send", "F$Icpt", "F$Sleep", "F$SSpd", /* 08..0B */ + "F$ID", "F$SPrior", "F$SSWI", "F$Perr", /* 0C..0F */ + "F$PrsNam", "F$CmpNam", "F$SchBit", "F$AllBit", /* 10..13 */ + "F$DelBit", "F$Time", "F$STime", "F$CRC", /* 14..17 */ + "F$GPrDsc", "F$GBlkMp", "F$GModDr", "F$CpyMem", /* 18..1B */ + "F$SUser", "F$UnLoad", "F$Alarm", "F$", /* 1C..1F */ + "F$", "F$NMLink", "F$NMLoad", "F$Ctime", /* 20..23 */ + "F$Cstime", "F$CTswi2", "F$", "F$VIRQ", /* 24..27 */ + "F$SRqMem", "F$SRtMem", "F$IRQ", "F$IOQu", /* 28..2B */ + "F$AProc", "F$NProc", "F$VModul", "F$Find64", /* 2C..2F */ + "F$All64", "F$Ret64", "F$SSvc", "F$IODel", /* 30..33 */ + "F$SLink", "F$Boot", "F$BtMem", "F$GProcP", /* 34..37 */ + "F$Move", "F$AllRAM", "F$AllImg", "F$DelImg", /* 38..3B */ + "F$SetImg", "F$FreeLB", "F$FreeHB", "F$AllTsk", /* 3C..3F */ + "F$DelTsk", "F$SetTsk", "F$ResTsk", "F$RelTsk", /* 40..43 */ + "F$DATLog", "F$DATTmp", "F$LDAXY", "F$LDAXYP", /* 44..47 */ + "F$LDDDXY", "F$LDABX", "F$STABX", "F$AllPrc", /* 48..4B */ + "F$DelPrc", "F$ELink", "F$FModul", "F$MapBlk", /* 4C..4F */ + "F$ClrBlk", "F$DelRAM", "F$GCMDir", "F$AlHRam", /* 50..53 */ + "F$", "F$", "F$", "F$", /* 54..57 */ + "F$", "F$", "F$", "F$", /* 58..5B */ + "F$", "F$", "F$", "F$", /* 5C..5F */ + "F$", "F$", "F$", "F$", /* 60..63 */ + "F$", "F$", "F$", "F$", /* 64..67 */ + "F$", "F$", "F$", "F$", /* 68..6B */ + "F$", "F$", "F$", "F$", /* 6C..6F */ + "F$", "F$", "F$", "F$", /* 70..73 */ + "F$", "F$", "F$", "F$", /* 74..77 */ + "F$", "F$", "F$", "F$", /* 78..7B */ + "F$", "F$", "F$", "F$", /* 7C..7F */ + "I$Attach", "I$Detach", "I$Dup", "I$Create", /* 80..83 */ + "I$Open", "I$MakDir", "I$Chgdir", "I$Delete", /* 84..87 */ + "I$Seek", "I$Read", "I$Write", "I$ReadLn", /* 88..8B */ + "I$WritLn", "I$GetStt", "I$SetStt", "I$Close", /* 8C..8F */ + "I$DeletX", "F$", "F$", "F$", /* 90..93 */ + "F$", "F$", "F$", "F$", /* 94..97 */ + "F$", "F$", "F$", "F$", /* 98..9B */ + "F$", "F$", "F$", "F$", /* 9C..9F */ + "F$", "F$", "F$", "F$", /* A0..A3 */ + "F$", "F$", "F$", "F$", /* A4..A7 */ + "F$", "F$", "F$", "F$", /* A8..AB */ + "F$", "F$", "F$", "F$", /* AC..AF */ + "F$", "F$", "F$", "F$", /* B0..B3 */ + "F$", "F$", "F$", "F$", /* B4..B7 */ + "F$", "F$", "F$", "F$", /* B8..BB */ + "F$", "F$", "F$", "F$", /* BC..BF */ + "F$", "F$", "F$", "F$", /* C0..C3 */ + "F$", "F$", "F$", "F$", /* C4..C7 */ + "F$", "F$", "F$", "F$", /* C8..CB */ + "F$", "F$", "F$", "F$", /* CC..CF */ + "F$", "F$", "F$", "F$", /* D0..D3 */ + "F$", "F$", "F$", "F$", /* D4..D7 */ + "F$", "F$", "F$", "F$", /* D8..DB */ + "F$", "F$", "F$", "F$", /* DC..DF */ + "F$", "F$", "F$", "F$", /* E0..E3 */ + "F$", "F$", "F$", "F$", /* E4..E7 */ + "F$", "F$", "F$", "F$", /* E8..EB */ + "F$", "F$", "F$", "F$", /* EC..EF */ + "F$", "F$", "F$", "F$", /* F0..F3 */ + "F$", "F$", "F$", "F$", /* F4..F7 */ + "F$", "F$", "F$", "F$", /* F8..FB */ + "F$", "F$", "F$", "F$" /* FC..FF */ + }; + + +/*===========================================================================*/ +/* Dasm6809 class members */ +/*===========================================================================*/ + +/*****************************************************************************/ +/* m6809_codes : table of all 6809 instruction bytes and types */ +/*****************************************************************************/ + +uint8_t Dasm6809::m6809_codes[512] = + { + _neg ,_dir, _ill ,_nom, _ill ,_nom, _com ,_dir, /* 00..03 */ + _lsr ,_dir, _ill ,_nom, _ror ,_dir, _asr ,_dir, /* 04..07 */ + _asl ,_dir, _rol ,_dir, _dec ,_dir, _ill ,_nom, /* 08..0B */ + _inc ,_dir, _tst ,_dir, _jmp ,_dir, _clr ,_dir, /* 0C..0F */ + _ill ,_nom, _ill ,_nom, _nop ,_imp, _sync ,_imp, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _lbra ,_rew, _lbsr ,_rew, /* 14..17 */ + _ill ,_nom, _daa ,_imp, _orcc ,_imb, _ill ,_nom, /* 18..1B */ + _andcc,_imb, _sex ,_imp, _exg ,_r1 , _tfr ,_r1 , /* 1C..1F */ + _bra ,_reb, _brn ,_reb, _bhi ,_reb, _bls ,_reb, /* 20..23 */ + _bcc ,_reb, _bcs ,_reb, _bne ,_reb, _beq ,_reb, /* 24..27 */ + _bvc ,_reb, _bvs ,_reb, _bpl ,_reb, _bmi ,_reb, /* 28..2B */ + _bge ,_reb, _blt ,_reb, _bgt ,_reb, _ble ,_reb, /* 2C..2F */ + _leax ,_ind, _leay ,_ind, _leas ,_ind, _leau ,_ind, /* 30..33 */ + _pshs ,_r2 , _puls ,_r2 , _pshu ,_r3 , _pulu ,_r3 , /* 34..37 */ + _ill ,_nom, _rts ,_imp, _abx ,_imp, _rti ,_imp, /* 38..3B */ + _cwai ,_imb, _mul ,_imp, _reset,_imp, _swi ,_imp, /* 3C..3F */ + _nega ,_imp, _ill ,_nom, _ill ,_nom, _coma ,_imp, /* 40..43 */ + _lsra ,_imp, _ill ,_nom, _rora ,_imp, _asra ,_imp, /* 44..47 */ + _asla ,_imp, _rola ,_imp, _deca ,_imp, _ill ,_nom, /* 48..4B */ + _inca ,_imp, _tsta ,_imp, _ill ,_nom, _clra ,_imp, /* 4C..4F */ + _negb ,_imp, _ill ,_nom, _ill ,_nom, _comb ,_imp, /* 50..53 */ + _lsrb ,_imp, _ill ,_nom, _rorb ,_imp, _asrb ,_imp, /* 54..57 */ + _aslb ,_imp, _rolb ,_imp, _decb ,_imp, _ill ,_nom, /* 58..5B */ + _incb ,_imp, _tstb ,_imp, _ill ,_nom, _clrb ,_imp, /* 5C..5F */ + _neg ,_ind, _ill ,_nom, _ill ,_nom, _com ,_ind, /* 60..63 */ + _lsr ,_ind, _ill ,_nom, _ror ,_ind, _asr ,_ind, /* 64..67 */ + _asl ,_ind, _rol ,_ind, _dec ,_ind, _ill ,_nom, /* 68..6B */ + _inc ,_ind, _tst ,_ind, _jmp ,_ind, _clr ,_ind, /* 6C..6F */ + _neg ,_ext, _ill ,_nom, _ill ,_nom, _com ,_ext, /* 70..73 */ + _lsr ,_ext, _ill ,_nom, _ror ,_ext, _asr ,_ext, /* 74..77 */ + _asl ,_ext, _rol ,_ext, _dec ,_ext, _ill ,_nom, /* 78..7B */ + _inc ,_ext, _tst ,_ext, _jmp ,_ext, _clr ,_ext, /* 7C..7F */ + _suba ,_imb, _cmpa ,_imb, _sbca ,_imb, _subd ,_imw, /* 80..83 */ + _anda ,_imb, _bita ,_imb, _lda ,_imb, _ill ,_nom, /* 84..87 */ + _eora ,_imb, _adca ,_imb, _ora ,_imb, _adda ,_imb, /* 88..8B */ + _cmpx ,_imw, _bsr ,_reb, _ldx ,_imw, _ill ,_nom, /* 8C..8F */ + _suba ,_dir, _cmpa ,_dir, _sbca ,_dir, _subd ,_dir, /* 90..93 */ + _anda ,_dir, _bita ,_dir, _lda ,_dir, _sta ,_dir, /* 94..97 */ + _eora ,_dir, _adca ,_dir, _ora ,_dir, _adda ,_dir, /* 98..9B */ + _cmpx ,_dir, _jsr ,_dir, _ldx ,_dir, _stx ,_dir, /* 9C..9F */ + _suba ,_ind, _cmpa ,_ind, _sbca ,_ind, _subd ,_ind, /* A0..A3 */ + _anda ,_ind, _bita ,_ind, _lda ,_ind, _sta ,_ind, /* A4..A7 */ + _eora ,_ind, _adca ,_ind, _ora ,_ind, _adda ,_ind, /* A8..AB */ + _cmpx ,_ind, _jsr ,_ind, _ldx ,_ind, _stx ,_ind, /* AC..AF */ + _suba ,_ext, _cmpa ,_ext, _sbca ,_ext, _subd ,_ext, /* B0..B3 */ + _anda ,_ext, _bita ,_ext, _lda ,_ext, _sta ,_ext, /* B4..B7 */ + _eora ,_ext, _adca ,_ext, _ora ,_ext, _adda ,_ext, /* B8..BB */ + _cmpx ,_ext, _jsr ,_ext, _ldx ,_ext, _stx ,_ext, /* BC..BF */ + _subb ,_imb, _cmpb ,_imb, _sbcb ,_imb, _addd ,_imw, /* C0..C3 */ + _andb ,_imb, _bitb ,_imb, _ldb ,_imb, _ill ,_nom, /* C4..C7 */ + _eorb ,_imb, _adcb ,_imb, _orb ,_imb, _addb ,_imb, /* C8..CB */ + _ldd ,_imw, _ill ,_nom, _ldu ,_imw, _ill ,_nom, /* CC..CF */ + _subb ,_dir, _cmpb ,_dir, _sbcb ,_dir, _addd ,_dir, /* D0..D3 */ + _andb ,_dir, _bitb ,_dir, _ldb ,_dir, _stb ,_dir, /* D4..D7 */ + _eorb ,_dir, _adcb ,_dir, _orb ,_dir, _addb ,_dir, /* D8..DB */ + _ldd ,_dir, _std ,_dir, _ldu ,_dir, _stu ,_dir, /* DC..DF */ + _subb ,_ind, _cmpb ,_ind, _sbcb ,_ind, _addd ,_ind, /* E0..E3 */ + _andb ,_ind, _bitb ,_ind, _ldb ,_ind, _stb ,_ind, /* E4..E7 */ + _eorb ,_ind, _adcb ,_ind, _orb ,_ind, _addb ,_ind, /* E8..EB */ + _ldd ,_ind, _std ,_ind, _ldu ,_ind, _stu ,_ind, /* EC..EF */ + _subb ,_ext, _cmpb ,_ext, _sbcb ,_ext, _addd ,_ext, /* F0..F3 */ + _andb ,_ext, _bitb ,_ext, _ldb ,_ext, _stb ,_ext, /* F4..F7 */ + _eorb ,_ext, _adcb ,_ext, _orb ,_ext, _addb ,_ext, /* F8..FB */ + _ldd ,_ext, _std ,_ext, _ldu ,_ext, _stu ,_ext, /* FC..FF */ + }; + +/*****************************************************************************/ +/* m6809_codes10 : $10 extended instruction 2nd byte */ +/*****************************************************************************/ + +uint8_t Dasm6809::m6809_codes10[512] = + { + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 04..07 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 08..0B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 0C..0F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 14..17 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 18..1B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _ill ,_nom, _lbrn ,_rew, _lbhi ,_rew, _lbls ,_rew, /* 20..23 */ + _lbcc ,_rew, _lbcs ,_rew, _lbne ,_rew, _lbeq ,_rew, /* 24..27 */ + _lbvc ,_rew, _lbvs ,_rew, _lbpl ,_rew, _lbmi ,_rew, /* 28..2B */ + _lbge ,_rew, _lblt ,_rew, _lbgt ,_rew, _lble ,_rew, /* 2C..2F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 30..33 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 34..37 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 38..3B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _swi2 ,_imp, /* 3C..3F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 40..43 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 44..47 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 48..4B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 4C..4F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 50..53 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 54..57 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 58..5B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 5C..5F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 60..63 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 64..67 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 68..6B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 6C..6F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 70..73 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 74..77 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 78..7B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 7C..7F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpd ,_imw, /* 80..83 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 84..87 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 88..8B */ + _cmpy ,_imw, _ill ,_nom, _ldy ,_imw, _ill ,_nom, /* 8C..8F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpd ,_dir, /* 90..93 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 94..97 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 98..9B */ + _cmpy ,_dir, _ill ,_nom, _ldy ,_dir, _sty ,_dir, /* 9C..9F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpd ,_ind, /* A0..A3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* A4..A7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* A8..AB */ + _cmpy ,_ind, _ill ,_nom, _ldy ,_ind, _sty ,_ind, /* AC..AF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpd ,_ext, /* B0..B3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* B4..B7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* B8..BB */ + _cmpy ,_ext, _ill ,_nom, _ldy ,_ext, _sty ,_ext, /* BC..BF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C0..C3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C4..C7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C8..CB */ + _ill ,_nom, _ill ,_nom, _lds ,_imw, _ill ,_nom, /* CC..CF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D0..D3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D4..D7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D8..DB */ + _ill ,_nom, _ill ,_nom, _lds ,_dir, _sts ,_dir, /* DC..DF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E0..E3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E4..E7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E8..EB */ + _ill ,_nom, _ill ,_nom, _lds ,_ind, _sts ,_ind, /* EC..EF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F0..F3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F4..F7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F8..FB */ + _ill ,_nom, _ill ,_nom, _lds ,_ext, _sts ,_ext, /* FC..FF */ + }; + +/*****************************************************************************/ +/* m6809_codes11 : $11 extended instruction 2nd byte */ +/*****************************************************************************/ + +uint8_t Dasm6809::m6809_codes11[512] = + { + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 00..03 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 04..07 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 08..0B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 0C..0F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 10..13 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 14..17 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 18..1B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 1C..1F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 20..23 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 24..27 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 28..2B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 2C..2F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 30..33 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 34..37 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 38..3B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _swi3 ,_imp, /* 3C..3F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 40..43 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 44..47 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 48..4B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 4C..4F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 50..53 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 54..57 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 58..5B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 5C..5F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 60..63 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 64..67 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 68..6B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 6C..6F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 70..73 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 74..77 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 78..7B */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 7C..7F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpu ,_imw, /* 80..83 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 84..87 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 88..8B */ + _cmps ,_imw, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 8C..8F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpu ,_dir, /* 90..93 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 94..97 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 98..9B */ + _cmps ,_dir, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* 9C..9F */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpu ,_ind, /* A0..A3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* A4..A7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* A8..AB */ + _cmps ,_ind, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* AC..AF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _cmpu ,_ext, /* B0..B3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* B4..B7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* B8..BB */ + _cmps ,_ext, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* BC..BF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C0..C3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C4..C7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* C8..CB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* CC..CF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D0..D3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D4..D7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* D8..DB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* DC..DF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E0..E3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E4..E7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* E8..EB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* EC..EF */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F0..F3 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F4..F7 */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* F8..FB */ + _ill ,_nom, _ill ,_nom, _ill ,_nom, _ill ,_nom, /* FC..FF */ + }; + + +static char *m6809_exg_tfr[] = + { + "D", "X", "Y", "U", "S", "PC","??","??", + "A", "B", "CC","DP","??","??","??","??" + }; + +char Dasm6809::reg[] = { 'X', 'Y', 'U', 'S' }; + +/*****************************************************************************/ +/* opcodes : additional opcodes over 6800 */ +/*****************************************************************************/ + +OpCode Dasm6809::opcodes[mnemo6809_count - mnemo6800_count] = + { + { "ABX", Data }, /* _abx */ + { "ADDD", Data }, /* _addd */ + { "ANDCC", Data }, /* _andcc */ + { "BRN", Code }, /* _brn */ + { "CMPD", Data }, /* _cmpd */ + { "CMPS", Data }, /* _cmps */ + { "CMPU", Data }, /* _cmpu */ + { "CMPX", Data }, /* _cmpx */ + { "CMPY", Data }, /* _cmpy */ + { "CWAI", Data }, /* _cwai */ + { "EXG", Data }, /* _exg */ + { "LBCC", Code }, /* _lbcc */ + { "LBCS", Code }, /* _lbcs */ + { "LBEQ", Code }, /* _lbeq */ + { "LBGE", Code }, /* _lbge */ + { "LBGT", Code }, /* _lbgt */ + { "LBHI", Code }, /* _lbhi */ + { "LBLE", Code }, /* _lble */ + { "LBLS", Code }, /* _lbls */ + { "LBLT", Code }, /* _lblt */ + { "LBMI", Code }, /* _lbmi */ + { "LBNE", Code }, /* _lbne */ + { "LBPL", Code }, /* _lbpl */ + { "LBRA", Code }, /* _lbra */ + { "LBRN", Code }, /* _lbrn */ + { "LBSR", Code }, /* _lbsr */ + { "LBVC", Code }, /* _lbvc */ + { "LBVS", Code }, /* _lbvs */ + { "LDD", Data }, /* _ldd */ + { "LDU", Data }, /* _ldu */ + { "LDY", Data }, /* _ldy */ + { "LEAS", Data }, /* _leas */ + { "LEAU", Data }, /* _leau */ + { "LEAX", Data }, /* _leax */ + { "LEAY", Data }, /* _leay */ + { "MUL", Data }, /* _mul */ + { "ORCC", Data }, /* _orcc */ + { "PSHS", Data }, /* _pshs */ + { "PSHU", Data }, /* _pshu */ + { "PULS", Data }, /* _puls */ + { "PULU", Data }, /* _pulu */ + { "RESET", Data }, /* _reset */ + { "SEX", Data }, /* _sex */ + { "STD", Data }, /* _std */ + { "STU", Data }, /* _stu */ + { "STY", Data }, /* _sty */ + { "SUBD", Data }, /* _subd */ + { "SWI2", Data }, /* _swi2 */ + { "SWI3", Data }, /* _swi3 */ + { "SYNC", Data }, /* _sync */ + { "TFR", Data }, /* _tfr */ + // Convenience mnemonics + { "CLF", Data }, /* _clf */ + { "CLIF", Data }, /* _clif */ + { "CLZ", Data }, /* _clz */ + { "DEU", Data }, /* _deu */ + { "DEY", Data }, /* _dey */ + { "INU", Data }, /* _inu */ + { "INY", Data }, /* _iny */ + { "SEF", Data }, /* _sef */ + { "SEIF", Data }, /* _seif */ + { "SEZ", Data }, /* _sez */ + + }; + +/*****************************************************************************/ +/* Dasm6809 : constructor */ +/*****************************************************************************/ + +Dasm6809::Dasm6809(void) +{ +codes = m6809_codes; +codes10 = m6809_codes10; +codes11 = m6809_codes11; +exg_tfr = m6809_exg_tfr; +os9Patch = false; +useFlex = false; +dirpage = 0; +mnemo.resize(mnemo6809_count); /* set up additional mnemonics */ +for (int i = 0; i < mnemo6809_count - mnemo6800_count; i++) + mnemo[mnemo6800_count + i] = opcodes[i]; +mnemo[_lda].mne = "LDA"; /* adjust slight mnemo differences */ +mnemo[_ldb].mne = "LDB"; +mnemo[_sta].mne = "STA"; +mnemo[_stb].mne = "STB"; +mnemo[_ora].mne = "ORA"; +mnemo[_orb].mne = "ORB"; + +// set up options table +// class uses one generic option setter/getter pair (not mandatory) +AddOption("flex", "{off|on}\tuse FLEX9 standard labels", + static_cast(&Dasm6809::Set6809Option), + static_cast(&Dasm6809::Get6809Option)); +AddOption("os9", "{off|on}\tpatch swi2 (os9 call)", + static_cast(&Dasm6809::Set6809Option), + static_cast(&Dasm6809::Get6809Option)); +} + +/*****************************************************************************/ +/* ~Dasm6809 : destructor */ +/*****************************************************************************/ + +Dasm6809::~Dasm6809(void) +{ +} + +/*****************************************************************************/ +/* Set6809Option : sets a disassembler option */ +/*****************************************************************************/ + +int Dasm6809::Set6809Option(std::string lname, std::string value) +{ +std::string lvalue(lowercase(value)); +int bnvalue = (lvalue == "off") ? 0 : (lvalue == "on") ? 1 : atoi(value.c_str()); + +if (lname == "flex") useFlex = !!bnvalue; +else if (lname == "os9") os9Patch = !!bnvalue; +else + return 0; /* only name consumed */ +return 1; /* name and value consumed */ +} + +/*****************************************************************************/ +/* Get6809Option : retrieves a disassembler option */ +/*****************************************************************************/ + +std::string Dasm6809::Get6809Option(std::string lname) +{ +if (lname == "flex") return useFlex ? "on" : "off"; +else if (lname == "os9") return os9Patch ? "on" : "off"; +return ""; +} + +/*****************************************************************************/ +/* ProcessInfo : process an info file line */ +/*****************************************************************************/ + +bool Dasm6809::ProcessInfo + ( + std::string key, + std::string value, + addr_t &from, + addr_t &to, + bool bProcInfo, + bool bDataBus + ) +{ +if (!bProcInfo || bDataBus) /* only if processing code bus... */ + return false; + +enum InfoCmd + { + infoUnknown = -1, /* unknown info command */ + infoSetDP, /* SETDP [addr[-addr]] dp */ + infoUnsetDP, /* UNSETDP [addr[-addr]] */ + }; +static struct /* structure to convert key to type */ + { + const char *name; + InfoCmd cmdType; + } sKey[] = + { + { "SETDP", infoSetDP }, + { "UNSETDP", infoSetDP }, + }; + +InfoCmd cmdType = infoUnknown; +for (int i = 0; i < _countof(sKey); i++) + if (key == sKey[i].name) + { + cmdType = sKey[i].cmdType; + break; + } +if (cmdType == infoUnknown) + return false; + +switch (cmdType) + { + case infoSetDP : /* SETDP [addr[-addr]] dp */ + { + std::string srange; + std::string::size_type idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + srange = value.substr(0, idx); + addr_t dp = NO_ADDRESS; + value = (idx == value.size()) ? "" : trim(value.substr(idx)); + if (value.size() && /* if addr[-addr] dp */ + value[0] != '*') + String2Number(value, dp); + if (dp == NO_ADDRESS && /* if only dp */ + from != NO_ADDRESS && + to == from) + { + dp = from; + from = to = NO_ADDRESS; + } + if (dp != NO_ADDRESS) /* unless it's OFF */ + { + if (dp & 0xff) /* get dp into page range $xx00 */ + dp <<= 8; + if (dp < GetLowestDataAddr() || dp > GetHighestDataAddr() - 15) + return false; + } + if (from == NO_ADDRESS) + dirpage = dp; + else for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + SetDirectPage(scanned, dp, bDataBus); + } + break; + case infoUnsetDP : /* UNSETDP [addr[-addr]] */ + if (from == NO_ADDRESS) + dirpage = 0; + else for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + SetDirectPage(scanned, 0, bDataBus); + break; + } +return true; +} + +/*****************************************************************************/ +/* InitParse : initialize parsing */ +/*****************************************************************************/ + +bool Dasm6809::InitParse(bool bDataBus) +{ +if (!bDataBus) + { + if (useFlex) + AddFlexLabels(); + + // set up SWI3-FIRQ system vectors (rest done by 6800) + static const char *vectbl[] = + { + "SWI3", /* fff2 */ + "SWI2", /* fff4 */ + "FIRQ", /* fff6 */ + }; + for (addr_t addr = 0xfff2; addr < 0xfff8; addr += 2) + { + if (GetMemType(addr) != Untyped) /* if system vector loaded */ + { + SetMemType(addr, Data); /* that's a data word */ + SetCellSize(addr, 2); + addr_t tgtaddr = GetUWord(addr); /* look whether it points to loaded */ + if (GetMemType(tgtaddr) != Untyped) + { /* if so, */ + SetMemType(tgtaddr, Code); /* that's code there */ + AddLabel(tgtaddr, Code, /* and it got a predefined label */ + sformat("vec_%s", vectbl[(addr - 0xfff2) / 2]), + true); + } + } + } + + } +return Dasm6800::InitParse(bDataBus); +} + +/*****************************************************************************/ +/* IndexParse : parses index for labels */ +/*****************************************************************************/ + +addr_t Dasm6809::IndexParse(int MI, addr_t pc) +{ +uint8_t T; +uint16_t W; +uint16_t Wrel; +char R; +addr_t PC = pc; +bool bSetLabel = true; + +T = GetUByte(PC++); +R = reg[(T >> 5) & 0x03]; + +if (T & 0x80) + { + switch(T & 0x1F) + { + case 0x00: /* register operations */ + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x0B: + case 0x11: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x1B: + break; + case 0x0C: + bSetLabel = !IsConst(PC); + T = GetUByte(PC++); + if (bSetLabel) + AddLabel((uint16_t)((int)((char)T) + PC), mnemo[MI].memType, "", true); + break; + case 0x08: + T = GetUByte(PC); + Wrel = (uint16_t)GetRelative(PC); + if (Wrel) + { + W = (uint16_t)((int)((char)T)); + bSetLabel = !IsConst(PC); + if (bSetLabel) + AddLabel((uint16_t)(W + Wrel), mnemo[MI].memType, "", true); + } + PC++; + break; + case 0x18: + case 0x1C: + T = GetUByte(PC++); + break; + case 0x0D: + bSetLabel = !IsConst(PC); + W = GetUWord(PC); PC += 2; + if (bSetLabel) + AddLabel((uint16_t)(W + PC), mnemo[MI].memType, "", true); + break; + case 0x09: + bSetLabel = !IsConst(PC); + W = GetUWord(PC); + Wrel = W + (uint16_t)GetRelative(PC); + PC += 2; + /* no labels in indirect addressing! */ + /* ...except when they are explicitly*/ + /* given in the info file, of course */ + if (W != Wrel || /* if it's relative, or */ + FindLabel(Wrel)) /* if there's a label given there */ + AddLabel(Wrel, /* mark it as used */ + mnemo[MI].memType, "", true); + break; + case 0x19: + case 0x1D: + bSetLabel = !IsConst(PC); + W = GetUWord(PC); PC += 2; + if (bSetLabel) + AddLabel(W, mnemo[MI].memType, "", true); + break; + + default: + if (T == 0x9F) + { + bSetLabel = !IsConst(PC); + W = GetUWord(PC); PC += 2; + if (bSetLabel) + AddLabel(W, mnemo[MI].memType, "", true); + } + break; + } + } +else + { + char c = T & 0x1F; + if (c & 0x10) + c |= 0xf0; + Wrel = (uint16_t)GetRelative(PC - 1); + if (Wrel) + { + bSetLabel = !IsConst(PC - 1); + W = (uint16_t)(c + Wrel); + if (bSetLabel) + AddLabel(W, mnemo[MI].memType, "", true); + } + } +return PC; +} + +/*****************************************************************************/ +/* IndexString : converts index to string */ +/*****************************************************************************/ + +std::string Dasm6809::IndexString(addr_t &pc) +{ +uint8_t T; +uint16_t W, Wrel; +char R; +std::string buf; +addr_t PC = pc; +bool bGetLabel; + +T = GetUByte(PC++); +R = reg[(T >> 5) & 0x03]; + +if (T & 0x80) + { + switch (T & 0x1F) + { + case 0x00: + buf = sformat(",%c+", R); + break; + case 0x01: + buf = sformat(",%c++", R); + break; + case 0x02: + buf = sformat(",-%c", R); + break; + case 0x03: + buf = sformat(",--%c", R); + break; + case 0x04: + buf = sformat(",%c", R); + if (GetRelative(PC - 1)) + { + bGetLabel = !IsConst(PC - 1); + buf += sformat(" %s (%s)", + commentStart.c_str(), + Label2String(0, bGetLabel, PC - 1).c_str()); + } + break; + case 0x05: + buf = sformat("B,%c", R); + break; + case 0x06: + buf = sformat("A,%c", R); + break; + case 0x08: + bGetLabel = !IsConst(PC); + T = GetUByte(PC++); + Wrel = (uint16_t)GetRelative(PC - 1); + if (Wrel) + { + W = (int)((char)T) + Wrel; + /* "<" needed for forward declaration*/ + buf = sformat( + ((W > PC) || (Wrel > PC)) ? "<%s,%c" : "%s,%c", + Label2String((uint16_t)((int)((char)T)), bGetLabel, PC - 1).c_str(), + R); + } + else + buf = sformat("%s,%c", + SignedNumber2String((int)((char)T), 2, PC - 1).c_str(), + R); + break; + case 0x09: + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + Wrel = W + (uint16_t)GetRelative(PC); + PC += 2; + if ((Wrel != W) || (FindLabel(Wrel))) + { + if (((W < 0x80) || (W >= 0xff80)) && forceExtendedAddr) + buf = sformat(">%s,%c", Label2String(W, bGetLabel, PC - 2).c_str(), R); + else + buf = sformat("%s,%c", Label2String(W, bGetLabel, PC - 2).c_str(), R); + } + else + { + if (((W < 0x80) || (W >= 0xff80)) && forceExtendedAddr) + buf = sformat(">%s,%c", SignedNumber2String((int)(short)W, 4, PC - 2).c_str(), R); + else + buf = sformat("%s,%c", Number2String((uint16_t)(int)(short)W, 4, PC - 2).c_str(), R); /* RB: this was "signed_string" */ + } + break; + case 0x0B: + buf = sformat("D,%c", R); + break; + case 0x0C: + T = GetUByte(PC); + bGetLabel = !IsConst(PC); + PC++; +#if 0 + sprintf(buf,"$%s,PC",signed_string((int)(char)T, 2, (word)(PC - 1))); +#else + if (bGetLabel) + buf = Label2String((uint16_t)((int)((char)T) + PC), bGetLabel, PC - 1) + ",PCR"; + else + buf = Number2String((uint16_t)(int)(char)T, 2, PC - 1) + ",PC"; +#endif + break; + case 0x0D: + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + if (((W < 0x80) || (W >= 0xff80)) && forceExtendedAddr) + buf = sformat(">%s,PCR", Label2String((uint16_t)(W + PC), bGetLabel, PC - 2).c_str()); + else + buf = sformat("%s,PCR", Label2String((uint16_t)(W + PC), bGetLabel, PC - 2).c_str()); + break; + case 0x11: + buf = sformat("[,%c++]", R); + break; + case 0x13: + buf = sformat("[,--%c]", R); + break; + case 0x14: + buf = sformat("[,%c]", R); + break; + case 0x15: + buf = sformat("[B,%c]", R); + break; + case 0x16: + buf = sformat("[A,%c]", R); + break; + case 0x18: + T = GetUByte(PC++); + buf = sformat("[%s,%c]", + Number2String(T, 2, PC - 1).c_str(), + R); + break; + case 0x19: + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + buf = sformat("[%s,%c]", Label2String(W, bGetLabel, PC - 2).c_str(),R); + break; + case 0x1B: + buf = sformat("[D,%c]", R); + break; + case 0x1C: + T = GetUByte(PC++); + buf = sformat("[%s,PC]", Number2String(T, 2, PC - 1).c_str()); + break; + case 0x1D: + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + buf = sformat("[%s,PC]", Label2String(W, bGetLabel, PC - 2).c_str()); + break; + case 0x07: + case 0x17: + case 0x0A: + case 0x1A: + case 0x0E: + case 0x1E: + buf = "???"; + break; + + default: + if (T == 0x9F) + { + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + buf = sformat("[%s]", Label2String(W, bGetLabel, PC - 2).c_str()); + } + else + buf = "???"; + break; + } + + } +else + { + char c = T & 0x1F; + if (c & 0x10) + c |= 0xf0; + Wrel = (uint16_t)GetRelative(PC - 1); + if (Wrel) + { + bGetLabel = !IsConst(PC - 1); + buf = sformat("%s,%c", Label2String((uint16_t)c, bGetLabel, PC - 1).c_str(), R); + } + else + buf = sformat("%s,%c", SignedNumber2String(c, 2, PC - 1).c_str(), R); + } + +pc = PC; +return buf; +} + +/*****************************************************************************/ +/* ParseCode : parse instruction at given memory address for labels */ +/*****************************************************************************/ + +addr_t Dasm6809::ParseCode + ( + addr_t addr, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +int MI; +const char *I; +addr_t PC = addr; +bool bSetLabel; +addr_t dp = GetDirectPage(addr); + + +O = T = GetUByte(PC++); +if (T == 0x10) + { + T = GetUByte(PC++); + W = T * 2; + MI = T = codes10[W++]; + I = mnemo[T].mne; + M = codes10[W]; + + if ((T == _swi2) && os9Patch) + return (PC + 1 - addr); + } +else if (T == 0x11) + { + T = GetUByte(PC++); + W = T * 2; + MI = T = codes11[W++]; + I = mnemo[T].mne; + M = codes11[W]; + } +else + { + W = T * 2; + MI = T = codes[W++]; + I = mnemo[T].mne; + M = codes[W]; + } + +switch (M) /* which mode is this ? */ + { + case _dir: /* direct */ + bSetLabel = !IsConst(PC); + T = GetUByte(PC); PC++; + if (dp != NO_ADDRESS) + { + if (bSetLabel) + { + W = (uint16_t)dp | T; + W = (uint16_t)PhaseInner(W, PC - 1); + AddLabel(W, mnemo[MI].memType, "", true); + } + } + break; + + case _ind: /* indexed */ + PC = IndexParse(MI,PC); + break; + + case _rew: /* relative word */ + bSetLabel = !IsConst(PC); + W = GetUWord(PC); PC += 2; + W += (uint16_t)PC; + W = (uint16_t)DephaseOuter(W, PC - 2); + if (bSetLabel) + AddLabel(W, mnemo[MI].memType, "", true); + break; + + case _r1: /* tfr/exg mode */ + T = GetUByte(PC); PC++; + break; + + case _r2: /* pul/psh system */ + case _r3: /* pul/psh user */ + T = GetUByte(PC); PC++; + break; + + default : /* anything else is handled by base */ + return Dasm6800::ParseCode(addr, bDataBus); + } +return PC - addr; /* pass back # processed bytes */ +} + +/*****************************************************************************/ +/* DisassembleCode : disassemble code instruction at given memory address */ +/*****************************************************************************/ + +addr_t Dasm6809::DisassembleCode + ( + addr_t addr, + std::string &smnemo, + std::string &sparm, + bool bDataBus /* ignored for 6800 and derivates */ + ) +{ +uint8_t O, T, M; +uint16_t W; +const char *I; +addr_t PC = addr; +bool bGetLabel; +addr_t dp = GetDirectPage(addr); + +O = T = GetUByte(PC++); +if (T == 0x10) + { + T = GetUByte(PC++); + W = T * 2; + T = codes10[W++]; + I = mnemo[T].mne; + M = codes10[W]; + + if ((T == _swi2) && os9Patch) + { + T = GetUByte(PC++); + smnemo = "OS9"; + sparm = os9_codes[T]; + return PC - addr; + } + } +else if (T == 0x11) + { + T = GetUByte(PC++); + W = T * 2; + T = codes11[W++]; + I = mnemo[T].mne; + M = codes11[W]; + } +else + { + W = T * 2; + T = codes[W++]; + M = codes[W]; + I = mnemo[T].mne; + } + +smnemo = I; /* initialize mnemonic */ + +switch (M) /* which mode is this? */ + { + case _imb: /* immediate byte */ + T = GetUByte(PC++); + if (useConvenience) + W = (uint16_t)(O << 8) | T; + else + W = 0; + switch (W) /* examine for special CC settings */ + { + case 0x1a01 : /* (6809) ORCC $01 */ + smnemo = mnemo[_sec].mne; + break; + case 0x1a02 : /* (6809) ORCC $02 */ + smnemo = mnemo[_sev].mne; + break; + case 0x1a04 : /* (6809) ORCC $04 */ + smnemo = mnemo[_sez].mne; + break; + case 0x1a10 : /* (6809) ORCC $10 */ + smnemo = mnemo[_sei].mne; + break; + case 0x1a40 : /* (6809) ORCC $40 */ + smnemo = mnemo[_sef].mne; + break; + case 0x1a50 : /* (6809) ORCC $40+$10 */ + smnemo = mnemo[_seif].mne; + break; + case 0x1cfe : /* (6809) ANDCC ~$01 */ + smnemo = mnemo[_clc].mne; + break; + case 0x1cfd : /* (6809) ANDCC ~$02 */ + smnemo = mnemo[_clv].mne; + break; + case 0x1cfb : /* (6809) ANDCC ~$04 */ + smnemo = mnemo[_clz].mne; + break; + case 0x1cef : /* (6809) ANDCC ~$10 */ + smnemo = mnemo[_cli].mne; + break; + case 0x1cbf : /* (6809) ANDCC ~$40 */ + smnemo = mnemo[_clf].mne; + break; + case 0x1caf : /* (6809) ANDCC ~($40 + $10) */ + smnemo = mnemo[_clif].mne; + break; + case 0x3cff : /* (6809) CWAI $FF */ + smnemo = mnemo[_wai].mne; + break; + default : + sparm = "#" + Number2String(T, 2, PC - 1); + } + break; + + case _dir: /* direct */ + bGetLabel = !IsConst(PC); + T = GetUByte(PC); + if (dp != NO_ADDRESS) + { + uint16_t ow = W = (uint16_t)dp | T; + if (bGetLabel) + W = (uint16_t)PhaseInner(ow, PC); + sparm = Label2String(W, bGetLabel, PC); + } + else + sparm = "<" + Number2String(T, 2, PC); + PC++; + break; + + case _ext: /* extended */ + bGetLabel = !IsConst(PC); + if (bGetLabel) + W = (uint16_t)PhaseInner(GetUWord(PC), PC); + PC += 2; + if (dp != NO_ADDRESS && + forceExtendedAddr && (W & (uint16_t)0xff00) == (uint16_t)dp) + sparm = ">" + Label2String(W, bGetLabel, PC - 2); + else + sparm = Label2String(W, bGetLabel, PC - 2); + break; + + case _ind: /* indexed */ + if (useConvenience) + W = (uint16_t)(O << 8) | GetUByte(PC); + else + W = 0; + switch (W) + { + case 0x3001 : /* (6809) LEAX +1 */ + smnemo = mnemo[_inx].mne; PC++; + break; + case 0x301f : /* (6809) LEAX -1 */ + smnemo = mnemo[_dex].mne; PC++; + break; + case 0x3121 : /* (6809) LEAY +1 */ + smnemo = mnemo[_iny].mne; PC++; + break; + case 0x313f : /* (6809) LEAY -1 */ + smnemo = mnemo[_dey].mne; PC++; + break; + case 0x3261 : /* (6809) LEAS +1 */ + smnemo = mnemo[_ins].mne; PC++; + break; + case 0x327f : /* (6809) LEAS -1 */ + smnemo = mnemo[_des].mne; PC++; + break; + case 0x3341 : /* (6809) LEAU +1 */ + smnemo = mnemo[_inu].mne; PC++; + break; + case 0x335f : /* (6809) LEAU -1 */ + smnemo = mnemo[_deu].mne; PC++; + break; + default : + sparm = IndexString(PC); + break; + } + break; + + case _rew: /* relative word */ + bGetLabel = !IsConst(PC); + W = GetUWord(PC); + PC += 2; + W += (uint16_t)PC; + W = (uint16_t)DephaseOuter(W, PC - 2); + sparm = Label2String(W, bGetLabel, PC - 2); + break; + + case _r1: /* tfr/exg mode */ + if (useConvenience) + W = (uint16_t)(O << 8) | GetUByte(PC); + else + W = 0; + switch (W) + { + case 0x1f14 : /* (6809) TFR X,S */ + smnemo = mnemo[_txs].mne; PC++; + break; + case 0x1f41 : /* (6809) TFR S,X */ + smnemo = mnemo[_tsx].mne; PC++; + break; +/* hairy - some assemblers expand TAB to TAB + TSTA... + but there's no guarantee. + case 0x1f89 : + smnemo = "TAB"; PC++; + break; */ + case 0x1f8a : /* (6809) TFR A,CC */ + smnemo = mnemo[_tap].mne; PC++; + break; +/* hairy - some assemblers expand TBA to TBA + TSTA... + but there's no guarantee. + case 0x1f98 : + smnemo = "TBA"; PC++; + break; */ + case 0x1fa8 : /* (6809) TFR CC,A */ + smnemo = mnemo[_tpa].mne; PC++; + break; + default : + T = GetUByte(PC++); + sparm = sformat("%s,%s", exg_tfr[T >> 4], exg_tfr[T & 0xF]); + break; + } + break; + + case _r2: /* pul/psh system */ + case _r3: /* pul/psh user */ + if (useConvenience) + W = (uint16_t)(O << 8) | GetUByte(PC); + else + W = 0; + switch (W) + { + case 0x3404 : /* (6809) PSHS B */ + if (FindLabel(PC + 1)) + W = 0; + else + W = GetUWord(PC + 1); + switch (W) + { + case 0xa0e0 : /* (6809) PSHS B / SUBA ,S++ */ + smnemo = mnemo[_sba].mne; PC += 3; + break; + case 0xa1e0 : /* (6809) PSHS B / CMPA ,S++ */ + smnemo = mnemo[_cba].mne; PC += 3; + break; + case 0xabe0 : /* (6809) PSHS B / ADDA ,S++ */ + smnemo = mnemo[_aba].mne; PC += 3; + break; + default: /* (6809) PSHS B / anything else */ + smnemo = mnemo[_pshb].mne; PC++; + break; + } + break; + case 0x3402 : /* (6809) PSHS A */ + smnemo = mnemo[_psha].mne; PC++; + break; + case 0x3406 : /* (6809) PSHS D */ + smnemo = "PSHD"; PC++; + break; + case 0x3410 : /* (6809) PSHS X */ + smnemo = "PSHX"; PC++; + break; + case 0x3420 : /* (6809) PSHS Y */ + smnemo = "PSHY"; PC++; + break; + case 0x3502 : /* (6809) PULS A */ + smnemo = mnemo[_pula].mne; PC++; + break; + case 0x3504 : /* (6809) PULS B */ + smnemo = mnemo[_pulb].mne; PC++; + break; + case 0x3506 : /* (6809) PULS D */ + smnemo = "PULD"; PC++; + break; + case 0x3510 : /* (6809) PULS X */ + smnemo = "PULX"; PC++; + break; + case 0x3520 : /* (6809) PULS Y */ + smnemo = "PULY"; PC++; + break; + default: + // buf[0] = '\0'; + T = GetUByte(PC++); + if (T & 0x80) + sparm += "PC,"; + if (T & 0x40) + { + if (M == _r2) + sparm += "U,"; + if (M == _r3) + sparm += "S,"; + } + if (T&0x20) + sparm += "Y,"; + if (T & 0x10) + sparm += "X,"; + if (T & 0x08) + sparm += "DP,"; + if ((T & 0x06) == 0x06) + sparm += "D,"; + else + { + if (T & 0x04) + sparm += "B,"; + if (T & 0x02) + sparm += "A,"; + } + if (T & 0x01) + sparm += "CC,"; + if (sparm.size()) + sparm = sparm.substr(0, sparm.size() - 1); + break; + } + break; + + default : /* anything else is handled by base */ + return Dasm6800::DisassembleCode(addr, smnemo, sparm, bDataBus); + } +return PC - addr; /* pass back # processed bytes */ +} + +/*****************************************************************************/ +/* DisassembleChanges : report dasm-specific state changes before/after addr */ +/*****************************************************************************/ + +bool Dasm6809::DisassembleChanges + ( + addr_t addr, + addr_t prevaddr, + addr_t prevsz, + bool bAfterLine, + std::vector &changes, + bool bDataBus + ) +{ +// init / exit +if (addr == NO_ADDRESS && prevaddr == NO_ADDRESS) + { + // no specialties here + return Dasm6800::DisassembleChanges(addr, prevaddr, prevsz, bAfterLine, changes, bDataBus); + } +if (!bAfterLine) /* if before the address */ + { + // report direct page changes + addr_t dpold = + (prevaddr == NO_ADDRESS) ? DEFAULT_ADDRESS : GetDirectPage(prevaddr, bDataBus); + addr_t dp = GetDirectPage(addr, bDataBus); + if (!dp && dpold == DEFAULT_ADDRESS) dpold = dp; + if (dp != dpold) + { + LineChange chg; + changes.push_back(chg); + chg.smnemo = "SETDP"; + if (dp != NO_ADDRESS) + chg.sparm = sformat("$%02X", dp >> 8); + changes.push_back(chg); + } + } +return Dasm6800::DisassembleChanges(addr, prevaddr, prevsz, bAfterLine, changes, bDataBus); +} + +/*****************************************************************************/ +/* AddFlexLabels : adds FLEX9 labels to disassembler */ +/*****************************************************************************/ + +void Dasm6809::AddFlexLabels() +{ +static struct + { + addr_t from; + addr_t to; + char const *txt; + } FlexLbls[] = + { + /* FLEX9 DOS entries */ + { 0xCD00, 0xCD00, "COLDS" }, + { 0xCD03, 0xCD03, "WARMS" }, + { 0xCD06, 0xCD06, "RENTER" }, + { 0xCD09, 0xCD09, "INCH" }, + { 0xCD0C, 0xCD0C, "INCH2" }, + { 0xCD0F, 0xCD0F, "OUTCH" }, + { 0xCD12, 0xCD12, "OUTCH2" }, + { 0xCD15, 0xCD15, "GETCHR" }, + { 0xCD18, 0xCD18, "PUTCHR" }, + { 0xCD1B, 0xCD1B, "INBUFF" }, + { 0xCD1E, 0xCD1E, "PSTRNG" }, + { 0xCD21, 0xCD21, "CLASS" }, + { 0xCD24, 0xCD24, "PCRLF" }, + { 0xCD27, 0xCD27, "NXTCH" }, + { 0xCD2A, 0xCD2A, "RSTRIO" }, + { 0xCD2D, 0xCD2D, "GETFIL" }, + { 0xCD30, 0xCD30, "LOAD" }, + { 0xCD33, 0xCD33, "SETEXT" }, + { 0xCD36, 0xCD36, "ADDBX" }, + { 0xCD39, 0xCD39, "OUTDEC" }, + { 0xCD3C, 0xCD3C, "OUTHEX" }, + { 0xCD3F, 0xCD3F, "RPTERR" }, + { 0xCD42, 0xCD42, "GETHEX" }, + { 0xCD45, 0xCD45, "OUTADR" }, + { 0xCD48, 0xCD48, "INDEC" }, + { 0xCD4B, 0xCD4B, "DOCMND" }, + { 0xCD4E, 0xCD4E, "STAT" }, + /* FLEX FMS entries: */ + { 0xD400, 0xD400, "FMSINI" }, /* FMS init */ + { 0xD403, 0xD403, "FMSCLS" }, /* FMS close */ + { 0xD406, 0xD406, "FMS" }, + { 0xC840, 0xC97F, "FCB" }, /* standard system FCB */ + /* miscellaneous: */ + { 0xD435, 0xD435, "VFYFLG" }, /* FMS verify flag */ + { 0xC080, 0xC0FF, "LINBUF" }, /* line buffer */ + { 0xCC00, 0xCC00, "TTYBS" }, /* TTYSET backspace character */ + { 0xCC01, 0xCC01, "TTYDEL" }, /* TTYSET delete character */ + { 0xCC02, 0xCC02, "TTYEOL" }, /* TTYSET EOL character */ + { 0xCC03, 0xCC03, "TTYDPT" }, /* TTYSET depth count */ + { 0xCC04, 0xCC04, "TTYWDT" }, /* TTYSET width count */ + { 0xCC05, 0xCC05, "TTYNUL" }, /* TTYSETnull count */ + { 0xCC06, 0xCC06, "TTYTAB" }, /* TTYSET tab character */ + { 0xCC07, 0xCC07, "TTYBSE" }, /* TTYSET backspace echo character */ + { 0xCC08, 0xCC08, "TTYEJ" }, /* TTYSET eject count */ + { 0xCC09, 0xCC09, "TTYPAU" }, /* TTYSET pause control */ + { 0xCC0A, 0xCC0A, "TTYESC" }, /* TTYSET escape character */ + { 0xCC0B, 0xCC0B, "SYSDRV" }, /* current system drive */ + { 0xCC0C, 0xCC0C, "WRKDRV" }, /* current working drive */ + { 0xCC0E, 0xCC10, "SYSDAT" }, /* System date month/day/year */ + { 0xCC11, 0xCC11, "TTYTRM" }, + { 0xCC12, 0xCC12, "COMTBL" }, /* user command table */ + { 0xCC14, 0xCC14, "LINBFP" }, /* line buffer pointer */ + { 0xCC16, 0xCC16, "ESCRET" }, /* escape return register */ + { 0xCC18, 0xCC18, "LINCHR" }, /* current char in linebuffer */ + { 0xCC19, 0xCC19, "LINPCH" }, /* previous char in linebuffer */ + { 0xCC1A, 0xCC1A, "LINENR" }, /* line nr of current page */ + { 0xCC1B, 0xCC1B, "LODOFS" }, /* loader address offset */ + { 0xCC1D, 0xCC1D, "TFRFLG" }, /* loader transfer flag */ + { 0xCC1E, 0xCC1E, "TFRADR" }, /* transfer address */ + { 0xCC20, 0xCC20, "FMSERR" }, /* FMS error type */ + { 0xCC21, 0xCC21, "IOFLG" }, /* special I/O flag */ + { 0xCC22, 0xCC22, "OUTSWT" }, /* output switch */ + { 0xCC23, 0xCC23, "INSWT" }, /* input switch */ + { 0xCC24, 0xCC24, "FOPADR" }, /* file output address */ + { 0xCC26, 0xCC26, "FIPADR" }, /* file input address */ + { 0xCC28, 0xCC28, "COMFLG" }, /* command flag */ + { 0xCC29, 0xCC29, "OUTCOL" }, /* current output column */ + { 0xCC2A, 0xCC2A, "SCRATC" }, /* system scratch */ + { 0xCC2B, 0xCC2B, "MEMEND" }, /* memory end */ + { 0xCC2D, 0xCC2D, "ERRVEC" }, /* error name vector */ + { 0xCC2F, 0xCC2F, "INECHO" }, /* file input echo flag */ + /* Printer support */ + { 0xCCC0, 0xCCC0, "PRTINI" }, /* printer initialize */ + { 0xCCD8, 0xCCD8, "PRTCHK" }, /* printer check */ + { 0xCCE4, 0xCCE4, "PRTOUT" }, /* printer output */ + /* Console I/O Driver Table : */ + { 0xd3e5, 0xd3e5, "CINCHNE" }, /* input character w/o echo */ + { 0xd3e7, 0xd3e7, "CIHNDLR" }, /* IRQ interrupt handler */ + { 0xd3e9, 0xd3e9, "CSWIVEC" }, /* SWI3 vector location */ + { 0xd3eb, 0xd3eb, "CIRQVEC" }, /* IRQ vector location */ + { 0xd3ed, 0xd3ed, "CTMOFF" }, /* timer off routine */ + { 0xd3ef, 0xd3ef, "CTMON" }, /* timer on routine */ + { 0xd3f1, 0xd3f1, "CTMINT" }, /* timer initialization */ + { 0xd3f3, 0xd3f3, "CMONITR" }, /* monitor entry address */ + { 0xd3f5, 0xd3f5, "CTINIT" }, /* terminal initialization */ + { 0xd3f7, 0xd3f7, "CSTAT" }, /* check terminal status */ + { 0xd3f9, 0xd3f9, "COUTCH" }, /* output character */ + { 0xd3fb, 0xd3fb, "CINCH" }, /* input character w/ echo */ + /* Disk Driver Jump Table : */ + { 0xde00, 0xde00, "DDJ_READ" }, /* read a single sector */ + { 0xde03, 0xde03, "DDJ_WRITE" }, /* write a single sector */ + { 0xde06, 0xde06, "DDJ_VERIFY" }, /* verify last sector written */ + { 0xde09, 0xde09, "DDJ_RESTORE" }, /* restore head to track #0 */ + { 0xde0c, 0xde0c, "DDJ_DRIVE" }, /* select the specified drive */ + { 0xde0f, 0xde0f, "DDJ_CHKRDY" }, /* Check for drive ready */ + { 0xde12, 0xde12, "DDJ_QUICK" }, /* Quick check for drive ready */ + { 0xde15, 0xde15, "DDJ_INIT" }, /* driver initialize (cold start) */ + { 0xde18, 0xde18, "DDJ_WARM" }, /* driver initialize (warm start) */ + { 0xde1b, 0xde1b, "DDJ_SEEK" }, /* seek to specified track */ + }; + +for (int i = 0; i < _countof(FlexLbls); i++) + { + for (addr_t a = FlexLbls[i].from; a <= FlexLbls[i].to; a++) + { + std::string s(FlexLbls[i].txt); + if (a != FlexLbls[i].from) + s += sformat("+%s", Number2String(a - FlexLbls[i].from, 4, a).c_str()); + AddLabel(a, Untyped, s); + } + } +} diff --git a/Dasm6809.h b/Dasm6809.h new file mode 100644 index 0000000..6bc2c5e --- /dev/null +++ b/Dasm6809.h @@ -0,0 +1,254 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Dasm6809.h : definition of the Dasm6809 class */ +/*****************************************************************************/ + +#ifndef __Dasm6809_h_defined__ +#define __Dasm6809_h_defined__ + +#include "Dasm6800.h" + +/*****************************************************************************/ +/* MemAttribute6809 : description of a memory cell's attributes for 6809 */ +/*****************************************************************************/ + +struct MemAttribute6809 : public MemAttribute + { + int16_t dirpage; /* direct page */ + MemAttribute6809(MemoryType memType = Code, + int cellSize = 1, + bool bUsed = true, + Type cellType = UnsignedInt, + Display display = Hex, + bool breakBefore = false, + addr_t dirpage = DEFAULT_ADDRESS) + : MemAttribute(memType, cellSize, bUsed, cellType, display, breakBefore) + { + SetDirectPage(dirpage); + } + addr_t GetDirectPage() { return (dirpage == (int16_t)-1) ? NO_ADDRESS : (dirpage == (int16_t)-2) ? DEFAULT_ADDRESS : (addr_t)dirpage << 8; } + void SetDirectPage(addr_t dp) { dirpage = (int16_t)((dp & 0xff) ? dp : dp >> 8); } + }; + +/*****************************************************************************/ +/* MemAttribute6809Handler : memory attribute handler for 6809 */ +/*****************************************************************************/ + +class MemAttribute6809Handler : public MemAttributeHandler +{ + public: + MemAttribute6809Handler() { } + virtual ~MemAttribute6809Handler() { } + + virtual bool AddMemory(addr_t addrStart = 0, addr_t memSize = 0, MemoryType memType = Code) + { return attr.AddMemory(addrStart, memSize, memType); } + virtual MemoryType GetMemType(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->GetMemType() : Untyped; } + virtual void SetMemType(addr_t addr, MemoryType newType = Code) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetMemType(newType); } + virtual bool IsCellUsed(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->IsUsed() : false; } + virtual void SetCellUsed(addr_t addr, bool bUsed = true) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetUsed(bUsed); } + virtual MemAttribute::Type GetCellType(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->GetCellType() : MemAttribute6809::CellUntyped; } + virtual void SetCellType(addr_t addr, MemAttribute::Type newType) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetCellType(newType); } + virtual int GetCellSize(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->GetSize() : 0; } + virtual void SetCellSize(addr_t addr, int newSize = 1) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetSize(newSize); } + virtual MemAttribute::Display GetDisplay(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->GetDisplay() : MemAttribute6809::CellUndisplayable; } + virtual void SetDisplay(addr_t addr, MemAttribute::Display newDisp = MemAttribute::Hex) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetDisplay(newDisp); } + virtual bool GetBreakBefore(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->GetBreakBefore() : false; } + virtual void SetBreakBefore(addr_t addr, bool bOn = true) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetBreakBefore(bOn); } + virtual uint32_t GetDisassemblyFlags(addr_t addr, uint8_t mem, Label *plbl) + { return GetBasicDisassemblyFlags(attr.getat(addr), mem, plbl); } + // basic access + virtual size_t size() { return (size_t)attr.size(); } + virtual addr_t GetStart(int index) { return attr[index].GetStart(); } + virtual size_t size(int index) { return attr[index].size(); } + // additional attributes for 6809 + virtual addr_t GetDirectPage(addr_t addr) + { MemAttribute6809 *pAttr = attr.getat(addr); return pAttr ? pAttr->GetDirectPage() : DEFAULT_ADDRESS; } + virtual void SetDirectPage(addr_t addr, addr_t dp) + { MemAttribute6809 *pAttr = attr.getat(addr); if (pAttr) pAttr->SetDirectPage(dp); } + protected: + TMemoryArray attr; + +}; + + +/*****************************************************************************/ +/* Dasm6809 : class for a Motorola 6809 Processor */ +/*****************************************************************************/ + +class Dasm6809 : public Dasm6800 + { + public: + Dasm6809(void); + virtual ~Dasm6809(void); + + // Overrides + public: + // return processor long name + virtual std::string GetName() { return "Motorola 6809"; } + + // Options handler + protected: + int Set6809Option(std::string name, std::string value); + std::string Get6809Option(std::string name); + + // Get/Set additional cell information + addr_t GetDirectPage(addr_t addr, bool bDataBus = false) + { + addr_t dp = memattr[bDataBus] ? ((MemAttribute6809Handler *)memattr[bDataBus])->GetDirectPage(addr) : DEFAULT_ADDRESS; + if (dp == DEFAULT_ADDRESS) + dp = dirpage; + return dp; + } + void SetDirectPage(addr_t addr, addr_t dp, bool bDataBus = false) + { if (memattr[bDataBus]) ((MemAttribute6809Handler *)memattr[bDataBus])->SetDirectPage(addr, dp); } + + virtual bool InitParse(bool bDataBus = false); + virtual bool ProcessInfo(std::string key, std::string value, addr_t &from, addr_t &to, bool bProcInfo = true, bool bDataBus = false); + + protected: + // parse instruction at given memory address for labels + virtual addr_t ParseCode(addr_t addr, bool bDataBus = false); + // disassemble instruction at given memory address + virtual addr_t DisassembleCode(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false); + public: + // pass back disassembler-specific state changes before/after a disassembly line + virtual bool DisassembleChanges(addr_t addr, addr_t prevaddr, addr_t prevsz, bool bAfterLine, std::vector &changes, bool bDataBus = false); + + protected: + + // additional 6809 addressing modes + enum AddrMode6809 + { + _ind = addrmodes6800_count, /* indexed */ + _rew, /* relative word */ + _r1 , /* tfr/exg mode */ + _r2 , /* pul/psh system */ + _r3 , /* pul/psh user */ + + addrmodes6809_count + }; + + // additional 6809 mnemonics + enum Mnemonics6809 + { + _abx = mnemo6800_count, + _addd, + _andcc, + _brn, + _cmpd, + _cmps, + _cmpu, + _cmpx, + _cmpy, + _cwai, + _exg, + _lbcc, + _lbcs, + _lbeq, + _lbge, + _lbgt, + _lbhi, + _lble, + _lbls, + _lblt, + _lbmi, + _lbne, + _lbpl, + _lbra, + _lbrn, + _lbsr, + _lbvc, + _lbvs, + _ldd, + _ldu, + _ldy, + _leas, + _leau, + _leax, + _leay, + _mul, + _orcc, + _pshs, + _pshu, + _puls, + _pulu, + _reset, + _sex, + _std, + _stu, + _sty, + _subd, + _swi2, + _swi3, + _sync, + _tfr, + // Convenience mnemonics + _clf, + _clif, + _clz, + _deu, + _dey, + _inu, + _iny, + _sef, + _seif, + _sez, + + mnemo6809_count + }; + + static uint8_t m6809_codes[512]; + static uint8_t m6809_codes10[512]; + static uint8_t m6809_codes11[512]; + static OpCode opcodes[mnemo6809_count - mnemo6800_count]; + static char *os9_codes[0x100]; + addr_t dirpage; + + uint8_t *codes10; + uint8_t *codes11; + char **exg_tfr; + static char reg[]; + + bool os9Patch; + bool useFlex; + + protected: + // must not be called from constructor! + virtual MemAttributeHandler *CreateAttributeHandler() { return new MemAttribute6809Handler; } + + virtual addr_t IndexParse(int MI, addr_t pc); + virtual std::string IndexString(addr_t &pc); + void AddFlexLabels(); + + }; + +#endif // __Dasm6809_h_defined__ diff --git a/Disassembler.cpp b/Disassembler.cpp new file mode 100644 index 0000000..1ab1737 --- /dev/null +++ b/Disassembler.cpp @@ -0,0 +1,748 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Disassembler.cpp : disassembler base class functionality */ +/*****************************************************************************/ + +#include "Disassembler.h" + +/*****************************************************************************/ +/* GetHex : retrieves a hex value in given length from file */ +/*****************************************************************************/ + +addr_t GetHex(FILE *f, int nChars, uint8_t *pchks) +{ +addr_t out = 0; + +for (int i = 0; i < nChars; i++) + { + int c = fgetc(f); + if (c == EOF) + return NO_ADDRESS; + if ((c >= 'a') && (c <= 'f')) + c -= ('a' - 'A'); + if ((!((c >= '0') && (c <= '9'))) && + (!((c >= 'A') && (c <= 'F')))) + return NO_ADDRESS; + c -= '0'; + if (c > 9) + c -= 7; + if (pchks) + *pchks += (i & 1) ? c : (c << 4); + out = out * 16 + c; + } + +return out; +} + +/*****************************************************************************/ +/* GetBasicDisassemblyFlags : returns basic disassembly flag set */ +/*****************************************************************************/ + +uint32_t GetBasicDisassemblyFlags(MemAttribute *pAttr, uint8_t mem, Label *plbl) +{ +// should be sufficient for most, if not all, disassemblers +uint32_t wf = 0; +if (!pAttr || + pAttr->GetMemType() == Code || + !pAttr->IsUsed()) + return 0; + +wf = pAttr->cellSize | SHMF_DATA; /* assemble flags for data byte */ + +if (pAttr->GetMemType() == Bss) + wf |= SHMF_RMB; +else if (pAttr->GetSize() == 1 +#if RB_VARIANT + && pAttr->GetDisplay() == MemAttribute::Char +#else + && pAttr->GetDisplay() != MemAttribute::Binary +#endif + ) + { + // NB: this is totally ASCII-centric, but as long as we don't + // have to deal with other encodings, it should be OK. + if ((mem >= 0x20) && (mem <= 0x7e) && + (mem != '&') && (mem != '\"') && + (pAttr->GetMemType() != Const)) + wf |= SHMF_TXT; + } +if (pAttr->GetBreakBefore()) + wf |= SHMF_BREAK; + +if (plbl && plbl->IsUsed()) + { + // labels containing '+' or '-' are no real labels; they are + // references to another label (e.g., "OLBL+4") + std::string &s = plbl->GetText(); + if (s.find('-') == s.npos && s.find('+') == s.npos) + wf |= SHMF_BREAK; + } + +#if 0 +// Should be done outside +if ((commentlines[pc]) || (lcomments[pc])) + wf |= SHMF_COMMENT; +#endif + +return wf; +} + + +/*===========================================================================*/ +/* Disassembler class members */ +/*===========================================================================*/ + +// determine the endianness of the machine the disassembler runs on +static const uint16_t chkEnd = (((uint16_t)Disassembler::BigEndian) << 8) | + (uint16_t)Disassembler::LittleEndian; +const Disassembler::Endian Disassembler::prgEndian = (Disassembler::Endian)*((uint8_t *)&chkEnd); + +/*****************************************************************************/ +/* Disassembler : constructor */ +/*****************************************************************************/ + +Disassembler::Disassembler() +{ +begin = load = NO_ADDRESS; +end = offset = 0; +memattr[0] = memattr[1] = NULL; +commentStart = ";"; +#if RB_VARIANT +labelDelim = ":"; +#else +labelDelim = ""; +#endif +defaultDisplay = MemAttribute::Hex; +pbase = 16; +bLoadLabel = true; + +// set up options table +// base class uses one generic option setter/getter pair (not mandatory) +AddOption("begin", "{addr}\tstart disassembly address", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +AddOption("end", "{addr}\tend disassembly address", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +AddOption("offset", "{addr}\taddress to load program", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +AddOption("cchar", "{char}\tcomment start character", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +AddOption("ldchar", "{char}\tlabel delimiter character", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +AddOption("loadlabel", "{off|on}\tflag whether to use entry point label", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +AddOption("pbase", "{number}\tdefault number base for parsing", + &Disassembler::DisassemblerSetOption, + &Disassembler::DisassemblerGetOption); +} + +/*****************************************************************************/ +/* ~Disassembler : destructor */ +/*****************************************************************************/ + +Disassembler::~Disassembler() +{ +for (int i = 0; i < GetOptionCount(); i++) + delete options[i]; +} + +/*****************************************************************************/ +/* AddOption : add an option and its handler to the options array */ +/*****************************************************************************/ + +bool Disassembler::AddOption + ( + std::string name, + std::string help, + PSetter setter, + PGetter getter + ) +{ +// allow overriding of base class option handlers +std::string lname(lowercase(name)); +for (int i = 0; i < GetOptionCount(); i++) + if (GetOptionName(i) == lname) + { + options[i]->help = help; + options[i]->setter = setter; + options[i]->getter = getter; + return true; + } +// append new option +try + { + OptionHandler *p = new OptionHandler; + if (p) + { + p->name = lname; + p->help = help; + p->setter = setter; + p->getter = getter; + options.push_back(p); + } + else return false; // for very old compilers + } +catch(...) + { + return false; + } +return true; +} + +/*****************************************************************************/ +/* FindOption : returns index for an option or -1 */ +/*****************************************************************************/ + +int Disassembler::FindOption(std::string name) +{ +std::string lname(lowercase(name)); +for (int i = 0; i < GetOptionCount(); i++) + if (name == options[i]->name) + return i; +return -1; +} + +/*****************************************************************************/ +/* SetOption : sets a disassembler option */ +/*****************************************************************************/ + +int Disassembler::SetOption(std::string name, std::string value) +{ +std::string lname(lowercase(name)); + +for (int i = 0; i < GetOptionCount(); i++) + if (name == options[i]->name) + return ((*this).*(options[i]->setter))(name, value); + +return 0; +} + +/*****************************************************************************/ +/* GetOption : retrieves a disassembler option */ +/*****************************************************************************/ + +std::string Disassembler::GetOption(std::string name) +{ +std::string lname(lowercase(name)); + +for (int i = 0; i < GetOptionCount(); i++) + if (name == options[i]->name) + return ((*this).*(options[i]->getter))(name); + +return ""; +} + +/*****************************************************************************/ +/* DisassemblerSetOption : disassembler base class option handler */ +/*****************************************************************************/ + +int Disassembler::DisassemblerSetOption(std::string lname, std::string value) +{ +// this could be expanded ... "0x" or "$" header come to mind... +std::string lvalue(lowercase(value)); +addr_t ivalue = (addr_t)strtoul(value.c_str(), NULL, 10); +addr_t avalue; +String2Number(value, avalue); +int bnvalue = (lvalue == "off") ? 0 : (lvalue == "on") ? 1 : atoi(value.c_str()); + +if (lname == "begin" && + avalue >= GetLowestCodeAddr() && + avalue <= GetHighestCodeAddr()) + begin = avalue; +else if (lname == "end" && + avalue >= GetLowestCodeAddr() && + avalue <= GetHighestCodeAddr()) + end = avalue; +else if (lname == "offset" && + avalue >= GetLowestCodeAddr() && + avalue <= GetHighestCodeAddr()) + offset = avalue; +else if (lname == "cchar") + commentStart = value; +else if (lname == "ldchar") + labelDelim = value; +else if (lname == "loadlabel") + bLoadLabel = !!bnvalue; +else if (lname == "pbase" && + ivalue >= 2 && ivalue <= 16) + pbase = ivalue; +else + return 0; /* only option consumed */ + +return 1; /* option + value consumed */ +} + +/*****************************************************************************/ +/* DisassemblerGetOption : disassembler base class option retrieval */ +/*****************************************************************************/ + +std::string Disassembler::DisassemblerGetOption(std::string lname) +{ +std::string oval; +if (lname == "begin") oval = sformat("0x%lx", begin); +else if (lname == "end") oval = sformat("0x%lx", end); +else if (lname == "offset") + oval = sformat("0x%lx", offset); +else if (lname == "cchar") oval = commentStart; +else if (lname == "ldchar") oval = labelDelim; +else if (lname == "loadlabel") oval = bLoadLabel ? "on" : "off"; +else if (lname == "pbase") oval = sformat("%ld", pbase); +return oval; +} + +/*****************************************************************************/ +/* Label2String : converts a value to a (label) string */ +/*****************************************************************************/ + +std::string Disassembler::Label2String + ( + addr_t value, + bool bUseLabel, + addr_t addr, + bool bDataBus + ) +{ +std::string sOut; +addr_t Wrel = value + GetRelative(addr); +std::string sLabel; + /* get label name */ +sLabel = (bUseLabel) ? GetLabel(Wrel, Untyped, bDataBus) : ""; + /* if there and absolute */ +if (Wrel == value && sLabel.size()) + return sLabel; /* return it */ + +if (sLabel.size()) + sOut = sLabel; +else if (bUseLabel && IsCLabel(Wrel, bDataBus)) + sOut = sformat("Z%0*X", GetCodeBits() / 4, Wrel); +else if (bUseLabel && IsDLabel(Wrel, bDataBus)) + sOut = sformat("M%0*X", GetDataBits() / 4, Wrel); +else + sOut = Number2String(Wrel, 4, addr, bDataBus).c_str(); + +if (Wrel != value) /* if it's relative addressing */ + { + std::string sAdd("-"); + bool bInvert = true; + int32_t nDiff = Wrel - value; /* get difference */ + + Wrel = GetRelative(addr, bDataBus); + /* get base name */ + sLabel = (bUseLabel) ? GetLabel(Wrel, Untyped, bDataBus) : ""; + if (sLabel.size()) + sAdd += sLabel; + else if (bUseLabel && IsCLabel(Wrel, bDataBus)) + sAdd += sformat("Z%0*X", GetCodeBits() / 4, Wrel); + else if (bUseLabel && IsDLabel(Wrel, bDataBus)) + sAdd += sformat("M%0*X", GetDataBits() / 4, Wrel); + else + { + if (nDiff < 0) /* if negative displacement */ + { + sAdd = "+"; /* negative*negative is positive... */ + bInvert = false; /* so invert the sign */ + /* and make the number positive */ + Wrel = (addr_t) (-((int32_t)Wrel)); + } + sAdd += Number2String(Wrel, 4, addr, bDataBus); + } + + if (bInvert) /* if inverting necessary, */ + { + std::string::iterator i = sAdd.begin(); + i++; + while (i != sAdd.end()) /* invert eventual signs! */ + { + if (*i == '+') + *i = '-'; + else if (*i == '-') + *i = '+'; + i++; + } + } + sOut += sAdd; + } + +return sOut; +} + +/*****************************************************************************/ +/* LoadIntelHex : tries to load as an Intel HEX file */ +/*****************************************************************************/ + +bool Disassembler::LoadIntelHex + ( + std::string filename, + FILE *f, + std::string &sLoadType, + int interleave + ) +{ +int nCurPos = ftell(f); +int c = 0, rectype; +bool done = false; +int nBytes = 0; +addr_t fbegin = GetHighestCodeAddr(); +addr_t fend = GetLowestCodeAddr(); +int segment = 0; /* segment address */ + +if ((c = fgetc(f)) == EOF) /* look whether starting with ':' */ + return false; +if (c != ':') + nBytes = -1; + +while (!done && (nBytes >= 0)) /* while there are lines */ + { + addr_t nAddr; + int nBytesOnLine, i; + uint8_t chks = 0; + if (c != ':') + break; + nBytesOnLine = GetHex(f, 2, &chks); /* retrieve # bytes on line */ + if (nBytesOnLine < 0) /* if error */ + { nBytes = -1; break; } /* return with error */ + else if (nBytesOnLine == 0) /* if end of file */ + break; /* just break; */ + nAddr = GetHex(f,4, &chks) + segment; /* get address for bytes */ + nAddr = (nAddr * interleave) + offset; + int nSpreadBytes = (nBytesOnLine * interleave) - (interleave - 1); + if ((nAddr < GetLowestCodeAddr()) || /* if illegal address */ + (nAddr + nSpreadBytes > GetHighestCodeAddr())) + { nBytes = -1; break; } /* return with error */ + if (nAddr < fbegin) /* adjust start and end values */ + { + fbegin = nAddr; + AddMemory(nAddr, nSpreadBytes); + } + if (nAddr + nSpreadBytes - 1 > fend) + { + AddMemory(nAddr, nSpreadBytes); + fend = nAddr + nSpreadBytes - 1; + } + nBytes += nBytesOnLine; + rectype = GetHex(f, 2, &chks); /* fetch record type character */ + switch (rectype) /* which type of record is this? */ + { + case 0 : /* data record */ + for (i = 0; i 0xff)) /* if illegal byte */ + { nBytes = -1; break; } /* return with error */ + setat(tgtaddr, (uint8_t)c); /* otherwise add memory byte */ + SetCellUsed(tgtaddr); /* mark as used byte */ + SetDisplay(tgtaddr, defaultDisplay); + } + break; + case 1 : /* End Of File record */ + done = true; + break; + case 2 : /* Extended Segment Address */ + segment = GetHex(f, 4, &chks); /* get segment value to use */ + segment <<= 4; /* convert to linear addition value */ + break; + case 3 : /* Start Segment Address */ + segment = GetHex(f, 4, &chks); /* get segment value to use */ + segment <<= 4; /* convert to linear addition value */ + nAddr = GetHex(f, 4, &chks) + /* get start instruction pointer */ + segment; + SetLoadAddr: + nAddr = (nAddr * interleave) + offset; + if ((nAddr < GetLowestCodeAddr()) || /* if illegal address */ + (nAddr > GetHighestCodeAddr())) + nBytes = -1; /* return with error */ + else + load = nAddr; + break; + case 4 : /* Extended Linear Address */ + segment = GetHex(f, 4, &chks); /* get segment value to use */ + segment <<= 16; /* convert to linear addition value */ + break; + case 5 : /* Start Linear Address */ + nAddr = GetHex(f, 8, &chks); /* get start instruction pointer */ + goto SetLoadAddr; + default : /* anything else? */ + nBytes = -1; /* unknown format. stop processing */ + break; + } + + /* ignore checksum byte; its calculation would be: + add up all decoded bytes after the ':', + take 2's complement of lowest byte */ + GetHex(f, 2, &chks); + // chks should be 0! + + while (((c = fgetc(f)) != EOF) && /* skip to newline */ + (c != '\r') && (c != '\n')) + ; + + while (((c = fgetc(f)) != EOF) && /* skip newline itself */ + ((c == '\r') || (c == '\n'))) + ; + } + +fseek(f, nCurPos, SEEK_SET); +if (nBytes >= 0) + { + if (fbegin < begin) + begin = fbegin; + if (fend > end) + end = fend; + } + +if (nBytes > 0) + sLoadType = "Intel HEX"; +return (nBytes > 0); /* pass back #bytes interpreted */ +} + +/*****************************************************************************/ +/* LoadMotorolaHex : tries to load as a Motorola HEX file */ +/*****************************************************************************/ + +bool Disassembler::LoadMotorolaHex + ( + std::string filename, + FILE *f, + std::string &sLoadType, + int interleave + ) +{ +int nCurPos = ftell(f); +int c = 0; +bool done = false; +int nBytes = 0; +addr_t fbegin = GetHighestCodeAddr(); +addr_t fend = GetLowestCodeAddr(); + +if ((c = fgetc(f)) == EOF) /* look whether starting with 'S' */ + return false; +if (c != 'S') + nBytes = -1; + +while ((!done) && (nBytes >= 0)) /* while there are lines */ + { + int nLineType = 0, nBytesOnLine, i; + addr_t nAddr; + uint8_t chks = 0; + if (c != 'S') + break; + fread(&nLineType, 1, 1, f); /* retrieve line type */ + nBytesOnLine = GetHex(f, 2, &chks); /* retrieve # bytes on line */ + if (nBytesOnLine < 0) /* if error */ + { nBytes = -1; break; } /* return with error */ + else if (nBytesOnLine == 0) /* if end of file */ + break; /* just break; */ + int nSpreadBytes = (nBytesOnLine * interleave) - (interleave - 1); + switch (nLineType) /* now examine line type */ + { + case '0' : +#if 0 /* simply ignore the rest of the line*/ + nBytesOnLine--; + while (nBytesOnLine--) + GetHex(f, 2); +#endif + break; + case '1' : /* record with 16bit address */ + nBytesOnLine -= 3; + nAddr = GetHex(f,4, &chks); /* get address for bytes */ + data16bit: + nAddr = (nAddr * interleave) + offset; + if ((nAddr < GetLowestCodeAddr()) || /* if illegal address */ + (nAddr + nSpreadBytes > GetHighestCodeAddr())) + { nBytes = -1; break; } /* return with error */ + if (nAddr < fbegin) /* adjust start and end values */ + { + fbegin = nAddr; + AddMemory(nAddr, nSpreadBytes); + } + if (nAddr + nSpreadBytes - 1 > fend) + { + fend = nAddr + nSpreadBytes - 1; + AddMemory(nAddr, nSpreadBytes); + } + nBytes += nBytesOnLine; + /* now get the bytes */ + for (i = 0; i < nBytesOnLine; i++) + { + addr_t tgtaddr = nAddr + (i * interleave); + c = GetHex(f, 2, &chks); /* retrieve a byte */ + if ((c < 0) || (c > 0xff)) /* if illegal byte */ + { nBytes = -1; break; } /* return with error */ + setat(tgtaddr, (uint8_t)c); /* otherwise add memory byte */ + SetCellUsed(tgtaddr); /* mark as used byte */ + SetDisplay(tgtaddr, defaultDisplay); + } + break; + case '2' : /* record with 24bit address */ + nBytesOnLine -= 4; + nAddr = GetHex(f, 6, &chks); /* get address for bytes */ + goto data16bit; + case '3' : /* record with 32bit address */ + nBytesOnLine -= 5; + nAddr = GetHex(f, 8, &chks); /* get address for bytes */ + goto data16bit; + /* S5/S6 records ignored; don't think they make any sense here */ + case '5' : + case '6' : + break; + case '7' : /* 32-bit entry point */ + nAddr = GetHex(f, 8, &chks); /* get address to jump to */ + goto entry16bit; + case '8' : /* 24-bit entry point */ + nAddr = GetHex(f, 6, &chks); /* get address to jump to */ + goto entry16bit; + case '9' : + nAddr = GetHex(f, 4, &chks); /* get address to jump to */ + entry16bit: + nAddr = (nAddr * interleave) + offset; + if ((nAddr < GetLowestCodeAddr()) || /* if illegal address */ + (nAddr > GetHighestCodeAddr())) + { nBytes = -1; break; } /* return with error */ + /* the documentation says "if address isn't needed, use 0". + * bad idea IMO (they should have allowed to pass NO address instead), + * but, well ... 0 MIGHT be a valid start address, so we need to live + * with the ambiguity. */ + load = nAddr; + done = true; + break; + default : + done = true; + break; + } + + /* ignore checksum byte; its calculation would be: + add up all decoded bytes after the record type, + take 1's complement of lowest byte */ + GetHex(f, 2, &chks); + // chks should be 0xff! + + while (((c = fgetc(f)) != EOF) && /* skip to newline */ + (c != '\r') && (c != '\n')) + ; + + while (((c = fgetc(f)) != EOF) && /* skip newline itself */ + ((c == '\r') || (c == '\n'))) + ; + } + +fseek(f, nCurPos, SEEK_SET); +if (nBytes >= 0) + { + if (fbegin < begin) + begin = fbegin; + if (fend > end) + end = fend; + } + +if (nBytes > 0) + sLoadType = "Motorola S"; +return (nBytes > 0); /* pass back #bytes interpreted */ +} + +/*****************************************************************************/ +/* LoadBinary : loads opened file as a binary */ +/*****************************************************************************/ + +bool Disassembler::LoadBinary + ( + std::string filename, + FILE *f, + std::string &sLoadType, + int interleave + ) +{ +int nCurPos = ftell(f); +addr_t i, off; +fseek(f, 0, SEEK_END); /* get file length */ +off = ftell(f) - nCurPos; +fseek(f, nCurPos, SEEK_SET); + /* restrict to maximum code size */ +if (offset + (off * interleave) > GetHighestCodeAddr() + 1) + off = (GetHighestCodeAddr() + 1) / interleave; + +if (begin < 0 || offset < begin) /* set begin if not specified */ + begin = offset; + /* set end if not specified */ +if (end < offset + (off * interleave) - 1) + end = offset + (off * interleave) -1; +AddMemory(begin, off * interleave); /* make sure memory is there */ + /* mark area as used */ +for (i = 0; i < off; i++) + { + addr_t tgtaddr = offset + (i * interleave); + int c = fgetc(f); /* read a byte from the file */ + if (c == EOF) /* if error, abort reading */ + { + fseek(f, nCurPos, SEEK_SET); + return false; + } + setat(tgtaddr, (uint8_t)c); /* otherwise add memory byte */ + SetCellUsed(tgtaddr); /* mark as used byte */ + SetDisplay(tgtaddr, defaultDisplay); + } + +sLoadType = "binary"; +return true; +} + +/*****************************************************************************/ +/* LoadFile : loads an opened file */ +/*****************************************************************************/ + +bool Disassembler::LoadFile + ( + std::string filename, + FILE *f, + std::string &sLoadType, + int interleave + ) +{ +return LoadIntelHex(filename, f, sLoadType) || + LoadMotorolaHex(filename, f, sLoadType) || + LoadBinary(filename, f, sLoadType); +} + +/*****************************************************************************/ +/* Load : loads a code file into the disassembler */ +/*****************************************************************************/ + +bool Disassembler::Load + ( + std::string filename, + std::string &sLoadType, + int interleave + ) +{ +sLoadType.clear(); +FILE *pFile = fopen(filename.c_str(), "rb"); +if (pFile == NULL) + return false; +bool bOK = LoadFile(filename, pFile, sLoadType, interleave); +fclose(pFile); +if (bOK) /* if loading done, */ + offset = end + 1; /* prepare for next file */ +return bOK; +} diff --git a/Disassembler.h b/Disassembler.h new file mode 100644 index 0000000..ea23c02 --- /dev/null +++ b/Disassembler.h @@ -0,0 +1,672 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Disassembler.h : definition of the Disassembler abstract base class */ +/*****************************************************************************/ + +#ifndef __Disassembler_h_defined__ +#define __Disassembler_h_defined__ + +#include "dasmfw.h" + +/*****************************************************************************/ +/* MemAttributeHandler : abstract base handler for memory attributes */ +/*****************************************************************************/ + +class MemAttributeHandler + { + public: + MemAttributeHandler() { } + virtual ~MemAttributeHandler() { } + virtual bool AddMemory(addr_t addrStart = 0, addr_t memSize = 0, MemoryType memType = Code) = 0; + virtual MemoryType GetMemType(addr_t addr) = 0; + virtual void SetMemType(addr_t addr, MemoryType newType = Code) = 0; + virtual bool IsCellUsed(addr_t addr) = 0; + virtual void SetCellUsed(addr_t addr, bool bUsed = true) = 0; + virtual MemAttribute::Type GetCellType(addr_t addr) = 0; + virtual void SetCellType(addr_t addr, MemAttribute::Type newType) = 0; + virtual int GetCellSize(addr_t addr) = 0; + virtual void SetCellSize(addr_t addr, int newSize = 1) = 0; + virtual MemAttribute::Display GetDisplay(addr_t addr) = 0; + virtual void SetDisplay(addr_t addr, MemAttribute::Display newDisp = MemAttribute::Hex) = 0; + virtual bool GetBreakBefore(addr_t addr) = 0; + virtual void SetBreakBefore(addr_t addr, bool bOn = true) = 0; + virtual uint32_t GetDisassemblyFlags(addr_t addr, uint8_t mem, Label *plbl) = 0; + // basic access + virtual size_t size() = 0; + virtual addr_t GetStart(int index) = 0; + virtual size_t size(int index) = 0; + }; + +/*****************************************************************************/ +/* BasicMemAttributeHandler : memory attribute handler for basics */ +/*****************************************************************************/ + +enum BasicDataDisassemblyFlags + { + // lowest 8 bits are reserved for (cell size - 1); if the need arises for + // larger cells, this has to be adjusted + SHMF_DATA = 1 << 8, /* Data byte (not Code) */ + SHMF_RMB = (SHMF_DATA << 1), /* no defined contents */ + SHMF_TXT = (SHMF_RMB << 1), /* Textual display possible */ + SHMF_BREAK = (SHMF_TXT << 1), /* mandatory break before */ + + SHMF_BasicSetMax = SHMF_BREAK + }; + +uint32_t GetBasicDisassemblyFlags(MemAttribute *pAttr, uint8_t mem, Label *plbl); +class BasicMemAttributeHandler : public MemAttributeHandler +{ + public: + BasicMemAttributeHandler() + { } + virtual ~BasicMemAttributeHandler() + { } + + virtual bool AddMemory(addr_t addrStart = 0, addr_t memSize = 0, MemoryType memType = Code) + { return attr.AddMemory(addrStart, memSize, memType); } + virtual MemoryType GetMemType(addr_t addr) + { MemAttribute *pAttr = attr.getat(addr); return pAttr ? pAttr->GetMemType() : Untyped; } + virtual void SetMemType(addr_t addr, MemoryType newType = Code) + { MemAttribute *pAttr = attr.getat(addr); if (pAttr) pAttr->SetMemType(newType); } + virtual bool IsCellUsed(addr_t addr) + { MemAttribute *pAttr = attr.getat(addr); return pAttr ? pAttr->IsUsed() : false; } + virtual void SetCellUsed(addr_t addr, bool bUsed = true) + { MemAttribute *pAttr = attr.getat(addr); if (pAttr) pAttr->SetUsed(bUsed); } + virtual MemAttribute::Type GetCellType(addr_t addr) + { MemAttribute *pAttr = attr.getat(addr); return pAttr ? pAttr->GetCellType() : MemAttribute::CellUntyped; } + virtual void SetCellType(addr_t addr, MemAttribute::Type newType) + { MemAttribute *pAttr = attr.getat(addr); if (pAttr) pAttr->SetCellType(newType); } + virtual int GetCellSize(addr_t addr) + { MemAttribute *pAttr = attr.getat(addr); return pAttr ? pAttr->GetSize() : 0; } + virtual void SetCellSize(addr_t addr, int newSize = 1) + { MemAttribute *pAttr = attr.getat(addr); if (pAttr) pAttr->SetSize(newSize); } + virtual MemAttribute::Display GetDisplay(addr_t addr) + { MemAttribute *pAttr = attr.getat(addr); return pAttr ? pAttr->GetDisplay() : MemAttribute::CellUndisplayable; } + virtual void SetDisplay(addr_t addr, MemAttribute::Display newDisp = MemAttribute::Hex) + { MemAttribute *pAttr = attr.getat(addr); if (pAttr) pAttr->SetDisplay(newDisp); } + virtual bool GetBreakBefore(addr_t addr) + { MemAttribute *pAttr = attr.getat(addr); return pAttr ? pAttr->GetBreakBefore() : false; } + virtual void SetBreakBefore(addr_t addr, bool bOn = true) + { MemAttribute *pAttr = attr.getat(addr); if (pAttr) pAttr->SetBreakBefore(bOn); } + virtual uint32_t GetDisassemblyFlags(addr_t addr, uint8_t mem, Label *plbl) + { return GetBasicDisassemblyFlags(attr.getat(addr), mem, plbl); } + // basic access + virtual size_t size() { return (size_t)attr.size(); } + virtual addr_t GetStart(int index) { return attr[index].GetStart(); } + virtual size_t size(int index) { return attr[index].size(); } + + protected: + TMemoryArray attr; + +}; + + +/*****************************************************************************/ +/* OpCode : a basic opcode definition */ +/*****************************************************************************/ + +struct OpCode + { + const char *mne; /* mnemonic */ + MemoryType memType; /* referenced memory type */ + }; + +/*****************************************************************************/ +/* Disassembler : abstract base class for a processor's disassembler */ +/*****************************************************************************/ + +class Disassembler + { + public: + Disassembler(); + virtual ~Disassembler(); + + // Endianness enumeration + public: + enum Endian + { + BigEndian, /* MSB first */ + LittleEndian /* LSB first */ + }; + enum Architecture + { + vonNeumann, /* Code and data share the same bus */ + Harvard /* Code and data have separate bus */ + }; + + // Information about the processor's capabilities + public: + // return processor long name + virtual std::string GetName() = 0; + // return whether big- or little-endian + virtual Endian GetEndianness() = 0; + // return architecture type + virtual Architecture GetArchitecture() { return vonNeumann; } // most are vN + // return code bits + virtual int GetCodeBits() = 0; + // return code pointer size in bytes + virtual int GetCodePtrSize() = 0; + // return lowest possible code address + virtual caddr_t GetLowestCodeAddr() { return 0; } + // return highest possible code address + virtual caddr_t GetHighestCodeAddr() = 0; + // return data bits + virtual int GetDataBits() = 0; + // return data pointer size in bytes + virtual int GetDataPtrSize() = 0; + // return lowest possible data address + virtual daddr_t GetLowestDataAddr() { return 0; } + // return highest possible data address + virtual daddr_t GetHighestDataAddr() = 0; + + // Setup disassembler after construction + virtual bool Setup() + { + // default to basic memory attribute handlers + memattr[0] = CreateAttributeHandler(); + memattr[1] = CreateAttributeHandler(); + return memattr[0] && memattr[1]; + } + + // Generic options handler + protected: + typedef int (Disassembler::*PSetter)(std::string lname, std::string value); + typedef std::string (Disassembler::*PGetter)(std::string lname); + struct OptionHandler + { + std::string name; + std::string help; + PSetter setter; + PGetter getter; + }; + std::vector options; + bool AddOption(std::string name, std::string help, PSetter setter, PGetter getter); + // + int DisassemblerSetOption(std::string lname, std::string value); + std::string DisassemblerGetOption(std::string lname); + public: + int GetOptionCount() { return options.size(); } + int FindOption(std::string name); + std::string GetOptionName(int idx) { return options[idx]->name; } + std::string GetOptionHelp(int idx) { return options[idx]->help; } + int SetOption(int idx, std::string value) { return ((*this).*(options[idx]->setter))(options[idx]->name, value); } + int SetOption(std::string name, std::string value); + std::string GetOption(int idx) { return ((*this).*(options[idx]->getter))(options[idx]->name); } + std::string GetOption(std::string name); + // global typed options + addr_t GetBegin() { return begin; } + addr_t GetEnd() { return end; } + addr_t GetOffset() { return offset; } + + // Memory access + public: + // Add memory area + virtual bool AddMemory(addr_t addrStart = 0, addr_t memSize = 0, MemoryType memType = Code, uint8_t *contents = NULL, bool bDataBus = false) + { + if (!memory[bDataBus].AddMemory(addrStart, memSize, memType, contents)) + return false; + return memattr[bDataBus] && memattr[bDataBus]->AddMemory(addrStart, memSize, memType); + } + template T getat(addr_t addr, bool bDataBus = false) + { + T val; + if (!getat(addr, (uint8_t *)&val, sizeof(val), bDataBus)) + return 0; + return val; + } + // Direct access to memory areas (... be careful!) + int GetMemoryArrayCount(bool bDataBus = false) { return memory[bDataBus].size(); } + TMemory &GetMemoryArray(int index, bool bDataBus = false) { return memory[bDataBus].at(index); } + int GetMemAttrArrayCount(bool bDataBus = false) { return memattr[bDataBus] ? memattr[bDataBus]->size() : 0; } + MemAttributeHandler *GetMemoryAttributeHandler(bool bDataBus = false) { return memattr[bDataBus]; } + // find memory area index for a given address + addr_t GetMemIndex(addr_t addr, bool bDataBus = false) + { return memory[bDataBus].GetMemIndex(addr); } + // get next loaded memory address + addr_t GetNextAddr(addr_t addr, bool bDataBus = false) + { + addr_t nextAddr = addr + 1; + while (!IsCellUsed(nextAddr, bDataBus)) + { + uint8_t *pNext = getat(nextAddr, bDataBus); + if (!pNext) + { + for (int i = 0; i < GetMemoryArrayCount(); i++) + { + addr_t nextStart = GetMemoryArray(i, bDataBus).GetStart(); + if (nextStart > nextAddr) + { + pNext = getat(nextStart, bDataBus); + nextAddr = nextStart; + break; + } + if (!pNext) + return NO_ADDRESS; + } + } + else + nextAddr++; + } + return nextAddr; + } + + // Get/Set memory byte + int8_t GetSByte(addr_t addr, bool bDataBus = false) + { return (int8_t)*getat(addr, bDataBus); } + uint8_t GetUByte(addr_t addr, bool bDataBus = false) + { uint8_t *pb = getat(addr, bDataBus); return pb ? *pb : 0; } + bool SetSByte(addr_t addr, int8_t val, bool bDataBus = false) + { return setat(addr, (uint8_t)val, bDataBus); } + bool SetUByte(addr_t addr, uint8_t val, bool bDataBus = false) + { return setat(addr, val, bDataBus); } + // Get/Set memory word + int16_t GetSWord(addr_t addr, bool bDataBus = false) + { return getat(addr, bDataBus); } + uint16_t GetUWord(addr_t addr, bool bDataBus = false) + { return getat(addr, bDataBus); } + bool SetSWord(addr_t addr, int16_t val, bool bDataBus = false) + { return setat(addr, (uint8_t *)&val, sizeof(val), bDataBus); } + bool SetUWord(addr_t addr, uint16_t val, bool bDataBus = false) + { return setat(addr, (uint8_t *)&val, sizeof(val), bDataBus); } + // Get/Set memory dword + int32_t GetSDWord(addr_t addr, bool bDataBus = false) + { return getat(addr, bDataBus); } + uint32_t GetUDWord(addr_t addr, bool bDataBus = false) + { return getat(addr, bDataBus); } + bool SetSDWord(addr_t addr, int32_t val, bool bDataBus = false) + { return setat(addr, (uint8_t *)&val, sizeof(val), bDataBus); } + bool SetUDWord(addr_t addr, uint32_t val, bool bDataBus = false) + { return setat(addr, (uint8_t *)&val, sizeof(val), bDataBus); } + // Get/Set 32-bit floating-point IEEE 854 value + float GetFloat(addr_t addr, bool bDataBus = false) + { return getat(addr, bDataBus); } + bool SetFloat(addr_t addr, float val, bool bDataBus = false) + { return setat(addr, (uint8_t *)&val, sizeof(val), bDataBus); } + // Get/Set 64-bit floating-point IEEE 854 value + double GetDouble(addr_t addr, bool bDataBus = false) + { return getat(addr, bDataBus); } + bool SetDouble(addr_t addr, double val, bool bDataBus = false) + { return setat(addr, (uint8_t *)&val, sizeof(val), bDataBus); } + // Get/set delimited ASCII string + std::string GetString(addr_t addr, char cTerm = '\0', bool bDataBus = false) + { + std::string s; + char c; + while ((c = (char)getat(addr++)) != cTerm) + s += c; + return s; + } + bool SetString(addr_t addr, std::string s, char cTerm = '\0', bool bDataBus = false) + { + if (setat(addr, (uint8_t *)s.c_str(), s.size(), bDataBus)) + return setat(addr + s.size(), (uint8_t)cTerm, bDataBus); + return false; + } + // in theory, strings with leading length byte/word might come up at some time + // we'll deal with it in time. + + // Get/Set cell information + MemoryType GetMemType(addr_t addr, bool bDataBus = false) + { return memattr[bDataBus] ? memattr[bDataBus]->GetMemType(addr) : Untyped; } + void SetMemType(addr_t addr, MemoryType newType = Code, bool bDataBus = false) + { if (memattr[bDataBus]) memattr[bDataBus]->SetMemType(addr, newType); } + bool IsCellUsed(addr_t addr, bool bDataBus = false) + { return memattr[bDataBus] ? memattr[bDataBus]->IsCellUsed(addr) : false; } + void SetCellUsed(addr_t addr, bool bUsed = true, bool bDataBus = false) + { if (memattr[bDataBus]) memattr[bDataBus]->SetCellUsed(addr, bUsed); } + MemAttribute::Type GetCellType(addr_t addr, bool bDataBus = false) + { return memattr[bDataBus] ? memattr[bDataBus]->GetCellType(addr) : MemAttribute::CellUntyped; } + void SetCellType(addr_t addr, MemAttribute::Type newType, bool bDataBus = false) + { if (memattr[bDataBus]) memattr[bDataBus]->SetCellType(addr, newType); } + int GetCellSize(addr_t addr, bool bDataBus = false) + { return memattr[bDataBus] ? memattr[bDataBus]->GetCellSize(addr) : 0; } + void SetCellSize(addr_t addr, int newSize = 1, bool bDataBus = false) + { if (memattr[bDataBus]) memattr[bDataBus]->SetCellSize(addr, newSize); } + MemAttribute::Display GetDisplay(addr_t addr, bool bDataBus = false) + { return memattr[bDataBus] ? memattr[bDataBus]->GetDisplay(addr) : MemAttribute::CellUndisplayable; } + void SetDisplay(addr_t addr, MemAttribute::Display newDisp = MemAttribute::Hex, bool bDataBus = false) + { if (memattr[bDataBus]) memattr[bDataBus]->SetDisplay(addr, newDisp); } + bool GetBreakBefore(addr_t addr, bool bDataBus = false) + { return memattr[bDataBus] ? memattr[bDataBus]->GetBreakBefore(addr) : false; } + void SetBreakBefore(addr_t addr, bool bOn = true, bool bDataBus = false) + { if (memattr[bDataBus]) memattr[bDataBus]->SetBreakBefore(addr, bOn); } + // get/set default cell display format + MemAttribute::Display GetDisplay() { return defaultDisplay; } + void SetDisplay(MemAttribute::Display newDisp) { defaultDisplay = newDisp; } + // Get Flags for disassembly of data areas + uint32_t GetDisassemblyFlags(addr_t addr, bool bDataBus = false) + { + uint8_t *mem = getat(addr, bDataBus); + if (!mem) return 0; + Label *plbl = FindLabel(addr, Untyped, bDataBus); + return memattr[bDataBus] ? memattr[bDataBus]->GetDisassemblyFlags(addr, *mem, plbl) : 0; + } + + // convenience functionality for the above + bool IsCode(addr_t addr, bool bDataBus = false) { return GetMemType(addr, bDataBus) == Code; } + bool IsData(addr_t addr, bool bDataBus = false) { return GetMemType(addr, bDataBus) == Data; } + bool IsConst(addr_t addr, bool bDataBus = false) { return GetMemType(addr, bDataBus) == Const; } + bool IsBss(addr_t addr, bool bDataBus = false) { return GetMemType(addr, bDataBus) == Bss; } + bool IsBinary(addr_t addr, bool bDataBus = false) { return GetDisplay(addr, bDataBus) == MemAttribute::Binary; } + bool IsChar(addr_t addr, bool bDataBus = false) { return GetDisplay(addr, bDataBus) == MemAttribute::Char; } + bool IsOctal(addr_t addr, bool bDataBus = false) { return GetDisplay(addr, bDataBus) == MemAttribute::Octal; } + bool IsDecimal(addr_t addr, bool bDataBus = false) { return GetDisplay(addr, bDataBus) == MemAttribute::Decimal; } + bool IsHex(addr_t addr, bool bDataBus = false) { return GetDisplay(addr, bDataBus) == MemAttribute::Hex; } + bool IsSigned(addr_t addr, bool bDataBus = false) { return GetCellType(addr, bDataBus) == MemAttribute::SignedInt; } + bool IsUnsigned(addr_t addr, bool bDataBus = false) { return GetCellType(addr, bDataBus) == MemAttribute::UnsignedInt; } + bool IsFloat(addr_t addr, bool bDataBus = false) { return GetCellType(addr, bDataBus) == MemAttribute::Float; } + + // Relative handling + public: + bool AddRelative(addr_t addr, addr_t relsize = 1, addr_t *contents = NULL, bool bDataBus = false) + { return Relatives[bDataBus].AddMemory(addr, relsize, 0, contents); } + addr_t GetRelative(addr_t addr, bool bDataBus = false) + { addr_t *paddr = Relatives[bDataBus].getat(addr); return paddr ? *paddr : 0; } + void SetRelative(addr_t addr, addr_t rel, bool bDataBus = false) + { addr_t *paddr = Relatives[bDataBus].getat(addr); if (paddr) *paddr = rel; } + + // Phase handling + public: + bool AddPhase(addr_t addr, addr_t phaseSize = 1, addr_t phase = 0, bool bDataBus = false) + { return Phases[bDataBus].AddMemory(addr, phaseSize, phase); } + TMemory *FindPhase(addr_t addr, bool bDataBus = false) + { return Phases[bDataBus].FindMem(addr); } + addr_t GetPhase(addr_t addr, bool bDataBus = false) + { TMemory *pArea = FindPhase(addr, bDataBus); return pArea ? pArea->GetType() : NO_ADDRESS; } + void SetPhase(addr_t addr, addr_t phase = NO_ADDRESS, bool bDataBus = false) + { addr_t *paddr = Phases[bDataBus].getat(addr); if (paddr) *paddr = phase; } + protected: + addr_t PhaseInner(addr_t value, addr_t addr, bool bDataBus = false) + { + // "phase" an address if it's inside the current range + TMemory *pArea = Phases[bDataBus].FindMem(addr); + if (pArea) + { + addr_t phStart = pArea->GetType(); + addr_t phEnd = phStart + pArea->size() - 1; + addr_t offset = pArea->at(addr); + if (value >= phStart && value <= phEnd || offset != NO_ADDRESS) + { + addr_t aStart = pArea->GetStart(); + if (offset == NO_ADDRESS) + offset = phStart - aStart; + else if (offset == DEFAULT_ADDRESS) + offset = 0; + else + offset -= aStart; + value -= offset; + } + } + return value; + } + addr_t DephaseOuter(addr_t value, addr_t addr, bool bDataBus = false) + { + // "de-phase" an address if it's outside the current range + TMemory *pArea = Phases[bDataBus].FindMem(addr); + if (pArea) + { + addr_t aStart = pArea->GetStart(); + addr_t aEnd = pArea->GetEnd(); + addr_t offset = pArea->at(addr); + if (value < aStart || value > aEnd || offset != NO_ADDRESS) + { + addr_t phStart = pArea->GetType(); + if (offset == NO_ADDRESS) + offset = aStart - phStart; + else if (offset == DEFAULT_ADDRESS) + offset = 0; + else + offset -= phStart; + value -= offset; + } + } + return value; + } + + // Label handling + public: + bool AddLabel(addr_t addr, MemoryType memType = Code, std::string sLabel = "", bool bUsed = false, bool bDataBus = false) + { + Label *pLbl = FindLabel(addr, Untyped, bDataBus); + MemoryType oType = pLbl ? pLbl->GetType() : memType; + if (pLbl && oType != Untyped && oType != memType) + memType = pLbl->GetType(); + if (!bUsed) + { + if (pLbl) + bUsed = pLbl->IsUsed(); + } + Labels[bDataBus].insert(new Label(addr, memType, sLabel, bUsed)); + return true; + } + Label *FindLabel(addr_t addr, MemoryType memType = Untyped, bool bDataBus = false) + { + AddrTextArray::iterator p = Labels[bDataBus].find(addr, memType); + return (p != Labels[bDataBus].end()) ? (Label *)(*p) : NULL; + } + int GetLabelCount(bool bDataBus = false) { return Labels[bDataBus].size(); } + Label *LabelAt(int index, bool bDataBus = false) { return (Label *)Labels[bDataBus].at(index); } + void RemoveLabelAt(int index, bool bDataBus = false) { Labels[bDataBus].erase(Labels[bDataBus].begin() + index); } + // convenience functionality for the above + std::string GetLabel(addr_t addr, MemoryType memType = Untyped, bool bDataBus = false) { Label *p = FindLabel(addr, memType); return p ? p->GetText() : ""; } + bool IsLabel(addr_t addr, bool bDataBus = false) { return !!FindLabel(addr, Untyped, bDataBus); } + bool IsCLabel(addr_t addr, bool bDataBus = false) { Label *pLabel = FindLabel(addr, Untyped); return pLabel ? pLabel->IsCode() : false; } + bool IsDLabel(addr_t addr, bool bDataBus = false) { Label *pLabel = FindLabel(addr, Untyped); return pLabel ? pLabel->IsData() : false; } + + // File handling + public: + // load a code file; interleave can be >1 for interleaved Low/High EPROM pairs, for example + bool Load(std::string filename, std::string &sLoadType, int interleave = 1); + // process an info file line + virtual bool ProcessInfo(std::string key, std::string value, addr_t &from, addr_t &to, bool bProcInfo = true, bool bDataBus = false) { return false; } + + // the real disassembler activities + protected: + // parse data area for labels + virtual addr_t ParseData(addr_t addr, bool bDataBus = false) = 0; + // parse instruction at given memory address for labels + virtual addr_t ParseCode(addr_t addr, bool bDataBus = false) = 0; + // disassemble data area at given memory address + virtual addr_t DisassembleData(addr_t addr, addr_t end, uint32_t flags, std::string &smnemo, std::string &sparm, int maxparmlen, bool bDataBus = false) = 0; + // disassemble instruction at given memory address + virtual addr_t DisassembleCode(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false) = 0; + // globally accessible dispatchers for the above + public: + // Initialize parsing + virtual bool InitParse(bool bDataBus = false) + { + if (!bDataBus && load != NO_ADDRESS && bLoadLabel) + AddLabel(load, Code, "", true); + return true; + } + // Parse memory area for labels + addr_t Parse(addr_t addr, bool bDataBus = false) + { return IsCode(addr, bDataBus) ? ParseCode(addr, bDataBus) : ParseData(addr, bDataBus); } + // Disassemble a line in the memory area + addr_t Disassemble(addr_t addr, std::string &smnemo, std::string &sparm, int maxparmlen, bool bDataBus = false) + { + if (IsCode(addr, bDataBus)) return DisassembleCode(addr, smnemo, sparm, bDataBus); + uint32_t flags = 0; + addr_t end = GetConsecutiveData(addr, flags, maxparmlen, bDataBus); + return DisassembleData(addr, end, flags, smnemo, sparm, maxparmlen, bDataBus); + } + // pass back correct mnemonic and parameters for a label + virtual bool DisassembleLabel(addr_t addr, std::string &smnemo, std::string &sparm, bool bDataBus = false) + { return false; } // no changes in base implementation + // pass back disassembler-specific state changes before/after a disassembly line + struct LineChange + { + std::string smnemo; + std::string sparm; + }; + virtual bool DisassembleChanges(addr_t addr, addr_t prevaddr, addr_t prevsz, bool bAfterLine, std::vector &changes, bool bDataBus = false) + { return changes.size() != 0; } // no additional changes in base implementation + + protected: + static const Endian prgEndian; + // memory[0]: instruction bus, memory[1]: data bus, if separate + MemoryArray memory[2]; + // memattr[0]: instruction bus, memattr[1]: data bus, if separate + MemAttributeHandler *memattr[2]; + // Labels[0]: instruction bus labels, Labels[1]; data bus labels, if separate + AddrTextArray Labels[2]; + // Relatives[0]: instruction bus relatives, Relatives[1]; data bus relatives, if separate + TMemoryArray Relatives[2]; + // Phases[0]: instruction bus phases, Phases[1]; data bus phases, if separate + TMemoryArray Phases[2]; + // begin / end / load (i.e., entry point) address + addr_t begin, end, load, offset; + // flag whether to honor load address + bool bLoadLabel; + // default display format + MemAttribute::Display defaultDisplay; + // disassembler-specific comment start character + std::string commentStart; + // disassembler-specific label delimiter + std::string labelDelim; + // parsing radix (default 10) + int pbase; + + std::vector mnemo; + + // must not be called from constructor! + virtual MemAttributeHandler *CreateAttributeHandler() { return new BasicMemAttributeHandler; } + // + TMemory *FindMem(addr_t addr, bool bDataBus = false) + { return memory[bDataBus].FindMem(addr); } + // fetch byte at a given address + uint8_t *getat(addr_t addr, bool bDataBus = false) + { return memory[bDataBus].getat(addr); } + // fetch multiple bytes with endianness correction + bool getat(addr_t addr, uint8_t *val, addr_t len, bool bDataBus = false) + { return memory[bDataBus].getat(addr, val, len, (GetEndianness() != prgEndian)); } + // write byte at a given address + bool setat(addr_t addr, uint8_t val, bool bDataBus = false) + { return memory[bDataBus].setat(addr, val); } + // write multiple bytes with endianness correction + bool setat(addr_t addr, uint8_t *val, addr_t len, bool bDataBus = false) + { return memory[bDataBus].setat(addr, val, len, (GetEndianness() != prgEndian)); } + + // load opened file (overridable for specific file types) + virtual bool LoadFile(std::string filename, FILE *f, std::string &sLoadType, int interleave = 1); + bool LoadIntelHex(std::string filename, FILE *f, std::string &sLoadType, int interleave = 1); + bool LoadMotorolaHex(std::string filename, FILE *f, std::string &sLoadType, int interleave = 1); + bool LoadBinary(std::string filename, FILE *f, std::string &sLoadType, int interleave = 1); + + // calculate consecutive data range (i.e., same type for all) + addr_t GetConsecutiveData(addr_t addr, uint32_t &flags, int maxparmlen, bool bDataBus = false) + { + addr_t end, maxaddr = bDataBus ? GetHighestDataAddr() : GetHighestCodeAddr(); + /* get flags for current byte */ + flags = GetDisassemblyFlags(addr, bDataBus) & + (~SHMF_BREAK); /* without break flag */ + // safety fuse - process no more than maxparmlen at a time unless it's + // RMB. This may still be too much, but should not be too far off. + if (!(flags & SHMF_RMB) && + addr + (addr_t)maxparmlen > addr && + addr + (addr_t)maxparmlen <= maxaddr) + maxaddr = addr + (addr_t)maxparmlen - 1; + + for (end = addr + 1; /* find end of block */ + end > addr && end <= maxaddr; + end++) + { + uint32_t fEnd = GetDisassemblyFlags(end, bDataBus); + if (fEnd != flags) + break; + } + if (flags & 0xff) /* if not 1-sized, */ + { + int dsz = (int)(flags & 0xff) + 1; + addr_t rest = (end - addr) % dsz; + if (rest) /* don't use incomplete last item */ + end -= rest; + if (end == addr) /* if there's nothing left */ + end = addr + dsz; /* use at least 1 item */ + // NB: defining n-byte fields starting at less than (n-1) bytes + // before the end of the highest memory address will produce garbage, + // but... well... GIGO. Should be caught by info file parser anyway. + } + return end; /* pass back last + 1 */ + } + + public: + // convert a string to an integer number, (dis)assembler-specific + virtual bool String2Number(std::string s, addr_t &value) + { + // Only thing that should always work... + // C-style number strings should be universal + std::string sFmt = s.substr(0, 2); + if (sFmt == "0x") + return (sscanf(s.substr(2).c_str(), "%x", &value) == 1); + // octal (leading 0), however, isn't. + // So interpret any pure number as having the default base. + char *end = NULL; + value = strtoul(s.c_str(), &end, pbase); + return (s.c_str() != end); + } + virtual int String2Range(std::string s, addr_t &from, addr_t &to) + { + from = to = NO_ADDRESS; + std::string::size_type midx = s.find('-'); + if (midx == 0) + { + midx = s.substr(1).find('-'); + if (midx != s.npos) midx++; + } + if (midx != s.npos) + return (int)String2Number(s.substr(0, midx), from) + + (int)String2Number(s.substr(midx + 1), to); + else + return (int)String2Number(s, from); + } + // convert a string to a floating-point number, (dis)assembler-specific + virtual bool String2Double(std::string s, double &value) + { + // Only thing that should always work... + value = 0.; + return (sscanf(s.c_str(), "%lf", &value) == 1); + } + // convert a number to a string + virtual std::string Number2String(addr_t value, int nDigits, addr_t addr, bool bDataBus = false) + { + // Only thing that should always work... + if (pbase == 16) + return sformat("0x%x", value); + else + return sformat("%d", value); + } + virtual std::string SignedNumber2String(int32_t value, int nDigits, addr_t addr, bool bDataBus = false) + { + std::string s; + // specialization for things that have to be signed in any case + if (value < 0) + { + s = "-"; + value = -value; + } + return s + Number2String((addr_t)value, nDigits, addr, bDataBus); + } + virtual std::string Label2String(addr_t value, bool bUseLabel, addr_t addr, bool bDataBus = false); + }; + +addr_t GetHex(FILE *f, int nChars, uint8_t *pchks = NULL); + +#endif // __Disassembler_h_defined__ diff --git a/Label.h b/Label.h new file mode 100644 index 0000000..3f1a65e --- /dev/null +++ b/Label.h @@ -0,0 +1,289 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Label.h : definitions for the Label classes */ +/*****************************************************************************/ + +#ifndef __Label_h_defined__ +#define __Label_h_defined__ + +#include "dasmfw.h" + +/*****************************************************************************/ +/* MemoryType : the various types of memory that may occur in a module */ +/*****************************************************************************/ + +enum MemoryType + { + Untyped = -1, /* unknown type */ + Code, /* Code */ + Data, /* initialized data */ + Const, /* initialized constant data */ + Bss, /* uninitialized data */ + }; + +/*****************************************************************************/ +/* AddrText : a basic Text with address and type */ +/*****************************************************************************/ + +class AddrText + { + public: + AddrText(addr_t addr = 0, MemoryType memType = Code, std::string stext = "") + : addr(addr), memType(memType), stext(stext) + { } + virtual ~AddrText() { } + + bool operator<(const AddrText &other) + { + if (addr != other.addr) + return addr < other.addr; + // allow "Untyped" wildcards + MemoryType imt = (memType == Untyped) ? other.memType : memType; + MemoryType omt = (other.memType == Untyped) ? imt : other.memType; + return imt < omt; + } + bool operator<=(const AddrText &other) + { + if (addr != other.addr) + return addr < other.addr; + // allow "Untyped" wildcards + MemoryType imt = (memType == Untyped) ? other.memType : memType; + MemoryType omt = (other.memType == Untyped) ? imt : other.memType; + return imt <= omt; + } + bool operator==(const AddrText &other) + { + if (addr != other.addr) + return false; + // allow "Untyped" wildcards + MemoryType imt = (memType == Untyped) ? other.memType : memType; + MemoryType omt = (other.memType == Untyped) ? imt : other.memType; + return imt == omt; + } + bool operator!=(const AddrText &other) { return !operator==(other); } + bool operator>=(const AddrText &other) { return !operator<(other); } + bool operator>(const AddrText &other) { return !operator<=(other); } + + // Attributes + public: + // Label Address + addr_t GetAddress() const { return addr; } + void SetAddress(addr_t newAddr = 0) { addr = newAddr; } + // Label Type + MemoryType GetType() { return memType; } + void SetType(MemoryType newType = Untyped) { memType = newType; } + bool IsCode() { return memType == Code; } + bool IsData() { return memType == Data || memType == Const; } + bool IsConst() { return memType == Const; } + bool IsBss() { return memType == Bss; } + void SetCode() { memType = Code; } + void SetData() { memType = Data; } + void SetConst() { memType = Const; } + bool SetBss() { memType = Bss; } + // Label Text + std::string GetText() const { return stext; } + bool SetText(std::string sNewText = "") { stext = sNewText; return true; } + + protected: + addr_t addr; + std::string stext; + MemoryType memType; + + }; + +/*****************************************************************************/ +/* Label : definition of a label */ +/*****************************************************************************/ + +class Label : public AddrText + { + public: + Label(addr_t addr = 0, MemoryType memType = Code, std::string sLabel = "", bool bUsed = false) + : AddrText(addr, memType, sLabel), bUsed(bUsed) + { } + virtual ~Label() { } + bool operator<(const Label &other) + { return AddrText::operator<((const AddrText &)other); } + bool operator<=(const Label &other) + { return AddrText::operator<=((const AddrText &)other); } + bool operator==(const Label &other) + { return AddrText::operator==((const AddrText &)other); } + bool operator!=(const Label &other) { return !operator==(other); } + bool operator>=(const Label &other) { return !operator<(other); } + bool operator>(const Label &other) { return !operator<=(other); } + + + // Attributes + public: + // Flag whether it is used + bool IsUsed() { return bUsed; } + bool SetUsed(bool bSet = true) { bUsed = bSet; return bSet; } + + protected: + bool bUsed; + + }; + + +/*****************************************************************************/ +/* AddrTextArray : an array of texts with address and type */ +/*****************************************************************************/ + +class AddrTextArray : public std::vector +{ + public: + AddrTextArray(bool bMultipleDefs = false) + : bMultipleDefs(bMultipleDefs) { } + virtual ~AddrTextArray(void) + { clear(); } + + void SetMultipleDefs(bool bOn = true) { bMultipleDefs = bOn; } + bool HasMultipleDefs() { return bMultipleDefs; } + + public: + void clear() + { + for (const_iterator cit = begin(); + cit != end(); + cit++) + { + AddrText *p = *cit; + delete p; + } + std::vector::clear(); + } + // binary search in sorted array + iterator find(const AddrText &l) + { + int lo, hi = size() - 1, mid; + // little optimization if definitely outside range + if (empty() || *at(0) > l || *at(hi) < l) + return end(); + lo = 0; + while (lo <= hi) + { + mid = (hi + lo) / 2; + if (*at(mid) < l) + lo = mid + 1; + else if (*at(mid) > l) + hi = mid - 1; + else + { + if (bMultipleDefs) + { + // return 1st match for multiple definitions + while (mid > 0 && *at(mid - 1) == l) + mid--; + } + return begin() + mid; + } + } + return end(); + } + // convenience - find code and/or data labels + iterator find(addr_t addr, MemoryType memType = Untyped) + { return find(AddrText(addr, memType)); } + // insert into sorted array of labels + iterator insert(AddrText *pText, bool bAfter = true) + { + iterator it; + // if multiple definitions not allowed, replace old one + if (!bMultipleDefs) + { + it = find(*pText); + if (it != end()) + { + if (pText->GetType() == Untyped) + pText->SetType((*it)->GetType()); + if (pText->GetText().empty()) + pText->SetText((*it)->GetText()); + delete *it; + *it = pText; + return it; + } + } + + int lo, max = size() - 1, hi = max, mid; + if (empty() || *pText < *at(0)) + it = begin(); + else if (*pText > *at(hi)) + it = end(); + else + { + // binary search for insert pos + lo = 0; + it = end(); + while (lo <= hi) + { + mid = (hi + lo) / 2; + if (*at(mid) < *pText) + lo = mid + 1; + else if (*at(mid) > *pText) + hi = mid - 1; + else + { + if (bMultipleDefs) + { + // we found an existing label for this address, + // so we /might/ check the label name to assure + // alphanumerically sorted labelling. + // For now, simply insert as last one (order by sequence). + do + { + if (bAfter) + mid++; + else + mid--; + } while (mid > 0 && mid <= max && *at(mid) == *pText); + } + break; + } + } + if (mid <= max && *at(mid) < *pText) + mid++; + it = (mid > max) ? end() : begin() + mid; + } + return std::vector::insert(it, pText); + } + // erase an element + iterator erase(iterator _Where) + { + AddrText *p = *_Where; + delete p; + return std::vector::erase(_Where); + } + iterator erase(iterator _First, iterator _Last) + { + for (const_iterator cit = _First; + cit != _Last; + cit++) + { + AddrText *p = *cit; + delete p; + } + return std::vector::erase(_First, _Last); + } + + + protected: + bool bMultipleDefs; // flag whether multiple definitions possible +}; + +#endif // __Label_h_defined__ diff --git a/Memory.h b/Memory.h new file mode 100644 index 0000000..4c4e60b --- /dev/null +++ b/Memory.h @@ -0,0 +1,317 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* Memory.h : definition for the memory classes */ +/*****************************************************************************/ + +#ifndef __Memory_h_defined__ +#define __Memory_h_defined__ + +#include "dasmfw.h" + +#include "Label.h" + +/* +Memory contents have some kinds of attributes: + +a) the memory type (Code, Data, Const, BSS) +b) flag whether used or unused +c) if not code, the cell size (1, 2, 4, 8, 10, 16, 32, ...) +d) if not code, the cell type (signed int, unsigned int, float) +e) if not code (or data reference / constant in code), + the display format (binary, character, octal, decimal, hex) +*/ + +/*****************************************************************************/ +/* TMemory : template for a vector with a start address */ +/*****************************************************************************/ + +template class TMemory : public std::vector + { + public: + TMemory(addr_t addrStart = 0, addr_t memSize = 0, TType newType = (TType)0) + : memType(newType) + { + label.SetAddress(addrStart); + if (memSize) + resize(memSize); + } + TMemory(TMemory const &org) + { DoCopy(org); } + TMemory &operator=(TMemory const &org) + { return DoCopy(org); } + + // Getters / Setters + void SetStart(addr_t addrStart = 0) { label.SetAddress(addrStart); } + addr_t GetStart() const { return label.GetAddress(); } + addr_t GetEnd() const { return GetStart() + size() - 1; } + std::string GetLabel() { return label.GetText(); } + bool SetLabel(std::string sNewText = "") { return label.SetText(sNewText); } + TType GetType() { return memType; } + void SetType(TType newType) { memType = newType; } + bool TypeMatches(TType chkType) { return memType == chkType; } + + // std::vector specializations + const_reference at(size_type _Pos) const { return std::vector::at(_Pos - GetStart()); } + reference at(size_type _Pos) { return std::vector::at(_Pos - GetStart()); } + const_reference operator[](size_type _Pos) const { return at(_Pos); } + reference operator[](size_type _Pos) { return at(_Pos); } + + protected: + Label label; + TType memType; + + TMemory &DoCopy(TMemory const &org) + { + label = org.label; + memType = org.memType; + assign(org.begin(), org.end()); + return *this; + } + }; + + +/*****************************************************************************/ +/* TMemoryArray : template for an array of disjunct vectors with start addr. */ +/*****************************************************************************/ + +template + class TMemoryArray : public std::vector> + { + public: + bool AddMemory(addr_t addrStart = 0, addr_t memSize = 0, TType memType = (TType)0, T *contents = NULL) + { + std::vector>::iterator i; + if (memSize) + { + addr_t addrEnd = addrStart + memSize - 1; + // append to existing array, if possible + for (i = begin(); i != end(); i++) + { + if (i->TypeMatches(memType)) + { + addr_t curStart = i->GetStart(); + addr_t curEnd = i->GetEnd(); + addr_t curSize = i->size(); + + // adjacent or overlapping existing memory block + if (addrStart <= curEnd + 1 && addrEnd + 1 >= curStart) + { + addr_t newStart = (curStart < addrStart) ? curStart : addrStart; + addr_t newEnd = (curEnd < addrEnd) ? addrEnd : curEnd; + addr_t newSize = newEnd - newStart + 1; + i->resize(newSize); + // if resized overlaps the next one, swallow next one + while (i + 1 != end() && + newEnd + 1 >= (i + 1)->GetStart()) + { + addr_t nextStart = (i + 1)->GetStart(); + addr_t nextEnd = (i + 1)->GetEnd(); + if (nextEnd > newEnd) + { + newEnd = nextEnd; + newSize = newEnd - newStart + 1; + i->resize(newSize); + for (addr_t j = nextStart; j <= nextEnd; j++) + i->at(j) = (i + 1)->at(j); + erase(i + 1); + } + } + // if inserted before current start, some shuffling is needed + if (newStart != curStart) + { + i->SetStart(newStart); + addr_t diff = curStart - newStart; + for (addr_t j = curSize; j > 0; j--) + i->at(newStart + j - 1 + diff) = i->at(newStart + j - 1); + } + if (contents) + { + for (addr_t j = 0; j < memSize; j++) + i->at(addrStart + j) = contents[j]; + } + return true; + } + } + } + } + // obviously not adjacent to another area + // do a simple insertion sort - shouldn't be too many areas + for (i = begin(); i != end(); i++) + if (addrStart < i->GetStart()) + break; + TMemory &t = + *insert(i, + TMemory(addrStart, 0, memType)); + if (memSize) + t.resize(memSize); + // done this way to avoid creating a potentially large temporary object + if (contents && memSize) + { + for (addr_t j = 0; j < memSize; j++) + t.at(addrStart + j) = contents[j]; + } + return true; + } + // find memory area index for a given address + addr_t GetMemIndex(addr_t addr) + { + for (TMemoryArray::size_type i = 0; i < size(); i++) + { + TMemory &mem = at(i); + if (mem.GetStart() <= addr && (addr_t)(mem.GetStart() + mem.size()) > addr) + return i; + } + return NO_ADDRESS; + } + TMemory *FindMem(addr_t addr) + { + addr_t idx = GetMemIndex(addr); + if (idx != NO_ADDRESS) + return &at(idx); + return NULL; + } + // get item at a given address + T *getat(addr_t addr) + { + TMemory *pmem = FindMem(addr); + return (pmem) ? &pmem->at(addr) : NULL; + } + // get multiple bytes with(out) byte reversal + bool getat(addr_t addr, T *val, addr_t len, bool bReverse = false) + { + addr_t i; + if (bReverse) + for (i = 0; i < len; i++) + { + TMemory *pmem = FindMem(addr + i); + if (!pmem) + return false; + val[len - 1 - i] = pmem->at(addr + i); + } + else + { + for (i = 0; i < len; i++) + { + TMemory *pmem = FindMem(addr + i); + if (!pmem) + return false; + val[i] = pmem->at(addr + i); + } + } + return true; + } + // write item at a given address + bool setat(addr_t addr, T val) + { + TMemory *pmem = FindMem(addr); + if (!pmem) return false; + pmem->at(addr) = val; + return true; + } + // write multiple bytes with(out) byte reversal + bool setat(addr_t addr, T *val, addr_t len, bool bReverse = false) + { + addr_t i; + if (bReverse) + { + for (i = 0; i < len; i++) + if (!setat(addr + i, val[len - 1 - i])) + return false; + } + else + { + for (i = 0; i < len; i++) + if (!setat(addr + i, val[i])) + return false; + } + return true; + } + }; + + +/*****************************************************************************/ +/* MemAttribute : basic description of a memory cell's attributes */ +/*****************************************************************************/ + +struct MemAttribute + { + unsigned cellSize: 8; /* cell size 1..256 (i.e., +1) */ + unsigned memType: 3; /* MemoryType */ + unsigned cellType: 3; /* CellType */ + unsigned display: 3; /* CellDisplay */ + unsigned used: 1; /* used (or not) */ + unsigned breakBefore: 1; /* line break in disassembly */ + + enum Type + { + CellUntyped = -1, + SignedInt, + UnsignedInt, + Float + }; + enum Display + { + CellUndisplayable = -1, + Binary, + Char, + Octal, + Decimal, + Hex + }; + + MemAttribute + ( + MemoryType memType = Code, + int cellSize = 1, + bool used = true, + Type cellType = UnsignedInt, + Display display = Hex, + bool breakBefore = false + ) + : memType(memType), used(used), cellSize(cellSize - 1), + cellType(cellType), display(display), breakBefore(breakBefore) + { } + + // MemAttribute Getters / Setters + MemoryType GetMemType() { return (MemoryType)memType; } + void SetMemType(MemoryType newType = Code) { memType = (unsigned)newType; } + bool IsUsed() { return !!used; } + void SetUsed(bool bUsed = true) { used = !!bUsed; } + Type GetCellType() { return (Type)cellType; } + void SetCellType(Type newType) { cellType = (unsigned)newType; } + int GetSize() { return cellSize + 1; } + void SetSize(int newSize = 1) { cellSize = (unsigned)(newSize - 1); } + Display GetDisplay() { return (Display)display; } + void SetDisplay(Display newDisp = Hex) { display = (unsigned)newDisp; } + bool GetBreakBefore() { return !!breakBefore; } + void SetBreakBefore(bool bOn = true) { breakBefore = !!bOn; } + }; + +/*****************************************************************************/ +/* MemoryArray : an array of memory areas */ +/*****************************************************************************/ + +class MemoryArray : public TMemoryArray + { + // currently, no specialization needed + }; + + +#endif // __Memory_h_defined__ diff --git a/backport_stdint.h b/backport_stdint.h new file mode 100644 index 0000000..a6ab56b --- /dev/null +++ b/backport_stdint.h @@ -0,0 +1,209 @@ +/*****************************************************************************/ +/* backport_stdint.h : backport of later versions' for VS2008 */ +/*****************************************************************************/ +/* Slightly modified so that it conforms to VstGUI4's definitions in + vstguibase.h and VS<2010's wchar.h */ + +/* stdint.h standard header */ +#pragma once +#ifndef _STDINT +#define _STDINT +#ifndef RC_INVOKED +#include + +/* NB: assumes + byte has 8 bits + long is 32 bits + pointer can convert to and from long long + long long is longest type + */ + +_C_STD_BEGIN + /* TYPE DEFINITIONS */ +//typedef signed char int8_t; +typedef char int8_t; +typedef short int16_t; +//typedef int int32_t; +typedef long int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +// typedef unsigned int uint32_t; +typedef unsigned long uint32_t; + +typedef signed char int_least8_t; +typedef short int_least16_t; +typedef int int_least32_t; + +typedef unsigned char uint_least8_t; +typedef unsigned short uint_least16_t; +typedef unsigned int uint_least32_t; + +typedef char int_fast8_t; +typedef int int_fast16_t; +typedef int int_fast32_t; + +typedef unsigned char uint_fast8_t; +typedef unsigned int uint_fast16_t; +typedef unsigned int uint_fast32_t; + +#ifndef _INTPTR_T_DEFINED + #define _INTPTR_T_DEFINED + #ifdef _WIN64 +typedef __int64 intptr_t; + #else /* _WIN64 */ +typedef _W64 int intptr_t; + #endif /* _WIN64 */ +#endif /* _INTPTR_T_DEFINED */ + +#ifndef _UINTPTR_T_DEFINED + #define _UINTPTR_T_DEFINED + #ifdef _WIN64 +typedef unsigned __int64 uintptr_t; + #else /* _WIN64 */ +typedef _W64 unsigned int uintptr_t; + #endif /* _WIN64 */ +#endif /* _UINTPTR_T_DEFINED */ + +typedef _Longlong int64_t; +typedef _ULonglong uint64_t; + +typedef _Longlong int_least64_t; +typedef _ULonglong uint_least64_t; + +typedef _Longlong int_fast64_t; +typedef _ULonglong uint_fast64_t; + +typedef _Longlong intmax_t; +typedef _ULonglong uintmax_t; + + /* LIMIT MACROS */ +#define INT8_MIN (-0x7f - _C2) +#define INT16_MIN (-0x7fff - _C2) +#define INT32_MIN (-0x7fffffff - _C2) + +#define INT8_MAX 0x7f +#define INT16_MAX 0x7fff +#define INT32_MAX 0x7fffffff +#define UINT8_MAX 0xff +#define UINT16_MAX 0xffff +#define UINT32_MAX 0xffffffff + +#define INT_LEAST8_MIN (-0x7f - _C2) +#define INT_LEAST16_MIN (-0x7fff - _C2) +#define INT_LEAST32_MIN (-0x7fffffff - _C2) + +#define INT_LEAST8_MAX 0x7f +#define INT_LEAST16_MAX 0x7fff +#define INT_LEAST32_MAX 0x7fffffff +#define UINT_LEAST8_MAX 0xff +#define UINT_LEAST16_MAX 0xffff +#define UINT_LEAST32_MAX 0xffffffff + +#define INT_FAST8_MIN (-0x7f - _C2) +#define INT_FAST16_MIN (-0x7fff - _C2) +#define INT_FAST32_MIN (-0x7fffffff - _C2) + +#define INT_FAST8_MAX 0x7f +#define INT_FAST16_MAX 0x7fff +#define INT_FAST32_MAX 0x7fffffff +#define UINT_FAST8_MAX 0xff +#define UINT_FAST16_MAX 0xffff +#define UINT_FAST32_MAX 0xffffffff + + #if _INTPTR == 0 || _INTPTR == 1 +#define INTPTR_MAX 0x7fffffff +#define INTPTR_MIN (-INTPTR_MAX - _C2) +#define UINTPTR_MAX 0xffffffff + + #else /* _INTPTR == 2 */ +#define INTPTR_MIN (-_LLONG_MAX - _C2) +#define INTPTR_MAX _LLONG_MAX +#define UINTPTR_MAX _ULLONG_MAX +#endif /* _INTPTR */ + +#define INT8_C(x) (x) +#define INT16_C(x) (x) +#define INT32_C(x) ((x) + (INT32_MAX - INT32_MAX)) + +#define UINT8_C(x) (x) +#define UINT16_C(x) (x) +#define UINT32_C(x) ((x) + (UINT32_MAX - UINT32_MAX)) + +#ifdef _WIN64 + #define PTRDIFF_MIN INT64_MIN + #define PTRDIFF_MAX INT64_MAX +#else /* _WIN64 */ + #define PTRDIFF_MIN INT32_MIN + #define PTRDIFF_MAX INT32_MAX +#endif /* _WIN64 */ + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#ifndef SIZE_MAX + #ifdef _WIN64 + #define SIZE_MAX UINT64_MAX + #else /* _WIN64 */ + #define SIZE_MAX UINT32_MAX + #endif /* _WIN64 */ +#endif /* SIZE_MAX */ + +//#define WCHAR_MIN 0x0000 +#define WCHAR_MIN 0 +#define WCHAR_MAX 0xffff + +#define WINT_MIN 0x0000 +#define WINT_MAX 0xffff + + #define INT64_MIN (-0x7fffffffffffffff - _C2) + #define INT64_MAX 0x7fffffffffffffff + #define UINT64_MAX 0xffffffffffffffffU + + #define INT_LEAST64_MIN (-0x7fffffffffffffff - _C2) + #define INT_LEAST64_MAX 0x7fffffffffffffff + #define UINT_LEAST64_MAX 0xffffffffffffffffU + + #define INT_FAST64_MIN (-0x7fffffffffffffff - _C2) + #define INT_FAST64_MAX 0x7fffffffffffffff + #define UINT_FAST64_MAX 0xffffffffffffffffU + + #define INTMAX_MIN (-0x7fffffffffffffff - _C2) + #define INTMAX_MAX 0x7fffffffffffffff + #define UINTMAX_MAX 0xffffffffffffffffU + +#define INT64_C(x) ((x) + (INT64_MAX - INT64_MAX)) +#define UINT64_C(x) ((x) + (UINT64_MAX - UINT64_MAX)) +#define INTMAX_C(x) INT64_C(x) +#define UINTMAX_C(x) UINT64_C(x) +_C_STD_END +#endif /* RC_INVOKED */ +#endif /* _STDINT */ + + #if defined(_STD_USING) +using _CSTD int8_t; using _CSTD int16_t; +using _CSTD int32_t; using _CSTD int64_t; + +using _CSTD uint8_t; using _CSTD uint16_t; +using _CSTD uint32_t; using _CSTD uint64_t; + +using _CSTD int_least8_t; using _CSTD int_least16_t; +using _CSTD int_least32_t; using _CSTD int_least64_t; +using _CSTD uint_least8_t; using _CSTD uint_least16_t; +using _CSTD uint_least32_t; using _CSTD uint_least64_t; + +using _CSTD intmax_t; using _CSTD uintmax_t; + +using _CSTD uintptr_t; +using _CSTD intptr_t; + +using _CSTD int_fast8_t; using _CSTD int_fast16_t; +using _CSTD int_fast32_t; using _CSTD int_fast64_t; +using _CSTD uint_fast8_t; using _CSTD uint_fast16_t; +using _CSTD uint_fast32_t; using _CSTD uint_fast64_t; + #endif /* defined(_STD_USING) */ + +/* + * Copyright (c) 1992-2009 by P.J. Plauger. ALL RIGHTS RESERVED. + * Consult your license regarding permissions and restrictions. +V5.20:0009 */ diff --git a/dasmfw.cpp b/dasmfw.cpp new file mode 100644 index 0000000..4e42c99 --- /dev/null +++ b/dasmfw.cpp @@ -0,0 +1,1907 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + + +/*****************************************************************************/ +/* dasmfw.cpp : main program for the DisASseMbler FrameWork */ +/*****************************************************************************/ + +#include "dasmfw.h" +#include "Disassembler.h" +#include "Label.h" +#include "Memory.h" + +/*****************************************************************************/ +/* Global Data */ +/*****************************************************************************/ + +static struct DisassemblerCreators /* structure for dasm creators: */ + { + std::string name; /* code name of the disassembler */ + Disassembler *(*Factory)(); /* factory to create it */ + } *Disassemblers = NULL; +static int nRegDisassemblers = 0; /* # registered disassemblers */ +static int nAllocDisassemblers = 0; /* # allocated disassembler structs */ + +/*****************************************************************************/ +/* RegisterDisassembler : registers a processor handler */ +/*****************************************************************************/ + +bool RegisterDisassembler(std::string name, Disassembler *(*CreateDisassembler)()) +{ +if (nRegDisassemblers + 1 > nAllocDisassemblers) + { + DisassemblerCreators *pNew; + try + { + pNew = new DisassemblerCreators[nRegDisassemblers + 10]; + if (!pNew) // deal with very old style allocator + return false; + } + catch(...) + { + return false; + } + for (int i = 0; i < nRegDisassemblers; i++) + { + pNew[i].name = Disassemblers[i].name; + pNew[i].Factory = Disassemblers[i].Factory; + } + if (Disassemblers) delete[] Disassemblers; + Disassemblers = pNew; + } + +// simple insertion sort will do +for (int i = 0; i < nRegDisassemblers; i++) + { + if (Disassemblers[i].name > name) + { + for (int j = ++nRegDisassemblers; j > i; j--) + { + Disassemblers[j].name = Disassemblers[j - 1].name; + Disassemblers[j].Factory = Disassemblers[j - 1].Factory; + } + Disassemblers[i].name = name; + Disassemblers[i].Factory = CreateDisassembler; + return true; + } + } +Disassemblers[nRegDisassemblers].name = name; +Disassemblers[nRegDisassemblers++].Factory = CreateDisassembler; +return true; +} + +/*****************************************************************************/ +/* CreateDisassembler : creates a disassembler with a given code name */ +/*****************************************************************************/ + +Disassembler *CreateDisassembler(std::string name, int *pidx = NULL) +{ +for (int da = 0; da < nRegDisassemblers; da++) + if (Disassemblers[da].name == name) + { + if (pidx) *pidx = da; + return Disassemblers[da].Factory(); + } +return NULL; +} + +/*****************************************************************************/ +/* ListDisassemblers : lists out all known disassemblers */ +/*****************************************************************************/ + +static void ListDisassemblers() +{ +printf("\nRegistered disassemblers:\n" + "%-8s %-16s %s\n" + "--------------------------------------------------------------\n", + "Code", "Instruction Set", "Attributes"); +for (int da = 0; da < nRegDisassemblers; da++) + { + Disassembler *pDasm = Disassemblers[da].Factory(); + printf("%-8s %-16s (%d/%d bits data/code, %s-endian", + Disassemblers[da].name.c_str(), + pDasm->GetName().c_str(), + pDasm->GetDataBits(), + pDasm->GetCodeBits(), + pDasm->GetEndianness() == Disassembler::BigEndian ? "big" : "little"); + if (pDasm->GetArchitecture() == Disassembler::Harvard) + printf(", separate data bus"); + printf(")\n"); + delete pDasm; + } +} + +/*****************************************************************************/ +/* sformat : sprintf for std::string */ +/*****************************************************************************/ + +std::string sformat(const std::string fmt_str, ...) +{ +int final_n, n = ((int)fmt_str.size()) * 2; +std::vector formatted; +va_list ap; +while (1) + { + formatted.resize(n); + va_start(ap, fmt_str); + final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap); + va_end(ap); + if (final_n < 0 || final_n >= n) + n += abs(final_n - n + 1); + else + break; + } +return std::string(&formatted[0]); +} + +/*****************************************************************************/ +/* lowercase : create lowercase copy of a string */ +/*****************************************************************************/ + +std::string lowercase(std::string s) +{ +std::string sout; +// primitive ASCII implementation +for (std::string::size_type i = 0; i < s.size(); i++) + sout += tolower(s[i]); +return sout; +} + +/*****************************************************************************/ +/* uppercase : create uppercase copy of a string */ +/*****************************************************************************/ + +std::string uppercase(std::string s) +{ +std::string sout; +// primitive ASCII implementation +for (std::string::size_type i = 0; i < s.size(); i++) + sout += toupper(s[i]); +return sout; +} + +/*****************************************************************************/ +/* trim : remove leading and trailing blanks from string */ +/*****************************************************************************/ + +std::string trim(std::string s) +{ +if (s.empty()) return s; +std::string::size_type from = s.find_first_not_of(" "); +if (from == s.npos) + return ""; +return s.substr(from, s.find_last_not_of(" ") - from + 1); +} + +/*****************************************************************************/ +/* main : main program function */ +/*****************************************************************************/ + +int main(int argc, char* argv[]) +{ +Application app(argc, argv); +return app.Run(); +} + + + +/*===========================================================================*/ +/* Application class members */ +/*===========================================================================*/ + +/*****************************************************************************/ +/* Application : constructor */ +/*****************************************************************************/ + +Application::Application(int argc, char* argv[]) + : argc(argc), argv(argv) + +{ +pDasm = NULL; /* selected disassembler */ +iDasm = -1; /* index of selected disassembler */ +bInfoBus = false; /* false = code, true = data */ +showHex = true; /* flag for hex data display */ +showAddr = true; /* flag for address display */ +#if RB_VARIANT +showAsc = false; /* flag for ASCII content display */ +#else +showAsc = true; /* flag for ASCII content display */ +#endif +out = stdout; +comments[0][0].SetMultipleDefs(); /* allow multi-line comments / lines */ +comments[0][1].SetMultipleDefs(); +comments[1][0].SetMultipleDefs(); +comments[1][1].SetMultipleDefs(); +lcomments[0].SetMultipleDefs(); +lcomments[1].SetMultipleDefs(); + +// pre-load matching disassembler, if possible +sDasmName = argv[0]; +std::string::size_type idx = sDasmName.find_last_of("\\/"); +if (idx != sDasmName.npos) + sDasmName = sDasmName.substr(idx + 1); +idx = sDasmName.rfind('.'); +if (idx != sDasmName.npos) + sDasmName = sDasmName.substr(0, idx); +// if the name is "dasm"+code, use this disassembler +if (lowercase(sDasmName.substr(0, 4)) == "dasm") + pDasm = CreateDisassembler(sDasmName.substr(4), &iDasm); + +printf("%s: %s\n", sDasmName.c_str(), "Disassembler Framework V" DASMFW_VERSION); +} + +/*****************************************************************************/ +/* ~Application : destructor */ +/*****************************************************************************/ + +Application::~Application() +{ +} + +/*****************************************************************************/ +/* Run : the application's main functionality */ +/*****************************************************************************/ + +int Application::Run() +{ +if (argc < 2) /* if no arguments given, give help */ + return Help(); /* and exit */ + +std::string defnfo[2]; /* global / user default info files */ +#ifdef _MSC_VER +// Microsoft C - guaranteed Windows environment +char const *pHomePath = getenv("USERPROFILE"); +defnfo[0] = pHomePath ? + std::string(pHomePath) + "\\.dasmfw\\" + sDasmName + ".nfo" : + ""; +#else +char const *pHomePath = getenv("HOME"); +defnfo[0] = pHomePath ? + std::string(pHomePath) + "/.dasmfw/" + sDasmName + ".nfo" : + ""; +#endif +defnfo[1] = sDasmName + ".nfo"; + +int i; + /* first, just search for "dasm" */ +for (i = 0; i < _countof(defnfo); i++) + if (!defnfo[i].empty()) + ParseOption("info", defnfo[i], true, false); +ParseOptions(argc, argv, true); +if (!pDasm) + return Help(); + /* then parse all other options */ +ParseOptions(argc, argv, false); + +int nInterleave = 1; +for (i = 0; /* load file(s) given on commandline */ + i < (int)saFNames.size(); /* and parsed from info files */ + i++) + { /* and load-relevant option settings */ + if (saFNames[i].substr(0, 7) == "-begin:") + ParseOption("begin", saFNames[i].substr(7)); + else if (saFNames[i].substr(0, 5) == "-end:") + ParseOption("end", saFNames[i].substr(5)); + else if (saFNames[i].substr(0, 8) == "-offset:") + ParseOption("offset", saFNames[i].substr(8)); + else if (saFNames[i].substr(0, 12) == "-interleave:") + nInterleave = atoi(saFNames[i].substr(12).c_str()); + else + { + std::string sLoadType; + bool bOK = pDasm->Load(saFNames[i], sLoadType, nInterleave); + saFNames[i] = sformat("%soaded: %s file \"%s\"", + bOK ? "L" : "NOT l", + sLoadType.c_str(), + saFNames[i].c_str()); + if (nInterleave != 1) + saFNames[i] += sformat(" (interleave=%d)", nInterleave); + printf("%s\n", saFNames[i].c_str()); + } + } + /* then process all info files */ +for (i = 0; i < _countof(defnfo); i++) + if (!defnfo[i].empty()) + { + bool bOK = LoadInfo(defnfo[i]); + if (bOK) + printf("Loaded: Info file \"%s\"\n", + defnfo[i].c_str()); + } +for (i = 0; + i < (int)saINames.size(); + i++) + { + bool bOK = LoadInfo(saINames[i]); + printf("%soaded: Info file \"%s\"\n", + bOK ? "L" : "NOT l", + saINames[i].c_str()); + } + +// parse labels in 2 passes +if (pDasm->GetMemoryArrayCount(false)) Parse(0, false); +if (pDasm->GetMemoryArrayCount(false)) Parse(0, true); +if (pDasm->GetMemoryArrayCount(true)) Parse(1, false); +if (pDasm->GetMemoryArrayCount(true)) Parse(1, true); +// resolve all XXXXXXXX+/-nnnn labels +ResolveRelativeLabels(false); +ResolveRelativeLabels(true); + +// set up often used texts and flags +std::string labelDelim = pDasm->GetOption("ldchar"); +std::string sComDel = pDasm->GetOption("cchar"); +std::string sComBlk = sComDel + " "; +std::string sComHdr(sComDel); +while (sComHdr.size() < 53) + sComHdr += '*'; + +// create output file +out = outname.size() ? fopen(outname.c_str(), "w") : stdout; +if (out == NULL) + out = stdout; +if (out != stdout) + PrintLine(sComDel + + sformat(" %s: Disassembler Framework V" DASMFW_VERSION, + sDasmName.c_str())); +for (i = 0; /* print loaded files */ + i < (int)saFNames.size(); + i++) + if (saFNames[i].substr(0, 1) != "-") + PrintLine(sComDel + " " + saFNames[i]); + +// TEST TEST TEST TEST TEST TEST TEST +// #ifdef _DEBUG +#if 0 +PrintLine(); +PrintLine(sComBlk + "After Parsing:"); +PrintLine(sComBlk + + sformat("Loaded memory areas: begin=%s, end=%s", + pDasm->GetOption("begin").c_str(), + pDasm->GetOption("end").c_str())); +DumpMem(false); +DumpMem(true); +#endif + + +// disassembler-specific initialization +DisassembleChanges(NO_ADDRESS, NO_ADDRESS, 0, false, false); + +AddrTextArray::iterator it; + +for (int bus = 0; bus < 2; bus++) + { + bool bDataBus = !!bus; + if (!pDasm->GetMemoryArrayCount(bDataBus)) + continue; + + // output of labels without data + DisassembleLabels(sComDel, sComHdr, bDataBus); + + addr_t prevaddr = NO_ADDRESS, prevsz = 0; + addr_t addr = pDasm->GetMemoryArray(0, bDataBus).GetStart(); + if (!pDasm->IsCellUsed(addr, bDataBus)) + addr = pDasm->GetNextAddr(addr, bDataBus); + bool bBusHdrOut = false; + while (addr != NO_ADDRESS) + { + if (!bBusHdrOut) + { + PrintLine(); + PrintLine(sComHdr); + PrintLine(sComBlk + + sformat("Program's %s Areas", + (bDataBus) ? "Data Bus Data" : "Code / Data")); + PrintLine(sComHdr); + PrintLine(); + + bBusHdrOut = true; + } + + DisassembleChanges(addr, prevaddr, prevsz, false, bDataBus); + + addr_t sz = DisassembleLine(addr, sComDel, sComHdr, labelDelim, bDataBus); + + DisassembleChanges(addr, prevaddr, prevsz, true, bDataBus); + + prevaddr = addr; + prevsz = sz; + addr = pDasm->GetNextAddr(addr + sz - 1, bDataBus); + } + + // disassembler-specific end of area handling + DisassembleChanges(addr, prevaddr, prevsz, false, bDataBus); + } + +// disassembler-specific closing +DisassembleChanges(NO_ADDRESS, NO_ADDRESS, 0, true, true); + +if (out != stdout) + fclose(out); +if (pDasm) delete pDasm; +return 0; +} + +/*****************************************************************************/ +/* Parse : go through the loaded memory areas and parse all labels */ +/*****************************************************************************/ + +bool Application::Parse(int nPass, bool bDataBus) +{ +if (!nPass && + !pDasm->InitParse(bDataBus)) + return false; + +if (!pDasm->GetMemoryArrayCount(bDataBus)) + return true; + +addr_t prevaddr = NO_ADDRESS; +addr_t addr = pDasm->GetMemoryArray(0, bDataBus).GetStart(); +if (!pDasm->IsCellUsed(addr, bDataBus)) + addr = pDasm->GetNextAddr(addr, bDataBus); + +while (addr != NO_ADDRESS) + { + addr_t sz = pDasm->Parse(addr, bDataBus); + prevaddr = addr; + addr = pDasm->GetNextAddr(addr + sz - 1, bDataBus); + } + +return true; +} + +/*****************************************************************************/ +/* ResolveRelativeLabels : resolve all XXXXXXXX+/-nnnn labels */ +/*****************************************************************************/ + +bool Application::ResolveRelativeLabels(bool bDataBus) +{ +for (int i = pDasm->GetLabelCount(bDataBus) - 1; i >= 0; i--) + { + Label *pLbl = pDasm->LabelAt(i, bDataBus); + if (!pLbl->IsUsed()) + continue; + std::string s = pLbl->GetText(); + std::string::size_type p = s.find_first_of("+-"); + addr_t offs; + if (p != s.npos && + pDasm->String2Number(s.substr(p + 1), offs)) + { + if (s[p] == '+') offs = (addr_t)(-(int32_t)offs); + pLbl->SetUsed(false); + pDasm->AddLabel(pLbl->GetAddress() + offs, pLbl->GetType(), + s.substr(0, p), true, bDataBus); + // this might have caused an insertion, so restart here + i++; + } + } + +return true; +} + +/*****************************************************************************/ +/* DisassembleChanges : parses pre-/post-changes for a disassembly line */ +/*****************************************************************************/ + +bool Application::DisassembleChanges + ( + addr_t addr, + addr_t prevaddr, + addr_t prevsz, + bool bAfterLine, + bool bDataBus + ) +{ +std::vector changes; +bool bRC = pDasm->DisassembleChanges(addr, + prevaddr, prevsz, + bAfterLine, + changes, + bDataBus); + +for (std::vector::size_type i = 0; + i < changes.size(); + i++) + { + PrintLine("", changes[i].smnemo.c_str(), changes[i].sparm.c_str()); + } +return bRC; +} + +/*****************************************************************************/ +/* DisassembleLabels : disassemble all labels without memory area */ +/*****************************************************************************/ + +bool Application::DisassembleLabels + ( + std::string sComDel, + std::string sComHdr, + bool bDataBus + ) +{ +std::string sComBlk(sComDel + " "); +AddrTextArray::iterator it; +Comment *pComment; +bool bULHOut = false; +for (int l = 0; l < pDasm->GetLabelCount(bDataBus); l++) + { + Label *pLbl = pDasm->LabelAt(l, bDataBus); + addr_t laddr = pLbl->GetAddress(); + if (pLbl->IsUsed() && + pDasm->GetMemType(laddr, bDataBus) == Untyped) + { + std::string smnemo, sparm; + if (pDasm->DisassembleLabel(laddr, smnemo, sparm, bDataBus)) + { + // header, if not yet done + if (!bULHOut) + { + PrintLine(); + PrintLine(sComHdr); + PrintLine(sComBlk + "Used Labels"); + PrintLine(sComHdr); + PrintLine(); + bULHOut = true; + } + // comments before line + pComment = GetFirstComment(laddr, it, false, bDataBus); + while (pComment) + { + PrintLine(pComment->GetText()); + pComment = GetNextComment(laddr, it, false, bDataBus); + } + + std::string slabel = pDasm->Label2String(laddr, true, laddr, bDataBus); + + // the line itself + pComment = GetFirstLComment(laddr, it, bDataBus); + std::string scomment = pComment ? pComment->GetText() : ""; + if (scomment.size()) scomment = sComBlk + scomment; + PrintLine(slabel, smnemo, sparm, scomment); + if (pComment) + { + while ((pComment = GetNextLComment(laddr, it, bDataBus)) != NULL) + PrintLine("", "", "", sComBlk + pComment->GetText()); + } + + // comments after line + pComment = GetFirstComment(laddr, it, true, bDataBus); + while (pComment) + { + PrintLine(pComment->GetText()); + pComment = GetNextComment(laddr, it, true, bDataBus); + } + } + } + } + +return true; +} + +/*****************************************************************************/ +/* DisassembleLine : create a line of disassembler output (+comments) */ +/*****************************************************************************/ + +addr_t Application::DisassembleLine + ( + addr_t addr, + std::string sComDel, + std::string sComHdr, + std::string labelDelim, + bool bDataBus + ) +{ +std::string sLabel, sMnemo, sParms, sComBlk(sComDel + " "); +AddrTextArray::iterator it; +Comment *pComment; +bool bWithComments = showHex || showAsc || showAddr; + +// comments before line +pComment = GetFirstComment(addr, it, false, bDataBus); +while (pComment) + { + PrintLine(pComment->GetText()); + pComment = GetNextComment(addr, it, false, bDataBus); + } + +// the line itself +Label *p = pDasm->FindLabel(addr, Untyped, bDataBus); +if (p && p->IsUsed()) + sLabel = pDasm->Label2String(addr, true, addr, bDataBus) + + labelDelim; +pComment = GetFirstLComment(addr, it, bDataBus); +int maxparmlen = (bWithComments || pComment) ? 24 : 52; +addr_t sz = pDasm->Disassemble(addr, sMnemo, sParms, maxparmlen, bDataBus); + +std::string scomment; +if (showAddr) + scomment += sformat("%0*X%s", + pDasm->GetCodeBits() / 4, addr, + (showHex || showAsc) ? ": " : " "); +if ((showHex || showAsc) && !pDasm->IsBss(addr, bDataBus)) + { + std::string sHex, sAsc("\'"); + addr_t i; + for (i = 0; i < sz; i++) + { + uint8_t c = pDasm->GetUByte(addr + i, bDataBus); + sHex += sformat("%02X ", c); + sAsc += (isprint(c)) ? c : '.'; + } + sAsc += '\''; + if (showHex || showAsc) + { + for (; i < 5; i++) + { + if (showHex && showAsc) + sHex += " "; + if (showAsc && pComment) + sAsc += ' '; + } + } + + if (showHex) + scomment += sHex; + if (showAsc) + scomment += sAsc; + } +scomment += pComment ? pComment->GetText() : ""; +if (scomment.size()) scomment = sComBlk + scomment; +PrintLine(sLabel, sMnemo, sParms, scomment); +if (pComment) + { +// following line comments + while ((pComment = GetNextLComment(addr, it, bDataBus)) != NULL) + PrintLine("", "", "", sComBlk + pComment->GetText()); + } + +// comments after line +pComment = GetFirstComment(addr, it, true, bDataBus); +while (pComment) + { + PrintLine(pComment->GetText()); + pComment = GetNextComment(addr, it, true, bDataBus); + } + +return sz; +} + +/*****************************************************************************/ +/* PrintLine : prints a formatted line to the output */ +/*****************************************************************************/ + +bool Application::PrintLine + ( + std::string sLabel, + std::string smnemo, + std::string sparm, + std::string scomment + ) +{ +// for now: VERY primitive output +int nLen = 0; +if (sLabel.size()) + nLen += fprintf(out, "%s ", sLabel.c_str()); +if (smnemo.size()) + { + if (nLen < 8) nLen += fprintf(out, "%*s", 8 - nLen, ""); + nLen += fprintf(out, "%s ", smnemo.c_str()); + } +if (sparm.size()) + { + if (nLen < 16) nLen += fprintf(out, "%*s", 16 - nLen, ""); + nLen += fprintf(out, "%s ", sparm.c_str()); + } +if (scomment.size()) + { + if (nLen < 41) nLen += fprintf(out, "%*s", 41 - nLen, ""); + nLen += fprintf(out, "%s ", scomment.c_str()); + } +nLen += fprintf(out, "\n"); +return nLen > 0; +} + +/*****************************************************************************/ +/* InfoHelp : pass back help for info files */ +/*****************************************************************************/ + +bool Application::InfoHelp() +{ +return true; +} + +/*****************************************************************************/ +/* ParseInfoRange : parses a range definition from an info file */ +/*****************************************************************************/ + +int Application::ParseInfoRange(std::string value, addr_t &from, addr_t &to) +{ +int n = pDasm->String2Range(value, from, to); +if (n < 1) + from = NO_ADDRESS; +if (from != NO_ADDRESS) + { + addr_t *pmap = remaps[bInfoBus].getat(from); + if (pmap) from += *pmap; + if ((bInfoBus && + (from < pDasm->GetLowestDataAddr() || + from > pDasm->GetHighestDataAddr())) || + (!bInfoBus && + (from < pDasm->GetLowestCodeAddr() || + from > pDasm->GetHighestCodeAddr()))) + { + from = NO_ADDRESS; + n = 0; + } + } +if (n < 2) + to = from; +else if (to != NO_ADDRESS) + { + addr_t *pmap = remaps[bInfoBus].getat(to); + if (pmap) to += *pmap; + if ((bInfoBus && + (to < pDasm->GetLowestDataAddr() || + to > pDasm->GetHighestDataAddr())) || + (!bInfoBus && + (to < pDasm->GetLowestCodeAddr() || + to > pDasm->GetHighestCodeAddr()))) + { + to = NO_ADDRESS; + n = 0; + } + } +return n; +} + +/*****************************************************************************/ +/* triminfo : trims an info line's value, cutting at comment character */ +/*****************************************************************************/ + +static std::string triminfo + ( + std::string s, + bool bCutComment = true, + bool bUnescape = true, + bool bDotStart = false + ) +{ +// copied from trim() +if (s.empty()) return s; +std::string::size_type from = s.find_first_not_of(" "); +if (from == s.npos) + return ""; +// up to here. The rest is info-specific +if (bDotStart && s[from] == '.') /* '.' can allow leading blanks */ + from++; /* (redundant f9dasm behavior) */ +std::string sout; +while (from < s.size()) /* copy the rest, with unescaping */ + { + if (bUnescape && s[from] == '\\' && from + 1 < s.size()) + sout += s[++from]; + else if (bCutComment && s[from] == '*') + break; + else + sout += s[from++]; + } + +if (sout.empty()) return sout; +return sout.substr(0, sout.find_last_not_of(" ") + 1); +} + +/*****************************************************************************/ +/* LoadInfo : loads an information file */ +/*****************************************************************************/ + +bool Application::LoadInfo + ( + std::string fileName, + std::vector &loadStack, + bool bProcInfo + ) +{ +if (fileName == "help") /* if help is needed */ + return InfoHelp(); /* give it. */ + +if (!pDasm && bProcInfo) /* no disassembler, no work. */ + return false; + /* inhibit recursion */ +for (std::vector::const_iterator lsi = loadStack.begin(); + lsi != loadStack.end(); + lsi++) + if (*lsi == fileName) + return false; + +enum InfoCmd + { + infoUnknown = -1, /* unknown info command */ + // bus selection + infoBus, /* BUS {code|data} */ + // memory types + infoCode, /* CODE addr[-addr] */ + infoData, /* DATA addr[-addr] */ + infoConstant, /* CONST addr[-addr] */ + infoCVector, /* CVEC[TOR] addr[-addr] */ + infoDVector, /* DVEC[TOR] addr[-addr] */ + infoRMB, /* RMB addr[-addr] */ + infoUnused, /* UNUSED addr[-addr] */ + // cell sizes + infoByte, /* BYTE addr[-addr] */ + infoWord, /* WORD addr[-addr] */ + infoDWord, /* DWORD addr[-addr] */ + // cell display types + infoBinary, /* BINARY addr[-addr] */ + infoChar, /* CHAR addr[-addr] */ + infoOct, /* OCT addr[-addr] */ + infoDec, /* DEC addr[-addr] */ + infoHex, /* HEX addr[-addr] */ + infoFloat, /* FLOAT addr[-addr] */ + infoDouble, /* DOUBLE addr[-addr] */ + infoTenBytes, /* TENBYTES addr[-addr] */ + // break before cell + infoBreak, /* BREAK addr[-addr] */ + infoUnBreak, /* UNBREAK addr[-addr] */ + // relative address + infoRelative, /* RELATIVE addr[-addr] rel */ + infoUnRelative, /* UNRELATIVE addr[-addr] */ + // label handling + infoLabel, /* LABEL addr[-addr] label */ + infoUsedLabel, /* USEDLABEL addr[-addr] [label] */ + infoUnlabel, /* UNLABEL addr[-addr] */ + // phasing support + infoPhase, /* PHASE addr[-addr] [+|-]phase */ + infoUnphase, /* UNPHASE addr[-addr] */ + + // handled outside disassembler engine: + infoInclude, /* INCLUDE infofilename */ + infoOption, /* OPTION name data */ + infoFile, /* FILE filename */ + infoRemap, /* REMAP addr[-addr] offs */ + // comment handling + infoComment, /* COMMENT addr[-addr] comment */ + infoPrepComm, /* PREPCOMM [addr[-addr]] comment */ + infoInsert, /* INSERT addr[-addr] text */ + infoPrepend, /* PREPEND [addr[-addr]] line */ + infoLComment, /* LCOMMENT addr[-addr] [.]lcomment */ + infoPrepLComm, /* PREPLCOMM addr[-addr] [.]lcomment */ + infoUncomment, /* UNCOMMENT addr[-addr] */ + infoUnLComment, /* UNLCOMMENT addr[-addr] */ + // patching support + infoPatch, /* PATCH addr [byte]* */ + infoPatchWord, /* PATCHW addr [word]* */ + infoPatchDWord, /* PATCHDW addr [dword]* */ + infoPatchFloat, /* PATCHF addr [float]* */ + + // end info file processing + infoEnd, /* END (processing this file) */ + }; +static struct /* structure to convert key to type */ + { + const char *name; + InfoCmd cmdType; + } sKey[] = + { + // bus selection + { "BUS", infoBus }, + // memory types + { "CODE", infoCode }, + { "DATA", infoData }, + { "CONSTANT", infoConstant }, + { "CONST", infoConstant }, + { "CVECTOR", infoCVector }, + { "CVEC", infoCVector }, + { "DVECTOR", infoDVector }, + { "DVEC", infoDVector }, + { "RMB", infoRMB }, + { "BSS", infoRMB }, + { "UNUSED", infoUnused }, + // cell sizes + { "BYTE", infoByte }, + { "WORD", infoWord }, + { "DWORD", infoDWord }, + // cell display types + { "BIN", infoBinary }, + { "BINARY", infoBinary }, + { "CHAR", infoChar }, + { "CHARACTER", infoChar }, + { "OCTAL", infoOct }, + { "OCT", infoOct }, + { "DECIMAL", infoDec }, + { "DEC", infoDec }, + { "HEXADECIMAL", infoHex }, + { "SEDECIMAL", infoHex }, + { "HEX", infoHex }, + { "FLOAT", infoFloat }, + { "DOUBLE", infoDouble }, + { "TENBYTES", infoTenBytes }, + // break before cell + { "BREAK", infoBreak }, + { "UNBREAK", infoUnBreak }, + // relative address + { "RELATIVE", infoRelative }, + { "REL", infoRelative }, + { "UNRELATIVE", infoUnRelative }, + { "UNREL", infoUnRelative }, + // label handling + { "LABEL", infoLabel }, + { "USED", infoUsedLabel }, + { "USEDLABEL", infoUsedLabel }, + { "UNLABEL", infoUnlabel }, + // phasing support + { "PHASE", infoPhase }, + { "UNPHASE", infoUnphase }, + + // handled outside disassembler engine: + { "INCLUDE", infoInclude }, + { "OPTION", infoOption }, + { "FILE", infoFile }, + { "REMAP", infoRemap }, + // comment handling + { "COMMENT", infoComment }, + { "COMM", infoComment }, + { "PREPCOMMENT", infoPrepComm }, + { "PREPCOMM", infoPrepComm }, + { "INSERT", infoInsert }, + { "PREPEND", infoPrepend }, + { "LCOMMENT", infoLComment }, + { "LCOMM", infoLComment }, + { "PREPLCOMMENT", infoPrepLComm }, + { "PREPLCOMM", infoPrepLComm }, + { "UNCOMMENT", infoUncomment }, + { "UNCOMM", infoUncomment }, + { "UNLCOMMENT", infoUnLComment }, + { "UNLCOMM", infoUnLComment }, + // patching support + { "PATCH", infoPatch }, + { "PATCHW", infoPatchWord }, + { "PATCHDW", infoPatchDWord }, + { "PATCHF", infoPatchFloat }, + + // end info file processing + { "END", infoEnd }, + }; + + /* that's definitely a text file */ +FILE *fp = fopen(fileName.c_str(), "r"); +if (!fp) + return false; + +int fc; +std::string line; +bool bMod = false, bEnd = false; +do + { + fc = fgetc(fp); + // skip leading whitespace + if ((fc == ' ' || fc == '\t') && !line.size()) + continue; + if (fc == '+' && !line.size()) + { + bMod = true; + continue; + } + if (fc != '\n' && fc != EOF) + { + line += (char)fc; + continue; + } + // newline or end of file encountered + if (line.size() && line[0] != '*') /* if line has contents */ + { + std::string key, value; + std::string::size_type idx = line.find_first_of(" \t"); + if (idx == line.npos) idx = line.size(); + key = uppercase(line.substr(0, idx)); + value = trim(line.substr(idx)); + + InfoCmd cmdType = infoUnknown; + for (int i = 0; i < _countof(sKey); i++) + if (key == sKey[i].name) + { + cmdType = sKey[i].cmdType; + break; + } + + bool bTgtBus = bInfoBus; /* target bus identification */ + idx = value.find_first_of(" \t"); + if (idx != value.npos && + lowercase(value.substr(0, idx)) == "bus") + { + std::string bval(trim(value.substr(idx))); + idx = bval.find_first_of(" \t"); + if (idx != bval.npos) + { + std::string tgtbus = lowercase(bval.substr(0, idx)); + bval = trim(bval.substr(idx)); + if (tgtbus == "code" || tgtbus == "0") + { + bTgtBus = false; + value = bval; + } + else if (tgtbus == "data" || tgtbus == "1") + { + bTgtBus = true; + value = bval; + } + } + } + + if (pDasm) /* let disassembler have a go at it */ + { + addr_t from, to; /* address range has to be first! */ + ParseInfoRange(value, from, to); + if (pDasm->ProcessInfo(key, value, from, to, bProcInfo, bInfoBus)) + cmdType = infoUnknown; + } + + if (!bProcInfo) /* if just loading includes and files*/ + { + if (cmdType != infoInclude && + cmdType != infoOption && + cmdType != infoFile) + cmdType = infoUnknown; /* ignore all unwanted command types */ + } + else /* if processing complete file */ + { + if (cmdType == infoFile) + cmdType = infoUnknown; /* ignore all unwanted command types */ + } + + switch (cmdType) + { + case infoBus : /* BUS {code|data} */ + { + std::string s = lowercase(value); + if (s == "code" || s == "0") + bInfoBus = false; + else if (s == "data" || s == "1") + bInfoBus = true; + } + break; + case infoInclude : /* INCLUDE filename */ + { + char delim1 = ' ', delim2 = '\t'; + std::string fn; + std::string::size_type i = 0; + if (value[i] == '\"' || value[i] == '\'') + { + delim1 = value[i++]; + delim2 = '\0'; + } + for (; i < value.size() && value[i] != delim1 && value[i] != delim2; i++) + fn += value[i]; + loadStack.push_back(fileName); + LoadInfo(fn, loadStack, bProcInfo); + loadStack.pop_back(); + } + break; + case infoFile : /* FILE filename [offset] */ + { + char delim1 = ' ', delim2 = '\t'; + std::string fn; + std::string::size_type i = 0; + if (value[i] == '\"' || value[i] == '\'') + { + delim1 = value[i++]; + delim2 = '\0'; + } + for (; i < value.size() && value[i] != delim1 && value[i] != delim2; i++) + fn += value[i]; + if (i < value.size()) + value = trim(value.substr(i + 1)); + else + value.clear(); + addr_t offs, ign; + ParseInfoRange(value, offs, ign); + if (offs != NO_ADDRESS) + saFNames.push_back(sformat("-offset:0x%x", offs)); + saFNames.push_back(fn); + } + break; + case infoOption : /* OPTION name value */ + { + std::string option; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + option = value.substr(0, idx); + value = trim(value.substr(idx)); + ParseOption(option, value, !bProcInfo); + } + break; + case infoRemap : /* REMAP addr[-addr] offset */ + { + std::string range; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + range = value.substr(0, idx); + value = trim(value.substr(idx)); + addr_t from, to, off; + // allow remapped remaps :-) + if (ParseInfoRange(range, from, to) >= 1 && + pDasm->String2Number(value, off)) + { + remaps[bInfoBus].AddMemory(from, to + 1 - from); + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + *remaps[bInfoBus].getat(scanned) += off; + } + } + break; + // memory types + case infoCode : /* CODE addr[-addr] */ + case infoData : /* DATA addr[-addr] */ + case infoConstant : /* CONST addr[-addr] */ + case infoCVector : /* CVEC[TOR] addr[-addr] */ + case infoDVector : /* DVEC[TOR] addr[-addr] */ + case infoRMB : /* RMB addr[-addr] */ + case infoUnused : /* UNUSED addr[-addr] */ + // cell sizes + case infoByte : /* BYTE addr[-addr] */ + case infoWord : /* WORD addr[-addr] */ + case infoDWord : /* DWORD addr[-addr] */ + // cell display types + case infoBinary : /* BINARY addr[-addr] */ + case infoChar : /* CHAR addr[-addr] */ + case infoOct : /* OCT addr[-addr] */ + case infoDec : /* DEC addr[-addr] */ + case infoHex : /* HEX addr[-addr] */ + // combined size + type + case infoFloat : /* FLOAT addr[-addr] */ + case infoDouble : /* DOUBLE addr[-addr] */ + case infoTenBytes : /* TENBYTES addr[-addr] */ + // break before + case infoBreak : /* BREAK addr[-addr] */ + case infoUnBreak: /* UNBREAK addr[-addr] */ + { + addr_t from, to, tgtaddr; + if (ParseInfoRange(value, from, to) >= 1) + { + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + { + MemoryType ty = pDasm->GetMemType(scanned, bInfoBus); + int sz; + if (ty != Untyped) + { + switch (cmdType) + { + case infoCode : + pDasm->SetMemType(scanned, Code, bInfoBus); + break; + case infoData : + pDasm->SetMemType(scanned, Data, bInfoBus); + break; + case infoConstant : + pDasm->SetMemType(scanned, Const, bInfoBus); + break; + case infoRMB : + pDasm->SetMemType(scanned, Bss, bInfoBus); + break; + case infoUnused : + pDasm->SetMemType(scanned, Untyped, bInfoBus); + pDasm->SetCellUsed(scanned, false, bInfoBus); + case infoByte : + pDasm->SetCellSize(scanned, 1, bInfoBus); + break; + case infoWord : + pDasm->SetCellSize(scanned, 2, bInfoBus); + break; + case infoDWord : + pDasm->SetCellSize(scanned, 4, bInfoBus); + break; + case infoBinary : + pDasm->SetDisplay(scanned, MemAttribute::Binary, bInfoBus); + break; + case infoChar : + pDasm->SetDisplay(scanned, MemAttribute::Char, bInfoBus); + break; + case infoOct : + pDasm->SetDisplay(scanned, MemAttribute::Octal, bInfoBus); + break; + case infoDec : + pDasm->SetDisplay(scanned, MemAttribute::Decimal, bInfoBus); + break; + case infoHex : + pDasm->SetDisplay(scanned, MemAttribute::Hex, bInfoBus); + break; + case infoFloat : + pDasm->SetCellSize(scanned, 4, bInfoBus); + pDasm->SetCellType(scanned, MemAttribute::Float, bInfoBus); + break; + case infoDouble : + pDasm->SetCellSize(scanned, 8, bInfoBus); + pDasm->SetCellType(scanned, MemAttribute::Float, bInfoBus); + break; + case infoTenBytes : + pDasm->SetCellSize(scanned, 10, bInfoBus); + pDasm->SetCellType(scanned, MemAttribute::Float, bInfoBus); + scanned += 9; + break; + case infoBreak : + pDasm->SetBreakBefore(scanned, true, bInfoBus); + break; + case infoUnBreak: + pDasm->SetBreakBefore(scanned, false, bInfoBus); + break; + case infoCVector : + // a code vector defines a table of code pointers + pDasm->SetMemType(scanned, Data, bInfoBus); + sz = pDasm->GetCodePtrSize(); + pDasm->SetCellSize(scanned, sz, bInfoBus); + if (sz == 1) + tgtaddr = pDasm->GetUByte(scanned, bInfoBus); + else if (sz == 2) + tgtaddr = pDasm->GetUWord(scanned, bInfoBus); + else if (sz == 4) + tgtaddr = pDasm->GetUDWord(scanned, bInfoBus); + pDasm->AddLabel(tgtaddr, Code, + sformat("Z%0*Xvia%0*X", + sz*2, tgtaddr, + sz*2, scanned), + true, bTgtBus); + scanned += sz - 1; + break; + case infoDVector : + // a data vector defines a table of data pointers + pDasm->SetMemType(scanned, Data, bInfoBus); + sz = pDasm->GetDataPtrSize(); + pDasm->SetCellSize(scanned, sz, bInfoBus); + if (sz == 1) + tgtaddr = pDasm->GetUByte(scanned, bInfoBus); + else if (sz == 2) + tgtaddr = pDasm->GetUWord(scanned, bInfoBus); + else if (sz == 4) + tgtaddr = pDasm->GetUDWord(scanned, bInfoBus); + pDasm->AddLabel(tgtaddr, Code, + sformat("M%0*Xvia%0*X", + sz*2, tgtaddr, + sz*2, scanned), + true, bTgtBus); + scanned += sz - 1; + break; + } + } + } + } + } + break; + case infoRelative : /* RELATIVE addr[-addr] rel */ + { + std::string range; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + range = value.substr(0, idx); + value = trim(value.substr(idx)); + addr_t from, to, rel; + if (ParseInfoRange(range, from, to) >= 1 && + pDasm->String2Number(value, rel)) + { + pDasm->AddRelative(from, to - from + 1, NULL, bInfoBus); + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + pDasm->SetRelative(scanned, rel, bInfoBus); + } + } + break; + case infoUnRelative : /* UNRELATIVE addr[-addr] */ + { + addr_t from, to; + if (ParseInfoRange(value, from, to) >= 1) + { + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + pDasm->SetRelative(scanned, 0, bInfoBus); + } + } + break; + case infoLabel : /* LABEL addr[-addr] label */ + case infoUsedLabel : /* USEDLABEL addr[-addr] [label] */ + { + addr_t from, to; + std::string range; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + range = value.substr(0, idx); + value = (idx < value.size()) ? triminfo(value.substr(idx), true, false) : ""; + idx = value.find_first_of(" \t"); + if (idx != value.npos) + value = trim(value.substr(0, idx)); + bool bTextOk = (cmdType == infoUsedLabel) || value.size(); + if (ParseInfoRange(range, from, to) >= 1 && bTextOk) + { + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + { + pDasm->AddLabel( + scanned, Untyped, + (scanned == from || + (cmdType == infoUsedLabel && value.empty())) ? + value : + sformat("%s+%d", value.c_str(), scanned - from), + cmdType == infoUsedLabel, + bInfoBus); + } + } + } + break; + case infoUnlabel : /* UNLABEL addr[-addr] */ + { + addr_t from, to; + if (ParseInfoRange(value, from, to) >= 1) + { + for (int i = pDasm->GetLabelCount(bInfoBus) - 1; i >= 0; i--) + { + addr_t laddr = pDasm->LabelAt(i, bInfoBus)->GetAddress(); + if (laddr < from) break; + if (laddr >= from && laddr <= to) + pDasm->RemoveLabelAt(i, bInfoBus); + } + } + } + break; + case infoPhase : /* PHASE addr[-addr] [+|-]phase */ + { + std::string range; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + range = value.substr(0, idx); + value = trim(value.substr(idx)); + char sign = value.size() ? value[0] : 0; + bool bSigned = (sign == '+' || sign == '-'); + addr_t from, to, phase; + if (ParseInfoRange(range, from, to) >= 1 && + pDasm->String2Number(value, phase)) + { + // This might cause garbage if overlapping or disjunct areas of + // different phase are specified. Well, so be it. Don't do it. + // The alternative would be to reallocate the phase area for each + // and every byte. + TMemory *pFrom = pDasm->FindPhase(from, bInfoBus); + TMemory *pTo = pDasm->FindPhase(to, bInfoBus); + if (!pFrom || !pTo) + { + // presumably, it's the same phase as others, so make sure + // to create a unique area + pDasm->AddPhase(from, to - from + 1, NO_ADDRESS, bInfoBus); + pFrom = pDasm->FindPhase(from, bInfoBus); + pFrom->SetType(phase); + } + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + { + TMemory *pArea = pDasm->FindPhase(scanned, bInfoBus); + if (pArea) + { + if (pArea->GetType() == phase) + pDasm->SetPhase(scanned, NO_ADDRESS, bInfoBus); + else + pDasm->SetPhase(scanned, + bSigned ? pArea->GetType() - phase : phase, + bInfoBus); + } + } + } + } + break; + case infoUnphase : /* UNPHASE addr[-addr] */ + { + addr_t from, to; + if (ParseInfoRange(value, from, to) >= 1) + { + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + pDasm->SetPhase(scanned, DEFAULT_ADDRESS, bInfoBus); + } + } + break; + case infoComment : /* COMMENT addr[-addr] comment */ + case infoPrepComm : /* PREPCOMM [addr[-addr]] comment */ + case infoInsert : /* INSERT addr[-addr] text */ + case infoPrepend : /* PREPEND [addr[-addr]] line */ + case infoLComment : /* LCOMMENT addr[-addr] [.]lcomment */ + case infoPrepLComm : /* PREPLCOMM addr[-addr] [.]lcomment */ + { + // special: "AFTER" as 1st string (line comment ignores it) + bool bAfter = false; + bool bPrepend = cmdType == infoPrepComm || + cmdType == infoPrepend || + cmdType == infoPrepLComm; + bool bIsComm = cmdType == infoComment || + cmdType == infoPrepComm; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + std::string after = lowercase(value.substr(0, idx)); + if (after == "after") + { + bAfter = true; + value = (idx < value.size()) ? trim(value.substr(idx)) : ""; + } + addr_t from, to; + std::string range; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + range = value.substr(0, idx); + value = (idx >= value.size()) ? "" : + triminfo(value.substr(idx), true, true, true); + if (bIsComm && value.size()) + value = pDasm->GetOption("cchar") + " " + value; + if (ParseInfoRange(range, from, to) >= 1) + { + for (addr_t scanned = from; + scanned >= from && scanned <= to; + scanned++) + { + /* make sure comment breaks output */ + pDasm->SetBreakBefore(scanned, true, bInfoBus); + switch (cmdType) + { + case infoComment : /* COMMENT addr[-addr] comment */ + case infoPrepComm : /* PREPCOMM [addr[-addr]] comment */ + case infoInsert : /* INSERT addr[-addr] text */ + case infoPrepend : /* PREPEND [addr[-addr]] line */ + AddComment(scanned, bAfter, value, bPrepend, bInfoBus); + break; + case infoLComment : /* LCOMMENT addr[-addr] [.]lcomment */ + case infoPrepLComm : /* PREPLCOMM addr[-addr] [.]lcomment */ + AddLComment(scanned, value, bPrepend, bInfoBus); + break; + } + } + } + } + break; + case infoUncomment : /* UNCOMMENT [BEFORE] addr[-addr] */ + case infoUnLComment : /* UNLCOMMENT addr[-addr] */ + { + // special: "AFTER" as 1st string (line comment ignores it) + bool bAfter = false; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + std::string after = lowercase(value.substr(0, idx)); + if (after == "after") + { + bAfter = true; + value = (idx < value.size()) ? trim(value.substr(idx)) : ""; + } + addr_t from, to; + if (ParseInfoRange(value, from, to) >= 1) + { + int i; + if (cmdType == infoUncomment) + { + for (i = (int)comments[bInfoBus][bAfter].size() - 1; i >= 0; i--) + { + AddrText *c = comments[bInfoBus][bAfter].at(i); + addr_t caddr = c->GetAddress(); + if (caddr < from) break; + if (caddr >= from && caddr <= to) + comments[bInfoBus][bAfter].erase(comments[bInfoBus][bAfter].begin() + i); + } + } + else + { + for (i = (int)lcomments[bInfoBus].size() - 1; i >= 0; i--) + { + AddrText *c = lcomments[bInfoBus].at(i); + addr_t caddr = c->GetAddress(); + if (caddr < from) break; + if (caddr >= from && caddr <= to) + lcomments[bInfoBus].erase(lcomments[bInfoBus].begin() + i); + } + } + } + } + break; + case infoPatch : /* PATCH addr [byte]* */ + case infoPatchWord : /* PATCHW addr [word]* */ + case infoPatchDWord : /* PATCHDW addr [dword]* */ + case infoPatchFloat : /* PATCHF addr [float]* */ + { + addr_t from, to; + std::string range; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + range = value.substr(0, idx); + value = (idx >= value.size()) ? "" : + triminfo(value.substr(idx), true, false); + if (ParseInfoRange(range, from, to) >= 1) + { + // "to" is not interesting here. + do + { + if (from < pDasm->GetLowestCodeAddr() || + from > pDasm->GetHighestCodeAddr()) + break; + idx = value.find_first_of(" \t"); + if (idx == value.npos) idx = value.size(); + std::string item = value.substr(0, idx); + value = (idx >= value.size()) ? "" : trim(value.substr(idx)); + to = 0; + switch (cmdType) + { + case infoPatch : /* PATCH addr [byte]* */ + if (sscanf(item.c_str(), "%x", &to) == 1) + { + if (pDasm->GetMemIndex(from, bInfoBus) == NO_ADDRESS) + pDasm->AddMemory(from, 1, Code, NULL, bInfoBus); + pDasm->SetUByte(from++, (uint8_t)to, bInfoBus); + } + else + from = NO_ADDRESS; + break; + case infoPatchWord : /* PATCHW addr [word]* */ + if (sscanf(item.c_str(), "%x", &to) == 1) + { + if (pDasm->GetMemIndex(from, bInfoBus) == NO_ADDRESS) + pDasm->AddMemory(from, 2, Data, NULL, bInfoBus); + pDasm->SetUWord(from, (uint16_t)to, bInfoBus); + from += 2; + } + else + from = NO_ADDRESS; + break; + case infoPatchDWord : /* PATCHDW addr [dword]* */ + if (sscanf(item.c_str(), "%x", &to) == 1) + { + if (pDasm->GetMemIndex(from, bInfoBus) == NO_ADDRESS) + pDasm->AddMemory(from, 4, Data, NULL, bInfoBus); + pDasm->SetUDWord(from, (uint32_t)to, bInfoBus); + from += 4; + } + else + from = NO_ADDRESS; + break; + case infoPatchFloat : /* PATCHF addr [float]* */ + { + double d; + if (sscanf(item.c_str(), "%lf", &d) == 1) + { + int sz; + if (pDasm->GetMemIndex(from, bInfoBus) == NO_ADDRESS) + { + pDasm->AddMemory(from, 4, Data, NULL, bInfoBus); + sz = 4; + } + else + sz = pDasm->GetCellSize(from, bInfoBus); + if (sz == 4) + pDasm->SetFloat(from, (float)d, bInfoBus); + else if (sz == 8) + pDasm->SetDouble(from, d, bInfoBus); + // Tenbytes ... no, sorry. Not yet. Maybe never. + else + from = NO_ADDRESS; + } + else + from = NO_ADDRESS; + } + break; + } + + } while (value.size() && from != NO_ADDRESS); + } + } + break; + case infoEnd : + bEnd = true; + break; + } + } + line.clear(); + bMod = false; + } while (fc != EOF && !bEnd); + +fclose(fp); +return true; +} + +/*****************************************************************************/ +/* ParseOption : parses an option and associated value */ +/*****************************************************************************/ + +int Application::ParseOption + ( + std::string option, /* option name */ + std::string value, /* new option value */ + bool bSetDasm, /* flag whether set disassembler */ + bool bProcInfo /* flag whether to fully process info*/ + ) +{ +std::string lvalue(lowercase(value)); +int bnvalue = (lvalue == "off") ? 0 : (lvalue == "on") ? 1 : atoi(value.c_str()); + +if (bSetDasm) /* 1st pass: find only dasm */ + { + if (option == "dasm") + { + if (pDasm) delete pDasm; /* use the last one */ + pDasm = CreateDisassembler(lowercase(value), &iDasm); + if (!pDasm) + printf("Unknown disassembler \"%s\"\n", value.c_str()); + return 1; + } + else if (option != "info") /* recurse through infofiles */ + return 0; /* and ignore anything else */ + } +else if (option == "dasm") /* 2nd pass: ignore dasm */ + return 1; + +if (option == "?" || option == "help") + Help(); +else if (option == "out") + { + outname = (value == "console") ? "" : value; + return 1; + } +else if (option == "info") + { + bool bOK = LoadInfo(value, bProcInfo); + if (bOK && !bSetDasm && !bProcInfo) + saINames.push_back(value); + return !!bOK; + } +else if (option == "addr") + showAddr = !!bnvalue; +else if (option == "hex") + showHex = !!bnvalue; +else if (option == "asc") + showAsc = !!bnvalue; +else if (pDasm) + { + // little special for f9dasm compatibility: "-no{option}" is interpreted + // as "-option=" (which should default to off) + if (option.substr(0, 2) == "no" && + pDasm->FindOption(option.substr(2)) >= 0) + pDasm->SetOption(option.substr(2), ""); + else + return pDasm->SetOption(option, value); + } + +return 0; +} + +/*****************************************************************************/ +/* ParseOptions : parse options */ +/*****************************************************************************/ + +void Application::ParseOptions + ( + int argc, + char* argv[], + bool bSetDasm + ) +{ +std::string curBegin, curEnd, curOff, curIlv("1"); + +// parse command line +for (int arg = 1; arg < argc; arg++) + { + if (argv[arg][0] == '-') + { + // allow -option:value or -option=value syntax, too + std::string s(argv[arg] + 1); + std::string::size_type x = s.find_first_of("=:"); + if (x != std::string::npos) + ParseOption(s.substr(0, x), s.substr(x + 1), + bSetDasm, false); + else + arg += ParseOption(s, arg < argc - 1 ? argv[arg + 1] : "", + bSetDasm, false); + } + else if (!bSetDasm) + { + std::string name(argv[arg]); + std::string silv("1"); + if (name.size() > 2) + { + // name can be name:interleave + std::string::size_type idx = name.rfind(':'); + if (idx != std::string::npos) + { + silv = name.substr(idx + 1); + if (silv.size() == 1 && + silv[0] >= '1' && silv[0] <= '8') + name = name.substr(0, idx); + else + silv = "1"; + } + } + // in any case, the file relies on the current begin/end/offset settings + // so their current setting must be preserved. + std::string newBegin(pDasm->GetOption("begin")); + if (newBegin != curBegin) + { + saFNames.push_back("-begin:"+newBegin); + curBegin = newBegin; + } + std::string newEnd(pDasm->GetOption("end")); + if (newEnd != curEnd) + { + saFNames.push_back("-end:"+newEnd); + curEnd = newEnd; + } + std::string newOff(pDasm->GetOption("offset")); + if (newOff != curOff) + { + saFNames.push_back("-offset:"+newOff); + curOff = newOff; + } + if (silv != curIlv) + { + saFNames.push_back("-interleave:"+silv); + curIlv = silv; + } + saFNames.push_back(name); + } + } +} + +/*****************************************************************************/ +/* ListOptions : lists the available options for the currently loaded dasm */ +/*****************************************************************************/ + +static void inline ListOptionLine + ( + std::string name, + std::string text, + std::string current = "" + ) +{ +printf(" %-13s ", name.c_str()); +std::string::size_type idx = text.find('\t'); +std::string optxt; +if (idx != std::string::npos) + { + optxt = text.substr(0, idx); + text = text.substr(idx + 1); + } +if (optxt.size()) + printf("%-10s ", optxt.c_str()); +printf("%s", text.c_str()); +if (current.size()) + printf(" (%s)", current.c_str()); +printf("\n"); +} + +void Application::ListOptions() +{ +printf("\nAvailable options"); +#if 0 +if (pDasm) + printf(" for %s (%s)", + Disassemblers[iDasm].name.c_str(), + pDasm->GetName().c_str()); +#endif +printf(":\n"); +ListOptionLine("?|help", "This Help list"); +ListOptionLine("out", "Output File name", outname.size() ? outname : "console"); +ListOptionLine("dasm", "{code}\tDisassembler to use", + pDasm ? Disassemblers[iDasm].name : std::string("")); + +if (!pDasm) + { + ListDisassemblers(); + printf("\nTo show the available options for a disassembler, select one first\n" + "and append -? to the command line\n"); + } +else + { + ListOptionLine("addr", "{off|on}\toutput address dump", showAddr ? "on" : "off"); + ListOptionLine("hex", "{off|on}\toutput hex dump", showHex ? "on" : "off"); + ListOptionLine("asc", "{off|on}\toutput ASCII rendering of code/data", showAsc ? "on" : "off"); + + for (int i = 0; i < pDasm->GetOptionCount(); i++) + ListOptionLine(pDasm->GetOptionName(i), + pDasm->GetOptionHelp(i), + pDasm->GetOption(i)); + } +printf("\nOptions can be given in the following formats:\n" + " -option value\n" + " -option=value\n" + " -option:value\n"); +} + + +/*****************************************************************************/ +/* Help : give help about the application */ +/*****************************************************************************/ + +int Application::Help(bool bQuit) +{ +printf("Usage: dasmfw [-option]* [filename]*\n"); + +ListOptions(); /* list options for selected dasm */ + +if (bQuit) exit(1); /* hard exit */ + +return 1; +} + +/*****************************************************************************/ +/* DumpMem : dump disassembler's memory areas */ +/*****************************************************************************/ + +#ifdef _DEBUG +void Application::DumpMem(bool bDataBus) +{ +if (!pDasm) return; + +std::string sComBlk = pDasm->GetOption("cchar") + " "; + +int mac = pDasm->GetMemoryArrayCount(bDataBus); +int maac = pDasm->GetMemAttrArrayCount(bDataBus); +PrintLine(sComBlk + + sformat("%s Bus: %d memory areas, %d memory attribute areas", + bDataBus ? "Data" : "Code", mac, maac)); +int i; +for (i = 0; i < mac; i++) + { + TMemory &area = pDasm->GetMemoryArray(i, bDataBus); + PrintLine(sComBlk + + sformat("Memory area %2d: start=%x size=%x", i, + area.GetStart(), + area.size())); + } +MemAttributeHandler *pmah = pDasm->GetMemoryAttributeHandler(bDataBus); +for (i = 0; i < maac; i++) + { + TMemory &area = pDasm->GetMemoryArray(i, bDataBus); + PrintLine(sComBlk + + sformat("Memory attribute area %2d: start=%x size=%x", i, + pmah->GetStart(i), + pmah->size(i))); + } + +int nLabels = pDasm->GetLabelCount(bDataBus); +for (i = 0; i < nLabels; i++) + { + Label *pLabel = pDasm->LabelAt(i, bDataBus); + PrintLine(sComBlk + + sformat("Label %4d: addr=%x type=%d \"%s\" %sused", + i, pLabel->GetAddress(), pLabel->GetType(), + pLabel->GetText().c_str(), + pLabel->IsUsed() ? "" : "un")); + } + +int nComments = GetCommentCount(false, bDataBus); +for (i = 0; i < nComments; i++) + { + Comment *pLabel = CommentAt(false, i, bDataBus); + PrintLine(sComBlk + + sformat("Comment %4d: before addr=%x \"%s\"", + i, pLabel->GetAddress(), + pLabel->GetText().c_str())); + } +nComments = GetCommentCount(true, bDataBus); +for (i = 0; i < nComments; i++) + { + Comment *pLabel = CommentAt(true, i, bDataBus); + PrintLine(sComBlk + + sformat("Comment %4d: after addr=%x \"%s\"", + i, pLabel->GetAddress(), + pLabel->GetText().c_str())); + } +} +#endif diff --git a/dasmfw.h b/dasmfw.h new file mode 100644 index 0000000..4d1e355 --- /dev/null +++ b/dasmfw.h @@ -0,0 +1,218 @@ +/*************************************************************************** + * dasmfw -- Disassembler Framework * + * * + * This program 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. * + * * + * This program 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 this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +/*****************************************************************************/ +/* dasmfw.h : global definitions for the DisASseMbler FrameWork */ +/*****************************************************************************/ + +#ifndef __dasmfw_h_defined__ +#define __dasmfw_h_defined__ + + +// Specials for Visual C++ +#ifdef _MSC_VER +#pragma once +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0510 +#endif +#if _MSC_VER < 1600 + #include "backport_stdint.h" +#else + #include +#endif +#else +// gcc and the like should have this anyway +#include +#endif + +#include +#include +#include +#include +#include + +#ifndef _countof +#define _countof(a) (sizeof(a) / sizeof(a[0])) +#endif + +/*****************************************************************************/ +/* Global definitions */ +/*****************************************************************************/ + +#define DASMFW_VERSION "0.3" + +// set these to int64_t once 64bit processors become part of the framework +typedef uint32_t caddr_t; /* container for maximal code address*/ +typedef uint32_t daddr_t; /* container for maximal data address*/ +typedef uint32_t addr_t; /* bigger of the 2 above */ + +#define NO_ADDRESS ((addr_t)-1) +#define DEFAULT_ADDRESS ((addr_t)-2) + +#include "Memory.h" + +/*****************************************************************************/ +/* Global functions */ +/*****************************************************************************/ + +std::string lowercase(std::string s); +std::string uppercase(std::string s); +std::string trim(std::string s); +std::string sformat(const std::string fmt_str, ...); + +/*****************************************************************************/ +/* Automatic Disassembler Registration */ +/*****************************************************************************/ + +class Disassembler; +bool RegisterDisassembler(std::string name, Disassembler * (*CreateDisassembler)()); + +/*****************************************************************************/ +/* Comment : definition of a comment or insert line */ +/*****************************************************************************/ + +class Comment : public AddrText + { + public: + Comment(addr_t addr = 0, std::string sline = "") + : AddrText(addr, Data, sline) + { } + virtual ~Comment() { } + + bool operator<(const Comment &other) + { return AddrText::operator<((const AddrText &)other); } + bool operator<=(const Comment &other) + { return AddrText::operator<=((const AddrText &)other); } + bool operator==(const Comment &other) + { return AddrText::operator==((const AddrText &)other); } + bool operator!=(const Comment &other) { return !operator==(other); } + bool operator>=(const Comment &other) { return !operator<(other); } + bool operator>(const Comment &other) { return !operator<=(other); } + }; + +/*****************************************************************************/ +/* Application : main application class */ +/*****************************************************************************/ + +class Application +{ +public: + Application(int argc, char* argv[]); + ~Application(); + + int Run(); + + bool LoadInfo(std::string fileName, bool bProcInfo = true) + { + std::vector loadStack; + return LoadInfo(fileName, loadStack, bProcInfo); + } + +protected: + bool Parse(int nPass, bool bDataBus = false); + bool ResolveRelativeLabels(bool bDataBus = false); + bool DisassembleChanges(addr_t addr, addr_t prevaddr, addr_t prevsz, bool bAfterLine, bool bDataBus = false); + bool DisassembleLabels(std::string sComDel, std::string sComHdr, bool bDataBus = false); + addr_t DisassembleLine(addr_t addr, std::string sComDel, std::string sComHdr, std::string labelDelim, bool bDataBus = false); + bool PrintLine(std::string sLabel = "", std::string smnemo = "", std::string sparm = "", std::string scomment = ""); + bool LoadInfo(std::string fileName, std::vector &loadStack, bool bProcInfo = true); + int ParseInfoRange(std::string value, addr_t &from, addr_t &to); + int ParseOption + ( + std::string option, /* option name */ + std::string value, /* new option value */ + bool bSetDasm = false, /* flag whether set disassembler */ + bool bProcInfo = true /* flag whether to fully process info*/ + ); + void ParseOptions + ( + int argc, + char* argv[], + bool bSetDasm = false /* flag whether set disassembler */ + ); + void ListOptions(); + bool InfoHelp(); + int Help(bool bQuit = false); +#ifdef _DEBUG + void DumpMem(bool bDataBus); +#endif + + // Comment / Text line handling + bool AddComment(addr_t addr, bool bAfter = false, std::string sComment = "", bool bPrepend = false, bool bDataBus = false) + { + comments[bDataBus][bAfter].insert(new Comment(addr, sComment), !bPrepend); + return true; + } + Comment *GetFirstComment(addr_t addr, AddrTextArray::iterator &it, bool bAfter = false, bool bDataBus = false) + { + it = comments[bDataBus][bAfter].find(addr, Data); + return it != comments[bDataBus][bAfter].end() ? (Comment *)(*it) : NULL; + } + Comment *GetNextComment(addr_t addr, AddrTextArray::iterator &it, bool bAfter = false, bool bDataBus = false) + { + it++; + return (it != comments[bDataBus][bAfter].end() && (*it)->GetAddress() == addr) ? (Comment *)(*it) : NULL; + } + + int GetCommentCount(bool bAfter, bool bDataBus = false) { return comments[bDataBus][bAfter].size(); } + Comment *CommentAt(bool bAfter, int index, bool bDataBus = false) { return (Comment *)comments[bDataBus][bAfter].at(index); } + void RemoveCommentAt(bool bAfter, int index, bool bDataBus = false) { comments[bDataBus][bAfter].erase(comments[bDataBus][bAfter].begin() + index); } + + // Line Comment handling + bool AddLComment(addr_t addr, std::string sComment = "", bool bPrepend = false, bool bDataBus = false) + { + lcomments[bDataBus].insert(new Comment(addr, sComment), !bPrepend); + return true; + } + Comment *GetFirstLComment(addr_t addr, AddrTextArray::iterator &it, bool bDataBus = false) + { + it = lcomments[bDataBus].find(addr, Data); + return it != lcomments[bDataBus].end() ? (Comment *)(*it) : NULL; + } + Comment *GetNextLComment(addr_t addr, AddrTextArray::iterator &it, bool bDataBus = false) + { + it++; + return (it != lcomments[bDataBus].end() && (*it)->GetAddress() == addr) ? (Comment *)(*it) : NULL; + } + int GetLCommentCount(bool bDataBus = false) { return lcomments[bDataBus].size(); } + Comment *LCommentAt(int index, bool bDataBus = false) { return (Comment *)lcomments[bDataBus].at(index); } + void RemoveLCommentAt(int index, bool bDataBus = false) { lcomments[bDataBus].erase(lcomments[bDataBus].begin() + index); } + + +protected: + int argc; + char **argv; + std::string sDasmName; /* program name */ + Disassembler *pDasm; /* selected disassembler */ + int iDasm; /* index of selected disassembler */ + std::vector saFNames; /* array of files to load */ + std::vector saINames; /* array of info files to load */ + std::string outname; /* output file name */ + FILE *out; /* output file */ + + bool bInfoBus; /* current bus selection */ + bool showHex; /* flag for hex data display */ + bool showAddr; /* flag for address display */ + bool showAsc; /* flag for ASCII content display */ + + TMemoryArray remaps[2]; /* remap arrays */ + AddrTextArray comments[2][2]; /* comment / line text arrays */ + AddrTextArray lcomments[2]; /* line comment arrays */ +}; + +#endif // __dasmfw_h_defined__ diff --git a/dasmfw.sln b/dasmfw.sln new file mode 100644 index 0000000..4700105 --- /dev/null +++ b/dasmfw.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dasmfw", "dasmfw.vcproj", "{5AA68B69-BC05-48B0-8254-6C43FCDA7259}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5AA68B69-BC05-48B0-8254-6C43FCDA7259}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AA68B69-BC05-48B0-8254-6C43FCDA7259}.Debug|Win32.Build.0 = Debug|Win32 + {5AA68B69-BC05-48B0-8254-6C43FCDA7259}.Release|Win32.ActiveCfg = Release|Win32 + {5AA68B69-BC05-48B0-8254-6C43FCDA7259}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/dasmfw.vcproj b/dasmfw.vcproj new file mode 100644 index 0000000..7afd791 --- /dev/null +++ b/dasmfw.vcproj @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/history.txt b/history.txt new file mode 100644 index 0000000..50ca788 --- /dev/null +++ b/history.txt @@ -0,0 +1,26 @@ +*************************************************************************** +* dasmfw -- Disassembler Framework * +* * +* This program 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. * +* * +* This program 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 this program; if not, write to the Free Software * +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * +*************************************************************************** + +History: + +v0.1 2015-06-30 Initial version +v0.2 2015-07-22 dasmfw roughly has f9dasm's capabilities now, although + some minute details have to be specified differently +v0.3 2015-07-23 phasing implemented + dasmfw surpasses f9dasm now (except for processing speed) +