update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
/*
* Interactive disassembler (IDA).
* Version 3.05
* Copyright (c) 1990-95 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* FIDO: 2:5020/209
* E-mail: ig@estar.msk.su
*/
#include "tms.hpp"
//------------------------------------------------------------------------
static void set_immd_bit(const insn_t &insn)
{
set_immd(insn.ea);
if ( is_defarg0(get_flags(insn.ea)) )
return;
switch ( insn.itype )
{
case TMS_and:
case TMS_bit:
case TMS_bitt:
case TMS_bsar:
case TMS_cmpr:
case TMS_in:
case TMS_intr:
case TMS_apl2:
case TMS_opl2:
case TMS_xpl2:
case TMS_or:
case TMS_rpt:
case TMS_xc:
case TMS_xor:
case TMS_rptz:
case TMS2_bit:
case TMS2_in:
case TMS2_out:
case TMS2_andk:
case TMS2_ork:
case TMS2_xork:
case TMS2_rptk:
op_num(insn.ea, 0);
break;
}
}
//----------------------------------------------------------------------
int tms320c5_t::find_ar(const insn_t &insn, ea_t *res) const
{
ea_t ea = insn.ea;
for ( int i=0; i < get_lookback(); i++ )
{
ea = prevInstruction(ea);
if ( !is_code(get_flags(ea)) )
break;
ushort _code = (ushort)get_wide_byte(ea);
if ( isC2() )
{
switch ( _code >> 11 )
{
case 6: // LAR
return 0;
case 0x18: // LARK
*res = map_data_ea(insn, _code & 0xFF);
return 1;
case 0x1A: // LRLK
if ( (_code & 0xF8FF) == 0xD000 )
{
ushort b = (ushort)get_wide_byte(ea+1);
*res = map_data_ea(insn, b);
return 1;
}
}
continue;
}
switch ( _code >> 11 )
{
case 0: // Load AR from addressed data
return 0; // LAR found, unknown address
case 0x16: // Load AR short immediate
*res = map_data_ea(insn, _code & 0xFF);
return 1;
case 0x17: // Load AR long immediate
if ( (_code & ~7) == 0xBF08 )
{
ushort b = (ushort)get_wide_byte(ea+1);
*res = map_data_ea(insn, b);
return 1;
}
}
}
return 0;
}
//----------------------------------------------------------------------
void tms320c5_t::handle_operand(const insn_t &insn, const op_t &x, bool isload)
{
ea_t ea;
switch ( x.type )
{
case o_phrase: // 2 registers or indirect addressing
if ( insn.itype != TMS_mar
&& insn.itype != TMS2_mar
&& find_ar(insn, &ea) )
{
goto SET_DREF;
}
case o_reg:
case o_bit:
case o_cond:
break;
case o_imm:
{
if ( !isload )
goto badTouch;
set_immd_bit(insn);
flags_t F = get_flags(insn.ea);
if ( op_adds_xrefs(F, x.n) )
insn.add_off_drefs(x, dr_O, is_mpy(insn) ? OOF_SIGNED : 0);
}
break;
case o_mem:
ea = map_data_ea(insn, x);
SET_DREF:
insn.create_op_data(ea, x);
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
if ( x.type == o_mem )
{
if ( insn.itype == TMS_dmov
|| insn.itype == TMS_ltd
|| insn.itype == TMS_macd
|| insn.itype == TMS_madd
|| insn.itype == TMS2_dmov
|| insn.itype == TMS2_macd )
{
insn.add_dref(ea+1, x.offb, dr_W);
}
}
break;
case o_near:
{
ea = map_code_ea(insn, x);
if ( insn.itype == TMS_blpd
|| insn.itype == TMS_mac
|| insn.itype == TMS_macd
|| insn.itype == TMS2_blkp
|| insn.itype == TMS2_mac
|| insn.itype == TMS2_macd )
{
goto SET_DREF;
}
ea_t segbase = (ea - x.addr) >> 4;
uval_t thisseg = insn.cs;
int iscall = has_insn_feature(insn.itype, CF_CALL);
if ( insn.itype == TMS_rptb && is_tail(get_flags(ea)) )
{
// small hack to display end_loop-1 instead of before_end_loop+1
ea++;
}
cref_t xtype = iscall
? (segbase == thisseg ? fl_CN : fl_CF)
: (segbase == thisseg ? fl_JN : fl_JF);
insn.add_cref(ea, x.offb, xtype);
if ( iscall && !func_does_return(ea) )
flow = false;
}
break;
default:
badTouch:
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
break;
}
}
//----------------------------------------------------------------------
static int isDelayedStop(ushort code)
{
switch ( code>>12 )
{
case 7:
return (code & 0xFF00u) == 0x7D00u;
case 0xB:
return code == 0xBE21u;
case 0xF:
return (code & 0xEFFFu) == 0xEF00u;
}
return 0;
}
//----------------------------------------------------------------------
bool tms320c5_t::can_flow(const insn_t &insn) const
{
if ( isC2() )
return true;
flags_t F = get_flags(insn.ea);
if ( !is_flow(F) )
return true; // no previous instructions
ea_t ea = prevInstruction(insn.ea);
if ( insn.size == 2 ) // our instruction is long
{
; // nothing to do
}
else
{ // our instruction short
if ( (insn.ea-ea) == 2 ) // prev instruction long
return true; // can flow always
F = get_flags(ea);
if ( !is_code(F) || !is_flow(F) )
return true; // no prev instr...
ea = prevInstruction(ea);
}
F = get_flags(ea);
return !is_code(F) || !isDelayedStop((ushort)get_wide_byte(ea));
}
//----------------------------------------------------------------------
int tms320c5_t::emu(const insn_t &insn)
{
uint32 Feature = insn.get_canon_feature(ph);
flow = ((Feature & CF_STOP) == 0);
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
if ( Feature & CF_JUMP )
remember_problem(PR_JUMP, insn.ea);
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
if ( flow && can_flow(insn) )
add_cref(insn.ea, insn.ea+insn.size, fl_F);
switch ( insn.itype )
{
case TMS_ldp: // change DP register
case TMS2_ldp: // change DP register
case TMS2_ldpk: // change DP register
{
uint v = (insn.Op1.type == o_imm) ? uint(insn.Op1.value) : -1u;
split_sreg_range(get_item_end(insn.ea), rDP, v, SR_auto);
}
break;
}
return 1;
}

View File

