Initial implementation for VIA-CUDA device.

This commit is contained in:
Maxim Poliakovski 2019-08-27 14:14:12 +02:00
parent 3131325bff
commit 5fc7ca761e
9 changed files with 258 additions and 211 deletions

View File

@ -1,9 +1,23 @@
#include <cinttypes>
#include <iostream>
#include "macio.h"
#include "viacuda.h"
using namespace std;
HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
{
this->viacuda = new ViaCuda();
assert(this->viacuda); // FIXME: do proper exception handling!
}
HeathrowIC::~HeathrowIC()
{
if (this->viacuda)
delete(this->viacuda);
}
uint32_t HeathrowIC::pci_cfg_read(uint32_t reg_offs, uint32_t size)
{
return this->pci_cfg_hdr[reg_offs & 0xFF];
@ -23,7 +37,7 @@ void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
cout << this->name << " err: BAR0 64-bit I/O space not supported!"
<< endl;
} else {
this->base_addr = value & 0xFFFFFFF0;
this->base_addr = value & 0xFFF80000;
this->host_instance->pci_register_mmio_region(this->base_addr, 0x80000, this);
cout << this->name << " base address set to " << hex << this->base_addr
<< endl;
@ -34,11 +48,100 @@ void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
uint32_t HeathrowIC::read(uint32_t offset, int size)
{
uint32_t res = 0;
cout << this->name << ": reading from offset " << hex << offset << endl;
return 0;
unsigned sub_dev = (offset >> 12) & 0x3F;
switch(sub_dev) {
case 0:
res = mio_ctrl_read(offset, size);
break;
case 8:
cout << "DMA channel register space" << endl;
break;
case 0x14:
cout << "AWACS-Screamer register space" << endl;
break;
case 0x16:
case 0x17:
res = this->viacuda->read((offset - 0x16000) >> 9);
break;
default:
cout << "unmapped I/O space" << endl;
}
return res;
}
void HeathrowIC::write(uint32_t offset, uint32_t value, int size)
{
cout << this->name << ": writing to offset " << hex << offset << endl;
unsigned sub_dev = (offset >> 12) & 0x3F;
switch(sub_dev) {
case 0:
mio_ctrl_write(offset, value, size);
break;
case 8:
cout << "DMA channel register space" << endl;
break;
case 0x14:
cout << "AWACS-Screamer register space" << endl;
break;
case 0x16:
case 0x17:
this->viacuda->write((offset - 0x16000) >> 9, value);
break;
default:
cout << "unmapped I/O space" << endl;
}
}
uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size)
{
uint32_t res = 0;
switch(offset & 0xFF) {
case 0x24:
cout << "read from MIO:Int_Mask1 register" << endl;
res = this->int_mask1;
break;
case 0x28:
cout << "read from MIO:Int_Clear1 register" << endl;
res = this->int_clear1;
break;
case 0x38:
cout << "read from MIO:Feat_Ctrl register" << endl;
res = this->feat_ctrl;
break;
default:
cout << "unknown MIO register at " << hex << offset << endl;
break;
}
return res;
}
void HeathrowIC::mio_ctrl_write(uint32_t offset, uint32_t value, int size)
{
switch(offset & 0xFF) {
case 0x24:
cout << "write " << hex << value << " to MIO:Int_Mask1 register" << endl;
this->int_mask1 = value;
break;
case 0x28:
cout << "write " << hex << value << " to MIO:Int_Clear1 register" << endl;
this->int_clear1 = value;
break;
case 0x38:
cout << "write " << hex << value << " to MIO:Feat_Ctrl register" << endl;
this->feat_ctrl = value;
break;
default:
cout << "unknown MIO register at " << hex << offset << endl;
break;
}
}

View File

@ -35,6 +35,7 @@
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "pcihost.h"
#include "viacuda.h"
/**
Heathrow ASIC emulation
@ -65,8 +66,8 @@ class HeathrowIC : public PCIDevice
public:
using PCIDevice::name;
HeathrowIC() : PCIDevice("mac-io/heathrow") {};
~HeathrowIC() = default;
HeathrowIC();
~HeathrowIC();
void set_host(PCIHost *host_instance) {this->host_instance = host_instance;};
@ -78,6 +79,10 @@ public:
uint32_t read(uint32_t offset, int size);
void write(uint32_t offset, uint32_t value, int size);
protected:
uint32_t mio_ctrl_read(uint32_t offset, int size);
void mio_ctrl_write(uint32_t offset, uint32_t value, int size);
private:
uint8_t pci_cfg_hdr[256] = {
0x6B, 0x10, // vendor ID: Apple Computer Inc.
@ -92,6 +97,13 @@ private:
0x00, 0x00, // unknown defaults
0x00, 0x00 // unknown defaults
};
uint32_t int_mask1;
uint32_t int_clear1;
uint32_t feat_ctrl; // features control register
/* device cells */
ViaCuda *viacuda; /* VIA cell with Cuda MCU attached to it */
};
#endif /* MACIO_H */

