Merge branch 'devices' into 'master'.

This commit is contained in:
Maxim Poliakovski 2019-10-15 11:41:00 +02:00
commit e50f4396db
32 changed files with 1544 additions and 1702 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
# Ignore compiled object files
*.o
*.d
# Ignore generated executables
dingusppc

View File

@ -1,35 +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 DAVBus (Sound Bus + Screamer?)
#include <iostream>
#include <cstring>
#include <cinttypes>
#include "ppcemumain.h"
uint32_t davbus_address;
uint32_t davbus_write_word;
uint32_t davbus_read_word;
void davbus_init(){
}
void davbus_read(){
davbus_read_word = (uint32_t)(machine_upperiocontrol_mem[davbus_address++]);
davbus_read_word = (uint32_t)((machine_upperiocontrol_mem[davbus_address++]) << 8);
davbus_read_word = (uint32_t)((machine_upperiocontrol_mem[davbus_address++]) << 16);
davbus_read_word = (uint32_t)((machine_upperiocontrol_mem[davbus_address]) << 24);
}
void davbus_write(){
machine_upperiocontrol_mem[davbus_address++] = (uint8_t)(davbus_write_word);
machine_upperiocontrol_mem[davbus_address++] = (uint8_t)((davbus_write_word) >> 8);
machine_upperiocontrol_mem[davbus_address++] = (uint8_t)((davbus_write_word) >> 16);
machine_upperiocontrol_mem[davbus_address] = (uint8_t)((davbus_write_word) >> 24);
}

View File

@ -1,22 +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 DAVBus (Sound Bus + Screamer?)
#ifndef DAVBUS_H_
#define DAVBUS_H_
extern uint32_t davbus_address;
extern uint32_t davbus_write_word;
extern uint32_t davbus_read_word;
extern void davbus_init();
extern void davbus_read();
extern void davbus_write();
#endif

155
devices/heathrow.cpp Normal file
View File

@ -0,0 +1,155 @@
#include <cinttypes>
#include <iostream>
#include "macio.h"
#include "viacuda.h"
/** Heathrow Mac I/O device emulation.
Author: Max Poliakovski 2019
*/
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];
}
void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
{
switch(reg_offs) {
case CFG_REG_BAR0: // base address register
value = LE2BE(value);
if (value == 0xFFFFFFFF) {
cout << this->name << " err: BAR0 block size determination not "
<< "implemented yet" << endl;
} else if (value & 1) {
cout << this->name << " err: BAR0 I/O space not supported!" << endl;
} else if (value & 0x06) {
cout << this->name << " err: BAR0 64-bit I/O space not supported!"
<< endl;
} else {
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;
}
break;
}
}
uint32_t HeathrowIC::read(uint32_t offset, int size)
{
uint32_t res = 0;
cout << this->name << ": reading from offset " << hex << offset << endl;
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 0x34: /* heathrowIDs / HEATHROW_MBCR (Linux): media bay config reg? */
res = 0xF0700000UL;
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;
}
}

37
devices/machineid.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef MACHINE_ID_H
#define MACHINE_ID_H
#include <cinttypes>
#include "mmiodevice.h"
/**
@file Contains definitions for PowerMacintosh machine ID registers.
The machine ID register is a memory-based register containing hardcoded
values the system software can read to identify machine/board it's running on.
Register location and value meaning are board-dependent.
*/
/**
The machine ID for the Gossamer board is accesible at 0xFF000004 (phys).
It contains a 16-bit value revealing machine's capabilities like bus speed,
ROM speed, I/O configuration etc.
Because the meaning of these bits is poorly documented, the code below
simply return raw values obtained from real hardware.
*/
class GossamerID : public MMIODevice {
public:
GossamerID(const uint16_t id) { this->id = id, this->name = "Machine-id"; };
~GossamerID() = default;
uint32_t read(uint32_t offset, int size) {
return ((!offset && size == 2) ? this->id : 0); };
void write(uint32_t offset, uint32_t value, int size) {}; /* not writable */
private:
uint16_t id;
};
#endif /* MACHINE_ID_H */

109
devices/macio.h Normal file
View File

@ -0,0 +1,109 @@
/** MacIO device family emulation
Mac I/O (MIO) is a family of ASICs to bring support for Apple legacy
I/O hardware to PCI-based Power Macintosh. That legacy hardware has
existed long before Power Macintosh was introduced. It includes:
- versatile interface adapter (VIA)
- Sander-Woz integrated machine (SWIM) that is a floppy disk controller
- CUDA MCU for ADB, parameter RAM, realtime clock and power management support
- serial communication controller (SCC)
- Macintosh Enhanced SCSI Hardware (MESH)
In the 68k Macintosh era, all this hardware was implemented using several
custom chips. In a PCI-compatible Power Macintosh, the above devices are part
of the MIO chip itself. MIO's functional blocks implementing virtual devices
are called "cells", i.e. "VIA cell", "SWIM cell" etc.
MIO itself is PCI compliant while the legacy hardware it emulates isn't.
MIO occupies 512Kb of PCI memory space divided into registers space and DMA
space. Access to emulated legacy devices is accomplished by reading from/
writing to MIO's PCI address space at predefined offsets.
MIO includes a DMA controller that offers 15 DMA channels implementing
Apple's own DMA protocol called descriptor-based DMA (DBDMA).
Official documentation (that is somewhat incomplete and erroneous) can be
found in the second chapter of the book "Macintosh Technology in the Common
Hardware Reference Platform" by Apple Computer, Inc.
*/
#ifndef MACIO_H
#define MACIO_H
#include <cinttypes>
#include "pcidevice.h"
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "pcihost.h"
#include "viacuda.h"
/**
Heathrow ASIC emulation
Author: Max Poliakovski
Heathrow is a MIO-compliant ASIC used in the Gossamer architecture. It's
hard-wired to PCI device number 16. Its I/O memory (512Kb) will be configured
by the Macintosh firmware to live at 0xF3000000.
Emulated subdevices and their offsets within Heathrow I/O space:
----------------------------------------------------------------
mesh(SCSI) register space: 0x00010000, DMA space: 0x00008000
bmac(ethernet) register space: 0x00011000, DMA space: 0x00008200, 0x00008300
escc(serial) register space: 0x00013000, size: 0x00001000
DMA space: 0x00008400, size: 0x00000400
escc:ch-a register space: 0x00013020, DMA space: 0x00008400, 0x00008500
escc:ch-b register space: 0x00013000, DMA space: 0x00008600, 0x00008700
davbus(sound) register space: 0x00014000, DMA space: 0x00008800, 0x00008900
SWIM3(floppy) register space: 0x00015000, DMA space: 0x00008100
NVRAM register space: 0x00060000, size: 0x00020000
IDE register space: 0x00020000, DMA space: 0x00008b00
VIA-CUDA register space: 0x00016000, size: 0x00002000
*/
class HeathrowIC : public PCIDevice
{
public:
using PCIDevice::name;
HeathrowIC();
~HeathrowIC();
void set_host(PCIHost *host_instance) {this->host_instance = host_instance;};
/* PCI device methods */
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);
void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size);
/* MMIO device methods */
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.
0x10, 0x00, // device ID: Heathrow Mac I/O
0x00, 0x00, // PCI command (set to 0 at power-up?)
0x00, 0x00, // PCI status (set to 0 at power-up?)
0x01, // revision ID
// class code is reported in OF property "class-code" as 0xff0000
0x00, // standard programming
0x00, // subclass code
0xFF, // class code: unassigned
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 */

131
devices/memctrlbase.cpp Normal file
View File

@ -0,0 +1,131 @@
#include <string>
#include <vector>
#include "memctrlbase.h"
MemCtrlBase::MemCtrlBase(std::string name)
{
this->name = name;
}
MemCtrlBase::~MemCtrlBase()
{
for (auto &reg : mem_regions) {
if (reg)
delete(reg);
}
this->mem_regions.clear();
this->address_map.clear();
}
AddressMapEntry *MemCtrlBase::find_range(uint32_t addr)
{
for (auto &entry : address_map) {
if (addr >= entry.start && addr <= entry.end)
return &entry;
}
return 0;
}
bool MemCtrlBase::add_mem_region(uint32_t start_addr, uint32_t size,
uint32_t dest_addr, uint32_t type, uint8_t init_val = 0)
{
AddressMapEntry entry;
/* error if a memory region for the given range already exists */
if (find_range(start_addr) || find_range(start_addr + size))
return false;
uint8_t *reg_content = new uint8_t[size];
if (!reg_content)
return false;
this->mem_regions.push_back(reg_content);
entry.start = start_addr;
entry.end = start_addr + size - 1;
entry.mirror = dest_addr;
entry.type = type;
entry.devobj = 0;
entry.mem_ptr = reg_content;
this->address_map.push_back(entry);
return true;
}
bool MemCtrlBase::add_rom_region(uint32_t start_addr, uint32_t size)
{
return add_mem_region(start_addr, size, 0, RT_ROM);
}
bool MemCtrlBase::add_ram_region(uint32_t start_addr, uint32_t size)
{
return add_mem_region(start_addr, size, 0, RT_RAM);
}
bool MemCtrlBase::add_mem_mirror(uint32_t start_addr, uint32_t dest_addr)
{
AddressMapEntry entry, *ref_entry;
ref_entry = find_range(dest_addr);
if (!ref_entry)
return false;
entry.start = start_addr;
entry.end = start_addr + (ref_entry->end - ref_entry->start) + 1;
entry.mirror = dest_addr;
entry.type = ref_entry->type | RT_MIRROR;
entry.devobj = 0;
entry.mem_ptr = ref_entry->mem_ptr;
this->address_map.push_back(entry);
return true;
}
bool MemCtrlBase::set_data(uint32_t reg_addr, const uint8_t *data, uint32_t size)
{
AddressMapEntry *ref_entry;
uint32_t cpy_size;
ref_entry = find_range(reg_addr);
if (!ref_entry)
return false;
cpy_size = std::min(ref_entry->end - ref_entry->start + 1, size);
memcpy(ref_entry->mem_ptr, data, cpy_size);
return true;
}
bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size,
MMIODevice *dev_instance)
{
AddressMapEntry entry;
/* error if another region for the given range already exists */
if (find_range(start_addr) || find_range(start_addr + size))
return false;
entry.start = start_addr;
entry.end = start_addr + size - 1;
entry.mirror = 0;
entry.type = RT_MMIO;
entry.devobj = dev_instance;
entry.mem_ptr = 0;
this->address_map.push_back(entry);
return true;
}

53
devices/memctrlbase.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef MEMORY_CONTROLLER_BASE_H
#define MEMORY_CONTROLLER_BASE_H
#include <cinttypes>
#include <string>
#include <vector>
#include "mmiodevice.h"
enum RangeType {
RT_ROM = 1, /* read-only memory */
RT_RAM = 2, /* random access memory */
RT_MMIO = 4, /* memory mapped I/O */
RT_MIRROR = 8 /* region mirror (content of another region is acessible
at some other address) */
};
typedef struct AddressMapEntry {
uint32_t start; /* first address of the corresponding range */
uint32_t end; /* last address of the corresponding range */
uint32_t mirror; /* mirror address for RT_MIRROR */
uint32_t type; /* range type */
MMIODevice *devobj; /* pointer to device object */
unsigned char *mem_ptr; /* direct pointer to data for memory objects */
} AddressMapEntry;
/** Base class for memory controllers. */
class MemCtrlBase {
public:
MemCtrlBase(std::string name);
virtual ~MemCtrlBase();
virtual bool add_rom_region(uint32_t start_addr, uint32_t size);
virtual bool add_ram_region(uint32_t start_addr, uint32_t size);
virtual bool add_mem_mirror(uint32_t start_addr, uint32_t dest_addr);
virtual bool add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice *dev_instance);
virtual bool set_data(uint32_t reg_addr, const uint8_t *data, uint32_t size);
AddressMapEntry *find_range(uint32_t addr);
protected:
bool add_mem_region(uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val);
std::string name;
private:
std::vector<uint8_t *> mem_regions;
std::vector<AddressMapEntry> address_map;
};
#endif /* MEMORY_CONTROLLER_BASE_H */

