|
|
nono 1.7.0
//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//
//
// MPU (HD647180)
//
#pragma once
#include "mpu.h"
#include "branchhistory.h"
#include "hd64180.h"
#include "message.h"
#include <array>
class HD647180ASCIDevice;
class PIO0Device;
class SSGDevice;
class XPbusDevice;
class MPU64180Device : public MPUDevice, private HD64180
{
using inherited = MPUDevice;
// タイマー1個分
struct XPTimer {
uint16 count; // 現在のカウント
uint16 reload; // リロードカウント
uint16 tmpcount; // 読み出し時用の内部バッファ
bool running; // カウントダウン中なら true
bool intr_enable; // TIEn ビットの状態 (IEF1 の状態は含まない)
// 割り込みフラグ TIFn はカウントが 0 になると立ち、
// その後 TCR と TDR をそれぞれ読むことで (AND 条件)、リセットできる。
// そのため、tif は 2ビットで管理し、
// カウントが 0 になれば $3 をセット、
// TCR の読み出しで bit0 をクリア、
// TDR の読み出しで bit1 をクリア、
// (tif != 0) なら割り込み状態、とする。
uint32 tif;
};
public:
MPU64180Device();
~MPU64180Device() override;
void putlogn(const char *fmt, ...) const override;
bool Create() override;
bool Init() override;
void ResetHard(bool poweron) override;
// 現在実行中の命令先頭の PC を取得
uint32 GetPPC() const override { return ppc; }
// CPU の動作モードを返す。
OpMode GetOpMode() const { return opmode; }
// RESET 信号をアサート(true)/ネゲート(false)する。
void ChangeRESET(bool);
void AssertRESET();
void NegateRESET();
// プロセッサをリセット
void Reset();
// INT0 信号線をアサートする (PIO1 から呼ばれる)。
// (ネゲートはローカルで行う)
void AssertINT0();
// ASCI0/1 の割り込みをアサート/ネゲートする (ASCI から呼ばれる)。
void ChangeASCIInt(uint n, bool req);
// ブランチ履歴 (例外履歴を含む)
BranchHistory_hd64180 brhist { OBJ_XP_BRHIST };
// 例外履歴のみ
BranchHistory_hd64180 exhist { OBJ_XP_EXHIST };
// I, R レジスタ
uint8 GetI() const { return reg_i; }
uint8 GetR() const { return reg_r & 0x7f; }
bool GetIEF1() const { return ief1; }
bool GetIEF2() const { return ief2; }
// アドレス変換 (デバッガ用)
uint32 TranslatePeek(uint32) const;
// MSXDOS エミュレーションのコールバックを指定する。
void SetSYSCALLCallback(void (*callback)(void *), void *arg);
hd64180reg reg {};
// 割り込み名
static std::vector<const char *> InterruptName;
private:
void EnterNormal();
void EnterSleep();
void EnterWakeup();
void ExecTrace(Event *);
void ExecNormal(Event *);
void ExecSleep(Event *);
void ExecWakeup(Event *);
void SetExec(EventCallback_t);
// トレース設定。デバッガから呼び出される。
void SetTrace(bool enable);
void TraceMessage(MessageID, uint32);
uint32 GetIHL() const;
void SetIHL(uint32);
uint32 LeaIHL();
uint32 GetWW(uint) const;
void SetWW(uint, uint32);
// CPU からの論理メモリアクセス
uint32 Fetch1();
uint32 Fetch2();
uint32 Read1(uint32 addr);
uint32 Write1(uint32 addr, uint32 data);
uint32 Read2(uint32 addr);
void Write2(uint32 addr, uint32 data);
void Jump(uint16);
void op_illegal(int pos);
void ops_ret();
void ops_ddfd(ixiy_t);
void ops_ldi(int);
void ops_cpi(int);
void ops_ini(int);
void ops_outi(int);
void ops_otim(int);
void ops_otmr_until();
#define OP_PROTO(name) void __CONCAT(op_,name)()
#include "hd64180ops.h"
#undef OP_PROTO
uint32 Translate(uint32) const;
void AssertIntmap(int source);
void NegateIntmap(int source);
void NegateINT0();
void DoInterrupt();
void ExceptionDirect(int source, uint32 addr);
void ExceptionVector(int source);
uint32 Peek1(uint32 addr) const;
uint32 Peek2(uint32 addr) const;
void Push2(uint32 data);
uint32 Pop2();
uint32 ReadIO(uint32 addr);
uint32 ReadInternalIO(uint32 offset);
uint32 ReadExternalIO(uint32 addr);
uint32 WriteIO(uint32 addr, uint32 data);
uint32 WriteInternalIO(uint32 offset, uint32 data);
uint32 WriteExternalIO(uint32 addr, uint32 data);
uint32 PeekIO(uint32 addr);
uint32 PeekInternalIO(uint32 offset);
uint32 PeekExternalIO(uint32 addr);
static std::string IOName(uint32 addr);
uint32 ReadTMDRL(int ch);
uint32 ReadTMDRH(int ch);
uint32 ReadTCR();
uint32 WriteTMDRL(int ch, uint32 data);
uint32 WriteTMDRH(int ch, uint32 data);
uint32 WriteRLDRL(int ch, uint32 data);
uint32 WriteRLDRH(int ch, uint32 data);
uint32 WriteTCR(uint32 data);
uint32 WriteDCNTL(uint32 data);
uint32 WriteIL(uint32 data);
uint32 WriteITC(uint32 data);
uint32 WriteRCR(uint32 data);
uint32 WriteCBR(uint32 data);
uint32 WriteBBR(uint32 data);
uint32 WriteCBAR(uint32 data);
uint32 WriteICR(uint32 data);
uint32 WriteRMCR(uint32 data);
uint32 PeekTMDRL(int ch) const;
uint32 PeekTMDRH(int ch) const;
uint32 PeekRLDRL(int ch) const;
uint32 PeekRLDRH(int ch) const;
uint32 PeekTCR() const;
uint32 PeekFRC() const;
uint32 PeekDCNTL() const;
uint32 PeekIL() const;
uint32 PeekITC() const;
uint32 PeekRCR() const;
uint32 PeekCBR() const;
uint32 PeekBBR() const;
uint32 PeekCBAR() const;
uint32 PeekICR() const;
uint32 PeekRMCR() const;
void CYCLE(int n) { used_cycle += n; }
void CYCLE_IX(int, int);
// タイマー
void EnableTimer();
void ChangeTimerInterrupt();
void TimerCallback(Event *);
void MakeActiveTimer();
uint16 ppc {};
uint8 reg_i {}; // I レジスタ
uint8 reg_r {}; // R レジスタ
uint ixiy {}; // 0=HL, 1=IX, 2=IY
// (IX+d)/(IY+d) の d。
// 読み込んでない時は (uint32)-1 にしておく。
// DD と DD CB で読む位置が違うので。
uint32 ixd {};
bool ief1 {}; // IEF1: Interrupt Enable Flag1
bool ief2 {}; // IEF2: Interrupt Enable Flag2
uint int0mode {}; // INT0 mode
bool intcheck {}; // この命令後の境界で割り込みチェックするなら true
// 割り込み信号線の状態
//
// bit 31 30 29 27 26 25 24 23 22 21 20 19 18 17 16 15 ... 0
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- --+
// intmap | 0| 0|I0|I1|I2|IC|OC|TV|T0|T1|D0|D1|CS|A0|A1| |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- ... --+
// 優先順位 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
//
// intmap (32bit) は最上位から割り込み優先順に 1ビットずつ割り当てる
// (ただし TRAP と NMI はここでは使わないので %0 のまま)。
// 割り込みが発生していなければ intmap == 0。
// 割り込みが発生すれば該当するビットを立てる。割り込みを処理する際は
// builtin_clz() で上から判定していく。
uint32 intmap {};
// 割り込み回数 (アサートのエッジでカウントアップする)
// [0] が優先順位 0 (TRAP) の割り込み回数。
// [14] が優先順位 14 (ASCI1) の割り込み回数。
uint64 int_counter[15] {};
// 動作モード。
// mode == Reset ならリセット信号アサート中。
OpMode opmode {};
// 現在の命令列
std::vector<uint8> ops {};
// 直近の命令語
uint8 op {};
uint64 clock_tsec {}; // MPU クロック [tsec]
// 電源オンからの累積消費サイクル
uint64 used_cycle {};
// タイマーと Free Running Counter
uint64 timer_epoch {};
std::array<XPTimer, 2> timer {};
std::vector<XPTimer *> active_timer {};
uint8 timer_toc {}; // Timer Output Control
// DCNTL
uint32 memwait {}; // メモリウェイト
uint32 iowait {}; // I/O ウェイト
uint32 dcntl {}; // DCNTL の残り部分 (未実装)
// IL: 割り込みベクタの下位バイト(のうち上位3ビット)。
// 書き込み時にマスクする。
uint32 intvec_low {};
// ITC: 割り込み制御
bool itc_trap {};
bool itc_ufo {};
bool itc_ite0 {}; // INT Enable 0
bool itc_ite1 {}; // INT Enable 1
bool itc_ite2 {}; // INT Enable 2
// RCR
uint32 rcr {};
// MMU
uint32 commbase {}; // Common Base Address
uint32 bankbase {}; // Bank Base Address
uint32 commarea {}; // Common Area の下限アドレス
uint32 bankarea {}; // Bank Area の下限アドレス
// ICR
uint32 io_address {}; // I/O アドレスの開始番地
// SYSCALL 用のコールバック
void (*syscall_callback)(void *) = NULL;
void *syscall_arg {};
std::unique_ptr<HD647180ASCIDevice> asci /*{}*/;
PIO0Device *pio0 {};
SSGDevice *ssg {};
XPbusDevice *xpbus {};
// モニター
DECLARE_MONITOR_SCREEN(MonitorScreenReg);
DECLARE_MONITOR_SCREEN(MonitorScreenIO);
DECLARE_MONITOR_SCREEN(MonitorScreenIntr);
Monitor *reg_monitor {};
Monitor *io_monitor {};
Monitor *intr_monitor {};
// 実行コールバック
EventCallback_t exec_func {};
// イベント
Event *timer_event {};
// 名前
static const char * const opmode_names[];
static std::vector<const char *> ionames;
};
inline MPU64180Device *GetMPU64180Device() {
return Object::GetObject<MPU64180Device>(OBJ_MPUXP);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.