Compare commits
10 Commits
9a70c3bdb0
...
a5416f521a
Author | SHA1 | Date |
---|---|---|
dingusdev | a5416f521a | |
joevt | a8023bb41b | |
dingusdev | fa01699786 | |
dingusdev | 5f1150cf4e | |
joevt | 5022ac89b4 | |
joevt | 382246905b | |
joevt | a5241d27c1 | |
joevt | 4479ecb1bb | |
joevt | b454ab45fe | |
joevt | d06d80619e |
|
@ -25,8 +25,10 @@
|
|||
- AppleFritter
|
||||
- Archive.org
|
||||
- Bitsavers
|
||||
- Blitter.net
|
||||
- Emaculation
|
||||
- GitHub
|
||||
- PenguinPPC
|
||||
- The makers of Loguru, SDL2, Capstone, and CLI11
|
||||
- The developers of other PowerPC Mac emulators, past and present
|
||||
- All those preserving the software of 68k and PowerPC Macs
|
||||
|
|
|
@ -33,6 +33,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach_time.h>
|
||||
#undef EXC_SYSCALL
|
||||
static struct mach_timebase_info timebase_info;
|
||||
static uint64_t
|
||||
ConvertHostTimeToNanos2(uint64_t host_time)
|
||||
{
|
||||
if (timebase_info.numer == timebase_info.denom)
|
||||
return host_time;
|
||||
long double answer = host_time;
|
||||
answer *= timebase_info.numer;
|
||||
answer /= timebase_info.denom;
|
||||
return (uint64_t)answer;
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace dppc_interpreter;
|
||||
|
||||
|
@ -65,7 +81,7 @@ bool dec_exception_pending = false;
|
|||
uint32_t glob_bb_start_la;
|
||||
|
||||
/* variables related to virtual time */
|
||||
bool g_realtime;
|
||||
const bool g_realtime = false;
|
||||
uint64_t g_nanoseconds_base;
|
||||
uint64_t g_icycles_base;
|
||||
uint64_t g_icycles;
|
||||
|
@ -277,9 +293,13 @@ void ppc_main_opcode()
|
|||
OpcodeGrabber[(ppc_cur_instruction >> 26) & 0x3F]();
|
||||
}
|
||||
|
||||
static long long now_ns() {
|
||||
long long now_ns() {
|
||||
#ifdef __APPLE__
|
||||
return ConvertHostTimeToNanos2(mach_absolute_time());
|
||||
#else
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t get_virt_time_ns()
|
||||
|
@ -841,7 +861,9 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, bool include_601,
|
|||
TimerManager::get_instance()->set_notify_changes_cb(&force_cycle_counter_reload);
|
||||
|
||||
// initialize time base facility
|
||||
g_realtime = false;
|
||||
#ifdef __APPLE__
|
||||
mach_timebase_info(&timebase_info);
|
||||
#endif
|
||||
g_nanoseconds_base = now_ns();
|
||||
g_icycles_base = 0;
|
||||
g_icycles = 0;
|
||||
|
|
|
@ -81,7 +81,6 @@ AddressMapEntry last_read_area;
|
|||
AddressMapEntry last_write_area;
|
||||
AddressMapEntry last_exec_area;
|
||||
AddressMapEntry last_ptab_area;
|
||||
AddressMapEntry last_dma_area;
|
||||
|
||||
/** 601-style block address translation. */
|
||||
static BATResult mpc601_block_address_translation(uint32_t la)
|
||||
|
@ -310,22 +309,16 @@ MapDmaResult mmu_map_dma_mem(uint32_t addr, uint32_t size, bool allow_mmio) {
|
|||
bool is_writable;
|
||||
AddressMapEntry *cur_dma_rgn;
|
||||
|
||||
if (addr >= last_dma_area.start && (addr + size) <= last_dma_area.end) {
|
||||
cur_dma_rgn = &last_dma_area;
|
||||
} else {
|
||||
cur_dma_rgn = mem_ctrl_instance->find_range(addr);
|
||||
if (!cur_dma_rgn || (addr + size) > cur_dma_rgn->end)
|
||||
ABORT_F("SOS: DMA access to unmapped physical memory %08X!", addr);
|
||||
|
||||
last_dma_area = *cur_dma_rgn;
|
||||
}
|
||||
cur_dma_rgn = mem_ctrl_instance->find_range(addr);
|
||||
if (!cur_dma_rgn || (addr + size) > cur_dma_rgn->end)
|
||||
ABORT_F("SOS: DMA access to unmapped physical memory %08X!", addr);
|
||||
|
||||
if ((cur_dma_rgn->type & RT_MMIO) && !allow_mmio)
|
||||
ABORT_F("SOS: DMA access to a MMIO region is not allowed");
|
||||
|
||||
if (cur_dma_rgn->type & (RT_ROM | RT_RAM)) {
|
||||
host_va = cur_dma_rgn->mem_ptr + (addr - cur_dma_rgn->start);
|
||||
is_writable = last_dma_area.type & RT_RAM;
|
||||
is_writable = cur_dma_rgn->type & RT_RAM;
|
||||
} else { // RT_MMIO
|
||||
devobj = cur_dma_rgn->devobj;
|
||||
dev_base = cur_dma_rgn->start;
|
||||
|
@ -1532,7 +1525,6 @@ void ppc_mmu_init()
|
|||
last_write_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};
|
||||
last_exec_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};
|
||||
last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};
|
||||
last_dma_area = {0xFFFFFFFF, 0xFFFFFFFF, 0, 0, nullptr, nullptr};
|
||||
|
||||
mmu_exception_handler = ppc_exception_handler;
|
||||
|
||||
|
|
|
@ -87,6 +87,17 @@ ViaCuda::ViaCuda() {
|
|||
this->cuda_init();
|
||||
|
||||
this->int_ctrl = nullptr;
|
||||
|
||||
std::tm tm = {
|
||||
.tm_sec = 0,
|
||||
.tm_min = 0,
|
||||
.tm_hour = 0,
|
||||
.tm_mday = 1,
|
||||
.tm_mon = 1 - 1,
|
||||
.tm_year = 1904 - 1900,
|
||||
.tm_isdst = -1 // Use DST value from local time zone
|
||||
};
|
||||
mac_epoch = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||
}
|
||||
|
||||
ViaCuda::~ViaCuda()
|
||||
|
@ -128,37 +139,49 @@ void ViaCuda::cuda_init() {
|
|||
}
|
||||
|
||||
uint8_t ViaCuda::read(int reg) {
|
||||
uint8_t value;
|
||||
/* reading from some VIA registers triggers special actions */
|
||||
switch (reg & 0xF) {
|
||||
case VIA_B:
|
||||
return (this->via_regs[VIA_B]);
|
||||
value = (this->via_regs[VIA_B]);
|
||||
break;
|
||||
case VIA_A:
|
||||
case VIA_ANH:
|
||||
value = this->via_regs[reg & 0xF];
|
||||
LOG_F(WARNING, "Attempted read from VIA Port A!");
|
||||
break;
|
||||
case VIA_IER:
|
||||
return (this->_via_ier | 0x80); // bit 7 always reads as "1"
|
||||
value = (this->_via_ier | 0x80); // bit 7 always reads as "1"
|
||||
break;
|
||||
case VIA_IFR:
|
||||
return this->_via_ifr;
|
||||
value = this->_via_ifr;
|
||||
break;
|
||||
case VIA_T1CL:
|
||||
this->_via_ifr &= ~VIA_IF_T1;
|
||||
update_irq();
|
||||
return this->calc_counter_val(this->t1_counter, this->t1_start_time) & 0xFFU;
|
||||
value = this->calc_counter_val(this->t1_counter, this->t1_start_time) & 0xFFU;
|
||||
break;
|
||||
case VIA_T1CH:
|
||||
return this->calc_counter_val(this->t1_counter, this->t1_start_time) >> 8;
|
||||
value = this->calc_counter_val(this->t1_counter, this->t1_start_time) >> 8;
|
||||
break;
|
||||
case VIA_T2CL:
|
||||
this->_via_ifr &= ~VIA_IF_T2;
|
||||
update_irq();
|
||||
return this->calc_counter_val(this->t2_counter, this->t2_start_time) & 0xFFU;
|
||||
value = this->calc_counter_val(this->t2_counter, this->t2_start_time) & 0xFFU;
|
||||
break;
|
||||
case VIA_T2CH:
|
||||
return this->calc_counter_val(this->t2_counter, this->t2_start_time) >> 8;
|
||||
value = this->calc_counter_val(this->t2_counter, this->t2_start_time) >> 8;
|
||||
break;
|
||||
case VIA_SR:
|
||||
value = this->via_regs[reg & 0xF];
|
||||
this->_via_ifr &= ~VIA_IF_SR;
|
||||
update_irq();
|
||||
break;
|
||||
default:
|
||||
value = this->via_regs[reg & 0xF];
|
||||
}
|
||||
|
||||
return (this->via_regs[reg & 0xF]);
|
||||
return value;
|
||||
}
|
||||
|
||||
void ViaCuda::write(int reg, uint8_t value) {
|
||||
|
@ -166,7 +189,7 @@ void ViaCuda::write(int reg, uint8_t value) {
|
|||
|
||||
switch (reg & 0xF) {
|
||||
case VIA_B:
|
||||
write(value);
|
||||
this->write(value);
|
||||
break;
|
||||
case VIA_A:
|
||||
case VIA_ANH:
|
||||
|
@ -259,7 +282,7 @@ void ViaCuda::write(int reg, uint8_t value) {
|
|||
|
||||
uint16_t ViaCuda::calc_counter_val(const uint16_t last_val, const uint64_t& last_time)
|
||||
{
|
||||
// calcualte current counter value based on elapsed time and timer frequency
|
||||
// calculate current counter value based on elapsed time and timer frequency
|
||||
uint64_t cur_time = TimerManager::get_instance()->current_time_ns();
|
||||
uint32_t diff = (cur_time - last_time) / this->via_clk_dur;
|
||||
return last_val - diff;
|
||||
|
@ -495,10 +518,7 @@ void ViaCuda::process_adb_command() {
|
|||
}
|
||||
|
||||
void ViaCuda::autopoll_handler() {
|
||||
if (!this->autopoll_enabled)
|
||||
return;
|
||||
|
||||
uint8_t poll_command = this->adb_bus_obj->poll();
|
||||
uint8_t poll_command = this->autopoll_enabled ? this->adb_bus_obj->poll() : 0;
|
||||
|
||||
if (poll_command) {
|
||||
if (!this->old_tip || !this->treq) {
|
||||
|
@ -520,6 +540,36 @@ void ViaCuda::autopoll_handler() {
|
|||
|
||||
// draw guest system's attention
|
||||
schedule_sr_int(USECS_TO_NSECS(30));
|
||||
} else if (this->one_sec_mode == 3) {
|
||||
uint32_t this_time = calc_real_time();
|
||||
if (this_time != this->last_time) {
|
||||
|
||||
if ((this->last_time & 15) == 0) {
|
||||
/*
|
||||
FIXME: This doesn't do anything in Mac OS 8.6.
|
||||
A real Mac probably doesn't do this. So why do I?
|
||||
supermario checks for packets that are not PKT_TICK
|
||||
to set the time but I don't know which Mac OS versions
|
||||
have that code and if that code is triggered by this.
|
||||
*/
|
||||
response_header(9, 0);
|
||||
this->out_buf[3] = CUDA_GET_REAL_TIME;
|
||||
uint32_t real_time = this_time + time_offset;
|
||||
WRITE_DWORD_BE_U(&this->out_buf[3], real_time);
|
||||
this->out_count = 7;
|
||||
} else {
|
||||
response_header(CUDA_PKT_TICK, 0);
|
||||
this->out_count = 1;
|
||||
}
|
||||
this->last_time = this_time;
|
||||
|
||||
// assert TREQ
|
||||
this->via_regs[VIA_B] &= ~CUDA_TREQ;
|
||||
this->treq = 0;
|
||||
|
||||
// draw guest system's attention
|
||||
schedule_sr_int(USECS_TO_NSECS(30));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,13 +606,14 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
|
|||
}
|
||||
this->is_open_ended = true;
|
||||
break;
|
||||
case CUDA_GET_REAL_TIME:
|
||||
case CUDA_GET_REAL_TIME: {
|
||||
response_header(CUDA_PKT_PSEUDO, 0);
|
||||
this->out_buf[2] = (uint8_t)((this->real_time >> 24) & 0xFF);
|
||||
this->out_buf[3] = (uint8_t)((this->real_time >> 16) & 0xFF);
|
||||
this->out_buf[4] = (uint8_t)((this->real_time >> 8) & 0xFF);
|
||||
this->out_buf[5] = (uint8_t)((this->real_time) & 0xFF);
|
||||
uint32_t this_time = this->calc_real_time();
|
||||
uint32_t real_time = this_time + time_offset;
|
||||
WRITE_DWORD_BE_U(&this->out_buf[3], real_time);
|
||||
this->out_count = 7;
|
||||
break;
|
||||
}
|
||||
case CUDA_WRITE_MCU_MEM:
|
||||
addr = READ_WORD_BE_A(&this->in_buf[2]);
|
||||
// if addr is inside PRAM, update PRAM with data from in_buf
|
||||
|
@ -587,13 +638,13 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
|
|||
error_response(CUDA_ERR_BAD_PAR);
|
||||
}
|
||||
break;
|
||||
case CUDA_SET_REAL_TIME:
|
||||
case CUDA_SET_REAL_TIME: {
|
||||
response_header(CUDA_PKT_PSEUDO, 0);
|
||||
this->real_time = ((uint32_t)in_buf[2]) >> 24;
|
||||
this->real_time += ((uint32_t)in_buf[3]) >> 16;
|
||||
this->real_time += ((uint32_t)in_buf[4]) >> 8;
|
||||
this->real_time += ((uint32_t)in_buf[5]);
|
||||
uint32_t real_time = this->calc_real_time();
|
||||
uint32_t new_time = READ_DWORD_BE_U(&in_buf[2]);
|
||||
this->time_offset = new_time - real_time;
|
||||
break;
|
||||
}
|
||||
case CUDA_WRITE_PRAM:
|
||||
addr = READ_WORD_BE_A(&this->in_buf[2]);
|
||||
if (addr <= 0xFF) {
|
||||
|
@ -637,7 +688,8 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
|
|||
this->out_buf[3] = (uint8_t)((this->device_mask) & 0xFF);
|
||||
break;
|
||||
case CUDA_ONE_SECOND_MODE:
|
||||
LOG_F(INFO, "Cuda: One Second Interrupt - Byte Sent: %d", this->in_buf[2]);
|
||||
LOG_F(INFO, "Cuda: One Second Interrupt Mode: %d", this->in_buf[2]);
|
||||
this->one_sec_mode = this->in_buf[2];
|
||||
response_header(CUDA_PKT_PSEUDO, 0);
|
||||
break;
|
||||
case CUDA_READ_WRITE_I2C:
|
||||
|
@ -673,6 +725,13 @@ void ViaCuda::pseudo_command(int cmd, int data_count) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t ViaCuda::calc_real_time() {
|
||||
auto end = std::chrono::system_clock::now();
|
||||
auto elapsed_systemclock = end - this->mac_epoch;
|
||||
auto elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>(elapsed_systemclock);
|
||||
return uint32_t(elapsed_seconds.count());
|
||||
}
|
||||
|
||||
/* sends data from the current I2C to host ad infinitum */
|
||||
void ViaCuda::i2c_handler() {
|
||||
this->receive_byte(this->curr_i2c_addr, &this->via_regs[VIA_SR]);
|
||||
|
|
|
@ -48,6 +48,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include <devices/common/nvram.h>
|
||||
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
|
||||
class AdbBus;
|
||||
class InterruptCtrl;
|
||||
|
@ -213,7 +214,10 @@ private:
|
|||
int32_t out_count;
|
||||
int32_t out_pos;
|
||||
uint8_t poll_rate;
|
||||
int32_t real_time = 0;
|
||||
uint32_t last_time = 0;
|
||||
uint32_t time_offset = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock> mac_epoch;
|
||||
uint8_t one_sec_mode = 0;
|
||||
bool file_server;
|
||||
uint16_t device_mask = 0;
|
||||
|
||||
|
@ -247,6 +251,7 @@ private:
|
|||
void process_packet();
|
||||
void process_adb_command();
|
||||
void pseudo_command(int cmd, int data_count);
|
||||
uint32_t calc_real_time();
|
||||
|
||||
void null_out_handler(void);
|
||||
void pram_out_handler(void);
|
||||
|
|
|
@ -88,7 +88,7 @@ protected:
|
|||
float refresh_rate;
|
||||
bool draw_fb = true;
|
||||
|
||||
uint32_t palette[256]; // internal DAC palette in RGBA format
|
||||
uint32_t palette[256] = {0}; // internal DAC palette in RGBA format
|
||||
|
||||
// Framebuffer parameters
|
||||
uint8_t* fb_ptr = nullptr;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
The AMIC is the I/O controller used in the Power Mac 6100.
|
||||
|
||||
It also:
|
||||
|
||||
* Controls the video timing signals
|
||||
|
||||
## Subdevices
|
||||
|
||||
| Subdevice | Range |
|
||||
|:--------------:|:--------------------:|
|
||||
| VIA Cuda | 0x0 - 0x1FFF |
|
||||
| SCC | 0x4000 - 0x5FFF |
|
||||
| SCSI | 0x10000 - 0x11FFF |
|
||||
| DMA | 0x31000 - 0x32FFF |
|
|
@ -1,4 +1,4 @@
|
|||
The ATI Rage is a video card that comes bundled with early Power Mac G3s and New World Macs (like the first revisions of the iMac G3).
|
||||
The ATI Rage is a video card that comes bundled with early Power Mac G3s and New World Macs (like the first revisions of the iMac G3). Its predecessor was the ATI Mach 64 GX, used in earlier Old World Macs.
|
||||
|
||||
# Memory Map
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
AWACS is an audio controller present on several Old World Macs and can usually be located at IOBase (ex.: 0xF3000000 for Power Mac G3 Beige) + 0x14000.
|
||||
|
||||
New World Macs have a Screamer chip, which is backwards compatible with the AWACS chip, but with some additional capabilities.
|
||||
|
||||
# Register Maps
|
||||
|
||||
## NuBus Macs
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
The KeyLargo ASIC is an intergrated I/O controller designed for use in New World Power
|
||||
Macintosh G3 and iMac computers.
|
||||
|
||||
It would later be succeeded by the K2 ASIC
|
||||
|
||||
## PCI configuration space registers
|
||||
|
||||
| Register name | Default value |
|
||||
|:-------------:|:--------------:|
|
||||
| VendorID | 0x106B (Apple) |
|
||||
| DeviceID | 0x0019 |
|
||||
| RevisionID | 0x01 |
|
||||
| Class code | 0xFF0000 |
|
||||
|
||||
## Additions
|
||||
|
||||
* USB support
|
||||
* MPIC support
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
The Old World ROM is always 4 megabytes (MB). The first three MB are reserved for the 68k code, while the last MB is for the PowerPC boot-up code.
|
||||
|
||||
New World ROMs are 1 MB stubs containing OpenFirmware and some basic drivers, but has an additional ROM stored on the Mac's hard disk to provide Toolbox functionality. The ROMs stored on the Mac's hard disk also had updates distributed.
|
||||
|
||||
Within Apple, the project to overhaul Mac OS ROM code from separate portable, low-end, and high-end branches into a single codebase was called SuperMario.
|
||||
|
||||
# Serial
|
||||
|
||||
For serial, it replicates the functionality of a Zilog ESCC. There are two different ports - one located at (MacIOBase) + 0x13000 for the printer, and the other at (MacIOBase) + 0x13020 for the modem.
|
||||
|
@ -63,6 +67,8 @@ Some New World Macs do have a SWIM 3 driver present, but this normally goes unus
|
|||
|
||||
Mac OS relies on 8 KB of NVRAM at minimum to run properly. It's usually found at IOBase (ex.: 0xF3000000 for Power Mac G3 Beige) + 0x60000.
|
||||
|
||||
On a physical machine, one has to hold the Command/Apple, Option, P and R keys together. However, using DingusPPC, one can simply delete the nvram.bin file instead.
|
||||
|
||||
# PMU
|
||||
|
||||
| Command Name | Number | Functionality |
|
||||
|
@ -77,6 +83,16 @@ Mac OS relies on 8 KB of NVRAM at minimum to run properly. It's usually found at
|
|||
| PMUPmgrPWRoff | 0x7E |
|
||||
| PMUResetCPU | 0xD0 |
|
||||
|
||||
# USB
|
||||
|
||||
|
||||
|
||||
# FireWire
|
||||
|
||||
Present in several New World Macs is a FireWire controller. Mac OS Classic normally only supports FireWire 400.
|
||||
|
||||
# Miscellaneous
|
||||
|
||||
The Power Mac G3 Beige has an additional register at 0xFF000004, which is dubbed varyingly as the "cpu-id" (by Open Firmware), the ""systemReg" (display driver) or "MachineID" (platform driver).
|
||||
* In order for the mouse to move, it generally needs to use the Vertical Blanking Interrupt (VBL) present on the video controller. However, the Pippin instead uses a virtual timer task to accomplish, as there is a bug that prevents the VBL from working in the Taos graphics controller.
|
||||
|
||||
* The Power Mac G3 Beige has an additional register at 0xFF000004, which is dubbed varyingly as the "cpu-id" (by Open Firmware), the ""systemReg" (display driver) or "MachineID" (platform driver).
|
||||
|
|
|
@ -43,6 +43,20 @@ as found in various Power Macintosh models.
|
|||
|
||||
*TBD*
|
||||
|
||||
## Packages
|
||||
|
||||
| Package Name | Purpose | Versions |
|
||||
|:--------------:|:---------------------------------------------:|:--------:|
|
||||
| obp-tftp | OpenBoot PROM with tftp | 1.0.5+ |
|
||||
| aix-boot | | 1.0.5+ |
|
||||
| xcoff-loader | | 1.0.5+ |
|
||||
| mac-files | Handle hard drives formatted with HFS | 1.0.5+ |
|
||||
| mac-parts | Find a partition with a Mac OS installed | 1.0.5+ |
|
||||
| fat-files | Handle hard drives formatted with FAT(16?) | 1.0.5+ |
|
||||
| iso-9660-files | Handle CD ROM images formatted with ISO 9660 | 1.0.5+ |
|
||||
| telnet | | 3.0+ |
|
||||
|
||||
|
||||
## Open Firmware image
|
||||
|
||||
### Old World Macs
|
||||
|
|
|
@ -36,8 +36,28 @@ Up to 128 instruction entries and 128 data entries can be stored at a time.
|
|||
| Time Base Facility (TBR) | 2 | Calculate, Store, and Load 32-bit fixed-point numbers |
|
||||
| Condition Register | 1 | Stores conditions based on the results of fixed-point operations |
|
||||
| Floating Point Condition Register | 1 | Stores conditions based on the results of floating-point operations |
|
||||
| Vector Status and Control Register (VSCR) | 1 | Stores conditions based on the results of vector operations |
|
||||
| Machine State Register | 1 | |
|
||||
|
||||
|
||||
# Special Registers
|
||||
|
||||
| Register Name | Register Number | Purpose |
|
||||
| :-------------------------------- | :------------------- | :---------------------------------------------------- |
|
||||
| Multiply Quotient Register (MQ) | 0 | (601 only) |
|
||||
| Integer Exception (XER) | 1 | |
|
||||
| RTC Upper Register (RTCU) | 4 | (601 only) |
|
||||
| RTC Lower Register (RTCL) | 5 | (601 only) |
|
||||
| Link Register (LR) | 8 | |
|
||||
| Counter Quotient Register (CTR) | 9 | |
|
||||
| Vector Save/Restore | 256 | (G4+) |
|
||||
| Time Base Lower (TBL) | 268 | (603+) |
|
||||
| Time Base Upper (TBU) | 269 | (603+) |
|
||||
| External Access (EAR) | 282 | |
|
||||
| Processor Version (PVR) | 287 | |
|
||||
| Hardware Implementation 0 (HID0) | 1008 | |
|
||||
| Hardware Implementation 1 (HID1) | 1009 | |
|
||||
|
||||
# HID 0
|
||||
|
||||
| Model | Bits Enabled |
|
||||
|
@ -56,4 +76,8 @@ Up to 128 instruction entries and 128 data entries can be stored at a time.
|
|||
|
||||
* Apple's memcpy routine uses double floating-point registers rather than general purpose registers to load and store 2 32-bit values at once. As the PowerPC usually operates on at least a 64-bit bus and floating-point processing comes with the processors by default, this saves some instructions and results in slightly faster speeds.
|
||||
|
||||
* As the PowerPC does not have an instruction to load an immediate 32-bit value, it's common to see a lis/ori coding pattern.
|
||||
* As the PowerPC does not have an instruction to load an immediate 32-bit value, it's common to see a lis/ori coding pattern.
|
||||
|
||||
* The 603 relies on the instructions tlbld and tlbli to assist in TLB reloading.
|
||||
|
||||
* To accomodate for early programs compiled on PowerPC 601 Macs, the classic Mac OS has to emulate the POWER instructions that were removed from later processors.
|
|
@ -1,5 +1,7 @@
|
|||
Using a combination of a 6522 along with some integrated circuits, the VIA Cuda is a microcontroller that heavily controls system operations. It's largely similar to Egret (used in many 68k Macs), but removes some commands.
|
||||
|
||||
In many New World Macs, the Cuda itself is emulated within various VLSI chips.
|
||||
|
||||
The usual offset for a VIA Cuda is IOBase (ex.: 0xF3000000 for Power Mac G3 Beige) + 0x16000. The registers are spaced out by 0x200 bytes on the Heathrow.
|
||||
|
||||
# Usage
|
||||
|
|
|
@ -22,7 +22,7 @@ DingusPPC uses two windows when booted up; a command line window and a monitor w
|
|||
|
||||
## Commands
|
||||
|
||||
DingusPPC is operated using the command line interface. As such, we will list the commands as required.
|
||||
DingusPPC is operated using the command line interface. As such, we will list the commands as required. These commands are separated by spaces.
|
||||
|
||||
```
|
||||
-r, --realtime
|
||||
|
@ -77,6 +77,12 @@ fdd_img
|
|||
|
||||
Set the floppy disk image
|
||||
|
||||
```
|
||||
fdd_wr_prot=1
|
||||
```
|
||||
|
||||
Set the floppy to read-only
|
||||
|
||||
```
|
||||
hdd_img
|
||||
```
|
||||
|
@ -102,8 +108,8 @@ emmo
|
|||
Access the factory tests
|
||||
|
||||
```
|
||||
serial_backend stdio
|
||||
serial_backend socket
|
||||
serial_backend=stdio
|
||||
serial_backend=socket
|
||||
```
|
||||
|
||||
Change where the output of OpenFirmware is directed to, either to the command line (with stdio) or a Unix socket (unavailable in Windows builds). OpenFirmware 1.x outputs here by default.
|
||||
|
@ -133,7 +139,7 @@ Currently, ISO images are supported. However, support is not yet implemented for
|
|||
|
||||
### Hard Disks
|
||||
|
||||
Because Sheepshaver, Basilisk II, and Mini vMac operate on raw disks, it is required to a program such as BlueSCSI to make their hard disk images work in an emulator like DingusPPC. This is because the Mac OS normally requires certain values in the hard disks that these emulators don't normally
|
||||
Because Sheepshaver, Basilisk II, and Mini vMac operate on raw disks, it is required to a program such as BlueSCSI to make their hard disk images work in an emulator like DingusPPC. This is because the Mac OS normally requires certain values in the hard disks that these emulators don't normally insert into the images. You may also need a third-party utility to create an HFS or HFS+ disk image.
|
||||
|
||||
### OS Support
|
||||
|
||||
|
|
Loading…
Reference in New Issue