22
devices/mmiodevice.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef MMIO_DEVICE_H
#define MMIO_DEVICE_H
#include <cinttypes>
#include <string>
#define READ_WORD_BE(addr) ((addr)[0] << 16) | (addr)[1]
#define READ_DWORD_BE(addr) ((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3]
#define READ_DWORD_LE(addr) ((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0]
/** Abstract class representing a simple, memory-mapped I/O device */
class MMIODevice {
public:
virtual uint32_t read(uint32_t offset, int size) = 0;
virtual void write(uint32_t offset, uint32_t value, int size) = 0;
virtual ~MMIODevice() = default;
protected:
std::string name;
};
#endif /* MMIO_DEVICE_H */

223
devices/mpc106.cpp Normal file
View File

@ -0,0 +1,223 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
/** MPC106 (Grackle) emulation
Author: Max Poliakovski
*/
#include <iostream>
#include <cstring>
#include <cinttypes>
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "mpc106.h"
MPC106::MPC106() : MemCtrlBase("Grackle"), PCIDevice("Grackle PCI host bridge")
{
/* add memory mapped I/O region for MPC106 registers */
add_mmio_region(0xFEC00000, 0x300000, this);
this->pci_0_bus.clear();
}
MPC106::~MPC106()
{
this->pci_0_bus.clear();
}
uint32_t MPC106::read(uint32_t offset, int size)
{
if (offset >= 0x200000) {
if (this->config_addr & 0x80) // process only if bit E (enable) is set
return pci_read(size);
}
/* FIXME: reading from CONFIG_ADDR is ignored for now */
return 0;
}
void MPC106::write(uint32_t offset, uint32_t value, int size)
{
if (offset < 0x200000) {
this->config_addr = value;
} else {
if (this->config_addr & 0x80) // process only if bit E (enable) is set
return pci_write(value, size);
}
}
uint32_t MPC106::pci_read(uint32_t size)
{
int bus_num, dev_num, fun_num, reg_offs;
bus_num = (this->config_addr >> 8) & 0xFF;
if (bus_num) {
std::cout << this->name << " err: read attempt from non-local PCI bus, "
<< "config_addr = " << std::hex << this->config_addr << std::endl;
return 0;
}
dev_num = (this->config_addr >> 19) & 0x1F;
fun_num = (this->config_addr >> 16) & 0x07;
reg_offs = (this->config_addr >> 24) & 0xFC;
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
return this->pci_cfg_read(reg_offs, size);
} else {
if (this->pci_0_bus.count(dev_num)) {
return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size);
} else {
std::cout << this->name << " err: read attempt from non-existing PCI device "
<< dev_num << std::endl;
return 0;
}
}
return 0;
}
void MPC106::pci_write(uint32_t value, uint32_t size)
{
int bus_num, dev_num, fun_num, reg_offs;
bus_num = (this->config_addr >> 8) & 0xFF;
if (bus_num) {
std::cout << this->name << " err: write attempt to non-local PCI bus, "
<< "config_addr = " << std::hex << this->config_addr << std::endl;
return;
}
dev_num = (this->config_addr >> 19) & 0x1F;
fun_num = (this->config_addr >> 16) & 0x07;
reg_offs = (this->config_addr >> 24) & 0xFC;
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
this->pci_cfg_write(reg_offs, value, size);
} else {
if (this->pci_0_bus.count(dev_num)) {
this->pci_0_bus[dev_num]->pci_cfg_write(reg_offs, value, size);
} else {
std::cout << this->name << " err: write attempt to non-existing PCI device "
<< dev_num << std::endl;
}
}
}
uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size)
{
#ifdef MPC106_DEBUG
printf("read from Grackle register %08X\n", reg_offs);
#endif
switch(size) {
case 1:
return this->my_pci_cfg_hdr[reg_offs];
break;
case 2:
return READ_WORD_BE(&this->my_pci_cfg_hdr[reg_offs]);
break;
case 4:
return READ_DWORD_BE(&this->my_pci_cfg_hdr[reg_offs]);
break;
default:
std::cout << "MPC106 read error: invalid size parameter " << size
<< std::endl;
}
return 0;
}
void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
{
#ifdef MPC106_DEBUG
printf("write %08X to Grackle register %08X\n", value, reg_offs);
#endif
// FIXME: implement write-protection for read-only registers
switch(size) {
case 1:
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
break;
case 2:
this->my_pci_cfg_hdr[reg_offs] = (value >> 8) & 0xFF;
this->my_pci_cfg_hdr[reg_offs+1] = value & 0xFF;
break;
case 4:
this->my_pci_cfg_hdr[reg_offs] = (value >> 24) & 0xFF;
this->my_pci_cfg_hdr[reg_offs+1] = (value >> 16) & 0xFF;
this->my_pci_cfg_hdr[reg_offs+2] = (value >> 8) & 0xFF;
this->my_pci_cfg_hdr[reg_offs+3] = value & 0xFF;
break;
default:
std::cout << "MPC106 read error: invalid size parameter " << size
<< std::endl;
}
if (this->my_pci_cfg_hdr[0xF2] & 8) {
#ifdef MPC106_DEBUG
std::cout << "MPC106: MCCR1[MEMGO] was set! " << std::endl;
#endif
setup_ram();
}
}
bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance)
{
if (this->pci_0_bus.count(dev_num)) // is dev_num already registered?
return false;
this->pci_0_bus[dev_num] = dev_instance;
dev_instance->set_host(this);
return true;
}
bool MPC106::pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj)
{
// FIXME: add sanity checks!
return this->add_mmio_region(start_addr, size, obj);
}
void MPC106::setup_ram()
{
uint32_t mem_start, mem_end, ext_mem_start, ext_mem_end, bank_start, bank_end;
uint32_t ram_size = 0;
uint8_t bank_en = this->my_pci_cfg_hdr[0xA0];
for (int bank = 0; bank < 8; bank++) {
if (bank_en & (1 << bank)) {
if (bank < 4) {
mem_start = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x80]);
ext_mem_start = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x88]);
mem_end = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x90]);
ext_mem_end = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x98]);
} else {
mem_start = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x84]);
ext_mem_start = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x8C]);
mem_end = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x94]);
ext_mem_end = READ_DWORD_LE(&this->my_pci_cfg_hdr[0x9C]);
}
bank_start = (((ext_mem_start >> bank * 8) & 3) << 30) |
(((mem_start >> bank * 8) & 0xFF) << 20);
bank_end = (((ext_mem_end >> bank * 8) & 3) << 30) |
(((mem_end >> bank * 8) & 0xFF) << 20) | 0xFFFFFUL;
if (bank && bank_start != ram_size)
std::cout << "MPC106 error: RAM not contiguous!" << std::endl;
ram_size += bank_end + 1;
}
}
if (!this->add_ram_region(0, ram_size)) {
std::cout << "MPC106 RAM allocation failed!" << std::endl;
}
}

91
devices/mpc106.h Normal file
View File

@ -0,0 +1,91 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
/** MPC106 (Grackle) emulation
Author: Max Poliakovski
Grackle IC is a combined memory and PCI controller manufactured by Motorola.
It's the central device in the Gossamer architecture.
Manual: https://www.nxp.com/docs/en/reference-manual/MPC106UM.pdf
This code emulates as much functionality as needed to run PowerMac Beige G3.
This implies that
- we only support address map B
- our virtual device reports revision 4.0 as expected by machine firmware
*/
#ifndef MPC106_H_
#define MPC106_H_
#include <cinttypes>
#include <unordered_map>
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "pcidevice.h"
#include "pcihost.h"
class MPC106 : public MemCtrlBase, public PCIDevice, public PCIHost
{
public:
using MemCtrlBase::name;
MPC106();
~MPC106();
uint32_t read(uint32_t offset, int size);
void write(uint32_t offset, uint32_t value, int size);
/* PCI host bridge API */
bool pci_register_device(int dev_num, PCIDevice *dev_instance);
protected:
/* PCI access */
uint32_t pci_read(uint32_t size);
void pci_write(uint32_t value, uint32_t size);
/* my own PCI configuration registers access */
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);
void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size);
void set_host(PCIHost *host_instance) {}; // unimplemented for now
/* PCI host bridge API */
//bool pci_register_device(int dev_num, PCIDevice *dev_instance);
bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj);
void setup_ram(void);
private:
uint8_t my_pci_cfg_hdr[256] = {
0x57, 0x10, // vendor ID: Motorola
0x02, 0x00, // device ID: MPC106
0x06, 0x00, // PCI command
0x80, 0x00, // PCI status
0x40, // revision ID: 4.0
0x00, // standard programming
0x00, // subclass code: host bridge
0x06, // class code: bridge device
[0x73] = 0xCD, // default value for ODCR
[0xA8] = 0x10, 0x00, 0x00, 0xFF, // PICR1
[0xAC] = 0x0C, 0x06, 0x0C, 0x00, // PICR2
[0xBA] = 0x04,
[0xC0] = 0x01,
[0xE0] = 0x42, 0x00, 0xFF, 0x0F,
[0xE8] = 0x20,
[0xF0] = 0x00, 0x00, 0x02, 0xFF,
[0xF4] = 0x03,
[0xFC] = 0x00, 0x00, 0x10, 0x00
};
uint32_t config_addr;
//uint32_t config_data;
std::unordered_map<int, PCIDevice*> pci_0_bus;
};
#endif

34
devices/pcidevice.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef PCI_DEVICE_H
#define PCI_DEVICE_H
#include <cinttypes>
#include <string>
#include "mmiodevice.h"
#include "pcihost.h"
/* convert little-endian DWORD to big-endian DWORD */
#define LE2BE(x) (x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24)
enum {
CFG_REG_BAR0 = 0x10 // base address register 0
};
class PCIDevice : public MMIODevice {
public:
PCIDevice(std::string name) {this->name = name;};
virtual ~PCIDevice() = default;
/* configuration space access methods */
virtual uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size) = 0;
virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) = 0;
virtual void set_host(PCIHost *host_instance) = 0;
protected:
std::string name; // human-readable device name
PCIHost *host_instance; // host bridge instance to call back
uint32_t base_addr; // base address register 0
};
#endif /* PCI_DEVICE_H */

15
devices/pcihost.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef PCI_HOST_H
#define PCI_HOST_H
#include <cinttypes>
class PCIDevice; // forward declaration to prevent errors
class PCIHost {
public:
virtual bool pci_register_device(int dev_num, PCIDevice *dev_instance) = 0;
virtual bool pci_register_mmio_region(uint32_t start_addr, uint32_t size,
PCIDevice *obj) = 0;
};
#endif /* PCI_HOST_H */

326
devices/viacuda.cpp Normal file
View File

