Skip to content

Commit bf5e2b0

Browse files
committed
Amiga: add experimental stack swap support.
* Workbench 2.04 onward: use StackSwap (inline ASM borrowed from codesets.library, LGPL 2.1). * AROS: use NewStackSwap. * MorphOS: use NewPPCStackSwap. * AmigaOS 3.2, 4.x: use a stack cookie.
1 parent fafbbf5 commit bf5e2b0

File tree

5 files changed

+199
-2
lines changed

5 files changed

+199
-2
lines changed

CREDITS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ The Authors
6060
- Thomas Pfaff <tpfaff@tp76.info>
6161
* OpenBSD sndio driver
6262

63+
- Alfonso Ranieri, codesets.library Open Source Team
64+
* Amiga StackSwap assembly routine
65+
66+
- Alice Rowan <petrifiedrowan@gmail.com>
67+
* Various features, sound driver enhancements and fixes
68+
6369
- Johan Samuelsson <spot@triad.se>
6470
* Amiga port and fixes
6571

Changelog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ Stable versions
88
sndio, WinMM, AIFF, file, WAV.
99
- Use XMP_MAX_SRATE as the limit for -f instead of 48000
1010
(requires libxmp 4.7.0+).
11+
- Amiga: automatically expand stack via stack cookie (OS 4),
12+
NewStackSwap (AROS), or StackSwap (Workbench 2.04+). The
13+
Workbench and AROS behavior can be disabled by defining
14+
XMP_NO_STACKSWAP.
1115
- Report pan value "---" for instruments/samples without
1216
a default panning value (sub->pan < 0).
1317
- Don't unmute muted IT channels unless explicitly unmuted by

src/Makefile.am

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ bin_PROGRAMS = xmp
88

99
xmp_SOURCES = \
1010
commands.c common.h delay.c getopt_long.h getopt_long.c info.c \
11-
main.c options.c read_config.c sound.c sound.h sound_file.c sound_null.c \
12-
sound_wav.c sound_aiff.c terminal.c util.c xmp_version.h
11+
main.c main_amiga.h options.c read_config.c sound.c sound.h \
12+
sound_aiff.c sound_file.c sound_null.c sound_wav.c terminal.c util.c \
13+
xmp_version.h
1314
xmp_LDADD = ${LIBXMP_LIBS}
1415
xmp_LDFLAGS = ${XMP_DARWIN_LDFLAGS}
1516

src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#if defined(XMP_AMIGA)
2121
#include <proto/timer.h>
2222
#include <time.h>
23+
#include "main_amiga.h"
2324
#endif
2425
#if defined(__WATCOMC__)
2526
#include <time.h>

