Skip to content

Commit 343488c

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 8a72bd3 commit 343488c

5 files changed

Lines changed: 209 additions & 2 deletions

File tree

‎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), NewPPCStackSwap (MorphOS), or StackSwap
13+
(Workbench 2.04+). Runtime swapping can be disabled by
14+
defining 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: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
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+
***************************************************************************/
23+
24+
/* Workbench, AmigaOS, AROS, MorphOS require manually setting the
25+
* size of the stack. Include in main.c and nowhere else.
26+
* Partially based on libinit.c code from codesets.library.
27+
*
28+
* Define XMP_NO_STACKSWAP to disable StackSwap/NewStackSwap/NewPPCStackSwap.
29+
*/
30+
#ifndef XMP_MAIN_AMIGA_H
31+
#define XMP_MAIN_AMIGA_H
32+
33+
#include "common.h"
34+
35+
#if defined(XMP_AMIGA)
36+
37+
#include <proto/exec.h>
38+
39+
#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 1))
40+
#define XMP_USED __attribute__((used))
41+
#else
42+
#define XMP_USED
43+
#endif
44+
45+
#define MIN_STACK_SIZE 32768
46+
47+
/* AmigaOS 3.2, 4.x */
48+
extern const char stack_cookie[];
49+
const char XMP_USED stack_cookie[] = "$STACK: 32768";
50+
51+
/* libnix, when swapstack.o is included (must be located manually...). */
52+
extern int __stack;
53+
int XMP_USED __stack = MIN_STACK_SIZE;
54+
55+
/* Workbench 2.04 through 3.1: manually set stack size via StackSwap.
56+
* This needs to be performed through inline ASM to be safe.
57+
*
58+
* AROS: use NewStackSwap instead.
59+
* MorphOS: use NewPPCStackSwap instead.
60+
*/
61+
#if !defined(__amigaos4__) && !defined(XMP_NO_STACKSWAP)
62+
63+
int real_main(int argc, char **argv);
64+
65+
/* The inline ASM from codesets.library expects one function argument, so
66+
* it's easier to just use its semantics for now instead of rewriting it. */
67+
struct main_args
68+
{
69+
int argc;
70+
char **argv;
71+
};
72+
73+
/* Work around -pedantic warnings */
74+
union main_ptr_conv
75+
{
76+
ULONG (*v_fn_ptr)(struct main_args *);
77+
APTR *v_ptr;
78+
};
79+
80+
static ULONG main_wrapper(struct main_args *args)
81+
{
82+
return real_main(args->argc, args->argv);
83+
}
84+
85+
#if defined(__mc68000__) && !defined(__AROS__)
86+
87+
ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
88+
ULONG (*main_fn)(struct main_args *args),
89+
struct main_args *args);
90+
91+
asm(" .text \n\
92+
.even \n\
93+
.globl _xmp_stackswap_call \n\
94+
_xmp_stackswap_call: \n\
95+
moveml #0x3022,sp@- \n\
96+
movel sp@(20),d3 \n\
97+
movel sp@(24),a2 \n\
98+
movel sp@(28),d2 \n\
99+
movel _SysBase,a6 \n\
100+
movel d3,a0 \n\
101+
jsr a6@(-732:W) \n\
102+
movel d2,sp@- \n\
103+
jbsr a2@ \n\
104+
movel d0,d2 \n\
105+
addql #4,sp \n\
106+
movel _SysBase,a6 \n\
107+
movel d3,a0 \n\
108+
jsr a6@(-732:W) \n\
109+
movel d2,d0 \n\
110+
moveml sp@+,#0x440c \n\
111+
rts"
112+
);
113+
114+
#elif defined(__AROS__)
115+
116+
static ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
117+
ULONG (*main_fn)(struct main_args *args),
118+
struct main_args *args)
119+
{
120+
struct StackSwapArgs sa;
121+
union main_ptr_conv cv;
122+
123+
sa.Args[0] = (IPTR)args;
124+
cv.v_fn_ptr = main_fn;
125+
126+
return NewStackSwap(stack, cv.v_ptr, &sa);
127+
}
128+
129+
#elif defined(__MORPHOS__)
130+
131+
static ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
132+
ULONG (*main_fn)(struct main_args *args),
133+
struct main_args *args)
134+
{
135+
struct PPCStackSwapArgs sa;
136+
union main_ptr_conv cv;
137+
138+
sa.Args[0] = (IPTR)args;
139+
cv.v_fn_ptr = main_fn;
140+
141+
return NewPPCStackSwap(stack, cv.v_ptr, &sa);
142+
}
143+
144+
#else
145+
#error Unknown Amiga OS variant
146+
#endif
147+
148+
int main(int argc, char **argv)
149+
{
150+
struct StackSwapStruct sw;
151+
struct Task *tc;
152+
ULONG sz;
153+
154+
tc = FindTask(NULL);
155+
156+
#ifdef __MORPHOS__
157+
NewGetTaskAttrsA(tc, &sz, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
158+
#else
159+
sz = (UBYTE *)tc->tc_SPUpper - (UBYTE *)tc->tc_SPLower;
160+
#endif
161+
162+
if (sz < MIN_STACK_SIZE) {
163+
sw.stk_Lower = AllocVec(MIN_STACK_SIZE, MEMF_PUBLIC);
164+
if (sw.stk_Lower != NULL) {
165+
struct main_args args;
166+
int ret;
167+
168+
sw.stk_Upper = (ULONG)sw.stk_Lower + MIN_STACK_SIZE;
169+
sw.stk_Pointer = (APTR)sw.stk_Upper;
170+
171+
#if 0
172+
fprintf(stderr, "Swapping stack from %u to %d...\n",
173+
(unsigned)sz, MIN_STACK_SIZE);
174+
fflush(stderr);
175+
#endif
176+
177+
args.argc = argc;
178+
args.argv = argv;
179+
ret = (int)xmp_stackswap_call(&sw, main_wrapper, &args);
180+
181+
FreeVec(sw.stk_Lower);
182+
return ret;
183+
}
184+
}
185+
186+
return real_main(argc, argv);
187+
}
188+
189+
#define main real_main
190+
191+
#endif /* !AmigaOS4 && !defined(XMP_NO_STACKSWAP) */
192+
193+
#endif /* XMP_AMIGA */
194+
195+
#endif /* XMP_MAIN_AMIGA_H */

0 commit comments

Comments
 (0)