|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
#include "m88100disasm.h"
#include "debugger_memory.h"
#include "m88100.h"
#include "m88100acc.h"
#include "mystring.h"
#define OP_DEF(name) void __CONCAT(m88100disasm::op_,name)()
#define OP_FUNC(name) __CONCAT(op_,name)()
// 別ニーモニックを使うなら true にする (外部から指定する)
/*static*/ bool m88100disasm::use_altname;
// コンストラクタ
m88100disasm::m88100disasm()
{
}
// デストラクタ
m88100disasm::~m88100disasm()
{
}
// 逆アセンブルを実行
bool
m88100disasm::Exec(DebuggerMemoryStream *mem_)
{
ExecInit(mem_);
opX = 0;
name.clear();
arg0.clear();
arg1.clear();
arg2.clear();
altname.clear();
altarg0.clear();
altarg1.clear();
altarg2.clear();
xip = mem->laddr.Addr();
opX = mem->Read(4);
uint32 op12 = M88100::op32_to_12(opX);
switch (op12) {
#include "m88100switch.inc"
default:
name = "illegal";
break;
}
// 出力文字列(ダンプ)
dump = string_format("%08x ", opX);
// 出力文字列(命令)
text = name;
if (!arg0.empty() || !arg1.empty() || !arg2.empty()) {
// オペランドがどれかでもあればインデントする
int len = text.length();
if (len < 8) {
text += std::string(8 - len, ' ');
} else {
text += ' ';
}
// arg0,1,2 の空でないやつを追加
std::string args;
int argc = 0;
if (!arg0.empty()) {
args += arg0;
argc++;
}
if (!arg1.empty()) {
if (argc != 0) {
args += ",";
while (args.length() < argc * 4)
args += " ";
}
args += arg1;
argc++;
}
if (!arg2.empty()) {
if (argc != 0) {
args += ",";
while (args.length() < argc * 4)
args += " ";
}
args += arg2;
}
text += args;
}
// 出力文字列(別名)
if (use_altname && !altname.empty()) {
if (altarg1.empty() && !altarg2.empty()) {
altarg1 = altarg2;
altarg2.clear();
}
// {mov rn, rn} -> {nop} は無条件に置換できるのでここでやる
if (altname == "mov" && altarg0 == altarg1 && altarg2.empty()) {
altname = "nop";
altarg0.clear();
altarg1.clear();
}
alttext += "{" + altname;
if (!altarg0.empty() || !altarg1.empty() || !altarg2.empty()) {
// オペランドがあればインデントする
int len = alttext.length();
if (len < 8) {
alttext += std::string(8 - len, ' ');
} else {
alttext += ' ';
}
// altarg0,1,2 の空でないやつを追加
std::string altargs;
int altargc = 0;
if (!altarg0.empty()) {
altargs += altarg0;
altargc++;
}
if (!altarg1.empty()) {
if (altargc != 0) {
altargs += ',';
while (altargs.length() < altargc * 4)
altargs += ' ';
}
altargs += altarg1;
altargc++;
}
if (!altarg2.empty()) {
if (altargc != 0) {
altargs += ',';
while (altargs.length() < altargc * 4)
altargs += ' ';
}
altargs += altarg2;
}
alttext += altargs;
}
alttext += '}';
}
// 出力バイナリ列
// bin は vector<uint8>。
bin.push_back( opX >> 24);
bin.push_back((opX >> 16) & 0xff);
bin.push_back((opX >> 8) & 0xff);
bin.push_back( opX & 0xff);
return true;
}
// フィールド部品
#define DD ((opX >> 21) & 0x1f)
#define S1 ((opX >> 16) & 0x1f)
#define S2 ( opX & 0x1f)
#define B5 ((opX >> 21) & 0x1f)
#define M5 ((opX >> 21) & 0x1f)
#define W5 ((opX >> 5) & 0x1f)
#define O5 ((opX ) & 0x1f)
#define CIO ((opX >> 8) & 0x03)
#define IMM16 (opX & 0x0000ffffU)
#define VEC9 (opX & 0x000001ffU)
#define D16 (((int32)(int16)opX) << 2)
#define D26 (((int32)(opX << 6)) >> 4)
std::string
m88100disasm::rd()
{
return string_format("r%u", (opX >> 21) & 0x1f);
}
std::string
m88100disasm::rs1()
{
return string_format("r%u", (opX >> 16) & 0x1f);
}
std::string
m88100disasm::rs2()
{
return string_format("r%u", (opX ) & 0x1f);
}
std::string
m88100disasm::imm16()
{
return string_format("#0x%04x", (opX & 0x0000ffff));
}
std::string
m88100disasm::d16()
{
return string_format("0x%08x", xip + D16);
}
std::string
m88100disasm::d26()
{
return string_format("0x%08x", xip + D26);
}
// 制御レジスタ名
std::string
m88100disasm::crs()
{
// CRS フィールドは 6 bit。ただし CR20 までしか存在しない
uint32 cr = (opX >> 5) & 0x3f;
static const char *crnames[] = {
"pid", "psr", "epsr", "ssbr", // cr0..3
"sxip", "snip", "sfip", "vbr", // cr4..7
"dmt0", "dmd0", "dma0", // cr8..10
"dmt1", "dmd1", "dma1", // cr11..13
"dmt2", "dmd2", "dma2", // cr14..16
"sr0", "sr1", "sr2", "sr3", // cr17..20
};
if (cr < countof(crnames)) {
return std::string(crnames[cr]);
} else {
return string_format("cr%u", cr); // こうなのか?
}
}
// FPU 制御レジスタ名
std::string
m88100disasm::fcrs()
{
uint32 cr = (opX >> 5) & 0x3f;
static const char *fcrnames[] = {
"fpecr", // fcr0
"fphs1", // fcr1
"fpls1", // fcr2
"fphs2", // fcr3
"fpls2", // fcr4
"fppt", // fcr5
"fprh", // fcr6
"fprl", // fcr7
"fpit", // fcr8
};
if (cr < countof(fcrnames)) {
return std::string(fcrnames[cr]);
} else if (cr == 62) {
return "fpsr";
} else if (cr == 63) {
return "fpcr";
} else {
return string_format("fcr%u", cr);
}
}
#define TD (5)
#define T1 (9)
#define T2 (7)
// FPU サイズサフィックス t は TD、T1、T2
std::string
m88100disasm::fsize(uint32 t)
{
uint32 sz = (opX >> t) & 3;
return sz == 1 ? "d" : "s";
}
// FPU サイズサフィックス (全部入り)
std::string
m88100disasm::fsize()
{
return fsize(TD) + fsize(T1) + fsize(T2);
}
// "Width<Offset>"
std::string
m88100disasm::wo5()
{
uint32 w5 = W5 ?: 32;
uint32 o5 = O5;
return string_format("%u<%u>", w5, o5);
}
// "Width<Offset>" 形式をビットマスク形式(数値)にして返す
uint32
m88100disasm::wo5mask()
{
uint32 w5 = W5 ?: 32;
uint32 o5 = O5;
uint64 mask = (1ULL << w5) - 1;
mask <<= o5;
return (uint32)mask;
}
// キャリーサフィックス
std::string
m88100disasm::cio()
{
uint32 c = (opX >> 8) & 3;
static const char *carrystr[] = {
"",
".co",
".ci",
".cio",
};
return std::string(carrystr[c]);
}
std::string
m88100disasm::b5()
{
return string_format("#%u", B5);
}
std::string
m88100disasm::m5()
{
uint32 m = M5;
switch (m) {
case 0x02: return "eq0";
case 0x0d: return "ne0";
case 0x01: return "gt0";
case 0x0c: return "lt0";
case 0x03: return "ge0";
case 0x0e: return "le0";
default:
break;
}
return string_format("#%u", m);
}
// M5(,rS1) に対する代替ニーモニックを返す。empty なら代替ニーモニックなし。
// 条件が 0(always false) でも .n かどうかがあるので nop とかにはしない。
// 15(always true) は無条件 br{,.n} だがこれは戻り値 "true" を呼び出し側が
// 比較して処理すること。
// 6 と 9 は使いみちがないので empty を返す。
// reserved なビットが立っていても動作には影響はないが、ニーモニックとしては
// 不正なものとして表示するためここでは empty を返す。
std::string
m88100disasm::alt_m5()
{
// 0000 false
// 0001 gt0 r > 0 (float)r > +0
// 0010 eq0 r == 0 (float)r == +0
// 0011 ge0 r >= 0 (float)r >= +0
// 0100 (float)r < -0
// 0101 (float)r != 0
// 0110 #6
// 0111 r != 0x80000000 (float)r != -0
// 1000 r == 0x80000000 (float)r == -0
// 1001 #9
// 1010 (float)r == 0
// 1011 (float)r >= -0
// 1100 lt0 r < 0 (float)r < +0
// 1101 ne0 r != 0 (float)r != +0
// 1110 le0 r <= 0 (float)r <= +0
// 1111 true
uint32 m = M5;
if (S1 == 0) {
if (m < 0x10) {
// r0 相手なら、下から 2bit 目が立っていれば true、
// そうでなければ false の二択。
if ((m & 0x02)) {
return "true";
} else {
return "false";
}
}
} else {
char rs[8];
strlcpy(rs, rs1().c_str(), sizeof(rs));
switch (m) {
case 0:
return "false";
case 1:
return string_format("(%s>0|(float)%s>+0)", rs, rs);
case 2:
return string_format("(%s==0|(float)%s==+0)", rs, rs);
case 3:
return string_format("(%s>=0|(float)%s>=+0)", rs, rs);
case 4:
return string_format("((float)%s<-0)", rs);
case 5:
return string_format("((float)%s!=0)", rs);
case 7:
return string_format("(%s!=0x80000000)", rs);
case 8:
return string_format("(%s==0x80000000)", rs);
case 0xa:
return string_format("((float)%s==0)", rs);
case 0xb:
return string_format("((float)%s>=-0)", rs);
case 0xc:
return string_format("(%s<0|(float)%s<+0)", rs, rs);
case 0xd:
return string_format("(%s!=0|(float)%s!=+0)", rs, rs);
case 0xe:
return string_format("(%s<=0|(float)%s<=+0)", rs, rs);
case 0xf: // always true
return "true";
case 6:
case 9:
default: // reserved
break;
}
}
return "";
}
std::string
m88100disasm::vec9()
{
return string_format("#0x%03x", VEC9);
}
// エミュレータ的未実装 (最終的にはなくなる)
void
m88100disasm::op_unimpl()
{
name = "unimplemented";
}
// ld_imm, st_imm, xmem_imm の共通部
// namebase にはサイズプレフィックスを含む。
void
m88100disasm::ops_ldst_imm(const std::string& namebase)
{
name = namebase;
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
altname = namebase;
altarg0 = rd();
if (IMM16 == 0) {
altarg1 = rs1();
} else {
altarg1 = rs1() + "," + imm16();
}
// 3文字目が 'a' になるのは lda しかない
if (namebase[2] != 'a') {
altarg1 = "(" + altarg1 + ")";
}
}
// 000000_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(xmem_bu_imm)
{
ops_ldst_imm("xmem.bu");
}
// 000001_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(xmem_w_imm)
{
ops_ldst_imm("xmem");
}
// 000010_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(ld_hu_imm)
{
ops_ldst_imm("ld.hu");
}
// 000011_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(ld_bu_imm)
{
ops_ldst_imm("ld.bu");
}
// 000100_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(ld_d_imm)
{
ops_ldst_imm("ld.d");
}
// 000101_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(ld_w_imm)
{
ops_ldst_imm("ld");
}
// 000110_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(ld_h_imm)
{
ops_ldst_imm("ld.h");
}
// 000111_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(ld_b_imm)
{
ops_ldst_imm("ld.b");
}
// 001000_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(st_d_imm)
{
ops_ldst_imm("st.d");
}
// 001001_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(st_w_imm)
{
ops_ldst_imm("st");
}
// 001010_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(st_h_imm)
{
ops_ldst_imm("st.h");
}
// 001011_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(st_b_imm)
{
ops_ldst_imm("st.b");
}
// 001100_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(lda_d_imm)
{
ops_ldst_imm("lda.d");
}
// 001101_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(lda_w_imm)
{
ops_ldst_imm("lda");
}
// 001110_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(lda_h_imm)
{
ops_ldst_imm("lda.h");
}
// 001111_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(lda_b_imm)
{
ops_ldst_imm("lda.b");
}
// 010000_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(and_imm)
{
name = "and";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm clr rd
// rd rd #imm and rd, #ffff'imm
// rd s1 #imm and rd, s1, #ffff'imm
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else {
altname = "and";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0xffff%04x", IMM16);
}
}
// 010001_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(and_u_imm)
{
name = "and.u";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm clr rd
// rd rd #imm and rd, #imm'ffff
// rd s1 #imm and rd, s1, #imm'ffff
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else {
altname = "and";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = imm16() + "ffff";
}
}
// 010010_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(mask_imm)
{
name = "mask";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm clr rd
// rd rd #imm and rd, #0000'imm
// rd s1 #imm and rd, s1, #0000'imm
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else {
altname = "and";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
}
// 010011_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(mask_u_imm)
{
name = "mask.u";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm clr rd
// rd rd #imm and rd, #imm'0000
// rd s1 #imm and rd, s1, #imm'0000
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else {
altname = "and";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = imm16() + "0000";
}
}
// 010100_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(xor_imm)
{
name = "xor";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm mov rd, #imm
// rd rd #imm xor rd, #imm
// rd s1 #imm xor rd, s1, #imm
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = imm16();
} else {
altname = "xor";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = imm16();
}
}
// 010101_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(xor_u_imm)
{
name = "xor.u";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm mov rd, #imm'0000
// rd rd #imm xor rd, #imm'0000
// rd s1 #imm xor rd, s1, #imm'0000
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = imm16() + "0000";
} else {
altname = "xor";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = imm16() + "0000";
}
}
// 010110_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(or_imm)
{
name = "or";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm mov rd, #imm
// rd rd #imm or rd, #imm
// rd s1 #imm or rd, s1, #imm
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = imm16();
} else {
altname = "or";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = imm16();
}
}
// 010111_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(or_u_imm)
{
name = "or.u";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm mov rd, #imm'0000
// rd rd #imm or rd, #imm'0000
// rd s1 #imm or rd, s1, #imm'0000
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = imm16() + "0000";
} else {
altname = "or";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = imm16() + "0000";
}
}
// 011000_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(addu_imm)
{
name = "addu";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm mov rd, #0000'imm
// rd rd #imm addu rd, #0000'imm
// rd s1 #imm addu rd, s1, #0000'imm
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = string_format("#0x0000%04x", IMM16);
} else {
altname = "addu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
}
// 011001_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(subu_imm)
{
name = "subu";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 #imm mov rd, #-imm
// rd rd #imm subu rd, #0000'imm
// rd s1 #imm subu rd, s1, #0000'imm
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = string_format("#0x%08x", -(int32)(uint32)IMM16);
} else {
altname = "subu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
}
// 011010_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(divu_imm)
{
name = "divu";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// 例外発生の可能性があるので r0 を含んでいたとしても別名にしない
altname = "divu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
// 011011_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(mul_imm)
{
name = "mul";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// 例外発生の可能性があるので r0 を含んでいたとしても別名にしない
altname = "mul";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
// 011100_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(add_imm)
{
name = "add";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// 例外発生の可能性があるので r0 を含んでいたとしても別名にしない
altname = "adds";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
// 011101_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(sub_imm)
{
name = "sub";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// 例外発生の可能性があるので r0 を含んでいたとしても別名にしない
altname = "subs";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
// 011110_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(div_imm)
{
name = "div";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
// 例外発生の可能性があるので r0 を含んでいたとしても別名にしない
altname = "div";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#0x0000%04x", IMM16);
}
// 011111_DDDDDSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(cmp_imm)
{
name = "cmp";
arg0 = rd();
arg1 = rs1();
arg2 = imm16();
if (DD == 0) {
altname = "nop";
} else {
altname = "cmp";
altarg0 = rd();
altarg1 = rs1();
altarg2 = string_format("#0x0000%04x", IMM16);
}
}
// 100000_DDDDDzzzzz_01000n_nnnnnzzzzz
OP_DEF(ldcr)
{
name = "ldcr";
arg0 = rd();
arg1 = crs();
}
// 100000_DDDDDzzzzz_01001n_nnnnnzzzzz
OP_DEF(fldcr)
{
name = "fldcr";
arg0 = rd();
arg1 = fcrs();
}
// 100000_zzzzzSSSSS_10000n_nnnnnsssss
OP_DEF(stcr)
{
uint32 s1 = (opX >> 16) & 0x1f;
uint32 s2 = (opX ) & 0x1f;
if (s1 == s2) {
name = "stcr";
arg1 = rs1();
arg2 = crs();
} else {
// どうすべ
OP_FUNC(unimpl);
}
}
// 100000_zzzzzSSSSS_10001n_nnnnnsssss
OP_DEF(fstcr)
{
uint32 s1 = (opX >> 16) & 0x1f;
uint32 s2 = (opX ) & 0x1f;
if (s1 == s2) {
name = "fstcr";
arg1 = rs1();
arg2 = fcrs();
} else {
// どうすべ
OP_FUNC(unimpl);
}
}
// 100000_DDDDDSSSSS_11000n_nnnnnsssss
OP_DEF(xcr)
{
uint32 s1 = (opX >> 16) & 0x1f;
uint32 s2 = (opX ) & 0x1f;
if (s1 == s2) {
name = "xcr";
arg0 = rd();
arg1 = rs1();
arg2 = crs();
} else {
// どうすべ
OP_FUNC(unimpl);
}
}
// 100000_DDDDDSSSSS_11001n_nnnnnsssss
OP_DEF(fxcr)
{
uint32 s1 = (opX >> 16) & 0x1f;
uint32 s2 = (opX ) & 0x1f;
if (s1 == s2) {
name = "fxcr";
arg0 = rd();
arg1 = rs1();
arg2 = fcrs();
} else {
// どうすべ
OP_FUNC(unimpl);
}
}
// 100001_DDDDDSSSSS_00000n_nnnnnsssss
OP_DEF(fmul)
{
name = "fmul." + fsize();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
}
// 100001_DDDDD00000_001000_000nnsssss
OP_DEF(flt)
{
name = "flt." + fsize(TD) + "s";
arg0 = rd();
arg2 = rs2();
}
// 100001_DDDDDSSSSS_00101n_nnnnnsssss
OP_DEF(fadd)
{
name = "fadd." + fsize();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
}
// 100001_DDDDDSSSSS_00110n_nnnnnsssss
OP_DEF(fsub)
{
name = "fsub." + fsize();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
}
// 100001_DDDDDSSSSS_00111n_nnnnnsssss
OP_DEF(fcmp)
{
name = "fcmp.s" + fsize(T1) + fsize(T2);
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
}
// 100001_DDDDD00000_010010_0nn00sssss
OP_DEF(int)
{
name = "int.s" + fsize(T2);
arg0 = rd();
arg1 = rs2();
}
// 100001_DDDDD00000_010100_0nn00sssss
OP_DEF(nint)
{
name = "nint.s" + fsize(T2);
arg0 = rd();
arg1 = rs2();
}
// 100001_DDDDD00000_010110_0nn00sssss
OP_DEF(trnc)
{
name = "trnc.s" + fsize(T2);
arg0 = rd();
arg2 = rs2();
}
// 100001_DDDDDSSSSS_01110n_nnnnnsssss
OP_DEF(fdiv)
{
name = "fdiv." + fsize();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
}
// 110000_nnnnnnnnnn_nnnnnn_nnnnnnnnnn
OP_DEF(br)
{
name = "br";
arg0 = d26();
}
// 110001_nnnnnnnnnn_nnnnnn_nnnnnnnnnn
OP_DEF(br_n)
{
name = "br.n";
arg0 = d26();
}
// 110010_nnnnnnnnnn_nnnnnn_nnnnnnnnnn
OP_DEF(bsr)
{
name = "bsr";
arg0 = d26();
}
// 110011_nnnnnnnnnn_nnnnnn_nnnnnnnnnn
OP_DEF(bsr_n)
{
name = "bsr.n";
arg0 = d26();
}
// bb の共通部
void
m88100disasm::ops_bb(std::string namebase)
{
name = namebase;
arg0 = b5();
arg1 = rs1();
arg2 = d16();
}
// 110100_nnnnnSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(bb0)
{
ops_bb("bb0");
}
// 110101_nnnnnSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(bb0_n)
{
ops_bb("bb0.n");
}
// 110110_nnnnnSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(bb1)
{
ops_bb("bb1");
}
// 110111_nnnnnSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(bb1_n)
{
ops_bb("bb1.n");
}
void
m88100disasm::ops_bcnd(std::string n)
{
name = "bcnd" + n;
arg0 = m5();
arg1 = rs1();
arg2 = d16();
const std::string cond = alt_m5();
if (cond.empty()) {
// 空なら表現できないやつなので代替表現もなし
return;
} else if (cond == "true") {
// 無条件分岐
altname = "br" + n;
altarg0 = arg2;
} else {
// 条件分岐
altname = "br" + n;
altarg0 = cond;
altarg1 = arg2;
}
}
// 111010_MMMMMSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(bcnd)
{
ops_bcnd("");
}
// 111011_MMMMMSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(bcnd_n)
{
ops_bcnd(".n");
}
// 111100_DDDDDSSSSS_100000_wwwwwooooo
OP_DEF(clr_1)
{
name = "clr";
arg0 = rd();
arg1 = rs1();
arg2 = wo5();
if (DD == 0) {
altname = "nop";
} else {
altname = "and";
altarg0 = rd();
altarg1 = rs1();
altarg2 = string_format("0x%08x", ~wo5mask());
}
}
// 111100_DDDDDSSSSS_100010_wwwwwooooo
OP_DEF(set_1)
{
name = "set";
arg0 = rd();
arg1 = rs1();
arg2 = wo5();
if (DD == 0) {
altname = "nop";
} else {
altname = "or";
altarg0 = rd();
altarg1 = rs1();
altarg2 = string_format("0x%08x", wo5mask());
}
}
// 111100_DDDDDSSSSS_100100_wwwwwooooo
OP_DEF(ext_1)
{
name = "ext";
arg0 = rd();
arg1 = rs1();
arg2 = wo5();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 w:o clr rd
// rd rd 32:o asr rd, #o
// rd s1 32:o asr rd, s1, #o
// rd rd w:o bfexts rd, w:o
// rd s1 w:o bfexts rd, s1, w:o
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (W5 == 0 || W5 + O5 >= 32) {
// W5 + O5 >= 32 なら単純なシフトに相当
altname = "asr";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#%u", O5);
} else {
altname = "bfexts";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = wo5();
}
}
// 111100_DDDDDSSSSS_100110_wwwwwooooo
OP_DEF(extu_1)
{
name = "extu";
arg0 = rd();
arg1 = rs1();
arg2 = wo5();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 w:o clr rd
// rd rd 32:o lsr rd, #o
// rd s1 32:o lsr rd, s1, #o
// rd rd w:o bfextu rd, w:o
// rd s1 w:o bfextu rd, s1, w:o
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (W5 == 0 || W5 + O5 >= 32) {
// W5 + O5 >= 32 なら単純なシフトに相当
altname = "lsr";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#%u", O5);
} else {
altname = "bfextu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = wo5();
}
}
// 111100_DDDDDSSSSS_101000_wwwwwooooo
OP_DEF(mak_1)
{
name = "mak";
arg0 = rd();
arg1 = rs1();
arg2 = wo5();
// rd s1 imm
// ----------
// r0 * * nop
// rd r0 w:o clr rd
// rd rd 32:o lsl rd, #o
// rd s1 32:o lsl rd, s1, #o
// rd rd w:o bfmak rd, w:o
// rd s1 w:o bfmak rd, s1, w:o
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (W5 == 0 || W5 + O5 >= 32) {
// W5 + O5 >= 32 なら単純なシフトに相当
altname = "lsl";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#%u", O5);
} else {
// XXX 名前から動作が想像しづらいのがつらいのだが、とりあえず後回し
altname = "bfmak";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = wo5();
}
}
// 111100_DDDDDSSSSS_101010_zzzzzooooo
OP_DEF(rot_1)
{
name = "rot";
arg0 = rd();
arg1 = rs1();
arg2 = string_format("<%u>", O5);
// rd s1 offset
// ----------
// r0 * * nop
// rd rd #0 nop
// rd r0 * clr rd
// rd rd 1-16 ror rd, #1-16
// rd s1 1-16 ror rd, s1, #1-16
// rd rd 17-31 rol rd, #1-15
// rd s1 17-31 rol rd, s1, #1-15
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (O5 == 0) {
if (DD == S1) {
altname = "nop";
} else {
altname = "clr";
altarg0 = rd();
}
} else {
// どう表記するのがいいかは状況によるかも知れないが
// 1-16ビット(右)ローテートなら ror #0-16、
// 17-31ビット(右)ローテートなら rol #1-15 としてみる
auto offset = O5;
if (offset > 16) {
altname = "rol";
offset = 32 - offset;
} else {
altname = "ror";
}
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = string_format("#%u", offset);
}
}
void
m88100disasm::ops_tb(std::string namebase)
{
name = namebase;
arg0 = b5();
arg1 = rs1();
arg2 = vec9();
}
// 111100_bbbbbSSSSS_110100_0vvvvvvvvv
OP_DEF(tb0)
{
ops_tb("tb0");
}
// 111100_bbbbbSSSSS_110110_0vvvvvvvvv
OP_DEF(tb1)
{
ops_tb("tb1");
if (S1 == 0) {
// tb1 *,r0,* はパイプライン同期を目的として使われる。
// この形式はトラップは発生しない。
if (VEC9 < 128) {
altname = "ssync";
} else {
altname = "usync";
}
}
}
// 111100_MMMMMSSSSS_111010_0vvvvvvvvv
OP_DEF(tcnd)
{
name = "tcnd";
arg0 = m5();
arg1 = rs1();
arg2 = vec9();
}
// ld_reg, st_reg, xmem_reg の共通部
// size は ".bu" などドットを含むサイズプレフィックス。
void
m88100disasm::ops_ldst_reg(const std::string& namebase, std::string size)
{
uint32 u = (opX >> 8) & 1;
uint32 scaled = (opX >> 9) & 1;
name = namebase + size;
if (u) {
name += ".usr";
}
arg0 = rd();
arg1 = rs1();
if (scaled == 0) {
arg2 = rs2();
} else {
arg1 += "[" + rs2() + "]";
}
// 別名
// ld.bu.usr はサフィックスの使い方が節操なさすぎるし
// ld と ld.usr はわりと違う命令なので、違う命令のように見せる。
altname = namebase;
if (u) {
altname += "usr";
}
altname += size;
altarg0 = rd();
// メモリアクセスはは括弧を付けて表す。
// lda はメモリアクセスではないので括弧なしのまま。
//
// rs1 rs2 scaled
// --------------
// r* r0 * ld rd, (r*)
// r0 s2 no ld rd, (s2)
// s1 s2 no ld rd, (s1,s2)
// r0 s2 yes ld rd, (r0[s2])
// s1 s2 yes ld rd, (s1[s2])
if (S2 == 0) {
altarg1 = rs1();
} else {
if (scaled == 0) {
if (S1 == 0) {
altarg1 = rs2();
} else {
altarg1 = rs1() + "," + rs2();
}
} else {
altarg1 = rs1() + "[" + rs2() + "]";
}
}
// 3文字目が 'a' になるのは lda しかない
if (namebase[2] != 'a') {
altarg1 = "(" + altarg1 + ")";
}
}
// 111101_DDDDDSSSSS_000000_xU000sssss
OP_DEF(xmem_bu)
{
ops_ldst_reg("xmem", ".bu");
}
// 111101_DDDDDSSSSS_000001_xU000sssss
OP_DEF(xmem_w)
{
ops_ldst_reg("xmem", "");
}
// 111101_DDDDDSSSSS_000010_xU000sssss
OP_DEF(ld_hu)
{
ops_ldst_reg("ld", ".hu");
}
// 111101_DDDDDSSSSS_000011_xU000sssss
OP_DEF(ld_bu)
{
ops_ldst_reg("ld", ".bu");
}
// 111101_DDDDDSSSSS_000100_xU000sssss
OP_DEF(ld_d)
{
ops_ldst_reg("ld", ".d");
}
// 111101_DDDDDSSSSS_000101_xU000sssss
OP_DEF(ld_w)
{
ops_ldst_reg("ld", "");
}
// 111101_DDDDDSSSSS_000110_xU000sssss
OP_DEF(ld_h)
{
ops_ldst_reg("ld", ".h");
}
// 111101_DDDDDSSSSS_000111_xU000sssss
OP_DEF(ld_b)
{
ops_ldst_reg("ld", ".b");
}
// 111101_DDDDDSSSSS_001000_xU000sssss
OP_DEF(st_d)
{
ops_ldst_reg("st", ".d");
}
// 111101_DDDDDSSSSS_001001_xU000sssss
OP_DEF(st_w)
{
ops_ldst_reg("st", "");
}
// 111101_DDDDDSSSSS_001010_xU000sssss
OP_DEF(st_h)
{
ops_ldst_reg("st", ".h");
}
// 111101_DDDDDSSSSS_001011_xU000sssss
OP_DEF(st_b)
{
ops_ldst_reg("st", ".b");
}
// 111101_DDDDDSSSSS_001100_xU000sssss
OP_DEF(lda_d)
{
// XXX bit8 が 1 だとどうなるのか
ops_ldst_reg("lda", ".d");
}
// 111101_DDDDDSSSSS_001101_xU000sssss
OP_DEF(lda_w)
{
// XXX bit8 が 1 だとどうなるのか
ops_ldst_reg("lda", "");
}
// 111101_DDDDDSSSSS_001110_xU000sssss
OP_DEF(lda_h)
{
// XXX bit8 が 1 だとどうなるのか
ops_ldst_reg("lda", ".h");
}
// 111101_DDDDDSSSSS_001111_xU000sssss
OP_DEF(lda_b)
{
// XXX bit8 が 1 だとどうなるのか
ops_ldst_reg("lda", ".b");
}
// 111101_DDDDDSSSSS_010000_00000sssss
OP_DEF(and)
{
name = "and";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 * clr rd
// rd * r0 clr rd
// rd rd rd nop
// rd s1 s1 mov rd, s1
// rd rd s2 and rd, s2
// rd s1 s2 and rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0 || S2 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S1 == S2) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "and";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
if (DD != S2) {
altarg2 = rs2();
}
}
}
// 111101_DDDDDSSSSS_010001_00000sssss
OP_DEF(and_c)
{
name = "and.c";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 * clr rd
// rd s1 r0 mov rd, s1
// rd rd r0 nop
// rd s1 s1 clr rd
// rd s1 s2 and rd, s1, ~s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else if (S1 == S2) {
altname = "clr";
altarg0 = rd();
} else {
altname = "and";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = "~" + rs2();
}
}
// 111101_DDDDDSSSSS_010100_00000sssss
OP_DEF(xor)
{
name = "xor";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 s1 clr rd
// rd r0 s2 mov rd, s2
// rd s1 r0 mov rd, s1
// rd s1 s2 xor rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == S2) {
altname = "clr";
altarg0 = rd();
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs2();
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "xor";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
if (DD != S2) {
altarg2 = rs2();
}
}
}
// 111101_DDDDDSSSSS_010101_00000sssss
OP_DEF(xor_c)
{
name = "xor.c";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 s1 mov rd, #0xffffffff
// rd r0 s2 not rd, s2
// rd s1 r0 not rd, s1
// rd s1 s2 xor rd, s1, ~s2
if (DD == 0) {
altname = "nop";
} else if (S1 == S2) {
altname = "mov";
altarg0 = rd();
altarg1 = "#0xffffffff";
} else if (S1 == 0) {
altname = "not";
altarg0 = rd();
if (DD != S2) {
altarg1 = rs2();
}
} else if (S2 == 0) {
altname = "not";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
} else {
altname = "xor";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = "~" + rs2();
}
}
// 111101_DDDDDSSSSS_010110_00000sssss
OP_DEF(or)
{
name = "or";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 r0 clr rd
// rd s1 s1 mov rd, s1
// rd s1 r0 mov rd, s1
// rd r0 s2 mov rd, s2
// rd s1 s2 or rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0 && S2 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S1 == S2 || S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else if (S1 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs2();
} else {
altname = "or";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
if (DD != S2) {
altarg2 = rs2();
}
}
}
// 111101_DDDDDSSSSS_010111_00000sssss
OP_DEF(or_c)
{
name = "or.c";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 r0 mov rd, #0xffffffff
// rd s1 s1 mov rd, #0xffffffff
// rd r0 s2 not rd, s2
// rd s1 s2 or rd, s1, ~s2
if (DD == 0) {
altname = "nop";
} else if (S2 == 0 || S1 == S2) {
altname = "mov";
altarg0 = rd();
altarg1 = "#0xffffffff";
} else if (S1 == 0) {
altname = "not";
altarg0 = rd();
if (DD != S2) {
altarg1 = rs2();
}
} else {
altname = "or";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = "~" + rs2();
}
}
// 111101_DDDDDSSSSS_011000_nn000sssss
OP_DEF(addu)
{
name = "addu" + cio();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
if (CIO == 0) {
// addu 無印の場合
//
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 r0 clr rd
// rd s1 r0 mov rd, s1
// rd r0 s2 mov rd, s2
// rd s1 s2 add rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0 && S2 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S1 == 0 || S2 == 0) {
altname = "mov";
altarg0 = rd();
if (S1 == 0) {
altarg1 = rs2();
}
if (S2 == 0) {
altarg1 = rs1();
}
} else if (DD == S1 && DD == S2) {
altname = "addu";
altarg0 = rd();
altarg1 = rs2();
} else {
altname = "addu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
if (DD != S2) {
altarg2 = rs2();
}
}
} else {
// addu キャリー込み .ci/co/cio のほうは 2 オペランドへの省略のみ。
// XXX addu の2項は交換可なので addu r1, r2, r1 は addu r1, r2 と
// 省略できていいがそれには未対応。
altname = "addu" + cio();
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_011001_nn000sssss
OP_DEF(subu)
{
name = "subu" + cio();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
if (CIO == 0) {
// subu 無印の場合
//
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 s1 clr rd
// rd s1 r0 mov rd, s1
// rd s1 s2 subu rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == S2) {
altname = "clr";
altarg0 = rd();
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "subu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
} else {
// subu キャリー込み .ci/co/cio のほうは 2 オペランドへの省略のみ。
altname = "subu" + cio();
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_011010_zz000sssss
OP_DEF(divu)
{
name = "divu";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// 例外が起きる可能性があるので 2オペランドへの省略のみ
altname = "divu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
// 111101_DDDDDSSSSS_011011_zz000sssss
OP_DEF(mul)
{
name = "mul";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// 例外が起きる可能性があるので 2オペランドへの省略のみ
altname = "mul";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
// 111101_DDDDDSSSSS_011100_nn000sssss
OP_DEF(add)
{
name = "add" + cio();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
if (CIO == 0) {
// add 無印は符号付きなので、より明示的な adds を使う。
// 符号付き加算ではオーバーフローが起きる可能性があるため、
// rD が r0 であってもただちに nop とはならない。
// 一方 r0 を加算する場合は何も起きないので圧縮表記したい。
// rd s1 s2
// ----------
// rd r0 r0 clr rd
// r0 r0 rd nop
// rd r0 rd nop
// rd r0 s2 mov rd, s2
// rd rd r0 nop
// rd s1 r0 mov rd, s1
// rd s1 s2 adds rd, s1, s2
if (S1 == 0 && S2 == 0) {
if (DD == 0) {
altname = "nop";
} else {
altname = "clr";
altarg0 = rd();
}
} else if (S1 == 0) {
if (DD == 0) {
altname = "nop";
} else {
altname = "mov";
altarg0 = rd();
altarg1 = rs2();
}
} else if (S2 == 0) {
if (DD == 0) {
altname = "nop";
} else {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
}
} else {
altname = "adds";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
} else {
// adds キャリー込み .ci/co/cio のほうは 2 オペランドへの省略のみ。
altname = "adds" + cio();
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_011101_nn000sssss
OP_DEF(sub)
{
name = "sub" + cio();
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
if (CIO == 0) {
// sub 無印は符号付きなので、より明示的な subs を使う。
// 符号付き減算ではオーバーフローが起きる可能性があるため、
// rD が r0 であってもただちに nop とはならない。
// 一方 r0 を減算する場合は何も起きないので圧縮表記したい。
// rd s1 s2
// ----------
// rd rd r0 nop
// rd r0 r0 clr rd
// rd s1 r0 mov rd, s1
// rd s1 s2 subs rd, s1, s2
if (S1 == 0 && S2 == 0) {
if (DD == 0) {
altname = "nop";
} else {
altname = "clr";
altarg0 = rd();
}
} else if (S2 == 0) {
if (DD == 0) {
altname = "nop";
} else {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
}
} else {
altname = "subs";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
} else {
// subs キャリー込み .ci/co/cio のほうは 2 オペランドへの省略のみ。
altname = "subs" + cio();
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_011110_zz000sssss
OP_DEF(div)
{
name = "div";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// 例外が起きる可能性があるので 2オペランドへの省略のみ
altname = "div";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
// 111101_DDDDDSSSSS_011111_zz000sssss
OP_DEF(cmp)
{
name = "cmp";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// cmp r0,*,* 以外は別表記を用意する必要ない
if (DD == 0) {
altname = "nop";
}
}
// 111101_DDDDDSSSSS_100000_00000sssss
OP_DEF(clr_2)
{
name = "clr";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 s2 clr rd
// rd s1 r0 mov rd, s1
// rd rd s2 bfclr rd, s2
// rd s1 s2 bfclr rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "bfclr";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_100010_00000sssss
OP_DEF(set_2)
{
name = "set";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 r0 mov rd, #0xffffffff
// rd rd s2 bfset rd, s2
// rd s1 s2 bfset rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = "#0xffffffff";
} else {
altname = "bfset";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_100100_00000sssss
OP_DEF(ext_2)
{
name = "ext";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 r0 mov rd, s1
// rd rd s2 bfexts rd, s2
// rd s1 s2 bfexts rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "bfexts";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_100110_00000sssss
OP_DEF(extu_2)
{
name = "extu";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd s1 r0 mov rd, s1
// rd rd s2 bfextu rd, s2
// rd s1 s2 bfextu rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "bfextu";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_101000_00000sssss
OP_DEF(mak_2)
{
name = "mak";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 s2 clr rd
// rd s1 r0 mov rd, s1
// rd s1 s2 bfmak rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "bfmak";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_DDDDDSSSSS_101010_00000sssss
OP_DEF(rot_2)
{
name = "rot";
arg0 = rd();
arg1 = rs1();
arg2 = rs2();
// rd s1 s2
// ----------
// r0 * * nop
// rd r0 s2 clr rd
// rd s1 r0 mov rd, s1
// rd s1 s2 ror rd, s1, s2
if (DD == 0) {
altname = "nop";
} else if (S1 == 0) {
altname = "clr";
altarg0 = rd();
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = rs1();
} else {
altname = "ror";
altarg0 = rd();
if (DD != S1) {
altarg1 = rs1();
}
altarg2 = rs2();
}
}
// 111101_zzzzzzzzzz_110000_00000sssss
OP_DEF(jmp)
{
name = "jmp";
arg0 = rs2();
}
// 111101_zzzzzzzzzz_110001_00000sssss
OP_DEF(jmp_n)
{
name = "jmp.n";
arg0 = rs2();
}
// 111101_zzzzzzzzzz_110010_00000sssss
OP_DEF(jsr)
{
name = "jsr";
arg0 = rs2();
}
// 111101_zzzzzzzzzz_110011_00000sssss
OP_DEF(jsr_n)
{
name = "jsr.n";
arg0 = rs2();
}
// 111101_DDDDDzzzzz_111010_00000sssss
OP_DEF(ff1)
{
name = "ff1";
arg0 = rd();
arg1 = rs2();
// rd s2
// ------
// r0 * nop
// rd r0 mov rd, #32
// rd s2 ff1 rd, s2
if (DD == 0) {
altname = "nop";
} else if (S2 == 0) {
altname = "mov";
altarg0 = rd();
altarg1 = "#32";
} else {
altname = "ff1";
altarg0 = rd();
altarg1 = rs2();
}
}
// 111101_DDDDDzzzzz_111011_00000sssss
OP_DEF(ff0)
{
name = "ff0";
arg0 = rd();
arg1 = rs2();
// rd s2
// ------
// r0 * nop
// rd r0 clr rd
// rd s2 ff0 rd, s2
if (DD == 0) {
altname = "nop";
} else if (S2 == 0) {
altname = "clr";
altarg0 = rd();
} else {
altname = "ff0";
altarg0 = rd();
altarg1 = rs2();
}
}
// 111101_zzzzzzzzzz_111111_0000000000
OP_DEF(rte)
{
name = "rte";
}
// 111101_zzzzzSSSSS_111110_00000SSSSS
OP_DEF(tbnd_1)
{
name = "tbnd";
arg1 = rs1();
arg2 = rs2();
}
// 111110_zzzzzSSSSS_nnnnnn_nnnnnnnnnn
OP_DEF(tbnd_2)
{
name = "tbnd";
arg1 = rs1();
arg2 = imm16();
}
// 111111_DDDDDSSSSS_000001_00nnnnnnnn
OP_DEF(doscall)
{
name = "doscall";
arg0 = rd();
arg1 = rs1();
arg2 = string_format("#0x%02x", (opX & 0xff));
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.