|
|
nono 1.7.0
//
// nono
// Copyright (C) 2023 nono project
// Licensed under nono-license.txt
//
//
// Nereid Ethernet/メモリ/USB 複合ボード (のうち Ethernet/バンクメモリ)
//
// Nereid の DIPSW
//
// SW1,2 : RAM をメインメモリとして使う場合の容量
// OFF,OFF = 割り当てない (この時だけバンクメモリが 16MB 使える)
// SW3,4,5 : RAM をメインメモリとして使う場合の開始アドレス
// SW6 : RAM をバンクメモリとして使う場合のウィンドウ
// OFF = $ee0000
// ON = $ef0000
// SW7 : アドレス、割り込みベクタ設定
// OFF = $ece3xx, $f9, $fb
// ON = $ecebxx, $f8, $fa
// SW8 : バンクメモリ有効無効
// OFF = 無効
// ON = 有効
//
// バンクメモリの容量は、SW1-2 でメインメモリに割り当てた余りのうち
// 4MB か 16MB のどちらか。Nereid のメモリをメインメモリに割り当てる機能は
// (意味がないので) 実装せず、SW1-2 を設定した結果バンクメモリ容量が 4MB か
// 16MB にできるところだけ再現する。
//
// Nereid は SW-6,7 により2枚まで同時に運用することが可能。
// SW6 と SW7 の組み合わせは本来自由だが、そこまで自由度を上げるメリットは
// なさそうなので、ここでは
// Nereid#0 が SW6=OFF、SW7=OFF
// Nereid#1 が SW6=ON、 SW7=ON
// と固定して扱う。
// 各デバイスのアドレス配置、割り込みベクタ
//
// #0 (SW7=OFF) #1 (SW7=ON)
// -------------- --------------
// $ece300-ece33f $eceb00-eceb3f : RTL8019AS (偶数アドレスのみ)
// $ece380-ece383 $eceb80-eceb83 : SL811HS/T (奇数アドレスのみ)
// $ece3f0 $ecebf0 : バンクページ選択
// $ece3f1 $ecebf1 : 制御ポート
//
// $f9 $f8 : RTL8019AS 割り込みベクタ
// $fb $fa : SL811HS/T 割り込みベクタ
#include "nereid.h"
#include "bankram.h"
#include "config.h"
#include "monitor.h"
#include "rtl8019as.h"
//
// Nereid 空間担当デバイス
//
// boards[0]、board[1] を所有し、アクセスをディスパッチする。
// コンストラクタ
NereidDevice::NereidDevice()
: inherited(OBJ_NEREID)
{
monitor = gMonitorManager->Regist(ID_MONITOR_NEREID, this);
monitor->SetCallback(&NereidDevice::MonitorScreen);
monitor->SetSize(41, 9);
}
// デストラクタ
NereidDevice::~NereidDevice()
{
}
// デバイス作成
bool
NereidDevice::Create()
{
// ボードの有無は nereid%u-enable だけで決まる。
for (int i = 0; i < 2; i++) {
std::string name = string_format("nereid%u-enable", i);
bool enable = gConfig->Find(name).AsBool();
if (enable) {
try {
boards[i].reset(new NereidBoardDevice(i));
} catch (...) { }
if ((bool)boards[i] == false) {
warnx("Failt to initialize NereidBoardDevice(%u) at %s",
i, __method__);
return false;
}
// 配置場所
if (i == 0) {
loc[i] = 0x03; // $ece300-
} else {
loc[i] = 0x0b; // $eceb00-
}
} else {
// アドレス比較で一致させないため -1 にしておく。
loc[i] = -1;
}
}
return true;
}
// Nereid が1枚でもささっていれば true。
// (X68kIO.Init() から呼ばれる)
bool
NereidDevice::IsInstalled() const
{
return (bool)boards[0] || (bool)boards[1];
}
inline uint32
NereidDevice::Decoder(uint32 addr) const
{
// ここで返すのはオフセットではなく、チップセレクトに近い。
// $ece3xx or $ecebxx の $3 か $b のところ (厳密にはそれを含む
// 5ビット) を返し、あらかじめ用意してある loc[i] と比較する。
return (addr >> 8) & 0x1f;
}
busdata
NereidDevice::Read(busaddr addr)
{
uint32 paddr = addr.Addr();
putlog(2, "Read $%06x.%c", paddr, (addr.GetSize() == 1 ? 'B' : 'W'));
uint32 cs = Decoder(paddr);
for (int i = 0; i < boards.size(); i++) {
if (cs == loc[i]) {
return boards[i]->Read(addr);
}
}
return BusData::BusErr;
}
busdata
NereidDevice::Write(busaddr addr, uint32 data)
{
uint32 paddr = addr.Addr();
putlog(2, "Write $%06x.%c", paddr, (addr.GetSize() == 1 ? 'B' : 'W'));
uint32 cs = Decoder(paddr);
for (int i = 0; i < boards.size(); i++) {
if (cs == loc[i]) {
return boards[i]->Write(addr, data);
}
}
return BusData::BusErr;
}
busdata
NereidDevice::Peek1(uint32 addr)
{
uint32 cs = Decoder(addr);
for (int i = 0; i < boards.size(); i++) {
if (cs == loc[i]) {
return boards[i]->Peek1(addr);
}
}
return BusData::BusErr;
}
void
NereidDevice::MonitorScreen(Monitor *, TextScreen& screen)
{
int y;
screen.Clear();
// 0123456789012345678901234567890123456789
// #0 #1
// Board : NotInstalled NotInstalled
// Ethernet : Enable
// Address : $ece300
// Vector : $f9
// Bank Memory : 16MB
// Page Select: $ece380
// Bank Window: $ee0000
// CurrentPage: $00
y = 1;
screen.Puts(0, y++, "Board :");
screen.Puts(1, y++, "Ethernet :");
screen.Puts(2, y++, "Address :");
screen.Puts(2, y++, "Vector :");
screen.Puts(1, y++, "Bank Memory :");
screen.Puts(2, y++, "Page Select:");
screen.Puts(2, y++, "Bank Window:");
screen.Puts(2, y++, "CurrentPage:");
for (int i = 0; i < 2; i++) {
int x = 15 + i * 14;
TA attr;
y = 0;
screen.Print(x, y++, "#%u", i);
// ボードがささっているか
bool installed = (bool)boards[i];
if (installed) {
screen.Puts(x, y, "Installed");
} else {
screen.Puts(x, y, "NotInstalled");
}
y++;
// イーサネット
attr = TA::Disable;
if (installed) {
if (boards[i]->IsNetEnable()) {
screen.Puts(x, y, "Available");
attr = TA::Normal;
} else {
screen.Puts(x, y, "NotAvailable");
}
} else {
screen.Puts(x, y, attr, "-");
}
y++;
screen.Print(x, y++, attr, "$%06x", 0xece300 + i * 0x800);
screen.Print(x, y++, attr, "$%02x", 0xf9 - i);
// バンクメモリ
attr = TA::Disable;
int ramsize = 0;
if (installed) {
ramsize = boards[i]->GetBankRAMSize();
if (ramsize > 0) {
screen.Print(x, y, "%u MB", ramsize);
attr = TA::Normal;
} else {
screen.Puts(x, y, "Disabled");
}
} else {
screen.Puts(x, y, attr, "-");
}
y++;
screen.Print(x, y++, attr, "$%06x", 0xece3f0 + i * 0x800);
screen.Print(x, y++, attr, "$%06x", 0xee0000 + i * 0x10000);
if (installed) {
if (ramsize > 0) {
attr = TA::Normal;
} else {
attr = TA::Disable;
}
screen.Print(x, y, attr, "$%02x", boards[i]->GetPage());
} else {
screen.Puts(x, y, attr, "---");
}
}
}
//
// Nereid ボード1枚分
//
// コンストラクタ
NereidBoardDevice::NereidBoardDevice(int id_)
: inherited(OBJ_NEREID_BOARD(id_))
{
id = id_;
}
// デストラクタ
NereidBoardDevice::~NereidBoardDevice()
{
}
bool
NereidBoardDevice::Create()
{
std::string netname = string_format("nereid%u-net", id);
std::string ramname = string_format("nereid%u-ram-size", id);
bool net_enable = gConfig->Find(netname).AsBool();
const ConfigItem iramsize = gConfig->Find(ramname);
ramsize_MB = iramsize.AsInt();
switch (ramsize_MB) {
case 0:
case 4:
case 16:
case -4:
case -16:
// 負数は、バンクメモリ無効時の制御ポート bit6 を明示したい場合用。
break;
default:
iramsize.Err("Valid value is one of 0, 4, 16 (or -4, -16)");
return false;
}
// ネットワークが無効の場合 (これは正常な実機では起きないが)、
// RTL8019ASDevice インスタンスの生成自体を行わず、net は NULL。
if (net_enable) {
int vector;
if (id == 0) {
vector = 0xf9;
} else {
vector = 0xf8;
}
try {
net.reset(new RTL8019ASDevice(id, vector));
} catch (...) { }
if ((bool)net == false) {
warnx("Failed to initialize RTL8019ASDevice(%u) at %s",
id, __method__);
return false;
}
}
// バンクメモリは (DIPSW によって) 有効/無効どちらであっても
// BankRAMDevice インスタンスの生成自体は行う。
// ページレジスタは存在している(はずの)ため。
try {
if (ramsize_MB <= 0) {
bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), 0));
} else {
bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), ramsize_MB));
// I/O 空間への登録は X68kIO 側から行っている。
}
} catch (...) { }
if ((bool)bank == false) {
warnx("Failed to initialize BankRAMDevice(%u) at %s", id, __method__);
return false;
}
return true;
}
inline uint32
NereidBoardDevice::Decoder(uint32 addr) const
{
return addr & 0xff;
}
busdata
NereidBoardDevice::Read(busaddr addr)
{
busdata data = BusData::BusErr;
uint32 paddr = addr.Addr();
uint32 offset = Decoder(paddr);
if (offset < 0x40) {
if ((bool)net) {
return net->Read(addr);
}
} else {
uint32 reqsize = addr.GetSize();
uint32 datasize = std::min(2 - (paddr & 1), reqsize);
if (datasize == 1) {
if (offset == 0xf0) {
data = GetPage();
} else if (offset == 0xf1) {
data = GetCtrl();
}
data |= BusData::Size1;
} else {
if (offset == 0xf0) {
data = GetPage() << 8;
data |= GetCtrl();
}
data |= BusData::Size2;
}
}
return data;
}
busdata
NereidBoardDevice::Write(busaddr addr, uint32 data)
{
busdata r;
uint32 paddr = addr.Addr();
uint32 offset = Decoder(paddr);
if (offset < 0x40) {
if ((bool)net) {
return net->Write(addr, data);
}
} else {
uint32 reqsize = addr.GetSize();
uint32 datasize = std::min(2 - (paddr & 1), reqsize);
data >>= (reqsize - datasize) * 8;
if (datasize == 1) {
if (offset == 0xf0) {
SetPage(data);
} else if (offset == 0xf1) {
SetCtrl(data);
} else {
r.SetBusErr();
}
r |= BusData::Size1;
} else {
if (offset == 0xf0) {
SetPage(data >> 8);
SetCtrl(data & 0xff);
} else {
r.SetBusErr();
}
r |= BusData::Size2;
}
}
return r;
}
busdata
NereidBoardDevice::Peek1(uint32 addr)
{
uint32 offset = Decoder(addr);
if (offset < 0x40) {
if ((bool)net) {
return net->Peek1(addr);
}
} else if (offset == 0xf0) {
return GetPage();
} else if (offset == 0xf1) {
return GetCtrl();
}
return BusData::BusErr;
}
// バンクページ選択レジスタの値を取得。
uint32
NereidBoardDevice::GetPage() const
{
return bank->GetPage();
}
// バンクページ選択レジスタに値を設定。
void
NereidBoardDevice::SetPage(uint32 data)
{
bank->SetPage(data);
}
// 制御ポートの値を取得。
uint32
NereidBoardDevice::GetCtrl() const
{
uint32 data;
// bit7: バンクメモリ有効 (%0=無効、%1=有効)、DIPSW8 が見える
// bit6: バンクメモリサイズ (%0=4M、%1=16M)
// bit5: バンクメモリウィンドウ (%0=$EE0000、%1=$EF0000)、DIPSW6 が見える
// bit4
// bit3
// bit2: USB 割り込み
// bit1: USB 電源
// bit0: USB 有効
// bit5、バンクメモリウィンドウは $EE0000 なら %0、$EF0000 なら %1 だが、
// 現状はボード #0 が $EE0000、ボード #1 が $EF0000 と固定してある。
data = id << 5;
// bit7、bit6。
//
// bit6 は DIPSW1=OFF, DIPSW2=OFF (メインメモリへの割り当てなし、
// つまり 16MB 全部をバンクメモリに割ける) 時に %1 になる。
// まったく実用性はないけど再現できるようにしておく。
//
// DIP8 DIP1 DIP2 bit7 bit6 BankRAM nereid?-ram-size=
// ---------------+-----------+----------+------
// ON OFF OFF : 1 1 : 16MB | 16
// ON * * : 1 0 : 4MB | 4
// OFF OFF OFF : 0 1 : Disabled | 0
// OFF OFF OFF : 0 1 : Disabled | -16
// OFF * * : 0 0 : Disabled | -4
if (ramsize_MB > 0) {
data |= 0x80;
if (ramsize_MB != 4) {
data |= 0x40;
}
} else {
if (ramsize_MB != -4) {
data |= 0x40;
}
}
// USB 関連は無効なままなので %0
return data;
}
void
NereidBoardDevice::SetCtrl(uint32 data)
{
// USB はないので書き込みは無効
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.