AMIC: implement periodic VBL (60.15 Hz) interrupt.

This commit is contained in:
Maxim Poliakovski 2022-01-21 12:40:26 +01:00
parent 0899186ffc
commit 3bdc6f915a
2 changed files with 27 additions and 8 deletions

View File

@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski Author: Max Poliakovski
*/ */
#include <core/timermanager.h>
#include <cpu/ppc/ppcemu.h> #include <cpu/ppc/ppcemu.h>
#include <cpu/ppc/ppcmmu.h> #include <cpu/ppc/ppcmmu.h>
#include <devices/common/scsi/ncr53c94.h> #include <devices/common/scsi/ncr53c94.h>
@ -46,19 +47,12 @@ AMIC::AMIC() : MMIODevice()
{ {
this->name = "Apple Memory-mapped I/O Controller"; this->name = "Apple Memory-mapped I/O Controller";
MemCtrlBase *mem_ctrl = dynamic_cast<MemCtrlBase *>
(gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
/* add memory mapped I/O region for the AMIC control registers */
if (!mem_ctrl->add_mmio_region(0x50F00000, 0x00040000, this)) {
LOG_F(ERROR, "Couldn't register AMIC registers!");
}
// register I/O devices // register I/O devices
this->scsi = std::unique_ptr<Ncr53C94> (new Ncr53C94()); this->scsi = std::unique_ptr<Ncr53C94> (new Ncr53C94());
this->escc = std::unique_ptr<EsccController> (new EsccController()); this->escc = std::unique_ptr<EsccController> (new EsccController());
this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID)); this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID));
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda()); this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda());
gMachineObj->add_subdevice("ViaCuda", this->viacuda.get());
// initialize sound HW // initialize sound HW
this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma()); this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma());
@ -73,6 +67,26 @@ AMIC::AMIC() : MMIODevice()
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl()); this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl());
} }
int AMIC::device_postinit()
{
MemCtrlBase *mem_ctrl = dynamic_cast<MemCtrlBase *>
(gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
// add memory mapped I/O region for the AMIC control registers
if (!mem_ctrl->add_mmio_region(0x50F00000, 0x00040000, this)) {
LOG_F(ERROR, "Couldn't register AMIC registers!");
}
// AMIC drives the VIA CA1 internally to generate 60.15 Hz interrupts
this->pseudo_vbl_tid = TimerManager::get_instance()->add_cyclic_timer(
static_cast<uint64_t>((1.0f/60.15) * NS_PER_SEC + 0.5f),
[this]() {
this->viacuda->assert_ctrl_line(ViaLine::CA1);
});
return 0;
}
uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size)
{ {
uint32_t phase_val; uint32_t phase_val;

View File

@ -142,10 +142,13 @@ public:
AMIC(); AMIC();
~AMIC() = default; ~AMIC() = default;
// HWComponent methods
bool supports_type(HWCompType type) { bool supports_type(HWCompType type) {
return (type == HWCompType::MMIO_DEV) || (type == HWCompType::INT_CTRL); return (type == HWCompType::MMIO_DEV) || (type == HWCompType::INT_CTRL);
}; };
int device_postinit();
/* MMIODevice methods */ /* MMIODevice methods */
uint32_t read(uint32_t reg_start, uint32_t offset, int size); uint32_t read(uint32_t reg_start, uint32_t offset, int size);
void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size); void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size);
@ -168,6 +171,8 @@ private:
uint8_t int_ctrl = 0; uint8_t int_ctrl = 0;
uint8_t dev_irq_lines = 0; // state of the IRQ lines uint8_t dev_irq_lines = 0; // state of the IRQ lines
uint32_t pseudo_vbl_tid; // ID for the pseudo-VBL timer
// AMIC subdevices instances // AMIC subdevices instances
std::unique_ptr<Ncr53C94> scsi; std::unique_ptr<Ncr53C94> scsi;
std::unique_ptr<EsccController> escc; std::unique_ptr<EsccController> escc;