|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// PIO/PPI (i8255)
//
#pragma once
#include "device.h"
#include <array>
class ADPCMDevice;
class InterruptDevice;
class LCDDevice;
class MPU64180Device;
class PIO1Device;
class PowerDevice;
// Intel 82C55 の仕様書にはコントロールポートからの読み出しは明記してある。
// NEC uPD8255 の仕様書にはコントロールポートからの読み出しについての記載が
// ない (禁止とも書いてない)。
class i8255Device : public IODevice
{
using inherited = IODevice;
public:
explicit i8255Device(uint objid_);
~i8255Device() override;
void ResetHard(bool poweron) override;
protected:
// BusIO インタフェース
bool PokePort(uint32 offset, uint32 data);
// コントロールポートの読み出し
uint32 ReadCtrl() const { return ctrl; }
// コントロールポートへの書き込み
void WriteCtrl(uint32);
// PortC への個別書き込み
virtual void SetPC(uint, uint) = 0;
// 共通部分
int MonitorScreenCommon(TextScreen& screen, int y);
// 7 6 5 4 3 2 1 0
// 1 AM AM AD CHD BM BD CLD
// | | | | | | +--- ポートC下位グループの方向。入力なら1
// | | | | | +------ ポートB の方向。入力なら1
// | | | | +--------- ポートB のモード。
// | | | +------------- ポートC上位グループの方向。入力なら1
// | | +---------------- ポートA の方向。入力なら1
// +--+------------------- ポートA のモード。
uint8 ctrl = 0; // コントロールポートの値
static const uint DIR_IN = 1;
static const uint DIR_OUT = 0;
// グループA/B (ポートA/B) のモード
uint GetGroupAMode() const { return (ctrl >> 5) & 3; }
uint GetGroupBMode() const { return (ctrl >> 2) & 1; }
// ポート A/B/C上位/C下位 の入出力方向
uint PortADir() const { return (ctrl & 0x10) ? DIR_IN : DIR_OUT; }
uint PortBDir() const { return (ctrl & 0x02) ? DIR_IN : DIR_OUT; }
uint PortCHDir() const { return (ctrl & 0x08) ? DIR_IN : DIR_OUT; }
uint PortCLDir() const { return (ctrl & 0x01) ? DIR_IN : DIR_OUT; }
};
class PPIDevice : public i8255Device
{
using inherited = i8255Device;
static const uint32 baseaddr = 0xe9a000;
public:
PPIDevice();
~PPIDevice() override;
bool Init() override;
protected:
// BusIO インタフェース
static const uint32 NPORT = 4;
busdata ReadPort(uint32 offset);
busdata WritePort(uint32 offset, uint32 data);
busdata PeekPort(uint32 offset);
private:
uint32 GetPC() const;
void SetPC(uint, uint) override;
// ADPCM サンプリングレートの設定値(0..3)をこちらでも持っておく。
uint32 adpcm_rate {};
ADPCMDevice *adpcm {};
};
class PIO0Device : public i8255Device
{
using inherited = i8255Device;
static const int INT_H = 0;
static const int INT_L = 1;
public:
PIO0Device();
~PIO0Device() override;
bool Init() override;
void ResetHard(bool poweron) override;
// DIPSW #1-1 が Up なら true を返す (ROM エミュレーション用)
bool IsDIPSW11Up() const { return dipsw1[0]; }
// XP からの割り込みは PIO0 が中継する
void InterruptXPHigh();
void InterruptXPLow();
protected:
// BusIO インタフェース
static const uint32 NPORT = 4;
busdata ReadPort(uint32 offset);
busdata WritePort(uint32 offset, uint32 data);
busdata PeekPort(uint32 offset);
private:
uint32 GetPA() const;
uint32 GetPB() const;
uint32 GetPC() const;
void SetPC(uint, uint) override;
void ChangeInterrupt();
DECLARE_MONITOR_SCREEN(MonitorScreen);
bool dipsw1[8] {};
bool dipsw2[8] {};
bool msb_first {}; // DIP-SW の1番が MSB なら true (LUNA-88K)
std::array<bool, 2> intreq {}; // XP 割り込み要求
std::array<bool, 2> inten {}; // XP 割り込み許可
bool parity {}; // $40 パリティ有効/無効
bool xp_reset {}; // $80 XP リセット
Monitor *monitor {};
InterruptDevice *interrupt {};
PIO1Device *pio1 {};
};
class PIO1Device : public i8255Device
{
using inherited = i8255Device;
public:
PIO1Device();
~PIO1Device() override;
bool Init() override;
void ResetHard(bool poweron) override;
// PIO0 の下請け
void MonitorScreenPIO1(TextScreen& screen, int y);
// BusIO インタフェース
// (内蔵 ROM からのアクセス用に特別に public にしてある)
busdata WritePort(uint32 offset, uint32 data);
protected:
static const uint32 NPORT = 4;
busdata ReadPort(uint32 offset);
busdata PeekPort(uint32 offset);
private:
uint32 GetPC() const;
void SetPC(uint, uint) override;
DECLARE_MONITOR_SCREEN(MonitorScreen);
bool power {}; // パワーダウン (false で電源オフ指示)
bool xp_intreq {}; // XP 割り込み要求。あり(true)なら %0
LCDDevice *lcd {};
MPU64180Device *mpu64180 {};
PowerDevice *powerdev {};
};
inline PPIDevice *GetPPIDevice() {
return Object::GetObject<PPIDevice>(OBJ_PPI);
}
inline PIO0Device *GetPIO0Device() {
return Object::GetObject<PIO0Device>(OBJ_PIO0);
}
inline PIO1Device *GetPIO1Device() {
return Object::GetObject<PIO1Device>(OBJ_PIO1);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.