From b85c7b5339d60880ea0610a81bf62fa612651cdc Mon Sep 17 00:00:00 2001 From: Hermann Seib Date: Thu, 23 Jul 2015 19:23:09 +0200 Subject: [PATCH] Initial import Roughly the same capabilities as f9dasm --- Dasm6301.cpp | 261 +++++++ Dasm6301.h | 74 ++ Dasm6309.cpp | 824 ++++++++++++++++++++ Dasm6309.h | 169 ++++ Dasm6800.cpp | 1022 ++++++++++++++++++++++++ Dasm6800.h | 255 ++++++ Dasm6801.cpp | 177 +++++ Dasm6801.h | 68 ++ Dasm6809.cpp | 1488 +++++++++++++++++++++++++++++++++++ Dasm6809.h | 254 ++++++ Disassembler.cpp | 748 ++++++++++++++++++ Disassembler.h | 672 ++++++++++++++++ Label.h | 289 +++++++ Memory.h | 317 ++++++++ backport_stdint.h | 209 +++++ dasmfw.cpp | 1907 +++++++++++++++++++++++++++++++++++++++++++++ dasmfw.h | 218 ++++++ dasmfw.sln | 20 + dasmfw.vcproj | 255 ++++++ history.txt | 26 + 20 files changed, 9253 insertions(+) create mode 100644 Dasm6301.cpp create mode 100644 Dasm6301.h create mode 100644 Dasm6309.cpp create mode 100644 Dasm6309.h create mode 100644 Dasm6800.cpp create mode 100644 Dasm6800.h create mode 100644 Dasm6801.cpp create mode 100644 Dasm6801.h create mode 100644 Dasm6809.cpp create mode 100644 Dasm6809.h create mode 100644 Disassembler.cpp create mode 100644 Disassembler.h create mode 100644 Label.h create mode 100644 Memory.h create mode 100644 backport_stdint.h create mode 100644 dasmfw.cpp create mode 100644 dasmfw.h create mode 100644 dasmfw.sln create mode 100644 dasmfw.vcproj create mode 100644 history.txt 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) +