File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / pio.h
Revision 1.1.1.16 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:00 2026 UTC (3 months ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
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);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.