Skip to content

Commit 21846e0

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 21846e0

File tree

5 files changed

+210
-2
lines changed

5 files changed

+210
-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), 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: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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+
__attribute__((noinline))
81+
static ULONG main_wrapper(struct main_args *args)
82+
{
83+
return real_main(args->argc, args->argv);
84+
}
85+
86+
#if defined(__mc68000__) && !defined(__AROS__)
87+
88+
ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
89+
ULONG (*main_fn)(struct main_args *args),
90+
struct main_args *args);
91+
92+
asm(" .text \n\
93+
.even \n\
94+
.globl _xmp_stackswap_call \n\
95+
_xmp_stackswap_call: \n\
96+
moveml #0x3022,sp@- \n\
97+
movel sp@(20),d3 \n\
98+
movel sp@(24),a2 \n\
99+
movel sp@(28),d2 \n\
100+
movel _SysBase,a6 \n\
101+
movel d3,a0 \n\
102+
jsr a6@(-732:W) \n\
103+
movel d2,sp@- \n\
104+
jbsr a2@ \n\
105+
movel d0,d2 \n\
106+
addql #4,sp \n\
107+
movel _SysBase,a6 \n\
108+
movel d3,a0 \n\
109+
jsr a6@(-732:W) \n\
110+
movel d2,d0 \n\
111+
moveml sp@+,#0x440c \n\
112+
rts"
113+
);
114+
115+
#elif defined(__AROS__)
116+
117+
static ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
118+
ULONG (*main_fn)(struct main_args *args),
119+
struct main_args *args)
120+
{
121+
struct StackSwapArgs sa;
122+
union main_ptr_conv cv;
123+
124+
sa.Args[0] = (IPTR)args;
125+
cv.v_fn_ptr = main_fn;
126+
127+
return NewStackSwap(stack, cv.v_ptr, &sa);
128+
}
129+
130+
#elif defined(__MORPHOS__)
131+
132+
static ULONG xmp_stackswap_call(struct StackSwapStruct *stack,
133+
ULONG (*main_fn)(struct main_args *args),
134+
struct main_args *args)
135+
{
136+
struct PPCStackSwapArgs sa;
137+
union main_ptr_conv cv;
138+
139+
sa.Args[0] = (IPTR)args;
140+
cv.v_fn_ptr = main_fn;
141+
142+
return NewPPCStackSwap(stack, cv.v_ptr, &sa);
143+
}
144+
145+
#else
146+
#error Unknown Amiga OS variant
147+
#endif
148+
149+
int main(int argc, char **argv)
150+
{
151+
struct StackSwapStruct sw;
152+
struct Task *tc;
153+
ULONG sz;
154+
155+
tc = FindTask(NULL);
156+
157+
#ifdef __MORPHOS__
158+
NewGetTaskAttrsA(tc, &sz, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
159+
#else
160+
sz = (UBYTE *)tc->tc_SPUpper - (UBYTE *)tc->tc_SPLower;
161+
#endif
162+
163+
if (sz < MIN_STACK_SIZE) {
164+
sw.stk_Lower = AllocVec(MIN_STACK_SIZE, MEMF_PUBLIC);
165+
if (sw.stk_Lower != NULL) {
166+
struct main_args args;
167+
int ret;
168+
169+
sw.stk_Upper = (ULONG)sw.stk_Lower + MIN_STACK_SIZE;
170+
sw.stk_Pointer = (APTR)sw.stk_Upper;
171+
172+
#if 0
173+
fprintf(stderr, "Swapping stack from %u to %d...\n",
174+
(unsigned)sz, MIN_STACK_SIZE);
175+
fflush(stderr);
176+
#endif
177+
178+
args.argc = argc;
179+
args.argv = argv;
180+
ret = (int)xmp_stackswap_call(&sw, main_wrapper, &args);
181+
182+
FreeVec(sw.stk_Lower);
183+
return ret;
184+
}
185+
}
186+
187+
return real_main(argc, argv);
188+
}
189+
190+
#define main real_main
191+
192+
#endif /* !AmigaOS4 && !defined(XMP_NO_STACKSWAP) */
193+
194+
#endif /* XMP_AMIGA */
195+
196+
#endif /* XMP_MAIN_AMIGA_H */

0 commit comments

Comments
 (0)