@ -0,0 +1,326 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
/** VIA-CUDA combo device emulation.
Author: Max Poliakovski 2019
*/
#include <iostream>
#include <cinttypes>
#include <vector>
#include "viacuda.h"
using namespace std;
ViaCuda::ViaCuda()
{
/* FIXME: is this the correct
VIA initialization? */
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;
this->cuda_init();
}
void ViaCuda::cuda_init()
{
this->old_tip = 0;
this->old_byteack = 0;
this->treq = 1;
this->in_count = 0;
this->out_count = 0;
}
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_B:
res = this->via_regs[VIA_B];
break;
case VIA_A:
case VIA_ANH:
cout << "WARNING: read attempt from VIA Port A!" << endl;
break;
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:
this->via_regs[VIA_B] = value;
cuda_write(value);
break;
case VIA_A:
case VIA_ANH:
cout << "WARNING: write attempt to VIA Port A!" << endl;
break;
case VIA_DIRB:
cout << "VIA_DIRB = " << hex << (uint32_t)value << endl;
this->via_regs[VIA_DIRB] = value;
break;
case VIA_DIRA:
cout << "VIA_DIRA = " << hex << (uint32_t)value << endl;
this->via_regs[VIA_DIRA] = value;
break;
case VIA_PCR:
cout << "VIA_PCR = " << hex << (uint32_t)value << endl;
this->via_regs[VIA_PCR] = value;
break;
case VIA_ACR:
cout << "VIA_ACR = " << hex << (uint32_t)value << endl;
this->via_regs[VIA_ACR] = value;
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;
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;
}
}
inline bool ViaCuda::cuda_ready()
{
return ((this->via_regs[VIA_DIRB] & 0x38) == 0x30);
}
inline void ViaCuda::assert_sr_int()
{
this->via_regs[VIA_IFR] |= 0x84;
}
void ViaCuda::cuda_write(uint8_t new_state)
{
if (!cuda_ready()) {
cout << "Cuda not ready!" << endl;
return;
}
int new_tip = !!(new_state & CUDA_TIP);
int new_byteack = !!(new_state & CUDA_BYTEACK);
/* return if there is no state change */
if (new_tip == this->old_tip && new_byteack == this->old_byteack)
return;
cout << "Cuda state changed!" << endl;
this->old_tip = new_tip;
this->old_byteack = new_byteack;
if (new_tip) {
if (new_byteack) {
this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */
this->treq = 1;
if (this->in_count) {
cuda_process_packet();
/* start response transaction */
this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */
this->treq = 0;
}
this->in_count = 0;
} else {
cout << "Cuda: enter sync state" << endl;
this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */
this->treq = 0;
this->in_count = 0;
this->out_count = 0;
}
assert_sr_int(); /* send dummy byte as idle acknowledge or attention */
} else {
if (this->via_regs[VIA_ACR] & 0x10) { /* data transfer: Host --> Cuda */
if (this->in_count < 16) {
this->in_buf[this->in_count++] = this->via_regs[VIA_SR];
assert_sr_int(); /* tell the system we've read the data */
} else {
cout << "Cuda input buffer exhausted!" << endl;
}
} else { /* data transfer: Cuda --> Host */
if (this->out_count) {
this->via_regs[VIA_SR] = this->out_buf[this->out_pos++];
if (this->out_pos >= this->out_count) {
cout << "Cuda: sending last byte" << endl;
this->out_count = 0;
this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */
this->treq = 1;
}
assert_sr_int(); /* tell the system we've written the data */
}
}
}
}
void ViaCuda::cuda_response_header(uint32_t pkt_type, uint32_t pkt_flag)
{
this->out_buf[0] = pkt_type;
this->out_buf[1] = pkt_flag;
this->out_buf[2] = this->in_buf[1]; /* copy original cmd */
this->out_count = 3;
this->out_pos = 0;
}
void ViaCuda::cuda_error_response(uint32_t error)
{
this->out_buf[0] = CUDA_PKT_ERROR;
this->out_buf[1] = error;
this->out_buf[2] = this->in_buf[0];
this->out_buf[3] = this->in_buf[1]; /* copy original cmd */
this->out_count = 4;
this->out_pos = 0;
}
void ViaCuda::cuda_process_packet()
{
if (this->in_count < 2) {
cout << "Cuda: invalid packet (too few data)!" << endl;
return;
}
switch(this->in_buf[0]) {
case CUDA_PKT_ADB:
cout << "Cuda: ADB packet received" << endl;
break;
case CUDA_PKT_PSEUDO:
cout << "Cuda: pseudo command packet received" << endl;
cout << "Command: " << hex << (uint32_t)(this->in_buf[1]) << endl;
cout << "Data count: " << dec << this->in_count << endl;
for (int i = 0; i < this->in_count; i++) {
cout << hex << (uint32_t)(this->in_buf[i]) << ", ";
}
cout << endl;
cuda_pseudo_command(this->in_buf[1], this->in_count - 2);
break;
default:
cout << "Cuda: unsupported packet type = " << dec << (uint32_t)(this->in_buf[0]) << endl;
}
}
void ViaCuda::cuda_pseudo_command(int cmd, int data_count)
{
switch(cmd) {
case CUDA_READ_WRITE_I2C:
cuda_response_header(CUDA_PKT_PSEUDO, 0);
/* bit 0 of the I2C address byte indicates operation kind:
0 - write to device, 1 - read from device
In the case of reading, Cuda will append one-byte result
to the response packet header */
i2c_simple_transaction(this->in_buf[2], &this->in_buf[3], this->in_count - 3);
break;
case CUDA_COMB_FMT_I2C:
/* HACK:
This command performs the so-called open-ended transaction, i.e.
Cuda will continue to send data as long as handshaking is completed
for each byte. To support that, we'd need another emulation approach.
Fortunately, HWInit is known to read/write max. 4 bytes at once
so we're going to use a prefilled buffer to make it work.
*/
cuda_response_header(CUDA_PKT_PSEUDO, 0);
if (this->in_count >= 5) {
i2c_comb_transaction(this->in_buf[2], this->in_buf[3], this->in_buf[4],
&this->in_buf[5], this->in_count - 5);
}
break;
case CUDA_OUT_PB0: /* undocumented call! */
cout << "Cuda: send " << dec << (int)(this->in_buf[2]) << " to PB0" << endl;
cuda_response_header(CUDA_PKT_PSEUDO, 0);
break;
default:
cout << "Cuda: unsupported pseudo command 0x" << hex << cmd << endl;
cuda_error_response(CUDA_ERR_BAD_CMD);
}
}
void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t *in_buf,
int in_bytes)
{
int tr_type = dev_addr & 1;
switch(dev_addr & 0xFE) {
case 0x50: /* unknown device on the Gossamer board */
if (tr_type) { /* read */
/* send dummy byte for now */
this->out_buf[this->out_count++] = 0xDD;
} else {
/* ignore writes */
}
break;
default:
cout << "Unsupported I2C device 0x" << hex << (int)dev_addr << endl;
cuda_error_response(CUDA_ERR_I2C);
}
}
void ViaCuda::i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr,
uint8_t dev_addr1, const uint8_t *in_buf, int in_bytes)
{
int tr_type = dev_addr1 & 1;
if ((dev_addr & 0xFE) != (dev_addr1 & 0xFE)) {
cout << "I2C combined, dev_addr mismatch!" << endl;
return;
}
switch(dev_addr1 & 0xFE) {
case 0xAE: /* SDRAM EEPROM, no clue which one */
if (tr_type) { /* read */
if (sub_addr != 2) {
cout << "Unsupported read position 0x" << hex << (int)sub_addr
<< " in SDRAM EEPROM 0x" << hex << (int)dev_addr1;
return;
}
/* FIXME: hardcoded SPD EEPROM values! This should be a proper
I2C device with user-configurable params */
this->out_buf[this->out_count++] = 0x04; /* memory type = SDRAM */
this->out_buf[this->out_count++] = 0x0B; /* row address bits per bank */
this->out_buf[this->out_count++] = 0x09; /* col address bits per bank */
this->out_buf[this->out_count++] = 0x02; /* num of RAM banks */
} else {
/* ignore writes */
}
break;
default:
cout << "Unsupported I2C device 0x" << hex << (int)dev_addr1 << endl;
cuda_error_response(CUDA_ERR_I2C);
}
}

123
devices/viacuda.h Normal file
View File

@ -0,0 +1,123 @@
//DingusPPC - Prototype 5bf2
//Written by divingkatae
//(c)2018-20 (theweirdo)
//Please ask for permission
//if you want to distribute this.
//(divingkatae#1017 on Discord)
/** VIA-CUDA combo device emulation.
Author: Max Poliakovski 2019
Versatile interface adapter (VIA) is an old I/O controller that can be found
in nearly every Macintosh computer. In the 68k era, VIA was used to control
various peripherial devices. In a Power Macintosh, its function is limited
to the I/O interface for the Cuda MCU. I therefore decided to put VIA
emulation code here.
Cuda MCU is a multipurpose IC built around a custom version of the Motorola
MC68HC05 microcontroller. It provides several functions including:
- Apple Desktop Bus (ADB) master
- I2C bus master
- Realtime clock (RTC)
- parameter RAM (first generation of the Power Macintosh)
- power management
MC68HC05 doesn't provide any dedicated hardware for serial communication
protocols. All signals required for ADB and I2C will be generated by Cuda
firmware using bit banging (https://en.wikipedia.org/wiki/Bit_banging).
*/
#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 */
};
/** Cuda communication signals. */
enum {
CUDA_TIP = 0x20, /* transaction in progress: 0 - true, 1 - false */
CUDA_BYTEACK = 0x10, /* byte acknowledge: 0 - true, 1 - false */
CUDA_TREQ = 0x08 /* Cuda requests transaction from host */
};
/** Cuda packet types. */
enum {
CUDA_PKT_ADB = 0,
CUDA_PKT_PSEUDO = 1,
CUDA_PKT_ERROR = 2,
CUDA_PKT_TICK = 3,
CUDA_PKT_POWER = 4
};
/** Cuda pseudo commands. */
enum {
CUDA_READ_WRITE_I2C = 0x22, /* read/write I2C device */
CUDA_COMB_FMT_I2C = 0x25, /* combined format I2C transaction */
CUDA_OUT_PB0 = 0x26, /* output one bit to Cuda's PB0 line */
};
/** Cuda error codes. */
enum {
CUDA_ERR_BAD_CMD = 2, /* invalid pseudo command */
CUDA_ERR_I2C = 5 /* invalid I2C data or no acknowledge */
};
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 */
/* Cuda state. */
uint8_t old_tip;
uint8_t old_byteack;
uint8_t treq;
uint8_t in_buf[16];
int32_t in_count;
uint8_t out_buf[16];
int32_t out_count;
int32_t out_pos;
void print_enabled_ints(); /* print enabled VIA interrupts and their sources */
void cuda_init();
bool cuda_ready();
void assert_sr_int();
void cuda_write(uint8_t new_state);
void cuda_response_header(uint32_t pkt_type, uint32_t pkt_flag);
void cuda_error_response(uint32_t error);
void cuda_process_packet();
void cuda_pseudo_command(int cmd, int data_count);
/* I2C related methods */
void i2c_simple_transaction(uint8_t dev_addr, const uint8_t *in_buf, int in_bytes);
void i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1,
const uint8_t *in_buf, int in_bytes);
};
#endif /* VIACUDA_H */

View File

@ -1,102 +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 Serial Ports
// Based on the Zilog Z8530 SCC chip
#include <iostream>
#include <cinttypes>
#include "macioserial.h"
#include "ppcemumain.h"
uint32_t mac_serial_address;
uint8_t serial_write_byte;
uint8_t serial_read_byte;
bool w7_prime;
void mac_serial_init(){
machine_iocontrolmem_mem[0x3013004] = 0x04;
machine_iocontrolmem_mem[0x3013009] = 0xC0;
machine_iocontrolmem_mem[0x301300B] = 0x08;
machine_iocontrolmem_mem[0x301300E] = 0x30;
machine_iocontrolmem_mem[0x301300F] = 0xF8;
machine_iocontrolmem_mem[0x3013010] = 0x44;
machine_iocontrolmem_mem[0x3013011] = 0x06;
}
void mac_serial_read(){
if (mac_serial_address >=0x3013020){
mac_serial_address -= 0x20;
}
if (w7_prime){
if (((machine_iocontrolmem_mem[0x301301F] >> 2) & 0x1) & ((machine_iocontrolmem_mem[0x3013007] >> 6) & 0x1)){
switch(mac_serial_address){
case 0x14: case 0x15:
serial_read_byte = machine_iocontrolmem_mem[(mac_serial_address - 0x10)];
break;
case 0x19:
serial_read_byte = machine_iocontrolmem_mem[0x3];
break;
case 0x1B:
serial_read_byte = machine_iocontrolmem_mem[0x10];
break;
case 0x1E:
serial_read_byte = machine_iocontrolmem_mem[0x07];
break;
default:
serial_read_byte = machine_iocontrolmem_mem[mac_serial_address];
break;
}
}
}
else{
if ((machine_iocontrolmem_mem[0x301300F] >> 2) & 0x1){
switch(mac_serial_address){
case 0x14: case 0x15:
serial_read_byte = machine_iocontrolmem_mem[(mac_serial_address - 4)];
break;
case 0x19: case 0x1B:
serial_read_byte = machine_iocontrolmem_mem[(mac_serial_address + 4)];
break;
default:
serial_read_byte = machine_iocontrolmem_mem[mac_serial_address];
break;
}
}
else {
switch(mac_serial_address){
case 0x14: case 0x15: case 0x16: case 0x17:
serial_read_byte = machine_iocontrolmem_mem[(mac_serial_address - 4)];
case 0x19: case 0x1B:
serial_read_byte = machine_iocontrolmem_mem[(mac_serial_address + 4)];
break;
default:
serial_read_byte = machine_iocontrolmem_mem[mac_serial_address];
break;
}
}
}
}
void mac_serial_write(){
if (mac_serial_address >=0x3013020){
mac_serial_address -= 0x20;
}
machine_iocontrolmem_mem[mac_serial_address] = serial_write_byte;
if ((machine_iocontrolmem_mem[0x0F]) & 0x1){
w7_prime = true;
}
else{
w7_prime = false;
}
machine_iocontrolmem_mem[(mac_serial_address + 0x10)] = machine_iocontrolmem_mem[mac_serial_address];
}