89
devices/viacuda.cpp Normal file
View File

@ -0,0 +1,89 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
//Functionality for the VIA CUDA
#include <iostream>
#include <cinttypes>
#include <vector>
#include "viacuda.h"
using namespace std;
ViaCuda::ViaCuda()
{
this->via_regs[VIA_A] = 0x80;
this->via_regs[VIA_DIRB] = 0xFF;
this->via_regs[VIA_DIRA] = 0xFF;
this->via_regs[VIA_T1LL] = 0xFF;
this->via_regs[VIA_T1LH] = 0xFF;
this->via_regs[VIA_IER] = 0x7F;
}
uint8_t ViaCuda::read(int reg)
{
uint8_t res;
cout << "Read VIA reg " << hex << (uint32_t)reg << endl;
res = this->via_regs[reg & 0xF];
/* reading from some VIA registers triggers special actions */
switch(reg & 0xF) {
case VIA_IER:
res |= 0x80; /* bit 7 always reads as "1" */
}
return res;
}
void ViaCuda::write(int reg, uint8_t value)
{
switch(reg & 0xF) {
case VIA_B:
cout << "VIA_B = " << hex << (uint32_t)value << endl;
break;
case VIA_A:
cout << "VIA_A = " << hex << (uint32_t)value << endl;
break;
case VIA_DIRB:
cout << "VIA_DIRB = " << hex << (uint32_t)value << endl;
break;
case VIA_DIRA:
cout << "VIA_DIRA = " << hex << (uint32_t)value << endl;
break;
case VIA_PCR:
cout << "VIA_PCR = " << hex << (uint32_t)value << endl;
break;
case VIA_ACR:
cout << "VIA_ACR = " << hex << (uint32_t)value << endl;
break;
case VIA_IER:
this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F
: this->via_regs[VIA_IER] & ~value;
cout << "VIA_IER updated to " << hex << (uint32_t)this->via_regs[VIA_IER]
<< endl;
print_enabled_ints();
break;
case VIA_ANH:
cout << "VIA_ANH = " << hex << (uint32_t)value << endl;
break;
default:
this->via_regs[reg & 0xF] = value;
}
}
void ViaCuda::print_enabled_ints()
{
vector<string> via_int_src = {"CA2", "CA1", "SR", "CB2", "CB1", "T2", "T1"};
for (int i = 0; i < 7; i++) {
if (this->via_regs[VIA_IER] & (1 << i))
cout << "VIA " << via_int_src[i] << " interrupt enabled." << endl;
}
}

46
devices/viacuda.h Normal file
View File

@ -0,0 +1,46 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
#ifndef VIACUDA_H
#define VIACUDA_H
/** VIA register offsets. */
enum {
VIA_B = 0x00, /* input/output register B */
VIA_A = 0x01, /* input/output register A */
VIA_DIRB = 0x02, /* direction B */
VIA_DIRA = 0x03, /* direction A */
VIA_T1CL = 0x04, /* low-order timer 1 counter */
VIA_T1CH = 0x05, /* high-order timer 1 counter */
VIA_T1LL = 0x06, /* low-order timer 1 latches */
VIA_T1LH = 0x07, /* high-order timer 1 latches */
VIA_T2CL = 0x08, /* low-order timer 2 latches */
VIA_T2CH = 0x09, /* high-order timer 2 counter */
VIA_SR = 0x0A, /* shift register */
VIA_ACR = 0x0B, /* auxiliary control register */
VIA_PCR = 0x0C, /* periheral control register */
VIA_IFR = 0x0D, /* interrupt flag register */
VIA_IER = 0x0E, /* interrupt enable register */
VIA_ANH = 0x0F, /* input/output register A, no handshake */
};
class ViaCuda
{
public:
ViaCuda();
~ViaCuda() = default;
uint8_t read(int reg);
void write(int reg, uint8_t value);
private:
uint8_t via_regs[16]; /* VIA virtual registers */
void print_enabled_ints(); /* print enabled VIA interrupts and their sources */
};
#endif /* VIACUDA_H */

View File

@ -22,7 +22,6 @@
#include "macioserial.h"
#include "macswim3.h"
#include "ppcmemory.h"
#include "viacuda.h"
#include "devices/mpc106.h"
#include "openpic.h"
#include "debugger.h"

View File

