|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// MPU (M88xx0)
//
#pragma once
#include "mpu.h"
#include "branchhistory.h"
#include "m88100.h"
#include "m88200.h"
#include <array>
class MPU88xx0Device : public MainMPUDevice, private M88100
{
using inherited = MainMPUDevice;
friend class Luna88kPROMEmuDevice;
public:
MPU88xx0Device();
~MPU88xx0Device() override;
bool Init() override;
void ResetHard(bool poweron) override;
// キャッシュ禁止通知 (LUNA-88K では使っていない?)
void SetCI() override { }
// 現在実行中の命令の PC を取得
uint32 GetPPC() const override { return reg.xip; }
// 現在の VBR を取得
uint32 GetVBR() const override { return reg.vbr; }
// MPU 名を取得
const char *GetMPUName() const override { return "MC88100"; }
// スーパーバイザ/ユーザモードなら true
bool IsSuper() const { return (reg.psr & PSR_SUPER) != 0; }
bool IsUser() const { return (reg.psr & PSR_SUPER) == 0; }
// 割り込みが許可なら true
bool IsIntrEnable() const { return (reg.psr & PSR_IND) == 0; }
// アクセスウェイト [clock] を加算。m88200 が呼ぶ。
void AddCycle(int32 cycle) {
// XXX 本来は今アクセスしてきている(= バスマスターの) CMMU に
// 対して加算するべき?かもだが、まだその辺の概念がない。
used_cycle += cycle;
}
// アクセスウェイト [nsec] を加算。m88200 が呼ぶ。
void AddWait(uint64 nsec) {
buswait += nsec;
}
// 割り込み発生を MPU に通知
void Interrupt(int level) override;
// DOS call エミュレーションのコールバックを指定する
void SetFLineCallback(bool (*callback)(MPU88xx0Device *, void *),
void *arg);
// op が負数ならバスエラーが起きた
static bool OpIsBusErr(uint64 op) {
return (int64)op < 0;
}
m88100reg reg {};
// 直近のデータアクセスアドレス。
// XXX メモリブレークポイント用だがもう少しなんとかしたい
uint64 lastaddr {};
private:
// リセット例外コールバック
void ResetCallback(Event *);
// 命令実行系コールバック
void ExecNormal(Event *);
void ExecTrace(Event *);
// トレース設定。デバッガから呼び出される。
void SetTrace(bool enable) override;
uint64 fetch() {
reg.nip = reg.fip;
reg.opF = cmmu[0]->load_4(reg.fip);
reg.fip += 4;
return reg.opF;
}
void Prefetch();
// PSR を newpsr に変更する。
// CY ビットは特別にこの関数を経由しないで変更してよいことにする。
void SetPSR(uint32 newpsr) {
reg.psr = newpsr;
SetPSR();
}
// 更新された psr に基づいて、PSR 変更によって必要な処理をする。
// CY ビットを変更した場合は呼ばなくてよいことにする。
void SetPSR();
// キャリーフラグが立っていれば 1 を返す
uint32 GetCY() const { return (reg.psr >> 28) & 1; }
// キャリーフラグをセットする。
// cy のうち最下位ビットのみ参照する (呼び出し側はマスクせず渡してよい)
void SetCY(uint cy) {
reg.psr &= ~PSR_C;
reg.psr |= ((cy & 1) << 28);
}
// SFU1(FPU)が有効なら true
bool IsFPUEnable() const { return (reg.psr & PSR_SFD1) == 0; }
// MXM (Misaligned Access Enable) なら true
bool IsMXM() const { return (reg.psr & PSR_MXM) != 0; }
// FPxS1, FPxS2 レジスタを設定
static void SetFPxS(uint32 *h, uint32 *l, double src, uint32 t);
void SetFPS1(double src, uint32 t1);
void SetFPS2(double src, uint32 t2);
void SetFPS1(uint32 src);
void SetFPS2(uint32 src);
// FP Result を FPIT, FPRH, FPRL レジスタに設定
void SetFPRx(double src);
void ExceptionCore(uint32 primask);
void Exception(uint32 pri);
void OuterException(uint32 pri);
void InternalException(uint32 vec);
void TrapException(uint32 vec);
uint32 MakeDMT(uint32 flag);
void ReadDataException32(uint32 addr, uint32 flag);
void ReadDataException64(uint32 addr, uint32 flag);
void WriteDataException32(uint32 addr, uint32 flag);
void WriteDataException64(uint32 addr, uint32 flag);
void XmemDataException(uint32 addr, uint32 flag);
void FPPreciseException(uint32 cause, double s2);
void FPPreciseException(uint32 cause, double s1, double s2);
void FPPreciseException(uint32 cause);
void FPImpreciseException(uint32 cause);
// ブランチ処理用
void DoBranch(uint32 toaddr, bool next_exec);
uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ
// ロードストア命令用の下処理
uint32 ldst_scale(uint32 size);
// 浮動小数点数命令用の処理
void ops_int(int mode);
#define OP_PROTO(name) void __CONCAT(op_,name)()
#include "m88100ops.h"
OP_PROTO(illegal);
#undef OP_PROTO
// float,double と整数値の相互変換
static float u2f(uint32 u) {
float v;
memcpy(&v, &u, sizeof(v));
return v;
}
static double u2d(uint64 u) {
double v;
memcpy(&v, &u, sizeof(v));
return v;
}
static uint32 f2u(float v) {
uint32 u;
memcpy(&u, &v, sizeof(u));
return u;
}
static uint64 d2u(double v) {
uint64 u;
memcpy(&u, &v, sizeof(u));
return u;
}
// [0] 命令バス
// [1] データバス
std::array<std::unique_ptr<m88200>, 2> cmmu {};
// ブランチ履歴 (例外履歴を含む)
BranchHistory_m88xx0 brhist { OBJ_MPU_BRHIST };
// 例外履歴のみ
BranchHistory_m88xx0 exhist { OBJ_MPU_EXHIST };
// 今のところサイクルを正確に実装するのは無理なので
// 適当に全部積み上げてある。
// 電源オンからの累積消費サイクル
uint64 used_cycle {};
// 今回のバスウェイト [nsec]
uint64 buswait {};
// 割り込み信号線の状態。
bool intr_asserted {};
// ペンディング中の例外優先度。EXCPRI_*
uint32 excep_pending {};
// 内部例外/トラップ例外のベクタ番号。EXCVEC_*
uint32 excep_vector {};
// 疑似 STOP 状態に入る機能を有効にする場合 true
bool pseudo_stop_enable {};
// DOS call エミュレーション
bool (*fline_callback)(MPU88xx0Device *, void *) = NULL;
void *fline_arg {};
// レジスタモニター
DECLARE_MONITOR_SCREEN(MonitorScreen);
Monitor *monitor {};
// イベントコールバック
EventCallback_t exec_normal {};
};
// これを呼びたい人は mpu を持ってるはず。
inline MPU88xx0Device *GetMPU88xx0Device(Device *mpu_) {
return dynamic_cast<MPU88xx0Device*>(mpu_);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.