@@ -0,0 +1,297 @@
/*
* Interactive disassembler (IDA).
* Version 3.05
* Copyright (c) 1990-95 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* FIDO: 2:5020/209
* E-mail: ig@estar.msk.su
*
*/
#include <ida.hpp>
#include <idp.hpp>
#include "ins.hpp"
const instruc_t Instructions[] =
{
{ "", 0 }, // Unknown Operation
{ "abs", 0 }, // Absolute value of Acc
{ "adcb", 0 }, // Add ACCB to Acc With Carry
{ "add", CF_USE1 }, // Add to Acc
{ "addb", 0 }, // Add ACCB to Acc
{ "addc", CF_USE1 }, // Add to Acc With Carry
{ "adds", CF_USE1 }, // Add to Acc With Sign-Extension Suppressed
{ "addt", CF_USE1 }, // Add to Acc With Shift Specified by TREG1
{ "adrk", CF_USE1 }, // Add to Aux Register With Short Immediate
{ "and", CF_USE1 }, // AND With Acc
{ "andb", 0 }, // AND ACCD With Acc
{ "apac", 0 }, // Add P Register to Acc
{ "apl", CF_USE1|CF_CHG1 }, // AND Data Memory Value With DBMR or Long Constant
{ "apl", CF_USE1|CF_USE2|CF_CHG2 }, // AND Data Memory Value With DBMR or Long Constant
{ "b", CF_USE1|CF_STOP }, // Branch Unconditionally
{ "bacc", CF_STOP|CF_JUMP }, // Branch to Location (Acc)
{ "baccd", CF_JUMP }, // Branch to Location (Acc) Delayed
{ "banz", CF_USE1 }, // Branch on Aux Register Not Zero
{ "banzd", CF_USE1 }, // Branch on Aux Register Not Zero Delayed
{ "bcnd", CF_USE1 }, // Branch Conditionally
{ "bcndd", CF_USE1 }, // Branch Conditionally Delayed
{ "bd", CF_USE1 }, // Branch Unconditionally Delayed
{ "bit", CF_USE1|CF_USE2 }, // Test Bit
{ "bitt", CF_USE1 }, // Test Bit Specified by TREG2
{ "bldd", CF_USE1|CF_CHG2 }, // Block Move From Data Memory to Data Memory
{ "bldp", CF_USE1 }, // Block Move From Data Memory to Program Memory
{ "blpd", CF_USE1|CF_CHG2 }, // Block Move From Program Memory to Data Memory
{ "bsar", CF_USE1 }, // Barrel Shift
{ "cala", CF_CALL|CF_JUMP }, // Call Subroutine at (Acc)
{ "calad", CF_CALL|CF_JUMP }, // Call Subroutine at (Acc) Delayed
{ "call", CF_USE1|CF_CALL }, // Call Unconditionally
{ "calld", CF_USE1|CF_CALL }, // Call Unconditionally Delayed
{ "cc", CF_USE1|CF_CALL }, // Call Conditionally
{ "ccd", CF_USE1|CF_CALL }, // Call Conditionally Delayed
{ "clrc", CF_CHG1 }, // Clear Control Bit
{ "cmpl", 0 }, // Complement Acc
{ "cmpr", CF_USE1 }, // Compare Aux Register With ARCR
{ "cpl", CF_USE1 }, // Compare DBMR or Long Immediate With Data Value
{ "cpl", CF_USE1|CF_USE2 }, // Compare DBMR or Long Immediate With Data Value
{ "crgt", 0 }, // Test for Acc Greater Than ACCB
{ "crlt", 0 }, // Test for Acc Smaller Than ACCB
{ "dmov", CF_USE1 }, // Data Move in Data Memory
{ "estop", CF_STOP }, // Emulator Stop
{ "exar", 0 }, // Exchange ACCB With Acc
{ "idle", 0 }, // Idle Until Interrupt
{ "idle2", 0 }, // Idle Until Interrupt - Low Power Mode
{ "in", CF_CHG1|CF_USE2 }, // Input Data From Port
{ "intr", CF_USE1 }, // Soft Interrupt
{ "lacb", 0 }, // Load Acc With ACCB
{ "lacc", CF_USE1 }, // Load Acc With Shift
{ "lacl", CF_USE1 }, // Load Low Acc and Clear High Acc
{ "lact", CF_USE1 }, // Load Acc With Shift Specified by TREG1
{ "lamm", CF_USE1 }, // Load Acc With Memory-Mapped Register
{ "lar", CF_CHG1|CF_USE2 }, // Load Aux Register
{ "ldp", CF_USE1 }, // Load Data Memory Pointer
{ "lmmr", CF_CHG1|CF_USE2 }, // Load Memory-Mapped Register
{ "lph", CF_USE1 }, // Load Product High Register
{ "lst", CF_USE1|CF_USE2 }, // Load Status Register
{ "lt", CF_USE1 }, // Load TREG0
{ "lta", CF_USE1 }, // Load TREG0 and Accumulate Previous Product
{ "ltd", CF_USE1 }, // Load TREG0,Accumulate Previous Product and Move Data
{ "ltp", CF_USE1 }, // Load TREG0 and Store P -> Acc
{ "lts", CF_USE1 }, // Load TREG0 and Subtract Previous Product
{ "mac", CF_USE1|CF_USE2 }, // Multiply and Accumulate
{ "macd", CF_USE1|CF_USE2 }, // Multiply and Accumulate With Data Move
{ "madd", CF_USE1 }, // Multiply and Accumulate With Data Move and Dynamic Addressing
{ "mads", CF_USE1 }, // Multiply and Accumulate With Dynamic Addressing
{ "mar", CF_USE1 }, // Modify Aux Register
{ "mpy", CF_USE1 }, // Multiply
{ "mpya", CF_USE1 }, // Multiply and Accumulate Previous Product
{ "mpys", CF_USE1 }, // Multiply and Subtract Previous Product
{ "mpyu", CF_USE1 }, // Multiply Unsigned
{ "neg", 0 }, // Negate Acc
{ "nmi", 0 }, // Nonmaskable Interrupt
{ "nop", 0 }, // No Operation
{ "norm", 0 }, // Normalize Contents of Acc
{ "opl", CF_USE1|CF_CHG1 }, // OR With DBMS or Long Immediate
{ "opl", CF_USE1|CF_USE2|CF_CHG2 }, // OR With DBMS or Long Immediate
{ "or", CF_USE1 }, // OR With Acc
{ "orb", 0 }, // OR ACCB With Accumulator
{ "out", CF_USE1|CF_USE2 }, // Out Data to Port
{ "pac", 0 }, // Load Acc <- P
{ "pop", 0 }, // Pop Top of Stack to Low Acc
{ "popd", CF_CHG1 }, // Pop Top of Stack to Data Memory
{ "pshd", CF_USE1 }, // Push Data Memory Value Onto Stack
{ "push", 0 }, // Push Low Acc Onto Stack
{ "ret", CF_STOP }, // Return From Subroutine
{ "retc", CF_USE1 }, // Return Conditionally
{ "retcd", CF_USE1 }, // Return Conditionally Delayed
{ "retd", 0 }, // Return From Subroutine Delayed
{ "rete", CF_STOP }, // Enable Interrupts and Return From Interrupt
{ "reti", CF_STOP }, // Return From Interrupt
{ "rol", 0 }, // Rotate Acc Left
{ "rolb", 0 }, // Rotate ACCB and Acc Left
{ "ror", 0 }, // Rotate Acc Right
{ "rorb", 0 }, // Rotate ACCB and Acc Right
{ "rpt", CF_USE1 }, // Repeat Next Instruction
{ "rptb", CF_USE1 }, // Repeat Block
{ "rptz", CF_USE1 }, // Repeat Preceded by Clearing Acc and P
{ "sacb", 0 }, // Store Acc in ACCB
{ "sach", CF_CHG1 }, // Store High Acc With Shift
{ "sacl", CF_CHG1 }, // Store Low Acc With Shift
{ "samm", CF_CHG1 }, // Store Acc in Memory-Mapped Register
{ "sar", CF_USE1|CF_CHG2 }, // Store Aux Register
{ "sath", 0 }, // Barrel Shift Acc as Specified by TREG1(4)
{ "satl", 0 }, // Barrel Shift Acc as Specified by TREG1(3-0)
{ "sbb", 0 }, // Subtract ACCB From Acc
{ "sbbb", 0 }, // Subtract ACCB From Acc With Borrow
{ "sbrk", CF_USE1 }, // Subtract From Aux Register Short Immediate
{ "setc", CF_CHG1 }, // Set Control Bit
{ "sfl", 0 }, // Shift Acc Left
{ "sflb", 0 }, // Shift ACCB and Acc Left
{ "sfr", 0 }, // Shift Acc Right
{ "sfrb", 0 }, // Shift ACCB and Acc Right
{ "smmr", CF_USE1|CF_CHG2 }, // Store Memory-Mapped Register
{ "spac", 0 }, // Subtract P From Acc
{ "sph", CF_CHG1 }, // Store High P Register
{ "spl", CF_CHG1 }, // Store Low P Register
{ "splk", CF_USE1|CF_CHG2 }, // Store Parallel Long Immediate
{ "spm", CF_USE1 }, // Store ACCB and Acc Right
{ "sqra", CF_USE1 }, // Square and Accumulate Previous Product
{ "sqrs", CF_USE1 }, // Square and Subtract Previous Product
{ "sst", CF_USE1|CF_CHG2 }, // Store Status Register
{ "sub", CF_USE1 }, // Subtract From Acc
{ "subb", CF_USE1 }, // Subtract From Acc With Borrow
{ "subc", CF_USE1 }, // Conditional Subtract
{ "subs", CF_USE1 }, // Subtract From Acc With Sign-Extension Suppressed
{ "subt", CF_USE1 }, // Subtract From Acc With Shift Specified by TREG1
{ "tblr", CF_CHG1 }, // Table Read
{ "tblw", CF_USE1 }, // Table Write
{ "trap", 0 }, // Software Interrupt
{ "xc", CF_USE1 }, // Execute Conditionally
{ "xor", CF_USE1 }, // Exclusive-OR With Acc
{ "xorb", 0 }, // Exclusive-OR of ACCB With Acc
{ "xpl", CF_USE1|CF_CHG1 }, // Exclusive-OR Data Memory Value
{ "xpl", CF_USE1|CF_USE2|CF_CHG2 }, // Exclusive-OR Data Memory Value
{ "zalr", CF_USE1 }, // Zero Low Acc Load High Acc With Rounding
{ "zap", 0 }, // Zero Acc and P
{ "zpr", 0 }, // Zero P Register
//
// TMS320C2x instructions
//
{ "abs", 0 }, // Absolute value of accumulator
{ "add", CF_USE1 }, // Add to accumulator with shift
{ "addc", CF_USE1 }, // Add to accumulator with carry
{ "addh", CF_USE1 }, // Add to high accumulator
{ "addk", CF_USE1 }, // Add to accumulator short immediate
{ "adds", CF_USE1 }, // Add to low accumulator with sign extension suppressed
{ "addt", CF_USE1 }, // Add to accumulator with shift specified by T register
{ "adlk", CF_USE1 }, // Add to accumulator long immediate with shift
{ "adrk", CF_USE1 }, // Add to auxiliary register short immediate
{ "and", CF_USE1 }, // And with accumulator
{ "andk", CF_USE1 }, // And immediate with accumulator with shift
{ "apac", 0 }, // Add P register to accumulator
{ "b", CF_USE1|CF_STOP }, // Branch unconditionally
{ "bacc", CF_JUMP|CF_STOP }, // Branch to address specified by accumulator
{ "banz", CF_USE1 }, // Bnrach on auxiliary register not zero
{ "bbnz", CF_USE1 }, // Branch if tc bit != 0
{ "bbz", CF_USE1 }, // Branch if tc bit = 0
{ "bc", CF_USE1 }, // Branch on carry
{ "bgez", CF_USE1 }, // Branch if accumulator >= 0
{ "bgz", CF_USE1 }, // Branch if accumulator > 0
{ "bioz", CF_USE1 }, // Branch on i/o status = 0
{ "bit", CF_USE1|CF_USE2 }, // Test bit
{ "bitt", CF_USE1 }, // Test bit specifed by T register
{ "blez", CF_USE1 }, // Branch if accumulator <= 0
{ "blkd", CF_USE1|CF_CHG2 }, // Block move from data memory to data memory
{ "blkp", CF_USE1|CF_CHG2 }, // Block move from program memory to data memory
{ "blz", CF_USE1 }, // Branch if accumulator < 0
{ "bnc", CF_USE1 }, // Branch on no carry
{ "bnv", CF_USE1 }, // Branch if no overflow
{ "bnz", CF_USE1 }, // Branch if accumulator != 0
{ "bv", CF_USE1 }, // Branch on overflow
{ "bz", CF_USE1 }, // Branch if accumulator = 0
{ "cala", CF_CALL|CF_JUMP }, // Call subroutine indirect
{ "call", CF_USE1|CF_CALL }, // Call subroutine
{ "cmpl", 0 }, // Complement accumulator
{ "cmpr", 0 }, // Compare auxiliary register with auxiliary register ar0
{ "cnfd", 0 }, // Configure block as data memory
{ "cnfp", 0 }, // Configure block as program memory
{ "conf", 0 }, // Configure block as data/program memory
{ "dint", 0 }, // Disable interrupt
{ "dmov", CF_USE1 }, // Data move in data memory
{ "eint", 0 }, // Enable interrupt
{ "fort", 0 }, // Format serial port registers
{ "idle", 0 }, // Idle until interrupt
{ "in", CF_CHG1|CF_USE2 }, // Input data from port
{ "lac", CF_USE1 }, // Load accumulator with shift
{ "lack", CF_USE1 }, // Load accumulator short immediate
{ "lact", CF_USE1 }, // Load accumulator with shift specified by T register
{ "lalk", CF_USE1 }, // Load accumulator long immediate with shift
{ "lar", 0 }, // Load auxiliary register
{ "lark", CF_CHG1|CF_USE2 }, // Load auxiliary register short immediate
{ "larp", 0 }, // Load auxiliary register pointer
{ "ldp", CF_USE1 }, // Load data memory page pointer
{ "ldpk", CF_USE1 }, // Load data memory page pointer immediate
{ "lph", CF_USE1 }, // Load high P register
{ "lrlk", CF_USE1 }, // Load auxiliary register long immediate
{ "lst", CF_USE1 }, // Load status register ST0
{ "lst1", CF_USE1 }, // Load status register ST1
{ "lt", CF_USE1 }, // Load T register
{ "lta", CF_USE1 }, // Load T register and accumulate previous product
{ "ltd", CF_USE1 }, // Load T register, accumulate previous product and move data
{ "ltp", CF_USE1 }, // Load T register and store P register in accumulator
{ "lts", CF_USE1 }, // Load T register and subtract previous product
{ "mac", CF_USE1|CF_USE2 }, // Multiply and accumulate
{ "macd", CF_USE1|CF_USE2 }, // Multiply and accumulate with data move
{ "mar", CF_USE1 }, // Modify auxiliary register
{ "mpy", CF_USE1 }, // Multiply (with T register, store product in P register)
{ "mpya", CF_USE1 }, // Multiply and accumulate previous product
{ "mpyk", CF_USE1 }, // Multiply immediate
{ "mpys", CF_USE1 }, // Multiply and subtract previous product
{ "mpyu", CF_USE1 }, // Multiply unsigned
{ "neg", 0 }, // Negate accumulator
{ "nop", 0 }, // No operation
{ "norm", 0 }, // Normalize contents of accumulator
{ "or", CF_USE1 }, // Or with accumulator
{ "ork", CF_USE1 }, // Or immediate with accumulator with shift
{ "out", CF_USE1|CF_USE2 }, // Output data to port
{ "pac", 0 }, // Load accumulator with P register
{ "pop", 0 }, // Pop top of stack to low accumulator
{ "popd", CF_CHG1 }, // Pop top of stack to data memory
{ "pshd", CF_USE1 }, // Push data memory value onto stack
{ "push", 0 }, // Push low accumulator onto stack
{ "rc", 0 }, // Reset carry bit
{ "ret", CF_STOP }, // Return from subroutine
{ "rfsm", 0 }, // Reset serial port frame synchronization mode
{ "rhm", 0 }, // Reset hold mode
{ "rol", 0 }, // Rotate accumulator left
{ "ror", 0 }, // Rotate acuumulator right
{ "rovm", 0 }, // Reset overflow mode
{ "rpt", CF_USE1 }, // Repeat instruction as specified by data memory value
{ "rptk", CF_USE1 }, // Repeat instruction as specified by immediate value
{ "rsxm", 0 }, // Reset sign extension mode
{ "rtc", 0 }, // Reset test/control flag
{ "rtxm", 0 }, // Reset serial port transmit mode
{ "rxf", 0 }, // Reset external flag
{ "sach", CF_CHG1 }, // Store high accumulator with shift
{ "sacl", CF_CHG1 }, // Store low accumulator with shift
{ "sar", CF_USE1|CF_CHG2 }, // Store auxiliary register
{ "sblk", CF_USE1 }, // Subtract from accumulator long immediate with shift
{ "sbrk", CF_USE1 }, // Subtract from auxiliary register short immediate
{ "sc", 0 }, // Set carry bit
{ "sfl", 0 }, // Shift accumulator left
{ "sfr", 0 }, // Shift accumulator right
{ "sfsm", 0 }, // Set serial port frame synchronization mode
{ "shm", 0 }, // Set hold mode
{ "sovm", 0 }, // Set overflow mode
{ "spac", 0 }, // Subtract P register from accumulator
{ "sph", CF_CHG1 }, // Store high P register
{ "spl", CF_CHG1 }, // Store low P register
{ "spm", CF_USE1 }, // Set P register output shift mode
{ "sqra", CF_USE1 }, // Square and accumulate
{ "sqrs", CF_USE1 }, // Square and subtract previous product
{ "sst", CF_CHG1 }, // Store status register ST0
{ "sst1", CF_CHG1 }, // Store status register ST1
{ "ssxm", 0 }, // Set sign extension mode
{ "stc", 0 }, // Set test/control flag
{ "stxm", 0 }, // Set serial port transmit mode
{ "sub", CF_USE1 }, // Subtract from accumulator with shift
{ "subb", CF_USE1 }, // Subtract from accumulator with borrow
{ "subc", CF_USE1 }, // Conditional subtract
{ "subh", CF_USE1 }, // Subtract from high accumulator
{ "subk", CF_USE1 }, // Subtract from accumulator shoft immediate
{ "subs", CF_USE1 }, // Subtract from low accumulator with sign extension suppressed
{ "subt", CF_USE1 }, // Subtract from accumulator with shift specified by T register
{ "sxf", 0 }, // Set external flag
{ "tblr", CF_CHG1 }, // Table read
{ "tblw", CF_USE1 }, // Table write
{ "trap", 0 }, // Software interrupt
{ "xor", CF_USE1 }, // Exclusive or with accumulator
{ "xork", CF_USE1 }, // Exclusive or immediate with accumulator with shift
{ "zac", 0 }, // Zero accumulator
{ "zalh", CF_USE1 }, // Zero low accumulator and load high accumulator
{ "zalr", CF_USE1 }, // Zero low accumulator and load high accumulator with rounding
{ "zals", CF_USE1 }, // Zero low accumulator and load high accumulator with sign extension suppressed
};
CASSERT(qnumber(Instructions) == TMS_last);

