mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 05:29:43 +00:00
Merge branch 'devices' into 'master'.
This commit is contained in:
commit
e50f4396db
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
||||
|
||||
# Ignore compiled object files
|
||||
*.o
|
||||
*.d
|
||||
|
||||
# Ignore generated executables
|
||||
dingusppc
|
||||
|
35
davbus.cpp
35
davbus.cpp
@ -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);
|
||||
}
|
22
davbus.h
22
davbus.h
@ -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
155
devices/heathrow.cpp
Normal 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
37
devices/machineid.h
Normal 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
109
devices/macio.h
Normal 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
131
devices/memctrlbase.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "memctrlbase.h"
|
||||
|
||||
|
||||
MemCtrlBase::MemCtrlBase(std::string name)
|
||||
{
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
|
||||
MemCtrlBase::~MemCtrlBase()
|
||||
{
|
||||
for (auto ® : 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
53
devices/memctrlbase.h
Normal 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
22
devices/mmiodevice.h
Normal 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
223
devices/mpc106.cpp
Normal 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
91
devices/mpc106.h
Normal 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
34
devices/pcidevice.h
Normal 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
15
devices/pcihost.h
Normal 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
326
devices/viacuda.cpp
Normal 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
123
devices/viacuda.h
Normal 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 */
|
102
macioserial.cpp
102
macioserial.cpp
@ -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];
|
||||
|
||||
}
|
@ -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
|
31
macscsi.cpp
31
macscsi.cpp
@ -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(){
|
||||
|
||||
}
|
||||
|
21
macscsi.h
21
macscsi.h
@ -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
|
29
macswim3.cpp
29
macswim3.cpp
@ -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;
|
||||
}
|
19
macswim3.h
19
macswim3.h
@ -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
247
main.cpp
@ -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);
|
||||
|
27
makefile
27
makefile
@ -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)
|
||||
|
372
mpc106.cpp
372
mpc106.cpp
@ -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;
|
||||
}
|
||||
}
|
38
mpc106.h
38
mpc106.h
@ -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
|
136
openpic.cpp
136
openpic.cpp
@ -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;
|
||||
}
|
||||
}
|
21
openpic.h
21
openpic.h
@ -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
|
@ -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;
|
||||
|
591
ppcmemory.cpp
591
ppcmemory.cpp
@ -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);
|
||||
}
|
||||
|
@ -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(){
|
||||
|
153
viacuda.cpp
153
viacuda.cpp
@ -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;
|
||||
}
|
48
viacuda.h
48
viacuda.h
@ -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
|
Loading…
x
Reference in New Issue
Block a user