mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 05:29:43 +00:00
Implement DBDMA channel registers.
This commit is contained in:
parent
751efb4cd6
commit
787ebfaff1
139
devices/dbdma.cpp
Normal file
139
devices/dbdma.cpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||||
|
Copyright (C) 2018-20 divingkatae and maximum
|
||||||
|
(theweirdo) spatium
|
||||||
|
|
||||||
|
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file Descriptor-based direct memory access emulation. */
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <thirdparty/loguru.hpp>
|
||||||
|
#include "dbdma.h"
|
||||||
|
#include "endianswap.h"
|
||||||
|
|
||||||
|
uint32_t DMAChannel::reg_read(uint32_t offset, int size)
|
||||||
|
{
|
||||||
|
uint32_t res = 0;
|
||||||
|
|
||||||
|
if (size != 4) {
|
||||||
|
LOG_F(WARNING, "Unsupported non-DWORD read from DMA channel");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(offset) {
|
||||||
|
case DMAReg::CH_CTRL:
|
||||||
|
res = 0; /* ChannelControl reads as 0 (DBDMA spec 5.5.1, table 74) */
|
||||||
|
break;
|
||||||
|
case DMAReg::CH_STAT:
|
||||||
|
res = BYTESWAP_32(this->ch_stat);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_F(WARNING, "Unsupported DMA channel register 0x%X", offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size)
|
||||||
|
{
|
||||||
|
uint16_t mask, old_stat, new_stat;
|
||||||
|
|
||||||
|
if (size != 4) {
|
||||||
|
LOG_F(WARNING, "Unsupported non-DWORD write to DMA channel");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = BYTESWAP_32(value);
|
||||||
|
old_stat = this->ch_stat;
|
||||||
|
|
||||||
|
switch(offset) {
|
||||||
|
case DMAReg::CH_CTRL:
|
||||||
|
mask = value >> 16;
|
||||||
|
new_stat = (value & mask & 0xF0FFU) | (old_stat & ~mask);
|
||||||
|
LOG_F(INFO, "New ChannelStatus value = 0x%X", new_stat);
|
||||||
|
|
||||||
|
if ((new_stat & CH_STAT_RUN) != (old_stat & CH_STAT_RUN)) {
|
||||||
|
if (new_stat & CH_STAT_RUN) {
|
||||||
|
new_stat |= CH_STAT_ACTIVE;
|
||||||
|
this->ch_stat = new_stat;
|
||||||
|
this->start();
|
||||||
|
} else {
|
||||||
|
new_stat &= ~CH_STAT_ACTIVE;
|
||||||
|
new_stat &= ~CH_STAT_DEAD;
|
||||||
|
this->ch_stat = new_stat;
|
||||||
|
this->abort();
|
||||||
|
}
|
||||||
|
} else if ((new_stat & CH_STAT_WAKE) != (old_stat & CH_STAT_WAKE)) {
|
||||||
|
new_stat |= CH_STAT_ACTIVE;
|
||||||
|
this->ch_stat = new_stat;
|
||||||
|
this->resume();
|
||||||
|
} else if ((new_stat & CH_STAT_PAUSE) != (old_stat & CH_STAT_PAUSE)) {
|
||||||
|
if (new_stat & CH_STAT_PAUSE) {
|
||||||
|
new_stat &= ~CH_STAT_ACTIVE;
|
||||||
|
this->ch_stat = new_stat;
|
||||||
|
this->pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (new_stat & CH_STAT_FLUSH) {
|
||||||
|
LOG_F(WARNING, "DMA flush not implemented!");
|
||||||
|
new_stat &= ~CH_STAT_FLUSH;
|
||||||
|
this->ch_stat = new_stat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DMAReg::CH_STAT:
|
||||||
|
break; /* ingore writes to ChannelStatus */
|
||||||
|
case DMAReg::CMD_PTR_LO:
|
||||||
|
if (!(this->ch_stat & CH_STAT_RUN) && !(this->ch_stat & CH_STAT_ACTIVE)) {
|
||||||
|
this->cmd_ptr = BYTESWAP_32(value);
|
||||||
|
LOG_F(INFO, "CommandPtrLo set to 0x%X", this->cmd_ptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_F(WARNING, "Unsupported DMA channel register 0x%X", offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMAChannel::start()
|
||||||
|
{
|
||||||
|
if (this->ch_stat & CH_STAT_PAUSE) {
|
||||||
|
LOG_F(WARNING, "Cannot start DMA channel, PAUSE bit is set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_F(INFO, "Starting DMA channel, stat = 0x%X", this->ch_stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMAChannel::resume()
|
||||||
|
{
|
||||||
|
if (this->ch_stat & CH_STAT_PAUSE) {
|
||||||
|
LOG_F(WARNING, "Cannot resume DMA channel, PAUSE bit is set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_F(INFO, "Resuming DMA channel");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMAChannel::abort()
|
||||||
|
{
|
||||||
|
LOG_F(INFO, "Aborting DMA channel");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DMAChannel::pause()
|
||||||
|
{
|
||||||
|
LOG_F(INFO, "Pausing DMA channel");
|
||||||
|
}
|
70
devices/dbdma.h
Normal file
70
devices/dbdma.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||||
|
Copyright (C) 2018-20 divingkatae and maximum
|
||||||
|
(theweirdo) spatium
|
||||||
|
|
||||||
|
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file Descriptor-based direct memory access emulation.
|
||||||
|
|
||||||
|
Official documentation can be found in the fifth chapter of the book
|
||||||
|
"Macintosh Technology in the Common Hardware Reference Platform"
|
||||||
|
by Apple Computer, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DB_DMA_H
|
||||||
|
#define DB_DMA_H
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
/** DBDMA Channel registers offsets */
|
||||||
|
enum DMAReg : uint32_t {
|
||||||
|
CH_CTRL = 0,
|
||||||
|
CH_STAT = 4,
|
||||||
|
CMD_PTR_LO = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Channel Status bits (DBDMA spec, 5.5.3) */
|
||||||
|
enum {
|
||||||
|
CH_STAT_ACTIVE = 0x400,
|
||||||
|
CH_STAT_DEAD = 0x800,
|
||||||
|
CH_STAT_WAKE = 0x1000,
|
||||||
|
CH_STAT_FLUSH = 0x2000,
|
||||||
|
CH_STAT_PAUSE = 0x4000,
|
||||||
|
CH_STAT_RUN = 0x8000
|
||||||
|
};
|
||||||
|
|
||||||
|
class DMAChannel {
|
||||||
|
public:
|
||||||
|
DMAChannel() = default;
|
||||||
|
~DMAChannel() = default;
|
||||||
|
|
||||||
|
uint32_t reg_read(uint32_t offset, int size);
|
||||||
|
void reg_write(uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void start(void);
|
||||||
|
void resume(void);
|
||||||
|
void abort(void);
|
||||||
|
void pause(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t ch_stat = 0;
|
||||||
|
uint32_t cmd_ptr = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DB_DMA_H */
|
@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include "macio.h"
|
#include "macio.h"
|
||||||
#include "viacuda.h"
|
#include "viacuda.h"
|
||||||
#include "awacs.h"
|
#include "awacs.h"
|
||||||
|
#include "dbdma.h"
|
||||||
#include "machines/machinebase.h"
|
#include "machines/machinebase.h"
|
||||||
|
|
||||||
/** Heathrow Mac I/O device emulation.
|
/** Heathrow Mac I/O device emulation.
|
||||||
@ -42,6 +43,7 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
|
|||||||
gMachineObj->add_subdevice("ViaCuda", this->viacuda);
|
gMachineObj->add_subdevice("ViaCuda", this->viacuda);
|
||||||
|
|
||||||
this->screamer = new AWACDevice();
|
this->screamer = new AWACDevice();
|
||||||
|
this->snd_out_dma = new DMAChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
HeathrowIC::~HeathrowIC()
|
HeathrowIC::~HeathrowIC()
|
||||||
@ -83,6 +85,33 @@ void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t HeathrowIC::dma_read(uint32_t offset, int size)
|
||||||
|
{
|
||||||
|
uint32_t res = 0;
|
||||||
|
|
||||||
|
switch(offset >> 8) {
|
||||||
|
case 8:
|
||||||
|
res = this->snd_out_dma->reg_read(offset & 0xFF, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_F(WARNING, "Unsupported DMA channel read, offset=0x%X", offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size)
|
||||||
|
{
|
||||||
|
switch(offset >> 8) {
|
||||||
|
case 8:
|
||||||
|
this->snd_out_dma->reg_write(offset & 0xFF, value, size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_F(WARNING, "Unsupported DMA channel write, offset=0x%X, val=0x%X", offset, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t HeathrowIC::read(uint32_t offset, int size)
|
uint32_t HeathrowIC::read(uint32_t offset, int size)
|
||||||
{
|
{
|
||||||
uint32_t res = 0;
|
uint32_t res = 0;
|
||||||
@ -96,7 +125,7 @@ uint32_t HeathrowIC::read(uint32_t offset, int size)
|
|||||||
res = mio_ctrl_read(offset, size);
|
res = mio_ctrl_read(offset, size);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
LOG_F(WARNING, "Attempting to read DMA channel register space \n");
|
res = dma_read(offset - 0x8000, size);
|
||||||
break;
|
break;
|
||||||
case 0x14:
|
case 0x14:
|
||||||
res = this->screamer->snd_ctrl_read(offset - 0x14000, size);
|
res = this->screamer->snd_ctrl_read(offset - 0x14000, size);
|
||||||
@ -128,7 +157,7 @@ void HeathrowIC::write(uint32_t offset, uint32_t value, int size)
|
|||||||
mio_ctrl_write(offset, value, size);
|
mio_ctrl_write(offset, value, size);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
LOG_F(WARNING, "Attempting to write to DMA channel register space \n");
|
dma_write(offset - 0x8000, value, size);
|
||||||
break;
|
break;
|
||||||
case 0x14:
|
case 0x14:
|
||||||
this->screamer->snd_ctrl_write(offset - 0x14000, value, size);
|
this->screamer->snd_ctrl_write(offset - 0x14000, value, size);
|
||||||
|
@ -60,6 +60,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include "viacuda.h"
|
#include "viacuda.h"
|
||||||
#include "nvram.h"
|
#include "nvram.h"
|
||||||
#include "awacs.h"
|
#include "awacs.h"
|
||||||
|
#include "dbdma.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Heathrow ASIC emulation
|
Heathrow ASIC emulation
|
||||||
@ -104,6 +105,9 @@ public:
|
|||||||
void write(uint32_t offset, uint32_t value, int size);
|
void write(uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
uint32_t dma_read(uint32_t offset, int size);
|
||||||
|
void dma_write(uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
uint32_t mio_ctrl_read(uint32_t offset, int size);
|
uint32_t mio_ctrl_read(uint32_t offset, int size);
|
||||||
void mio_ctrl_write(uint32_t offset, uint32_t value, int size);
|
void mio_ctrl_write(uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
@ -130,6 +134,8 @@ private:
|
|||||||
ViaCuda *viacuda; /* VIA cell with Cuda MCU attached to it */
|
ViaCuda *viacuda; /* VIA cell with Cuda MCU attached to it */
|
||||||
NVram *nvram; /* NVRAM cell */
|
NVram *nvram; /* NVRAM cell */
|
||||||
AWACDevice *screamer; /* Screamer audio codec instance */
|
AWACDevice *screamer; /* Screamer audio codec instance */
|
||||||
|
|
||||||
|
DMAChannel *snd_out_dma;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MACIO_H */
|
#endif /* MACIO_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user