@ -14,7 +14,6 @@
#include <array>
#include <thread>
#include <atomic>
#include "viacuda.h"
#include "macioserial.h"
#include "macswim3.h"
#include "ppcemumain.h"

View File

@ -1115,7 +1115,7 @@ void ppc_divwdot(){
void ppc_divwo(){
ppc_grab_regsdab();
//handle division by zero cases
switch (ppc_result_b){
case 0:
@ -1889,15 +1889,15 @@ void ppc_twi(){
}
void ppc_eieio(){
std::cout << "Oops. Placeholder for eieio." << std::endl;
//std::cout << "Oops. Placeholder for eieio." << std::endl;
}
void ppc_isync(){
std::cout << "Oops. Placeholder for isync." << std::endl;
//std::cout << "Oops. Placeholder for isync." << std::endl;
}
void ppc_sync(){
std::cout << "Oops. Placeholder for sync." << std::endl;
//std::cout << "Oops. Placeholder for sync." << std::endl;
}
void ppc_icbi(){

View File

@ -1,153 +0,0 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
//Functionality for the VIA CUDA
#include <iostream>
#include <cinttypes>
#include "viacuda.h"
#include "ppcemumain.h"
uint32_t via_cuda_address;
uint32_t via_set_mode;
uint8_t via_opcode_store_bit;
uint8_t via_write_byte;
uint8_t via_read_byte;
unsigned char porta_ca1, porta_ca2 = 0;
unsigned char porta_cb1, porta_cb2 = 0;
bool via_cuda_confirm;
bool via_cuda_signal_read;
bool via_cuda_signal_write;
void via_ifr_update(){
if ((machine_iocontrolmem_mem[VIACUDA_IFR] & 127) && (machine_iocontrolmem_mem[VIACUDA_IER] & 127)){
machine_iocontrolmem_mem[VIACUDA_IFR] |= 128;
}
else{
machine_iocontrolmem_mem[VIACUDA_IFR] &= 127;
}
}
void via_t1_update(){
if (machine_iocontrolmem_mem[VIACUDA_T1CH] > 0){
machine_iocontrolmem_mem[VIACUDA_T1CH]--;
}
else{
machine_iocontrolmem_mem[VIACUDA_T1CH] = machine_iocontrolmem_mem[VIACUDA_T1LH];
}
if (machine_iocontrolmem_mem[VIACUDA_T1CL] > 0){
machine_iocontrolmem_mem[VIACUDA_T1CL]--;
}
else{
machine_iocontrolmem_mem[VIACUDA_T1CL] = machine_iocontrolmem_mem[VIACUDA_T1LL];
}
}
void via_cuda_init(){
machine_iocontrolmem_mem[VIACUDA_A] = 0x80;
machine_iocontrolmem_mem[VIACUDA_DIRB] = 0xFF;
machine_iocontrolmem_mem[VIACUDA_DIRA] = 0xFF;
machine_iocontrolmem_mem[VIACUDA_T1LL] = 0xFF;
machine_iocontrolmem_mem[VIACUDA_T1LH] = 0xFF;
machine_iocontrolmem_mem[VIACUDA_IER] = 0x7F;
}
void via_cuda_read(){
switch(via_cuda_address){
case VIACUDA_B:
if (machine_iocontrolmem_mem[VIACUDA_DIRB] != 0){
via_read_byte = (via_write_byte & ~machine_iocontrolmem_mem[VIACUDA_DIRB]) | (machine_iocontrolmem_mem[VIACUDA_B] & machine_iocontrolmem_mem[VIACUDA_DIRB]);
break;
}
case VIACUDA_A:
machine_iocontrolmem_mem[VIACUDA_IFR] = ~porta_ca1;
via_read_byte = (machine_iocontrolmem_mem[VIACUDA_A] & ~machine_iocontrolmem_mem[VIACUDA_DIRA]) | (machine_iocontrolmem_mem[VIACUDA_A] & machine_iocontrolmem_mem[VIACUDA_DIRA]);
break;
case VIACUDA_IER:
via_read_byte = machine_iocontrolmem_mem[VIACUDA_IER] | 0x80;
break;
case VIACUDA_ANH:
via_read_byte = machine_iocontrolmem_mem[VIACUDA_A] & ~machine_iocontrolmem_mem[VIACUDA_DIRA];
break;
default:
via_read_byte = machine_iocontrolmem_mem[via_cuda_address];
}
via_read_byte = machine_iocontrolmem_mem[via_cuda_address];
}
void via_cuda_write(){
switch(via_cuda_address){
case VIACUDA_B:
machine_iocontrolmem_mem[VIACUDA_B] = via_write_byte & machine_iocontrolmem_mem[VIACUDA_DIRB];
break;
case VIACUDA_A:
machine_iocontrolmem_mem[VIACUDA_IFR] = ~porta_ca1;
if ((machine_iocontrolmem_mem[VIACUDA_PCR] & 0x0A) != 0x02){
machine_iocontrolmem_mem[VIACUDA_IFR] = ~porta_ca2;
}
via_ifr_update();
machine_iocontrolmem_mem[VIACUDA_A] = (via_write_byte & machine_iocontrolmem_mem[VIACUDA_DIRA]) | (~machine_iocontrolmem_mem[VIACUDA_DIRA]);
break;
case VIACUDA_DIRB:
machine_iocontrolmem_mem[VIACUDA_DIRB] = via_write_byte;
break;
case VIACUDA_DIRA:
machine_iocontrolmem_mem[VIACUDA_DIRA] = via_write_byte;
break;
case VIACUDA_T1LL:
case VIACUDA_T1LH:
via_t1_update();
machine_iocontrolmem_mem[via_cuda_address] = via_write_byte;
break;
case VIACUDA_T2CH:
via_t1_update();
machine_iocontrolmem_mem[VIACUDA_T2CH] = via_write_byte;
break;
case VIACUDA_PCR:
machine_iocontrolmem_mem[VIACUDA_PCR] = via_write_byte;
if ((via_write_byte & 0x0E) == 0x0C){
porta_ca2 = 0;
}
else if ((via_write_byte & 0x08)){
porta_ca2 = 1;
}
if ((via_write_byte & 0xE0) == 0xC0){
porta_cb2 = 0;
}
if ((via_write_byte & 0x80)){
porta_cb2 = 1;
}
break;
case VIACUDA_IFR:
if (via_write_byte & 0x80){
machine_iocontrolmem_mem[VIACUDA_IFR] &= (via_write_byte & 0x7F);
}
else{
machine_iocontrolmem_mem[VIACUDA_IFR] &= ~(via_write_byte & 0x7F);
}
via_ifr_update();
break;
case VIACUDA_IER:
machine_iocontrolmem_mem[VIACUDA_IER] &= ~(via_write_byte & 0x7F);
via_ifr_update();
break;
case VIACUDA_ANH:
machine_iocontrolmem_mem[VIACUDA_A] = (via_write_byte & machine_iocontrolmem_mem[VIACUDA_DIRA]) | (~machine_iocontrolmem_mem[VIACUDA_DIRA]);
break;
default:
machine_iocontrolmem_mem[via_cuda_address] = via_write_byte;
}
machine_iocontrolmem_mem[via_cuda_address] = via_write_byte;
}

View File

@ -1,48 +0,0 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
#ifndef VIACUDA_H_
#define VIACUDA_H_
#define VIACUDA_B 0x3016000 /* B-side data */
#define VIACUDA_A 0x3016200 /* A-side data */
#define VIACUDA_DIRB 0x3016400 /* B-side direction (1=output) */
#define VIACUDA_DIRA 0x3016600 /* A-side direction (1=output) */
#define VIACUDA_T1CL 0x3016800 /* Timer 1 ctr/latch (low 8 bits) */
#define VIACUDA_T1CH 0x3016A00 /* Timer 1 counter (high 8 bits) */
#define VIACUDA_T1LL 0x3016C00 /* Timer 1 latch (low 8 bits) */
#define VIACUDA_T1LH 0x3016E00 /* Timer 1 latch (high 8 bits) */
#define VIACUDA_T2CL 0x3017000 /* Timer 2 ctr/latch (low 8 bits) */
#define VIACUDA_T2CH 0x3017200 /* Timer 2 counter (high 8 bits) */
#define VIACUDA_SR 0x3017400 /* Shift register */
#define VIACUDA_ACR 0x3017600 /* Auxiliary control register */
#define VIACUDA_PCR 0x3017800 /* Peripheral control register */
#define VIACUDA_IFR 0x3017A00 /* Interrupt flag register */
#define VIACUDA_IER 0x3017C00 /* Interrupt enable register */
#define VIACUDA_ANH 0x3017E00 /* A-side data, no handshake */
extern uint32_t via_cuda_address;
extern uint8_t via_opcode_store_bit;
extern uint8_t via_write_byte;
extern uint8_t via_read_byte;
extern bool via_cuda_confirm;
extern bool via_cuda_signal_read;
extern bool via_cuda_signal_write;
extern unsigned char porta_ca1, porta_ca2;
extern unsigned char porta_cb1, porta_cb2;
extern uint32_t via_set_mode;
extern void via_ifr_update();
extern void via_t1_update();
extern void via_cuda_init();
extern void via_cuda_read();
extern void via_cuda_write();
#endif // VIACUDA_H