--- nono/vm/dmac.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/dmac.cpp 2026/04/29 17:04:32 1.1.1.2 @@ -4,6 +4,9 @@ // #include "dmac.h" +#include "mystring.h" + +std::unique_ptr gDMAC; DMACDevice::DMACDevice() { @@ -11,6 +14,24 @@ DMACDevice::DMACDevice() devname = "DMAC"; devaddr = baseaddr; devlen = 0x2000; + + monitor.Init(80, 30); + + for (int i = 0; i < countof(dmac.chan); i++) { + dmac.chan[i].ch = i; + dmac.chan[i].parent = this; + } + dmac.chan[0].desc = "FD"; + dmac.chan[1].desc = "HD"; + dmac.chan[2].desc = "User"; + dmac.chan[3].desc = "ADPCM"; + + for (int i = 0; i < countof(event); i++) { + event[i].dev = this; + event[i].func = (DeviceCallback_t)&DMACDevice::Transfer; + event[i].SetName(string_format("DMAC #%d", i)); + event[i].code = i; + } } DMACDevice::~DMACDevice() @@ -24,113 +45,142 @@ DMACDevice::Read8(uint32 addr) int ch; ch = (addr - baseaddr) / 0x40; - struct DMAC::channel *chan = &dmac.chan[ch]; + DMAC::Channel *chan = &dmac.chan[ch]; int n = (addr - baseaddr) % 0x40; switch (n) { case DMAC::CSR: - data = chan->csr; + data = chan->PeekCSR(); + putlog(4, "#%d CSR -> $%02x", ch, data); break; case DMAC::CER: data = chan->cer; + putlog(4, "#%d CER -> $%02x", ch, data); break; case DMAC::DCR: data = chan->dcr; + putlog(4, "#%d DCR -> $%02x", ch, data); break; case DMAC::OCR: data = chan->ocr; + putlog(4, "#%d OCR -> $%02x", ch, data); break; case DMAC::SCR: data = chan->scr; + putlog(4, "#%d SCR -> $%02x", ch, data); break; case DMAC::CCR: - data = chan->ccr; + data = chan->PeekCCR(); + putlog(4, "#%d CCR -> $%02x", ch, data); break; case DMAC::MTC: data = chan->mtc >> 8; + putlog(4, "#%d MTC:H -> $%02x", ch, data); break; case DMAC::MTC + 1: data = chan->mtc & 0xff; + putlog(4, "#%d MTC:L -> $%02x", ch, data); break; case DMAC::MAR: data = chan->mar >> 24; + putlog(4, "#%d MAR:0 -> $%02x", ch, data); break; case DMAC::MAR + 1: data = (chan->mar >> 16) & 0xff; + putlog(4, "#%d MAR:1 -> $%02x", ch, data); break; case DMAC::MAR + 2: data = (chan->mar >> 8) & 0xff; + putlog(4, "#%d MAR:2 -> $%02x", ch, data); break; case DMAC::MAR + 3: data = chan->mar & 0xff; + putlog(4, "#%d MAR:3 -> $%02x", ch, data); break; case DMAC::DAR: data = chan->dar >> 24; + putlog(4, "#%d DAR:0 -> $%02x", ch, data); break; case DMAC::DAR + 1: data = (chan->dar >> 16) & 0xff; + putlog(4, "#%d DAR:1 -> $%02x", ch, data); break; case DMAC::DAR + 2: data = (chan->dar >> 8) & 0xff; + putlog(4, "#%d DAR:2 -> $%02x", ch, data); break; case DMAC::DAR + 3: data = chan->dar & 0xff; + putlog(4, "#%d DAR:3 -> $%02x", ch, data); break; case DMAC::BTC: data = chan->btc >> 8; + putlog(4, "#%d BTC:H -> $%02x", ch, data); break; case DMAC::BTC + 1: data = chan->btc & 0xff; + putlog(4, "#%d BTC:L -> $%02x", ch, data); break; case DMAC::BAR: data = chan->bar >> 24; + putlog(4, "#%d BAR:0 -> $%02x", ch, data); break; case DMAC::BAR + 1: data = (chan->bar >> 16) & 0xff; + putlog(4, "#%d BAR:1 -> $%02x", ch, data); break; case DMAC::BAR + 2: data = (chan->bar >> 8) & 0xff; + putlog(4, "#%d BAR:2 -> $%02x", ch, data); break; case DMAC::BAR + 3: data = chan->bar & 0xff; + putlog(4, "#%d BAR:3 -> $%02x", ch, data); break; case DMAC::NIV: data = chan->niv; + putlog(4, "#%d NIV -> $%02x", ch, data); break; case DMAC::EIV: data = chan->eiv; + putlog(4, "#%d EIV -> $%02x", ch, data); break; case DMAC::MFC: data = chan->mfc; + putlog(4, "#%d MFC -> $%02x", ch, data); break; case DMAC::CPR: data = chan->cpr; + putlog(4, "#%d CPR -> $%02x", ch, data); break; case DMAC::DFC: data = chan->dfc; + putlog(4, "#%d DFC -> $%02x", ch, data); break; case DMAC::BFC: data = chan->bfc; + putlog(4, "#%d BFC -> $%02x", ch, data); break; case DMAC::GCR: if (ch == 3) { data = dmac.gcr; + putlog(4, "GCR -> $%02x", data); break; } else { data = 0xff; @@ -151,11 +201,11 @@ DMACDevice::Write8(uint32 addr, uint32 d int ch; ch = (addr - baseaddr) / 0x40; - struct DMAC::channel *chan = &dmac.chan[ch]; + DMAC::Channel *chan = &dmac.chan[ch]; int n = (addr - baseaddr) % 0x40; switch (n) { case DMAC::CSR: - write_csr(ch, data); + chan->WriteCSR(data); break; case DMAC::CER: @@ -163,100 +213,127 @@ DMACDevice::Write8(uint32 addr, uint32 d break; case DMAC::DCR: + putlog(4, "#%d DCR <- $%02x", ch, data); chan->dcr = data & 0xfb; break; case DMAC::OCR: + putlog(4, "#%d OCR <- $%02x", ch, data); chan->ocr = data; break; case DMAC::SCR: + putlog(4, "#%d SCR <- $%02x", ch, data); chan->scr = data & 0x0f; break; case DMAC::CCR: - write_ccr(ch, data); + putlog(4, "#%d CCR <- $%02x", ch, data); + chan->WriteCCR(data); break; case DMAC::MTC: chan->mtc = (chan->mtc & 0x00ff) | (data << 8); + putlog(4, "#%d MTC:H <- $%02x (MTC=$%04x)", ch, data, chan->mtc); break; case DMAC::MTC + 1: chan->mtc = (chan->mtc & 0xff00) | data; + putlog(4, "#%d MTC:L <- $%02x (MTC=$%04x)", ch, data, chan->mtc); break; case DMAC::MAR: chan->mar = (chan->mar & 0x00ffffff) | (data << 24); + putlog(4, "#%d MAR:0 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 1: chan->mar = (chan->mar & 0xff00ffff) | (data << 16); + putlog(4, "#%d MAR:1 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 2: chan->mar = (chan->mar & 0xffff00ff) | (data << 8); + putlog(4, "#%d MAR:2 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::MAR + 3: chan->mar = (chan->mar & 0xffffff00) | data; + putlog(4, "#%d MAR:3 <- $%02x (MAR=$%08x)", ch, data, chan->mar); break; case DMAC::DAR: chan->dar = (chan->dar & 0x00ffffff) | (data << 24); + putlog(4, "#%d DAR:0 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 1: chan->dar = (chan->dar & 0xff00ffff) | (data << 16); + putlog(4, "#%d DAR:1 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 2: chan->dar = (chan->dar & 0xffff00ff) | (data << 8); + putlog(4, "#%d DAR:2 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::DAR + 3: chan->dar = (chan->dar & 0xffffff00) | data; + putlog(4, "#%d DAR:3 <- $%02x (DAR=$%08x)", ch, data, chan->dar); break; case DMAC::BTC: chan->btc = (chan->btc & 0x00ff) | (data << 8); + putlog(4, "#%d BTC:H <- $%02x (BTC=$%04x)", ch, data, chan->btc); break; case DMAC::BTC + 1: chan->btc = (chan->btc & 0xff00) | data; + putlog(4, "#%d BTC:L <- $%02x (BTC=$%04x)", ch, data, chan->btc); break; case DMAC::BAR: chan->bar = (chan->bar & 0x00ffffff) | (data << 24); + putlog(4, "#%d BAR:0 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 1: chan->bar = (chan->bar & 0xff00ffff) | (data << 16); + putlog(4, "#%d BAR:1 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 2: chan->bar = (chan->bar & 0xffff00ff) | (data << 8); + putlog(4, "#%d BAR:2 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::BAR + 3: chan->bar = (chan->bar & 0xffffff00) | data; + putlog(4, "#%d BAR:3 <- $%02x (BAR=$%08x)", ch, data, chan->bar); break; case DMAC::NIV: + putlog(4, "#%d NIV <- $%02x", ch, data); chan->niv = data; break; case DMAC::EIV: + putlog(4, "#%d EIV <- $%02x", ch, data); chan->eiv = data; break; case DMAC::MFC: + putlog(4, "#%d MFC <- $%02x", ch, data); chan->mfc = data & 7; break; case DMAC::CPR: + putlog(4, "#%d CPR <- $%02x", ch, data); chan->cpr = data & 3; break; case DMAC::DFC: + putlog(4, "#%d DFC <- $%02x", ch, data); chan->dfc = data & 7; break; case DMAC::BFC: + putlog(4, "#%d BFC <- $%02x", ch, data); chan->bfc = data & 7; break; case DMAC::GCR: if (ch == 3) { + putlog(4, "GCR <- $%02x", data); dmac.gcr = data; } break; @@ -274,11 +351,11 @@ DMACDevice::Peek8(uint32 addr) int ch; ch = (addr - baseaddr) / 0x40; - struct DMAC::channel *chan = &dmac.chan[ch]; + const DMAC::Channel *chan = &dmac.chan[ch]; int n = (addr - baseaddr) % 0x40; switch (n) { case DMAC::CSR: - data = chan->csr; + data = chan->PeekCSR(); break; case DMAC::CER: @@ -298,7 +375,7 @@ DMACDevice::Peek8(uint32 addr) break; case DMAC::CCR: - data = chan->ccr; + data = chan->PeekCCR(); break; case DMAC::MTC: @@ -395,15 +472,525 @@ DMACDevice::Peek8(uint32 addr) return data; } +bool +DMACDevice::MonitorUpdate() +{ + int x; + int y; + + monitor.Clear(); + + y = 1; + monitor.Print(0, y++, "CSR"); + y += 2; + monitor.Print(0, y++, "CER"); + monitor.Print(0, y++, "DCR:XRM"); + monitor.Print(0, y++, "DCR:DTYP"); + monitor.Print(0, y++, "DCR:DPS"); + monitor.Print(0, y++, "DCR:PCL"); + monitor.Print(0, y++, "OCR:DIR"); + monitor.Print(0, y++, "OCR:SIZE"); + monitor.Print(0, y++, "OCR:CHAIN"); + monitor.Print(0, y++, "OCR:REQG"); + monitor.Print(0, y++, "SCR:MAC"); + monitor.Print(0, y++, "SCR:DAC"); + monitor.Print(0, y++, "CCR"); + y += 2; + monitor.Print(0, y++, "MTC"); + monitor.Print(0, y++, "MAR"); + monitor.Print(0, y++, "DAR"); + monitor.Print(0, y++, "BTC"); + monitor.Print(0, y++, "BAR"); + monitor.Print(0, y++, "NIV"); + monitor.Print(0, y++, "EIV"); + monitor.Print(0, y++, "MFC"); + monitor.Print(0, y++, "CPR"); + monitor.Print(0, y++, "DFC"); + monitor.Print(0, y++, "BFC"); + + for (int ch = 0; ch < 4; ch++) { + DMAC::Channel *chan = &dmac.chan[ch]; + int val; + x = 12 + ch * 17; + y = 0; + + // 地味だけど有効なチャンネルをハイライトしてみる + monitor.Print(x, y++, (chan->active ? TA::Em : TA::Off), + "#%d (%s)", chan->ch, chan->desc); + + // CSR + val = chan->PeekCSR(); + monitor.Print(x, y++, "$%02x", val); + static const char * const csrname[] = { + "COC", "BTC", "NDT", "ERR", "ACT", "---", "PCT", "PCS", + }; + MonitorReg4(x, y++, val >> 4, &csrname[0]); + MonitorReg4(x, y++, val & 0xff, &csrname[4]); + + // CER + val = chan->cer & 0x1f; + const char *e; + if (val <= 0x11 && errnames[val]) { + e = errnames[val]; + } else { + e = "?"; + } + monitor.Print(x, y, "$%02x", chan->cer); + if (val > 0) { + monitor.Print(x + 3, y, ":%s", e); + } + y++; + + // DCR:XRM + static const char * const dcr_xrm[] = { + //1234567890123 + "Burst", + "undefined", + "CycleW/O Hold", + "CycleWithHold", + }; + val = chan->dcr >> 6; + monitor.Print(x, y++, "%d:%s", val, dcr_xrm[val]); + + // DCR:DTYP + static const char * const dcr_dtyp[] = { + //1234567890123 + "68000", + "6800", + "ACK", + "ACK+READY", + }; + val = (chan->dcr >> 4) & 3; + monitor.Print(x, y++, "%d:%s", val, dcr_dtyp[val]); + + // DCR:DPS + static const char * const dcr_dps[] = { + //1234567890123 + "8bit", + "16bit", + }; + val = (chan->dcr >> 3) & 1; + monitor.Print(x, y++, "%d:%s", val, dcr_dps[val]); + + // DCR:PCL + monitor.Print(x, y++, "XXX PCL"); + + // OCR:DIR + static const char * const ocr_dir[] = { + //1234567890123 + "MemoryToDevice", + "DeviceToMemory", + }; + val = (chan->ocr >> 7); + monitor.Print(x, y++, "%d:%s", val, ocr_dir[val]); + + // OCR:SIZE + static const char * const ocr_size[] = { + //1234567890123 + "8bit", + "16bit", + "32bit", + "8bit Unpacked", + }; + val = (chan->ocr >> 4) & 3; + monitor.Print(x, y++, "%d:%s", val, ocr_size[val]); + + // OCR:CHAIN + static const char * const ocr_chain[] = { + //1234567890123 + "NoChain", + "undefined", + "ArrayChain", + "LinkArrayChain", + }; + val = (chan->ocr >> 2) & 3; + monitor.Print(x, y++, "%d:%s", val, ocr_chain[val]); + + // OCR:REQG + static const char * const ocr_reqg[] = { + //1234567890123 + "AutoReq(Limit)", + "AutoReq(Max)", + "ExternalReq", + "AutoThenExt", + }; + val = (chan->ocr & 3); + monitor.Print(x, y++, "%d:%s", val, ocr_reqg[val]); + + // SCR:MAC + static const char * const scr_xac[] = { + //1234567890123 + "NoCount", + "CountUp", + "CountDown", + "undefined", + }; + val = (chan->scr >> 2) & 3; + monitor.Print(x, y++, "%d:%s", val, scr_xac[val]); + val = chan->scr & 3; + monitor.Print(x, y++, "%d:%s", val, scr_xac[val]); + + // CCR + val = chan->PeekCCR(); + monitor.Print(x, y++, "$%02x", val); + static const char * const ccrnames[] = { + "STR", "CNT", "HLT", "SAB", "INT", "---", "---", "---", + }; + MonitorReg4(x, y++, (val >> 4), &ccrnames[0]); + MonitorReg4(x, y++, (val & 0xff), &ccrnames[4]); + + // MTC + monitor.Print(x, y++, "$%04x", chan->mtc); + // MAR + // X680x0 がターゲットなので24bit超える設定は目立たせる + if (chan->mar > 0xffffff) { + monitor.Print(x, y++, TA::On, "$%08x", chan->mar); + } else { + monitor.Print(x, y++, "$%06x", chan->mar); + } + // DAR + if (chan->dar > 0xffffff) { + monitor.Print(x, y++, TA::On, "$%08x", chan->dar); + } else { + monitor.Print(x, y++, "$%06x", chan->dar); + } + // BTC + monitor.Print(x, y++, "$%04x", chan->btc); + // BAR + if (chan->bar > 0xffffff) { + monitor.Print(x, y++, TA::On, "$%08x", chan->bar); + } else { + monitor.Print(x, y++, "$%06x", chan->bar); + } + + // NIV + monitor.Print(x, y++, "$%02x", chan->niv); + // EIV + monitor.Print(x, y++, "$%02x", chan->eiv); + + // MFC + monitor.Print(x, y++, "$%02x", chan->mfc); + // CPR + monitor.Print(x, y++, "$%02x", chan->cpr); + // DFC + monitor.Print(x, y++, "$%02x", chan->dfc); + // BFC + monitor.Print(x, y++, "$%02x", chan->bfc); + + if (ch == 3) { + monitor.Print(x - 5, y++, "GCR: $%02x", dmac.gcr); + } + } + + return true; +} + +// 4ビット分を表示する。MonitorUpdate の下請け +void +DMACDevice::MonitorReg4(int x, int y, uint32 reg, const char * const *names) +{ + for (int i = 0; i < 4; i++) { + bool b = reg & (1 << (3 - i)); + uint attr = b ? TA::On : TA::Off; + monitor.Print(x + i * 4, y, attr, "%s", names[i]); + } +} + +/*static*/ const char * const +DMACDevice::errnames[] = { + //12345678901 + "", // $00 No Error + "ConfigErr", // $01 + "OperTiming", // $02 + NULL, // $03 + NULL, // $04 + "AddrErrInMAR", // $05 + "AddrErrInDAR", // $06 + "AddrErrInBAR", // $07 + NULL, // $08 + "BusErrInMAR", // $09 + "BusErrInDAR", // $0a + "BusErrInBAR", // $0b + NULL, // $0c + "CntErrInMTC", // $0d + NULL, // $0e + "CntErrInBTC", // $0f + "ExternAbort", // $10 + "SoftAbort", // $11 +}; + +// Read と Peek とそれ以外からも呼ばれるので副作用を持たせてはいけない。 +uint8 +DMAC::Channel::PeekCSR() const +{ + uint32 val; + + val = csr & 0xf0; + if (active) { + val |= CSR_ACT; + } + // PCT は PCL が High から Low に変わるとセット + if (prev_pcl == true && pcl == false) { + val |= CSR_PCT; + } + if (pcl) { + val |= CSR_PCS; + } + return val; +} + void -DMACDevice::write_csr(int ch, uint32 data) +DMAC::Channel::WriteCSR(uint32 data) { - putlog(1, "write_csr[%d] <- $%02x 未実装書き込み", ch, data); + // 上位4ビットは %1 の書き込みでクリア + csr &= ~(data & 0xf0); + + // PCT も %1 の書き込みでクリア + // PCT は PCL が High → Low の時セットなので prev_pcl を下げればよい + if ((data & DMAC::CSR_PCT)) { + prev_pcl = false; + } + + parent->putlog(4, "#%d CSR <- $%02x (CSR = $%02x)", ch, data, PeekCSR()); +} + +// Read と Peek から呼ばれるので副作用を持たせてはいけない。 +uint8 +DMAC::Channel::PeekCCR() const +{ + uint32 val; + + val = ccr & 0xf0; + if (int_enable) { + val |= DMAC::CCR_INT; + } + return val; } void -DMACDevice::write_ccr(int ch, uint32 data) +DMAC::Channel::WriteCCR(uint32 data) { - putlog(1, "write_ccr[%d] <- $%02x 未実装書き込み", ch, data); + // 割り込み許可ビットは常に反映 + int_enable = (data & DMAC::CCR_INT); + + // SAB (Software Abort) + if ((data & DMAC::CCR_SAB)) { + // イベントを触るため親デバイスで処理する + parent->AbortTransfer(this); + } + + // HLT (Halt Operation) + if ((data & DMAC::CCR_HLT)) { + parent->putlog(0, "CCR HLT 未実装"); + } + + // CNT (Continue Operation) + if ((data & DMAC::CCR_CNT)) { + parent->putlog(0, "CCR CNT 未実装"); + } + + // STR (Start Operation) + if ((data & DMAC::CCR_STR)) { + StartTransfer(); + } } +// 割り込み要因ビットをセットし、必要なら割り込みを上げる。 +// PCL は割り込み条件を満たしている時だけ呼ぶこと。 +// ここはレジスタに対する書き込みではない。 +void +DMAC::Channel::SetINT(uint32 val) +{ + int vector; + + csr |= val; + + // ERR ビットが立つと SAB をクリアする + if ((csr & CSR_ERR)) { + ccr &= ~CCR_SAB; + } + + if (int_enable) { + if ((csr & CSR_ERR)) { + vector = eiv; + } else { + vector = niv; + } + gMPU680x0->Interrupt(3, vector); + } +} + +// 転送開始 +void +DMAC::Channel::StartTransfer() +{ + // CSR の COC,BTC,NDT,ERR が立ってたら開始しない + if ((csr & 0xf0) != 0) { + cer = CER_CONFIG; // ? + csr |= CSR_ERR; + return; + } + + active = true; + + // XXX CER をどこかでクリアしないといけないようだがどこだ? + cer = 0; + + // 転送方法は DPS(1bit) と SIZE(2bit) で合計 8通り。 + // (その中にさらに転送方向が2通りずつあるけど) + // + // xfertype DPS SIZE + // 0 8bit 8bit packed + // 1 8bit 16bit + // 2 8bit 32bit + // 3 8bit 8bit + // 4 16bit 8bit packed + // 5 16bit 16bit + // 6 16bit 32bit + // 7 16bit 8bit + xfertype = (GetDPS() << 2) | GetSIZE(); + + // 転送モード + switch (GetREQG()) { + case DMAC::OCR_REQG_AUTO_LIM: + PANIC("REQG_AUTO_LIM 未実装"); + break; + + case DMAC::OCR_REQG_AUTO_MAX: + // 自発的に転送を開始する + parent->Transfer(ch); + break; + + case DMAC::OCR_REQG_EXTERNAL: + case DMAC::OCR_REQG_AUTOFIRST: + PANIC("未実装 REQG"); + break; + + default: + __unreachable(); + } +} + +// 転送 +// (イベントを持つのでこれはデバイスクラスのメソッド) +void +DMACDevice::Transfer(int ch) +{ + DMAC::Channel *chan = &dmac.chan[ch]; + int64 rv; + + putlog(4, "#%d Transfer (MTC=$%04x)", ch, chan->mtc); + + rv = 0; + switch (chan->xfertype) { + case 0: // 8ビットポート、8ビットサイズ、パック動作 + + case 1: // 8ビットポート、16ビットサイズ + + case 2: // 8ビットポート、32ビットサイズ + PANIC("未実装 xfer type"); + + case 3: // 8ビットポート、8ビットサイズ、パックなし動作 + if (chan->GetDIR() == DMAC::OCR_DIR_MtoD) { + rv = TransferM8toD8(chan); + } else { + rv = TransferD8toM8(chan); + } + break; + + case 4: // 16ビットポート、8ビットサイズ、パック動作 + case 5: // 16ビットポート、16ビットサイズ + case 6: // 16ビットポート、32ビットサイズ + case 7: // 16ビットポート、8ビットサイズ、パックなし動作 + PANIC("未実装 xfer type"); + } + + // XXX バスエラーは? + if (rv < 0) { + return; + } + + // バスエラーでなければカウンタを更新 + // XXX とりあえず。後で書く + switch (chan->GetMAC()) { + case DMAC::SCR_COUNT_UP: + chan->mar += 1; + break; + case DMAC::SCR_COUNT_DOWN: + chan->mar -= 1; + break; + } + switch (chan->GetDAC()) { + case DMAC::SCR_COUNT_UP: + chan->dar += 1; + break; + case DMAC::SCR_COUNT_DOWN: + chan->dar -= 1; + break; + } + + chan->mtc--; + if (chan->mtc == 0) { + // 転送完了 + chan->active = false; + chan->SetINT(DMAC::CSR_COC); + } else { + // 次回の転送 + // XXX とりあえず 1us で1回の転送にする + event[ch].time = 1_usec; + event[ch].Start(); + } +} + +// メモリから 8ビットデバイスへ (パックなし動作) +int64 +DMACDevice::TransferM8toD8(DMAC::Channel *chan) +{ + uint64 data; + int64 rv; + + data = vm_phys_read_8(chan->mar); + if ((int64)data < 0) + return data; + rv = vm_phys_write_8(chan->dar, data); + if (rv < 0) + return rv; + + return 0; +} + +// 8ビットデバイスからメモリへ (パックなし動作) +int64 +DMACDevice::TransferD8toM8(DMAC::Channel *chan) +{ + uint64 data; + int64 rv; + + data = vm_phys_read_8(chan->dar); + if ((int64)data < 0) + return data; + rv = vm_phys_write_8(chan->mar, data); + if (rv < 0) + return rv; + + return 0; +} + +// ソフトウェアアボート +// (イベントを持つのでこれはデバイスクラスのメソッド) +void +DMACDevice::AbortTransfer(DMAC::Channel *chan) +{ + int ch = chan->ch; + + putlog(2, "CCR SAB ソフトウェアアボート"); + + // %1 を書き込むことで実際には SAB はセットされるが、ERR が立つと + // SAB をクリアする動作のため、書き込んだ %1 が読めることはない。 + // ここでは SAB ビットのセットを省略。 + + event[ch].Stop(); + chan->active = false; + chan->cer = DMAC::CER_SOFT_ABORT; + chan->SetINT(DMAC::CSR_ERR); +}