--- nono/vm/dmac.cpp 2026/04/29 17:05:25 1.1.1.13 +++ nono/vm/dmac.cpp 2026/04/29 17:05:33 1.1.1.15 @@ -13,6 +13,7 @@ #include "fdc.h" #include "interrupt.h" #include "mainbus.h" +#include "monitor.h" #include "mpu.h" #include "scheduler.h" @@ -52,11 +53,9 @@ DMACDevice::DMACDevice() channel[2].pcl_prev = true; // #3 は未対応 - event.Regist("DMAC"); - - monitor.func = ToMonitorCallback(&DMACDevice::MonitorUpdate); - monitor.SetSize(80, 34); - monitor.Regist(ID_MONITOR_DMAC); + monitor = gMonitorManager->Regist(ID_MONITOR_DMAC, this); + monitor->func = ToMonitorCallback(&DMACDevice::MonitorUpdate); + monitor->SetSize(80, 34); } // デストラクタ @@ -77,6 +76,9 @@ DMACDevice::Init() interrupt = GetInterruptDevice(); mainbus = GetMainbusDevice(); + event.SetName("DMAC"); + scheduler->RegistEvent(event); + return true; } @@ -90,6 +92,18 @@ DMACDevice::ResetHard(bool poweron) // NIV and EIV are all set to $0F (uninitialized interrupt vector). // MTC, MAR, DAR, BTC, BAR, MFC, DFC and BFC are not affected. + // 電源オン時、少なくとも BFC は $07 のようだ + // (X68030 IPLROM が #0, #1 の BFC を初期化していないので読める)。 + // MFC、DFC くらいは同様かも知れない。 + if (poweron) { + for (int ch = 0; ch < channel.size(); ch++) { + DMACChan *chan = &channel[ch]; + chan->SetMFC(0x07); + chan->SetDFC(0x07); + chan->SetBFC(0x07); + } + } + gcr = 0; for (int ch = 0; ch < channel.size(); ch++) { DMACChan *chan = &channel[ch]; @@ -115,277 +129,65 @@ DMACDevice::ResetHard(bool poweron) } busdata -DMACDevice::Read8(uint32 addr) +DMACDevice::Read(busaddr addr) { + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(2 - (paddr & 1U), reqsize); busdata data; - uint32 offset = addr & 0xff; - int ch = offset / 0x40; - int n = offset % 0x40; - DMACChan *chan = &channel[ch]; - - switch (n) { - case DMAC::CSR: - data = chan->GetCSR(); - putlog(3, "#%d CSR -> $%02x", ch, data.Data()); - break; - - case DMAC::CER: - data = chan->cer; - putlog(3, "#%d CER -> $%02x", ch, data.Data()); - break; - - case DMAC::DCR: - data = chan->GetDCR(); - putlog(3, "#%d DCR -> $%02x", ch, data.Data()); - break; - - case DMAC::OCR: - data = chan->GetOCR(); - putlog(3, "#%d OCR -> $%02x", ch, data.Data()); - break; - - case DMAC::SCR: - data = chan->GetSCR(); - putlog(3, "#%d SCR -> $%02x", ch, data.Data()); - break; - - case DMAC::CCR: - data = chan->GetCCR(); - putlog(3, "#%d CCR -> $%02x", ch, data.Data()); - break; - - case DMAC::MTC: - data = chan->mtc >> 8; - 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.Data()); - break; - - case DMAC::MAR: - data = chan->mar >> 24; - 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.Data()); - break; - case DMAC::MAR + 2: - data = (chan->mar >> 8) & 0xff; - 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.Data()); - break; - - case DMAC::DAR: - data = chan->dar >> 24; - 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.Data()); - break; - case DMAC::DAR + 2: - data = (chan->dar >> 8) & 0xff; - 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.Data()); - break; - - case DMAC::BTC: - data = chan->btc >> 8; - 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.Data()); - break; - - case DMAC::BAR: - data = chan->bar >> 24; - 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.Data()); - break; - case DMAC::BAR + 2: - data = (chan->bar >> 8) & 0xff; - 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.Data()); - break; - - case DMAC::NIV: - data = chan->niv; - putlog(3, "#%d NIV -> $%02x", ch, data.Data()); - break; - - case DMAC::EIV: - data = chan->eiv; - putlog(3, "#%d EIV -> $%02x", ch, data.Data()); - break; - - case DMAC::MFC: - 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.Data()); - break; - - case DMAC::DFC: - data = chan->dfc.GetFC(); - putlog(3, "#%d DFC -> $%02x", ch, data.Data()); - break; - - case DMAC::BFC: - data = chan->bfc.GetFC(); - putlog(3, "#%d BFC -> $%02x", ch, data.Data()); - break; + if (datasize == 1) { + data = Peek1(paddr); + } else { + data = Peek1(paddr) << 8; + data |= Peek1(paddr + 1); + } - case DMAC::GCR: - if (ch == 3) { - data = gcr; - putlog(3, "GCR -> $%02x", data.Data()); - break; + if (__predict_false(loglevel >= 3)) { + uint32 offset = paddr & 0xff; + uint ch = offset / 0x40; + uint n = offset % 0x40; + if (datasize == 1) { + if (regname1[n]) { + putlogn("#%u %s -> $%02x", ch, regname1[n], data.Data()); + } else if (offset == 0xff) { + putlogn("GCR -> $%02x", data.Data()); + } } else { - data = 0xff; + if (regname2[n / 2]) { + putlogn("#%u %s -> $%04x", ch, regname2[n / 2], data.Data()); + } else if (offset == 0xfe) { + putlogn("GCR(W) -> $%04x", data.Data()); + } } - break; - - default: - data = 0xff; - break; } data |= read_wait; + data |= busdata::Size(datasize); return data; } busdata -DMACDevice::Read16(uint32 addr) +DMACDevice::Write(busaddr addr, uint32 data) { - busdata data; - - uint32 offset = addr & 0xff; - int ch = offset / 0x40; - int n = offset % 0x40; + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(2 - (paddr & 1U), reqsize); + data >>= (reqsize - datasize) * 8; + + uint32 offset = paddr & 0xff; + uint32 ch = offset / 0x40; + uint32 n = offset % 0x40; DMACChan *chan = &channel[ch]; - - switch (n) { - case DMAC::CSR: // CSR | CER - data = chan->GetCSR() << 8; - data |= chan->cer; - 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.Data()); - break; - - case DMAC::SCR: // SCR | CCR - data = chan->GetSCR() << 8; - data |= chan->GetCCR(); - putlog(3, "#%d SCR:CCR -> $%04x", ch, data.Data()); - break; - - case DMAC::MTC: - data = chan->mtc; - putlog(3, "#%d MTC -> $%04x", ch, data.Data()); - break; - - case DMAC::MAR: - data = chan->mar >> 16; - 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.Data()); - break; - - case DMAC::DAR: - data = chan->dar >> 16; - 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.Data()); - break; - - case DMAC::BTC: - data = chan->btc; - putlog(3, "#%d BTC -> $%04x", ch, data.Data()); - break; - - case DMAC::BAR: - data = chan->bar >> 16; - 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.Data()); - break; - - case DMAC::NIV: - data = chan->niv | 0xff00; - putlog(3, "#%d NIV -> $%04x", ch, data.Data()); - break; - - case DMAC::EIV: - data = chan->eiv | 0xff00; - putlog(3, "#%d EIV -> $%04x", ch, data.Data()); - break; - - case DMAC::MFC: - 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.Data()); - break; - - case DMAC::DFC: - data = chan->dfc.GetFC() | 0xff00; - putlog(3, "#%d DFC -> $%04x", ch, data.Data()); - break; - - case DMAC::BFC: - 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.Data()); - break; - } else { - data = 0xffff; - } - break; - - default: - data = 0xffff; - break; + if (datasize == 1) { + WriteByte(chan, n, data); + } else { + WriteWord(chan, n, data); } - data |= read_wait; - return data; + busdata r = write_wait; + r |= busdata::Size(datasize); + return r; } // STR か ACT が立っている時に書き込むとタイミングエラー @@ -399,19 +201,17 @@ DMACDevice::Read16(uint32 addr) // ログ表示版 #define TIMING_ERR_IF_RUNNING_log(regname) do { \ if (chan->str || chan->active) { \ - putlog(2, "#%d %s <- $%02x", ch, regname, data); \ + putlog(2, "#%u %s <- $%02x", ch, regname, data); \ Error(chan, DMAC::CER_TIMING); \ break; \ } \ } while (0) +// バイト書き込み。 busdata -DMACDevice::Write8(uint32 addr, uint32 data) +DMACDevice::WriteByte(DMACChan *chan, uint32 n, uint32 data) { - uint32 offset = addr & 0xff; - int ch = offset / 0x40; - int n = offset % 0x40; - DMACChan *chan = &channel[ch]; + uint ch = chan->ch; switch (n) { case DMAC::CSR: @@ -423,19 +223,19 @@ DMACDevice::Write8(uint32 addr, uint32 d break; case DMAC::DCR: - putlog(2, "#%d DCR <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); TIMING_ERR_IF_RUNNING; chan->SetDCR(data); break; case DMAC::OCR: - putlog(2, "#%d OCR <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); TIMING_ERR_IF_RUNNING; chan->SetOCR(data); break; case DMAC::SCR: - putlog(2, "#%d SCR <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); TIMING_ERR_IF_RUNNING; chan->SetSCR(data); break; @@ -445,7 +245,7 @@ DMACDevice::Write8(uint32 addr, uint32 d // %0 -> %1 に変化したビットだけを評価する。 uint8 up = (chan->GetCCR() ^ data) & data; // バイトサイズのログを (up 込みで) 表示。 - putlog(2, "#%d CCR <- $%02x (up=$%02x)", chan->ch, data, up); + putlog(2, "#%u CCR <- $%02x (up=$%02x)", chan->ch, data, up); // CCR を更新してから WriteCCR() で動作をする。 chan->SetCCR(data); WriteCCR(chan, data, up); @@ -455,111 +255,111 @@ DMACDevice::Write8(uint32 addr, uint32 d case DMAC::MTC: TIMING_ERR_IF_RUNNING_log("MTC:H"); chan->mtc = (chan->mtc & 0x00ff) | (data << 8); - putlog(2, "#%d MTC:H <- $%02x (MTC=$%04x)", ch, data, chan->mtc); + putlog(2, "#%u MTC:H <- $%02x (MTC=$%04x)", ch, data, chan->mtc); break; case DMAC::MTC + 1: TIMING_ERR_IF_RUNNING_log("MTC:L"); chan->mtc = (chan->mtc & 0xff00) | data; - putlog(2, "#%d MTC:L <- $%02x (MTC=$%04x)", ch, data, chan->mtc); + putlog(2, "#%u MTC:L <- $%02x (MTC=$%04x)", ch, data, chan->mtc); break; case DMAC::MAR: TIMING_ERR_IF_RUNNING_log("MAR:0"); chan->mar = (chan->mar & 0x00ffffff) | (data << 24); - putlog(2, "#%d MAR:0 <- $%02x (MAR=$%08x)", ch, data, chan->mar); + putlog(2, "#%u MAR:0 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 1: TIMING_ERR_IF_RUNNING_log("MAR:1"); chan->mar = (chan->mar & 0xff00ffff) | (data << 16); - putlog(2, "#%d MAR:1 <- $%02x (MAR=$%08x)", ch, data, chan->mar); + putlog(2, "#%u MAR:1 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 2: TIMING_ERR_IF_RUNNING_log("MAR:2"); chan->mar = (chan->mar & 0xffff00ff) | (data << 8); - putlog(2, "#%d MAR:2 <- $%02x (MAR=$%08x)", ch, data, chan->mar); + putlog(2, "#%u MAR:2 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 3: TIMING_ERR_IF_RUNNING_log("MAR:3"); chan->mar = (chan->mar & 0xffffff00) | data; - putlog(2, "#%d MAR:3 <- $%02x (MAR=$%08x)", ch, data, chan->mar); + putlog(2, "#%u MAR:3 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::DAR: TIMING_ERR_IF_RUNNING_log("DAR:0"); chan->dar = (chan->dar & 0x00ffffff) | (data << 24); - putlog(2, "#%d DAR:0 <- $%02x (DAR=$%08x)", ch, data, chan->dar); + putlog(2, "#%u DAR:0 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 1: TIMING_ERR_IF_RUNNING_log("DAR:1"); chan->dar = (chan->dar & 0xff00ffff) | (data << 16); - putlog(2, "#%d DAR:1 <- $%02x (DAR=$%08x)", ch, data, chan->dar); + putlog(2, "#%u DAR:1 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 2: TIMING_ERR_IF_RUNNING_log("DAR:2"); chan->dar = (chan->dar & 0xffff00ff) | (data << 8); - putlog(2, "#%d DAR:2 <- $%02x (DAR=$%08x)", ch, data, chan->dar); + putlog(2, "#%u DAR:2 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 3: TIMING_ERR_IF_RUNNING_log("DAR:3"); chan->dar = (chan->dar & 0xffffff00) | data; - putlog(2, "#%d DAR:3 <- $%02x (DAR=$%08x)", ch, data, chan->dar); + putlog(2, "#%u DAR:3 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::BTC: chan->btc = (chan->btc & 0x00ff) | (data << 8); - putlog(2, "#%d BTC:H <- $%02x (BTC=$%04x)", ch, data, chan->btc); + putlog(2, "#%u BTC:H <- $%02x (BTC=$%04x)", ch, data, chan->btc); break; case DMAC::BTC + 1: chan->btc = (chan->btc & 0xff00) | data; - putlog(2, "#%d BTC:L <- $%02x (BTC=$%04x)", ch, data, chan->btc); + putlog(2, "#%u BTC:L <- $%02x (BTC=$%04x)", ch, data, chan->btc); break; case DMAC::BAR: chan->bar = (chan->bar & 0x00ffffff) | (data << 24); - putlog(2, "#%d BAR:0 <- $%02x (BAR=$%08x)", ch, data, chan->bar); + putlog(2, "#%u BAR:0 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 1: chan->bar = (chan->bar & 0xff00ffff) | (data << 16); - putlog(2, "#%d BAR:1 <- $%02x (BAR=$%08x)", ch, data, chan->bar); + putlog(2, "#%u BAR:1 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 2: chan->bar = (chan->bar & 0xffff00ff) | (data << 8); - putlog(2, "#%d BAR:2 <- $%02x (BAR=$%08x)", ch, data, chan->bar); + putlog(2, "#%u BAR:2 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 3: chan->bar = (chan->bar & 0xffffff00) | data; - putlog(2, "#%d BAR:3 <- $%02x (BAR=$%08x)", ch, data, chan->bar); + putlog(2, "#%u BAR:3 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::NIV: - putlog(2, "#%d NIV <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); chan->SetNIV(data); break; case DMAC::EIV: - putlog(2, "#%d EIV <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); chan->SetEIV(data); break; case DMAC::MFC: - putlog(2, "#%d MFC <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); TIMING_ERR_IF_RUNNING; chan->SetMFC(data); break; case DMAC::CPR: - putlog(2, "#%d CPR <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); chan->SetCPR(data); break; case DMAC::DFC: - putlog(2, "#%d DFC <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); TIMING_ERR_IF_RUNNING; chan->SetDFC(data); break; case DMAC::BFC: - putlog(2, "#%d BFC <- $%02x", ch, data); + putlog(2, "#%u %s <- $%02x", ch, regname1[n], data); chan->SetBFC(data); break; @@ -576,13 +376,11 @@ DMACDevice::Write8(uint32 addr, uint32 d return write_wait; } +// ワード書き込み。 busdata -DMACDevice::Write16(uint32 addr, uint32 data) +DMACDevice::WriteWord(DMACChan *chan, uint32 n, uint32 data) { - uint32 offset = addr & 0xff; - int ch = offset / 0x40; - int n = offset % 0x40; - DMACChan *chan = &channel[ch]; + uint ch = chan->ch; switch (n) { case DMAC::CSR: // CSR | CER @@ -592,7 +390,7 @@ DMACDevice::Write16(uint32 addr, uint32 break; case DMAC::DCR: // DCR | OCR - putlog(2, "#%d DCR:OCR <- $%04x", ch, data); + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); TIMING_ERR_IF_RUNNING; chan->SetDCR(data >> 8); chan->SetOCR(data & 0xff); @@ -603,7 +401,7 @@ DMACDevice::Write16(uint32 addr, uint32 // CCR の %0 -> %1 に変化したビットだけを取り出す。 uint8 up = (chan->GetCCR() ^ data) & data; // ワードサイズのログを (CCR の up 込みで) 表示。 - putlog(2, "#%d SCR:CCR <- $%04x (up=$%02x)", ch, data, up); + putlog(2, "#%u SCR:CCR <- $%04x (up=$%02x)", ch, data, up); // 両方のレジスタの値を更新。 chan->SetSCR(data >> 8); chan->SetCCR(data); @@ -616,7 +414,7 @@ DMACDevice::Write16(uint32 addr, uint32 } case DMAC::MTC: - putlog(2, "#%d MTC <- $%04x", ch, data); + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); TIMING_ERR_IF_RUNNING; chan->mtc = data; break; @@ -624,27 +422,27 @@ DMACDevice::Write16(uint32 addr, uint32 case DMAC::MAR: TIMING_ERR_IF_RUNNING_log("MAR:H"); chan->mar = (chan->mar & 0x0000ffff) | (data << 16); - putlog(2, "#%d MAR:H <- $%04x (MAR=$%08x)", ch, data, chan->mar); + putlog(2, "#%u MAR:H <- $%04x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 2: TIMING_ERR_IF_RUNNING_log("MAR:L"); chan->mar = (chan->mar & 0xffff0000) | data; - putlog(2, "#%d MAR:L <- $%04x (MAR=$%08x)", ch, data, chan->mar); + putlog(2, "#%u MAR:L <- $%04x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::DAR: TIMING_ERR_IF_RUNNING_log("DAR:H"); chan->dar = (chan->dar & 0x0000ffff) | (data << 16); - putlog(2, "#%d DAR:H <- $%04x (DAR=$%08x)", ch, data, chan->dar); + putlog(2, "#%u DAR:H <- $%04x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 2: TIMING_ERR_IF_RUNNING_log("DAR:L"); chan->dar = (chan->dar & 0xffff0000) | data; - putlog(2, "#%d DAR:L <- $%04x (DAR=$%08x)", ch, data, chan->dar); + putlog(2, "#%u DAR:L <- $%04x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::BTC: - putlog(2, "#%d BTC <- $%04x", ch, data); + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); TIMING_ERR_IF_RUNNING; chan->btc = data; break; @@ -652,47 +450,47 @@ DMACDevice::Write16(uint32 addr, uint32 case DMAC::BAR: TIMING_ERR_IF_RUNNING_log("BAR:H"); chan->bar = (chan->bar & 0x0000ffff) | (data << 16); - putlog(2, "#%d BAR:H <- $%04x (BAR=$%08x)", ch, data, chan->bar); + putlog(2, "#%u BAR:H <- $%04x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 2: TIMING_ERR_IF_RUNNING_log("BAR:L"); chan->bar = (chan->bar & 0xffff0000) | data; - putlog(2, "#%d BAR:L <- $%04x (BAR=$%08x)", ch, data, chan->bar); + putlog(2, "#%u BAR:L <- $%04x (BAR=$%08x)", ch, data, chan->bar); break; - case DMAC::NIV: - putlog(2, "#%d NIV <- $%02x", ch, data); + case DMAC::NIV & ~1U: + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); chan->SetNIV(data); break; - case DMAC::EIV: - putlog(2, "#%d EIV <- $%02x", ch, data); + case DMAC::EIV & ~1U: + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); chan->SetEIV(data); break; - case DMAC::MFC: - putlog(2, "#%d MFC <- $%02x", ch, data); + case DMAC::MFC & ~1U: + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); TIMING_ERR_IF_RUNNING; chan->SetMFC(data); break; - case DMAC::CPR: - putlog(2, "#%d CPR <- $%02x", ch, data); + case DMAC::CPR & ~1U: + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); chan->SetCPR(data); break; - case DMAC::DFC: - putlog(2, "#%d DFC <- $%02x", ch, data); + case DMAC::DFC & ~1U: + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); TIMING_ERR_IF_RUNNING; chan->SetDFC(data); break; - case DMAC::BFC: - putlog(2, "#%d BFC <- $%02x", ch, data); + case DMAC::BFC & ~1U: + putlog(2, "#%u %s <- $%04x", ch, regname2[n / 2], data); chan->SetBFC(data); break; - case DMAC::GCR - 1: + case DMAC::GCR & ~1U: if (ch == 3) { WriteGCR(data); } @@ -706,13 +504,13 @@ DMACDevice::Write16(uint32 addr, uint32 } busdata -DMACDevice::Peek8(uint32 addr) +DMACDevice::Peek1(uint32 addr) { uint8 data; uint32 offset = addr & 0xff; - int ch = offset / 0x40; - int n = offset % 0x40; + uint ch = offset / 0x40; + uint n = offset % 0x40; DMACChan *chan = &channel[ch]; switch (n) { @@ -873,15 +671,15 @@ DMACDevice::MonitorUpdate(Monitor *, Tex screen.Print(0, y++, "+$%02x DFC:", DMAC::DFC); screen.Print(0, y++, "+$%02x BFC:", DMAC::BFC); - for (int ch = 0; ch < 4; ch++) { + for (uint ch = 0; ch < 4; ch++) { DMACChan *chan = &channel[ch]; - int val; + uint val; x = 13 + ch * 17; y = 0; // 地味だけど有効なチャンネルをハイライトしてみる screen.Print(x, y++, (chan->active ? TA::Em : TA::Normal), - "#%d (%s)", chan->ch, chan->desc); + "#%u (%s)", chan->ch, chan->desc); // アドレス screen.Print(x, y++, "$%06x", baseaddr + ch * 0x40); @@ -921,7 +719,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "CycleWithHold", }; val = chan->GetXRM(); - screen.Print(x, y++, "%d:%s", val, dcr_xrm[val]); + screen.Print(x, y++, "%u:%s", val, dcr_xrm[val]); // DCR:DTYP static const char * const dcr_dtyp[] = { @@ -932,7 +730,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "ACK+READY", }; val = chan->GetDTYP(); - screen.Print(x, y++, "%d:%s", val, dcr_dtyp[val]); + screen.Print(x, y++, "%u:%s", val, dcr_dtyp[val]); // DCR:DPS static const char * const dcr_dps[] = { @@ -941,7 +739,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "16bit", }; val = chan->GetDPS(); - screen.Print(x, y++, "%d:%s", val, dcr_dps[val]); + screen.Print(x, y++, "%u:%s", val, dcr_dps[val]); // DCR:PCL static const char * const dcr_pcl_name[] = { @@ -952,7 +750,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "Abort", }; val = chan->dcr_pcl; - screen.Print(x, y++, "%d:%s", val, dcr_pcl_name[val]); + screen.Print(x, y++, "%u:%s", val, dcr_pcl_name[val]); // OCR screen.Print(x, y++, "$%02x", chan->GetOCR()); @@ -964,7 +762,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "DeviceToMemory", }; val = chan->GetDIR(); - screen.Print(x, y++, "%d:%s", val, ocr_dir[val]); + screen.Print(x, y++, "%u:%s", val, ocr_dir[val]); // OCR:SIZE static const char * const ocr_size[] = { @@ -975,7 +773,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "8bit Unpacked", }; val = chan->GetSIZE(); - screen.Print(x, y++, "%d:%s", val, ocr_size[val]); + screen.Print(x, y++, "%u:%s", val, ocr_size[val]); // OCR:CHAIN static const char * const ocr_chain[] = { @@ -986,7 +784,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "LinkArrayChain", }; val = chan->GetCHAIN(); - screen.Print(x, y++, "%d:%s", val, ocr_chain[val]); + screen.Print(x, y++, "%u:%s", val, ocr_chain[val]); // OCR:REQG static const char * const ocr_reqg[] = { @@ -997,7 +795,7 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "AutoThenExt", }; val = chan->GetREQG(); - screen.Print(x, y++, "%d:%s", val, ocr_reqg[val]); + screen.Print(x, y++, "%u:%s", val, ocr_reqg[val]); // SCR screen.Print(x, y++, "$%02x", chan->GetSCR()); @@ -1011,9 +809,9 @@ DMACDevice::MonitorUpdate(Monitor *, Tex "undefined", }; val = chan->GetMAC(); - screen.Print(x, y++, "%d:%s", val, scr_xac[val]); + screen.Print(x, y++, "%u:%s", val, scr_xac[val]); val = chan->GetDAC(); - screen.Print(x, y++, "%d:%s", val, scr_xac[val]); + screen.Print(x, y++, "%u:%s", val, scr_xac[val]); // CCR val = chan->GetCCR(); @@ -1073,7 +871,7 @@ void DMACDevice::MonitorReg4(TextScreen& screen, int x, int y, uint32 reg, const char * const *names) { - for (int i = 0; i < 4; i++) { + for (uint i = 0; i < 4; i++) { if (names[i][0] == '-') { screen.Puts(x + i * 4, y, TA::Disable, "---"); } else { @@ -1126,7 +924,7 @@ DMACDevice::WriteCSR(DMACChan *chan, uin chan->pcl_prev = false; } - putlog(2, "#%d CSR <- $%02x (CSR = $%02x)", chan->ch, data, chan->GetCSR()); + putlog(2, "#%u CSR <- $%02x (CSR = $%02x)", chan->ch, data, chan->GetCSR()); ChangeInterrupt(); } @@ -1249,7 +1047,7 @@ DMACDevice::WriteCCR(DMACChan *chan, uin // 転送開始 void -DMACDevice::StartTransfer(DMACChan* chan) +DMACDevice::StartTransfer(DMACChan *chan) { // Operation Timing Error (ii) // CSR の ACT,COC,BTC,NDT,ERR が立ってたら開始しない @@ -1311,20 +1109,27 @@ DMACDevice::StartTransfer(DMACChan* chan break; default: - VMPANIC("corrupted reqg=%d", reqg); + VMPANIC("corrupted reqg=%u", reqg); } // 転送開始ログ。全パラメータは無理なので概要だけ表示。 if (loglevel >= 1) { + static const char * const countstr[] = { + "-", + "", + "+", + }; std::string msg; if (chan->GetDIR() == DMAC::DIR_MtoD) { - msg = string_format("$%06x to $%06x mtc=$%04x", - chan->mar, chan->dar, chan->mtc); + msg = string_format("$%06x%s to $%06x%s", + chan->mar, countstr[chan->mac + 1], + chan->dar, countstr[chan->dac + 1]); } else { - msg = string_format("$%06x to $%06x mtc=$%04x", - chan->dar, chan->mar, chan->mtc); + msg = string_format("$%06x%s to $%06x%s", + chan->dar, countstr[chan->dac + 1], + chan->mar, countstr[chan->mac + 1]); } - putlogn("#%d Start %s", chan->ch, msg.c_str()); + putlogn("#%u Start %s mtc=$%04x", chan->ch, msg.c_str(), chan->mtc); } if (event.IsRunning() == false) { @@ -1358,7 +1163,7 @@ DMACDevice::SelectChannel() return NULL; } else { chan = &channel[ch]; - event.SetName(string_format("DMAC #%d", chan->ch)); + event.SetName(string_format("DMAC #%u", chan->ch)); return chan; } } @@ -1449,6 +1254,15 @@ DMACDevice::StartCallback(Event& ev) } } + if (__predict_false(loglevel >= 5)) { + std::string ss; + for (const auto op : chan->seq) { + ss += ' '; + ss += seqname[op]; + } + putlogn("#%u %s seq:%s", chan->ch, __func__, ss.c_str()); + } + CallAfter(TransferCallback, 1, 0); } @@ -1462,7 +1276,10 @@ DMACDevice::TransferCallback(Event& ev) return; } - int op = chan->seq[chan->seq_index]; + uint op = chan->seq[chan->seq_index]; + putlog(5, "#%u %s [%u] %s", + chan->ch, __func__, chan->seq_index, seqname[op]); + uint64 data; busdata r; @@ -1507,18 +1324,37 @@ DMACDevice::TransferCallback(Event& ev) case RD_M16: case WR_M8: case WR_M16: - addr.Set(chan->mar, chan->mfc); + addr = busaddr(chan->mar) | chan->mfc; break; case RD_D8: case RD_D16: case WR_D8: case WR_D16: - addr.Set(chan->dar, chan->dfc); + addr = busaddr(chan->dar) | chan->dfc; break; default: break; } + // サイズを指定。 + switch (op) { + case RD_M8: + case RD_D8: + case WR_M8: + case WR_D8: + addr.ChangeSize(1); + break; + case RD_M16: + case RD_D16: + case WR_M16: + case WR_D16: + addr.ChangeSize(2); + break; + default: + break; + } + + // 書き込みならキューからデータを取得。 switch (op) { case WR_M8: @@ -1535,41 +1371,48 @@ DMACDevice::TransferCallback(Event& ev) 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); + bool accessible = + __predict_true(addr.IsSuper() || useraccess[addr.Addr() / 0x2000]); + + // 1回分のアクセス。 + switch (op) { + case RD_M8: + case RD_D8: + case RD_M16: + case RD_D16: + if (accessible) { + r = mainbus->Read(addr); + // IODevice からの読み込みはポートサイズ単位で行う仕様なので、 + // ここでダイナミックバスサイジングの要領で必要な部分を抜き出す。 + // 実際の HD63450 は 68000 バス用のデバイスなので、このあたりの + // バス変換を YUKI ちゃんなどの周辺回路がやってるはず。 + data = MainbusDevice::DYNAMIC_BUS_SIZING_R(addr, r); + r.ChangeData(data); + } else { + r.SetBusErr(); + } + break; + case WR_M8: + case WR_D8: + case WR_M16: + case WR_D16: + if (accessible) { + r = mainbus->Write(addr, data); + } else { + r.SetBusErr(); } + break; + case NOP: + r = 0; + break; + default: + VMPANIC("corrupted op=%u", op); } + if (__predict_false(loglevel >= 4)) { TransferLog(chan, op, addr, r, data); } @@ -1628,7 +1471,7 @@ DMACDevice::TransferCallback(Event& ev) case NOP: break; default: - VMPANIC("corrupted op=%d", op); + VMPANIC("corrupted op=%u", op); } // シーケンス完了で MTC の転送1回分 @@ -1652,7 +1495,7 @@ DMACDevice::TransferCallback(Event& ev) // 転送エラー void -DMACDevice::TransferError(DMACChan *chan, int op, busdata r, uint32 data) +DMACDevice::TransferError(DMACChan *chan, uint op, busdata r, uint32 data) { if (r.IsRetry()) { // DTACK が出ていない (SPC)。 @@ -1682,7 +1525,7 @@ DMACDevice::TransferError(DMACChan *chan return; } else { // タイムアウトしたらバスエラーにフォールスルー - putlog(3, "#%d retry exceeds", chan->ch); + putlog(3, "#%u retry exceeds", chan->ch); } } @@ -1701,16 +1544,17 @@ DMACDevice::TransferError(DMACChan *chan Error(chan, DMAC::CER_BUS_DAR); break; default: - VMPANIC("corrupted op=%d", op); + VMPANIC("corrupted op=%u", op); } } // 1転送ごとのログを出力。 // ログを出力することが決まってから呼ばれる。 void -DMACDevice::TransferLog(DMACChan *chan, int op, busaddr addr, +DMACDevice::TransferLog(DMACChan *chan, uint op, busaddr addr, busdata r, uint64 data) { + // Nop // Read $%06x -> $xx // Read $%06x -> BusErr // Read $%06x -> $xx (1 retried) @@ -1719,7 +1563,7 @@ DMACDevice::TransferLog(DMACChan *chan, // Write $%06x <- $xx (1 retried) if (op == NOP) { - // どうする? + putlogn("#%u Nop", chan->ch); return; } @@ -1750,7 +1594,7 @@ DMACDevice::TransferLog(DMACChan *chan, break; } - std::string str = string_format("#%d %s $%06x %s ", + std::string str = string_format("#%u %s $%06x %s ", chan->ch, act, addr.Addr(), dir); switch (op) { @@ -1782,7 +1626,7 @@ DMACDevice::TransferLog(DMACChan *chan, } if (chan->retry != 0) { - str += string_format(" (%d retried)", chan->retry); + str += string_format(" (%u retried)", chan->retry); } putlogn("%s", str.c_str()); @@ -1844,9 +1688,9 @@ DMACDevice::NegateACK(DMACChan *chan) // REQ#n 信号線アサート (外部から呼ばれる) void -DMACDevice::AssertREQ(int ch) +DMACDevice::AssertREQ(uint ch) { - assert(0 <= ch && ch < 4); + assert(ch < 4); DMACChan *chan = &channel[ch]; chan->req = true; @@ -1863,9 +1707,9 @@ DMACDevice::AssertREQ(int ch) // REQ#n 信号線ネゲート (外部から呼ばれる) void -DMACDevice::NegateREQ(int ch) +DMACDevice::NegateREQ(uint ch) { - assert(0 <= ch && ch < 4); + assert(ch < 4); DMACChan *chan = &channel[ch]; chan->req = false; @@ -1952,7 +1796,7 @@ DMACDevice::InterruptAcknowledge() return chan->niv; } } else { - return busdata::BusErr; + return BusData::BusErr; } } @@ -2127,3 +1971,123 @@ DMACChan::SetBFC(uint8 val) { bfc = busaddr::FC(val & 0x07); } + +// レジスタ名 (バイト) +/*static*/ const char * const +DMACDevice::regname1[0x40] = { + "CSR", // 00 + "CER", // 01 + NULL, // 02 + NULL, // 03 + "DCR", // 04 + "OCR", // 05 + "SCR", // 06 + "CCR", // 07 + NULL, // 08 + NULL, // 09 + "MTC:H", // 0a + "MTC:L", // 0b + "MAR:0", // 0c + "MAR:1", // 0d + "MAR:2", // 0e + "MAR:3", // 0f + NULL, // 10 + NULL, // 11 + NULL, // 12 + NULL, // 13 + "DAR:0", // 14 + "DAR:1", // 15 + "DAR:2", // 16 + "DAR:3", // 17 + NULL, // 18 + NULL, // 19 + "BTC:H", // 1a + "BTC:L", // 1b + "BAR:0", // 1c + "BAR:1", // 1d + "BAR:2", // 1e + "BAR:3", // 1f + NULL, // 20 + NULL, // 21 + NULL, // 22 + NULL, // 23 + NULL, // 24 + "NIV", // 25 + NULL, // 26 + "EIV", // 27 + NULL, // 28 + "MFC", // 29 + NULL, // 2a + NULL, // 2b + NULL, // 2c + "CPR", // 2d + NULL, // 2e + NULL, // 2f + NULL, // 30 + "DFC", // 31 + NULL, // 32 + NULL, // 33 + NULL, // 34 + NULL, // 35 + NULL, // 36 + NULL, // 37 + NULL, // 38 + "BFC", // 39 + NULL, // 3a + NULL, // 3b + NULL, // 3c + NULL, // 3d + NULL, // 3e + NULL, // 3f (GCR は別処理) +}; + +// レジスタ名 (ワード) +/*static*/ const char * const +DMACDevice::regname2[0x40 / 2] = { + "CSR:CER", // 00 + NULL, // 02 + "DCR:OCR", // 04 + "SCR:CCR", // 06 + NULL, // 08 + "MTC", // 0a + "MAR:H", // 0c + "MAR:L", // 0e + NULL, // 10 + NULL, // 12 + "DAR:H", // 14 + "DAR:L", // 16 + NULL, // 18 + "BTC", // 1a + "BAR:H", // 1c + "BAR:L", // 1e + NULL, // 20 + NULL, // 22 + "NIV(W)", // 24 + "EIV(W)", // 26 + "MFC(W)", // 28 + NULL, // 2a + "CPR(W)", // 2c + NULL, // 2f + "DFC(W)", // 30 + NULL, // 32 + NULL, // 34 + NULL, // 36 + "BFC(W)", // 38 + NULL, // 3a + NULL, // 3c + NULL, // 3e (GCR は別処理) +}; + +/*static*/ const char * const +DMACDevice::seqname[DMACDevice::SEQ_MAX] = +{ + "NOP", + "RD_M8", + "RD_M16", + "RD_D8", + "RD_D16", + "WR_M8", + "WR_M16", + "WR_D8", + "WR_D16", +};