diff --git a/mach/i80/libem/pmfile b/mach/i80/libem/pmfile new file mode 100644 index 000000000..ecc69cf16 --- /dev/null +++ b/mach/i80/libem/pmfile @@ -0,0 +1,49 @@ +-- $Source$ +-- $State$ +-- $Revision$ + +local d = ROOTDIR.."mach/i80/libem/" + +libem_i80 = acklibrary { + outputs = {"%U%/libem-%PLATFORM%.a"}, + + ackfile (d.."aar2.s"), + ackfile (d.."adi4.s"), + ackfile (d.."and.s"), + ackfile (d.."blm.s"), + ackfile (d.."cii.s"), + ackfile (d.."cmi4.s"), + ackfile (d.."cms.s"), + ackfile (d.."com.s"), + ackfile (d.."csa.s"), + ackfile (d.."csb.s"), + ackfile (d.."dup.s"), + ackfile (d.."dvi2.s"), + ackfile (d.."exg.s"), + ackfile (d.."flp.s"), + ackfile (d.."inn.s"), + ackfile (d.."ior.s"), + ackfile (d.."lar2.s"), + ackfile (d.."mli2.s"), + ackfile (d.."mli4.s"), + ackfile (d.."mlu2.s"), + ackfile (d.."ngi4.s"), + ackfile (d.."nop.s"), + ackfile (d.."rol4.s"), + ackfile (d.."ror4.s"), + ackfile (d.."sar2.s"), + ackfile (d.."sbi4.s"), + ackfile (d.."set.s"), + ackfile (d.."set2.s"), + ackfile (d.."sli2.s"), + ackfile (d.."sli4.s"), + ackfile (d.."sri2.s"), + ackfile (d.."sri4.s"), + ackfile (d.."xor.s"), + ackfile (d.."loi.s"), + ackfile (d.."sti.s"), + ackfile (d.."dvi4.s"), + ackfile (d.."rck.s"), + + install = pm.install("%BINDIR%lib/%PLATFORM%/libem.a"), +} diff --git a/mach/i80/libend/em_end.s b/mach/i80/libend/em_end.s index 6848f6642..e95664edd 100644 --- a/mach/i80/libend/em_end.s +++ b/mach/i80/libend/em_end.s @@ -1,12 +1,18 @@ +! $Source$ +! $State$ +! $Revision$ + .sect .text .sect .rom .sect .data .sect .bss .sect .end ! only for declaration of _end, __end and endbss. -.define endtext,enddata,endbss,__end +.define endtext, endrom, enddata, endbss, __end .sect .text endtext: + .sect .rom +endrom: .sect .data enddata: .sect .end diff --git a/mach/i80/libend/pmfile b/mach/i80/libend/pmfile new file mode 100644 index 000000000..78e6bb5f3 --- /dev/null +++ b/mach/i80/libend/pmfile @@ -0,0 +1,16 @@ +-- $Source$ +-- $State$ +-- $Revision$ + +local d = ROOTDIR.."mach/i80/libend/" + +libend_i80 = acklibrary { + outputs = {"%U%/libend-%PLATFORM%.a"}, + + ackfile (d.."edata.s"), + ackfile (d.."em_end.s"), + ackfile (d.."end.s"), + ackfile (d.."etext.s"), + + install = pm.install("%BINDIR%lib/%PLATFORM%/libend.a"), +} diff --git a/mach/i80/pmfile b/mach/i80/pmfile index 1fdc34539..b5994f318 100644 --- a/mach/i80/pmfile +++ b/mach/i80/pmfile @@ -3,6 +3,9 @@ local d = ROOTDIR.."mach/i80/" +include (d.."libem/pmfile") +include (d.."libend/pmfile") + mach_i80 = group { ARCH = "i80", @@ -12,8 +15,10 @@ mach_i80 = group { install = pm.install("%ROOTDIR%/lib/%ARCH%/descr", "%BINDIR%%PLATIND%/%ARCH%/descr") } --- Revision history --- $Log$ --- Revision 1.1 2006-07-20 23:18:18 dtrg --- First version in CVS. --- +support_i80 = group { + OPTIMISATION = "-O", + + libem_i80, + libend_i80, +} + diff --git a/plat/cpm/.distr b/plat/cpm/.distr new file mode 100644 index 000000000..9bcdd612a --- /dev/null +++ b/plat/cpm/.distr @@ -0,0 +1,24 @@ +descr +boot.s +pmfile +README +include/ack/config.h +include/unistd.h +libsys/pmfile +libsys/_hol0.s +libsys/brk.c +libsys/close.c +libsys/creat.c +libsys/errno.s +libsys/getpid.c +libsys/isatty.c +libsys/kill.c +libsys/libsys.h +libsys/lseek.c +libsys/open.c +libsys/read.c +libsys/signal.c +libsys/time.c +libsys/write.c +libsys/_sys_rawread.s +libsys/_sys_rawwrite.s diff --git a/plat/cpm/README b/plat/cpm/README new file mode 100644 index 000000000..5b2bb9fad --- /dev/null +++ b/plat/cpm/README @@ -0,0 +1,33 @@ +# $Source$ +# $State$ +# $Revision$ + + +The cpm platform +================= + +cpm is an i80-based BSP that generates CP/M executables that can be run on any +CP/M-compliant machine. + +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). + +There's a special, if rather minimilist, interface to give applications access +to CP/M. See include/cpm.h for details. + + +Example command line +==================== + +ack -mcpm -O -o cpm.com examples/paranoia.c + +The file cpm.com can then be run. + +(Although note that Paranoia is very big, and you'll need a CP/M machine with +lots of memory for it to fit. Which it does, just.) + + +David Given +dg@cowlark.com diff --git a/plat/cpm/boot.s b/plat/cpm/boot.s new file mode 100644 index 000000000..bb55898ed --- /dev/null +++ b/plat/cpm/boot.s @@ -0,0 +1,66 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .bss +STACKSIZE = 2*1024 +.comm stack, STACKSIZE +.comm oldstack, 2 + +.sect .text +begtext: + lxi sp, oldstack + STACKSIZE + + lxi h, 0 + push h + push h + push h + call __m_a_i_n + jmp EXIT + +! Emergency exit routine. + +.define EXIT, __exit +EXIT: +__exit: + rst 0 + +! Define symbols at the beginning of our various segments, so that we can find +! them. (Except .text, which has already been done.) + +.define begtext, begdata, begbss +.sect .data; begdata: +.sect .rom; begrom: +.sect .bss; begbss: + +! Some magic data. All EM systems need these. + +.define .trppc, .ignmask, _errno +.comm .trppc, 2 +.comm .ignmask, 2 +.comm _errno, 2 + +! These are used specifically by the CP/M port. + +.define .trapproc, .retadr, .retadr1 +.define .bcreg, .areg +.define .tmp1, .fra, block1, block2, block3 + +.comm .trapproc, 2 +.comm .retadr, 2 ! used to save return address +.comm .retadr1, 2 ! reserve +.comm .bcreg, 2 +.comm .areg, 1 +.comm .tmp1, 2 +.comm .fra, 8 ! 8 bytes function return area +block1: .space 4 ! used by 32 bits divide and +block2: .space 4 ! multiply routines +block3: .space 4 ! must be contiguous (.comm doesn't guarantee this) diff --git a/plat/cpm/descr b/plat/cpm/descr new file mode 100644 index 000000000..a89c832f5 --- /dev/null +++ b/plat/cpm/descr @@ -0,0 +1,69 @@ +# $Source$ +# $State$ +# $Revision$ + +var w=2 +var p=2 +var s=2 +var l=4 +var f=4 +var d=8 +var ARCH=i80 +var PLATFORM=cpm +var PLATFORMDIR={EM}/lib/{PLATFORM} +var CPP_F=-D__unix +var ALIGN=-a0:1 -a1:1 -a2:1 -a3:1 -b0:0x0100 +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 + program {EM}/lib.bin/{PLATFORM}/ncg + args < + stdout + need .e +end +name as + from .s.so + to .o + program {EM}/lib.bin/{PLATFORM}/as + args - -o > < + prep cond +end +name led + from .o.a + to .out + program {EM}/lib.bin/em_led + mapflag -l* LNAME={PLATFORMDIR}/lib* + mapflag -i SEPID=-b1:0 + mapflag -fp FLOATS={EM}/{ILIB}fp + args {ALIGN} {SEPID?} \ + (.e:{HEAD}={PLATFORMDIR}/boot.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 > < \ + (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \ + (.b:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \ + {FLOATS?} \ + (.e:{TAIL}={PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libsys.a \ + {PLATFORMDIR}/libend.a) + linker +end +name cv + from .out + to .img + program {EM}/bin/aslod + args < > + outfile cpm.com +end diff --git a/plat/cpm/include/ack/config.h b/plat/cpm/include/ack/config.h new file mode 100644 index 000000000..ebd5c1198 --- /dev/null +++ b/plat/cpm/include/ack/config.h @@ -0,0 +1,19 @@ +/* $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 + +/* Since the i80 code generator doesn't support floating point, don't include + * it in the stdio libraries. */ + +#define ACKCONF_NO_STDIO_FLOAT + +#endif diff --git a/plat/cpm/include/cpm.h b/plat/cpm/include/cpm.h new file mode 100644 index 000000000..bdda5ed23 --- /dev/null +++ b/plat/cpm/include/cpm.h @@ -0,0 +1,66 @@ +/* + * unistd.h - standard system calls + */ +/* $Id$ */ + +#ifndef _CPM_H +#define _CPM_H + +#include + +/* These interface provides a very bare-bones interface to the CP/M BDOS. Set + * the following four variables as you wish, call cpm_bdos(), and the contents + * of the variables will have been updated accordingly. */ + +extern uint8_t cpm_a_register; +extern uint16_t cpm_bc_register; +extern uint16_t cpm_de_register; +extern uint16_t cpm_hl_register; + +extern void cpm_bdos(void); + +/* Describes the available CP/M BDOS calls. They're a fairly conservative set + * taken from the CP/M 2.0 manual. */ + +enum +{ + CPM_BDOS_SYSTEM_RESET, + CPM_BDOS_CONSOLE_INPUT, + CPM_BDOS_CONSOLE_OUTPUT, + CPM_BDOS_READER_INPUT, + CPM_BDOS_PUNCH_OUTPUT, + CPM_BDOS_LIST_OUTPUT, + CPM_BDOS_CONSOLE_IO, + CPM_BDOS_GET_IO_BYTE, + CPM_BDOS_SET_IO_BYTE, + CPM_BDOS_PRINT_STRING, + CPM_BDOS_READ_CONSOLE_BUFFER, + CPM_BDOS_GET_CONSOLE_STATUS, + CPM_BDOS_GET_VERSION_NUMBER, + CPM_BDOS_RESET_DISK_SYSTEM, + CPM_BDOS_SELECT_DISK, + CPM_BDOS_OPEN_FILE, + CPM_BDOS_CLOSE_FILE, + CPM_BDOS_SEARCHFIRST, + CPM_BDOS_SEARCHNEXT, + CPM_BDOS_DELETE_FILE, + CPM_BDOS_READ_SEQ, + CPM_BDOS_WRITE_SEQ, + CPM_BDOS_MAKE_FILE, + CPM_BDOS_RENAME_FILE, + CPM_BDOS_GET_LOGIN_VECTOR, + CPM_BDOS_GET_CURRENT_DISK, + CPM_BDOS_SET_DMA_ADDRESS, + CPM_BDOS_GET_ALLOC_VECTOR, + CPM_BDOS_WRITE_PROTECT, + CPM_BDOS_GET_RO_VECTOR, + CPM_BDOS_SET_FILE_ATTR, + CPM_BDOS_GET_DISK_PARMS, + CPM_BDOS_SETGET_USER, + CPM_BDOS_READ_RANDOM, + CPM_BDOS_WRITE_RANDOM, + CPM_BDOS_GET_FILE_SIZE, + CPM_BDOS_SET_RANDOM +}; + +#endif diff --git a/plat/cpm/include/unistd.h b/plat/cpm/include/unistd.h new file mode 100644 index 000000000..2af9db921 --- /dev/null +++ b/plat/cpm/include/unistd.h @@ -0,0 +1,71 @@ +/* + * unistd.h - standard system calls + */ +/* $Id$ */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include + +/* 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 SIGILL 11 /* Illegal instruction */ + +#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 diff --git a/plat/cpm/libsys/_bdos.s b/plat/cpm/libsys/_bdos.s new file mode 100644 index 000000000..4a05dfcdf --- /dev/null +++ b/plat/cpm/libsys/_bdos.s @@ -0,0 +1,55 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Calls a BDOS routine. + +.define _cpm_bdos +_cpm_bdos: + push b + + lda _cpm_a_register + + lhld _cpm_bc_register + mov b, h + mov c, l + + lhld _cpm_de_register + mov d, h + mov e, l + + lhld _cpm_hl_register + + call 5 + + shld _cpm_hl_register + + mov h, d + mov l, e + shld _cpm_de_register + + mov h, b + mov l, c + shld _cpm_bc_register + + sta _cpm_a_register + + pop b + ret + +.sect .bss +.define _cpm_a_register, _cpm_bc_register, _cpm_de_register, _cpm_hl_register +.comm _cpm_a_register, 1 +.comm _cpm_bc_register, 2 +.comm _cpm_de_register, 2 +.comm _cpm_hl_register, 2 diff --git a/plat/cpm/libsys/_hol0.s b/plat/cpm/libsys/_hol0.s new file mode 100644 index 000000000..f01566fe8 --- /dev/null +++ b/plat/cpm/libsys/_hol0.s @@ -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 diff --git a/plat/cpm/libsys/_inn2.s b/plat/cpm/libsys/_inn2.s new file mode 100644 index 000000000..64cc8f220 --- /dev/null +++ b/plat/cpm/libsys/_inn2.s @@ -0,0 +1,50 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +! Bit test on 16 bits set +! Expects on stack: bit number +! set to be tested +! Yields in de-registers: 0 if bit is reset or bit number out of range +! 1 if bit is set + +.sect .text +.define .inn2 +.inn2: pop h + shld .retadr + + pop d !bit number + pop h !set to be tested + mov a,e + cpi 16 + jnc 3f + cpi 8 + jnc 1f + mov e,a + mov a,l !l-reg contains the wanted bit + jmp 2f + +1: sbi 8 + mov e,a + mov a,h !h-reg contains the wanted bit + +2: dcr e + jm 4f + rar + jmp 2b + +3: xra a !return 0 if bit number out of range +4: ani 1 + mov e,a + mvi d,0 + + lhld .retadr + pchl diff --git a/plat/cpm/libsys/_trap.s b/plat/cpm/libsys/_trap.s new file mode 100644 index 000000000..543e0c6a0 --- /dev/null +++ b/plat/cpm/libsys/_trap.s @@ -0,0 +1,220 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.define .trp +.define earray, erange, eset, eiovfl, efovfl, efunfl, eidivz, eidivz +.define efdivz, eiund, efund, econv, estack, eheap, eillins, eoddz +.define ecase, ememflt, ebadptr, ebadpc, ebadlae, ebadmon, ebadlin, ebadgto +.define eunimpl + +.sect .text + +! Trap routine +! Expects trap number on stack. +! Just returns if trap has to be ignored. +! Otherwise it calls a user-defined trap handler if provided. +! When no user-defined trap handler is provided or when the user-defined +! trap handler causes a new trap, a message is printed +! and control is returned to the monitor. + + EARRAY = 0 + ERANGE = 1 + ESET = 2 + EIOVFL = 3 + EFOVFL = 4 + EFUNFL = 5 + EIDIVZ = 6 + EFDIVZ = 7 + EIUND = 8 + EFUND = 9 + ECONV = 10 + ESTACK = 16 + EHEAP = 17 + EILLINS = 18 + EODDZ = 19 + ECASE = 20 + EMEMFLT = 21 + EBADPTR = 22 + EBADPC = 23 + EBADLAE = 24 + EBADMON = 25 + EBADLIN = 26 + EBADGTO = 27 + EUNIMPL = 63 ! unimplemented em-instruction called + +earray: lxi h,EARRAY + push h + call .trp + ret + +erange: lxi h,ERANGE + push h + call .trp + ret + +eset: lxi h,ESET + push h + call .trp + ret + +eiovfl: lxi h,EIOVFL + push h + call .trp + ret + +efovfl: lxi h,EFOVFL + push h + call .trp + ret + +efunfl: lxi h,EFUNFL + push h + call .trp + ret + +eidivz: lxi h,EIDIVZ + push h + call .trp + ret + +efdivz: lxi h,EFDIVZ + push h + call .trp + ret + +eiund: lxi h,EIUND + push h + call .trp + ret + +efund: lxi h,EFUND + push h + call .trp + ret + +econv: lxi h,ECONV + push h + call .trp + ret + +estack: lxi h,ESTACK + push h + call .trp + ret + +eheap: lxi h,EHEAP + push h + call .trp + ret + +eillins:lxi h,EILLINS + push h + call .trp + ret + +eoddz: lxi h,EODDZ + push h + call .trp + ret + +ecase: lxi h,ECASE + push h + call .trp + ret + +ememflt:lxi h,EMEMFLT + push h + call .trp + ret + +ebadptr:lxi h,EBADPTR + push h + call .trp + ret + +ebadpc: lxi h,EBADPC + push h + call .trp + ret + +ebadlae:lxi h,EBADLAE + push h + call .trp + ret + +ebadmon:lxi h,EBADMON + push h + call .trp + ret + +ebadlin:lxi h,EBADLIN + push h + call .trp + ret + +ebadgto:lxi h,EBADGTO + push h + call .trp + ret + +eunimpl:lxi h,EUNIMPL + push h + call .trp + ret + +.trp: + pop h + xthl + push h ! trap number and return address exchanged + mov a,l + cpi 16 + jnc 3f ! jump if trap cannot be ignored + +! check if trap has to be ignored + xchg ! de = trap number + lhld .ignmask + push h ! hl = set to be tested + push d + call .inn2 ! de = 1 if bit is set, 0 otherwise + mov a,e + rar + jnc 3f ! jump if trap should not be ignored + pop h ! remove trap number + ret ! OGEN DICHT EN ... SPRING!!! + +3: + lhld .trapproc ! user defined trap handler? + mov a,l + ora h + jz 1f ! jump if there was not + xra a + sta .trapproc ! .trapproc := 0 + sta .trapproc+1 + lxi d,2f + push d + pchl ! call user defined trap handler +2: + pop d + ret +1: + lxi h, 1 + push h + lxi h, text + push h + lxi h, 6 + push h + call _write + jmp EXIT + +.sect .rom +text: .ascii "TRAP!\n" + diff --git a/plat/cpm/libsys/brk.c b/plat/cpm/libsys/brk.c new file mode 100644 index 000000000..e29dc565b --- /dev/null +++ b/plat/cpm/libsys/brk.c @@ -0,0 +1,43 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +#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) +{ + /* We determine the amount of free memory by looking at the address of the + * BDOS vector at 0x0006. */ + char* memtop = (char*) ((*(unsigned char*)0x0007)<<8); + char* p = newend; + + if ((p >= memtop) || + (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; +} diff --git a/plat/cpm/libsys/close.c b/plat/cpm/libsys/close.c new file mode 100644 index 000000000..1c570029b --- /dev/null +++ b/plat/cpm/libsys/close.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int close(int fd) +{ + errno = EBADF; + return -1; +} diff --git a/plat/cpm/libsys/creat.c b/plat/cpm/libsys/creat.c new file mode 100644 index 000000000..65af5c2dc --- /dev/null +++ b/plat/cpm/libsys/creat.c @@ -0,0 +1,13 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int creat(const char* path, int mode) +{ + return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode); +} diff --git a/plat/cpm/libsys/errno.s b/plat/cpm/libsys/errno.s new file mode 100644 index 000000000..9858d2640 --- /dev/null +++ b/plat/cpm/libsys/errno.s @@ -0,0 +1,28 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +#define D(e) .define e; e + +.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 +D(EHEAP) = 17 +D(EILLINS) = 18 +D(EODDZ) = 19 +D(ECASE) = 20 +D(EBADMON) = 25 + diff --git a/plat/cpm/libsys/getpid.c b/plat/cpm/libsys/getpid.c new file mode 100644 index 000000000..5e6eb003e --- /dev/null +++ b/plat/cpm/libsys/getpid.c @@ -0,0 +1,13 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +pid_t getpid(void) +{ + return 0; +} diff --git a/plat/cpm/libsys/isatty.c b/plat/cpm/libsys/isatty.c new file mode 100644 index 000000000..ad01e343f --- /dev/null +++ b/plat/cpm/libsys/isatty.c @@ -0,0 +1,13 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int isatty(int fd) +{ + return 1; +} diff --git a/plat/cpm/libsys/kill.c b/plat/cpm/libsys/kill.c new file mode 100644 index 000000000..4a179c47c --- /dev/null +++ b/plat/cpm/libsys/kill.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int kill(pid_t pid, int sig) +{ + errno = EINVAL; + return -1; +} diff --git a/plat/cpm/libsys/lseek.c b/plat/cpm/libsys/lseek.c new file mode 100644 index 000000000..ecbc4b520 --- /dev/null +++ b/plat/cpm/libsys/lseek.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +off_t lseek(int fd, off_t offset, int whence) +{ + errno = EINVAL; + return -1; +} diff --git a/plat/cpm/libsys/open.c b/plat/cpm/libsys/open.c new file mode 100644 index 000000000..f3522eae5 --- /dev/null +++ b/plat/cpm/libsys/open.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include + +int open(const char* path, int access, ...) +{ + errno = EACCES; + return -1; +} diff --git a/plat/cpm/libsys/pmfile b/plat/cpm/libsys/pmfile new file mode 100644 index 000000000..cb564e9c3 --- /dev/null +++ b/plat/cpm/libsys/pmfile @@ -0,0 +1,29 @@ +-- $Source$ +-- $State$ +-- $Revision$ + +local d = ROOTDIR.."plat/cpm/libsys/" + +libsys_cpm = acklibrary { + ACKINCLUDES = {"%BINDIR%include"}, + + ackfile (d.."errno.s"), + ackfile (d.."_hol0.s"), + ackfile (d.."_bdos.s"), + ackfile (d.."_trap.s"), + ackfile (d.."_inn2.s"), + ackfile (d.."open.c"), + ackfile (d.."creat.c"), + ackfile (d.."close.c"), + ackfile (d.."read.c"), + ackfile (d.."write.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"), +} diff --git a/plat/cpm/libsys/read.c b/plat/cpm/libsys/read.c new file mode 100644 index 000000000..8a0ba0cb1 --- /dev/null +++ b/plat/cpm/libsys/read.c @@ -0,0 +1,38 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include + +int read(int fd, void* buffer, size_t count) +{ + char i; + + /* We're only allowed to read from fd 0, 1 or 2. */ + + if ((fd < 0) || (fd > 2)) + { + errno = EBADF; + return -1; + } + + /* Empty buffer? */ + + if (count == 0) + return 0; + + /* Read one byte. */ + + cpm_bc_register = CPM_BDOS_CONSOLE_INPUT; + cpm_bdos(); + + if (cpm_a_register == '\r') + cpm_a_register = '\n'; + *(char*)buffer = cpm_a_register; + + return 1; +} diff --git a/plat/cpm/libsys/signal.c b/plat/cpm/libsys/signal.c new file mode 100644 index 000000000..8f145f6f1 --- /dev/null +++ b/plat/cpm/libsys/signal.c @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include + +sighandler_t signal(int signum, sighandler_t handler) +{ + return SIG_DFL; +} diff --git a/plat/cpm/libsys/time.c b/plat/cpm/libsys/time.c new file mode 100644 index 000000000..4215a3b6f --- /dev/null +++ b/plat/cpm/libsys/time.c @@ -0,0 +1,16 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include + +time_t time(time_t* t) +{ + if (t) + *t = 0; + return 0; +} diff --git a/plat/cpm/libsys/write.c b/plat/cpm/libsys/write.c new file mode 100644 index 000000000..0b5f2613d --- /dev/null +++ b/plat/cpm/libsys/write.c @@ -0,0 +1,51 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include + +void _sys_write_tty(char c) +{ + cpm_bc_register = CPM_BDOS_CONSOLE_OUTPUT; + cpm_de_register = c; + cpm_bdos(); + + if (c == '\n') + { + cpm_bc_register = CPM_BDOS_CONSOLE_OUTPUT; + cpm_de_register = '\r'; + cpm_bdos(); + } +} + +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 ((fd < 0) || (fd > 2)) + { + errno = EBADF; + return -1; + } + + /* Write all data. */ + + i = 0; + while (i < count) + { + _sys_write_tty(*p++); + + i++; + } + + /* No failures. */ + + return count; +} diff --git a/plat/cpm/pmfile b/plat/cpm/pmfile new file mode 100644 index 000000000..43320f1c2 --- /dev/null +++ b/plat/cpm/pmfile @@ -0,0 +1,47 @@ +-- $Source$ +-- $State$ +-- $Revision$ + +local d = ROOTDIR.."plat/cpm/" + +include (d.."libsys/pmfile") + +local bootsector = ackfile { + file (d.."boot.s"), + install = pm.install("%BINDIR%lib/cpm/boot.o"), +} + +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"), + pm.install(d.."include/cpm.h", "%BINDIR%%PLATIND%/%PLATFORM%/include/cpm.h"), + } +} + +platform_cpm = group { + ARCH = "i80", + PLATFORM = "cpm", + OPTIMISATION = "-O", + + -- Ensure the descr and headers are installed first because we'll need + -- them to build the libraries. + + descr, + headers, + + -- Build the back-end support. + + mach_i80, + support_i80, + lang_runtimes, + + -- Build the CP/M syscall library. + + libsys_cpm, + bootsector, +} diff --git a/pmfile b/pmfile index 2a476674d..c7a806f08 100644 --- a/pmfile +++ b/pmfile @@ -95,6 +95,9 @@ include "plat/pc86/pmfile" -- PC standalone include "mach/i386/pmfile" -- generic i386 include "plat/linux386/pmfile" -- Linux executables +include "mach/i80/pmfile" -- generic 8080 +include "plat/cpm/pmfile" -- CP/M + default = group { -- Lots of things use LLgen, so we need to build it first. @@ -161,8 +164,6 @@ default = group { mach_6805, mach_6809, mach_arm, lang_runtimes { ARCH="arm", OPTIMISATION="-O" }, - mach_i386, lang_runtimes { ARCH="i386", OPTIMISATION="-O" }, - mach_i80, lang_runtimes { ARCH="i80", OPTIMISATION="-O" }, mach_m68020, lang_runtimes { ARCH="m68020", OPTIMISATION="-O" }, -- mach_m68k2, lang_runtimes { ARCH="m68k2", OPTIMISATION="-O" }, @@ -178,7 +179,8 @@ default = group { -- Build the platforms. platform_pc86, - platform_linux386 + platform_linux386, + platform_cpm } -- Ensure that the work directories exist.