--- nono/vm/dmac.cpp 2026/04/29 17:05:14 1.1.1.11 +++ nono/vm/dmac.cpp 2026/04/29 17:05:25 1.1.1.13 @@ -10,30 +10,28 @@ #include "dmac.h" #include "adpcm.h" -#include "bus.h" #include "fdc.h" #include "interrupt.h" +#include "mainbus.h" #include "mpu.h" #include "scheduler.h" // time 時間後に呼び出すコールバックをセットする。 // func の書式が面倒なのを省略して書きたいため。 -#define CallAfter(func_, time_) do { \ +#define CallAfter(func_, time_, wait_) do { \ event.func = ToEventCallback(&DMACDevice::func_); \ - event.time = time_ * 80_nsec; \ - gScheduler->StartEvent(event); \ + event.time = time_ * 80_nsec + wait_; \ + scheduler->StartEvent(event); \ } while (0) -// グローバル参照用 -DMACDevice *gDMAC; +// InsideOut p.135 +static const busdata read_wait = busdata::Wait(37 * 40_nsec); +static const busdata write_wait = busdata::Wait(31 * 40_nsec); // コンストラクタ DMACDevice::DMACDevice() - : inherited("DMAC") + : inherited(OBJ_DMAC) { - devaddr = baseaddr; - devlen = 0x2000; - for (int i = 0; i < channel.size(); i++) { channel[i].ch = i; } @@ -64,7 +62,22 @@ DMACDevice::DMACDevice() // デストラクタ DMACDevice::~DMACDevice() { - gDMAC = NULL; +} + +// 初期化 +bool +DMACDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + adpcm = GetADPCMDevice(); + fdc = GetFDCDevice(); + interrupt = GetInterruptDevice(); + mainbus = GetMainbusDevice(); + + return true; } // リセット @@ -94,18 +107,17 @@ DMACDevice::ResetHard(bool poweron) chan->priority = 0; } + ChangeInterrupt(); // イベントを停止 event.SetName("DMAC"); - gScheduler->StopEvent(event); + scheduler->StopEvent(event); } -uint64 +busdata DMACDevice::Read8(uint32 addr) { - uint8 data; - - gMPU->AddCycle(37); // InsideOut p.135 + busdata data; uint32 offset = addr & 0xff; int ch = offset / 0x40; @@ -115,137 +127,137 @@ DMACDevice::Read8(uint32 addr) switch (n) { case DMAC::CSR: data = chan->GetCSR(); - putlog(3, "#%d CSR -> $%02x", ch, data); + putlog(3, "#%d CSR -> $%02x", ch, data.Data()); break; case DMAC::CER: data = chan->cer; - putlog(3, "#%d CER -> $%02x", ch, data); + putlog(3, "#%d CER -> $%02x", ch, data.Data()); break; case DMAC::DCR: data = chan->GetDCR(); - putlog(3, "#%d DCR -> $%02x", ch, data); + putlog(3, "#%d DCR -> $%02x", ch, data.Data()); break; case DMAC::OCR: data = chan->GetOCR(); - putlog(3, "#%d OCR -> $%02x", ch, data); + putlog(3, "#%d OCR -> $%02x", ch, data.Data()); break; case DMAC::SCR: data = chan->GetSCR(); - putlog(3, "#%d SCR -> $%02x", ch, data); + putlog(3, "#%d SCR -> $%02x", ch, data.Data()); break; case DMAC::CCR: data = chan->GetCCR(); - putlog(3, "#%d CCR -> $%02x", ch, data); + putlog(3, "#%d CCR -> $%02x", ch, data.Data()); break; case DMAC::MTC: data = chan->mtc >> 8; - putlog(3, "#%d MTC:H -> $%02x", ch, data); + putlog(3, "#%d MTC:H -> $%02x", ch, data.Data()); break; case DMAC::MTC + 1: data = chan->mtc & 0xff; - putlog(3, "#%d MTC:L -> $%02x", ch, data); + putlog(3, "#%d MTC:L -> $%02x", ch, data.Data()); break; case DMAC::MAR: data = chan->mar >> 24; - putlog(3, "#%d MAR:0 -> $%02x", ch, data); + putlog(3, "#%d MAR:0 -> $%02x", ch, data.Data()); break; case DMAC::MAR + 1: data = (chan->mar >> 16) & 0xff; - putlog(3, "#%d MAR:1 -> $%02x", ch, data); + putlog(3, "#%d MAR:1 -> $%02x", ch, data.Data()); break; case DMAC::MAR + 2: data = (chan->mar >> 8) & 0xff; - putlog(3, "#%d MAR:2 -> $%02x", ch, data); + putlog(3, "#%d MAR:2 -> $%02x", ch, data.Data()); break; case DMAC::MAR + 3: data = chan->mar & 0xff; - putlog(3, "#%d MAR:3 -> $%02x", ch, data); + putlog(3, "#%d MAR:3 -> $%02x", ch, data.Data()); break; case DMAC::DAR: data = chan->dar >> 24; - putlog(3, "#%d DAR:0 -> $%02x", ch, data); + putlog(3, "#%d DAR:0 -> $%02x", ch, data.Data()); break; case DMAC::DAR + 1: data = (chan->dar >> 16) & 0xff; - putlog(3, "#%d DAR:1 -> $%02x", ch, data); + putlog(3, "#%d DAR:1 -> $%02x", ch, data.Data()); break; case DMAC::DAR + 2: data = (chan->dar >> 8) & 0xff; - putlog(3, "#%d DAR:2 -> $%02x", ch, data); + putlog(3, "#%d DAR:2 -> $%02x", ch, data.Data()); break; case DMAC::DAR + 3: data = chan->dar & 0xff; - putlog(3, "#%d DAR:3 -> $%02x", ch, data); + putlog(3, "#%d DAR:3 -> $%02x", ch, data.Data()); break; case DMAC::BTC: data = chan->btc >> 8; - putlog(3, "#%d BTC:H -> $%02x", ch, data); + putlog(3, "#%d BTC:H -> $%02x", ch, data.Data()); break; case DMAC::BTC + 1: data = chan->btc & 0xff; - putlog(3, "#%d BTC:L -> $%02x", ch, data); + putlog(3, "#%d BTC:L -> $%02x", ch, data.Data()); break; case DMAC::BAR: data = chan->bar >> 24; - putlog(3, "#%d BAR:0 -> $%02x", ch, data); + putlog(3, "#%d BAR:0 -> $%02x", ch, data.Data()); break; case DMAC::BAR + 1: data = (chan->bar >> 16) & 0xff; - putlog(3, "#%d BAR:1 -> $%02x", ch, data); + putlog(3, "#%d BAR:1 -> $%02x", ch, data.Data()); break; case DMAC::BAR + 2: data = (chan->bar >> 8) & 0xff; - putlog(3, "#%d BAR:2 -> $%02x", ch, data); + putlog(3, "#%d BAR:2 -> $%02x", ch, data.Data()); break; case DMAC::BAR + 3: data = chan->bar & 0xff; - putlog(3, "#%d BAR:3 -> $%02x", ch, data); + putlog(3, "#%d BAR:3 -> $%02x", ch, data.Data()); break; case DMAC::NIV: data = chan->niv; - putlog(3, "#%d NIV -> $%02x", ch, data); + putlog(3, "#%d NIV -> $%02x", ch, data.Data()); break; case DMAC::EIV: data = chan->eiv; - putlog(3, "#%d EIV -> $%02x", ch, data); + putlog(3, "#%d EIV -> $%02x", ch, data.Data()); break; case DMAC::MFC: - data = chan->mfc; - putlog(3, "#%d MFC -> $%02x", ch, data); + data = chan->mfc.GetFC(); + putlog(3, "#%d MFC -> $%02x", ch, data.Data()); break; case DMAC::CPR: data = chan->cpr; - putlog(3, "#%d CPR -> $%02x", ch, data); + putlog(3, "#%d CPR -> $%02x", ch, data.Data()); break; case DMAC::DFC: - data = chan->dfc; - putlog(3, "#%d DFC -> $%02x", ch, data); + data = chan->dfc.GetFC(); + putlog(3, "#%d DFC -> $%02x", ch, data.Data()); break; case DMAC::BFC: - data = chan->bfc; - putlog(3, "#%d BFC -> $%02x", ch, data); + data = chan->bfc.GetFC(); + putlog(3, "#%d BFC -> $%02x", ch, data.Data()); break; case DMAC::GCR: if (ch == 3) { data = gcr; - putlog(3, "GCR -> $%02x", data); + putlog(3, "GCR -> $%02x", data.Data()); break; } else { data = 0xff; @@ -257,15 +269,14 @@ DMACDevice::Read8(uint32 addr) break; } + data |= read_wait; return data; } -uint64 +busdata DMACDevice::Read16(uint32 addr) { - uint16 data; - - gMPU->AddCycle(37); // InsideOut p.135 + busdata data; uint32 offset = addr & 0xff; int ch = offset / 0x40; @@ -276,92 +287,92 @@ DMACDevice::Read16(uint32 addr) case DMAC::CSR: // CSR | CER data = chan->GetCSR() << 8; data |= chan->cer; - putlog(3, "#%d CSR:CER -> $%04x", ch, data); + putlog(3, "#%d CSR:CER -> $%04x", ch, data.Data()); break; case DMAC::DCR: // DCR | OCR data = chan->GetDCR() << 8; data |= chan->GetOCR(); - putlog(3, "#%d DCR:OCR -> $%04x", ch, data); + putlog(3, "#%d DCR:OCR -> $%04x", ch, data.Data()); break; case DMAC::SCR: // SCR | CCR data = chan->GetSCR() << 8; data |= chan->GetCCR(); - putlog(3, "#%d SCR:CCR -> $%04x", ch, data); + putlog(3, "#%d SCR:CCR -> $%04x", ch, data.Data()); break; case DMAC::MTC: data = chan->mtc; - putlog(3, "#%d MTC -> $%04x", ch, data); + putlog(3, "#%d MTC -> $%04x", ch, data.Data()); break; case DMAC::MAR: data = chan->mar >> 16; - putlog(3, "#%d MAR:H -> $%04x", ch, data); + putlog(3, "#%d MAR:H -> $%04x", ch, data.Data()); break; case DMAC::MAR + 2: data = chan->mar & 0xffff; - putlog(3, "#%d MAR:L -> $%04x", ch, data); + putlog(3, "#%d MAR:L -> $%04x", ch, data.Data()); break; case DMAC::DAR: data = chan->dar >> 16; - putlog(3, "#%d DAR:H -> $%04x", ch, data); + putlog(3, "#%d DAR:H -> $%04x", ch, data.Data()); break; case DMAC::DAR + 2: data = chan->dar & 0xffff; - putlog(3, "#%d DAR:L -> $%04x", ch, data); + putlog(3, "#%d DAR:L -> $%04x", ch, data.Data()); break; case DMAC::BTC: data = chan->btc; - putlog(3, "#%d BTC -> $%04x", ch, data); + putlog(3, "#%d BTC -> $%04x", ch, data.Data()); break; case DMAC::BAR: data = chan->bar >> 16; - putlog(3, "#%d BAR:H -> $%04x", ch, data); + putlog(3, "#%d BAR:H -> $%04x", ch, data.Data()); break; case DMAC::BAR + 2: data = chan->bar & 0xffff; - putlog(3, "#%d BAR:L -> $%04x", ch, data); + putlog(3, "#%d BAR:L -> $%04x", ch, data.Data()); break; case DMAC::NIV: data = chan->niv | 0xff00; - putlog(3, "#%d NIV -> $%04x", ch, data); + putlog(3, "#%d NIV -> $%04x", ch, data.Data()); break; case DMAC::EIV: data = chan->eiv | 0xff00; - putlog(3, "#%d EIV -> $%04x", ch, data); + putlog(3, "#%d EIV -> $%04x", ch, data.Data()); break; case DMAC::MFC: - data = chan->mfc | 0xff00; - putlog(3, "#%d MFC -> $%04x", ch, data); + data = chan->mfc.GetFC() | 0xff00; + putlog(3, "#%d MFC -> $%04x", ch, data.Data()); break; case DMAC::CPR: data = chan->cpr | 0xff00; - putlog(3, "#%d CPR -> $%04x", ch, data); + putlog(3, "#%d CPR -> $%04x", ch, data.Data()); break; case DMAC::DFC: - data = chan->dfc | 0xff00; - putlog(3, "#%d DFC -> $%04x", ch, data); + data = chan->dfc.GetFC() | 0xff00; + putlog(3, "#%d DFC -> $%04x", ch, data.Data()); break; case DMAC::BFC: - data = chan->bfc | 0xff00; - putlog(3, "#%d BFC -> $%04x", ch, data); + data = chan->bfc.GetFC() | 0xff00; + putlog(3, "#%d BFC -> $%04x", ch, data.Data()); break; case DMAC::GCR: if (ch == 3) { data = gcr | 0xff00; - putlog(3, "GCR -> $%04x", data); + putlog(3, "GCR -> $%04x", data.Data()); break; } else { data = 0xffff; @@ -373,6 +384,7 @@ DMACDevice::Read16(uint32 addr) break; } + data |= read_wait; return data; } @@ -393,11 +405,9 @@ DMACDevice::Read16(uint32 addr) } \ } while (0) -uint64 +busdata DMACDevice::Write8(uint32 addr, uint32 data) { - gMPU->AddCycle(31); // InsideOut p.135 - uint32 offset = addr & 0xff; int ch = offset / 0x40; int n = offset % 0x40; @@ -562,14 +572,13 @@ DMACDevice::Write8(uint32 addr, uint32 d default: break; } - return 0; + + return write_wait; } -uint64 +busdata DMACDevice::Write16(uint32 addr, uint32 data) { - gMPU->AddCycle(31); // InsideOut p.135 - uint32 offset = addr & 0xff; int ch = offset / 0x40; int n = offset % 0x40; @@ -692,10 +701,11 @@ DMACDevice::Write16(uint32 addr, uint32 default: break; } - return 0; + + return write_wait; } -uint64 +busdata DMACDevice::Peek8(uint32 addr) { uint8 data; @@ -792,7 +802,7 @@ DMACDevice::Peek8(uint32 addr) break; case DMAC::MFC: - data = chan->mfc; + data = chan->mfc.GetFC(); break; case DMAC::CPR: @@ -800,11 +810,11 @@ DMACDevice::Peek8(uint32 addr) break; case DMAC::DFC: - data = chan->dfc; + data = chan->dfc.GetFC(); break; case DMAC::BFC: - data = chan->bfc; + data = chan->bfc.GetFC(); break; case DMAC::GCR: @@ -1044,13 +1054,13 @@ DMACDevice::MonitorUpdate(Monitor *, Tex screen.Print(x, y++, "$%02x", chan->eiv); // MFC - screen.Print(x, y++, "$%02x", chan->mfc); + screen.Print(x, y++, "$%02x", chan->mfc.GetFC()); // CPR screen.Print(x, y++, "$%02x", chan->cpr); // DFC - screen.Print(x, y++, "$%02x", chan->dfc); + screen.Print(x, y++, "$%02x", chan->dfc.GetFC()); // BFC - screen.Print(x, y++, "$%02x", chan->bfc); + screen.Print(x, y++, "$%02x", chan->bfc.GetFC()); if (ch == 3) { screen.Print(x - 10, y++, "+$3f GCR: $%02x", gcr); @@ -1281,7 +1291,8 @@ DMACDevice::StartTransfer(DMACChan* chan chan->data.Clear(); // 転送モード - switch (chan->GetREQG()) { + uint reqg = chan->GetREQG(); + switch (reqg) { case DMAC::REQG_AUTO_LIM: VMPANIC("REQG_AUTO_LIM 未実装"); break; @@ -1300,7 +1311,7 @@ DMACDevice::StartTransfer(DMACChan* chan break; default: - __unreachable(); + VMPANIC("corrupted reqg=%d", reqg); } // 転送開始ログ。全パラメータは無理なので概要だけ表示。 @@ -1317,7 +1328,7 @@ DMACDevice::StartTransfer(DMACChan* chan } if (event.IsRunning() == false) { - CallAfter(StartCallback, 0); + CallAfter(StartCallback, 0, 0); } } @@ -1438,7 +1449,7 @@ DMACDevice::StartCallback(Event& ev) } } - CallAfter(TransferCallback, 1); + CallAfter(TransferCallback, 1, 0); } // 転送処理 @@ -1453,6 +1464,7 @@ DMACDevice::TransferCallback(Event& ev) int op = chan->seq[chan->seq_index]; uint64 data; + busdata r; // デバイスアクセスなら ACK#n 信号と DONE 信号のドライブ switch (op) { @@ -1488,43 +1500,78 @@ DMACDevice::TransferCallback(Event& ev) } } - // 1回分のアクセス - data = 0; + // アドレスを生成。 + busaddr addr; switch (op) { case RD_M8: - data = vm_phys_read_8(chan->mar); - break; case RD_M16: - data = vm_phys_read_16(chan->mar); + case WR_M8: + case WR_M16: + addr.Set(chan->mar, chan->mfc); break; case RD_D8: - data = vm_phys_read_8(chan->dar); - break; case RD_D16: - data = vm_phys_read_16(chan->dar); - break; - case WR_M8: - data = chan->data.Dequeue(); - data = vm_phys_write_8(chan->mar, data); + case WR_D8: + case WR_D16: + addr.Set(chan->dar, chan->dfc); break; - case WR_M16: - data = chan->data.Dequeue() << 8; - data |= chan->data.Dequeue(); - data = vm_phys_write_16(chan->mar, data); + default: break; + } + + // 書き込みならキューからデータを取得。 + switch (op) { + case WR_M8: case WR_D8: data = chan->data.Dequeue(); - data = vm_phys_write_8(chan->dar, data); break; + case WR_M16: case WR_D16: data = chan->data.Dequeue() << 8; data |= chan->data.Dequeue(); - data = vm_phys_write_16(chan->dar, data); - break; - case NOP: break; default: - __unreachable(); + data = 0; + break; + } + + // 1回分のアクセス。 + + // ユーザ空間へのアクセスが可能かどうかここで調べる。 + // 本来は DMAC ではなくメインバスで管理すべきことだが、パフォーマンスの + // 観点から MPU 側に FC2 カットによる可動部を増やしたくないので、 + // アクセス頻度の低い DMAC 側で肩代わりしている。 + if (__predict_false(addr.IsSuper() == false) && + useraccess[addr.Addr() / 0x2000] == false) + { + r.SetBusErr(); + } else { + switch (op) { + case RD_M8: + case RD_D8: + r = mainbus->Read8(addr); + break; + case RD_M16: + case RD_D16: + r = mainbus->Read16(addr); + break; + case WR_M8: + case WR_D8: + r = mainbus->Write8(addr, data); + break; + case WR_M16: + case WR_D16: + r = mainbus->Write16(addr, data); + break; + case NOP: + r.Clear(); + break; + default: + VMPANIC("corrupted op=%d", op); + } + } + if (__predict_false(loglevel >= 4)) { + TransferLog(chan, op, addr, r, data); } // デバイスアクセスなら ACK#n 信号と DONE 信号のドライブ @@ -1539,9 +1586,9 @@ DMACDevice::TransferCallback(Event& ev) break; } - // バスエラーか。ACK を下ろした後で行う。 - if ((int64)data < 0) { - TransferError(chan, op, data); + // バスエラー(もしくはリトライ)か。ACK を下ろした後で行う。 + if (r.IsOK() == false) { + TransferError(chan, op, r, data); return; } @@ -1549,12 +1596,12 @@ DMACDevice::TransferCallback(Event& ev) switch (op) { case RD_M8: case RD_D8: - chan->data.Enqueue(data); + chan->data.Enqueue(r.Data()); break; case RD_M16: case RD_D16: - chan->data.Enqueue(data >> 8); - chan->data.Enqueue(data & 0xff); + chan->data.Enqueue(r.Data() >> 8); + chan->data.Enqueue(r.Data() & 0xff); break; default: break; @@ -1581,7 +1628,7 @@ DMACDevice::TransferCallback(Event& ev) case NOP: break; default: - __unreachable(); + VMPANIC("corrupted op=%d", op); } // シーケンス完了で MTC の転送1回分 @@ -1596,30 +1643,47 @@ DMACDevice::TransferCallback(Event& ev) } // XXX ディレイはあとから見直す - CallAfter(StartCallback, 4); + CallAfter(StartCallback, 4, r.GetWait()); } else { // XXX ディレイはあとから見直す - CallAfter(TransferCallback, 4); + CallAfter(TransferCallback, 4, r.GetWait()); } } // 転送エラー void -DMACDevice::TransferError(DMACChan *chan, int op, uint64 r) +DMACDevice::TransferError(DMACChan *chan, int op, busdata r, uint32 data) { - if ((int64)r == -2) { + if (r.IsRetry()) { // DTACK が出ていない (SPC)。 // 本当は DTACK が出たことをコールバックしてくれれば // 効率がいいのだがポーリングでもかまわんだろう。 chan->retry++; - putlog(4, "retry=%d", chan->retry); if (chan->retry < 100) { + // 書き込みがリトライになったら仕方ないので、今書こうとして + // 取り出したデータをキューに戻してから再実行。うーんこの。 + switch (op) { + case WR_M8: + case WR_D8: + chan->data.PushFront(data); + break; + case WR_M16: + case WR_D16: + chan->data.PushFront(data); + chan->data.PushFront(data >> 8); + break; + default: + break; + } + // 現在のイベントを再実行 event.time = 1 * 80_nsec; - gScheduler->StartEvent(event); + scheduler->StartEvent(event); return; + } else { + // タイムアウトしたらバスエラーにフォールスルー + putlog(3, "#%d retry exceeds", chan->ch); } - // タイムアウトしたらバスエラーにフォールスルー } // バスエラー @@ -1637,10 +1701,93 @@ DMACDevice::TransferError(DMACChan *chan Error(chan, DMAC::CER_BUS_DAR); break; default: - __unreachable(); + VMPANIC("corrupted op=%d", op); } } +// 1転送ごとのログを出力。 +// ログを出力することが決まってから呼ばれる。 +void +DMACDevice::TransferLog(DMACChan *chan, int op, busaddr addr, + busdata r, uint64 data) +{ + // Read $%06x -> $xx + // Read $%06x -> BusErr + // Read $%06x -> $xx (1 retried) + // Write $%06x <- $xx + // Write $%06x <- $xx BusErr + // Write $%06x <- $xx (1 retried) + + if (op == NOP) { + // どうする? + return; + } + + if (r.IsRetry()) { + return; + } + + const char *act; + const char *dir; + switch (op) { + case RD_M8: + case RD_D8: + case RD_M16: + case RD_D16: + act = "Read "; + dir = "->"; + break; + case WR_M8: + case WR_D8: + case WR_M16: + case WR_D16: + act = "Write"; + dir = "<-"; + break; + default: + act = ""; + dir = ""; + break; + } + + std::string str = string_format("#%d %s $%06x %s ", + chan->ch, act, addr.Addr(), dir); + + switch (op) { + case RD_M8: + case RD_D8: + if (r.IsOK()) { + str += string_format("$%02x", r.Data()); + } + break; + case RD_M16: + case RD_D16: + if (r.IsOK()) { + str += string_format("$%04x", r.Data()); + } + case WR_M8: + case WR_D8: + str += string_format("$%02x", (uint32)data); + break; + case WR_M16: + case WR_D16: + str += string_format("$%04x", (uint32)data); + break; + default: + break; + } + + if (r.IsBusErr()) { + str += " BusErr"; + } + + if (chan->retry != 0) { + str += string_format(" (%d retried)", chan->retry); + } + + putlogn("%s", str.c_str()); +} + // エラー発生 void DMACDevice::Error(DMACChan *chan, uint8 errcode) @@ -1652,7 +1799,7 @@ DMACDevice::Error(DMACChan *chan, uint8 chan->str = false; chan->cnt = false; ChangeInterrupt(); - CallAfter(StartCallback, 0); + CallAfter(StartCallback, 0, 0); } // ACK#n 信号線をアサート @@ -1661,16 +1808,17 @@ DMACDevice::AssertACK(DMACChan *chan) { switch (chan->ch) { case 0: - gFDC->AssertDACK(chan->mtc == 1); + fdc->AssertDACK(chan->mtc == 1); break; case 1: + case 2: // 接続されていない break; case 3: - gADPCM->AssertDACK(chan->mtc == 1); + adpcm->AssertDACK(chan->mtc == 1); break; default: - VMPANIC("未実装"); + __unreachable(); } } @@ -1680,16 +1828,17 @@ DMACDevice::NegateACK(DMACChan *chan) { switch (chan->ch) { case 0: - gFDC->NegateDACK(); + fdc->NegateDACK(); break; case 1: + case 2: // 接続されていない break; case 3: - gADPCM->NegateDACK(); + adpcm->NegateDACK(); break; default: - VMPANIC("未実装"); + __unreachable(); } } @@ -1708,7 +1857,7 @@ DMACDevice::AssertREQ(int ch) } if (event.IsRunning() == false) { - gScheduler->StartEvent(event); + scheduler->StartEvent(event); } } @@ -1747,6 +1896,18 @@ DMACDevice::AbortTransfer(DMACChan *chan ChangeInterrupt(); } +// インデックス化されたアドレス start から end (の手前まで) のユーザ空間 +// アクセスの可否を設定する。x68kio から呼ばれる。 +// accessible true なら (MPU の FC2 ピンによらず) ユーザアクセス可能。 +// アドレスは 8KB 単位なので start=1 ならアドレスは $2000。 +void +DMACDevice::SetUdevice(uint32 start, uint32 end, bool accessible) +{ + for (int i = start; i < end; i++) { + useraccess[i] = accessible; + } +} + // 割り込み信号線の状態を変える。 void DMACDevice::ChangeInterrupt() @@ -1760,11 +1921,11 @@ DMACDevice::ChangeInterrupt() irq = true; } } - gInterrupt->ChangeINT(this, irq); + interrupt->ChangeINT(this, irq); } // 割り込みアクノリッジ -int +busdata DMACDevice::InterruptAcknowledge() { DMACChan *chan; @@ -1783,16 +1944,16 @@ DMACDevice::InterruptAcknowledge() } } - if (top >= 0) { + if (__predict_true(top >= 0)) { chan = &channel[top]; if ((chan->csr & DMAC::CSR_ERR)) { return chan->eiv; } else { return chan->niv; } + } else { + return busdata::BusErr; } - // XXX 誰もいなかったら? - VMPANIC("InterruptAcknowledge no active channels?"); } // @@ -1941,7 +2102,7 @@ DMACChan::SetEIV(uint8 val) void DMACChan::SetMFC(uint8 val) { - mfc = val & 0x07; + mfc = busaddr::FC(val & 0x07); } // CPR を設定する @@ -1957,12 +2118,12 @@ DMACChan::SetCPR(uint8 val) void DMACChan::SetDFC(uint8 val) { - dfc = val & 0x07; + dfc = busaddr::FC(val & 0x07); } // BFC を設定する void DMACChan::SetBFC(uint8 val) { - bfc = val & 0x07; + bfc = busaddr::FC(val & 0x07); }