|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// MFP (MC68901)
//
#pragma once
#include "device.h"
#include <array>
class InterruptDevice;
class Syncer;
class X68030Keyboard;
struct MFP
{
static const uint GPIP = 0; // $E88001
static const uint AER = 1; // $E88003
static const uint DDR = 2; // $E88005
static const uint IERA = 3; // $E88007
static const uint IERB = 4; // $E88009
static const uint IPRA = 5; // $E8800B
static const uint IPRB = 6; // $E8800D
static const uint ISRA = 7; // $E8800F
static const uint ISRB = 8; // $E88011
static const uint IMRA = 9; // $E88013
static const uint IMRB = 10; // $E88015
static const uint VR = 11; // $E88017
static const uint TACR = 12; // $E88019
static const uint TBCR = 13; // $E8801B
static const uint TCDCR = 14; // $E8801D
static const uint TADR = 15; // $E8801F
static const uint TBDR = 16; // $E88021
static const uint TCDR = 17; // $E88023
static const uint TDDR = 18; // $E88025
static const uint SCR = 19; // $E88027
static const uint UCR = 20; // $E88029
static const uint RSR = 21; // $E8802B
static const uint TSR = 22; // $E8802D
static const uint UDR = 23; // $E8802F
static const uint RegMax = 24;
union ir16 {
uint16 w;
struct {
#if BYTE_ORDER == LITTLE_ENDIAN
uint8 b, a;
#else
uint8 a, b;
#endif
};
};
// ハードウェア未実装ビットは書き込み時に '0' にする
uint8 gpip;
uint8 aer;
uint8 ddr;
static const uint GPIP_HSYNC = 7;
static const uint GPIP_CIRQ = 6;
// 5 は常に '1'
static const uint GPIP_VDISP = 4;
static const uint GPIP_FMIRQ = 3;
static const uint GPIP_POWSW = 2;
static const uint GPIP_EXPON = 1;
static const uint GPIP_ALARM = 0;
static const uint INTR_RTC_ALARM = 0;
static const uint INTR_EXPON = 1;
static const uint INTR_POW_SW = 2;
static const uint INTR_FM_IRQ = 3;
static const uint INTR_TIMER_D = 4;
static const uint INTR_TIMER_C = 5;
static const uint INTR_VDISP = 6;
static const uint INTR_unused = 7;
static const uint INTR_TIMER_B = 8;
static const uint INTR_TXERR = 9;
static const uint INTR_TXEMPTY = 10;
static const uint INTR_RXERR = 11;
static const uint INTR_RXFULL = 12;
static const uint INTR_TIMER_A = 13;
static const uint INTR_CRTC_IRQ = 14;
static const uint INTR_HSYNC = 15;
ir16 ier;
ir16 ipr;
ir16 isr;
ir16 imr;
// b7 b6 b5 b4 b3 b2 b1 b0
// +-----+-----+-----+-----+-----+-----+-----+-----+
// VR | V7 | V6 | V5 | V4 | S | --- | --- | --- |
// +-----+-----+-----+-----+-----+-----+-----+-----+
// | | | | |
// | | | | +------------ In-Service Register Enable
// +-----+-----+-----+------------------ Vector Number
uint8 vr_vec; // ベクタの上位4ビット
uint8 vr_s; // %1:ソフトウェアEOI(ISR有効)、%0:自動EOI(ISR無効)
uint8 GetVR() const { return vr_vec | vr_s; }
// タイマー
struct Timer {
// タイマー停止中は、カウンタの現在値 (1-256) を保持。
// タイマー動作中は、現在カウントダウン中のカウントの初期値(1-256)。
// TxDR レジスタ値際は、タイマー動作中/停止中どちらでも
// これではなく GetTDR() を使うこと。
uint32 tdr;
// 次回の TxDR のリロード値 (1-256)。
uint32 next_tdr;
// タイマーの開始時刻。
uint64 start;
// tcr は書き込み値、現在のモードを保持する。
// TACR: --- --- --- RST AC3 AC2 AC1 AC0
// TBCR: --- --- --- RST BC3 BC2 BC1 BC0
// TCDCR: --- CC2 CC1 CC0 --- DC2 DC1 DC0
uint8 tcr;
bool IsStopped() const noexcept { return (tcr == 0); }
bool IsDelay() const noexcept { return (0 < tcr && tcr < 8); }
bool IsEvent() const noexcept { return (tcr == 8); }
bool IsPulseWidth() const noexcept { return (tcr > 8); }
// 現在時刻 now とメインカウンタ周期 period から
// 現在のメインカウンタの値を求める。
// タイマー動作中のみ呼ぶこと。
uint8 GetCounter(uint64 now, uint64 period) const;
} timer[4];
// TCDCR の値
uint8 GetTCDCR() const {
return (timer[2].tcr << 4) | timer[3].tcr;
}
uint8 scr;
// b7 b6 b5 b4 b3 b2 b1 b0
// +-----+-----+-----+-----+-----+-----+-----+-----+
// UCR | CLK | WL | ST | PE | E/O | --- |
// +-----+-----+-----+-----+-----+-----+-----+-----+
// | | | | |
// | | | | +--------- %1で偶数パリティ
// | | | +--------------- %1でパリティエラー
// | | +------------------- スタート/ストップビット
// | +--- データ長 %00 同期
// | %00:8bit, %01:7bit %01 非同期 1bit/1bit
// | %10:6bit, %11:5bit %10 非同期 1bit/1.5bit
// | %11 非同期 1bit/2bit
// |
// +------------------------------------- %1 送受信速度が入力の1/16
static const uint32 UCR_CLK = 0x80;
static const uint32 UCR_WL = 0x60;
static const uint32 UCR_ST = 0x18;
static const uint32 UCR_PE = 0x04;
static const uint32 UCR_EO = 0x02;
uint8 ucr;
// b7 b6 b5 b4 b3 b2 b1 b0
// +-----+-----+-----+-----+-----+-----+-----+-----+
// RSR | BF | OE | PE | FE | B | CIP | SS | RE |
// +-----+-----+-----+-----+-----+-----+-----+-----+
// | | | | | | | |
// | | | | | | | +--- %1 RX Enable
// | | | | | | +--------- Sync Stop
// | | | | | +--------------- 非同期なら
// | | | | | %1 Detect Start Bit
// | | | | | %0 Detect Stop Bit
// | | | | +--------------------- %1 非同期ならBreak
// | | | +--------------------------- %1 Framing Error
// | | +--------------------------------- %1 Parity Error
// | +--------------------------------------- %1 Overflow Error
// +--------------------------------------------- %1 RX Buffer Full
static const uint32 RSR_BF = 0x80;
static const uint32 RSR_OE = 0x40;
static const uint32 RSR_PE = 0x20;
static const uint32 RSR_FE = 0x10;
static const uint32 RSR_B = 0x08;
static const uint32 RSR_CIP = 0x04;
static const uint32 RSR_SS = 0x02;
static const uint32 RSR_RE = 0x01;
uint8 rsr;
// b7 b6 b5 b4 b3 b2 b1 b0
// +-----+-----+-----+-----+-----+-----+-----+-----+
// TSR | BE | UE | AT | END | B | H | L | TE |
// +-----+-----+-----+-----+-----+-----+-----+-----+
// | | | |
// | | | +--- %1 TX Enable
// | | +--------------------------- %1 TX Disabled
// | +--------------------------------------- %1 Underrun Error
// +--------------------------------------------- %1 TX Buffer Empty
static const uint32 TSR_BE = 0x80;
static const uint32 TSR_UE = 0x40;
static const uint32 TSR_AT = 0x20;
static const uint32 TSR_END = 0x10;
static const uint32 TSR_B = 0x08;
static const uint32 TSR_H = 0x04;
static const uint32 TSR_L = 0x02;
static const uint32 TSR_TE = 0x01;
uint8 tsr;
// 送受信レジスタ。
// 受信データがなければ -1 にする
uint16 udr;
};
class MFPDevice : public IODevice
{
using inherited = IODevice;
static const uint32 baseaddr = 0xe88000;
public:
MFPDevice();
~MFPDevice() override;
bool Init() override;
void ResetHard(bool poweron) override;
// 割り込みアクノリッジ
busdata InterruptAcknowledge();
// HSync 入力
void SetHSync(bool hsync);
// VDisp 入力
void SetVDisp(bool vdisp);
// 電源ボタン状態入力
void SetPowSW(bool powsw);
// ALARM 信号入力
void SetAlarmOut(bool alarm);
// KEY CTRL 状態を設定する
void SetKeyCtrl(bool ctrl);
// キーボードからの送信が可能なら true を返す。
bool RxIsReady() const;
// キーボードからデータを受信
void Rx(uint32 data);
protected:
// BusIO インタフェース
static const uint32 NPORT = 0x20;
busdata ReadPort(uint32 offset);
busdata WritePort(uint32 offset, uint32 data);
busdata PeekPort(uint32 offset);
bool PokePort(uint32 offset, uint32 data);
private:
void SetIER(uint16 data);
void SetTCR(int ch, uint32 data);
uint8 GetTDR(int ch) const;
void SetTDR(int ch, uint32 data);
void RestartTimerEvent(int ch);
void StopTimerEvent(int ch);
bool IsTimerIntrEnable(int ch) const;
// GPIP の信号状態をセットする
void SetGPIP(int num, bool val);
void SetUCR(uint32 data);
void SetRSR(uint32 data);
void SetUDR(uint32 data);
// RSR::BF ビットの状態を変える
void SetBF();
void ClearBF();
// MFP の RR 線の状態を返す
bool IsRR() const;
// イベントコールバック
void TimerCallback(Event *);
void KeyCallback(Event *);
// 必要なら割り込みを上げる
void SetInterrupt(uint ch);
// 割り込み信号線の状態を変える
void ChangeInterrupt();
DECLARE_MONITOR_SCREEN(MonitorScreen);
struct MFP mfp {};
std::array<Event *, 4> event {};
Event *key_event {};
// 各タイマーが刻んでいる時刻 (時間軸)
std::array<uint64, 4> stime {};
// 各タイマーの周期
std::array<uint64, 4> rt_period {};
// タイマーを実時間に追従する場合は true。
bool sync_rt {};
Monitor *monitor {};
InterruptDevice *interrupt {};
Syncer *syncer {};
X68030Keyboard *keyboard {};
static const busdata wait;
static const char *intrname[];
static const char *gpipname[];
static const uint64 prescale_tsec[8];
static const char *prescale_str[8];
static const uint timer_vector[4];
static const char *regname[MFP::RegMax];
};
inline MFPDevice *GetMFPDevice() {
return Object::GetObject<MFPDevice>(OBJ_MFP);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.