From 8f645b0b9ee83d6c4e8c809c53a21744be487514 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sat, 5 May 2018 12:34:12 +0200 Subject: [PATCH] start figuring out how to create MPW Tools using Retro68 --- CMakeLists.txt | 5 + Samples/MPWTool/CMakeLists.txt | 22 ++++ Samples/MPWTool/main.c | 194 +++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 Samples/MPWTool/CMakeLists.txt create mode 100644 Samples/MPWTool/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 04da98e6b8..7129ebc5f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,11 @@ add_subdirectory(Samples/SystemExtension) add_subdirectory(Samples/WDEF) endif() +if(CMAKE_SYSTEM_NAME MATCHES RetroCarbon) +else() +add_subdirectory(Samples/MPWTool) +endif() + add_subdirectory(LaunchAPPL) enable_testing() diff --git a/Samples/MPWTool/CMakeLists.txt b/Samples/MPWTool/CMakeLists.txt new file mode 100644 index 0000000000..8283ba3943 --- /dev/null +++ b/Samples/MPWTool/CMakeLists.txt @@ -0,0 +1,22 @@ + +# An MPW tool is an application with a special +# file type. +add_application(MPWTool + TYPE "MPST" + CREATOR "MPS " + main.c +) +if(CMAKE_SYSTEM_NAME MATCHES Retro68) + # On 68K, the application must be single-segment. + + # The trap patches required for Retro68's multi-segment + # support are incompatible with MPW. + + # As always, -gc-sections removes unused code. + + set_target_properties(MPWTool PROPERTIES + LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single") +else() + set_target_properties(MPWTool PROPERTIES + LINK_FLAGS "-Wl,-gc-sections") +endif() diff --git a/Samples/MPWTool/main.c b/Samples/MPWTool/main.c new file mode 100644 index 0000000000..d16007f329 --- /dev/null +++ b/Samples/MPWTool/main.c @@ -0,0 +1,194 @@ +/* + Copyright 2018 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +/* + * The following is a simple "Hello, world." MPW tool. + * + * Everything here should move to a library, + * so this can be written using a standard printf. + * + * The basic idea is that MPW makes the low-memory + * global at 0x316 point to a special struct that + * contains pointers to callbacks for doing standard + * input and output (and a few other things). + * The struct also contains argc and argv, + * as well as a place to store the tool's exit code. + * The tool must exit by returning from main() rather + * than by calling ExitToShell. + */ + +#include +#include +#include +#include +#include + +#pragma pack (push, 2) + +struct MPWFile; + +struct fsysTable +{ + void (*quit)(); + void (*access)(); + void (*close)(struct MPWFile *); + void (*read)(struct MPWFile *); + void (*write)(struct MPWFile *); + void (*ioctl)(); +}; + +struct devtable +{ + OSType fsysSig; + struct fsysTable fsys; +}; + +struct MPWFile +{ + short flags; + short err; + struct fsysTable *functions; + long cookie; + long count; + void *buffer; +}; + +struct pgminfo2 +{ + short magic2; + + int argc; + char **argv; + char **envp; + // 0x0e + int exitCode; + + // 0x12 + int x; + // 0x16 + int y; + // 0x1a + short tableSize; + struct MPWFile *ioptr; + struct devtable *devptr; +}; + +struct pgminfo +{ + OSType magic; + struct pgminfo2 *rest; +}; +#pragma pack (pop) + + +// Get MPW's magic struct +struct pgminfo2 * getPgmInfo() +{ + struct pgminfo *pgm0 = *(struct pgminfo**) 0x316; + if(!pgm0) + return NULL; + if(pgm0 == (struct pgminfo*)-1) + return NULL; + if(pgm0->magic != 'MPGM') + return NULL; + if(!pgm0->rest) + return NULL; + if(pgm0->rest->magic2 != 0x5348) + return NULL; + return pgm0->rest; +} + +jmp_buf exit_buf; + +// called by standard library's exit() +// Store +void _exit(int status) +{ + struct pgminfo2 *pgm = getPgmInfo(); + if(pgm) + pgm->exitCode = status; + longjmp(exit_buf, 1); +} + +const int procInfo = kCStackBased + | STACK_ROUTINE_PARAMETER(1, kFourByteCode); + +int main() +{ + struct pgminfo2 *pgm = getPgmInfo(); + if(pgm) + { + struct MPWFile *f = &pgm->ioptr[1]; + f->count = 14; + f->buffer = "Hello, world.\r"; + + #if TARGET_CPU_PPC + CallUniversalProc((UniversalProcPtr) f->functions->write, procInfo, f); + #else + f->functions->write(f); + #endif + } + return 0; +} + +#if TARGET_CPU_PPC + +void __do_global_dtors(); + +void __start() +{ + if(setjmp(exit_buf)) + ; + else + { + atexit(&__do_global_dtors); + int result; + { + char *argv[2] = { "./a.out", NULL }; + result = main(1, argv); + } + exit(result); + } +} + +void *__dso_handle = &__dso_handle; + +#else + +void _start() +{ + RETRO68_RELOCATE(); + + if(setjmp(exit_buf)) + ; + else + { + atexit(&Retro68CallDestructors); + Retro68CallConstructors(); + + int result; + { + char *argv[2] = { "./a.out", NULL }; + result = main(1, argv); + } + exit(result); + } +} + +#endif