View File

@@ -0,0 +1,298 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __INSTRS_HPP
#define __INSTRS_HPP
extern const instruc_t Instructions[];
enum nameNum ENUM_SIZE(uint16)
{
TMS_null = 0, // Unknown Operation
TMS_abs, // Absolute value of Acc
TMS_adcb, // Add ACCB to Acc With Carry
TMS_add, // Add to Acc
TMS_addb, // Add ACCB to Acc
TMS_addc, // Add to Acc With Carry
TMS_adds, // Add to Acc With Sign-Extension Suppressed
TMS_addt, // Add to Acc With Shift Specified by TREG1
TMS_adrk, // Add to Aux Register With Short Immediate
TMS_and, // AND With Acc
TMS_andb, // AND ACCD With Acc
TMS_apac, // Add P Register to Acc
TMS_apl, // AND Data Memory Value With DBMR
TMS_apl2, // AND Data Memory Value With Long Constant
TMS_b, // Branch Unconditionally
TMS_bacc, // Branch to Location (Acc)
TMS_baccd, // Branch to Location (Acc) Delayed
TMS_banz, // Branch on Aux Register Not Zero
TMS_banzd, // Branch on Aux Register Not Zero Delayed
TMS_bcnd, // Branch Conditionally
TMS_bcndd, // Branch Conditionally Delayed
TMS_bd, // Branch Unconditionally Delayed
TMS_bit, // Test Bit
TMS_bitt, // Test Bit Specified by TREG2
TMS_bldd, // Block Move From Data Memory to Data Memory
TMS_bldp, // Block Move From Data Memory to Program Memory
TMS_blpd, // Block Move From Program Memory to Data Memory
TMS_bsar, // Barrel Shift
TMS_cala, // Call Subroutine at (Acc)
TMS_calad, // Call Subroutine at (Acc) Delayed
TMS_call, // Call Unconditionally
TMS_calld, // Call Unconditionally Delayed
TMS_cc, // Call Conditionally
TMS_ccd, // Call Conditionally Delayed
TMS_clrc, // Clear Control Bit
TMS_cmpl, // Complement Acc
TMS_cmpr, // Compare Aux Register With ARCR
TMS_cpl, // Compare DBMR With Data Value
TMS_cpl2, // Compare Long Immediate With Data Value
TMS_crgt, // Test for Acc Greater Than ACCB
TMS_crlt, // Test for Acc Smaller Than ACCB
TMS_dmov, // Data Move in Data Memory
TMS_estop, // Emulator Stop
TMS_exar, // Exchange ACCB With Acc
TMS_idle, // Idle Until Interrupt
TMS_idle2, // Idle Until Interrupt - Low Power Mode
TMS_in, // Input Data From Port
TMS_intr, // Soft Interrupt
TMS_lacb, // Load Acc With ACCB
TMS_lacc, // Load Acc With Shift
TMS_lacl, // Load Low Acc and Clear High Acc
TMS_lact, // Load Acc With Shift Specified by TREG1
TMS_lamm, // Load Acc With Memory-Mapped Register
TMS_lar, // Load Aux Register
TMS_ldp, // Load Data Memory Pointer
TMS_lmmr, // Load Memory-Mapped Register
TMS_lph, // Load Product High Register
TMS_lst, // Load Status Register
TMS_lt, // Load TREG0
TMS_lta, // Load TREG0 and Accumulate Previous Product
TMS_ltd, // Load TREG0,Accumulate Previous Product and Move Data
TMS_ltp, // Load TREG0 and Store P -> Acc
TMS_lts, // Load TREG0 and Subtract Previous Product
TMS_mac, // Multiply and Accumulate
TMS_macd, // Multiply and Accumulate With Data Move
TMS_madd, // Multiply and Accumulate With Data Move and Dynamic Addressing
TMS_mads, // Multiply and Accumulate With Dynamic Addressing
TMS_mar, // Modify Aux Register
TMS_mpy, // Multiply
TMS_mpya, // Multiply and Accumulate Previous Product
TMS_mpys, // Multiply and Subtract Previous Product
TMS_mpyu, // Multiply Unsigned
TMS_neg, // Negate Acc
TMS_nmi, // Nonmaskable Interrupt
TMS_nop, // No Operation
TMS_norm, // Normalize Contents of Acc
TMS_opl, // OR With DBMS
TMS_opl2, // OR With Long Immediate
TMS_or, // OR With Acc
TMS_orb, // OR ACCB With Accumulator
TMS_out, // Out Data to Port
TMS_pac, // Load Acc <- P
TMS_pop, // Pop Top of Stack to Low Acc
TMS_popd, // Pop Top of Stack to Data Memory
TMS_pshd, // Push Data Memory Value Onto Stack
TMS_push, // Push Low Acc Onto Stack
TMS_ret, // Return From Subroutine
TMS_retc, // Return Conditionally
TMS_retcd, // Return Conditionally Delayed
TMS_retd, // Return From Subroutine Delayed
TMS_rete, // Enable Interrupts and Return From Interrupt
TMS_reti, // Return From Interrupt
TMS_rol, // Rotate Acc Left
TMS_rolb, // Rotate ACCB and Acc Left
TMS_ror, // Rotate Acc Right
TMS_rorb, // Rotate ACCB and Acc Right
TMS_rpt, // Repeat Next Instruction
TMS_rptb, // Repeat Block
TMS_rptz, // Repeat Preceded by Clearing Acc and P
TMS_sacb, // Store Acc in ACCB
TMS_sach, // Store High Acc With Shift
TMS_sacl, // Store Low Acc With Shift
TMS_samm, // Store Acc in Memory-Mapped Register
TMS_sar, // Store Aux Register
TMS_sath, // Barrel Shift Acc as Specified by TREG1(4)
TMS_satl, // Barrel Shift Acc as Specified by TREG1(3-0)
TMS_sbb, // Subtract ACCB From Acc
TMS_sbbb, // Subtract ACCB From Acc With Borrow
TMS_sbrk, // Subtract From Aux Register Short Immediate
TMS_setc, // Set Control Bit
TMS_sfl, // Shift Acc Left
TMS_sflb, // Shift ACCB and Acc Left
TMS_sfr, // Shift Acc Right
TMS_sfrb, // Shift ACCB and Acc Right
TMS_smmr, // Store Memory-Mapped Register
TMS_spac, // Subtract P From Acc
TMS_sph, // Store High P Register
TMS_spl, // Store Low P Register
TMS_splk, // Store Parallel Long Immediate
TMS_spm, // Store ACCB and Acc Right
TMS_sqra, // Square and Accumulate Previous Product
TMS_sqrs, // Square and Subtract Previous Product
TMS_sst, // Store Status Register
TMS_sub, // Subtract From Acc
TMS_subb, // Subtract From Acc With Borrow
TMS_subc, // Conditional Subtract
TMS_subs, // Subtract From Acc With Sign-Extension Suppressed
TMS_subt, // Subtract From Acc With Shift Specified by TREG1
TMS_tblr, // Table Read
TMS_tblw, // Table Write
TMS_trap, // Software Interrupt
TMS_xc, // Execute Conditionally
TMS_xor, // Exclusive-OR With Acc
TMS_xorb, // Exclusive-OR of ACCB With Acc
TMS_xpl, // Exclusive-OR Data Memory Value
TMS_xpl2, // Exclusive-OR Data Memory Value
TMS_zalr, // Zero Low Acc Load High Acc With Rounding
TMS_zap, // Zero Acc and P
TMS_zpr, // Zero P Register
//
// TMS320C2x instructions
//
TMS2_abs, // Absolute value of accumulator
TMS2_add, // Add to accumulator with shift
TMS2_addc, // Add to accumulator with carry
TMS2_addh, // Add to high accumulator
TMS2_addk, // Add to accumulator short immediate
TMS2_adds, // Add to low accumulator with sign extension suppressed
TMS2_addt, // Add to accumulator with shift specified by T register
TMS2_adlk, // Add to accumulator long immediate with shift
TMS2_adrk, // Add to auxiliary register short immediate
TMS2_and, // And with accumulator
TMS2_andk, // And immediate with accumulator with shift
TMS2_apac, // App P register to accumulator
TMS2_b, // Branch unconditionally
TMS2_bacc, // Branch to address specified by accumulator
TMS2_banz, // Bnrach on auxiliary register not zero
TMS2_bbnz, // Branch if tc bit != 0
TMS2_bbz, // Branch if tc bit = 0
TMS2_bc, // Branch on carry
TMS2_bgez, // Branch if accumulator >= 0
TMS2_bgz, // Branch if accumulator > 0
TMS2_bioz, // Branch on i/o status = 0
TMS2_bit, // Test bit
TMS2_bitt, // Test bit specifed by T register
TMS2_blez, // Branch if accumulator <= 0
TMS2_blkd, // Block move from data memory to data memory
TMS2_blkp, // Block move from program memory to data memory
TMS2_blz, // Branch if accumulator < 0
TMS2_bnc, // Branch on no carry
TMS2_bnv, // Branch if no overflow
TMS2_bnz, // Branch if accumulator != 0
TMS2_bv, // Branch on overflow
TMS2_bz, // Branch if accumulator = 0
TMS2_cala, // Call subroutine indirect
TMS2_call, // Call subroutine
TMS2_cmpl, // Complement accumulator
TMS2_cmpr, // Compare auxiliary register with auxiliary register ar0
TMS2_cnfd, // Configure block as data memory
TMS2_cnfp, // Configure block as program memory
TMS2_conf, // Configure block as data/program memory
TMS2_dint, // Disable interrupt
TMS2_dmov, // Data move in data memory
TMS2_eint, // Enable interrupt
TMS2_fort, // Format serial port registers
TMS2_idle, // Idle until interrupt
TMS2_in, // Input data from port
TMS2_lac, // Load accumulator with shift
TMS2_lack, // Load accumulator short immediate
TMS2_lact, // Load accumulator with shift specified by T register
TMS2_lalk, // Load accumulator long immediate with shift
TMS2_lar, // Load auxiliary register
TMS2_lark, // Load auxiliary register short immediate
TMS2_larp, // Load auxiliary register pointer
TMS2_ldp, // Load data memory page pointer
TMS2_ldpk, // Load data memory page pointer immediate
TMS2_lph, // Load high P register
TMS2_lrlk, // Load auxiliary register long immediate
TMS2_lst, // Load status register ST0
TMS2_lst1, // Load status register ST1
TMS2_lt, // Load T register
TMS2_lta, // Load T register and accumulate previous product
TMS2_ltd, // Load T register, accumulate previous product and move data
TMS2_ltp, // Load T register and store P register in accumulator
TMS2_lts, // Load T register and subtract previous product
TMS2_mac, // Multiply and accumulate
TMS2_macd, // Multiply and accumulate with data move
TMS2_mar, // Modify auxiliary register
TMS2_mpy, // Multiply (with T register, store product in P register)
TMS2_mpya, // Multiply and accumulate previous product
TMS2_mpyk, // Multiply immediate
TMS2_mpys, // Multiply and subtract previous product
TMS2_mpyu, // Multiply unsigned
TMS2_neg, // Negate accumulator
TMS2_nop, // No operation
TMS2_norm, // Normalize contents of accumulator
TMS2_or, // Or with accumulator
TMS2_ork, // Or immediate with accumulator with shift
TMS2_out, // Output data to port
TMS2_pac, // Load accumulator with P register
TMS2_pop, // Pop top of stack to low accumulator
TMS2_popd, // Pop top of stack to data memory
TMS2_pshd, // Push data memory value onto stack
TMS2_push, // Push low accumulator onto stack
TMS2_rc, // Reset carry bit
TMS2_ret, // Return from subroutine
TMS2_rfsm, // Reset serial port frame synchronization mode
TMS2_rhm, // Reset hold mode
TMS2_rol, // Rotate accumulator left
TMS2_ror, // Rotate acuumulator right
TMS2_rovm, // Reset overflow mode
TMS2_rpt, // Repeat instruction as specified by data memory value
TMS2_rptk, // Repeat instruction as specified by immediate value
TMS2_rsxm, // Reset sign extension mode
TMS2_rtc, // Reset test/control flag
TMS2_rtxm, // Reset serial port transmit mode
TMS2_rxf, // Reset external flag
TMS2_sach, // Store high accumulator with shift
TMS2_sacl, // Store low accumulator with shift
TMS2_sar, // Store auxiliary register
TMS2_sblk, // Subtract from accumulator long immediate with shift
TMS2_sbrk, // Subtract from auxiliary register short immediate
TMS2_sc, // Set carry bit
TMS2_sfl, // Shift accumulator left
TMS2_sfr, // Shift accumulator right
TMS2_sfsm, // Set serial port frame synchronization mode
TMS2_shm, // Set hold mode
TMS2_sovm, // Set overflow mode
TMS2_spac, // Subtract P register from accumulator
TMS2_sph, // Store high P register
TMS2_spl, // Store low P register
TMS2_spm, // Set P register output shift mode
TMS2_sqra, // Square and accumulate
TMS2_sqrs, // Square and subtract previous product
TMS2_sst, // Store status register ST0
TMS2_sst1, // Store status register ST1
TMS2_ssxm, // Set sign extension mode
TMS2_stc, // Set test/control flag
TMS2_stxm, // Set serial port transmit mode
TMS2_sub, // Subtract from accumulator with shift
TMS2_subb, // Subtract from accumulator with borrow
TMS2_subc, // Conditional subtract
TMS2_subh, // Subtract from high accumulator
TMS2_subk, // Subtract from accumulator shoft immediate
TMS2_subs, // Subtract from low accumulator with sign extension suppressed
TMS2_subt, // Subtract from accumulator with shift specified by T register
TMS2_sxf, // Set external flag
TMS2_tblr, // Table read
TMS2_tblw, // Table write
TMS2_trap, // Software interrupt
TMS2_xor, // Exclusive or with accumulator
TMS2_xork, // Exclusive or immediate with accumulator with shift
TMS2_zac, // Zero accumulator
TMS2_zalh, // Zero low accumulator and load high accumulator
TMS2_zalr, // Zero low accumulator and load high accumulator with rounding
TMS2_zals, // Zero low accumulator and load high accumulator with sign extension suppressed
TMS_last,
};
#endif