src/main_amiga.h

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/***************************************************************************
2+
3+
codesets.library - Amiga shared library for handling different codesets
4+
Copyright (C) 2001-2005 by Alfonso [alfie] Ranieri <alforan@tin.it>.
5+
Copyright (C) 2005-2021 codesets.library Open Source Team
6+
7+
Extended Module Player modifications:
8+
Copyright (C) 2026 Lachesis <petrifiedrowan@gmail.com>
9+
10+
This library is free software; you can redistribute it and/or
11+
modify it under the terms of the GNU Lesser General Public
12+
License as published by the Free Software Foundation; either
13+
version 2.1 of the License, or (at your option) any later version.
14+
15+
This library is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18+
Lesser General Public License for more details.
19+
20+
codesets.library project: http://sourceforge.net/projects/codesetslib/
21+
22+
$Id$
23+
24+
***************************************************************************/
25+
26+
/* Workbench, AmigaOS, AROS, MorphOS require manually setting the
27+
* size of the stack. Include in main.c and nowhere else.
28+
* Partially based on libinit.c code from codesets.library.
29+
*
30+
* Define XMP_NO_STACKSWAP to disable StackSwap/NewStackSwap/NewPPCStackSwap.
31+
*/
32+
#ifndef XMP_MAIN_AMIGA_H
33+
#define XMP_MAIN_AMIGA_H
34+
35+
#include "common.h"
36+
37+
#if defined(XMP_AMIGA)
38+
39+
#include <proto/exec.h>
40+
41+
#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 1))
42+
#define XMP_USED __attribute__((used))
43+
#else
44+
#define XMP_USED
45+
#endif
46+
47+
#define MIN_STACK_SIZE 32768
48+
49+
/* AmigaOS 3.2, 4.x */
50+
extern const char stack_cookie[];
51+
const char XMP_USED stack_cookie[] = "$STACK: 32768";
52+
53+
/* libnix, when swapstack.o is included (must be located manually...). */
54+
extern int __stack;
55+
int XMP_USED __stack = MIN_STACK_SIZE;
56+
57+
/* Workbench 2.04 through 3.1: manually set stack size via StackSwap.
58+
* This needs to be performed through inline ASM to be safe.
59+
*
60+
* AROS: use NewStackSwap instead.
61+
* MorphOS: use NewPPCStackSwap instead.
62+
*/
63+
#if !defined(__amigaos4__) && !defined(XMP_NO_STACKSWAP)
64+
65+
int real_main(int argc, char **argv);
66+
67+
/* The inline ASM from codesets.library expects one function argument, so
68+
* it's easier to just use its semantics for now instead of rewriting it. */
69+
struct main_args
70+
{
71+
int argc;
72+
char **argv;
73+
};
74+
75+
static ULONG main_wrapper(struct main_args *args)
76+
{
77+
return (ULONG)real_main(args->argc, args->argv);
78+
}
79+
80+
#if defined(__mc68000__) && !defined(__AROS__)
81+
82+
ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
83+
ULONG (*main_fn)(struct main_args *args),
84+
struct main_args *args);
85+
86+
asm(" .text \n\
87+
.even \n\
88+
.globl _xmp_stackswap_call \n\
89+
_xmp_stackswap_call: \n\
90+
moveml #0x3022,sp@- \n\
91+
movel sp@(20),d3 \n\
92+
movel sp@(24),a2 \n\
93+
movel sp@(28),d2 \n\
94+
movel _SysBase,a6 \n\
95+
movel d3,a0 \n\
96+
jsr a6@(-732:W) \n\
97+
movel d2,sp@- \n\
98+
jbsr a2@ \n\
99+
movel d0,d2 \n\
100+
addql #4,sp \n\
101+
movel _SysBase,a6 \n\
102+
movel d3,a0 \n\
103+
jsr a6@(-732:W) \n\
104+
movel d2,d0 \n\
105+
moveml sp@+,#0x440c \n\
106+
rts"
107+
);
108+
109+
#elif defined(__AROS__)
110+
111+
static ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
112+
ULONG (*main_fn)(struct main_args *args),
113+
struct main_args *args);
114+
{
115+
struct StackSwapArgs sa;
116+
117+
sa.Args[0] = (IPTR)args;
118+
119+
return NewStackSwap(stack, main_fn, &sa);
120+
}
121+
122+
#elif defined(__MORPHOS__)
123+
124+
static ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
125+
ULONG (*main_fn)(struct main_args *args),
126+
struct main_args *args);
127+
{
128+
struct PPCStackSwapArgs sa;
129+
130+
sa.Args[0] = (IPTR)args;
131+
132+
return NewPPCStackSwap(stack, main_fn, &sa);
133+
}
134+
135+
#else
136+
#error Unknown Amiga OS variant
137+
#endif
138+
139+
int main(int argc, char **argv)
140+
{
141+
struct StackSwapStruct sw;
142+
struct Task *tc;
143+
ULONG sz;
144+
145+
tc = FindTask(NULL);
146+
147+
#ifdef __MORPHOS__
148+
NewGetTaskAttrsA(tc, &sz, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
149+
#else
150+
sz = (UBYTE *)tc->tc_SPUpper - (UBYTE *)tc->tc_SPLower;
151+
#endif
152+
153+
if (sz < MIN_STACK_SIZE) {
154+
sw.stk_Lower = AllocVec(MIN_STACK_SIZE, MEMF_PUBLIC);
155+
if (sw.stk_Lower != NULL) {
156+
struct main_args args;
157+
int ret;
158+
159+
sw.stk_Upper = (ULONG)sw.stk_Lower + MIN_STACK_SIZE;
160+
sw.stk_Pointer = (APTR)sw.stk_Upper;
161+
162+
/*
163+
printf("Swapping stack to size %d...\n", MIN_STACK_SIZE);
164+
fflush(stdout);
165+
*/
166+
167+
args.argc = argc;
168+
args.argv = argv;
169+
ret = (int)xmp_stackswap_call(&sw, main_wrapper, &args);
170+
171+
FreeVec(sw.stk_Lower);
172+
return ret;
173+
}
174+
}
175+
176+
return real_main(argc, argv);
177+
}
178+
179+
#define main real_main
180+
181+
#endif /* !AmigaOS4 && !defined(XMP_NO_STACKSWAP) */
182+
183+
#endif /* XMP_AMIGA */
184+
185+
#endif /* XMP_MAIN_AMIGA_H */

0 commit comments

Comments
 (0)