mirror of
https://github.com/ksherlock/mpw.git
synced 2025-01-09 13:30:34 +00:00
get ready for trap overrides.
This commit is contained in:
parent
17c5b40ac8
commit
ea5f213921
@ -26,8 +26,11 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <cpu/defs.h>
|
#include <cpu/defs.h>
|
||||||
#include <cpu/CpuModule.h>
|
#include <cpu/CpuModule.h>
|
||||||
@ -41,18 +44,251 @@
|
|||||||
#include "sane.h"
|
#include "sane.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "stackframe.h"
|
||||||
#include "macos/traps.h"
|
#include "macos/traps.h"
|
||||||
|
|
||||||
// yuck. TST.W d0
|
// yuck. TST.W d0
|
||||||
extern "C" void cpuSetFlagsNZ00NewW(UWO res);
|
extern "C" void cpuSetFlagsNZ00NewW(UWO res);
|
||||||
|
|
||||||
|
|
||||||
|
template<int Bytes>
|
||||||
|
void Push__(uint32_t sp)
|
||||||
|
{
|
||||||
|
static_assert(Bytes == 0, "Invalid Stack Size");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int Bytes, typename... Args>
|
||||||
|
void Push__(uint32_t sp, uint16_t value, Args&&... args);
|
||||||
|
|
||||||
|
template<int Bytes, typename... Args>
|
||||||
|
void Push__(uint32_t sp, uint32_t value, Args&&... args);
|
||||||
|
|
||||||
|
|
||||||
|
template<int Bytes, typename... Args>
|
||||||
|
void Push__(uint32_t sp, uint16_t value, Args&&... args)
|
||||||
|
{
|
||||||
|
memoryWriteWord(value, sp);
|
||||||
|
Push__<Bytes-2>(sp + 2, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int Bytes, typename... Args>
|
||||||
|
void Push__(uint32_t sp, uint32_t value, Args&&... args)
|
||||||
|
{
|
||||||
|
memoryWriteLong(value, sp);
|
||||||
|
Push__<Bytes-4>(sp + 4, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int Bytes, typename... Args>
|
||||||
|
void Push(Args&&... args)
|
||||||
|
{
|
||||||
|
uint32_t sp = cpuGetAReg(7) - Bytes;
|
||||||
|
cpuSetAReg(7, sp);
|
||||||
|
|
||||||
|
Push__<Bytes>(sp, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace ToolBox {
|
namespace ToolBox {
|
||||||
|
|
||||||
bool Trace = false;
|
bool Trace = false;
|
||||||
|
|
||||||
|
uint32_t trap_address[1024];
|
||||||
|
uint32_t os_address[256];
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
inline constexpr bool is_tool_trap(uint16_t trap)
|
||||||
|
{
|
||||||
|
// %1010 | x . . . | . . . . . . . . |
|
||||||
|
//
|
||||||
|
// x = 1 if this is a toolbox call, x = 0 if this is an os call.
|
||||||
|
|
||||||
|
return (trap & 0x0800) == 0x0800;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool auto_pop(uint16_t trap)
|
||||||
|
{
|
||||||
|
// %1010 | 1 x . . | . . . . . . . . |
|
||||||
|
//
|
||||||
|
// if x = 1, an extra rts is pushed,
|
||||||
|
return (trap & 0x0c00) == 0x0c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool save_a0(uint16_t trap)
|
||||||
|
{
|
||||||
|
// %1010 | 0 . . x | . . . . . . . . |
|
||||||
|
//
|
||||||
|
// if x = 0, a0 is saved and restored.
|
||||||
|
// if x = 1, a0 is not saved and restored.
|
||||||
|
return (trap & 0x0900) == 0x0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr unsigned os_flags(uint16_t trap)
|
||||||
|
{
|
||||||
|
// %1010 | 0 x x . | . . . . . . . . |
|
||||||
|
return trap & 0x0600;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_dispatch(uint16_t trap)
|
||||||
|
{
|
||||||
|
uint32_t returnPC = 0;
|
||||||
|
|
||||||
|
bool saveA0 = false;
|
||||||
|
uint32_t a0 = cpuGetAReg(0);
|
||||||
|
|
||||||
|
if (trap == 0xafff)
|
||||||
|
{
|
||||||
|
// called from the trap address stub.
|
||||||
|
|
||||||
|
// uint16_t 0xafff
|
||||||
|
// uint16_t trap
|
||||||
|
// return address, etc, is on stack.
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t pc = cpuGetPC();
|
||||||
|
trap = memoryReadWord(pc);
|
||||||
|
|
||||||
|
if (is_tool_trap(trap))
|
||||||
|
{
|
||||||
|
StackFrame<4>(returnPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* os stubs:
|
||||||
|
* os_return_a0
|
||||||
|
* pop registers a0, a1, d0, d1, d2
|
||||||
|
* pop long word
|
||||||
|
* tst.w d0
|
||||||
|
* rts
|
||||||
|
*
|
||||||
|
* os_return:
|
||||||
|
* pop registers a0, a1, d0, d1, d2
|
||||||
|
* pop long word
|
||||||
|
* tst.w d0
|
||||||
|
* rts
|
||||||
|
*
|
||||||
|
* os_entry_a0:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// os calls push the trap dispatcher pc as well.
|
||||||
|
uint32_t tmp;
|
||||||
|
uint32_t a0, a1, d0, d1, d2;
|
||||||
|
if (save_a0(trap))
|
||||||
|
{
|
||||||
|
StackFrame<4*8>(returnPC, tmp, a0, a1, d0, d1, d2, tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StackFrame<4*7>(returnPC, tmp, a1, d0, d1, d2, tmp);
|
||||||
|
}
|
||||||
|
trap = d1; // trap w/ flag bits.
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dispatch(trap);
|
||||||
|
cpuInitializeFromNewPC(returnPC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The auto-pop bit is bit 10 in an A-line instruction for a
|
||||||
|
* Toolbox routine. Some language systems prefer to generate
|
||||||
|
* jump-subroutine calls (JSR) to intermediate routines, called
|
||||||
|
* glue routines, which then call Toolbox routines instead of
|
||||||
|
* executing the Toolbox routine directly. This glue method
|
||||||
|
* would normally interfere with Toolbox traps because the
|
||||||
|
* return address of the glue subroutine is placed on the stack
|
||||||
|
* between the Toolbox routine's parameters and the address of
|
||||||
|
* the place where the glue routine was called from (where
|
||||||
|
* control returns once the Toolbox routine has completed
|
||||||
|
* execution).
|
||||||
|
*
|
||||||
|
* The auto-pop bit forces the trap dispatcher to remove the
|
||||||
|
* top 4 bytes from the stack before dispatching to the Toolbox
|
||||||
|
* routine. After the Toolbox routine completes execution,
|
||||||
|
* control is transferred back to the place where the glue
|
||||||
|
* routine was called from, not back to the glue routine.
|
||||||
|
*
|
||||||
|
* Most development environments, including MPW, do not use
|
||||||
|
* this feature.
|
||||||
|
*
|
||||||
|
* (Trap Manager, 8-20)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (auto_pop(trap))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* | args |
|
||||||
|
* | returnPC |
|
||||||
|
* -------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
StackFrame<4>(returnPC);
|
||||||
|
trap &= ~0x0400;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_tool_trap(trap))
|
||||||
|
{
|
||||||
|
uint16_t tt = trap & 0x03ff;
|
||||||
|
uint32_t address = trap_address[tt];
|
||||||
|
if (address)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* parameters were pushed on the stack but
|
||||||
|
* the a-line instruction was intercepted
|
||||||
|
* before an exception occurred. Therefore,
|
||||||
|
* we need to push the return address on the
|
||||||
|
* stack and set the new pc to the trap address.
|
||||||
|
*
|
||||||
|
* returnPC may have been previously set from the
|
||||||
|
* auto pop bit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Push<4>(returnPC == 0 ? cpuGetPC() : returnPC);
|
||||||
|
cpuInitializeFromNewPC(address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// os calls - check the return/save a0 bit.
|
||||||
|
// if bit 8 is 0, a0 is saved and restored.
|
||||||
|
// if bit 8 is 1, a0 is modified.
|
||||||
|
// Trap Manager 8-12.
|
||||||
|
|
||||||
|
// not actually an issue yet, will only matter
|
||||||
|
// if os address is overridden.
|
||||||
|
|
||||||
|
if (save_a0(trap)) {
|
||||||
|
saveA0 = true;
|
||||||
|
}
|
||||||
|
uint16_t tt = trap & 0x00ff;
|
||||||
|
|
||||||
|
uint32_t address = os_address[tt];
|
||||||
|
|
||||||
|
if (address) {
|
||||||
|
assert("OS trap overrides are not yet supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dispatch(trap);
|
||||||
|
|
||||||
|
if (saveA0) cpuSetAReg(0, a0);
|
||||||
|
if (returnPC) cpuInitializeFromNewPC(returnPC);
|
||||||
|
}
|
||||||
|
|
||||||
void dispatch(uint16_t trap)
|
void dispatch(uint16_t trap)
|
||||||
{
|
{
|
||||||
// todo -- check/remove extra bits for save a0, toolglue, etc.
|
|
||||||
|
|
||||||
uint32_t d0 = 0;
|
uint32_t d0 = 0;
|
||||||
switch (trap)
|
switch (trap)
|
||||||
@ -534,6 +770,7 @@ namespace ToolBox {
|
|||||||
|
|
||||||
cpuSetDReg(0, d0);
|
cpuSetDReg(0, d0);
|
||||||
cpuSetFlagsNZ00NewW(d0);
|
cpuSetFlagsNZ00NewW(d0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ReadCString(uint32_t address, bool fname)
|
std::string ReadCString(uint32_t address, bool fname)
|
||||||
@ -611,4 +848,4 @@ namespace ToolBox {
|
|||||||
return std::string(tmp);
|
return std::string(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user