View File

@ -1,22 +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 Serial Ports
// Based on the Zilog Z8530 SCC chip
#ifndef MAC_IO_SERIAL_H
#define MAC_IO_SERIAL_H
extern uint32_t mac_serial_address;
extern uint8_t serial_write_byte;
extern uint8_t serial_read_byte;
extern void mac_serial_init();
extern void mac_serial_read();
extern void mac_serial_write();
#endif

View File

@ -1,31 +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 SCSI
#include <iostream>
#include <cstring>
#include <cinttypes>
#include "ppcemumain.h"
#include "macscsi.h"
uint32_t macscsi_address;
uint8_t macscsi_write_byte;
uint8_t macscsi_read_byte;
void macscsi_init(){
}
void macscsi_read(){
}
void macscsi_write(){
}

View File

@ -1,21 +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 SCSI
#ifndef MACSCSI_H_
#define MACSCSI_H_
extern uint32_t macscsi_address;
extern uint8_t macscsi_write_byte;
extern uint8_t macscsi_read_byte;
extern void macscsi_init();
extern void macscsi_read();
extern void macscsi_write();
#endif

View File

@ -1,29 +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 Swim 3 Floppy Drive
#include <iostream>
#include <cinttypes>
#include "macswim3.h"
#include "ppcemumain.h"
uint32_t mac_swim3_address;
uint8_t swim3_write_byte;
uint8_t swim3_read_byte;
void mac_swim3_init(){
machine_iocontrolmem_mem[0x3015C00] = 0xF0;
}
void mac_swim3_read(){
swim3_read_byte = machine_iocontrolmem_mem[mac_swim3_address];
}
void mac_swim3_write(){
machine_iocontrolmem_mem[mac_swim3_address] = swim3_write_byte;
}

View File

@ -1,19 +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 MAC_SWIM3_H
#define MAC_SWIM3_H
extern uint32_t mac_swim3_address;
extern uint8_t swim3_write_byte;
extern uint8_t swim3_read_byte;
extern void mac_swim3_init();
extern void mac_swim3_read();
extern void mac_swim3_write();
#endif // MAC_IO_SERIAL_H

247
main.cpp
View File

@ -19,14 +19,12 @@
#include <ctime>
#include <stdexcept>
#include "ppcemumain.h"
#include "macioserial.h"
#include "macswim3.h"
#include "ppcmemory.h"
#include "viacuda.h"
#include "mpc106.h"
#include "openpic.h"
#include "devices/mpc106.h"
#include "debugger.h"
//#include <vector>
#include "devices/machineid.h"
#include "devices/macio.h"
#include "devices/mpc106.h"
#define max_16b_int 65535
#define max_32b_int 4294967295
@ -38,6 +36,33 @@
using namespace std;
/**
Power Macintosh ROM identification string
is located in the ConfigInfo structure starting at 0x30D064 (PCI Macs)
or 0x30C064 (Nubus Macs). This helps a lot to determine which
hardware is to be used.
*/
static const map<string,string> PPCMac_ROMIdentity = { //Codename Abbreviation for...
{"Alch", "Performa 6400"}, //Alchemy
{"Come", "PowerBook 2400"}, //Comet
{"Cord", "Power Mac 5200/6200 series"}, //Cordyceps
{"Gaze", "Power Mac 6500"}, //Gazelle
{"Goss", "Power Mac G3 Beige"}, //Gossamer
{"GRX ", "PowerBook G3 Wallstreet"}, //(Unknown)
{"Hoop", "PowerBook 3400"}, //Hooper
{"PBX ", "PowerBook Pre-G3"}, //(Unknown)
{"PDM ", "Nubus Power Mac or WGS"}, //Piltdown Man (6100/7100/8100)
{"Pip ", "Pippin... uh... yeah..."}, //Pippin
{"Powe", "Generic Power Mac"}, //PowerMac?
{"Spar", "20th Anniversay Mac, you lucky thing."}, //Spartacus
{"Tanz", "Power Mac 4400"}, //Tanzania
{"TNT ", "Power Mac 7xxxx/8xxx series"}, //Trinitrotoluene :-)
{"Zanz", "A complete engima."}, //Zanzibar (mentioned in Sheepshaver's code, but no match to any known ROM)
{"????", "A clone, perhaps?"} //N/A (Placeholder ID)
};
SetPRS ppc_state;
bool power_on = 1;
@ -55,6 +80,9 @@ uint32_t ppc_next_instruction_address; //Used for branching, setting up the NIA
uint32_t return_value;
MemCtrlBase *mem_ctrl_instance = 0;
HeathrowIC *heathrow = 0;
GossamerID *machine_id;
//A pointer to a pointer, used for quick movement to one of the following
//memory areas. These are listed right below.
@ -90,7 +118,7 @@ bool msr_es_change; //Check Endian
uint32_t rom_file_begin; //where to start storing ROM files in memory
uint32_t pci_io_end;
uint32_t rom_file_setsize;
uint32_t rom_filesize;
clock_t clock_test_begin; //Used to make sure the TBR does not increment so quickly.
@ -397,26 +425,14 @@ int main(int argc, char **argv)
rom_file_begin = 0xFFF00000; //where to start storing ROM files in memory
pci_io_end = 0x83FFFFFF;
rom_file_setsize = 0x400000;
rom_filesize = 0x400000;
//Init virtual CPU.
reg_init();
/**
uint16_t test_endianness = 0x1234;
//Test for endianess before beginning
uint8_t grab_result = (uint8_t) (test_endianness >> 8);
endian_switch endis;
//Special case for little-endian machines
switch(unsigned(grab_result)){
case 18:
endis = little_end;
break;
default:
endis = big_end;
}
**/
//0xFFF00100 is where the reset vector is.
//In other words, begin executing code here.
ppc_state.ppc_pc = 0xFFF00100;
uint32_t opcode_entered = 0; //used for testing opcodes in playground
@ -431,38 +447,25 @@ int main(int argc, char **argv)
romFile.open("rom.bin", ios::in|ios::binary);
if (romFile.fail()){
cerr << "rom.bin not present. Creating it right now. Please restart this program.\n";
std::ofstream outfile ("rom.bin", ios::binary);
outfile << "Testing!" << std::endl;
outfile.close();
cerr << "rom.bin not present. Please provide an appropriate ROM file"
<< "and restart this program.\n";
romFile.close();
return 1;
}
//Allocate memory for ROM, RAM, and I/O.
//Calculate and validate ROM file size.
romFile.seekg(0, romFile.end);
rom_file_setsize = romFile.tellg();
printf("Rom SIZE: %d \n", rom_file_setsize);
rom_filesize = romFile.tellg();
printf("Rom SIZE: %d \n", rom_filesize);
romFile.seekg (0, romFile.beg);
/**
Allocate memory wisely.
if (rom_filesize != 0x400000){
cerr << "Unsupported ROM File size. Expected size is 4 megabytes.\n";
romFile.close();
return 1;
}
Corresponds (mostly) to the follow memory patterns seen in
https://www.nxp.com/docs/en/reference-manual/MPC106UM.pdf
machine_sysram_mem - 0x00000000 to 0x7FFFFFFF
machine_upperiocontrol_mem - 0x80000000 to 0x807FFFFF
machine_iocontrolcdma_mem - 0x80800000 to 0x80FFFFFF
machine_loweriocontrol_mem - 0x81000000 to 0xBF7FFFFF
machine_interruptack_mem - 0xBFFFFFF0 to 0xBFFFFFFF
machine_iocontrolmem_mem - 0xC0000000 to 0xFFBFFFFF
machine_sysrom_mem - 0xFFC00000 to 0xFFFFFFFF
**/
//grab_disk_buf = (unsigned char*) calloc (32768, 1);
machine_sysram_mem = (unsigned char*) calloc (67108864, 1);
machine_sysconfig_mem = (unsigned char*) calloc (2048, 1);
machine_upperiocontrol_mem = (unsigned char*) calloc (8388608, 1);
@ -476,7 +479,7 @@ int main(int argc, char **argv)
machine_feexxx_mem = (unsigned char*) calloc (4096, 1);
machine_ff00xx_mem = (unsigned char*) calloc (4096, 1);
machine_ff80xx_mem = (unsigned char*) calloc (1048576, 1);
machine_sysrom_mem = (unsigned char*) calloc (rom_file_setsize, 1);
machine_sysrom_mem = (unsigned char*) calloc (rom_filesize, 1);
memset(machine_sysram_mem, 0x0, 67108864);
memset(machine_sysconfig_mem, 0x0, 2048);
@ -492,19 +495,10 @@ int main(int argc, char **argv)
memset(machine_ff80xx_mem, 0x0, 1048576);
grab_sysram_size = sizeof(machine_sysram_mem);
grab_sysrom_size = rom_file_setsize;
grab_sysrom_size = rom_filesize;
//Sanity checks - Prevent the input files being too small or too big.
//Also prevent the ROM area from overflow.
if (grab_sysrom_size < 0x100000){
cerr << "ROM File is too small. Must be at least 1 megabyte.\n";
return 1;
}
else if (grab_sysrom_size > 0x400000){
cerr << "ROM File is too big. Must be no more than 4 megabytes.\n";
return 1;
}
if (ram_size_set < 0x800000){
cerr << "The RAM size must be at least 8 MB to function.\n";
return 1;
@ -516,41 +510,11 @@ int main(int argc, char **argv)
rom_file_begin = 0xFFFFFFFF - grab_sysrom_size + 1;
/**
Test for PowerPC Mac ROMS
Starting at 0x30D064 (0x30C064 in older ROMS), there is a boot
identifier string in the ROM. This helps a lot to determine which
setup is to by used.
**/
char * memPPCBlock = new char[5];
map<string,string> PPCMac_ROMIdentity = { //Codename Abbreviation for...
{"Alch", "Performa 6400"}, //Alchemy
{"Come", "PowerBook 2400"}, //Comet
{"Cord", "Power Mac 5200/6200 series"}, //Cordyceps
{"Gaze", "Power Mac 6500"}, //Gazelle
{"Goss", "Power Mac G3 Beige"}, //Gossamer
{"GRX ", "PowerBook G3 Wallstreet"}, //(Unknown)
{"Hoop", "PowerBook 3400"}, //Hooper
{"PBX ", "PowerBook Pre-G3"}, //(Unknown)
{"PDM ", "Power Mac G1 or WGS"}, //(Unknown)
{"Pip ", "Pippin... uh... yeah..."}, //Pippin
{"Powe", "Generic Power Mac"}, //PowerMac?
{"Spar", "20th Anniversay Mac, you lucky thing."}, //Spartacus
{"Tanz", "Power Mac 4400"}, //Tanzania
{"TNT ", "Power Mac 7xxxx/8xxx series"}, //Trinitrotoluene :-)
{"Zanz", "A complete engima."}, //Zanzibar (mentioned in Sheepshaver's code, but no match to any known ROM)
{"????", "A clone, perhaps?"} //N/A (Placeholder ID)
};
char configGrab = 0;
uint32_t configInfoOffset = 0;
if (grab_sysrom_size == 0x400000){
romFile.seekg (0x300082, ios::beg); //This is where the place to get the offset is
romFile.get(configGrab); //just one byte to determine where the identifier string is
romFile.get(configGrab); //just one byte to determine ConfigInfo location
configInfoOffset = (uint32_t)(configGrab & 0xff);
if (configInfoOffset == 0xC0){
@ -558,8 +522,11 @@ int main(int argc, char **argv)
}
uint32_t configInfoAddr = 0x300000 + (configInfoOffset << 8) + 0x69; //address to check the identifier string
char memPPCBlock[5]; //First four chars are enough to distinguish between codenames
romFile.seekg (configInfoAddr, ios::beg);
romFile.read(memPPCBlock, sizeof(uint32_t)); //Only four chars needed to distinguish between codenames
romFile.read(memPPCBlock, 4);
memPPCBlock[4] = 0;
uint32_t rom_id = (memPPCBlock[0] << 24) | (memPPCBlock[1] << 16) | (memPPCBlock[2] << 8) | memPPCBlock[3];
std::string string_test = std::string(memPPCBlock);
@ -571,58 +538,43 @@ int main(int argc, char **argv)
if (string_test.compare(redo_me) == 0){
cout << "The machine is identified as..." << iter->second << endl;
romFile.seekg (0x0, ios::beg);
//This is where the first real instruction is in the ROM
//0xFFF00000 - 0xFFF02FFF is for the exception table,
//which is stored in all PPC ROMs here, btw.
//0xFFF00100 is where the reset vector is.
//In other words, begin executing code here.
ppc_state.ppc_pc = 0xFFF00100;//Please don't move this from here.
//A strange bug will happen where this will prevent proper branching
mpc106_init();
mac_serial_init();
mac_swim3_init();
via_cuda_init();
openpic_init();
break;
}
else{
iter++;
}
}
switch(rom_id) {
case 0x476F7373: {
cout << "Initialize Gossamer hardware...";
MPC106 *mpc106 = new MPC106();
mem_ctrl_instance = mpc106;
if (!mem_ctrl_instance->add_rom_region(0xFFC00000, 0x400000)) {
cout << "failure!\n" << endl;
delete(mem_ctrl_instance);
romFile.close();
return 1;
}
machine_id = new GossamerID(0x3d8c);
assert(machine_id != 0);
mpc106->add_mmio_region(0xFF000004, 4096, machine_id);
heathrow = new HeathrowIC();
assert(heathrow != 0);
mpc106->pci_register_device(16, heathrow);
cout << "done" << endl;
}
break;
default:
cout << "This machine not supported yet." << endl;
return 1;
}
//Copy the contents of the IO data and the ROM to memory appropriate locations.
//Read ROM file content and transfer it to the dedicated ROM region
romFile.read ((char *)machine_sysrom_mem,grab_sysrom_size);
/*
//Open the Disk File.
uint64_t disk_file_setsize = 0;
ifstream diskFile;
diskFile.open("disk.img", ios::in|ios::binary);
if (diskFile){
diskFile.seekg(0, romFile.end);
disk_file_setsize = romFile.tellg();
diskFile.seekg(0, romFile.beg);
if (disk_file_setsize % 32678 != 0){
cout << "WARNING - Disk file has improper offsets. Make sure the disk image has even 32 KB sectors." << endl;
}
else{
//Copy the contents of the IO data and the ROM to memory appropriate locations.
diskFile.read ((char *)machine_sysram_mem,(sizeof(uint8_t)*0x8000));
disk_inserted = 1;
disk_offset = 0;
}
}
else{
disk_inserted = 0;
}
*/
mem_ctrl_instance->set_data(0xFFC00000, machine_sysrom_mem, rom_filesize);
romFile.close();
clock_test_begin = clock();
@ -641,29 +593,6 @@ int main(int argc, char **argv)
}
else if ((checker=="1")|(checker=="realtime")|(checker=="/realtime")|(checker=="-realtime")){
execute_interpreter();
/*
if (disk_inserted){
if (disk_word == 32768){
if (disk_offset < disk_file_setsize){
disk_offset += 32768;
diskFile.seekg(disk_offset, romFile.beg);
char *ptr = ((char*)machine_iocontrolmem_mem + (0xF3008000 % 0x4000000));
diskFile.read (ptr,(sizeof(uint8_t)*0x8000));
disk_word = 0;
}
else{
disk_offset = 0;
diskFile.seekg(0, romFile.beg);
char *ptr = ((char*)machine_iocontrolmem_mem + (0xF3008000 % 0x4000000));
diskFile.read (ptr,(sizeof(uint8_t)*0x8000));
disk_word = 0;
}
}
else{
disk_word += 4;
}
}
*/
}
else if ((checker=="e")|(checker=="loadelf")|(checker=="/loadelf")|(checker=="-loadelf")){
ifstream elfFile;
@ -864,7 +793,9 @@ int main(int argc, char **argv)
std::cout << "playground - Mess around with and opcodes. " << endl;
}
romFile.close();
delete(heathrow);
delete(machine_id);
delete(mem_ctrl_instance);
//Free memory after the emulation is completed.
free(machine_sysram_mem);

