mirror of
https://github.com/aphrody-labs/cygwin.git
synced 2026-10-13 22:03:45 +00:00
Added target m68k-atari-elf supporting Atari 16/32bit TOS systems.
This commit is contained in:
1 parent
45f9b48413
commit
cac47030fb
45 files changed
+2043
-14
No files matched your search
@@ -497,3 +497,7 @@ and need not follow the licensing terms described here, provided that
|
||||
the new terms are clearly indicated on the first page of each file where
|
||||
they apply.
|
||||
|
||||
(26) - Atari 16/32 bit TOS (m68k-atari-elf target)
|
||||
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
@@ -1570,3 +1570,7 @@ Software.
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
(58) - Atari 16/32 bit TOS (m68k-atari-elf target)
|
||||
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
Vendored
+12
-12
@@ -2857,6 +2857,11 @@ case "${target}" in
|
||||
ac_config_files="$ac_config_files m68k/Makefile"
|
||||
|
||||
subdirs="$subdirs m68k"
|
||||
case "${target}" in
|
||||
m68k-atari-*)
|
||||
config_libnosys=false
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
hppa*-*-pro*)
|
||||
ac_config_files="$ac_config_files pa/Makefile"
|
||||
@@ -5461,16 +5466,18 @@ case "${target}" in
|
||||
MIPS_SCRIPT_LIST="dve idt jmr3904app jmr3904dram jmr3904dram-java jmr3904app-java sde32 sde64 mti32 mti64 mti64_n32 mti64_64"
|
||||
MIPS_BSP_LIST="libdve.a libidt.a libjmr3904.a"
|
||||
;;
|
||||
mipsisa32-*-* | mipsisa32el-*-* | \
|
||||
mipsisa32r2-*-* | mipsisa32r2el-*-* | \
|
||||
mipsisa64*-*-*)
|
||||
MIPS_CRT0="crt0_cfe.o crt0_cygmon.o crt0.o"
|
||||
MIPS_SCRIPT_LIST="idt32 idt64 cfe"
|
||||
MIPS_BSP_LIST="libcygmon.a libidt.a libcfe.a"
|
||||
;;
|
||||
mips*-lsi*-*)
|
||||
MIPS_PART_SPECIFIC_OBJ="entry.o"
|
||||
MIPS_SCRIPT_LIST="lsi"
|
||||
MIPS_BSP_LIST=liblsi.a
|
||||
;;
|
||||
mips*-mti*-* | mips*-img*-*)
|
||||
MIPS_CRT0="crt0.o"
|
||||
MIPS_SCRIPT_LIST="idt nullmon mti32 mti64_n32 mti64_64 uhi32 uhi64_64 uhi64_n32 malta32-yamon bootcode"
|
||||
MIPS_BSP_LIST="libidt.a libnullmon.a libuhi.a libyamon.a libhal.a libcm3_impl.a"
|
||||
;;
|
||||
mips64vr5*-*-*)
|
||||
MIPS_PART_SPECIFIC_OBJ="vr5xxx.o cma101.o"
|
||||
MIPS_PART_SPECIFIC_DEFINES=-DR5000
|
||||
@@ -5482,13 +5489,6 @@ case "${target}" in
|
||||
MIPS_SCRIPT_LIST="ddb ddb-kseg0 nullmon"
|
||||
MIPS_BSP_LIST="libpmon.a libnullmon.a"
|
||||
;;
|
||||
mipsisa32-*-* | mipsisa32el-*-* | \
|
||||
mipsisa32r2-*-* | mipsisa32r2el-*-* | \
|
||||
mipsisa64*-*-*)
|
||||
MIPS_CRT0="crt0_cfe.o crt0_cygmon.o crt0.o"
|
||||
MIPS_SCRIPT_LIST="idt32 idt64 cfe"
|
||||
MIPS_BSP_LIST="libcygmon.a libidt.a libcfe.a"
|
||||
;;
|
||||
mips*)
|
||||
MIPS_CRT0="crt0_cfe.o crt0.o"
|
||||
MIPS_PART_SPECIFIC_OBJ="vr4300.o cma101.o"
|
||||
|
||||
@@ -79,6 +79,11 @@ case "${target}" in
|
||||
fido-*-* | m68*-*-*)
|
||||
AC_CONFIG_FILES([m68k/Makefile])
|
||||
subdirs="$subdirs m68k"
|
||||
case "${target}" in
|
||||
m68k-atari-*)
|
||||
config_libnosys=false
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
hppa*-*-pro*)
|
||||
AC_CONFIG_FILES([pa/Makefile])
|
||||
|
||||
@@ -31,6 +31,7 @@ program_transform_name = @program_transform_name@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
tooldir = $(exec_prefix)/$(target_alias)
|
||||
specsdir = $(libdir)/gcc/$(target_alias)
|
||||
|
||||
# Multilib support variables.
|
||||
# TOP is used instead of MULTI{BUILD,SRC}TOP.
|
||||
@@ -71,6 +72,14 @@ OBJS = close.o fstat.o getpid.o isatty.o kill.o \
|
||||
# What targets to build for. This is a list of {m68k,cf}
|
||||
TARGET = @M68K_TARGET@
|
||||
|
||||
# Check if vendor is atari and if so, adjust the target
|
||||
target_vendor = @target_vendor@
|
||||
ifdef target_vendor
|
||||
ifeq ($(target_vendor), atari)
|
||||
TARGET := $(TARGET)_$(target_vendor)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Here is all of the simulator stuff
|
||||
SIM_SCRIPTS = sim.ld
|
||||
SIM_LDFLAGS = -Tsim.ld
|
||||
@@ -197,6 +206,29 @@ UNHOSTED_OBJS= unhosted-close.o unhosted-fstat.o \
|
||||
HOSTED_BSP= libhosted.a
|
||||
HOSTED_OBJS= hosted-gdb.o hosted-exit.o $(patsubst un%,%,$(UNHOSTED_OBJS))
|
||||
|
||||
#
|
||||
# here's all the atari stuff
|
||||
#
|
||||
|
||||
ATARI_SRC_LIBGLOSS := atari-environ.c atari-execve.c atari-link.c atari-times.c \
|
||||
atari-wait.c atari-traps.c atari-gem_errno.c atari-close.c atari-fstat.c \
|
||||
atari-getpid.c atari-isatty.c atari-kill.c atari-lseek.c atari-open.c atari-read.c \
|
||||
atari-sbrk.c atari-stat.c atari-unlink.c atari-write.c \
|
||||
atari-chown.c atari-fork.c atari-getentropy.c atari-gettod.c atari-readlink.c \
|
||||
atari-symlink.c atari-chdir.c atari-getcwd.c atari-mkdir.c atari-rmdir.c \
|
||||
atari-rename.c
|
||||
|
||||
ATARI_OBJS_LIBGLOSS := $(foreach source,$(ATARI_SRC_LIBGLOSS),$(basename $(source)).o)
|
||||
|
||||
ATARI_CRTI := atari-crti.o
|
||||
ATARI_CRTN := atari-crtn.o
|
||||
ATARI_CRT0 := atari-crt0.o
|
||||
ATARI_NEWLIB := libatari-tos.a
|
||||
ATARI_LINK := atari-tos.ld
|
||||
ATARI_SPECS := atari-tos.specs
|
||||
|
||||
ATARI_ASFLAGS := -Xassembler --register-prefix-optional
|
||||
|
||||
# Host specific makefile fragment comes in here.
|
||||
@host_makefile_frag@
|
||||
|
||||
@@ -206,9 +238,19 @@ all :: $(TARGET:%=all_%)
|
||||
# here's where we build the board support packages for each target
|
||||
#
|
||||
|
||||
.PHONY: all_m68k_atari
|
||||
all_m68k_atari :: $(ATARI_CRTI) $(ATARI_CRTN) $(ATARI_CRT0) $(ATARI_NEWLIB)
|
||||
|
||||
.PHONY: all_cf_atari
|
||||
all_cf_atari :: all_m68k_atari
|
||||
|
||||
.PHONY: all_fido_atari
|
||||
all_fido_atari :: all_m68k_atari
|
||||
|
||||
.PHONY: all_m68k
|
||||
all_m68k :: ${SIM_CRT0} ${SIM_BSP} ${CRT0} ${BCC_BSP} ${IDP_BSP} \
|
||||
${IDPGDB_BSP} ${MVME135_BSP} ${MVME162_BSP}
|
||||
|
||||
.PHONY: all_cf
|
||||
all_cf :: ${CF_CRT0S} ${CF_BSP} ${CF_SCRIPTS} ${HOSTED_BSP} ${UNHOSTED_BSP}
|
||||
|
||||
@@ -240,6 +282,23 @@ ${MVME162_BSP}: $(OBJS) ${MVME162_OBJS}
|
||||
${AR} ${ARFLAGS} $@ $(OBJS) ${MVME162_OBJS}
|
||||
${RANLIB} $@
|
||||
|
||||
# build atari library
|
||||
$(ATARI_CRT0): atari/atari-crt0.S
|
||||
$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(ATARI_ASFLAGS) -c $< -o $@
|
||||
|
||||
$(ATARI_CRTI): atari/atari-crti.S
|
||||
$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(ATARI_ASFLAGS) -c $< -o $@
|
||||
|
||||
$(ATARI_CRTN): atari/atari-crtn.S
|
||||
$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(ATARI_ASFLAGS) -c $< -o $@
|
||||
|
||||
%.o: atari/%.c
|
||||
$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
$(ATARI_NEWLIB): $(ATARI_OBJS_LIBGLOSS)
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
$(RANLIB) $@
|
||||
|
||||
# build hosted library
|
||||
$(HOSTED_OBJS): hosted%.o: io%.c io.h
|
||||
$(CC) $(CFLAGS_FOR_TARGET) $(CFLAGS) -DHOSTED=1 $(INCLUDES) -c $< -o $@
|
||||
@@ -409,6 +468,22 @@ unlink.o: $(srcdir)/../unlink.c
|
||||
install:: $(TARGET:%=install_%)
|
||||
|
||||
|
||||
.PHONY:install_m68k_atari
|
||||
install_m68k_atari::
|
||||
${mkinstalldirs} ${DESTDIR}${tooldir}/lib${MULTISUBDIR}
|
||||
$(INSTALL_PROGRAM) $(ATARI_CRTI) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/crti.o
|
||||
$(INSTALL_PROGRAM) $(ATARI_CRTN) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/crtn.o
|
||||
$(INSTALL_PROGRAM) $(ATARI_CRT0) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/crt0.o
|
||||
$(INSTALL_PROGRAM) $(ATARI_NEWLIB) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/$(ATARI_NEWLIB)
|
||||
$(INSTALL_DATA) ${srcdir}/atari/$(ATARI_LINK) $(DESTDIR)$(tooldir)/lib${MULTISUBDIR}/$(ATARI_LINK)
|
||||
$(INSTALL_DATA) ${srcdir}/atari/$(ATARI_SPECS) $(DESTDIR)$(specsdir)/specs
|
||||
|
||||
.PHONY:install_cf_atari
|
||||
install_cf_atari:: install_m68k_atari
|
||||
|
||||
.PHONY:install_fido_atari
|
||||
install_fido_atari:: install_m68k_atari
|
||||
|
||||
.PHONY:install_m68k
|
||||
install_m68k::
|
||||
${mkinstalldirs} ${DESTDIR}${tooldir}/lib${MULTISUBDIR}
|
||||
@@ -473,7 +548,7 @@ install_io::
|
||||
@target_makefile_frag@
|
||||
|
||||
clean mostlyclean:
|
||||
rm -f a.out core *.i *~ *.a *.o *-test *.srec *.dis *.x *.map
|
||||
rm -f a.out core *.i *~ *.a *.o *-test *.srec *.dis *.x *.map *.ld
|
||||
|
||||
distclean maintainer-clean realclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
Atari 16/32 bit TOS (not MINT) target.
|
||||
Target name: m68k-atari-elf.
|
||||
|
||||
Stack size:
|
||||
The default stack size is set at 2000 bytes.
|
||||
To change stack size, add the following line to your C/C++ code:
|
||||
unsigned int _STACK_SIZE = *WANTED_STACK_SIZE*;
|
||||
Where "*WANTED_STACK_SIZE*" is the size in bytes you want to allocate for stack space.
|
||||
Do not use odd size!
|
||||
|
||||
Heap size:
|
||||
The default heap size is to use all available memory.
|
||||
If you want to leave memory for other programs to use, then add the following line to your C/C++ code:
|
||||
unsigned int _HEAP_SIZE = *WANTED_HEAP_SIZE*;
|
||||
Where "*WANTED_HEAP_SIZE*" is the size in bytes you want to allocate for heap space.
|
||||
Do not use odd size!
|
||||
|
||||
Program base page:
|
||||
A pointer to the program base page is stored at: _BasePage
|
||||
|
||||
ELF output:
|
||||
The executable elf output have four interesting segments:
|
||||
".text", ".data", ".bss" and ".prgheader" as described in "atari-tos.ld".
|
||||
All relevant code and data have been properly sorted into those segments, and the ".prgheader"
|
||||
contains a valid atari prg header pointing to relevant segments.
|
||||
Relocation data from the link switch "--emit-relocs" (defaultted by "atari-tos.specs") is
|
||||
included in the elf output so additional fixup information can be added to the prg file.
|
||||
Addresses in elf and prg files are the same and thus compatible for interchangeable symbol lookup.
|
||||
|
||||
More information:
|
||||
Can be found at: https://github.com/hildenborg/m68k-atari-dev
|
||||
Where build scripts for complete toolchain, executables for converting elf to prg, and a remote debug server with full symbolic debugging are available.
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
int chdir(const char *path)
|
||||
{
|
||||
int err = GEM_E_OK;
|
||||
if (path != 0)
|
||||
{
|
||||
if (path[1] == ':')
|
||||
{
|
||||
unsigned int drives = 0;
|
||||
unsigned short drive = 0;
|
||||
if (path[0] >= 'A' && path[0] <= 'Z')
|
||||
{
|
||||
drive = (unsigned short)(path[0] - 'A');
|
||||
}
|
||||
else if (path[0] >= 'a' && path[0] <= 'z')
|
||||
{
|
||||
drive = (unsigned short)(path[0] - 'a');
|
||||
}
|
||||
drives = trap1_e(drive);
|
||||
if ((drives & (1 << drive)) == 0)
|
||||
{
|
||||
err = GEM_EDRIVE;
|
||||
}
|
||||
path += 2;
|
||||
}
|
||||
if (err == GEM_E_OK)
|
||||
{
|
||||
err = trap1_3b(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = GEM_EPTHNF;
|
||||
}
|
||||
if (err < 0)
|
||||
{
|
||||
gem_error_to_errno(err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <_ansi.h>
|
||||
#include <_syslist.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int chown(const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(chown)
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
int err = GEM_EIHNDL;
|
||||
if (fd >= 0)
|
||||
{
|
||||
err = trap1_3e((unsigned short)fd);
|
||||
}
|
||||
if (err < 0)
|
||||
{
|
||||
gem_error_to_errno(err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
.global exit
|
||||
|
||||
.section ".init"
|
||||
.global __call_main_with_argc_argv
|
||||
.type __call_main_with_argc_argv,#function
|
||||
__call_main_with_argc_argv:
|
||||
|
||||
/*
|
||||
Need to implement "The Atari Extended Argument Specification".
|
||||
Also, there is no guarantee that the command line is zero terminated.
|
||||
*/
|
||||
| this occurs after crtbegin.o have done all global constructors etc.
|
||||
|
||||
move.l a7, a6
|
||||
moveq #0, d0
|
||||
moveq #0, d2
|
||||
movea.l _BasePage, a0
|
||||
lea 128(a0), a0 | add offset to the cmdline
|
||||
lea _cmdline, a1
|
||||
move.b (a0)+, d2 | d2 contains number of bytes in command line (max 127)
|
||||
beq.s 3f
|
||||
clr.b (a1, d2.w) | end our decoded args with a zero.
|
||||
bra.s 2f
|
||||
1:
|
||||
move.b (a0, d2.w), d1
|
||||
cmp.b #' ', d1
|
||||
bne.s 4f
|
||||
moveq #0, d1
|
||||
lea 1(a1, d2.w), a2
|
||||
tst.b (a2)
|
||||
beq.s 4f
|
||||
move.l a2, -(a7)
|
||||
addq.w #1, d0
|
||||
4:
|
||||
move.b d1, (a1, d2.w)
|
||||
2:
|
||||
subq.w #1, d2
|
||||
bcc.s 1b
|
||||
move.l a1, -(a7)
|
||||
addq.w #1, d0
|
||||
3:
|
||||
pea _procname | first argument is always the proc name. That we do not know...
|
||||
addq.w #1, d0
|
||||
move.l a7, a5
|
||||
move.l a6, -(a7) | To know where to move it back again.
|
||||
|
||||
move.l a5, -(a7) | argv
|
||||
move.l d0, -(a7) | argc
|
||||
jsr main
|
||||
move.l 8(a7), a7 | move it back.
|
||||
move.l d0, -(a7)
|
||||
jsr exit | not expected to return
|
||||
illegal
|
||||
|
||||
.global _exit
|
||||
.type _exit,#function
|
||||
_exit:
|
||||
move.l 4(a7), d0
|
||||
move.w d0, _program_return_code
|
||||
| crtend.o follows here with global destructors etc.
|
||||
|
||||
.data
|
||||
_procname:
|
||||
.asciz "yourapp.lol"
|
||||
.even
|
||||
|
||||
.bss
|
||||
.lcomm _cmdline, 128
|
||||
.even
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifdef _HAVE_INITFINI_ARRAY
|
||||
#define _init __libc_init_array
|
||||
#define _fini __libc_fini_array
|
||||
#endif
|
||||
|
||||
.equ DEFAULT_STACK, 2000
|
||||
|
||||
.global _BasePage
|
||||
.weak _STACK_SIZE
|
||||
.weak _HEAP_SIZE
|
||||
.global _HeapPtr
|
||||
.global _HeapBottom
|
||||
.global _HeapTop
|
||||
.global _atari_4ba_at_prg_start
|
||||
.global __BSS_SEGMENT_END
|
||||
|
||||
.section ".init"
|
||||
.global _init
|
||||
.type _init,#function
|
||||
_init:
|
||||
move.l 4(a7),a0
|
||||
move.l a0, _BasePage
|
||||
|
||||
| Init stack
|
||||
lea __BSS_SEGMENT_END, a2
|
||||
lea _STACK_SIZE, a1
|
||||
cmpa.w #0, a1
|
||||
jeq default_stack_size
|
||||
add.l (a1), a2
|
||||
jra stack_size_selected
|
||||
default_stack_size:
|
||||
lea DEFAULT_STACK(a2), a2
|
||||
stack_size_selected:
|
||||
move.l a2, a7
|
||||
|
||||
| Init heap
|
||||
move.l a7, d0
|
||||
move.l d0, _HeapBottom
|
||||
move.l d0, _HeapPtr
|
||||
move.l 4(a0), _HeapTop
|
||||
|
||||
lea _HEAP_SIZE, a1
|
||||
cmpa.w #0, a1
|
||||
jeq heap_setup_done
|
||||
add.l (a1), d0
|
||||
sub.l (a0), d0 | d0 is now the TPA size
|
||||
|
||||
| Program do not want all memory, so we shrink it.
|
||||
move.l d0, -(a7)
|
||||
move.l a0, -(a7)
|
||||
clr.w -(a7)
|
||||
move.w #0x4a, -(a7) | Mshrink()
|
||||
trap #1
|
||||
lea 12(a7), a7
|
||||
tst.l d0
|
||||
jpl heap_setup_done
|
||||
| Error, just quit with d0 as return code.
|
||||
move.w d0,-(a7)
|
||||
move.w #0x4c,-(a7)
|
||||
trap #1
|
||||
super_init:
|
||||
| Init stuff that needs supervisor mode set.
|
||||
move.l 0x4ba, _atari_4ba_at_prg_start
|
||||
rts
|
||||
heap_setup_done:
|
||||
move.l #super_init, -(a7)
|
||||
move.w #0x26, -(a7)
|
||||
trap #14
|
||||
addq.l #6, a7
|
||||
| crtbegin.o follows here with global constructors etc. init.
|
||||
|
||||
|
||||
.section ".fini"
|
||||
/*
|
||||
Empty.
|
||||
*/
|
||||
|
||||
|
||||
.bss
|
||||
.lcomm _BasePage, 4
|
||||
.lcomm _HeapPtr, 4
|
||||
.lcomm _HeapBottom, 4
|
||||
.lcomm _HeapTop, 4
|
||||
.lcomm _atari_4ba_at_prg_start, 4
|
||||
.even
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
.global _program_return_code
|
||||
|
||||
.section ".init"
|
||||
/*
|
||||
Empty.
|
||||
*/
|
||||
|
||||
|
||||
.section ".fini"
|
||||
.global _fini
|
||||
.type _fini,#function
|
||||
_fini:
|
||||
| this occurs after crtend.o have done all global destructors etc.
|
||||
move.w _program_return_code,-(a7)
|
||||
move.w #0x4c,-(a7)
|
||||
trap #1
|
||||
|
||||
.bss
|
||||
.lcomm _program_return_code, 2
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
// Should point to a list of global environment variables.
|
||||
char *__env[1] = { 0 };
|
||||
char **environ = __env;
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int execve(char *name, char **argv, char **env)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(execve)
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <_ansi.h>
|
||||
#include <_syslist.h>
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int fork(void)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(fork)
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
#include "atari-gem_basepage.h"
|
||||
|
||||
/*
|
||||
From man page:
|
||||
"only the st_uid, st_gid, st_size, and st_mode fields,
|
||||
and only the S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH file permission bits need be valid."
|
||||
*/
|
||||
|
||||
int fstat(int fd, struct stat *buf)
|
||||
{
|
||||
struct DTA *dta = (struct DTA *)GEM_EIHNDL;
|
||||
// For now, we just support files.
|
||||
if (fd >= 6)
|
||||
{
|
||||
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
|
||||
// files
|
||||
dta = trap1_2f((unsigned int)fd);
|
||||
if ((int)dta >= 0)
|
||||
{
|
||||
// Attribs
|
||||
buf->st_mode |= (dta->d_attrib & FA_DIR) ? S_IFDIR : S_IFREG;
|
||||
if ((dta->d_attrib & FA_READONLY) != 0)
|
||||
{
|
||||
buf->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
}
|
||||
buf->st_size = dta->d_length;
|
||||
// st_uid, st_gid have no meaning for the st, so we ignore them.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// unsupported, fake something.
|
||||
buf->st_mode = S_IFCHR;
|
||||
buf->st_blksize = 0;
|
||||
}
|
||||
if ((int)dta < 0)
|
||||
{
|
||||
gem_error_to_errno((int)dta);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef GEM_BASEPAGE_H
|
||||
#define GEM_BASEPAGE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is the process base page data, containing information about the executable.
|
||||
*/
|
||||
|
||||
#define FA_READONLY 0x01 // Read-only flag
|
||||
#define FA_HIDDEN 0x02 // Hidden file flag
|
||||
#define FA_SYSTEM 0x04 // System file flag
|
||||
#define FA_VOLUME 0x08 // Volume label flag
|
||||
#define FA_DIR 0x10 // Subdirectory
|
||||
#define FA_ARCHIVE 0x20 // Archive flag
|
||||
|
||||
struct DTA
|
||||
{
|
||||
unsigned char d_reserved[21];
|
||||
unsigned char d_attrib;
|
||||
unsigned short d_time;
|
||||
unsigned short d_date;
|
||||
unsigned int d_length;
|
||||
char d_fname[14];
|
||||
};
|
||||
|
||||
struct BasePage
|
||||
{
|
||||
unsigned char* p_lowtpa; // This LONG contains a pointer to the Transient Program Area (TPA).
|
||||
unsigned char* p_hitpa; // This LONG contains a pointer to the top of the TPA + 1.
|
||||
unsigned char* p_tbase; // This LONG contains a pointer to the base of the text segment
|
||||
unsigned int p_tlen; // This LONG contains the length of the text segment.
|
||||
unsigned char* p_dbase; // This LONG contains a pointer to the base of the data segment.
|
||||
unsigned int p_dlen; // This LONG contains the length of the data segment.
|
||||
unsigned char* p_bbase; // This LONG contains a pointer to the base of the BSS segment.
|
||||
unsigned int p_blen; // This LONG contains the length of the BSS segment.
|
||||
struct DTA* p_dta; // This LONG contains a pointer to the processes’ DTA.
|
||||
struct BasePage* p_parent; // This LONG contains a pointer to the processes’ parent’s basepage.
|
||||
unsigned int p_reserved; // This LONG is currently unused and is reserved.
|
||||
char* p_env; // This LONG contains a pointer to the processes’ environment string.
|
||||
unsigned char p_undef[80]; // This area contains 80 unused, reserved bytes.
|
||||
char p_cmdlin[128]; // This area contains a copy of the 128 byte command line string.
|
||||
};
|
||||
|
||||
extern struct BasePage* _BasePage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GEM_BASEPAGE_H
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include <_ansi.h>
|
||||
|
||||
/*
|
||||
The conversion between gem errors and errno is not a one to one match,
|
||||
so the goal has been to try and report errors to errno in such way that
|
||||
code depending on this will run as expected.
|
||||
This remains to be proven correct.
|
||||
*/
|
||||
void gem_error_to_errno(int gem_error)
|
||||
{
|
||||
errno = ENOSYS; // Use this as default error code.
|
||||
switch (gem_error)
|
||||
{
|
||||
case GEM_EDRVNR:
|
||||
case GEM_EMEDIA:
|
||||
case GEM_EPAPER:
|
||||
errno = EIO;
|
||||
break;
|
||||
case GEM_EBADRQ:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case GEM_E_SEEK:
|
||||
errno = ESPIPE;
|
||||
break;
|
||||
case GEM_ESECNF:
|
||||
case GEM_EWRITF:
|
||||
case GEM_EREADF:
|
||||
errno = EIO;
|
||||
break;
|
||||
case GEM_EWRPRO:
|
||||
errno = EROFS;
|
||||
break;
|
||||
case GEM_EUNDEV:
|
||||
case GEM_EDRIVE:
|
||||
errno = ENODEV;
|
||||
break;
|
||||
case GEM_EFILNF:
|
||||
case GEM_EPTHNF:
|
||||
case GEM_EMOUNT:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case GEM_ENHNDL:
|
||||
case GEM_ENMFIL:
|
||||
errno = EMFILE;
|
||||
break;
|
||||
case GEM_EACCDN:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case GEM_EIHNDL:
|
||||
errno = EBADF;
|
||||
break;
|
||||
case GEM_ENSMEM:
|
||||
case GEM_EGSBF:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case GEM_EIMBA:
|
||||
errno = EADDRNOTAVAIL;
|
||||
break;
|
||||
case GEM_ENSAME:
|
||||
errno = EXDEV;
|
||||
break;
|
||||
case GEM_ELOCKED:
|
||||
case GEM_ENSLOCK:
|
||||
errno = ENOLCK;
|
||||
break;
|
||||
case GEM_ENAMETOOLONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case GEM_EPLFMT:
|
||||
errno = ENOEXEC;
|
||||
break;
|
||||
case GEM_ELOOP:
|
||||
errno = EMLINK;
|
||||
break;
|
||||
case GEM_E_OK:
|
||||
case GEM_ERROR:
|
||||
case GEM_EUNCMD:
|
||||
case GEM_E_CRC:
|
||||
case GEM_E_CHNG:
|
||||
case GEM_EBADSF:
|
||||
case GEM_EOTHER:
|
||||
case GEM_EINVFN:
|
||||
case GEM_EINTRN:
|
||||
default:
|
||||
errno = -gem_error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef GEM_ERRNO_DEFINED
|
||||
#define GEM_ERRNO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GEM_E_OK 0 // No error
|
||||
#define GEM_ERROR -1 // Generic error
|
||||
#define GEM_EDRVNR -2 // Drive not ready
|
||||
#define GEM_EUNCMD -3 // Unknown command
|
||||
#define GEM_E_CRC -4 // CRC error
|
||||
#define GEM_EBADRQ -5 // Bad request
|
||||
#define GEM_E_SEEK -6 // Seek error
|
||||
#define GEM_EMEDIA -7 // Unknown media
|
||||
#define GEM_ESECNF -8 // Sector not found
|
||||
#define GEM_EPAPER -9 // Out of paper
|
||||
#define GEM_EWRITF -10 // Write fault
|
||||
#define GEM_EREADF -11 // Read fault
|
||||
#define GEM_EWRPRO -12 // Device is write protected
|
||||
#define GEM_E_CHNG -14 // Media change detected
|
||||
#define GEM_EUNDEV -15 // Unknown device
|
||||
#define GEM_EBADSF -16 // Bad sectors on format
|
||||
#define GEM_EOTHER -17 // Insert other disk (request)
|
||||
#define GEM_EINVFN -32 // Invalid function
|
||||
#define GEM_EFILNF -33 // File not found
|
||||
#define GEM_EPTHNF -34 // Path not found
|
||||
#define GEM_ENHNDL -35 // No more handles
|
||||
#define GEM_EACCDN -36 // Access denied
|
||||
#define GEM_EIHNDL -37 // Invalid handle
|
||||
#define GEM_ENSMEM -39 // Insufficient memory
|
||||
#define GEM_EIMBA -40 // Invalid memory block address
|
||||
#define GEM_EDRIVE -46 // Invalid drive specification
|
||||
#define GEM_ENSAME -48 // Cross device rename
|
||||
#define GEM_ENMFIL -49 // No more files
|
||||
#define GEM_ELOCKED -58 // Record is already locked
|
||||
#define GEM_ENSLOCK -59 // Invalid lock removal request
|
||||
#define GEM_ERANGE -64 // Range error
|
||||
#define GEM_ENAMETOOLONG -64 // Range error
|
||||
#define GEM_EINTRN -65 // Internal error
|
||||
#define GEM_EPLFMT -66 // Invalid program load format
|
||||
#define GEM_EGSBF -67 // Memory block growth failure
|
||||
#define GEM_ELOOP -80 // Too many symbolic links
|
||||
#define GEM_EMOUNT -200 // Mount point crossed (indicator)
|
||||
|
||||
void gem_error_to_errno(int gem_error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GEM_ERRNO_DEFINED
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
char *getcwd(char *buf, size_t size)
|
||||
{
|
||||
char *retbuf = buf;
|
||||
if (retbuf == 0)
|
||||
{
|
||||
errno = EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned short drive = trap1_19();
|
||||
int result = trap1_47(retbuf + 2, drive + 1);
|
||||
if (result < 0)
|
||||
{
|
||||
gem_error_to_errno(result);
|
||||
return 0;
|
||||
}
|
||||
retbuf[0] = (char)('A' + drive);
|
||||
retbuf[1] = ':';
|
||||
return retbuf;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include <_syslist.h>
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
/*
|
||||
Xorshift pseudorandom number generator.
|
||||
https://en.wikipedia.org/wiki/Xorshift
|
||||
Inited with random seed.
|
||||
*/
|
||||
|
||||
int getentropy(void *buf, size_t buflen)
|
||||
{
|
||||
unsigned int a;
|
||||
unsigned int state[4];
|
||||
|
||||
// Init state
|
||||
a = trap14_11(); // Atari Random func.
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
// xorshift32
|
||||
a ^= (a << 13);
|
||||
a ^= (a >> 17);
|
||||
a ^= (a << 5);
|
||||
state[i] = a;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buflen; ++i)
|
||||
{
|
||||
// xorshift128
|
||||
unsigned int t = state[3];
|
||||
unsigned int s = state[0];
|
||||
state[3] = state[2];
|
||||
state[2] = state[1];
|
||||
state[1] = s;
|
||||
|
||||
t ^= t << 11;
|
||||
t ^= t >> 7;
|
||||
state[0] = t ^ s ^ (s >> 19);
|
||||
|
||||
// use lowest byte (could be optimized to adapt to buf len and output whole 32 bits when possible.)
|
||||
((unsigned char*)buf)[i] = (unsigned char)state[0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
|
||||
int getpid(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
/*
|
||||
Atari can only handle dates from 1980 to 2107.
|
||||
time_t on m68k is 32bit signed, so that gives us an upper limit of 2038.
|
||||
The code below uses that limitation to simplify the code.
|
||||
*/
|
||||
|
||||
#define SEC_1900_TO_1980 2524521600
|
||||
#define SEC_1900_TO_MAX 0x7fffffff
|
||||
#define SECONDS_IN_A_DAY (24 * 60 * 60)
|
||||
#define SEC_JAN_AND_FEB ((31 + 29) * SECONDS_IN_A_DAY) // In a leap year
|
||||
#define SECONDS_IN_A_YEAR (365 * SECONDS_IN_A_DAY)
|
||||
|
||||
static const short month_to_day[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
|
||||
|
||||
int gettimeofday(struct timeval* tv, void* __tz)
|
||||
{
|
||||
struct timezone* tz = __tz;
|
||||
if (tz != 0)
|
||||
{
|
||||
// Support for timezone have been removed from linux glibc, so we just fill in a zero timezone.
|
||||
tz->tz_minuteswest = 0;
|
||||
tz->tz_dsttime = 0;
|
||||
}
|
||||
if (tv != 0)
|
||||
{
|
||||
unsigned short date = trap1_2a();
|
||||
unsigned short time = trap1_2c();
|
||||
|
||||
int year = ((date >> 9) & 0x7f); // from 1980
|
||||
int month = ((date >> 5) & 0xf) - 1;
|
||||
int day = date & 0x1f;
|
||||
int hour = ((time >> 11) & 0x1f);
|
||||
int min = ((time >> 5) & 0x3f);
|
||||
int sec = (time & 0x1f) * 2;
|
||||
|
||||
// Days passed in current year
|
||||
time_t days = day + month_to_day[month];
|
||||
// Add days for every passed year
|
||||
days += year * 365;
|
||||
|
||||
// Add days for every passed leap year
|
||||
int months = year * 12 + month; // total months
|
||||
months -= 2; // remove januari and februari
|
||||
if (months > 0)
|
||||
{
|
||||
// We must have passed at least one leap day.
|
||||
int leap_days = (months / (12*4)) + 1;
|
||||
days += leap_days;
|
||||
}
|
||||
|
||||
// Add it all together
|
||||
tv->tv_sec = (((((days * 24) + hour) * 60) + min) * 60) + sec + SEC_1900_TO_1980;
|
||||
tv->tv_usec = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settimeofday(const struct timeval* tv, const struct timezone* tz)
|
||||
{
|
||||
// Support for timezone have been removed from linux glibc, so we just ignore it.
|
||||
if (tv != 0)
|
||||
{
|
||||
if (tv->tv_sec < SEC_1900_TO_1980 || tv->tv_sec >= SEC_1900_TO_MAX)
|
||||
{
|
||||
// Outside the ranges we can handle.
|
||||
gem_error_to_errno(GEM_EBADRQ);
|
||||
return -1;
|
||||
}
|
||||
|
||||
time_t seconds = tv->tv_sec - SEC_1900_TO_1980;
|
||||
int year = 0;
|
||||
time_t ysec = SECONDS_IN_A_YEAR;
|
||||
do
|
||||
{
|
||||
ysec = SECONDS_IN_A_YEAR;
|
||||
if ((year % 4) == 0)
|
||||
{
|
||||
ysec += SECONDS_IN_A_DAY;
|
||||
}
|
||||
++year;
|
||||
seconds -= ysec;
|
||||
} while (seconds >= 0);
|
||||
--year;
|
||||
seconds += ysec;
|
||||
|
||||
int minutes = seconds / 60;
|
||||
int hours = minutes / 60;
|
||||
int days = hours / 24;
|
||||
int month = 0;
|
||||
int leap = year % 4;
|
||||
short ld = month_to_day[0];
|
||||
for (int m = 0; m < 12; ++m)
|
||||
{
|
||||
short d = month_to_day[m + 1];
|
||||
if (leap == 0 && m > 0) {d += 1;}
|
||||
if (d > days)
|
||||
{
|
||||
month = m;
|
||||
days -= ld;
|
||||
break;
|
||||
}
|
||||
ld = d;
|
||||
}
|
||||
|
||||
unsigned short date = (unsigned short)(year << 9);
|
||||
date |= (unsigned short)((month + 1) << 5);
|
||||
date |= (unsigned short)days;
|
||||
unsigned short time = (unsigned short)((hours % 24) << 11);
|
||||
time |= (unsigned short)((minutes % 60) << 5);
|
||||
time |= (unsigned short)((seconds % 60) >> 1);
|
||||
|
||||
int err;
|
||||
if ((err = trap1_2b(date)) < 0)
|
||||
{
|
||||
gem_error_to_errno(err);
|
||||
return -1;
|
||||
}
|
||||
if ((err = trap1_2d(time)) < 0)
|
||||
{
|
||||
gem_error_to_errno(err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include "atari-traps.h"
|
||||
|
||||
int isatty(int fd)
|
||||
{
|
||||
return fd == GSH_AUX ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
|
||||
/*
|
||||
* kill -- go out via exit...
|
||||
*/
|
||||
int kill(int pid, int sig)
|
||||
{
|
||||
_exit(sig);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <_ansi.h>
|
||||
#include <_syslist.h>
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int link(char *old, char *new)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(link)
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
int newoff = GEM_EIHNDL;
|
||||
if (fd >= 0 && fd <= 2)
|
||||
{
|
||||
// stdin, stdout and stderr just returns OK without doing anything.
|
||||
return 0;
|
||||
}
|
||||
else if (fd >= 3)
|
||||
{
|
||||
// Any file descriptor
|
||||
unsigned short bios_mode = 3; // invalid mode
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
bios_mode = 0;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
bios_mode = 1;
|
||||
break;
|
||||
case SEEK_END:
|
||||
bios_mode = 2;
|
||||
break;
|
||||
}
|
||||
newoff = trap1_42((unsigned int)offset, (unsigned short)fd, bios_mode);
|
||||
}
|
||||
if (newoff < 0)
|
||||
{
|
||||
gem_error_to_errno(newoff);
|
||||
return (off_t)-1;
|
||||
}
|
||||
return (off_t)newoff;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
int mkdir(const char *pathname, mode_t mode)
|
||||
{
|
||||
// Ignore mode, it is not supported by the st.
|
||||
int result = trap1_39(pathname);
|
||||
if (result < 0)
|
||||
{
|
||||
gem_error_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
// I really don't like having these defines here,
|
||||
// fcntl.h where they are, also defines a function for "open",
|
||||
// that is different from the one libgloss is supposed to provide...
|
||||
#ifndef O_CREAT
|
||||
#define O_CREAT 0x0200
|
||||
#endif // O_CREAT
|
||||
#ifndef O_APPEND
|
||||
#define O_APPEND 0x0008
|
||||
#endif // O_APPEND
|
||||
#ifndef O_EXCL
|
||||
#define O_EXCL 0x0800
|
||||
#endif // O_EXCL
|
||||
#ifndef O_TRUNC
|
||||
#define O_TRUNC 0x0400
|
||||
#endif // O_TRUNC
|
||||
|
||||
// mode is ignored. Those kind of settings is not supported by the st.
|
||||
int open(const char *buf, int flags, int mode)
|
||||
{
|
||||
int bios_handle = -1;
|
||||
unsigned short bios_mode = (unsigned short)(flags & 0x3); // bits 0-1 the same for st and linux.
|
||||
int create = flags & O_CREAT;
|
||||
int append = flags & O_APPEND; // open doc says that seek end should be done before each write call. We assume that newlib handles that.
|
||||
int excl = flags & O_EXCL; // File must be created by this call.
|
||||
int trunc = flags & O_TRUNC; // File is forced to be created and thus truncated.
|
||||
|
||||
const char *bios_path = buf;
|
||||
if (!trunc)
|
||||
{
|
||||
bios_handle = trap1_3d(bios_path, bios_mode);
|
||||
}
|
||||
if (bios_handle < 0 && (create || trunc))
|
||||
{
|
||||
unsigned short bios_attrib = 0;
|
||||
bios_handle = trap1_3c(bios_path, bios_attrib);
|
||||
}
|
||||
else if (create && excl)
|
||||
{
|
||||
// We explicitly specified that file must be created, and it already existed, so error!
|
||||
gem_error_to_errno(GEM_EACCDN);
|
||||
// Close file.
|
||||
trap1_3e((unsigned short)bios_handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bios_handle >= 0 && append)
|
||||
{
|
||||
// Seek to end.
|
||||
int new_file_pos = trap1_42(0, (unsigned short)bios_handle, 2);
|
||||
if (new_file_pos < 0)
|
||||
{
|
||||
gem_error_to_errno(new_file_pos);
|
||||
// Close file.
|
||||
trap1_3e((unsigned short)bios_handle);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bios_handle < 0)
|
||||
{
|
||||
gem_error_to_errno(bios_handle);
|
||||
bios_handle = -1;
|
||||
}
|
||||
/*
|
||||
If bios_handle is positive, then the low word is the gemdos handle, and the high word is zero.
|
||||
*/
|
||||
return bios_handle;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
_READ_WRITE_RETURN_TYPE read(int fd, void *buf, size_t nbytes)
|
||||
{
|
||||
int numRead = GEM_EIHNDL;
|
||||
if (fd >= 0)
|
||||
{
|
||||
numRead = trap1_3f((unsigned short)fd, nbytes, buf);
|
||||
if (numRead >= 0 && numRead < nbytes && fd == GSH_CONIN)
|
||||
{
|
||||
/*
|
||||
When reading from console, the EOF character is "\n".
|
||||
Atari tos do not return the EOF character, but posix read do.
|
||||
So we assume that when the trap call have not reached the nbytes limit,
|
||||
then it must have gotten an EOF.
|
||||
So in that case we insert "\n" to the end of the buffer and increase lenth by 1.
|
||||
*/
|
||||
((char*)buf)[numRead] = '\n';
|
||||
++numRead;
|
||||
/*
|
||||
This is not enough however...
|
||||
Atari tos requires a line feed to be "\r\n", and apparently, the "\r" is executed by tos
|
||||
but not returned when reading. This is not a problem for us, but the "\n" as it is an EOF
|
||||
is simply discarded and not executed. So we also need to send a "\n" to stdout to fully comply
|
||||
with standard C behaviour.
|
||||
*/
|
||||
trap1_40(GSH_CONOUT, 1, "\n");
|
||||
}
|
||||
}
|
||||
if (numRead < 0)
|
||||
{
|
||||
gem_error_to_errno(numRead);
|
||||
return -1;
|
||||
}
|
||||
return numRead;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <_ansi.h>
|
||||
#include <_syslist.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int readlink(const char *path, char *buf, size_t bufsize)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(readlink)
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
int _rename(const char *old_filename, const char *new_filename)
|
||||
{
|
||||
int err = trap1_56(old_filename, new_filename);
|
||||
if (err < 0)
|
||||
{
|
||||
gem_error_to_errno(err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
int rmdir(const char *pathname)
|
||||
{
|
||||
int result = trap1_3a(pathname);
|
||||
if (result < 0)
|
||||
{
|
||||
gem_error_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <_ansi.h>
|
||||
|
||||
extern char *_HeapPtr;
|
||||
extern char *_HeapBottom;
|
||||
extern char *_HeapTop;
|
||||
|
||||
char *sbrk(int nbytes)
|
||||
{
|
||||
char *newheap = _HeapPtr + nbytes;
|
||||
if (newheap > _HeapTop)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return ((char *)-1);
|
||||
}
|
||||
char *retptr = _HeapPtr;
|
||||
_HeapPtr = newheap;
|
||||
return retptr;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
|
||||
// I don't like this extern declaration here...
|
||||
extern int open(const char *buf, int flags, int mode);
|
||||
|
||||
int stat(const char *path, struct stat *buf)
|
||||
{
|
||||
int handle = open(path, 0, 0); // read only
|
||||
if (handle >= 0)
|
||||
{
|
||||
int err = fstat(handle, buf);
|
||||
close(handle);
|
||||
handle = err;
|
||||
}
|
||||
if (handle < 0)
|
||||
{
|
||||
gem_error_to_errno(handle);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <_ansi.h>
|
||||
#include <_syslist.h>
|
||||
#include <errno.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int symlink(const char *path1, const char *path2)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(symlink)
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/times.h>
|
||||
#include "atari-traps.h"
|
||||
#include "atari-gem_errno.h"
|
||||
|
||||
// Defined and initialized in atari-crti.S
|
||||
extern unsigned int _atari_4ba_at_prg_start;
|
||||
|
||||
|
||||
// The memory location read is actually unsigned, so we cast that in the caller func.
|
||||
int read200hzMem(void)
|
||||
{
|
||||
// 0x4ba is a privileged address only readable in supervisor mode.
|
||||
return *((int*)0x4ba);
|
||||
}
|
||||
|
||||
clock_t times(struct tms *buf)
|
||||
{
|
||||
// Call callback in supervisor mode.
|
||||
unsigned long long int ticks200hz = (unsigned long long int)trap14_26(read200hzMem);
|
||||
unsigned long long int libcticks = (ticks200hz * CLK_TCK) / 200;
|
||||
|
||||
unsigned long long int processticks = ((unsigned long long int)_atari_4ba_at_prg_start * CLK_TCK) / 200;
|
||||
processticks = libcticks - processticks;
|
||||
|
||||
// For a single threaded system like the atari, only tms_utime is meaningful.
|
||||
buf->tms_utime = (clock_t)processticks;
|
||||
buf->tms_stime = 0;
|
||||
buf->tms_cutime = 0;
|
||||
buf->tms_cstime = 0;
|
||||
return (clock_t)libcticks;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
|
||||
OUTPUT_ARCH(m68k)
|
||||
INPUT (crti.o crtn.o crt0.o)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/*
|
||||
Start all addresses at 0.
|
||||
That way, the relocation is a bit easier when converting to prg.
|
||||
*/
|
||||
. = 0x0;
|
||||
.text : {
|
||||
*crti.o(.init)
|
||||
*crtbegin.o(.init)
|
||||
*crtend.o(.init)
|
||||
*crtn.o(.init)
|
||||
*crt0.o(.init)
|
||||
*crti.o(.fini)
|
||||
*crtbegin.o(.fini)
|
||||
*crtend.o(.fini)
|
||||
*crtn.o(.fini)
|
||||
*(.text*)
|
||||
*(.gnu.warning)
|
||||
FILL(0x0000);
|
||||
. = ALIGN(0x4);
|
||||
}
|
||||
/*
|
||||
There is no rodata in a prg file, so we store all data in .data section.
|
||||
*/
|
||||
.data BLOCK(0x4) : {
|
||||
__DATA_SEGMENT__ = .;
|
||||
*(.data*);
|
||||
. = ALIGN(0x4);
|
||||
*(.rodata*);
|
||||
. = ALIGN(0x4);
|
||||
|
||||
*(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*)
|
||||
*(.eh_frame) *(.eh_frame.*)
|
||||
*(.sframe) *(.sframe.*)
|
||||
*(.gcc_except_table .gcc_except_table.*)
|
||||
*(.gnu_extab*)
|
||||
|
||||
/*
|
||||
All constructors
|
||||
*/
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
|
||||
/*
|
||||
All destructors
|
||||
*/
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
|
||||
FILL(0x0000);
|
||||
. = ALIGN(0x4);
|
||||
}
|
||||
.bss BLOCK(0x4) : {
|
||||
__BSS_SEGMENT__ = .;
|
||||
*(.bss);
|
||||
. = ALIGN(0x4);
|
||||
*(COMMON);
|
||||
. = ALIGN(0x4);
|
||||
}
|
||||
__BSS_SEGMENT_END = .;
|
||||
|
||||
/*
|
||||
Atari Prg header.
|
||||
We don't care what the address is for this.
|
||||
*/
|
||||
.prgheader : {
|
||||
SHORT(0x601a); /* Branch to start of the program (must be 0x601a, used as magic number!) */
|
||||
LONG(__DATA_SEGMENT__); /* Length of the TEXT segment */
|
||||
LONG(__BSS_SEGMENT__ - __DATA_SEGMENT__); /* Length of the DATA segment */
|
||||
LONG(__BSS_SEGMENT_END - __BSS_SEGMENT__); /* Length of the BSS segment */
|
||||
LONG(0); /* Length of the symbol table */
|
||||
LONG(0); /* Reserved, should be 0 */
|
||||
LONG(0); /* Program flags */
|
||||
SHORT(0); /* 0 = Relocation info present */
|
||||
}
|
||||
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 (INFO) : { *(.comment); LINKER_VERSION; }
|
||||
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0.
|
||||
*/
|
||||
/* DWARF 1. */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
||||
/* GNU DWARF 1 extensions. */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
|
||||
/* DWARF 1.1 and DWARF 2. */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
|
||||
/* DWARF 2. */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
|
||||
/* SGI/MIPS DWARF 2 extensions. */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
|
||||
/* DWARF 3. */
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
|
||||
/* DWARF 5. */
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.debug_line_str 0 : { *(.debug_line_str) }
|
||||
.debug_loclists 0 : { *(.debug_loclists) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_names 0 : { *(.debug_names) }
|
||||
.debug_rnglists 0 : { *(.debug_rnglists) }
|
||||
.debug_str_offsets 0 : { *(.debug_str_offsets) }
|
||||
.debug_sup 0 : { *(.debug_sup) }
|
||||
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2025 Mikael Hildenborg
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
# Atari gcc specs
|
||||
|
||||
*link:
|
||||
+ --emit-relocs --no-warn-rwx-segments -static --no-warn-execstack --undefined=__errno -T atari-tos.ld
|
||||
|
||||
*lib:
|
||||
+ -latari-tos
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "atari-traps.h"
|
||||
|
||||
// Store stack pointer in a3, that by Atari documentation will be left untouched by the trap call.
|
||||
#define TRAP_BEGIN "move.l %%a7, %%a3\n\t"
|
||||
// Make trap call and then restore the stack pointer from the stored value in a3
|
||||
#define TRAP_FUNC(num, func) "move.w #" #func ", %%a7@-\n\ttrap #" #num "\n\tmove.l %%a3, %%a7\n\t"
|
||||
// Registers d1,d2 and a0, a1, a2 may be affected by trap #1 calls. Register a3 is used to store/restore a7
|
||||
#define CLOBBER_REG "d1", "d2", "a0", "a1", "a2", "a3"
|
||||
|
||||
unsigned int trap1_e(unsigned short bios_drive)
|
||||
{
|
||||
register unsigned int bios_mounted_drives asm ("d0") = 0;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0xe)
|
||||
: "=r" (bios_mounted_drives)
|
||||
: "r" (bios_drive)
|
||||
: CLOBBER_REG);
|
||||
return bios_mounted_drives;
|
||||
}
|
||||
|
||||
unsigned short trap1_19(void)
|
||||
{
|
||||
register unsigned short bios_drive asm ("d0") = 0;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
TRAP_FUNC(1, 0x19)
|
||||
: "=r" (bios_drive)
|
||||
:
|
||||
: CLOBBER_REG);
|
||||
return bios_drive;
|
||||
}
|
||||
|
||||
unsigned short trap1_2a(void)
|
||||
{
|
||||
register unsigned short date asm ("d0") = 0;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
TRAP_FUNC(1, 0x2a)
|
||||
: "=r" (date)
|
||||
:
|
||||
: CLOBBER_REG);
|
||||
return date;
|
||||
}
|
||||
|
||||
int trap1_2b(unsigned short date)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x2b)
|
||||
: "=r" (result)
|
||||
:"r" (date)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned short trap1_2c(void)
|
||||
{
|
||||
register unsigned short time asm ("d0") = 0;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
TRAP_FUNC(1, 0x2c)
|
||||
: "=r" (time)
|
||||
:
|
||||
: CLOBBER_REG);
|
||||
return time;
|
||||
}
|
||||
|
||||
int trap1_2d(unsigned short time)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x2d)
|
||||
: "=r" (result)
|
||||
:"r" (time)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
struct DTA* trap1_2f(unsigned short bios_handle)
|
||||
{
|
||||
register struct DTA* result asm ("d0") = (struct DTA*)-1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x2f)
|
||||
: "=r" (result)
|
||||
: "r" (bios_handle)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int trap1_39(const char* bios_path)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x39)
|
||||
: "=r" (result)
|
||||
: "r" (bios_path)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_3a(const char* bios_path)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x3a)
|
||||
: "=r" (result)
|
||||
: "r" (bios_path)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_3b(const char* bios_path)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x3b)
|
||||
: "=r" (result)
|
||||
: "r" (bios_path)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_3c(const char* bios_path, unsigned short bios_attrib)
|
||||
{
|
||||
register int bios_handle asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %2, %%a7@-\n\t"
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x3c)
|
||||
: "=r" (bios_handle)
|
||||
: "r" (bios_path), "r" (bios_attrib)
|
||||
: CLOBBER_REG);
|
||||
return bios_handle;
|
||||
}
|
||||
|
||||
int trap1_3d(const char* bios_path, unsigned short bios_mode)
|
||||
{
|
||||
register int bios_handle asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %2, %%a7@-\n\t"
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x3d)
|
||||
: "=r" (bios_handle)
|
||||
: "r" (bios_path), "r" (bios_mode)
|
||||
: CLOBBER_REG);
|
||||
return bios_handle;
|
||||
}
|
||||
|
||||
int trap1_3e(unsigned short bios_handle)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x3e)
|
||||
: "=r" (result)
|
||||
: "r" (bios_handle)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_3f(unsigned short bios_handle, int length, void* buf)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %3, %%a7@-\n\t"
|
||||
"move.l %2, %%a7@-\n\t"
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x3f)
|
||||
: "=r" (result)
|
||||
: "r" (bios_handle), "r" (length), "r" (buf)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_40(unsigned short bios_handle, int length, const void* buf)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %3, %%a7@-\n\t"
|
||||
"move.l %2, %%a7@-\n\t"
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x40)
|
||||
: "=r" (result)
|
||||
: "r" (bios_handle), "r" (length), "r" (buf)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_41(const char* bios_path)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x41)
|
||||
: "=r" (result)
|
||||
: "r" (bios_path)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_42(unsigned int file_position, unsigned short bios_handle, unsigned short bios_mode)
|
||||
{
|
||||
register int new_position asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %3, %%a7@-\n\t"
|
||||
"move.w %2, %%a7@-\n\t"
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x42)
|
||||
: "=r" (new_position)
|
||||
: "r" (file_position), "r" (bios_handle), "r" (bios_mode)
|
||||
: CLOBBER_REG);
|
||||
return new_position;
|
||||
}
|
||||
|
||||
int trap1_47(char* buf, unsigned short bios_drive)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.w %2, %%a7@-\n\t"
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x47)
|
||||
: "=r" (result)
|
||||
: "r" (buf), "r" (bios_drive)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_4b(unsigned short mode, const char* file_name, const char* cmdline, const char* envstring)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %4, %%a7@-\n\t"
|
||||
"move.l %3, %%a7@-\n\t"
|
||||
"move.l %2, %%a7@-\n\t"
|
||||
"move.w %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x4b)
|
||||
: "=r" (result)
|
||||
: "r" (mode), "r" (file_name), "r" (cmdline), "r" (envstring)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap1_56(const char* oldname, const char* newname)
|
||||
{
|
||||
register int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %2, %%a7@-\n\t"
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
"move.w #0, %%a7@-\n\t"
|
||||
TRAP_FUNC(1, 0x56)
|
||||
: "=r" (result)
|
||||
: "r" (oldname), "r" (newname)
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int trap14_11(void)
|
||||
{
|
||||
register unsigned int result asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
TRAP_FUNC(14, 0x11)
|
||||
: "=r" (result)
|
||||
:
|
||||
: CLOBBER_REG);
|
||||
return result;
|
||||
}
|
||||
|
||||
int trap14_26(int (*callback)(void))
|
||||
{
|
||||
register int callback_return asm ("d0") = -1;
|
||||
__asm__ volatile (
|
||||
TRAP_BEGIN
|
||||
"move.l %1, %%a7@-\n\t"
|
||||
TRAP_FUNC(14, 0x26)
|
||||
: "=r" (callback_return)
|
||||
: "r" (callback)
|
||||
: CLOBBER_REG);
|
||||
return callback_return;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef TRAPS_DEFINED
|
||||
#define TRAPS_DEFINED
|
||||
|
||||
#include "atari-gem_basepage.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Only trap calls used by atari libgloss is included here.
|
||||
*/
|
||||
|
||||
unsigned int trap1_e(unsigned short bios_drive);
|
||||
|
||||
// Returned drive starts at 0 for A
|
||||
unsigned short trap1_19(void);
|
||||
|
||||
unsigned short trap1_2a(void);
|
||||
|
||||
int trap1_2b(unsigned short date);
|
||||
|
||||
unsigned short trap1_2c(void);
|
||||
|
||||
int trap1_2d(unsigned short time);
|
||||
|
||||
struct DTA* trap1_2f(unsigned short bios_handle);
|
||||
|
||||
int trap1_39(const char* bios_path);
|
||||
|
||||
int trap1_3a(const char* bios_path);
|
||||
|
||||
int trap1_3b(const char* bios_path);
|
||||
|
||||
int trap1_3c(const char* bios_path, unsigned short bios_attrib);
|
||||
|
||||
int trap1_3d(const char* bios_path, unsigned short bios_mode);
|
||||
|
||||
#define GSH_BIOSCON 0xFFFF
|
||||
#define GSH_BIOSAUX 0xFFFE
|
||||
#define GSH_BIOSPRN 0xFFFD
|
||||
#define GSH_BIOSMIDIIN 0xFFFC
|
||||
#define GSH_BIOSMIDIOUT 0xFFFB
|
||||
#define GSH_CONIN 0x00
|
||||
#define GSH_CONOUT 0x01
|
||||
#define GSH_AUX 0x02
|
||||
#define GSH_PRN 0x03
|
||||
|
||||
int trap1_3e(unsigned short bios_handle);
|
||||
|
||||
int trap1_3f(unsigned short bios_handle, int length, void* buf);
|
||||
|
||||
int trap1_40(unsigned short bios_handle, int length, const void* buf);
|
||||
|
||||
int trap1_41(const char* bios_path);
|
||||
|
||||
int trap1_42(unsigned int file_position, unsigned short bios_handle, unsigned short bios_mode);
|
||||
|
||||
// bios_drive 0 is default drive, and 1 and upwards is A...
|
||||
int trap1_47(char* buf, unsigned short bios_drive);
|
||||
|
||||
#define PE_LOADGO 0
|
||||
#define PE_LOAD 3
|
||||
#define PE_GO 4
|
||||
#define PE_BASEPAGE 5
|
||||
#define PE_GOTHENFREE 6
|
||||
int trap1_4b(unsigned short mode, const char* file_name, const char* cmdline, const char* envstring);
|
||||
|
||||
int trap1_56(const char* oldname, const char* newname);
|
||||
|
||||
unsigned int trap14_11(void);
|
||||
|
||||
int trap14_26(int (*callback)(void));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TRAPS_DEFINED
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
int unlink(char *path)
|
||||
{
|
||||
int err = trap1_41(path);
|
||||
if (err < 0)
|
||||
{
|
||||
gem_error_to_errno(err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include "libnosys/warning.h"
|
||||
|
||||
int wait(int *status)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stub_warning(wait)
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright (C) 2025 Mikael Hildenborg
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <_ansi.h>
|
||||
#include "atari-gem_errno.h"
|
||||
#include "atari-traps.h"
|
||||
|
||||
const char* lineEnding = "\r\n";
|
||||
|
||||
int writeUntilDoneOrError(int fd, size_t len, const char* buf)
|
||||
{
|
||||
size_t written = 0;
|
||||
if (len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
do
|
||||
{
|
||||
int n = trap1_40((unsigned short)fd, len, buf);
|
||||
if (n < 0)
|
||||
{
|
||||
gem_error_to_errno(n);
|
||||
return -1;
|
||||
}
|
||||
written += n;
|
||||
buf += n;
|
||||
} while (written < len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
_READ_WRITE_RETURN_TYPE write(int fd, const void *buf, size_t nbytes)
|
||||
{
|
||||
int numWritten = GEM_EIHNDL;
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (fd == 2)
|
||||
{
|
||||
fd = GSH_CONOUT; // Use console out for stderr.
|
||||
}
|
||||
if (fd == GSH_CONOUT)
|
||||
{
|
||||
// When we write to stdout on Atari, we must add a \r after \n to
|
||||
// get the correct C output behaviour.
|
||||
const char* stream = (const char*)buf;
|
||||
size_t lastWrite = 0;
|
||||
for (size_t i = 0; i < nbytes; ++i)
|
||||
{
|
||||
if (stream[i] == '\n')
|
||||
{
|
||||
int len = i - lastWrite; // length up to but not including \n
|
||||
if (writeUntilDoneOrError(fd, len, stream + lastWrite) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (writeUntilDoneOrError(fd, 2, lineEnding) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
lastWrite = i + 1; // Include the \n
|
||||
}
|
||||
}
|
||||
if (lastWrite < nbytes)
|
||||
{
|
||||
int len = nbytes - lastWrite;
|
||||
if (writeUntilDoneOrError(fd, len, stream + lastWrite) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
numWritten = nbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
numWritten = trap1_40((unsigned short)fd, nbytes, buf);
|
||||
}
|
||||
}
|
||||
if (numWritten < 0)
|
||||
{
|
||||
gem_error_to_errno(numWritten);
|
||||
return -1;
|
||||
}
|
||||
return numWritten;
|
||||
}
|
||||
@@ -252,7 +252,6 @@ case "${host_cpu}" in
|
||||
mips*)
|
||||
machine_dir=mips
|
||||
libm_machine_dir=mips
|
||||
newlib_cflags="${newlib_cflags}"
|
||||
;;
|
||||
mmix)
|
||||
;;
|
||||
@@ -769,6 +768,10 @@ newlib_cflags="${newlib_cflags} -DCLOCK_PROVIDED -DMALLOC_PROVIDED -DEXIT_PROVID
|
||||
newlib_cflags="${newlib_cflags} -DHAVE_RENAME -DHAVE_SYSTEM -DMISSING_SYSCALL_NAMES"
|
||||
syscall_dir=
|
||||
;;
|
||||
m68k-atari-elf)
|
||||
newlib_cflags="${newlib_cflags} -DHAVE_RENAME -DMISSING_SYSCALL_NAMES"
|
||||
syscall_dir=
|
||||
;;
|
||||
mcore-*-*)
|
||||
syscall_dir=syscalls
|
||||
;;
|
||||
|
||||
Reference in new issue
Block a user