View File

@@ -0,0 +1,46 @@
PROC=tms320c5
include ../module.mak
# MAKEDEP dependency list ------------------
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
$(I)nalt.hpp $(I)name.hpp \
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
ana.cpp ins.hpp tms.hpp
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
$(I)nalt.hpp $(I)name.hpp \
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
emu.cpp ins.hpp tms.hpp
$(F)ins$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp \
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
$(I)ua.hpp $(I)xref.hpp ins.cpp ins.hpp
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
$(I)nalt.hpp $(I)name.hpp \
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
ins.hpp out.cpp tms.hpp
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
$(I)nalt.hpp $(I)name.hpp \
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
ins.hpp reg.cpp tms.hpp

View File

@@ -0,0 +1,458 @@
/*
* Interactive disassembler (IDA).
* Version 3.05
* Copyright (c) 1990-95 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* FIDO: 2:5020/209
* E-mail: ig@estar.msk.su
*
*/
#include "tms.hpp"
// simple wrapper class for syntactic sugar of member functions
// this class may have only simple member functions.
// virtual functions and data fields are forbidden, otherwise the class
// layout may change
class out_tms320c5_t : public outctx_t
{
out_tms320c5_t(void) = delete; // not used
void set_has_phrase(void) { user_data = (void*)1; }
bool has_phrase() const { return user_data != NULL; }
const tms320c5_t &pm() const { return *static_cast<tms320c5_t *>(procmod); }
public:
bool out_operand(const op_t &x);
void out_insn(void);
void outreg(int r) { out_register(ph.reg_names[r]); }
void OutDecimal(uval_t x);
int outnextar(const op_t &o, bool comma);
bool shouldIndent(void) const;
void outphraseAr(void);
void OutImmVoid(const op_t &x);
};
CASSERT(sizeof(out_tms320c5_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_tms320c5_t)
//----------------------------------------------------------------------
static const char *const phrases[] =
{
"*", "*-", "*+", "?",
"*br0-", "*0-", "*0+", "*br0+"
};
//----------------------------------------------------------------------
void out_tms320c5_t::OutDecimal(uval_t x)
{
char buf[40];
qsnprintf(buf, sizeof(buf), "%" FMT_EA "u", x);
out_line(buf, COLOR_NUMBER);
}
//----------------------------------------------------------------------
bool is_mpy(const insn_t &insn)
{
switch ( insn.itype )
{
case TMS_mpy: // Multiply
case TMS_mpya: // Multiply and Accumulate Previous Product
case TMS_mpys: // Multiply and Subtract Previous Product
case TMS2_mpy: // Multiply (with T register, store product in P register)
case TMS2_mpya: // Multiply and accumulate previous product
case TMS2_mpyk: // Multiply immediate
case TMS2_mpys: // Multiply and subtract previous product
return true;
}
return false;
}
//----------------------------------------------------------------------
bool out_tms320c5_t::out_operand(const op_t &x)
{
switch ( x.type )
{
case o_reg:
outreg(x.reg);
break;
case o_phrase:
QASSERT(10087, (x.phrase>>4) < qnumber(phrases));
out_line(phrases[x.phrase>>4], COLOR_SYMBOL);
set_has_phrase();
break;
case o_imm:
switch ( x.sib )
{
default:
{
if ( !pm().isC2() )
out_symbol('#');
flags_t saved = F;
if ( !is_defarg(F, x.n)
&& (is_mpy(insn) || is_invsign(insn.ea, F, x.n)) )
{
F |= dec_flag();
}
int outflags = OOFW_16|(is_mpy(insn) ? OOF_SIGNED : 0);
out_value(x, outflags);
F = saved;
}
break;
case 1:
out_value(x, OOF_NUMBER|OOFS_NOSIGN);
break;
case 2:
case 3:
OutDecimal(x.value);
break;
}
break;
case o_near:
if ( insn.itype == TMS_blpd )
out_symbol('#');
// fallthrough
case o_mem:
{
if ( insn.itype == TMS_bldd && x.sib )
out_symbol('#');
ea_t v = map_ea(insn, x, x.type == o_near);
bool rptb_tail = false;
uval_t addr = x.addr;
if ( insn.itype == TMS_rptb && is_tail(get_flags(v)) )
{
// small hack to display end_loop-1 instead of before_end_loop+1
v++;
addr++;
rptb_tail = true;
}
bool ok = out_name_expr(x, v, addr);
if ( !ok )
{
out_value(x, OOF_ADDR|OOF_NUMBER|OOFS_NOSIGN|OOFW_16);
remember_problem(PR_NONAME, insn.ea);
}
else
{
if ( rptb_tail )
{
out_symbol('-');
out_line("1", COLOR_NUMBER);
}
}
}
break;
case o_void:
return 0;
case o_bit:
{
static const char *const bitnames[] =
{
"intm", "ovm", "cnf", "sxm",
"hm", "tc", "xf", "c"
};
out_keyword(bitnames[uchar(x.value)]);
}
break;
case o_cond:
{
int mask = int(x.value>>0) & 0xF;
int cond = int(x.value>>4) & 0xF;
int comma = 1;
out_tagon(COLOR_KEYWORD);
switch ( (mask>>2) & 3 ) // Z L
{
case 0:
comma = 0;
break;
case 1:
out_line((cond>>2)&1 ? "lt" : "gt");
break;
case 2:
out_line((cond>>2)&2 ? "eq" : "neq");
break;
case 3:
switch ( (cond>>2)&3 )
{
case 2: out_line("geq"); break;
case 3: out_line("leq"); break;
}
break;
}
if ( mask & 1 ) // C
{
if ( comma )
out_char(',');
if ( (cond & 1) == 0 )
out_char('n');
out_char('c');
comma = 1;
}
if ( mask & 2 ) // V
{
if ( comma )
out_char(',');
if ( (cond & 2) == 0 )
out_char('n');
out_char('o');
out_char('v');
comma = 1;
}
static const char *const TP[] = { "bio", "tc", "ntc", NULL };
const char *ptr = TP[int(x.value>>8) & 3];
if ( ptr != NULL )
{
if ( comma )
out_char(',');
out_line(ptr);
}
out_tagoff(COLOR_KEYWORD);
}
break;
default:
warning("out: %a: bad optype %d", insn.ea, x.type);
break;
}
return 1;
}
//----------------------------------------------------------------------
int out_tms320c5_t::outnextar(const op_t &o, bool comma)
{
if ( o.type == o_phrase && (o.phrase & 8) != 0 )
{
if ( comma )
{
out_symbol(',');
out_char(' ');
}
outreg(rAr0+(o.phrase&7));
return 1;
}
return 0;
}
//----------------------------------------------------------------------
static int isDelayed(ushort code)
{
// 7D?? BD 0111 1101 1AAA AAAA + 1 Branch unconditional with AR update delayed
// 7E?? CALLD 0111 1110 1AAA AAAA + 1 Call unconditional with AR update delayed
// 7F?? BANZD 0111 1111 1AAA AAAA + 1 Branch AR=0 with AR update delayed
// BE3D CALAD 1011 1110 0011 1101 Call subroutine addressed by ACC delayed
// BE21 BACCD 1011 1110 0010 0001 Branch addressed by ACC delayed
// FF00 RETD 1111 1111 0000 0000 Return, delayed
// F??? CCD 1111 10TP ZLVC ZLVC + 1 Call conditional delayed
// F??? RETCD 1111 11TP ZLVC ZLVC Return conditional delayed
// F??? BCNDD 1111 00TP ZLVC ZLVC + 1 Branch conditional delayed
ushort subcode;
switch ( code>>12 )
{
case 7:
subcode = (code >> 7);
return subcode == 0xFB || subcode == 0xFD || subcode == 0xFF;
case 0xB:
return code == 0xBE21u || code == 0xBE3Du;
case 0xF:
if ( code == 0xFF00 )
return 1;
subcode = (code & 0x0C00);
return subcode != 0x400;
}
return 0;
}
//----------------------------------------------------------------------
ea_t prevInstruction(ea_t ea)
{
ea--;
if ( !is_code(get_flags(ea)) )
ea--;
return ea;
}
//----------------------------------------------------------------------
bool out_tms320c5_t::shouldIndent(void) const
{
if ( pm().isC2() )
return false; // TMS320C2 - no indention
if ( !is_flow(F) )
return false; // no previous instructions
ea_t ea = prevInstruction(insn.ea);
flags_t flags = get_flags(ea);
if ( !is_code(flags) )
return false;
if ( isDelayed((ushort)get_wide_byte(ea)) )
return true;
if ( insn.size == 2 ) // our instruction is long
{
; // nothing to do
}
else
{ // our instruction short
if ( (insn.ea-ea) == 2 ) // prev instruction long
return false; // can't be executed in delayed manner
if ( !is_flow(flags) )
return false; // no prev instr...
ea = prevInstruction(ea);
flags = get_flags(ea);
}
return is_code(flags) && isDelayed((ushort)get_wide_byte(ea));
}
//----------------------------------------------------------------------
void out_tms320c5_t::outphraseAr(void)
{
ea_t ar;
if ( pm().find_ar(insn, &ar) )
{
char buf[MAXSTR];
ea2str(buf, sizeof(buf), ar);
out_printf(COLSTR(" %s(%s)", SCOLOR_AUTOCMT), ash.cmnt, buf);
}
}
//----------------------------------------------------------------------
void out_tms320c5_t::OutImmVoid(const op_t &x)
{
if ( !pm().tmsfunny )
return;
if ( x.type == o_imm )
{
if ( x.value != 0 )
{
int v = int(short(x.value) * 10000L / 0x7FFF);
out_char(' ');
out_tagon(COLOR_AUTOCMT);
out_line(ash.cmnt);
out_char(' ');
if ( v < 0 )
{
out_char('-');
v = -v;
}
char buf[10];
if ( v == 10000 )
qstrncpy(buf, "1.0000", sizeof(buf));
else
qsnprintf(buf, sizeof(buf), "0.%04d", v);
out_line(buf);
out_tagoff(COLOR_AUTOCMT);
}
}
}
//----------------------------------------------------------------------
void out_tms320c5_t::out_insn(void)
{
if ( shouldIndent() )
out_char(' ');
out_mnemonic();
bool comma = insn.Op1.shown() && out_one_operand(0);
if ( insn.Op2.shown() && insn.Op2.type != o_void )
{
if ( comma )
{
out_tagon(COLOR_SYMBOL);
out_char(',');
out_tagoff(COLOR_SYMBOL);
out_char(' ');
}
out_one_operand(1);
}
if ( insn.Op1.type == o_phrase )
if ( outnextar(insn.Op1, comma) )
comma = true;
if ( insn.Op2.type == o_phrase )
outnextar(insn.Op2, comma);
out_immchar_cmts();
if ( has_phrase() )
outphraseAr();
flush_outbuf();
}
//--------------------------------------------------------------------------
void idaapi header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
}
//--------------------------------------------------------------------------
//lint -e{818} seg could be const
void tms320c5_t::segstart(outctx_t &ctx, segment_t *seg) const
{
qstring sname;
get_visible_segm_name(&sname, seg);
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".sect \"%s\"", SCOLOR_ASMDIR), sname.c_str());
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
{
ea_t org = seg->start_ea - get_segm_base(seg);
if ( org != 0 )
{
char buf[MAX_NUMBUF];
btoa(buf, sizeof(buf), org);
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s .org %s", SCOLOR_AUTOCMT),
ash.cmnt, buf);
}
}
}
//--------------------------------------------------------------------------
void tms320c5_t::footer(outctx_t &ctx) const
{
if ( ash.end != NULL )
{
ctx.gen_empty_line();
ctx.out_line(ash.end, COLOR_ASMDIR);
qstring name;
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
{
ctx.out_char(' ');
ctx.out_line(name.begin());
}
ctx.flush_outbuf(DEFAULT_INDENT);
}
else
{
ctx.gen_cmt_line("end of file");
}
}
//--------------------------------------------------------------------------
//lint -e{1764} ctx could be const
void tms320c5_t::tms_assumes(outctx_t &ctx) const
{
ea_t ea = ctx.insn_ea;
segment_t *seg = getseg(ea);
if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || seg == NULL )
return;
bool seg_started = (ea == seg->start_ea);
if ( seg->type == SEG_XTRN
|| seg->type == SEG_DATA
|| (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 )
{
return;
}
sreg_range_t sra;
if ( !get_sreg_range(&sra, ea, rDP) )
return;
bool show = sra.start_ea == ea;
if ( show )
{
sreg_range_t prev_sra;
if ( get_prev_sreg_range(&prev_sra, ea, rDP) )
show = sra.val != prev_sra.val;
}
if ( seg_started || show )
ctx.gen_printf(DEFAULT_INDENT,
COLSTR("%s --- assume DP %04a", SCOLOR_AUTOCMT),
ash.cmnt, sra.val);
}

