|
|
nono 1.0.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
// EA は大別して5種類。
//
// |d m rxwp | 制御 CalcCtrl サイズ不問
// |dam+-rxw | 可変 CalcData B/W/L
// | m rxwp | MMU CalcMMU サイズ不問
// |dam+-rxwpi| FPU CalcFPU B/W/L/S/D/X/P
// |d m+-rxwpi| データ FetchData B/W/L
// |dam+-rxwpi| All FetchAll B/W/L
//
// CalcCtrl はユーザーズマニュアルで「制御(Control)」と呼ばれている
// グループで、デスティネーション側のため EA の計算のみ。
// また (An)+/-(An) を含まないため、サイズに関係なく1種類だけでよい。
//
// CalcData はユーザーズマニュアルで「可変」と呼ばれているグループで、
// デスティネーション側のため EA の計算のみ。サイズは B/W/L。
// (An)+/-(An) ならレジスタを保存する。
//
// CalcMMU は対 MMU 用に勝手に用意したもの。
//
// CalcFPU は対 FPU 用。ソースであっても CalcFPU を使用する。
// サイズは B/W/L/S/D/X/P。
// (An)+/-(An) ならレジスタを保存する。
// フェッチサイクルは別途存在するはずだが不詳。
//
// FetchData はユーザーズマニュアルで「データ(Data)」と呼ばれている
// グループで、ソース側のため EA 計算および値の取得。サイズは B/W/L。
// (An)+/-(An) ならレジスタを保存する。
//
// FetchAll はユーザーズマニュアルのここには記載がないグループで、
// ソース側のため EA 計算および値の取得。サイズは B/W/L。
// (An)+/-(An) ならレジスタを保存する。
//
// CalcCtrl、CalcData でアドレッシングモードに D や A が含まれている場合は
// その命令のデスティネーションに Dn、An が指定できるという意味であり、
// EA 処理であるここには関係ない。
// EA 計算より前に呼出側で条件分けして処理すること。
//
// CalcCtrl、CalcData と FetchData には (*) 印の例外があるので留意。
//
// (CalcCtrl)
// | m rxwp | CMP2/CHK2
// | m rxwp | JMP/JSR
// | m rxwp | LEA/PEA
// |d m rxwp | BFEXT*/BFFFO/BFTST
// |d m rxw | (*) BFCHG/BFCLR/BFINS/BFSET <ea>{#o:#w}
//
// (CalcData)
// | m+-rxw | ADD/SUB/CMP Dx,<ea>
// | m+-rxw | CAS/TAS <ea>
// | m+-rxw | MOVES <ea>,Rn
// | m+-rxw | shift/rotate.W <ea>
// | m+-rxw | BCHG/BCLR/BSET src,<ea>
// |d m+-rxw | ADDI/SUBI Dx,<ea>
// |d m+-rwx | NBCD <ea>
// |d m+-rxw | AND/OR/EOR Dx,<ea>
// |d m+-rxw | CLR/NEG/NEGX/NOT/TST/Scc <ea>
// |d m+-rxw | MOVE CCR/SR,<ea>
// |dam+-rxw | ADDQ/SUBQ #qqq,<ea>
// |dam+-rxw | (*) MOVE の dst 側。EA の分類的には CalcData だが、
// 下位6ビットの IR ではないので、cea_data_NN() ではなく
// 各々 cea_XXXX() のほうを個別に呼ぶこと。
//
// (CalcMMU)
// | m rxw | MMU
//
// (CalcFPU)
// |d m+-rxw | FScc.B <ea>
// |dam+-rxw | FMOVE.f FPn,<ea>
// |dam+-rxw | FMOVE.L ctl,<ea>
// |dam+-rxw | FMOVEM.L ctl,<ea>
// |d m+-rxwpi| Fgen <ea>,FPn
// |d m+-rxwpi| FMOVE.f <ea>,FPn
// |dam+-rwxpi| FMOVE.L <ea>,ctl
// |dam+-rxwpi| FMOVEM.L <ea>,ctl
// 実際にどのアドレッシングモードが有効かどうかは極力個別の命令内で判断する?
// ここは実行サイクル数的な分類。
//
// (FetchData)
// |d m+-rxwpi| AND/OR/CHK <ea>,Dn
// |d m+-rxwpi| MOVE.B <ea>,dst
// |d m+-rxwpi| MOVE <ea>,CCR/SR
// |d m+-rxwpi| MUL*/DIV* <ea>,Dn
// |d m+-rxwp | (*) TST.B <ea>
// |d m+-rxwp | (*) CMPI #<data>,<ea>
// | m+-rxwp | (*) BTST.B #<data>,<ea>
// | m+-rxwpi| (*) BTST.B Dx,<ea>
//
// (FetchAll)
// |dam+-rxwpi| ADD/SUB/CMP <ea>,Dn
// |dam+-rxwpi| MOVEA/ADDA/SUBA/CMPA <ea>,An
// |dam+-rxwpi| TST.WL <ea>
// |dam+-rxwpi| MOVE.WL <ea>,dst
//
// (たぶん別対応)
// | m -rxw | MOVEM list,<ea>
// | m -rxw | FMOVEM.X reg,<ea>
// | m -rxw | FSAVE <ea>
// | m+ rxwp | MOVEM <ea>,list
// | m+ rxwp | FMOVEM.X <ea>,reg
// | m+ rxwp | FRESTORE <ea>
#include "mpu680x0.h"
//
// Calc EA
//
// 個別 EA は (An)+/-(An) でもレジスタを保存しない。
// 自動的に保存する cea_data() 等を介さずこれらを呼ぶ時は
// レジスタ保存のタイミングや回数に注意すること。
uint32
MPU680x0Device::cea_anin(uint n)
{
CYCLE(2);
return internal_ea_anin(n);
}
uint32
MPU680x0Device::cea_anpi_1(uint n)
{
CYCLE(2);
return internal_ea_anpi_1(n);
}
uint32
MPU680x0Device::cea_anpi_2(uint n)
{
CYCLE(2);
return internal_ea_anpi_2(n);
}
uint32
MPU680x0Device::cea_anpi_4(uint n)
{
CYCLE(2);
return internal_ea_anpi_4(n);
}
uint32
MPU680x0Device::cea_anpd_1(uint n)
{
CYCLE(2);
return internal_ea_anpd_1(n);
}
uint32
MPU680x0Device::cea_anpd_2(uint n)
{
CYCLE(2);
return internal_ea_anpd_2(n);
}
uint32
MPU680x0Device::cea_anpd_4(uint n)
{
CYCLE(2);
return internal_ea_anpd_4(n);
}
uint32
MPU680x0Device::cea_andi(uint n)
{
CYCLE(2);
return internal_ea_andi(n);
}
uint32
MPU680x0Device::cea_anix(uint n)
{
CYCLE(10); // XXX 4,4-18,20
return internal_ea_anix(n);
}
uint32
MPU680x0Device::cea_absw()
{
CYCLE(2);
return internal_ea_absw();
}
uint32
MPU680x0Device::cea_absl()
{
CYCLE(4);
return internal_ea_absl();
}
uint32
MPU680x0Device::cea_pcdi()
{
CYCLE(2);
return internal_ea_pcdi();
}
uint32
MPU680x0Device::cea_pcix()
{
CYCLE(10); // XXX 4,4-18,20
return internal_ea_pcix();
}
//
// Fetch EA
//
inline uint32
MPU680x0Device::fea_anin()
{
CYCLE(3);
return internal_ea_anin(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anpi_1()
{
CYCLE(3);
return internal_ea_anpi_1(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anpi_2()
{
CYCLE(3);
return internal_ea_anpi_2(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anpi_4()
{
CYCLE(3);
return internal_ea_anpi_4(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anpd_1()
{
CYCLE(4);
return internal_ea_anpd_1(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anpd_2()
{
CYCLE(4);
return internal_ea_anpd_2(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anpd_4()
{
CYCLE(4);
return internal_ea_anpd_4(eanum(ir));
}
inline uint32
MPU680x0Device::fea_andi()
{
CYCLE(4);
return internal_ea_andi(eanum(ir));
}
inline uint32
MPU680x0Device::fea_anix()
{
CYCLE2(12, 14); // XXX 6,6-18,21
return internal_ea_anix(eanum(ir));
}
inline uint32
MPU680x0Device::fea_absw()
{
CYCLE(4);
return internal_ea_absw();
}
inline uint32
MPU680x0Device::fea_absl()
{
CYCLE2(4, 5);
return internal_ea_absl();
}
inline uint32
MPU680x0Device::fea_pcdi()
{
CYCLE(4);
return internal_ea_pcdi();
}
inline uint32
MPU680x0Device::fea_pcix()
{
CYCLE2(12, 14); // XXX 6,6-18,21
return internal_ea_pcix();
}
inline void
MPU680x0Device::fea_imm_2()
{
CYCLE(2);
}
inline void
MPU680x0Device::fea_imm_4()
{
CYCLE(4);
}
//
// EA の拡張ワード
//
uint32
MPU680x0Device::internal_ea_ix(uint32 anpc)
{
uint16 ext = fetch_2();
uint rn = (ext >> 12) & 15;
bool idx_long = (ext & 0x0800);
uint scale = (ext >> 9) & 3;
if ((ext & 0x0100) == 0) {
// Brief extension
//
// F E D C B A 9 8 7 6 5 4 3 2 1 0
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | DA| n | WL| SCALE | 0 | disp |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// WL: インデックスレジスタ(Rn)のサイズ 1=.L 0=.W
// SCALE: スケールファクタ %00=*1 %01=*2 %10=*4 %11=*8
CYCLE(4);
int32 disp = (int32)(int8)(ext & 0xff);
uint32 idx;
if (idx_long) {
idx = reg.R[rn];
} else {
idx = (int32)(int16)(reg.R[rn] & 0xffff);
}
idx <<= scale;
return anpc + (int32)idx + disp;
} else {
// Full extension
//
// F E D C B A 9 8 7 6 5 4 3 2 1 0
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | DA| n | WL| SCALE | 1 | BS| IS| BDSZ | 0 | I/IS |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// BS=1: ベースレジスタ・サプレス
// IS=1: インデックスオペランド・サプレス
// BDSZ: ベースディスプレースメントのサイズ %01=null %10=.W %11=.L
// I/IS: モード
// クロックは概略値なので完全に正確ではないがまず基本は以下の2通り。
// メモリ間接なし (6, 6)
// メモリ間接あり (10, 10)
// これを元に必要に応じて以下をそれぞれ加算する。
// bd16 (+2, +3)
// bd32 (メモリ間接なし) (+4, +6)
// bd32 (メモリ間接あり) (+6, +6)
// outer (W/L 不問) (+2, +3)
// ただしここでは実行順の都合で bd32 はいずれも (+4, +6) とした。
bool bs = (ext & 0x0080);
bool is = (ext & 0x0040);
uint bdsize = (ext >> 4) & 3;
uint iis = (ext & 7);
// ベースレジスタ
if (bs) {
anpc = 0;
}
// ベース・ディスプレースメント
uint32 base = 0;
switch (bdsize) {
case 0: // 予約
// XXX 未定義命令列になるんだろうか?
PANIC("BDSIZE==0 not impl");
case 1: // ベースはヌル
break;
case 2: // ベース.W
base = (int32)(int16)fetch_2();
CYCLE2(2, 3);
break;
case 3: // ベース.L
base = fetch_4();
CYCLE2(4, 6);
break;
default:
__unreachable();
}
uint32 outer;
if (is == 0) {
// インデックス
uint32 idx = 0;
if (idx_long) {
idx = reg.R[rn];
} else {
idx = (int32)(int16)(reg.R[rn] & 0xffff);
}
idx <<= scale;
switch (iis) {
case 0: // no memory indirection
CYCLE(6);
return anpc + base + idx;
case 1: // indirect pre-index with null outer
CYCLE(10);
return read_4(anpc + base + idx);
case 2: // indirect pre-index with word outer
CYCLE2(10+2, 10+3);
outer = (int32)(int16)fetch_2();
return read_4(anpc + base + idx) + outer;
case 3: // indirect pre-index with long outer
CYCLE2(10+2, 10+3);
outer = fetch_4();
return read_4(anpc + base + idx) + outer;
case 4:
PANIC("iis==4 reserved");
case 5: // indirect post-index with null outer
CYCLE(10);
return read_4(anpc + base) + idx;
case 6: // indirect post-index with word outer
CYCLE2(10+2, 10+3);
outer = (int32)(int16)fetch_2();
return read_4(anpc + base) + idx + outer;
case 7: // indirect post-index with long outer
CYCLE2(10+2, 10+3);
outer = fetch_4();
return read_4(anpc + base) + idx + outer;
default:
__unreachable();
}
} else {
switch (iis) {
case 0: // no memory indirection
CYCLE(6);
return anpc + base;
case 1: // memory indirect with null outer
CYCLE(10);
return read_4(anpc + base);
case 2: // memory indirect with word outer
CYCLE2(10+2, 10+3);
outer = (int32)(int16)fetch_2();
return read_4(anpc + base) + outer;
case 3: // memory indirect with long outer
CYCLE2(10+2, 10+3);
outer = fetch_4();
return read_4(anpc + base) + outer;
default:
PANIC("is==1 && iis>3 reserved");
}
}
}
}
//
// Calc EA
//
uint32
MPU680x0Device::cea_ctrl()
{
switch (eamode(ir)) {
case 2: // (An)
return cea_anin(eanum(ir));
case 5: // d16(An)
return cea_andi(eanum(ir));
case 6: // (An,IX)
return cea_anix(eanum(ir));
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
return cea_absw();
case 1: // Abs.L
return cea_absl();
case 2: // d16(PC)
return cea_pcdi();
case 3: // (PC,IX)
return cea_pcix();
default:
break;
}
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::cea_data_1()
{
switch (eamode(ir)) {
case 2: // (An)
return cea_anin(eanum(ir));
case 3: // (An)+
save_reg_pi(eanum(ir));
return cea_anpi_1(eanum(ir));
case 4: // -(An)
save_reg_pd(eanum(ir));
return cea_anpd_1(eanum(ir));
case 5: // d16(An)
return cea_andi(eanum(ir));
case 6: // (An,IX)
return cea_anix(eanum(ir));
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
return cea_absw();
case 1: // Abs.L
return cea_absl();
default:
break;
}
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::cea_data_2()
{
switch (eamode(ir)) {
case 2: // (An)
return cea_anin(eanum(ir));
case 3: // (An)+
save_reg_pi(eanum(ir));
return cea_anpi_2(eanum(ir));
case 4: // -(An)
save_reg_pd(eanum(ir));
return cea_anpd_2(eanum(ir));
case 5: // d16(An)
return cea_andi(eanum(ir));
case 6: // (An,IX)
return cea_anix(eanum(ir));
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
return cea_absw();
case 1: // Abs.L
return cea_absl();
default:
break;
}
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::cea_data_4()
{
switch (eamode(ir)) {
case 2: // (An)
return cea_anin(eanum(ir));
case 3: // (An)+
save_reg_pi(eanum(ir));
return cea_anpi_4(eanum(ir));
case 4: // -(An)
save_reg_pd(eanum(ir));
return cea_anpd_4(eanum(ir));
case 5: // d16(An)
return cea_andi(eanum(ir));
case 6: // (An,IX)
return cea_anix(eanum(ir));
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
return cea_absw();
case 1: // Abs.L
return cea_absl();
default:
break;
}
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
// MMU からの呼び出し用。
uint32
MPU680x0Device::cea_copro()
{
switch (eamode(ir)) {
case 2: // (An)
CYCLE(4);
return internal_ea_anin(eanum(ir));
case 5: // d16(An)
CYCLE(4);
return internal_ea_andi(eanum(ir));
case 6: // (An,IX)
CYCLE(4);
return internal_ea_anix(eanum(ir));
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
CYCLE(4);
return internal_ea_absw();
case 1: // Abs.L
CYCLE(6);
return internal_ea_absl();
default:
break;
}
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
//
// Fetch EA
//
uint32
MPU680x0Device::fea_data_1()
{
uint32 ea;
switch (eamode(ir)) {
case 0: // Dn
return reg.D[eanum(ir)] & 0xff;
case 2: // (An)
ea = fea_anin();
return read_1(ea);
case 3: // (An)+
save_reg_pi(eanum(ir));
ea = fea_anpi_1();
return read_1(ea);
case 4: // -(An)
save_reg_pd(eanum(ir));
ea = fea_anpd_1();
return read_1(ea);
case 5: // d16(An)
ea = fea_andi();
return read_1(ea);
case 6: // (An,IX)
ea = fea_anix();
return read_1(ea);
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = fea_absw();
return read_1(ea);
case 1: // Abs.L
ea = fea_absl();
return read_1(ea);
case 2: // d16(PC)
ea = fea_pcdi();
return read_1(ea);
case 3: // (PC,IX)
ea = fea_pcix();
return read_1(ea);
case 4: // #imm
fea_imm_2();
return fetch_2() & 0xff;
default:
break;
}
break;
default:
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::fea_data_2()
{
uint32 ea;
switch (eamode(ir)) {
case 0: // Dn
return reg.D[eanum(ir)] & 0xffff;
case 2: // (An)
ea = fea_anin();
return read_2(ea);
case 3: // (An)+
save_reg_pi(eanum(ir));
ea = fea_anpi_2();
return read_2(ea);
case 4: // -(An)
save_reg_pd(eanum(ir));
ea = fea_anpd_2();
return read_2(ea);
case 5: // d16(An)
ea = fea_andi();
return read_2(ea);
case 6: // (An,IX)
ea = fea_anix();
return read_2(ea);
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = fea_absw();
return read_2(ea);
case 1: // Abs.L
ea = fea_absl();
return read_2(ea);
case 2: // d16(PC)
ea = fea_pcdi();
return read_2(ea);
case 3: // (PC,IX)
ea = fea_pcix();
return read_2(ea);
case 4: // #imm
fea_imm_2();
return fetch_2();
default:
break;
}
break;
default:
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::fea_data_4()
{
uint32 ea;
switch (eamode(ir)) {
case 0: // Dn
return reg.D[eanum(ir)];
case 2: // (An)
ea = fea_anin();
return read_4(ea);
case 3: // (An)+
save_reg_pi(eanum(ir));
ea = fea_anpi_4();
return read_4(ea);
case 4: // -(An)
save_reg_pd(eanum(ir));
ea = fea_anpd_4();
return read_4(ea);
case 5: // d16(An)
ea = fea_andi();
return read_4(ea);
case 6: // (An,IX)
ea = fea_anix();
return read_4(ea);
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = fea_absw();
return read_4(ea);
case 1: // Abs.L
ea = fea_absl();
return read_4(ea);
case 2: // d16(PC)
ea = fea_pcdi();
return read_4(ea);
case 3: // (PC,IX)
ea = fea_pcix();
return read_4(ea);
case 4: // #imm
fea_imm_4();
return fetch_4();
default:
break;
}
break;
default:
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::fea_all_1()
{
uint32 ea;
switch (eamode(ir)) {
case 0: // Dn
return reg.D[eanum(ir)] & 0xff;
case 1: // An
// An.B は不当命令
break;
case 2: // (An)
ea = fea_anin();
return read_1(ea);
case 3: // (An)+
save_reg_pi(eanum(ir));
ea = fea_anpi_1();
return read_1(ea);
case 4: // -(An)
save_reg_pd(eanum(ir));
ea = fea_anpd_1();
return read_1(ea);
case 5: // d16(An)
ea = fea_andi();
return read_1(ea);
case 6: // (An,IX)
ea = fea_anix();
return read_1(ea);
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = fea_absw();
return read_1(ea);
case 1: // Abs.L
ea = fea_absl();
return read_1(ea);
case 2: // d16(PC)
ea = fea_pcdi();
return read_1(ea);
case 3: // (PC,IX)
ea = fea_pcix();
return read_1(ea);
case 4: // #imm
fea_imm_2();
return fetch_2() & 0xff;
default:
break;
}
break;
default:
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::fea_all_2()
{
uint32 ea;
switch (eamode(ir)) {
case 0: // Dn
case 1: // An
return reg.R[ir & 15] & 0xffff;
case 2: // (An)
ea = fea_anin();
return read_2(ea);
case 3: // (An)+
save_reg_pi(eanum(ir));
ea = fea_anpi_2();
return read_2(ea);
case 4: // -(An)
save_reg_pd(eanum(ir));
ea = fea_anpd_2();
return read_2(ea);
case 5: // d16(An)
ea = fea_andi();
return read_2(ea);
case 6: // (An,IX)
ea = fea_anix();
return read_2(ea);
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = fea_absw();
return read_2(ea);
case 1: // Abs.L
ea = fea_absl();
return read_2(ea);
case 2: // d16(PC)
ea = fea_pcdi();
return read_2(ea);
case 3: // (PC,IX)
ea = fea_pcix();
return read_2(ea);
case 4: // #imm
fea_imm_2();
return fetch_2();
default:
break;
}
break;
default:
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
uint32
MPU680x0Device::fea_all_4()
{
uint32 ea;
switch (eamode(ir)) {
case 0: // Dn
case 1: // An
return reg.R[ir & 15];
case 2: // (An)
ea = fea_anin();
return read_4(ea);
case 3: // (An)+
save_reg_pi(eanum(ir));
ea = fea_anpi_4();
return read_4(ea);
case 4: // -(An)
save_reg_pd(eanum(ir));
ea = fea_anpd_4();
return read_4(ea);
case 5: // d16(An)
ea = fea_andi();
return read_4(ea);
case 6: // (An,IX)
ea = fea_anix();
return read_4(ea);
case 7:
switch (eanum(ir)) {
case 0: // Abs.W
ea = fea_absw();
return read_4(ea);
case 1: // Abs.L
ea = fea_absl();
return read_4(ea);
case 2: // d16(PC)
ea = fea_pcdi();
return read_4(ea);
case 3: // (PC,IX)
ea = fea_pcix();
return read_4(ea);
case 4: // #imm
fea_imm_4();
return fetch_4();
default:
break;
}
break;
default:
break;
}
// 不当命令
throw M68K::EXCEP_ILLEGAL;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.