Updated to work with the new libmon-less setup.

This commit is contained in:
dtrg 2007-04-21 22:59:42 +00:00
parent 04860c08a8
commit 201c66879d
24 changed files with 357 additions and 316 deletions

View file

@ -2,6 +2,7 @@
# $State$
# $Revision$
The pc86 platform
=================
@ -15,28 +16,20 @@ This means that there's not very much memory available. It would be very easy
to change it to run in SMALL mode, where CS occupies one segment and DS and SS
another, which would give 64kB for nearly all programs; I just haven't done it.
This port uses a syscall interface, which means you get *all* of the ACK's
builtin libc with no shortcuts. File descriptors 0, 1 and 2 represent the
console. All reads block. There's enough TTY emulation to allow \n conversion
(set RAW to turn off) and local echo (unset ECHO to turn off); this is needed
to make Basic work.
This port only implements a very limited set of syscalls --- and most of those
are stubs required to make the demo apps link. File descriptors 0, 1 and 2
represent the console. All reads block. There's enough TTY emulation to allow
\n conversion and local echo (but it can't be turned off).
Language support
================
Tested with C (both), Basic, Pascal, Occam, Modula-2.
Basic works, but because Basic programs require access to a data file to work,
and pc86 doesn't (of course) have a file system, programs won't start unless
you hack the compiler not to try and open it.
Example command line
====================
ack -mpc86 -O -ansi -o pc86.img test.c
ack -mpc86 -O -o pc86.img examples/paranoia.c
The file pc86.img can then be copied onto a floppy and booted, or run via qemu
or somesuch emulator.
David Given
dg@cowlark.com

View file

@ -244,7 +244,6 @@ write_hex4:
finished:
mov si, running_msg
call write_string
call pause
! Wipe the bss. (I'm a little suprised that __m_a_i_n doesn't do this.)
@ -256,11 +255,9 @@ finished:
! Push standard parameters onto the stack and go.
mov ax, 1
xor ax, ax
push ax ! argc
mov ax, 2
push ax ! argc
mov ax, 3
push ax ! argv
push ax ! envp
call __m_a_i_n
! fall through into the exit routine.
@ -301,22 +298,18 @@ running_msg: .asciz '\n\rRunning.\n\r'
.define begtext,begdata,begbss
.define hol0,.trppc,.ignmask
.define ERANGE,ESET,EHEAP,ECASE,EILLINS,EIDIVZ,EODDZ
.extern _end
.sect .data
hol0:
.data2 0,0
.data2 0,0
.ignmask:
.data2 0
.trppc:
.data2 0
! Define symbols at the beginning of our various segments, so that we can find
! them. (Except .text, which has already been done.)
.sect .data; begdata:
.sect .rom; begrom:
.sect .bss; begbss:
! Some magic data. All EM systems need these.
.define .trppc, .ignmask
.comm .trppc, 4
.comm .ignmask, 4

View file

@ -13,9 +13,13 @@ var PLATFORM=pc86
var PLATFORMDIR={EM}/lib/{PLATFORM}
var CPP_F=-D__unix
var ALIGN=-a0:1 -a1:1 -a2:1 -a3:1
var C_LIB={PLATFORMDIR}/libc-stdio-knr.a {PLATFORMDIR}/libc-knr.a
var OLD_C_LIB={C_LIB}
var MACHOPT_F=-m8
# Override the setting in fe so that files compiled for linux386 can see
# the platform-specific headers.
var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/include/ansi
name be
from .m.g
to .s
@ -38,12 +42,10 @@ name led
mapflag -l* LNAME={PLATFORMDIR}/lib*
mapflag -i SEPID=-b1:0
mapflag -fp FLOATS={EM}/{ILIB}fp
mapflag -ansi C_LIB={PLATFORMDIR}/libc-ansi.a
args {ALIGN} {SEPID?} \
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
({RTS}:.ocm.b={PLATFORMDIR}/c-knr.o) \
({RTS}{ANSI?}:.c={PLATFORMDIR}/c-knr.o) \
({RTS}{ANSI?}:.cansi={PLATFORMDIR}/c-ansi.o) \
({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
({RTS}:.p={PLATFORMDIR}/pascal.o) \
-o > < \
@ -51,12 +53,9 @@ name led
(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
(.ocm.b:{TAIL}={OLD_C_LIB}) \
(.c:{TAIL}={C_LIB}) \
(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
{FLOATS?} \
(.e:{TAIL}={PLATFORMDIR}/libsys.a \
{PLATFORMDIR}/libmon.a \
{PLATFORMDIR}/libsys.a \
{PLATFORMDIR}/libem.a \
{PLATFORMDIR}/libend.a)
linker

View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#ifndef _ACK_CONFIG_H
#define _ACK_CONFIG_H
/* We're providing a time() system call rather than wanting a wrapper around
* gettimeofday() in the libc. */
#define ACKCONF_TIME_IS_A_SYSCALL
#endif

View file

@ -0,0 +1,70 @@
/*
* unistd.h - standard system calls
*/
/* $Id$ */
#ifndef _UNISTD_H
#define _UNISTD_H
#include <stddef.h>
/* Types */
typedef int pid_t;
typedef int mode_t;
/* Constants for file access (open and friends) */
enum
{
O_ACCMODE = 0x3,
O_RDONLY = 0,
O_WRONLY = 1,
O_RDWR = 2,
O_CREAT = 0100,
O_TRUNC = 01000,
O_APPEND = 02000,
O_NONBLOCK = 04000
};
/* Special variables */
extern char** environ;
/* Implemented system calls */
extern void _exit(int);
extern pid_t getpid(void);
extern void* sbrk(intptr_t increment);
extern int isatty(int d);
extern off_t lseek(int fildes, off_t offset, int whence);
extern int close(int d);
extern int open(const char* path, int access, ...);
extern int creat(const char* path, mode_t mode);
extern int read(int fd, void* buffer, size_t count);
extern int write(int fd, void* buffer, size_t count);
/* Unimplemented system calls (these are just prototypes to let the library
* compile). */
extern int fcntl(int fd, int op, ...);
/* Signal handling */
typedef int sig_atomic_t;
#define SIG_ERR ((__sighandler_t) -1) /* Error return. */
#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
#define SIGABRT 6 /* Abort (ANSI). */
#define _NSIG 32 /* Biggest signal number + 1
(not including real-time signals). */
typedef void (*sighandler_t)(int);
extern sighandler_t signal(int signum, sighandler_t handler);
extern int raise(int signum);
#endif

View file

@ -1,55 +0,0 @@
#
! $Source$
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
! This file contains the code necessary to extend the ACK heap. This is called
! by a i86/libem helper function called .strhp, which takes care of updating
! some magic global variables --- defined here.
! Pointer to the current top of the heap.
.sect .data
.define .reghp
.reghp:
.data2 endbss
! Pointer to the current top of memory.
.sect .data
.define .limhp
.limhp:
.data2 endbss
! Claims more memory from the system, but does not actually change those
! global variables (.strhp does that). This does not use the C calling
! convention!
!
! Stack: ( desired_limhp : actual_limhp )
! Also returns: ax = -1 on failure
.sect .text
.define BRK
BRK:
pop bx ! holds return address
pop ax ! holds desired limhp
cmp ax, sp ! compare sp with si
jae fail ! si too big? (Overlaps stack?)
cmp ax, endbss ! compare with bottom of heap
jb fail ! si too small? (Overlaps bss?)
return:
push ax ! success
jmp bx
fail:
mov ax, -1
jmp return

19
plat/pc86/libsys/_hol0.s Normal file
View file

@ -0,0 +1,19 @@
#
! $Source$
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .bss
! This data block is used to store information about the current line number
! and file.
.define hol0
.comm hol0, 8

View file

@ -1,166 +0,0 @@
#
! $Source$
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .bss
.define __sys_params_in
.comm __sys_params_in, 6
.define __sys_params_out
.comm __sys_params_out, 2
.comm opcode, 2
.comm returnto, 2
.sect .text
! Called on system call. This does *not* use the C calling convention:
! ax: syscall number
! stack: ( param3 param2 param1 - result )
.define .mon
.mon:
mov (opcode), ax
pop (returnto)
cmp ax, 1
je exit
cmp ax, 3
je read
cmp ax, 4
je write
cmp ax, 5
je open
cmp ax, 6
je nop_1 ! close
cmp ax, 20
je nop_0 ! getpid
cmp ax, 35
je nop_1 ! time
cmp ax, 48
je sigtrp
cmp ax, 54
je ioctl
! Syscall not supported --- write out an error message and halt.
unsupported:
mov si, msg
1:
lodsb
andb al, al
jz 2f
movb ah, 0xE ! service
mov bx, 0x0007 ! page 0, white
int 0x10
jmp 1b
2:
! Write out the syscall number.
mov dx, (opcode)
mov cx, 4 ! 4 hex digits
1:
rol dx, 1 ! rotate so that highest 4 bits are at the bottom
rol dx, 1
rol dx, 1
rol dx, 1
mov ax, 0xE0F ! ah = request, al = mask for nybble
andb al, dl
addb al, 0x90 ! convert al to ascii hex (four instructions)
daa
adcb al, 0x40
daa
int 0x10
loop 1b
! Exit.
jmp EXIT
.sect .rom
msg:
.asciz 'NOSYS'
.sect .text
exit:
jmp EXIT
read:
mov ax, __sys_read
jmp in_3_out_1
write:
mov ax, __sys_write
jmp in_3_out_1
open:
add sp, 2*2
jmp unimplemented
ioctl:
mov ax, __sys_ioctl
jmp in_3_out_0
sigtrp:
add sp, 4
jmp unimplemented
in_3_out_0:
pop (__sys_params_in+0)
pop (__sys_params_in+2)
pop (__sys_params_in+4)
call ax
jmp out_0
in_3_out_1:
pop (__sys_params_in+0)
pop (__sys_params_in+2)
pop (__sys_params_in+4)
call ax
jmp out_1
out_0:
or ax, ax
jnz failed
push ax
jmp return
out_1:
or ax, ax
jnz failed
push (__sys_params_out)
push ax
jmp return
unimplemented:
mov ax, EBADMON
failed:
push ax
push ax
jmp return
nop_1:
add sp, 1*2
jmp nop_0
nop_3:
add sp, 3*2
nop_0:
mov ax, 0
push ax
jmp return
return:
jmp (returnto)

43
plat/pc86/libsys/brk.c Normal file
View file

@ -0,0 +1,43 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#define OUT_OF_MEMORY (void*)(-1) /* sbrk returns this on failure */
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
extern char _end[1];
static char* current = _end;
int brk(void* newend)
{
/* This variable is used to figure out the current stack pointer,
* by taking its address. */
char dummy;
char* p = newend;
if ((p > (&dummy - STACK_BUFFER)) ||
(p < _end))
return -1;
current = p;
return 0;
}
void* sbrk(intptr_t increment)
{
char* old;
if (increment == 0)
return current;
old = current;
if (brk(old + increment) < 0)
return OUT_OF_MEMORY;
return old;
}

14
plat/pc86/libsys/close.c Normal file
View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int close(int fd)
{
errno = EBADF;
return -1;
}

15
plat/pc86/libsys/creat.c Normal file
View file

@ -0,0 +1,15 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int open(const char* path, int access, ...)
{
errno = EACCES;
return -1;
}

View file

@ -14,6 +14,9 @@
.sect .data
! Define various ACK error numbers. Note that these are *not* ANSI C
! errnos, and are used for different purposes.
D(ERANGE) = 1
D(ESET) = 2
D(EIDIVZ) = 6

13
plat/pc86/libsys/getpid.c Normal file
View file

@ -0,0 +1,13 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
pid_t getpid(void)
{
return 0;
}

13
plat/pc86/libsys/isatty.c Normal file
View file

@ -0,0 +1,13 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int isatty(int fd)
{
return 1;
}

14
plat/pc86/libsys/kill.c Normal file
View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int kill(pid_t pid, int sig)
{
errno = EINVAL;
return -1;
}

View file

@ -11,6 +11,6 @@ extern unsigned char _sys_rawread(void);
extern void _sys_write_tty(char c);
extern int _sys_ttyflags;
/* extern int _sys_ttyflags; */
#endif

14
plat/pc86/libsys/lseek.c Normal file
View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence)
{
errno = EINVAL;
return -1;
}

14
plat/pc86/libsys/open.c Normal file
View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int creat(const char* path, int mode)
{
return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
}

View file

@ -9,13 +9,22 @@ libsys_pc86 = acklibrary {
ACKINCLUDES = {"%BINDIR%include"},
ackfile (d.."errno.s"),
ackfile (d.."_mon.s"),
ackfile (d.."_brk.s"),
ackfile (d.."_hol0.s"),
ackfile (d.."_sys_rawread.s"),
ackfile (d.."_sys_rawwrite.s"),
ackfile (d.."_sys_read.c"),
ackfile (d.."_sys_write.c"),
ackfile (d.."_sys_ioctl.c"),
ackfile (d.."open.c"),
ackfile (d.."creat.c"),
ackfile (d.."close.c"),
ackfile (d.."read.c"),
ackfile (d.."write.c"),
-- ackfile (d.."_sys_ioctl.c"),
ackfile (d.."brk.c"),
ackfile (d.."getpid.c"),
ackfile (d.."kill.c"),
ackfile (d.."isatty.c"),
ackfile (d.."lseek.c"),
ackfile (d.."time.c"),
ackfile (d.."signal.c"),
install = pm.install("%BINDIR%lib/%PLATFORM%/libsys.a"),
}

View file

@ -5,50 +5,39 @@
#include <stdlib.h>
#include <errno.h>
#include <sgtty.h>
#include <unistd.h>
#include "libsys.h"
extern struct
{
int fd;
char* buffer;
size_t count;
} _sys_params_in;
extern struct
{
size_t bytesread;
} _sys_params_out;
#define P _sys_params_in
int _sys_read(void)
int read(int fd, void* buffer, size_t count)
{
char i;
/* We're only allowed to read from fd 0, 1 or 2. */
if ((P.fd < 0) || (P.fd > 2))
return EBADF;
if ((fd < 0) || (fd > 2))
{
errno = EBADF;
return -1;
}
/* Empty buffer? */
if (P.count == 0)
{
_sys_params_out.bytesread = 0;
if (count == 0)
return 0;
}
/* Read one byte. */
i = _sys_rawread();
#if 0
if ((i == '\r') && !(_sys_ttyflags & RAW))
i = '\n';
if (_sys_ttyflags & ECHO)
_sys_write_tty(i);
#endif
if (i == '\r')
i = '\n';
_sys_write_tty(i);
*P.buffer = i;
_sys_params_out.bytesread = 1;
return 0;
*(char*)buffer = i;
return 1;
}

15
plat/pc86/libsys/signal.c Normal file
View file

@ -0,0 +1,15 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include "libsys.h"
sighandler_t signal(int signum, sighandler_t handler)
{
return SIG_DFL;
}

17
plat/pc86/libsys/time.c Normal file
View file

@ -0,0 +1,17 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include "libsys.h"
time_t time(time_t* t)
{
if (t)
*t = 0;
return 0;
}

View file

@ -5,51 +5,44 @@
#include <stdlib.h>
#include <errno.h>
#include <sgtty.h>
#include <unistd.h>
#include "libsys.h"
extern struct
{
int fd;
const char* buffer;
size_t count;
} _sys_params_in;
extern struct
{
size_t byteswritten;
} _sys_params_out;
#define P _sys_params_in
void _sys_write_tty(char c)
{
_sys_rawwrite(c);
#if 0
if ((c == '\n') && !(_sys_ttyflags & RAW))
_sys_rawwrite('\r');
#endif
if (c == '\n')
_sys_rawwrite('\r');
}
int _sys_write(void)
int write(int fd, void* buffer, size_t count)
{
int i;
char* p = buffer;
/* We're only allowed to write to fd 0, 1 or 2. */
if ((P.fd < 0) || (P.fd > 2))
return EBADF;
if ((fd < 0) || (fd > 2))
{
errno = EBADF;
return -1;
}
/* Write all data. */
i = 0;
while (i < P.count)
while (i < count)
{
_sys_write_tty(*P.buffer++);
_sys_write_tty(*p++);
i++;
}
/* No failures. */
_sys_params_out.byteswritten = P.count;
return 0;
return count;
}

View file

@ -15,15 +15,23 @@ local descr = group {
install = pm.install(d.."descr", "%BINDIR%%PLATIND%/%PLATFORM%/descr")
}
local headers = group {
install = {
pm.install(d.."include/ack/config.h", "%BINDIR%%PLATIND%/%PLATFORM%/include/ack/config.h"),
pm.install(d.."include/unistd.h", "%BINDIR%%PLATIND%/%PLATFORM%/include/unistd.h"),
}
}
platform_pc86 = group {
ARCH = "i86",
PLATFORM = "pc86",
OPTIMISATION = "-O",
-- Ensure the descr file is installed first because we'll need it
-- to build the libraries.
-- Ensure the descr and headers are installed first because we'll need
-- them to build the libraries.
descr,
headers,
-- Build the back-end support.