View File

@@ -0,0 +1,360 @@
/*
* Interactive disassembler (IDA).
* Version 3.05
* Copyright (c) 1990-95 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* FIDO: 2:5020/209
* E-mail: ig@estar.msk.su
*
*/
#include "tms.hpp"
//--------------------------------------------------------------------------
static const char *const RegNames[] =
{
"acc","p","bmar",
"ar0","ar1","ar2","ar3","ar4","ar5","ar6","ar7",
"cs","ds","dp"
};
//--------------------------------------------------------------------------
const static predefined_t iregs[] =
{
{ 0x00, "Reserved_0", NULL },
{ 0x01, "Reserved_1", NULL },
{ 0x02, "Reserved_2", NULL },
{ 0x03, "Reserved_3", NULL },
{ 0x04, "imr", "Interrupt mask register" },
{ 0x05, "greg", "Global memory allocation register" },
{ 0x06, "ifr", "Interrupt flag register" },
{ 0x07, "pmst", "Processor mode status register" },
{ 0x08, "rptc", "Repeat counter register" },
{ 0x09, "brcr", "Block repeat counter register" },
{ 0x0A, "pasr", "Block repeat program address start register" },
{ 0x0B, "paer", "Block repeat program address end register" },
{ 0x0C, "treg0", "Temp reg - multiplicand" },
{ 0x0D, "treg1", "Temp reg - dynamic shift count (5 bits)" },
{ 0x0E, "treg2", "Temp reg - bit pointer in dynamic bit test (4 bits)" },
{ 0x0F, "dbmr", "Dynamic bit manipulation register" },
{ 0x10, "ar0", NULL },
{ 0x11, "ar1", NULL },
{ 0x12, "ar2", NULL },
{ 0x13, "ar3", NULL },
{ 0x14, "ar4", NULL },
{ 0x15, "ar5", NULL },
{ 0x16, "ar6", NULL },
{ 0x17, "ar7", NULL },
{ 0x18, "indx", "Index register" },
{ 0x19, "arcr", "Auxiliary compare register" },
{ 0x1A, "cbsr1", "Circular buffer 1 start" },
{ 0x1B, "cber1", "Circular buffer 1 end" },
{ 0x1C, "cbsr2", "Circular buffer 2 start" },
{ 0x1D, "cber2", "Circular buffer 2 end" },
{ 0x1E, "cbcr", "Circular buffer control register" },
{ 0x1F, "bmar", "Block move address register" },
{ 0x20, "drr", "Data receive register" },
{ 0x21, "dxr", "Data transmit register" },
{ 0x22, "spc", "Serial port control register" },
{ 0x23, "Reserved_23", NULL },
{ 0x24, "tim", "Timer register" },
{ 0x25, "prd", "Period register" },
{ 0x26, "tcr", "Timer control register" },
{ 0x27, "Reserved_27", NULL },
{ 0x28, "pdwsr", "Program/Data S/W Wait-State register" },
{ 0x29, "iowsr", "I/O Port S/W Wait-State register" },
{ 0x2A, "cwsr", "Control S/W Wait-State register" },
{ 0x2B, "Reserved_2b", NULL },
{ 0x2C, "Reserved_2c", NULL },
{ 0x2D, "Reserved_2d", NULL },
{ 0x2E, "Reserved_2e", NULL },
{ 0x2F, "Reserved_2f", NULL },
{ 0x30, "trcv", "TDM Data receive register" },
{ 0x31, "tdxr", "TDM Data transmit register" },
{ 0x32, "tspc", "TDM Serial port control register" },
{ 0x33, "tcsr", "TDM channel select register" },
{ 0x34, "trta", "TDM Receive/Transmit address register" },
{ 0x35, "trad", "TDM Received address register" },
{ 0x00, NULL, NULL }
};
static const predefined_t c2_iregs[] =
{
{ 0x00, "drr", "Data receive register" },
{ 0x01, "dxr", "Data transmit register" },
{ 0x02, "tim", "Timer register" },
{ 0x03, "prd", "Period register" },
{ 0x04, "imr", "Interrupt mask register" },
{ 0x05, "greg", "Global memory allocation register" },
{ 0x00, NULL, NULL }
};
//----------------------------------------------------------------------
// This old-style callback only returns the processor module object.
static ssize_t idaapi notify(void *, int msgid, va_list)
{
if ( msgid == processor_t::ev_get_procmod )
return size_t(new tms320c5_t);
return 0;
}
//----------------------------------------------------------------------
ssize_t idaapi tms320c5_t::on_event(ssize_t msgid, va_list va)
{
int retcode = 0;
switch ( msgid )
{
case processor_t::ev_newfile:
{
inf_set_wide_high_byte_first(true);
segment_t *sptr = get_first_seg();
ea_t codeseg;
if ( sptr != NULL )
{
codeseg = sptr->start_ea;
if ( codeseg-get_segm_base(sptr) == 0 )
{
inf_set_start_ea(sptr->start_ea);
inf_set_start_ip(0);
}
}
else
{
codeseg = BADADDR;
}
set_segm_class(sptr, "CODE");
set_segm_name(sptr,"cseg");
sel_t sel;
ea_t data_start;
segment_t *s1 = get_next_seg(codeseg);
if ( s1 == NULL )
{
segment_t s;
uint32 size = 64 * 1024L;
s.start_ea = free_chunk(0,size,0xF);
s.end_ea = s.start_ea + size;
s.sel = ushort(s.start_ea >> 4);
s.align = saRelByte;
s.comb = scPub;
add_segm_ex(&s, "dseg", NULL, ADDSEG_NOSREG);
sel = s.sel;
data_start = s.start_ea;
}
else
{
sel = s1->sel;
data_start = s1->start_ea;
}
set_default_sreg_value(getseg(codeseg), rVds, sel);
split_sreg_range(inf_get_start_ea(), rDP, 0, SR_auto);
inf_set_nametype(NM_NAM_OFF);
const predefined_t *ptr = isC2() ? c2_iregs : iregs;
for ( ; ptr->name != NULL; ptr++ )
{
ea_t ea = data_start + ptr->addr;
create_byte(ea,1);
set_name(ea, ptr->name, SN_NODUMMY);
if ( ptr->cmt != NULL )
set_cmt(ea, ptr->cmt, true);
}
tmsfunny = qgetenv("TMSFIX");
}
break;
case processor_t::ev_newprc:
nprc = va_arg(va, int);
// bool keep_cfg = va_argi(va, bool);
break;
case processor_t::ev_ending_undo:
nprc = ph.get_proc_index();
//fall through
case processor_t::ev_oldfile:
inf_set_wide_high_byte_first(true); // to be able to work with old bases
break;
case processor_t::ev_out_header:
{
outctx_t *ctx = va_arg(va, outctx_t *);
header(*ctx);
return 1;
}
case processor_t::ev_out_footer:
{
outctx_t *ctx = va_arg(va, outctx_t *);
footer(*ctx);
return 1;
}
case processor_t::ev_out_segstart:
{
outctx_t *ctx = va_arg(va, outctx_t *);
segment_t *seg = va_arg(va, segment_t *);
segstart(*ctx, seg);
return 1;
}
case processor_t::ev_out_assumes:
{
outctx_t *ctx = va_arg(va, outctx_t *);
tms_assumes(*ctx);
return 1;
}
case processor_t::ev_ana_insn:
{
insn_t *out = va_arg(va, insn_t *);
return ana(out);
}
case processor_t::ev_emu_insn:
{
const insn_t *insn = va_arg(va, const insn_t *);
return emu(*insn) ? 1 : -1;
}
case processor_t::ev_out_insn:
{
outctx_t *ctx = va_arg(va, outctx_t *);
out_insn(*ctx);
return 1;
}
case processor_t::ev_out_operand:
{
outctx_t *ctx = va_arg(va, outctx_t *);
const op_t *op = va_arg(va, const op_t *);
return out_opnd(*ctx, *op) ? 1 : -1;
}
default:
break;
}
return retcode;
}
//-----------------------------------------------------------------------
// DSP Fixed Point COFF Assembler Version 6.20
// Copyright (c) 1987-1991 Texas Instruments Incorporated
//-----------------------------------------------------------------------
static const char *const dspasm_header[] =
{
".mmregs",
NULL
};
static const asm_t dspasm =
{
AS_COLON | ASH_HEXF0,
0,
"DSP Fixed Point COFF Assembler Version 6.20",
0,
dspasm_header, // header lines
NULL, // org
".end",
";", // comment string
'"', // string delimiter
'\'', // char delimiter
"\\\"'", // special symbols in char and string constants
".string", // ascii string directive
".word", // byte directive
".long", // word directive
NULL, // double words
NULL, // no qwords
NULL, // oword (16 bytes)
NULL, // float (4 bytes)
NULL, // double (8 bytes)
NULL, // tbyte (10/12 bytes)
NULL, // packed decimal real
NULL, // arrays (#h,#d,#v,#s(...)
".space 16*%s",// uninited arrays
".set", // equ
NULL, // seg prefix
NULL, // curip
NULL, // func_header
NULL, // func_footer
NULL, // public
NULL, // weak
NULL, // extrn
NULL, // comm
NULL, // get_type_name
NULL, // align
'(', ')', // lbrace, rbrace
NULL, // mod
NULL, // and
NULL, // or
NULL, // xor
NULL, // not
NULL, // shl
NULL, // shr
NULL, // sizeof
};
static const asm_t *const asms[] = { &dspasm, NULL };
//-----------------------------------------------------------------------
#define FAMILY "TMS320C5x series:"
static const char *const shnames[] = { "TMS320C5", "TMS320C2", NULL };
static const char *const lnames[] =
{
FAMILY"Texas Instruments TMS320C5x",
"Texas Instruments TMS320C2x",
NULL
};
//--------------------------------------------------------------------------
static const uchar retcode_1[] = { 0x00, 0xEF };
static const uchar retcode_2[] = { 0x00, 0xFF };
static const uchar retcode_3[] = { 0x3A, 0xBE };
static const uchar retcode_4[] = { 0x38, 0xBE };
static const bytes_t retcodes[] =
{
{ sizeof(retcode_1), retcode_1 },
{ sizeof(retcode_2), retcode_2 },
{ sizeof(retcode_3), retcode_3 },
{ sizeof(retcode_4), retcode_4 },
{ 0, NULL }
};
//-----------------------------------------------------------------------
// Processor Definition
//-----------------------------------------------------------------------
processor_t LPH =
{
IDP_INTERFACE_VERSION, // version
PLFM_TMS, // id
// flag
PR_SEGS
| PR_RNAMESOK // can use register names for byte names
| PR_SEGTRANS,
// flag2
0,
16, // 8 bits in a byte for code segments
16, // 8 bits in a byte for other segments
shnames,
lnames,
asms,
notify,
RegNames, // Register names
qnumber(RegNames), // Number of registers
rVcs, // first
rDP, // last
2, // size of a segment register
rVcs,rVds,
NULL, // No known code start sequences
retcodes,
0,TMS_last,
Instructions, // instruc
};