View File

@ -1,17 +1,26 @@
OBJS = main.o macioserial.o macscsi.o macswim3.o mpc106.o openpic.o poweropcodes.o \
ppcfpopcodes.o ppcgekkoopcodes.o ppcmemory.o ppcopcodes.o viacuda.o davbus.o \
debugger.o
EXE := dingusppc
MODULES := . devices
SRCS := $(foreach sdir,$(MODULES),$(wildcard $(sdir)/*.cpp))
#SRCS = $(wildcard *.cpp)
OBJS := $(patsubst %.cpp, %.o, $(SRCS))
OUT = dingusppc
CXX = g++
CXXFLAGS = -g -c -Wall -std=c++11
LFLAGS =
all: $(OBJS)
$(CXX) -g $(OBJS) -o $(OUT) $(LFLAGS)
VPATH := devices
*.o : *.cpp
$(CXX) $(CXXFLAGS) -c $(input) -o $(output)
DEPS = $(OBJS:.o=.d)
all: $(EXE)
$(EXE) : $(OBJS)
$(CXX) -o $@ $^
%.o : %.cpp
$(CXX) $(CXXFLAGS) -MMD -o $@ $<
clean:
rm -f *.o $(OUT)
rm -rf *.o *.d devices/*.o devices/*.d $(EXE)
-include $(DEPS)

View File

@ -1,372 +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 MPC106
#include <iostream>
#include <cstring>
#include <cinttypes>
#include "viacuda.h"
#include "mpc106.h"
#include "ppcemumain.h"
#include "ppcmemory.h"
bool mpc106_membound_change;
bool mpc106_mem_approve; //Confirm memory transaction
uint32_t mpc106_address; // For fe000000 - fe00ffff
uint32_t mpc_config_addr; // Device No. and Reg No. included
uint32_t mpc_config_dat; // Value to write to the device
uint32_t cust_grab_size; // Custom bit size
uint32_t mpc106_write_word;
uint32_t mpc106_read_word;
uint16_t mpc106_write_half;
uint16_t mpc106_read_half;
uint8_t mpc106_write_byte;
uint8_t mpc106_read_byte;
uint8_t mpc106_word_custom_size;
//The below array is used for ROM banks
//Top eight entries are for the starting addresses
//Bottom eight entries are for the ending addresses
uint32_t mpc106_memory_bounds[16] =
{
0x00000, 0x00000, 0x00000, 0x00000,
0x00000, 0x00000, 0x00000, 0x00000,
0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF,
0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF,
};
//Entries are organized like so...
//ROM Banks 0-3 (ext. starting address) (starting address) (0x00000)
//ROM Banks 4-7 (ext. starting address) (starting address) (0x00000)
//ROM Banks 0-3 (ext. ending address) ( ending address) (0x00000)
//ROM Banks 4-7 (ext. ending address) ( ending address) (0x00000)
void mpc106_init(){
mpc_config_addr = 0;
mpc_config_dat = 0;
//Initialize Vendor & Device IDs
machine_fexxxx_mem[0x00] = 0x57;
machine_fexxxx_mem[0x01] = 0x10;
machine_fexxxx_mem[0x02] = 0x02;
//PCI command + status
machine_fexxxx_mem[0x04] = 0x06;
machine_fexxxx_mem[0x06] = 0x80;
machine_fexxxx_mem[0x0B] = 0x06;
machine_fexxxx_mem[0x0C] = 0x08;
machine_fexxxx_mem[0x73] = 0xCD;
machine_fexxxx_mem[0xA8] = 0x10;
machine_fexxxx_mem[0xA9] = 0x00;
machine_fexxxx_mem[0xAA] = 0x00;
machine_fexxxx_mem[0xAB] = 0xFF;
machine_fexxxx_mem[0xAC] = 0x0C;
machine_fexxxx_mem[0xAD] = 0x06;
machine_fexxxx_mem[0xAE] = 0x0C;
machine_fexxxx_mem[0xAF] = 0x00;
machine_fexxxx_mem[0xBA] = 0x04;
machine_fexxxx_mem[0xC0] = 0x01;
machine_fexxxx_mem[0xE0] = 0x42;
machine_fexxxx_mem[0xE1] = 0x00;
machine_fexxxx_mem[0xE2] = 0xFF;
machine_fexxxx_mem[0xE3] = 0x0F;
machine_fexxxx_mem[0xF0] = 0x00;
machine_fexxxx_mem[0xF1] = 0x00;
machine_fexxxx_mem[0xF2] = 0x02;
machine_fexxxx_mem[0xF3] = 0xFF;
machine_fexxxx_mem[0xF4] = 0x03;
machine_fexxxx_mem[0xF5] = 0x00;
machine_fexxxx_mem[0xF6] = 0x00;
machine_fexxxx_mem[0xF7] = 0x00;
machine_fexxxx_mem[0xFC] = 0x00;
machine_fexxxx_mem[0xFD] = 0x00;
machine_fexxxx_mem[0xFE] = 0x10;
machine_fexxxx_mem[0xFF] = 0x00;
mpc106_mem_approve = false;
mpc106_word_custom_size = 0;
}
uint32_t mpc106_write_device(uint32_t device_addr, uint32_t insert_to_device, uint8_t bit_length){
//Write to the specified device - Invoked when a write is made to 0xFEExxxxx.
//device_addr is what's stored in 0xFEC00CF8 (The MPG106/Grackle's CONFIG_ADDR Register).
uint32_t reg_num = (device_addr & 0x07FC) >> 2;
uint32_t dev_num = (device_addr & 0xF800) >> 11;
switch(dev_num){
case 0:
//Device 0 is reserved to the grackle by default
mpc106_address = reg_num;
mpc106_write(insert_to_device);
break;
case 16:
case 17:
via_cuda_address = (reg_num << 9) + (dev_num << 12) + 0x3000000;
via_write_byte = (uint8_t)insert_to_device;
via_cuda_write();
break;
}
return 0;
}
uint32_t mpc106_read_device(uint32_t device_addr, uint8_t bit_length){
//Read to the specified device - Invoked when a read is made to 0xFEExxxxx.
//device_addr is what's stored in 0xFEC00CF8 (The MPG106/Grackle's CONFIG_ADDR Register).
uint32_t reg_num = (device_addr & 0x07FC) >> 2;
uint32_t dev_num = (device_addr & 0xF800) >> 11;
uint32_t grab_value = 0;
switch(dev_num){
case 0:
//Device 0 is reserved to the grackle by default
mpc106_address = reg_num;
mpc106_read();
grab_value = mpc106_read_word;
break;
case 16:
case 17:
via_cuda_address = (reg_num << 8) + (dev_num << 12) + 0x3000000;
via_cuda_read();
grab_value = (uint32_t)via_read_byte;
break;
}
return grab_value;
}
bool mpc106_check_membound(uint32_t attempted_address){
uint32_t mem_address_begin;
uint32_t mem_address_end;
for (int get_rom_bank = 0; get_rom_bank < 8; get_rom_bank++){
mem_address_begin = mpc106_memory_bounds[get_rom_bank];
mem_address_end = mpc106_memory_bounds[get_rom_bank + 8];
if ((attempted_address >= mem_address_begin) & (attempted_address <= mem_address_end)){
uint8_t is_valid = (machine_fexxxx_mem[0xA0] >> get_rom_bank) & 0x01;
if (is_valid == 0){
return true;
}
}
}
return false;
}
void mpc106_set_membound_begin(uint8_t bound_area){
uint32_t bcheck_area = 0x80 + bound_area;
uint32_t newbound = machine_fexxxx_mem[bcheck_area];
uint32_t bound_entry = bound_area % 8;
uint32_t change_entry = mpc106_memory_bounds[bound_entry];
change_entry &= 0xfffff;
change_entry = newbound << 20;
mpc106_memory_bounds[bound_entry] = change_entry;
}
void mpc106_set_membound_extbegin(uint8_t bound_area){
uint32_t bcheck_area = 0x88 + bound_area;
uint32_t newbound = machine_fexxxx_mem[bcheck_area];
uint32_t bound_entry = bound_area % 8;
uint32_t change_entry = mpc106_memory_bounds[bound_entry];
change_entry &= 0x0fffffff;
change_entry = (newbound & 0x3) << 28;
mpc106_memory_bounds[bound_entry] = change_entry;
}
void mpc106_set_membound_end(uint8_t bound_area){
uint32_t bcheck_area = 0x90 + bound_area;
uint32_t newbound = machine_fexxxx_mem[bcheck_area];
uint32_t bound_entry = (bound_area % 8) + 8;
uint32_t change_entry = mpc106_memory_bounds[bound_entry];
change_entry &= 0xfffff;
change_entry = newbound << 20;
mpc106_memory_bounds[bound_entry] = change_entry;
}
void mpc106_set_membound_extend(uint8_t bound_area){
uint32_t bcheck_area = 0x98 + bound_area;
uint32_t newbound = machine_fexxxx_mem[bcheck_area];
uint32_t bound_entry = (bound_area % 8) + 8;
uint32_t change_entry = mpc106_memory_bounds[bound_entry];
change_entry &= 0x0fffffff;
change_entry = (newbound & 0x3) << 28;
mpc106_memory_bounds[bound_entry] = change_entry;
}
void mpc106_read(){
uint8_t read_length = 4;
if ((mpc106_address >= 0x80) | (mpc106_address < 0xA0)){
mpc106_membound_change = true;
read_length = mpc106_word_custom_size;
}
else{
switch (mpc106_address){
case 0x8:
case 0x9:
case 0xA:
case 0xB:
case 0xC:
case 0xD:
case 0xE:
case 0xF:
case 0x3C:
case 0x3D:
case 0x3E:
case 0x3F:
case 0x72:
case 0x73:
case 0xA0:
case 0xA3:
read_length = 1;
break;
case 0x0:
case 0x2:
case 0x4:
case 0x6:
case 0x70:
read_length = 2;
break;
case 0xF0:
case 0xF4:
case 0xF8:
case 0xFC:
read_length = 4;
default: //Avoid writing into reserved areas
read_length = 0;
}
}
switch(read_length){
case 1:
mpc106_read_word |= (grab_macmem_ptr[mpc106_address]);
break;
case 2:
mpc106_read_word |= (grab_macmem_ptr[mpc106_address++]);
mpc106_read_word |= (grab_macmem_ptr[mpc106_address]) << 8;
break;
case 4:
mpc106_read_word |= (grab_macmem_ptr[mpc106_address++]);
mpc106_read_word |= (grab_macmem_ptr[mpc106_address++]) << 8;
mpc106_read_word |= (grab_macmem_ptr[mpc106_address++]) << 16;
mpc106_read_word |= (grab_macmem_ptr[mpc106_address]) << 24;
break;
}
}
void mpc106_write(uint32_t write_word){
uint8_t write_length = 4;
if ((mpc106_address >= 0x80) | (mpc106_address < 0xA0)){
mpc106_membound_change = true;
write_length = mpc106_word_custom_size;
}
else{
switch (mpc106_address){
case 0x70:
case 0x72:
case 0x73:
case 0xA0:
case 0xA3:
write_length = 1;
break;
case 0x4:
case 0x6:
write_length = 2;
break;
case 0xF0:
case 0xF4:
case 0xF8:
case 0xFC:
write_length = 4;
default: //Avoid writing into reserved areas
write_length = 0;
}
}
if (mpc106_membound_change){
switch(write_length){
case 1:
change_membound_time();
grab_macmem_ptr[mpc106_address] |= (uint8_t)((mpc106_read_word) & 0xFF);
break;
case 2:
change_membound_time();
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word) & 0xFF);
change_membound_time();
grab_macmem_ptr[mpc106_address] |= (uint8_t)((mpc106_read_word >> 8) & 0xFF);
break;
case 4:
change_membound_time();
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word) & 0xFF);
change_membound_time();
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word >> 8) & 0xFF);
change_membound_time();
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word >> 16) & 0xFF);
change_membound_time();
grab_macmem_ptr[mpc106_address] |= (uint8_t)((mpc106_read_word >> 24) & 0xFF);
break;
}
}
else{
switch(write_length){
case 1:
grab_macmem_ptr[mpc106_address] |= (uint8_t)((mpc106_read_word) & 0xFF);
break;
case 2:
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word) & 0xFF);
grab_macmem_ptr[mpc106_address] |= (uint8_t)((mpc106_read_word >> 8) & 0xFF);
break;
case 4:
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word) & 0xFF);
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word >> 8) & 0xFF);
grab_macmem_ptr[mpc106_address++] |= (uint8_t)((mpc106_read_word >> 16) & 0xFF);
grab_macmem_ptr[mpc106_address] |= (uint8_t)((mpc106_read_word >> 24) & 0xFF);
break;
}
}
}
void change_membound_time(){
if (mpc106_address < 0x88){
mpc106_set_membound_begin(mpc106_address);
mpc106_membound_change = false;
}
else if (mpc106_address < 0x90){
mpc106_set_membound_extbegin(mpc106_address);
mpc106_membound_change = false;
}
else if (mpc106_address < 0x98){
mpc106_set_membound_end(mpc106_address);
mpc106_membound_change = false;
}
else if (mpc106_address < 0xA0){
mpc106_set_membound_extend(mpc106_address);
mpc106_membound_change = false;
}
}

View File

@ -1,38 +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 MPC106
#ifndef MPC106_H_
#define MPC106_H_
#define mpc106_addres_map_a 1
#define mpc106_addres_map_b 0
extern uint32_t mpc106_address;
extern uint32_t mpc_config_addr;
extern uint32_t mpc_config_dat;
extern uint32_t mpc106_write_word;
extern uint32_t mpc106_read_word;
extern uint16_t mpc106_write_half;
extern uint16_t mpc106_read_half;
extern uint8_t mpc106_write_byte;
extern uint8_t mpc106_read_byte;
extern uint8_t mpc106_word_custom_size;
extern unsigned char* mpc106_regs;
extern void change_membound_time();
extern void mpc106_init();
extern void mpc106_read();
extern void mpc106_write(uint32_t write_word);
extern uint32_t mpc106_write_device(uint32_t device_addr, uint32_t insert_to_device, uint8_t bit_length);
extern uint32_t mpc106_read_device(uint32_t device_addr, uint8_t bit_length);
extern bool mpc106_check_membound(uint32_t attempted_address);
#endif

View File

@ -1,136 +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 OPENPIC
#include <iostream>
#include <cstring>
#include <cinttypes>
#include "ppcemumain.h"
uint32_t openpic_address;
uint32_t openpic_write_word;
uint32_t openpic_read_word;
uint32_t openpic_prev_address;
bool openpic_int_go;
//OPENPIC ADDRESS MAP goes like this...
//(Assuming that it's placed at 0x80040000
//Per Processor Registers [private access] 0x40000 - 0x40fff
//Global registers 0x41000 - 0x4ffff
//Interrupt Source Configuration Registers 0x50000 - 0x5ffff
//Per Processor Registers [global access] 0x60000 - 0x7ffff
//Taken from FreeBSD source code
void openpic_init(){
machine_upperiocontrol_mem[0x40000] = 0x14;
machine_upperiocontrol_mem[0x40001] = 0x10;
machine_upperiocontrol_mem[0x40002] = 0x46;
machine_upperiocontrol_mem[0x40003] = 0x00;
machine_upperiocontrol_mem[0x40007] = 0x02;
for (int i = 0x41004; i < 0x7FFFF; i++){
if (i % 16 == 0){
i += 4;
}
machine_upperiocontrol_mem[i] = 0xFF;
}
machine_upperiocontrol_mem[0x41000] = 0x02;
machine_upperiocontrol_mem[0x41002] = 0x80;
machine_upperiocontrol_mem[0x41080] = 0x14;
machine_upperiocontrol_mem[0x41081] = 0x46;
machine_upperiocontrol_mem[0x41090] = 0x01;
machine_upperiocontrol_mem[0x410E0] = 0xFF;
}
void openpic_read(){
if (openpic_address > 0x60000){
openpic_address = (openpic_address % 0x8000) + 0x60000;
}
openpic_read_word = (uint32_t)(machine_upperiocontrol_mem[openpic_address++]);
openpic_read_word = (uint32_t)((machine_upperiocontrol_mem[openpic_address++]) << 8);
openpic_read_word = (uint32_t)((machine_upperiocontrol_mem[openpic_address++]) << 16);
openpic_read_word = (uint32_t)((machine_upperiocontrol_mem[openpic_address]) << 24);
}
void openpic_write(){
//Max of 128 interrupts per processor
//Each interrupt line takes up 0x8000 bytes
uint32_t op_interrupt_check = (openpic_address & 0xFF);
//We have only one processor
if (openpic_address > 0x60000){
openpic_address = (openpic_address % 0x8000) + 0x60000;
}
switch(openpic_address){
//Make sure we don't touch any of the following read-only regs
case 0x41000:
case 0x41080:
case 0x41100:
case 0x41140:
case 0x41180:
case 0x411C0:
case 0x600A0:
case 0x600B0:
case 0x610A0:
case 0x610B0:
case 0x620A0:
case 0x620B0:
case 0x630A0:
case 0x630B0:
return;
default:
if (openpic_address == openpic_prev_address){
return;
}
else{
openpic_prev_address = openpic_address;
}
machine_upperiocontrol_mem[openpic_address++] = (uint8_t)(openpic_write_word);
machine_upperiocontrol_mem[openpic_address++] = (uint8_t)((openpic_write_word) >> 8);
machine_upperiocontrol_mem[openpic_address++] = (uint8_t)((openpic_write_word) >> 16);
machine_upperiocontrol_mem[openpic_address] = (uint8_t)((openpic_write_word) >> 24);
break;
}
switch (op_interrupt_check){
case 0x40:
printf("IPI 0 stuff goes here! \n");
break;
case 0x50:
printf("IPI 1 stuff goes here! \n");
break;
case 0x60:
printf("IPI 2 stuff goes here! \n");
break;
case 0x70:
printf("IPI 3 stuff goes here! \n");
break;
case 0x80:
printf("Task Priority Reg stuff goes here! \n");
break;
case 0x90:
printf("WHOAMI stuff goes here! \n");
break;
case 0xA0:
openpic_int_go = true;
break;
case 0xB0:
openpic_int_go = false;
break;
}
}

View File

@ -1,21 +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 OPENPIC
#ifndef OPENPIC_H_
#define OPENPIC_H_
extern uint32_t openpic_address;
extern uint32_t openpic_write_word;
extern uint32_t openpic_read_word;
extern void openpic_init();
extern void openpic_read();
extern void openpic_write();
#endif

View File

@ -10,6 +10,8 @@
#include <map>
#include "devices/memctrlbase.h"
//Uncomment this to help debug the emulator further
//#define EXHAUSTIVE_DEBUG 1
@ -102,7 +104,7 @@ extern uint32_t ram_size_set;
extern uint32_t rom_file_begin; //where to start storing ROM files in memory
extern uint32_t pci_io_end;
extern uint32_t rom_file_setsize;
extern uint32_t rom_filesize;
//Additional steps to prevent overflow?
extern int32_t add_result;
@ -226,6 +228,8 @@ void ppc_tbr_update();
void ppc_exception_handler(uint32_t exception_type, uint32_t handle_args);
//MEMORY DECLARATIONS
extern MemCtrlBase *mem_ctrl_instance;
extern unsigned char * machine_sysram_mem;
extern unsigned char * machine_sysconfig_mem;
//Mapped to 0x68000000 - extern unsigned char * machine_68kemu_mem;

View File

@ -14,14 +14,11 @@
#include <array>
#include <thread>
#include <atomic>
#include "viacuda.h"
#include "macioserial.h"
#include "macswim3.h"
#include "ppcemumain.h"
#include "ppcmemory.h"
#include "openpic.h"
#include "mpc106.h"
#include "davbus.h"
#include "devices/memctrlbase.h"
#include "devices/mmiodevice.h"
#include "devices/mpc106.h"
std::vector<uint32_t> pte_storage;
@ -94,76 +91,70 @@ void msr_status_update(){
msr_dr_test = (ppc_state.ppc_msr >> 4) & 1;
}
inline void ppc_set_cur_instruction(uint32_t mem_index)
static inline void ppc_set_cur_instruction(unsigned char *ptr, uint32_t offset)
{
ppc_cur_instruction = (grab_macmem_ptr[mem_index] << 24) |
(grab_macmem_ptr[mem_index+1] << 16) |
(grab_macmem_ptr[mem_index+2] << 8) |
grab_macmem_ptr[mem_index+3];
ppc_cur_instruction = (ptr[offset] << 24) | (ptr[offset+1] << 16) |
(ptr[offset+2] << 8) | ptr[offset+3];
}
void ppc_set_return_val(uint32_t mem_index, int num_size)
static inline void ppc_set_return_val(unsigned char *ptr, uint32_t offset,
int num_size)
{
//Put the final result in return_value here
//This is what gets put back into the register
if (ppc_state.ppc_msr & 1) { /* little-endian byte ordering */
if (num_size == 1) { // BYTE
return_value = grab_macmem_ptr[mem_index];
return_value = ptr[offset];
}
else if (num_size == 2) { // WORD
return_value = grab_macmem_ptr[mem_index] |
(grab_macmem_ptr[mem_index+1] << 8);
return_value = ptr[offset] | (ptr[offset+1] << 8);
}
else if (num_size == 4) { // DWORD
return_value = grab_macmem_ptr[mem_index] |
(grab_macmem_ptr[mem_index+1] << 8) |
(grab_macmem_ptr[mem_index+2] << 16) |
(grab_macmem_ptr[mem_index+3] << 24);
return_value = ptr[offset] | (ptr[offset+1] << 8) |
(ptr[offset+2] << 16) | (ptr[offset+3] << 24);
}
} else { /* big-endian byte ordering */
if (num_size == 1) { // BYTE
return_value = grab_macmem_ptr[mem_index];
return_value = ptr[offset];
}
else if (num_size == 2) { // WORD
return_value = (grab_macmem_ptr[mem_index] << 8) |
grab_macmem_ptr[mem_index+1];
return_value = (ptr[offset] << 8) | ptr[offset+1];
}
else if (num_size == 4) { // DWORD
return_value = (grab_macmem_ptr[mem_index] << 24) |
(grab_macmem_ptr[mem_index+1] << 16) |
(grab_macmem_ptr[mem_index+2] << 8) |
grab_macmem_ptr[mem_index+3];
return_value = (ptr[offset] << 24) | (ptr[offset+1] << 16) |
(ptr[offset+2] << 8) | ptr[offset+3];
}
}
}
void ppc_memstore_value(uint32_t value_insert, uint32_t mem_index, int num_size)
static inline void ppc_memstore_value(unsigned char *ptr, uint32_t value,
uint32_t offset, int num_size)
{
if (ppc_state.ppc_msr & 1) { /* little-endian byte ordering */
if (num_size >= 1) { // BYTE
grab_macmem_ptr[mem_index] = value_insert & 0xFF;
ptr[offset] = value & 0xFF;
}
if (num_size >= 2) { // WORD
grab_macmem_ptr[mem_index+1] = (value_insert >> 8) & 0xFF;
ptr[offset+1] = (value >> 8) & 0xFF;
}
if (num_size == 4) { // DWORD
grab_macmem_ptr[mem_index+2] = (value_insert >> 16) & 0xFF;
grab_macmem_ptr[mem_index+3] = (value_insert >> 24) & 0xFF;
ptr[offset+2] = (value >> 16) & 0xFF;
ptr[offset+3] = (value >> 24) & 0xFF;
}
} else { /* big-endian byte ordering */
if (num_size == 1) { // BYTE
grab_macmem_ptr[mem_index] = value_insert & 0xFF;
ptr[offset] = value & 0xFF;
}
else if (num_size == 2) { // WORD
grab_macmem_ptr[mem_index] = (value_insert >> 8) & 0xFF;
grab_macmem_ptr[mem_index+1] = value_insert & 0xFF;
ptr[offset] = (value >> 8) & 0xFF;
ptr[offset+1] = value & 0xFF;
}
else if (num_size == 4) { // DWORD
grab_macmem_ptr[mem_index] = (value_insert >> 24) & 0xFF;
grab_macmem_ptr[mem_index+1] = (value_insert >> 16) & 0xFF;
grab_macmem_ptr[mem_index+2] = (value_insert >> 8) & 0xFF;
grab_macmem_ptr[mem_index+3] = value_insert & 0xFF;
ptr[offset] = (value >> 24) & 0xFF;
ptr[offset+1] = (value >> 16) & 0xFF;
ptr[offset+2] = (value >> 8) & 0xFF;
ptr[offset+3] = value & 0xFF;
}
}
}
@ -282,7 +273,7 @@ void get_pointer_pteg1(uint32_t address_grab){
}
}
else{
pte_word1 = address_grab % rom_file_setsize;
pte_word1 = address_grab % rom_filesize;
grab_pteg1_ptr = machine_sysrom_mem;
}
}
@ -359,7 +350,7 @@ void get_pointer_pteg2(uint32_t address_grab){
}
}
else{
pte_word2 = address_grab % rom_file_setsize;
pte_word2 = address_grab % rom_filesize;
grab_pteg2_ptr = machine_sysrom_mem;
}
}
@ -561,465 +552,101 @@ uint32_t ppc_mmu_addr_translate(uint32_t la, uint32_t access_type)
}
/** Insert a value into memory from a register. */
void address_quickinsert_translate(uint32_t value_insert, uint32_t address_grab,
uint8_t num_bytes)
uint32_t write_last_pa_start = 0;
uint32_t write_last_pa_end = 0;
unsigned char *write_last_ptr = 0;
void address_quickinsert_translate(uint32_t value, uint32_t addr, uint8_t num_bytes)
{
uint32_t storage_area = 0;
printf("Inserting into address %x with %x \n", address_grab, value_insert);
// data address translation if enabled
if (ppc_state.ppc_msr & 0x10) {
printf("DATA RELOCATION GO! - INSERTING \n");
address_grab = ppc_mmu_addr_translate(address_grab, 0);
}
//regular grabbing
if (address_grab < 0x80000000){
if (mpc106_check_membound(address_grab)){
if (address_grab > 0x03ffffff){ //for debug purposes
storage_area = address_grab;
grab_macmem_ptr = machine_sysram_mem;
}
else if ((address_grab >= 0x40000000) && (address_grab < 0x40400000)){
if (is_nubus){
storage_area = address_grab % rom_file_setsize;
grab_macmem_ptr = machine_sysrom_mem;
ppc_memstore_value(value_insert, storage_area, num_bytes);
return;
}
else{
return;
}
}
else if ((address_grab >= 0x5fffe000) && (address_grab <= 0x5fffffff)){
storage_area = address_grab % 0x2000;
grab_macmem_ptr = machine_sysconfig_mem;
}
else{
storage_area = address_grab % 0x04000000;
grab_macmem_ptr = machine_sysram_mem;
printf("Uncharted territory: %x \n", address_grab);
}
}
else{
return;
}
}
else if (address_grab < 0x80800000){
storage_area = address_grab % 0x800000;
if (address_grab == 0x80000CF8){
storage_area = 0x0CF8; //CONFIG_ADDR
value_insert = rev_endian32(value_insert);
grab_macmem_ptr = machine_fecxxx_mem;
uint32_t reg_num = (value_insert & 0x07FC) >> 2;
uint32_t dev_num = (value_insert & 0xF800) >> 11;
printf("ADDRESS SET FOR GRACKLE: ");
printf("Device Number: %d ", dev_num);
printf("Hex Register Number: %x \n", reg_num);
mpc106_address = value_insert;
}
else{
grab_macmem_ptr = machine_upperiocontrol_mem;
}
if ((address_grab >= 0x80040000) && (address_grab < 0x80080000)){
openpic_address = address_grab - 0x80000000;
openpic_read_word = value_insert;
openpic_read();
return;
}
printf("Uncharted territory: %x \n", address_grab);
}
else if (address_grab < 0x81000000){
if (address_grab > 0x83FFFFFF){
return;
}
storage_area = address_grab;
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_iocontrolcdma_mem;
}
else if (address_grab < 0xBF800000){
storage_area = address_grab % 33554432;
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_loweriocontrol_mem;
}
else if (address_grab < 0xC0000000){
storage_area = address_grab % 16;
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_interruptack_mem;
}
else if (address_grab < 0xF0000000){
printf("Invalid Memory Attempt: %x \n", address_grab);
return;
}
else if (address_grab < 0xF8000000){
storage_area = address_grab % 67108864;
if ((address_grab >= 0xF3013000) && (address_grab < 0xF3013040)){
mac_serial_address = storage_area;
serial_write_byte = (uint8_t)value_insert;
printf("Writing byte to Serial address %x ... %x \n", address_grab, via_write_byte);
mac_serial_write();
return;
}
else if ((address_grab >= 0xF3014000) && (address_grab < 0xF3015000)){
davbus_address = storage_area;
davbus_write_word = value_insert;
printf("\nWriting to DAVBus: %x \n", return_value);
davbus_write();
return;
}
else if ((address_grab >= 0xF3015000) && (address_grab < 0xF3016000)){
mac_swim3_address = storage_area;
swim3_write_byte = (uint8_t)value_insert;
printf("Writing byte to SWIM3 address %x ... %x \n", address_grab, swim3_write_byte);
mac_swim3_write();
return;
}
else if ((address_grab >= 0xF3016000) && (address_grab < 0xF3018000)){
via_cuda_address = storage_area;
via_write_byte = (uint8_t)value_insert;
printf("Writing byte to CUDA address %x ... %x \n", address_grab, via_write_byte);
via_cuda_write();
return;
}
else if ((address_grab >= 0xF3040000) && (address_grab < 0xF3080000)){
openpic_address = storage_area - 0x3000000;
openpic_write_word = value_insert;
printf("Writing byte to OpenPIC address %x ... %x \n", address_grab, openpic_write_word);
openpic_write();
return;
}
else if (address_grab > 0xF3FFFFFF){
printf("Uncharted territory: %x", address_grab);
return;
}
grab_macmem_ptr = machine_iocontrolmem_mem;
}
else if (address_grab < rom_file_begin){
//Get back to this! (weeny1)
if (address_grab < 0xFE000000){
storage_area = address_grab % 4096;
grab_macmem_ptr = machine_f8xxxx_mem;
}
else if (address_grab < 0xFEC00000){
mpc106_address = address_grab % 65536;
mpc106_write(value_insert);
return;
}
else if (address_grab < 0xFEE00000){
storage_area = 0x0CF8; //CONFIG_ADDR
grab_macmem_ptr = machine_fecxxx_mem;
value_insert = rev_endian32(value_insert);
uint32_t reg_num = (value_insert & 0x07FC) >> 2;
uint32_t dev_num = (value_insert & 0xF800) >> 11;
printf("ADDRESS SET FOR GRACKLE \n");
printf("Device Number: %d ", dev_num);
printf("Hex Register Number: %x \n", reg_num);
mpc_config_addr = value_insert;
}
else if (address_grab < 0xFF000000){
storage_area = 0x0CFC; //CONFIG_DATA
mpc106_word_custom_size = num_bytes;
mpc106_write_device(mpc_config_addr, value_insert, num_bytes);
grab_macmem_ptr = machine_feexxx_mem;
}
else if (address_grab < 0xFF800000){
storage_area = address_grab % 4096;
grab_macmem_ptr = machine_ff00xx_mem;
}
else{
storage_area = (address_grab % 1048576) + 0x400000;
grab_macmem_ptr = machine_sysram_mem;
}
}
else{
storage_area = address_grab % rom_file_setsize;
grab_macmem_ptr = machine_sysrom_mem;
}
ppc_memstore_value(value_insert, storage_area, num_bytes);
}
/** Grab a value from memory into a register */
void address_quickgrab_translate(uint32_t address_grab, uint8_t num_bytes)
{
uint32_t storage_area = 0;
//printf("Grabbing from address %x \n", address_grab);
return_value = 0; //reset this before going into the real fun.
/* data address translation if enabled */
if (ppc_state.ppc_msr & 0x10) {
printf("DATA RELOCATION GO! - GRABBING \n");
address_grab = ppc_mmu_addr_translate(address_grab, 0);
addr = ppc_mmu_addr_translate(addr, 0);
}
if (address_grab >= 0xFFC00000){
//printf("Charting ROM Area: %x \n", address_grab);
storage_area = address_grab % rom_file_setsize;
grab_macmem_ptr = machine_sysrom_mem;
ppc_set_return_val(storage_area, num_bytes);
return;
}
//regular grabbing
else if (address_grab < 0x80000000){
if ((address_grab >= 0x40000000) && (address_grab < 0x40400000) && is_nubus){
storage_area = address_grab % rom_file_setsize;
grab_macmem_ptr = machine_sysrom_mem;
ppc_set_return_val(storage_area, num_bytes);
return;
}
if (mpc106_check_membound(address_grab)){
if (address_grab > 0x03ffffff){ //for debug purposes
storage_area = address_grab;
grab_macmem_ptr = machine_sysram_mem;
if (addr >= write_last_pa_start && addr <= write_last_pa_end) {
ppc_memstore_value(write_last_ptr, value, addr - write_last_pa_start, num_bytes);
} else {
AddressMapEntry *entry = mem_ctrl_instance->find_range(addr);
if (entry) {
if (entry->type & RT_RAM) {
write_last_pa_start = entry->start;
write_last_pa_end = entry->end;
write_last_ptr = entry->mem_ptr;
ppc_memstore_value(write_last_ptr, value, addr - entry->start, num_bytes);
} else if (entry->type & RT_MMIO) {
entry->devobj->write(addr - entry->start, value, num_bytes);
} else {
printf("Please check your address map!\n");
}
else if ((address_grab >= 0x40000000) && (address_grab < 0x40400000)){
storage_area = address_grab;
grab_macmem_ptr = machine_sysram_mem;
}
else if ((address_grab >= 0x5fffe000) && (address_grab <= 0x5fffffff)){
storage_area = address_grab % 0x2000;
grab_macmem_ptr = machine_sysconfig_mem;
}
else{
return_value = (num_bytes == 1)?0xFF:(num_bytes == 2)?0xFFFF:0xFFFFFFFF;
return;
}
}
else{
//The address is not within the ROM banks
return_value = (num_bytes == 1)?0xFF:(num_bytes == 2)?0xFFFF:0xFFFFFFFF;
return;
} else {
printf("WARNING: write attempt to unmapped memory at 0x%08X!\n", addr);
}
}
else if (address_grab < 0x80800000){
if ((address_grab >= 0x80040000) && (address_grab < 0x80080000)){
openpic_address = address_grab - 0x80000000;
openpic_write();
return_value = openpic_write_word;
return;
}
storage_area = address_grab % 0x800000;
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_upperiocontrol_mem;
}
else if (address_grab < 0x81000000){
storage_area = address_grab;
if (address_grab > 0x83FFFFFF){
return_value = (num_bytes == 1)?0xFF:(num_bytes == 2)?0xFFFF:0xFFFFFFFF;
return;
}
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_iocontrolcdma_mem;
}
else if (address_grab < 0xBF800000){
storage_area = address_grab % 33554432;
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_loweriocontrol_mem;
}
else if (address_grab < 0xC0000000){
storage_area = address_grab % 16;
printf("Uncharted territory: %x \n", address_grab);
grab_macmem_ptr = machine_interruptack_mem;
}
else if (address_grab < 0xF0000000){
return_value = (num_bytes == 1)?0xFF:(num_bytes == 2)?0xFFFF:0xFFFFFFFF;
return;
}
else if (address_grab < 0xF8000000){
storage_area = address_grab % 67108864;
if ((address_grab >= 0xF3013000) && (address_grab < 0xF3013040)){
mac_serial_address = storage_area;
mac_serial_read();
return_value = serial_read_byte;
printf("\n Read from Serial: %x \n", return_value);
return;
}
else if ((address_grab >= 0xF3014000) && (address_grab < 0xF3015000)){
davbus_address = storage_area;
davbus_read();
return_value = davbus_read_word;
printf("\n Read from DAVBus: %x \n", return_value);
return;
}
else if ((address_grab >= 0xF3015000) && (address_grab < 0xF3016000)){
mac_swim3_address = storage_area;
mac_swim3_read();
return_value = swim3_read_byte;
printf("\n Read from Swim3: %x \n", return_value);
return;
}
else if ((address_grab >= 0xF3016000) && (address_grab < 0xF3018000)){
via_cuda_address = storage_area;
via_cuda_read();
return_value = via_read_byte;
printf("\n Read from CUDA: %x \n", return_value);
return;
}
else if ((address_grab >= 0xF3040000) && (address_grab < 0xF3080000)){
openpic_address = storage_area - 0x3000000;
openpic_read();
return_value = openpic_write_word;
return;
}
else if (address_grab > 0xF3FFFFFF){
return_value = (num_bytes == 1)?0xFF:(num_bytes == 2)?0xFFFF:0xFFFFFFFF;
return;
}
grab_macmem_ptr = machine_iocontrolmem_mem;
}
else if (address_grab < rom_file_begin){
//Get back to this! (weeny1)
if (address_grab < 0xFE000000){
storage_area = address_grab % 4096;
grab_macmem_ptr = machine_f8xxxx_mem;
}
else if (address_grab < 0xFEC00000){
mpc106_address = address_grab % 65536;
mpc106_read();
return_value = mpc106_read_word;
return;
}
else if (address_grab < 0xFEE00000){
return_value = (num_bytes == 1)? (mpc106_address & 0xFF):(num_bytes == 2)?(mpc106_address & 0xFFFF):mpc106_address;
return;
}
else if (address_grab < 0xFF000000){
mpc106_word_custom_size = num_bytes;
return_value = mpc106_read_device(mpc_config_addr, num_bytes);
return_value = rev_endian32(return_value);
return;
}
else if (address_grab < 0xFF800000){
storage_area = address_grab % 4096;
grab_macmem_ptr = machine_ff00xx_mem;
}
else{
storage_area = (address_grab % 1048576) + 0x400000;
grab_macmem_ptr = machine_sysram_mem;
}
}
ppc_set_return_val(storage_area, num_bytes);
}
void quickinstruction_translate(uint32_t address_grab)
uint32_t read_last_pa_start = 0;
uint32_t read_last_pa_end = 0;
unsigned char *read_last_ptr = 0;
/** Grab a value from memory into a register */
void address_quickgrab_translate(uint32_t addr, uint8_t num_bytes)
{
uint32_t storage_area = 0;
/* data address translation if enabled */
if (ppc_state.ppc_msr & 0x10) {
//printf("DATA RELOCATION GO! - GRABBING \n");
return_value = 0; //reset this before going into the real fun.
addr = ppc_mmu_addr_translate(addr, 0);
}
if (addr >= read_last_pa_start && addr <= read_last_pa_end) {
ppc_set_return_val(read_last_ptr, addr - read_last_pa_start, num_bytes);
} else {
AddressMapEntry *entry = mem_ctrl_instance->find_range(addr);
if (entry) {
if (entry->type & (RT_ROM | RT_RAM)) {
read_last_pa_start = entry->start;
read_last_pa_end = entry->end;
read_last_ptr = entry->mem_ptr;
ppc_set_return_val(read_last_ptr, addr - entry->start, num_bytes);
} else if (entry->type & RT_MMIO) {
return_value = entry->devobj->read(addr - entry->start, num_bytes);
} else {
printf("Please check your address map!\n");
}
} else {
printf("WARNING: read attempt from unmapped memory at 0x%08X!\n", addr);
/* reading from unmapped memory will return unmapped value */
for (return_value = 0xFF; --num_bytes > 0;)
return_value = (return_value << 8) | 0xFF;
}
}
}
uint32_t exec_last_pa_start = 0;
uint32_t exec_last_pa_end = 0;
unsigned char *exec_last_ptr = 0;
void quickinstruction_translate(uint32_t addr)
{
/* instruction address translation if enabled */
if (ppc_state.ppc_msr & 0x20) {
printf("INSTRUCTION RELOCATION GO! \n");
address_grab = ppc_mmu_instr_translate(address_grab);
addr = ppc_mmu_instr_translate(addr);
}
//grab opcode from memory area
if (address_grab >= 0xFFC00000){
storage_area = address_grab % rom_file_setsize;
grab_macmem_ptr = machine_sysrom_mem;
ppc_set_cur_instruction(storage_area);
return;
}
else if (address_grab < 0x80000000){
if (address_grab < 0x040000000){ //for debug purposes
storage_area = address_grab;
grab_macmem_ptr = machine_sysram_mem;
}
else if ((address_grab >= 0x40000000) && (address_grab < 0x40400000)){
if (is_nubus){
storage_area = address_grab % rom_file_setsize;
grab_macmem_ptr = machine_sysrom_mem;
ppc_set_cur_instruction(storage_area);
return;
}
else{
storage_area = address_grab;
grab_macmem_ptr = machine_sysram_mem;
}
}
else if ((address_grab >= 0x5fffe000) && (address_grab <= 0x5fffffff)){
storage_area = address_grab % 0x2000;
grab_macmem_ptr = machine_sysconfig_mem;
}
else{
storage_area = address_grab % 0x04000000;
grab_macmem_ptr = machine_sysram_mem;
printf("Uncharted territory: %x \n", address_grab);
if (addr >= exec_last_pa_start && addr <= exec_last_pa_end) {
ppc_set_cur_instruction(exec_last_ptr, addr - exec_last_pa_start);
} else {
AddressMapEntry *entry = mem_ctrl_instance->find_range(addr);
if (entry && entry->type & (RT_ROM | RT_RAM)) {
exec_last_pa_start = entry->start;
exec_last_pa_end = entry->end;
exec_last_ptr = entry->mem_ptr;
ppc_set_cur_instruction(exec_last_ptr, addr - exec_last_pa_start);
} else {
printf("WARNING: attempt to execute code at %08X!\n", addr);
}
}
else if (address_grab < 0x80800000){
storage_area = address_grab % 0x800000;
grab_macmem_ptr = machine_upperiocontrol_mem;
}
else if (address_grab < 0x81000000){
storage_area = address_grab % 0x800000;
grab_macmem_ptr = machine_iocontrolcdma_mem;
}
else if (address_grab < 0xBF80000){
storage_area = address_grab % 33554432;
grab_macmem_ptr = machine_loweriocontrol_mem;
}
else if (address_grab < 0xC0000000){
storage_area = address_grab % 16;
grab_macmem_ptr = machine_interruptack_mem;
}
else if (address_grab < 0xF0000000){
printf("Invalid Memory Attempt: %x \n", address_grab);
return;
}
else if (address_grab < 0xF8000000){
storage_area = address_grab % 67108864;
grab_macmem_ptr = machine_iocontrolmem_mem;
}
else if (address_grab < rom_file_begin){
//Get back to this! (weeny1)
if (address_grab < 0xFE000000){
storage_area = address_grab % 4096;
grab_macmem_ptr = machine_f8xxxx_mem;
}
else if (address_grab < 0xFEC00000){
storage_area = address_grab % 65536;
grab_macmem_ptr = machine_fexxxx_mem;
}
else if (address_grab < 0xFEE00000){
storage_area = 0x0CF8; //CONFIG_ADDR
grab_macmem_ptr = machine_fecxxx_mem;
}
else if (address_grab < 0xFF000000){
storage_area = 0x0CFC; //CONFIG_DATA
grab_macmem_ptr = machine_feexxx_mem;
}
else if (address_grab < 0xFF800000){
storage_area = address_grab % 4096;
grab_macmem_ptr = machine_ff00xx_mem;
}
else{
storage_area = (address_grab % 1048576) + 0x400000;
grab_macmem_ptr = machine_sysram_mem;
}
}
ppc_set_cur_instruction(storage_area);
}

View File

@ -1899,15 +1899,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