/* codepdp11.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS */
/* */
/* Code Generator PDP-11 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include "bpemu.h"
#include "strutil.h"
#include "headids.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmallg.h"
#include "asmcode.h"
#include "asmitree.h"
#include "codevars.h"
#include "codepseudo.h"
#include "errmsg.h"
#include "intpseudo.h"
#include "motpseudo.h"
#include "onoff_common.h"
#include "cpu2phys.h"
#include "decfloat.h"
#include "codepdp11.h"
#define default_regsyms_name "DEFAULT_REGSYMS"
#define REG_PC 7
#define REG_SP 6
#define APR_COUNT 8
#define ASSUME_COUNT (2 * APR_COUNT)
typedef enum
{
ModReg = 0,
ModImm = 1,
ModMem = 2
} adr_mode_t;
#define MModReg (1 << ModReg)
#define MModImm (1 << ModImm)
#define MModMem (1 << ModMem)
#define CODE_FLAG_GEN_IMM (1 << 0)
#define CODE_FLAG_16BIT (1 << 1)
/* only used for FP11 insns */
#define CODE_FLAG_32BIT (1 << 2)
#define CODE_FLAG_F64BIT (1 << 3)
#define CODE_FLAG_ARGSWAP (1 << 4)
typedef struct
{
Word mode;
unsigned count;
Word vals[4];
} adr_vals_t;
enum
{
e_ext_eis = 0, /* MUL, DIV, ASH, ASHC */
e_ext_fis = 1, /* FADD, FSUB, FDIV, FMUL */
e_ext_fp11 = 2,
e_ext_cis = 3,
e_ext_opt_cnt,
e_ext_sob_sxt = e_ext_opt_cnt,
e_ext_xor = 5,
e_ext_rtt = 6,
e_ext_mark = 7,
e_ext_mfpt = 8,
e_ext_mfp_mtp = 9,
e_ext_spl = 10,
e_ext_csm = 11,
e_ext_wrtlck = 12,
e_ext_tstset = 13,
e_ext_mfps_mtps = 14,
e_ext_wd16 = 15, /* not a real extension, but an instruction set discriminator */
e_ext_cnt
};
#define e_cpu_flag_eis (1 << e_ext_eis)
#define e_cpu_flag_fis (1 << e_ext_fis)
#define e_cpu_flag_fp11 (1 << e_ext_fp11)
#define e_cpu_flag_cis (1 << e_ext_cis)
#define e_cpu_flag_sob_sxt (1 << e_ext_sob_sxt)
#define e_cpu_flag_xor (1 << e_ext_xor)
#define e_cpu_flag_rtt (1 << e_ext_rtt)
#define e_cpu_flag_mark (1 << e_ext_mark)
#define e_cpu_flag_mfpt (1 << e_ext_mfpt)
#define e_cpu_flag_mfp_mtp (1 << e_ext_mfp_mtp)
#define e_cpu_flag_spl (1 << e_ext_spl)
#define e_cpu_flag_csm (1 << e_ext_csm)
#define e_cpu_flag_wrtlck (1 << e_ext_wrtlck)
#define e_cpu_flag_tstset (1 << e_ext_tstset)
#define e_cpu_flag_mfps_mtps (1 << e_ext_mfps_mtps)
#define e_cpu_flag_wd16 (1 << e_ext_wd16)
typedef struct
{
char name[15];
Byte addr_space, opt_flags;
Word flags;
} cpu_props_t;
static const cpu_props_t *p_curr_cpu_props;
static tSymbolSize op_size;
static Boolean default_regsyms;
static LongInt *reg_par, *reg_pdr;
static Boolean is_wd16(void)
{
return !!(p_curr_cpu_props->flags & e_cpu_flag_wd16);
}
/*-------------------------------------------------------------------------*/
/* Register Symbols */
/*!------------------------------------------------------------------------
* \fn decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
* \brief check whether argument is a CPU register
* \param p_arg argument to check
* \param p_result numeric register value if yes
* \param p_size returns register size
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
{
if (!as_strcasecmp(p_arg, "PC") && default_regsyms)
{
*p_result = REG_PC | REGSYM_FLAG_ALIAS;
*p_size = eSymbolSize16Bit;
return True;
}
else if (!as_strcasecmp(p_arg, "SP") && default_regsyms)
{
*p_result = REG_SP | REGSYM_FLAG_ALIAS;
*p_size = eSymbolSize16Bit;
return True;
}
{
case 2:
if ((((as_toupper(*p_arg) == 'R') && default_regsyms)
|| (*p_arg == '%'))
&& (p_arg[1] < '8'))
{
*p_result = p_arg[1] - '0';
*p_size = eSymbolSize16Bit;
return True;
}
break;
case 3:
if ((as_toupper(*p_arg) == 'A')
&& (as_toupper(p_arg[1]) == 'C')
&& (p_arg[2] < '6'))
{
*p_result = p_arg[2] - '0';
*p_size = eSymbolSizeFloat64Bit;
return True;
}
break;
default:
break;
}
return False;
}
/*!------------------------------------------------------------------------
* \fn dissect_reg_pdp11(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
* \brief dissect register symbols - PDP-11 variant
* \param p_dest destination buffer
* \param dest_size destination buffer size
* \param value numeric register value
* \param inp_size register size
* ------------------------------------------------------------------------ */
static void dissect_reg_pdp11(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
{
switch (inp_size)
{
case eSymbolSize16Bit:
switch (value)
{
case REGSYM_FLAG_ALIAS | REG_PC:
as_snprintf(p_dest, dest_size, "PC");
break;
case REGSYM_FLAG_ALIAS | REG_SP:
as_snprintf(p_dest, dest_size, "SP");
break;
default:
as_snprintf(p_dest, dest_size, "R%u", (unsigned)(value & 7));
}
break;
case eSymbolSizeFloat64Bit:
as_snprintf(p_dest, dest_size, "AC%u", (unsigned)(value & 7));
break;
default:
as_snprintf(p_dest, dest_size, "%d-%u", (int)inp_size, (unsigned)value);
}
}
/*--------------------------------------------------------------------------*/
/* PDP-11 specific flags */
/*!------------------------------------------------------------------------
* \fn onoff_ext_add(Boolean def_value)
* \brief register on/off command for specific instruction set extension
* \param def_value default value of flag upon first use
* ------------------------------------------------------------------------ */
static Byte ext_registered = 0;
unsigned ext_test_and_set(unsigned mask)
{
unsigned curr = ext_registered;
ext_registered |= mask;
return curr & mask;
}
static const char ext_names[e_ext_opt_cnt][5] = { "EIS", "FIS", "FP11", "CIS" };
static Boolean ext_avail[e_ext_opt_cnt];
/* default value setting only upon first registration, similar to scheme in
onoff_common.c: */
static void onoff_ext_add(unsigned ext, Boolean def_value)
{
Byte ext_mask = 1 << ext;
if (!ext_test_and_set(ext_mask))
SetFlag(&ext_avail[ext], ext_names[ext], def_value);
AddONOFF(ext_names[ext], &ext_avail[ext], ext_names[ext], False);
}
/*!------------------------------------------------------------------------
* \fn check_cpu_ext(unsigned ext)
* \brief check whether instruction is allowed on CPU
* \param ext request instruction set extension
* \return True if usage is OK
* ------------------------------------------------------------------------ */
static Boolean check_cpu_ext(unsigned ext)
{
unsigned mask = 1 << ext;
if (p_curr_cpu_props->flags & mask)
return True;
else if ((ext < e_ext_opt_cnt) && (p_curr_cpu_props->opt_flags & mask) && ext_avail[ext])
return True;
else
{
if (ext < e_ext_opt_cnt)
WrXErrorPos(ErrNum_InstructionNotSupported, ext_names[ext], &OpPart.Pos);
else
WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
return False;
}
}
/*--------------------------------------------------------------------------*/
/* Address Mode Parser */
/*!------------------------------------------------------------------------
* \fn check_sup_mode(void)
* \brief check for CPU in supervisor mode
* \return constant true
* ------------------------------------------------------------------------ */
static Boolean check_sup_mode(void)
{
if (!SupAllowed)
WrStrErrorPos(ErrNum_PrivOrder, &OpPart);
return True;
}
/*!------------------------------------------------------------------------
* \fn reset_adr_vals(adr_vals_t *p_vals)
* \brief clear encoded addressing mode
* \param p_vals encoded mode to reset
* ------------------------------------------------------------------------ */
static void reset_adr_vals(adr_vals_t *p_vals)
{
p_vals->mode = 0;
p_vals->count = 0;
p_vals->vals[0] = 0;
}
/*!------------------------------------------------------------------------
* \fn decode_reg(const tStrComp *p_arg, Word *p_result, tSymbolSize *p_size, tSymbolSize req_size, Boolean must_be_reg)
* \brief check whether argument is a CPU register or register alias
* \param p_arg argument to check
* \param p_result numeric register value if yes
* \param p_size returns operand size of register (I16 or F64)
* \param req_size request specific operand/register size
* \param must_be_reg argument is expected to be a register
* \return RegEvalResult
* ------------------------------------------------------------------------ */
static tErrorNum chk_reg_size(tSymbolSize req_size, tSymbolSize act_size)
{
if ((act_size == eSymbolSizeUnknown)
|| (req_size == eSymbolSizeUnknown)
|| (req_size == act_size))
return ErrNum_None;
else if ((req_size == eSymbolSize16Bit) && (act_size == eSymbolSizeFloat64Bit))
return ErrNum_IntButFloat;
else if ((req_size == eSymbolSizeFloat64Bit) && (act_size == eSymbolSize16Bit))
return ErrNum_FloatButInt;
else
return ErrNum_InvOpSize;
}
static tRegEvalResult decode_reg(const tStrComp *p_arg, Word *p_result, tSymbolSize *p_size, tSymbolSize req_size, Boolean must_be_reg)
{
tRegDescr reg_descr;
tEvalResult eval_result;
tRegEvalResult reg_eval_result;
if (decode_reg_core(p_arg->str.p_str, p_result, &eval_result.DataSize))
{
reg_descr.Reg = *p_result;
reg_eval_result = eIsReg;
}
else
reg_eval_result = EvalStrRegExpressionAsOperand(p_arg, ®_descr, &eval_result, eSymbolSizeUnknown, must_be_reg);
if (reg_eval_result == eIsReg)
{
tErrorNum error_num = chk_reg_size(req_size, eval_result.DataSize);
if (error_num)
{
WrStrErrorPos(error_num, p_arg);
reg_eval_result = must_be_reg ? eIsNoReg : eRegAbort;
}
}
*p_result = reg_descr.Reg & ~REGSYM_FLAG_ALIAS;
if (p_size) *p_size = eval_result.DataSize;
return reg_eval_result;
}
static Boolean decode_reg_or_const(const tStrComp *p_arg, Word *p_result)
{
switch (decode_reg(p_arg, p_result, NULL, eSymbolSize16Bit, False))
{
case eIsReg:
return True;
case eIsNoReg:
{
Boolean ok;
*p_result = EvalStrIntExpression(p_arg, UInt3, &ok);
return ok;
}
default:
return False;
}
}
/*!------------------------------------------------------------------------
* \fn decode_adr(tStrComp *p_arg, adr_vals_t *p_result, Word pc_value, unsigned mode_mask)
* \brief parse address expression
* \param p_arg source argument
* \param p_result parsed result
* \param pc_value value of PC to be used in PC-relative calculation
* \param mode_mask bit mask of allowed addressing modes
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean is_pre_decrement(const tStrComp *p_arg, Word *p_result, tRegEvalResult *p_reg_eval_result)
{
String reg;
tStrComp reg_comp;
size_t arg_len
= strlen(p_arg
->str.
p_str);
if ((arg_len < 4)
|| (p_arg->str.p_str[0] != '-')
|| (p_arg->str.p_str[1] != '(')
|| (p_arg->str.p_str[arg_len - 1] != ')'))
return False;
StrCompMkTemp(®_comp, reg, sizeof(reg));
StrCompCopySub(®_comp, p_arg, 2, arg_len - 3);
KillPrefBlanksStrComp(®_comp);
KillPostBlanksStrComp(®_comp);
*p_reg_eval_result = decode_reg(®_comp, p_result, NULL, eSymbolSize16Bit, False);
return (*p_reg_eval_result != eIsNoReg);
}
static Boolean is_post_increment(const tStrComp *p_arg, Word *p_result, tRegEvalResult *p_reg_eval_result)
{
String reg;
tStrComp reg_comp;
size_t arg_len
= strlen(p_arg
->str.
p_str);
if ((arg_len < 4)
|| (p_arg->str.p_str[0] != '(')
|| (p_arg->str.p_str[arg_len - 2] != ')')
|| (p_arg->str.p_str[arg_len - 1] != '+'))
return False;
StrCompMkTemp(®_comp, reg, sizeof(reg));
StrCompCopySub(®_comp, p_arg, 1, arg_len - 3);
KillPrefBlanksStrComp(®_comp);
KillPostBlanksStrComp(®_comp);
/* Opposed to -(...), (...)+ cannot be interpreted as an arbitrary
arithmetic expression. The expression in parentheses MUST be a
register: */
*p_reg_eval_result = decode_reg(®_comp, p_result, NULL, eSymbolSize16Bit, True);
if (*p_reg_eval_result == eIsNoReg)
*p_reg_eval_result = eRegAbort;
return (*p_reg_eval_result != eIsNoReg);
}
static Boolean decode_abs(const tStrComp *p_arg, Word *p_addr)
{
Boolean ok;
*p_addr = EvalStrIntExpression(p_arg, UInt16, &ok);
return ok;
}
static Boolean decode_imm8(const tStrComp *p_arg, Word *p_value)
{
Boolean ok;
*p_value = EvalStrIntExpression(p_arg, Int8, &ok) & 0xff;
return ok;
}
static Boolean check_mode_mask(unsigned mode_mask, unsigned act_mask, tStrComp *p_arg)
{
if (!(mode_mask & act_mask))
{
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
return False;
}
else
return True;
}
static Boolean decode_adr(tStrComp *p_arg, adr_vals_t *p_result, Word pc_value, unsigned mode_mask)
{
tEvalResult eval_result;
tRegEvalResult reg_eval_result;
Boolean deferred;
tStrComp arg;
int arg_len, split_pos;
reset_adr_vals(p_result);
/* split off deferred flag? */
deferred = (p_arg->str.p_str[0] == '@');
StrCompRefRight(&arg, p_arg, deferred);
if (deferred)
KillPrefBlanksStrCompRef(&arg);
/* Rn, @Rn, ACn: */
switch (decode_reg(&arg, &p_result->mode, NULL, (deferred || (op_size < eSymbolSizeFloat32Bit)) ? eSymbolSize16Bit : eSymbolSizeFloat64Bit, False))
{
case eIsReg:
p_result->mode |= deferred ? 010 : 000;
return check_mode_mask(mode_mask, deferred ? MModMem : MModReg, p_arg);
case eRegAbort:
return False;
default:
break;
}
/* #imm, @#abs */
if (*arg.str.p_str == '#')
{
tStrComp imm_arg;
if (!deferred && !check_mode_mask(mode_mask, deferred ? MModMem : MModImm, p_arg))
return False;
StrCompRefRight(&imm_arg, &arg, 1);
if (deferred)
{
eval_result.OK = decode_abs(&imm_arg, &p_result->vals[0]);
if (eval_result.OK)
p_result->count = 2;
}
else switch (op_size)
{
case eSymbolSize8Bit:
eval_result.OK = decode_imm8(&imm_arg, &p_result->vals[0]);
if (eval_result.OK)
p_result->count = 2;
break;
case eSymbolSize16Bit:
p_result->vals[0] = EvalStrIntExpressionWithResult(&imm_arg, Int16, &eval_result);
if (eval_result.OK)
p_result->count = 2;
break;
case eSymbolSize32Bit:
{
LongWord l_val = EvalStrIntExpressionWithResult(&imm_arg, Int32, &eval_result);
if (eval_result.OK)
{
p_result->vals[0] = (l_val >> 16) & 0xffff;
p_result->vals[1] = l_val & 0xffff;
p_result->count = 4;
}
break;
}
case eSymbolSizeFloat32Bit:
{
Double f_val = EvalStrFloatExpressionWithResult(&imm_arg, Float64, &eval_result);
if (eval_result.OK)
{
int ret = Double_2_dec4(f_val, p_result->vals);
eval_result.OK = check_dec_fp_dispose_result(ret, &imm_arg);
}
if (eval_result.OK)
p_result->count = 4;
break;
}
case eSymbolSizeFloat64Bit:
{
Double f_val = EvalStrFloatExpressionWithResult(&imm_arg, Float64, &eval_result);
if (eval_result.OK)
{
int ret = Double_2_dec8(f_val, p_result->vals);
eval_result.OK = check_dec_fp_dispose_result(ret, &imm_arg);
}
if (eval_result.OK)
p_result->count = 8;
break;
}
case eSymbolSizeUnknown:
WrStrErrorPos(ErrNum_UndefOpSizes, p_arg);
eval_result.OK = False;
break;
default:
WrStrErrorPos(ErrNum_InvOpSize, p_arg);
eval_result.OK = False;
}
if (eval_result.OK)
{
/* immediate is actually (PC)+, absolute is actually @(PC)+ */
p_result->mode = (deferred ? 030 : 020) | REG_PC;
}
return eval_result.OK;
}
/* (Rn)+, @(Rn)+ */
if (is_post_increment(&arg, &p_result->mode, ®_eval_result))
{
if (eRegAbort == reg_eval_result)
return False;
p_result->mode |= deferred ? 030 : 020;
return check_mode_mask(mode_mask, MModMem, p_arg);
}
/* -(Rn), @-(Rn) */
if (is_pre_decrement(&arg, &p_result->mode, ®_eval_result))
{
if (eRegAbort == reg_eval_result)
return False;
p_result->mode |= (deferred ? 050 : 040);
return check_mode_mask(mode_mask, MModMem, p_arg);
}
/* (Rn), X(Rn) */
split_pos = FindDispBaseSplitWithQualifier(arg.str.p_str, &arg_len, NULL, "()");
if (split_pos >= 0)
{
tStrComp disp_arg, reg_arg;
StrCompSplitRef(&disp_arg, ®_arg, &arg, &arg.str.p_str[split_pos]);
KillPostBlanksStrComp(&disp_arg);
KillPrefBlanksStrCompRef(®_arg);
StrCompShorten(®_arg, 1);
KillPostBlanksStrComp(®_arg);
if (!decode_reg_or_const(®_arg, &p_result->mode))
return False;
if (!*disp_arg.str.p_str && !deferred)
p_result->mode |= 010;
else
{
p_result->vals[0] = EvalStrIntExpressionWithResult(&disp_arg, Int16, &eval_result);
if (!eval_result.OK)
return False;
p_result->mode |= deferred ? 070 : 060;
p_result->count = 2;
}
return check_mode_mask(mode_mask, MModMem, p_arg);
}
/* Remains: rel, @rel
PC value is the PC value after displacement was loaded: */
p_result->vals[0] = EvalStrIntExpressionWithResult(&arg, UInt16, &eval_result) - (pc_value + 2);
if (!eval_result.OK)
return False;
p_result->mode = REG_PC | (deferred ? 070 : 060);
p_result->count = 2;
return check_mode_mask(mode_mask, MModMem, p_arg);
}
/*!------------------------------------------------------------------------
* \fn decode_ac_03(tStrComp *p_arg, Word *p_result)
* \brief handle FP11 argument that may only refer AC0...AC3
* \param p_arg source argument
* \param p_result resulting AC number
* \return True if valid argument
* ------------------------------------------------------------------------ */
static Boolean decode_ac_03(tStrComp *p_arg, Word *p_result)
{
adr_vals_t adr_vals;
/* operand size must have been set to a floating point type before */
if (!decode_adr(p_arg, &adr_vals, EProgCounter() + 2, MModReg))
return False;
*p_result = adr_vals.mode & 7;
if (*p_result > 3)
{
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
return False;
}
return True;
}
/*--------------------------------------------------------------------------*/
/* Instruction Handler Helpers */
static void append_word(Word code)
{
WAsmCode[CodeLen >> 1] = code;
CodeLen += 2;
}
static void append_adr_vals(const adr_vals_t *p_vals)
{
if (p_vals->count >= 2)
append_word(p_vals->vals[0]);
if (p_vals->count >= 4)
append_word(p_vals->vals[1]);
if (p_vals->count >= 6)
append_word(p_vals->vals[2]);
if (p_vals->count >= 8)
append_word(p_vals->vals[3]);
}
static unsigned imm_mask(Word code)
{
return (code & CODE_FLAG_GEN_IMM) ? MModImm : 0;
}
/*--------------------------------------------------------------------------*/
/* Instruction Handlers */
/*!------------------------------------------------------------------------
* \fn decode_fixed(Word code)
* \brief handle instructions without argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fixed(Word code)
{
if (ChkArgCnt(0, 0))
append_word(code);
}
/*!------------------------------------------------------------------------
* \fn decode_fixed_sup(Word code)
* \brief handle privileged instructions without argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fixed_sup(Word code)
{
if (ChkArgCnt(0, 0) && check_sup_mode())
append_word(code);
}
/*!------------------------------------------------------------------------
* \fn decode_mfpt(Word code)
* \brief handle MFPT instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_mfpt(Word code)
{
if (ChkArgCnt(0, 0) && check_cpu_ext(e_ext_mfpt))
append_word(code);
}
/*!------------------------------------------------------------------------
* \fn decode_rtt(Word code)
* \brief handle RTT instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_rtt(Word code)
{
if (ChkArgCnt(0, 0) && check_cpu_ext(e_ext_rtt))
append_word(code);
}
/*!------------------------------------------------------------------------
* \fn decode_one_reg(Word code)
* \brief handle instructions with one register as argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_one_reg(Word code)
{
if (ChkArgCnt(1, 1))
{
adr_vals_t reg_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], ®_adr_vals, EProgCounter() + 2, MModReg))
append_word((code & 0xfff8) | reg_adr_vals.mode);
}
}
/*!------------------------------------------------------------------------
* \fn decode_two_reg(Word code)
* \brief handle instructions with two registers as argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_two_reg(Word code)
{
if (ChkArgCnt(2, 2))
{
adr_vals_t src_adr_vals, dest_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], &src_adr_vals, EProgCounter() + 2, MModReg)
&& decode_adr(&ArgStr[2], &dest_adr_vals, EProgCounter() + 2, MModReg))
append_word((code & 0xffc0) | ((src_adr_vals.mode & 7) << 3) | (dest_adr_vals.mode & 7));
}
}
/*!------------------------------------------------------------------------
* \fn decode_one_arg(Word code)
* \brief handle instructions with one generic arg
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_one_arg(Word code)
{
if (ChkArgCnt(1, 1))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_tstset(Word code)
* \brief handle TSTSET instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_tstset(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_tstset))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_mfp_mtp(Word code)
* \brief handle MFP/MTP instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_mfp_mtp(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_mfp_mtp))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_mfps_mtps(Word code)
* \brief handle MFPS/MTPS instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_mfps_mtps(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_mfps_mtps))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_csm(Word code)
* \brief handle CSM instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_csm(Word code)
{
/* TODO: not in kernel mode */
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_csm))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_sxt(Word code)
* \brief handle SXT instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_sxt(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_sob_sxt))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_fp11_f1_f3(Word code)
* \brief handle FP11 instructions with two arguments (AC is dest)
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fp11_f1_f3(Word code)
{
if (ChkArgCnt(2, 2) && check_cpu_ext(e_ext_fp11))
{
adr_vals_t adr_vals;
Word ac_num;
int ac_arg_index = (code & CODE_FLAG_ARGSWAP) ? 1 : 2;
if (code & CODE_FLAG_16BIT)
op_size = eSymbolSize16Bit;
else if (code & CODE_FLAG_32BIT)
op_size = eSymbolSize32Bit;
else if (code & CODE_FLAG_F64BIT)
op_size = eSymbolSizeFloat64Bit;
else
op_size = eSymbolSizeFloat32Bit;
if (decode_adr(&ArgStr[3 - ac_arg_index], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
op_size = (code & CODE_FLAG_F64BIT) ? eSymbolSizeFloat64Bit : eSymbolSizeFloat32Bit;
if (decode_ac_03(&ArgStr[ac_arg_index], &ac_num))
{
append_word((code & 0177400) | (ac_num << 6) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_fp11_f2(Word code)
* \brief handle FP11 instructions with one (float) arg
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fp11_f2(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_fp11))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_F64BIT) ? eSymbolSizeFloat64Bit : eSymbolSizeFloat32Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn void decode_fp11_f4(Word code)
* \brief handle FP11 instructions with one (int) arg
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fp11_f4(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_fp11))
{
adr_vals_t adr_vals;
if (code & CODE_FLAG_16BIT)
op_size = eSymbolSize16Bit;
else if (code & CODE_FLAG_32BIT)
op_size = eSymbolSize32Bit;
else
op_size = eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_fp11_f5(Word code)
* \brief handle FP11 instructions with no arg
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fp11_f5(Word code)
{
if (ChkArgCnt(0, 0) && check_cpu_ext(e_ext_fp11))
append_word(code);
}
/*!------------------------------------------------------------------------
* \fn decode_cis_0(Word code)
* \brief handle CIS instructions with no arguments
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_0(Word code)
{
if (ChkArgCnt(0, 0) && check_cpu_ext(e_ext_cis))
append_word(code);
}
/* TODO: CIS instructions take address of descriptors. Should
this be written as absolute addressing? */
/*!------------------------------------------------------------------------
* \fn decode_cis_1i(Word code)
* \brief handle CIS instructions with one address and one immediate argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_1i(Word code)
{
Word src, imm;
if (ChkArgCnt(2, 2)
&& check_cpu_ext(e_ext_cis)
&& decode_abs(&ArgStr[1], &src)
&& decode_imm8(&ArgStr[2], &imm))
{
append_word(code);
append_word(src);
append_word(imm);
}
}
/*!------------------------------------------------------------------------
* \fn decode_cis_2(Word code)
* \brief handle CIS instructions with two address arguments
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_2(Word code)
{
Word src, dest;
if (ChkArgCnt(2, 2)
&& check_cpu_ext(e_ext_cis)
&& decode_abs(&ArgStr[1], &src)
&& decode_abs(&ArgStr[2], &dest))
{
append_word(code);
append_word(src);
append_word(dest);
}
}
/*!------------------------------------------------------------------------
* \fn decode_cis_2i(Word code)
* \brief handle CIS instructions with two address and one immediate argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_2i(Word code)
{
Word src, dest, imm;
if (ChkArgCnt(3, 3)
&& check_cpu_ext(e_ext_cis)
&& decode_abs(&ArgStr[1], &src)
&& decode_abs(&ArgStr[2], &dest)
&& decode_imm8(&ArgStr[3], &imm))
{
append_word(code);
append_word(src);
append_word(dest);
append_word(imm);
}
}
/*!------------------------------------------------------------------------
* \fn decode_cis_2i1(Word code)
* \brief handle CIS instructions with two src address, one immediate,
and one dest address argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_2i1(Word code)
{
Word src1, src2, dest, imm;
if (ChkArgCnt(4, 4)
&& check_cpu_ext(e_ext_cis)
&& decode_abs(&ArgStr[1], &src1)
&& decode_abs(&ArgStr[2], &src2)
&& decode_imm8(&ArgStr[3], &imm)
&& decode_abs(&ArgStr[4], &dest))
{
append_word(code);
append_word(src1);
append_word(src2);
append_word(imm);
append_word(dest);
}
}
/*!------------------------------------------------------------------------
* \fn decode_cis_3(Word code)
* \brief handle CIS instructions with three address arguments
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_3(Word code)
{
Word src1, src2, dest;
if (ChkArgCnt(3, 3)
&& check_cpu_ext(e_ext_cis)
&& decode_abs(&ArgStr[1], &src1)
&& decode_abs(&ArgStr[2], &src2)
&& decode_abs(&ArgStr[3], &dest))
{
append_word(code);
append_word(src1);
append_word(src2);
append_word(dest);
}
}
/*!------------------------------------------------------------------------
* \fn decode_cis_ld(Word code)
* \brief handle CIS instructions with one post-inc argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_cis_ld(Word code)
{
adr_vals_t adr_vals;
if (ChkArgCnt(1, 1)
&& check_cpu_ext(e_ext_cis)
&& decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModMem))
{
if ((adr_vals.mode & 070) != 020) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
else
append_word(code | (adr_vals.mode & 07));
}
}
/*!------------------------------------------------------------------------
* \fn decode_wrtlck(Word code)
* \brief handle WRTLCK instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_wrtlck(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_wrtlck))
{
adr_vals_t adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModMem | imm_mask(code)))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_two_arg(Word code)
* \brief handle instructions with two generic args
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_two_arg(Word code)
{
if (ChkArgCnt(2, 2))
{
adr_vals_t src_adr_vals, dest_adr_vals;
op_size = (code & CODE_FLAG_16BIT) ? eSymbolSize16Bit : eSymbolSize8Bit;
if (decode_adr(&ArgStr[1], &src_adr_vals, EProgCounter() + 2, MModReg | MModMem | MModImm)
&& decode_adr(&ArgStr[2], &dest_adr_vals, EProgCounter() + 2 + src_adr_vals.count, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0170000) | (src_adr_vals.mode << 6) | dest_adr_vals.mode);
append_adr_vals(&src_adr_vals);
append_adr_vals(&dest_adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_eis(Word code)
* \brief handle EIS instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_eis(Word code)
{
if (ChkArgCnt(2, 2) && check_cpu_ext(e_ext_eis))
{
adr_vals_t src_adr_vals, dest_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], &src_adr_vals, EProgCounter() + 2, MModReg | MModMem | MModImm)
&& decode_adr(&ArgStr[2], &dest_adr_vals, EProgCounter() + 2 + src_adr_vals.count, MModReg))
{
append_word((code & 0177000) | ((dest_adr_vals.mode & 7) << 6) | src_adr_vals.mode);
append_adr_vals(&src_adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_reg_gen(Word code)
* \brief handle instructions with one register and one general argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_reg_gen(Word code)
{
if (ChkArgCnt(2, 2))
{
adr_vals_t reg_adr_vals, dest_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], ®_adr_vals, EProgCounter() + 2, MModReg)
&& decode_adr(&ArgStr[2], &dest_adr_vals, EProgCounter() + 2 + reg_adr_vals.count, MModReg | MModMem | MModImm))
{
append_word((code & 0177000) | ((reg_adr_vals.mode & 7) << 6) | dest_adr_vals.mode);
append_adr_vals(&dest_adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_xor(Word code)
* \brief handle XOR instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_xor(Word code)
{
if (ChkArgCnt(2, 2) && check_cpu_ext(e_ext_xor))
{
adr_vals_t src_adr_vals, dest_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], &src_adr_vals, EProgCounter() + 2, MModReg)
&& decode_adr(&ArgStr[2], &dest_adr_vals, EProgCounter() + 2 + src_adr_vals.count, MModReg | MModMem | imm_mask(code)))
{
append_word((code & 0177000) | ((src_adr_vals.mode & 7) << 6) | dest_adr_vals.mode);
append_adr_vals(&dest_adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_fis(Word code)
* \brief handle FIS instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_fis(Word code)
{
adr_vals_t reg_adr_vals;
if (ChkArgCnt(1, 1)
&& check_cpu_ext(e_ext_fis)
&& decode_adr(&ArgStr[1], ®_adr_vals, EProgCounter() + 2, MModReg))
append_word((code & 0177770) | (reg_adr_vals.mode & 7));
}
/*!------------------------------------------------------------------------
* \fn decode_branch(Word code)
* \brief handle branch instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_branch(Word code)
{
if (ChkArgCnt(1, 1))
{
tEvalResult eval_result;
LongInt dist = EvalStrIntExpressionWithResult(&ArgStr[1], UInt16, &eval_result) - (EProgCounter() + 2);
if (eval_result.OK)
{
if ((dist & 1) && !mFirstPassUnknownOrQuestionable(eval_result.Flags)) WrStrErrorPos(ErrNum_DistIsOdd, &ArgStr[1]);
else
{
dist /= 2;
if (!RangeCheck(dist, SInt8) && !mFirstPassUnknownOrQuestionable(eval_result.Flags)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
else
append_word((code & 0xff00) | (dist & 0x00ff));
}
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_sob(Word code)
* \brief handle SOB instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_sob(Word code)
{
adr_vals_t reg_adr_vals;
if (ChkArgCnt(2, 2)
&& check_cpu_ext(e_ext_sob_sxt)
&& decode_adr(&ArgStr[1], ®_adr_vals, EProgCounter() + 2, MModReg))
{
tEvalResult eval_result;
LongInt dist = EvalStrIntExpressionWithResult(&ArgStr[2], UInt16, &eval_result) - (EProgCounter() + 2);
if ((dist & 1) && !mFirstPassUnknownOrQuestionable(eval_result.Flags)) WrStrErrorPos(ErrNum_DistIsOdd, &ArgStr[1]);
else
{
dist /= 2;
if (((dist > 0) || (dist < -63)) && !mFirstPassUnknownOrQuestionable(eval_result.Flags)) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
else
append_word((code & 0177000) | ((reg_adr_vals.mode & 7) << 6) | ((-dist) & 077));
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_jmp(Word code)
* \brief handle JMP instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_jmp(Word code)
{
if (ChkArgCnt(1, 1))
{
adr_vals_t adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], &adr_vals, EProgCounter() + 2, MModMem | MModImm))
{
append_word((code & 0177700) | adr_vals.mode);
append_adr_vals(&adr_vals);
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_jsr_core(Word code, Word reg)
* \brief JSR instruction common core
* \param code machine code
* \param reg register operand
* ------------------------------------------------------------------------ */
static void decode_jsr_core(Word code, Word reg)
{
adr_vals_t addr_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[ArgCnt], &addr_adr_vals, EProgCounter() + 2, (is_wd16() ? 0 : MModReg) | MModMem | MModImm))
{
append_word((code & 0177000) | ((reg & 7) << 6) | addr_adr_vals.mode);
append_adr_vals(&addr_adr_vals);
}
}
/*!------------------------------------------------------------------------
* \fn decode_jsr(Word code)
* \brief handle JSR instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_jsr(Word code)
{
if (ChkArgCnt(2, 2))
{
adr_vals_t reg_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], ®_adr_vals, EProgCounter() + 2, MModReg))
decode_jsr_core(code, reg_adr_vals.mode & 7);
}
}
/*!------------------------------------------------------------------------
* \fn decode_call(Word code)
* \brief handle CALL instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_call(Word code)
{
if (ChkArgCnt(1, 1))
decode_jsr_core(code, REG_PC);
}
/*!------------------------------------------------------------------------
* \fn decode_rts(Word code)
* \brief handle RTS instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_rts(Word code)
{
if (ChkArgCnt(1, 1))
{
adr_vals_t reg_adr_vals;
op_size = eSymbolSize16Bit;
if (decode_adr(&ArgStr[1], ®_adr_vals, EProgCounter() + 2, MModReg))
append_word((code & 0177770) | (reg_adr_vals.mode & 7));
}
}
/*!------------------------------------------------------------------------
* \fn decode_imm6(Word code)
* \brief handle instructions with 6 bit numeric argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_imm6(Word code)
{
if (ChkArgCnt(1, 1))
{
Boolean ok;
Word num = EvalStrIntExpression(&ArgStr[1], UInt6, &ok);
if (ok)
append_word(code | (num & 63));
}
}
/*!------------------------------------------------------------------------
* \fn decode_mark(Word code)
* \brief handle MARK instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_mark(Word code)
{
if (check_cpu_ext(e_ext_mark))
decode_imm6(code);
}
/*!------------------------------------------------------------------------
* \fn decode_imm4p1_reg(Word code)
* \brief handle instructions with 4 bit immediate and register argument
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_imm4p1_reg(Word code)
{
adr_vals_t reg_adr_vals;
if (ChkArgCnt(2, 2)
&& decode_adr(&ArgStr[2], ®_adr_vals, EProgCounter() + 2, MModReg))
{
tEvalResult eval_result;
Word imm_val = EvalStrIntExpressionWithResult(&ArgStr[1], UInt5, &eval_result);
if (eval_result.OK)
{
if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
imm_val = 1;
if (ChkRange(imm_val, 1, 16))
append_word(code | ((reg_adr_vals.mode & 7) << 6) | ((imm_val - 1) & 15));
}
}
}
/*!------------------------------------------------------------------------
* \fn decode_spl(Word code)
* \brief handle SPL instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_spl(Word code)
{
if (ChkArgCnt(1, 1) && check_cpu_ext(e_ext_spl))
{
Boolean ok;
Word num = EvalStrIntExpression(&ArgStr[1], UInt3, &ok);
if (ok)
append_word(code | (num & 7));
}
}
/*!------------------------------------------------------------------------
* \fn decode_trap(Word code)
* \brief handle trap instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_trap(Word code)
{
if (ChkArgCnt(0, 1))
{
Boolean ok = True;
Word num = (ArgCnt >= 1) ? EvalStrIntExpression(&ArgStr[1], UInt8, &ok) : 0;
if (ok)
append_word(code | (num & 255));
}
}
/*!------------------------------------------------------------------------
* \fn decode_flags(Word code)
* \brief handle generic flag set/clear instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_flags(Word code)
{
if (ChkArgCnt(1, 1))
{
Boolean ok = True;
Word num = EvalStrIntExpression(&ArgStr[1], UInt4, &ok);
if (ok)
append_word(code | (num & 15));
}
}
/*!------------------------------------------------------------------------
* \fn decode_lcc(Word code)
* \brief handle LCC instruction (WD16)
* \param code machine code
* ------------------------------------------------------------------------ */
static void decode_lcc(Word code)
{
if (ChkArgCnt(1, 1))
{
Boolean ok;
Word num = EvalStrIntExpression(&ArgStr[1], UInt4, &ok);
if (ok)
append_word(code | (num & 15));
}
}
/*!------------------------------------------------------------------------
* \fn decode_format11(Word code)
* \brief handle format 11 instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static Boolean decode_adr_01(tStrComp *p_arg, adr_vals_t *p_vals)
{
if (!decode_adr(p_arg, p_vals, EProgCounter() + 2, MModReg | MModMem))
return False;
switch (p_vals->mode & 070)
{
case 010:
p_vals->mode = (p_vals->mode & 007) | 000;
break;
case 070:
if (p_vals->vals[0] == 0)
{
p_vals->count = 0;
p_vals->mode = (p_vals->mode & 007) | 010;
break;
}
/* else fall-through */
default:
WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
reset_adr_vals(p_vals);
return False;
}
return True;
}
static void decode_format11(Word code)
{
adr_vals_t src_adr_vals, dest_adr_vals;
if (ChkArgCnt(2, 2)
&& decode_adr_01(&ArgStr[1], &src_adr_vals)
&& decode_adr_01(&ArgStr[2], &dest_adr_vals))
append_word(code | ((src_adr_vals.mode & 15) << 4) | (dest_adr_vals.mode& 15));
}
/*!------------------------------------------------------------------------
* \fn decode_pseudo(void)
* \brief handle pseudo instructions
* \return True if handled
* ------------------------------------------------------------------------ */
static Boolean decode_pseudo(void)
{
if (Memo("REG"))
{
if (LabPart.str.p_str[0])
CodeREG(0);
else if (ChkArgCnt(1, 1))
{
Boolean IsON;
if (CheckONOFFArg(&ArgStr[1], &IsON))
SetFlag(&default_regsyms, default_regsyms_name, IsON);
}
return True;
}
if (Memo("BYTE"))
{
DecodeIntelDB(eIntPseudoFlag_DECFormat | eIntPseudoFlag_AllowString);
return True;
}
if (Memo("WORD"))
{
DecodeIntelDW(eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString | eIntPseudoFlag_DECFormat);
return True;
}
if (is_wd16())
{
if (Memo("FLT3"))
{
DecodeIntelDM(eIntPseudoFlag_AllowFloat | eIntPseudoFlag_DECFormat);
return True;
}
}
{
if (Memo("FLT2"))
{
DecodeIntelDD(eIntPseudoFlag_AllowFloat | eIntPseudoFlag_DECFormat);
return True;
}
if (Memo("FLT4"))
{
DecodeIntelDQ(eIntPseudoFlag_AllowFloat | eIntPseudoFlag_DECFormat);
return True;
}
}
if (Memo("PRWINS"))
{
cpu_2_phys_area_dump(SegCode, stdout);
return True;
}
return False;
}
/*--------------------------------------------------------------------------*/
/* Memory Management */
/*!------------------------------------------------------------------------
* \fn update_apr(void)
* \brief compute the CPU -> physical mapping from the current APR values
* ------------------------------------------------------------------------ */
static void update_apr(void)
{
int z;
LargeWord base, size;
Word acf;
cpu_2_phys_area_clear(SegCode);
for (z = 0, base = 0; z < APR_COUNT; z++, base += 0x2000)
{
/* page at least read only? */
acf = reg_pdr[z] & 7;
if ((acf == 00) || (acf == 03) || (acf == 07))
continue;
/* extract size field */
size = (reg_pdr[z] >> 8) & 0xff;
/* expand downward -> size field is 2s complement of number of blocks */
if (reg_pdr[z] & 0x08)
{
size = ((size ^ 0xff) + 1) << 6;
cpu_2_phys_area_add(SegCode, base + 0x2000 - size, (reg_par[z] << 6) + 0x2000 - size, size);
}
/* expand upward -> size field is highest block number */
else
{
size = ((size & 0x7f) + 1) << 6;
cpu_2_phys_area_add(SegCode, base, reg_par[z] << 6, size);
}
}
cpu_2_phys_area_set_cpu_end(SegCode, 0xffff);
}
/*--------------------------------------------------------------------------*/
/* Instruction Lookup Table */
/*!------------------------------------------------------------------------
* \fn init_branches(void)
* \brief add branch instructions to lookup table (same on PDP-11 and WD16)
* ------------------------------------------------------------------------ */
static void init_branches(void)
{
AddInstTable(InstTable, "BCC" , 0103000, decode_branch);
AddInstTable(InstTable, "BCS" , 0103400, decode_branch);
AddInstTable(InstTable, "BEQ" , 0001400, decode_branch);
AddInstTable(InstTable, "BGE" , 0002000, decode_branch);
AddInstTable(InstTable, "BGT" , 0003000, decode_branch);
AddInstTable(InstTable, "BHI" , 0101000, decode_branch);
AddInstTable(InstTable, "BHIS", 0103000, decode_branch);
AddInstTable(InstTable, "BLE" , 0003400, decode_branch);
AddInstTable(InstTable, "BLO" , 0103400, decode_branch);
AddInstTable(InstTable, "BLOS", 0101400, decode_branch);
AddInstTable(InstTable, "BLT" , 0002400, decode_branch);
AddInstTable(InstTable, "BMI" , 0100400, decode_branch);
AddInstTable(InstTable, "BNE" , 0001000, decode_branch);
AddInstTable(InstTable, "BPL" , 0100000, decode_branch);
AddInstTable(InstTable, "BR" , 0000400, decode_branch);
AddInstTable(InstTable, "BVC" , 0102000, decode_branch);
AddInstTable(InstTable, "BVS" , 0102400, decode_branch);
}
/*!------------------------------------------------------------------------
* \fn init_fields_pdp11(void)
* \brief create lookup table - PDP-11 encoding
* ------------------------------------------------------------------------ */
static void add_one_arg(const char *p_name, Word code)
{
char name[10];
AddInstTable(InstTable, p_name, code | CODE_FLAG_16BIT, decode_one_arg);
as_snprintf(name, sizeof(name), "%sB", p_name);
AddInstTable(InstTable, name, 0100000 | code, decode_one_arg);
}
static void add_two_arg(const char *p_name, Word code)
{
char name[10];
AddInstTable(InstTable, p_name, code | CODE_FLAG_16BIT, decode_two_arg);
as_snprintf(name, sizeof(name), "%sB", p_name);
AddInstTable(InstTable, name, 0100000 | code, decode_two_arg);
}
static void add_fp11(const char *p_name, Word code, InstProc proc)
{
char name[10];
as_snprintf(name, sizeof(name), "%sF", p_name);
AddInstTable(InstTable, name, code, proc);
as_snprintf(name, sizeof(name), "%sD", p_name);
AddInstTable(InstTable, name, code | CODE_FLAG_F64BIT, proc);
}
static void add_cis(const char *p_name, Word code, InstProc inline_proc)
{
char name[10];
AddInstTable(InstTable, p_name, code, decode_cis_0);
as_snprintf(name, sizeof(name), "%sI", p_name);
AddInstTable(InstTable, name, code | 0000100, inline_proc);
}
static void init_fields_pdp11(void)
{
InstTable = CreateInstTable(201);
SetDynamicInstTable(InstTable);
AddInstTable(InstTable, "BPT", 000003, decode_fixed);
AddInstTable(InstTable, "CCC", 000257, decode_fixed);
AddInstTable(InstTable, "CLC", 000241, decode_fixed);
AddInstTable(InstTable, "CLN", 000250, decode_fixed);
AddInstTable(InstTable, "CLV", 000242, decode_fixed);
AddInstTable(InstTable, "CLZ", 000244, decode_fixed);
AddInstTable(InstTable, "HALT", 000000, decode_fixed_sup);
AddInstTable(InstTable, "IOT", 000004, decode_fixed);
AddInstTable(InstTable, "MFPT", 000007, decode_mfpt);
AddInstTable(InstTable, "NOP", NOPCode, decode_fixed);
AddInstTable(InstTable, "RESET", 000005, decode_fixed_sup);
AddInstTable(InstTable, "RTI", 000002, decode_fixed);
AddInstTable(InstTable, "RTT", 000006, decode_rtt);
AddInstTable(InstTable, "SCC", 000277, decode_fixed);
AddInstTable(InstTable, "SEC", 000261, decode_fixed);
AddInstTable(InstTable, "SEN", 000270, decode_fixed);
AddInstTable(InstTable, "SEV", 000262, decode_fixed);
AddInstTable(InstTable, "SEZ", 000264, decode_fixed);
AddInstTable(InstTable, "WAIT", 000001, decode_fixed);
add_one_arg("ADC", 005500);
add_one_arg("ASL", 006300);
add_one_arg("ASR", 006200);
add_one_arg("CLR", 005000);
add_one_arg("COM", 005100);
add_one_arg("NEG", 005400);
add_one_arg("DEC", 005300);
add_one_arg("INC", 005200);
add_one_arg("ROL", 006100);
add_one_arg("ROR", 006000);
add_one_arg("SBC", 005600);
AddInstTable(InstTable, "SWAB", 000300, decode_one_arg);
AddInstTable(InstTable, "SXT", 006700, decode_sxt);
add_one_arg("TST", 005700);
AddInstTable(InstTable, "TSTSET", 0007200, decode_tstset);
AddInstTable(InstTable, "WRTLCK", 0007300, decode_wrtlck);
AddInstTable(InstTable, "CSM" , 0007000 | CODE_FLAG_16BIT | CODE_FLAG_GEN_IMM, decode_csm);
AddInstTable(InstTable, "MFPD" , 0006500 | CODE_FLAG_16BIT | CODE_FLAG_GEN_IMM, decode_mfp_mtp);
AddInstTable(InstTable, "MFPI" , 0106500 | CODE_FLAG_16BIT | CODE_FLAG_GEN_IMM, decode_mfp_mtp);
AddInstTable(InstTable, "MFPS" , 0106700 , decode_mfps_mtps);
AddInstTable(InstTable, "MTPD" , 0006600 | CODE_FLAG_16BIT, decode_mfp_mtp);
AddInstTable(InstTable, "MTPI" , 0106600 | CODE_FLAG_16BIT, decode_mfp_mtp);
AddInstTable(InstTable, "MTPS" , 0106400 | CODE_FLAG_GEN_IMM, decode_mfps_mtps);
AddInstTable(InstTable, "FADD" , 0075000, decode_fis);
AddInstTable(InstTable, "FSUB" , 0075010, decode_fis);
AddInstTable(InstTable, "FMUL" , 0075020, decode_fis);
AddInstTable(InstTable, "FDIV" , 0075030, decode_fis);
add_fp11("ADD" , 0172000 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
add_fp11("CMP" , 0173400 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
add_fp11("DIV" , 0174400 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDCDF", 0177400 | CODE_FLAG_GEN_IMM | CODE_FLAG_F64BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDCFD", 0177400 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDCIF", 0177000 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDCID", 0177000 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT | CODE_FLAG_F64BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDCLF", 0177000 | CODE_FLAG_GEN_IMM | CODE_FLAG_32BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDCLD", 0177000 | CODE_FLAG_GEN_IMM | CODE_FLAG_32BIT | CODE_FLAG_F64BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "STCFI", 0175400 | CODE_FLAG_ARGSWAP | CODE_FLAG_16BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "STCDI", 0175400 | CODE_FLAG_ARGSWAP | CODE_FLAG_16BIT | CODE_FLAG_F64BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "STCFL", 0175400 | CODE_FLAG_ARGSWAP | CODE_FLAG_32BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "STCDL", 0175400 | CODE_FLAG_ARGSWAP | CODE_FLAG_32BIT | CODE_FLAG_F64BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "LDEXP", 0176400 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_fp11_f1_f3);
AddInstTable(InstTable, "STEXP", 0175000 | CODE_FLAG_ARGSWAP | CODE_FLAG_16BIT, decode_fp11_f1_f3);
add_fp11("LD" , 0172400 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
add_fp11("ST" , 0174000 | CODE_FLAG_ARGSWAP, decode_fp11_f1_f3);
add_fp11("MOD" , 0171400 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
add_fp11("MUL" , 0171000 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
add_fp11("SUB" , 0173000 | CODE_FLAG_GEN_IMM, decode_fp11_f1_f3);
add_fp11("ABS" , 0170600, decode_fp11_f2);
add_fp11("CLR" , 0170400, decode_fp11_f2);
add_fp11("NEG" , 0170700, decode_fp11_f2);
add_fp11("TST" , 0170500 | CODE_FLAG_GEN_IMM, decode_fp11_f2);
AddInstTable(InstTable, "LDFPS", 0170100 | CODE_FLAG_16BIT | CODE_FLAG_GEN_IMM, decode_fp11_f4);
AddInstTable(InstTable, "STFPS", 0170200 | CODE_FLAG_16BIT, decode_fp11_f4);
AddInstTable(InstTable, "STST" , 0170300 | CODE_FLAG_32BIT, decode_fp11_f4);
AddInstTable(InstTable, "CFCC", 0170000, decode_fp11_f5);
AddInstTable(InstTable, "SETF", 0170001, decode_fp11_f5);
AddInstTable(InstTable, "SETD", 0170011, decode_fp11_f5);
AddInstTable(InstTable, "SETI", 0170002, decode_fp11_f5);
AddInstTable(InstTable, "SETL", 0170012, decode_fp11_f5);
add_two_arg("CMP", 0020000 | CODE_FLAG_GEN_IMM);
add_two_arg("BIC", 0040000);
add_two_arg("BIS", 0050000);
add_two_arg("BIT", 0030000 | CODE_FLAG_GEN_IMM);
add_two_arg("MOV", 0010000);
AddInstTable(InstTable, "ADD", 0060000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "SUB", 0160000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "ASH" , 0072000, decode_eis);
AddInstTable(InstTable, "ASHC", 0073000, decode_eis);
AddInstTable(InstTable, "DIV" , 0071000, decode_eis);
AddInstTable(InstTable, "MUL" , 0070000, decode_eis);
AddInstTable(InstTable, "XOR" , 0074000, decode_xor);
init_branches();
AddInstTable(InstTable, "SOB" , 0077000, decode_sob);
AddInstTable(InstTable, "JMP" , 000100, decode_jmp);
AddInstTable(InstTable, "JSR" , 004000, decode_jsr);
AddInstTable(InstTable, "CALL", 004000, decode_call);
AddInstTable(InstTable, "RTS" , 000200, decode_rts);
AddInstTable(InstTable, "MARK", 006400, decode_mark);
AddInstTable(InstTable, "EMT" , 0104000, decode_trap);
AddInstTable(InstTable, "TRAP" , 0104400, decode_trap);
AddInstTable(InstTable, "SPL" , 0000230, decode_spl);
AddInstTable(InstTable, "C" , 000240, decode_flags);
AddInstTable(InstTable, "S" , 000260, decode_flags);
add_cis("ADDN" , 0076050, decode_cis_3);
add_cis("ADDP" , 0076070, decode_cis_3);
add_cis("ASHN" , 0076056, decode_cis_2i);
add_cis("ASHP" , 0076076, decode_cis_2i);
add_cis("CMPC" , 0076044, decode_cis_2i);
add_cis("CMPN" , 0076052, decode_cis_2);
add_cis("CMPP" , 0076072, decode_cis_2);
add_cis("CVTLN", 0076057, decode_cis_2);
add_cis("CVTLP", 0076077, decode_cis_2);
add_cis("CVTNL", 0076053, decode_cis_2);
add_cis("CVTPL", 0076073, decode_cis_2);
add_cis("CVTNP", 0076055, decode_cis_2);
add_cis("CVTPN", 0076054, decode_cis_2);
add_cis("DIVP" , 0076075, decode_cis_3);
add_cis("LOCC" , 0076040, decode_cis_2i);
AddInstTable(InstTable, "L2DR" , 0076020, decode_cis_ld);
AddInstTable(InstTable, "L3DR" , 0076060, decode_cis_ld);
add_cis("MATC" , 0076045, decode_cis_2);
add_cis("MOVC" , 0076030, decode_cis_2i);
add_cis("MOVRC", 0076031, decode_cis_2i);
add_cis("MOVTC", 0076032, decode_cis_2i1);
add_cis("MULP" , 0076074, decode_cis_3);
add_cis("SCANC", 0076042, decode_cis_2);
add_cis("SKPC" , 0076041, decode_cis_1i);
add_cis("SPANC", 0076043, decode_cis_2);
add_cis("SUBN" , 0076051, decode_cis_3);
add_cis("SUBP" , 0076071, decode_cis_3);
}
/*!------------------------------------------------------------------------
* \fn init_fields_wd16(void)
* \brief create lookup table - WD16 encoding
* ------------------------------------------------------------------------ */
static Boolean TrueFnc(void)
{
return True;
}
static void init_fields_wd16(void)
{
InstTable = CreateInstTable(201);
SetDynamicInstTable(InstTable);
AddInstTable(InstTable, "NOP" , NOPCode, decode_fixed);
AddInstTable(InstTable, "RESET", 0x0001 , decode_fixed);
AddInstTable(InstTable, "IEN" , 0x0002 , decode_fixed);
AddInstTable(InstTable, "IDS" , 0x0003 , decode_fixed);
AddInstTable(InstTable, "HALT" , 0x0004 , decode_fixed);
AddInstTable(InstTable, "XCT" , 0x0005 , decode_fixed);
AddInstTable(InstTable, "BPT" , 0x0006 , decode_fixed);
AddInstTable(InstTable, "WFI" , 0x0007 , decode_fixed);
AddInstTable(InstTable, "RSVC" , 0x0008 , decode_fixed);
AddInstTable(InstTable, "RRTT" , 0x0009 , decode_fixed);
AddInstTable(InstTable, "SAVE" , 0x000a , decode_fixed); SaveIsOccupiedFnc = TrueFnc;
AddInstTable(InstTable, "SAVS" , 0x000b , decode_fixed);
AddInstTable(InstTable, "REST" , 0x000c , decode_fixed);
AddInstTable(InstTable, "RRTN" , 0x000d , decode_fixed);
AddInstTable(InstTable, "RSTS" , 0x000e , decode_fixed);
AddInstTable(InstTable, "RTT" , 0x000f , decode_fixed);
AddInstTable(InstTable, "IAK" , 0x0010 , decode_one_reg);
AddInstTable(InstTable, "RTN" , 0x0018 , decode_one_reg);
AddInstTable(InstTable, "MSKO" , 0x0020 , decode_one_reg);
AddInstTable(InstTable, "PRTN" , 0x0028 , decode_one_reg);
AddInstTable(InstTable, "LCC" , 0x0030 , decode_lcc);
AddInstTable(InstTable, "SVCA" , 0x0040 , decode_imm6);
AddInstTable(InstTable, "SVCB" , 0x0080 , decode_imm6);
AddInstTable(InstTable, "SVCC" , 0x00c0 , decode_imm6);
AddInstTable(InstTable, "ADDI" , 0x0800 , decode_imm4p1_reg);
AddInstTable(InstTable, "SUBI" , 0x0810 , decode_imm4p1_reg);
AddInstTable(InstTable, "BICI" , 0x0820 , decode_imm4p1_reg);
AddInstTable(InstTable, "MOVI" , 0x0830 , decode_imm4p1_reg);
AddInstTable(InstTable, "SSRR" , 0x8800 , decode_imm4p1_reg);
AddInstTable(InstTable, "SSLR" , 0x8810 , decode_imm4p1_reg);
AddInstTable(InstTable, "SSRA" , 0x8820 , decode_imm4p1_reg);
AddInstTable(InstTable, "SSLA" , 0x8830 , decode_imm4p1_reg);
AddInstTable(InstTable, "SDRR" , 0x8e00 , decode_imm4p1_reg);
AddInstTable(InstTable, "SDLR" , 0x8e10 , decode_imm4p1_reg);
AddInstTable(InstTable, "SDRA" , 0x8e20 , decode_imm4p1_reg);
AddInstTable(InstTable, "SDLA" , 0x8e30 , decode_imm4p1_reg);
add_one_arg("ROR", 0x0a00);
add_one_arg("ROL", 0x0a40);
add_one_arg("TST", 0x0a80);
add_one_arg("ASL", 0x0ac0);
add_one_arg("SET", 0x0b00); SetIsOccupiedFnc = TrueFnc;
add_one_arg("CLR", 0x0b40);
add_one_arg("ASR", 0x0b80);
add_one_arg("COM", 0x0c00);
add_one_arg("NEG", 0x0c40);
add_one_arg("INC", 0x0c80);
add_one_arg("DEC", 0x0cc0);
AddInstTable(InstTable, "SWAB" , 0x0bc0, decode_one_arg);
AddInstTable(InstTable, "SWAD" , 0x8bc0, decode_one_arg);
AddInstTable(InstTable, "IW2" , 0x0d00, decode_one_arg);
AddInstTable(InstTable, "SXT" , 0x0d40, decode_one_arg);
AddInstTable(InstTable, "TCALL", 0x0d80 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_one_arg);
AddInstTable(InstTable, "TJMP" , 0x0dc0 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_one_arg);
AddInstTable(InstTable, "LSTS" , 0x8d00 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_one_arg);
AddInstTable(InstTable, "SSTS" , 0x8d40, decode_one_arg);
AddInstTable(InstTable, "ADC" , 0x8d80, decode_one_arg);
AddInstTable(InstTable, "SBC" , 0x8dc0, decode_one_arg);
AddInstTable(InstTable, "MBWU" , 0x0e00, decode_two_reg);
AddInstTable(InstTable, "MBWD" , 0x0e40, decode_two_reg);
AddInstTable(InstTable, "MBBU" , 0x0e80, decode_two_reg);
AddInstTable(InstTable, "MBBD" , 0x0ec0, decode_two_reg);
AddInstTable(InstTable, "MBWA" , 0x0f00, decode_two_reg);
AddInstTable(InstTable, "MBBA" , 0x0f40, decode_two_reg);
AddInstTable(InstTable, "MABW" , 0x0f80, decode_two_reg);
AddInstTable(InstTable, "MABB" , 0x0fc0, decode_two_reg);
AddInstTable(InstTable, "JSR" , 0x7000, decode_jsr);
AddInstTable(InstTable, "CALL", 0x7000, decode_call);
AddInstTable(InstTable, "LEA" , 0x7200, decode_jsr);
AddInstTable(InstTable, "JMP" , 0x7200, decode_call);
AddInstTable(InstTable, "ASH" , 0x7400, decode_reg_gen);
AddInstTable(InstTable, "SOB" , 0x7600, decode_sob);
AddInstTable(InstTable, "XCH" , 0x7800, decode_reg_gen);
AddInstTable(InstTable, "ASHC", 0x7a00, decode_reg_gen);
AddInstTable(InstTable, "MUL" , 0x7c00, decode_reg_gen);
AddInstTable(InstTable, "DIV" , 0x7e00, decode_reg_gen);
AddInstTable(InstTable, "ADD" , 0x1000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "SUB" , 0x2000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "AND" , 0x3000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "BIC" , 0x4000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "BIS" , 0x5000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "XOR" , 0x6000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "CMP" , 0x9000 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "BIT" , 0xa000 | CODE_FLAG_GEN_IMM | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "MOV" , 0xb000 | CODE_FLAG_16BIT, decode_two_arg);
AddInstTable(InstTable, "CMPB", 0xc000 | CODE_FLAG_GEN_IMM, decode_two_arg);
AddInstTable(InstTable, "MOVB", 0xd000, decode_two_arg);
AddInstTable(InstTable, "BISB", 0xe000, decode_two_arg);
AddInstTable(InstTable, "FADD", 0xf000, decode_format11);
AddInstTable(InstTable, "FSUB", 0xf100, decode_format11);
AddInstTable(InstTable, "FMUL", 0xf200, decode_format11);
AddInstTable(InstTable, "FDIV", 0xf300, decode_format11);
AddInstTable(InstTable, "FCMP", 0xf400, decode_format11);
init_branches();
}
/*!------------------------------------------------------------------------
* \fn deinit_fields(void)
* \brief destroy/cleanup lookup table
* ------------------------------------------------------------------------ */
static void deinit_fields(void)
{
DestroyInstTable(InstTable);
}
/*--------------------------------------------------------------------------*/
/* Interface Functions */
/*!------------------------------------------------------------------------
* \fn intern_symbol_pdp11(char *pArg, TempResult *pResult)
* \brief handle built-in (register) symbols for PDP-11
* \param p_arg source argument
* \param p_result result buffer
* ------------------------------------------------------------------------ */
static void intern_symbol_pdp11(char *p_arg, TempResult *p_result)
{
Word reg_num;
if (decode_reg_core(p_arg, ®_num, &p_result->DataSize))
{
p_result->Typ = TempReg;
p_result->Contents.RegDescr.Reg = reg_num;
p_result->Contents.RegDescr.Dissect = dissect_reg_pdp11;
p_result->Contents.RegDescr.compare = NULL;
}
}
/*!------------------------------------------------------------------------
* \fn make_code_pdp11(void)
* \brief encode machine instruction
* ------------------------------------------------------------------------ */
static void make_code_pdp11(void)
{
CodeLen = 0; DontPrint = False;
op_size = eSymbolSizeUnknown;
/* to be ignored */
if (Memo("")) return;
/* Pseudo Instructions */
if (decode_pseudo())
return;
/* machine instructions may not begin on odd addresses */
if (Odd(EProgCounter()))
{
if (DoPadding)
InsertPadding(1, False);
else
WrError(ErrNum_AddrNotAligned);
}
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
/*!------------------------------------------------------------------------
* \fn is_def_pdp11(void)
* \brief check whether insn makes own use of label
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean is_def_pdp11(void)
{
return Memo("REG");
}
/*!------------------------------------------------------------------------
* \fn initpass_pdp11(void)
* \brief pre-initialize APRs to 1:1 mapping
* ------------------------------------------------------------------------ */
static void initpass_pdp11(void)
{
/* if the PDP-11 target is never used, the memory never gets allocated: */
if (reg_par)
{
int z;
/* initialize APRs to 1:1 mapping */
for (z = 0; z < APR_COUNT; z++)
{
reg_par[z] = z << 7;
reg_pdr[z] = 0x7f05;
}
}
ext_registered = 0;
}
/*!------------------------------------------------------------------------
* \fn switch_from_pdp11(void)
* \brief deinitialize as target
* ------------------------------------------------------------------------ */
static void switch_from_pdp11(void)
{
deinit_fields();
p_curr_cpu_props = NULL;
}
/*!------------------------------------------------------------------------
* \fn switch_to_pdp11(void *p_user)
* \brief prepare to assemble code for this target
* ------------------------------------------------------------------------ */
static void switch_to_pdp11(void *p_user)
{
static char *p_assume_reg_names = NULL;
static ASSUMERec *p_assumes = NULL;
const TFamilyDescr *p_descr;
p_curr_cpu_props = (const cpu_props_t*)p_user;
p_descr = FindFamilyByName(is_wd16() ? "WD16" : "PDP-11");
TurnWords = False;
SetIntConstMode(eIntConstModeC);
PCSymbol = "*";
HeaderID = p_descr->Id;
NOPCode = is_wd16() ? 0x0000 : 000240;
DivideChars = ",";
ValidSegs = 1 << SegCode;
Grans[SegCode] = 1;
ListGrans[SegCode] = 2;
SegInits[SegCode] = 0;
SegLimits[SegCode] = IntTypeDefs[p_curr_cpu_props->addr_space].Max;
MakeCode = make_code_pdp11;
IsDef = is_def_pdp11;
SwitchFrom = switch_from_pdp11;
InternSymbol = intern_symbol_pdp11;
DissectReg = dissect_reg_pdp11;
multi_char_le = True;
if (!is_wd16())
onoff_supmode_add();
AddONOFF(DoPaddingName, &DoPadding, DoPaddingName, False);
if (p_curr_cpu_props->opt_flags & e_cpu_flag_eis)
onoff_ext_add(e_ext_eis, False);
if (p_curr_cpu_props->opt_flags & e_cpu_flag_fis)
onoff_ext_add(e_ext_fis, False);
if (p_curr_cpu_props->opt_flags & e_cpu_flag_fp11)
onoff_ext_add(e_ext_fp11, False);
if (p_curr_cpu_props->opt_flags & e_cpu_flag_cis)
onoff_ext_add(e_ext_cis, False);
if (!ext_test_and_set(0x80))
SetFlag(&default_regsyms, default_regsyms_name, True);
/* create list of PDP-11 paging registers upon first use */
if (!is_wd16())
{
if (!reg_par)
{
reg_par
= (LongInt
*)calloc(APR_COUNT
, sizeof(*reg_par
));
reg_pdr
= (LongInt
*)calloc(APR_COUNT
, sizeof(*reg_pdr
));
initpass_pdp11();
}
if (!p_assumes)
{
int apr_index, assume_index, l;
char *p_reg_name;
if (!p_assume_reg_names)
p_assume_reg_names
= (char*)malloc(ASSUME_COUNT
* (4 + 1));
p_assumes
= (ASSUMERec
*)calloc(ASSUME_COUNT
, sizeof(*p_assumes
));
p_reg_name = p_assume_reg_names;
for (apr_index = 0; apr_index < APR_COUNT; apr_index++)
{
l = as_snprintf(p_reg_name, 6, "PAR%c", apr_index + '0');
p_assumes[apr_index * 2].Name = p_reg_name;
p_assumes[apr_index * 2].Dest = ®_par[apr_index];
p_reg_name += l + 1;
l = as_snprintf(p_reg_name, 6, "PDR%c", apr_index + '0');
p_assumes[apr_index * 2 + 1].Name = p_reg_name;
p_assumes[apr_index * 2 + 1].Dest = ®_pdr[apr_index];
p_reg_name += l + 1;
}
for (assume_index = 0; assume_index < ASSUME_COUNT; assume_index++)
{
p_assumes[assume_index].Min = 0x0000;
p_assumes[assume_index].Max = 0xffff;
p_assumes[assume_index].NothingVal = 0x0000;
p_assumes[assume_index].pPostProc = update_apr;
}
}
pASSUMERecs = p_assumes;
ASSUMERecCnt = ASSUME_COUNT;
update_apr();
}
if (is_wd16())
init_fields_wd16();
else
init_fields_pdp11();
}
/*!------------------------------------------------------------------------
* \fn codepdp11_init(void)
* \brief register PDP-11 target
* ------------------------------------------------------------------------ */
/* NOTE: the KEV-11C implements DIS, which is actually a subset of CIS, but
since noone knows which subset, we just treat DIS as CIS: */
#define opt_cpu_flags_lsi11 (e_cpu_flag_eis | e_cpu_flag_fis | e_cpu_flag_cis)
#define cpu_flags_lsi11 (e_cpu_flag_sob_sxt | e_cpu_flag_xor | e_cpu_flag_rtt | e_cpu_flag_mark | e_cpu_flag_mfps_mtps)
#define opt_cpu_flags_f11 (e_cpu_flag_fp11)
#define cpu_flags_f11 (e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_xor | e_cpu_flag_mfpt | e_cpu_flag_eis | e_cpu_flag_mfp_mtp | e_cpu_flag_mfps_mtps)
#define opt_cpu_flags_t11 0
#define cpu_flags_t11 (e_cpu_flag_sob_sxt | e_cpu_flag_rtt | e_cpu_flag_mfps_mtps)
#define opt_cpu_flags_j11 0
#define cpu_flags_j11 (e_cpu_flag_eis | e_cpu_flag_fp11 | e_cpu_flag_sob_sxt | e_cpu_flag_xor | e_cpu_flag_rtt | e_cpu_flag_mark | e_cpu_flag_mfpt | e_cpu_flag_mfp_mtp | e_cpu_flag_mfps_mtps | e_cpu_flag_spl | e_cpu_flag_csm | e_cpu_flag_wrtlck | e_cpu_flag_tstset)
static const cpu_props_t cpu_props[] =
{
{ "PDP-11/03" , UInt16, opt_cpu_flags_lsi11 , cpu_flags_lsi11 },
{ "PDP-11/04" , UInt16, 0 , e_cpu_flag_rtt },
{ "PDP-11/05" , UInt16, 0 , 0 }, /* OEM version of PDP-11/10 */
{ "PDP-11/10" , UInt16, 0 , 0 },
{ "PDP-11/15" , UInt16, 0 , 0 }, /* OEM version of PDP-11/20 */
{ "PDP-11/20" , UInt16, 0 , 0 },
{ "PDP-11/23" , UInt22, opt_cpu_flags_f11 , cpu_flags_f11 },
{ "PDP-11/24" , UInt22, opt_cpu_flags_f11 , cpu_flags_f11 },
{ "PDP-11/34" , UInt18, e_cpu_flag_fp11 , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_mfp_mtp | e_cpu_flag_mfps_mtps },
{ "PDP-11/35" , UInt18, e_cpu_flag_eis | e_cpu_flag_fis , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_xor | e_cpu_flag_mfp_mtp }, /* OEM version of PDP-11/40 */
{ "PDP-11/40" , UInt18, e_cpu_flag_eis | e_cpu_flag_fis , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_xor | e_cpu_flag_mfp_mtp },
{ "PDP-11/44" , UInt22, e_cpu_flag_fp11 | e_cpu_flag_cis , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_mfpt | e_cpu_flag_mfp_mtp | e_cpu_flag_spl | e_cpu_flag_csm },
{ "PDP-11/45" , UInt18, e_cpu_flag_fp11 , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_spl },
{ "PDP-11/50" , UInt18, e_cpu_flag_fp11 , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_spl },
{ "MicroPDP-11/53" , UInt22, opt_cpu_flags_j11 , cpu_flags_j11 },
{ "PDP-11/55" , UInt18, e_cpu_flag_fp11 , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_spl },
{ "PDP-11/60" , UInt18, 0 , e_cpu_flag_fp11 | e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_mfp_mtp },
{ "PDP-11/70" , UInt22, e_cpu_flag_fp11 , e_cpu_flag_sob_sxt | e_cpu_flag_mark | e_cpu_flag_rtt | e_cpu_flag_eis | e_cpu_flag_xor | e_cpu_flag_mfp_mtp | e_cpu_flag_spl },
{ "MicroPDP-11/73" , UInt22, opt_cpu_flags_j11 , cpu_flags_j11 },
{ "MicroPDP-11/83" , UInt22, opt_cpu_flags_j11 , cpu_flags_j11 },
{ "PDP-11/84" , UInt22, opt_cpu_flags_j11 , cpu_flags_j11 },
{ "MicroPDP-11/93" , UInt22, opt_cpu_flags_j11 , cpu_flags_j11 },
{ "PDP-11/94" , UInt22, opt_cpu_flags_j11 , cpu_flags_j11 },
{ "T-11" , UInt16, opt_cpu_flags_t11 , cpu_flags_t11 },
/* The WD16 is basically an LSI-11 with
- different microcode,
- different opcodes,
- different floating point format
but same architecture: */
{ "WD16" , UInt16, 0 , e_cpu_flag_wd16 | e_cpu_flag_sob_sxt },
};
void codepdp11_init(void)
{
const cpu_props_t *p_prop;
for (p_prop = cpu_props; p_prop < cpu_props + as_array_size(cpu_props); p_prop++)
(void)AddCPUUserWithArgs(p_prop->name, switch_to_pdp11, (void*)p_prop, NULL, NULL);
AddInitPassProc(initpass_pdp11);
}