View File

@@ -0,0 +1,79 @@
/*
* Interactive disassembler (IDA).
* Version 3.05
* Copyright (c) 1990-95 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* FIDO: 2:5020/209
* E-mail: ig@estar.msk.su
*
*/
#ifndef _TMS_HPP
#define _TMS_HPP
#include "../idaidp.hpp"
#include "ins.hpp"
#include <segregs.hpp>
//------------------------------------------------------------------------
// customization of cmd structure:
#define o_bit o_idpspec0
#define o_bitnot o_idpspec1
#define o_cond o_idpspec2
#define sib specflag1
#define Cond reg
#define PT_TMS320C5 0
#define PT_TMS320C2 1
//------------------------------------------------------------------------
struct tms320c5_t : public procmod_t
{
int nprc = 0; // processor number
int tmsfunny = -1;
uint code;
bool flow = false;
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
int ana(insn_t *insn);
int op_iaa(const insn_t &insn, op_t &o) const;
int op_indir(op_t &o);
int op_maa(const insn_t &insn, op_t &o) const;
void op_short(op_t &o) const;
int op_cond(op_t &o) const;
void op_bit(op_t &o) const;
int ana_c2(insn_t &insn);
int emu(const insn_t &insn);
void handle_operand(const insn_t &insn, const op_t &x, bool isload);
int find_ar(const insn_t &insn, ea_t *res) const;
bool can_flow(const insn_t &insn) const;
bool isC2(void) const { return nprc == PT_TMS320C2; }
void segstart(outctx_t &ctx, segment_t *seg) const;
void footer(outctx_t &ctx) const;
void tms_assumes(outctx_t &ctx) const;
};
//------------------------------------------------------------------------
enum TMS_registers { rAcc,rP,rBMAR,rAr0,rAr1,rAr2,rAr3,rAr4,rAr5,rAr6,rAr7,rVcs,rVds,rDP };
enum TMS_bits { bit_intm,bit_ovm,bit_cnf,bit_sxm,bit_hm,bit_tc,bit_xf,bit_c };
//------------------------------------------------------------------------
struct predefined_t
{
uchar addr;
const char *name;
const char *cmt;
};
bool is_mpy(const insn_t &insn);
ea_t prevInstruction(ea_t ea);
//------------------------------------------------------------------------
void idaapi header(outctx_t &ctx);
#endif