fuzix: Halloween Release
authorAlan Cox <alan@etchedpixels.co.uk>
Fri, 31 Oct 2014 12:13:21 +0000 (12:13 +0000)
committerAlan Cox <alan@etchedpixels.co.uk>
Fri, 31 Oct 2014 12:13:21 +0000 (12:13 +0000)
First cut of the development tree. Not terribly useful but hey its hackable
and boots.

531 files changed:
Applications/ASM/init.s [new file with mode: 0644]
Applications/util/Makefile [new file with mode: 0644]
Applications/util/basename.c [new file with mode: 0644]
Applications/util/bd.c [new file with mode: 0644]
Applications/util/cal.c [new file with mode: 0644]
Applications/util/cat.c [new file with mode: 0644]
Applications/util/chgrp.c [new file with mode: 0644]
Applications/util/chmod.c [new file with mode: 0644]
Applications/util/chown.c [new file with mode: 0644]
Applications/util/cp.c [new file with mode: 0644]
Applications/util/cut.c [new file with mode: 0644]
Applications/util/date.c [new file with mode: 0644]
Applications/util/dd.c [new file with mode: 0644]
Applications/util/df.c [new file with mode: 0644]
Applications/util/dirent.h [new file with mode: 0644]
Applications/util/dirname.c [new file with mode: 0644]
Applications/util/du.c [new file with mode: 0644]
Applications/util/dumb.c [new file with mode: 0644]
Applications/util/echo.c [new file with mode: 0644]
Applications/util/ed.c [new file with mode: 0644]
Applications/util/false.c [new file with mode: 0644]
Applications/util/fsck.c [new file with mode: 0644]
Applications/util/grep.c [new file with mode: 0644]
Applications/util/grp.h [new file with mode: 0644]
Applications/util/id.c [new file with mode: 0644]
Applications/util/init.c [new file with mode: 0644]
Applications/util/kill.c [new file with mode: 0644]
Applications/util/ll.c [new file with mode: 0644]
Applications/util/ln.c [new file with mode: 0644]
Applications/util/ls.c [new file with mode: 0644]
Applications/util/mkdir.c [new file with mode: 0644]
Applications/util/mkfs.c [new file with mode: 0644]
Applications/util/mknod.c [new file with mode: 0644]
Applications/util/more.c [new file with mode: 0644]
Applications/util/mount.c [new file with mode: 0644]
Applications/util/mv.c [new file with mode: 0644]
Applications/util/od.c [new file with mode: 0644]
Applications/util/passwd.c [new file with mode: 0644]
Applications/util/patchcpm.c [new file with mode: 0644]
Applications/util/printenv.c [new file with mode: 0644]
Applications/util/prtroot.c [new file with mode: 0644]
Applications/util/ps.c [new file with mode: 0644]
Applications/util/pwd.c [new file with mode: 0644]
Applications/util/pwd.h [new file with mode: 0644]
Applications/util/rm.c [new file with mode: 0644]
Applications/util/rmdir.c [new file with mode: 0644]
Applications/util/sleep.c [new file with mode: 0644]
Applications/util/ssh.c [new file with mode: 0644]
Applications/util/su.c [new file with mode: 0644]
Applications/util/sync.c [new file with mode: 0644]
Applications/util/termcap.c [new file with mode: 0644]
Applications/util/termcap.h [new file with mode: 0644]
Applications/util/tget.c [new file with mode: 0644]
Applications/util/touch.c [new file with mode: 0644]
Applications/util/tr.c [new file with mode: 0644]
Applications/util/true.c [new file with mode: 0644]
Applications/util/umount.c [new file with mode: 0644]
Applications/util/uniq.c [new file with mode: 0644]
Applications/util/uud.c [new file with mode: 0644]
Applications/util/uue.c [new file with mode: 0644]
Applications/util/wc.c [new file with mode: 0644]
Applications/util/which.c [new file with mode: 0644]
Applications/util/whoami.c [new file with mode: 0644]
Kernel/BUGS [new file with mode: 0644]
Kernel/COPYING [new file with mode: 0644]
Kernel/Makefile [new file with mode: 0644]
Kernel/PORTING [new file with mode: 0644]
Kernel/README [new file with mode: 0644]
Kernel/TODO [new file with mode: 0644]
Kernel/bank16k.c [new file with mode: 0644]
Kernel/bank32k.c [new file with mode: 0644]
Kernel/bankfixed.c [new file with mode: 0644]
Kernel/cpm-emulator/README.WRS [new file with mode: 0644]
Kernel/cpm-emulator/emulator.s [new file with mode: 0644]
Kernel/cpu-6502/cpu.h [new file with mode: 0644]
Kernel/cpu-6809/cpu.h [new file with mode: 0644]
Kernel/cpu-z80/cpu.h [new file with mode: 0644]
Kernel/devio.c [new file with mode: 0644]
Kernel/devsys.c [new file with mode: 0644]
Kernel/filesys.c [new file with mode: 0644]
Kernel/font4x6.c [new file with mode: 0644]
Kernel/font8x8.c [new file with mode: 0644]
Kernel/include/devsys.h [new file with mode: 0644]
Kernel/include/kdata.h [new file with mode: 0644]
Kernel/include/kernel.h [new file with mode: 0644]
Kernel/include/printf.h [new file with mode: 0644]
Kernel/include/syscall_name.h [new file with mode: 0644]
Kernel/include/timer.h [new file with mode: 0644]
Kernel/include/tty.h [new file with mode: 0644]
Kernel/include/version.h [new file with mode: 0644]
Kernel/include/vt.h [new file with mode: 0644]
Kernel/inode.c [new file with mode: 0644]
Kernel/kdata.c [new file with mode: 0644]
Kernel/kernel.def [new file with mode: 0644]
Kernel/kernel02.def [new file with mode: 0644]
Kernel/kernel09.def [new file with mode: 0644]
Kernel/lowlevel-6502.s [new file with mode: 0644]
Kernel/lowlevel-6809.s [new file with mode: 0644]
Kernel/lowlevel-z80.s [new file with mode: 0644]
Kernel/makeversion [new file with mode: 0755]
Kernel/mm.c [new file with mode: 0644]
Kernel/platform-6502test/Makefile [new file with mode: 0644]
Kernel/platform-6502test/commonmem.s [new file with mode: 0644]
Kernel/platform-6502test/config.h [new file with mode: 0644]
Kernel/platform-6502test/crt0.s [new file with mode: 0644]
Kernel/platform-6502test/device.h [new file with mode: 0644]
Kernel/platform-6502test/devices.c [new file with mode: 0644]
Kernel/platform-6502test/devlpr.c [new file with mode: 0644]
Kernel/platform-6502test/devlpr.h [new file with mode: 0644]
Kernel/platform-6502test/devrd.c [new file with mode: 0644]
Kernel/platform-6502test/devrd.h [new file with mode: 0644]
Kernel/platform-6502test/devtty.c [new file with mode: 0644]
Kernel/platform-6502test/devtty.h [new file with mode: 0644]
Kernel/platform-6502test/kernel.def [new file with mode: 0644]
Kernel/platform-6502test/ld65.cfg [new file with mode: 0644]
Kernel/platform-6502test/libc.c [new file with mode: 0644]
Kernel/platform-6502test/main.c [new file with mode: 0644]
Kernel/platform-6502test/p6502.s [new file with mode: 0644]
Kernel/platform-6502test/tricks.s [new file with mode: 0644]
Kernel/platform-6809test/Makefile [new file with mode: 0644]
Kernel/platform-6809test/commonmem.s [new file with mode: 0644]
Kernel/platform-6809test/config.h [new file with mode: 0644]
Kernel/platform-6809test/crt0.s [new file with mode: 0644]
Kernel/platform-6809test/device.h [new file with mode: 0644]
Kernel/platform-6809test/devices.c [new file with mode: 0644]
Kernel/platform-6809test/devlpr.c [new file with mode: 0644]
Kernel/platform-6809test/devlpr.h [new file with mode: 0644]
Kernel/platform-6809test/devrd.c [new file with mode: 0644]
Kernel/platform-6809test/devrd.h [new file with mode: 0644]
Kernel/platform-6809test/devtty.c [new file with mode: 0644]
Kernel/platform-6809test/devtty.h [new file with mode: 0644]
Kernel/platform-6809test/kernel.def [new file with mode: 0644]
Kernel/platform-6809test/libc.c [new file with mode: 0644]
Kernel/platform-6809test/main.c [new file with mode: 0644]
Kernel/platform-6809test/p6809.s [new file with mode: 0644]
Kernel/platform-6809test/tricks.s [new file with mode: 0644]
Kernel/platform-micropack/Makefile [new file with mode: 0644]
Kernel/platform-micropack/README [new file with mode: 0644]
Kernel/platform-micropack/bootblock.s [new file with mode: 0644]
Kernel/platform-micropack/commonmem.s [new file with mode: 0644]
Kernel/platform-micropack/config.h [new file with mode: 0644]
Kernel/platform-micropack/crt0.s [new file with mode: 0644]
Kernel/platform-micropack/devfd.c [new file with mode: 0644]
Kernel/platform-micropack/devfd.h [new file with mode: 0644]
Kernel/platform-micropack/devices.c [new file with mode: 0644]
Kernel/platform-micropack/devlpr.c [new file with mode: 0644]
Kernel/platform-micropack/devlpr.h [new file with mode: 0644]
Kernel/platform-micropack/devtty.c [new file with mode: 0644]
Kernel/platform-micropack/devtty.h [new file with mode: 0644]
Kernel/platform-micropack/kernel.def [new file with mode: 0644]
Kernel/platform-micropack/main.c [new file with mode: 0644]
Kernel/platform-micropack/tricks.s [new file with mode: 0644]
Kernel/platform-micropack/uzi.lnk [new file with mode: 0644]
Kernel/platform-micropack/z80pack.s [new file with mode: 0644]
Kernel/platform-nc100/Makefile [new file with mode: 0644]
Kernel/platform-nc100/README [new file with mode: 0644]
Kernel/platform-nc100/bootblock.s [new file with mode: 0644]
Kernel/platform-nc100/commonmem.s [new file with mode: 0644]
Kernel/platform-nc100/config.h [new file with mode: 0644]
Kernel/platform-nc100/crt0.s [new file with mode: 0644]
Kernel/platform-nc100/device.h [new file with mode: 0644]
Kernel/platform-nc100/devices.c [new file with mode: 0644]
Kernel/platform-nc100/devlpr.c [new file with mode: 0644]
Kernel/platform-nc100/devlpr.h [new file with mode: 0644]
Kernel/platform-nc100/devrd.c [new file with mode: 0644]
Kernel/platform-nc100/devrd.h [new file with mode: 0644]
Kernel/platform-nc100/devtty.c [new file with mode: 0644]
Kernel/platform-nc100/devtty.h [new file with mode: 0644]
Kernel/platform-nc100/kernel.def [new file with mode: 0644]
Kernel/platform-nc100/main.c [new file with mode: 0644]
Kernel/platform-nc100/nc100.s [new file with mode: 0644]
Kernel/platform-nc100/nc100emu.s [new file with mode: 0644]
Kernel/platform-nc100/tricks.s [new file with mode: 0644]
Kernel/platform-nc100/uzi.lnk [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/765.s [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/765.s.old [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/765.s~ [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/bootcsum [new file with mode: 0755]
Kernel/platform-pcw8256/BOOTBLOCK/bootcsum.c [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/sector2.s [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/sector2.s~ [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.ams [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.bds [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cas [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cim [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cmd [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.hex [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/765.lcas [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.ams [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.bds [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cas [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cim [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cmd [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.hex [new file with mode: 0644]
Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.lcas [new file with mode: 0644]
Kernel/platform-pcw8256/Makefile [new file with mode: 0644]
Kernel/platform-pcw8256/README [new file with mode: 0644]
Kernel/platform-pcw8256/commonmem.s [new file with mode: 0644]
Kernel/platform-pcw8256/config.h [new file with mode: 0644]
Kernel/platform-pcw8256/crt0.s [new file with mode: 0644]
Kernel/platform-pcw8256/devfd.c [new file with mode: 0644]
Kernel/platform-pcw8256/devfd.h [new file with mode: 0644]
Kernel/platform-pcw8256/devices.c [new file with mode: 0644]
Kernel/platform-pcw8256/devlpr.c [new file with mode: 0644]
Kernel/platform-pcw8256/devlpr.h [new file with mode: 0644]
Kernel/platform-pcw8256/devtty.c [new file with mode: 0644]
Kernel/platform-pcw8256/devtty.h [new file with mode: 0644]
Kernel/platform-pcw8256/fdc765.s [new file with mode: 0644]
Kernel/platform-pcw8256/kernel.def [new file with mode: 0644]
Kernel/platform-pcw8256/main.c [new file with mode: 0644]
Kernel/platform-pcw8256/pcw8256.h [new file with mode: 0644]
Kernel/platform-pcw8256/pcw8256.s [new file with mode: 0644]
Kernel/platform-pcw8256/tricks.s [new file with mode: 0644]
Kernel/platform-trs80/Makefile [new file with mode: 0644]
Kernel/platform-trs80/README [new file with mode: 0644]
Kernel/platform-trs80/commonmem.s [new file with mode: 0644]
Kernel/platform-trs80/config.h [new file with mode: 0644]
Kernel/platform-trs80/crt0.s [new file with mode: 0644]
Kernel/platform-trs80/devfd.c [new file with mode: 0644]
Kernel/platform-trs80/devfd.h [new file with mode: 0644]
Kernel/platform-trs80/devices.c [new file with mode: 0644]
Kernel/platform-trs80/devlpr.c [new file with mode: 0644]
Kernel/platform-trs80/devlpr.h [new file with mode: 0644]
Kernel/platform-trs80/devtty.c [new file with mode: 0644]
Kernel/platform-trs80/devtty.h [new file with mode: 0644]
Kernel/platform-trs80/kernel.def [new file with mode: 0644]
Kernel/platform-trs80/main.c [new file with mode: 0644]
Kernel/platform-trs80/tricks.s [new file with mode: 0644]
Kernel/platform-trs80/trs80.s [new file with mode: 0644]
Kernel/platform-trs80/trsfd.s [new file with mode: 0644]
Kernel/platform-trs80/uzi.lnk [new file with mode: 0644]
Kernel/platform-z80pack-lite/Makefile [new file with mode: 0644]
Kernel/platform-z80pack-lite/README [new file with mode: 0644]
Kernel/platform-z80pack-lite/bootblock.s [new file with mode: 0644]
Kernel/platform-z80pack-lite/commonmem.s [new file with mode: 0644]
Kernel/platform-z80pack-lite/config.h [new file with mode: 0644]
Kernel/platform-z80pack-lite/crt0.s [new file with mode: 0644]
Kernel/platform-z80pack-lite/devfd.c [new file with mode: 0644]
Kernel/platform-z80pack-lite/devfd.h [new file with mode: 0644]
Kernel/platform-z80pack-lite/devices.c [new file with mode: 0644]
Kernel/platform-z80pack-lite/devlpr.c [new file with mode: 0644]
Kernel/platform-z80pack-lite/devlpr.h [new file with mode: 0644]
Kernel/platform-z80pack-lite/devtty.c [new file with mode: 0644]
Kernel/platform-z80pack-lite/devtty.h [new file with mode: 0644]
Kernel/platform-z80pack-lite/kernel.def [new file with mode: 0644]
Kernel/platform-z80pack-lite/main.c [new file with mode: 0644]
Kernel/platform-z80pack-lite/tricks.s [new file with mode: 0644]
Kernel/platform-z80pack-lite/usermem.s [new file with mode: 0644]
Kernel/platform-z80pack-lite/uzi.lnk [new file with mode: 0644]
Kernel/platform-z80pack-lite/z80pack.s [new file with mode: 0644]
Kernel/platform-z80pack/Makefile [new file with mode: 0644]
Kernel/platform-z80pack/README [new file with mode: 0644]
Kernel/platform-z80pack/bootblock.s [new file with mode: 0644]
Kernel/platform-z80pack/commonmem.s [new file with mode: 0644]
Kernel/platform-z80pack/config.h [new file with mode: 0644]
Kernel/platform-z80pack/crt0.s [new file with mode: 0644]
Kernel/platform-z80pack/devfd.c [new file with mode: 0644]
Kernel/platform-z80pack/devfd.h [new file with mode: 0644]
Kernel/platform-z80pack/devices.c [new file with mode: 0644]
Kernel/platform-z80pack/devlpr.c [new file with mode: 0644]
Kernel/platform-z80pack/devlpr.h [new file with mode: 0644]
Kernel/platform-z80pack/devtty.c [new file with mode: 0644]
Kernel/platform-z80pack/devtty.h [new file with mode: 0644]
Kernel/platform-z80pack/kernel.def [new file with mode: 0644]
Kernel/platform-z80pack/main.c [new file with mode: 0644]
Kernel/platform-z80pack/tricks.s [new file with mode: 0644]
Kernel/platform-z80pack/uzi.lnk [new file with mode: 0644]
Kernel/platform-z80pack/z80pack.s [new file with mode: 0644]
Kernel/process.c [new file with mode: 0644]
Kernel/select.c [new file with mode: 0644]
Kernel/simple.c [new file with mode: 0644]
Kernel/single.c [new file with mode: 0644]
Kernel/start.c [new file with mode: 0644]
Kernel/swap.c [new file with mode: 0644]
Kernel/syscall_fs.c [new file with mode: 0644]
Kernel/syscall_fs2.c [new file with mode: 0644]
Kernel/syscall_other.c [new file with mode: 0644]
Kernel/syscall_proc.c [new file with mode: 0644]
Kernel/timer.c [new file with mode: 0644]
Kernel/tools/analysemap.c [new file with mode: 0644]
Kernel/tools/binman.c [new file with mode: 0644]
Kernel/tools/filesizes.c [new file with mode: 0644]
Kernel/tools/make4x6.c [new file with mode: 0644]
Kernel/tty.c [new file with mode: 0644]
Kernel/unbanked.c [new file with mode: 0644]
Kernel/usermem.c [new file with mode: 0644]
Kernel/usermem_std-6502.s [new file with mode: 0644]
Kernel/usermem_std-6809.s [new file with mode: 0644]
Kernel/usermem_std-z80.s [new file with mode: 0644]
Kernel/vt.c [new file with mode: 0644]
LICENSE
Library/Makefile [new file with mode: 0644]
Library/include/alloc.h [new file with mode: 0644]
Library/include/ar.h [new file with mode: 0644]
Library/include/assert.h [new file with mode: 0644]
Library/include/ctype.h [new file with mode: 0644]
Library/include/curses.h [new file with mode: 0644]
Library/include/dirent.h [new file with mode: 0644]
Library/include/errno.h [new file with mode: 0644]
Library/include/fcntl.h [new file with mode: 0644]
Library/include/features.h [new file with mode: 0644]
Library/include/float.h [new file with mode: 0644]
Library/include/ftw.h [new file with mode: 0644]
Library/include/fuzix.h [new file with mode: 0644]
Library/include/getopt.h [new file with mode: 0644]
Library/include/grp.h [new file with mode: 0644]
Library/include/limits.h [new file with mode: 0644]
Library/include/malloc.h [new file with mode: 0644]
Library/include/math.h [new file with mode: 0644]
Library/include/memory.h [new file with mode: 0644]
Library/include/ncurses.h [new file with mode: 0644]
Library/include/paths.h [new file with mode: 0644]
Library/include/poll.h [new file with mode: 0644]
Library/include/pwd.h [new file with mode: 0644]
Library/include/regexp.h [new file with mode: 0644]
Library/include/regmagic.h [new file with mode: 0644]
Library/include/search.h [new file with mode: 0644]
Library/include/setjmp.h [new file with mode: 0644]
Library/include/sgtty.h [new file with mode: 0644]
Library/include/signal.h [new file with mode: 0644]
Library/include/stdio.h [new file with mode: 0644]
Library/include/stdlib.h [new file with mode: 0644]
Library/include/string.h [new file with mode: 0644]
Library/include/strings.h [new file with mode: 0644]
Library/include/sys/cdefs.h [new file with mode: 0755]
Library/include/sys/errno.h [new file with mode: 0644]
Library/include/sys/exec.h [new file with mode: 0755]
Library/include/sys/file.h [new file with mode: 0644]
Library/include/sys/fp.h [new file with mode: 0644]
Library/include/sys/ioctl.h [new file with mode: 0755]
Library/include/sys/lock.h [new file with mode: 0644]
Library/include/sys/mman.h [new file with mode: 0644]
Library/include/sys/mount.h [new file with mode: 0644]
Library/include/sys/param.h [new file with mode: 0644]
Library/include/sys/resource.h [new file with mode: 0644]
Library/include/sys/seek.h [new file with mode: 0755]
Library/include/sys/signal.h [new file with mode: 0644]
Library/include/sys/stat.h [new file with mode: 0755]
Library/include/sys/statfs.h [new file with mode: 0644]
Library/include/sys/time.h [new file with mode: 0644]
Library/include/sys/times.h [new file with mode: 0644]
Library/include/sys/types.h [new file with mode: 0644]
Library/include/sys/utsname.h [new file with mode: 0755]
Library/include/sys/wait.h [new file with mode: 0755]
Library/include/syscalls.h [new file with mode: 0644]
Library/include/termcap.h [new file with mode: 0644]
Library/include/termio.h [new file with mode: 0644]
Library/include/termios.h [new file with mode: 0644]
Library/include/time.h [new file with mode: 0644]
Library/include/types.h [new file with mode: 0644]
Library/include/unistd.h [new file with mode: 0644]
Library/include/utime.h [new file with mode: 0644]
Library/include/utmp.h [new file with mode: 0644]
Library/include/utsname.h [new file with mode: 0644]
Library/include/varargs.h [new file with mode: 0644]
Library/include/wait.h [new file with mode: 0644]
Library/libs/Makefile [new file with mode: 0644]
Library/libs/README.regexp [new file with mode: 0644]
Library/libs/TODO [new file with mode: 0644]
Library/libs/__getgrent.c [new file with mode: 0644]
Library/libs/__getpwent.c [new file with mode: 0644]
Library/libs/abort.c [new file with mode: 0644]
Library/libs/abs.c [new file with mode: 0644]
Library/libs/asctime.c [new file with mode: 0644]
Library/libs/assert.c [new file with mode: 0644]
Library/libs/atexit.c [new file with mode: 0644]
Library/libs/atof.c [new file with mode: 0644]
Library/libs/atoi.c [new file with mode: 0644]
Library/libs/atol.c [new file with mode: 0644]
Library/libs/bcmp.c [new file with mode: 0644]
Library/libs/bcopy.c [new file with mode: 0644]
Library/libs/bsearch.c [new file with mode: 0644]
Library/libs/bzero.c [new file with mode: 0644]
Library/libs/calloc.c [new file with mode: 0644]
Library/libs/cfmakeraw.c [new file with mode: 0644]
Library/libs/cfree.c [new file with mode: 0644]
Library/libs/cfspeed.c [new file with mode: 0644]
Library/libs/clock.c [new file with mode: 0644]
Library/libs/closedir.c [new file with mode: 0644]
Library/libs/config-getent.h [new file with mode: 0644]
Library/libs/config-grp.h [new file with mode: 0644]
Library/libs/confstr.c [new file with mode: 0644]
Library/libs/creat.c [new file with mode: 0644]
Library/libs/crt0.s [new file with mode: 0644]
Library/libs/crypt.c [new file with mode: 0644]
Library/libs/ctime.c [new file with mode: 0644]
Library/libs/ctype.c [new file with mode: 0644]
Library/libs/difftime.c [new file with mode: 0644]
Library/libs/errno.c [new file with mode: 0644]
Library/libs/error.c [new file with mode: 0644]
Library/libs/execl.c [new file with mode: 0644]
Library/libs/execv.c [new file with mode: 0644]
Library/libs/execvp.c [new file with mode: 0644]
Library/libs/exit.c [new file with mode: 0644]
Library/libs/fclose.c [new file with mode: 0644]
Library/libs/fflush.c [new file with mode: 0644]
Library/libs/fgetc.c [new file with mode: 0644]
Library/libs/fgetgrent.c [new file with mode: 0644]
Library/libs/fgetpos.c [new file with mode: 0644]
Library/libs/fgetpwent.c [new file with mode: 0644]
Library/libs/fgets.c [new file with mode: 0644]
Library/libs/fopen.c [new file with mode: 0644]
Library/libs/fprintf.c [new file with mode: 0644]
Library/libs/fputc.c [new file with mode: 0644]
Library/libs/fputs.c [new file with mode: 0644]
Library/libs/fread.c [new file with mode: 0644]
Library/libs/free.c [new file with mode: 0644]
Library/libs/fscanf.c [new file with mode: 0644]
Library/libs/fsetpos.c [new file with mode: 0644]
Library/libs/ftell.c [new file with mode: 0644]
Library/libs/fuzix/Makefile [new file with mode: 0644]
Library/libs/fuzix/syscall.s [new file with mode: 0644]
Library/libs/fwrite.c [new file with mode: 0644]
Library/libs/getcwd.c [new file with mode: 0644]
Library/libs/getenv.c [new file with mode: 0644]
Library/libs/getgrgid.c [new file with mode: 0644]
Library/libs/getgrnam.c [new file with mode: 0644]
Library/libs/gethostname.c [new file with mode: 0644]
Library/libs/getopt.c [new file with mode: 0644]
Library/libs/getpass.c [new file with mode: 0644]
Library/libs/getpw.c [new file with mode: 0644]
Library/libs/getpwnam.c [new file with mode: 0644]
Library/libs/getpwuid.c [new file with mode: 0644]
Library/libs/gets.c [new file with mode: 0644]
Library/libs/gmtime.c [new file with mode: 0644]
Library/libs/grent.c [new file with mode: 0644]
Library/libs/index.c [new file with mode: 0644]
Library/libs/initgroups.c [new file with mode: 0644]
Library/libs/isatty.c [new file with mode: 0644]
Library/libs/itoa.c [new file with mode: 0644]
Library/libs/killpg.c [new file with mode: 0644]
Library/libs/labs.c [new file with mode: 0644]
Library/libs/localtim.c [new file with mode: 0644]
Library/libs/lsearch.c [new file with mode: 0644]
Library/libs/lseek.c [new file with mode: 0644]
Library/libs/lstat.c [new file with mode: 0644]
Library/libs/ltoa.c [new file with mode: 0644]
Library/libs/ltostr.c [new file with mode: 0644]
Library/libs/malloc-l.h [new file with mode: 0644]
Library/libs/malloc.c [new file with mode: 0644]
Library/libs/memccpy.c [new file with mode: 0644]
Library/libs/memchr.c [new file with mode: 0644]
Library/libs/memcmp.c [new file with mode: 0644]
Library/libs/memcpy.c [new file with mode: 0644]
Library/libs/memset.c [new file with mode: 0644]
Library/libs/mkfifo.c [new file with mode: 0644]
Library/libs/opendir.c [new file with mode: 0644]
Library/libs/pause.c [new file with mode: 0644]
Library/libs/perror.c [new file with mode: 0644]
Library/libs/popen.c [new file with mode: 0644]
Library/libs/printf.c [new file with mode: 0644]
Library/libs/printf.h [new file with mode: 0644]
Library/libs/putenv.c [new file with mode: 0644]
Library/libs/putgetch.c [new file with mode: 0644]
Library/libs/putpwent.c [new file with mode: 0644]
Library/libs/pwent.c [new file with mode: 0644]
Library/libs/qsort.c [new file with mode: 0644]
Library/libs/raise.c [new file with mode: 0644]
Library/libs/rand.c [new file with mode: 0644]
Library/libs/readdir.c [new file with mode: 0644]
Library/libs/readlink.c [new file with mode: 0644]
Library/libs/realloc.c [new file with mode: 0644]
Library/libs/regerror.c [new file with mode: 0644]
Library/libs/regexp.c [new file with mode: 0644]
Library/libs/regexp.h [new file with mode: 0644]
Library/libs/regmagic.h [new file with mode: 0644]
Library/libs/regsub.c [new file with mode: 0644]
Library/libs/remove.c [new file with mode: 0644]
Library/libs/revoke.c [new file with mode: 0644]
Library/libs/rewind.c [new file with mode: 0644]
Library/libs/rindex.c [new file with mode: 0644]
Library/libs/scanf.c [new file with mode: 0644]
Library/libs/setbuffer.c [new file with mode: 0644]
Library/libs/setenv.c [new file with mode: 0644]
Library/libs/setjmp.c [new file with mode: 0644]
Library/libs/setvbuf.c [new file with mode: 0644]
Library/libs/sleep.c [new file with mode: 0644]
Library/libs/sprintf.c [new file with mode: 0644]
Library/libs/sscanf.c [new file with mode: 0644]
Library/libs/stat.c [new file with mode: 0644]
Library/libs/stdio-l.h [new file with mode: 0644]
Library/libs/stdio0.c [new file with mode: 0644]
Library/libs/strcasecmp.c [new file with mode: 0644]
Library/libs/strcat.c [new file with mode: 0644]
Library/libs/strchr.c [new file with mode: 0644]
Library/libs/strcmp.c [new file with mode: 0644]
Library/libs/strcpy.c [new file with mode: 0644]
Library/libs/strcspn.c [new file with mode: 0644]
Library/libs/strdup.c [new file with mode: 0644]
Library/libs/stricmp.c [new file with mode: 0644]
Library/libs/strlen.c [new file with mode: 0644]
Library/libs/strncasecmp.c [new file with mode: 0644]
Library/libs/strncat.c [new file with mode: 0644]
Library/libs/strncpy.c [new file with mode: 0644]
Library/libs/strnicmp.c [new file with mode: 0644]
Library/libs/strpbrk.c [new file with mode: 0644]
Library/libs/strrchr.c [new file with mode: 0644]
Library/libs/strsep.c [new file with mode: 0644]
Library/libs/strspn.c [new file with mode: 0644]
Library/libs/strstr.c [new file with mode: 0644]
Library/libs/strtod.c [new file with mode: 0644]
Library/libs/strtok.c [new file with mode: 0644]
Library/libs/strtol.c [new file with mode: 0644]
Library/libs/sysconf.c [new file with mode: 0644]
Library/libs/system.c [new file with mode: 0644]
Library/libs/tcdrain.c [new file with mode: 0644]
Library/libs/tcflow.c [new file with mode: 0644]
Library/libs/tcflush.c [new file with mode: 0644]
Library/libs/tcgetattr.c [new file with mode: 0644]
Library/libs/tcsetattr.c [new file with mode: 0644]
Library/libs/time.c [new file with mode: 0644]
Library/libs/tmpnam.c [new file with mode: 0644]
Library/libs/ttyname.c [new file with mode: 0644]
Library/libs/tzset.c [new file with mode: 0644]
Library/libs/ultoa.c [new file with mode: 0644]
Library/libs/ungetc.c [new file with mode: 0644]
Library/libs/utent.c [new file with mode: 0644]
Library/libs/utsname.c [new file with mode: 0644]
Library/libs/vfprintf.c [new file with mode: 0644]
Library/libs/vfscanf.c [new file with mode: 0644]
Library/libs/vprintf.c [new file with mode: 0644]
Library/libs/vscanf.c [new file with mode: 0644]
Library/libs/vsscanf.c [new file with mode: 0644]
Library/libs/wait.c [new file with mode: 0644]
Library/libs/xitoa.c [new file with mode: 0644]
Library/tools/TODO [new file with mode: 0644]
Library/tools/binman.c [new file with mode: 0644]
Library/tools/fcc.c [new file with mode: 0644]
Library/tools/fsize.c [new file with mode: 0644]
Library/tools/libclean [new file with mode: 0755]
Library/tools/syscall.c [new file with mode: 0644]

diff --git a/Applications/ASM/init.s b/Applications/ASM/init.s
new file mode 100644 (file)
index 0000000..1fbd02a
--- /dev/null
@@ -0,0 +1,38 @@
+;
+;      A simple testing setup for FUZIX
+;
+               .org 0x100
+start:         jp      start2
+               .db     'F'
+               .db     'Z'
+               .db     'X'
+               .db     '1'
+               .dw     0
+start2:
+               ld a, '*'
+               out (1), a
+               ld hl, 2
+               push hl
+               ld hl, devtty
+               push hl
+               ld hl, 1
+               push hl
+               rst 0x30
+               ld hl, 13
+               push hl
+               ld hl, banner
+               push hl
+               ld hl, 0
+               push hl
+               ld hl, 8
+               push hl
+               rst 0x30
+               ld hl, 0
+               push hl
+               ld hl, 37
+               push hl
+               rst 0x30
+banner:
+               .db 'Hello World'
+               .db 13,10
+devtty:                .db '/dev/tty1',0
\ No newline at end of file
diff --git a/Applications/util/Makefile b/Applications/util/Makefile
new file mode 100644 (file)
index 0000000..ba0126f
--- /dev/null
@@ -0,0 +1,92 @@
+CC = sdcc
+ASM = sdasz80
+AR = sdar
+LINKER = sdcc
+#CC_OPT = -mz80 -c --opt-code-size --std-c89 --max-allocs-per-node 2000000 -I../../Library/include
+CC_OPT = -mz80 --std-c99 -c --opt-code-size --max-allocs-per-node 20000 -I../../Library/include
+#--oldralloc
+ASM_OPT = -l -o -s
+LINKER_OPT = --code-loc 0 -mz80 --nostdlib --no-std-crt0
+
+.SUFFIXES: .c .rel
+
+
+SRCS  = basename.c \
+       bd.c \
+       cal.c \
+       cat.c \
+       chgrp.c \
+       chmod.c \
+       chown.c \
+       cp.c \
+       cut.c \
+       date.c \
+       dd.c \
+       df.c \
+       dirname.c \
+       du.c \
+       echo.c \
+       ed.c \
+       false.c \
+       fsck.c \
+       grep.c \
+       id.c \
+       init.c \
+       kill.c \
+       ll.c \
+       ln.c \
+       ls.c \
+       mkdir.c \
+       mkfs.c \
+       mknod.c \
+       more.c \
+       mount.c \
+       mv.c \
+       od.c \
+       passwd.c \
+       patchcpm.c \
+       printenv.c \
+       prtroot.c \
+       ps.c \
+       pwd.c \
+       rm.c \
+       rmdir.c \
+       sleep.c \
+       ssh.c \
+       su.c \
+       sync.c \
+       termcap.c \
+       tget.c \
+       touch.c \
+       tr.c \
+       true.c \
+       umount.c \
+       uniq.c \
+       uud.c \
+       uue.c \
+       wc.c \
+       which.c \
+       whoami.c
+
+OBJS = $(SRCS:.c=.rel)
+
+LIBS = ../../Library/libs/syslib.lib
+
+APPS = $(OBJS:.rel=)
+
+all: $(APPS)
+
+$(OBJS): $(SRCS)
+
+.c.rel:
+       $(CC) $(CC_OPT) $(@:.rel=.c)
+
+%: %.rel
+       $(LINKER) $(LINKER_OPT) ../../Library/libs/crt0.rel $< $(LIBS)
+
+clean:
+       rm -f $(OBJS) $(APPS) core *~ *.asm *.lst *.sym *.map *.noi *.lk
+
+rmbak:
+       rm -f *~ core
+
diff --git a/Applications/util/basename.c b/Applications/util/basename.c
new file mode 100644 (file)
index 0000000..7e64872
--- /dev/null
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define STDIN_FILENO   0
+#define STDOUT_FILENO  1
+#define STDERR_FILENO  2
+
+static void remove_suffix(char *name, char *suffix)
+{
+    char *np, *sp;
+
+    np = name + strlen(name);
+    sp = suffix + strlen(suffix);
+
+    while (np > name && sp > suffix)
+       if (*--np != *--sp)
+           return;
+
+    if (np > name)
+       *np = '\0';
+}
+
+
+char *basename(char *name)
+{
+    char *base;
+
+    base = rindex(name, '/');
+    return base ? base + 1 : name;
+}
+
+
+void strip_trailing_slashes(char *path)
+{
+    int last;
+
+    last = strlen(path) - 1;
+    while (last > 0 && path[last] == '/')
+       path[last--] = '\0';
+}
+
+
+int main(int argc, char *argv[])
+{
+    char *line;
+
+    if (argc == 2 || argc == 3) {
+       strip_trailing_slashes(argv[1]);
+       line = basename(argv[1]);
+       if (argc == 3)
+           remove_suffix(line, argv[2]);
+       write(STDOUT_FILENO, line, strlen(line));
+       write(STDOUT_FILENO, "\n", 1);
+    }
+    
+    return 0;
+}
diff --git a/Applications/util/bd.c b/Applications/util/bd.c
new file mode 100644 (file)
index 0000000..cf62389
--- /dev/null
@@ -0,0 +1,67 @@
+/**************************************************
+UZI (Unix Z80 Implementation) Utilities:  bd.c
+***************************************************/
+/*
+ *  Block Dump - to examine floppy and hard disks.
+ *
+ *  Usage:  bd dev blkno
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+char buf[512];
+
+int main(int argc, char *argv[])
+{
+    int  i, j, d;
+    unsigned blkno;
+    char ch;
+
+    if (argc != 3 || !isdigit(argv[2][0])) {
+       fprintf(stderr, "usage: bd device blkno\n");
+       exit(1);
+    }
+
+    blkno = atoi(argv[2]);
+    d = open(argv[1], O_RDONLY);
+    if (d < 0) {
+        printf("bd: can't open %s\n", argv[1]);
+        exit(1);
+    }
+
+    lseek(d, blkno * 512L, 0);
+    i = read(d, buf, 512);
+    close(d);
+    
+    if (i != 512) {
+        printf("bd: error reading block %d\n", blkno);
+        exit(1);
+    }
+
+    for (i = 0; i < 512 / 16; ++i) {
+       printf("%04x  ", 16 * i);
+       for (j = 0; j < 16; ++j) {
+           printf("%02x ", buf[16 * i + j] & 0xff);
+       }
+       printf("    ");
+       for (j = 0; j < 16; ++j) {
+           ch = (buf[16 * i + j] & 0x00ff);
+           if ((ch >= ' ') && (ch < 0x7f))
+               putchar(ch);
+           else
+               printf(".");
+       }
+       printf("\n");
+       if (((i + 1) % 16 == 0) && (i < 31)) {
+           printf("[return for more]");
+           getchar();
+           printf("\n");
+       }
+    }
+    exit(0);
+}
diff --git a/Applications/util/cal.c b/Applications/util/cal.c
new file mode 100644 (file)
index 0000000..b8ca093
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kim Letkeman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+       The Regents of the University of California.  All rights reserved.\n";
+static char sccsid[] = "@(#)cal.c      8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int time_zone = 0;
+long timezone = 0;
+
+int errx(int exv, char *str)
+{
+    fprintf(stderr, "cal: %s\n", str);
+    exit(exv);
+}
+
+#define        THURSDAY                4       /* for reformation */
+#define        SATURDAY                6       /* 1 Jan 1 was a Saturday */
+
+#define        FIRST_MISSING_DAY       639787  /* 3 Sep 1752 */
+#define        NUMBER_MISSING_DAYS     11      /* 11 day correction */
+
+#define        MAXDAYS                 42      /* max slots in a month array */
+#define        SPACE                   -1      /* used in day array */
+
+static int days_in_month[2][13] =
+{
+    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+};
+
+int sep1752[MAXDAYS] =
+{
+    SPACE, SPACE, 1,     2,     14,    15,    16,
+    17,    18,    19,    20,    21,    22,    23,
+    24,    25,    26,    27,    28,    29,    30,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+}, j_sep1752[MAXDAYS] =
+{
+    SPACE, SPACE, 245,   246,   258,   259,   260,
+    261,   262,   263,   264,   265,   266,   267,
+    268,   269,   270,   271,   272,   273,   274,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+}, empty[MAXDAYS] =
+{
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+    SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+};
+
+char day_headings[] = "Su Mo Tu We Th Fr Sa ";
+char j_day_headings[] = "Sun Mon Tue Wed Thu Fri Sat ";
+char *full_month[12] = {
+    "January",   "February", "March",    "April",
+    "May",       "June",     "July",     "August",
+    "September", "October",  "November", "December"
+};
+
+/* leap year -- account for gregorian reformation in 1752 */
+#define        leap_year(yr) \
+       ((yr) <= 1752 ? !((yr) % 4) : \
+       (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400))
+
+/* number of centuries since 1700, not inclusive */
+#define        centuries_since_1700(yr) \
+       ((yr) > 1700 ? (yr) / 100 - 17 : 0)
+
+/* number of centuries since 1700 whose modulo of 400 is 0 */
+#define        quad_centuries_since_1700(yr) \
+       ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
+
+/* number of leap years between year 1 and this year, not inclusive */
+#define        leap_years_since_year_1(yr) \
+       ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
+
+int julian;
+
+void ascii_day(char *, int);
+void center(char *, int, int);
+void day_array(int, int, int *);
+int  day_in_week(int, int, int);
+int  day_in_year(int, int, int);
+void j_yearly(int);
+void monthly(int, int);
+void trim_trailing_spaces(char *);
+void usage(void);
+void yearly(int);
+
+int main(int argc, char *argv[])
+{
+    struct tm *local_time;
+    time_t now;
+    int  ch, month, year, yflag;
+
+    julian = yflag = 0;
+
+#if 1
+    while ((ch = getopt(argc, argv, "jy")) != EOF)
+       switch (ch) {
+       case 'j':
+           julian = 1;
+           break;
+       case 'y':
+           yflag = 1;
+           break;
+       case '?':
+       default:
+           usage();
+       }
+    argc -= optind;
+    argv += optind;
+#else
+    argc--;
+    argv++;
+#endif
+
+    month = 0;
+    switch (argc) {
+    case 2:
+       if ((month = atoi(*argv++)) < 1 || month > 12)
+           errx(1, "illegal month value: use 1-12");
+       /* FALLTHROUGH */
+    case 1:
+       if ((year = atoi(*argv)) < 1 || year > 9999)
+           errx(1, "illegal year value: use 1-9999");
+       break;
+
+    case 0:
+       now = time(NULL);
+       local_time = localtime(&now);
+       year = local_time->tm_year + 1900;
+       if (!yflag)
+           month = local_time->tm_mon + 1;
+       break;
+
+    default:
+       usage();
+    }
+
+    if (month)
+       monthly(month, year);
+    else if (julian)
+       j_yearly(year);
+    else
+       yearly(year);
+    exit(0);
+}
+
+#define        DAY_LEN         3       /* 3 spaces per day */
+#define        J_DAY_LEN       4       /* 4 spaces per day */
+#define        WEEK_LEN        21      /* 7 days * 3 characters */
+#define        J_WEEK_LEN      28      /* 7 days * 4 characters */
+#define        HEAD_SEP        2       /* spaces between day headings */
+#define        J_HEAD_SEP      2
+
+void monthly(int month, int year)
+{
+    int col, row, len, days[MAXDAYS];
+    char *p, lineout[30];
+
+    day_array(month, year, days);
+    len = sprintf(lineout, "%s %d", full_month[month - 1], year);
+    printf("%*s%s\n%s\n",
+          ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
+          lineout, julian ? j_day_headings : day_headings);
+    for (row = 0; row < 6; row++) {
+       for (col = 0, p = lineout; col < 7; col++,
+            p += julian ? J_DAY_LEN : DAY_LEN)
+           ascii_day(p, days[row * 7 + col]);
+       *p = '\0';
+       trim_trailing_spaces(lineout);
+       printf("%s\n", lineout);
+    }
+}
+
+void j_yearly(int year)
+{
+    char *p;
+    int col, *dp, i, month, row, which_cal;
+    int days[12][MAXDAYS];
+    char lineout[80];
+
+    sprintf(lineout, "%d", year);
+    center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
+    printf("\n\n");
+    for (i = 0; i < 12; i++)
+       day_array(i + 1, year, days[i]);
+#if 0
+    memset(lineout, ' ', sizeof(lineout) - 1);
+#else /* Hi-Tech C */
+    memset(lineout, sizeof(lineout) - 1, ' ');
+#endif
+    lineout[sizeof(lineout) - 1] = '\0';
+    for (month = 0; month < 12; month += 2) {
+       center(full_month[month], J_WEEK_LEN, J_HEAD_SEP);
+       center(full_month[month + 1], J_WEEK_LEN, 0);
+       printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "", j_day_headings);
+       for (row = 0; row < 6; row++) {
+           for (which_cal = 0; which_cal < 2; which_cal++) {
+               p = lineout + which_cal * (J_WEEK_LEN + 2);
+               dp = &days[month + which_cal][row * 7];
+               for (col = 0; col < 7; col++, p += J_DAY_LEN)
+                   ascii_day(p, *dp++);
+           }
+           *p = '\0';
+           trim_trailing_spaces(lineout);
+           printf("%s\n", lineout);
+       }
+    }
+    printf("\n");
+}
+
+void yearly(int year)
+{
+    char *p;
+    int col, *dp, i, month, row, which_cal;
+    int days[12][MAXDAYS];
+    char lineout[80];
+
+    sprintf(lineout, "%d", year);
+    center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
+    printf("\n\n");
+    for (i = 0; i < 12; i++)
+       day_array(i + 1, year, days[i]);
+#if 0
+    memset(lineout, ' ', sizeof(lineout) - 1);
+#else /* Hi-Tech C */
+    memset(lineout, sizeof(lineout) - 1, ' ');
+#endif
+    lineout[sizeof(lineout) - 1] = '\0';
+    for (month = 0; month < 12; month += 3) {
+       center(full_month[month], WEEK_LEN, HEAD_SEP);
+       center(full_month[month + 1], WEEK_LEN, HEAD_SEP);
+       center(full_month[month + 2], WEEK_LEN, 0);
+       printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
+                     "", day_headings, HEAD_SEP, "", day_headings);
+       for (row = 0; row < 6; row++) {
+           for (which_cal = 0; which_cal < 3; which_cal++) {
+               p = lineout + which_cal * (WEEK_LEN + 2);
+               dp = &days[month + which_cal][row * 7];
+               for (col = 0; col < 7; col++, p += DAY_LEN)
+                   ascii_day(p, *dp++);
+           }
+           *p = '\0';
+           trim_trailing_spaces(lineout);
+           printf("%s\n", lineout);
+       }
+    }
+    printf("\n");
+}
+
+/*
+ * day_array --
+ *      Fill in an array of 42 integers with a calendar.  Assume for a moment
+ *      that you took the (maximum) 6 rows in a calendar and stretched them
+ *      out end to end.  You would have 42 numbers or spaces.  This routine
+ *      builds that array for any month from Jan. 1 through Dec. 9999.
+ */
+void day_array(int month, int year, int *days)
+{
+    int day, dw, dm;
+
+    if (month == 9 && year == 1752) {
+       memmove(days,
+               julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
+       return;
+    }
+    memmove(days, empty, MAXDAYS * sizeof(int));
+    dm = days_in_month[leap_year(year)][month];
+    dw = day_in_week(1, month, year);
+    day = julian ? day_in_year(1, month, year) : 1;
+    while (dm--)
+       days[dw++] = day++;
+}
+
+/*
+ * day_in_year --
+ *      return the 1 based day number within the year
+ */
+int day_in_year(int day, int month, int year)
+{
+    int i, leap;
+
+    leap = leap_year(year);
+    for (i = 1; i < month; i++)
+       day += days_in_month[leap][i];
+    return (day);
+}
+
+/*
+ * day_in_week
+ *      return the 0 based day number for any date from 1 Jan. 1 to
+ *      31 Dec. 9999.  Assumes the Gregorian reformation eliminates
+ *      3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
+ *      missing days.
+ */
+int day_in_week(int day, int month, int year)
+{
+    long temp;
+
+    temp = (long) (year - 1) * 365 + leap_years_since_year_1(year - 1)
+       + day_in_year(day, month, year);
+    if (temp < FIRST_MISSING_DAY)
+       return ((temp - 1 + SATURDAY) % 7);
+    if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
+       return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
+    return (THURSDAY);
+}
+
+void ascii_day(char *p, int day)
+{
+    int display, val;
+    static char *aday[] =
+    {
+       "",
+       " 1", " 2", " 3", " 4", " 5", " 6", " 7",
+       " 8", " 9", "10", "11", "12", "13", "14",
+       "15", "16", "17", "18", "19", "20", "21",
+       "22", "23", "24", "25", "26", "27", "28",
+       "29", "30", "31",
+    };
+
+    if (day == SPACE) {
+       memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
+       return;
+    }
+    if (julian) {
+       if ((val = day / 100)) {
+           day %= 100;
+           *p++ = val + '0';
+           display = 1;
+       } else {
+           *p++ = ' ';
+           display = 0;
+       }
+       val = day / 10;
+       if (val || display)
+           *p++ = val + '0';
+       else
+           *p++ = ' ';
+       *p++ = day % 10 + '0';
+    } else {
+       *p++ = aday[day][0];
+       *p++ = aday[day][1];
+    }
+    *p = ' ';
+}
+
+void trim_trailing_spaces(char *s)
+{
+    char *p;
+
+    for (p = s; *p; ++p)
+       continue;
+    while (p > s && isspace(*--p))
+       continue;
+    if (p > s)
+       ++p;
+    *p = '\0';
+}
+
+void center(char *str, int len, int separate)
+{
+
+    len -= strlen(str);
+    printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
+    if (separate)
+       printf("%*s", separate, "");
+}
+
+void usage(void)
+{
+    fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
+    exit(1);
+}
+
+#if 0
+/*------------------------------------------------------------------*/
+
+/*
+ * getopt - parse command-line options
+ */
+
+#define ERR(s, c)       if(opterr){\
+       fputs(argv[0], stderr);\
+       fputs(s, stderr);\
+       fputc(c, stderr);\
+       fputc('\n', stderr);}
+
+int  opterr = 1;
+int  optind = 1;
+int  optopt;
+char *optarg;
+
+int getopt(argc, argv, opts)
+int argc;
+char **argv;
+char *opts;
+{
+    static int sp = 1;
+    register c;
+    register char *cp;
+
+    if (sp == 1) {
+       if (optind >= argc ||
+           argv[optind][0] != '-' || argv[optind][1] == '\0')
+           return EOF;
+       else if (!strcmp(argv[optind], "--")) {
+           optind++;
+           return EOF;
+       }
+    }
+
+    optopt = c = argv[optind][sp];
+    if (c == ':' || (cp=strchr(opts, c)) == NULL) {
+       ERR (": illegal option -- ", c);
+       if (argv[optind][++sp] == '\0') {
+           optind++;
+           sp = 1;
+       }
+       return '?';
+    }
+    if (*++cp == ':') {
+       if (argv[optind][sp+1] != '\0') {
+           optarg = &argv[optind++][sp+1];
+       } else if (++optind >= argc) {
+           ERR (": option requires an argument -- ", c);
+           sp = 1;
+           return '?';
+       } else {
+           optarg = argv[optind++];
+       }
+       sp = 1;
+    } else {
+       if (argv[optind][++sp] == '\0') {
+           sp = 1;
+           optind++;
+       }
+       optarg = NULL;
+    }
+
+    return c;
+}
+#endif
diff --git a/Applications/util/cat.c b/Applications/util/cat.c
new file mode 100644 (file)
index 0000000..d4879b7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * tiny-cat.c - This file is part of the tiny-utils package for Linux & ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#define STDIN_FILENO   0  /* fileno(stdin)  */
+#define STDOUT_FILENO  1  /* fileno(stdout) */
+
+#define BUFFER_SIZE    512
+
+
+/* The name of the file currently being displayed, "-" indicates stdin. */
+
+char *filename;
+
+int open_file(char *new_filename)
+{
+    int fd;
+
+    filename = new_filename;
+
+    if (*filename == '-' && *(filename + 1) == '\0')
+       return (STDIN_FILENO);
+
+    /*
+     * If open() returns an error, the accepted behavior is for cat to
+     * report the error and move on to the next file in the argument list.
+     */
+    if ((fd = open(filename, O_RDONLY)) < 0)
+       perror(filename);
+
+    return (fd);
+}
+
+
+/*
+ * Output from the current fd until we reach EOF, and then return.
+ */
+
+int output_file(int fd)
+{
+    int bytes_read;
+    char buff[BUFFER_SIZE];
+
+    while ((bytes_read = read(fd, buff, BUFFER_SIZE)) > 0)
+       write(STDOUT_FILENO, buff, bytes_read);
+
+    if (bytes_read < 0)
+        perror(filename);
+
+    return (1);
+}
+
+int main(int argc, char **argv)
+{
+    /* File descriptor for the input file */
+    int curr_input_fd;
+    int arg_num;
+
+    if (argc == 1)
+       arg_num = 0;
+    else
+       arg_num = 1;
+
+    while (arg_num < argc) {
+       if (argc == 1)
+           curr_input_fd = open_file("-");
+       else
+           curr_input_fd = open_file(argv[arg_num]);
+
+       if (curr_input_fd >= 0) {
+           output_file(curr_input_fd);
+           close(curr_input_fd);
+       }
+       arg_num++;
+    }
+
+    close(1);
+
+    return (0);
+}
diff --git a/Applications/util/chgrp.c b/Applications/util/chgrp.c
new file mode 100644 (file)
index 0000000..fd54d0d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ */
+
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+int main(int argc, char *argv[])
+{
+    char *cp;
+    int gid;
+    struct group *grp;
+    struct stat statbuf;
+
+    cp = argv[1];
+    if (!cp) {
+       fprintf(stderr, "chgrp: too few arguments\n");
+       return 1;
+    }
+    if (isdigit(*cp)) {
+       gid = 0;
+       while (isdigit(*cp))
+           gid = gid * 10 + (*cp++ - '0');
+
+       if (*cp) {
+           fprintf(stderr, "chgrp: bad gid value\n");
+           return 1;
+       }
+    } else {
+       grp = getgrnam(cp);
+       if (grp == NULL) {
+           fprintf(stderr, "chgrp: unknown group name\n");
+           return 1;
+       }
+       gid = grp->gr_gid;
+    }
+
+    argc--;
+    argv++;
+
+    while (argc-- > 1) {
+       argv++;
+       if ((stat(*argv, &statbuf) < 0) ||
+           (chown(*argv, statbuf.st_uid, gid) < 0)) {
+           perror(*argv);
+           return 1;
+       }
+    }
+
+    return 0;
+}
diff --git a/Applications/util/chmod.c b/Applications/util/chmod.c
new file mode 100644 (file)
index 0000000..3977c9f
--- /dev/null
@@ -0,0 +1,263 @@
+/* chmod - Change file modes                           Author: V. Archer */
+
+/* Copyright 1991 by Vincent Archer
+ *     You may freely redistribute this software, in source or binary
+ *     form, provided that you do not alter this copyright mention in any
+ *     way.
+ */
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef S_ISLNK
+#define S_ISLNK(mode)  0
+#define lstat          stat
+#endif
+
+#define USR_MODES (S_ISUID|S_IRWXU)
+#define GRP_MODES (S_ISGID|S_IRWXG)
+#define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH)
+#ifdef S_ISVTX
+#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX)
+#else
+#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO)
+#endif
+
+#define PATH_MAX       512     /* FIXME: it's a sysconf shouldn't be
+                                   static here */
+/* Common variables */
+char *symbolic;
+mode_t new_mode, u_mask;
+int  rflag, errors;
+struct stat st;
+char path[PATH_MAX + 1];
+
+int main(int argc, char **argv);
+mode_t parsemode(char *symbolic, mode_t oldmode);
+int do_change(char *name);
+void usage(void);
+
+/* Parse a P1003.2 4.7.7-conformant symbolic mode. */
+mode_t parsemode(char *symbolic, mode_t oldmode)
+{
+    mode_t who, mask, newmode, tmpmask;
+    char action;
+
+    newmode = oldmode & ALL_MODES;
+    while (*symbolic) {
+       who = 0;
+       for (; *symbolic; symbolic++) {
+           if (*symbolic == 'a') {
+               who |= ALL_MODES;
+               continue;
+           }
+           if (*symbolic == 'u') {
+               who |= USR_MODES;
+               continue;
+           }
+           if (*symbolic == 'g') {
+               who |= GRP_MODES;
+               continue;
+           }
+           if (*symbolic == 'o') {
+               who |= S_IRWXO;
+               continue;
+           }
+           break;
+       }
+       if (!*symbolic || *symbolic == ',')
+           usage();
+       while (*symbolic) {
+           if (*symbolic == ',')
+               break;
+           switch (*symbolic) {
+               default: usage();
+               case '+':
+               case '-':
+               case '=': action = *symbolic++; break;
+           }
+           mask = 0;
+           for (; *symbolic; symbolic++) {
+               if (*symbolic == 'u') {
+                   tmpmask = newmode & S_IRWXU;
+                   mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6);
+                   symbolic++;
+                   break;
+               }
+               if (*symbolic == 'g') {
+                   tmpmask = newmode & S_IRWXG;
+                   mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
+                   symbolic++;
+                   break;
+               }
+               if (*symbolic == 'o') {
+                   tmpmask = newmode & S_IRWXO;
+                   mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
+                   symbolic++;
+                   break;
+               }
+               if (*symbolic == 'r') {
+                   mask |= S_IRUSR | S_IRGRP | S_IROTH;
+                   continue;
+               }
+               if (*symbolic == 'w') {
+                   mask |= S_IWUSR | S_IWGRP | S_IWOTH;
+                   continue;
+               }
+               if (*symbolic == 'x') {
+                   mask |= EXE_MODES;
+                   continue;
+               }
+               if (*symbolic == 's') {
+                   mask |= S_ISUID | S_ISGID;
+                   continue;
+               }
+               if (*symbolic == 'X') {
+                   if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
+                       mask |= EXE_MODES;
+                   continue;
+               }
+#ifdef S_ISVTX
+               if (*symbolic == 't') {
+                   mask |= S_ISVTX;
+                   who |= S_ISVTX;
+                   continue;
+               }
+#endif
+               break;
+           }
+           switch (action) {
+           case '=':
+               if (who)
+                   newmode &= ~who;
+               else
+                   newmode = 0;
+           case '+':
+               if (who)
+                   newmode |= who & mask;
+               else
+                   newmode |= mask & (~u_mask);
+               break;
+           case '-':
+               if (who)
+                   newmode &= ~(who & mask);
+               else
+                   newmode &= ~mask | u_mask;
+           }
+       }
+       if (*symbolic)
+           symbolic++;
+    }
+    return (newmode);
+}
+
+
+/*
+ *  Main module. The single option possible (-R) does not warrant a call to
+ *  the getopt() stuff.
+ */
+
+int main(int argc, char *argv[])
+{
+    int ex_code = 0;
+
+    argc--;
+    argv++;
+
+    if (argc && strcmp(*argv, "-R") == 0) {
+       argc--;
+       argv++;
+       rflag = 1;
+    } else {
+       rflag = 0;
+    }
+
+    if (!argc--) usage();
+
+    if (!strcmp(argv[0], "--")) {      /* Allow chmod -- -r, as in Draft11 example */
+       if (!argc--) usage();
+       argv++;
+    }
+
+    symbolic = *argv++;
+    if (!argc) usage();
+
+    if (*symbolic >= '0' && *symbolic <= '7') {
+       new_mode = 0;
+       while (*symbolic >= '0' && *symbolic <= '7')
+           new_mode = (new_mode << 3) | (*symbolic++ & 07);
+       if (*symbolic) usage();
+       new_mode &= ALL_MODES;
+       symbolic = (char *) 0;
+    } else {
+       u_mask = umask(0);
+    }
+
+    while (argc--)
+       if (do_change(*argv++))
+           ex_code = 1;
+
+    return (ex_code);
+}
+
+
+/* Apply a mode change to a given file system element. */
+int do_change(char *name)
+{
+    mode_t m;
+    DIR *dirp;
+    struct dirent *entp;
+    char *namp;
+
+    if (lstat(name, &st)) {
+       perror(name);
+       return (1);
+    }
+
+    if (S_ISLNK(st.st_mode) && rflag)
+       return (0);             /* Note: violates POSIX. */
+
+    if (!symbolic)
+       m = new_mode;
+    else
+       m = parsemode(symbolic, st.st_mode);
+
+    if (chmod(name, m)) {
+       perror(name);
+       errors = 1;
+    } else {
+       errors = 0;
+    }
+
+    if (S_ISDIR(st.st_mode) && rflag) {
+       if (!(dirp = opendir(name))) {
+           perror(name);
+           return (1);
+       }
+       if (name != path)
+           strcpy(path, name);
+       namp = path + strlen(path);
+       *namp++ = '/';
+       while (entp = readdir(dirp))
+           if (entp->d_name[0] != '.' ||
+               (entp->d_name[1] &&
+                (entp->d_name[1] != '.' || entp->d_name[2]))) {
+               strcpy(namp, entp->d_name);
+               errors |= do_change(path);
+           }
+       closedir(dirp);
+       *--namp = '\0';
+    }
+    return (errors);
+}
+
+
+/* Display Posix prototype */
+void usage(void)
+{
+    fprintf(stderr, "Usage: chmod [-R] mode file...\n");
+    exit(1);
+}
diff --git a/Applications/util/chown.c b/Applications/util/chown.c
new file mode 100644 (file)
index 0000000..9a8201b
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ */
+
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+int main(int argc, char *argv[])
+{
+    char *cp;
+    int uid;
+    struct passwd *pwd;
+    struct stat statbuf;
+
+    cp = argv[1];
+    if (!cp) {
+       fprintf(stderr, "chown: too few arguments\n");
+       return 1;
+    }
+    if (isdigit(*cp)) {
+       uid = 0;
+       while (isdigit(*cp))
+           uid = uid * 10 + (*cp++ - '0');
+
+       if (*cp) {
+           fprintf(stderr, "chown: bad uid value\n");
+           return 1;
+       }
+    } else {
+       pwd = getpwnam(cp);
+       if (pwd == NULL) {
+           fprintf(stderr, "chown: unknown user name\n");
+           return 1;
+       }
+       uid = pwd->pw_uid;
+    }
+
+    argc--;
+    argv++;
+
+    while (argc-- > 1) {
+       argv++;
+       if ((stat(*argv, &statbuf) < 0) ||
+           (chown(*argv, uid, statbuf.st_gid) < 0)) {
+           perror(*argv);
+           return 1;
+       }
+    }
+
+    return 0;
+}
diff --git a/Applications/util/cp.c b/Applications/util/cp.c
new file mode 100644 (file)
index 0000000..f1b8dc4
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Most simple built-in commands are here.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <utime.h>
+
+typedef unsigned char BOOL;
+
+#define FALSE 0
+#define TRUE  1
+
+#define PATHLEN  512
+
+BOOL intflag;
+
+BOOL isadir(char *);
+BOOL copyfile(char *, char *, BOOL);
+
+char *buildname(char *, char *);
+
+int main(int argc, char *argv[])
+{
+    BOOL dirflag;
+    char *srcname;
+    char *destname;
+    char *lastarg;
+
+    lastarg = argv[argc - 1];
+
+    dirflag = isadir(lastarg);
+
+    if ((argc > 3) && !dirflag) {
+        fputs(lastarg, stderr);
+        fputs(": not a directory\n", stderr);
+       return 1;
+    }
+    while (argc-- > 2) {
+        srcname = argv[1];
+       destname = lastarg;
+       if (dirflag)
+           destname = buildname(destname, srcname);
+
+       copyfile(*++argv, destname, FALSE);
+    }
+    return 0;
+}
+
+#define BUF_SIZE 4096
+
+/*
+ * Return TRUE if a filename is a directory.
+ * Nonexistant files return FALSE.
+ */
+BOOL
+isadir(char *name)
+{
+    struct stat statbuf;
+
+    if (stat(name, &statbuf) < 0)
+       return FALSE;
+
+    return S_ISDIR(statbuf.st_mode);
+}
+
+/*
+ * Copy one file to another, while possibly preserving its modes, times,
+ * and modes.  Returns TRUE if successful, or FALSE on a failure with an
+ * error message output.  (Failure is not indicted if the attributes cannot
+ * be set.)
+ */
+BOOL copyfile(char *srcname, char *destname, BOOL setmodes)
+{
+    int  rfd, wfd, rcc, wcc;
+    char *bp, *buf;
+    struct stat statbuf1;
+    struct stat statbuf2;
+    struct utimbuf times;
+
+    if (stat(srcname, &statbuf1) < 0) {
+       perror(srcname);
+       return FALSE;
+    }
+    if (stat(destname, &statbuf2) < 0) {
+       statbuf2.st_ino = -1;
+       statbuf2.st_dev = -1;
+    }
+    if ((statbuf1.st_dev == statbuf2.st_dev) &&
+       (statbuf1.st_ino == statbuf2.st_ino)) {
+       fputs("Copying file \"", stderr);
+       fputs(srcname, stderr);
+       fputs("\" to itself\n", stderr);
+       return FALSE;
+    }
+    rfd = open(srcname, 0);
+    if (rfd < 0) {
+       perror(srcname);
+       return FALSE;
+    }
+    wfd = creat(destname, statbuf1.st_mode);
+    if (wfd < 0) {
+       perror(destname);
+       close(rfd);
+       return FALSE;
+    }
+    buf = malloc(BUF_SIZE);
+    while ((rcc = read(rfd, buf, BUF_SIZE)) > 0) {
+       if (intflag) {
+           close(rfd);
+           close(wfd);
+           return FALSE;
+       }
+       bp = buf;
+       while (rcc > 0) {
+           wcc = write(wfd, bp, rcc);
+           if (wcc < 0) {
+               perror(destname);
+               goto error_exit;
+           }
+           bp += wcc;
+           rcc -= wcc;
+       }
+    }
+
+    if (rcc < 0) {
+       perror(srcname);
+       goto error_exit;
+    }
+    close(rfd);
+    if (close(wfd) < 0) {
+       perror(destname);
+       return FALSE;
+    }
+    if (setmodes) {
+       chmod(destname, statbuf1.st_mode);
+
+       chown(destname, statbuf1.st_uid, statbuf1.st_gid);
+
+       times.actime = statbuf1.st_atime;
+       times.modtime = statbuf1.st_mtime;
+
+       utime(destname, &times);
+    }
+    return TRUE;
+
+
+  error_exit:
+    close(rfd);
+    close(wfd);
+
+    return FALSE;
+}
+
+/*
+ * Build a path name from the specified directory name and file name.
+ * If the directory name is NULL, then the original filename is returned.
+ * The built path is in a static area, and is overwritten for each call.
+ */
+char *buildname(char *dirname, char *filename)
+{
+    char *cp;
+    static char buf[PATHLEN];
+
+    if ((dirname == NULL) || (*dirname == '\0'))
+       return filename;
+
+    cp = strrchr(filename, '/');
+    if (cp)
+       filename = cp + 1;
+
+    strcpy(buf, dirname);
+    strcat(buf, "/");
+    strcat(buf, filename);
+
+    return buf;
+}
diff --git a/Applications/util/cut.c b/Applications/util/cut.c
new file mode 100644 (file)
index 0000000..b51b878
--- /dev/null
@@ -0,0 +1,339 @@
+/* cut - extract columns from a file or stdin.  Author: Michael J. Holme
+ *
+ *      Copyright 1989, Michael John Holme, All rights reserved.
+ *      This code may be freely distributed, provided that this notice
+ *      remains intact.
+ *
+ *      V1.1: 6th September 1989
+ *
+ *      Bugs, criticisms, etc,
+ *      c/o Mark Powell
+ *          JANET sq79@uk.ac.liv
+ *          ARPA  sq79%liv.ac.uk@nsfnet-relay.ac.uk
+ *          UUCP  ...!mcvax!ukc!liv.ac.uk!sq79
+ *-------------------------------------------------------------------------
+ *      Changed for POSIX1003.2/Draft10 conformance
+ *      Thomas Brupbacher (tobr@mw.lpc.ethz.ch), September 1990.
+ *      Changes:
+ *          - separation of error messages ( stderr) and output (stdout).
+ *          - support for -b and -n (no effect, -b acts as -c)
+ *          - support for -s
+ *-------------------------------------------------------------------------
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define MAX_FIELD      80      /* Pointers to the beginning of each field
+                                * are stored in columns[], if a line holds
+                                * more than MAX_FIELD columns the array
+                                * boundary is exceed. But unlikely at 80 */
+
+#define MAX_ARGS       32      /* Maximum number of fields following -f or
+                                * -c switches                                                                                                    */
+int args[MAX_ARGS * 2];
+int num_args;
+
+/* Lots of new defines, should easen maintainance... */
+#define DUMP_STDIN     0       /* define for mode: no options */
+#define OPTIONF                1       /* define for mode: option -f  */
+#define OPTIONC                2       /* define for mode: option -c  */
+#define OPTIONB                3       /* define for mode: option -b  */
+#define NOTSET         0       /* option not selected         */
+#define SET            1       /* option selected             */
+
+/* Defines for the warnings */
+#define DELIMITER_NOT_APPLICABLE       0
+#define OVERRIDING_PREVIOUS_MODE       1
+#define OPTION_NOT_APPLICABLE          2
+#define UNKNOWN_OPTION                 3
+#define FILE_NOT_READABLE              4
+
+/* Defines for the fatal errors */
+#define SYNTAX_ERROR                   101
+#define POSITION_ERROR                 102
+#define USAGE                          103
+#define LINE_TO_LONG_ERROR             104
+#define RANGE_ERROR                    105
+#define MAX_FIELDS_EXCEEDED_ERROR      106
+#define MAX_ARGS_EXCEEDED_ERROR                107
+
+
+int  mode;                     /* 0 = dump stdin to stdout, 1=-f, 2=-c */
+int  flag_i;                   /* SET = -i set on command line         */
+int  flag_s;                   /* SET = -s set on command line         */
+char delim = '\t';             /* default delimiting character         */
+FILE *fd;
+char *name;
+char line[BUFSIZ];
+int  exit_status;
+
+
+void warn(int warn_number, char *option)
+{
+    static char *warn_msg[] =
+    {
+       "%s: Option -d allowed only with -f\n",
+       "%s: -%s overrides earlier option\n",
+       "%s: -%s not allowed in current mode\n",
+       "%s: Cannot open %s\n"
+    };
+
+    fprintf(stderr, warn_msg[warn_number], name, option);
+    exit_status = warn_number + 1;
+
+}
+
+void cuterror(int err)
+{
+    static char *err_mes[] =
+    {
+       "%s: syntax error\n",
+       "%s: position must be >0\n",
+        "%s: usage: cut [-f args [-i] [-d x]]|[-c args] [filename [...]]\n",
+       "%s: line longer than BUFSIZ\n",
+       "%s: range must not decrease from left to right\n",
+       "%s: MAX_FIELD exceeded\n",
+       "%s: MAX_ARGS exceeded\n"
+    };
+
+    fprintf(stderr, err_mes[err - 101], name);
+    exit(err);
+}
+
+
+void get_args(void)
+{
+    int i = 0;
+    int arg_ptr = 0;
+    int flag;
+
+    num_args = 0;
+    do {
+       if (num_args == MAX_ARGS)
+           cuterror(MAX_ARGS_EXCEEDED_ERROR);
+       if (!isdigit(line[i]) && line[i] != '-')
+           cuterror(SYNTAX_ERROR);
+
+       args[arg_ptr] = 1;
+       args[arg_ptr + 1] = BUFSIZ;
+       flag = 1;
+
+       while (line[i] != ',' && line[i] != 0) {
+           if (isdigit(line[i])) {
+               args[arg_ptr] = 0;
+               while (isdigit(line[i]))
+                   args[arg_ptr] = 10 * args[arg_ptr] + line[i++] - '0';
+               if (!args[arg_ptr])
+                   cuterror(POSITION_ERROR);
+               arg_ptr++;
+           }
+           if (line[i] == '-') {
+               arg_ptr |= 1;
+               i++;
+               flag = 0;
+           }
+       }
+       if (flag && arg_ptr & 1)
+           args[arg_ptr] = args[arg_ptr - 1];
+       if (args[num_args * 2] > args[num_args * 2 + 1])
+           cuterror(RANGE_ERROR);
+       num_args++;
+       arg_ptr = num_args * 2;
+    }
+    while (line[i++]);
+}
+
+
+void cut(void)
+{
+    int i, j, length, maxcol;
+    char *columns[MAX_FIELD];
+
+    while (fgets(line, BUFSIZ, fd)) {
+
+       length = strlen(line) - 1;
+       *(line + length) = 0;
+
+       switch (mode) {
+       case DUMP_STDIN:
+           printf("%s", line);
+           break;
+
+       case OPTIONF:
+           maxcol = 0;
+           columns[maxcol++] = line;
+           for (i = 0; i < length; i++) {
+               if (*(line + i) == delim) {
+                   *(line + i) = 0;
+                   if (maxcol == MAX_FIELD)
+                       cuterror(MAX_FIELDS_EXCEEDED_ERROR);
+                   columns[maxcol] = line + i + 1;
+                   while (*(line + i + 1) == delim && flag_i) {
+                       columns[maxcol]++;
+                       i++;
+                   }
+                   maxcol++;
+               }
+           }
+           if (maxcol == 1) {
+               if (flag_s != SET)
+                   printf("%s", line);
+           } else {
+               for (i = 0; i < num_args; i++) {
+                   for (j = args[i * 2]; j <= args[i * 2 + 1]; j++)
+                       if (j <= maxcol) {
+                           printf("%s", columns[j - 1]);
+                           if (i != num_args - 1 || j != args[i * 2 + 1])
+                               putchar(delim);
+                       }
+               }
+           }
+           break;
+
+       case OPTIONC:
+           for (i = 0; i < num_args; i++) {
+               for (j = args[i * 2]; j <= (args[i * 2 + 1] > length ? length :
+                                           args[i * 2 + 1]); j++)
+                   putchar(*(line + j - 1));
+           }
+       }
+
+       if (maxcol == 1 && flag_s == SET) {
+           ;
+       } else {
+           putchar('\n');
+       }
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    int i = 1;
+    int numberFilenames = 0;
+    name = argv[0];
+
+    if (argc == 1)
+       cuterror(USAGE);
+
+    while (i < argc) {
+       if (argv[i][0] == '-') {
+           switch (argv[i++][1]) {
+           case 'd':
+               if (mode == OPTIONC || mode == OPTIONB)
+                   warn(DELIMITER_NOT_APPLICABLE, "d");
+               delim = argv[i++][0];
+               break;
+
+           case 'f':
+               sprintf(line, "%s", argv[i++]);
+               if (mode == OPTIONC || mode == OPTIONB)
+                   warn(OVERRIDING_PREVIOUS_MODE, "f");
+               mode = OPTIONF;
+               break;
+
+           case 'b':
+               sprintf(line, "%s", argv[i++]);
+               if (mode == OPTIONF || mode == OPTIONC)
+                   warn(OVERRIDING_PREVIOUS_MODE, "b");
+               mode = OPTIONB;
+               break;
+
+           case 'c':
+               sprintf(line, "%s", argv[i++]);
+               if (mode == OPTIONF || mode == OPTIONB)
+                   warn(OVERRIDING_PREVIOUS_MODE, "c");
+               mode = OPTIONC;
+               break;
+
+           case 'i':
+               flag_i = SET;
+               break;
+
+           case 's':
+               flag_s = SET;
+               break;
+
+           case '\0':          /* - means: read from stdin */
+               numberFilenames++;
+               break;
+
+           case 'n':           /* needed for Posix, but no effect here */
+               if (mode != OPTIONB)
+                   warn(OPTION_NOT_APPLICABLE, "n");
+               break;
+
+           default:
+               warn(UNKNOWN_OPTION, &(argv[i - 1][1]));
+           }
+       } else {
+           i++;
+           numberFilenames++;
+       }
+    }
+
+    /* Here follow the checks, if the selected options are reasonable. */
+
+    if (mode == OPTIONB)       /* since in Minix char == byte */
+       mode = OPTIONC;
+
+    /* Flag -s is only allowed with -f, otherwise warn and reset flag_s */
+    if (flag_s == SET && (mode == OPTIONB || mode == OPTIONC)) {
+       warn(OPTION_NOT_APPLICABLE, "s");
+       flag_s = NOTSET;
+    }
+
+    /* Flag -i is only allowed with -f, otherwise warn and reset flag_i */
+    if (flag_i == SET && mode == OPTIONF) {
+       warn(OPTION_NOT_APPLICABLE, "s");
+       flag_i = NOTSET;
+    }
+
+    get_args();
+
+    if (numberFilenames != 0) {
+       i = 1;
+       while (i < argc) {
+           if (argv[i][0] == '-') {
+               switch (argv[i][1]) {
+               case 'f':
+               case 'c':
+               case 'b':
+               case 'd':
+                   i += 2;
+                   break;
+
+               case 'n':
+               case 'i':
+               case 's':
+                   i++;
+                   break;
+
+               case '\0':
+                   fd = stdin;
+                   i++;
+                   cut();
+                   break;
+
+               default:
+                   i++;
+               }
+           } else {
+               if ((fd = fopen(argv[i++], "r")) == NULL) {
+                   warn(FILE_NOT_READABLE, argv[i - 1]);
+               } else {
+                   cut();
+                   fclose(fd);
+               }
+           }
+       }
+    } else {
+       fd = stdin;
+       cut();
+    }
+
+    return (exit_status);
+}
diff --git a/Applications/util/date.c b/Applications/util/date.c
new file mode 100644 (file)
index 0000000..2157b39
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+    time_t now;
+
+    now = time(NULL);
+    fputs(ctime(&now), stdout);
+
+    return 0;
+}
diff --git a/Applications/util/dd.c b/Applications/util/dd.c
new file mode 100644 (file)
index 0000000..e29bd39
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * The "dd" built-in command.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+typedef unsigned char BOOL;
+
+#ifndef FALSE
+#define FALSE  0
+#define TRUE   1
+#endif
+
+#define        PAR_NONE        0
+#define        PAR_IF          1
+#define        PAR_OF          2
+#define        PAR_BS          3
+#define        PAR_COUNT       4
+#define        PAR_SEEK        5
+#define        PAR_SKIP        6
+
+
+typedef struct {
+    char *name;
+    int value;
+} PARAM;
+
+
+static PARAM params[] =
+{
+    {"if",    PAR_IF},
+    {"of",    PAR_OF},
+    {"bs",    PAR_BS},
+    {"count", PAR_COUNT},
+    {"seek",  PAR_SEEK},
+    {"skip",  PAR_SKIP},
+    {NULL,    PAR_NONE}
+};
+
+
+static long getnum(char *);
+
+BOOL intflag;
+
+static char localbuf[8192];
+
+void main(int argc, char *argv[])
+{
+    char *str;
+    char *cp;
+    PARAM *par;
+    char *infile;
+    char *outfile;
+    int infd;
+    int outfd;
+    int incc;
+    int outcc;
+    int blocksize;
+    long count;
+    long seekval;
+    long skipval;
+    long intotal;
+    long outtotal;
+    char *buf;
+
+    infile = NULL;
+    outfile = NULL;
+    seekval = 0;
+    skipval = 0;
+    blocksize = 512;
+    count = 0x7fffffff;
+
+    while (--argc > 0) {
+       str = *++argv;
+       cp = strchr(str, '=');
+       if (cp == NULL) {
+           fprintf(stderr, "Bad dd argument\n");
+           return;
+       }
+       *cp++ = '\0';
+
+       for (par = params; par->name; par++) {
+           if (strcmp(str, par->name) == 0)
+               break;
+       }
+
+       switch (par->value) {
+       case PAR_IF:
+           if (infile) {
+               fprintf(stderr, "Multiple input files illegal\n");
+               return;
+           }
+           infile = cp;
+           break;
+
+       case PAR_OF:
+           if (outfile) {
+               fprintf(stderr, "Multiple output files illegal\n");
+               return;
+           }
+           outfile = cp;
+           break;
+
+       case PAR_BS:
+           blocksize = getnum(cp);
+           if (blocksize <= 0) {
+               fprintf(stderr, "Bad block size value\n");
+               return;
+           }
+           break;
+
+       case PAR_COUNT:
+           count = getnum(cp);
+           if (count < 0) {
+               fprintf(stderr, "Bad count value\n");
+               return;
+           }
+           break;
+
+       case PAR_SEEK:
+           seekval = getnum(cp);
+           if (seekval < 0) {
+               fprintf(stderr, "Bad seek value\n");
+               return;
+           }
+           break;
+
+       case PAR_SKIP:
+           skipval = getnum(cp);
+           if (skipval < 0) {
+               fprintf(stderr, "Bad skip value\n");
+               return;
+           }
+           break;
+
+       default:
+           fprintf(stderr, "Unknown dd parameter\n");
+           return;
+       }
+    }
+
+    if (infile == NULL) {
+       fprintf(stderr, "No input file specified\n");
+       return;
+    }
+    if (outfile == NULL) {
+       fprintf(stderr, "No output file specified\n");
+       return;
+    }
+    buf = localbuf;
+    if (blocksize > sizeof(localbuf)) {
+       buf = malloc(blocksize);
+       if (buf == NULL) {
+           fprintf(stderr, "Cannot allocate buffer\n");
+           return;
+       }
+    }
+    intotal = 0;
+    outtotal = 0;
+
+    infd = open(infile, 0);
+    if (infd < 0) {
+       perror(infile);
+       if (buf != localbuf)
+           free(buf);
+       return;
+    }
+    outfd = creat(outfile, 0666);
+    if (outfd < 0) {
+       perror(outfile);
+       close(infd);
+       if (buf != localbuf)
+           free(buf);
+       return;
+    }
+    if (skipval) {
+       if (lseek(infd, skipval * blocksize, 0) < 0) {
+           while (skipval-- > 0) {
+               incc = read(infd, buf, blocksize);
+               if (incc < 0) {
+                   perror(infile);
+                   goto cleanup;
+               }
+               if (incc == 0) {
+                   fprintf(stderr, "End of file while skipping\n");
+                   goto cleanup;
+               }
+           }
+       }
+    }
+    if (seekval) {
+       if (lseek(outfd, seekval * blocksize, 0) < 0) {
+           perror(outfile);
+           goto cleanup;
+       }
+    }
+    while ((incc = read(infd, buf, blocksize)) > 0) {
+       intotal += incc;
+       cp = buf;
+
+       if (intflag) {
+           fprintf(stderr, "Interrupted\n");
+           goto cleanup;
+       }
+       while (incc > 0) {
+           outcc = write(outfd, cp, incc);
+           if (outcc < 0) {
+               perror(outfile);
+               goto cleanup;
+           }
+           outtotal += outcc;
+           cp += outcc;
+           incc -= outcc;
+       }
+    }
+
+    if (incc < 0)
+       perror(infile);
+
+  cleanup:
+    close(infd);
+
+    if (close(outfd) < 0)
+       perror(outfile);
+
+    if (buf != localbuf)
+       free(buf);
+
+    printf("%d+%d records in\n", intotal / blocksize,
+          (intotal % blocksize) != 0);
+
+    printf("%d+%d records out\n", outtotal / blocksize,
+          (outtotal % blocksize) != 0);
+}
+
+
+/*
+ * Read a number with a possible multiplier.
+ * Returns -1 if the number format is illegal.
+ */
+static long getnum(char *cp)
+{
+    long value;
+
+    if (!isdigit(*cp))
+       return -1;
+
+    value = 0;
+    while (isdigit(*cp))
+       value = value * 10 + *cp++ - '0';
+
+    switch (*cp++) {
+    case 'k':
+       value *= 1024;
+       break;
+
+    case 'b':
+       value *= 512;
+       break;
+
+    case 'w':
+       value *= 2;
+       break;
+
+    case '\0':
+       return value;
+
+    default:
+       return -1;
+    }
+
+    if (*cp)
+       return -1;
+
+    return value;
+}
+
+
+/* END CODE */
diff --git a/Applications/util/df.c b/Applications/util/df.c
new file mode 100644 (file)
index 0000000..f1c42b0
--- /dev/null
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+
+char *devname(dev_t);
+char *mntpoint(const char *);
+
+int main(int argc, char *argv[])
+{
+    char *p;
+    int  i, j, Total, Used, Free, Percent, iflag = 0, kflag = 0, fflag = 0;
+    struct _uzifilesys fsys;
+
+    for (i = 1; i < argc; ++i) {
+       p = argv[i];
+       if (p[0] == '-') {
+           for (++p; *p; ++p) {
+               switch (*p) {
+               case 'i': iflag = 1; break;
+               case 'k': kflag = 1; break;
+               case 'f': fflag = 1; break;
+               default:
+                   printf("usage: %s [-ikf]\n", argv[0]);
+                   return 1;
+               }
+           }
+       } else {
+           break;
+       }
+    }
+
+    printf("%-16s %6s %6s %6s %6s %s\n",
+           "Filesystem",
+            iflag ? "Inodes" : kflag ? "KBytes" : "Blocks",
+            iflag ? "IUsed" : "Used",
+            iflag ? "IFree" : "Free",
+            iflag ? (fflag ? "%IFree" : "%IUsed") : (fflag ? "%Free" : "%Used"),
+            "Mounted on");
+
+    if (i < argc) {
+       for (; i < argc; ++i) {
+           p = argv[i];
+       }
+    } else {
+       for (j = 0; j < 8; ++j) {
+           if ((_getfsys(j, &fsys) == 0) && fsys.s_mounted) {
+               Total = iflag ? 8 * (fsys.s_isize - 2) : fsys.s_fsize;
+               Used  = iflag ? Total - fsys.s_tinode :
+                               Total - fsys.s_isize - fsys.s_tfree;
+               Free  = iflag ? fsys.s_tinode : fsys.s_tfree;
+
+               if (!iflag && kflag) {
+                   Total /= 2;
+                   Used /= 2;
+                   Free /= 2;
+               }
+               if (fflag) {
+                 if ((Percent = Total / 100) != 0) Percent = Free / Percent;
+               } else {
+                 if ((Percent = Total / 100) != 0) Percent = Used / Percent;
+               }
+               p = devname(j);
+               printf("%-16s %6u %6u %6u %5u%% %s\n",
+                      p, Total, Used, Free, Percent,
+                      fsys.s_mntpt ? mntpoint(p) : "/");
+           }
+       }
+    }
+
+    return 0;
+}
+
+/* Search /dev until an entry with the specified device number is found */
+
+#define DEV_PATH   "/dev"
+
+char *devname(dev_t devno)
+{
+    DIR *dp;
+    struct dirent *entry;
+    struct stat fstat;
+    static char namebuf[sizeof(DEV_PATH) + MAXNAMLEN + 2];
+
+    if ((dp = opendir(DEV_PATH)) != (DIR *) NULL) {
+       while ((entry = readdir(dp)) != (struct dirent *) NULL) {
+           sprintf(namebuf, "%s/%s", DEV_PATH, entry->d_name);
+           if (stat(namebuf, &fstat) != 0)
+               continue;
+           if (!S_ISBLK(fstat.st_mode))
+               continue;
+           if (fstat.st_rdev != devno)
+               continue;
+           return namebuf;
+       }
+    }
+
+    sprintf(namebuf, "%d", devno);
+    return namebuf;
+}
+
+/* Find the mount point in /etc/mtab for the specified device */
+
+char *mntpoint(const char *devname)
+{
+    FILE *f;
+    static char tmp[256];
+    static char dev[20], mntpt[20], fstype[20], rwflag[20];
+    
+    f = fopen("/etc/mtab", "r");
+    if (f) {
+        while (fgets(tmp, 256, f)) {
+            sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag);
+            if (strcmp(dev, devname) == 0) {
+                fclose(f);
+                return mntpt;
+            }
+        }
+        fclose(f);
+    }
+
+    return "???";
+}
diff --git a/Applications/util/dirent.h b/Applications/util/dirent.h
new file mode 100644 (file)
index 0000000..2e4add5
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef        __DIRENT_H
+#define        __DIRENT_H
+
+#include "unix.h"
+
+#ifndef        MAXNAMLEN
+#define        MAXNAMLEN       13
+#endif
+
+/* Directory stream type */
+
+typedef struct {
+  int dd_fd;                   /* file descriptor */
+  int dd_loc;                  /* offset in buffer */
+  int dd_size;                 /* # of valid entries in buffer */
+  struct direct dd_buf;                /* directory entry buffer */
+} DIR;                         /* stream data from opendir() */
+
+extern DIR *opendir(char *);
+extern int closedir(DIR *);
+extern struct direct *readdir(DIR *);
+
+#endif /* dirent.h  */
+
diff --git a/Applications/util/dirname.c b/Applications/util/dirname.c
new file mode 100644 (file)
index 0000000..6fc75c4
--- /dev/null
@@ -0,0 +1,37 @@
+#include <string.h>
+#include <unistd.h>
+#define STDIN_FILENO   0
+#define STDOUT_FILENO  1
+#define STDERR_FILENO  2
+
+void strip_trailing_slashes(char *path)
+{
+    int last;
+
+    last = strlen(path) - 1;
+    while (last > 0 && path[last] == '/')
+       path[last--] = '\0';
+}
+
+
+int main(int argc, char *argv[])
+{
+    char *line;
+
+    if (argc == 2) {
+       strip_trailing_slashes(argv[1]);
+       line = rindex(argv[1], '/');
+       if (line == NULL) {
+           line = ".";
+       } else {
+           while (line > argv[1] && *line == '/')
+               --line;
+           line[1] = 0;
+           line = argv[1];
+       }
+
+       write(STDOUT_FILENO, line, strlen(line));
+       write(STDOUT_FILENO, "\n", 1);
+    }
+    return 0;
+}
diff --git a/Applications/util/du.c b/Applications/util/du.c
new file mode 100644 (file)
index 0000000..a7c10d6
--- /dev/null
@@ -0,0 +1,228 @@
+/* du - report on disk usage           Author: Alistair G. Crooks */
+
+/*
+ *     du.c            1.1     27/5/87         agc     Joypace Ltd.
+ *                     1.2     24 Mar 89       nick@nswitgould.oz
+ *                     1.3     31 Mar 89       nick@nswitgould.oz
+ *                     1.4     22 Feb 90       meulenbr@cst.prl.philips.nl
+ *                     1.5     09 Jul 91       hp@vmars.tuwien.ac.at
+ *                     1.6     01 Oct 92       kjb@cs.vu.nl
+ *                     1.7     04 Jan 93       bde
+ *                     1.8     19 Sep 94       kjb
+ *                     1.9     28 Oct 99       kjb
+ *
+ *     Copyright 1987, Joypace Ltd., London UK. All rights reserved.
+ *     This code may be freely distributed, provided that this notice
+ *     remains attached.
+ *
+ *     du - a public domain interpretation of du(1).
+ *
+ *  1.2:       Fixed bug involving 14 character long filenames
+ *  1.3:       Add [-l levels] option to restrict printing.
+ *  1.4:       Added processing of multiple arguments
+ *  1.5:       Fixed processing of multiple arguments. General cleanup.
+ *  1.6:       Use readdir
+ *  1.7:       Merged 1.5 and 1.6.
+ *             Print totals even for non-dirs at top level.
+ *             Count blocks for each dir before printing total for the dir.
+ *             Count blocks for all non-special files.
+ *             Don't clutter link buffer with directories.
+ *  1.8:       Remember all links.
+ *  1.9:       Added -x flag to not cross device boundaries.  Type fixes.
+ *
+ *             Ported to UZI180 10 Jun 2001 (Hector Peraza)
+ */
+
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define        LINELEN         256
+#define        NR_ALREADY      512
+#define BLOCK_SIZE     512
+
+typedef struct already {
+    struct already *al_next;
+    int al_dev;
+    ino_t al_inum;
+    nlink_t al_nlink;
+} ALREADY;
+
+int  main(int argc, char **argv);
+int  makedname(char *d, char *f, char *out, int outlen);
+int  done(dev_t dev, ino_t inum, nlink_t nlink);
+long dodir(char *d, int thislev, dev_t dev);
+
+char *prog;                    /* program name */
+char *optstr = "asxdkl:";      /* options */
+int  silent = 0;               /* silent mode */
+int  all = 0;                  /* all directory entries mode */
+int  crosschk = 0;             /* do not cross device boundaries mode */
+int  kbytes = 0;               /* report size in kilobytes, not blocks */
+char *startdir = ".";          /* starting from here */
+int levels = 20000;            /* # of directory levels to print */
+ALREADY *already[NR_ALREADY];
+int alc;
+
+/*
+ *     makedname - make the pathname from the directory name, and the
+ *     directory entry, placing it in out. If this would overflow,
+ *     return 0, otherwise 1.
+ */
+int makedname(char *d, char *f, char *out, int outlen)
+{
+    char *cp;
+    int length;
+
+    length = strlen(f);
+    if (strlen(d) + length + 2 > outlen) return (0);
+    for (cp = out; *d; *cp++ = *d++) ;
+    if (*(cp - 1) != '/') *cp++ = '/';
+    while (length--) *cp++ = *f++;
+    *cp = '\0';
+
+    return 1;
+}
+
+/*
+ *     done - have we encountered (dev, inum) before? Returns 1 for yes,
+ *     0 for no, and remembers (dev, inum, nlink).
+ */
+int done(dev_t dev, ino_t inum, nlink_t nlink)
+{
+    register ALREADY **pap, *ap;
+
+    pap = &already[(unsigned) inum % NR_ALREADY];
+    while ((ap = *pap) != NULL) {
+       if (ap->al_inum == inum && ap->al_dev == dev) {
+           if (--ap->al_nlink == 0) {
+               *pap = ap->al_next;
+               free(ap);
+           }
+           return 1;
+       }
+       pap = &ap->al_next;
+    }
+    if ((ap = malloc(sizeof(*ap))) == NULL) {
+       fprintf(stderr, "du: Out of memory\n");
+       exit(1);
+    }
+    ap->al_next = NULL;
+    ap->al_inum = inum;
+    ap->al_dev = dev;
+    ap->al_nlink = nlink - 1;
+    *pap = ap;
+
+    return 0;
+}
+
+/*
+ *     dodir - process the directory d. Return the long size (in blocks)
+ *     of d and its descendants.
+ */
+long dodir(char *d, int thislev, dev_t dev)
+{
+    int  maybe_print;
+    struct stat s;
+    long total;
+    DIR  *dp;
+    struct dirent *entry;
+    char dent[LINELEN];
+
+    if (lstat(d, &s) < 0) {
+       fprintf(stderr, "%s: %s: %s\n", prog, d, strerror(errno));
+       return 0L;
+    }
+
+    if (s.st_dev != dev && dev != 0 && crosschk)
+       return 0L;
+
+    total = s.st_size;
+
+    if (kbytes)
+       total = (total + 1023L) / 1024L;
+    else
+       total = (total + (long) (BLOCK_SIZE - 1L)) / (long) BLOCK_SIZE;
+
+    switch (s.st_mode & S_IFMT) {
+    case S_IFDIR:
+        /*
+        * Directories should not be linked except to "." and "..", so this
+        * directory should not already have been done.
+        */
+       maybe_print = !silent;
+       if ((dp = opendir(d)) == NULL) break;
+       while ((entry = readdir(dp)) != NULL) {
+           if (strcmp(entry->d_name, ".") == 0 ||
+               strcmp(entry->d_name, "..") == 0)
+               continue;
+           if (!makedname(d, entry->d_name, dent, sizeof(dent)))
+               continue;
+           total += dodir(dent, thislev - 1, s.st_dev);
+       }
+       closedir(dp);
+       break;
+
+    case S_IFBLK:
+    case S_IFCHR:
+       /* st_size for special files is not related to blocks used. */
+       total = 0L;
+       /* Fall through. */
+    default:
+       if (s.st_nlink > 1 && done(s.st_dev, s.st_ino, s.st_nlink))
+           return 0L;
+       maybe_print = all;
+       break;
+    }
+    if (thislev >= levels || (maybe_print && thislev >= 0))
+       printf("%ld\t%s\n", total, d);
+
+    return (total);
+}
+
+int main(int argc, char *argv[])
+{
+    int c;
+
+    prog = argv[0];
+    while ((c = getopt(argc, argv, optstr)) != EOF)
+       switch (c) {
+       case 'a':
+           all = 1;
+           break;
+
+       case 's':
+           silent = 1;
+           break;
+
+       case 'x':
+       case 'd':
+           crosschk = 1;
+           break;
+
+       case 'l':
+           levels = atoi(optarg);
+           break;
+           
+       case 'k':
+           kbytes = 1;
+           break;
+
+       default:
+           fprintf(stderr, "Usage: %s [-asxk] [-l levels] [startdir]\n", prog);
+           exit(1);
+       }
+
+    do {
+       if (optind < argc) startdir = argv[optind++];
+       alc = 0;
+       dodir(startdir, levels, 0);
+    } while (optind < argc);
+
+    return (0);
+}
+
diff --git a/Applications/util/dumb.c b/Applications/util/dumb.c
new file mode 100644 (file)
index 0000000..050384a
--- /dev/null
@@ -0,0 +1,4 @@
+long long foo(long long a, long long b)
+{
+  return a%b;
+}
diff --git a/Applications/util/echo.c b/Applications/util/echo.c
new file mode 100644 (file)
index 0000000..a9b25f9
--- /dev/null
@@ -0,0 +1,53 @@
+/* echo command */
+
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, const char *argv[])
+{
+    const char *p;
+    char c;
+    int  i, nflag, eflag;
+
+    nflag = eflag = 0;
+    p = *(++argv);
+
+    while (p && *p == '-') {
+        c = *(++p);
+       if (c == 'n')
+           nflag = 1;
+       else if (c == 'e')
+           eflag = 1;
+       else
+           break;
+       if (*(++p)) break;
+       p = *(++argv);
+    }
+    
+    while ((p = *argv++) != NULL) {
+       while ((c = *p++) != '\0') {
+           if (c == '\\' && eflag) {
+               switch (*p++) {
+               case '0':  c = 0;
+                          for (i = 0; i < 3 && *p >= '0' && *p <= '7'; ++i)
+                              c = (c << 3) + *p++ - '0';
+                          break;
+               case 'b':  c = '\b'; break;
+               case 'c':  return 0;
+               case 'f':  c = '\f'; break;
+               case 'n':  c = '\n'; break;
+               case 'r':  c = '\r'; break;
+               case 't':  c = '\t'; break;
+               case 'v':  c = '\v'; break;
+               case '\\': break;
+               default:   --p; break;
+               }
+           }
+           putchar(c);
+       }
+       if (*argv) putchar(' ');
+    }
+    if (!nflag) putchar('\n');
+    
+    return 0;
+}
diff --git a/Applications/util/ed.c b/Applications/util/ed.c
new file mode 100644 (file)
index 0000000..bb44310
--- /dev/null
@@ -0,0 +1,1170 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * The "ed" built-in command (much simplified)
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+typedef unsigned char BOOL;
+
+#define FALSE   ((BOOL) 0)
+#define TRUE    ((BOOL) 1)
+#define USERSIZE       1024    /* max line length typed in by user */
+#define INITBUFSIZE    1024    /* initial buffer size */
+#define STDIN           0
+#define STDOUT          1
+
+/*
+#define isblank(ch)     (((ch) == ' ')  || ((ch) == '\t'))
+#define isdecimal(ch)   (((ch) >= '0')  && ((ch) <= '9'))
+*/
+#define isblank(ch)    isspace(ch)
+
+typedef int NUM;
+typedef int LEN;
+
+typedef struct LINE LINE;
+struct LINE {
+    LINE *next;
+    LINE *prev;
+    LEN len;
+    char data[1];
+};
+
+
+static LINE lines;
+static LINE *curline;
+static NUM curnum;
+static NUM lastnum;
+static NUM marks[26];
+static BOOL dirty;
+static char *filename;
+static char searchstring[USERSIZE];
+
+static char *bufbase;
+static char *bufp;
+static LEN bufused;
+static LEN bufsize;
+
+
+static void docommands(void);
+static void subcommand(char *, NUM, NUM);
+static BOOL getnum(char **, BOOL *, NUM *);
+static BOOL setcurnum(NUM);
+static BOOL initedit(void);
+static void termedit(void);
+static void addlines(NUM);
+static BOOL insertline(NUM, char *, LEN);
+static BOOL deletelines(NUM, NUM);
+static BOOL printlines(NUM,NUM, BOOL);
+static BOOL writelines(char *, NUM, NUM);
+static BOOL readlines(char *, NUM);
+static NUM searchlines(char *, NUM, NUM);
+static LEN findstring(LINE *, char *, LEN, LEN);
+static LINE *findline(NUM);
+
+BOOL intflag;
+
+void main(int argc, char *argv[])
+{
+    if (!initedit())
+       return;
+
+    if (argc > 1) {
+       filename = strdup(argv[1]);
+       if (filename == NULL) {
+           fprintf(stderr, "No memory\n");
+           termedit();
+           return;
+       }
+       if (!readlines(filename, 1)) {
+           termedit();
+           return;
+       }
+       if (lastnum)
+           setcurnum(1);
+
+       dirty = FALSE;
+    }
+    docommands();
+
+    termedit();
+}
+
+
+/*
+ * Read commands until we are told to stop.
+ */
+static void docommands(void)
+{
+    char *cp;
+    int len;
+    NUM num1;
+    NUM num2;
+    BOOL have1;
+    BOOL have2;
+    char buf[USERSIZE];
+
+    while (TRUE) {
+       intflag = FALSE;
+       printf(": ");
+       fflush(stdout);
+
+       if (fgets(buf, sizeof(buf), stdin) == NULL)
+           return;
+
+       len = strlen(buf);
+       if (len == 0)
+           return;
+
+       cp = &buf[len - 1];
+       if (*cp != '\n') {
+           fprintf(stderr, "Command line too long\n");
+           do {
+               len = fgetc(stdin);
+           } while ((len != EOF) && (len != '\n'));
+
+           continue;
+       }
+       while ((cp > buf) && isblank(cp[-1]))
+           cp--;
+       *cp = '\0';
+
+       cp = buf;
+       while (isblank(*cp))
+           *cp++;
+
+       have1 = FALSE;
+       have2 = FALSE;
+
+       if ((curnum == 0) && (lastnum > 0)) {
+           curnum = 1;
+           curline = lines.next;
+       }
+       if (!getnum(&cp, &have1, &num1))
+           continue;
+
+       while (isblank(*cp))
+           cp++;
+
+       if (*cp == ',') {
+           cp++;
+           if (!getnum(&cp, &have2, &num2))
+               continue;
+
+           if (!have1)
+               num1 = 1;
+
+           if (!have2)
+               num2 = lastnum;
+
+           have1 = TRUE;
+           have2 = TRUE;
+       }
+       if (!have1)
+           num1 = curnum;
+
+       if (!have2)
+           num2 = num1;
+
+       switch (*cp++) {
+       case 'a':
+           addlines(num1 + 1);
+           break;
+
+       case 'c':
+           deletelines(num1, num2);
+           addlines(num1);
+           break;
+
+       case 'd':
+           deletelines(num1, num2);
+           break;
+
+       case 'f':
+           if (*cp && !isblank(*cp)) {
+               fprintf(stderr, "Bad file command\n");
+               break;
+           }
+           while (isblank(*cp))
+               cp++;
+           if (*cp == '\0') {
+               if (filename)
+                   printf("\"%s\"\n", filename);
+               else
+                   printf("No filename\n");
+               break;
+           }
+           cp = strdup(cp);
+           if (cp == NULL) {
+               fprintf(stderr, "No memory for filename\n");
+               break;
+           }
+           if (filename)
+               free(filename);
+           filename = cp;
+           break;
+
+       case 'i':
+           addlines(num1);
+           break;
+
+       case 'k':
+           while (isblank(*cp))
+               cp++;
+
+           if ((*cp < 'a') || (*cp > 'a') || cp[1]) {
+               fprintf(stderr, "Bad mark name\n");
+               break;
+           }
+           marks[*cp - 'a'] = num2;
+           break;
+
+       case 'l':
+           printlines(num1, num2, TRUE);
+           break;
+
+       case 'p':
+           printlines(num1, num2, FALSE);
+           break;
+
+       case 'q':
+           while (isblank(*cp))
+               cp++;
+           if (have1 || *cp) {
+               fprintf(stderr, "Bad quit command\n");
+               break;
+           }
+           if (!dirty)
+               return;
+
+           printf("Really quit? ");
+           fflush(stdout);
+
+           buf[0] = '\0';
+           fgets(buf, sizeof(buf), stdin);
+           cp = buf;
+           while (isblank(*cp))
+               cp++;
+           if ((*cp == 'y') || (*cp == 'Y'))
+               return;
+           break;
+
+       case 'r':
+           if (*cp && !isblank(*cp)) {
+               fprintf(stderr, "Bad read command\n");
+               break;
+           }
+           while (isblank(*cp))
+               cp++;
+           if (*cp == '\0') {
+               fprintf(stderr, "No filename\n");
+               break;
+           }
+           if (!have1)
+               num1 = lastnum;
+
+           if (readlines(cp, num1 + 1))
+               break;
+
+           if (filename == NULL)
+               filename = strdup(cp);
+           break;
+
+       case 's':
+           subcommand(cp, num1, num2);
+           break;
+
+       case 'w':
+           if (*cp && !isblank(*cp)) {
+               fprintf(stderr, "Bad write command\n");
+               break;
+           }
+           while (isblank(*cp))
+               cp++;
+
+           if (!have1) {
+               num1 = 1;
+               num2 = lastnum;
+           }
+           if (*cp == '\0')
+               cp = filename;
+           if (cp == NULL) {
+               fprintf(stderr, "No file name specified\n");
+               break;
+           }
+           writelines(cp, num1, num2);
+           break;
+
+       case 'z':
+           switch (*cp) {
+           case '-':
+               printlines(curnum - 21, curnum, FALSE);
+               break;
+           case '.':
+               printlines(curnum - 11, curnum + 10, FALSE);
+               break;
+           default:
+               printlines(curnum, curnum + 21, FALSE);
+               break;
+           }
+           break;
+
+       case '.':
+           if (have1) {
+               fprintf(stderr, "No arguments allowed\n");
+               break;
+           }
+           printlines(curnum, curnum, FALSE);
+           break;
+
+       case '-':
+           if (setcurnum(curnum - 1))
+               printlines(curnum, curnum, FALSE);
+           break;
+
+       case '=':
+           printf("%d\n", num1);
+           break;
+
+       case '\0':
+           if (have1) {
+               printlines(num2, num2, FALSE);
+               break;
+           }
+           if (setcurnum(curnum + 1))
+               printlines(curnum, curnum, FALSE);
+           break;
+
+       default:
+           fprintf(stderr, "Unimplemented command\n");
+           break;
+       }
+    }
+}
+
+
+/*
+ * Do the substitute command.
+ * The current line is set to the last substitution done.
+ */
+static void subcommand(char *cp, NUM num1, NUM num2)
+{
+    int delim;
+    char *oldstr;
+    char *newstr;
+    LEN oldlen;
+    LEN newlen;
+    LEN deltalen;
+    LEN offset;
+    LINE *lp;
+    LINE *nlp;
+    BOOL globalflag;
+    BOOL printflag;
+    BOOL didsub;
+    BOOL needprint;
+
+    if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
+       fprintf(stderr, "Bad line range for substitute\n");
+       return;
+    }
+    globalflag = FALSE;
+    printflag = FALSE;
+    didsub = FALSE;
+    needprint = FALSE;
+
+    if (isblank(*cp) || (*cp == '\0')) {
+       fprintf(stderr, "Bad delimiter for substitute\n");
+       return;
+    }
+    delim = *cp++;
+    oldstr = cp;
+
+    cp = strchr(cp, delim);
+    if (cp == NULL) {
+       fprintf(stderr, "Missing 2nd delimiter for substitute\n");
+       return;
+    }
+    *cp++ = '\0';
+
+    newstr = cp;
+    cp = strchr(cp, delim);
+    if (cp)
+       *cp++ = '\0';
+    else
+       cp = "";
+
+    while (*cp)
+       switch (*cp++) {
+       case 'g':
+           globalflag = TRUE;
+           break;
+
+       case 'p':
+           printflag = TRUE;
+           break;
+
+       default:
+           fprintf(stderr, "Unknown option for substitute\n");
+           return;
+       }
+
+    if (*oldstr == '\0') {
+       if (searchstring[0] == '\0') {
+           fprintf(stderr, "No previous search string\n");
+           return;
+       }
+       oldstr = searchstring;
+    }
+    if (oldstr != searchstring)
+       strcpy(searchstring, oldstr);
+
+    lp = findline(num1);
+    if (lp == NULL)
+       return;
+
+    oldlen = strlen(oldstr);
+    newlen = strlen(newstr);
+    deltalen = newlen - oldlen;
+    offset = 0;
+
+    while (num1 <= num2) {
+       offset = findstring(lp, oldstr, oldlen, offset);
+       if (offset < 0) {
+           if (needprint) {
+               printlines(num1, num1, FALSE);
+               needprint = FALSE;
+           }
+           offset = 0;
+           lp = lp->next;
+           num1++;
+           continue;
+       }
+       needprint = printflag;
+       didsub = TRUE;
+       dirty = TRUE;
+
+       /*
+        * If the replacement string is the same size or shorter
+        * than the old string, then the substitution is easy.
+        */
+       if (deltalen <= 0) {
+           memcpy(&lp->data[offset], newstr, newlen);
+
+           if (deltalen) {
+               memcpy(&lp->data[offset + newlen],
+                      &lp->data[offset + oldlen],
+                      lp->len - offset - oldlen);
+
+               lp->len += deltalen;
+           }
+           offset += newlen;
+           if (globalflag)
+               continue;
+
+           if (needprint) {
+               printlines(num1, num1, FALSE);
+               needprint = FALSE;
+           }
+           lp = nlp->next;
+           num1++;
+           continue;
+       }
+       /*
+        * The new string is larger, so allocate a new line
+        * structure and use that.  Link it in in place of
+        * the old line structure.
+        */
+       nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltalen);
+       if (nlp == NULL) {
+           fprintf(stderr, "Cannot get memory for line\n");
+           return;
+       }
+       nlp->len = lp->len + deltalen;
+
+       memcpy(nlp->data, lp->data, offset);
+
+       memcpy(&nlp->data[offset], newstr, newlen);
+
+       memcpy(&nlp->data[offset + newlen],
+              &lp->data[offset + oldlen],
+              lp->len - offset - oldlen);
+
+       nlp->next = lp->next;
+       nlp->prev = lp->prev;
+       nlp->prev->next = nlp;
+       nlp->next->prev = nlp;
+
+       if (curline == lp)
+           curline = nlp;
+
+       free(lp);
+       lp = nlp;
+
+       offset += newlen;
+
+       if (globalflag)
+           continue;
+
+       if (needprint) {
+           printlines(num1, num1, FALSE);
+           needprint = FALSE;
+       }
+       lp = lp->next;
+       num1++;
+    }
+
+    if (!didsub)
+       fprintf(stderr, "No substitutions found for \"%s\"\n", oldstr);
+}
+
+
+/*
+ * Search a line for the specified string starting at the specified
+ * offset in the line.  Returns the offset of the found string, or -1.
+ */
+static LEN findstring(LINE *lp, char *str, LEN len, LEN offset)
+{
+    LEN left;
+    char *cp;
+    char *ncp;
+
+    cp = &lp->data[offset];
+    left = lp->len - offset;
+
+    while (left >= len) {
+       ncp = memchr(cp, *str, left);
+       if (ncp == NULL)
+           return -1;
+
+       left -= (ncp - cp);
+       if (left < len)
+           return -1;
+
+       cp = ncp;
+       if (memcmp(cp, str, len) == 0)
+           return (cp - lp->data);
+
+       cp++;
+       left--;
+    }
+
+    return -1;
+}
+
+
+/*
+ * Add lines which are typed in by the user.
+ * The lines are inserted just before the specified line number.
+ * The lines are terminated by a line containing a single dot (ugly!),
+ * or by an end of file.
+ */
+static void addlines(NUM num)
+{
+    int len;
+    char buf[USERSIZE + 1];
+
+    while (fgets(buf, sizeof(buf), stdin)) {
+       if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
+           return;
+
+       len = strlen(buf);
+       if (len == 0)
+           return;
+
+       if (buf[len - 1] != '\n') {
+           fprintf(stderr, "Line too long\n");
+           do {
+               len = fgetc(stdin);
+           } while ((len != EOF) && (len != '\n'));
+           return;
+       }
+       if (!insertline(num++, buf, len))
+           return;
+    }
+}
+
+
+/*
+ * Parse a line number argument if it is present.  This is a sum
+ * or difference of numbers, '.', '$', 'x, or a search string.
+ * Returns TRUE if successful (whether or not there was a number).
+ * Returns FALSE if there was a parsing error, with a message output.
+ * Whether there was a number is returned indirectly, as is the number.
+ * The character pointer which stopped the scan is also returned.
+ */
+static BOOL getnum(char **retcp, BOOL *rethavenum, NUM *retnum)
+{
+    char *cp;
+    char *str;
+    BOOL havenum;
+    NUM value;
+    NUM num;
+    NUM sign;
+
+    cp = *retcp;
+    havenum = FALSE;
+    value = 0;
+    sign = 1;
+
+    while (TRUE) {
+       while (isblank(*cp))
+           cp++;
+
+       switch (*cp) {
+       case '.':
+           havenum = TRUE;
+           num = curnum;
+           cp++;
+           break;
+
+       case '$':
+           havenum = TRUE;
+           num = lastnum;
+           cp++;
+           break;
+
+       case '\'':
+           cp++;
+           if ((*cp < 'a') || (*cp > 'z')) {
+               fprintf(stderr, "Bad mark name\n");
+               return FALSE;
+           }
+           havenum = TRUE;
+           num = marks[*cp++ - 'a'];
+           break;
+
+       case '/':
+           str = ++cp;
+           cp = strchr(str, '/');
+           if (cp)
+               *cp++ = '\0';
+           else
+               cp = "";
+           num = searchlines(str, curnum, lastnum);
+           if (num == 0)
+               return FALSE;
+
+           havenum = TRUE;
+           break;
+
+       default:
+           if (!isdecimal(*cp)) {
+               *retcp = cp;
+               *rethavenum = havenum;
+               *retnum = value;
+               return TRUE;
+           }
+           num = 0;
+           while (isdecimal(*cp))
+               num = num * 10 + *cp++ - '0';
+           havenum = TRUE;
+           break;
+       }
+
+       value += num * sign;
+
+       while (isblank(*cp))
+           cp++;
+
+       switch (*cp) {
+       case '-':
+           sign = -1;
+           cp++;
+           break;
+       case '+':
+           sign = 1;
+           cp++;
+           break;
+
+       default:
+           *retcp = cp;
+           *rethavenum = havenum;
+           *retnum = value;
+           return TRUE;
+       }
+    }
+}
+
+
+/*
+ * Initialize everything for editing.
+ */
+static BOOL initedit(void)
+{
+    int i;
+
+    bufsize = INITBUFSIZE;
+    bufbase = malloc(bufsize);
+    if (bufbase == NULL) {
+       fprintf(stderr, "No memory for buffer\n");
+       return FALSE;
+    }
+    bufp = bufbase;
+    bufused = 0;
+
+    lines.next = &lines;
+    lines.prev = &lines;
+
+    curline = NULL;
+    curnum = 0;
+    lastnum = 0;
+    dirty = FALSE;
+    filename = NULL;
+    searchstring[0] = '\0';
+
+    for (i = 0; i < 26; i++)
+       marks[i] = 0;
+    return TRUE;
+}
+
+
+/*
+ * Finish editing.
+ */
+static void termedit(void)
+{
+    if (bufbase)
+       free(bufbase);
+    bufbase = NULL;
+    bufp = NULL;
+    bufsize = 0;
+    bufused = 0;
+
+    if (filename)
+       free(filename);
+    filename = NULL;
+
+    searchstring[0] = '\0';
+
+    if (lastnum)
+       deletelines(1, lastnum);
+
+    lastnum = 0;
+    curnum = 0;
+    curline = NULL;
+}
+
+
+/*
+ * Read lines from a file at the specified line number.
+ * Returns TRUE if the file was successfully read.
+ */
+static BOOL readlines(char *file, NUM num)
+{
+    int fd;
+    int cc;
+    LEN len;
+    LEN linecount;
+    LEN charcount;
+    char *cp;
+
+    if ((num < 1) || (num > lastnum + 1)) {
+       fprintf(stderr, "Bad line for read\n");
+       return FALSE;
+    }
+    fd = open(file, 0);
+    if (fd < 0) {
+       perror(file);
+       return FALSE;
+    }
+    bufp = bufbase;
+    bufused = 0;
+    linecount = 0;
+    charcount = 0;
+
+    printf("\"%s\", ", file);
+    fflush(stdout);
+
+    do {
+       if (intflag) {
+           printf("INTERRUPTED, ");
+           bufused = 0;
+           break;
+       }
+       cp = memchr(bufp, '\n', bufused);
+       if (cp) {
+           len = (cp - bufp) + 1;
+           if (!insertline(num, bufp, len)) {
+               close(fd);
+               return FALSE;
+           }
+           bufp += len;
+           bufused -= len;
+           charcount += len;
+           linecount++;
+           num++;
+           continue;
+       }
+       if (bufp != bufbase) {
+           memcpy(bufbase, bufp, bufused);
+           bufp = bufbase + bufused;
+       }
+       if (bufused >= bufsize) {
+           len = (bufsize * 3) / 2;
+           cp = realloc(bufbase, len);
+           if (cp == NULL) {
+               fprintf(stderr, "No memory for buffer\n");
+               close(fd);
+               return FALSE;
+           }
+           bufbase = cp;
+           bufp = bufbase + bufused;
+           bufsize = len;
+       }
+       cc = read(fd, bufp, bufsize - bufused);
+       bufused += cc;
+       bufp = bufbase;
+
+    } while (cc > 0);
+
+    if (cc < 0) {
+       perror(file);
+       close(fd);
+       return FALSE;
+    }
+    if (bufused) {
+       if (!insertline(num, bufp, bufused)) {
+           close(fd);
+           return -1;
+       }
+       linecount++;
+       charcount += bufused;
+    }
+    close(fd);
+
+    printf("%d lines%s, %d chars\n", linecount,
+          (bufused ? " (incomplete)" : ""), charcount);
+
+    return TRUE;
+}
+
+
+/*
+ * Write the specified lines out to the specified file.
+ * Returns TRUE if successful, or FALSE on an error with a message output.
+ */
+static BOOL writelines(char *file, NUM num1, NUM num2)
+{
+    int fd;
+    LINE *lp;
+    LEN linecount;
+    LEN charcount;
+
+    if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
+       fprintf(stderr, "Bad line range for write\n");
+       return FALSE;
+    }
+    linecount = 0;
+    charcount = 0;
+
+    unlink(file);              /* if CREAT resets file size/data, remove this line */
+    fd = creat(file, 0666);
+    if (fd < 0) {
+       perror(file);
+       return FALSE;
+    }
+    printf("\"%s\", ", file);
+    fflush(stdout);
+
+    lp = findline(num1);
+    if (lp == NULL) {
+       close(fd);
+       return FALSE;
+    }
+    while (num1++ <= num2) {
+       if (write(fd, lp->data, lp->len) != lp->len) {
+           perror(file);
+           close(fd);
+           return FALSE;
+       }
+       charcount += lp->len;
+       linecount++;
+       lp = lp->next;
+    }
+
+    if (close(fd) < 0) {
+       perror(file);
+       return FALSE;
+    }
+    printf("%d lines, %d chars\n", linecount, charcount);
+
+    return TRUE;
+}
+
+
+/*
+ * Print lines in a specified range.
+ * The last line printed becomes the current line.
+ * If expandflag is TRUE, then the line is printed specially to
+ * show magic characters.
+ */
+static BOOL printlines(NUM num1, NUM num2, BOOL expandflag)
+{
+    LINE *lp;
+    unsigned char *cp;
+    int ch;
+    LEN count;
+
+    if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
+       fprintf(stderr, "Bad line range for print\n");
+       return FALSE;
+    }
+    lp = findline(num1);
+    if (lp == NULL)
+       return FALSE;
+
+    while (!intflag && (num1 <= num2)) {
+       if (!expandflag) {
+           write(STDOUT, lp->data, lp->len);
+           setcurnum(num1++);
+           lp = lp->next;
+           continue;
+       }
+       /*
+        * Show control characters and characters with the
+        * high bit set specially.
+        */
+       cp = lp->data;
+       count = lp->len;
+       if ((count > 0) && (cp[count - 1] == '\n'))
+           count--;
+
+       while (count-- > 0) {
+           ch = *cp++;
+           if (ch & 0x80) {
+               fputs("M-", stdout);
+               ch &= 0x7f;
+           }
+           if (ch < ' ') {
+               fputc('^', stdout);
+               ch += '@';
+           }
+           if (ch == 0x7f) {
+               fputc('^', stdout);
+               ch = '?';
+           }
+           fputc(ch, stdout);
+       }
+       fputs("$\n", stdout);
+
+       setcurnum(num1++);
+       lp = lp->next;
+    }
+
+    return TRUE;
+}
+
+
+/*
+ * Insert a new line with the specified text.
+ * The line is inserted so as to become the specified line,
+ * thus pushing any existing and further lines down one.
+ * The inserted line is also set to become the current line.
+ * Returns TRUE if successful.
+ */
+static BOOL insertline(NUM num, char *data, LEN len)
+{
+    LINE *newlp;
+    LINE *lp;
+
+    if ((num < 1) || (num > lastnum + 1)) {
+       fprintf(stderr, "Inserting at bad line number\n");
+       return FALSE;
+    }
+    newlp = (LINE *) malloc(sizeof(LINE) + len - 1);
+    if (newlp == NULL) {
+       fprintf(stderr, "Failed to allocate memory for line\n");
+       return FALSE;
+    }
+    memcpy(newlp->data, data, len);
+    newlp->len = len;
+
+    if (num > lastnum)
+       lp = &lines;
+    else {
+       lp = findline(num);
+       if (lp == NULL) {
+           free((char *) newlp);
+           return FALSE;
+       }
+    }
+
+    newlp->next = lp;
+    newlp->prev = lp->prev;
+    lp->prev->next = newlp;
+    lp->prev = newlp;
+
+    lastnum++;
+    dirty = TRUE;
+
+    return setcurnum(num);
+}
+
+
+/*
+ * Delete lines from the given range.
+ */
+static BOOL deletelines(NUM num1, NUM num2)
+{
+    LINE *lp;
+    LINE *nlp;
+    LINE *plp;
+    NUM count;
+
+    if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
+       fprintf(stderr, "Bad line numbers for delete\n");
+       return FALSE;
+    }
+    lp = findline(num1);
+    if (lp == NULL)
+       return FALSE;
+
+    if ((curnum >= num1) && (curnum <= num2)) {
+       if (num2 < lastnum)
+           setcurnum(num2 + 1);
+       else if (num1 > 1)
+           setcurnum(num1 - 1);
+       else
+           curnum = 0;
+    }
+    count = num2 - num1 + 1;
+
+    if (curnum > num2)
+       curnum -= count;
+
+    lastnum -= count;
+
+    while (count-- > 0) {
+       nlp = lp->next;
+       plp = lp->prev;
+       plp->next = nlp;
+       nlp->prev = plp;
+       lp->next = NULL;
+       lp->prev = NULL;
+       lp->len = 0;
+       free(lp);
+       lp = nlp;
+    }
+
+    dirty = TRUE;
+
+    return TRUE;
+}
+
+
+/*
+ * Search for a line which contains the specified string.
+ * If the string is NULL, then the previously searched for string
+ * is used.  The currently searched for string is saved for future use.
+ * Returns the line number which matches, or 0 if there was no match
+ * with an error printed.
+ */
+static NUM searchlines(char *str, NUM num1, NUM num2)
+{
+    LINE *lp;
+    int len;
+
+    if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) {
+       fprintf(stderr, "Bad line numbers for search\n");
+       return 0;
+    }
+    if (*str == '\0') {
+       if (searchstring[0] == '\0') {
+           fprintf(stderr, "No previous search string\n");
+           return 0;
+       }
+       str = searchstring;
+    }
+    if (str != searchstring)
+       strcpy(searchstring, str);
+
+    len = strlen(str);
+
+    lp = findline(num1);
+    if (lp == NULL)
+       return 0;
+
+    while (num1 <= num2) {
+       if (findstring(lp, str, len, 0) >= 0)
+           return num1;
+
+       num1++;
+       lp = lp->next;
+    }
+
+    fprintf(stderr, "Cannot find string \"%s\"\n", str);
+
+    return 0;
+}
+
+
+/*
+ * Return a pointer to the specified line number.
+ */
+static LINE *findline(NUM num)
+{
+    LINE *lp;
+    NUM lnum;
+
+    if ((num < 1) || (num > lastnum)) {
+       fprintf(stderr, "Line number %d does not exist\n", num);
+       return NULL;
+    }
+    if (curnum <= 0) {
+       curnum = 1;
+       curline = lines.next;
+    }
+    if (num == curnum)
+       return curline;
+
+    lp = curline;
+    lnum = curnum;
+
+    if (num < (curnum / 2)) {
+       lp = lines.next;
+       lnum = 1;
+    } else if (num > ((curnum + lastnum) / 2)) {
+       lp = lines.prev;
+       lnum = lastnum;
+    }
+    while (lnum < num) {
+       lp = lp->next;
+       lnum++;
+    }
+
+    while (lnum > num) {
+       lp = lp->prev;
+       lnum--;
+    }
+
+    return lp;
+}
+
+
+/*
+ * Set the current line number.
+ * Returns TRUE if successful.
+ */
+static BOOL setcurnum(NUM num)
+{
+    LINE *lp;
+
+    lp = findline(num);
+    if (lp == NULL)
+       return FALSE;
+
+    curnum = num;
+    curline = lp;
+
+    return TRUE;
+}
+
+/* END CODE */
diff --git a/Applications/util/false.c b/Applications/util/false.c
new file mode 100644 (file)
index 0000000..241975f
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+    exit(1);
+}
diff --git a/Applications/util/fsck.c b/Applications/util/fsck.c
new file mode 100644 (file)
index 0000000..6de8a1b
--- /dev/null
@@ -0,0 +1,797 @@
+/**************************************************
+UZI (Unix Z80 Implementation) Utilities:  fsck.c
+ 21.09.99  corrected daread, ckdir   - HP
+ 06.05.01  adapted to work under uzi - HP
+***************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define MAXDEPTH 20    /* Maximum depth of directory tree to search */
+
+/* This checks a filesystem */
+
+int dev;
+struct _uzifilesys filsys;
+
+#define SMOUNTED 12472
+
+typedef uint16_t blkno_t;
+
+char *bitmap;
+int16_t *linkmap;
+
+char *daread(uint16_t blk);
+int yes(void);
+
+struct dinode {
+    uint16_t i_mode;
+    uint16_t i_nlink;
+    uint16_t i_uid;
+    uint16_t i_gid;
+    off_t    i_size;
+    uint32_t   i_atime;                /* Breaks in 2038 */
+    uint32_t   i_mtime;                /* Need to hide some extra bits ? */
+    uint32_t   i_ctime;                /* 24 bytes */
+    blkno_t  i_addr[20];
+};               /* Exactly 64 bytes long! */
+
+/* Internal version */
+struct _uzidirent {
+       uint16_t        d_ino;
+       char            d_name[30];
+};
+
+#define ROOTINODE      1
+
+
+char *daread(uint16_t blk)
+{
+    static char da_buf[512];
+
+    lseek(dev, blk * 512L, 0);
+    if (read(dev, da_buf, 512) != 512) {
+       fprintf(stderr, "Read of block %d failed.\n", blk);
+       exit(-1);
+    }
+
+    return da_buf;
+}
+
+
+void dwrite(uint16_t blk, char *addr)
+{
+
+    lseek(dev, blk * 512L, 0);
+    if (write(dev, addr, 512) != 512)
+        fprintf(stderr, "Write of block %d failed %d.\n", blk, errno);
+    /*sync();*/
+}
+
+
+/*
+ *  Getblkno gets a pointer index, and a number of a block in the file.
+ *  It returns the number of the block on the disk.  A value of zero
+ *  means an unallocated block.
+ */
+
+blkno_t getblkno(struct dinode *ino, blkno_t num)
+{
+    blkno_t indb;
+    blkno_t dindb;
+    blkno_t *buf;
+
+    if (num < 18) {            /* Direct block */
+       return (ino->i_addr[num]);
+    }
+    if (num < 256 + 18) {      /* Single indirect */
+       indb = ino->i_addr[18];
+       if (indb == 0)
+           return (0);
+       buf = (blkno_t *) daread(indb);
+       return (buf[num - 18]);
+    }
+                               /* Double indirect */
+    indb = ino->i_addr[19];
+    if (indb == 0)
+       return (0);
+
+    buf = (blkno_t *) daread(indb);
+
+    dindb = buf[(num - (18 + 256)) >> 8];
+    buf = (blkno_t *) daread(dindb);
+
+    return (buf[(num - (18 + 256)) & 0x00ff]);
+}
+
+
+/*
+ *  Setblkno sets the given block number of the given file to the given
+ *  disk block number, possibly creating or modifiying the indirect blocks.
+ *  A return of zero means there were no blocks available to create an 
+ *  indirect block. This should never happen in fsck.
+ */
+
+void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
+{
+    blkno_t indb;
+    blkno_t dindb;
+    blkno_t *buf;
+
+    if (num < 18) {                    /* Direct block */
+       ino->i_addr[num] = dnum;
+    } else if (num < 256 + 18) {       /* Single indirect */
+       indb = ino->i_addr[18];
+       if (indb == 0) {
+           fprintf(stderr, "Missing indirect block");
+           exit(-1);
+       }
+
+       buf = (blkno_t *) daread(indb);
+       buf[num - 18] = dnum;
+       dwrite(indb, (char *) buf);
+    } else {                           /* Double indirect */
+       indb = ino->i_addr[19];
+       if (indb == 0) {
+           fprintf(stderr, "Missing indirect block");
+           exit(-1);
+       }
+
+       buf = (blkno_t *) daread(indb);
+       dindb = buf[(num - (18 + 256)) >> 8];
+       if (dindb == 0) {
+           fprintf(stderr, "Missing indirect block");
+           exit(-1);
+       }
+
+       buf = (blkno_t *) daread(dindb);
+       buf[(num - (18 + 256)) & 0x00ff] = num;
+       dwrite(indb, (char *) buf);
+    }
+}
+
+
+/*
+ *  blk_alloc0 allocates an unused block.
+ *  A returned block number of zero means no more blocks.
+ */
+
+/*--- was blk_alloc ---*/
+
+blkno_t blk_alloc0(struct _uzifilesys *filsys)
+{
+    blkno_t newno;
+    blkno_t *buf;
+    int16_t j;
+
+    newno = filsys->s_free[--filsys->s_nfree];
+    if (!newno) {
+       ++filsys->s_nfree;
+       return (0);
+    }
+
+    /* See if we must refill the s_free array */
+
+    if (!filsys->s_nfree) {
+       buf = (blkno_t *) daread(newno);
+       filsys->s_nfree = buf[0];
+       for (j = 0; j < 50; j++) {
+           filsys->s_free[j] = buf[j + 1];
+       }
+    }
+
+    --filsys->s_tfree;
+
+    if (newno < filsys->s_isize || newno >= filsys->s_fsize) {
+       printf("Free list is corrupt.  Did you rebuild it?\n");
+       return (0);
+    }
+    dwrite((blkno_t) 1, (char *) filsys);
+    return (newno);
+}
+
+
+
+void iread(uint16_t ino, struct dinode *buf)
+{
+    struct dinode *addr;
+
+    addr = (struct dinode *) daread((ino >> 3) + 2);
+    bcopy((char *) &addr[ino & 7], (char *) buf, sizeof(struct dinode));
+}
+
+
+void iwrite(uint16_t ino, struct dinode *buf)
+{
+    struct dinode *addr;
+
+    addr = (struct dinode *) daread((ino >> 3) + 2);
+    bcopy((char *) buf, (char *) &addr[ino & 7], sizeof(struct dinode));
+    dwrite((ino >> 3) + 2, (char *) addr);
+}
+
+
+void dirread(struct dinode *ino, uint16_t j, struct _uzidirent *dentry)
+{
+    blkno_t blkno;
+    char *buf;
+
+    blkno = getblkno(ino, (blkno_t) j / 16);
+    if (blkno == 0) {
+       fprintf(stderr, "Missing block in directory");
+       exit(-1);
+    }
+    buf = daread(blkno);
+    bcopy(buf + 32 * (j % 16), (char *) dentry, 32);
+}
+
+
+void dirwrite(struct dinode *ino, uint16_t j, struct _uzidirent *dentry)
+{
+    blkno_t blkno;
+    char *buf;
+
+    blkno = getblkno(ino, (blkno_t) j / 32);
+    if (blkno == 0) {
+       fprintf(stderr, "Missing block in directory");
+       exit(-1);
+    }
+    buf = daread(blkno);
+    bcopy((char *) dentry, buf + 32 * (j % 16), 32);
+    dwrite(blkno, buf);
+}
+
+/* This makes an entry in "lost+found" for inode n */
+
+void mkentry(uint16_t inum)
+{
+    struct dinode rootino;
+    struct _uzidirent dentry;
+    uint16_t d;
+
+    iread(ROOTINODE, &rootino);
+    for (d = 0; d < rootino.i_size/32; ++d) {
+       dirread(&rootino, d, &dentry);
+       if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') {
+           dentry.d_ino = inum;
+           sprintf(dentry.d_name, "l+f%d", inum);
+           dirwrite(&rootino, d, &dentry);
+           return;
+       }
+    }
+    printf("Sorry... No empty slots in root directory.\n");
+}
+
+
+/*
+ *  Pass 1 checks each inode independently for validity, zaps bad block
+ *  numbers in the inodes, and builds the block allocation map.
+ */
+
+void pass1(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    uint16_t mode;
+    blkno_t b;
+    blkno_t bno;
+    uint16_t icount;
+    blkno_t *buf;
+
+    icount = 0;
+
+    for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) {
+       iread(n, &ino);
+       linkmap[n] = -1;
+       if (ino.i_mode == 0)
+           continue;
+
+       mode = ino.i_mode & S_IFMT;
+
+       /* FIXME: named pipes ? */
+       /* Check mode */
+       if (mode != S_IFREG && mode != S_IFDIR && mode != S_IFBLK && mode != S_IFCHR) {
+           printf("Inode %d with mode 0%o is not of correct type. Zap? ",
+                  n, ino.i_mode);
+           if (yes()) {
+               ino.i_mode = 0;
+               ino.i_nlink = 0;
+               iwrite(n, &ino);
+               continue;
+           }
+       }
+       linkmap[n] = 0;
+       ++icount;
+       /* Check size */
+
+       if (ino.i_size < 0) {
+           printf("Inode %d offset is negative with value of %ld. Fix? ",
+                  n, ino.i_size);
+           if (yes()) {
+               ino.i_size = 0;
+               iwrite(n, &ino);
+           }
+       }
+       /* Check blocks and build free block map */
+       if (mode == S_IFREG || mode == S_IFDIR) {
+           /* Check singly indirect blocks */
+
+           for (b = 18; b < 20; ++b) {
+               if (ino.i_addr[b] != 0 && (ino.i_addr[b] < filsys.s_isize ||
+                                     ino.i_addr[b] >= filsys.s_fsize)) {
+                   printf("Inode %d singly ind. blk %d out of range, val = %u. Zap? ",
+                          n, b, ino.i_addr[b]);
+                   if (yes()) {
+                       ino.i_addr[b] = 0;
+                       iwrite(n, &ino);
+                   }
+               }
+               if (ino.i_addr[b] != 0 && ino.i_size < 18*512) {
+                   printf("Inode %d singly ind. blk %d past end of file, val = %u. Zap? ",
+                          n, b, ino.i_addr[b]);
+                   if (yes()) {
+                       ino.i_addr[b] = 0;
+                       iwrite(n, &ino);
+                   }
+               }
+               if (ino.i_addr[b] != 0)
+                   bitmap[ino.i_addr[b]] = 1;
+           }
+
+           /* Check the double indirect blocks */
+           if (ino.i_addr[19] != 0) {
+               buf = (blkno_t *) daread(ino.i_addr[19]);
+               for (b = 0; b < 256; ++b) {
+                   if (buf[b] != 0 && (buf[b] < filsys.s_isize ||
+                                       buf[b] >= filsys.s_fsize)) {
+                       printf("Inode %d doubly ind. blk %d is ", n, b);
+                       printf("out of range, val = %u. Zap? ", buf[b]);
+                       /* 1.4.98 - line split.  HFB */
+                       if (yes()) {
+                           buf[b] = 0;
+                           dwrite(b, (char *) buf);
+                       }
+                   }
+                   if (buf[b] != 0)
+                       bitmap[buf[b]] = 1;
+               }
+           }
+           /* Check the rest */
+           for (bno = 0; bno <= ino.i_size >> 9; ++bno) {
+               b = getblkno(&ino, bno);
+
+               if (b != 0 && (b < filsys.s_isize || b >= filsys.s_fsize)) {
+                   printf("Inode %d block %d out of range, val = %u. Zap? ",
+                          n, bno, b);
+                   if (yes()) {
+                       setblkno(&ino, bno, 0);
+                       iwrite(n, &ino);
+                   }
+               }
+               if (b != 0)
+                   bitmap[b] = 1;
+           }
+       }
+    }
+    /* Fix free inode count in super block */
+    if (filsys.s_tinode != 8 * (filsys.s_isize - 2) - ROOTINODE - icount) {
+       printf("Free inode count in super block is %u, should be %u. Fix? ",
+        filsys.s_tinode, 8 * (filsys.s_isize - 2) - ROOTINODE - icount);
+
+       if (yes()) {
+           filsys.s_tinode = 8 * (filsys.s_isize - 2) - ROOTINODE - icount;
+           dwrite((blkno_t) 1, (char *) &filsys);
+       }
+    }
+}
+
+
+/* Clear inode free list, rebuild block free list using bit map. */
+
+void pass2(void)
+{
+    blkno_t j;
+    blkno_t oldtfree;
+
+    printf("Rebuild free list? ");
+    if (!yes())
+       return;
+
+    oldtfree = filsys.s_tfree;
+
+    /* Initialize the super-block */
+
+    filsys.s_ninode = 0;
+    filsys.s_nfree = 1;
+    filsys.s_free[0] = 0;
+    filsys.s_tfree = 0;
+
+    /* Free each block, building the free list */
+
+    for (j = filsys.s_fsize - 1; j >= filsys.s_isize; --j) {
+       if (bitmap[j] == 0) {
+           if (filsys.s_nfree == 50) {
+               dwrite(j, (char *) &filsys.s_nfree);
+               filsys.s_nfree = 0;
+           }
+           ++filsys.s_tfree;
+           filsys.s_free[(filsys.s_nfree)++] = j;
+       }
+    }
+
+    dwrite((blkno_t) 1, (char *) &filsys);
+
+    if (oldtfree != filsys.s_tfree)
+       printf("During free list regeneration s_tfree was changed to %d from %d.\n",
+              filsys.s_tfree, oldtfree);
+
+}
+
+
+/* Pass 3 finds and fixes multiply allocated blocks. */
+
+void pass3(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    uint16_t mode;
+    blkno_t b;
+    blkno_t bno;
+    blkno_t newno;
+
+    for (b = filsys.s_isize; b < filsys.s_fsize; ++b)
+       bitmap[b] = 0;
+
+    for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) {
+       iread(n, &ino);
+
+       mode = ino.i_mode & S_IFMT;
+       if (mode != S_IFREG && mode != S_IFDIR)
+           continue;
+
+       /* Check singly indirect blocks */
+
+       for (b = 18; b < 20; ++b) {
+           if (ino.i_addr[b] != 0) {
+               if (bitmap[ino.i_addr[b]] != 0) {
+                   printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ",
+                          b, n, ino.i_addr[b]);
+                   if (yes()) {
+                       newno = blk_alloc0(&filsys);
+                       if (newno == 0)
+                           printf("Sorry... No more free blocks.\n");
+                       else {
+                           dwrite(newno, daread(ino.i_addr[b]));
+                           ino.i_addr[b] = newno;
+                           iwrite(n, &ino);
+                       }
+                   }
+               } else
+                   bitmap[ino.i_addr[b]] = 1;
+           }
+       }
+
+       /* Check the rest */
+       for (bno = 0; bno <= ino.i_size >> 9; ++bno) {
+           b = getblkno(&ino, bno);
+
+           if (b != 0) {
+               if (bitmap[b] != 0) {
+                   printf("Block %d in inode %u value %u multiply allocated. Fix? ",
+                          bno, n, b);
+                   if (yes()) {
+                       newno = blk_alloc0(&filsys);
+                       if (newno == 0)
+                           printf("Sorry... No more free blocks.\n");
+                       else {
+                           dwrite(newno, daread(b));
+                           setblkno(&ino, bno, newno);
+                           iwrite(n, &ino);
+                       }
+                   }
+               } else
+                   bitmap[b] = 1;
+           }
+       }
+
+    }
+
+}
+
+int depth;
+
+
+/* This recursively checks the directories */
+
+void ckdir(uint16_t inum, uint16_t pnum, char *name)
+{
+    struct dinode ino;
+    struct _uzidirent dentry;
+    uint16_t j;
+    int c;
+    int nentries;
+    char ename[150];
+
+    iread(inum, &ino);
+    if ((ino.i_mode & S_IFMT) != S_IFDIR)
+       return;
+    ++depth;
+
+    if (ino.i_size % 32 != 0) {
+       printf("Directory inode %d has improper length. Fix? ");
+       if (yes()) {
+           ino.i_size &= (~0x1f);
+           iwrite(inum, &ino);
+       }
+    }
+    nentries = ino.i_size/32;
+
+    for (j = 0; j < nentries; ++j) {
+       dirread(&ino, j, &dentry);
+
+#if 1 /* cleanup entry - HP */
+        {
+        int i;
+        
+        for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break;
+        for (     ; i < 30; ++i) dentry.d_name[i] = '\0';
+        dirwrite(&ino, j, &dentry);
+        }
+#endif
+
+
+       if (dentry.d_ino == 0)
+           continue;
+
+       if (dentry.d_ino < ROOTINODE || dentry.d_ino >= 8 * filsys.s_isize) {
+           printf("Directory entry %s%-1.30s has out-of-range inode %u. Zap? ",
+                  name, dentry.d_name, dentry.d_ino);
+           if (yes()) {
+               dentry.d_ino = 0;
+               dentry.d_name[0] = '\0';
+               dirwrite(&ino, j, &dentry);
+               continue;
+           }
+       }
+       if (dentry.d_ino && linkmap[dentry.d_ino] == -1) {
+           printf("Directory entry %s%-1.30s points to bogus inode %u. Zap? ",
+                  name, dentry.d_name, dentry.d_ino);
+           if (yes()) {
+               dentry.d_ino = 0;
+               dentry.d_name[0] = '\0';
+               dirwrite(&ino, j, &dentry);
+               continue;
+           }
+       }
+       ++linkmap[dentry.d_ino];
+
+       for (c = 0; c < 14 && dentry.d_name[c]; ++c) {
+           if (dentry.d_name[c] == '/') {
+               printf("Directory entry %s%-1.30s contains slash. Fix? ",
+                      name, dentry.d_name);
+               if (yes()) {
+                   dentry.d_name[c] = 'X';
+                   dirwrite(&ino, j, &dentry);
+               }
+           }
+       }
+
+       if (strncmp(dentry.d_name, ".", 14) == 0 && dentry.d_ino != inum) {
+           printf("\".\" entry %s%-1.30s points to wrong place. Fix? ",
+                  name, dentry.d_name);
+           if (yes()) {
+               dentry.d_ino = inum;
+               dirwrite(&ino, j, &dentry);
+           }
+       }
+       if (strncmp(dentry.d_name, "..", 14) == 0 && dentry.d_ino != pnum) {
+           printf("\"..\" entry %s%-1.30s points to wrong place. Fix? ",
+                  name, dentry.d_name);
+           if (yes()) {
+               dentry.d_ino = pnum;
+               dirwrite(&ino, j, &dentry);
+           }
+       }
+       if (dentry.d_ino != pnum && dentry.d_ino != inum && depth < MAXDEPTH) {
+           strcpy(ename, name);
+           strcat(ename, dentry.d_name);
+           strcat(ename, "/");
+           ckdir(dentry.d_ino, inum, ename);
+       }
+    }
+    --depth;
+}
+
+/*
+ *  Pass 4 traverses the directory tree, fixing bad directory entries
+ *  and finding the actual number of references to each inode.
+ */
+
+void pass4(void)
+{
+    depth = 0;
+    linkmap[ROOTINODE] = 1;
+    ckdir(ROOTINODE, ROOTINODE, "/");
+    if (depth != 0) {
+       fprintf(stderr, "Inconsistent depth");
+       exit(-1);
+    }
+}
+
+
+
+/* Pass 5 compares the link counts found in pass 4 with the inodes. */
+
+void pass5(void)
+{
+    uint16_t n;
+    struct dinode ino;
+
+    for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) {
+       iread(n, &ino);
+
+       if (ino.i_mode == 0) {
+           if (linkmap[n] != -1) {
+               fprintf(stderr, "Inconsistent linkmap");
+               exit(-1);
+           }
+           continue;
+       }
+
+       if (linkmap[n] == -1 && ino.i_mode != 0) {
+           fprintf(stderr, "Inconsistent linkmap");
+           exit(-1);
+       }
+
+       if (linkmap[n] > 0 && ino.i_nlink != linkmap[n]) {
+           printf("Inode %d has link count %d should be %d. Fix? ",
+                  n, ino.i_nlink, linkmap[n]);
+           if (yes()) {
+               ino.i_nlink = linkmap[n];
+               iwrite(n, &ino);
+           }
+       }
+
+       if (linkmap[n] == 0) {
+           if ((ino.i_mode & S_IFMT) == S_IFBLK ||
+               (ino.i_mode & S_IFMT) == S_IFCHR ||
+               (ino.i_size == 0)) {
+               printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ",
+                      n, ino.i_mode, ino.i_nlink);
+               if (yes()) {
+                   ino.i_nlink = 0;
+                   ino.i_mode = 0;
+                   iwrite(n, &ino);
+                   ++filsys.s_tinode;
+                   dwrite((blkno_t) 1, (char *) &filsys);
+               }
+           } else {
+#if 0
+               printf("Inode %d has become detached. Link count is %d. Fix? ",
+                      n, ino.i_nlink);
+               if (yes()) {
+                   ino.i_nlink = 1;
+                   iwrite(n, &ino);
+                   mkentry(n);
+               }
+#else
+               printf("Inode %d has become detached. Link count is %d. ",
+                      n, ino.i_nlink);
+               if (ino.i_nlink == 0)
+                   printf("Zap? ");
+               else
+                   printf("Fix? ");
+               if (yes()) {
+                   if (ino.i_nlink == 0) {
+                       ino.i_nlink = 0;
+                       ino.i_mode = 0;
+                       iwrite(n, &ino);
+                       ++filsys.s_tinode;
+                       dwrite((blkno_t) 1, (char *) &filsys);
+                   } else {
+                       ino.i_nlink = 1;
+                       iwrite(n, &ino);
+                       mkentry(n);
+                   }
+               }
+#endif
+           }
+       }
+       
+    }
+}
+
+
+
+
+int yes(void)
+{
+    char line[20];
+    /*int  fgets(); -- HP */
+
+    if (!fgets(line, sizeof(line), stdin) || (*line != 'y' && *line != 'Y'))
+       return (0);
+
+    return (1);
+}
+
+
+main(int argc, char *argv[])
+{
+    char *buf;
+    struct stat statbuf;
+
+    if (argc != 2) {
+       fprintf(stderr, "usage: fsck device\n");
+       exit(-1);
+    }
+
+    if (stat(argv[1], &statbuf) != 0) {
+        fprintf(stderr, "fsck: can't stat %s\n", argv[1]);
+        exit(-1);
+    }
+    
+    if ((statbuf.st_mode & S_IFMT) != S_IFBLK) {
+        fprintf(stderr, "fsck: %s is not a valid device\n", argv[1]);
+        exit(-1);
+    }
+
+    dev = open(argv[1], O_RDWR);
+    if (dev < 0) {
+        fprintf(stderr, "fsck: can't open device %s\n", argv[1]);
+        exit(-1);
+    }
+
+    /* Read in the super block. */
+
+    buf = daread(1);
+    bcopy(buf, (char *) &filsys, sizeof(struct _uzifilesys));
+
+    /* Verify the fsize and isize parameters */
+
+    if (filsys.s_mounted != SMOUNTED) {
+       printf("Device %s has invalid magic number %d. Fix? ",
+              argv[1], filsys.s_mounted);
+       if (!yes())
+           exit(-1);
+       filsys.s_mounted = SMOUNTED;
+       dwrite((blkno_t) 1, (char *) &filsys);
+    }
+    printf("Device %s has fsize = %d and isize = %d. Continue? ",
+          argv[1], filsys.s_fsize, filsys.s_isize);
+    if (!yes())
+       exit(-1);
+
+    bitmap = calloc(filsys.s_fsize, sizeof(char));
+    linkmap = (int16_t *) calloc(8 * filsys.s_isize, sizeof(int16_t));
+
+    if (!bitmap || !linkmap) {
+       fprintf(stderr, "Not enough memory.\n");
+       exit(-1);
+    }
+
+    printf("Pass 1: Checking inodes...\n");
+    pass1();
+
+    printf("Pass 2: Rebuilding free list...\n");
+    pass2();
+
+    printf("Pass 3: Checking block allocation...\n");
+    pass3();
+
+    printf("Pass 4: Checking directory entries...\n");
+    pass4();
+
+    printf("Pass 5: Checking link counts...\n");
+    pass5();
+
+    sync();
+    printf("Done.\n");
+
+    return 0;
+}
+
diff --git a/Applications/util/grep.c b/Applications/util/grep.c
new file mode 100644 (file)
index 0000000..7e27416
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * The "grep" built-in command.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+typedef unsigned char BOOL;
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE  1
+#endif
+
+BOOL intflag;
+static char buf[8192];
+
+/*
+ * See if the specified word is found in the specified string.
+ */
+static BOOL search(char *string, char *word, BOOL ignorecase)
+{
+    char *cp1, *cp2;
+    int  ch1, ch2, len, lowfirst;
+
+    len = strlen(word);
+
+    if (!ignorecase) {
+       while (TRUE) {
+           string = strchr(string, word[0]);
+           if (string == NULL)
+               return FALSE;
+
+           if (memcmp(string, word, len) == 0)
+               return TRUE;
+
+           string++;
+       }
+    }
+    /*
+     * Here if we need to check case independence.
+     * Do the search by lower casing both strings.
+     */
+    lowfirst = *word;
+    if (isupper(lowfirst))
+       lowfirst = tolower(lowfirst);
+
+    while (TRUE) {
+       while (*string && (*string != lowfirst) &&
+              (!isupper(*string) || (tolower(*string) != lowfirst)))
+           string++;
+
+       if (*string == '\0')
+           return FALSE;
+
+       cp1 = string;
+       cp2 = word;
+
+       do {
+           if (*cp2 == '\0')
+               return TRUE;
+
+           ch1 = *cp1++;
+           if (isupper(ch1))
+               ch1 = tolower(ch1);
+
+           ch2 = *cp2++;
+           if (isupper(ch2))
+               ch2 = tolower(ch2);
+
+       } while (ch1 == ch2);
+
+       string++;
+    }
+}
+
+
+void main(int argc, char *argv[])
+{
+    FILE *fp;
+    char *word, *name, *cp;
+    BOOL tellname, ignorecase, tellline;
+    long line;
+
+    ignorecase = FALSE;
+    tellline = FALSE;
+
+    argc--;
+    argv++;
+
+    if (**argv == '-') {
+       argc--;
+       cp = *argv++;
+
+       while (*++cp)
+           switch (*cp) {
+           case 'i':
+               ignorecase = TRUE;
+               break;
+
+           case 'n':
+               tellline = TRUE;
+               break;
+
+           default:
+               fprintf(stderr, "Unknown option\n");
+               return;
+           }
+    }
+    word = *argv++;
+    argc--;
+
+    tellname = (argc > 1);
+
+    while (argc-- > 0) {
+       name = *argv++;
+
+       fp = fopen(name, "r");
+       if (fp == NULL) {
+           perror(name);
+           continue;
+       }
+       line = 0;
+
+       while (fgets(buf, sizeof(buf), fp)) {
+           if (intflag) {
+               fclose(fp);
+               return;
+           }
+           line++;
+
+           cp = &buf[strlen(buf) - 1];
+           if (*cp != '\n')
+               fprintf(stderr, "%s: Line too long\n", name);
+
+           if (search(buf, word, ignorecase)) {
+               if (tellname)
+                   printf("%s: ", name);
+               if (tellline)
+                   printf("%d: ", line);
+
+               fputs(buf, stdout);
+           }
+       }
+
+       if (ferror(fp))
+           perror(name);
+
+       fclose(fp);
+    }
+}
+
+/* END CODE */
diff --git a/Applications/util/grp.h b/Applications/util/grp.h
new file mode 100644 (file)
index 0000000..dfcf25c
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef        __GRP_H
+#define        __GRP_H
+
+#include <stdio.h>
+
+#ifndef _UID_T
+#define _UID_T
+typedef int uid_t;
+#endif
+
+#ifndef _GID_T
+#define _GID_T
+typedef int gid_t;
+#endif
+
+/* The passwd structure */
+struct group
+{
+  char *gr_name;               /* group name     */
+  char *gr_passwd;             /* group password */
+  gid_t gr_gid;                        /* group ID       */
+  char **gr_mem;               /* group members  */
+};
+
+
+extern int  setgrent(void);
+extern void endgrent(void);
+extern struct group *getgrent(void);
+
+extern int putgrent(struct group *, FILE *);
+extern int getgr(gid_t uid, char *buf);
+
+extern struct group *getgrgid(gid_t);
+extern struct group *getgrnam(char *);
+
+
+#endif /* grp.h  */
diff --git a/Applications/util/id.c b/Applications/util/id.c
new file mode 100644 (file)
index 0000000..c528a72
--- /dev/null
@@ -0,0 +1,52 @@
+/* id - return uid and gid             Author: John J. Marco */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
+/*             ----- id.c -----                                        */
+/* Id - get real and effective user id and group id                    */
+/* Author: John J. Marco                                               */
+/*        pa1343@sdcc15.ucsd.edu                                       */
+/* Modified for UZI180 by H. Peraza                                     */
+/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+
+int main(int argc, char *argv[])
+{
+    struct passwd *pwd;
+    struct group *grp;
+    int uid, gid, euid, egid;
+
+    uid = getuid();
+    gid = getgid();
+    euid = geteuid();
+    egid = getegid();
+
+    if ((pwd = getpwuid(uid)) == NULL)
+       printf("uid=%d ", uid);
+    else
+       printf("uid=%d(%s) " , uid, pwd->pw_name);
+
+    if ((grp = getgrgid(gid)) == NULL)
+       printf("gid=%d ", gid);
+    else
+       printf("gid=%d(%s) ", gid, grp->gr_name);
+
+    if (uid != euid)
+       if ((pwd = getpwuid(euid)) != NULL)
+           printf("euid=%d(%s) ", euid, pwd->pw_name);
+       else
+           printf("euid=%d ", euid);
+
+    if (gid != egid)
+       if ((grp = getgrgid(egid)) != NULL)
+           printf("egid=%d(%s) ", egid, grp->gr_name);
+       else
+           printf("egid=%d ", egid);
+
+    printf("\n");
+    return(0);
+}
diff --git a/Applications/util/init.c b/Applications/util/init.c
new file mode 100644 (file)
index 0000000..fb3eeff
--- /dev/null
@@ -0,0 +1,212 @@
+/* init.c - simplified init program for UZI180 (mix of init/getty/login)
+ *          only handles logins in /dev/tty1
+ *          handles user names from /etc/passwd
+ */
+
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+extern char **environ;
+
+char *argp[] = { "sh", NULL };
+
+#define crlf   write(1, "\n", 1)
+
+int  login(char *);
+void spawn(struct passwd *);
+int  showfile(char *);
+void putstr(char *);
+void sigalarm(unsigned int);
+
+int main(int argc, char *argv[])
+{
+    int fdtty1, sh_pid, pid;
+
+    signal(SIGINT, SIG_IGN);
+
+    /* remove any stale /etc/mtab file */
+
+    unlink("/etc/mtab");
+
+    /* loop until we can open the first terminal */
+
+    do {
+        fdtty1 = open("/dev/tty1", O_RDWR);
+    } while (fdtty1 < 0);
+
+    /* make stdin, stdout and stderr point to /dev/tty1 */
+
+    if (fdtty1 != 0) close(0);
+    dup(fdtty1);
+    close(1);
+    dup(fdtty1);
+    close(2);
+    dup(fdtty1);
+
+    putstr("init version 0.8\n");
+    
+    /* then call the login procedure on it */
+
+    for (;;) {
+
+        sh_pid = login("/dev/tty1");
+
+        /* wait until the user exits the shell */
+
+        do {
+            pid = wait(NULL);
+        } while (sh_pid != pid);
+
+        /* then loop to call login again */
+        
+        crlf;
+    }
+}
+
+int login(char *ttyname)
+{
+    int  fdtty, pid;
+    struct passwd *pwd;
+    char *p, buf[50], salt[3];
+
+    fdtty = open(ttyname, O_RDWR);
+    if (fdtty < 0) return -1;
+
+    for (;;) {
+        pid = fork();
+        if (pid == -1) {
+            putstr("init: can't fork\n");
+        } else {
+            if (pid != 0) {
+                close(fdtty);
+                /* parent's context: return pid of the child process */
+                return pid;
+            }
+            
+            /* here we are inside child's context of execution */
+            
+            putenv("PATH=:/bin:/usr/bin");
+            strcpy(buf, "CTTY=");
+            strcat(buf, ttyname);
+            putenv(buf);
+
+            /* make stdin, stdout and stderr point to fdtty */
+
+            close(0);
+            dup(fdtty);
+            close(1);
+            dup(fdtty);
+            close(2);
+            dup(fdtty);
+
+            /* display the /etc/issue file, if exists */
+            showfile("/etc/issue");
+
+            /* loop until a valid user name is entered
+             * and a shell is spawned */
+
+            for (;;) {
+                putstr("login: ");
+                while (read(0, buf, 20) < 0);    /* EINTR might happens because of the alarm() call below */
+
+                if ((p = strchr(buf, '\n')) != NULL)
+                    *p = '\0';                    /* strip newline */
+
+                pwd = getpwnam(buf);
+                
+                if (pwd) {
+                    if (pwd->pw_passwd[0] != '\0') {
+                        p = getpass("Password: ");
+                        salt[0] = pwd->pw_passwd[0];
+                        salt[1] = pwd->pw_passwd[1];
+                        salt[2] = '\0';
+                        p = crypt(p, salt);
+                    } else {
+                        p = "";
+                    }
+                    if (strcmp(p, pwd->pw_passwd) == 0) spawn(pwd);
+                }
+
+                putstr("Login incorrect\n\n");
+                signal(SIGALRM, sigalarm);
+                alarm(2);
+                pause();
+            }
+        }
+    }
+}
+
+void spawn(struct passwd *pwd)
+{
+    char *p, buf[50];
+
+    setgid(pwd->pw_gid);
+    setuid(pwd->pw_uid);
+    signal(SIGINT, SIG_DFL);
+
+    /* setup user environment variables */
+
+    strcpy(buf, "LOGNAME=");
+    strcat(buf, pwd->pw_name);
+    putenv(buf);
+
+    strcpy(buf, "HOME=");
+    strcat(buf, pwd->pw_dir);
+    putenv(buf);
+
+    strcpy(buf, "SHELL=");
+    strcat(buf, pwd->pw_shell);
+    putenv(buf);
+
+    /*chdir(pwd->pw_dir);*/
+
+    /* show the motd file */
+
+    if (!showfile("/etc/motd")) crlf;
+
+    /* and spawn the shell */
+
+    strcpy(buf, "-");
+    if ((p = strrchr(pwd->pw_shell, '/')) != NULL)
+        strcat(buf, ++p);
+    else
+        strcat(buf, pwd->pw_shell);
+
+    argp[0] = buf;
+    argp[1] = NULL;
+
+    execve(pwd->pw_shell, argp, environ);
+    putstr("login: can't execute shell\n");
+    exit(1);
+}
+
+void sigalarm(unsigned int sig)
+{
+    return;
+}
+
+int showfile(char *fname)
+{
+    int  fd, len;
+    char buf[80];
+    
+    fd = open(fname, O_RDONLY);
+    if (fd > 0) {
+        do {
+            len = read(fd, buf, 80);
+            write(1, buf, len);
+        } while (len > 0);
+        close(fd);
+        return 1;
+    }
+    return 0;
+}
+
+void putstr(char *str)
+{
+    write(1, str, strlen(str));
+}
diff --git a/Applications/util/kill.c b/Applications/util/kill.c
new file mode 100644 (file)
index 0000000..87e1db8
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Most simple built-in commands are here.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+    char *cp;
+    int pid, sig = SIGTERM;
+
+    if (argc < 2) {
+       fprintf(stderr, "usage: kill [-sig] pid ...\n");
+       return 0;
+    }
+    if (argv[1][0] == '-') {
+       cp = &argv[1][1];
+       if (!strncmp(cp, "SIG", 3))
+           cp += 3;
+       if (!strcmp(cp, "HUP"))
+           sig = SIGHUP;
+       else if (!strcmp(cp, "INT"))
+           sig = SIGINT;
+       else if (!strcmp(cp, "QUIT"))
+           sig = SIGQUIT;
+       else if (strcmp(cp, "KILL"))
+           sig = SIGKILL;
+       else if (strcmp(cp, "TERM"))
+           sig = SIGTERM;
+       else {
+           sig = 0;
+           while (isdigit(*cp))
+               sig = sig * 10 + *cp++ - '0';
+           if (*cp) {
+               fprintf(stderr, "kill: unknown signal\n");
+               return 1;
+           }
+       }
+       argc--;
+       argv++;
+    }
+    while (argc-- > 1) {
+       cp = *++argv;
+       pid = 0;
+       while (isdigit(*cp))
+           pid = pid * 10 + *cp++ - '0';
+       if (*cp) {
+           fprintf(stderr, "kill: non-numeric pid\n");
+           continue;
+       }
+       if (kill(pid, sig) < 0) {
+           perror(*argv);
+           return 1;
+       }
+    }
+    return 0;
+}
diff --git a/Applications/util/ll.c b/Applications/util/ll.c
new file mode 100644 (file)
index 0000000..3555c9c
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+char *month[] = { "Jan", "Feb", "Mar", "Apr",
+                  "May", "Jun", "Jul", "Aug",
+                  "Sep", "Oct", "Nov", "Dec" };
+
+
+void prmode(int mode)
+{
+    if (mode & 4)
+        printf("r");
+    else
+        printf("-");
+
+    if (mode & 2)
+        printf("w");
+    else
+        printf("-");
+
+    if (mode & 1)
+        printf("x");
+    else
+        printf("-");
+}
+
+/* FIXME: use readdir */
+struct _uzidirent {
+ uint16_t ino;
+ char d_name[30];
+};
+
+int ls(char *path)
+{
+    int    d, st;
+    struct _uzidirent buf;
+    struct stat statbuf;
+    char   dname[128];
+
+    if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+        printf("ls: can't stat %s\n", path);
+        return -1;
+    }
+
+    d = open(path, O_RDONLY);
+    if (d < 0) {
+        printf ("ls: can't open %s\n", path);
+        return -1;
+    }
+
+    /* FIXME: use readdir etc */
+    while (read(d, (char *)&buf, 32) == 16) {
+        if (buf.d_name[0] == '\0')
+            continue;
+
+        if (path[0] != '.' || path[1]) {
+            strcpy(dname, path);
+            strcat(dname, "/");
+        } else {
+            dname[0] = '\0';
+        }
+
+        /* FIXME: 128 byte overflow */
+        strcat(dname, buf.d_name);
+
+        if (stat(dname, &statbuf) != 0) {
+            printf("ls: can't stat %s\n", dname);
+            break;
+        }
+
+        st = statbuf.st_mode & S_IFMT;
+
+        if (st == S_IFDIR)
+            printf("d");
+        else if (st == S_IFCHR)
+            printf("c");
+        else if (st == S_IFBLK)
+            printf("b");
+        else if (st == S_IFIFO)
+            printf("p");
+        else if ((st & S_IFREG) == 0)
+            printf("l");
+        else
+            printf("-");
+
+        prmode(statbuf.st_mode >> 6);
+        prmode(statbuf.st_mode >> 3);
+        prmode(statbuf.st_mode);
+
+        printf("%4d %5d", statbuf.st_nlink, statbuf.st_ino);
+        if (S_ISDIR(statbuf.st_mode))
+            strcat(dname, "/");
+        else if (statbuf.st_mode & 0111)
+            strcat(dname, "*");
+
+        printf("%12lu ",
+                (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) ?
+                    statbuf.st_rdev :
+                    statbuf.st_size);
+
+        if (statbuf.st_mtime == 0) {  /* st_mtime? */
+            printf("                   ");
+        } else {
+            struct tm *t = localtime(&statbuf.st_mtime);
+            printf("%2s %02d %4d   ",
+                   month[t->tm_mon], 
+                   t->tm_mday,
+                   t->tm_year);
+
+            printf("%2d:%02d",
+                   t->tm_hour,
+                   t->tm_min);
+        }
+
+        printf("  %-30s\n", dname);
+    }
+    close (d);
+    return 0;
+}
+
+int main(int argc, char *argval[])
+{
+    if (argc < 2)
+        return ls(".");
+    else
+        return ls(argval[1]);
+}
diff --git a/Applications/util/ln.c b/Applications/util/ln.c
new file mode 100644 (file)
index 0000000..01b2b16
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#ifndef BOOL
+#define BOOL  int
+#define TRUE  1
+#define FALSE 0
+#endif
+
+#define PATHLEN 512
+
+
+/*
+ * Return TRUE if name is a directory.
+ * Return FALSE otherwise or if the file does not exist.
+ */
+
+BOOL isadir(char *name)
+{
+    struct stat statbuf;
+
+    if (stat(name, &statbuf) < 0)
+       return FALSE;
+
+    return S_ISDIR(statbuf.st_mode);
+}
+
+
+/*
+ * Build a path name from the specified directory name and file name.
+ * If the directory name is NULL, then the original filename is returned.
+ * The built path is in a static area, and is overwritten for each call.
+ */
+
+char *buildname(char *dirname, char *filename)
+{
+    char *cp;
+    static char buf[PATHLEN];
+
+    if ((dirname == NULL) || (*dirname == '\0'))
+       return filename;
+
+    cp = strrchr(filename, '/');
+    if (cp)
+       filename = cp + 1;
+
+    /* FIXME: overflow check */
+    strcpy(buf, dirname);
+    strcat(buf, "/");
+    strcat(buf, filename);
+
+    return buf;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int  dirflag;
+    char *srcname, *destname, *lastarg;
+
+    /* Symbolic link? */
+
+    if (argv[1][0] == '-') {
+#if defined(S_ISLNK) && 0      /* FIXME */
+       if (strcmp(argv[1], "-s") == 0) {
+           if (argc != 4) {
+               fprintf(stderr, "%s: wrong number of arguments for symbolic link\n", argv[0]);
+               return 1;
+           }
+
+           if (symlink(argv[2], argv[3]) < 0) {
+               perror(argv[3]);
+               return 1;
+           }
+           return 0;
+
+       }
+#endif
+       fprintf(stderr, "%s: unknown option %s\n", argv[0], argv[1]);
+       return 1;
+    }
+
+    /* Here for normal hard links. */
+
+    lastarg = argv[argc - 1];
+    dirflag = isadir(lastarg);
+
+    if ((argc > 3) && !dirflag) {
+        fprintf(stderr, "%s: not a directory\n", lastarg);
+       return 1;
+    }
+
+    while (argc-- > 2) {
+       srcname = *(++argv);
+       if (access(srcname, 0) < 0) {
+           perror(srcname);
+           continue;
+       }
+
+       destname = lastarg;
+       if (dirflag)
+           destname = buildname(destname, srcname);
+
+       if (link(srcname, destname) < 0) {
+           perror(destname);
+           continue;
+       }
+    }
+
+    return 0;
+}
diff --git a/Applications/util/ls.c b/Applications/util/ls.c
new file mode 100644 (file)
index 0000000..97da0a0
--- /dev/null
@@ -0,0 +1,342 @@
+/* The "ls" standard command.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+
+#define LISTSIZE       256
+
+typedef unsigned char BOOL;
+
+#define PATHLEN                512
+
+#ifdef S_ISLNK
+#define LSTAT  lstat
+#else
+#define LSTAT  stat
+#endif
+
+/*
+ * Flags for the LS command.
+ */
+#define LSF_LONG       0x01
+#define LSF_DIR        0x02
+#define LSF_INODE      0x04
+#define LSF_MULT       0x08
+#define LSF_FILE       0x10
+#define LSF_DOWN       0x20
+#define LSF_ALL                0x40
+#define LSF_OCT                0x80
+#define LSF_UNSORT     0x100
+
+static char **list;
+static int listsize;
+static int listused;
+static int flags;
+
+static void lsfile(char *, struct stat *, int);
+static char *modestring(int mode);
+char *timestring(time_t *t);
+int namesort(const void *p1, const void *p2);
+
+long time_zone = 0;
+long timezone = 0;
+
+
+/*
+ * Sort routine for list of filenames.
+ */
+int namesort(const void *p1, const void *p2)
+{
+    return strcmp(* (char * const *)p1, * (char * const *) p2);
+}
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+static char *modestring(int mode)
+{
+    static char buf[12];
+
+    if (flags & LSF_OCT) {
+       sprintf(buf, "%06o", mode);
+       return buf;
+    }
+    strcpy(buf, "----------");
+
+    /* Fill in the file type. */
+    if (S_ISDIR(mode))
+       buf[0] = 'd';
+    if (S_ISCHR(mode))
+       buf[0] = 'c';
+    if (S_ISBLK(mode))
+       buf[0] = 'b';
+#ifdef S_ISLNK
+    if (S_ISLNK(mode))
+       buf[0] = 'l';
+#endif
+    /* Now fill in the normal file permissions. */
+    if (mode & S_IRUSR)
+       buf[1] = 'r';
+    if (mode & S_IWUSR)
+       buf[2] = 'w';
+    if (mode & S_IXUSR)
+       buf[3] = 'x';
+
+    if (mode & S_IRGRP)
+       buf[4] = 'r';
+    if (mode & S_IWGRP)
+       buf[5] = 'w';
+    if (mode & S_IXGRP)
+       buf[6] = 'x';
+
+    if (mode & S_IROTH)
+       buf[7] = 'r';
+    if (mode & S_IWOTH)
+       buf[8] = 'w';
+    if (mode & S_IXOTH)
+       buf[9] = 'x';
+
+    /* Finally fill in magic stuff like suid and sticky text. */
+    if (mode & S_ISUID)
+       buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
+    if (mode & S_ISGID)
+       buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
+    if (mode & S_ISVTX)
+       buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
+    return buf;
+}
+
+/*
+ * Get the time to be used for a file.
+ * This is down to the minute for new files, but only the date for old files.
+ * The string is returned from a static buffer, and so is overwritten for
+ * each call.
+ */
+char *timestring(time_t *t)
+{
+    char *str;
+    static char buf[26];
+
+    str = ctime(t);
+    strcpy(buf, &str[4]);
+    buf[12] = '\0';
+#if 0                          /* ??? */
+    if ((t > now) || (t < now - 365 * 24 * 60 * 60L)) {
+       strcpy(&buf[7], &str[20]);
+       buf[11] = '\0';
+    }
+#endif
+    return buf;
+}
+
+/*
+ * Do an LS of a particular file name according to the flags.
+ */
+static void lsfile(char *name, struct stat *statbuf, int flags)
+{
+    static char username[12];
+    static int userid;
+    static BOOL useridknown;
+    static char groupname[12];
+    static int groupid;
+    static BOOL groupidknown;
+
+    struct passwd *pwd;
+    struct group *grp;
+    char buf[PATHLEN], *cp = buf;
+    int len;
+
+    *cp = '\0';
+    if (flags & LSF_INODE) {
+       sprintf(cp, "%5d ", statbuf->st_ino);
+       cp += strlen(cp);
+    }
+    if (flags & LSF_LONG) {
+       cp += strlen(strcpy(cp, modestring(statbuf->st_mode)));
+       sprintf(cp, "%4d ", statbuf->st_nlink);
+       cp += strlen(cp);
+#if 1
+       if (!useridknown || (statbuf->st_uid != userid)) {
+           if ((pwd = getpwuid(statbuf->st_uid)) != NULL)
+               strcpy(username, pwd->pw_name);
+           else
+               sprintf(username, "%d", statbuf->st_uid);
+           userid = statbuf->st_uid;
+           useridknown = 1;
+       }
+       sprintf(cp, "%-8s ", username);
+       cp += strlen(cp);
+       if (!groupidknown || (statbuf->st_gid != groupid)) {
+           if ((grp = getgrgid(statbuf->st_gid)) != NULL)
+               strcpy(groupname, grp->gr_name);
+           else
+               sprintf(groupname, "%d", statbuf->st_gid);
+           groupid = statbuf->st_gid;
+           groupidknown = 1;
+       }
+       sprintf(cp, "%-8s ", groupname);
+       cp += strlen(cp);
+#endif
+       if (S_ISDEV(statbuf->st_mode))
+           sprintf(cp, "%3d,%-3d  ",
+                   statbuf->st_rdev >> 8, statbuf->st_rdev & 0xFF);
+       else
+           sprintf(cp, "%8ld ", (long) statbuf->st_size);
+       cp += strlen(cp);
+       sprintf(cp, "%-12s ", timestring(&statbuf->st_mtime));
+    }
+    fputs(buf, stdout);
+    fputs(name, stdout);
+#ifdef S_ISLNK
+    if ((flags & LSF_LONG) && S_ISLNK(statbuf->st_mode)) {
+       if ((len = readlink(name, buf, PATHLEN - 1)) >= 0) {
+           buf[len] = '\0';
+           printf(" -> %s", buf);
+       }
+    }
+#endif
+    fputc('\n', stdout);
+}
+
+void main(int argc, char *argv[])
+{
+    static char *def[1] =
+    {"."};
+
+    struct stat statbuf;
+    struct dirent *dp;
+    BOOL endslash;
+    DIR *dirp;
+    int i;
+    char *cp, *name, **newlist, fullname[PATHLEN];
+
+    if ((list = (char **) malloc(LISTSIZE * sizeof(char *))) == NULL) {
+       fprintf(stderr, "No memory for ls buffer\n");
+       return;
+    }
+    listsize = LISTSIZE;
+    listused = 0;
+    flags = 0;
+    for (--argc, ++argv; argc > 0 && argv[0][0] == '-'; --argc, ++argv) {
+       for (cp = *argv + 1; *cp; ++cp) {
+           switch (*cp) {
+           case 'h':
+               printf("Usage: ls [-dilfaouR] [pattern]\n");
+               return;
+           case 'd':
+               flags |= LSF_DIR;
+               break;
+           case 'i':
+               flags |= LSF_INODE;
+               break;
+           case 'l':
+               flags |= LSF_LONG;
+               break;
+           case 'f':
+               flags |= LSF_FILE;
+               break;
+           case 'a':
+               flags |= LSF_ALL;
+               break;
+           case 'o':
+               flags |= LSF_OCT;
+               break;
+           case 'u':
+               flags |= LSF_UNSORT;
+               break;
+           case 'R':
+               flags |= LSF_DOWN;
+               break;
+           default:
+               fprintf(stderr, "Unknown option -%c\n", *cp);
+               return;
+           }
+       }
+    }
+    if (argc == 0) {
+       argc = 1;
+       argv = def;
+    }
+    if (argc > 1)
+       flags |= LSF_MULT;
+    while (--argc >= 0) {
+       name = *argv++;
+       endslash = (*name && (name[strlen(name) - 1] == '/'));
+       if (LSTAT(name, &statbuf) < 0) {
+           perror(name);
+           continue;
+       }
+       if ((flags & LSF_DIR) || (!S_ISDIR(statbuf.st_mode))) {
+           lsfile(name, &statbuf, flags);
+           continue;
+       }
+       /* Do all the files in a directory. */
+       if ((dirp = opendir(name)) == NULL) {
+           perror(name);
+           continue;
+       }
+       if (flags & LSF_MULT)
+           printf("\n%s:\n", name);
+       while ((dp = readdir(dirp)) != NULL) {
+           if (dp->d_name[0] == '\0')
+               continue;
+           if (!(flags & LSF_ALL) && dp->d_name[0] == '.')
+               continue;
+           fullname[0] = '\0';
+           if ((*name != '.') || (name[1] != '\0')) {
+               strcpy(fullname, name);
+               if (!endslash)
+                   strcat(fullname, "/");
+           }
+           strcat(fullname, dp->d_name);
+           if (listused >= listsize) {
+               newlist = realloc(list,
+                           ((sizeof(char **)) * (listsize + LISTSIZE)));
+               if (newlist == NULL) {
+                   fprintf(stderr, "No memory for ls buffer\n");
+                   break;
+               }
+               list = newlist;
+               listsize += LISTSIZE;
+           }
+           if ((list[listused] = strdup(fullname)) == NULL) {
+               fprintf(stderr, "No memory for filenames\n");
+               break;
+           }
+           listused++;
+       }
+       closedir(dirp);
+       /* Sort the files. */
+       if (!(flags & LSF_UNSORT))
+           qsort((char *) list, listused,
+                 sizeof(char *), namesort);           /**/
+               /* Now finally list the filenames. */
+       for (i = 0; i < listused; i++, free(name)) {
+           name = list[i];
+           if (LSTAT(name, &statbuf) < 0) {
+               perror(name);
+               continue;
+           }
+           if (((flags & LSF_DIR) && !S_ISDIR(statbuf.st_mode)) ||
+               ((flags & LSF_FILE) && S_ISDIR(statbuf.st_mode)))
+               continue;
+           if ((cp = strrchr(name, '/')) != 0)
+               ++cp;
+           else
+               cp = name;
+           lsfile(cp, &statbuf, flags);
+       }
+       listused = 0;
+    }
+    fflush(stdout);
+}
+
diff --git a/Applications/util/mkdir.c b/Applications/util/mkdir.c
new file mode 100644 (file)
index 0000000..ea7209f
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned short newmode;
+
+int make_dir(const char *name, int f)
+{
+    char *line;
+    char iname[256];
+
+    int l = strlen(name) - 1;
+
+    /* FIXME: Size check ! */
+    strcpy(iname, name);
+    if (l && iname[l] == '/')
+        iname[l] = 0;
+    if (((line = rindex(iname, '/')) != NULL) && f) {
+       while ((line > iname) && (*line == '/'))
+           --line;
+       line[1] = 0;
+       make_dir(iname, 1);
+    }
+    if (mkdir(name, newmode) && !f)
+       return (1);
+    else
+       return (0);
+}
+
+
+int main(int argc, char *argv[])
+{
+    int i, parent = 0, er = 0;
+
+    if ((argv[1][0] == '-') && (argv[1][1] == 'p'))
+       parent = 1;
+
+    newmode = 0777 & ~umask(0);
+
+    for (i = parent + 1; i < argc; i++) {
+       if (argv[i][0] != '-') {
+
+           if (make_dir(argv[i], parent)) {
+               fprintf(stderr, "mkdir: cannot create directory %s\n", argv[i]);
+               er = 1;
+           }
+       } else {
+           fprintf(stderr, "mkdir: usage error\n");
+           exit(1);
+       }
+    }
+    return er;
+}
diff --git a/Applications/util/mkfs.c b/Applications/util/mkfs.c
new file mode 100644 (file)
index 0000000..0b6e252
--- /dev/null
@@ -0,0 +1,175 @@
+/**************************************************
+UZI (Unix Z80 Implementation) Utilities:  mkfs.c
+***************************************************/
+
+/* This utility creates an UZI file system for a defined block device.
+ * the format is:
+ *                  mkfs device isize fsize
+ * where: device is the logical block on which to install a filesystem
+ *        isize is the number of 512-byte blocks (less two reserved for
+ *            system use) to use for storing 64-byte i-nodes
+ *        fsize is the total number of 512-byte blocks to assign to the
+ *            filesystem.  Space available for storage of data is therefore
+ *            fsize-isize blocks.
+ *
+ * Revisions:
+ *   Based on UZI280 version (minor changes from original UZI.  HFB
+ *   Modified for use under UZI.                                HP
+ */
+
+#include <stdio.h>
+#include <unix.h>
+
+long lseek(uchar, long, uchar);
+
+int dev;
+
+direct dirbuf[32] = { ROOTINODE, ".", ROOTINODE, ".." };
+struct dinode inode[8];
+struct filesys fs_tab;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+    uint16 fsize, isize;
+    struct stat statbuf;
+    int atoi(), yes(), stat(), open();
+
+    if (argc != 4) {
+       fprintf(stderr, "usage: mkfs device isize fsize\n");
+       exit(-1);
+    }
+
+    if (stat(argv[1], &statbuf) != 0) {
+        fprintf(stderr, "mkfs: can't stat %s\n", argv[1]);
+        exit(-1);
+    }
+    
+    if ((statbuf.st_mode & F_BDEV) != F_BDEV) {
+        fprintf(stderr, "mkfs: %s is not a block device\n", argv[1]);
+        exit(-1);
+    }
+
+    isize = (uint16) atoi(argv[2]);
+    fsize = (uint16) atoi(argv[3]);
+
+    if (fsize < 3 || isize < 2 || isize >= fsize) {
+       fprintf(stderr, "mkfs: bad parameter values\n");
+       exit(-1);
+    }
+
+    printf("Making filesystem on device %s with isize %u fsize %u. Confirm? ",
+          argv[1], isize, fsize);
+    if (!yes())
+       exit(-1);
+
+    dev = open(argv[1], O_RDWR);
+    if (dev < 0) {
+        fprintf(stderr, "mkfs: can't open device %s\n", argv[1]);
+        exit(-1);
+    }
+
+    mkfs(fsize, isize);
+
+    exit(0);
+}
+
+
+mkfs(fsize, isize)
+uint16 fsize, isize;
+{
+    uint16 j;
+    char *zeros;
+    char *zerobuf();
+
+    /* Zero out the blocks */
+    printf("Zeroizing i-blocks...\n");
+    zeros = zerobuf();         /* Get a zero filled buffer */
+
+#if 1
+    for (j = 0; j < fsize; ++j)
+       dwrite(j, zeros);
+#else
+    for (j = 0; j < isize; ++j)
+       dwrite(j, zeros);
+#endif
+
+    /* Initialize the super-block */
+    fs_tab.s_mounted = SMOUNTED;       /* Magic number */
+    fs_tab.s_isize = isize;
+    fs_tab.s_fsize = fsize;
+    fs_tab.s_nfree = 1;
+    fs_tab.s_free[0] = 0;
+    fs_tab.s_tfree = 0;
+    fs_tab.s_ninode = 0;
+    fs_tab.s_tinode = (8 * (isize - 2)) - 2;
+
+    /* Free each block, building the free list */
+
+    printf("Building free list...\n");
+    for (j = fsize - 1; j > isize; --j) {
+       if (fs_tab.s_nfree == 50) {
+           dwrite(j, (char *) &fs_tab.s_nfree);
+           fs_tab.s_nfree = 0;
+       }
+       ++fs_tab.s_tfree;
+       fs_tab.s_free[(fs_tab.s_nfree)++] = j;
+    }
+
+    /* The inodes are already zeroed out */
+    /* create the root dir */
+
+    inode[ROOTINODE].i_mode = F_DIR | (0777 & MODE_MASK);
+    inode[ROOTINODE].i_nlink = 3;
+    inode[ROOTINODE].i_size.o_blkno = 0;
+    inode[ROOTINODE].i_size.o_offset = 32;
+    inode[ROOTINODE].i_addr[0] = isize;
+
+    /* Reserve reserved inode */
+    inode[0].i_nlink = 1;
+    inode[0].i_mode = ~0;
+
+    printf("Writing initial inode and superblock...\n");
+
+    sync();
+    dwrite(2, (char *) inode);
+    dwrite(isize, (char *) dirbuf);
+
+    sync();
+    /* Write out super block */
+    dwrite(1, (char *) &fs_tab);
+
+    sync();
+    printf("Done.\n");
+}
+
+
+dwrite(blk, addr)
+uint16 blk;
+char *addr;
+{
+    int write();
+        
+    lseek(dev, blk * 512L, 0);
+    write(dev, addr, 512);
+}
+
+char *zerobuf()
+{
+    static char buf[512];
+    
+    blkclr(buf, 512);
+    return buf;
+}
+
+
+int yes()
+{
+    char line[20];
+
+    if (!fgets(line, sizeof(line), stdin) || (*line != 'y' && *line != 'Y'))
+       return (0);
+
+    return (1);
+}
diff --git a/Applications/util/mknod.c b/Applications/util/mknod.c
new file mode 100644 (file)
index 0000000..97a0794
--- /dev/null
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+
+int do_mknod(char *path, char *modes, char *devs)
+{
+    int mode;
+    int dev;
+
+    mode = -1;
+    sscanf(modes, "%o", &mode);
+    if (mode == -1) {
+        printf("mknod: bad mode\n");
+        return (-1);
+    }
+    
+    if (!S_ISFIFO(mode) && !S_ISDEV(mode)) {
+        printf("mknod: mode is not device/fifo\n");
+        return (-1);
+    }
+
+    if (sscanf(devs, "%d", &dev) != 1) {
+        printf("mknod: bad device\n");
+        return (-1);
+    }
+
+    if (mknod(path, mode, dev) != 0) {
+        perror("mknod");
+        return (-1);
+    }
+    return(0);
+}
+
+int main(int argc, char *argv[])
+{
+    if (argc != 4) {
+        printf("usage: mknod path modes devs\n");
+        return 1;
+    }
+    return do_mknod(argv[1], argv[2], argv[3]);
+}
diff --git a/Applications/util/more.c b/Applications/util/more.c
new file mode 100644 (file)
index 0000000..f59f358
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int more(FILE *fp);
+
+int main(int argc, char *argv[])
+{
+    FILE *fp;
+    char *name;
+    int  next;
+
+    if (argc == 1) {
+
+        next = dup(0);
+        close(0);
+        name = getenv("CTTY");
+        if (!name) {
+            fprintf(stderr, "%s: CTTY not set\n", argv[0]);
+            return -1;
+        }
+        if (open(name, O_RDWR) == 0) {
+           fp = fdopen(next, "r");
+            if (fp) more(fp);
+        } else {
+           perror("more (CTTY)");
+       }
+
+    } else while (argc-- > 1) {
+
+       name = *(++argv);
+
+       fp = fopen(name, "r");
+       if (fp == NULL) {
+           perror(name);
+           return 1;
+       }
+       
+       printf("<< %s >>\n", name);
+       next = more(fp);
+       fclose(fp);
+       if (!next) break;
+    }
+    
+    return 0;
+}
+
+int more(FILE *fp)
+{
+    int  ch, line, col;
+    char buf[80];
+
+    line = 1;
+    col = 0;
+
+    while ((ch = fgetc(fp)) != EOF) {
+       switch (ch) {
+       case '\r':
+           col = 0;
+           break;
+
+       case '\n':
+           line++;
+           col = 0;
+           break;
+
+       case '\t':
+           col = ((col + 1) | 0x07) + 1;
+           break;
+
+       case '\b':
+           if (col > 0) --col;
+           break;
+
+       default:
+           col++;
+       }
+
+       putchar(ch);
+       if (col >= 80) {
+           col -= 80;
+           ++line;
+       }
+       if (line < 24)
+           continue;
+
+       if (col > 0)
+           putchar('\n');
+
+       printf("--More--");
+           fflush(stdout);
+
+       if (read(0, buf, sizeof(buf)) < 0) {
+           return 0;
+       }
+       ch = buf[0];
+       if (ch == ':')
+           ch = buf[1];
+
+       switch (ch) {
+       case 'N':       /* next file */
+       case 'n':
+           return 1;
+
+       case 'Q':       /* quit */
+       case 'q':
+           return 0;
+       }
+
+       col = 0;
+       line = 1;
+    }
+
+    return 1;
+}
diff --git a/Applications/util/mount.c b/Applications/util/mount.c
new file mode 100644 (file)
index 0000000..72e4693
--- /dev/null
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+char tmp[256];
+
+int lsmtab(void)
+{
+    FILE *f;
+    static char dev[20], mntpt[20], fstype[20], rwflag[20];
+    
+    f = fopen("/etc/mtab", "r");
+    if (f) {
+        while (fgets(tmp, 256, f)) {
+            sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag);
+            if (strcmp(fstype, "swap") == 0)
+                printf("%s is swapspace\n", dev);
+            else
+                printf("%s mounted on %s read-%s\n", dev, mntpt,
+                       (strcmp(rwflag, "ro") == 0) ? "only" : "write");
+        }
+        fclose(f);
+    }
+    
+    return 0;
+}
+
+int add2mtab(char *dev, char *mntpt, char *fstype, char *rwflag)
+{
+    FILE *inpf, *outf;
+    char *tmp_fname;
+
+    if ((tmp_fname = tmpnam(NULL)) == NULL) {
+        perror("Error getting temporary file name");
+        exit(1);
+    }
+    inpf = fopen("/etc/mtab", "r");
+    outf = fopen(tmp_fname, "w");
+    if (!outf) {
+        perror("Can't create temporary file");
+        exit(1);
+    }
+    if (inpf) {
+        while (fgets(tmp, 255, inpf)) {
+            fprintf(outf, "%s", tmp);
+        }
+        fclose(inpf);
+    }
+    fprintf(outf, "%s %s %s %s\n", dev, mntpt, fstype, rwflag);
+    fclose(outf);
+    if (inpf && unlink("/etc/mtab") < 0) {
+        perror("Can't delete old /etc/mtab file");
+        exit(1);
+    }
+    if (rename(tmp_fname, "/etc/mtab") < 0) {
+        perror("Error installing /etc/mtab");
+        exit(1);
+    }
+    return 0;
+}
+
+main(int argc, char *argv[])
+{
+    if (argc == 1) {
+        lsmtab();
+        return 0;
+    }
+
+    if (argc != 3) {
+        printf("usage: mount device path\n");
+        return 1;
+    }
+
+    if (mount(argv[1], argv[2], 0) == 0) {
+        add2mtab(argv[1], argv[2], "uzi", "rw");
+    } else {
+        perror("mount");
+        return 1;
+    }
+    return 0;
+}
diff --git a/Applications/util/mv.c b/Applications/util/mv.c
new file mode 100644 (file)
index 0000000..f3bffef
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Most simple built-in commands are here.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <errno.h>
+
+typedef unsigned char BOOL;
+
+#define FALSE 0
+#define TRUE  1
+
+#define PATHLEN  512
+
+        
+BOOL intflag;
+
+#define BUF_SIZE 4096
+
+/*
+ * Return TRUE if a filename is a directory.
+ * Nonexistant files return FALSE.
+ */
+BOOL isadir(char *name)
+{
+    struct stat statbuf;
+
+    if (stat(name, &statbuf) < 0)
+       return FALSE;
+
+    return S_ISDIR(statbuf.st_mode);
+}
+
+/*
+ * Copy one file to another, while possibly preserving its modes, times,
+ * and modes.  Returns TRUE if successful, or FALSE on a failure with an
+ * error message output.  (Failure is not indicted if the attributes cannot
+ * be set.)
+ */
+BOOL copyfile(char *srcname, char *destname, BOOL setmodes)
+{
+    int rfd;
+    int wfd;
+    int rcc;
+    int wcc;
+    char *bp;
+    char *buf;
+    struct stat statbuf1;
+    struct stat statbuf2;
+    struct utimbuf times;
+
+    if (stat(srcname, &statbuf1) < 0) {
+       perror(srcname);
+       return FALSE;
+    }
+
+    if (stat(destname, &statbuf2) < 0) {
+       statbuf2.st_ino = -1;
+       statbuf2.st_dev = -1;
+    }
+
+    if ((statbuf1.st_dev == statbuf2.st_dev) &&
+       (statbuf1.st_ino == statbuf2.st_ino)) {
+       fprintf(stderr, "Copying file \"%s\" to itself\n", srcname);
+       return FALSE;
+    }
+
+    rfd = open(srcname, 0);
+    if (rfd < 0) {
+       perror(srcname);
+       return FALSE;
+    }
+
+    wfd = creat(destname, statbuf1.st_mode);
+    if (wfd < 0) {
+       perror(destname);
+       close(rfd);
+       return FALSE;
+    }
+
+    buf = malloc(BUF_SIZE);
+    if (buf == NULL) {
+        fprintf(stderr, "Out of memory.\n");
+        goto error_exit;
+    }
+    while ((rcc = read(rfd, buf, BUF_SIZE)) > 0) {
+       bp = buf;
+       while (rcc > 0) {
+           wcc = write(wfd, bp, rcc);
+           if (wcc < 0) {
+               perror(destname);
+               goto error_exit;
+           }
+           bp += wcc;
+           rcc -= wcc;
+       }
+    }
+
+    if (rcc < 0) {
+       perror(srcname);
+       goto error_exit;
+    }
+
+    close(rfd);
+    if (close(wfd) < 0) {
+       perror(destname);
+       return FALSE;
+    }
+
+    if (setmodes) {
+       chmod(destname, statbuf1.st_mode);
+
+       chown(destname, statbuf1.st_uid, statbuf1.st_gid);
+
+       times.actime = statbuf1.st_atime;
+       times.modtime = statbuf1.st_mtime;
+
+       utime(destname, &times);
+    }
+
+    return TRUE;
+
+
+  error_exit:
+    close(rfd);
+    close(wfd);
+
+    return FALSE;
+}
+
+/*
+ * Build a path name from the specified directory name and file name.
+ * If the directory name is NULL, then the original filename is returned.
+ * The built path is in a static area, and is overwritten for each call.
+ */
+char *buildname(char *dirname, char *filename)
+{
+    char *cp;
+    /* FIXME: length check */
+    static char buf[PATHLEN];
+
+    if ((dirname == NULL) || (*dirname == '\0'))
+       return filename;
+
+    cp = strrchr(filename, '/');
+    if (cp)
+       filename = cp + 1;
+
+    strcpy(buf, dirname);
+    strcat(buf, "/");
+    strcat(buf, filename);
+
+    return buf;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int  dirflag;
+    char *srcname;
+    char *destname;
+    char *lastarg;
+
+    lastarg = argv[argc - 1];
+
+    dirflag = isadir(lastarg);
+
+    if ((argc > 3) && !dirflag) {
+       fprintf(stderr, "%s: not a directory\n", lastarg);
+       return 1;
+    }
+
+    while (argc-- > 2) {
+       srcname = *(++argv);
+       if (access(srcname, 0) < 0) {
+           perror(srcname);
+           continue;
+       }
+
+       destname = lastarg;
+       if (dirflag)
+           destname = buildname(destname, srcname);
+
+       if (rename(srcname, destname) >= 0)
+           continue;
+
+       if (errno != EXDEV) {
+           perror(destname);
+           continue;
+       }
+
+       if (!copyfile(srcname, destname, TRUE))
+           continue;
+
+       if (unlink(srcname) < 0)
+           perror(srcname);
+    }
+
+    return 0;
+}
diff --git a/Applications/util/od.c b/Applications/util/od.c
new file mode 100644 (file)
index 0000000..6d20aaf
--- /dev/null
@@ -0,0 +1,308 @@
+/* od - octal dump                Author: Andy Tanenbaum */
+/* Adapted to UZI180 by H. Peraza                         */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int  bflag, cflag, dflag, oflag, xflag, hflag, vflag;
+int  linenr, width, state, ever;
+int  prevwds[8];
+long off;
+char buf[512], buffer[BUFSIZ];
+int  next;
+int  bytespresent;
+
+
+int  main(int argc, char **argv);
+long offset(int argc, char *argv[], int k);
+void dumpfile(void);
+void wdump(short *words, int k, int radix);
+void bdump(char bytes[16], int k, int c);
+void byte(int val, int c);
+int  getwords(short **words);
+int  same(short *w1, int *w2);
+void outword(int val, int radix);
+void outnum(int num, int radix);
+void addrout(long l);
+char hexit(int k);
+void usage(void);
+
+
+
+long offset(int argc, char *argv[], int k)
+{
+    int dot, radix;
+    char *p, c;
+    long val;
+
+    /* See if the offset is decimal. */
+    dot = 0;
+    p = argv[k];
+    while (*p)
+       if (*p++ == '.') dot = 1;
+
+    /* Convert offset to binary. */
+    radix = (dot ? 10 : 8);
+    val = 0;
+    p = argv[k];
+    if (*p == '+') p++;
+    while (*p != 0 && *p != '.') {
+       c = *p++;
+       if (c < '0' || c > '9') {
+           printf("Bad character in offset: %c\n", c);
+           exit(1);
+       }
+       val = (long) radix * val + (long) (c - '0');
+    }
+
+    p = argv[k + 1];
+    if (k + 1 == argc - 1 && *p == 'b') val = 512L * val;
+
+    return(val);
+}
+
+
+void dumpfile(void)
+{
+    int k;
+    short *words;
+
+    while ((k = getwords(&words))) {   /* 'k' is # bytes read */
+       if (!vflag) {           /* ensure 'lazy' evaluation */
+           if (k == 16 && ever == 1 && same(words, prevwds)) {
+               if (state == 0) {
+                   printf("*\n");
+                   state = 1;
+                   off += 16L;
+                   continue;
+               } else if (state == 1) {
+                   off += 16L;
+                   continue;
+               }
+           }
+       }
+       addrout(off);
+       off += (long) k;
+       state = 0;
+       ever = 1;
+       linenr = 1;
+       if (oflag) wdump(words, k, 8);
+       if (dflag) wdump(words, k, 10);
+       if (xflag) wdump(words, k, 16);
+       if (cflag) bdump((char *)words, k, (int)'c');
+       if (bflag) bdump((char *)words, k, (int)'b');
+       for (k = 0; k < 8; k++) prevwds[k] = words[k];
+       for (k = 0; k < 8; k++) words[k] = 0;
+    }
+}
+
+
+void wdump(short *words, int k, int radix)
+{
+    int i;
+
+    if (linenr++ != 1) printf("       ");
+    for (i = 0; i < (k + 1) / 2; i++)
+       outword(words[i] & 0xFFFF, radix);
+    printf("\n");
+}
+
+
+void bdump(char bytes[16], int k, int c)
+{
+    int i;
+
+    if (linenr++ != 1) printf("       ");
+    for (i = 0; i < k; i++)
+       byte(bytes[i] & 0377, c);
+    printf("\n");
+}
+
+void byte(int val, int c)
+{
+    if (c == 'b') {
+       printf(" ");
+       outnum(val, 7);
+       return;
+    }
+    if (val == 0)
+       printf("  \\0");
+    else if (val == '\b')
+       printf("  \\b");
+    else if (val == '\f')
+       printf("  \\f");
+    else if (val == '\n')
+       printf("  \\n");
+    else if (val == '\r')
+       printf("  \\r");
+    else if (val == '\t')
+       printf("  \\t");
+    else if (val >= ' ' && val < 0177)
+       printf("   %c", val);
+    else {
+       printf(" ");
+       outnum(val, 7);
+    }
+}
+
+
+int getwords(short **words)
+{
+    int count;
+
+    if (next >= bytespresent) {
+       bytespresent = read(0, buf, 512);
+       next = 0;
+    }
+    if (next >= bytespresent) return(0);
+    *words = (short *) &buf[next];
+    if (next + 16 <= bytespresent)
+       count = 16;
+    else
+       count = bytespresent - next;
+
+    next += count;
+
+    return(count);
+}
+
+int same(short *w1, int *w2)
+{
+    int i;
+
+    i = 8;
+    while (i--)
+       if (*w1++ != *w2++) return(0);
+
+    return(1);
+}
+
+void outword(int val, int radix)
+{
+    /* Output 'val' in 'radix' in a field of total size 'width'. */
+
+    int i = 4;
+
+    if (radix == 16) i = width - 4;
+    if (radix == 10) i = width - 5;
+    if (radix == 8)  i = width - 6;
+
+    if (i == 1)
+       printf(" ");
+    else if (i == 2)
+       printf("  ");
+    else if (i == 3)
+       printf("   ");
+    else if (i == 4)
+       printf("    ");
+
+    outnum(val, radix);
+}
+
+
+void outnum(int num, int radix)
+{
+    /*  Output a number with all leading 0s present.  Octal is 6 places,
+     *  decimal is 5 places, hex is 4 places.
+     */
+    unsigned val;
+
+    val = (unsigned) num;
+    if (radix == 8)
+       printf ("%06o", val);
+    else if (radix == 10)
+       printf ("%05u", val);
+    else if (radix == 16)
+       printf ("%04x", val);
+    else if (radix == 7) {
+       /* special case */
+       printf ("%03o", val);
+    }
+}
+
+
+void addrout(long l)
+{
+    if (hflag == 0) {
+       printf("%07lo", l);
+    } else {
+       printf("%07lx", l);
+    }
+}
+
+
+void usage(void)
+{
+    fprintf(stderr, "Usage: od [-bcdhovx] [file] [ [+] offset [.] [b] ]\n");
+    exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+    int k, flags;
+    char *p;
+
+    /* Process flags */
+    setbuf(stdout, buffer);
+    flags = 0;
+    p = argv[1];
+    if (argc > 1 && *p == '-') {
+       /* Flags present. */
+       flags++;
+       p++;
+       while (*p) {
+           switch (*p) {
+               case 'b': bflag++; break;
+               case 'c': cflag++; break;
+               case 'd': dflag++; break;
+               case 'h': hflag++; break;
+               case 'o': oflag++; break;
+               case 'v': vflag++; break;       
+               case 'x': xflag++; break;
+               default:  usage();
+           }
+           p++;
+       }
+    } else {
+       oflag = 1;
+    }
+
+    if ((bflag | cflag | dflag | oflag | xflag) == 0) oflag = 1;
+    k = (flags ? 2 : 1);
+    if (bflag | cflag) {
+       width = 8;
+    } else if (oflag) {
+       width = 7;
+    } else if (dflag) {
+       width = 6;
+    } else {
+       width = 5;
+    }
+
+    /* Process file name, if any. */
+    p = argv[k];
+    if (k < argc && *p != '+') {
+       /* Explicit file name given. */
+       close(0);
+       if (open(argv[k], O_RDONLY) != 0) {
+           fprintf(stderr, "od: cannot open %s\n", argv[k]);
+           exit(1);
+       }
+       k++;
+    }
+
+    /* Process offset, if any. */
+    if (k < argc) {
+       /* Offset present. */
+       off = offset(argc, argv, k);
+       off = (off / 16L) * 16L;
+       lseek(0, off, SEEK_SET);
+    }
+
+    dumpfile();
+    addrout(off);
+    printf("\n");
+
+    return(0);
+}
diff --git a/Applications/util/passwd.c b/Applications/util/passwd.c
new file mode 100644 (file)
index 0000000..7ca6e0a
--- /dev/null
@@ -0,0 +1,140 @@
+/* passwd.c
+ * description:  change user password
+ * author:      Shane Kerr <kerr@wizard.net>
+ * copyright:   1998 by Shane Kerr <kerr@wizard.net>, under terms of GPL
+ */  
+    
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <time.h>
+    
+/* maximum allowed errors */ 
+#define MAX_FAILURE 5
+    
+/* valid characters for a salt value */ 
+static char salt_char[] =
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+char nbuf1[128], nbuf2[128];
+
+int time_zone = 0;
+
+int main(int argc, char *argv[])
+{
+    char *s, *pbuf, *tmp_fname, *pwf = "/etc/passwd";
+    char salt[3];
+    int  n, failure_cnt, uid, gid;
+    struct passwd *pwd;
+    FILE * passwd_fp;
+    time_t now;
+    long   lnow;
+
+    umask(022);
+
+    switch (argc) {
+    case 1:
+       if ((pwd = getpwuid(getuid())) == NULL) {
+           fprintf(stderr, "%s: error reading password file\n", argv[0]);
+           return 1;
+       }
+       break;
+
+    case 2:
+       if ((pwd = getpwnam(argv[1])) == NULL) {
+           fprintf(stderr, "%s: unknown user %s\n", argv[0], argv[1]);
+           return 1;
+       }
+       if ((getuid() != 0) && (getuid() != pwd->pw_uid)) {
+           fprintf(stderr, "You may not change the password for %s.\n",
+                   argv[1]);
+           return 1;
+       }
+       break;
+
+    default:
+       fprintf(stderr, "usage: %s [name]\n", argv[0]);
+       return 1;
+    }
+
+    printf("Changing password for %s\n", pwd->pw_name);
+    if ((getuid() != 0) && (pwd->pw_passwd[0] != 0)) {
+       pbuf = getpass("Old password: ");
+       salt[0] = pwd->pw_passwd[0];
+       salt[1] = pwd->pw_passwd[1];
+       salt[2] = 0;
+       if (strcmp(crypt(pbuf, salt), pwd->pw_passwd)) {
+           fprintf(stderr, "Incorrect password for %s\n", pwd->pw_name);
+           return 1;
+       }
+       memset(pbuf, 0, strlen(pbuf));
+    }
+    failure_cnt = 0;
+    for (;;) {
+       pbuf = getpass("New password: ");
+       strcpy(nbuf1, pbuf);
+       pbuf = getpass("Re-enter new password: ");
+       strcpy(nbuf2, pbuf);
+       if (strcmp(nbuf1, nbuf2) == 0) {
+           /* need to create a tmp file for the new password */ 
+           if ((tmp_fname = tmpnam(NULL)) == NULL) {
+               perror("Error getting temporary file name");
+               return 1;
+           }
+           if ((passwd_fp = fopen(tmp_fname, "w")) == NULL) {
+               perror(tmp_fname);
+               return 1;
+           }
+           
+           /* save off our UID */ 
+           uid = pwd->pw_uid;
+           gid = pwd->pw_gid;
+           time(&now);
+           salt[0] = salt_char[(now) & 0x3F];
+           salt[1] = salt_char[(now >> 6) & 0x3F];
+           salt[2] = 0;
+           s = crypt(nbuf1, salt);
+           
+           /* save entries to the new file */ 
+           setpwent();
+           for (n = 0; (pwd = getpwent()) != NULL; ++n) {
+               if (pwd->pw_uid == uid && pwd->pw_gid == gid)
+                   pwd->pw_passwd = s;
+               if (putpwent(pwd, passwd_fp) == -1) {
+                   perror("Error writing password file");
+                   return 1;
+               }
+           }
+           endpwent();
+           
+           /* update the file and move it into position */ 
+           fclose(passwd_fp);
+           if (n < 1) {
+               fprintf(stderr, "Can't rewrite %s\n", pwf);
+           }
+           strcpy(nbuf2, pwf);
+           strcat(nbuf2, "~");
+           unlink(nbuf2);
+           if (rename(pwf, nbuf2) < 0) {
+               perror("Error renaming old password file");
+               return 1;
+           }
+           if (rename(tmp_fname, pwf) < 0) {
+               perror("Error installing new password file");
+               return 1;
+           }
+           
+           /* celebrate our success */ 
+           printf("Password changed.\n");
+           return 0;
+       }
+       if (++failure_cnt >= MAX_FAILURE) {
+           fprintf(stderr, "The password for %s is unchanged.\n",
+                   pwd->pw_name);
+           return 1;
+       }
+       fprintf(stderr, "They don't match; try again.\n");
+    }
+}
diff --git a/Applications/util/patchcpm.c b/Applications/util/patchcpm.c
new file mode 100644 (file)
index 0000000..fe3b408
--- /dev/null
@@ -0,0 +1,93 @@
+/***************************************************************
+ * Utility to patch CP/M executable files as required by UZI's *
+ * CP/M emulator. Copyright (C) 2000, 2001, Hector Peraza.     *
+ ***************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+off_t tell(int fd)
+{
+  return lseek(fd, 0L, 0);
+}
+
+int main(int argc, char *argv[]) 
+{
+  int  fd;
+  long fsize;
+  unsigned char b1, b2, b3, bfr[14];
+
+
+  if (argc != 2) {
+    fprintf(stderr, "usage: %s filename\n", argv[0]);
+    return 1;
+  }
+
+  fd = open(argv[1], O_RDWR);
+  if (fd < 0) {
+    fprintf(stderr, "%s: can't open file %s\n", argv[0], argv[1]);
+    return 1;
+  }
+
+  if (read(fd, bfr, 3) != 3) {
+    fprintf(stderr, "%s: read error from %s\n", argv[0], argv[1]);
+    return 1;
+  }
+
+  b1 = bfr[0];
+  b2 = bfr[1];
+  b3 = bfr[2];
+
+  if (b1 == 0xc3) {  /* jp already there */
+    printf("%s: no patch needed\n", argv[0]);
+    close(fd);
+    return 0;
+  }
+
+  lseek(fd, 0L, SEEK_END);
+  fsize = tell(fd);
+
+  bfr[0] = 0x21;    /* ld hl,100h */
+  bfr[1] = 0x00;
+  bfr[2] = 0x01;
+  
+  bfr[3] = 0x36;    /* ld (hl),b1 */
+  bfr[4] = b1;
+  bfr[5] = 0x23;    /* inc hl */
+
+  bfr[6] = 0x36;    /* ld (hl),b2 */
+  bfr[7] = b2;
+  bfr[8] = 0x23;    /* inc hl */
+
+  bfr[9] = 0x36;    /* ld (hl),b3 */
+  bfr[10] = b3;
+
+  bfr[11] = 0xc3;   /* jp 100h */
+  bfr[12] = 0x00;
+  bfr[13] = 0x01;
+
+  if (write(fd, bfr, 14) != 14) {
+    fprintf(stderr, "%s: file write error\n", argv[0]);
+    return -1;
+  }
+
+  lseek(fd, 0L, SEEK_SET);
+  if (tell(fd) != 0L) {
+    fprintf(stderr, "%s: seek error\n", argv[0]);
+    return -1;
+  }
+
+  bfr[0] = 0xc3;    /* jp instruction to our patching code */
+  bfr[1] = (fsize + 0x100) & 0xff;
+  bfr[2] = ((fsize + 0x100) >> 8) & 0xff;
+
+  if (write(fd, bfr, 3) != 3) {
+    fprintf(stderr, "%s: file write error\n", argv[0]);
+    return -1;
+  }
+
+  close(fd);
+
+  return 0;
+}
diff --git a/Applications/util/printenv.c b/Applications/util/printenv.c
new file mode 100644 (file)
index 0000000..ee6e805
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+int main(int argc, char *argv[])
+{
+    char **env;
+    extern char **environ;
+    int len;
+
+    env = environ;
+
+    if (argc == 1) {
+       while (*env)
+           printf("%s\n", *env++);
+       return 0;
+    }
+
+    len = strlen(argv[1]);
+    while (*env) {
+       if ((strlen(*env) > len) && (env[0][len] == '=') &&
+           (memcmp(argv[1], *env, len) == 0)) {
+           printf("%s\n", &env[0][len + 1]);
+           return 0;
+       }
+       env++;
+    }
+    
+    return 1;
+}
diff --git a/Applications/util/prtroot.c b/Applications/util/prtroot.c
new file mode 100644 (file)
index 0000000..19dce5a
--- /dev/null
@@ -0,0 +1,71 @@
+/* printroot - print root device on stdout     Author: Bruce Evans */
+
+/* This program figures out what the root device is by doing a stat on it, and
+ * then searching /dev until it finds an entry with the same device number.
+ * A typical use (probably the only use) is in /etc/rc for initializing
+ * /etc/mtab, as follows:
+ *
+ *     /usr/bin/printroot >/etc/mtab
+ *
+ *  9 Dec 1989 - clean up for 1.5 - full prototypes (BDE)
+ * 15 Oct 1989 - avoid ACK cc bugs (BDE):
+ *             - sizeof "foo" is 2 (from wrong type char *) instead of 4
+ *             - char foo[10] = "bar"; allocates 4 bytes instead of 10
+ *  1 Oct 1989 - Minor changes by Andy Tanenbaum
+ *  5 Oct 1992 - Use readdir (kjb)
+ * 26 Nov 1994 - Flag -r: print just the root device (kjb)
+ * 19 May 2001  - Ported to UZI180
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#define DEV_PATH       "/dev/"
+#define MESSAGE                " / uzi rw\n"
+#define UNKNOWN_DEV    "/dev/unknown"
+#define ROOT           "/"
+
+int rflag;
+
+void done(const char *name, int status)
+{
+    write(1, name, strlen(name));
+    if (rflag) {
+       write(1, "\n", 1);
+       exit(status);
+    }
+    write(1, MESSAGE, sizeof(MESSAGE));
+
+    exit(status);
+}
+
+int main(int argc, const char *argv[])
+{
+    DIR *dp;
+    struct dirent *entry;
+    struct stat filestat, rootstat;
+    static char namebuf[sizeof(DEV_PATH) + MAXNAMLEN + 1];
+
+    rflag = (argc > 1 && strcmp(argv[1], "-r") == 0);
+
+    if (stat(ROOT, &rootstat) == 0
+       && (dp = opendir(DEV_PATH)) != (DIR *) NULL) {
+       while ((entry = readdir(dp)) != (struct dirent *) NULL) {
+           strcpy(namebuf, DEV_PATH);
+           strcat(namebuf, entry->d_name);
+           if (stat(namebuf, &filestat) != 0)
+               continue;
+           if (!S_ISBLK(filestat.st_mode))
+               continue;
+           if (filestat.st_rdev != rootstat.st_dev)
+               continue;
+           done(namebuf, 0);
+       }
+    }
+    done(UNKNOWN_DEV, 1);
+    return (0);                        /* not reached */
+}
+
diff --git a/Applications/util/ps.c b/Applications/util/ps.c
new file mode 100644 (file)
index 0000000..1b12ea2
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <pwd.h>
+#include <unix.h>
+
+#define        F_a     0x01            /* all users flag */
+#define        F_h     0x02            /* no header flag */
+#define        F_r     0x04            /* running only flag */
+#define        F_n     0x08            /* numeric output flag */
+
+int flags;
+
+char *mapstat(char s)
+{
+    switch (s) {
+       case P_ZOMBIE:
+       case P_ZOMBIE2: return "Defunct";
+       case P_FORKING: return "Forking";
+       case P_RUNNING: return "Running";
+       case P_READY:   return "Ready";
+       case P_SLEEP:   
+       case P_XSLEEP:  return "Sleeping";
+       case P_PAUSE:   return "Paused";
+       case P_WAIT:    return "Waiting";
+    }
+    return "?";
+}
+
+int do_ps(void)
+{
+    ptptr pp;
+    int i, j, uid, pfd, ptsize;
+    int open(), ioctl(), read(), close(), getuid();
+    struct passwd *pwd;
+    struct p_tab ptab[PTABSIZE];
+    char name[10], uname[20];
+
+    uid = getuid();
+
+    if ((pfd = open("/dev/proc", O_RDONLY)) < 0) {
+        perror("ps");
+        return 1;
+    }
+        
+    if (ioctl(pfd, 1, (char *) &ptsize) != 0) {
+        perror("ioctl");
+        close(pfd);
+        return 1;
+    }
+    
+    if (ptsize > PTABSIZE) ptsize = PTABSIZE;
+    
+    for (i = 0; i < ptsize; ++i) {
+        if (read(pfd, &ptab[i], sizeof(struct p_tab)) !=
+                                sizeof(struct p_tab)) {
+            fprintf(stderr, "ps: error reading from /dev/proc\n");
+            close(pfd);
+            return 1;
+        }
+    }
+    close(pfd);
+
+    if (!(flags & F_h)) {
+        if (flags & F_n)
+           printf("  PID\tUID\tSTAT\tWCHAN\tALARM\tCOMMAND\n");
+       else
+           printf("USER\t  PID\tSTAT\tWCHAN\tALARM\tCOMMAND\n");
+    }
+
+    for (pp = ptab, i = 0; i < ptsize; ++i, ++pp) {
+       if (pp->p_status == 0)
+           continue;
+
+       if ((flags & F_r) &&
+           (pp->p_status != P_RUNNING && pp->p_status != P_READY))
+           continue;
+           
+       if (!(flags & F_a) && (pp->p_uid != uid))
+           continue;
+
+        strncpy(name, pp->p_name, 8);
+        name[8] = '\0';
+
+        for (j = 0; j < 8; ++j) {
+            if (name[j] != 0)
+                if (name[j] < ' ') name[j] = '?';
+        }
+
+       if (flags & F_n) {
+           printf("%5d\t%-3d\t%s\t%04x\t%-5d\t%s\n",
+                  pp->p_pid, pp->p_uid,
+                  mapstat(pp->p_status), pp->p_wait, pp->p_alarm,
+                  name);
+       } else {
+           pwd = getpwuid(pp->p_uid);
+           if (pwd)
+               strcpy(uname, pwd->pw_name);
+           else
+               sprintf(uname, "%d", pp->p_uid);
+           printf("%s\t%5d\t%s\t%04x\t%-5d\t%s\n",
+                  uname, pp->p_pid,
+                  mapstat(pp->p_status), pp->p_wait, pp->p_alarm,
+                  name);
+       }
+    }
+
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int i;
+
+    flags = 0;
+    for (i = 1; i < argc; ++i) {
+       char *p = argv[i];
+
+       if (*p == '-') ++p;
+       while (*p)
+           switch (*p++) {
+               case 'a': flags |= F_a; break;
+               case 'h': flags |= F_h; break;
+               case 'r': flags |= F_r; break;
+               case 'n': flags |= F_n; break;
+               default:
+                   fprintf(stderr, "usage: ps [-][ahrn]\n");
+                   return 1;
+           }
+    }
+
+    return do_ps();
+}
diff --git a/Applications/util/pwd.c b/Applications/util/pwd.c
new file mode 100644 (file)
index 0000000..5375d23
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, const char *argv[])
+{
+    char buf[512];
+    
+    if (getcwd(buf, 512) == NULL) {
+        fprintf(stderr, "pwd: cannot get current directory\n");
+        return -1;
+    }
+    printf("%s\n", buf);
+    return 0;
+}
diff --git a/Applications/util/pwd.h b/Applications/util/pwd.h
new file mode 100644 (file)
index 0000000..ee0418a
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef        __PWD_H
+#define        __PWD_H
+
+#include <stdio.h>
+
+#ifndef _UID_T
+#define _UID_T
+typedef int uid_t;
+#endif
+
+#ifndef _GID_T
+#define _GID_T
+typedef int gid_t;
+#endif
+
+/* The passwd structure */
+struct passwd
+{
+  char *pw_name;               /* Username       */
+  char *pw_passwd;             /* Password       */
+  uid_t pw_uid;                        /* User ID        */
+  gid_t pw_gid;                        /* Group ID       */
+  char *pw_gecos;              /* Real name      */
+  char *pw_dir;                        /* Home directory */
+  char *pw_shell;              /* Shell program  */
+};
+
+
+extern int  setpwent(void);
+extern void endpwent(void);
+extern struct passwd *getpwent(void);
+
+extern int putpwent(struct passwd *, FILE *);
+extern int getpw(uid_t uid, char *buf);
+
+extern struct passwd *getpwuid(uid_t);
+extern struct passwd *getpwnam(char *);
+
+
+#endif /* pwd.h  */
diff --git a/Applications/util/rm.c b/Applications/util/rm.c
new file mode 100644 (file)
index 0000000..6fc4556
--- /dev/null
@@ -0,0 +1,28 @@
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+char *basename(char *name)
+{
+    char *base = rindex(name, '/');
+    return base ? base + 1 : name;
+}
+
+
+int main(int argc, const char *argv[])
+{
+    int i /*, recurse = 0, interact =0 */ ;
+    struct stat sbuf;
+
+    for (i = 1; i < argc; i++) {
+       if (argv[i][0] != '-') {
+           if (!lstat(argv[i], &sbuf)) {
+               if (unlink(argv[i])) {
+                   fprintf(stderr, "rm: could not remove %s\n", argv[i]);
+               }
+           }
+       }
+    }
+    return 0;
+}
diff --git a/Applications/util/rmdir.c b/Applications/util/rmdir.c
new file mode 100644 (file)
index 0000000..c0c702f
--- /dev/null
@@ -0,0 +1,47 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+unsigned short newmode;
+
+int remove_dir(char *name, int f)
+{
+    int er, era = 2;
+    char *line;
+    char *p = name + strlen(name) - 1;
+    while(p >= name && *p == '/')
+        *p-- = '\0';
+
+    while (((er = rmdir(name)) == 0)
+          && ((line = rindex(name, '/')) != NULL) && f) {
+       while ((line > name) && (*line == '/')) --line;
+       line[1] = 0;
+       era = 0;
+    }
+    return (er && era);
+}
+
+
+int main(int argc, char **argv)
+{
+    int i, parent = 0, er = 0;
+
+    if ((argv[1][0] == '-') && (argv[1][1] == 'p'))
+       parent = 1;
+
+    newmode = 0666 & ~umask(0);
+
+    for (i = parent + 1; i < argc; i++) {
+       if (argv[i][0] != '-') {
+           if (remove_dir(argv[i], parent)) {
+               fprintf(stderr, "rmdir: cannot remove directory %s\n", argv[i]);
+               er = 1;
+           }
+       } else {
+           fprintf(stderr, "rmdir: usage error\n");
+           exit(1);
+       }
+    }
+    return er;
+}
+
diff --git a/Applications/util/sleep.c b/Applications/util/sleep.c
new file mode 100644 (file)
index 0000000..802216f
--- /dev/null
@@ -0,0 +1,76 @@
+/* sleep - delay for a specified amount of time.
+   Copyright (C) 84, 91, 92, 93, 1994 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* The name by which this program was run. */
+char *program_name;
+
+static void usage(void)
+{
+    printf("Usage: %s number[h|m|s]\n", program_name);
+    exit(1);
+}
+
+unsigned int argdecode(char *s)
+{
+    unsigned int  value;
+    register char *p = s;
+    register char c;
+
+    value = 0;
+    while ((c = *p++) >= '0' && c <= '9')
+       value = value * 10L + (long) (c - '0');
+
+    switch (c) {
+    case 's':
+       break;
+    case 'm':
+       value *= 60L;
+       break;
+    case 'h':
+       value *= 60L * 60L;
+       break;
+    default:
+       p--;
+    }
+
+    if (*p) {
+       fprintf(stderr, "%s: invalid time interval `%s'\n", program_name, s);
+       exit(1);
+    }
+    return value;
+}
+
+void main(int argc, char *argv[])
+{
+    int i;
+    unsigned int seconds = 0;
+
+    program_name = argv[0];
+
+    if (argc == 1) {
+       usage();
+    }
+    for (i = 1; i < argc; i++)
+       seconds += argdecode(argv[i]);
+
+    sleep(seconds);
+    exit(0);
+}
+
diff --git a/Applications/util/ssh.c b/Applications/util/ssh.c
new file mode 100644 (file)
index 0000000..6399ac7
--- /dev/null
@@ -0,0 +1,166 @@
+/***************************************************
+ UZI (Unix Z80 Implementation) Utilities:  ssh.c
+  Simple Shell.  Copyright (C) 1998, Harold F. Bower
+
+ 15 Mar 1998 - Added Path searching from Minix.  HFB
+ 26 Sep 1999 - Added kill command                HP
+ 29 Sep 1999 - Added pwd and sync commands       HP
+ 04 Oct 1999 - Added umask command               HP
+ 27 MAy 2001 - Added simple support for env vars HP
+****************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern char **environ;      /* Location of Envp from executable Header */
+
+#define MAX_ARGS  10
+
+char buf[128];
+char eline[45];                    /* Line for Search command */
+
+char cmd[50], arg[MAX_ARGS][50];
+
+
+main(int argc, char *argval[])
+{
+    char  *path, *tp, *sp;     /* Pointers for Path Searching */
+    int   login_sh, pid, sig, stat, count, asis, i;
+    char  cprompt;
+    char  *home;
+    char  *argv[MAX_ARGS+1];
+
+    login_sh = 0;
+    if (argval[0][0] == '-') login_sh = 1;
+
+    signal(SIGINT, SIG_IGN);
+    signal(SIGQUIT, SIG_IGN);
+
+    if (login_sh) {
+       home = getenv("HOME");
+       if (!home) putenv("HOME=/");
+       chdir("/");
+    }
+
+    cprompt = (getuid() == 0) ? '#' : '$';
+
+    for (;;) {
+        cmd[0] = (char) 0;
+        for (i = 0; i < MAX_ARGS; i++) arg[i][0] = (char) 0;
+        do {
+            printf("ssh%c ", cprompt);
+            fgets(buf, 127, stdin);
+            if (feof(stdin)) return 0;     /* user typed ^D ? */
+            buf[strlen(buf) - 1] = '\0';   /* Strip newline from fgets */
+        }
+        while (buf[0] == (char) 0);
+        count = sscanf(buf, "%s %s %s %s %s %s %s %s %s %s %s",
+                            cmd,
+                            arg[0], arg[1], arg[2], arg[3], arg[4],
+                            arg[5], arg[6], arg[7], arg[8], arg[9]);
+
+        /* Check for User-Requested Exit back to Login Prompt */
+        if (strcmp(cmd, "exit") == 0)
+            return (0);                      /* Quit if requested */
+
+        /* Check for User request to change Current Working Directory */
+        else if (strcmp(cmd, "cd") == 0) {
+            stat = chdir(*arg[0] ? arg[0] : getenv("HOME"));
+            if (stat)
+                perror("cd");
+        }
+
+        else if (strcmp(cmd, "pwd") == 0) {
+            if (getcwd(buf, 128))
+                printf("%s\n", buf);
+            else
+                printf("pwd: cannot get current directory\n");
+        }
+        
+        else if (strcmp(cmd, "sync") == 0) {
+            sync();
+        }
+        
+        else if (strcmp(cmd, "umask") == 0) {
+            if (arg[0][0] == (char) 0) {
+                i = umask(0);
+                umask(i);
+                printf("%03o\n", i);
+            } else {
+                i = 0;
+                tp = arg[0];
+                while (*tp >= '0' && *tp <= '7')
+                    i = (i << 3) + *tp++ - '0';
+                if (*tp || (i & ~0777))
+                    printf("umask: bad mask value\n");
+                else
+                    umask(i);
+            }
+        }
+
+        /* Check for User request to kill a process */
+        else if (strcmp(cmd, "kill") == 0) {
+            if (arg[0][0] == '-') {
+                sig = atoi(&arg[0][1]);
+                pid = atoi(arg[1]);
+            } else {
+                sig = SIGINT;
+                pid = atoi(arg[0]);
+            }
+            if (pid == 0 || pid == 1) {
+                printf("kill: can't kill process %d\n", pid);
+            } else {
+                stat = kill(pid, sig);
+                if (stat)
+                    perror("kill");
+            }
+        }
+
+        /* Check for environmen variable assignment */
+        else if ((tp = strchr(cmd, '=')) != NULL) {
+            if (*(tp+1) == '\0') *tp = '\0';
+            putenv(cmd);
+        }
+
+        /* No built-in Command, Try to find Executable Command File */
+        else {
+            argv[0] = cmd;                  /* Build Argv Pointer Array */
+            for (i = 0; i < MAX_ARGS; ++i)
+               argv[i+1] = *arg[i] ? arg[i] : (char *) NULL;
+
+            if ((pid = fork()) == -1) {     /* Try to spawn new Process */
+                printf("ssh: can't fork\n");
+            } else {
+                if (pid == 0) {             /* Child is in context */
+                    signal(SIGINT, SIG_DFL);
+                    signal(SIGQUIT, SIG_DFL);
+                    /* Path search adapted from Univ of Washington's Minix */
+                    path = getenv("PATH");  /* Get base of path string, or NULL */
+                    eline[0] = '\0';
+                    sp = strchr(cmd, '/') ? "" : path;
+                    asis = *sp == '\0';
+                    while (asis || *sp != '\0') {
+                        asis = 0;
+                        tp = eline;
+                        for (; *sp != '\0'; tp++)
+                            if ((*tp = *sp++) == ':') {
+                                asis = *sp == '\0';
+                                break;
+                            }
+                        if (tp != eline)
+                            *tp++ = '/';
+                        for (i = 0; (*tp++ = cmd[i++]) != '\0'; )
+                            ;
+                        execve(eline, argv, environ);
+                    }
+                    printf("ssh: %s?\n", buf);      /* Say we can't exec */
+                    exit(1);
+                }                                   /* Parent is in context */
+                wait(0);                    /* Parent waits for completion */
+                kill(pid, SIGKILL);         /* then kills child process */
+            }
+        }
+    }
+}
diff --git a/Applications/util/su.c b/Applications/util/su.c
new file mode 100644 (file)
index 0000000..c8583f3
--- /dev/null
@@ -0,0 +1,97 @@
+/* su - become super-user              Author: Patrick van Kleef */
+/* Ported to UZI by Hector Peraza */
+
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* True if the invoker need not give a password. */
+#define privileged()   (getgid() == 0)
+
+static char *shell1 = "/bin/sh";
+static char *shell2 = "/usr/bin/sh";
+static char *shell3 = "/bin/ssh";
+
+static char USER[20], LOGNAME[25], HOME[100], SHELL[100];
+
+int main(int argc, char *argv[])
+{
+    register char *name, *password;
+    register struct passwd *pwd;
+    int  login_shell = 0;
+    char *shell, arg0[20];
+
+    if (argc > 1 && strcmp(argv[1], "-") == 0) {
+       login_shell = 1;        /* Read .profile */
+       argv[1] = argv[0];
+       argv++;
+       argc--;
+    }
+
+    if (argc > 1) {
+       if (argv[1][0] == '-') {
+           fprintf(stderr, "Usage: su [-] [user [shell-arguments ...]]\n");
+           exit(1);
+       }
+       name = argv[1];
+       argv[1] = argv[0];
+       argv++;
+    } else {
+       name = "root";
+    }
+
+    if ((pwd = getpwnam(name)) == 0) {
+       fprintf(stderr, "%s: user %s does not exist\n", argv[0], name);
+       exit(1);
+    }
+
+    if (!privileged() && 
+        strcmp(pwd->pw_passwd, crypt("", pwd->pw_passwd)) != 0) {
+       password = getpass("Password: ");
+       if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd))) {
+           fprintf(stderr, "%s: incorrect password\n", argv[0]);
+           exit(2);
+       }
+    }
+
+    if (login_shell) {
+       if ((shell = pwd->pw_shell)[0] == 0) shell = shell1;
+    } else {
+       if ((shell = getenv("SHELL")) == NULL) shell = shell1;
+    }
+
+    if (access(shell, 0) < 0) shell = shell2;
+    if (access(shell, 0) < 0) shell = shell3;
+
+    if ((argv[0] = strrchr(shell, '/')) == NULL)
+       argv[0] = shell;
+    else
+       argv[0]++;
+
+    if (login_shell) {
+       arg0[0] = '-';
+       strncpy(arg0 + 1, argv[0], sizeof(arg0) - 2);
+       arg0[sizeof(arg0) - 1] = 0;
+       argv[0] = arg0;
+       strcpy(USER, "USER=");
+       strcpy(USER + 5, name);
+       putenv(USER);
+       strcpy(LOGNAME, "LOGNAME=");
+       strcpy(LOGNAME + 8, name);
+       putenv(LOGNAME);
+       strcpy(SHELL, "SHELL=");
+       strcpy(SHELL + 6, shell);
+       putenv(SHELL);
+       strcpy(HOME, "HOME=");
+       strcpy(HOME + 5, pwd->pw_dir);
+       putenv(HOME);
+       chdir(pwd->pw_dir);
+    }
+    setgid(pwd->pw_gid);
+    setuid(pwd->pw_uid);
+    execve(shell, argv, environ);
+
+    fprintf(stderr, "%s: no shell\n", argv[0]);
+    return (3);
+}
diff --git a/Applications/util/sync.c b/Applications/util/sync.c
new file mode 100644 (file)
index 0000000..863d689
--- /dev/null
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+main(int argc, const char *argv[])
+{
+    return sync();
+}
diff --git a/Applications/util/termcap.c b/Applications/util/termcap.c
new file mode 100644 (file)
index 0000000..99c5489
--- /dev/null
@@ -0,0 +1,504 @@
+/* termcap - print termcap settings    Author: Terrence Holm */
+
+#include <termcap.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define  TC_BUFFER  1024       /* Size of termcap(3) buffer    */
+
+/****************************************************************/
+/*                                                             */
+/*    termcap  [ type ]                                                */
+/*                                                             */
+/*    Prints out all of the termcap capabilities as described  */
+/*    in termcap(4). If "type" is not supplied then $TERM is   */
+/*    used.                                                    */
+/*                                                             */
+/****************************************************************/
+
+int  main(int argc, char **argv);
+void Print(char *comment, char *name);
+void Error(char *message, char *arg);
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+    char *term;
+    char buffer[TC_BUFFER];
+
+    /*  Check for an argument  */
+
+    if (argc > 2)
+       Error("Usage: %s [type]\n", argv[0]);
+
+    if (argc == 2)
+       term = argv[1];
+    else
+       term = getenv("TERM");
+
+    if (term == NULL)
+       Error("termcap: $TERM is not defined\n", "");
+
+
+    /*  Read in the termcap entry  */
+
+    if (tgetent(buffer, term) != 1)
+       Error("termcap: No termcap entry for %s\n", term);
+
+
+    /*  Print out the entry's contents  */
+
+    printf("TERM = %s\n\n", term);
+
+    if (tgetflag("am") == 1)
+       printf("End of line wraps to next line   (am)\n");
+
+    if (tgetflag("bs") == 1)
+       printf("Ctrl/H performs a backspace      (bs)\n");
+
+    printf("Number of columns                (co) = %d\n", tgetnum("co"));
+    printf("Number of lines                  (li) = %d\n", tgetnum("li"));
+
+    Print("Clear to end of line", "ce");
+    Print("Clear to end of screen", "cd");
+    Print("Clear the whole screen", "cl");
+
+    Print("Start \"stand out\" mode", "so");
+    Print("End \"stand out\" mode", "se");
+    Print("Start underscore mode", "us");
+    Print("End underscore mode", "ue");
+    Print("Start blinking mode", "mb");
+    Print("Start bold mode", "md");
+    Print("Start reverse mode", "mr");
+    Print("Return to normal mode", "me");
+
+    Print("Scroll backwards", "sr");
+    Print("Cursor motion", "cm");
+
+    Print("Up one line", "up");
+    Print("Down one line", "do");
+    Print("Left one space", "le");
+    Print("Right one space", "nd");
+    Print("Move to top left corner", "ho");
+
+    Print("Generated by \"UP\"", "ku");
+    Print("Generated by \"DOWN\"", "kd");
+    Print("Generated by \"LEFT\"", "kl");
+    Print("Generated by \"RIGHT\"", "kr");
+    Print("Generated by \"HOME\"", "kh");
+    Print("Generated by \"END\"", "k0");
+    Print("Generated by \"PGUP\"", "k1");
+    Print("Generated by \"PGDN\"", "k2");
+    Print("Generated by numeric \"+\"", "k3");
+    Print("Generated by numeric \"-\"", "k4");
+    Print("Generated by numeric \"5\"", "k5");
+
+    return (0);
+}
+
+
+/****************************************************************/
+/*                                                             */
+/*     Print(comment, name)                                    */
+/*                                                             */
+/*             If a termcap entry exists for "name", then      */
+/*             print out "comment" and the entry. Control      */
+/*             characters are printed as ^x.                   */
+/*                                                             */
+/****************************************************************/
+
+void Print(comment, name)
+char *comment;
+char *name;
+{
+    char entry[50];
+    char *p = entry;
+
+    if (tgetstr(name, &p) == NULL)
+       return;
+
+    printf("%-32s (%s) = ", comment, name);
+
+    for (p = entry; *p != '\0'; ++p)
+       if (*p < ' ')
+           printf("^%c", *p + '@');
+       else if (*p == '\177')
+           printf("^?");
+       else
+           putchar(*p);
+
+    putchar('\n');
+}
+
+
+/****************************************************************/
+/*                                                             */
+/*     Error(message, arg)                                     */
+/*                                                             */
+/*             Printf the "message" and abort.                 */
+/*                                                             */
+/****************************************************************/
+
+void Error(message, arg)
+char *message;
+char *arg;
+{
+    fprintf(stderr, message, arg);
+    exit(1);
+}
+
+/****************************/
+
+/*#include <termcap_lib.c>*/
+/*
+ *     termcap.c       V1.1    20/7/87         agc     Joypace Ltd
+ *
+ *     Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
+ *     This file may be freely distributed provided that this notice
+ *     remains attached.
+ *
+ *     A public domain implementation of the termcap(3) routines.
+ *
+ *
+ *
+ *      Klamer Schutte       V1.2    Nov. 1988
+ *
+ *   - Can match multiple terminal names                [tgetent]
+ *   - Removal of **area assignments                    [tgetstr]
+ *
+ *      Terrence W. Holm     V1.3    May, Sep, Oct.  1988
+ *
+ *   - Correct when TERM != name and TERMCAP is defined         [tgetent]
+ *   - Correct the comparison for the terminal name     [tgetent]
+ *   - Correct the value of ^x escapes                  [tgetstr]
+ *   - Added %r to reverse row/column                   [tgoto]
+ *   - Fixed end of definition test                     [tgetnum/flag/str]
+ *
+ *      Terrence W. Holm     V1.4    Jan. 1989
+ *
+ *   - Incorporated Klamer's V1.2 fixes into V1.3
+ *   - Added %d, (old %d is now %2)                     [tgoto]
+ *   - Allow '#' comments in definition file            [tgetent]
+ */
+
+#include <termcap.h>
+#include <ctype.h>
+/*#include <stdlib.h>
+#include <stdio.h>*/
+#include <string.h>
+
+char *capab = (char *) NULL;   /* the capability itself */
+
+#if 0
+/*  The following are not yet used.  */
+extern short ospeed;           /* output speed */
+extern char PC;                        /* padding character */
+extern char *BC;               /* back cursor movement */
+extern char *UP;               /* up cursor movement */
+#endif
+
+
+/*
+ *     tgetent - get the termcap entry for terminal name, and put it
+ *     in bp (which must be an array of 1024 chars). Returns 1 if
+ *     termcap entry found, 0 if not found, and -1 if file not found.
+ */
+
+int tgetent(bp, name)
+char *bp;
+char *name;
+{
+    FILE *fp;
+    char *file;
+    char *term;
+    short len = strlen(name);
+
+    capab = bp;
+
+    /* If TERMCAP begins with a '/' then use TERMCAP as the path   */
+    /* Name of the termcap definitions file. If TERMCAP is a       */
+    /* Definition and TERM equals "name" then use TERMCAP as the   */
+    /* Definition. Otherwise use "/etc/termcap" as the path name.  */
+
+    if ((file = getenv("TERMCAP")) == (char *) NULL)
+       file = "/etc/termcap";
+    else if (*file != '/')
+       if ((term = getenv("TERM")) != (char *) NULL
+           && strcmp(term, name) == 0) {
+           *bp = '\0';
+           strncat(bp, file, 1023);
+           return (1);
+       } else
+           file = "/etc/termcap";
+
+    if ((fp = fopen(file, "r")) == (FILE *) NULL) {
+       capab = (char *) NULL;  /* no valid termcap  */
+       return (-1);
+    }
+    for (;;) {
+       /* Read in each definition */
+       int def_len = 0;
+       char *cp = bp;
+
+       do {
+           if (fgets(&bp[def_len], (unsigned int) (1024 - def_len), fp) ==
+               (char *) NULL) {
+               fclose(fp);
+               capab = (char *) NULL;  /* no valid termcap */
+               return (0);
+           }
+           def_len = strlen(bp) - 2;
+       } while (bp[def_len] == '\\');
+
+       while (isspace(*cp))
+           cp++;
+
+       /* Comment lines start with a '#'  */
+       if (*cp == '#')
+           continue;
+
+       /* See if any of the terminal names in this definition */
+       /* Match "name".                                       */
+
+       do {
+           if (strncmp(name, cp, len) == 0 &&
+               (cp[len] == '|' || cp[len] == ':')) {
+               fclose(fp);
+               return (1);
+           }
+           while ((*cp) && (*cp != '|') && (*cp != ':'))
+               cp++;
+       } while (*cp++ == '|');
+    }
+}
+
+
+/*
+ *     tgetnum - get the numeric terminal capability corresponding
+ *     to id. Returns the value, -1 if invalid.
+ */
+
+int tgetnum(id)
+char *id;
+{
+    register char *cp = capab;
+
+    if (cp == (char *) NULL || id == (char *) NULL)
+       return (-1);
+
+    for (;;) {
+       while (*cp++ != ':')
+           if (cp[-1] == '\0')
+               return (-1);
+
+       while (isspace(*cp))
+           cp++;
+
+       if (strncmp(cp, id, 2) == 0 && cp[2] == '#')
+           return (atoi(cp + 3));
+    }
+}
+
+
+/*
+ *     tgetflag - get the boolean flag corresponding to id. Returns -1
+ *     if invalid, 0 if the flag is not in termcap entry, or 1 if it is
+ *     present.
+ */
+
+int tgetflag(id)
+char *id;
+{
+    register char *cp = capab;
+
+    if (cp == (char *) NULL || id == (char *) NULL)
+       return (-1);
+
+    for (;;) {
+       while (*cp++ != ':')
+           if (cp[-1] == '\0')
+               return (0);
+
+       while (isspace(*cp))
+           cp++;
+
+       if (strncmp(cp, id, 2) == 0)
+           return (1);
+    }
+}
+
+
+/*
+ *     tgetstr - get the string capability corresponding to id and place
+ *     it in area (advancing area at same time). Expand escape sequences
+ *     etc. Returns the string, or NULL if it can't do it.
+ */
+
+char *tgetstr(id, area)
+char *id;
+char **area;
+{
+    register char *cp = capab;
+    register char *wsp = *area;        /* workspace pointer  */
+
+    if (cp == (char *) NULL || id == (char *) NULL)
+       return ((char *) NULL);
+
+    for (;;) {
+       while (*cp++ != ':')
+           if (cp[-1] == '\0')
+               return ((char *) NULL);
+
+       while (isspace(*cp))
+           cp++;
+
+       if (strncmp(cp, id, 2) == 0 && cp[2] == '=') {
+           for (cp += 3; *cp && *cp != ':'; wsp++, cp++)
+               switch (*cp) {
+               case '^':
+                   *wsp = *++cp - '@';
+                   break;
+
+               case '\\':
+                   switch (*++cp) {
+                   case 'E':
+                       *wsp = '\033';
+                       break;
+                   case 'n':
+                       *wsp = '\n';
+                       break;
+                   case 'r':
+                       *wsp = '\r';
+                       break;
+                   case 't':
+                       *wsp = '\t';
+                       break;
+                   case 'b':
+                       *wsp = '\b';
+                       break;
+                   case 'f':
+                       *wsp = '\f';
+                       break;
+                   case '0':
+                   case '1':
+                   case '2':
+                   case '3':
+                       {
+                           int i;
+                           int t = 0;
+                           for (i = 0; i < 3 && isdigit(*cp); ++i, ++cp)
+                               t = t * 8 + *cp - '0';
+                           *wsp = t;
+                           cp--;
+                           break;
+                       }
+                   default:
+                       *wsp = *cp;
+                   }
+                   break;
+
+               default:
+                   *wsp = *cp;
+               }
+
+           *wsp++ = '\0';
+
+           {
+               char *ret = *area;
+               *area = wsp;
+               return (ret);
+           }
+       }
+    }                          /* end for(;;) */
+}
+
+
+/*
+ *     tgoto - given the cursor motion string cm, make up the string
+ *     for the cursor to go to (destcol, destline), and return the string.
+ *     Returns "OOPS" if something's gone wrong, or the string otherwise.
+ */
+
+char *tgoto(cm, destcol, destline)
+char *cm;
+int destcol;
+int destline;
+{
+    static char ret[24];
+    char *rp = ret;
+    int incr = 0;
+    int argno = 0;
+    int numval;
+
+    for (; *cm; cm++) {
+       if (*cm == '%') {
+           switch (*++cm) {
+           case 'i':
+               incr = 1;
+               break;
+
+           case 'r':
+               argno = 1;
+               break;
+
+           case '+':
+               numval = (argno == 0 ? destline : destcol);
+               *rp++ = numval + incr + *++cm;
+               argno = 1 - argno;
+               break;
+
+           case '2':
+               numval = (argno == 0 ? destline : destcol);
+               numval = (numval + incr) % 100;
+               *rp++ = '0' + (numval / 10);
+               *rp++ = '0' + (numval % 10);
+               argno = 1 - argno;
+               break;
+
+           case 'd':
+               numval = (argno == 0 ? destline : destcol);
+               numval = (numval + incr) % 1000;
+               if (numval > 99)
+                   *rp++ = '0' + (numval / 100);
+               if (numval > 9)
+                   *rp++ = '0' + (numval / 10) % 10;
+               *rp++ = '0' + (numval % 10);
+               argno = 1 - argno;
+               break;
+
+           case '%':
+               *rp++ = '%';
+               break;
+
+           default:
+               return ("OOPS");
+           }
+
+       } else
+           *rp++ = *cm;
+    }
+
+    *rp = '\0';
+    return (ret);
+}
+
+
+/*
+ *     tputs - put the string cp out onto the terminal, using the function
+ *     outc. This should do padding for the terminal, but I can't find a
+ *     terminal that needs padding at the moment...
+ */
+
+int tputs(cp, affcnt, outc)
+register char *cp;
+int affcnt;
+void (*outc)(int ch);
+{
+    if (cp == (char *) NULL)
+       return (1);
+    /* Do any padding interpretation - left null for MINIX just now */
+    while (*cp)
+       (*outc) (*cp++);
+    return (1);
+}
diff --git a/Applications/util/termcap.h b/Applications/util/termcap.h
new file mode 100644 (file)
index 0000000..1dc96c0
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _TERMCAP_H
+#define _TERMCAP_H
+
+int  tgetent(char *_bp, char *_name);
+int  tgetflag(char *_id);
+int  tgetnum(char *_id);
+char *tgetstr(char *_id, char **_area);
+char *tgoto(char *_cm, int _destcol, int _destline);
+int  tputs(char *_cp, int _affcnt, int (*_outc)(int));
+
+#endif /* _TERMCAP_H */
diff --git a/Applications/util/tget.c b/Applications/util/tget.c
new file mode 100644 (file)
index 0000000..ef3f5ab
--- /dev/null
@@ -0,0 +1,99 @@
+/*     tget 1.0 - get termcap values                   Author: Kees J. Bot
+ *                                                             6 Mar 1994
+ */
+
+#define nil 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "termcap.h"
+
+int fputchar(int c)
+{
+    putchar(c);
+    return 0;
+}
+
+void usage(void)
+{
+    fprintf(stderr,
+           "Usage: tget [-flag id] [-num id] [-str id] [-goto col line] [[-echo] string]\n");
+    exit(-1);
+}
+
+char termbuf[1024];
+char string[256], *pstr;
+
+void main(int argc, char **argv)
+{
+    char *term;
+    int  i, excode = 0;
+
+    if ((term = getenv("TERM")) == nil) {
+       fprintf(stderr, "tget: $TERM is not set\n");
+       exit(-1);
+    }
+
+    if (tgetent(termbuf, term) != 1) {
+       fprintf(stderr, "tget: no termcap entry for '%s'\n", term);
+       exit(-1);
+    }
+
+    for (i = 1; i < argc; i++) {
+       char *option = argv[i];
+       char *id;
+
+       if (option[0] != '-') {
+           fputs(option, stdout);
+           continue;
+       }
+
+       if (++i == argc)
+           usage();
+       id = argv[i];
+
+       if (strcmp(option, "-flag") == 0) {
+           excode = tgetflag(id) ? 0 : 1;
+       } else if (strcmp(option, "-num") == 0) {
+           int num;
+
+           if ((num = tgetnum(id)) == -1) {
+               excode = 1;
+           } else {
+               excode = 0;
+               printf("%d", num);
+           }
+       } else if (strcmp(option, "-str") == 0) {
+           char *str;
+
+           if ((str = tgetstr(id, (pstr = string, &pstr))) == nil) {
+               excode = 1;
+           } else {
+               excode = 0;
+               tputs(str, 0, fputchar);
+           }
+       } else if (strcmp(option, "-goto") == 0) {
+           char *cm;
+           int col, line;
+
+           col = atoi(id);
+           if (++i == argc)
+               usage();
+           line = atoi(argv[i]);
+
+           if ((cm = tgetstr("cm", (pstr = string, &pstr))) == nil) {
+               excode = 1;
+           } else {
+               excode = 0;
+               tputs(tgoto(cm, col, line), 0, fputchar);
+           }
+       } else if (strcmp(option, "-echo") == 0) {
+           fputs(id, stdout);
+       } else {
+           usage();
+       }
+    }
+
+    exit(excode);
+}
diff --git a/Applications/util/touch.c b/Applications/util/touch.c
new file mode 100644 (file)
index 0000000..9aa8c5e
--- /dev/null
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <utime.h>
+
+static time_t settime;
+
+int main(int argc, const char *argv[])
+{
+    int er = 0, i, ncreate = 0;
+    struct stat sbuf;
+    struct utimbuf tbuf;
+
+    if ((argv[1][0] == '-') && (argv[1][1] == 'c'))
+       ncreate = 1;
+
+    for (i = ncreate + 1; i < argc; i++) {
+       if (argv[i][0] != '-') {
+           if (stat(argv[i], &sbuf)) {
+               if (!ncreate)
+                   er = close(creat(argv[i], 0666));
+           } else {
+               settime = time(NULL);
+                tbuf.actime = settime;
+               tbuf.modtime = settime;
+                er |= utime(argv[i], &tbuf);
+           }
+       }
+    }
+    return er;
+}
diff --git a/Applications/util/tr.c b/Applications/util/tr.c
new file mode 100644 (file)
index 0000000..3f23a3f
--- /dev/null
@@ -0,0 +1,172 @@
+/* tr - translate characters           Author: Michiel Huisjes */
+
+/* Usage: tr [-cds] [string1 [string2]]
+ *     c: take complement of string1
+ *     d: delete input characters coded string1
+ *     s: squeeze multiple output characters of string2 into one character
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdlib.h>
+
+#define BUFFER_SIZE    1024
+#define ASCII          0377
+
+typedef char BOOL;
+#define TRUE   1
+#define FALSE  0
+
+#define NIL_PTR                ((char *) 0)
+
+BOOL com_fl, del_fl, sq_fl;
+
+unsigned char output[BUFFER_SIZE], input[BUFFER_SIZE];
+unsigned char vector[ASCII + 1];
+BOOL invec[ASCII + 1], outvec[ASCII + 1];
+
+short in_index, out_index;
+
+int  main(int argc, char **argv);
+void convert(void);
+void map(unsigned char *string1, unsigned char *string2);
+void expand(char *arg, unsigned char *buffer);
+void complement(unsigned char *buffer);
+
+int main(int argc, char *argv[])
+{
+    register unsigned char *ptr;
+    int index = 1;
+    short i;
+
+    if (argc > 1 && argv[index][0] == '-') {
+       for (ptr = (unsigned char *) &argv[index][1]; *ptr; ptr++) {
+           switch (*ptr) {
+           case 'c':
+               com_fl = TRUE;
+               break;
+           case 'd':
+               del_fl = TRUE;
+               break;
+           case 's':
+               sq_fl = TRUE;
+               break;
+           default:
+               write(2, "Usage: tr [-cds] [string1 [string2]].\n", 38);
+               exit(1);
+           }
+       }
+       index++;
+    }
+
+    for (i = 0; i <= ASCII; i++) {
+       vector[i] = i;
+       invec[i] = outvec[i] = FALSE;
+    }
+
+    if (argv[index] != NIL_PTR) {
+       expand(argv[index++], input);
+       if (com_fl) complement(input);
+       if (argv[index] != NIL_PTR) expand(argv[index], output);
+       if (argv[index] != NIL_PTR) map(input, output);
+       for (ptr = input;  *ptr; ptr++) invec[*ptr]  = TRUE;
+       for (ptr = output; *ptr; ptr++) outvec[*ptr] = TRUE;
+    }
+
+    convert();
+
+    return (0);
+}
+
+void convert(void)
+{
+    short read_chars = 0;
+    short c, coded;
+    short last = -1;
+
+    for (;;) {
+       if (in_index == read_chars) {
+           if ((read_chars = read(0, (char *) input, BUFFER_SIZE)) <= 0) {
+               if (write(1, (char *) output, out_index) != out_index)
+                   write(2, "Bad write\n", 10);
+               exit(0);
+           }
+           in_index = 0;
+       }
+       c = input[in_index++];
+       coded = vector[c];
+       if (del_fl && invec[c]) continue;
+       if (sq_fl && last == coded && outvec[coded]) continue;
+       output[out_index++] = last = coded;
+       if (out_index == BUFFER_SIZE) {
+           if (write(1, (char *) output, out_index) != out_index) {
+               write(2, "Bad write\n", 10);
+               exit(1);
+           }
+           out_index = 0;
+       }
+    }
+
+    /* NOTREACHED */
+}
+
+void map(unsigned char *string1, unsigned char *string2)
+{
+    unsigned char last = 0;
+
+    while (*string1) {
+       if (*string2 == '\0')
+           vector[*string1] = last;
+       else
+           vector[*string1] = last = *string2++;
+       string1++;
+    }
+}
+
+void expand(char *arg, unsigned char *buffer)
+{
+    int i, ac;
+
+    while (*arg) {
+       if (*arg == '\\') {
+           arg++;
+           i = ac = 0;
+           if (*arg >= '0' && *arg <= '7') {
+               do {
+                   ac = (ac << 3) + *arg++ - '0';
+                   i++;
+               } while (i < 4 && *arg >= '0' && *arg <= '7');
+               *buffer++ = ac;
+           } else if (*arg != '\0')
+               *buffer++ = *arg++;
+       } else if (*arg == '[') {
+           arg++;
+           i = *arg++;
+           if (*arg++ != '-') {
+               *buffer++ = '[';
+               arg -= 2;
+               continue;
+           }
+           ac = *arg++;
+           while (i <= ac) *buffer++ = i++;
+           arg++;              /* Skip ']' */
+       } else {
+           *buffer++ = *arg++;
+       }
+    }
+}
+
+void complement(unsigned char *buffer)
+{
+    register unsigned char *ptr;
+    register short i, index;
+    unsigned char conv[ASCII + 2];
+
+    index = 0;
+    for (i = 1; i <= ASCII; i++) {
+       for (ptr = buffer; *ptr; ptr++)
+           if (*ptr == i) break;
+       if (*ptr == '\0') conv[index++] = i & ASCII;
+    }
+    conv[index] = '\0';
+    strcpy((char *) buffer, (char *) conv);
+}
diff --git a/Applications/util/true.c b/Applications/util/true.c
new file mode 100644 (file)
index 0000000..d66447b
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+    return 0;
+}
diff --git a/Applications/util/umount.c b/Applications/util/umount.c
new file mode 100644 (file)
index 0000000..7aa71b2
--- /dev/null
@@ -0,0 +1,89 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+char tmp[256];
+
+char *getdev(char *arg)
+{
+    FILE *f;
+    static char dev[20], mntpt[20], fstype[20], rwflag[20];
+    
+    f = fopen("/etc/mtab", "r");
+    if (f) {
+        while (fgets(tmp, 256, f)) {
+            sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag);
+            if ((strcmp(dev, arg) == 0) || (strcmp(mntpt, arg) == 0)) {
+                fclose(f);
+                return dev;
+            }
+        }
+        fclose(f);
+    }
+
+    return NULL;
+}
+
+
+int rm_mtab(char *devname)
+{
+    FILE *inpf, *outf;
+    char *tmp_fname;
+    static char dev[20], mntpt[20], fstype[20], rwflag[20];
+
+    if ((tmp_fname = tmpnam(NULL)) == NULL) {
+        perror("Error getting temporary file name");
+        exit(1);
+    }
+    inpf = fopen("/etc/mtab", "r");
+    if (!inpf) {
+        perror("Can't open /etc/mtab");
+        exit(1);
+    }
+    outf = fopen(tmp_fname, "w");
+    if (!outf) {
+        perror("Can't create temporary file");
+        exit(1);
+    }
+    while (fgets(tmp, 255, inpf)) {
+        sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag);
+        if (strcmp(dev, devname) == 0) {
+            continue;
+        } else {
+            fprintf(outf, "%s", tmp);
+        }
+    }
+    fclose(inpf);
+    fclose(outf);
+    if (unlink("/etc/mtab") < 0) {
+        perror("Can't delete old /etc/mtab file");
+        exit(1);
+    }
+    if (rename(tmp_fname, "/etc/mtab") < 0) {
+        perror("Error installing /etc/mtab");
+        exit(1);
+    }
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    char *dev;
+
+    if (argc != 2) {
+        printf("usage: umount device\n");
+        return 1;
+    }
+
+    dev = getdev(argv[1]);
+    if (!dev) dev = argv[1];
+
+    if (umount(dev) == 0) {
+        rm_mtab(dev);
+    } else {
+        perror("umount");
+        return 1;
+    }
+    return 0;
+}
diff --git a/Applications/util/uniq.c b/Applications/util/uniq.c
new file mode 100644 (file)
index 0000000..1eefe95
--- /dev/null
@@ -0,0 +1,192 @@
+/* uniq - compact repeated lines                Author: John Woods */
+/* uniq [-udc] [-n] [+n] [infile [outfile]]
+ *
+ *      Written 02/08/86 by John Woods, placed into public domain.  Enjoy.
+ *
+ */
+
+/* If the symbol WRITE_ERROR is defined, uniq will exit(1) if it gets a
+ * write error on the output.  This is not (of course) how V7 uniq does it,
+ * so undefine the symbol if you want to lose your output to a full disk
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define WRITE_ERROR 1
+
+char buffer[BUFSIZ];
+int  uflag = 1;                        /* default is union of -d and -u outputs */
+int  dflag = 1;                        /* flags are mutually exclusive */
+int  cflag = 0;
+int  fields = 0;
+int  chars = 0;
+
+char *skip(char *);
+int  equal(char *, char *);
+void show(char *, int);
+int  uniq(void);
+void usage(void);
+int  getline(char *, int);
+
+FILE *xfopen(char *fn, char *mode)
+{
+    FILE *p;
+
+    if ((p = fopen(fn, mode)) == NULL) {
+       perror("uniq");
+       fflush(stdout);
+       exit(1);
+    }
+    return (p);
+}
+
+int main(int argc, char *argv[])
+{
+    char *p;
+    int inf = -1, outf;
+
+    setbuf(stdout, buffer);
+    for (--argc, ++argv; argc > 0 && (**argv == '-' || **argv == '+');
+        --argc, ++argv) {
+       if (*argv[0] == '+')
+           chars = atoi(*argv + 1);
+       else if (isdigit(argv[0][1]))
+           fields = atoi(*argv + 1);
+       else if (argv[0][1] == '\0')
+           inf = 0;            /* - is stdin */
+       else
+           for (p = *argv + 1; *p; p++) {
+               switch (*p) {
+               case 'd':
+                   dflag = 1;
+                   uflag = 0;
+                   break;
+               case 'u':
+                   uflag = 1;
+                   dflag = 0;
+                   break;
+               case 'c':
+                   cflag = 1;
+                   break;
+               default:
+                   usage();
+               }
+           }
+    }
+
+    /* Input file */
+    if (argc == 0) {
+       inf = 0;
+    } else if (inf == -1) {    /* if - was not given */
+       fclose(stdin);
+       xfopen(*argv++, "r");
+       argc--;
+    }
+
+    if (argc == 0) {
+       outf = 1;
+    } else {
+       fclose(stdout);
+       xfopen(*argv++, "w");
+       argc--;
+    }
+
+    uniq();
+    fflush(stdout);
+
+    return (0);
+}
+
+char *skip(char *s)
+{
+    int n;
+
+    /* Skip fields */
+    for (n = fields; n > 0; --n) {
+       /* Skip blanks */
+       while (*s && (*s == ' ' || *s == '\t')) s++;
+       if (!*s) return s;
+       while (*s && (*s != ' ' && *s != '\t')) s++;
+       if (!*s) return s;
+    }
+
+    /* Skip characters */
+    for (n = chars; n > 0; --n) {
+       if (!*s) return s;
+       s++;
+    }
+    return s;
+}
+
+int equal(char *s1, char *s2)
+{
+    return !strcmp(skip(s1), skip(s2));
+}
+
+void show(char *line, int count)
+{
+    if (cflag) {
+       printf("%4d %s", count, line);
+    } else {
+       if ((uflag && count == 1) || (dflag && count != 1))
+           printf("%s", line);
+    }
+}
+
+/* The meat of the whole affair */
+char *nowline, *prevline, buf1[1024], buf2[1024];
+
+int uniq(void)
+{
+    char *p;
+    int  seen;
+
+    /* Setup */
+    prevline = buf1;
+    if (getline(prevline, 1024) < 0) return (0);
+    seen = 1;
+    nowline = buf2;
+
+    /* Get nowline and compare if not equal, dump prevline and swap
+     * pointers else continue, bumping seen count */
+    while (getline(nowline, 1024) > 0) {
+       if (!equal(prevline, nowline)) {
+           show(prevline, seen);
+           seen = 1;
+           p = nowline;
+           nowline = prevline;
+           prevline = p;
+       } else {
+           seen += 1;
+       }
+    }
+    show(prevline, seen);
+
+    return 0;
+}
+
+void usage(void)
+{
+    fprintf(stderr, "Usage: uniq [-udc] [+n] [-n] [input [output]]\n");
+    exit(1);
+}
+
+int getline(char *buf, int count)
+{
+    int c;
+    int ct = 0;
+
+    while (ct++ < count) {
+       c = getc(stdin);
+       if (c < 0) return (-1);
+       *buf++ = c;
+       if (c == '\n') {
+           *buf++ = 0;
+           return (ct);
+       }
+    }
+    return (ct);
+}
diff --git a/Applications/util/uud.c b/Applications/util/uud.c
new file mode 100644 (file)
index 0000000..42d82f8
--- /dev/null
@@ -0,0 +1,437 @@
+/* uud - bulletproof version of uudecode */
+
+/*
+ * Uud -- decode a uuencoded file back to binary form.
+ *
+ * UZI port of the minix version.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define loop   for(;;)
+
+#define NCHARS  256
+#define LINELEN 256
+#define FILELEN 64
+#define NORMLEN 60             /* allows for 80 encoded chars per line */
+
+#define SEQMAX 'z'
+#define SEQMIN 'a'
+char seqc;
+int first, secnd, check, numl;
+
+FILE *inpf, *outf;
+char *pos;
+char ifname[FILELEN], ofname[FILELEN];
+char *source = NULL, *target = NULL;
+char blank, part = '\0';
+int  partn, lens;
+int  debug = 0, nochk = 0, onedone = 0;
+int  chtbl[NCHARS], cdlen[NORMLEN + 3];
+
+int  main(int argc, char **argv);
+char *getnword(char *str, int n);
+void gettable(void);
+void decode(void);
+void getfile(char *buf);
+
+int main(int argc, char *argv[])
+{
+    int mode;
+    register int i, j;
+    char *curarg;
+    char dest[FILELEN], buf[LINELEN];
+
+    while ((curarg = argv[1]) != NULL && curarg[0] == '-') {
+       if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
+           (curarg[2] == '\0')) {
+           debug = 1;
+       } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
+                  (curarg[2] == '\0')) {
+           nochk = 1;
+       } else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
+                  (curarg[2] == '\0')) {
+           argv++;
+           argc--;
+           if (argc < 2) {
+               printf("uud: Missing target directory.\n");
+               exit(15);
+           }
+           target = argv[1];
+           if (debug)
+               printf("Target dir = %s\n", target);
+       } else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
+                   (curarg[2] == '\0')) {
+           argv++;
+           argc--;
+           if (argc < 2) {
+               printf("uud: Missing source directory.\n");
+               exit(15);
+           }
+           source = argv[1];
+           if (debug)
+               printf("Source dir = %s\n", source);
+       } else if (curarg[1] != '\0') {
+           printf("Usage: uud [-n] [-d] [-s dir] [-t dir] [input-file]\n");
+           exit(1);
+       } else
+           break;
+       argv++;
+       argc--;
+    }
+
+    if (curarg == NULL || ((curarg[0] == '-') && (curarg[1] == '\0'))) {
+       inpf = stdin;
+       strcpy(ifname, "<stdin>");
+    } else {
+       if (source != NULL) {
+           strcpy(ifname, source);
+           strcat(ifname, curarg);
+       } else {
+           strcpy(ifname, curarg);
+       }
+       if ((inpf = fopen(ifname, "r")) == NULL) {
+           printf("uud: Can't open %s\n", ifname);
+           exit(2);
+       }
+       numl = 0;
+    }
+
+    /* Set up the default translation table. */
+    for (i = 0; i < ' '; i++) chtbl[i] = -1;
+    for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
+    for (i = ' ' + 64; i < NCHARS; i++) chtbl[i] = -1;
+    chtbl['`'] = chtbl[' '];   /* common mutation */
+    chtbl['~'] = chtbl['^'];   /* an other common mutation */
+    blank = ' ';
+
+    /* Set up the line length table, to avoid computing lotsa * and / ...  */
+    cdlen[0] = 1;
+    for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
+       cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
+
+    /* Search for header or translation table line. */
+    loop {             /* master loop for multiple decodes in one file */
+       partn = 'a';
+       loop {
+           if (fgets(buf, sizeof buf, inpf) == NULL) {
+               if (onedone) {
+                   if (debug)
+                       printf("End of file.\n");
+                   exit(0);
+               } else {
+                   printf("uud: No begin line.\n");
+                   exit(3);
+               }
+           }
+           numl++;
+           if (strncmp(buf, "table", (size_t) 5) == 0) {
+               gettable();
+               continue;
+           }
+           if (strncmp(buf, "begin", (size_t) 5) == 0) {
+               break;
+           }
+       }
+       lens = strlen(buf);
+       if (lens) buf[--lens] = '\0';
+
+       if (sscanf(buf, "begin%o%s", &mode, dest) != 2) {
+           printf("uud: Missing filename in begin line.\n");
+           exit(10);
+       }
+
+       if (target != NULL) {
+           strcpy(ofname, target);
+           strcat(ofname, dest);
+       } else {
+           strcpy(ofname, dest);
+       }
+
+       if ((outf = fopen(ofname, "w")) == NULL) {      /* binary! */
+           printf("uud: Cannot open output file: %s\n", ofname);
+           exit(4);
+       }
+
+       if (debug)
+           printf("Begin uudecoding: %s\n", ofname);
+
+       seqc = SEQMAX;
+       check = nochk ? 0 : 1;
+       first = 1;
+       secnd = 0;
+
+       decode();
+       fclose(outf);
+       chmod(ofname, mode);
+
+       onedone = 1;
+
+       if (debug)
+           printf("End uudecoding: %s\n", ofname);
+
+    }          /* master loop for multiple decodes in one file */
+}
+
+
+/* Bring back a pointer to the start of the nth word. */
+
+char *getnword(char *str, int n)
+{
+    while ((*str == '\t') || (*str == ' ')) str++;
+    if (!*str) return NULL;
+
+    while (--n) {
+       while ((*str != '\t') && (*str != ' ') && (*str)) str++;
+       if (!*str) return NULL;
+       while ((*str == '\t') || (*str == ' ')) str++;
+       if (!*str) return NULL;
+    }
+
+    return str;
+}
+
+
+/* Install the table in memory for later use. */
+
+void gettable(void)
+{
+    register int c, n = 0;
+    register char *cpt;
+    char buf[LINELEN];
+
+    for (c = 0; c < NCHARS; c++) chtbl[c] = -1;
+
+  again:
+    if (fgets(buf, sizeof buf, inpf) == NULL) {
+       printf("uud: EOF while in translation table.\n");
+       exit(5);
+    }
+    numl++;
+    if (strncmp(buf, "begin", (size_t) 5) == 0) {
+       printf("uud: Incomplete translation table.\n");
+       exit(6);
+    }
+    cpt = buf + strlen(buf) - 1;
+    *cpt = ' ';
+    while (*(cpt) == ' ') {
+       *cpt = 0;
+       cpt--;
+    }
+    cpt = buf;
+    while (c = *cpt) {
+       if (chtbl[c] != -1) {
+           printf("uud: Duplicate char in translation table.\n");
+           exit(7);
+       }
+       if (n == 0) blank = c;
+       chtbl[c] = n++;
+       if (n >= 64) return;
+       cpt++;
+    }
+    goto again;
+}
+
+
+/* Copy from inpf to outf, decoding as you go along. */
+
+void decode(void)
+{
+    register char *bp, *ut;
+    register int *trtbl = chtbl;
+    register int n, c, rlen;
+    register unsigned int len;
+    char buf[LINELEN], outl[LINELEN];
+
+    loop {
+       if (fgets(buf, sizeof buf, inpf) == NULL) {
+           printf("uud: EOF before end.\n");
+           fclose(outf);
+           exit(8);
+       }
+       numl++;
+       len = strlen(buf);
+       if (len) buf[--len] = '\0';
+
+        /* Is it an unprotected empty line before the end line ? */
+       if (len == 0) continue;
+
+       /* Get the binary line length. */
+       n = trtbl[*buf];
+       if (n >= 0)
+           goto decod;
+
+       /* End of uuencoded file ? */
+       if (strncmp(buf, "end", (size_t) 3) == 0)
+           return;
+
+       /* End of current file ? : get next one. */
+       if (strncmp(buf, "include", (size_t) 7) == 0) {
+           getfile(buf);
+           continue;
+       }
+       printf("uud: Bad prefix line %d in file: %s\n", numl, ifname);
+       if (debug)
+           printf("Bad line = %s\n", buf);
+       exit(11);
+
+       /* Sequence checking ? */
+    decod:
+        rlen = cdlen[n];
+
+       /* Is it the empty line before the end line ? */
+       if (n == 0) continue;
+
+       /* Pad with blanks. */
+       for (bp = &buf[c = len]; c < rlen; c++, bp++) *bp = blank;
+
+       /* Verify if asked for. */
+       if (debug) {
+           for (len = 0, bp = buf; len < rlen; len++) {
+               if (trtbl[*bp] < 0) {
+                   printf("Non uuencoded char <%c>, line %d in file: %s\n",
+                          *bp, numl, ifname);
+                   printf("Bad line = %s\n", buf);
+                   exit(16);
+               }
+               bp++;
+           }
+       }
+
+       /*
+        *  All this just to check for uuencodes that append
+        *  a 'z' to each line....
+        */
+       if (secnd && check) {
+           secnd = 0;
+           if (buf[rlen] == SEQMAX) {
+               check = 0;
+               if (debug)
+                   printf("Sequence check turned off (2).\n");
+           } else if (debug)
+               printf("Sequence check on (2).\n");
+       } else if (first && check) {
+           first = 0;
+           secnd = 1;
+           if (buf[rlen] != SEQMAX) {
+               check = 0;
+               if (debug)
+                   printf("No sequence check (1).\n");
+           } else if (debug)
+               printf("Sequence check on (1).\n");
+       }
+
+       /* There we check. */
+       if (check) {
+           if (buf[rlen] != seqc) {
+               printf("uud: Wrong sequence line %d in %s\n",
+                      numl, ifname);
+               if (debug)
+                   printf("Sequence char is <%c> instead of <%c>.\n",
+                          buf[rlen], seqc);
+               exit(18);
+           }
+           seqc--;
+           if (seqc < SEQMIN) seqc = SEQMAX;
+       }
+
+       /*
+        * Output a group of 3 bytes (4 input characters). The input chars
+        * are pointed to by p, they are to be output to file f.n is used
+        * to tell us not to output all of them at the end of the file.
+        */
+       ut = outl;
+       len = n;
+       bp = &buf[1];
+       while (n > 0) {
+           *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
+           n--;
+           if (n) {
+               *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
+               n--;
+           }
+           if (n) {
+               *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
+               n--;
+           }
+           bp += 4;
+       }
+       if ((n = fwrite(outl, (size_t) 1, (size_t) len, outf)) <= 0) {
+           printf("uud: Error on writing decoded file.\n");
+           exit(18);
+       }
+    }
+}
+
+/*
+ * Find the next needed file, if existing, otherwise try further
+ * on next file.
+ */
+void getfile(char *buf)
+{
+    if ((pos = getnword(buf, 2)) == NULL) {
+       printf("uud: Missing include file name.\n");
+       exit(17);
+    } else if (source != NULL) {
+       strcpy(ifname, source);
+       strcat(ifname, pos);
+    } else {
+       strcpy(ifname, pos);
+    }
+
+    if (access(ifname, 04)) {
+       if (debug) {
+           printf("Can't find: %s\n", ifname);
+           printf("Continuing to read same file.\n");
+       }
+    } else {
+       if (freopen(ifname, "r", inpf) == inpf) {
+           numl = 0;
+           if (debug)
+               printf("Reading next section from: %s\n", ifname);
+       } else {
+           printf("uud: freopen abort: %s\n", ifname);
+           exit(9);
+       }
+    }
+
+    loop {
+       if (fgets(buf, LINELEN, inpf) == NULL) {
+           printf("uud: No begin line after include: %s\n", ifname);
+           exit(12);
+       }
+       numl++;
+       if (strncmp(buf, "table", (size_t) 5) == 0) {
+           gettable();
+           continue;
+       }
+       if (strncmp(buf, "begin", (size_t) 5) == 0)
+           break;
+    }
+
+    lens = strlen(buf);
+    if (lens) buf[--lens] = '\0';
+
+    /* Check the part suffix. */
+
+    if ((pos = getnword(buf, 3)) == NULL) {
+       printf("uud: Missing part name, in included file: %s\n", ifname);
+       exit(13);
+    } else {
+       part = *pos;
+       partn++;
+       if (partn > 'z') partn = 'a';
+       if (part != partn) {
+           printf("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
+                  part, partn);
+           exit(14);
+       }
+       if (debug)
+           printf("Reading part %c\n", *pos);
+    }
+}
+
diff --git a/Applications/util/uue.c b/Applications/util/uue.c
new file mode 100644 (file)
index 0000000..a6e664a
--- /dev/null
@@ -0,0 +1,192 @@
+/* uue - bulletproof version of uuencode */
+
+/* Uue -- encode a file so that it's printable ascii, short lines
+ *
+ * UZI port of the minix version by HPG.
+ */
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define FILE_NAME 10           /* affects how long names are truncated */
+
+/* ENC is the basic 1 character encoding function to make a char printing */
+#define ENC(c) (((c) & 077) + ' ')
+
+FILE *fp, *outp;
+char ofname[80];
+int  lenofname;
+int  stdo = 0;
+
+int part = 'a', chap = 'a';
+
+#define SEQMAX 'z'
+#define SEQMIN 'a'
+
+char seqc = SEQMAX;
+
+int split = 0;
+int fileln = 32000;
+
+int  main(int argc, char **argv);
+void maketable(void);
+void makename(void);
+void encode(void);
+void outdec(char *p);
+
+int main(int argc, char *argv[])
+{
+    char *fname, *prog_name;
+    int  filter;
+
+    prog_name = argv[0] + strlen(argv[0]);
+    while (prog_name > argv[0] && prog_name[-1] != '/') prog_name--;
+    filter = strcmp(prog_name, "uuencode") == 0;
+
+    if (argc < 2) {
+       fprintf(stderr, "Usage: %s [-n] inputfile [-]\n", prog_name);
+       exit(2);
+    }
+
+    if (argv[1][0] == '-') {
+       fileln = -atoi(argv[1]);
+       if (fileln <= 0) {
+           fprintf(stderr, "Wrong file length arg.\n");
+           exit(3);
+       }
+       split = 1;
+       argv++;
+       argc--;
+    }
+
+    if (filter) {              /* old uuencode reads from standard input */
+       fp = stdin;
+    } else {
+       if ((fp = fopen(argv[1], "r")) == NULL) {       /* binary input! */
+           fprintf(stderr, "Cannot open %s\n", argv[1]);
+           exit(1);
+       }
+    }
+
+    fname = argv[1] + strlen(argv[1]);
+    while (fname > argv[1] && fname[-1] != '/') fname--;
+    strcpy(ofname, fname);
+    fname = ofname;
+    do {
+       if (*fname == '.') *fname = '\0';
+    } while (*fname++);
+
+    /* 10 char prefix + .uue -> 14 chars MAX */
+    lenofname = strlen(ofname);
+    if (lenofname > FILE_NAME) ofname[FILE_NAME] = '\0';
+    strcat(ofname, ".uue");
+    lenofname = strlen(ofname);
+    if (!split && (filter || (argc > 2) && (argv[2][0] == '-'))) {
+       stdo = 1;
+       outp = stdout;
+    } else {
+       makename();
+       if ((outp = fopen(ofname, "w")) == NULL) {
+           fprintf(stderr, "Cannot open %s\n", ofname);
+           exit(1);
+       }
+    }
+    maketable();
+    fprintf(outp, "begin %o %s\n", 0644, argv[1]);
+    encode();
+    fprintf(outp, "end\n");
+    fclose(outp);
+
+    return (0);
+}
+
+
+/*
+ *  Create ASCII table so a mailer can screw it up and the decode
+ *  program can restore the error.
+ */
+void maketable(void)
+{
+    register int i, j;
+
+    fputs("table\n", outp);
+    for (i = ' ', j = 0; i < '`'; j++) {
+       if (j == 32) putc('\n', outp);
+       fputc(i++, outp);
+    }
+    putc('\n', outp);
+}
+
+
+/* Generate the names needed for single and multiple part encoding. */
+
+void makename(void)
+{
+    if (split) {
+       ofname[lenofname - 1] = part;
+       ofname[lenofname - 2] = chap;
+    }
+}
+
+
+/* Copy from in to out, encoding as you go along. */
+
+void encode(void)
+{
+    char buf[80];
+    register int i, n;
+    register int lines;
+    lines = 6;
+
+    for (;;) {
+       n = fread(buf, 1, 45, fp);
+       putc(ENC(n), outp);
+       for (i = 0; i < n; i += 3) outdec(&buf[i]);
+       putc(seqc, outp);
+       seqc--;
+       if (seqc < SEQMIN) seqc = SEQMAX;
+       putc('\n', outp);
+       ++lines;
+       if (split && (lines > fileln)) {
+           part++;
+           if (part > 'z') {
+               part = 'a';
+               if (chap == 'z')
+                   chap = 'a'; /* loop ... */
+               else
+                   chap++;
+           }
+           makename();
+           fprintf(outp, "include %s\n", ofname);
+           fclose(outp);
+           if ((outp = fopen(ofname, "w")) == NULL) {
+               fprintf(stderr, "Cannot open %s\n", ofname);
+               exit(1);
+           }
+           maketable();
+           fprintf(outp, "begin part %c %s\n", part, ofname);
+           lines = 6;
+       }
+       if (n <= 0) break;
+    }
+}
+
+
+/* Output one group of 3 bytes, pointed at by p, on file f.  */
+
+void outdec(char *p)
+{
+    register int c1, c2, c3, c4;
+
+    c1 = *p >> 2;
+    c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
+    c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
+    c4 = p[2] & 077;
+    putc(ENC(c1), outp);
+    putc(ENC(c2), outp);
+    putc(ENC(c3), outp);
+    putc(ENC(c4), outp);
+}
diff --git a/Applications/util/wc.c b/Applications/util/wc.c
new file mode 100644 (file)
index 0000000..81463bf
--- /dev/null
@@ -0,0 +1,148 @@
+/* wc - count lines, words and characters       Author: David Messer */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ *      Usage:  wc [-lwc] [names]
+ *
+ *              Flags:
+ *                      l - count lines.
+ *                      w - count words.
+ *                      c - count characters.
+ *
+ *              Flags l, w, and c are default.
+ *              Words are delimited by any non-alphabetic character.
+ *
+ *  Released into the PUBLIC-DOMAIN 02/10/86
+ *
+ *      If you find this program to be of use to you, a donation of
+ *      whatever you think it is worth will be cheerfully accepted.
+ *
+ *      Written by: David L. Messer
+ *                              P.O. Box 19130, Mpls, MN,  55119
+ *      Program (heavily) modified by Andy Tanenbaum
+ */
+
+
+int  lflag;                    /* Count lines */
+int  wflag;                    /* Count words */
+int  cflag;                    /* Count characters */
+
+long lcount;                   /* Count of lines */
+long wcount;                   /* Count of words */
+long ccount;                   /* Count of characters */
+
+long ltotal;                   /* Total count of lines */
+long wtotal;                   /* Total count of words */
+long ctotal;                   /* Total count of characters */
+
+void count(FILE *f);
+void usage(void);
+
+int main(int argc, char *argv[])
+{
+    int  k;
+    char *cp;
+    int  tflag, files;
+
+    /* Get flags. */
+    files = argc - 1;
+    k = 1;
+    cp = argv[1];
+    if (argc > 1 && *cp++ == '-') {
+       files--;
+       k++;                    /* points to first file */
+       while (*cp != 0) {
+           switch (*cp) {
+               case 'l': lflag++; break;
+               case 'w': wflag++; break;
+               case 'c': cflag++; break;
+               default:  usage();
+           }
+           cp++;
+       }
+    }
+
+    /* If no flags are set, treat as wc -lwc. */
+    if (!lflag && !wflag && !cflag) {
+       lflag = 1;
+       wflag = 1;
+       cflag = 1;
+    }
+
+    /* Process files. */
+    tflag = (files >= 2);      /* set if # files > 1 */
+
+    /* Check to see if input comes from std input. */
+    if (k >= argc) {
+       count(stdin);
+       if (lflag) printf(" %6ld", lcount);
+       if (wflag) printf(" %6ld", wcount);
+       if (cflag) printf(" %6ld", ccount);
+       printf(" \n");
+       fflush(stdout);
+
+       return 0;
+    }
+
+    /* There is an explicit list of files.  Loop on files. */
+    while (k < argc) {
+       FILE *f;
+
+       if ((f = fopen(argv[k], "r")) == NULL) {
+           fprintf(stderr, "wc: cannot open %s\n", argv[k]);
+       } else {
+           count(f);
+           if (lflag) printf(" %6ld", lcount);
+           if (wflag) printf(" %6ld", wcount);
+           if (cflag) printf(" %6ld", ccount);
+           printf(" %s\n", argv[k]);
+           fclose(f);
+       }
+       k++;
+    }
+
+    if (tflag) {
+       if (lflag) printf(" %6ld", ltotal);
+       if (wflag) printf(" %6ld", wtotal);
+       if (cflag) printf(" %6ld", ctotal);
+       printf(" total\n");
+    }
+    fflush(stdout);
+
+    return 0;
+}
+
+void count(FILE *f)
+{
+    register int c;
+    register int word = 0;
+
+    lcount = 0;
+    wcount = 0;
+    ccount = 0L;
+
+    while ((c = getc(f)) != EOF) {
+       ccount++;
+
+       if (isspace(c)) {
+           if (word) wcount++;
+           word = 0;
+       } else {
+           word = 1;
+       }
+
+       if (c == '\n' || c == '\f') lcount++;
+    }
+    ltotal += lcount;
+    wtotal += wcount;
+    ctotal += ccount;
+}
+
+void usage(void)
+{
+    fprintf(stderr, "Usage: wc [-lwc] [name ...]\n");
+    exit(1);
+}
diff --git a/Applications/util/which.c b/Applications/util/which.c
new file mode 100644 (file)
index 0000000..b25d33f
--- /dev/null
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+    int  quit, found;
+    char *envpath;
+    char *path, *cp;
+    char buf[200];
+    char patbuf[512];
+
+    if (argc < 2) {
+       fprintf(stderr, "Usage: which cmd [cmd, ..]\n");
+       return 1;
+    }
+    if ((envpath = getenv("PATH")) == 0) {
+       envpath = ".";
+    }
+    argv[argc] = 0;
+    for (argv++; *argv; argv++) {
+
+       strcpy(patbuf, envpath);
+       cp = path = patbuf;
+       quit = found = 0;
+
+       while (!quit) {
+           cp = index(path, ':');
+           if (cp == NULL) {
+               quit++;
+           } else {
+               *cp = '\0';
+           }
+           sprintf(buf, "%s/%s", (*path ? path : "."), *argv);
+           path = ++cp;
+
+           if (access(buf, 1) == 0) {
+               printf("%s\n", buf);
+               found++;
+           }
+       }
+       if (!found) {
+           printf("No %s in %s\n", *argv, envpath);
+       }
+    }
+
+    return 0;
+}
diff --git a/Applications/util/whoami.c b/Applications/util/whoami.c
new file mode 100644 (file)
index 0000000..3e48db4
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+
+int main(int argc, const char *argv[])
+{
+    register struct passwd *pw;
+    register uid_t uid;
+
+    uid = geteuid();
+    pw = getpwuid(uid);
+    if (pw) {
+       printf("%s\n", pw->pw_name);
+       return 0;
+    }
+
+    return 1;
+}
diff --git a/Kernel/BUGS b/Kernel/BUGS
new file mode 100644 (file)
index 0000000..9b558d1
--- /dev/null
@@ -0,0 +1,2 @@
+- SIGSTOP/TSTP behaviour wrong
+- SIGCHLD not sent
diff --git a/Kernel/COPYING b/Kernel/COPYING
new file mode 100644 (file)
index 0000000..e77696a
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Kernel/Makefile b/Kernel/Makefile
new file mode 100644 (file)
index 0000000..8bfd6f3
--- /dev/null
@@ -0,0 +1,163 @@
+TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-spec3 platform-trs80 platform-z80pack platform-z80pack-lite 
+
+export TARGET= trs80
+export CPU = z80
+#export TARGET = 6809test
+#export CPU = 6809
+#export TARGET = 6502test
+#export CPU = 6502
+export VERSION = "0.1"
+export SUBVERSION = "ac1"
+
+ifeq ($(CPU),z80)
+export CROSS_AS=sdasz80
+export CROSS_LD=sdldz80
+export CROSS_CC=sdcc
+#export CROSS_CCOPTS=-c --std-sdcc99 --no-std-crt0 -mz80 -I$(ROOT_DIR)/cpu-z80 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include --max-allocs-per-node 1000000 --opt-code-size --Werror --stack-auto --constseg CONST
+export CROSS_CCOPTS=-c --std-sdcc99 --no-std-crt0 -mz80 -I$(ROOT_DIR)/cpu-z80 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include --max-allocs-per-node 30000 --opt-code-size --Werror --stack-auto --constseg CONST
+#export CROSS_CCOPTS+=--nostdlib --nostdinc -Isdcclib/include 
+export CROSS_CC_SEG2=--codeseg CODE2
+export CROSS_CC_SEGDISC=--codeseg DISCARD
+export CROSS_CC_FONT=--constseg FONT
+export ASOPTS=-plosff
+export BINEXT = .rel
+else ifeq ($(CPU),6502)
+export CROSS_AS=ca65
+export CROSS_LD=cl65
+export CROSS_CC=cl65
+export CROSS_CCOPTS=-c -Or -t c128 -I$(ROOT_DIR)/cpu-6502 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include
+export BINEXT = .o
+else
+export CROSS_AS=m6809-unknown-as
+export CROSS_LD=m6809-unknown-ld
+export CROSS_CC = m6809-unknown-gcc
+#export CROSS_CCOPTS=-Wall -O2 -I$(ROOT_DIR)/cpu-6809 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include
+export CROSS_CCOPTS=-c -Wall -O2 -I$(ROOT_DIR)/cpu-6809 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include
+export ASOPTS=
+endif
+
+ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+
+
+#
+#      We put these into two code segments so that the caller can plan to
+#      bank them with a ROM banking tool. We pull out const data because on
+#      such a system you want to the constants unbanked otherwise badness
+#      happens on stuff like printf("Hello world\n"); when you bank switch
+#      the code.
+#
+#      This is also useful if you've got an annoying box where the kernel can't
+#      be a linear chunk eg if you need to put the kernel in two non adjacent 16K
+#      chunks or compile it around a hole for videomemory or similar
+#
+
+CDSRCS = start.c
+C1SRCS =  version.c kdata.c filesys.c
+C1SRCS += inode.c syscall_fs.c
+C2SRCS =  devio.c process.c syscall_proc.c timer.c 
+C2SRCS += syscall_fs2.c syscall_other.c
+C2SRCS += bank16k.c bank32k.c bankfixed.c single.c simple.c
+C2SRCS += vt.c tty.c devsys.c
+C2SRCS += mm.c swap.c usermem.c
+
+CFONTSRCS += font4x6.c font8x8.c
+
+
+ASRCS =  lowlevel-$(CPU).s usermem_std-$(CPU).s
+
+
+CDOBJS = $(CDSRCS:.c=$(BINEXT))
+C1OBJS = $(C1SRCS:.c=$(BINEXT))
+C2OBJS = $(C2SRCS:.c=$(BINEXT))
+CFONTOBJS = $(CFONTSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.s=$(BINEXT))
+
+CSRCS = $(CDSRCS) $(C1SRCS) $(C2SRCS) $(CFONTSRCS)
+COBJS = $(CDOBJS) $(C1OBJS) $(C2OBJS) $(CFONTOBJS)
+
+OBJS  = $(COBJS) $(AOBJS)
+
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.s) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(CSRCS:.c=.o)  $(ASRCS:.s=.rst)
+
+all:   uzi.bin
+
+.SUFFIXES:             # delete the default suffixes
+.SUFFIXES: .c .s .rel
+
+target:
+       -rm platform
+       ln -sf platform-$(TARGET) platform
+       $(MAKE) -C platform-$(TARGET)
+
+$(C1OBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $<
+
+$(CDOBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) $<
+
+$(C2OBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) $<
+
+$(CFONTOBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_FONT) $<
+
+$(AOBJS): %$(BINEXT): %.s
+       $(CROSS_AS) $(ASOPTS) -o $*$(BINEXT) $<
+
+version.c: makeversion
+       ./makeversion $(VERSION) $(SUBVERSION) $(TARGET)
+
+toosl/analysemap: tools/analysemap.c
+
+tools/memhogs: tools/analysemap
+       cp tools/analysemap tools/memhogs
+
+tools/binman: tools/binman.c
+
+tools/filesizes: tools/filesizes.c
+
+tools/make4x6: tools/make4x6.c
+
+font4x6.c: tools/make4x6
+       tools/make4x6 >font4x6.c
+
+loader/loader.com:
+       +make -C loader loader.com
+
+ifeq ($(CPU), z80)
+uzi.ihx: target $(OBJS) platform-$(TARGET)/uzi.lnk
+       $(CROSS_LD) -n -f platform-$(TARGET)/uzi.lnk
+       
+uzi.bin: uzi.ihx tools/analysemap tools/memhogs tools/binman
+       tools/analysemap <uzi.map
+       -cp hogs.txt hogs.txt.old
+       tools/memhogs <uzi.map |sort -nr >hogs.txt
+       head -5 hogs.txt
+       makebin -s 65536 -p uzi.ihx >uzi.tmp
+       tools/binman uzi.tmp uzi.map uzi.bin
+       $(MAKE) -C platform-$(TARGET) image
+else
+uzi.bin: target $(OBJS)
+       $(MAKE) -C platform-$(TARGET) image
+endif
+
+# srec_cat -disable-sequence-warning uzi.ihx -intel -fill 0x00 0x0000 0x10000 -output uzi.bin -binary
+uzi.com: target $(OBJS) loader/loader.com tools/analysemap tools/memhogs
+       loader/makeloader loader/loader.com uzi.ihx uzi.com --zerotop
+
+sendcpm:       uzi.com
+       echo -n "!~!~!~" > /dev/ttyUSB1
+       sleep 0.1
+       echo "rboot 200" > /dev/ttyUSB1
+       sleep 0.1
+       sendcpm uzi.com
+       echo "uzi 1" > /dev/ttyUSB1
+
+clean:
+       rm -f $(OBJS) $(JUNK) uzi.cdb uzi.com uzi.bin uzi.map uzi.noi uzi.ihx core *~ include/*~ version.c tools/analysemap tools/memhogs tools/binman hogs.txt hogs.txt.old tools/*~
+       +make -C loader clean
+       +make -C platform-$(TARGET) clean
+
+clean-all: clean
+       $(foreach target,$(TARGET_LIST), make -C $(target) clean;)
diff --git a/Kernel/PORTING b/Kernel/PORTING
new file mode 100644 (file)
index 0000000..6abe8e2
--- /dev/null
@@ -0,0 +1,606 @@
+Minimal Requirements
+--------------------
+
+- Z80 processor
+- 128K memory (the kernel itself wants between 32 and 40K R/O and about
+  8-16K R/W depending upon the configuration.
+- Some kind of memory banking giving a common area and multiple banks
+- A storage device, preferable hard disk or SD card or similar
+- A timer interrupt (but you can sort of run single user with just a serial
+  / keyboard irq)
+
+In the ideal world
+  256K of RAM or more
+  An RTC
+  16K flexible memory banking
+
+With a bit more work (ie the planning for it is in place but someone needs
+to do the work) it should also be possible to run with
+
+- Other 8bit processors with banked RAM (eg 6809)
+- The kernel code banked in ROM in 3 x 16K banks
+- Base/limit address space with a common area and ideally two ranges
+  (eg Z180)
+- 16/32bit processors with either segments, base/limit pairs or just
+  vfork() style switching
+
+Porting Fuzix to a new Z80 based machine generally requires the following
+
+- Pick an output device that is easy to drive (serial or video) and write a
+  mininal test output driver for it standalone. Serial is usually best if
+  you don't have a character mapped console
+
+- Extend that into a suitable boot loader, unless loading from existing
+  firmware (see tips below for CP/M booting)
+
+- Select the appropriate model
+
+  CONFIG_SINGLETASK
+  - single tasking (no fast swap device, limited memory). Processes are
+  run one at a time and the parent is run length compressed into upper
+  memory by default. This will provide all your pagemap helpers
+  automatically. This can (untested yet) be combined with SWAP_DEV if
+  you have a slow swap device to use other than RAM. With a fast swap
+  device and single process you can define SWAP_DEV and not define this.
+
+  CONFIG_MULTI
+  - multi process in memory at once (multiple non kernel banks)
+
+  SWAP_DEV
+  - swap device number if you have a suitable device for swap. This
+    is usually best done after it boots ok
+
+- Pick an appropriate platform to clone.
+
+- A lot of standard code is available to make porting easy
+
+ CONFIG_BANK16 selects support for four flexible 16K bank registers
+
+ CONFIG_BANK32 selects support for two flexible 32K bank registers
+
+ CONFIG_BANK_FIXED selects support for systems where you have a selector for
+ all of the lower parts of memory in banks, and a fixed common at the top.
+ It can also be used if the banking is more flexible but has annoying
+ restrictions like not being able to map banks into other addresses (eg MSX1)
+
+ CONFIG_BANK_LINEAR selects a system where memory is managed linearly with
+ base/limit pairs or similar and a common. This isn't yet tested but is
+ intended for Z180 and similar, and might be handy as a basis for M68K etc
+
+ CONFIG_USERMEM_C tells the kernel to use the standard C helpers for user
+ memory copying. Set this initially for new architectures or for 6502/809,
+ and define BANK_PROCESS and BANK_KERNEL to switch kernel/user space. Make
+ sure you keep the code in common. The Z80 tree has a standard asm version
+ that uses your map_process/map_kernel functions.
+
+ CONFIG_VT
+ VT_WIDTH, VT_HEIGHT, VT_RIGHT, VT_BOTTOM
+
+ Include a standard virtual terminal core based upon VT52 emulation
+
+ CONFIG_VT_SIMPLE
+
+ Lets you define VT_BASE and it will drive a character mapped display with
+ typical layout. You may need to wrap vt calls in page switches according
+ to your platform
+
+ CONFIG_FONT_8x8 and CONFIG_FONT_4x6 will include fonts. For 4x6 font usage
+ see nc100.s. The fonts are put in a special segment _FONT and your crt0.s
+ needs to decide where to place it. If you place it after the data then
+ the binman tool will relocate it to the end of the packed commonmem so it
+ can be moved into another segment (eg to be with the video screen data).
+ See pcw8256 for an example of this.
+
+- Set the basic system parameters
+
+ TICKSPERSEC   -       clock rate
+ PROGBASE      -       low memory address fo applications (should be 0x100
+                       to run standard binaries). Some bits of start.c
+                       still break if this is not 0x0100
+ PROGTOP       -       first byte above main memory, usually the start of
+                       the udata area and common memory. Typically above
+                       0xF000 but if your system has a fixed upper common
+                       then this may need to be lower (eg 0xC000)
+ BOOT_TTY      -       the device you will use as your 'console' at boot
+                       time
+
+ CMDLINE       -       pointer to a command line passed from the
+                       loader/firmare. If booting from CP/M (see below) use
+                       0x88
+
+ NUM_DEV_TTY   -       number of tty devices (video consoles/serial)
+
+ NDEVS         -       number of entries for disk/block devices at the
+                       start of your device table
+ TTYDEV                -       device init will use as input/output (usually BOOT_TTY)
+
+ NBUFS         -       number of buffers for disk cache (each a bit of 512
+                       bytes)
+
+ NMOUNTS       -       number of things that can be mounted at a time
+                       (NDEVS or less)
+
+
+If you have non interrupt driven serial ports then poll them in your IRQ
+handler and provide a platform_idle which also polls the ports (makes it
+feel much snappier).
+
+Provide a putchar() that writes to your console correctly either via direct
+debug code or later via the tty helper. Provide a similar (register
+preserving) assembler hook in outchar. That gives you a usable kprintf in C
+and outhl/outde/outcharhex/.. series of methods in assembler for debugging.
+
+On a non single user system provide a pagemap_init which loads a list of
+page numbers via pagemap_add. The numbers must *not* include a page 0. If
+need be bias or xor with 0x80 or something. At boot you should have 2 or 4
+pages mapped (depending upon your kernel), one of which (usually the top) is
+common. Add all the pages that are not kernel.
+
+In the 16K bank case you then lastly add the common page. This will then be allocated
+to init and become the common for the init. That means you must keep kernel
+code/data below 0xC000. Right now that is easy enough but once we add TCP/IP
+might need banking.
+
+On 32K banking you can't do this so will need to play uarea swapping games
+and keep the top bank as a kernel bank. This is much uglier but unlike
+UZI180 only needs to swap uareas around on a true task switch.
+
+If your system has a fixed common area with single not flexible banks then
+load the bank selections into the table rather than just loading pages
+
+MAX_MAPS is the max number of pages (or banks whatever you have) that you
+can have. Set it to the largest you might need and load those present if
+your system comes in different memory sizes.
+
+If you are using swap then
+
+SWAPBASE       -       lowest address that will be swapped
+SWAPTOP                -       highest address that will be swapped
+                       (TOP - BASE is usually a round number of blocks
+                        so you don't have to do disk gymnastics in the driver)
+                       Include the uarea in the common bank.
+
+UDATA_BLOCKS   -       special use (set to 0)
+UDATA_SWAPSIZE
+SWAP_SIZE      -       number of disk blocks needed to hold all the swap
+                       for one process
+MAX_SWAPS      -       largest number of SWAP_SIZE chunks that will be used
+                       (bounded by disks/process table size/common sense)
+
+
+
+
+
+Functions to provide: (*) indicates they should be in COMMONMEM
+
+init_early     -       assembler function called right at the start, can be
+                       NULL
+
+init_hardware  -       called before main and C entry
+
+                       Set _ramsize
+                       Set _procmem
+                       call _program_vectors with HL = 0
+                       (will map_kernel and set the RST vectors)
+                       Enable any timers
+                       Call _vtinit if you are using VT
+                       Do *not* enable interrupts
+
+_program_vectors(*) -  Program the vectors
+
+                       You can usually just re-use the default but this may
+                       vary if you have odd commonmem setups
+
+_trap_monitor(*)    -  Return to ROM monitor/debugger or similar
+
+_trap_reboot(*)        -       Reboot the machine (may be useful to not do so
+                       during debug)
+
+map_kernel(*)  -       Set the page mappings to those used by the kernel
+
+                       Must damage no registers
+
+map_process_always(*)- Set the page mappings to those of the current
+                       process. These are held in the 4 bytes UDATA__U_PAGE
+
+map_process(*) -       If HL is 0 map the kernel, if not map using the 4
+                       bytes pointed to by HL
+
+map_save(*)    -       Save the current mapping state
+
+map_restore(*) -       Restore to the saved mapping state
+
+                       These two routines will be called with the same
+                       common mapped in all cases. The state can therefore
+                       be saved to common memory.
+
+outchar(*)     -       Output the character in A to your debug device.
+                       Affect no other registers
+
+
+_switchout(*)  -       Switch out a task
+
+                       Copy the one from an appropriate kernel type. This
+                       will hopefully move into the core code soon
+
+_switchin(*)   -       Switch in a task
+
+                       Make the task we want to run runnable. If it is no
+                       disk and we are swapping then swap it in, if there
+                       is no room in memory swap stuff out
+
+                       Scary bits, copy from a suitable example and do not
+                       debug after midnight.
+
+_dofork(*)     -       Create two instances of the same task
+
+                       This varies by platform type and the code is fairly
+                       scary. Copy a suitable example. This will also
+                       hopefully end up in the core once it's stabilized.
+
+If you are using vt
+
+_scroll_up     -       Scroll display up one line
+
+                       The vt layer will ask for the bottom line clear itself
+
+_scroll_down   -       Scroll display down one line
+
+                       The vt layer will ask for the top line clear itself
+
+_plot_char     -       Write a character to the display. Passed arguments
+                       are y, x and the character
+
+_clear_lines   -       clear the display from line y for n lines
+
+_clear_across  -       clear the current line from y,x for n characters
+
+_cursor_on     -       put the cursor at y,x
+
+_cursor_off    -       remove the cursor
+
+
+C interfaces
+------------
+
+Devices.c
+
+dev_tab is the device table for your platform indicating what is present.
+Usually best taken from another platform and hacked up
+
+bool validdev(uint16_t dev)
+
+Check a device is valid. Cut and paste, it just needs to live with the
+definition
+
+void device_init(void)
+
+Called early on before init runs so devices can do initialization before
+they are opened. May well be blank
+
+Devtty.c
+
+Define a TTYSIZE buffer for each device present
+Copy the struct s_queue from another filled in for your devices/buffers.
+
+Provide putchar(c) if it is not already provided by your asm code
+
+bool tty_writeready(uint8_t minor)
+
+Returns true fi you can write bytes to this port (1..n). For things like
+video consoles just return true
+
+void tty_putc(uint8_t minor, char c)
+
+Write a character to the tty minor
+
+int tty_carrier(uint8_t minor)
+
+Return 1 if carrier raised or you arenot implementing the carrier interfaces
+yet.
+
+void tty_setup(uint8_t minor)
+
+Do any tty set up required. Called on open and when the user changes the
+termios parameters for the tty so you can set speed etc.
+
+void platform_interrupt(void)
+
+Called every interrupt in kernel context with the process state saved. You
+may not sleep/taskswitch, you need to keep stack use fairly low. Every timer
+tick you should call timer_interrupt() and the OS will do its other
+housekeepking.
+
+Note: timer_interrupt may switch task and thus common so call it last unless
+you are sure you *really* understand what is going on with fork.
+
+If your tty devices are polled then poll them on the IRQ if not then handle
+them here. Either way call tty_inproc(minor, c) with the character to queue
+it for input. This may call back to your tty_putc.
+
+
+Main.c
+
+uint8_t *swapout_prepare_uarea(ptptr p)
+uint8_t *swapin_prepare_uarea(ptptr p)
+
+Just return NULL unless you are doing clever things with udata
+
+void platform_idle(void)
+
+Usually you want to either poll the non interrupt driven devices (ttys) or
+if they are IRQ driven then execute a halt instruction. In some cases you
+may want to enter a processor low power state or drop to the lowest clock
+speed.
+
+void do_beep(void)
+
+Provided for the vt driver. Make an irritating noise. The emulation is vt52
+so arguably the beep emulation should sound like someone stripping the gears
+on a tank while trying to reverse.
+
+void pagemap_init(void)
+
+See notes earlier - add your pages to the pagemap.
+
+
+Disk Devices
+
+_open(uint8_t minor, uint16_t flag)
+
+is called on opening. Usually it just checks minor is valid but could check
+if a disc is loaded etc
+
+_close(uint8_t minor)
+
+is called on close (eg to force a final flush or to unlock)
+
+_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+
+is called to read blocks. It has three modes
+
+       rawflag = 0
+
+       A normal read to kernel space. Must be supported. Fetch the
+       requested 512 byte block
+
+       udata.u_buf->bf_data is the buffer data to load into
+       udata.u_buf->bf_blk is the block number
+
+       If your media is 128 or 256 byte sectors you get to read several.
+
+       rawflag = 1 (optional)
+
+       Allows the char equivalent device to be opened for direct copies
+       to the userspace. This means the copy itself will need to be run
+       from common memory.
+
+       udata.u_count is the number of blocks
+       udata.u_base is the address
+       udata.u_offset.o_blkno is the starting block
+
+       Data goes to the current user process
+
+       rawflag = 2 (swap device only)
+
+       swapcnt is the number of blocks
+       swapbase is the starting address
+       swapproc is the process to swap in
+       swapblk is the block number to start at
+
+For a simple system you only need to implement rawflag = 0 and error = 1.
+rawflag = 2 will only occur if this is your SWAP_DEV. rawflag = 1 support
+may become mandatory as it'll be a good way to optimise execve().
+
+In the swap case beware of the following. You may get issued a request to
+write/read processes other than the current process. The map_process
+function is defined on 16K banked platforms to remap banks 0-2, as 3 is
+switched on task switching and holds the common copy, uarea and top of
+process. That means that while uput/uget do the right thing for the current
+process, it will *not* do so for addresses above 0xC000 of another process
+and this may require special handling.
+
+_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+
+Same arguments, other direction. This means a lot of drivers turn both into
+a call to a common transfer method.
+
+
+
+A Note On Geometry Mapping
+--------------------------
+
+The conventional mapping of block numbers is to start at track 0, side 0,
+sector 1 as block 0, and then follow the usual upward pattern. The OS
+reserves block 0 as a boot block, and puts the superblock at block 1.
+
+If you have a disc with a loadable kernel on it then put the kernel on the
+*end* of the disc. This means you get a smaller file system on the media but
+also means you don't to special case 'boot tracks' or waste any of a data
+disc.
+
+The limit on blocks is 65536. Be careful of wraps and overflows when mapping
+the geometry. With large media you can provide several 'disks' with
+different minor numbers and add 65536 blocks to the base depending upon the
+minor.
+
+Nothing stops a driver doing partition tables but we don't currently have a
+library for it.
+
+BinMan
+------
+
+BinMan processes the SDCC final output image from a ROMable format to
+something that fits disc loading. It moves the initializers into the
+initialized area (so crt0.s doesn't need to) and it then appends the common
+memory on the old initializer address and trims the image. It doesn't touch
+relocations. On startup crt0.s sorts out any mappings and then copies s__INITIALIZER
+into s__COMMONMEM for l__COMMONMEM before zeroing s__DATA for l__DATA
+
+Tips
+----
+The most important bit of debug initially is usually proving you got from
+your loader to crt0, and then tracking bank changes until the bank code
+works properly. On an emulated system you can make it print out bank
+switches in the emulator - very useful
+
+If you build a FUZIX kernel image so that cmdline is 0x0088 and it starts at
+0x0100 then you can run it from unbanked CP/M (banked CP/M may get a bit
+odd unless your crt0.s handles it specially).
+
+Hard Cases
+==========
+
+Machines with low banks and a single fixed common
+-------------------------------------------------
+This needs mucking around copying the udata area back and forth between the
+system and a cached copy (much as is needed on 32K banking). Take a look at
+the z80pack virtual platform and port to see how to do this. You can
+probably simply import z80pack and adjust the drivers. Note that z80pack
+supports multiple bank/fixed divides and numbers of banks, so you can bring
+z80pack up with your platform configuration
+
+You may have to decide between limited process size or being prepared to do
+copying tricks to copy big chunks of memory around. 
+
+If you have only a single user bank however it's easy - see z80pack-lite 8)
+
+Inflexible banking
+------------------
+Systems where some banks can only fit at some locations. In this case copy
+bank16k or bank32 as appropriate but update your swapper logic to find the
+owner of a page in the ranges you need and victimise them, or if they are
+not usefully flexible then set up fixed sets of them as "banks" and use the
+fixed bank model.
+
+The pagemap_alloc/realloc and friends will also need updating - perhaps with
+2 or more map tables.
+
+In other cases (eg the TRS80) you can only have one "high" bank mapped. This
+really limits the TRS80 to single task with floppy or swapping to disk with
+HD. Given the 128K limit that isn't too bad.
+
+The other examples are things like the Microbee (one 32K bank is flexible
+the other is very rigid), and things like the Sinclair Spectrum/Amstrad CPC boxes.
+
+Research Problems
+-----------------
+In theory the kernel could be built as 2 or 3 16K banks of pure code, plus data
+and some overspill in RAM. This might be very useful for Amstrad CPC type
+boxes or the Sinclair Spectrum 128+/+2/+3 type boxes with awkward mapping
+limits. Sadly sdcc isn't yet good enough to do this for you.
+
+Swapping Hints
+--------------
+
+Your swap device does not need to be a disk. If you have a really demented
+memory map and page limits it may actually make sense to treat all the near
+unusable memory as swap, especially in singletasking mode. In fact in
+singletasking mode your swap acts as a stack. Likewise if your system has
+lots of RAM accessible through a small window you can treat it as "swap"
+rather than process memory
+
+Known Performance Problems
+--------------------------
+
+execve pulls all pages into kernel maps and then copies them to the task.
+Fixing this is non trivial but may happen. If so then raw = 1 support for
+all disks will become mandatory.
+
+fork is generally used as fork/execve. This causes a copy which is somewhat
+surplus but is very bad on singletasking as it is both slow (the compressor
+wants rewriting in Z80 someone) and also may prevent the child task fitting.
+BSD unix implemented vfork() some systems implemented forkexecve(). We
+should probably support vfork().
+
+Other Processors
+----------------
+
+Currently only Z80 is supported. Clones should also work as should FPGA cores
+like T80. The current build uses no undocumented instructions in any core
+code.
+
+Z180 is not yet supported. This requires a rather unique memory banking
+module to be debugged plus some driver pieces. It should however then enable
+systems like N8VEM Mark IV and maybe even the 'Super TRS80' hacked hardware.
+
+Platform wise there are lots that could be supported. MSX is a notable gap,
+especially given that UZIX has some MSX code.
+
+It ought to be possible to port UZI to any other small processor with
+banking. That would include banked 6809/6309 systems and perhaps 65C816
+(Apple IIGS anyone ?) with a suitable compiler. The current core code has
+been test built purely to verify it seems ok on 6809 (gcc) and 6502 (cc65).
+Various endianisms in the core code have been fixed but there may be more.
+
+The constraints roughly speaking for any port are
+
+- banked memory
+- near full 8bit address space
+- some way to do udata. (or take the hit of making it a macro pointer)
+- an ANSI C compiler
+- timer interrupt, and preferably tty I/O interrupts
+- blocking disk I/O. Fundamental to the size and design of the UZI core is
+  the assumption that accessing user space and block I/O do not block and
+  reschedule
+- uniprocessor (well OK there are ways and means to do more but it won't be
+  too happy above a couple I suspect)
+
+Without banked memory but with a large address space you would need vfork()
+and relocatable binaries. Doable as AmigaOS showed but forget swapping.
+
+As far as I can tell we have suitable open toolchains for
+
+6809 (gcc fork) - although 6809 is well served by NitrOS/9. The core code
+has been built with gcc 6809 as a minimal sanity test.
+
+68HC11/2 (for the variants with banked RAM)
+
+TI990 (gcc development) - http://www.cozx.com/~dpitts/tigccinst.html
+(TI 99/4A anyone ;-))
+
+8086 is a gap but I'm working on pcc 8086 targets and could do with help
+there (http://pcc.ludd.ltu.se/). Once the compiler is done the port should
+be easy and cover both XT and 286.
+
+6502 is probably a cause too far (but prove me wrong...). The core code will
+build with cc65.
+
+658C16 seems to lack a serious open compiler although there is a tcc port !
+(snes-sdk)
+
+The ANSI ACK can build rather decent 8080 code. Whether the output would fit
+in 64K and anyone ever built a banked 8080 who knows 8)
+
+Various other early minicomputers probably also fit the target.
+
+Going to early 32bit CPU is hard because
+- not all of the core code is 32bit clean (I've tried to begin marking out
+  the argument parameters and the like to fix it)
+- the fs code knows that you can't write a size bigger than the filesystem
+  so other sanity checks would need adding
+
+A 2BSD/RetroBSD port might make a lot more sense anyway on such a system
+
+
+Other Things That Would Help
+----------------------------
+
+Teaching SDCC to generate better code. It's not bad but sometimes it makes a
+right mess, especially of long types. Someone also needs to write the
+longlongs signed mod function and fix the fact that discarding the output
+of a longlong call currently blows up sdcc.
+
+Writing a longlong implementation of mod for SDCC (needed for the C lib)
+
+We want 64bit time_t values in the ABI in order to get 2038 safety. We need
+32bit versions to support non Z80 systems perhaps using structs for time_t
+
+SDCC call by register
+
+A tool to take all the compiler asm output of FUZIX on Z80, identify common
+code blocks containing only internal references (jump/call) and (considering
+segments) turn chunks of them into calls (sort of an executable compress).
+O88 could do this for 8086. If we can shave a few K off this way it would
+be brilliant
+
diff --git a/Kernel/README b/Kernel/README
new file mode 100644 (file)
index 0000000..63b414b
--- /dev/null
@@ -0,0 +1,929 @@
+FUZIX
+=====
+
+FUZIX is a fusion of various elements from the assorted UZI forks and
+branches beaten together into some kind of semi-coherent platform and then
+extended from V7 to somewhere in the SYS3 to SYS5.x world with bits of POSIX
+thrown in for good measure. Various learnings and tricks from ELKS and from
+OMU also got blended in
+
+What does FUZIX have over UZI
+=============================
+
+o      Support for multiple processes in banked memory (as per UZI180) but
+       with Minix style chmem and efficient use of bank allocations.
+o      Support for multiple processes via hard disk or non mappable RAM
+       drive switching (as per UZI, UZIX).
+o      The ability to run single tasking on small devices, for bring up
+       and for standalone tool execution
+o      Support for "real" swapping combined with banked memory.
+o      Proper sane off_t and lseek
+o      Normal dev_t
+o      30 character filenames
+o      Proper sane time_t
+o      System 5 signals (half baked)
+o      Posix termios (does all the original UZI tty did but much can be added)
+o      Blocking on carrier for terminals
+o      Optimisations to avoid bogus uarea copying compared to UZI180
+o      More modern system call API: 3 argument open, mkdir, rmdir, rename,
+       chroot (with correct .. semantics), fchdir, fchmod, fchown, fstat,
+       fcntl, setpgrp, sighold and friends, waitpid, setpgrp, nice
+       O_NDELAY, O_CLOEXEC, F_SETFL, F_DUPFD etc
+o      Address validation checks on all syscall copies
+o      Builds with a modern ANSI C compiler (SDCC)
+o      Core code can be built for 6809 and 6502 so should be far more
+       portable
+o      Core architecture designed to support building and maintaining
+       multiple target machines without forking each one
+o      Helpers to make many bits of implementation wrappers to core code
+o      Lots more bugs right now
+
+What does UZI have over FUZIX
+=============================
+
+o      Can run in 64K of RAM (32K kernel/32K user). FUZIX would need
+       banked ROM or similar to pull this off.
+
+What do the UZI branches have that FUZIX has not yet integrated
+===============================================================
+
+o      Minimal TCP/IP (UZIX 2.0). Unfortunately the original TCP was never
+released openly.
+o      Symbolic links (UZIX)
+o      Various clever fusions of syscalls that may save a few bytes
+       (UZIX)
+o      setprio (UZIX)
+o      Rather crude loadable drivers (UZIX)
+o      Use of __naked and __asm for Z80 specific bits to avoid more
+       .S files than are needed (UMZIX)
+
+Plus OMU has a really clever function passing trick for open/creat and
+friends, while UMZIX has a neat unified "make anything" function.
+
+What Key Features Are Missing Still
+===================================
+o      ptrace, core dumps, ulimit
+o      root reserved disk blocks
+o      banked executables
+o      TCP/IP
+o      select/poll()
+o      Z180 banking support
+o      /dev/tty alias
+o      Support for > 32MB filesystems (but first figure out how to fsck
+       a giant fs on a slow 8bit micro!)
+o      Uptime
+o      Smarter scheduler
+o      Optimisations for disk block/inode allocator (2.11BSD)
+o      CP/M emulator has not yet been ported to FUZIX syscall API
+
+
+Tool Issues
+===========
+o      No useful 8086 compiler option (started work on pcc 8086 but help
+       needed)
+o      6809 gcc and cc65 don't have long long 64bit (for sane time_t)
+o      SDCC has long long bugs and gaps
+o      SDCC can generate ROMmable binaries but not banked ones
+o      SDCC has no register passing function call support, and for some
+       stuff it really shows
+o      SDCC generates quite bloaty small applications. Needs research
+       on how to improve.
+o      None of the above have an O88 style common sequence compressor
+
+
+Platforms
+=========
+o      Z80Pack - used as a dev and test environment for both large swapping
+       mulitprocess and for small single tasking
+o      Amstrad NC100 - real hardware sanity check
+
+Various other platforms are partly filled out to sanity check assumptions
+and start making progress on them. The main need there is now to tackle all
+the billion different ways of interfacing the floppy controllers.
+
+
+
+--------------------------- Historical README files ------------------------------
+
+       UZI180 - Unix Z80 Implementation for the Z-180 (UZI180)
+    Adapted from UZI by Doug Braun and UZI280 by Stefan Nitschke
+               Copyright (C) 1998 by Harold F. Bower
+                    <HalBower@worldnet.att.net>
+          Portions Copyright (C) 1995 by Stefan Nitschke
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License (file LICENSE.TXT) for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+UZI180 is a multi-tasking, multi-user operating for the Zilog Z180 family
+of microprocessors.  It is a port of the original UZI incorporating many
+fixes from UZI280 and some additional features.  Significant changes
+include an updated floppy disk driver based on a NEC765 derivative cont-
+roller, a restructuring and reorganization of the various kernel modules
+to ease porting to different hardware platforms, a simpler loading
+structure from CP/M, and an integral (albeit minimal) CP/M 2.2 emulator.
+The task was undertaken to learn more about the Unix operating system and
+the C programming language with an eye to using it to replace several
+aging CP/M systems.
+
+Like the original UZI, this system is based on Unix Edition 7 which was
+one of the direct predecessors of Unix System V.  UZI180 incorporates the
+original system calls and the UZI280 extensions added by Stefan Nitschke.
+Some minor additions were also added to provide additional System V compa-
+tible features.  As stated in the original documentation, there are only a
+few significant differences in the UZI kernel calls.  The principal
+deviations are:
+
+ - 32-bit return values are not provided, so data structures are passed
+   via pointers to pass essential information.  "seek" is therefore incor-
+   porated as a kernel function with "lseek" provided as a library call.
+
+ - The system "times" are reported in a different format than the standard
+   32-bit count of seconds since 1 January 1970.  32-bit Date/Time struc-
+   tures are in the packed binary form used in IBM PCs, therefore
+   resulting in 2-second granularity.  As a convention, the 0-99 year
+   should be interpreted as: 70-99 implying 1970-1999, and 0-69 being
+   2000-2069 to provide Year 2000 compliance.  Standard functions are
+   available as library routines.
+
+ - The "stat" call has a different file length format due to the 32-bit
+   length omission and use of only 16-bit block and inode numbers.  A data
+   structure is used to contain the information (see library source for
+   details).
+
+ARCHITECTURE:
+
+UZI180 makes extensive use of the Memory Management (MMU) of the Z180 core
+to provide as much process isolation as possible with the chip.  Since the
+MMU granularity is 4k, this establishes the basic process structure.  The
+top 4k of logical address space (one MMU slice) is defined as Common1 memory
+space and contains critical routines that either must always be resident in
+memory, or are associated with the currently-running process. Some of the
+key elements placed in the Common memory space are:
+
+       - Interrupt Handlers
+       - Process Swapper
+       - System and Interrupt Stack Space
+       - User Process Data Structure
+       - Kernel Service Handler
+
+A full 64k is assigned to each process, with 60k available to application
+code and data, with the remaining 4k used for system storage.  This
+organization permits one 64k bank for the kernel/common memory and seven
+process banks on a 512k system where all RAM is usable.  The UZI180 memory
+map therefore appears as:
+
+                 First 64k           Subsequent 64k banks
+       FFFF    +------------+          +------------+
+    Common     |   Common   |          | Task Store |+
+       F000    +------------+          +------------+|+
+               |            |          |            |+|+
+               |   Kernel   |          |  Process   ||+|
+    Banked     |    Code    |          |    Code    |||+
+               |            |          |   & Data   ||||
+               |            |          |            ||||
+       0100    +------------+          +------------+|||
+               |  Reserved  |          |  Reserved  |+||
+       0000    +------------+          +------------+|+|
+                                        +------------+|+
+                                         +------------+|
+                                          +------------+
+
+Areas marked as "Reserved" are used for Restart and Interrupt vectors,
+and to host the required Page 0 storage elements for the CP/M Emulator.
+Constructing executable code modules starting at 100H also allows use of
+normal CP/M tools without conflicting memory use.
+
+The architecture accomodates MMU base addresses beginning at the first
+available RAM address wherever that is.  For YASBEC and P112 systems that
+shadow the ROM into RAM, the initial BBR (MMU Base Bank Register) reading
+is 08H, while on the MicroMint SB180 RAM begins at 40H.  64k Banks will
+therefore begin with BBR values of 08H, 18H, ..., 78H for the former; and
+40H, 50H, ..., 70H for a 256k SB180.
+
+For 256k systems that have all RAM available (i.e. do NOT shadow the ROM),
+the kernel and only three process banks will be available.  While this may
+be minimally usable for a single-user system, a 512k system is the minimum
+recommended.  For systems which DO shadow the system ROM, 32k is normally
+reserved (beginning at physical RAM address 0), thereby reducing available
+RAM by 32k.  This leaves 480k available in a 512k system resulting in only
+six process areas after allowing 64k for the kernel and common bank.  The
+last 32k will be unused.
+
+The algorithm for computing true 20-bit addresses in a Z180 (for DMA) is:
+
+       BBR     7654 3210
+       Addr         hhhhhhhh llllllll
+               ----------------------
+               bbbb xxxxxxxx yyyyyyyy
+
+An initial check should be made for common area access (assumed to be the
+top 4k) which will be addresses of the form "1111hhhh llllllll" or FxxxH.
+For these addresses, the raw BBR value for the first 64k of usable RAM is
+added.  As an example, the first byte of the Common Area is computed for
+DMA use on a P112 with 512k of memory (ROM shadowed) as:
+
+       BBR     0000 1000                       08
+       Addr         11110000 00000000           F000
+               ----------------------          -----
+               0001 01110000 00000000          17000
+
+A kernel variable (osBank) for the Common Area holds the BBR value for the
+top 4k which is always accessible by the processor.  It is used to specify
+the source address when swapping out, and for the destination address when
+swapping in.  The BBR value associated with each process space is stored
+both in the kernel process table, and in each process' user data block.
+This value is used for the other address in process swaps.
+
+Task switching consists of saving the current process status in the User
+stack and data area, block moving the user data area and stacks to the
+respective process area in the reserved top 4k (via DMA), restoring the
+new task's data into common memory (also via DMA), changing the Bank Base
+Register in the Z180 MMU to bring the new task in context, resetting the
+new process' stack pointer, restoring processor status and continuing as
+before.  This results in relatively rapid response since the bulk of time
+required is due to two 768-byte DMA transfers which consume 1536 * 6 T-
+states or 9216 / 18,432,000 = .0005 Sec = 500 microseconds on a 18.432 MHz
+P112 or YASBEC upgraded with the Z8S180, and double this time, or 1000
+microseconds (1 millisecond) on a standard 9.216 MHz YASBEC.  This ignores
+any additional time due to insertion of memory wait states and the
+relatively insignificant overhead associated with housekeeping.
+
+Time slices were initially set to 50 mS (20 ticks per second) based on one
+of the internal Z180 Programmable Reload Timers.  At that rate, less than
+4% of a time slice was consumed in swapping processes.  The development
+systems have subsequently shortened the slice time to 20 mS to minimize
+data loss from polled serial ports.  A disadvantage of shortening the time
+is that a greater percentage of CPU time is consumed during process swaps
+with a subsequent lengthening of task run times.  This may be adjusted by
+appropriately setting parameters in the C and Assembly include files and
+re-building the kernel.
+
+Since peripherals in small systems often are not capable of Interrupt-
+driven operation, UZI180 implements polling of such ports during timer
+interrupt cycles.  Unfortunately, this can lead to inaccurate timekeeping
+if the timer is the sole source of Real Time in the system.  A prime
+example of this is in the Floppy Disk Driver.  Polled operation often
+dictates that interrupts be disabled during disk accesses to avoid data
+loss and/or corruption.  During the comparively long time which may elapse
+(up to one revolution of 200 milliseconds for 3.5" drives), several clock
+ticks may be lost before timekeeping resumes.
+
+Wall-Time is corrected automatically by reading the Real-Time Clock every
+time the number of ticks-per-second (set by a constant in include files)
+elapses and updating a global kernel variable.  This variable is then used
+by kernel functions when necessary to perform such tasks as time stamping
+files and returning current time-of-day.
+
+Polled IO sampling on timer interrupts is not so easily handled and data
+loss may be significant.  For systems which must operate in this manner,
+it is recommended that low-priority processes be placed on those inter-
+faces.  Also, use of peripherals that disable interrupts for long periods,
+such as polled Floppy Disk drivers, should be minimized.
+
+
+OPERATION:
+
+The UZI180 kernel is Process 0 and executes in the lowest 64k of RAM in
+the system as a standalone CP/M executable program.  Several stages of
+initialization occur when first started.  The code and initial data which
+is destined for the Common Memory is moved into position, having been
+linked to an executable image during the link process.  After initializing
+various kernel data elements, Process 1 is initialized in the lower 60k of
+the next higher 64k memory region.  Normally Process 1 is "init" which
+logs in users and starts (forks) a shell or other user interface.  Each
+consecutive fork without termination of a previous process is loaded into
+the lower 60k of successively higher 64k increments.
+
+When a new process is initiated, data in the process' address is prepared
+with several pieces of data.  Necessary arguments and environment
+variables are copied into high addresses along with the pointer arrays per
+standard UZI definitions.  Location 0H is initialized with a jump to a
+TRAP (illegal instruction fetch) error handler, and location 0030H (RST
+30H) with a jump to the kernel service handler.  Both of these handlers
+reside in the Common Memory bank beginning at 0F000H.  Version-specific
+locations may also be initialized at this phase such as the Interrupt
+Vector at 0038H (RST 38) and the Non-Maskable Interrupt at 0066H.
+
+Process swaps are initiated by a simple timeout of a per-process counter
+which is decremented.  When a process is initiated (via an execve kernel
+call) or the process is swapped into context, the counter is initiated to
+a defined priority value.  Each "tick" of the periodic clock interrupt
+decrements the counter until it reaches zero.  At that time, the User data
+and associated stacks (User, Swap and Kernel) are copied to the highest 4k
+of the respective process' memory space via DMA, data for the next
+runnable process is loaded into the Common area, and the new process is
+swapped into context by remapping the Bank Base value of the Z180's Memory
+Management Unit.
+
+UZI180 kernel service calls are initiated by pushing necessary parameters
+and the desired function number on the stack and executing a Restart 30H.
+A jump to the service handler in common memory was placed at 0030H during
+process initialization.  Since a Restart functions as a one-byte CALL, a
+return address is placed on the stack below the function number.  The
+Service handler obtains the stack address, switches to a kernel stack in
+common memory, extracts information (function number and parameters) from
+the user stack, switches the kernel in context, and passes control to the
+kernel function process handler.  When the function completes (except for
+_exit), status information is passed to the kernel exit code in common
+memory, the user process is restored to context along with the user stack,
+and the Restart "returns" to the user code.  Parameters are pushed onto
+the stack in standard C form of right to left as specified in the function
+declaration (contrary to UZI and UZI280).  This places the left-most
+declared parameter immediately above the return address on the user stack.
+
+Executable programs in UZI display the CP/M roots of the system in that
+all programs begin execution at 100H.  In melding the original Unix tech-
+nique of testing the first character(s) of a file for "magic numbers" with
+CP/M, all executable programs in UZI require that the first instruction be
+a long jump (JP xxxx, opcode 0C3H).  For native UZI applications, this
+header is contained in the crt.obj file linked with all executable files.
+UZI180 modifies this file to follow the jump with a text string containing
+the three letters 'UZI'.  If these three letters are missing but the
+"magic number" 0C3H is present, then a CP/M executable is assumed and
+execution commences under a CP/M emulator described below.
+
+
+EMULATOR:
+
+In addition to the UZI kernel service calls used by native applications, a
+minimal CP/M 2.2 emulator is built into UZI180 to allow many existing CP/M
+and Z-System utilities to run under UZI180 without modification.  The
+emulator intercepts CP/M Bios and Bdos function requests and interprets
+them into equivalent UZI kernel calls, or processes them directly.  To
+minimize the amount of memory consumed, only essential functions are
+included, and not all programs will function correctly.  Some of the more
+significant limitations of the emulator are:
+
+       - No Z-System data structures (ENV, IOP, RCP, FCP) are included
+       - Only Drive A:, User 0 (as the current directory) is available
+       - No ALV bits are included so Directory programs will be unable
+             to report free space
+       - The Bdos size is smaller than 3.5k so programs assuming standard
+             components by subtracting from Bios WB address will be wrong
+       - No Command Processor is included
+
+When needed, the emulator is moved into high process memory below the env
+and arg parameters.  Instead of transferring execution to the program at
+100H as an UZI executable, the process begins by executing the base code
+of the emulator.  Code at this location is later overwritten by the CP/M
+stack since it is only used during process initialization.  This sequence
+sets up CP/M vectors at 0H (Bios Warm Boot), 5H (Bdos service vector),
+catenates argv parameters into a capitalized command line tail in the
+default buffer starting at 0080H, and initializes other storage locations
+(Current Drive/User, FCBs, etc) before beginning execution at 100H.  CP/M
+program termination by executing either a Bios Warm Boot or Bdos function
+0 will trigger an UZI _exit kernel function and terminate the process.
+
+In the initial form, env parameters are not used by the emulator, but use
+of the PATH variable is planned to make the system more usable.
+
+
+DEVELOPMENT ENVIRONMENT.
+
+The bulk of UZI is programmed in the C language under the CP/M 2.2 or
+compatible operating system.  Doug Braun's original UZI was written with
+the Codeworks' QC compiler which resulted in some odd interfaces since
+parameters were passed the system stack in backwards order (left-to-right)
+instead of the conventional right-to-left ordering used in the C program-
+ming language.  UZI280 and UZI180 were both written for the Hi-Tech ANSI
+Standard compiler Version 3.09 released for non-commercial use in 1987 and
+included in Walnut Creek's CP/M CD-ROM.  The Hi-Tech package also included
+a Z80/Z180 assembler, linker, librarian and source code for the CP/M run-
+time library.  This system forms the complete development environment
+(less text editor) for UZI180.
+
+The Hi-Tech Compiler requires a rather large Transient Program Area to
+compile the UZI sources.  Consequently, users normally operating with the
+Z-System may need to remove several of the standard ZCPR3.x components to
+free up enough memory to compile the system.  UZI180 was developed on the
+author's Banked and Portable (B/P) Bios system with banked ZSDOS2 and
+generated using autosizing of the system (BDOS and ZCPR) with no RCP or
+IOP.  Since the compiler overwrites the Command Processor, the base of
+BDOS forms the upper limit of Transient Program Area which is 0E486H in
+the author's system.  The BIOS Warm Boot vector is at 0EE03H.  This is
+only slightly larger than a standard 62k CP/M system where the BDOS vector
+is at 0E405H and BIOS WB vector at 0F203H.  A standard 62k CP/M system
+should be sufficient since the majority of initial work occured on a
+slightly smaller system.
+
+Following Stefan Nitschke's lead with UZI280, assembly-language modules
+were added to several portions of kernel code to provide platform-
+dependant interfaces where necessary.  Assembly code modules were also
+added to improve performance, particularly to minimize context switches
+and change parameter passing to the standard 'C' conventions of placing
+parameters on the stack from right-to-left.  In some cases, these assembly
+modules were necessitated by apparent problems with the Hi-Tech compiler's
+ability to handle inline assembly with optimization turned on.  To avoid
+severe performance penalties and code bloat, all modules were compiled
+with optimization turned ON.
+
+When bringing up UZI180 for the first time, you must first extract all
+member files in the basic Kernel library module, and member files for the
+specific version for your platform.  Begin by tailoring values in the
+version-specific files to reflect your needs, particularly the Hard Disk
+parameters in HDCONF.H.  Check the Z180 initialization values in both
+Z180ASM.ASZ and ASMDEF.I to insure that such items as Serial Data rates
+and CPU clock frequency are accurate.
+
+You must next Compile/Assemble all source code C and Assembly modules for
+the kernel.  The simplest way to perform this is to execute the SUBmit
+script CMPILUZI.SUB.  In selecting the software tools for this task, use
+either the original CP/M 2.2 SUB.COM or an equivalent such as SUPERSUB.
+XSUB, EX and ZEX cannot be used since they install in high memory as a
+Resident System Extension (RSX) below the Command Processor, thereby
+reducing Transient Program Area space and creating problems for the
+compiler.  Development of UZI180 used SUPERSUB under the B/P Bios/ZSDOS2
+system described earlier.  NOTE: with Operating Systems such as ZSDOS
+which do not re-log hard disk partitions on warm boots, the $$$.SUB
+temporary file is not re-detected to initiate the next line.  Relogging
+of the hard disk can be forced in a ZSDOS system by executing the ZSDOS
+utility RELOG.COM after each line of the submit script.  All but the
+last line of the script should reflect the appended command when placed
+in the Multiple Command Line buffer.  An example compile command line
+from CMPILUZI.SUB is:
+
+       c -o -c -v process.c;relog
+
+After each module is compiled/assembled, either manually or via the SUBmit
+script, the components must be linked into a loadable kernel image.  A
+script is provided for this purpose which is read into the Hi-Tech linker.
+The script is set to produce an output file of UZI.COM which appears to
+CP/M as a normal COMmand file, but siezes complete control and becomes the
+UZI kernel when executed.  This method of using the script with the Hi-
+Tech linker is needed to handle the case-sensitivity of segment names in
+the Hi-Tech relocatable format.  Invoke the linker redirecting input from
+the script file as:
+
+       link <linkuzi
+
+To aid in system maintenance and debugging, a symbol table (UZI.SYM) as
+well as the UZI.COM kernel image is also generated in this step.
+
+TOOLKIT.
+
+Doug Braun provided several utilities which allow you to make an UZI file-
+system and prepare it for use.  These must be compiled and linked with
+modified versions of UZI kernel modules to form CP/M executable programs.
+Some of the kernel modules are simply compiled with the utility include
+files, while others such as the process and call modules are actually
+older versions of the kernel code with some modifications to run as CP/M
+programs instead of assuming total control of the computer.  In the case
+of the core Floppy Disk driver, XFLOPASM.ASZ, hardware timeout via the
+Interrupt timer is removed for utilities in favor of countdown timers and
+letting the Floppy Disk motors remain running after the initial spinup.
+
+The basic tools are:
+
+MKFS - Make an UZI file system on a block device (HDx, FDx) and prepare it
+        for use.
+
+UDP  - Display specified UZI File System Block Number on the Screen in Hex.
+
+FSCK - Check an UZI file system on a block device for consistency.
+
+UCP  - Copy files between CP/M and an UZI storage device, type files to
+        the CP/M Console, mount/umount another device into the UZI file-
+        system and delete files.  If you are running ZSDOS with file
+        date/time stamping, this program also adds date/time stamps to
+        the UZI file system when copying files to the UZI file system.
+
+Portions of the UCP utility were extracted into stand-alone UZI applica-
+tions during UZI180 development to test various functions of the kernel,
+and to form the necessary core suite of utilities to make the system
+"feel" like a Unix system.  These are also provided along with a re-
+written LIBC library containing the UZI180 interfaces.  A separate .DOC
+file details the steps needed to compile and link applications to form
+native UZI180 executables under CP/M.  UCP may then be used to move the
+resulting executables into an UZI file system from where they may be
+executed.
+
+
+THINGS TO DO. (Beta Notes, 18 August 1998 - HFB)
+
+- Add complete hardware initialization (probably in MACHASM.ASZ) to set
+  all system parameters.  Currently, UZI180 relies on settings performed
+  by CP/M or compatible OS/BIOS prior to booting UZI.
+
+- Add TTYASM.ASZ module for setting the TTY port parameters when changed.
+  Currently, the serial port parameters (Data rate, # Bits, Parity, etc)
+  are whatever was set prior to booting UZI.
+
+- Polish the Floppy Driver (FLOPASM.ASZ) to add variable formats (auto-
+  sense on mount?), local bufffering for 1k sector sizes, and accomodate
+  disk formats with CP/M Boot Tracks.  The module is currently locked
+  into a pseudo-MSDOS 1.44 MB High-Density 3.5" disk format.
+
+- Refine the Emulator a bit and massage the addresses to provide full
+  Environment space (512 bytes) and Argument area (512 bytes max).  Also
+  add path default to a defined CP/M directory for accessing overlays,
+  libraries, etc.
+
+
+                ------------------------------------
+
+
+UZIX - UNIX Implementation for MSX
+(c) 1997-2001 Arcady Schekochikhin
+             Adriano C. R. da Cunha
+                                                     http://uzix.msx.org
+
+What is the UZIX?
+
+       UZIX: UNIX IMPLEMENTATION FOR MSX based on UZI written by Douglas
+Braun and ported to MS-DOS / MSX by Arcady Schekochikhin and Adriano
+Rodrigues da Cunha.
+       UZIX is an implementation of the UNIX kernel written for a MSX/PC
+computer. It implements almost all 7th Edition AT&T UNIX kernel
+functionality. UZIX was written to run on PC (under MS DOS) or MSX2/2+/TR.
+The source code is written mostly in C, and was compiled with Turbo-C (PC)
+or Hitech-C (MSX). UZIX's code was based on public domain Doug Braun's
+UZI, which was written from scratch, and contains no AT&T code, so it is
+not subject to any of AT&T's copyright or licensing restrictions.
+       UZIX implements almost all of the 7th Edition functionality. All
+file I/O, directories, mountable file systems, user and group IDs, pipes,
+and applicable device I/O are supported. The number of processes is
+limited only by the swap space available, with a maximum of 31 processes
+(total of 1024k memory). UZIX implements UNIX well enough to run the
+Bourne Shell in its full functionality.
+       UZIX is very small. The code size of the kernel is less than 30Kb
+(in fact, it's 25.8Kb). I think it is the smallest UNIX 7th Edition-like
+implementation you can get.
+       Due to the limitation of a 64Kb linear addressing space of 
+Z80, UZIX supports only applications with a maximum size of 32Kb.
+
+Features:
+
+* UZIX is running on any MSX system (MSX2, MSX2+, TR and even emulators);
+* Full working multitask environment;
+* Full working multiuser environment;
+* Stable filesystem, almost bugless;
+* Very stable kernel, shell and environment;
+* System shell and utilities running with no errors;
+* Module support (only used by TCP/IP Stack now); 
+* Harddisk support (ESE MegaSCSI and Sunrise IDE); 
+
+How it works:
+
+       UZIX uses MSX2 memory mapper to achieve multiprocessing. On PC
+UZIX use additional PC memory for swapping. In both cases UZIX use 64K of
+virtual address space (full Z80 space or one full segment on PC).
+       UZIX itself occupies the upper 32K of address space, and the
+currently running process occupies the lower 32K.
+       UZIX does need some additional hardware support. First, UZIX uses
+system clock that provide a periodic interrupt. Also, the current
+implementation uses an additional real-time clock to get the time for file
+timestamps, etc. The current TTY driver assumes an polling-driven buffered
+keyboard, which should exist on most systems.
+
+How UZIX is different than real UNIX:
+
+       UZIX implements almost all of the 7th Edition AT&T UNIX
+functionality. All file I/O, directories, mountable file systems, user and
+group IDs, pipes, and applicable device I/O are supported. Process control
+(fork(), execve(), signal(), kill(), pause(), alarm(), and wait()) are
+fully supported. The number of processes is limited only by the swap space
+available, with a maximum of 31 processes (total of 1024k memory). As
+mentioned, UZIX implements UNIX well enough to run the Bourne Shell in its
+full functionality. The only changes made to the shell's source code were
+to satisfy the limitations of the C compiler.
+       Here is a (possibly incomplete) list of missing features and
+limitations:
+
+* The debugger- and profiler-related system calls do not exist.
+* The supplied TTY driver is bare-bones. It supports only one port.
+* Inode numbers are only 16-bit, so filesystems are 32MB or less. 
+* File dates are not in the standard format. Instead they look like those
+  used by MS-DOS.
+* The 4.2BSD execve() was implemented. Additional flavors of exec() are
+  supported by the library.
+* The necessary semaphores and locking mechanisms to implement reentrant
+  disk I/O are not there. This would make it harder to implement
+  interrupt-driven disk I/O without busy-waiting.
+
+Developer notes:
+
+       MSX UZIX can be compiled with any ANSI-compatible C compilers. The
+only true one for MSX is Hitech-C (CP/M version) and MS-DOS Hitech-C
+(cross-compiler). MSX UZIX was written using Hitech-C. You'll find many
+constructions and functions not supported (and also limitations) by other
+MSX C compilers if you try compiling UZIX with them. Of course UZIX can be
+compiled using other compiler, but it will requires a lot of changes in
+the source code.  Initially, MSX UZIX couldn't be compiled for running on
+a MSX1, since it uses Memory Mapper for multitasking, system real-time
+clock for file timestamps, and 80-column screen.
+       Of course, is possible doing a "light" MSX UZIX for MSX1, with a
+fake real-time clock (software emulated by the kernel), using a 40-column
+display and other memory device (such as MegaRAM) for multitasking, but
+it's not the target of this release.
+       But, just for fun (and as a curiousity), there is a version of MSX
+UZIX for MSX1. It emulates the system real-time clock and uses the
+brazilian MegaRAM for multitasking. The system overall performance is
+lower than using Memory Mapper, since due to switching restrictions of
+MegaRAM (due to UZIX design, MegaRAM pages can be switched only on memory
+page 1), some memory block copies are needed for context switching. Also,
+the user must input the actual date and time when system boots. The
+40-column display doesn't represent a serious restriction, but some
+applications (like top, ps or banner) will display bad formatted texts on
+screen.
+       This release of MSX UZIX can handle a maximum of 31 processes
+(limited to the size of available RAM). It could handle up to 127
+processes (4Mb RAM), but it's nonsense a single user running so many
+processes at a time. That's why this limit of 31 concurrent processes.
+
+Known bugs and missing features:
+
+* Some DiskROMs doesn't work well with UZIX. MSX Turbo-R DiskROM also have
+  this problem, and it's related to stopping the drive. If the drive stops
+  spinning, the next access to it returns a 'not ready' error after a long
+  delay. It can be solved with the appropriate settings on 'Advanced
+  settings' in UZIX installation program or pressing the space bar while
+  ZILO is loading. By an unknown reason, the  drive returns`not ready`
+  error for a disk access after stop spinning. The load of init/login
+  access disk  continuously, so everything works. During the time UZIX
+  presents `login:` and you enter the login name, disk stops spinning.
+  The disk access after entering login generates the `not ready` error. The
+  solution found is: after each  disk  block  read  access, a reset() is
+  done. This is also done in ZILO (via call to 4029h) before loading UZIX
+  kernel. The bad side is that this practice slows down disk access a lot
+  on MSX machines that aren't Turbo-R.
+
+* Disk access is slowed down since disk buffers were decreased to
+  accomodate module functions in kernel. Also, the number of simultaneous
+  opened files is less than previous versions (0.1.5 and below);
+
+* TABs are not correctly erased by BS key. DEVTTY backs 8 chars in screen,
+  clearing them. It's  not  perfect,  cause the TAB could not  jumped 8
+  chars, but less, so we erase chars that are still in stdin queue;
+
+* If lpd can print all the docs, the daemon is fini shed (init  executes
+  the  wait()  and  the  daemon exits).If not, the process become zombie
+  until SASH exits(init executes the wait() for SASH and lpd). It seems to
+  occur only with RuMSX emulator  (sorry, I don't have a printer attached
+  to my MSX to test this...).
+
+* UZIX doesn't have the concept of background/foreground applications
+  controlled by user;
+
+* Only ESE MegaSCSI and Sunrise IDE harddisk controllers were tested;
+  Novaxis SCSI interfaces return error when system tries to access a
+  disk; UZIX should run on other interfaces (Bert, Gouda, etc) but
+  some fine tunning is necessary;
+
+* With ESE MegaSCSI, stopdrive countdown during interrupt must be
+  disabled. If enabled, UZIX can't mount root filesystem. If disabled,
+  when accessing  disk-drives, the disk remains spinning forever.
+
+* On UCP, if you have an existing directory (for example, /usr) and want
+  to create another dir under this one (for example, /usr/bin), doing:
+  cd /,mkdir usr/bin on UCP causes an inconsistent inode count (check
+  with fsck). You must do: cd /usr, mkdir bin.
+
+* FILESYS.C sometimes mark fs as bad if no room for writing a file (UCP).
+
+* reset() in DEVFLOP.MSX is a bad procedure. It stops ALL diskdrives
+  connected to MSX. A perfect  reset() should stop only the drive given by
+  fdrive.
+
+* In passwd.c, getpwuid gets the first password entry that has the given
+  UID. It DOESN'T look for GID, so entries with different GIDs and equal
+  UIDs will be treated as the same.
+
+Things that would be nice to do:
+
+* Create the man-pages of:
+  aal
+  chat
+  clock
+  clone
+  cr
+  diskusag
+  dosdel
+  dosemu
+  dtree
+  find
+  finger
+  ftp
+  gres
+  ic
+  inodes
+  key
+  keybstat
+  lpd
+  lpr
+  mailf
+  ncheck
+  ncr
+  netstat
+  nslookup
+  od
+  pathchk
+  ping
+  pppd
+  renice
+  roff
+  setclock
+  setchar
+  slattach
+  uuencode
+  uudecode
+* Implement TTY support on curses library. Now all references on code
+  were supressed.
+* Create a dosformat utility.
+* Put a "see also" section on UZIX man-pages.
+* Better pipe handling in sash (it only supports two commands now).
+* Implement options -c, -l and -s in cmp.
+* Create fsck/mkfs/mkboot for UZIX.
+
+Copy license:
+
+       All the UZIX source (kernel, utilities and related sources) is
+released under the GNU GPL license. Read the COPYING file for details.
+
+               -----------------------------------------------------
+
+               UZI: UNIX Z-80 IMPLEMENTATION
+
+                 Written by Douglas Braun
+
+
+Introduction:
+
+UZI is an implementation of the Unix kernel written for a Z-80 based
+computer.  It implementts almost all of the functionality of the
+7th Edition Unix kernel.  UZI was written to run on one specific
+collection of custom-built hardware, but since it can easily have device
+drivers added to it, and it does not use any memory management hardware,
+it should be possible to port it to numerous computers that current use
+the CP/M operating system.  The source code is written mostly in C,
+and was compiled with The Code Works' Q/C compiler.  UZI's code was
+written from scratch, and contains no AT&T code, so it is not subject
+to any of AT&T's copyright or licensing restrictions.  Numerous 7th
+Edition programs have been ported to UZI with little or no difficulty,
+including the complete Bourne shell, ed, sed, dc, cpp, etc.
+
+
+How it works:
+
+Since there is no standard memory management hardware on 8080-family
+computers, UZI uses "total swapping" to achieve multiprocessing.
+This has two implications:  First, UZI requires a reasonably fast
+hard disk.  Second, there is no point in running a different process
+while a process is waiting for disk I/O.  This simplifies the design
+of the block device drivers, since they do not have to be interrupt-based.
+
+UZI itself occupies the upper 32K of memory, and the currently running
+process occupies the lower 32K.   Since UZI currently barely fits in 32K,
+a full 64K of RAM is necessary.
+
+UZI does need some additional hardware support.  First, there must be
+some sort of clock or timer that can provide a periodic interrupt.
+Also, the current implementation uses an additional real-time clock
+to get the time for file timestamps, etc.  The current TTY driver assumes
+an interrupt-driven keyboard, which should exist on most systems.
+The distribution contains code for hard and floppy disk drivers, but
+since these were written for custom hardware, they are provided only
+as templates to write new ones.
+
+
+How UZI is different than real Unix:
+
+UZI implements almost all of the 7th Edition functionality.
+All file I/O, directories, mountable file systems, user and group IDs,
+pipes, and applicable device I/O are supported.  Process control
+(fork(), execve(), signal(), kill(), pause(), alarm(), and wait()) are fully
+supported.  The number of processes is limited only by the swap space
+available.  As mentioned above,  UZI implements Unix well enough to
+run the Bourne shell in its full functionality.  The only changes made
+to the shell's source code were to satisfy the limitations of the C compiler.
+
+Here is a (possibly incomplete) list of missing features and limitations:
+
+    The debugger- and profiler-related system calls do not exist.
+
+    The old 6th edition seek() was implemented, instead of lseek().
+
+    The supplied TTY driver is bare-bones.  It supports only one port,
+    and most IOCTLs are not supported.
+
+    Inode numbers are only 16-bit, so filesystems are 32 Meg or less.
+
+    File dates are not in the standard format.  Instead they look like
+    those used by MS-DOS.
+
+    The 4.2BSD execve() was implemented.  Additional flavors of exec()
+    are supported by the library.
+
+    The format of the device driver switch table is unlike that of
+    the 7th Edition.
+
+    The necessary semaphores and locking mechanisms to implement 
+    reentrant disk I/O are not there.  This would make it harder to
+    implement interrupt-driven disk I/O without busy-waiting.
+
+
+A Description of this Release:
+
+Here is a list of the files supplied, and a brief description of each:
+
+
+intro:         What you are reading
+
+config.h:      Setup parameters, such as table sizes, and the device
+               driver switch table.
+
+unix.h:                All strcuture declarations, typedefs and defines.
+               (Includes things like errno.h).
+
+extern.h:      Declarations of all global variables and tables.
+
+data.c:                Dummy to source extern.h and devine globals.
+
+dispatch.c:    System call dispatch table.
+
+scall1.c:      System calls, mostly file-related.
+
+scall2.c:      Rest of system calls.
+
+filesys.c:     Routines for managing file system.
+
+process.c:     Routines for process management and context switching.
+               Somewhat machine-dependent.
+
+devio.c:       Generic I/O routines, including queue routines.
+
+devtty.c:      Simple TTY driver, slightly-machine dependent.
+
+devwd.c:       Hard disk driver.  Very machine-dependent.
+
+devflop.c:     Floppy disk driver.  Very machine-dependent.
+
+devmisc.c:     Simple device drivers, such as /dev/mem.
+
+machdep.c:     Machine-dependent code, especially real-time-clock and
+               interrupt handling code.
+
+extras.c:      Procedures missing from the Q/C compiler's library.
+
+filler.mac:    Dummy to make linker load UZI at correct address.
+
+makeunix.sub:  CP/M SUBMIT file to compile everything.
+
+loadunix.sub:  CP/M SUBMIT file to load everything.
+
+
+Miscellaneous Notes:
+
+UZI was compiled with the Code Works Q/C C compiler and the Microsoft
+M80 assembler under the CP/M operating system, on the same hardware
+it runs on.  Also used was a version of cpp ported to CP/M, since
+the Q/C compiler does not handle macros with arguments.  However, there
+are only a couple of these in the code, and they could easily be removed.
+
+Because UZI occupies the upper 32K of memory, the standard L80 linker
+could not be used to link it.  Instead, a homebrew L80 replacement linker
+was used.  This generated a 64K-byte CP/M .COM file, which has the lower 
+32K pruned by the CP/M PIP utility.  This is the reason for appearance
+of the string "MOMBASSA" in filler.mac and loadunix.sub.
+
+To boot UZI, a short CP/M program was run that reads in the UZI image,
+copies it to the upper 32K of memory, and jumps to its start address.
+Other CP/M programs were written to build, inspect, and check UZI filesystems
+under CP/M.  These made it possible to have a root file system made before
+starting up UZI.  If the demand exists, these programs can be included
+in another release.
+
+
+Running programs under UZI:
+
+A number of 7th Edition, System V, and 4.2BSD programs were ported to
+UZI.  Most notably, the Bourne shell and ed run fine under UZI.
+In addition the 4.2BSD stdio library was also ported.  This, along
+with the Code Works Q/C library and miscellaneous System V library 
+functions, was used when porting programs.
+
+Due to obvious legal reasons, the source or executables for most of these
+programs cannot be released.  However, some kernel-dependent programs
+such as ps and fsck were written from scratch and can be included in future
+releases.  Also, a package was created that can be linked to CP/M .COM
+files that will allow them to run under UZI.  This was used to get
+the M80 assembler and L80 linker to run under UZI.  Cpp was also
+ported to UZI.  However, it was not possible to fit the Q/C compiler
+into 32K, so all programs (and UZI itself) were cross-compiled under CP/M.
+
+The Minix operating system, written for PCs by Andrew Tanenbaum et al,
+contains many programs that should compile and run under UZI.  Since
+Minix is much less encumbered by licensing provisions than real Unix,
+it would make sense to port Minix programs to UZI.  In fact, UZI itself
+could be ported to the PC, and used as a replacement for the Minix kernel.
+
diff --git a/Kernel/TODO b/Kernel/TODO
new file mode 100644 (file)
index 0000000..5edde9e
--- /dev/null
@@ -0,0 +1,47 @@
+Big TODO Items Before 0.1 Release
+---------------------------------
+
+o      BSD groups can be done but do we care ?
+IP     Termios and speed hooks to tty drivers
+DONE   hangup ioctl (vhangup) plus hangups for group leader exits
+o      rename should delete old files it renames over
+o      SYS5 signal functionality and other signals (SIGCLD, STOP etc)
+IP     SYS5 signal holding
+o      ptrace
+o      Core dumps
+o      time_t bits hidden in inode
+o      n_openw() - as n_open but errors on R/O mount or media, getinodew ??
+       and update setftime ?
+o      RTC setting
+o      Can we make the mount point buffers writable to disk too so we can
+       drop the quiet ones when busy ?
+o      Simplify exec logic and split into multiple functions
+o      Add "shared lib" (or more accurately copied lib) support for libc
+       to keep binary size small
+o      Can we make inodes partially pageable given our on disk guarantees ?
+       Disk inode in cinode would then become a pointer. Might allow more open
+       objects and less memory usage. Might be nicer alternative to the BSD
+       inode shrinking hack (although that would fix the time_t question!)
+o      Finish the cpm emulator port
+
+Big Speed Up Points
+-------------------
+
+o      Rewrite the compressor in assembler
+o      Support 'raw' I/O on files
+o      Make execve use this to avoid all the copies
+o      Vfork
+o      Make mount pin a buffer rather than keeping mount blocks around
+       unused.
+
+Maybe
+-----
+o      Different magic for "big" fs - 32bit block numbers only on raw
+       devices. Split blkno_t into blkno_t blknodev_t or similar
+o      Rewrite the compressor in assembler
+IP     Carrier handling for tty devices
+o      Revoke 8)
+o      Uptime/loadaverage/swapfree etc data
+o      Virtual device hooks for networking
+o      Pty/tty devices
+o      Finish select/poll
diff --git a/Kernel/bank16k.c b/Kernel/bank16k.c
new file mode 100644 (file)
index 0000000..a575ff6
--- /dev/null
@@ -0,0 +1,135 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+#ifdef CONFIG_BANK16
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set of pages
+ * with the last page repeated to fill any holes.
+ */
+
+static unsigned char pfree[MAX_MAPS];
+static unsigned char pfptr = 0;
+
+/*
+ *     Helper for platform to add pages at boot
+ */
+void pagemap_add(uint8_t page)
+{
+       if (pfptr == MAX_MAPS)
+               panic("map over");
+       pfree[pfptr++] = page;
+}
+
+/*
+ *     Free the maps for this task
+ */
+void pagemap_free(ptptr p)
+{
+       uint8_t *ptr = (uint8_t *) & p->p_page;
+       uint8_t last = 0xff;
+       int i;
+       for (i = 0; i < 4; i++) {
+               if (*ptr != last) {
+                       pfree[pfptr++] = *ptr;
+                       last = *ptr;
+               }
+               ptr++;
+       }
+}
+
+static int maps_needed(uint16_t top)
+{
+       /* FIXME: unhardwire the 0x1000 common assumption ! */
+       uint16_t needed = top + 0xFFF;  /* 0x1000 common - 1 for shift and inc */
+       needed >>= 14;          /* in banks */
+       needed++;               /* rounded */
+       return needed;
+}
+
+/*
+ *     Allocate the maps for this task post fork
+ *     We have a hackish fix for init that would be nice
+ *     resolve.
+ */
+int pagemap_alloc(ptptr p)
+{
+       uint8_t *ptr = (uint8_t *) & p->p_page;
+       int needed = maps_needed(udata.u_top);
+       int i;
+
+#ifdef SWAPDEV
+       /* Throw our toys out of our pram until we have enough room */
+       while (needed > pfptr)
+               if (swapneeded(p, 1) == NULL)
+                       return ENOMEM;
+#else
+       if (needed > pfptr)     /* We have no swap so poof... */
+               return ENOMEM;
+#endif
+
+       /* Pages in the low then repeat the top one */
+       for (i = 0; i < needed; i++)
+               ptr[i] = pfree[--pfptr];
+
+       while (i < 4) {
+               ptr[i] = ptr[i - 1];
+               i++;
+       }
+       return 0;
+}
+
+/*
+ *     Reallocate the maps for a process
+ */
+int pagemap_realloc(uint16_t size)
+{
+       int have = maps_needed(udata.u_top);
+       int want = maps_needed(size);
+       uint8_t *ptr = (uint8_t *) & udata.u_page;
+       int i;
+       irqflags_t irq;
+
+       /* If we are shrinking then free pages and propogate the
+          common page into the freed spaces */
+       if (want == have)
+               return 0;
+       if (have > want) {
+               for (i = want; i < have; i++) {
+                       pfree[pfptr++] = ptr[i];
+                       ptr[i] = ptr[3];
+               }
+               udata.u_ptab->p_page = udata.u_page;
+               udata.u_ptab->p_page2 = udata.u_page2;
+               return 0;
+       }
+
+       /* If we are adding then just insert the new pages, keeping the common
+          unchanged at the top */
+       if (want - have > pfptr)
+               return ENOMEM;
+       /* We don't want to take an interrupt here while our page mappings are
+          incomplete. We may restore bogus mappings and then take a second IRQ
+          into hyperspace */
+        irq = di();
+
+       for (i = have; i < want; i++)
+               ptr[i - 1] = pfree[--pfptr];
+       /* Copy the updated allocation into the ptab */
+       udata.u_ptab->p_page = udata.u_page;
+       udata.u_ptab->p_page2 = udata.u_page2;
+       /* Now fix the vectors up - they've potentially teleported up to 48K up
+          the user address space, we need to put a copy back in low memory before
+          we switch to this memory map */
+       program_vectors(&udata.u_page);
+
+       irqrestore(irq);
+       return 0;
+}
+
+uint16_t pagemap_mem_used(void)
+{
+       return pfptr << 4;
+}
+
+#endif
diff --git a/Kernel/bank32k.c b/Kernel/bank32k.c
new file mode 100644 (file)
index 0000000..84e769e
--- /dev/null
@@ -0,0 +1,122 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+#ifdef CONFIG_BANK32
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set of pages
+ * with the last page repeated to fill any holes.
+ *
+ * 32K paging is actually a bit of a pain. The kernel is 32K + data which means
+ * the port will need to play games with the UAREA unless it has some other mapping
+ * options
+ *
+ * We have at least one potential oddball to cater for here later. The Sam Coupe has
+ * 32K banking but you can pick blocks to bank high or low on a 16K alignment.
+ * 
+ */
+
+static unsigned char pfree[MAX_MAPS];
+static unsigned char pfptr = 0;
+
+/*
+ *     Helper for platform to add pages at boot
+ */
+void pagemap_add(uint8_t page)
+{
+       if (pfptr == MAX_MAPS)
+               panic("map over");
+       pfree[pfptr++] = page;
+}
+
+/*
+ *     Free the maps for this task
+ */
+void pagemap_free(ptptr p)
+{
+       uint8_t *ptr = (uint8_t *) & p->p_page;
+       pfree[pfptr--] = *ptr;
+       if (*ptr != ptr[1])
+               pfree[pfptr--] = ptr[1];
+}
+
+static int maps_needed(uint16_t top)
+{
+       /* FIXME: unhardwire the 4K common assumption */
+       uint16_t needed = top + 0xFFF;  /* 0x1000 common - 1 for shift and inc */
+       if (needed & 0x8000)
+               return 2;
+       return return 1;
+}
+
+/*
+ *     Allocate the maps for this task post fork
+ *     We have a hackish fix for init that would be nice
+ *     resolve.
+ */
+int pagemap_alloc(ptptr p)
+{
+       uint8_t *ptr = (uint8_t *) & p->p_page;
+       int needed = maps_needed(udata.u_top);
+       int i;
+
+#ifdef SWAPDEV
+       /* Throw our toys out of our pram until we have enough room */
+       while (needed > pfptr)
+               if (swapneeded(p, 1) == NULL)
+                       return ENOMEM;
+#else
+       if (needed > pfptr)     /* We have no swap so poof... */
+               return ENOMEM;
+#endif
+
+       *ptr = pfree[--pfptr];
+       if (needed == 1)
+               ptr[1] = *ptr;
+       else
+               ptr[1] = pfree[--pfptr];
+       return 0;
+}
+
+/*
+ *     Reallocate the maps for a process
+ */
+int pagemap_realloc(uint16_t size) {
+       int have = maps_needed(udata.u_top);
+       int want = maps_needed(size);
+       uint8_t *ptr = (uint8_t *) & udata.u_page;
+       int i;
+
+       /* If we are shrinking then free pages and propogate the
+          common page into the freed spaces */
+       if (want == have)
+               return 0;
+       if (have > want) {
+               pfree[pfptr++] = ptr[1];
+               udata.u_ptab->p_page = udata.u_page;
+               return 0;
+       }
+       /* If we are adding then just insert the new pages, keeping the common
+          unchanged at the top */
+       if (want - have > pfptr)
+               return ENOMEM;
+       /* We don't want to take an interrupt here while our page mappings are
+          incomplete. We may restore bogus mappings and then take a second IRQ
+          into hyperspace */
+       __critical {
+               ptr[0] = pfree[--pfptr];
+               /* Copy the updated allocation into the ptab */
+               udata.u_ptab->p_page = udata.u_page;
+               /* Now fix the vectors up - they've potentially teleported up to 32K up
+                  the user address space, we need to put a copy back in low memory before
+                  we switch to this memory map */
+               program_vectors(&udata.u_page);
+       }
+       return 0;
+}
+
+uint16_t pagemap_mem_used(void) {
+       return pfptr << 5;
+}
+
+#endif
diff --git a/Kernel/bankfixed.c b/Kernel/bankfixed.c
new file mode 100644 (file)
index 0000000..67f7fc4
--- /dev/null
@@ -0,0 +1,52 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+
+#ifdef CONFIG_BANK_FIXED
+
+/* Kernel is 0, apps 1,2,3 etc */
+static unsigned char pfree[MAX_MAPS];
+static unsigned char pfptr = 0;
+static unsigned char pfmax;
+
+void pagemap_add(uint8_t page)
+{
+       pfree[pfptr++] = page;
+       pfmax = pfptr;
+}
+
+void pagemap_free(ptptr p)
+{
+       if (p->p_page == 0)
+               panic("free0");
+       pfree[pfptr++] = p->p_page;
+}
+
+int pagemap_alloc(ptptr p)
+{
+#ifdef SWAP_DEV
+       if (pfptr == 0) {
+               swapneeded(p, 1);
+       }
+#endif
+       if (pfptr == 0)
+               return ENOMEM;
+       p->p_page = pfree[--pfptr];
+       return 0;
+}
+
+/* Realloc is trivial - we can't do anything useful */
+int pagemap_realloc(uint16_t size)
+{
+       if (size >= MAP_SIZE)
+               return ENOMEM;
+       return 0;
+}
+
+uint16_t pagemap_mem_used(void)
+{
+       return (pfmax - pfptr) * (MAP_SIZE >> 10);
+}
+
+#endif
diff --git a/Kernel/cpm-emulator/README.WRS b/Kernel/cpm-emulator/README.WRS
new file mode 100644 (file)
index 0000000..eb5d878
--- /dev/null
@@ -0,0 +1,3 @@
+Assemble with "zmac emulator.s"
+
+Copy output file zout/emulator.cim to /usr/cpm/emulator on target filesystem
diff --git a/Kernel/cpm-emulator/emulator.s b/Kernel/cpm-emulator/emulator.s
new file mode 100644 (file)
index 0000000..de59650
--- /dev/null
@@ -0,0 +1,1547 @@
+    ; must begin on a page boundary (address % 256 == 0) to ensure
+    ; the jump table is correctly aligned
+    .org 0xf000
+startaddr:
+
+fcb       EQU     005CH           ; Default CP/M FCB
+buff      EQU     0080H           ; Default CP/M Buffer
+BS        EQU     08H             ; ASCII BackSpace
+TAB       EQU     09H             ; ASCII Horizontal Tab
+LF        EQU     0AH             ; ASCII Line Feed
+CR        EQU     0DH             ; ASCII Carriage Return
+ESC       EQU     1BH             ; ASCII ESCape Char
+
+TCGETS   EQU     1               ; Fuzix - get tty data
+TCSETS    EQU     2               ; Fuzix - set tty data
+
+STDIN     EQU     0               ; file descriptor value of keyboard
+STDOUT    EQU     1               ; file descriptor value of display
+
+; Initialize both FCB entries to blank values
+
+EStart:        LD      HL,fcbDat       ; Move initial FCB
+       PUSH    HL
+       LD      DE,fcb          ;  into
+       LD      BC,16           ;   position
+       LDIR
+       POP     HL
+       LD      C,16            ;    init 2nd entry
+       LDIR
+
+; Catenate argv[] elements into default buffer
+
+       POP     IX              ; Skip argc
+       POP     IX              ;  Get Ptr to argv[]
+       LD      DE,buff+1       ; Pt to CP/M Dflt Buffer
+       LD      C,0             ;  Cnt to 0
+       INC     IX              ;   Skip Argv[0]
+       INC     IX
+Cold0: LD      L,(IX+0)        ; Get Ptr to Arg element
+       INC     IX
+       LD      H,(IX+0)
+       INC     IX
+       LD      A,H
+       OR      L               ; End?
+       JR      Z,Cold2         ; ..exit if Yes
+       LD      A,' '           ; Add space separator for args
+       LD      (DE),A
+       INC     DE
+       INC     C               ;   bump count
+Cold1: LD      A,(HL)
+       OR      A               ; End of string?
+       JR      Z,Cold0         ; ..try next if Yes
+       CP      'a'             ; ensure
+       JR      C,NoCap         ;  it
+       CP      'z'+1           ;   is
+       JR      NC,NoCap        ;    UCase
+       AND     5FH
+NoCap: LD      (DE),A          ; Move a byte
+       INC     HL
+       INC     C               ;   bump count
+       INC     E               ;  bump ptr
+       JR      NZ,Cold1        ; ..get next byte if no bfr ovfl
+                       ;..else 0FF->100H, terminate
+       DEC     E               ;  (back up for Null-termination)
+Cold2: XOR     A
+       LD      (DE),A          ;   Null-terminate for safety
+
+       LD      HL,buff         ; Pt to count loc'n in buff
+       LD      (HL),C          ;  save total arg count
+       INC     HL              ;   advance to 1st char
+       LD      DE,fcb+1
+       CALL    FilNm           ; Get Name/Typ in 1st FCB
+       OR      A               ;  (set End flag)
+       LD      DE,fcb+17       ;   (prepare)
+       CALL    NZ,FilNm        ;    Get Tame/Typ in 2nd FCB if present
+
+       LD      DE,dir
+       LD      B,128
+       CALL    ZeroDE          ; Clear Directory Buffer
+
+       LD      HL,0
+       LD      (0003H),HL      ; Clear IOBYTE and Default Drive/User
+
+       JP      __bios          ; Go to Cold Start setup
+
+; Fill FCB Name.Typ fields with any present data
+
+FilNm: LD      A,(HL)          ; Get char
+       INC     HL              ;   bump
+       OR      A               ; End of String?
+       RET     Z
+       CP      ' '             ; "Whitespace"?
+       JR      Z,FilNm0        ; ..jump if Yes
+       CP      TAB
+       JR      NZ,FilNm1       ; ..jump if No
+FilNm0:        DEC     C               ; Count down total length
+       LD      A,C             ;  (prepare)
+       JR      NZ,FilNm        ; ..loop if Not End
+       RET                     ;  ..else Exit showing EOL
+
+FilNm1:        LD      B,8             ; Set length of Name field
+       PUSH    DE              ;   save Ptr to Name[0]
+       CALL    FilFl0          ;  Get Name
+       POP     DE              ;   restore Ptr to Name
+       OR      A
+       RET     Z               ; ..return if End-of-Line
+       CP      ' '
+       RET     Z               ; ..return if separator
+       CP      '.'
+       JR      Z,FilNm2        ; ..bypass char skip
+
+FilNm3:        LD      A,(HL)
+       INC     HL
+       OR      A
+       RET     Z               ; Exit if End of Line
+       CP      ' '
+       RET     Z               ;  or End of Field
+       CP      '.'
+       JR      NZ,FilNm3       ; ..loop til End or period
+
+FilNm2:        LD      A,E
+       ADD     A,8             ; Adjust FCB ptr to type field
+       LD      E,A
+       LD      B,3
+                       ;..fall thru to get next char..
+; Move bytes from (HL) to (DE) for Count in C, Count in B or Ch in {' ','.',0}
+
+FilFld:        LD      A,(HL)          ; Get Char
+       INC     HL              ;   bump ptr
+       OR      A               ; End of String?
+       RET     Z               ; ..return if Yes
+FilFl0:        CP      '.'             ; Period?
+       RET     Z
+       CP      ' '             ; Space?
+       RET     Z
+       LD      (DE),A          ; Else Store byte
+       INC     DE              ;   bump dest ptr
+       DEC     C               ; End of Input String?
+       LD      A,C             ;  (prepare)
+       RET     Z               ; .return End if Yes
+       DJNZ    FilFld          ; ..loop til field counter ends
+       OR      0FFH            ; Return flag
+       RET
+
+fcbDat:        DEFB    0
+       DEFM    '           '
+       DEFB    0,0,0,0
+
+;==========================================================
+;     Resident Portion of Basic Disk Operating System
+;==========================================================
+; bdos()
+; {
+__bdos:        JP      _bdos0
+; }
+
+;.....
+; BDOS Function Dispatch Table
+
+fcnTbl:        defw    Fcn0            ; Warm Boot
+       defw    Fcn1            ; ConIn
+       defw    Fcn2            ; ConOut
+       defw    Fcn3            ; Reader In
+       defw    Fcn4            ; Punch Out
+       defw    Fcn5            ; List Output
+       defw    Fcn6            ; Direct Console IO
+       defw    Fcn7            ; Get IOBYTE
+       defw    Fcn8            ; Set IOBYTE
+       defw    Fcn9            ; WrBuf
+       defw    Fcn10           ; RdBuf
+       defw    Fcn11           ; Get Console Status
+       defw    Fcn12           ; Return Version #
+       defw    Fcn13           ; Reset Disk Drive
+       defw    Fcn14           ; Select Disk
+       defw    Fcn15           ; Open File
+       defw    Fcn16           ; Close File
+       defw    Fcn17           ; Search First Occurance
+       defw    Fcn18           ; Search Next Occurance
+       defw    Fcn19           ; Delete File
+       defw    Fcn20           ; Read File
+       defw    Fcn21           ; Write File
+       defw    Fcn22           ; Create File
+       defw    Fcn23           ; Rename File
+       defw    Fcn24           ; Return Disk Login Vector
+       defw    Fcn25           ; Return Current Disk
+       defw    Fcn26           ; Set DMA
+       defw    Fcn27           ; Get Allocation Map
+       defw    Fcn28           ; Write Protect Disk
+       defw    Fcn29           ; Get R/O Vector Address
+       defw    Fcn30           ; Set File Attributes
+       defw    Fcn31           ; Get Disk Parameter Table Address
+       defw    Fcn32           ; Set/Get User Code
+       defw    Fcn33           ; Read Random
+       defw    Fcn34           ; Write Random
+       defw    Fcn35           ; Compute File Size
+       defw    Fcn36           ; Set Random Record Field in FCB
+;      defw    Fcn37           ; Reset Multiple Drives
+;      defw    null            ; (Fcn38 not implemented)
+;      defw    Fcn39           ; Get Fixed Disk Vector
+;      defw    Fcn40           ; Write Random
+TBLSZ   EQU  $-fcnTbl
+MAXFCN  EQU  TBLSZ/2
+
+;------------------------------------------------
+; bdos0()
+; {
+
+_bdos0:        LD      (_arg),DE
+       LD      A,C
+       LD      (_call),A
+       CP      MAXFCN          ; Legal Function?
+       LD      A,0FFH          ;  Prepare Error code
+       LD      L,A
+       RET     NC              ; ..return if Illegal
+       LD      (_userSP),SP
+       LD      SP,_Bstack
+       PUSH    IX
+       PUSH    IY
+       LD      B,0             ; Fcn # to Word
+       LD      HL,_bdosX
+       PUSH    HL              ;  (ret Addr to Stack)
+       LD      HL,fcnTbl
+       ADD     HL,BC
+       ADD     HL,BC           ;   Pt to Fcn entry in Table
+       LD      A,(HL)
+       INC     HL
+       LD      H,(HL)
+       LD      L,A
+       JP      (HL)            ; "Call" Function #
+
+_bdosX:        POP     IY
+       POP     IX
+       LD      SP,(_userSP)
+       LD      DE,(_arg)       ; Return Orig contents of DE
+       LD      A,(_call)
+       LD      C,A             ; Return Orig contents of C
+       LD      A,L
+       LD      B,H             ; Strict compatibility
+       OR      A
+       RET
+; }
+
+;------------------------------------------------
+;         case 0: _exit();                     /* Warm Boot */
+
+Fcn0:  JP      WBoot
+
+;------------------------------------------------
+;         case 6: if (arg < 0xfe)              /* Direct Console I/O */
+;                     goto conout;
+;                 else if (arg == 0xfe)
+;                     return (ConSt);
+;                 else if (ConSt)       /* 0xff */
+;                     goto conout;
+;                 else return (0);
+
+Fcn6:  LD      A,E             ; _arg in DE
+       CP      0FEH            ; < 0FE ?
+       JR      C,Fcn2          ; ..jump if Write if Yes
+       PUSH    AF
+       CALL    BConSt          ; Else get Console Status
+       POP     AF
+       INC     A
+       RET     NZ              ; ..exit with 0ffh if 0feh
+       LD      A,H
+       OR      L               ; Any char ready?
+       RET     Z               ; ..exit if Nothing available
+                       ;..else fall thru to Fcn1..
+;------------------------------------------------
+;         case 1:                              /* Console Input */
+;         conin:  read (0, &c, 1);
+;                 if (c == '\n')
+;                     c = '\r';
+;                 return (c);
+
+Fcn1:  CALL    BConIn          ; Get Char from Bios
+Fcn1A: LD      H,0
+       CP      0AH             ; \n?
+       LD      L,A             ;  (prepare for return
+       RET     NZ              ; ..return if Not
+       LD      L,0DH           ; Else return CR
+       RET
+
+;------------------------------------------------
+;         case 3:                              /* Reader (Aux) Input */
+;         conin:  read (0, &c, 1);
+;                 if (c == '\n')
+;                     c = '\r';
+;                 return (c);
+
+Fcn3:  CALL    AuxIn           ; Get Char from Bios
+       JR      Fcn1A           ; ..exit via common code
+
+;------------------------------------------------
+;         case 2:                              /* Console Output */
+;         conout: if (arg == '\r')
+;                     return (0);
+;                 c = arg;
+;                 write (1, &c, 1);
+;                 break;
+
+Fcn2:  LD      C,E             ; _arg in DE, need char in C
+       JP      BConOu
+
+;------------------------------------------------
+;         case 4:                              /* Punch (Aux) Output */
+;         conout: if (arg == '\r')
+;                     return (0);
+;                 c = arg;
+;                 write (1, &c, 1);
+;                 break;
+
+Fcn4:  LD      C,E             ; _arg in DE, need char in C
+       JP      AuxOut
+
+;------------------------------------------------
+;         case 5: if (arg == '\r')             /* List (Prntr) Output */
+;                     return (0);
+;                 c = arg;
+;                 write (2, &c, 1);
+;                 break;
+
+Fcn5:  LD      A,E             ; _arg in DE
+       CP      13              ; \r?
+       RET     Z
+       JP      List            ; ..go to Bios
+
+;------------------------------------------------
+;         case 9: ptr = (char *)arg;           /* Print '$'-term String */
+;                 while (*ptr != '$')
+;                 {
+;                     if (*ptr != '\r')
+;                         write (1, ptr, 1);
+;                     ++ptr;
+;                 }
+;                 break;
+                               ; Enter: DE -> String (arg)
+Fcn9:  LD      A,(DE)          ; Get char
+       INC     DE              ;   pt to Next
+       CP      '$'             ; End?
+       RET     Z               ; ..quit if Yes
+       LD      C,A
+       PUSH    DE
+       CALL    BConOu
+       POP     DE
+       JR      Fcn9            ; ..loop Til done
+       
+;------------------------------------------------
+;         case 10: rdbuf (arg);
+;                  break;
+; rdbuf (arg)
+; char *arg;
+; {
+;     int nread;
+
+;     nread = read (0, arg+2, *arg & 0xff);
+
+Fcn10:
+       push    de
+       ex      de,hl           ; hl - buffer
+       ld      e,(hl)          ; e - max chars
+       inc     hl
+       inc     hl
+       ld      d,0             ; d - char cnt
+get:   push    hl
+       push    de
+       call    BConIn
+       pop     de
+       pop     hl
+       cp      8
+       jr      z,del
+       cp      7Fh
+       jr      z,del
+       cp      3
+       jp      z,0
+       push    hl
+       push    de
+       push    af
+       ld      c,a
+       call    BConOu
+       pop     af
+       pop     de
+       pop     hl
+       ld      (hl),a
+       cp      CR
+       jr      z,eol
+       ld      a,e
+       cp      d
+       jr      z,eol1
+       inc     hl
+       inc     d
+       jr      get
+del:   ld      a,d
+       or      a
+       jr      z,get
+       push    hl
+       push    de
+       ld      c,8
+       call    BConOu
+       ld      c,' '
+       call    BConOu
+       ld      c,8
+       call    BConOu
+       pop     de
+       pop     hl
+       dec     hl
+       dec     d
+       jr      get
+eol:   ld      (hl),0
+eol1:  ld      a,d
+       pop     de
+       inc     de
+       ld      (de),a
+       ld      hl,0
+       ret
+
+
+;------------------------------------------------
+;         case 11: return (ConSt);             /* Get Console Status */
+
+Fcn11: JP      BConSt
+
+;------------------------------------------------
+;         case 12:                             /* Return Version # */
+
+Fcn12: LD      HL,0022H        ; Say this is CP/M 2.2
+       RET
+
+;------------------------------------------------
+;         case 13:                             /* Reset Disk Drive */
+;              SDma(0x80);
+;              break;
+Fcn13:
+       LD      BC,80h
+       JP      BSDma
+
+;------------------------------------------------
+;         case 7:                              /* Get IO Byte */
+;         case 8: break;                       /* Set IO Byte */
+;         case 14: break;                      /* Select Disk
+;         case 25: break;                      /* Return Current Disk */
+;         case 28: break;                      /* Write Protect Disk */
+;         case 30: break;                      /* Set File Attribytes */
+;         case 32: break;                      /* Get/Set User Code */
+Fcn7:
+Fcn8:
+Fcn14:
+Fcn25:                         ; 0 = Drive A
+Fcn28:
+Fcn30:
+Fcn32:                         ; Return User 0
+;         default: break;
+;     }
+;     return (0);
+
+Exit0: LD      HL,0
+       RET
+
+;------------------------------------------------
+;         case 15: return (openfile (arg));            /* Open File */
+; openfile (blk)
+; {
+;     desc = open (getname (arg), 2);
+                               ; DE -> arg
+Fcn15: CALL    Fcn17           ; Does this file exist?
+       LD      A,H
+       AND     L
+       INC     A               ; File Not Found (-1)?
+       RET     Z               ; ..return -1 if File doesn't exist
+
+Open1: CALL    CkSrch          ;  (Close Search File)
+
+;     arg.recno = 0;
+
+       CALL    ZeroCR
+       LD      (IY+13),80h     ; use S1 as file open flag
+
+       JR      Exit0           ;  Return Dir Code for Entry
+
+;.....
+; Common File Open Routine.  Used by Read, Write and Search First.
+; Enter: DE = File Mode
+;       HL = Ptr to Null-terminated Path String
+; Exit : A = 0 if Error, HL = -1
+;           File Descriptor, A <> 0 if Ok
+
+OpenF: PUSH    DE              ; Mode
+       PUSH    HL              ;  Path
+       LD      HL,1            ;   Fuzix Open Fcn #
+       PUSH    HL
+       RST     30H             ;    _open (Path, Mode);
+       POP     BC              ; Clean Stack
+       POP     BC
+       POP     BC
+       LD      A,H
+       AND     L
+       INC     A               ; FF -> 0?
+       RET                     ; ..return (HL=-1/A=0 if Err, HL=fd/A<>0 of Ok)
+
+;------------------------------------------------
+;         case 16: return (closefile (arg));           /* Close File */
+
+;     if (close (arg->desc) == -1)
+
+Fcn16: LD      IY,(_arg)
+       LD      (IY+13),0       ; clear file open flag
+
+       LD      HL,11           ; Fuzix sync function #
+       PUSH    HL
+       RST     30H             ; Execute!
+       POP     BC              ; Clean Stack
+
+       JP      Exit0           ; Return OK
+
+;....
+; Close file descriptor
+
+CloseV:        PUSH    DE
+       LD      HL,2            ;  Fuzix Close Fcn #
+       PUSH    HL
+       RST     30H             ;   Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+       RET
+
+;------------------------------------------------
+;         case 17:                                     /* Search First */
+
+Fcn17: CALL    CkSrch          ; Ensure Search File closed
+       LD      HL,'.'          ; Open current directory
+       LD      (RName),HL      ;  store name in Secondary work string
+       LD      DE,0            ; Open Read-Only
+       LD      HL,RName
+       CALL    OpenF           ;  _open ('.', 0);
+       RET     Z               ; HL = -1, A = 0 if Can't Open
+
+       LD      (srchFD),HL     ; Else Ok, Save File Descriptor
+       LD      (curFil),HL     ;   Duplicate for Reading
+                       ;..fall thru to read one entry..
+;------------------------------------------------
+;         case 18: return (255);                       /* Search Next */
+
+;
+;      FIXME: dir entries need to be bigger
+;
+Fcn18: LD      HL,(dmaadr)
+       LD      (dmaSav),HL     ; Save "real" DMA
+Fcn18A:        LD      HL,dir+16
+       LD      (dmaadr),HL     ;  Set DMA for Dir Op'n
+       LD      A,16            ;  Getdirent
+       LD      DE,32           ;  Len of Dir entries
+       CALL    RdWrt0          ;   Read an Entry
+       JR      C,Fcn18E        ; Error if Carry Set
+       OR      A               ; Read Ok?
+       JR      Z,Fcn18E        ; ..Return HL=-1 if EOF
+       CALL    ChkDir          ; Else Set Dir to CP/M, Check Match
+       OR      A
+       JR      NZ,Fcn18A       ; ..loop if No Match
+
+       LD      A,(_call)
+       CP      15              ; Is this a File Open internal Call?
+       LD      HL,0            ;  (set Success, Index 0)
+       JR      Z,Fcn18X        ; ..exit now if Yes
+
+       LD      HL,dir          ; Else
+       LD      DE,(dmaSav)     ;  Move Dir Buffer to "real" DMA
+       LD      BC,128
+       LDIR
+       LD      L,B             ; Use 0 in BC
+       LD      H,C             ;   to show Index 0 (success)
+       JR      Fcn18X          ;  ..exit
+
+Fcn18E:        LD      HL,-1
+Fcn18X:        LD      DE,(dmaSav)
+       LD      (dmaadr),DE     ; Restore "real" DMA Addr
+       RET
+
+;------------------------------------------------
+;         case 19: return (delete (arg));              /* Delete File */
+
+Fcn19: CALL    CkSrch          ; Ensure Search file closed
+
+;     if (unlink (getname (arg)) == -1)
+                               ; DE -> arg
+       CALL    GetNam          ;  Parse to String
+       PUSH    HL              ; String
+       LD      HL,6            ;  UZI Unlink Fcn #
+       PUSH    HL
+       RST     30H             ;   Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+
+;         return (255);
+;     return (0);
+
+       LD      A,H
+       AND     L
+       INC     A               ; FF->0?
+       JP      NZ,Exit0        ;  return Ok if No
+
+ExitM1:        LD      HL,-1
+       RET
+
+
+;------------------------------------------------
+;         case 33:                                     /* Read File Random */
+;          readrandom (fcb)
+;          {
+
+Fcn33: CALL    RWprep          ; Prepare File for access
+       JP      Z,Exit1
+
+       LD      IY,(_arg)
+       LD      A,(IY+33)       ; Set Record Count from
+       LD      (IY+32),A       ; Random Record number
+       LD      A,(IY+34)       ;
+       LD      (IY+12),A       ;
+
+       CALL    DoRead
+       JR      RWEx
+
+;....
+DoRead:
+       CALL    SkOff           ; Seek to Offset (128-byte rec in Block)
+       CALL    SkBlk           ; Seek to 512-byte Block
+
+       CALL    BRead           ; Read 1 Sector
+
+       PUSH    AF
+       LD      DE,(curFil)
+;;;;   CALL    CloseV          ; Close the file
+       LD      DE,0
+       LD      (curFil),DE
+       POP     AF
+
+       RET
+
+
+;------------------------------------------------
+;         case 20: return (readfile (arg));            /* Read File */
+; readfile (arg)
+; {
+;     nread = read (blk->desc, dmaadr, 128);
+                               ; DE -> arg (FCB)
+Fcn20: CALL    RWprep          ; Prepare file for access
+       JP      Z,Exit1
+
+       CALL    DoRead          ; Read 1 Sector
+
+;     arg.recno++;
+
+       PUSH    AF
+       CALL    IncCR           ; Bump Current Record #
+       POP     AF
+
+RWEx:  JP      C,Exit1         ; ..Error if Carry Set
+
+;     if (nread == 0)
+;         return (0);
+
+       OR      A               ; Good Read?
+       JP      Z,Exit0         ;   exit w/0 if Yes
+
+;     else  return (1)
+
+       JP      Exit1
+
+;------------------------------------------------
+;         case 34:                                     /* Write File Random */
+;          writerandom (fcb)
+;          {
+;          /* CAUTION the seek calls MUST be in this order */
+;              _seek (f, (int)(fcb+33) % 128, 0);          /* byte  seek */
+;              _seek (f, (int)(fcb+33) / 128, 3);          /* block seek */
+
+Fcn34: CALL    RWprep          ; Prepare file for access
+       JP      Z,Exit1
+
+       LD      IY,(_arg)
+       LD      A,(IY+33)       ; Set Record Count from
+       LD      (IY+32),A       ; Random Record number
+       LD      A,(IY+34)       ;
+       LD      (IY+12),A       ;
+
+       CALL    DoWrite
+       JR      RWEx
+
+;....
+DoWrite:
+       CALL    SkOff           ; Seek to Offset (128-byte rec in Block)
+       CALL    SkBlk           ; Seek to 512-byte Block
+
+       CALL    BWrit           ; Write 1 Sector
+
+       PUSH    AF
+       LD      DE,(curFil)
+;;;;   CALL    CloseV          ; Close the file
+       LD      DE,0
+       LD      (curFil),DE
+       POP     AF
+
+       RET
+
+;------------------------------------------------
+;         case 21: return (writefile (arg));           /* Write File */
+; writefile (arg)
+; {
+;     if (write (blk->desc, dmaadr, 128) != 128)
+
+                               ; DE -> arg (FCB)
+Fcn21: CALL    RWprep          ; Prepare file for access
+       JP      Z,Exit1
+
+Fcn21A:        CALL    DoWrite         ;   Write
+
+;     arg.recno++;
+
+       PUSH    AF
+       CALL    IncCR           ; Bump Current Record #
+       POP     AF
+
+;         return (255);
+;     return (0);
+
+       JR      RWEx            ; ..exit via Common R/W Code
+; }
+
+;------------------------------------------------
+;         case 22: return (makefile (arg));            /* Create File */
+; makefile (arg)
+; {
+;     desc = creat (getname (blk), 0666);
+
+Fcn22: CALL    CkSrch          ; Ensure Search file closed
+       LD      HL,0666Q        ; Own/Grp/Oth are Read/Execute
+       PUSH    HL              ; DE -> arg
+       LD      HL, 502H        ; O_CREAT|O_RDWR|O_TRUNC
+       CALL    GetNam          ;  This name string
+       PUSH    HL
+       LD      HL,1            ;   Fuzix open Fcn #
+       PUSH    HL
+       RST     30H             ;    Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+       POP     BC
+       POP     BC
+
+;     if (desc == -1)
+
+       LD      A,H
+       AND     L
+       INC     A               ; FF -> 0?
+
+;         return (255);
+
+       RET     Z               ; ..return -1 if Yes
+
+;     arg.recno = 0;
+
+       EX      DE,HL
+       CALL    CloseV
+       JP      Open1
+
+;------------------------------------------------
+;         case 23: return (rename (arg));              /* Rename File */
+; rename (arg)
+; {
+;     RName = getname (arg);
+;
+;      FIXME: should use rename() syscall now
+;
+Fcn23: CALL    CkSrch          ; Ensure Search file closed
+       PUSH    DE              ; Save FCB Ptr
+       CALL    GetNam          ;  parse to UZI String
+
+       LD      HL,FName
+       LD      DE,RName
+       LD      BC,12
+       LDIR                    ; Copy to Rename string
+
+;     FName = getname (arg+16);
+
+       POP     DE              ; DE -> _arg
+       LD      HL,16
+       ADD     HL,DE           ; Offset to New Name
+       EX      DE,HL
+       CALL    GetNam          ;  parse it returning HL -> FName
+
+;     if (link (RName, FName) < 0) {
+
+       PUSH    HL              ; New Name
+       LD      HL,RName        ;  Old Name
+       PUSH    HL
+       LD      HL,5            ;   UZI link Fcn #
+       PUSH    HL
+       RST     30H             ;    Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+       POP     BC
+
+;         return (-1);
+
+       JP      C,ExitM1        ; Exit w/Err if Bad
+;     }
+;     if (unlink (RName) < 0) {
+
+       LD      HL,RName        ; Old Name
+       PUSH    HL
+       LD      HL,6            ;  UZI unlink Fcn #
+       PUSH    HL
+       RST     30H             ;   Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+       JP      NC,Exit0        ;   exit w/0 if Ok
+
+;         unlink (FName);
+                               ; Else remove the new iNode
+       LD      HL,FName        ; New Name
+       PUSH    HL
+       LD      HL,6            ;  UZI unlink Fcn #
+       PUSH    HL
+       RST     30H             ;   Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+
+;         return (-1);
+
+       JP      C,ExitM1        ;  return -1 if Bad
+;     }
+;     return (0);
+
+       JP      Exit0           ;   else return Ok
+; }
+
+;------------------------------------------------
+;         case 24: return (1);                 /* Return Disk Login Vector */
+
+Fcn24:
+Exit1: LD      HL,1
+       RET
+
+;------------------------------------------------
+;         case 26: dmaadr = (char *)arg;               /* Set DMA Address */
+;                  break;
+                               ; Enter DE = DMA Address
+Fcn26: LD      C,E
+       LD      B,D             ; Move to Bios Regs
+       JP      BSDma           ;  Set in Bios & return
+
+;------------------------------------------------
+;         case 27: return (-1)                 /* Get Allocation Map */
+;         case 29: return (-1)                 /* Get R/O Vector Address */
+Fcn27:
+Fcn29: LD      HL,-1
+       RET
+
+;------------------------------------------------
+;         case 31: return (&dpb);              /* Get Disk Param Table Addr */
+
+Fcn31: LD      HL,dpb
+       RET
+; }
+
+;------------------------------------------------
+;         case 35:                             /* Return File Size in FCB */
+;                                 /* Use stat fcn, rounding up to mod-128 */
+;          if (_stat (dname, &statbuf) == 0) {
+                               ; DE -> fcb
+Fcn35: CALL    CkSrch          ; Ensure Search file closed
+       CALL    GetNam          ;  parse to UZI String
+       LD      DE,stBuf
+       PUSH    DE              ; &statbuf
+       PUSH    HL              ;  dname
+       LD      HL,15           ;   UZI stat Fcn #
+       PUSH    HL
+       RST     30H             ;    Execute!
+       POP     BC              ; Clean Stk
+       POP     BC
+       POP     BC
+       LD      IY,(_arg)
+       LD      A,H
+       OR      L               ; 0?
+       JR      NZ,Fcn35X       ; ..jump if Bad
+
+;              (int)fcb+33 = ((512 * statbuf.st_size.o_blkno
+;                            + statbuf.st_size.o_offset)
+;                            + 127)
+;                            >> 7;
+;      FIXME: offset is now a simple number so this is wrong
+;
+       LD      HL,(stBuf+14)   ; Get Offset
+       LD      DE,127
+       ADD     HL,DE           ;  round up to next 128-byte block
+       ADD     HL,HL           ;   Shift so H has 128-byte blk #
+       LD      E,H             ;    position in DE
+       LD      HL,(stBuf+16)   ; Get Block
+       ADD     HL,HL           ;  * 2
+       ADD     HL,HL           ;   * 4 for 128-byte Block Count
+       ADD     HL,DE           ; Now have CP/M Record Size
+       LD      (IY+33),L
+       LD      (IY+34),H       ;  Store in RR fields in FCB
+       LD      (IY+35),D       ; (D = 0)
+
+;              return (0);
+
+       LD      L,D
+       LD      H,D             ; HL = 0
+       RET
+
+;          else {
+;              (int)fcb+33 = 0;
+
+Fcn35X:        LD      (IY+33),0
+       LD      (IY+34),0
+       LD      (IY+35),0
+
+;              return (-1);
+
+       LD      HL,-1
+;          }
+       RET
+
+;------------------------------------------------
+;         case 36:                     /* Set Random Record Field in FCB */
+
+Fcn36: LD      IY,(_arg)
+       LD      A,(IY+32)       ; Fetch RecNo
+       LD      (IY+33),A       ;  place in LSB of RR field (r0)
+       LD      A,(IY+12)
+       LD      (IY+34),A       ;  set (r1)
+       LD      (IY+35),0       ;  Clear Hi byte of RR (r2)
+
+       LD      HL,0            ; Return Ok
+       RET
+
+;===========================================================
+;                BDos Support Routines
+;===========================================================
+; char *
+; getname (struct fcb *blk)
+; {
+;     int j;
+;     static char name[16];
+;     char *p;
+
+;     p = name;
+                               ; Enter: DE -> FCB drive byte
+GetNam:        LD      IX,FName        ; Dest to string
+       EX      DE,HL
+       PUSH    HL              ;   (save)
+       INC     HL              ;  adv to 1st char of FN
+
+;     for (j = 0; j < 8; ++j)
+;     {
+;         if (!blk->name[j] || blk->name[j] == ' ')
+;             break;
+
+       LD      B,8
+GetN0: LD      A,(HL)
+       INC     HL
+       OR      A
+       JR      Z,GetN1
+       CP      ' '
+       JR      Z,GetN1
+
+;         *p++ = chlower (blk->name[j]);
+
+       CALL    ChLower
+       LD      (IX+0),A
+       INC     IX
+       DJNZ    GetN0
+;     }
+
+GetN1: POP     HL
+       LD      DE,9
+       ADD     HL,DE           ; Pt to 1st char of FT
+       LD      A,(HL)
+       CP      ' '             ; Any Type?
+       JR      Z,GetNX         ; ..quit if Not
+
+;     *p++ = '.';
+
+       LD      (IX+0),'.'
+       INC     IX
+
+;     for (j = 0; j < 3; ++j)
+
+       LD      B,3
+
+;     {
+;         if (!blk->ext[j] || blk->ext[j] == ' ')
+;             break;
+
+GetN2: LD      A,(HL)
+       INC     HL
+       CP      ' '
+       JR      Z,GetNX
+
+;         *p++ = chlower (blk->ext[j]);
+
+       CALL    ChLower
+       LD      (IX+0),A
+       INC     IX
+       DJNZ    GetN2
+
+;     }
+;     *p = '\0';
+
+GetNX: LD      (IX+0),0
+
+;     return (name);
+
+       LD      HL,FName
+       RET
+; }
+
+;
+;      FIXME: we need to use lseek for Fuzix
+;
+;.....
+; Seek Offset.  Uses Record Count to set 128-byte offset in 512-byte Sctr.
+
+SkOff: LD      BC,0
+       PUSH    BC              ; 0 Mode (Absolute Offset Position)
+       LD      IY,(_arg)       ; Pt to current fcb
+       LD      A,(IY+32)       ; Fetch Lo Byte of Offset
+       AND     03H             ;  (kill all but mod 512, 2 bits)
+       LD      B,A
+       SRL     B
+       RR      C               ;   Offset is pos'n within 512-byte Rec
+       JR      SeekV           ;  ..finish in Common Code
+
+;.....
+; Seek Block.  Uses Record Count to set Div-512 Block Number
+
+SkBlk: LD      HL,3            ; 3 Mode (Absolute Block Position)
+       PUSH    HL              ;  to Stk
+       LD      IY,(_arg)
+       LD      C,(IY+32)
+       LD      B,(IY+12)
+       SRL     B
+       RR      C
+       SRL     B
+       RR      C               ;   Blk # is DIV 512
+SeekV: PUSH    BC
+       LD      HL,(curFil)     ;    fd
+       PUSH    HL
+       LD      HL,9            ;     UZI Seek Fcn #
+       PUSH    HL
+       RST     30H             ;      Execute!
+       POP     BC
+       POP     BC
+       POP     BC
+       POP     BC
+       RET
+
+;.....
+; Perform File Access Preparatory actions:
+; Open file for R/W and Seek to current Record #
+; Enter: DE = Ptr to FCB
+; Exit : A = 0 and HL = -1 if Error, A <> 0 if Ok
+
+RWprep:        CALL    CkSrch          ; Ensure Search file closed
+       LD      HL,13           ; offset to S1 (file open flag)
+       ADD     HL,DE
+       LD      A,(HL)
+       AND     80h
+       LD      HL,-1
+       RET     Z
+
+       CALL    GetNam          ;  Parse FCB Fn.Ft to String
+
+       CALL    COpen
+       RET     Z               ; ..return -1 on error
+
+       LD      (curFil),HL     ; store file descriptor for Bios
+       RET
+
+COpen: PUSH    HL
+       LD      DE,CName
+chk:   LD      A,(DE)
+       CP      (HL)            ; compare filename with cached name
+       JR      NZ,differ
+       OR      A
+       JR      Z,same
+       INC     HL
+       INC     DE
+       JR      chk
+same:  POP     DE              ; if same, just return the cached file descr
+       LD      HL,(Cfd)
+       LD      A,H
+       AND     L
+       INC     A
+       RET     NZ
+       EX      DE,HL
+       JR      op1
+differ:        LD      HL,(Cfd)
+       LD      A,H
+       AND     L
+       INC     A
+       EX      DE,HL
+       CALL    NZ,CloseV       ; close old file
+       POP     HL              ; restore file name
+       CALL    Ccopy
+op1:   LD      DE,2            ; open for R/W
+       CALL    OpenF
+       LD      (Cfd),HL
+       RET
+
+Ccopy: PUSH    HL
+       LD      DE,CName
+cpy:   LD      A,(HL)
+       LD      (DE),A
+       INC     HL
+       INC     DE
+       OR      A
+       JR      NZ,cpy
+       POP     HL
+       RET
+
+;.....
+; Convert UZI Directory Entry at dir+16 to CP/M FCB entry at dir, Zero rest.
+; Ambiguously compare FCB FN.FT at dir to that passed at arg, returning Zero
+; if Match, Non-Zero if mismatch.
+
+ChkDir:        LD      DE,dir
+       LD      HL,dir+16+2     ; Pt to 1st char of Name
+       XOR     A
+       LD      (DE),A          ; Zero Drive field
+       INC     DE              ;  Pt to 1st char of FN
+       LD      B,8
+       CALL    ChkD0           ;   Fix Name
+       LD      B,3
+       CALL    ChkD0           ;    & Type
+       LD      B,21
+       CALL    ZeroDE          ;     Clear rest of Dir entry
+
+       LD      DE,(_arg)
+       INC     DE              ; Pt to 1st char of FN
+       LD      A,(DE)
+       CP      ' '             ; Any Name present?
+       JR      NZ,ChkFN0       ; ..jump if Yes
+       LD      HL,8
+       ADD     HL,DE           ;  Else offset to 1st char of FT
+       LD      A,(HL)
+       CP      ' '             ;   Type present?
+       LD      A,0FFH          ;    (Assume Error)
+       RET     Z               ;     Return w/Err Flag if no Type either
+
+ChkFN0:        LD      HL,dir+1        ; Else Compare name/type fields
+       LD      B,11
+                       ; Ambiguous FN.FT compare of (HL) to (DE)
+ChkL:  LD      A,(DE)
+       CP      '?'             ; Accept anything?
+       JR      Z,ChkL0         ; ..jump if ambiguous
+       XOR     (HL)
+       AND     7FH             ; Match?
+       RET     NZ              ; .Return Non-Zero if Not
+ChkL0: INC     HL
+       INC     DE
+       DJNZ    ChkL            ; ..loop til Done
+       XOR     A               ;    return Zero for Match
+       RET
+
+;.....
+; Parse FileSpec addressed by HL into FN.FT Spec addressed by DE.
+
+ChkD0: LD      A,(HL)          ; Get Char
+       CP      'a'
+       JR      C,ChkD1
+       CP      'z'+1
+       JR      NC,ChkD1
+       AND     5FH             ; Convert to Uppercase
+ChkD1: OR      A               ; End of String?
+       JR      Z,ChkDE         ; ..jump if End
+       INC     HL              ;     (bump Inp Ptr if Not End)
+       CP      '.'
+       JR      Z,ChkDE         ;  ..or Period field separator
+       LD      (DE),A          ; Store char
+       INC     DE              ;  bump Dest
+       DJNZ    ChkD0           ; ..loop til field done
+ChkD2: LD      A,(HL)          ; Get Next
+       OR      A
+       RET     Z               ;  Exit at End of string
+       INC     HL              ;   (adv to next)
+       CP      '.'
+       RET     Z               ;   or field separator
+       JR      ChkD2           ;  ..loop til end found
+
+ChkDE: LD      A,' '           ; Fill rest w/Spaces
+ChkD3: INC     B
+       DEC     B               ; More in field?
+       RET     Z               ; ..exit if Not
+       JR      ZeroL           ;  ..else stuff spaces til field ends
+
+;.....
+; Zero area addressed by DE for B Bytes.  Uses A,B,DE.
+
+ZeroDE:        XOR     A
+ZeroL: LD      (DE),A
+       INC     DE
+       DJNZ    ZeroL
+       RET
+
+;.....
+; Close the Directory if we just exitted a SearchF/SearchN sequence
+
+CkSrch:        PUSH    DE              ; Save Regs
+       PUSH    HL
+       LD      DE,(srchFD)     ; Get File Desc
+       LD      A,D
+       OR      E               ; Anything open?
+       CALL    NZ,CloseV       ;  Close file if Yes
+       LD      HL,0
+       LD      (srchFD),HL     ;   Mark as closed
+       POP     HL              ;    (ignore Errors)
+       POP     DE
+       RET
+
+;.....
+; Bump current Record # for sequential R/W operations
+
+IncCR: LD      IY,(_arg)
+       INC     (IY+32)         ; Bump Lo byte
+       RET     NZ
+       INC     (IY+12)         ; Bump Hi byte
+       RET
+
+;.....
+; Init Current Record #
+
+ZeroCR:        LD      IY,(_arg)
+       LD      (IY+32),0       ; Clear Lo Byte
+       LD      (IY+12),0       ; Clear Hi Byte
+       RET
+
+;.....
+; Convert char in A to Lowercase Ascii
+
+ChLower:
+       CP      'A'
+       RET     C
+       CP      'Z'+1
+       RET     NC
+       OR      20H             ; Convert to Lcase
+       RET
+
+;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+; Bdos data in Text Segment for treating as single module
+
+; struct fcb {
+;     char drive;
+;     char name[8];
+;     char ext[3];
+;     char junk1[4];
+;     char desc;       /* This byte & 1st byte of Name used for file desc */
+;     char name2[8];
+;     char ext2[3];
+;     char junk2[4];
+;     char junk3;
+; };
+
+_arg:  DEFW    00              ; Argument passed to Bdos       (char *arg;)
+_call: DEFB    0               ; Bdos Function #               (char call;)
+FName: DEFM    '            '  ; Storage for FCB "name" String
+RName: DEFM    '            '  ; 2nd Storage for FCB "name" String (rename)
+
+CName: DEFM    '            '  ; cached filename
+       DEFB    0
+Cfd:   DEFW    -1              ; cached file descriptor
+
+curFil:        DEFW    00              ; Storage for File Descriptor of FCB
+                               ;  (set by Bdos, Used by Bios)
+stBuf: DEFS    30              ; Buffer for stat() results
+
+DOSSIZ   EQU  $-EStart
+RESV   EQU     100H-(DOSSIZ&0FFH)
+       DEFS    RESV            ; Pad to make Bios start on even mult of 256
+
+;============================================================
+; The Bios Jump table MUST start on an even MOD 256 boundary
+;============================================================
+
+__bios:        JP      __cold          ; 0 Cold Boot
+WBoot: JP      Exit            ; 1 Warm Boot
+BConSt:        JP      ConSt           ; 2 Console Status
+BConIn:        JP      ConIn           ; 3 Console Input
+BConOu:        JP      ConOut          ; 4 Console Output
+       JP      List            ; 5 Printer Output
+       JP      AuxOut          ; 6 Auxiliary Output (Punch)
+       JP      AuxIn           ; 7 Auxiliary Input (Reader)
+       JP      Home            ; 8 Home drive head
+       JP      SelDsk          ; 9 Select Drive
+       JP      SetTrk          ; 10 Set Track
+       JP      SetSec          ; 11 Set Sector
+BSDma: JP      SetDMA          ; 12 Set DMA Address
+BRead: JP      Read            ; 13 Read Sector
+BWrit: JP      Write           ; 14 Write Sector
+       JP      ListSt          ; 15 Printer Status
+       JP      SecTrn          ; 16 Translate Sector
+
+;------------------------------------------------
+; Cold Entry.  Set up CP/M vectors and Stack, Get
+; Current TTY Parms, Save for Exit, and begin
+
+__cold:        LD      A,0C3H
+       LD      HL,__bdos
+       LD      SP,HL           ; Set CP/M Stack for execution
+       LD      (0005H),A       ;  Set Bdos Vector
+       LD      (0006H),HL
+       LD      HL,WBoot
+       LD      (0000H),A       ;   Set Bios Warm Boot Vector
+       LD      (0001H),HL
+
+       LD      HL,ttTermios0   ; & buf
+       LD      DE,TCGETS       ;  ioctl fcn to Get Parms
+       CALL    IoCtl           ;   Execute ioctl fcn on STDIN
+       LD      HL,ttTermios0
+       LD      DE,ttTermios
+       LD      BC, 20
+       LDIR                    ;  Move to Work Area
+               ; Now we need to Change Modes defined in DEVTTY as:
+               ;   RAW    = 20H        (0000040)
+               ;   CRMOD  = 10H        (0000020)
+               ;   ECHO   = 08H        (0000010)
+               ;   CBREAK = 02H        (0000002)
+               ;   COOKED = 00H        (0000000)
+       LD      HL, 0
+       ; Turn all the input and output magic off
+       LD      (ttTermios), HL
+       LD      (ttTermios + 2), HL
+       XOR     A
+       LD      (ttTermios+6), A        ; Echo etch off
+       LD      A, (ttTermios+7)
+       AND     0xF0            ; canonical processing off
+       LD      (ttTermios+7), A
+       LD      HL, 1                   ; VTIME 0
+       LD      (ttTermios+8), HL       ; VMIN 1
+       LD      HL, ttTermios
+       LD      DE, TCSETS
+       CALL    IoCtl                   ; Set terminal bits 
+       
+       CALL    0100H           ;  ..Execute!
+
+;.....
+; 1 - Warm Boot Vector (Exits back to UZI)             {exit (0);}
+;     TTY Port Settings are restored to original state.
+
+Exit:  LD      C,0Dh
+       CALL    ConOut
+       LD      C,0Ah
+       CALL    ConOut
+       LD      HL,ttTermios0   ; & buf
+       LD      DE,TCSETS       ;  ioctl fcn to Set Parms
+       CALL    IoCtl           ;   Execute ioctl Fcn on STDIN
+
+       LD      HL,0            ; Exit Good Status
+       PUSH    HL
+       PUSH    HL              ;  UZI Fcn 0 (_exit)
+       RST     30H             ;   Execute!
+       DI
+       HALT
+
+;.....
+; 2 - Return Console Input Status
+
+ConSt: LD      HL,cnt          ; &buf
+       LD      DE,TIOCINQ      ;  ioctl fcn to read queue count
+       CALL    IoCtl           ;   Execute ioctl on STDIN
+       LD      HL,(cnt)
+       LD      A,H
+       OR      L               ; Anything There?
+       RET     Z               ; ..return Zero if Not
+       OR      0FFH            ; Else signify char waiting
+       RET
+
+;.....
+; 3 - Read Console Input Char                  {read (stdin, &char, 1);}
+
+ConIn: call    ConSt
+       jr      z,ConIn
+       LD      HL,1            ; 1 char
+       PUSH    HL
+       LD      DE,char         ;  Addr to put char
+       PUSH    DE
+       LD      L,STDIN         ;   fd
+       PUSH    HL
+       LD      L,7             ;    UZI Read Fcn
+ChrV0: PUSH    HL
+       RST     30H             ;     Execute
+       POP     BC
+       POP     BC
+       POP     BC
+       POP     BC
+       LD      A,(char)
+       RET
+
+;.....
+; 4 - Write Char in C to Console               {write (stdout, &char, 1);}
+
+ConOut:        LD      A,C
+       LD      DE,char
+       LD      (DE),A          ; Stash char
+       LD      HL,1            ; 1 char
+       PUSH    HL
+       PUSH    DE              ;  Addr to get char
+       LD      L,STDOUT        ;   fd
+       PUSH    HL
+       LD      L,8             ;    UZI Write Fcn
+       JR      ChrV0           ;   ..go to common code
+
+;.....
+
+List:                          ; Bios Fcn 5
+AuxOut:                                ; Bios Fcn 6
+AuxIn:                         ; Bios Fcn 7
+Home:                          ; Bios Fcn 8
+SetTrk:                                ; Bios Fcn 10
+SetSec:                                ; Bios Fcn 11
+ListSt:                                ; Bios Fcn 15
+SecTrn:        XOR     A               ; Bios Fcn 16.  These are No-Ops
+       RET
+
+;.....
+; 9 - Select Disk.  Simply return the DPH pointer
+
+SelDsk:        LD      HL,dph          ; Return DPH Pointer
+       RET
+
+;.....
+; 12 - Set DMA Transfer Address
+
+SetDMA:        LD      (dmaadr),BC     ; Save Address
+       Ret
+
+;.....
+; 13 - Read a "Sector" to DMA Address          {read (curFil, dmaadr, 128);}
+
+Read:  LD      A,7             ; Set UZI Read Fcn
+       CALL    RdWrt           ;  Do the work
+       RET     C               ; ..exit if Error
+       OR      A               ; 0 bytes Read?
+       JR      Z,XErr1         ; ..Return Error if Yes (EOF)
+       SUB     128             ; A full 128 bytes Read?
+       RET     Z               ;   return Ok if Yes
+       LD      DE,(dmaadr)
+       ADD     HL,DE           ; Else offset to byte after end
+Feof:  LD      (HL),1AH        ;  stuff EOF in case of text
+       INC     HL
+       INC     A
+       JR      NZ,Feof
+       RET                     ;   exit with OK status
+
+;.....
+; 14 - Write a "Sector" from DMA Address       {write (curFil, dmaadr, 128);}
+
+Write: LD      A,8             ; Set UZI Write Fcn
+       CALL    RdWrt           ;  Do the work
+       RET     C               ; ..exit if Error
+       SUB     128             ; Good Write?
+       RET     Z               ;   return Ok if Yes
+XErr1: SCF
+       JR      XErr            ;  Else Return Error
+
+; Common Read/Write Support Routine
+
+RdWrt: LD      DE,128          ; 1 "Sector" char
+                       ; Entry Point accessed by Search Next (BDos)
+RdWrt0:        PUSH    DE
+       LD      HL,(dmaadr)     ;  from here
+       PUSH    HL
+       LD      HL,(curFil)     ;   to this file
+       PUSH    HL
+       LD      E,A             ;    Position R/W Fcn #
+       PUSH    DE
+       RST     30H             ;     Execute!
+       POP     BC              ; Clear Stack
+       POP     BC
+       POP     BC
+       POP     BC
+       LD      A,L             ; Shuffle possible byte quantity
+       RET     NC              ; ..return if No Error
+XErr:  LD      A,01H           ; Else Signal Error (keeping Carry)
+       RET
+
+;==========================================================
+;               Bios Support Utilities
+;==========================================================
+; Execute ioctl Function on STDIN
+; Enter: HL = Addr of Parm Block
+;       DE = ioctl Function to execute
+; Exit : None
+; Uses : AF,BC,DE,HL
+
+IoCtl: PUSH    HL              ; &buf
+       PUSH    DE              ;  ioctl fcn
+       LD      E,STDIN         ;   fd
+       PUSH    DE
+       LD      E,29            ;    Fuzix ioctl Fcn #
+       PUSH    DE
+       RST     30H             ;     Execute!
+       POP     BC              ; Clean Stack
+       POP     BC
+       POP     BC
+       POP     BC
+       RET
+
+;- - - - - - - - - - Data Structures - - - - - - - - -
+
+dph:   DEFW    0               ; Ptr to Skew Table
+       DEFW    0,0,0           ; Scratch Words for BDos use
+       DEFW    dir             ; Ptr to Directory Buffer
+       DEFW    dpb             ; Ptr to DPB
+       DEFW    0               ; Ptr to Disk Checksum Buffer
+       DEFW    0               ; Ptr to ALV Buffer
+
+
+dpb:   DEFW    64              ; Dummy Disk Parameter Block
+       DEFB    4
+       DEFB    15
+       DEFW    0FFFFH
+       DEFW    1023
+       DEFB    0FFH,0
+       DEFB    0,0,0,0
+
+;----------------------- Data -----------------------
+
+dmaadr:        DEFW    0080H           ; Read/Write Transfer Addr   (char *dmaadr;)
+dmaSav:        DEFW    0               ; Temp storage of current DMA Address
+srchFD:        DEFW    0               ; File Descriptor for Searches
+char:  DEFB    ' '             ; Byte storage for Conin/Conout
+cnt:   DEFW    0               ; Count of waiting keys
+ttTermios:
+       DEFS    20              ; Working TTY Port Settings
+ttTermios0:
+       DEFS    20              ; Initial TTY Port Settings
+
+dir:   DEFS    128             ; Directory Buffer
+
+       DEFS    128
+_Bstack:
+_userSP:DEFW    0       ; WRS: important that we write data all the way to the very last byte used
+
+BIOSIZ EQU     $-__bios
+CPMSIZ EQU     $-__bdos
+
+        .end startaddr
diff --git a/Kernel/cpu-6502/cpu.h b/Kernel/cpu-6502/cpu.h
new file mode 100644 (file)
index 0000000..e735a08
--- /dev/null
@@ -0,0 +1,21 @@
+typedef unsigned long uint32_t;
+typedef signed long int32_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef signed int size_t;
+
+typedef uint8_t irqflags_t;
+
+typedef int16_t arg_t;
+typedef uint16_t usize_t;              /* Largest value passed by userspace */
+typedef int16_t susize_t;
+
+extern void ei(void);
+extern irqflags_t di(void);
+extern void irqrestore(irqflags_t f);
+
+extern void *memcpy(void *, void *, size_t);
+extern void *memset(void *, int, size_t);
+extern size_t strlen(const char *);
diff --git a/Kernel/cpu-6809/cpu.h b/Kernel/cpu-6809/cpu.h
new file mode 100644 (file)
index 0000000..cc116d1
--- /dev/null
@@ -0,0 +1,22 @@
+typedef unsigned long uint32_t;
+typedef signed long int32_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef signed int size_t;
+
+typedef uint8_t irqflags_t;
+
+typedef int16_t arg_t;
+typedef uint16_t usize_t;              /* Largest value passed by userspace */
+typedef int16_t susize_t;
+
+extern void ei(void);
+extern irqflags_t di(void);
+extern void irqrestore(irqflags_t f);
+
+
+extern void *memcpy(void *, void *, size_t);
+extern void *memset(void *, int, size_t);
+extern size_t strlen(const char *);
\ No newline at end of file
diff --git a/Kernel/cpu-z80/cpu.h b/Kernel/cpu-z80/cpu.h
new file mode 100644 (file)
index 0000000..a88adcd
--- /dev/null
@@ -0,0 +1,29 @@
+typedef unsigned long uint32_t;
+typedef signed long int32_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef int16_t arg_t;                 /* Holds arguments */
+typedef uint16_t usize_t;              /* Largest value passed by userspace */
+typedef int16_t susize_t;
+
+#define ei()   do {__asm ei __endasm; } while(0);
+
+typedef uint16_t irqflags_t;
+
+extern irqflags_t di(void);
+extern void irqrestore(irqflags_t f);
+
+/* compiler provides optimised versions of these: */
+#if defined(__SDCC_z80) || defined(__SDCC_z180) || defined(__SDCC_r2k) || defined(__SDCC_r3ka)
+#define memcpy(dst, src, n) __builtin_memcpy(dst, src, n)
+#define strcpy(dst, src) __builtin_strcpy(dst, src)
+#define strncpy(dst, src, n) __builtin_strncpy(dst, src, n)
+#define strchr(s, c) __builtin_strchr(s, c)
+#define memset(dst, c, n) __builtin_memset(dst, c, n)
+
+extern int16_t strlen(const char *p);
+
+#endif
diff --git a/Kernel/devio.c b/Kernel/devio.c
new file mode 100644 (file)
index 0000000..717e836
--- /dev/null
@@ -0,0 +1,526 @@
+#include <kernel.h>
+#include <printf.h>
+#include <kdata.h>
+#include <stdarg.h>
+
+/* Buffer pool management */
+/*********************************************************************
+The high-level interface is through bread() and bfree().
+Bread() is given a device and block number, and a rewrite flag.  If
+rewrite is 0, the block is actually read if it is not already in the
+buffer pool. If rewrite is set, it is assumed that the caller plans to
+rewrite the entire contents of the block, and it will not be read in,
+but only have a buffer named after it.
+
+Bfree() is given a buffer pointer and a dirty flag.  If the dirty flag
+is 0, the buffer is made available for further use.  If the flag is 1,
+the buffer is marked "dirty", and it will eventually be written out to
+disk.  If the flag is 2, it will be immediately written out.
+
+Zerobuf() returns a buffer of zeroes not belonging to any device.  It
+must be bfree'd after use, and must not be dirty. It is used when a
+read() wants to read an unallocated block of a file.
+
+Bufsync() write outs all dirty blocks.
+
+Note that a pointer to a buffer structure is the same as a pointer to
+the data.  This is very important.
+**********************************************************************/
+
+uint16_t bufclock;             /* Time-stamp counter for LRU */
+
+uint8_t *bread(uint16_t dev, blkno_t blk, bool rewrite)
+{
+       register bufptr bp;
+
+       if ((bp = bfind(dev, blk)) != NULL) {
+               if (bp->bf_busy)
+                       panic("want busy block");
+               goto done;
+       }
+       bp = freebuf();
+       bp->bf_dev = dev;
+       bp->bf_blk = blk;
+
+       /* If rewrite is set, we are about to write over the entire block,
+          so we don't need the previous contents */
+       if (!rewrite) {
+               if (bdread(bp) == -1) {
+                       udata.u_error = EIO;
+                       return (NULL);
+               }
+       }
+
+      done:
+       bp->bf_busy = 1;
+       bp->bf_time = ++bufclock;       /* Time stamp it */
+       return (bp->bf_data);
+}
+
+
+void brelse(void *bp)
+{
+       bfree((bufptr) bp, 0);
+}
+
+
+void bawrite(void *bp)
+{
+       bfree((bufptr) bp, 1);
+}
+
+
+int bfree(bufptr bp, uint8_t dirty)
+{                              /* dirty: 0=clean, 1=dirty (write back), 2=dirty+immediate write */
+       if (dirty)
+               bp->bf_dirty = true;
+       bp->bf_busy = false;
+
+       if (dirty > 1) {        // immediate writeback
+               if (bdwrite(bp) == -1)
+                       udata.u_error = EIO;
+               bp->bf_dirty = false;
+               return -1;
+       }
+       return 0;
+}
+
+
+/* This returns a busy block not belonging to any device, with
+ * garbage contents.  It is essentially a malloc for the kernel.
+ * Free it with brelse()!
+ */
+void *tmpbuf(void)
+{
+       bufptr bp;
+
+       bp = freebuf();
+       bp->bf_dev = NO_DEVICE;
+       bp->bf_busy = true;
+       bp->bf_time = ++bufclock;       /* Time stamp it */
+       return bp->bf_data;
+}
+
+
+void *zerobuf(void)
+{
+       void *b;
+
+       b = tmpbuf();
+       memset(b, 0, 512);
+
+       return b;
+}
+
+
+void bufsync(void)
+{
+       bufptr bp;
+
+       for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
+               if ((bp->bf_dev != NO_DEVICE) && bp->bf_dirty) {
+                       bdwrite(bp);
+                       if (!bp->bf_busy)
+                               bp->bf_dirty = false;
+               }
+       }
+}
+
+bufptr bfind(uint16_t dev, blkno_t blk)
+{
+       bufptr bp;
+
+       for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
+               if (bp->bf_dev == dev && bp->bf_blk == blk)
+                       return bp;
+       }
+       return NULL;
+}
+
+
+bufptr freebuf(void)
+{
+       bufptr bp;
+       bufptr oldest;
+       int16_t oldtime;
+
+       /* Try to find a non-busy buffer and write out the data if it is dirty */
+       oldest = NULL;
+       oldtime = 0;
+       for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
+               if (bufclock - bp->bf_time >= oldtime && !bp->bf_busy) {
+                       oldest = bp;
+                       oldtime = bufclock - bp->bf_time;
+               }
+       }
+       if (!oldest)
+               panic("no free buffers");
+
+       if (oldest->bf_dirty) {
+               if (bdwrite(oldest) == -1)
+                       udata.u_error = EIO;
+               oldest->bf_dirty = false;
+       }
+       return oldest;
+}
+
+
+void bufinit(void)
+{
+       bufptr bp;
+
+       for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
+               bp->bf_dev = NO_DEVICE;
+               bp->bf_busy = false;
+       }
+}
+
+/*
+ *     Helper for hinting that a buffer is not likely to be re-read rapidly
+ *     Ignores the hint if the buffer is dirty, resets it if the buffer is
+ *     requested again
+ */
+void bufdiscard(bufptr bp)
+{
+       if (!bp->bf_dirty)
+               /* Make this the oldest buffer */
+               bp->bf_time = bufclock - 1000;
+}
+
+void bufdump(void)
+{
+       bufptr j;
+
+       kprintf("\ndev\tblock\tdirty\tbusy\ttime clock %d\n", bufclock);
+       for (j = bufpool; j < bufpool + NBUFS; ++j)
+               kprintf("%d\t%u\t%d\t%d\t%u\n", j->bf_dev, j->bf_blk,
+                       j->bf_dirty, j->bf_busy, j->bf_time);
+}
+
+
+/*********************************************************************
+Bdread() and bdwrite() are the block device interface routines.  They
+are given a buffer pointer, which contains the device, block number,
+and data location.  They basically validate the device and vector the
+call.
+
+Cdread() and cdwrite are the same for character (or "raw") devices,
+and are handed a device number.  Udata.u_base, count, and offset have
+the rest of the data.
+**********************************************************************/
+
+/*********************************************************************
+The device driver read and write routines now have only two arguments,
+minor and rawflag.  If rawflag is zero, a single block is desired, and
+the necessary data can be found in udata.u_buf.  Otherwise, a "raw" or
+character read is desired, and udata.u_offset, udata.u_count, and
+udata.u_base should be consulted instead.
+Any device other than a disk will have only raw access.
+**********************************************************************/
+
+int bdread(bufptr bp)
+{
+       uint16_t dev = bp->bf_dev;
+       if (!validdev(dev))
+               panic("bdread: invalid dev");
+
+       udata.u_buf = bp;
+       return ((*dev_tab[major(dev)].dev_read) (minor(dev), 0, 0));
+}
+
+
+int bdwrite(bufptr bp)
+{
+       uint16_t dev = bp->bf_dev;
+       if (!validdev(dev))
+               panic("bdwrite: invalid dev");
+
+       udata.u_buf = bp;
+       return ((*dev_tab[major(dev)].dev_write) (minor(dev), 0, 0));
+}
+
+int cdread(uint16_t dev, uint8_t flag)
+{
+       if (!validdev(dev))
+               panic("cdread: invalid dev");
+       return ((*dev_tab[major(dev)].dev_read) (minor(dev), 1, flag));
+}
+
+int cdwrite(uint16_t dev, uint8_t flag)
+{
+       if (!validdev(dev))
+               panic("cdwrite: invalid dev");
+       return ((*dev_tab[major(dev)].dev_write) (minor(dev), 1, flag));
+}
+
+// WRS: swapread(), swapwrite() removed.
+
+int d_open(uint16_t dev, uint8_t flag)
+{
+       if (!validdev(dev))
+               return -1;
+       return ((*dev_tab[major(dev)].dev_open) (minor(dev), flag));
+}
+
+
+int d_close(uint16_t dev)
+{
+       if (!validdev(dev))
+               panic("d_close: bad device");
+       return (*dev_tab[major(dev)].dev_close) (minor(dev));
+}
+
+int d_ioctl(uint16_t dev, uint16_t request, char *data)
+{
+       if (!validdev(dev)) {
+               udata.u_error = ENXIO;
+               return -1;
+       }
+
+       if ((*dev_tab[major(dev)].dev_ioctl) (minor(dev), request, data)) {
+               if (!udata.u_error)     // maybe the ioctl routine might set this?
+                       udata.u_error = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ *     No such device handler
+ */
+
+int nxio_open(uint8_t minor, uint16_t flag)
+{
+       minor;
+       flag;
+       udata.u_error = ENXIO;
+       return -1;
+}
+
+/*
+ *     Default handlers.
+ */
+int no_open(uint8_t minor, uint16_t flag)
+{
+       minor;
+       flag;
+       return 0;
+}
+
+int no_close(uint8_t minor)
+{
+       minor;
+       return 0;
+}
+
+int no_rdwr(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       minor;
+       rawflag;
+       flag;
+       udata.u_error = EINVAL;
+       return -1;
+}
+
+int no_ioctl(uint8_t minor, uint16_t a, char *b)
+{
+       minor;
+       a;
+       b;
+       udata.u_error = ENOTTY;
+       return -1;
+}
+
+/*
+ *             Character queue management routines
+ */
+
+/* add something to the tail of the queue. */
+bool insq(struct s_queue * q, char c)
+{
+       bool r;
+
+       irqflags_t irq = di();
+
+       if (q->q_count == q->q_size)
+               r = false;      // no space left :(
+       else {
+               *(q->q_tail) = c;
+               ++q->q_count;
+               if (++q->q_tail >= q->q_base + q->q_size)
+                       q->q_tail = q->q_base;
+               r = true;
+       }
+       irqrestore(irq);
+       return r;
+}
+
+
+/* Remove something from the head of the queue. */
+bool remq(struct s_queue * q, char *cp)
+{
+       bool r;
+
+       irqflags_t irq = di();
+
+       if (!q->q_count)
+               r = false;
+       else {
+               *cp = *(q->q_head);
+               --q->q_count;
+               if (++q->q_head >= q->q_base + q->q_size)
+                       q->q_head = q->q_base;
+               r = true;
+       }
+
+       irqrestore(irq);
+       return r;
+}
+
+
+/* Clear the queue to empty conditions.  (UZI280 addition) */
+void clrq(struct s_queue *q)
+{
+       irqflags_t irq = di();
+
+       q->q_head = q->q_tail = q->q_base;
+       q->q_count = 0;
+
+       irqrestore(irq);
+}
+
+
+/* Remove something from the tail; the most recently added char. */
+bool uninsq(struct s_queue *q, char *cp)
+{
+       bool r;
+       irqflags_t irq = di();
+
+       if (!q->q_count)
+               r = false;
+       else {
+               --q->q_count;
+               if (--q->q_tail < q->q_base)
+                       q->q_tail = q->q_base + q->q_size - 1;
+               *cp = *(q->q_tail);
+               r = true;
+       }
+       irqrestore(irq);
+       return r;
+}
+
+// WRS: this isn't used
+// /* Returns true if the queue has more characters than its wakeup number
+//  */
+// bool fullq(struct s_queue *q)
+// {
+//     if (q->q_count > q->q_wakeup) // WRS: shouldn't this be >= ?
+//         return true;
+//     else
+//         return false;
+// }
+
+/*********************************************************************
+             Miscellaneous helpers
+**********************************************************************/
+
+int psleep_flags(void *p, unsigned char flags)
+{
+       if (flags & O_NDELAY) {
+               udata.u_error = EAGAIN;
+               return (-1);
+       }
+       psleep(p);
+       if (udata.u_cursig || udata.u_ptab->p_pending) {        /* messy */
+               udata.u_error = EINTR;
+               return (-1);
+       }
+       return 0;
+}
+
+void kputs(const char *p)
+{
+       while (*p)
+               kputchar(*p++);
+}
+
+static void putdigit0(unsigned char c)
+{
+       kputchar("0123456789ABCDEF"[c & 15]);
+}
+
+static void putdigit(unsigned char c, unsigned char *flag)
+{
+       if (c || *flag) {
+               putdigit0(c);
+               *flag |= c;
+       }
+}
+
+void kputhex(unsigned int v)
+{
+       putdigit0(v >> 12);
+       putdigit0(v >> 8);
+       putdigit0(v >> 4);
+       putdigit0(v);
+}
+
+void kputunum(unsigned int v)
+{
+       unsigned char n = 0;
+       putdigit((v / 10000) % 10, &n);
+       putdigit((v / 1000) % 10, &n);
+       putdigit((v / 100) % 10, &n);
+       putdigit((v / 10) % 10, &n);
+       putdigit0(v % 10);
+}
+
+void kputnum(int v)
+{
+       if (v < 0) {
+               kputchar('-');
+               v = -v;
+       }
+       kputunum(v);
+}
+
+void kprintf(const char *fmt, ...)
+{
+       char *str;
+       unsigned int v;
+       char c;
+       va_list ap;
+
+       va_start(ap, fmt);
+       while (*fmt) {
+               if (*fmt == '%') {
+                       fmt++;
+                       if (*fmt == 's') {
+                               str = va_arg(ap, char *);
+                               kputs(str);
+                               fmt++;
+                               continue;
+                       }
+                       if (*fmt == 'c') {
+                               c = va_arg(ap, int);
+                               kputchar(c);
+                               fmt++;
+                               continue;
+                       }
+                       if (*fmt == 'x' || *fmt == 'd' || *fmt == 'u') {
+                               v = va_arg(ap, int);
+                               if (*fmt == 'x')
+                                       kputhex(v);
+                               if (*fmt == 'd')
+                                       kputnum(v);
+                               if (*fmt == 'u')
+                                       kputunum(v);
+                               fmt++;
+                               continue;
+                       }
+               }
+               kputchar(*fmt);
+               fmt++;
+       }
+}
diff --git a/Kernel/devsys.c b/Kernel/devsys.c
new file mode 100644 (file)
index 0000000..91d2aa0
--- /dev/null
@@ -0,0 +1,93 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devsys.h>
+
+/*
+ *     System devices:
+ *
+ *     Minor   0       null
+ *     Minor   1       mem
+ *     Minor   2       zero
+ *     Minor   3       proc
+ *
+ *     Use Minor 128+ for platform specific devices
+ */
+
+int sys_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+  unsigned char *addr = (unsigned char *) ptab;
+
+  rawflag;flag;
+
+  switch(minor){
+  case 0:
+    return 0;
+  case 1:
+        return uputsys((unsigned char *)udata.u_offset, udata.u_count);
+  case 2:
+       if (udata.u_sysio)
+               memset(udata.u_base, 0, udata.u_count);
+       else
+               uzero(udata.u_base, udata.u_count);
+       return udata.u_count;
+  case 3:
+       if (udata.u_offset >= PTABSIZE * sizeof(struct p_tab))
+               return 0;
+       return uputsys(addr + udata.u_offset, udata.u_count);
+  default:
+    udata.u_error = ENXIO;
+    return -1;
+  }
+}
+
+int sys_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+  unsigned char *addr = (unsigned char *) ptab;
+
+  rawflag;flag;
+
+  switch(minor){
+  case 0:
+  case 2:
+    return udata.u_count;
+  case 1:
+    if (udata.u_offset < 0x0100) {
+      udata.u_error = EPERM;
+      return -1;
+    }
+    return ugetsys((unsigned char *)udata.u_offset, udata.u_count);
+  case 3:
+    udata.u_error = EINVAL;
+    return -1;
+  default:
+    udata.u_error = ENXIO;
+    return -1;
+  }
+}
+
+#define PIO_TABSIZE    1
+#define PIO_ENTRYSIZE  2
+
+int sys_ioctl(uint8_t minor, uint16_t request, char *data)
+{
+       if (minor != 3) {
+          udata.u_error = ENOTTY;
+         return -1;
+        }
+
+       switch (request) {
+       case PIO_TABSIZE:
+               uputw(maxproc, data);
+               break;
+
+       case PIO_ENTRYSIZE:
+               uputw(sizeof(struct p_tab), data);
+               break;
+
+       default:
+               udata.u_error = EINVAL;
+               return (-1);
+       }
+       return 0;
+}
diff --git a/Kernel/filesys.c b/Kernel/filesys.c
new file mode 100644 (file)
index 0000000..324e904
--- /dev/null
@@ -0,0 +1,1076 @@
+#undef DEBUG
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+/* N_open is given a string containing a path name in user space,
+ * and returns an inode table pointer.  If it returns NULL, the file
+ * did not exist.  If the parent existed, and parent is not null,
+ * parent will be filled in with the parents inoptr. Otherwise, parent
+ * will be set to NULL.
+ */
+
+inoptr n_open(char *uname, inoptr *parent)
+{
+    inoptr r;
+    char *tb;
+
+    tb = (char*)tmpbuf(); /* temporary memory to hold kernel's copy of the filename */
+
+    if (ugets(uname, tb, 512) == -1) {
+        *parent = NULLINODE;
+        return NULLINODE;
+    }
+
+#ifdef DEBUG
+    kprintf("n_open(\"%s\")\n", tb);
+#endif
+
+    r = kn_open(tb, parent);
+
+    brelse(tb);
+
+    return r;
+}
+
+inoptr kn_open(char *name, inoptr *parent)
+{
+    inoptr wd;     /* the directory we are currently searching. */
+    register char *np = name;
+    inoptr ninode;
+    inoptr temp;
+
+#ifdef DEBUG
+    kprintf("kn_open(\"%s\")\n", name);
+#endif
+
+    if(*name == '/')
+        wd = udata.u_root;
+    else
+        wd = udata.u_cwd;
+
+    i_ref(ninode = wd);
+    i_ref(ninode);
+
+    for(;;)
+    {
+        if(ninode)
+            magic(ninode);
+
+        /* cheap way to spot rename inside yourself */
+        if (udata.u_rename == ninode)
+            udata.u_rename = NULLINODE;
+
+        /* See if we are at a mount point */
+        if(ninode)
+            ninode = srch_mt(ninode);
+
+        while(*name == '/')    /* Skip(possibly repeated) slashes */
+            ++name;
+        if(!*name)           /* No more components of path? */
+            break;
+        if(!ninode){
+            udata.u_error = ENOENT;
+            goto nodir;
+        }
+        i_deref(wd);
+        wd = ninode;
+        if(getmode(wd) != F_DIR){
+            udata.u_error = ENOTDIR;
+            goto nodir;
+        }
+        if(!(getperm(wd) & OTH_EX)){
+            udata.u_error = EPERM;
+            goto nodir;
+        }
+
+        /* See if we are going up through a mount point */
+        if((wd == udata.u_root || (wd->c_num == ROOTINODE && wd->c_dev != root_dev)) &&
+                name[0] == '.' && name[1] == '.' &&
+                (name[2] == '/' || name[2] == '\0')){
+            if (wd == udata.u_root) {
+                ninode = wd;
+                name += 2;
+                continue;
+            }
+            temp = fs_tab_get(wd->c_dev)->m_fs->s_mntpt;
+            ++temp->c_refs;
+            i_deref(wd);
+            wd = temp;
+        }
+
+        ninode = srch_dir(wd, name);
+
+        while(*name != '/' && *name)
+            ++name;
+    }
+
+    if(parent)
+        *parent = wd;
+    else
+        i_deref(wd);
+
+    if(!(parent || ninode))
+        udata.u_error = ENOENT;
+
+    return ninode;
+
+nodir:
+    if(parent)
+        *parent = NULLINODE;
+    i_deref(wd);
+    return NULLINODE;
+}
+
+/* Srch_dir is given an inode pointer of an open directory and a string
+ * containing a filename, and searches the directory for the file.  If
+ * it exists, it opens it and returns the inode pointer, otherwise NULL.
+ * This depends on the fact that ba_read will return unallocated blocks
+ * as zero-filled, and a partially allocated block will be padded with
+ * zeroes.
+ */
+
+inoptr srch_dir(inoptr wd, char *compname)
+{
+    int curentry;
+    blkno_t curblock;
+    struct direct *buf;
+    int nblocks;
+    uint16_t inum;
+
+    nblocks = (wd->c_node.i_size + BLKMASK) >> BLKSHIFT;
+
+    for(curblock=0; curblock < nblocks; ++curblock) {
+        buf = (struct direct *)bread(wd->c_dev, bmap(wd, curblock, 1), 0);
+        for(curentry = 0; curentry < (512/DIR_LEN); ++curentry) {
+            if(namecomp(compname, buf[curentry].d_name)) {
+                inum = buf[curentry & 0x1f].d_ino;
+                brelse(buf);
+                return i_open(wd->c_dev, inum);
+            }
+        }
+        brelse(buf);
+    }
+    return NULLINODE;
+}
+
+
+/* Srch_mt sees if the given inode is a mount point. If so it
+ * dereferences it, and references and returns a pointer to the
+ * root of the mounted filesystem.
+ */
+
+inoptr srch_mt(inoptr ino)
+{
+    uint8_t j;
+    struct mount *m = &fs_tab[0];
+
+    for(j=0; j < NMOUNTS; ++j){
+        if(m->m_dev != NO_DEVICE &&  m->m_fs->s_mntpt == ino) {
+            i_deref(ino);
+            return i_open(m->m_dev, ROOTINODE);
+        }
+        m++;
+    };
+    return ino;
+}
+
+
+/* I_open is given an inode number and a device number,
+ * and makes an entry in the inode table for them, or
+ * increases it reference count if it is already there.
+ * An inode # of zero means a newly allocated inode.
+ */
+
+inoptr i_open(uint16_t dev, uint16_t ino)
+{
+    struct dinode *buf;
+    inoptr nindex, j;
+    bool isnew = false;
+
+    if(!validdev(dev))
+        panic("i_open: bad dev");
+
+    if(!ino){        /* ino==0 means we want a new one */
+        isnew = true;
+        ino = i_alloc(dev);
+        if(!ino) {
+            udata.u_error = ENOSPC;
+            return NULLINODE;
+        }
+    }
+
+    /* Maybe make this DEBUG only eventually - the fs_tab_get cost
+       is higher than ideal */
+    if(ino < ROOTINODE || ino >= (fs_tab_get(dev)->m_fs->s_isize - 2) * 8) {
+        kputs("i_open: bad inode number\n");
+        return NULLINODE;
+    }
+
+    nindex = NULLINODE;
+    for(j=i_tab; j<i_tab+ITABSIZE; j++){
+        if(!j->c_refs) // free slot?
+            nindex = j;
+
+        if(j->c_dev == dev && j->c_num == ino) {
+            nindex = j;
+            goto found;
+        }
+    }
+    /* Not already in the table. */
+
+    if(!nindex){      /* No unrefed slots in inode table */
+        udata.u_error = ENFILE;
+        return(NULLINODE);
+    }
+
+    buf =(struct dinode *)bread(dev,(ino>>3)+2, 0);
+    memcpy((char *)&(nindex->c_node), (char *)&(buf[ino & 0x07]), 64);
+    brelse(buf);
+
+    nindex->c_dev = dev;
+    nindex->c_num = ino;
+    nindex->c_magic = CMAGIC;
+
+found:
+    if(isnew) {
+        if(nindex->c_node.i_nlink || nindex->c_node.i_mode & F_MASK)
+            goto badino;
+    } else {
+        if(!(nindex->c_node.i_nlink && nindex->c_node.i_mode & F_MASK))
+            goto badino;
+    }
+    nindex->c_refs++;
+    return nindex;
+
+badino:
+    kputs("i_open: bad disk inode\n");
+    return NULLINODE;
+}
+
+
+
+/* Ch_link modifies or makes a new entry in the directory for the name
+ * and inode pointer given. The directory is searched for oldname.  When
+ * found, it is changed to newname, and it inode # is that of *nindex.
+ * A oldname of "" matches a unused slot, and a nindex of NULLINODE
+ * means an inode # of 0.  A return status of 0 means there was no
+ * space left in the filesystem, or a non-empty oldname was not found,
+ * or the user did not have write permission.
+ */
+
+bool ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex)
+{
+    struct direct curentry;
+    int i;
+
+    if(!(getperm(wd) & OTH_WR))
+    {
+        udata.u_error = EPERM;
+        return false;
+    }
+    /* Inserting a new blank entry ? */
+    if (!*newname && nindex != NULLINODE) {
+        udata.u_error = EEXIST;
+        return false;
+    }
+
+    /* Search the directory for the desired slot. */
+
+    udata.u_offset = 0;
+
+    for(;;)
+    {
+        udata.u_count = DIR_LEN;
+        udata.u_base  =(char *)&curentry;
+        udata.u_sysio = true;
+        readi(wd, 0);
+
+        /* Read until EOF or name is found.  readi() advances udata.u_offset */
+        if(udata.u_count == 0 || namecomp(oldname, curentry.d_name))
+            break;
+    }
+
+    if(udata.u_count == 0 && *oldname)
+        return false;                  /* Entry not found */
+
+    memcpy(curentry.d_name, newname, FILENAME_LEN);
+    // pad name with NULLs
+    for(i = 0; i < FILENAME_LEN; ++i)
+        if(curentry.d_name[i] == '\0')
+            break;
+    for(; i < FILENAME_LEN; ++i)
+        curentry.d_name[i] = '\0';
+
+    if(nindex)
+        curentry.d_ino = nindex->c_num;
+    else
+        curentry.d_ino = 0;
+
+    /* If an existing slot is being used, we must back up the file offset */
+    if(udata.u_count){
+        udata.u_offset -= DIR_LEN;
+    }
+
+    udata.u_count = DIR_LEN;
+    udata.u_base  = (char*)&curentry;
+    udata.u_sysio = true;
+    writei(wd, 0);
+
+    if(udata.u_error)
+        return false;
+
+    setftime(wd, A_TIME|M_TIME|C_TIME);     /* Sets c_dirty */
+
+    /* Update file length to next block */
+    if(wd->c_node.i_size & BLKMASK)
+        wd->c_node.i_size += BLKSIZE - (wd->c_node.i_size & BLKMASK);
+
+    return true; // success
+}
+
+
+
+/* Filename is given a path name in user space, and copies
+ * the final component of it to name(in system space).
+ */
+
+void filename(char *userspace_upath, char *name)
+{
+    char *buf;
+    char *ptr;
+
+    buf = tmpbuf();
+    if(ugets(userspace_upath, buf, 512)) {
+        brelse(buf);
+        *name = '\0';
+        return;          /* An access violation reading the name */
+    }
+    ptr = buf;
+    while(*ptr)
+        ++ptr;
+    /* Special case for "...name.../" */
+    while(*ptr != '/' && ptr-- > buf);
+    ptr++;
+    memcpy(name, ptr, FILENAME_LEN);
+    brelse(buf);
+}
+
+
+/* Namecomp compares two strings to see if they are the same file name.
+ * It stops at FILENAME_LEN chars or a null or a slash. It returns 0 for difference.
+ */
+bool namecomp(char *n1, char *n2) // return true if n1 == n2
+{
+    uint8_t n; // do we have enough variables called n?
+
+    n = FILENAME_LEN;
+    while(*n1 && *n1 != '/')
+    {
+        if(*n1++ != *n2++)
+            return false; // mismatch
+        n--;
+        if(n==0)
+            return true; // match
+    }
+
+    return (*n2 == '\0' || *n2 == '/');
+}
+
+
+/* Newfile is given a pointer to a directory and a name, and creates
+ * an entry in the directory for the name, dereferences the parent,
+ * and returns a pointer to the new inode.  It allocates an inode
+ * number, and creates a new entry in the inode table for the new
+ * file, and initializes the inode table entry for the new file.
+ * The new file will have one reference, and 0 links to it.
+ * Better make sure there isn't already an entry with the same name.
+ */
+
+inoptr newfile(inoptr pino, char *name)
+{
+    inoptr nindex;
+    uint8_t j;
+
+    /* First see if parent is writeable */
+    if(!(getperm(pino) & OTH_WR))
+        goto nogood;
+
+    if(!(nindex = i_open(pino->c_dev, 0)))
+        goto nogood;
+
+    /* BUG FIX:  user/group setting was missing  SN */
+    nindex->c_node.i_uid = udata.u_euid;
+    nindex->c_node.i_gid = udata.u_egid;
+
+    nindex->c_node.i_mode = F_REG;   /* For the time being */
+    nindex->c_node.i_nlink = 1;
+    nindex->c_node.i_size = 0;
+    for(j=0; j <20; j++)
+        nindex->c_node.i_addr[j] = 0;
+    wr_inode(nindex);
+
+    if(!ch_link(pino, "", name, nindex)) {
+        i_deref(nindex);
+        goto nogood;
+    }
+    i_deref(pino);
+    return nindex;
+
+nogood:
+    i_deref(pino);
+    return NULLINODE;
+}
+
+
+/* Check the given device number, and return its address in the mount
+ * table.  Also time-stamp the superblock of dev, and mark it modified.
+ * Used when freeing and allocating blocks and inodes.
+ */
+
+fsptr getdev(uint16_t dev)
+{
+    struct mount *mnt;
+    fsptr devfs;
+    time_t t;
+
+    mnt = fs_tab_get(dev);
+
+    if (!mnt || !(devfs = mnt->m_fs) || devfs->s_mounted) {
+        panic("getdev: bad dev");
+        /* Return needed to persuade SDCC all is ok */
+        return NULL;
+    }
+    rdtime(&t);
+    devfs->s_time = (uint32_t)t;
+    devfs->s_timeh = (uint8_t)(t >> 32);
+    devfs->s_fmod = true;
+    ((bufptr)devfs)->bf_dirty = true;
+    return devfs;
+}
+
+
+/* Returns true if the magic number of a superblock is corrupt.
+*/
+
+bool baddev(fsptr dev)
+{
+    return(dev->s_mounted != SMOUNTED);
+}
+
+
+/* I_alloc finds an unused inode number, and returns it, or 0
+ * if there are no more inodes available.
+ */
+
+uint16_t i_alloc(uint16_t devno)
+{
+    fsptr dev;
+    blkno_t blk;
+    struct dinode *buf;
+    int j, k;
+    unsigned ino;
+
+    if(baddev(dev = getdev(devno)))
+        goto corrupt;
+
+tryagain:
+    if(dev->s_ninode) {
+        if(!(dev->s_tinode))
+            goto corrupt;
+        ino = dev->s_inode[--dev->s_ninode];
+        if(ino < 2 || ino >=(dev->s_isize-2)*8)
+            goto corrupt;
+        --dev->s_tinode;
+        return(ino);
+    }
+    /* We must scan the inodes, and fill up the table */
+
+    _sync();           /* Make on-disk inodes consistent */
+    k = 0;
+    for(blk = 2; blk < dev->s_isize; blk++) {
+        buf = (struct dinode *)bread(devno, blk, 0);
+        for(j=0; j < 8; j++) {
+            if(!(buf[j].i_mode || buf[j].i_nlink))
+                dev->s_inode[k++] = 8*(blk-2) + j;
+            if(k==FILESYS_TABSIZE) {
+                brelse(buf);
+                goto done;
+            }
+        }
+        brelse(buf);
+    }
+
+done:
+    if(!k) {
+        if(dev->s_tinode)
+            goto corrupt;
+        udata.u_error = ENOSPC;
+        return(0);
+    }
+    dev->s_ninode = k;
+    goto tryagain;
+
+corrupt:
+    kputs("i_alloc: corrupt superblock\n");
+    dev->s_mounted = 1;
+    udata.u_error = ENOSPC;
+    return(0);
+}
+
+
+/* I_free is given a device and inode number, and frees the inode.
+ * It is assumed that there are no references to the inode in the
+ * inode table or in the filesystem.
+ */
+
+void i_free(uint16_t devno, uint16_t ino)
+{
+    fsptr dev;
+
+    if(baddev(dev = getdev(devno)))
+        return;
+
+    if(ino < 2 || ino >=(dev->s_isize-2)*8)
+        panic("i_free: bad ino");
+
+    ++dev->s_tinode;
+    if(dev->s_ninode < FILESYS_TABSIZE)
+        dev->s_inode[dev->s_ninode++] = ino;
+}
+
+
+/* Blk_alloc is given a device number, and allocates an unused block
+ * from it. A returned block number of zero means no more blocks.
+ */
+
+blkno_t blk_alloc(uint16_t devno)
+{
+    fsptr dev;
+    blkno_t newno;
+    blkno_t *buf;
+    uint8_t *mbuf;
+    int j;
+
+    if(baddev(dev = getdev(devno)))
+        goto corrupt2;
+
+    if(dev->s_nfree <= 0 || dev->s_nfree > FILESYS_TABSIZE)
+        goto corrupt;
+
+    newno = dev->s_free[--dev->s_nfree];
+    if(!newno)
+    {
+        if(dev->s_tfree != 0)
+            goto corrupt;
+        udata.u_error = ENOSPC;
+        ++dev->s_nfree;
+        return(0);
+    }
+
+    /* See if we must refill the s_free array */
+
+    if(!dev->s_nfree)
+    {
+        buf =(blkno_t *)bread(devno, newno, 0);
+        dev->s_nfree = buf[0];
+        for(j=0; j < FILESYS_TABSIZE; j++)
+        {
+            dev->s_free[j] = buf[j+1];
+        }
+        brelse((char *)buf);
+    }
+
+    validblk(devno, newno);
+
+    if(!dev->s_tfree)
+        goto corrupt;
+    --dev->s_tfree;
+
+    /* Zero out the new block */
+    mbuf = bread(devno, newno, 2);
+    memset(mbuf, 0, 512);
+    bawrite(mbuf);
+    return newno;
+
+corrupt:
+    kputs("blk_alloc: corrupt\n");
+    dev->s_mounted = 1;
+corrupt2:
+    udata.u_error = ENOSPC;
+    return 0;
+}
+
+
+/* Blk_free is given a device number and a block number,
+ * and frees the block.
+ */
+
+void blk_free(uint16_t devno, blkno_t blk)
+{
+    fsptr dev;
+    uint8_t *buf;
+
+    if(!blk)
+        return;
+
+    if(baddev(dev = getdev(devno)))
+        return;
+
+    validblk(devno, blk);
+
+    if(dev->s_nfree == FILESYS_TABSIZE) {
+        buf = bread(devno, blk, 1);
+        memcpy(buf, (char *)&(dev->s_nfree), 51*sizeof(int));
+        bawrite(buf);
+        dev->s_nfree = 0;
+    }
+
+    ++dev->s_tfree;
+    dev->s_free[(dev->s_nfree)++] = blk;
+}
+
+
+/* Oft_alloc and oft_deref allocate and dereference(and possibly free)
+ * entries in the open file table.
+ */
+
+int8_t oft_alloc(void)
+{
+    uint8_t j;
+
+    for(j=0; j < OFTSIZE ; ++j) {
+        if(of_tab[j].o_refs == 0) {
+            of_tab[j].o_refs = 1;
+            of_tab[j].o_inode = NULLINODE;
+            return j;
+        }
+    }
+    udata.u_error = ENFILE;
+    return -1;
+}
+
+
+void oft_deref(int8_t of)
+{
+    struct oft *ofptr;
+
+    ofptr = of_tab + of;
+    if(!(--ofptr->o_refs) && ofptr->o_inode) {
+        i_deref(ofptr->o_inode);
+        ofptr->o_inode = NULLINODE;
+    }
+}
+
+
+/* Uf_alloc finds an unused slot in the user file table.
+*/
+
+int8_t uf_alloc_n(int base)
+{
+    uint8_t j;
+
+    for(j=base; j < UFTSIZE ; ++j) {
+        if(udata.u_files[j] == NO_FILE) {
+            return j;
+        }
+    }
+    udata.u_error = ENFILE;
+    return -1;
+}
+
+
+int8_t uf_alloc(void)
+{
+    return uf_alloc_n(0);
+}
+
+
+
+/* I_ref increases the reference count of the given inode table entry.
+*/
+
+void i_ref(inoptr ino)
+{
+    ino->c_refs++;
+}
+
+
+/* I_deref decreases the reference count of an inode, and frees it from
+ * the table if there are no more references to it.  If it also has no
+ * links, the inode itself and its blocks(if not a device) is freed.
+ */
+
+void i_deref(inoptr ino)
+{
+    magic(ino);
+
+    if(!ino->c_refs)
+        panic("inode freed.");
+
+    if((ino->c_node.i_mode & F_MASK) == F_PIPE)
+        wakeup((char *)ino);
+
+    /* If the inode has no links and no refs, it must have
+       its blocks freed. */
+
+    if(!(--ino->c_refs || ino->c_node.i_nlink))
+        /*
+           SN (mcy)
+           */
+        if(((ino->c_node.i_mode & F_MASK) == F_REG) ||
+                ((ino->c_node.i_mode & F_MASK) == F_DIR) ||
+                ((ino->c_node.i_mode & F_MASK) == F_PIPE))
+            f_trunc(ino);
+
+    /* If the inode was modified, we must write it to disk. */
+    if(!(ino->c_refs) && ino->c_dirty)
+    {
+        if(!(ino->c_node.i_nlink))
+        {
+            ino->c_node.i_mode = 0;
+            i_free(ino->c_dev, ino->c_num);
+        }
+        wr_inode(ino);
+    }
+}
+
+
+/* Wr_inode writes out the given inode in the inode table out to disk,
+ * and resets its dirty bit.
+ */
+
+void wr_inode(inoptr ino)
+{
+    struct dinode *buf;
+    blkno_t blkno;
+
+    magic(ino);
+
+    blkno =(ino->c_num >> 3) + 2;
+    buf =(struct dinode *)bread(ino->c_dev, blkno,0);
+    memcpy((char *)((char **)&buf[ino->c_num & 0x07]), (char *)(&ino->c_node), 64);
+    bfree((bufptr)buf, 2);
+    ino->c_dirty = false;
+}
+
+
+/* isdevice(ino) returns true if ino points to a device */
+bool isdevice(inoptr ino)
+{
+    return (ino->c_node.i_mode & F_CDEV);
+}
+
+
+/* This returns the device number of an inode representing a device */
+uint16_t devnum(inoptr ino)
+{
+    return (uint16_t)ino->c_node.i_addr[0];
+}
+
+
+/* F_trunc frees all the blocks associated with the file, if it
+ * is a disk file.
+ */
+void f_trunc(inoptr ino)
+{
+    uint16_t dev;
+    int8_t j;
+
+    dev = ino->c_dev;
+
+    /* First deallocate the double indirect blocks */
+    freeblk(dev, ino->c_node.i_addr[19], 2);
+
+    /* Also deallocate the indirect blocks */
+    freeblk(dev, ino->c_node.i_addr[18], 1);
+
+    /* Finally, free the direct blocks */
+    for(j=17; j >= 0; --j)
+        freeblk(dev, ino->c_node.i_addr[j], 0);
+
+    memset((char *)ino->c_node.i_addr, 0, sizeof(ino->c_node.i_addr));
+
+    ino->c_dirty = true;
+    ino->c_node.i_size = 0;
+}
+
+
+/* Companion function to f_trunc(). */
+void freeblk(uint16_t dev, blkno_t blk, uint8_t level)
+{
+    blkno_t *buf;
+    int8_t j;
+
+    if(!blk)
+        return;
+
+    if(level){
+        buf = (blkno_t *)bread(dev, blk, 0);
+        for(j=255; j >= 0; --j)
+            freeblk(dev, buf[j], level-1);
+        brelse((char *)buf);
+    }
+    blk_free(dev, blk);
+}
+
+
+
+/* Changes: blk_alloc zeroes block it allocates */
+/*
+ * Bmap defines the structure of file system storage by returning
+ * the physical block number on a device given the inode and the
+ * logical block number in a file.  The block is zeroed if created.
+ */
+blkno_t bmap(inoptr ip, blkno_t bn, int rwflg)
+{
+    int i;
+    bufptr bp;
+    int j;
+    blkno_t nb;
+    int sh;
+    uint16_t dev;
+
+    if(getmode(ip) == F_BDEV)
+        return(bn);
+
+    dev = ip->c_dev;
+
+    /* blocks 0..17 are direct blocks
+    */
+    if(bn < 18) {
+        nb = ip->c_node.i_addr[bn];
+        if(nb == 0) {
+            if(rwflg ||(nb = blk_alloc(dev))==0)
+                return(NULLBLK);
+            ip->c_node.i_addr[bn] = nb;
+            ip->c_dirty = true;
+        }
+        return(nb);
+    }
+
+    /* addresses 18 and 19 have single and double indirect blocks.
+     * the first step is to determine how many levels of indirection.
+     */
+    bn -= 18;
+    sh = 0;
+    j = 2;
+    if(bn & 0xff00){       /* bn > 255  so double indirect */
+        sh = 8;
+        bn -= 256;
+        j = 1;
+    }
+
+    /* fetch the address from the inode
+     * Create the first indirect block if needed.
+     */
+    if(!(nb = ip->c_node.i_addr[20-j]))
+    {
+        if(rwflg || !(nb = blk_alloc(dev)))
+            return(NULLBLK);
+        ip->c_node.i_addr[20-j] = nb;
+        ip->c_dirty = true;
+    }
+
+    /* fetch through the indirect blocks
+    */
+    for(; j<=2; j++) {
+        bp =(bufptr)bread(dev, nb, 0);
+        /******
+          if(bp->bf_error) {
+          brelse(bp);
+          return((blkno_t)0);
+          }
+         ******/
+        i =(bn>>sh) & 0xff;
+        if((nb =((blkno_t *)bp)[i]) != 0)
+            brelse(bp);
+        else
+        {
+            if(rwflg || !(nb = blk_alloc(dev))) {
+                brelse(bp);
+                return(NULLBLK);
+            }
+            ((blkno_t *)bp)[i] = nb;
+            bawrite(bp);
+        }
+        sh -= 8;
+    }
+    return(nb);
+}
+
+
+
+/* Validblk panics if the given block number is not a valid
+ *  data block for the given device.
+ */
+void validblk(uint16_t dev, blkno_t num)
+{
+    struct mount *mnt;
+    fsptr devptr;
+
+    mnt = fs_tab_get(dev);
+
+    if(mnt == NULL || !(devptr = mnt->m_fs) || devptr->s_mounted == 0) {
+        panic("validblk: not mounted");
+        return;
+    }
+
+    if(num < devptr->s_isize || num >= devptr->s_fsize)
+        panic("validblk: invalid blk");
+}
+
+
+/* This returns the inode pointer associated with a user's file
+ * descriptor, checking for valid data structures.
+ */
+inoptr getinode(uint8_t uindex)
+{
+    uint8_t oftindex;
+    inoptr inoindex;
+
+    if(uindex >= UFTSIZE || udata.u_files[uindex] == NO_FILE) {
+        udata.u_error = EBADF;
+        return NULLINODE;
+    }
+
+    oftindex = udata.u_files[uindex];
+
+    if(oftindex >= OFTSIZE || oftindex == NO_FILE)
+        panic("getinode: bad desc table");
+
+    if((inoindex = of_tab[oftindex].o_inode) < i_tab || inoindex >= i_tab+ITABSIZE)
+        panic("getinode: bad OFT");
+
+    magic(inoindex);
+    return(inoindex);
+}
+
+
+/* Super returns true if we are the superuser */
+bool super(void)
+{
+    return(udata.u_euid == 0);
+}
+
+/* Similar but this helper sets the error code */
+bool esuper(void)
+{
+    if (udata.u_euid) {
+        udata.u_error = EPERM;
+        return -1;
+    }
+    return 0;
+}
+
+/* Getperm looks at the given inode and the effective user/group ids,
+ * and returns the effective permissions in the low-order 3 bits.
+ */
+uint8_t getperm(inoptr ino)
+{
+    int mode;
+
+    if(super())
+        return(07);
+
+    mode = ino->c_node.i_mode;
+    if(ino->c_node.i_uid == udata.u_euid)
+        mode >>= 6;
+    else if(ino->c_node.i_gid == udata.u_egid)
+        mode >>= 3;
+
+    return(mode & 07);
+}
+
+
+/* This sets the times of the given inode, according to the flags.
+*/
+void setftime(inoptr ino, uint8_t flag)
+{
+    ino->c_dirty = true;
+
+    if(flag & A_TIME)
+        rdtime32(&(ino->c_node.i_atime));
+    if(flag & M_TIME)
+        rdtime32(&(ino->c_node.i_mtime));
+    if(flag & C_TIME)
+        rdtime32(&(ino->c_node.i_ctime));
+}
+
+
+uint16_t getmode(inoptr ino)
+{
+    return(ino->c_node.i_mode & F_MASK);
+}
+
+
+static struct mount *newfstab(void)
+{
+    struct mount *m = fs_tab;
+    int i;
+    for (i = 0; i < NMOUNTS; i++) {
+        if (m->m_dev != NO_DEVICE)
+            return m;
+        m++;
+    }
+    return NULL;
+}
+
+static struct mount *fs_tab_get(uint16_t dev)
+{
+    struct mount *m = fs_tab;
+    int i;
+    for (i = 0; i < NMOUNTS; i++) {
+        if (m->m_dev == dev)
+            return m;
+        m++;
+    }
+    return NULL;
+}
+
+/* Fmount places the given device in the mount table with mount point ino.
+*/
+bool fmount(uint16_t dev, inoptr ino, uint16_t flags)
+{
+    struct mount *m;
+    struct filesys *fp;
+
+    if(d_open(dev, 0) != 0)
+        panic("fmount: can't open filesystem");
+
+    m = newfstab();
+    if (m == NULL) {
+        udata.u_error = EMFILE;
+        return true;   /* Table is full */
+    }
+    /* Pin the buffer at dev 0 blk 1, it will only be released
+       by umount */
+    fp = (filesys *)bread(dev, 1, 0);
+
+    //   kprintf("fp->s_mounted=0x%x, fp->s_isize=0x%x, fp->s_fsize=0x%x\n", 
+    //   fp->s_mounted, fp->s_isize, fp->s_fsize);
+
+    /* See if there really is a filesystem on the device */
+    if(fp->s_mounted != SMOUNTED  ||  fp->s_isize >= fp->s_fsize) {
+        udata.u_error = EINVAL;
+        bfree((bufptr)fp, 0);
+        return true; // failure
+    }
+
+    fp->s_mntpt = ino;
+    if(ino)
+        ++ino->c_refs;
+    m->m_flags = flags;
+    /* Makes our entry findable */
+    m->m_fs = fp;
+    m->m_dev = dev;
+    return false; // success
+}
+
+
+void magic(inoptr ino)
+{
+    if(ino->c_magic != CMAGIC)
+        panic("corrupt inode");
+}
diff --git a/Kernel/font4x6.c b/Kernel/font4x6.c
new file mode 100644 (file)
index 0000000..2d304a6
--- /dev/null
@@ -0,0 +1,139 @@
+#include <config.h>
+
+#ifdef CONFIG_FONT_4X6
+
+const unsigned char font4x6[] = {
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0xee, 0xee, 0xee, 0xee, 0xee, 0x00, 
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x00, 
+       0x4e, 0x4e, 0x4e, 0x0e, 0x4e, 0x00, 
+       0xae, 0xae, 0x0e, 0x0e, 0x0e, 0x00, 
+       0xae, 0xfe, 0xfe, 0xae, 0x0e, 0x00, 
+       0x4e, 0x6e, 0xee, 0xce, 0x4e, 0x00, 
+       0xae, 0x2e, 0x4e, 0x8e, 0xae, 0x00, 
+       0x6e, 0x9e, 0x6e, 0xae, 0xde, 0x00, 
+       0x2e, 0x4e, 0x0e, 0x0e, 0x0e, 0x00, 
+       0x2e, 0x4e, 0x4e, 0x4e, 0x2e, 0x00, 
+       0x4e, 0x2e, 0x2e, 0x2e, 0x4e, 0x00, 
+       0x0e, 0xee, 0xee, 0xee, 0x0e, 0x00, 
+       0x0e, 0x4e, 0xee, 0x4e, 0x0e, 0x00, 
+       0x0e, 0x0e, 0x0e, 0x4e, 0x8e, 0x00, 
+       0x0e, 0x0e, 0xee, 0x0e, 0x0e, 0x00, 
+       0x00, 0x06, 0x0c, 0x06, 0x40, 0x00, 
+       0x00, 0x2c, 0x46, 0x8c, 0x00, 0x00, 
+       0x48, 0xa2, 0xa8, 0xa2, 0x48, 0x02, 
+       0x4a, 0xc5, 0x4a, 0x45, 0xea, 0x05, 
+       0xcd, 0x2b, 0x4d, 0x8b, 0xed, 0x0b, 
+       0xe4, 0x24, 0x64, 0x24, 0xe4, 0x04, 
+       0xa4, 0xa4, 0xec, 0x24, 0x24, 0x04, 
+       0xe4, 0x84, 0xec, 0x2c, 0xe4, 0x04, 
+       0xe6, 0x86, 0xee, 0xa6, 0xe6, 0x06, 
+       0xe0, 0x20, 0x2e, 0x26, 0x26, 0x06, 
+       0xe0, 0xa0, 0xec, 0xac, 0xe4, 0x04, 
+       0xe6, 0xa6, 0xee, 0x2e, 0x26, 0x06, 
+       0x06, 0x06, 0x46, 0x06, 0x46, 0x06, 
+       0x00, 0x00, 0x4e, 0x0e, 0x46, 0x86, 
+       0x26, 0x46, 0x8e, 0x4e, 0x20, 0x00, 
+       0x06, 0xe6, 0x0e, 0xe0, 0x00, 0x00, 
+       0x84, 0x44, 0x2c, 0x4c, 0x80, 0x00, 
+       0xe0, 0x20, 0x6c, 0x04, 0x44, 0x04, 
+       0x44, 0xe4, 0xe7, 0x80, 0x40, 0x00, 
+       0x44, 0xa4, 0xef, 0xa0, 0xa0, 0x00, 
+       0xc0, 0xa0, 0xcf, 0xa4, 0xc4, 0x04, 
+       0x64, 0x84, 0x87, 0x84, 0x64, 0x04, 
+       0xc0, 0xa0, 0xaf, 0xa0, 0xc0, 0x00, 
+       0xe4, 0x84, 0xef, 0x84, 0xe4, 0x04, 
+       0xe4, 0x84, 0xe7, 0x87, 0x84, 0x04, 
+       0x66, 0x86, 0xe7, 0xa6, 0x66, 0x06, 
+       0xa6, 0xa6, 0xe7, 0xa7, 0xa0, 0x00, 
+       0xe0, 0x40, 0x47, 0x47, 0xe6, 0x06, 
+       0x26, 0x26, 0x2f, 0xaf, 0x40, 0x00, 
+       0xa0, 0xa0, 0xcf, 0xaf, 0xa6, 0x06, 
+       0x86, 0x86, 0x87, 0x87, 0xe6, 0x06, 
+       0xa0, 0xe0, 0xef, 0xaf, 0xa0, 0x00, 
+       0xa6, 0xe6, 0xef, 0xef, 0xa6, 0x06, 
+       0x44, 0xa4, 0xaf, 0xaf, 0x40, 0x00, 
+       0xc6, 0xa6, 0xcf, 0x80, 0x80, 0x00, 
+       0x40, 0xa0, 0xaf, 0xef, 0x64, 0x04, 
+       0xc0, 0xa0, 0xef, 0xc6, 0xa6, 0x06, 
+       0x66, 0x86, 0x47, 0x20, 0xc0, 0x00, 
+       0xe4, 0x44, 0x47, 0x47, 0x40, 0x00, 
+       0xa0, 0xa0, 0xa7, 0xa7, 0x64, 0x04, 
+       0xa0, 0xa0, 0xa7, 0x46, 0x46, 0x06, 
+       0xa6, 0xa6, 0xef, 0xe6, 0xa6, 0x06, 
+       0xa4, 0xa4, 0x4f, 0xaf, 0xa4, 0x04, 
+       0xa4, 0xa4, 0x4c, 0x40, 0x40, 0x00, 
+       0xe0, 0x20, 0x47, 0x84, 0xe4, 0x04, 
+       0x6f, 0x4f, 0x4f, 0x4f, 0x6f, 0x0f, 
+       0x00, 0x80, 0x40, 0x2f, 0x0f, 0x0f, 
+       0x6c, 0x2c, 0x2c, 0x2c, 0x6c, 0x0c, 
+       0x43, 0xa3, 0x03, 0x03, 0x03, 0x03, 
+       0x0f, 0x0f, 0x0f, 0x00, 0x00, 0xf0, 
+       0x8e, 0x4e, 0x0e, 0x0e, 0x0e, 0x00, 
+       0x0e, 0x0e, 0x6e, 0xae, 0xee, 0x00, 
+       0x8e, 0x8e, 0xce, 0xae, 0xce, 0x00, 
+       0x0e, 0x0e, 0x6e, 0x8e, 0x6e, 0x00, 
+       0x2e, 0x2e, 0x6e, 0xae, 0x6e, 0x00, 
+       0x0e, 0xee, 0xee, 0x8e, 0x6e, 0x00, 
+       0x2e, 0x4e, 0xee, 0x4e, 0x4e, 0x00, 
+       0x0e, 0x6e, 0xae, 0x6e, 0xee, 0x00, 
+       0x8e, 0x8e, 0xce, 0xae, 0xae, 0x00, 
+       0x4e, 0x0e, 0x4e, 0x4e, 0x4e, 0x00, 
+       0x4e, 0x0e, 0x4e, 0x4e, 0x8e, 0x00, 
+       0x0e, 0x8e, 0xae, 0xce, 0xae, 0x00, 
+       0x0e, 0xce, 0x4e, 0x4e, 0xee, 0x00, 
+       0x0e, 0x0e, 0xee, 0xee, 0xae, 0x00, 
+       0x0e, 0x0e, 0xce, 0xae, 0xae, 0x00, 
+       0x0e, 0x4e, 0xae, 0xae, 0x4e, 0x00, 
+       0x0e, 0x0e, 0xce, 0xae, 0xce, 0x80, 
+       0x0e, 0x0e, 0x6e, 0xae, 0x6e, 0x20, 
+       0x0e, 0xce, 0xae, 0x8e, 0x8e, 0x00, 
+       0x0e, 0x6e, 0xce, 0x2e, 0xce, 0x00, 
+       0x0e, 0x4e, 0xee, 0x4e, 0x4e, 0x00, 
+       0x0e, 0x0e, 0xae, 0xae, 0x6e, 0x00, 
+       0x0e, 0x0e, 0xae, 0xee, 0x4e, 0x00, 
+       0x0e, 0x0e, 0xae, 0xee, 0xee, 0x00, 
+       0x0e, 0x0e, 0xae, 0x4e, 0xae, 0x00, 
+       0x0e, 0x0e, 0xae, 0xee, 0x2e, 0xc0, 
+       0x0e, 0xee, 0x6e, 0xce, 0xee, 0x00, 
+       0x2e, 0x4e, 0xce, 0x4e, 0x2e, 0x00, 
+       0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x00, 
+       0x8e, 0x4e, 0x6e, 0x4e, 0x8e, 0x00, 
+       0x50, 0xa0, 0x06, 0x06, 0x00, 0x00, 
+       0x4e, 0xae, 0xae, 0xee, 0x0e, 0x00, 
+};
+
+#endif
+struct sdcc_is_anal {
+       int cant_have_an_empty_file;
+};
diff --git a/Kernel/font8x8.c b/Kernel/font8x8.c
new file mode 100644 (file)
index 0000000..0137312
--- /dev/null
@@ -0,0 +1,2579 @@
+#include <config.h>
+
+#ifdef CONFIG_FONT8X8
+
+/*
+ *     System font for 8x8 pixels. From the Linux font_8x8.c
+ */
+
+#define FONTDATAMAX 2048
+
+const unsigned char fontdata_8x8[FONTDATAMAX] = {
+
+       /* 0 0x00 '^@' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 1 0x01 '^A' */
+       0x7e, /* 01111110 */
+       0x81, /* 10000001 */
+       0xa5, /* 10100101 */
+       0x81, /* 10000001 */
+       0xbd, /* 10111101 */
+       0x99, /* 10011001 */
+       0x81, /* 10000001 */
+       0x7e, /* 01111110 */
+
+       /* 2 0x02 '^B' */
+       0x7e, /* 01111110 */
+       0xff, /* 11111111 */
+       0xdb, /* 11011011 */
+       0xff, /* 11111111 */
+       0xc3, /* 11000011 */
+       0xe7, /* 11100111 */
+       0xff, /* 11111111 */
+       0x7e, /* 01111110 */
+
+       /* 3 0x03 '^C' */
+       0x6c, /* 01101100 */
+       0xfe, /* 11111110 */
+       0xfe, /* 11111110 */
+       0xfe, /* 11111110 */
+       0x7c, /* 01111100 */
+       0x38, /* 00111000 */
+       0x10, /* 00010000 */
+       0x00, /* 00000000 */
+
+       /* 4 0x04 '^D' */
+       0x10, /* 00010000 */
+       0x38, /* 00111000 */
+       0x7c, /* 01111100 */
+       0xfe, /* 11111110 */
+       0x7c, /* 01111100 */
+       0x38, /* 00111000 */
+       0x10, /* 00010000 */
+       0x00, /* 00000000 */
+
+       /* 5 0x05 '^E' */
+       0x38, /* 00111000 */
+       0x7c, /* 01111100 */
+       0x38, /* 00111000 */
+       0xfe, /* 11111110 */
+       0xfe, /* 11111110 */
+       0xd6, /* 11010110 */
+       0x10, /* 00010000 */
+       0x38, /* 00111000 */
+
+       /* 6 0x06 '^F' */
+       0x10, /* 00010000 */
+       0x38, /* 00111000 */
+       0x7c, /* 01111100 */
+       0xfe, /* 11111110 */
+       0xfe, /* 11111110 */
+       0x7c, /* 01111100 */
+       0x10, /* 00010000 */
+       0x38, /* 00111000 */
+
+       /* 7 0x07 '^G' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 8 0x08 '^H' */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xe7, /* 11100111 */
+       0xc3, /* 11000011 */
+       0xc3, /* 11000011 */
+       0xe7, /* 11100111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+
+       /* 9 0x09 '^I' */
+       0x00, /* 00000000 */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x42, /* 01000010 */
+       0x42, /* 01000010 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 10 0x0a '^J' */
+       0xff, /* 11111111 */
+       0xc3, /* 11000011 */
+       0x99, /* 10011001 */
+       0xbd, /* 10111101 */
+       0xbd, /* 10111101 */
+       0x99, /* 10011001 */
+       0xc3, /* 11000011 */
+       0xff, /* 11111111 */
+
+       /* 11 0x0b '^K' */
+       0x0f, /* 00001111 */
+       0x07, /* 00000111 */
+       0x0f, /* 00001111 */
+       0x7d, /* 01111101 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x78, /* 01111000 */
+
+       /* 12 0x0c '^L' */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+
+       /* 13 0x0d '^M' */
+       0x3f, /* 00111111 */
+       0x33, /* 00110011 */
+       0x3f, /* 00111111 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x70, /* 01110000 */
+       0xf0, /* 11110000 */
+       0xe0, /* 11100000 */
+
+       /* 14 0x0e '^N' */
+       0x7f, /* 01111111 */
+       0x63, /* 01100011 */
+       0x7f, /* 01111111 */
+       0x63, /* 01100011 */
+       0x63, /* 01100011 */
+       0x67, /* 01100111 */
+       0xe6, /* 11100110 */
+       0xc0, /* 11000000 */
+
+       /* 15 0x0f '^O' */
+       0x18, /* 00011000 */
+       0xdb, /* 11011011 */
+       0x3c, /* 00111100 */
+       0xe7, /* 11100111 */
+       0xe7, /* 11100111 */
+       0x3c, /* 00111100 */
+       0xdb, /* 11011011 */
+       0x18, /* 00011000 */
+
+       /* 16 0x10 '^P' */
+       0x80, /* 10000000 */
+       0xe0, /* 11100000 */
+       0xf8, /* 11111000 */
+       0xfe, /* 11111110 */
+       0xf8, /* 11111000 */
+       0xe0, /* 11100000 */
+       0x80, /* 10000000 */
+       0x00, /* 00000000 */
+
+       /* 17 0x11 '^Q' */
+       0x02, /* 00000010 */
+       0x0e, /* 00001110 */
+       0x3e, /* 00111110 */
+       0xfe, /* 11111110 */
+       0x3e, /* 00111110 */
+       0x0e, /* 00001110 */
+       0x02, /* 00000010 */
+       0x00, /* 00000000 */
+
+       /* 18 0x12 '^R' */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+
+       /* 19 0x13 '^S' */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x00, /* 00000000 */
+       0x66, /* 01100110 */
+       0x00, /* 00000000 */
+
+       /* 20 0x14 '^T' */
+       0x7f, /* 01111111 */
+       0xdb, /* 11011011 */
+       0xdb, /* 11011011 */
+       0x7b, /* 01111011 */
+       0x1b, /* 00011011 */
+       0x1b, /* 00011011 */
+       0x1b, /* 00011011 */
+       0x00, /* 00000000 */
+
+       /* 21 0x15 '^U' */
+       0x3e, /* 00111110 */
+       0x61, /* 01100001 */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x86, /* 10000110 */
+       0x7c, /* 01111100 */
+
+       /* 22 0x16 '^V' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x7e, /* 01111110 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 23 0x17 '^W' */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0xff, /* 11111111 */
+
+       /* 24 0x18 '^X' */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 25 0x19 '^Y' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 26 0x1a '^Z' */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0xfe, /* 11111110 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 27 0x1b '^[' */
+       0x00, /* 00000000 */
+       0x30, /* 00110000 */
+       0x60, /* 01100000 */
+       0xfe, /* 11111110 */
+       0x60, /* 01100000 */
+       0x30, /* 00110000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 28 0x1c '^\' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 29 0x1d '^]' */
+       0x00, /* 00000000 */
+       0x24, /* 00100100 */
+       0x66, /* 01100110 */
+       0xff, /* 11111111 */
+       0x66, /* 01100110 */
+       0x24, /* 00100100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 30 0x1e '^^' */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x7e, /* 01111110 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 31 0x1f '^_' */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0x7e, /* 01111110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 32 0x20 ' ' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 33 0x21 '!' */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 34 0x22 '"' */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x24, /* 00100100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 35 0x23 '#' */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0xfe, /* 11111110 */
+       0x6c, /* 01101100 */
+       0xfe, /* 11111110 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x00, /* 00000000 */
+
+       /* 36 0x24 '$' */
+       0x18, /* 00011000 */
+       0x3e, /* 00111110 */
+       0x60, /* 01100000 */
+       0x3c, /* 00111100 */
+       0x06, /* 00000110 */
+       0x7c, /* 01111100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 37 0x25 '%' */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0xcc, /* 11001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x66, /* 01100110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 38 0x26 '&' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 39 0x27 ''' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 40 0x28 '(' */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x00, /* 00000000 */
+
+       /* 41 0x29 ')' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x00, /* 00000000 */
+
+       /* 42 0x2a '*' */
+       0x00, /* 00000000 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0xff, /* 11111111 */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 43 0x2b '+' */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 44 0x2c ',' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+
+       /* 45 0x2d '-' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 46 0x2e '.' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 47 0x2f '/' */
+       0x06, /* 00000110 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x60, /* 01100000 */
+       0xc0, /* 11000000 */
+       0x80, /* 10000000 */
+       0x00, /* 00000000 */
+
+       /* 48 0x30 '0' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xd6, /* 11010110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+
+       /* 49 0x31 '1' */
+       0x18, /* 00011000 */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 50 0x32 '2' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0x06, /* 00000110 */
+       0x1c, /* 00011100 */
+       0x30, /* 00110000 */
+       0x66, /* 01100110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 51 0x33 '3' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0x06, /* 00000110 */
+       0x3c, /* 00111100 */
+       0x06, /* 00000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 52 0x34 '4' */
+       0x1c, /* 00011100 */
+       0x3c, /* 00111100 */
+       0x6c, /* 01101100 */
+       0xcc, /* 11001100 */
+       0xfe, /* 11111110 */
+       0x0c, /* 00001100 */
+       0x1e, /* 00011110 */
+       0x00, /* 00000000 */
+
+       /* 53 0x35 '5' */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xfc, /* 11111100 */
+       0x06, /* 00000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 54 0x36 '6' */
+       0x38, /* 00111000 */
+       0x60, /* 01100000 */
+       0xc0, /* 11000000 */
+       0xfc, /* 11111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 55 0x37 '7' */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x00, /* 00000000 */
+
+       /* 56 0x38 '8' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 57 0x39 '9' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7e, /* 01111110 */
+       0x06, /* 00000110 */
+       0x0c, /* 00001100 */
+       0x78, /* 01111000 */
+       0x00, /* 00000000 */
+
+       /* 58 0x3a ':' */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 59 0x3b ';' */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+
+       /* 60 0x3c '<' */
+       0x06, /* 00000110 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x06, /* 00000110 */
+       0x00, /* 00000000 */
+
+       /* 61 0x3d '=' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 62 0x3e '>' */
+       0x60, /* 01100000 */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x60, /* 01100000 */
+       0x00, /* 00000000 */
+
+       /* 63 0x3f '?' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 64 0x40 '@' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xde, /* 11011110 */
+       0xde, /* 11011110 */
+       0xde, /* 11011110 */
+       0xc0, /* 11000000 */
+       0x78, /* 01111000 */
+       0x00, /* 00000000 */
+
+       /* 65 0x41 'A' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 66 0x42 'B' */
+       0xfc, /* 11111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x7c, /* 01111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0xfc, /* 11111100 */
+       0x00, /* 00000000 */
+
+       /* 67 0x43 'C' */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 68 0x44 'D' */
+       0xf8, /* 11111000 */
+       0x6c, /* 01101100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x6c, /* 01101100 */
+       0xf8, /* 11111000 */
+       0x00, /* 00000000 */
+
+       /* 69 0x45 'E' */
+       0xfe, /* 11111110 */
+       0x62, /* 01100010 */
+       0x68, /* 01101000 */
+       0x78, /* 01111000 */
+       0x68, /* 01101000 */
+       0x62, /* 01100010 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 70 0x46 'F' */
+       0xfe, /* 11111110 */
+       0x62, /* 01100010 */
+       0x68, /* 01101000 */
+       0x78, /* 01111000 */
+       0x68, /* 01101000 */
+       0x60, /* 01100000 */
+       0xf0, /* 11110000 */
+       0x00, /* 00000000 */
+
+       /* 71 0x47 'G' */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xce, /* 11001110 */
+       0x66, /* 01100110 */
+       0x3a, /* 00111010 */
+       0x00, /* 00000000 */
+
+       /* 72 0x48 'H' */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 73 0x49 'I' */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 74 0x4a 'J' */
+       0x1e, /* 00011110 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x78, /* 01111000 */
+       0x00, /* 00000000 */
+
+       /* 75 0x4b 'K' */
+       0xe6, /* 11100110 */
+       0x66, /* 01100110 */
+       0x6c, /* 01101100 */
+       0x78, /* 01111000 */
+       0x6c, /* 01101100 */
+       0x66, /* 01100110 */
+       0xe6, /* 11100110 */
+       0x00, /* 00000000 */
+
+       /* 76 0x4c 'L' */
+       0xf0, /* 11110000 */
+       0x60, /* 01100000 */
+       0x60, /* 01100000 */
+       0x60, /* 01100000 */
+       0x62, /* 01100010 */
+       0x66, /* 01100110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 77 0x4d 'M' */
+       0xc6, /* 11000110 */
+       0xee, /* 11101110 */
+       0xfe, /* 11111110 */
+       0xfe, /* 11111110 */
+       0xd6, /* 11010110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 78 0x4e 'N' */
+       0xc6, /* 11000110 */
+       0xe6, /* 11100110 */
+       0xf6, /* 11110110 */
+       0xde, /* 11011110 */
+       0xce, /* 11001110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 79 0x4f 'O' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 80 0x50 'P' */
+       0xfc, /* 11111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x7c, /* 01111100 */
+       0x60, /* 01100000 */
+       0x60, /* 01100000 */
+       0xf0, /* 11110000 */
+       0x00, /* 00000000 */
+
+       /* 81 0x51 'Q' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xce, /* 11001110 */
+       0x7c, /* 01111100 */
+       0x0e, /* 00001110 */
+
+       /* 82 0x52 'R' */
+       0xfc, /* 11111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x7c, /* 01111100 */
+       0x6c, /* 01101100 */
+       0x66, /* 01100110 */
+       0xe6, /* 11100110 */
+       0x00, /* 00000000 */
+
+       /* 83 0x53 'S' */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 84 0x54 'T' */
+       0x7e, /* 01111110 */
+       0x7e, /* 01111110 */
+       0x5a, /* 01011010 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 85 0x55 'U' */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 86 0x56 'V' */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+
+       /* 87 0x57 'W' */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xd6, /* 11010110 */
+       0xd6, /* 11010110 */
+       0xfe, /* 11111110 */
+       0x6c, /* 01101100 */
+       0x00, /* 00000000 */
+
+       /* 88 0x58 'X' */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 89 0x59 'Y' */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 90 0x5a 'Z' */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0x8c, /* 10001100 */
+       0x18, /* 00011000 */
+       0x32, /* 00110010 */
+       0x66, /* 01100110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 91 0x5b '[' */
+       0x3c, /* 00111100 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 92 0x5c '\' */
+       0xc0, /* 11000000 */
+       0x60, /* 01100000 */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x06, /* 00000110 */
+       0x02, /* 00000010 */
+       0x00, /* 00000000 */
+
+       /* 93 0x5d ']' */
+       0x3c, /* 00111100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 94 0x5e '^' */
+       0x10, /* 00010000 */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 95 0x5f '_' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+
+       /* 96 0x60 '`' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 97 0x61 'a' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 98 0x62 'b' */
+       0xe0, /* 11100000 */
+       0x60, /* 01100000 */
+       0x7c, /* 01111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0xdc, /* 11011100 */
+       0x00, /* 00000000 */
+
+       /* 99 0x63 'c' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc0, /* 11000000 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 100 0x64 'd' */
+       0x1c, /* 00011100 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 101 0x65 'e' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 102 0x66 'f' */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x60, /* 01100000 */
+       0xf8, /* 11111000 */
+       0x60, /* 01100000 */
+       0x60, /* 01100000 */
+       0xf0, /* 11110000 */
+       0x00, /* 00000000 */
+
+       /* 103 0x67 'g' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x76, /* 01110110 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x7c, /* 01111100 */
+       0x0c, /* 00001100 */
+       0xf8, /* 11111000 */
+
+       /* 104 0x68 'h' */
+       0xe0, /* 11100000 */
+       0x60, /* 01100000 */
+       0x6c, /* 01101100 */
+       0x76, /* 01110110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0xe6, /* 11100110 */
+       0x00, /* 00000000 */
+
+       /* 105 0x69 'i' */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 106 0x6a 'j' */
+       0x06, /* 00000110 */
+       0x00, /* 00000000 */
+       0x06, /* 00000110 */
+       0x06, /* 00000110 */
+       0x06, /* 00000110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+
+       /* 107 0x6b 'k' */
+       0xe0, /* 11100000 */
+       0x60, /* 01100000 */
+       0x66, /* 01100110 */
+       0x6c, /* 01101100 */
+       0x78, /* 01111000 */
+       0x6c, /* 01101100 */
+       0xe6, /* 11100110 */
+       0x00, /* 00000000 */
+
+       /* 108 0x6c 'l' */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 109 0x6d 'm' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xec, /* 11101100 */
+       0xfe, /* 11111110 */
+       0xd6, /* 11010110 */
+       0xd6, /* 11010110 */
+       0xd6, /* 11010110 */
+       0x00, /* 00000000 */
+
+       /* 110 0x6e 'n' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xdc, /* 11011100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x00, /* 00000000 */
+
+       /* 111 0x6f 'o' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 112 0x70 'p' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xdc, /* 11011100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x7c, /* 01111100 */
+       0x60, /* 01100000 */
+       0xf0, /* 11110000 */
+
+       /* 113 0x71 'q' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x76, /* 01110110 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x7c, /* 01111100 */
+       0x0c, /* 00001100 */
+       0x1e, /* 00011110 */
+
+       /* 114 0x72 'r' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xdc, /* 11011100 */
+       0x76, /* 01110110 */
+       0x60, /* 01100000 */
+       0x60, /* 01100000 */
+       0xf0, /* 11110000 */
+       0x00, /* 00000000 */
+
+       /* 115 0x73 's' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0xc0, /* 11000000 */
+       0x7c, /* 01111100 */
+       0x06, /* 00000110 */
+       0xfc, /* 11111100 */
+       0x00, /* 00000000 */
+
+       /* 116 0x74 't' */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0xfc, /* 11111100 */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x36, /* 00110110 */
+       0x1c, /* 00011100 */
+       0x00, /* 00000000 */
+
+       /* 117 0x75 'u' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 118 0x76 'v' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+
+       /* 119 0x77 'w' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0xd6, /* 11010110 */
+       0xd6, /* 11010110 */
+       0xfe, /* 11111110 */
+       0x6c, /* 01101100 */
+       0x00, /* 00000000 */
+
+       /* 120 0x78 'x' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 121 0x79 'y' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7e, /* 01111110 */
+       0x06, /* 00000110 */
+       0xfc, /* 11111100 */
+
+       /* 122 0x7a 'z' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x4c, /* 01001100 */
+       0x18, /* 00011000 */
+       0x32, /* 00110010 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 123 0x7b '{' */
+       0x0e, /* 00001110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x70, /* 01110000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x0e, /* 00001110 */
+       0x00, /* 00000000 */
+
+       /* 124 0x7c '|' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 125 0x7d '}' */
+       0x70, /* 01110000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x0e, /* 00001110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x70, /* 01110000 */
+       0x00, /* 00000000 */
+
+       /* 126 0x7e '~' */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 127 0x7f '\7f' */
+       0x00, /* 00000000 */
+       0x10, /* 00010000 */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 128 0x80 '\80' */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x0c, /* 00001100 */
+       0x78, /* 01111000 */
+
+       /* 129 0x81 '\81' */
+       0xcc, /* 11001100 */
+       0x00, /* 00000000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 130 0x82 '\82' */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 131 0x83 '\83' */
+       0x7c, /* 01111100 */
+       0x82, /* 10000010 */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 132 0x84 '\84' */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 133 0x85 '\85' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 134 0x86 '\86' */
+       0x30, /* 00110000 */
+       0x30, /* 00110000 */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 135 0x87 '\87' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0x7e, /* 01111110 */
+       0x0c, /* 00001100 */
+       0x38, /* 00111000 */
+
+       /* 136 0x88 '\88' */
+       0x7c, /* 01111100 */
+       0x82, /* 10000010 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 137 0x89 '\89' */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 138 0x8a '\8a' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 139 0x8b '\8b' */
+       0x66, /* 01100110 */
+       0x00, /* 00000000 */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 140 0x8c '\8c' */
+       0x7c, /* 01111100 */
+       0x82, /* 10000010 */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 141 0x8d '\8d' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 142 0x8e '\8e' */
+       0xc6, /* 11000110 */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 143 0x8f '\8f' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 144 0x90 '\90' */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0xf8, /* 11111000 */
+       0xc0, /* 11000000 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 145 0x91 '\91' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0xd8, /* 11011000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 146 0x92 '\92' */
+       0x3e, /* 00111110 */
+       0x6c, /* 01101100 */
+       0xcc, /* 11001100 */
+       0xfe, /* 11111110 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xce, /* 11001110 */
+       0x00, /* 00000000 */
+
+       /* 147 0x93 '\93' */
+       0x7c, /* 01111100 */
+       0x82, /* 10000010 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 148 0x94 '\94' */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 149 0x95 '\95' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 150 0x96 '\96' */
+       0x78, /* 01111000 */
+       0x84, /* 10000100 */
+       0x00, /* 00000000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 151 0x97 '\97' */
+       0x60, /* 01100000 */
+       0x30, /* 00110000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 152 0x98 '\98' */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7e, /* 01111110 */
+       0x06, /* 00000110 */
+       0xfc, /* 11111100 */
+
+       /* 153 0x99 '\99' */
+       0xc6, /* 11000110 */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+
+       /* 154 0x9a '\9a' */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 155 0x9b '\9b' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 156 0x9c '\9c' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0x64, /* 01100100 */
+       0xf0, /* 11110000 */
+       0x60, /* 01100000 */
+       0x66, /* 01100110 */
+       0xfc, /* 11111100 */
+       0x00, /* 00000000 */
+
+       /* 157 0x9d '\9d' */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 158 0x9e '\9e' */
+       0xf8, /* 11111000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xfa, /* 11111010 */
+       0xc6, /* 11000110 */
+       0xcf, /* 11001111 */
+       0xc6, /* 11000110 */
+       0xc7, /* 11000111 */
+
+       /* 159 0x9f '\9f' */
+       0x0e, /* 00001110 */
+       0x1b, /* 00011011 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0xd8, /* 11011000 */
+       0x70, /* 01110000 */
+       0x00, /* 00000000 */
+
+       /* 160 0xa0 ' ' */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x7c, /* 01111100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 161 0xa1 '¡' */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x38, /* 00111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 162 0xa2 '¢' */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+
+       /* 163 0xa3 '£' */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 164 0xa4 '¤' */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0x00, /* 00000000 */
+       0xdc, /* 11011100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x00, /* 00000000 */
+
+       /* 165 0xa5 '¥' */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0x00, /* 00000000 */
+       0xe6, /* 11100110 */
+       0xf6, /* 11110110 */
+       0xde, /* 11011110 */
+       0xce, /* 11001110 */
+       0x00, /* 00000000 */
+
+       /* 166 0xa6 '¦' */
+       0x3c, /* 00111100 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x3e, /* 00111110 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 167 0xa7 '§' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 168 0xa8 '¨' */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x63, /* 01100011 */
+       0x3e, /* 00111110 */
+       0x00, /* 00000000 */
+
+       /* 169 0xa9 '©' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 170 0xaa 'ª' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x06, /* 00000110 */
+       0x06, /* 00000110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 171 0xab '«' */
+       0x63, /* 01100011 */
+       0xe6, /* 11100110 */
+       0x6c, /* 01101100 */
+       0x7e, /* 01111110 */
+       0x33, /* 00110011 */
+       0x66, /* 01100110 */
+       0xcc, /* 11001100 */
+       0x0f, /* 00001111 */
+
+       /* 172 0xac '¬' */
+       0x63, /* 01100011 */
+       0xe6, /* 11100110 */
+       0x6c, /* 01101100 */
+       0x7a, /* 01111010 */
+       0x36, /* 00110110 */
+       0x6a, /* 01101010 */
+       0xdf, /* 11011111 */
+       0x06, /* 00000110 */
+
+       /* 173 0xad '­' */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 174 0xae '®' */
+       0x00, /* 00000000 */
+       0x33, /* 00110011 */
+       0x66, /* 01100110 */
+       0xcc, /* 11001100 */
+       0x66, /* 01100110 */
+       0x33, /* 00110011 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 175 0xaf '¯' */
+       0x00, /* 00000000 */
+       0xcc, /* 11001100 */
+       0x66, /* 01100110 */
+       0x33, /* 00110011 */
+       0x66, /* 01100110 */
+       0xcc, /* 11001100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 176 0xb0 '°' */
+       0x22, /* 00100010 */
+       0x88, /* 10001000 */
+       0x22, /* 00100010 */
+       0x88, /* 10001000 */
+       0x22, /* 00100010 */
+       0x88, /* 10001000 */
+       0x22, /* 00100010 */
+       0x88, /* 10001000 */
+
+       /* 177 0xb1 '±' */
+       0x55, /* 01010101 */
+       0xaa, /* 10101010 */
+       0x55, /* 01010101 */
+       0xaa, /* 10101010 */
+       0x55, /* 01010101 */
+       0xaa, /* 10101010 */
+       0x55, /* 01010101 */
+       0xaa, /* 10101010 */
+
+       /* 178 0xb2 '²' */
+       0x77, /* 01110111 */
+       0xdd, /* 11011101 */
+       0x77, /* 01110111 */
+       0xdd, /* 11011101 */
+       0x77, /* 01110111 */
+       0xdd, /* 11011101 */
+       0x77, /* 01110111 */
+       0xdd, /* 11011101 */
+
+       /* 179 0xb3 '³' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 180 0xb4 '´' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 181 0xb5 'µ' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 182 0xb6 '¶' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xf6, /* 11110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 183 0xb7 '·' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 184 0xb8 '¸' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 185 0xb9 '¹' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xf6, /* 11110110 */
+       0x06, /* 00000110 */
+       0xf6, /* 11110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 186 0xba 'º' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 187 0xbb '»' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x06, /* 00000110 */
+       0xf6, /* 11110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 188 0xbc '¼' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xf6, /* 11110110 */
+       0x06, /* 00000110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 189 0xbd '½' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 190 0xbe '¾' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 191 0xbf '¿' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xf8, /* 11111000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 192 0xc0 'À' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 193 0xc1 'Á' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 194 0xc2 'Â' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 195 0xc3 'Ã' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 196 0xc4 'Ä' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 197 0xc5 'Å' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xff, /* 11111111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 198 0xc6 'Æ' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 199 0xc7 'Ç' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x37, /* 00110111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 200 0xc8 'È' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x37, /* 00110111 */
+       0x30, /* 00110000 */
+       0x3f, /* 00111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 201 0xc9 'É' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x3f, /* 00111111 */
+       0x30, /* 00110000 */
+       0x37, /* 00110111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 202 0xca 'Ê' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xf7, /* 11110111 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 203 0xcb 'Ë' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0xf7, /* 11110111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 204 0xcc 'Ì' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x37, /* 00110111 */
+       0x30, /* 00110000 */
+       0x37, /* 00110111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 205 0xcd 'Í' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 206 0xce 'Î' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xf7, /* 11110111 */
+       0x00, /* 00000000 */
+       0xf7, /* 11110111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 207 0xcf 'Ï' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 208 0xd0 'Ð' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 209 0xd1 'Ñ' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 210 0xd2 'Ò' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 211 0xd3 'Ó' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x3f, /* 00111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 212 0xd4 'Ô' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 213 0xd5 'Õ' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 214 0xd6 'Ö' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x3f, /* 00111111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 215 0xd7 '×' */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0xff, /* 11111111 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+
+       /* 216 0xd8 'Ø' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xff, /* 11111111 */
+       0x18, /* 00011000 */
+       0xff, /* 11111111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 217 0xd9 'Ù' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xf8, /* 11111000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 218 0xda 'Ú' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x1f, /* 00011111 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 219 0xdb 'Û' */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+
+       /* 220 0xdc 'Ü' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+
+       /* 221 0xdd 'Ý' */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+       0xf0, /* 11110000 */
+
+       /* 222 0xde 'Þ' */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+       0x0f, /* 00001111 */
+
+       /* 223 0xdf 'ß' */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0xff, /* 11111111 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 224 0xe0 'à' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0xc8, /* 11001000 */
+       0xdc, /* 11011100 */
+       0x76, /* 01110110 */
+       0x00, /* 00000000 */
+
+       /* 225 0xe1 'á' */
+       0x78, /* 01111000 */
+       0xcc, /* 11001100 */
+       0xcc, /* 11001100 */
+       0xd8, /* 11011000 */
+       0xcc, /* 11001100 */
+       0xc6, /* 11000110 */
+       0xcc, /* 11001100 */
+       0x00, /* 00000000 */
+
+       /* 226 0xe2 'â' */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0xc0, /* 11000000 */
+       0x00, /* 00000000 */
+
+       /* 227 0xe3 'ã' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x00, /* 00000000 */
+
+       /* 228 0xe4 'ä' */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0x60, /* 01100000 */
+       0x30, /* 00110000 */
+       0x60, /* 01100000 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+
+       /* 229 0xe5 'å' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0xd8, /* 11011000 */
+       0xd8, /* 11011000 */
+       0xd8, /* 11011000 */
+       0x70, /* 01110000 */
+       0x00, /* 00000000 */
+
+       /* 230 0xe6 'æ' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x7c, /* 01111100 */
+       0xc0, /* 11000000 */
+
+       /* 231 0xe7 'ç' */
+       0x00, /* 00000000 */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+
+       /* 232 0xe8 'è' */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x3c, /* 00111100 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+
+       /* 233 0xe9 'é' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xfe, /* 11111110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+
+       /* 234 0xea 'ê' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0xee, /* 11101110 */
+       0x00, /* 00000000 */
+
+       /* 235 0xeb 'ë' */
+       0x0e, /* 00001110 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x3e, /* 00111110 */
+       0x66, /* 01100110 */
+       0x66, /* 01100110 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+
+       /* 236 0xec 'ì' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0xdb, /* 11011011 */
+       0xdb, /* 11011011 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 237 0xed 'í' */
+       0x06, /* 00000110 */
+       0x0c, /* 00001100 */
+       0x7e, /* 01111110 */
+       0xdb, /* 11011011 */
+       0xdb, /* 11011011 */
+       0x7e, /* 01111110 */
+       0x60, /* 01100000 */
+       0xc0, /* 11000000 */
+
+       /* 238 0xee 'î' */
+       0x1e, /* 00011110 */
+       0x30, /* 00110000 */
+       0x60, /* 01100000 */
+       0x7e, /* 01111110 */
+       0x60, /* 01100000 */
+       0x30, /* 00110000 */
+       0x1e, /* 00011110 */
+       0x00, /* 00000000 */
+
+       /* 239 0xef 'ï' */
+       0x00, /* 00000000 */
+       0x7c, /* 01111100 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0xc6, /* 11000110 */
+       0x00, /* 00000000 */
+
+       /* 240 0xf0 'ð' */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+       0xfe, /* 11111110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 241 0xf1 'ñ' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x7e, /* 01111110 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 242 0xf2 'ò' */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 243 0xf3 'ó' */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x18, /* 00011000 */
+       0x0c, /* 00001100 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+
+       /* 244 0xf4 'ô' */
+       0x0e, /* 00001110 */
+       0x1b, /* 00011011 */
+       0x1b, /* 00011011 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+
+       /* 245 0xf5 'õ' */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0xd8, /* 11011000 */
+       0xd8, /* 11011000 */
+       0x70, /* 01110000 */
+
+       /* 246 0xf6 'ö' */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x7e, /* 01111110 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 247 0xf7 '÷' */
+       0x00, /* 00000000 */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0x00, /* 00000000 */
+       0x76, /* 01110110 */
+       0xdc, /* 11011100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 248 0xf8 'ø' */
+       0x38, /* 00111000 */
+       0x6c, /* 01101100 */
+       0x6c, /* 01101100 */
+       0x38, /* 00111000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 249 0xf9 'ù' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 250 0xfa 'ú' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x18, /* 00011000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 251 0xfb 'û' */
+       0x0f, /* 00001111 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0x0c, /* 00001100 */
+       0xec, /* 11101100 */
+       0x6c, /* 01101100 */
+       0x3c, /* 00111100 */
+       0x1c, /* 00011100 */
+
+       /* 252 0xfc 'ü' */
+       0x6c, /* 01101100 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x36, /* 00110110 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 253 0xfd 'ý' */
+       0x78, /* 01111000 */
+       0x0c, /* 00001100 */
+       0x18, /* 00011000 */
+       0x30, /* 00110000 */
+       0x7c, /* 01111100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 254 0xfe 'þ' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x3c, /* 00111100 */
+       0x3c, /* 00111100 */
+       0x3c, /* 00111100 */
+       0x3c, /* 00111100 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+       /* 255 0xff 'ÿ' */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+       0x00, /* 00000000 */
+
+};
+
+#endif
+
+struct sdcc_is_anal {
+       int cant_have_an_empty_file;
+};
diff --git a/Kernel/include/devsys.h b/Kernel/include/devsys.h
new file mode 100644 (file)
index 0000000..39bbf24
--- /dev/null
@@ -0,0 +1,3 @@
+extern int sys_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int sys_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int sys_ioctl(uint8_t minor, uint16_t request, char *data);
diff --git a/Kernel/include/kdata.h b/Kernel/include/kdata.h
new file mode 100644 (file)
index 0000000..771674a
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __KDATA_DOT_H__
+#define __KDATA_DOT_H__
+
+#include <stdbool.h>
+
+extern char *cmdline;
+extern char bootline[2];
+
+extern struct u_block ub;
+extern struct u_data udata;
+
+extern uint16_t maxproc;   /* Actual max number of processes */
+extern uint16_t ramsize;
+extern uint16_t procmem;
+extern uint16_t nproc;    /* Current number of processes */
+extern uint16_t nready;           /* Number of ready processes */
+
+extern inoptr root;        /* Address of root dir in inode table */
+extern uint8_t root_dev;   /* Device number of root filesystem. */
+
+extern struct blkbuf bufpool[NBUFS];
+extern struct p_tab ptab[PTABSIZE];
+extern struct oft of_tab[OFTSIZE];       /* Open File Table */
+extern struct cinode i_tab[ITABSIZE];    /* In-core inode table */
+extern struct mount fs_tab[NMOUNTS];    /* Mount table */
+
+extern ptptr init_process;  /* The process table address of the first process. */
+extern bool inint;     /* flag is set whenever interrupts are being serviced */
+
+extern uint8_t ticks_this_dsecond;       /* Tick counter for counting off one decisecond */
+extern uint16_t runticks;  /* Number of ticks current process has been swapped in */
+
+extern time_t tod;      /* Time of day */
+extern clock_t ticks;    /* Cumulative tick counter, in minutes and ticks  */
+
+extern char *swapbase;  /* Used by device driver for swapping */
+extern unsigned swapcnt;
+extern blkno_t swapblk;
+
+extern uint16_t waitno;   /* Serial number of processes entering wait state */
+
+extern int16_t acct_fh;          /* acct() filehandle */
+extern struct sysinfoblk sysinfo;
+
+// The device driver switch table
+typedef int (*dev_read_t)(uint8_t minor, uint8_t rawflag, uint8_t flag);
+typedef int (*dev_write_t)(uint8_t minor, uint8_t rawflag, uint8_t flag);
+typedef int (*dev_init_t)(void);
+typedef int (*dev_open_t)(uint8_t minor, uint16_t flag);
+typedef int (*dev_close_t)(uint8_t minor);
+typedef int (*dev_ioctl_t)(uint8_t minor, uint16_t request, char *data); // note: data is in userspace
+
+typedef struct devsw {
+    dev_open_t dev_open;  /* The routines for reading, etc */
+    dev_close_t dev_close; /* Format: op(minor,blkno,offset,count,buf); */
+    dev_read_t dev_read;  /* Offset would be ignored for block devices */
+    dev_write_t dev_write; /* Blkno and offset ignored for tty, etc. */
+    dev_ioctl_t dev_ioctl; /* Count is rounded to 512 for block devices */
+} devsw;
+
+extern struct devsw dev_tab[];
+
+// the system call dispatch table
+#define UZI_SYSCALL_COUNT 61
+typedef int16_t (*syscall_t)(void);
+extern const syscall_t syscall_dispatch[UZI_SYSCALL_COUNT];
+
+#endif
diff --git a/Kernel/include/kernel.h b/Kernel/include/kernel.h
new file mode 100644 (file)
index 0000000..017d5a0
--- /dev/null
@@ -0,0 +1,771 @@
+/****************************************************
+FUZIX (Unix Z80 Implementation) Kernel:  unix.h
+From UZI by Doug Braun and UZI280 by Stefan Nitschke.
+*****************************************************/
+/* History:
+ *   21.12.97 - Removed leading ? from Per-Process equates.    HFB
+ *   11.07.98 - Shortened Time Slices to 50 Ticks/Sec (20 mS). HFB
+ */
+
+#ifndef __FUZIX__KERNEL_DOT_H__
+#define __FUZIX__KERNEL_DOT_H__
+
+#include <stdbool.h>
+
+#include "config.h"
+#include "cpu.h"
+
+#ifndef DEFAULT_ROOT
+#define DEFAULT_ROOT 0
+#endif
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+#define min(a,b) ( (a) < (b) ? (a) : (b) )
+#define max(a,b) ( (a) > (b) ? (a) : (b) )
+
+#define CPM_EMULATOR_FILENAME    "/usr/cpm/emulator"
+
+/* Maximum UFTSIZE can be is 16, then you need to alter the O_CLOEXEC code */
+
+#ifndef UFTSIZE
+#define UFTSIZE 10       /* Number of user files */            /*280 = 22*/
+#endif
+#ifndef OFTSIZE
+#define OFTSIZE 15       /* Open file table size */            /*280 = 45*/
+#endif
+#ifndef ITABSIZE
+#define ITABSIZE 20      /* Inode table size */                        /*280 = 45*/
+#endif
+#ifndef PTABSIZE
+#define PTABSIZE 15      /* Process table size. */
+#endif
+
+#define MAXTICKS     10   /* Max ticks before switching out (time slice)
+                            default process time slice */
+// #define MAXBACK      3   /* Process time slice for tasks not connected
+//                             to the current tty */
+// #define MAXBACK2     2   /* Process time slice for background tasks */
+// #define MAXINTER     5   /* Process time slice for interactive tasks */
+
+#define MAXPID    32000
+
+#define NSIGS    32      /* Number of signals <= 32 */
+#define ROOTINODE 1       /* Inode # of / for all mounted filesystems. */
+#define EMAGIC    0xc3    /* Header of executable */
+#define CMAGIC    24721   /* Random number for cinode c_magic */
+#define SMOUNTED  12742   /* Magic number to specify mounted filesystem */
+
+#define OS_BANK 0
+#define NO_DEVICE (0xFFFFU)
+#define NO_FILE   (0xFF)
+
+typedef struct s_queue {
+    char *q_base;    /* Pointer to data */
+    char *q_head;    /* Pointer to addr of next char to read. */
+    char *q_tail;    /* Pointer to where next char to insert goes. */
+    int   q_size;    /* Max size of queue */
+    int   q_count;   /* How many characters presently in queue */
+    int   q_wakeup;  /* Threshold for waking up processes waiting on queue */
+} queue_t;
+
+/* User's structure for times() system call */
+typedef unsigned long clock_t;
+typedef unsigned long long time_t;
+
+struct tms {
+       clock_t  tms_utime;
+       clock_t  tms_stime;
+       clock_t  tms_cutime;
+       clock_t  tms_cstime;
+       clock_t  tms_etime;      /* Elapsed real time */
+} ;
+
+/* Flags for setftime() */
+#define A_TIME 1
+#define M_TIME 2
+#define C_TIME 4
+
+typedef int32_t off_t; /* 32MB file and fs size limit */
+
+typedef uint16_t blkno_t;    /* Can have 65536 512-byte blocks in filesystem */
+#define NULLBLK ((blkno_t)-1)
+
+#define BLKSIZE                512
+#define BLKSHIFT       9
+#define BLKMASK                511
+
+/* FIXME: if we could split the data and the header we could keep blocks
+   outside of our kernel data (as ELKS does) which would be a win, but need
+   some more care on copies, block indexes and directory ops */
+typedef struct blkbuf {
+    uint8_t     bf_data[BLKSIZE];    /* This MUST be first ! */
+    uint16_t    bf_dev;
+    blkno_t     bf_blk;
+    bool        bf_dirty;
+    bool        bf_busy;
+    uint16_t    bf_time;         /* LRU time stamp */
+} blkbuf, *bufptr;
+
+/* TODO: consider smaller inodes or clever caching. 2BSD uses small
+   direct block lists to keep inodes small as they must be in memory when
+   'live' - we could also split them into the 28 bytes we always need to
+   keep live (i_addr[0] for the dev ptr) and the 36 we don't (or 32/32 for
+   speed). We'd then be able to drop half the bits for an open inode onto
+   disk safely */
+typedef struct dinode {
+    uint16_t i_mode;
+    uint16_t i_nlink;
+    uint16_t i_uid;
+    uint16_t i_gid;
+    off_t    i_size;
+    uint32_t   i_atime;                /* Breaks in 2038 */
+    uint32_t   i_mtime;                /* Need to hide some extra bits ? */
+    uint32_t   i_ctime;                /* 24 bytes */
+    blkno_t  i_addr[20];
+} dinode;               /* Exactly 64 bytes long! */
+
+struct  stat    /* Really only used by libc */
+{
+       int16_t   st_dev;
+       uint16_t  st_ino;
+       uint16_t  st_mode;
+       uint16_t  st_nlink;
+       uint16_t  st_uid;
+       uint16_t  st_gid;
+       uint16_t  st_rdev;
+       off_t   st_size;
+       uint32_t  st_atime;     /* Break in 2038 */
+       uint32_t  st_mtime;
+       uint32_t  st_ctime;
+};
+
+/* Bit masks for i_mode and st_mode */
+
+#define OTH_EX  0001
+#define OTH_WR  0002
+#define OTH_RD  0004
+#define GRP_EX  0010
+#define GRP_WR  0020
+#define GRP_RD  0040
+#define OWN_EX  0100
+#define OWN_WR  0200
+#define OWN_RD  0400
+
+#define SAV_TXT 01000
+#define SET_GID 02000
+#define SET_UID 04000
+
+#define MODE_MASK 07777
+
+#define F_REG   0100000
+#define F_DIR   040000
+#define F_PIPE  010000
+#define F_BDEV  060000  // important that F_BDEV & F_CDEV != 0 (see isdevice() function)
+#define F_CDEV  020000
+
+#define F_MASK  0170000
+
+#define major(x) ((x) >> 8)
+#define minor(x) ((x) & 0xFF)
+
+typedef struct cinode { // note: exists in memory *and* on disk
+    uint16_t   c_magic;           /* Used to check for corruption. */
+    uint16_t   c_dev;             /* Inode's device */
+    uint16_t   c_num;             /* Inode # */
+    dinode     c_node;
+    uint8_t    c_refs;            /* In-core reference count */
+    bool       c_dirty;           /* Modified flag. */
+} cinode, *inoptr;
+
+#define NULLINODE ((inoptr)NULL)
+#define NULLINOPTR ((inoptr*)NULL)
+
+#define FILENAME_LEN   30
+#define DIR_LEN                32
+typedef struct direct {
+    uint16_t   d_ino;
+    char     d_name[FILENAME_LEN];
+} direct;
+
+
+/*
+ *     This is actually overlaid over a blkbuf holding the actual
+ *     record in question, and pinned until we umount the fs.
+ */
+#define FILESYS_TABSIZE 50
+typedef struct filesys { // note: exists in mem and on disk
+    int16_t       s_mounted;
+    uint16_t      s_isize;
+    uint16_t      s_fsize;
+    uint16_t      s_nfree;
+    blkno_t       s_free[FILESYS_TABSIZE];
+    int16_t       s_ninode;
+    uint16_t      s_inode[FILESYS_TABSIZE];
+    bool          s_fmod;
+    uint8_t       s_timeh;     /* bits 32-40: FIXME - wire up */
+    uint32_t      s_time;
+    blkno_t       s_tfree;
+    uint16_t      s_tinode;
+    inoptr        s_mntpt;     /* Mount point */
+} filesys, *fsptr;
+
+typedef struct oft {
+    off_t     o_ptr;      /* File position pointer */
+    inoptr    o_inode;    /* Pointer into in-core inode table */
+    uint8_t   o_access;   /* O_RDONLY, O_WRONLY, or O_RDWR + flag bits */
+    uint8_t   o_refs;     /* Reference count: depends on # of active children */
+} oft;
+
+/* Mount table entries */
+struct mount {
+    uint16_t m_dev;
+    uint16_t m_flags;
+    struct filesys *m_fs;
+};
+/* The flags are not yet implemented */
+#define MS_RDONLY      1
+#define MS_NOSUID      2
+
+/* Process table p_status values */
+
+#define P_EMPTY         0    /* Unused slot */
+#define P_RUNNING       1    /* Currently running process (must match value in kernel.def) */
+/* The sleeping range must be together see swap.c */
+#define P_READY         2    /* Runnable   */
+#define P_SLEEP         3    /* Sleeping; can be awakened by signal */
+#define P_XSLEEP        4    /* Sleeping, don't wake up for signal */
+#define P_PAUSE         5    /* Sleeping for pause(); can wakeup for signal */
+#define P_WAIT          6    /* Executed a wait() */
+#define P_FORKING       7    /* In process of forking; do not mess with */
+#define P_ZOMBIE2       8    /* Exited but code pages still valid. */
+#define P_ZOMBIE        9    /* Exited. */
+
+
+/* 0 is used to mean 'check we could signal this process' */
+
+/* FIXME: finish signal handling */
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+#define  SIG_DFL   (int16_t (*)())0
+#define  SIG_IGN   (int16_t (*)())1
+
+#define sigmask(sig)    (1UL<<(sig))
+
+/* uadmin */
+
+#define A_SHUTDOWN             1
+#define A_REBOOT               2
+#define A_DUMP                 3
+#define A_FREEZE               4       /* Unimplemented, want for NC100 */
+#define A_SWAPCTL              16      /* Unimplemented */
+#define A_CONFIG               17      /* Unimplemented */
+#define A_FTRACE               18      /* Unimplemented: 
+                                          Hook to the syscall trace debug */
+
+#define AD_NOSYNC              1       /* Unimplemented */
+                                          
+/* Process table entry */
+
+typedef struct p_tab {
+    /* WRS: UPDATE kernel.def IF YOU CHANGE THIS STRUCTURE */
+    uint8_t     p_status;       /* Process status: MUST BE FIRST MEMBER OF STRUCT */
+    uint8_t     p_tty;          /* Process' controlling tty minor # */
+    uint16_t    p_pid;          /* Process ID */
+    uint16_t    p_uid;
+    struct p_tab *p_pptr;      /* Process parent's table entry */
+    uint16_t    p_alarm;        /* Centiseconds until alarm goes off */
+    uint16_t    p_exitval;      /* Exit value */
+    void *      p_wait;         /* Address of thing waited for */
+    uint16_t    p_page;         /* Page mapping data */
+    uint16_t   p_page2;        /* It's really four bytes for the platform */
+    /* Update kernel.def if you change fields above this comment */
+    /* Everything below here is overlaid by time info at exit */
+    uint16_t    p_priority;     /* Process priority */
+    uint32_t    p_pending;      /* Bitmask of pending signals */
+    uint32_t    p_ignored;      /* Bitmask of ignored signals */
+    uint32_t    p_held;         /* Bitmask of held signals */
+    struct u_block *p_ublk;     /* Pointer to udata block when not running */
+    uint16_t    p_waitno;       /* wait #; for finding longest waiting proc */
+    uint16_t    p_timeout;      /* timeout in centiseconds - 1 */
+                                /* 0 indicates no timeout, 1 = expired */
+
+/**HP**/
+    char    p_name[8];
+    clock_t p_time, p_utime, p_stime, p_cutime, p_cstime;
+/**HP**/
+    uint16_t   p_pgrp;         /* Process group */
+    uint8_t    p_nice;
+#ifdef CONFIG_PROFIL
+    uint8_t    p_profscale;
+    void *     p_profbuf;
+    uint16_t   p_profsize;
+    uint16_t   p_profoff;
+#endif    
+} p_tab, *ptptr;
+
+typedef struct u_data {
+    /**** If you change this top section, also update offsets in "kernel.def" ****/
+    struct p_tab *u_ptab;       /* Process table pointer */
+    uint16_t    u_page;         /* Process page data (equal to u_ptab->p_page) */
+    uint16_t    u_page2;        /* Process page data (equal to u_ptab->p_page2) */
+    bool        u_insys;        /* True if in kernel */
+    uint8_t     u_callno;       /* sys call being executed. */
+    void *      u_syscall_sp;   /* Stores SP when process makes system call */
+    susize_t    u_retval;       /* Return value from sys call */
+    int16_t     u_error;        /* Last error number */
+    void *      u_sp;           /* Stores SP when process is switchped */
+    bool        u_ininterrupt;  /* True when the interrupt handler is runnign (prevents recursive interrupts) */
+    int8_t      u_cursig;       /* Next signal to be dispatched */
+    arg_t       u_argn;         /* Last system call arg */
+    arg_t       u_argn1;        /* This way because args on stack backwards */
+    arg_t       u_argn2;
+    arg_t       u_argn3;        /* args n-3, n-2, n-1, and n */
+    void *      u_isp;          /* Value of initial sp (argv) */
+    usize_t    u_top;          /* Top of memory for this task */
+    int16_t     (*u_sigvec[NSIGS])();   /* Array of signal vectors */
+    /**** If you change this top section, also update offsets in "kernel.def" ****/
+
+    char *      u_base;         /* Source or dest for I/O */
+    usize_t     u_count;        /* Amount for I/O */
+    off_t       u_offset;       /* Place in file for I/O */
+    struct blkbuf *u_buf;
+    bool        u_sysio;        /* True if I/O to system space */
+
+    /* This block gets written to acct */
+    
+    /* We overwrite u_mask with p->p_uid on the exit */
+    uint16_t    u_mask;         /* umask: file creation mode mask */
+    uint16_t    u_gid;
+    uint16_t    u_euid;
+    uint16_t    u_egid;
+    uint16_t    u_break;        /* Top of data space */
+    char        u_name[8];      /* Name invoked with */
+    clock_t     u_utime;        /* Elapsed ticks in user mode */
+    clock_t     u_stime;        /* Ticks in system mode */
+    clock_t     u_cutime;       /* Total childrens ticks */
+    clock_t     u_cstime;
+    clock_t     u_time;         /* Start time */
+    
+    /* This section is not written out except as padding */
+    uint8_t     u_files[UFTSIZE];       /* Process file table: indices into open file table, or NO_FILE. */
+    uint16_t   u_cloexec;      /* Close on exec flags */
+    inoptr      u_cwd;          /* Index into inode table of cwd. */
+    inoptr     u_root;         /* Index into inode table of / */
+    //inoptr      u_ino;          /* Used during execve() */
+    inoptr     u_rename;       /* Used in n_open for rename() checking */
+} u_data;
+
+
+/* This is the user data structure, padded out to 512 bytes with the
+ * System Stack.
+ */
+typedef struct u_block {
+        u_data u_d;
+        char   u_s [512 - sizeof(struct u_data)];
+} u_block;
+
+
+/* Struct to temporarily hold arguments in execve */
+struct s_argblk {
+    int a_argc;
+    int a_arglen;
+    int a_envc;
+    uint8_t a_buf[512-3*sizeof(int)];
+};
+
+
+/* waitpid options */
+#define WNOHANG                1       /* don't support others yet */
+
+
+/* Open() parameters. */
+
+/* Bits 0-7 are saved, bits 8-15 are discard post open. Not all are handled
+   in the kernel yet */
+#define O_RDONLY        0
+#define O_WRONLY        1
+#define O_RDWR          2
+#define O_ACCMODE(x)   ((x) & 3)
+#define O_APPEND       4
+#define O_SYNC         8
+#define O_NDELAY       16
+#define O_CREAT                256
+#define O_EXCL         512
+#define O_TRUNC                1024
+#define O_NOCTTY       2048
+#define O_CLOEXEC      4096
+
+#define O_BADBITS      (32 | 64 | 128 | 8192 | 16384 | 32768U)
+
+#define F_GETFL                0
+#define F_SETFL                1
+#define F_GETFD                2
+#define F_SETFD                3
+#define F_DUPFD                4
+
+#define FNDELAY                O_NDELAY
+
+
+/*
+ * Error codes
+ */
+#define EPERM           1               /* Not owner */
+#define ENOENT          2               /* No such file or directory */
+#define ESRCH           3               /* No such process */
+#define EINTR           4               /* Interrupted System Call */
+#define EIO             5               /* I/O Error */
+#define ENXIO           6               /* No such device or address */
+#define E2BIG           7               /* Arg list too long */
+#define ENOEXEC         8               /* Exec format error */
+#define EBADF           9               /* Bad file number */
+#define ECHILD          10              /* No children */
+#define EAGAIN          11              /* No more processes */
+#define ENOMEM          12              /* Not enough core */
+#define EACCES          13              /* Permission denied */
+#define EFAULT          14              /* Bad address */
+#define ENOTBLK         15              /* Block device required */
+#define EBUSY           16              /* Mount device busy */
+#define EEXIST          17              /* File exists */
+#define EXDEV           18              /* Cross-device link */
+#define ENODEV          19              /* No such device */
+#define ENOTDIR         20              /* Not a directory */
+#define EISDIR          21              /* Is a directory */
+#define EINVAL          22              /* Invalid argument */
+#define ENFILE          23              /* File table overflow */
+#define EMFILE          24              /* Too many open files */
+#define ENOTTY          25              /* Not a typewriter */
+#define ETXTBSY         26              /* Text file busy */
+#define EFBIG           27              /* File too large */
+#define ENOSPC          28              /* No space left on device */
+#define ESPIPE          29              /* Illegal seek */
+#define EROFS           30              /* Read-only file system */
+#define EMLINK          31              /* Too many links */
+#define EPIPE           32              /* Broken pipe */
+
+/* math software */
+#define EDOM            33              /* Argument too large */
+#define ERANGE          34              /* Result too large */
+
+#define EWOULDBLOCK    35              /* Operation would block */
+#define ENOTEMPTY      36              /* Directory is not empty */
+#define ENAMETOOLONG    37              /* File name too long */
+
+/*
+ * ioctls for kernel internal operations start at 0x8000 and cannot be issued
+ * by userspace.
+ */
+#define SELECT_BEGIN           0x8000
+#define SELECT_END             0x8001
+
+struct sysinfoblk {
+  uint8_t infosize;            /* For expandability */
+  uint8_t banks;               /* Banks in our 64K (and thus pagesize) */
+  uint8_t max_open;
+  uint16_t ticks;              /* Tick rate in HZ */
+  uint16_t memk;               /* Memory in KB */
+  uint16_t usedk;              /* Used memory in KB */
+  uint16_t config;             /* Config flag mask */
+#define CONF_PROFIL            1
+#define CONF_NET               2       /* Hah.. 8) */
+                               /* Followed by uname strings */
+};
+
+/* Select: if we do the map optimisation trick then we will want one bit free
+   for optimising, so ideal PTABSIZE will become 1 below a multiple of 8 */
+
+#define SELMAPSIZE  ((PTABSIZE+7)/8)
+
+struct selmap {
+  uint8_t map[SELMAPSIZE];
+};
+
+#define SELECT_IN              1
+#define SELECT_OUT             2
+#define SELECT_EX              4
+
+
+
+/* functions in common memory */
+
+/* switches to a temporary stack in common memory */
+void tempstack(void); 
+
+/* debug functions */
+void trap_monitor(void);
+void idump(void);
+
+/* start.c */
+
+/* kdata.c */
+bool validdev(uint16_t dev);
+
+/* usermem.c */
+usize_t valaddr(char *base, usize_t size);
+int uget(const void *userspace_source, void *dest, usize_t count);
+int16_t  ugetc(const void *userspace_source);
+uint16_t ugetw(const void *userspace_source);
+int ugets(const void *userspace_source, void *dest, usize_t maxlen);
+int uput (const void *source,   void *userspace_dest, usize_t count);
+int uputc(uint16_t value,  void *userspace_dest);      /* u16_t so we don't get wacky 8bit stack games */
+int uputw(uint16_t value, void *userspace_dest);
+int uzero(void *userspace_dest, usize_t count);
+
+/* usermem.c or usermem_std.s */
+usize_t _uget(const uint8_t *user, uint8_t *dst, usize_t count);
+int16_t _ugetc(const uint8_t *user);
+uint16_t _ugetw(const uint16_t *user);
+int _ugets(const uint8_t *user, uint8_t *dest, usize_t maxlen);
+int _uput(const uint8_t *source, uint8_t *user, usize_t count);
+int _uputc(uint16_t value,  uint8_t *user);
+int _uputw(uint16_t value,  uint16_t *user);
+int _uzero(uint8_t *user, usize_t count);
+
+/* tricks.s */
+void switchout(void);
+void doexec(void *start_addr);
+void switchin(ptptr process);
+int16_t dofork(ptptr child);
+
+/* devio.c */
+uint8_t *bread (uint16_t dev, blkno_t blk, bool rewrite);
+void brelse(void *bp);
+void bawrite(void *bp);
+int bfree(bufptr bp, uint8_t dirty); /* dirty: 0=clean, 1=dirty (write back), 2=dirty+immediate write */
+void *tmpbuf(void);
+void *zerobuf(void);
+void bufsync(void);
+bufptr bfind(uint16_t dev, blkno_t blk);
+bufptr freebuf(void);
+void bufinit(void);
+void bufdiscard(bufptr bp);
+void bufdump (void);
+int bdread(bufptr bp);
+int bdwrite(bufptr bp);
+int cdread(uint16_t dev, uint8_t flag);
+int d_open(uint16_t dev, uint8_t flag);
+int d_close(uint16_t dev);
+int d_ioctl(uint16_t dev, uint16_t request, char *data);
+int cdwrite(uint16_t dev, uint8_t flag);
+bool insq(struct s_queue *q, char c);
+bool remq(struct s_queue *q, char *cp);
+void clrq(struct s_queue *q);
+bool uninsq(struct s_queue *q, char *cp);
+int psleep_flags(void *event, unsigned char flags);
+int nxio_open(uint8_t minor, uint16_t flag);
+int no_open(uint8_t minor, uint16_t flag);
+int no_close(uint8_t minor);
+int no_rdwr(uint8_t minir, uint8_t rawflag, uint8_t flag);
+int no_ioctl(uint8_t minor, uint16_t a, char *b);
+
+/* filesys.c */
+/* open file, "name" in user address space */
+inoptr n_open(char *uname, inoptr *parent); 
+/* open file, "name" in kernel address space */
+inoptr kn_open(char *uname, inoptr *parent); 
+inoptr i_open(uint16_t dev, uint16_t ino);
+inoptr srch_dir(inoptr wd, char *compname);
+inoptr srch_mt(inoptr ino);
+bool ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex);
+void filename(char *userspace_upath, char *name);
+/* return true if n1 == n2 */
+bool namecomp(char *n1, char *n2); 
+inoptr newfile(inoptr pino, char *name);
+fsptr getdev(uint16_t dev);
+bool baddev(fsptr dev);
+uint16_t i_alloc(uint16_t devno);
+void i_free(uint16_t devno, uint16_t ino);
+blkno_t blk_alloc(uint16_t devno);
+void blk_free(uint16_t devno, blkno_t blk);
+int8_t oft_alloc(void);
+void oft_deref(int8_t of);
+/* returns index of slot, or -1 on failure */
+int8_t uf_alloc(void); 
+/* returns index of slot, or -1 on failure */
+int8_t uf_alloc_n(int n); 
+void i_ref(inoptr ino);
+void i_deref(inoptr ino);
+void wr_inode(inoptr ino);
+bool isdevice(inoptr ino);
+void f_trunc(inoptr ino);
+void freeblk(uint16_t dev, blkno_t blk, uint8_t level);
+blkno_t bmap(inoptr ip, blkno_t bn, int rwflg);
+void validblk(uint16_t dev, blkno_t num);
+inoptr getinode(uint8_t uindex);
+bool super(void);
+bool esuper(void);
+uint8_t getperm(inoptr ino);
+void setftime(inoptr ino, uint8_t flag);
+uint16_t getmode(inoptr ino);
+struct mount *fs_tab_get(uint16_t dev);
+/* returns true on failure, false on success */
+bool fmount(uint16_t dev, inoptr ino, uint16_t flags);
+void magic(inoptr ino);
+
+/* inode.c */
+void readi(inoptr ino, uint8_t flag);
+void writei(inoptr ino, uint8_t flag);
+int16_t doclose (uint8_t uindex);
+inoptr rwsetup (bool is_read, uint8_t *flag);
+
+/* mm.c */
+unsigned int uputsys(unsigned char *from, unsigned int size);
+unsigned int ugetsys(unsigned char *to, unsigned int size);
+
+/* process.c */
+void psleep(void *event);
+void wakeup(void *event);
+void pwake(ptptr p);
+ptptr getproc(void);
+void newproc(ptptr p);
+ptptr ptab_alloc(void);
+void ssig(ptptr proc, uint16_t sig);
+void chksigs(void);
+void program_vectors(uint16_t *pageptr);
+void sgrpsig(uint16_t pgrp, uint16_t sig);
+void unix_syscall(void);
+void timer_interrupt(void);
+void doexit (int16_t val, int16_t val2);
+void panic(char *deathcry);
+void exec_or_die(void);
+
+/* select.c */
+extern void seladdwait(struct selmap *s);
+extern void selrmwait(struct selmap *s);
+extern void selwake(struct selmap *s);
+extern int _select(void);
+
+/* swap.c */
+extern ptptr swapproc;
+extern char *swapbase;
+extern unsigned int swapcnt;
+extern blkno_t swapblk;
+
+extern void swapmap_add(uint8_t swap);
+extern ptptr swapneeded(ptptr p, int selfok);
+extern void swapper(ptptr p);
+
+/* syscalls_fs.c, syscalls_proc.c, syscall_other.c */
+void updoff(void);
+int stcpy(inoptr ino, char *buf);
+bool rargs (char **userspace_argv, struct s_argblk *argbuf);
+char **wargs(char *userspace_ptr, struct s_argblk *argbuf, int  *cnt);
+extern int unlinki(inoptr ino, inoptr pino, char *fname);
+
+/* timer.c */
+void rdtime(time_t *tloc);
+void rdtime32(uint32_t *tloc);
+void wrtime(time_t *tloc);
+extern void updatetod(void);
+
+/* provided by architecture or helpers */
+void device_init(void);        /* provided by platform */
+void pagemap_init(void);
+void pagemap_add(uint8_t page);
+void pagemap_free(ptptr p);
+int pagemap_alloc(ptptr p);
+int pagemap_realloc(uint16_t p);
+uint16_t pagemap_mem_used(void);
+uint8_t *swapout_prepare_uarea(ptptr p);
+uint8_t *swapin_prepare_uarea(ptptr p);
+void map_init(void);
+void platform_idle(void);
+extern uint8_t *ramtop;             /* Note: ramtop must be in common in some cases */
+extern void platform_interrupt(void);
+
+int16_t __exit(void);        /* FUZIX system call 0 */
+int16_t _open(void);         /* FUZIX system call 1 */
+int16_t _close(void);        /* FUZIX system call 2 */
+int16_t _rename(void);       /* FUZIX system call 3 */
+int16_t _mknod(void);        /* FUZIX system call 4 */
+int16_t _link(void);         /* FUZIX system call 5 */
+int16_t _unlink(void);       /* FUZIX system call 6 */
+int16_t _read(void);         /* FUZIX system call 7 */
+int16_t _write(void);        /* FUZIX system call 8 */
+int16_t _lseek(void);        /* FUZIX system call 9 */
+int16_t _chdir(void);        /* FUZIX system call 10 */
+int16_t _sync(void);         /* FUZIX system call 11 */
+int16_t _access(void);       /* FUZIX system call 12 */
+int16_t _chmod(void);        /* FUZIX system call 13 */
+int16_t _chown(void);        /* FUZIX system call 14 */
+int16_t _stat(void);         /* FUZIX system call 15 */
+int16_t _fstat(void);        /* FUZIX system call 16 */
+int16_t _dup(void);          /* FUZIX system call 17 */
+int16_t _getpid(void);       /* FUZIX system call 18 */
+int16_t _getppid(void);      /* FUZIX system call 19 */
+int16_t _getuid(void);       /* FUZIX system call 20 */
+int16_t _umask(void);        /* FUZIX system call 21 */
+int16_t _getfsys(void);      /* FUZIX system call 22 */
+int16_t _execve(void);       /* FUZIX system call 23 */
+int16_t _getdirent(void);    /* FUZIX system call 24 */
+int16_t _setuid(void);       /* FUZIX system call 25 */
+int16_t _setgid(void);       /* FUZIX system call 26 */
+int16_t _time(void);         /* FUZIX system call 27 */
+int16_t _stime(void);        /* FUZIX system call 28 */
+int16_t _ioctl(void);        /* FUZIX system call 29 */
+int16_t _brk(void);          /* FUZIX system call 30 */
+int16_t _sbrk(void);         /* FUZIX system call 31 */
+int16_t _fork(void);         /* FUZIX system call 32 */
+int16_t _mount(void);        /* FUZIX system call 33 */
+int16_t _umount(void);       /* FUZIX system call 34 */
+int16_t _signal(void);       /* FUZIX system call 35 */
+int16_t _dup2(void);         /* FUZIX system call 36 */
+int16_t _pause(void);        /* FUZIX system call 37 */
+int16_t _alarm(void);        /* FUZIX system call 38 */
+int16_t _kill(void);         /* FUZIX system call 39 */
+int16_t _pipe(void);         /* FUZIX system call 40 */
+int16_t _getgid(void);       /* FUZIX system call 41 */
+int16_t _times(void);        /* FUZIX system call 42 */
+int16_t _utime(void);        /* FUZIX system call 43 */
+int16_t _geteuid(void);      /* FUZIX system call 44 */
+int16_t _getegid(void);      /* FUZIX system call 45 */
+int16_t _chroot(void);       /* FUZIX system call 46 */
+int16_t _fcntl(void);        /* FUZIX system call 47 */
+int16_t _fchdir(void);       /* FUZIX system call 48 */
+int16_t _fchmod(void);       /* FUZIX system call 49 */
+int16_t _fchown(void);       /* FUZIX system call 50 */
+int16_t _mkdir(void);       /* FUZIX system call 51 */
+int16_t _rmdir(void);        /* FUZIX system call 52 */
+int16_t _setpgrp(void);             /* FUZIX system call 53 */
+int16_t _uname(void);       /* FUZIX system call 54 */
+int16_t _waitpid(void);             /* FUZIX system call 55 */
+int16_t _profil(void);      /* FUZIX system call 56 */
+int16_t _uadmin(void);      /* FUZIX system call 57 */
+int16_t _nice(void);         /* FUZIX system call 58 */
+int16_t _sigdisp(void);             /* FUZIX system call 59 */
+#endif /* __FUZIX__KERNEL_DOT_H__ */
diff --git a/Kernel/include/printf.h b/Kernel/include/printf.h
new file mode 100644 (file)
index 0000000..3c4233a
--- /dev/null
@@ -0,0 +1,8 @@
+extern void kprintf(const char *, ...);
+extern void kputs(const char *);
+extern void kputnum(int v);
+extern void kuputunum(unsigned int v);
+extern void kputhex(unsigned int v);
+
+/* The platform must provide this method */
+extern void kputchar(char c);
diff --git a/Kernel/include/syscall_name.h b/Kernel/include/syscall_name.h
new file mode 100644 (file)
index 0000000..2de2038
--- /dev/null
@@ -0,0 +1,64 @@
+#define NR_SYSCALL 60
+
+char *syscall_name[NR_SYSCALL] = {
+       "_exit",
+       "open",
+       "close",
+       "rename",
+       "mknod",
+       "link",
+       "unlink",
+       "read",
+       "write",
+       "_lseek",
+       "chdir",
+       "sync",
+       "access",
+       "chmod",
+       "chown",
+       "_stat",
+       "_fstat",
+       "dup",
+       "getpid",
+       "getppid",
+       "getuid",
+       "umask",
+       "_getfsys",
+       "execve",
+       "_getdirent",
+       "setuid",
+       "setgid",
+       "_time",
+       "stime",
+       "ioctl",
+       "brk",
+       "sbrk",
+       "fork",
+       "mount",
+       "umount",
+       "signal",
+       "dup2",
+       "_pause",
+       "alarm",
+       "kill",
+       "pipe",
+       "getgid",
+       "times",
+       "utime",
+       "geteuid",
+       "getegid",
+       "chroot",
+       "fcntl",
+       "fchdir",
+       "fchmod",
+       "fchown",
+       "mkdir",
+       "rmdir",
+       "setpgrp",
+       "_uname",
+       "waitpid",
+       "_profil",
+       "uadmin",
+       "nice",
+       "_sigdisp",
+};
diff --git a/Kernel/include/timer.h b/Kernel/include/timer.h
new file mode 100644 (file)
index 0000000..845dfee
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __TIMER_DOT_H__
+#define __TIMER_DOT_H__
+
+#include <stdbool.h>
+#include <kernel.h>
+
+typedef uint16_t timer_t;
+
+extern timer_t system_timer; /* counts up at TICKSPERSEC, wraps to zero */
+timer_t set_timer_duration(uint16_t duration); /* good for up to approx 0x8000 ticks */
+bool timer_expired(timer_t timer_val);
+
+#endif
diff --git a/Kernel/include/tty.h b/Kernel/include/tty.h
new file mode 100644 (file)
index 0000000..7b19097
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef __TTY_DOT_H__
+#define __TTY_DOT_H__
+
+typedef uint16_t tcflag_t;
+typedef uint16_t speed_t;
+typedef uint8_t cc_t;
+
+#define NCCS 12
+struct termios {
+  tcflag_t c_iflag;
+  tcflag_t c_oflag;
+  tcflag_t c_cflag;
+  tcflag_t c_lflag;
+  cc_t c_cc[NCCS];
+};
+
+#define VMIN           0       /* Supported */
+#define VEOF           0       /* Supported */
+#define VTIME          1
+#define VEOL           1       /* partial - FIXME, EOF in input */
+#define VERASE         2       /* Supported */
+#define VINTR          3       /* Supported */
+#define VKILL          4       /* Supported */
+#define VQUIT          5       /* Supported */
+#define VSTART         6       /* Supported */
+#define VSTOP          7       /* Supported */
+#define VSUSP          8
+#define VDSUSP         9
+#define VLNEXT         10
+#define VDISCARD       11      /* Supported */
+
+#define BRKINT 0x0001
+#define ICRNL  0x0002  /* Supported */
+#define IGNBRK 0x0004
+#define IGNCR  0x0008
+#define IGNPAR 0x0010
+#define INLCR  0x0020  /* Supported */
+#define INPCK  0x0040
+#define ISTRIP 0x0080  /* Supported */
+#define IUCLC  0x0100
+#define IXANY  0x0200
+#define IXOFF  0x0400
+#define PARMRK 0x0800
+#define IXON   0x1000
+
+#define OPOST  0x0001  /* Supported */
+#define OLCUC  0x0002
+#define ONLCR  0x0004  /* Supported */
+#define OCRNL  0x0008
+#define ONLRET 0x0010
+#define OFILL  0x0020
+#define NLDLY  0x0040
+#define NL0    0x0000
+#define NL1    0x0040
+#define CRDLY  0x0180
+#define CR0    0x0000
+#define CR1    0x0080
+#define CR2    0x0100
+#define CR3    0x0180
+#define TABDLY 0x0600
+#define TAB0   0x0000
+#define TAB1   0x0200
+#define TAB2   0x0400
+#define TAB3   0x0600
+#define BSDLY  0x0800
+#define BS0    0x0000
+#define BS1    0x0800
+#define VTDLY  0x1000
+#define VT0    0x0000
+#define VT1    0x1000
+#define FFDLY  0x2000
+#define FF0    0x0000
+#define FF1    0x2000
+
+#define B0     0x0000
+#define B50    0x0001
+#define B75    0x0002
+#define B110   0x0003
+#define B134   0x0004
+#define B150   0x0005
+#define B300   0x0006
+#define B600   0x0007
+#define B1200  0x0008
+#define B2400  0x0009
+#define B4800  0x000A
+#define B9600   0x000B
+#define B19200 0x000C
+#define B38400 0x000D
+#define B57600 0x000E
+#define B115200        0x000F
+
+#define CSIZE  0x0030
+#define CS5    0x0000
+#define CS6    0x0010
+#define CS7    0x0020
+#define CS8    0x0030
+#define CSTOPB 0x0040
+#define CREAD  0x0080
+#define PARENB 0x0100
+#define PARODD 0x0200
+#define HUPCL  0x0400
+#define CLOCAL 0x0800
+#define CRTSCTS 0x1000
+#define CBAUD  0x000F
+
+#define ECHO   0x0001  /* Supported */
+#define ECHOE  0x0002  /* Supported */
+#define ECHOK  0x0004  /* Supported */
+#define ECHONL 0x0008
+#define ICANON 0x0010  /* Supported */
+#define IEXTEN 0x0020
+#define ISIG   0x0040  /* Supported */
+#define NOFLUSH        0x0080
+#define TOSTOP 0x0100
+#define XCASE  0x0200
+
+#define TCSANOW                0
+#define TCSADRAIN      1
+#define TCSAFLUSH      2
+
+#define TCIFLUSH       1
+#define TCOFLUSH       2
+#define TCIOFLUSH      3
+
+#define TCIOFF         0
+#define TCION          1
+#define TCOOFF         2
+#define TCOON          3
+
+#define TCGETS         1
+#define TCSETS         2
+#define TCSETSW                3
+#define TCSETSF                4
+#define TIOCINQ                5
+#define TIOCFLUSH      6
+
+#define TIOCHANGUP     7       /* vhangup() */
+
+#define CTRL(c)  (c & 0x1f)
+
+/* Character Input Queue size */
+#define TTYSIZ 132
+
+extern struct termios ttydata[NUM_DEV_TTY + 1];
+extern uint16_t tty_pgrp[NUM_DEV_TTY + 1];
+
+extern void tty_init(void);
+
+extern int tty_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int tty_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int tty_open(uint8_t minor, uint16_t flag);
+extern int tty_close(uint8_t minor);
+extern int tty_ioctl(uint8_t minor, uint16_t request, char *data);
+
+extern void tty_hangup(uint8_t minor);
+extern void tty_carrier_drop(uint8_t minor);
+extern void tty_carrier_raise(uint8_t minor);
+
+extern int ptty_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int ptty_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int ptty_open(uint8_t minor, uint16_t flag);
+extern int ptty_close(uint8_t minor);
+extern int ptty_ioctl(uint8_t minor, uint16_t request, char *data);
+
+extern int pty_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int pty_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int pty_open(uint8_t minor, uint16_t flag);
+extern int pty_close(uint8_t minor);
+extern int pty_ioctl(uint8_t minor, uint16_t request, char *data);
+
+extern int tty_inproc(uint8_t minor, unsigned char c);
+extern void tty_outproc(uint8_t minor);
+extern void tty_echo(uint8_t minor, unsigned char c);
+extern void tty_erase(uint8_t minor);
+extern void tty_putc_wait(uint8_t minor, unsigned char c);
+
+/* provided by platform */
+extern struct s_queue ttyinq[NUM_DEV_TTY + 1];
+extern bool tty_writeready(uint8_t minor);
+extern void tty_putc(uint8_t minor, unsigned char c);
+extern void tty_setup(uint8_t minor);
+extern int tty_carrier(uint8_t minor);
+/* PTY pieces: 8 ptys both sides of */
+#ifdef CONFIG_PTY_DEV
+#define PTY_BUFFERS \
+static char pbuf0[TTYSIZ];\
+static char pbuf1[TTYSIZ];\
+static char pbuf2[TTYSIZ];\
+static char pbuf3[TTYSIZ];\
+static char pbuf4[TTYSIZ];\
+static char pbuf5[TTYSIZ];\
+static char pbuf6[TTYSIZ];\
+static char pbuf7[TTYSIZ];\
+static char pbuf8[TTYSIZ];\
+static char pbuf9[TTYSIZ];\
+static char pbufa[TTYSIZ];\
+static char pbufb[TTYSIZ];\
+static char pbufc[TTYSIZ];\
+static char pbufd[TTYSIZ];\
+static char pbufe[TTYSIZ];\
+static char pbuff[TTYSIZ];\
+
+#define PTY_QUEUES \
+    {pbuf0, pubf0, pubf0, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf1, pubf1, pubf1, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf2, pubf2, pubf2, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf3, pubf3, pubf3, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf4, pubf4, pubf4, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf5, pubf5, pubf5, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf6, pubf6, pubf6, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf7, pubf7, pubf7, TTYSIZ, 0, TTYSIZ/2}
+    {pbuf8, pubf8, pubf8, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuf9, pubf9, pubf9, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbufa, pubfa, pubfa, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbufb, pubfb, pubfb, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbufc, pubfc, pubfc, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbufd, pubfd, pubfd, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbufe, pubfe, pubfe, TTYSIZ, 0, TTYSIZ/2}, \
+    {pbuff, pubff, pubff, TTYSIZ, 0, TTYSIZ/2}
+
+#else
+
+#define PTY_BUFFERS
+#define PTY_QUEUES
+#define PTY_OFFSET     NUM_DEV_TTY
+#endif /* CONFIG_PTY_DEV */
+#endif /* TTY_DOT_H */
diff --git a/Kernel/include/version.h b/Kernel/include/version.h
new file mode 100644 (file)
index 0000000..2937135
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __VERSION_DOT_H__
+#define __VERSION_DOT_H__
+
+extern const char uname_str[];
+extern const uint8_t uname_len;
+
+#endif
diff --git a/Kernel/include/vt.h b/Kernel/include/vt.h
new file mode 100644 (file)
index 0000000..52e4cdb
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __VT_DOT_H__
+#define __VT_DOT_H__
+
+/* Core functions */
+void vtoutput(unsigned char *p, unsigned int len);
+void vtinit(void);
+/* Platform functions */
+void clear_lines(int8_t y, int8_t ct);
+void clear_across(int8_t y, int8_t x, int16_t l);
+void cursor_off(void);
+void cursor_on(int8_t y, int8_t x);
+void scroll_up(void);
+void scroll_down(void);
+void plot_char(int8_t y, int8_t x, uint16_t c);
+void do_beep(void);
+
+#endif
\ No newline at end of file
diff --git a/Kernel/inode.c b/Kernel/inode.c
new file mode 100644 (file)
index 0000000..c8a1697
--- /dev/null
@@ -0,0 +1,236 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+/* Writei (and readi) need more i/o error handling */
+void readi(inoptr ino, uint8_t flag)
+{
+       usize_t amount;
+       usize_t toread;
+       blkno_t pblk;
+       unsigned char *bp;
+       uint16_t dev;
+       bool ispipe;
+
+       dev = ino->c_dev;
+       ispipe = false;
+       switch (getmode(ino)) {
+       case F_DIR:
+       case F_REG:
+
+               /* See if end of file will limit read */
+
+               udata.u_count = min(udata.u_count,
+                               ino->c_node.i_size - udata.u_offset);
+               toread = udata.u_count;
+               goto loop;
+
+       case F_PIPE:
+               ispipe = true;
+               while (ino->c_node.i_size == 0 && !(flag & O_NDELAY)) {
+                       if (ino->c_refs == 1)   /* No writers */
+                               break;
+                       /* Sleep if empty pipe */
+                       psleep(ino);
+               }
+               toread = udata.u_count = min(udata.u_count, ino->c_node.i_size);
+               if (toread == 0) {
+                       udata.u_error = EWOULDBLOCK;
+                       break;
+               }
+               goto loop;
+
+       case F_BDEV:
+               toread = udata.u_count;
+               dev = *(ino->c_node.i_addr);
+
+             loop:
+               while (toread) {
+                       if ((pblk =
+                            bmap(ino, udata.u_offset >> BLKSHIFT,
+                                 1)) != NULLBLK)
+                               bp = bread(dev, pblk, 0);
+                       else
+                               bp = zerobuf();
+
+                       amount =
+                           min(toread, BLKSIZE - (udata.u_offset&BLKMASK));
+
+                       uputsys(bp + (udata.u_offset & BLKMASK), amount);
+
+                       brelse(bp);
+
+                       udata.u_base += amount;
+                       udata.u_offset += amount;
+                       if (ispipe && udata.u_offset >= 18 * BLKSIZE)
+                               udata.u_offset = 0;
+                       toread -= amount;
+                       if (ispipe) {
+                               ino->c_node.i_size -= amount;
+                               wakeup(ino);
+                       }
+               }
+               break;
+
+       case F_CDEV:
+               udata.u_count = cdread(ino->c_node.i_addr[0], flag);
+
+               if (udata.u_count != -1)
+                       udata.u_offset += udata.u_count;
+               break;
+
+       default:
+               udata.u_error = ENODEV;
+       }
+}
+
+
+
+void writei(inoptr ino, uint8_t flag)
+{
+       usize_t amount;
+       usize_t towrite;
+       unsigned char *bp;
+       bool ispipe;
+       blkno_t pblk;
+       uint16_t dev;
+       bool ndelay = (flag & O_NDELAY) ? 1 : 0;
+
+       dev = ino->c_dev;
+
+       switch (getmode(ino)) {
+
+       case F_BDEV:
+               dev = *(ino->c_node.i_addr);
+       case F_DIR:
+       case F_REG:
+               ispipe = false;
+               towrite = udata.u_count;
+               goto loop;
+
+       case F_PIPE:
+               ispipe = true;
+               while ((towrite = udata.u_count) > (16 * BLKSIZE) - 
+                                       ino->c_node.i_size) {
+                       if (ino->c_refs == 1) { /* No readers */
+                               udata.u_count = -1;
+                               udata.u_error = EPIPE;
+                               ssig(udata.u_ptab, SIGPIPE);
+                               return;
+                       }
+                       /* Sleep if empty pipe */
+                       if (ndelay) {
+                               udata.u_error = EWOULDBLOCK;
+                               return;
+                       }
+                       psleep(ino);
+               }
+               /* Sleep if empty pipe */
+               goto loop;
+
+             loop:
+
+               while (towrite) {
+                       amount = min(towrite, 512 - (udata.u_offset&BLKMASK));
+
+                       if ((pblk =
+                            bmap(ino, udata.u_offset >> BLKSHIFT,
+                                 0)) == NULLBLK)
+                               break;  /* No space to make more blocks */
+
+                       /* If we are writing an entire block, we don't care
+                        * about its previous contents
+                        */
+                       bp = bread(dev, pblk, (amount == BLKSIZE));
+
+                       ugetsys(bp + (udata.u_offset & BLKMASK), amount);
+
+                       /* FIXME: O_SYNC */
+                       bawrite(bp);
+
+                       udata.u_base += amount;
+                       udata.u_offset += amount;
+                       if (ispipe) {
+                               if (udata.u_offset >= 18 * 512)
+                                       udata.u_offset = 0;
+                               ino->c_node.i_size += amount;
+                               /* Wake up any readers */
+                               wakeup(ino);
+                       }
+                       towrite -= amount;
+               }
+
+               /* Update size if file grew */
+               if (!ispipe) {
+                       if (udata.u_offset > ino->c_node.i_size) {
+                               ino->c_node.i_size = udata.u_offset;
+                               ino->c_dirty = 1;
+                       }
+               }
+               break;
+
+       case F_CDEV:
+               udata.u_count = cdwrite(ino->c_node.i_addr[0], flag);
+
+               if (udata.u_count != -1)
+                       udata.u_offset += udata.u_count;
+               break;
+
+       default:
+               udata.u_error = ENODEV;
+       }
+}
+
+int16_t doclose(uint8_t uindex)
+{
+       int8_t oftindex;
+       inoptr ino;
+
+       if (!(ino = getinode(uindex)))
+               return (-1);
+
+       oftindex = udata.u_files[uindex];
+
+       if (isdevice(ino)
+               && ino->c_refs == 1 && of_tab[oftindex].o_refs == 1)
+               d_close((int) (ino->c_node.i_addr[0]));
+
+       udata.u_files[uindex] = NO_FILE;
+       udata.u_cloexec &= ~(1 << uindex);
+       oft_deref(oftindex);
+
+       return (0);
+}
+
+inoptr rwsetup(bool is_read, uint8_t * flag)
+{
+       inoptr ino;
+       struct oft *oftp;
+
+       udata.u_sysio = false;  /* I/O to user data space */
+       udata.u_base = (char *) udata.u_argn1;  /* buf */
+       udata.u_count = (susize_t) udata.u_argn2;       /* nbytes */
+
+       if ((ino = getinode(udata.u_argn)) == NULLINODE) {
+               /* kprintf("[WRS: rwsetup(): getinode(%x) fails]", udata.u_argn); */
+               return (NULLINODE);
+       }
+
+       oftp = of_tab + udata.u_files[udata.u_argn];
+       *flag = oftp->o_access;
+       if (O_ACCMODE(oftp->o_access) == (is_read ? O_WRONLY : O_RDONLY)) {
+               udata.u_error = EBADF;
+               return (NULLINODE);
+       }
+       setftime(ino, is_read ? A_TIME : (A_TIME | M_TIME | C_TIME));
+
+       if (getmode(ino) == F_REG && is_read == 0
+           && (oftp->o_access & O_APPEND))
+               oftp->o_ptr = ino->c_node.i_size;
+       /* Initialize u_offset from file pointer */
+       udata.u_offset = oftp->o_ptr;
+       /* FIXME: for 32bit we will need to check for overflow of the
+           file size here in the r/w inode code */
+       return (ino);
+}
diff --git a/Kernel/kdata.c b/Kernel/kdata.c
new file mode 100644 (file)
index 0000000..98494fe
--- /dev/null
@@ -0,0 +1,99 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+
+p_tab *init_process;
+char *cmdline = (char *) CMDLINE;
+char bootline[2];
+uint16_t ramsize, procmem, maxproc, nproc, nready;
+uint16_t runticks;
+uint16_t system_tick_counter;
+bool inint;
+uint8_t root_dev = DEFAULT_ROOT;
+uint8_t ticks_this_dsecond;
+inoptr root;
+uint16_t waitno;
+time_t tod;                    // time of day
+clock_t ticks;                 // system tick counter
+
+int16_t acct_fh = -1;          /* Accounting file handle */
+
+/* We keep the boot up strings in the buffer pool then toss them! 8) */
+
+struct blkbuf bufpool[NBUFS] = {
+       {"FUZIX version %s\n"
+        "Copyright (c) 1988-2002 by H.F.Bower, D.Braun, S.Nitschke, H.Peraza\n"
+        "Copyright (C) 1997-2001 by Arcady Schekochikhin, Adriano C. R. da Cunha\n"
+        "Copyright (c) 2013 Will Sowerbutts <will@sowerbutts.com>\n"
+        "Copyright (c) 2014 Alan Cox <alan@etchedpixels.co.uk>\nDevboot\n",},
+       {"WARNING: Increase PTABSIZE to %d to use available RAM\n",},
+       {"%dkB total RAM, %dkB available to processes (%d processes max)\n",},
+};
+
+struct p_tab ptab[PTABSIZE];
+struct oft of_tab[OFTSIZE];    /* Open File Table */
+struct cinode i_tab[ITABSIZE]; /* In-core inode table */
+struct mount fs_tab[NMOUNTS];  /* In-core mount table */
+
+const syscall_t syscall_dispatch[UZI_SYSCALL_COUNT] = {
+       __exit,                 /* FUZIX system call 0 */
+       _open,                  /* FUZIX system call 1 */
+       _close,                 /* FUZIX system call 2 */
+       _rename,                /* FUZIX system call 3 */
+       _mknod,                 /* FUZIX system call 4 */
+       _link,                  /* FUZIX system call 5 */
+       _unlink,                /* FUZIX system call 6 */
+       _read,                  /* FUZIX system call 7 */
+       _write,                 /* FUZIX system call 8 */
+       _lseek,                 /* FUZIX system call 9 */
+       _chdir,                 /* FUZIX system call 10 */
+       _sync,                  /* FUZIX system call 11 */
+       _access,                /* FUZIX system call 12 */
+       _chmod,                 /* FUZIX system call 13 */
+       _chown,                 /* FUZIX system call 14 */
+       _stat,                  /* FUZIX system call 15 */
+       _fstat,                 /* FUZIX system call 16 */
+       _dup,                   /* FUZIX system call 17 */
+       _getpid,                /* FUZIX system call 18 */
+       _getppid,               /* FUZIX system call 19 */
+       _getuid,                /* FUZIX system call 20 */
+       _umask,                 /* FUZIX system call 21 */
+       _getfsys,               /* FUZIX system call 22 */
+       _execve,                /* FUZIX system call 23 */
+       _getdirent,             /* FUZIX system call 24 */
+       _setuid,                /* FUZIX system call 25 */
+       _setgid,                /* FUZIX system call 26 */
+       _time,                  /* FUZIX system call 27 */
+       _stime,                 /* FUZIX system call 28 */
+       _ioctl,                 /* FUZIX system call 29 */
+       _brk,                   /* FUZIX system call 30 */
+       _sbrk,                  /* FUZIX system call 31 */
+       _fork,                  /* FUZIX system call 32 */
+       _mount,                 /* FUZIX system call 33 */
+       _umount,                /* FUZIX system call 34 */
+       _signal,                /* FUZIX system call 35 */
+       _dup2,                  /* FUZIX system call 36 */
+       _pause,                 /* FUZIX system call 37 */
+       _alarm,                 /* FUZIX system call 38 */
+       _kill,                  /* FUZIX system call 39 */
+       _pipe,                  /* FUZIX system call 40 */
+       _getgid,                /* FUZIX system call 41 */
+       _times,                 /* FUZIX system call 42 */
+       _utime,                 /* FUZIX system call 43 */
+       _geteuid,               /* FUZIX system call 44 */
+       _getegid,               /* FUZIX system call 45 */
+       _chroot,                /* FUZIX system call 46 */
+       _fcntl,                 /* FUZIX system call 47 */
+       _fchdir,                /* FUZIX system call 48 */
+       _fchmod,                /* FUZIX system call 49 */
+       _fchown,                /* FUZIX system call 50 */
+       _mkdir,                 /* FUZIX system call 51 */
+       _rmdir,                 /* FUZIX system call 52 */
+       _setpgrp,               /* FUZIX system call 53 */
+       _uname,                 /* FUZIX system call 54 */
+       _waitpid,               /* FUZIX system call 55 */
+       _profil,                /* FUZIX system call 56 */
+       _uadmin,                /* FUZIX systen call 57 */
+       _nice,                  /* FUZIX system call 58 */
+       _sigdisp                /* FUZIX system call 59 */
+};
diff --git a/Kernel/kernel.def b/Kernel/kernel.def
new file mode 100644 (file)
index 0000000..b2987db
--- /dev/null
@@ -0,0 +1,32 @@
+; Keep these in sync with struct u_data!!
+U_DATA__U_PTAB              .equ (U_DATA+0)   ; struct p_tab*
+U_DATA__U_PAGE              .equ (U_DATA+2)   ; uint16_t
+U_DATA__U_PAGE2             .equ (U_DATA+4)   ; uint16_t
+U_DATA__U_INSYS             .equ (U_DATA+6)   ; bool
+U_DATA__U_CALLNO            .equ (U_DATA+7)   ; uint8_t
+U_DATA__U_SYSCALL_SP        .equ (U_DATA+8)   ; void *
+U_DATA__U_RETVAL            .equ (U_DATA+10)   ; int16_t
+U_DATA__U_ERROR             .equ (U_DATA+12)  ; int16_t
+U_DATA__U_SP                .equ (U_DATA+14)  ; void *
+U_DATA__U_ININTERRUPT       .equ (U_DATA+16)  ; bool
+U_DATA__U_CURSIG            .equ (U_DATA+17)  ; int8_t
+U_DATA__U_ARGN              .equ (U_DATA+18)  ; uint16_t
+U_DATA__U_ARGN1             .equ (U_DATA+20)  ; uint16_t
+U_DATA__U_ARGN2             .equ (U_DATA+22)  ; uint16_t
+U_DATA__U_ARGN3             .equ (U_DATA+24)  ; uint16_t
+U_DATA__U_ISP               .equ (U_DATA+26)  ; void * (initial stack pointer when _exec()ing)
+U_DATA__U_TOP               .equ (U_DATA+28)  ; uint16_t
+U_DATA__U_SIGVEC            .equ (U_DATA+30)  ; table of function pointers (void *)
+
+; Keep these in sync with struct p_tab!!
+P_TAB__P_STATUS_OFFSET      .equ 0
+P_TAB__P_TTY_OFFSET         .equ 1
+P_TAB__P_PID_OFFSET         .equ 2
+P_TAB__P_PAGE_OFFSET        .equ 14
+
+P_RUNNING                   .equ 1            ; value from include/kernel.h
+P_READY                     .equ 2            ; value from include/kernel.h
+
+OS_BANK                     .equ 0            ; value from include/kernel.h
+
+EAGAIN                      .equ 11           ; value from include/kernel.h
diff --git a/Kernel/kernel02.def b/Kernel/kernel02.def
new file mode 100644 (file)
index 0000000..87f9e1f
--- /dev/null
@@ -0,0 +1,32 @@
+; Keep these in sync with struct u_data!!
+U_DATA__U_PTAB              .set (U_DATA+0)   ; struct p_tab*
+U_DATA__U_PAGE              .set (U_DATA+2)   ; uint16_t
+U_DATA__U_PAGE2             .set (U_DATA+4)   ; uint16_t
+U_DATA__U_INSYS             .set (U_DATA+6)   ; bool
+U_DATA__U_CALLNO            .set (U_DATA+7)   ; uint8_t
+U_DATA__U_SYSCALL_SP        .set (U_DATA+8)   ; void *
+U_DATA__U_RETVAL            .set (U_DATA+10)   ; int16_t
+U_DATA__U_ERROR             .set (U_DATA+12)  ; int16_t
+U_DATA__U_SP                .set (U_DATA+14)  ; void *
+U_DATA__U_ININTERRUPT       .set (U_DATA+16)  ; bool
+U_DATA__U_CURSIG            .set (U_DATA+17)  ; int8_t
+U_DATA__U_ARGN              .set (U_DATA+18)  ; uint16_t
+U_DATA__U_ARGN1             .set (U_DATA+20)  ; uint16_t
+U_DATA__U_ARGN2             .set (U_DATA+22)  ; uint16_t
+U_DATA__U_ARGN3             .set (U_DATA+24)  ; uint16_t
+U_DATA__U_SIGVEC            .set (U_DATA+26)  ; table of function pointers (void *)
+U_DATA__U_ISP               .set (U_DATA+58)  ; void * (initial stack pointer when _exec()ing)
+U_DATA__U_TOP               .set (U_DATA+60)  ; uint16_t
+
+; Keep these in sync with struct p_tab!!
+P_TAB__P_STATUS_OFFSET      .set 0
+P_TAB__P_TTY_OFFSET         .set 1
+P_TAB__P_PID_OFFSET         .set 2
+P_TAB__P_PAGE_OFFSET        .set 14
+
+P_RUNNING                   .set 1            ; value from include/kernel.h
+P_READY                     .set 2            ; value from include/kernel.h
+
+OS_BANK                     .set 0            ; value from include/kernel.h
+
+EAGAIN                      .set 11           ; value from include/kernel.h
diff --git a/Kernel/kernel09.def b/Kernel/kernel09.def
new file mode 100644 (file)
index 0000000..d3f061d
--- /dev/null
@@ -0,0 +1,32 @@
+; Keep these in sync with struct u_data!!
+U_DATA__U_PTAB              equ (U_DATA+0)   ; struct p_tab*
+U_DATA__U_PAGE              equ (U_DATA+2)   ; uint16_t
+U_DATA__U_PAGE2             equ (U_DATA+4)   ; uint16_t
+U_DATA__U_INSYS             equ (U_DATA+6)   ; bool
+U_DATA__U_CALLNO            equ (U_DATA+7)   ; uint8_t
+U_DATA__U_SYSCALL_SP        equ (U_DATA+8)   ; void *
+U_DATA__U_RETVAL            equ (U_DATA+10)   ; int16_t
+U_DATA__U_ERROR             equ (U_DATA+12)  ; int16_t
+U_DATA__U_SP                equ (U_DATA+14)  ; void *
+U_DATA__U_ININTERRUPT       equ (U_DATA+16)  ; bool
+U_DATA__U_CURSIG            equ (U_DATA+17)  ; int8_t
+U_DATA__U_ARGN              equ (U_DATA+18)  ; uint16_t
+U_DATA__U_ARGN1             equ (U_DATA+20)  ; uint16_t
+U_DATA__U_ARGN2             equ (U_DATA+22)  ; uint16_t
+U_DATA__U_ARGN3             equ (U_DATA+24)  ; uint16_t
+U_DATA__U_SIGVEC            equ (U_DATA+26)  ; table of function pointers (void *)
+U_DATA__U_ISP               equ (U_DATA+58)  ; void * (initial stack pointer when _exec()ing)
+U_DATA__U_TOP               equ (U_DATA+60)  ; uint16_t
+
+; Keep these in sync with struct p_tab!!
+P_TAB__P_STATUS_OFFSET      equ 0
+P_TAB__P_TTY_OFFSET         equ 1
+P_TAB__P_PID_OFFSET         equ 2
+P_TAB__P_PAGE_OFFSET        equ 14
+
+P_RUNNING                   equ 1            ; value from include/kernel.h
+P_READY                     equ 2            ; value from include/kernel.h
+
+OS_BANK                     equ 0            ; value from include/kernel.h
+
+EAGAIN                      equ 11           ; value from include/kernel.h
diff --git a/Kernel/lowlevel-6502.s b/Kernel/lowlevel-6502.s
new file mode 100644 (file)
index 0000000..d0496a0
--- /dev/null
@@ -0,0 +1,30 @@
+
+
+       .export unix_syscall_entry
+       .export _doexec
+       .export interrupt_handler
+       .export null_handler
+       .export nmi_handler
+       .export trap_illegal
+
+       .export outstring
+       .export outstringhex
+       .export outnewline
+       .export outx
+       .export outy
+       .export outcharhex
+
+
+unix_syscall_entry:
+_doexec:
+interrupt_handler:
+null_handler:
+nmi_handler:
+trap_illegal:
+outstring:
+outstringhex:
+outnewline:
+outx:
+outy:
+outcharhex:
+       rts
diff --git a/Kernel/lowlevel-6809.s b/Kernel/lowlevel-6809.s
new file mode 100644 (file)
index 0000000..bf55c3e
--- /dev/null
@@ -0,0 +1,464 @@
+;
+;      Common elements of low level interrupt and other handling. We
+; collect this here to minimise the amount of platform specific gloop
+; involved in a port
+;
+;      Based upon code (C) 2013 William R Sowerbutts
+;
+
+       .module lowlevel
+
+       ; compiler support
+       .globl  _euclid
+       .globl  _udivhi3
+       .globl  _umodhi3
+
+       ; debugging aids
+       .globl outcharhex
+       .globl outd,outx,outy
+       .globl outnewline
+       .globl outstring
+       .globl outstringhex
+       .globl outnibble
+
+       ; platform provided functions
+       .globl map_kernel
+       .globl map_process_always
+        .globl map_save
+        .globl map_restore
+       .globl outchar
+       .globl _kernel_flag
+       .globl _inint
+       .globl _platform_interrupt
+
+        ; exported symbols
+        .globl unix_syscall_entry
+       .globl null_handler
+       .globl _system_tick_counter
+       .globl unix_syscall_entry
+       .globl dispatch_process_signal
+        .globl _doexec
+        .globl trap_illegal
+       .globl nmi_handler
+       .globl interrupt_handler
+
+        ; imported symbols
+        .globl _trap_monitor
+        .globl _unix_syscall
+        .globl outstring
+        .globl kstack_top
+        .globl dispatch_process_signal
+       .globl istack_switched_sp
+       .globl istack_top
+       .globl _ssig
+
+        include "platform/kernel.def"
+        include "kernel09.def"
+
+        .area _COMMONMEM
+
+; entry point for UZI system calls
+;
+; Called by swi, which has already saved our CPU state for us
+;
+unix_syscall_entry:
+        orcc #0x10             ; interrupts off
+       ; FIXME: save the zero page ptr ??
+
+       ; make sure the interrupt logic knows we are in kernel mode
+       lda #1
+       sta _kernel_flag
+
+;FIXME
+;
+; locate function call arguments on the userspace stack
+;        ld hl, #18     ; 16 bytes machine state, plus 2 bytes return address
+;        add hl, sp
+;        ; save system call number
+;        ld a, (hl)
+;        ld (U_DATA__U_CALLNO), a
+;        ; advance to syscall arguments
+;        inc hl
+;        inc hl
+;        ; copy arguments to common memory
+;        ld bc, #8      ; four 16-bit values
+;        ld de, #U_DATA__U_ARGN
+;        ldir           ; copy
+
+        ; save process stack pointer
+        sts U_DATA__U_SYSCALL_SP
+        ; switch to kernel stack
+        lds #kstack_top
+
+        ; map in kernel keeping common
+       jsr map_kernel
+
+        ; re-enable interrupts
+        andcc #0xef
+
+        ; now pass control to C
+        jsr _unix_syscall
+
+        orcc #0x10
+       ; let the interrupt logic know we are not in kernel mode any more
+       ; kernel_flag is not in common so write it before we map it away
+       clr _kernel_flag
+
+        ; map process memory back in based on common (common may have
+        ; changed on a task switch)
+        jsr map_process_always
+
+        ; switch back to user stack
+        lds U_DATA__U_SYSCALL_SP
+
+        ; check for signals, call the handlers
+        jsr dispatch_process_signal
+
+        ; check if error condition to be signalled on return
+        ldd U_DATA__U_ERROR
+       ldx #-1 
+        ; error code in d, result in x
+        bra unix_return
+
+not_error:
+        ; no error to signal! return syscall return value instead of error code
+        ldx U_DATA__U_RETVAL
+       ldd #0
+unix_return:
+       ; zero page restore ??
+        andcc #0xef
+       rti
+
+dispatch_process_signal:
+        ; check if any signal outstanding
+        ldb U_DATA__U_CURSIG
+        beq dosigrts
+        ; put number on the stack as the argument for the signal handler
+       ; so extend it to 16bit
+       clra
+       tfr d,x
+
+       lslb            ;       2 bytes per entry
+        ; load the address of signal handler function
+       ldy #U_DATA__U_SIGVEC
+       ldu b,y         ; now y = udata.u_sigvec[cursig]
+
+        ; udata.u_cursig = 0;
+       clr U_DATA__U_CURSIG
+
+        ; restore signal handler to the default.
+        ; udata.u_sigvec[cursig] = SIG_DFL;
+        ; SIG_DFL = 0
+       leay b,y
+       clr ,y+
+       clr ,y
+
+        ldu #signal_return
+        pshs u      ; push return address
+
+        andcc #0xef
+       jmp ,x
+
+signal_return:
+       puls x
+        orcc #0x10
+;
+;      FIXME: port over the Z80 loop and check for next signal
+;
+dosigrts:
+        rts
+
+_doexec:
+       ; x is the jump address
+        orcc #0x10
+       ; this is a funny extra path out of syscall so we must also cover
+       ; the exit from kernel here
+       clr _kernel_flag
+
+        ; map task into address space (kernel_flag is no longer mapped, don't
+       ; re-order this)
+       ; preserves x
+        jsr map_process_always
+
+        lds U_DATA__U_ISP
+
+        ; u_data.u_insys = false
+        clr U_DATA__U_INSYS
+       andcc #0xef
+        jmp ,x
+
+;
+;      Very simple IRQ handler, we get interrupts at 50Hz and we have to
+;      poll ttys from it. The more logic we could move to common here the
+;      better.
+;
+interrupt_handler:
+            ; machine state stored by the cpu
+           ; save zero page ??
+            ldd _system_tick_counter
+           addd #1
+            std _system_tick_counter
+
+           ; FIXME: add profil support here (need to keep profil ptrs
+           ; unbanked if so ?)
+
+            ; don't allow us to run re-entrant, we've only got one interrupt stack
+           lda U_DATA__U_ININTERRUPT
+            bne interrupt_return
+            inca
+            sta U_DATA__U_ININTERRUPT
+
+            ; switch stacks
+            sts istack_switched_sp
+           ; the istack is not banked (very important!)
+            lds #istack_top
+           ; FIXME: check store/dec order might need to be -2 here!!!!
+
+           jsr map_save
+
+           lda 0               ; save address 0 contents for checking
+
+           ; preserves registers
+           jsr map_kernel
+           ;
+           ; kernel_flag is in the kernel map so we need to map early, we
+           ; need to map anyway for trap_signal
+           ;
+           ldb _kernel_flag
+           pshs b
+           bne in_kernel
+
+            ; we're not in kernel mode, check for signals and fault
+           cmpa #0xA5          ;FIXME correct code needed!!
+           beq nofault
+           jsr map_process_always ; map the process
+           lda #0xA5           ; put it back
+           sta 0               ; write
+           jsr map_kernel      ; restore the map
+           ldx #11             ; SIGSEGV
+           jsr trap_signal     ; signal the user with a fault
+
+nofault:
+in_kernel:
+            ; set inint to true
+            lda #1
+            sta _inint
+
+           ; this may task switch if not within a system call
+           ; if we switch then istack_switched_sp is out of date.
+           ; When this occurs we will exit via the resume path 
+            jsr _platform_interrupt
+
+            clr _inint
+
+           puls b                      ; Z = in kernel
+           bne in_kernel_2
+
+           ; On a return to user space always do a new map, we may have
+           ; changed process
+           jsr map_process_always
+            bra int_switch
+           ; On a return from an interrupt in kernel mode restore the old
+           ; mapping as it will vary during kernel activity and the kernel
+           ; wants it put back as it was before
+in_kernel_2:
+          jsr map_restore
+int_switch:
+            lds istack_switched_sp     ; stack back
+            clr U_DATA__U_ININTERRUPT
+            lda U_DATA__U_INSYS
+            bne interrupt_return
+
+            ; we're not in kernel mode, check for signals
+            jsr dispatch_process_signal
+
+interrupt_return:
+           ; restore zero page ??
+            andcc #0xef
+            rts
+
+;  Enter with X being the signal to send ourself
+trap_signal:
+           ldy U_DATA__U_PTAB
+           pshs x,y
+            jsr _ssig
+           puls x,y,pc
+
+;  Called from process context (hopefully)
+null_handler:
+           ; kernel jump to NULL is bad
+           lda U_DATA__U_INSYS
+           beq trap_illegal
+           ; user is merely not good
+           ; check order of push arguments !!
+            ldx #7
+           ldy U_DATA__U_PTAB
+           ldd #10             ;       signal (getpid(), SIGBUS)
+           pshs d,x,y
+           swi
+           puls d,x,y
+           ldd #0
+           tfr d,x
+           pshs d,x
+            swi                        ; exit
+
+
+
+illegalmsg: .ascii "[trap_illegal]"
+            .db 13,10,0
+
+trap_illegal:
+           ldx #illegalmsg
+           jsr outstring
+           jsr _trap_monitor
+
+dpsmsg:            .ascii "[dispsig]"
+            .db 13,10,0
+
+
+nmimsg:     .ascii "[NMI]"
+            .db 13,10,0
+
+nmi_handler:
+       jsr map_kernel
+        ldx #nmimsg
+       jsr outstring
+        jsr _trap_monitor
+
+
+       .area _COMMONMEM
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; outstring: Print the string at X until 0 byte is found
+; destroys: AF HL
+outstring:
+       lda ,x+
+       beq outstrdone
+        jsr outchar
+        bra outstring
+outstrdone:
+       rts
+
+; print the string at (HL) in hex (continues until 0 byte seen)
+outstringhex:
+       lda ,x+
+       beq outstrdone
+        jsr outcharhex
+       lda #32
+       jsr outchar
+        bra outstringhex
+
+; output a newline
+outnewline:
+        lda #0x0d  ; output newline
+        jsr outchar
+        lda #0x0a
+        jsr outchar
+        rts
+
+outd:  ; prints D in hex.
+       pshs b
+        tfr b,a
+        jsr outcharhex
+        puls b
+        jsr outcharhex
+        rts
+
+outx:  ; prints X
+       pshs d
+       tfr x,d
+       bsr outd
+       puls d,pc
+
+outy:  ; prints Y
+       pshs d
+       tfr y,d
+       bsr outd
+       puls d,pc
+
+; print the byte in A as a two-character hex value
+outcharhex:
+       pshs a
+        lsra
+        lsra
+        lsra
+        lsra
+        jsr outnibble
+       puls a
+        jsr outnibble
+        rts
+
+; print the nibble in the low four bits of A
+outnibble:
+        anda #0x0f ; mask off low four bits
+        cmpa #9
+        ble numeral ; less than 10?
+        adda #0x07 ; start at 'A' (10+7+0x30=0x41='A')
+numeral:adda #0x30 ; start at '0' (0x30='0')
+        jsr outchar
+        rts
+
+
+div0:
+       ldx     #div0msg
+       jsr     outstring
+       jsr     _trap_monitor
+div0msg        .ascii  'Divby0'
+       .db     13,10,0
+;
+;      Maths helpers - could be called from anywhere in C code
+;      From the GCC
+;
+_umodhi3:
+       ldd     2,s
+       beq     div0
+       pshs    x
+       jsr     _euclid
+       leas    2,s
+       tfr     d,x
+       rts
+
+_udivhi3:
+       ldd     2,s
+       beq     div0
+       pshs    x
+       jsr     _euclid
+       puls    x,pc
+
+       left=5
+       right=1                 ; word
+       count=0                 ; byte
+       CARRY=1                 ; alias
+_euclid:
+       leas    -3,s            ; 2 local variables
+       clr     count,s         ; prescale divisor
+       inc     count,s
+       tsta
+presc:
+       bmi     presc_done
+       inc     count,s
+       aslb
+       rola
+       bra     presc
+presc_done:
+       std     right,s
+       ldd     left,s
+       clr     left,s          ; quotient = 0
+       clr     left+1,s
+mod1:
+       subd    right,s         ; check subtract
+       bcc     mod2
+       addd    right,s
+       andcc   #~CARRY
+       bra     mod3
+mod2:
+       orcc    #CARRY
+mod3:
+       rol     left+1,s        ; roll in carry
+       rol     left,s
+       lsr     right,s
+       ror     right+1,s
+       dec     count,s
+       bne     mod1
+       leas    3,s
+       rts
diff --git a/Kernel/lowlevel-z80.s b/Kernel/lowlevel-z80.s
new file mode 100644 (file)
index 0000000..242e29f
--- /dev/null
@@ -0,0 +1,523 @@
+;
+;      Common elements of low level interrupt and other handling. We
+; collect this here to minimise the amount of platform specific gloop
+; involved in a port
+;
+;      Based upon code (C) 2013 William R Sowerbutts
+;
+
+       .module lowlevel
+
+
+       ; debugging aids
+       .globl outcharhex
+       .globl outbc, outde, outhl
+       .globl outnewline
+       .globl outstring
+       .globl outstringhex
+       .globl outnibble
+
+       ; platform provided functions
+       .globl map_kernel
+       .globl map_process_always
+        .globl map_process
+        .globl map_save
+        .globl map_restore
+       .globl outchar
+       .globl _kernel_flag
+       .globl _inint
+       .globl _platform_interrupt
+
+        .module syscall
+
+        ; exported symbols
+        .globl unix_syscall_entry
+       .globl _chksigs
+       .globl null_handler
+       .globl _system_tick_counter
+       .globl unix_syscall_entry
+       .globl dispatch_process_signal
+        .globl _doexec
+        .globl trap_illegal
+       .globl nmi_handler
+       .globl interrupt_handler
+       .globl _di
+       .globl _irqrestore
+
+        ; imported symbols
+        .globl _trap_monitor
+        .globl _unix_syscall
+        .globl outstring
+        .globl kstack_top
+        .globl dispatch_process_signal
+       .globl istack_switched_sp
+       .globl istack_top
+       .globl _ssig
+
+        .include "platform/kernel.def"
+        .include "kernel.def"
+
+        .area _COMMONMEM
+
+; entry point for UZI system calls
+unix_syscall_entry:
+        di
+        ; store processor state
+        ex af, af'
+        push af
+        ex af, af'
+        exx
+        push bc
+        push de
+        push hl
+        exx
+        ; push af ;; WRS: also skip this
+        push bc
+        push de
+        ; push hl ;; WRS: we could skip this since we always set HL on return
+        push ix
+        push iy
+
+       ; make sure the interrupt logic knows we are in kernel mode
+       ld a, #1
+       ld (_kernel_flag), a
+
+        ; locate function call arguments on the userspace stack
+        ld hl, #18     ; 16 bytes machine state, plus 2 bytes return address
+        add hl, sp
+        ; save system call number
+        ld a, (hl)
+        ld (U_DATA__U_CALLNO), a
+        ; advance to syscall arguments
+        inc hl
+        inc hl
+        ; copy arguments to common memory
+        ld bc, #8      ; four 16-bit values
+        ld de, #U_DATA__U_ARGN
+        ldir           ; copy
+
+        ; save process stack pointer
+        ld (U_DATA__U_SYSCALL_SP), sp
+        ; switch to kernel stack
+        ld sp, #kstack_top
+
+        ; map in kernel keeping common
+       call map_kernel
+
+        ; re-enable interrupts
+        ei
+
+        ; now pass control to C
+        call _unix_syscall
+
+        di
+       ; let the interrupt logic know we are not in kernel mode any more
+       ; kernel_flag is not in common so write it before we map it away
+       xor a
+       ld (_kernel_flag), a
+       ;
+       ; We restart from here on a unix syscall signal return path
+       ;
+unix_sig_exit:
+        ; map process memory back in based on common (common may have
+        ; changed on a task switch)
+        call map_process_always
+
+        ; switch back to user stack
+        ld sp, (U_DATA__U_SYSCALL_SP)
+
+        ; check for signals, call the handlers
+        call dispatch_process_signal
+
+        ; check if error condition to be signalled on return
+        ld hl, (U_DATA__U_ERROR)
+        ld a, h
+        or l    ; set NZ flag if we are to return error
+        jr z, not_error
+
+        scf    ; set carry flag
+        ; note error code remains in HL
+        jr unix_return
+
+not_error:
+        ; no error to signal! return syscall return value instead of error code
+        ld hl, (U_DATA__U_RETVAL)
+        ; fall through to return code
+
+unix_return:
+        ; restore machine state
+        pop iy
+        pop ix
+        ; pop hl ;; WRS: skip this!
+        pop de
+        pop bc
+        ; pop af ;; WRS: skip this!
+        exx
+        pop hl
+        pop de
+        pop bc
+        exx
+        ex af, af'
+        pop af
+        ex af, af'
+        ei
+        ret ; must immediately follow EI
+
+dispatch_process_signal:
+        ; check if any signal outstanding
+        ld a, (U_DATA__U_CURSIG)
+        or a
+        ret z
+
+        ; put system call number on the stack as the argument for the signal handler
+        ld l, a
+        ld h, #0
+        push hl
+
+        ; load the address of signal handler function
+        add hl, hl
+        ld de, #U_DATA__U_SIGVEC
+        add hl, de
+        ld e, (hl)
+        inc hl
+        ld d, (hl)      ; now DE = udata.u_sigvec[cursig]
+
+        ; udata.u_cursig = 0;
+        xor a
+        ld (U_DATA__U_CURSIG), a
+
+        ; restore signal handler to the default.
+        ; udata.u_sigvec[cursig] = SIG_DFL;
+        ; SIG_DFL = 0, A is still 0 from above, HL points at second byte of the signal vector.
+        ld (hl), a
+        dec hl
+        ld (hl), a
+
+        ld hl, #signal_return
+        push hl      ; push return address
+
+        ex de,hl
+        ei
+        jp (hl)        ; call signal handler in userspace, with interrupts enabled
+
+signal_return:
+        pop hl  ; remove arg from stack
+       pop hl  ; we won't be using the return address either
+        di     ; So we don't screw up in mapping and stack games
+        ; save process stack pointer
+        ld (U_DATA__U_SYSCALL_SP), sp
+        ; switch to kernel stack
+        ld sp, #kstack_top
+       call map_kernel
+       call _chksigs
+       ; Loop back around, switch stacks, check if there is a signal
+       ; and if so process it.
+       ;
+       ; If we do restartable signals we can just check the restartable
+       ; info and jmp back further up the syscall path *providing* that
+       ; on signal exit paths we write back any needed parameters with
+       ; their new info
+       jr unix_sig_exit
+
+_doexec:
+        di
+       ; this is a funny extra path out of syscall so we must also cover
+       ; the exit from kernel here
+       xor a
+       ld (_kernel_flag), a
+        ; map task into address space (kernel_flag is no longer mapped, don't
+       ; re-order this)
+        call map_process_always
+
+        pop bc ; return address
+        pop de ; start address
+        ;; push de ; restore stack ... but we're about to discard SP anyway!
+        ;; push bc 
+
+        ld hl, (U_DATA__U_ISP)
+        ld sp, hl      ; Initialize user stack, below main() parameters and the environment
+
+        ; u_data.u_insys = false
+        xor a
+        ld (U_DATA__U_INSYS), a
+
+        ex de, hl
+        ei
+        jp (hl)
+
+;
+;      Very simple IRQ handler, we get interrupts at 50Hz and we have to
+;      poll ttys from it. The more logic we could move to common here the
+;      better.
+;
+interrupt_handler:
+            ; store machine state
+            ; we arrive here via the trampoline at 0038h with interrupts disabled
+            ; save CPU registers (restored in _IRET)
+            ex af,af'
+            push af
+            ex af,af'
+            exx
+            push bc
+            push de
+            push hl
+            exx
+            push af
+            push bc
+            push de
+            push hl
+            push ix
+            push iy
+
+            ld hl, (_system_tick_counter)
+            inc hl
+            ld (_system_tick_counter), hl
+           ; FIXME: add profil support here (need to keep profil ptrs
+           ; unbanked if so ?)
+
+            ; don't allow us to run re-entrant, we've only got one interrupt stack
+            ld a, (U_DATA__U_ININTERRUPT)
+            or a
+            jp nz, interrupt_return
+            inc a
+            ld (U_DATA__U_ININTERRUPT), a
+
+            ; switch stacks
+            ld (istack_switched_sp), sp
+           ; the istack is not banked (very important!)
+            ld sp, #istack_top
+
+           call map_save
+
+           ld a, (0)           ; save address 0 contents for checking
+           ld b, a
+
+           call map_kernel
+           ;
+           ; kernel_flag is in the kernel map so we need to map early, we
+           ; need to map anyway for trap_signal
+           ;
+           ld a, (_kernel_flag)
+           push af
+           or a
+           jr nz, in_kernel
+
+            ; we're not in kernel mode, check for signals and fault
+           ld a, #0xC3
+           cp b                ; should be a jump
+           jr z, nofault
+           call map_process_always; map the process
+           ld a, #0xC3         ; put it back
+           ld (0), a           ; write
+           call map_kernel     ; restore the map
+           ld hl, #11          ; SIGSEGV
+           call trap_signal    ; signal the user with a fault
+
+nofault:
+in_kernel:
+            ; set inint to true
+            ld a, #1
+            ld (_inint), a
+
+           ; this may task switch if not within a system call
+           ; if we switch then istack_switched_sp is out of date.
+           ; When this occurs we will exit via the resume path 
+            call _platform_interrupt
+
+            xor a
+            ld (_inint), a
+
+           pop af                      ; Z = in kernel
+           jr nz, in_kernel_2
+
+           ; On a return to user space always do a new map, we may have
+           ; changed process
+           call map_process_always
+            jr int_switch
+           ; On a return from an interrupt in kernel mode restore the old
+           ; mapping as it will vary during kernel activity and the kernel
+           ; wants it put back as it was before
+in_kernel_2:
+          call map_restore
+int_switch:
+            ld sp, (istack_switched_sp)        ; stack back
+
+            xor a
+            ld (U_DATA__U_ININTERRUPT), a
+
+            ld a, (U_DATA__U_INSYS)
+            or a
+            jr nz, interrupt_return
+
+            ; we're not in kernel mode, check for signals
+            call dispatch_process_signal
+           ; FIXME: we should loop for multiple signals probably
+
+interrupt_return:
+            pop iy
+            pop ix
+            pop hl
+            pop de
+            pop bc
+            pop af
+            exx
+            pop hl
+            pop de
+            pop bc
+            exx
+            ex af, af'
+            pop af
+            ex af, af'
+            ei
+            ret
+
+;  Enter with HL being the signal to send ourself
+trap_signal:
+            push hl
+           ld hl, (U_DATA__U_PTAB);
+            push hl
+            call _ssig
+            pop hl
+            pop hl
+           ret
+
+;  Called from process context (hopefully)
+null_handler:
+           ; kernel jump to NULL is bad
+           ld a, (U_DATA__U_INSYS)
+           or a
+           jp z, trap_illegal
+           ; user is merely not good
+            ld hl, #7
+            push hl
+           ld hl, (U_DATA__U_PTAB)
+            push hl
+           ld hl, #10          ; signal (getpid(), SIGBUS)
+            rst #0x30          ; syscall
+            pop hl
+            pop hl
+            ld hl, #0
+            rst #0x30          ; exit
+
+
+
+illegalmsg: .ascii "[trap_illegal]"
+            .db 13, 10, 0
+
+trap_illegal:
+        ld hl, #illegalmsg
+        call outstring
+        call _trap_monitor
+
+dpsmsg: .ascii "[dispsig]"
+        .db 13, 10, 0
+
+
+nmimsg: .ascii "[NMI]"
+        .db 13,10,0
+nmi_handler:
+       call map_kernel
+        ld hl, #nmimsg
+        call outstring
+        jp _trap_monitor
+
+
+       .area _COMMONMEM
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+               ; IRQ helpers, in common as they may get used by common C
+               ; code (and are tiny)
+
+_di:           ld a, i
+               push af
+               pop hl
+               ret
+
+_irqrestore:   pop hl          ; sdcc needs to get register arg passing
+               pop af          ; so badly
+               jp po, was_di
+               ei
+was_di:
+               push af
+               jp (hl)
+
+
+
+
+; outstring: Print the string at (HL) until 0 byte is found
+; destroys: AF HL
+outstring:
+        ld a, (hl)     ; load next character
+        and a          ; test if zero
+        ret z          ; return when we find a 0 byte
+        call outchar
+        inc hl         ; next char please
+        jr outstring
+
+; print the string at (HL) in hex (continues until 0 byte seen)
+outstringhex:
+        ld a, (hl)     ; load next character
+        and a          ; test if zero
+        ret z          ; return when we find a 0 byte
+        call outcharhex
+        ld a, #0x20 ; space
+        call outchar
+        inc hl         ; next char please
+        jr outstringhex
+
+; output a newline
+outnewline:
+        ld a, #0x0d  ; output newline
+        call outchar
+        ld a, #0x0a
+        call outchar
+        ret
+
+outhl:  ; prints HL in hex. Destroys AF.
+        ld a, h
+        call outcharhex
+        ld a, l
+        call outcharhex
+        ret
+
+outbc:  ; prints BC in hex. Destroys AF.
+        ld a, b
+        call outcharhex
+        ld a, c
+        call outcharhex
+        ret
+
+outde:  ; prints DE in hex. Destroys AF.
+        ld a, d
+        call outcharhex
+        ld a, e
+        call outcharhex
+        ret
+
+; print the byte in A as a two-character hex value
+outcharhex:
+        push bc
+        ld c, a  ; copy value
+        ; print the top nibble
+        rra
+        rra
+        rra
+        rra
+        call outnibble
+        ; print the bottom nibble
+        ld a, c
+        call outnibble
+        pop bc
+        ret
+
+; print the nibble in the low four bits of A
+outnibble:
+        and #0x0f ; mask off low four bits
+        cp #10
+        jr c, numeral ; less than 10?
+        add a, #0x07 ; start at 'A' (10+7+0x30=0x41='A')
+numeral:add a, #0x30 ; start at '0' (0x30='0')
+        call outchar
+        ret
+
diff --git a/Kernel/makeversion b/Kernel/makeversion
new file mode 100755 (executable)
index 0000000..18b0895
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+cat <<EOF > version.c
+#include "kernel.h"
+#include "version.h"
+
+/* Format is version/sysname/release/system */
+/* pack version first so we can use uname_str as a printf target */
+struct sysinfoblk sysinfo = {
+       sizeof(struct sysinfoblk),
+       CONFIG_BANKS,
+       UFTSIZE,
+       TICKSPERSEC,
+       0,
+       0,
+#ifdef CONFIG_PROFIL
+       CONF_PROFIL |
+#endif
+       0
+};
+/* Must follow immediately afterwards */
+/* Quoting to work around cc65 bug */
+const char uname_str[] = "$1\0""UZI+\0""$2\0""$3";
+EOF
+X=$(echo "$1XFuzix$2X$3X"|wc -c)
+echo "const uint8_t uname_len = "$X";" >>version.c
+
+
diff --git a/Kernel/mm.c b/Kernel/mm.c
new file mode 100644 (file)
index 0000000..8e722f6
--- /dev/null
@@ -0,0 +1,31 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+/* Will move into arch code: for most platforms is a 'don't care' as
+   switching is cheap */
+#define is_common(a,b) (udata.u_base >= (char *) PROGTOP)
+
+/*
+ * If System is in context or destination is in Common memory
+ * (F000-FFFF is always in context), simply copy the data.
+ * Otherwise perform Interbank move (uput) to User bank.
+ */
+
+unsigned int uputsys(unsigned char *from, unsigned int size)
+{
+       if (udata.u_sysio || is_common(from, size))
+               memcpy(udata.u_base, from, size);
+       else
+               uput(from, udata.u_base, size);
+       return size;
+}
+
+unsigned int ugetsys(unsigned char *to, unsigned int size)
+{
+       if (udata.u_sysio || is_common(from, size))
+               memcpy(to, udata.u_base, size);
+       else
+               uget(udata.u_base, to, size);
+       return size;
+}
diff --git a/Kernel/platform-6502test/Makefile b/Kernel/platform-6502test/Makefile
new file mode 100644 (file)
index 0000000..a3bec2e
--- /dev/null
@@ -0,0 +1,32 @@
+
+CSRCS = devlpr.c devtty.c devrd.c
+CSRCS += devices.c main.c libc.c
+
+ASRCS = p6502.s crt0.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.s=$(BINEXT))
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.o) $(CSRCS:.c=.s) $(ASRCS:.s=.o)
+
+all:   $(OBJS)
+
+$(COBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $<
+
+$(AOBJS): %$(BINEXT): %.s
+       $(CROSS_AS) $(ASOPTS) $< -o $*$(BINEXT)
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
+       $(CROSS_LD) -o uzi.bin --mapfile uzi.map -C ld65.cfg crt0.o commonmem.o \
+       p6502.o ../start.o ../version.o ../lowlevel-6502.o \
+       tricks.o main.o ../timer.o ../kdata.o devrd.o devices.o \
+       ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+       ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o ../bank16k.o \
+       ../tty.o ../devnull.o ../devzero.o ../devproc.o ../devmem.o \
+       ../usermem.o devlpr.o devtty.o libc.o 
diff --git a/Kernel/platform-6502test/commonmem.s b/Kernel/platform-6502test/commonmem.s
new file mode 100644 (file)
index 0000000..1a20a30
--- /dev/null
@@ -0,0 +1,25 @@
+;
+;      Put the udata at the start of common. We have four 16K banks so we
+; keep the non .common kernel elements below C000 and then keep bank 3 as a
+; true common bank
+;
+        ; exported symbols
+        .export _ub
+        .export _udata
+        .export kstack_top
+        .export istack_top
+        .export istack_switched_sp
+
+        .segment "COMMONMEM"
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+       .res 512,0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+       .res 254,0
+istack_top:
+istack_switched_sp: .word 0
diff --git a/Kernel/platform-6502test/config.h b/Kernel/platform-6502test/config.h
new file mode 100644 (file)
index 0000000..25532a8
--- /dev/null
@@ -0,0 +1,60 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Acct syscall support */
+#define CONFIG_ACCT
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+/* Use the C language usermem helpers */
+#define CONFIG_USERMEM_C
+/* TODO: these need to be defined as the code to flip the banks over */
+#define BANK_PROCESS
+#define BANK_KERNEL
+
+/* We use flexible 16K banks so use the helper */
+#define CONFIG_BANK16
+#define MAX_MAPS 16
+/* And swapping */
+#define SWAPDEV 6      /* FIXME */
+#define SWAP_SIZE   0x80       /* 64K blocks */
+/* FIXME */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0xF000      /* vectors so its a round number of sectors */
+#define UDATA_BLOCKS   0       /* We swap the uarea in the data */
+#define UDATA_SWAPSIZE 0
+#define MAX_SWAPS      32
+
+
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* We want the 8x8 font */
+#define CONFIG_FONT_8X8
+/* Vt definitions */
+#define VT_WIDTH       64
+#define VT_HEIGHT      24
+#define VT_RIGHT       63
+#define VT_BOTTOM      23
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xF000))  /* Top of program, base of U_DATA */
+
+#define BOOT_TTY 3        /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+                            /* Temp FIXME set to serial port for debug ease */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+#define NDEVS    1        /* Devices 0..NDEVS-1 are capable of being mounted */
+                          /*  (add new mountable devices to beginning area.) */
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         1        /* Number of mounts at a time - nothing mountable! */
diff --git a/Kernel/platform-6502test/crt0.s b/Kernel/platform-6502test/crt0.s
new file mode 100644 (file)
index 0000000..2056410
--- /dev/null
@@ -0,0 +1,42 @@
+               ; Ordering of segments for the linker.
+               ; WRS: Note we list all our segments here, even though
+               ; we don't use them all, because their ordering is set
+               ; when they are first seen.     
+
+               ; imported symbols
+               .export start
+
+               ; startup code @0
+               .code
+
+start:         
+;              orcc #0x10              ; interrupts definitely off
+;              lds #kstack_top
+               ; move the common memory where it belongs    
+               ; we do this dowards, not out of any concern about
+               ; about overlap (although its correct for this) but because
+               ; it deals with linker reloc limits nicely
+;              ldd #s__INITIALIZER
+;              addd #l__COMMONMEM
+;              tfr d,x
+;              ldd #s__COMMONMEM
+;              addd #l__COMMONMEM
+;              tfr d,y
+               
+;copier:               lda ,-x
+;              sta ,-y
+;              cmpy #s__COMMONMEM
+;              bgt copier
+
+;wiper:                ldx #s__DATA
+;              ldd #l__DATA
+;              clr ,x+
+;              subd #1
+;              bne wiper
+
+;              jsr init_early
+;              jsr init_hardware
+;              jsr _fuzix_main
+;              orcc #0x10
+;stop:         bra stop
+
diff --git a/Kernel/platform-6502test/device.h b/Kernel/platform-6502test/device.h
new file mode 100644 (file)
index 0000000..6f4c1e2
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern void mod_control(uint8_t set, uint8_t clr);
+
+#endif /* __DEVICE_DOT_H__ */
diff --git a/Kernel/platform-6502test/devices.c b/Kernel/platform-6502test/devices.c
new file mode 100644 (file)
index 0000000..4f9e16b
--- /dev/null
@@ -0,0 +1,43 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devrd.h>
+#include <devmem.h>
+#include <devzero.h>
+#include <devnull.h>
+#include <devproc.h>
+#include <devlpr.h>
+#include <tty.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* Memory disk block devices  */
+  {  0,  rd_open,     no_close,    rd_read,   rd_write,   no_ioctl },   //   0   /dev/rd0
+
+  /* devices below here are not mountable (as per NDEVS) */
+  {  0, lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },  //  1   /dev/lp  
+  {  0, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  2   /dev/tty
+  {  1, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  3   /dev/tty1
+  {  2, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  4   /dev/tty2
+  {  0, no_open,      no_close,    null_read, null_write, no_ioctl  },  //  5   /dev/null
+  {  0, no_open,      no_close,    zero_read, no_rdwr,    no_ioctl  },  //  6   /dev/zero
+  {  0, no_open,      no_close,    mem_read,  mem_write,  no_ioctl  },  //  7   /dev/kmem
+  {  0, no_open,      no_close,    proc_read, no_rdwr, proc_ioctl}      //  8  /dev/proc
+  /* Add more tty channels here if available, incrementing minor# */
+};
+
+bool validdev(uint8_t dev)
+{
+    if(dev >= (sizeof(dev_tab)/sizeof(struct devsw)))
+        return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+}
+
diff --git a/Kernel/platform-6502test/devlpr.c b/Kernel/platform-6502test/devlpr.c
new file mode 100644 (file)
index 0000000..a011085
--- /dev/null
@@ -0,0 +1,54 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <device.h>
+#include <devlpr.h>
+
+/* random test places */
+uint8_t *lpstat = (uint8_t *)0xFF00;
+uint8_t *lpdata = (uint8_t *)0xFF01;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+       minor;
+       flag;                   // shut up compiler
+       return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+       minor;                  // shut up compiler
+       return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       int c = udata.u_count;
+       char *p = udata.u_base;
+       uint16_t ct;
+
+       minor;
+       rawflag;
+       flag;                   // shut up compiler
+
+       while (c-- > 0) {
+               ct = 0;
+
+               /* Try and balance polling and sleeping */
+               while (*lpstat & 2) {
+                       ct++;
+                       if (ct == 10000) {
+                               udata.u_ptab->p_timeout = 3;
+                               if (psleep_flags(NULL, flag)) {
+                                       if (udata.u_count)
+                                               udata.u_error = 0;
+                                       return udata.u_count;
+                               }
+                               ct = 0;
+                       }
+               }
+               /* Data */
+               *lpdata = ugetc(p++);
+       }
+       return udata.u_count;
+}
diff --git a/Kernel/platform-6502test/devlpr.h b/Kernel/platform-6502test/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-6502test/devrd.c b/Kernel/platform-6502test/devrd.c
new file mode 100644 (file)
index 0000000..d71fe08
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+ * NC100 RD PCMCIA driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devrd.h>
+
+static int rd_transfer(bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;
+    uint16_t dptr;
+    int dlen;
+    int ct = 0;
+    int map;
+
+    /* FIXME: raw is broken unless nicely aligned */
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        if (dptr & 0x1FF) {
+            udata.u_error = EIO;
+            return -1;
+        }
+        block = udata.u_offset.o_blkno;
+        block_xfer = dlen >> 9;
+        map = 1;
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 1;
+        map = 0;
+    }
+    block += 2*320;    /* ramdisc starts at 320K in */
+        
+    while (ct < block_xfer) {
+/*        rd_memcpy(is_read, map, dptr, block); */
+        block++;
+        ct++;
+    }
+    return ct;
+}
+
+int rd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor != 0) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(true, rawflag);
+}
+
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(false, rawflag);
+}
+
diff --git a/Kernel/platform-6502test/devrd.h b/Kernel/platform-6502test/devrd.h
new file mode 100644 (file)
index 0000000..6320b26
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __DEVRD_DOT_H__
+#define __DEVRD_DOT_H__
+
+/* public interface */
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_open(uint8_t minor, uint16_t flag);
+
+/* asm banking helper */
+void rd_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block);
+
+#endif /* __DEVRD_DOT_H__ */
+
diff --git a/Kernel/platform-6502test/devtty.c b/Kernel/platform-6502test/devtty.c
new file mode 100644 (file)
index 0000000..e217f60
--- /dev/null
@@ -0,0 +1,67 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <vt.h>
+#include <tty.h>
+
+#undef  DEBUG                  /* UNdefine to delete debug code sequences */
+
+uint8_t *uarta = (uint8_t *)0xFF04;
+uint8_t *uartb = (uint8_t *)0xFF05;
+
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+PTY_BUFFERS;
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     /* ttyinq[0] is never used */
+       {NULL, NULL, NULL, 0, 0, 0},
+       {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
+       PTY_QUEUES
+};
+
+static void nap(void)
+{
+}
+
+/* tty1 is the screen tty2 is the serial port */
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+bool tty_writeready(uint8_t minor)
+{
+       uint8_t c;
+       if (minor == 1)
+               return 1;
+       c = *uartb;
+       return c & 1;
+}
+
+void tty_putc(uint8_t minor, char c)
+{
+       minor;
+#if 0
+       if (minor == 1) {
+               vtoutput(&c, 1);
+               return;
+       }
+#endif 
+       *uarta = c;
+}
+
+void platform_interrupt(void)
+{
+       timer_interrupt();
+}
+
+/* This is used by the vt asm code, but needs to live at the top of the kernel */
+uint16_t cursorpos;
diff --git a/Kernel/platform-6502test/devtty.h b/Kernel/platform-6502test/devtty.h
new file mode 100644 (file)
index 0000000..948cc29
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+extern int nc100_tty_open(uint8_t minor, uint16_t flag);
+extern int nc100_tty_close(uint8_t minor);
+extern void nc100_tty_init(void);
+#endif
diff --git a/Kernel/platform-6502test/kernel.def b/Kernel/platform-6502test/kernel.def
new file mode 100644 (file)
index 0000000..02621e4
--- /dev/null
@@ -0,0 +1,7 @@
+; UZI mnemonics for memory addresses etc
+
+; (this is struct u_data from kernel.h)
+U_DATA                      .set $F000
+; 256+256+256 bytes.
+U_DATA__TOTALSIZE           .set $300        
+
diff --git a/Kernel/platform-6502test/ld65.cfg b/Kernel/platform-6502test/ld65.cfg
new file mode 100644 (file)
index 0000000..62af64f
--- /dev/null
@@ -0,0 +1,15 @@
+MEMORY {
+       RAMZ:   start = $0000, size = $0100;
+       RAM0:   start = $0800, size = $E800;
+       RAM1:   start = $F000, size = $0800;
+}
+
+SEGMENTS {
+       ZEROPAGE: load = RAMZ, type = rw;
+       CODE:   load = RAM0, type = ro;
+       RODATA: load = RAM0, type = ro;
+       DATA:   load = RAM0, type = rw;
+       BSS:    load = RAM0, type = bss, define=yes;
+       COMMONMEM: load = RAM1, type = rw;
+}
+
diff --git a/Kernel/platform-6502test/libc.c b/Kernel/platform-6502test/libc.c
new file mode 100644 (file)
index 0000000..8a97283
--- /dev/null
@@ -0,0 +1,17 @@
+#include "cpu.h"
+
+void *memcpy(void *d, void *s, size_t sz)
+{
+  unsigned char *dp, *sp;
+  while(sz--)
+    *dp++=*sp++;
+  return d;
+}
+
+size_t strlen(const char *p)
+{
+  const char *e = p;
+  while(*e++);
+  return e-p-1;
+}
+
diff --git a/Kernel/platform-6502test/main.c b/Kernel/platform-6502test/main.c
new file mode 100644 (file)
index 0000000..eb35695
--- /dev/null
@@ -0,0 +1,50 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+/* The uarea is already synched to the stash which is written with the
+   process */
+uint8_t *swapout_prepare_uarea(ptptr p)
+{
+  p;
+  return NULL;
+}
+
+/* The switchin code will move the uarea into the process itself, we just
+   need to fix up the u_page pointer */
+uint8_t *swapin_prepare_uarea(ptptr p)
+{
+  p;
+  return NULL;
+}
+
+void platform_idle(void)
+{
+}
+
+void do_beep(void)
+{
+}
+
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set of pages
+ * with the last page repeated to fill any holes.
+ */
+
+void pagemap_init(void)
+{
+    int i;
+    /* 0/1/2 image, 3/4/5 kernel 6-19 apps */
+    /* Don't add page 6 yet - it's the initial common at boot */
+    for (i = 0x80 + 7; i < 0x80 + 20; i++)
+        pagemap_add(i);
+    /*
+     * The kernel boots with 0x86 as the common, list it last here so it also
+     * gets given to init as the kernel kicks off the init stub. init will then
+     * exec preserving this common and all forks will be copies from it.
+     */
+    pagemap_add(0x86);
+}
+
diff --git a/Kernel/platform-6502test/p6502.s b/Kernel/platform-6502test/p6502.s
new file mode 100644 (file)
index 0000000..a54f333
--- /dev/null
@@ -0,0 +1,199 @@
+;
+;          6502 Build testing
+;
+
+            .export init_early
+            .export init_hardware
+            .export _program_vectors
+           .export map_kernel
+           .export map_process
+           .export map_process_always
+           .export map_save
+           .export map_restore
+
+            ; exported debugging tools
+            .export _trap_monitor
+            .export outchar
+           .export _di
+           .export _ei
+           .export _irqrestore
+
+            .include "kernel.def"
+            .include "../kernel02.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .segment "COMMONMEM"
+
+trapmsg:    .asciiz "Trapdoor: SP="
+trapmsg2:   .asciiz ", PC="
+tm_user_sp: .word 0
+
+_trap_monitor:
+;          orcc #0x10
+;          bra _trap_monitor
+
+_trap_reboot:
+;          lda 0xff90
+;          anda #0xfc          ; map in the ROM
+;          jmp 0
+
+_di:
+;          tfr cc,b            ; return the old irq state
+;          orcc #0x10
+           rts
+_ei:
+;          andcc #0xef
+           rts
+
+_irqrestore:                   ; B holds the data
+;          tfr b,cc
+           rts
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .code
+
+init_early:
+            rts
+
+init_hardware:
+;            ; set system RAM size
+;          ldd #256
+;          std _ramsize
+;          ldd #192
+;          std _procmem
+;
+;          ; Our vectors are in high memory unlike Z80 but we still
+;          ; need vectors
+;          ldx #0
+;            jsr _program_vectors
+
+            rts
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .segment "COMMONMEM"
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+;            orcc #0x10                ; di just to be sure
+
+;          jsr map_process
+
+;          ldx #0xFFF2
+;          ldd #badswi_handler
+;          std ,y++
+;          std ,y++                    ; SWI2 and 3 both bad SWI
+;          ldd #firq_handler
+;          std ,y++
+;            ldd #interrupt_handler
+;          std ,y++
+;            ldd #unix_syscall_entry
+;          stx ,y++
+;          ldd #nmi_handler
+;          stx ,y
+;          jsr map_kernel
+           rts
+
+;
+;      Userspace mapping pages 7+  kernel mapping pages 3-5, first common 6
+;
+;
+;      All registers preserved
+;
+map_process_always:
+;          pshs y,u
+;          ldx #U_DATA__U_PAGE
+;          jsr map_process_2
+;          puls y,u,pc
+;
+;      HL is the page table to use, A is eaten, HL is eaten
+;
+map_process:
+;          cmpx #0
+;          bne map_process_2
+;
+;      Map in the kernel below the current common, all registers preserved
+;
+map_kernel:
+;
+;      Two MMU mappings is pure luxury
+;
+;      Kernel map was set up by boot loader, just flip to it
+;
+;          lda 0xff91                  ; INIT1, use 0xFFA8 maps
+;          ora #0x01
+;          sta 0xff91
+           rts
+;
+;      User is in the FFA0 map with the top 8K as common
+;
+;      As the core code currently does 16K happily but not 8 we just pair
+;      up pages
+;
+map_process_2:
+;          pshs x,y,a
+;          ldy #0xffa0                 ; MMU user map. We can fiddle with
+;          lda ,x+                     ; this to our hearts content
+;          sta ,y+                     ; as it's not live yet
+;          inca
+;          sta ,y+
+;          lda ,x+
+;          sta ,y+
+;          inca
+;          sta ,y+
+;          lda ,x+
+;          sta ,y+
+;          inca
+;          sta ,y+
+;          lda ,x+
+;          sta ,y+
+;          inca        
+;          sta ,y
+;          lda 0xff91
+;          anda #0xfe
+;          sta 0xff91                  ; new mapping goes live here
+;          puls x,y,a,pc               ; so had better include common!
+;
+;      Restore a saved mapping. We are guaranteed that we won't switch
+;      common copy between save and restore. Preserve all registers
+;
+;      We cheat somewhat. We have two mapping sets, so just remember
+;      which space we were in
+;
+map_restore:
+;          pshs a
+;          lda 0xff91
+;          ora saved_map
+;          sta 0xff91
+;          puls a,pc
+;          
+
+;      Save the current mapping.
+;
+map_save:
+;          pshs a
+;          lda 0xff91
+;          anda #1
+;          sta saved_map
+;          puls a,pc
+
+saved_map:  .dbyt 0
+           
+
+; outchar: Wait for UART TX idle, then print the char in a
+
+outchar:
+;          pshs b
+outcharw:
+;          ldb 0xffa0
+;          bitb #0x02
+;          beq outcharw
+;          sta 0xffa1
+;          puls b,pc
diff --git a/Kernel/platform-6502test/tricks.s b/Kernel/platform-6502test/tricks.s
new file mode 100644 (file)
index 0000000..feee3a8
--- /dev/null
@@ -0,0 +1,191 @@
+;
+;      6809 version
+;
+        .export _switchout
+        .export _switchin
+        .export _dofork
+       .export _ramtop
+
+
+        .include "kernel.def"
+        .include "../kernel02.def"
+
+        .segment "COMMONMEM"
+
+; ramtop must be in common for single process swapping cases
+; and its a constant for the others from before init forks so it'll be fine
+; here
+_ramtop:
+       .word 0
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+;      orcc #0x10              ; irq off
+;        jsr _chksigs
+;
+;        ; save machine state
+;        ldd #0 ; return code set here is ignored, but _switchin can 
+;        ; return from either _switchout OR _dofork, so they must both write 
+;        ; U_DATA__U_SP with the following on the stack:
+;      pshs d
+;      sts U_DATA__U_SP
+;
+;        ; set inint to false
+;      lda #0
+;      sta _inint
+;
+;        ; find another process to run (may select this one again) returns it
+;        ; in X
+;        jsr _getproc
+;        jsr _switchin
+;        ; we should never get here
+;        jsr _trap_monitor
+
+badswitchmsg: .asciiz "_switchin: FAIL\r\n"
+
+; new process pointer is in X
+_switchin:
+;        orcc #0x10            ; irq off
+;
+;      ldy P_TAB__P_PAGE_OFFSET+3,x
+;      ; FIXME: can we skip the usermaps here ?
+;      stx 0xffa6              ; map the process uarea we want
+;      adda #1
+;      stx 0xffa7
+;      stx 0xffaf              ; and include the kernel mapping
+;
+       ; ------- No stack -------
+        ; check u_data->u_ptab matches what we wanted
+;      cmpx U_DATA__U_PTAB
+;        bne switchinfail
+;
+       ; wants optimising up a bit
+;      lda #P_RUNNING
+;      sta P_TAB__P_STATUS_OFFSET,x
+
+;      lda #0
+;      sta _runticks
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+;        lds U_DATA__U_SP
+
+;        puls x ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+;      lda _inint
+;        beq swtchdone ; in ISR, leave interrupts off
+;      andcc #0xef
+;swtchdone:
+;        rts
+
+switchinfail:
+;      jsr outx
+;        ldx #badswitchmsg
+;        jsr outstring
+;      ; something went wrong and we didn't switch in what we asked for
+;        jmp _trap_monitor
+
+fork_proc_ptr: .word 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+;        ; always disconnect the vehicle battery before performing maintenance
+;        orcc #0x10     ; should already be the case ... belt and braces.
+
+       ; new process in X, get parent pid into y
+
+;      stx fork_proc_ptr
+;      ldy P_TAB__P_PID_OFFSET,x
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+;        pshs y ; y  has p->p_pid from above, the return value in the parent
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+ ;       sts U_DATA__U_SP
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ; --------- we switch stack copies in this call -----------
+;      jsr fork_copy                   ; copy 0x000 to udata.u_top and the
+                                       ; uarea and return on the childs
+                                       ; common
+       ; We are now in the kernel child context
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+;      puls y
+
+;        ldx fork_proc_ptr
+;        jsr _newproc
+
+       ; any calls to map process will now map the childs memory
+
+        ; runticks = 0;
+;        clr _runticks
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+;        rts
+
+fork_copy:
+;      ldd U_DATA__U_TOP
+;      addd #0x0fff            ; + 0x1000 (-1 for the rounding to follow)
+;      lsra            
+;      lsra
+;      lsra
+;      lsra
+;      lsra                    ; bits 2/1 for 8K pages
+;      anda #6                 ; lose bit 0
+;      adda #2                 ; and round up to the next bank (but in 8K terms)
+;
+;      ldx fork_proc_ptr
+;      ldy P_TAB__P_PAGE_OFFSET,x
+;      ; y now points to the child page pointers
+;      ldx U_DATA__U_PAGE
+;      ; and x to the parent
+;fork_next:
+;      ld a,(hl)
+;      out (0x11), a           ; 0x4000 map the child
+;      ld c, a
+;      inc hl
+;      ld a, (de)
+;      out (0x12), a           ; 0x8000 maps the parent
+;      inc de
+;      exx
+;      ld hl, #0x8000          ; copy the bank
+;      ld de, #0x4000
+;      ld bc, #0x4000          ; we copy the whole bank, we could optimise
+;                              ; further
+;      ldir
+;      exx
+;      call map_kernel         ; put the maps back so we can look in p_tab
+; FIXME: can't map_kernel here - we've been playing with the maps, fix
+; directly
+;      suba #1
+;      bne fork_next
+
+;      ld a, c
+;      out (0x13), a           ; our last bank repeats up to common
+       ; --- we are now on the stack copy, parent stack is locked away ---
+;      rts                     ; this stack is copied so safe to return on
+
+       
diff --git a/Kernel/platform-6809test/Makefile b/Kernel/platform-6809test/Makefile
new file mode 100644 (file)
index 0000000..3f75014
--- /dev/null
@@ -0,0 +1,32 @@
+
+CSRCS = devlpr.c devtty.c devrd.c
+CSRCS += devices.c main.c libc.c
+
+ASRCS = p6809.s crt0.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.s=$(BINEXT))
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.o) $(ASRCS:.s=.o)
+
+all:   $(OBJS)
+
+$(COBJS): %$(BINEXT): %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %$(BINEXT): %.s
+       $(CROSS_AS) $(ASOPTS) $< -o $*$(BINEXT)
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
+       $(CROSS_LD) -o uzi.bin --map uzi.map -nostdlib crt0.o commonmem.o \
+       p6809.o ../start.o ../version.o ../lowlevel-6809.o \
+       tricks.o main.o ../timer.o ../kdata.o devrd.o devices.o \
+       ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+       ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o ../bank16k.o \
+       ../tty.o ../devnull.o ../devzero.o ../devproc.o ../devmem.o \
+       ../usermem_std-6809.o devlpr.o devtty.o libc.o
diff --git a/Kernel/platform-6809test/commonmem.s b/Kernel/platform-6809test/commonmem.s
new file mode 100644 (file)
index 0000000..83ffb65
--- /dev/null
@@ -0,0 +1,27 @@
+;
+;      Put the udata at the start of common. We have four 16K banks so we
+; keep the non .common kernel elements below C000 and then keep bank 3 as a
+; true common bank
+;
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _COMMONMEM
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+       zmb 512
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+       zmb 254
+istack_top:
+istack_switched_sp: .dw 0
diff --git a/Kernel/platform-6809test/config.h b/Kernel/platform-6809test/config.h
new file mode 100644 (file)
index 0000000..2d80c09
--- /dev/null
@@ -0,0 +1,55 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+/* Use C helpers for usermem */
+#define CONFIG_USERMEM_C
+#define BANK_PROCESS   *((volatile uint8_t *)0xff91) &= ~1
+#define BANK_KERNEL    *((volatile uint8_t *)0xff91) |= 1
+/* We use flexible 16K banks so use the helper */
+#define CONFIG_BANK16
+#define MAX_MAPS 16
+/* And swapping */
+#define SWAPDEV 6      /* FIXME */
+#define SWAP_SIZE   0x80       /* 64K blocks */
+/* FIXME */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0xF000      /* vectors so its a round number of sectors */
+#define UDATA_BLOCKS   0       /* We swap the uarea in the data */
+#define UDATA_SWAPSIZE 0
+#define MAX_SWAPS      32
+
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* We want the 8x8 font */
+#define CONFIG_FONT_8X8
+/* Vt definitions */
+#define VT_WIDTH       64
+#define VT_HEIGHT      24
+#define VT_RIGHT       63
+#define VT_BOTTOM      23
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xF000))  /* Top of program, base of U_DATA */
+
+#define BOOT_TTY 3        /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+                            /* Temp FIXME set to serial port for debug ease */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+#define NDEVS    1        /* Devices 0..NDEVS-1 are capable of being mounted */
+                          /*  (add new mountable devices to beginning area.) */
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         1        /* Number of mounts at a time - nothing mountable! */
diff --git a/Kernel/platform-6809test/crt0.s b/Kernel/platform-6809test/crt0.s
new file mode 100644 (file)
index 0000000..8125100
--- /dev/null
@@ -0,0 +1,44 @@
+               ; Ordering of segments for the linker.
+               ; WRS: Note we list all our segments here, even though
+               ; we don't use them all, because their ordering is set
+               ; when they are first seen.     
+
+               ; imported symbols
+               .globl _fuzix_main
+               .globl init_early
+               .globl init_hardware
+               .globl kstack_top
+
+               ; startup code @0
+               .area .text
+
+start:         orcc #0x10              ; interrupts definitely off
+               lds #kstack_top
+               ; move the common memory where it belongs    
+               ; we do this dowards, not out of any concern about
+               ; about overlap (although its correct for this) but because
+               ; it deals with linker reloc limits nicely
+;              ldd #s__INITIALIZER
+;              addd #l__COMMONMEM
+;              tfr d,x
+;              ldd #s__COMMONMEM
+;              addd #l__COMMONMEM
+;              tfr d,y
+               
+;copier:               lda ,-x
+;              sta ,-y
+;              cmpy #s__COMMONMEM
+;              bgt copier
+
+;wiper:                ldx #s__DATA
+;              ldd #l__DATA
+;              clr ,x+
+;              subd #1
+;              bne wiper
+
+               jsr init_early
+               jsr init_hardware
+               jsr _fuzix_main
+               orcc #0x10
+stop:          bra stop
+
diff --git a/Kernel/platform-6809test/device.h b/Kernel/platform-6809test/device.h
new file mode 100644 (file)
index 0000000..6f4c1e2
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern void mod_control(uint8_t set, uint8_t clr);
+
+#endif /* __DEVICE_DOT_H__ */
diff --git a/Kernel/platform-6809test/devices.c b/Kernel/platform-6809test/devices.c
new file mode 100644 (file)
index 0000000..4f9e16b
--- /dev/null
@@ -0,0 +1,43 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devrd.h>
+#include <devmem.h>
+#include <devzero.h>
+#include <devnull.h>
+#include <devproc.h>
+#include <devlpr.h>
+#include <tty.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* Memory disk block devices  */
+  {  0,  rd_open,     no_close,    rd_read,   rd_write,   no_ioctl },   //   0   /dev/rd0
+
+  /* devices below here are not mountable (as per NDEVS) */
+  {  0, lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },  //  1   /dev/lp  
+  {  0, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  2   /dev/tty
+  {  1, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  3   /dev/tty1
+  {  2, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  4   /dev/tty2
+  {  0, no_open,      no_close,    null_read, null_write, no_ioctl  },  //  5   /dev/null
+  {  0, no_open,      no_close,    zero_read, no_rdwr,    no_ioctl  },  //  6   /dev/zero
+  {  0, no_open,      no_close,    mem_read,  mem_write,  no_ioctl  },  //  7   /dev/kmem
+  {  0, no_open,      no_close,    proc_read, no_rdwr, proc_ioctl}      //  8  /dev/proc
+  /* Add more tty channels here if available, incrementing minor# */
+};
+
+bool validdev(uint8_t dev)
+{
+    if(dev >= (sizeof(dev_tab)/sizeof(struct devsw)))
+        return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+}
+
diff --git a/Kernel/platform-6809test/devlpr.c b/Kernel/platform-6809test/devlpr.c
new file mode 100644 (file)
index 0000000..a011085
--- /dev/null
@@ -0,0 +1,54 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <device.h>
+#include <devlpr.h>
+
+/* random test places */
+uint8_t *lpstat = (uint8_t *)0xFF00;
+uint8_t *lpdata = (uint8_t *)0xFF01;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+       minor;
+       flag;                   // shut up compiler
+       return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+       minor;                  // shut up compiler
+       return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       int c = udata.u_count;
+       char *p = udata.u_base;
+       uint16_t ct;
+
+       minor;
+       rawflag;
+       flag;                   // shut up compiler
+
+       while (c-- > 0) {
+               ct = 0;
+
+               /* Try and balance polling and sleeping */
+               while (*lpstat & 2) {
+                       ct++;
+                       if (ct == 10000) {
+                               udata.u_ptab->p_timeout = 3;
+                               if (psleep_flags(NULL, flag)) {
+                                       if (udata.u_count)
+                                               udata.u_error = 0;
+                                       return udata.u_count;
+                               }
+                               ct = 0;
+                       }
+               }
+               /* Data */
+               *lpdata = ugetc(p++);
+       }
+       return udata.u_count;
+}
diff --git a/Kernel/platform-6809test/devlpr.h b/Kernel/platform-6809test/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-6809test/devrd.c b/Kernel/platform-6809test/devrd.c
new file mode 100644 (file)
index 0000000..d71fe08
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+ * NC100 RD PCMCIA driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devrd.h>
+
+static int rd_transfer(bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;
+    uint16_t dptr;
+    int dlen;
+    int ct = 0;
+    int map;
+
+    /* FIXME: raw is broken unless nicely aligned */
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        if (dptr & 0x1FF) {
+            udata.u_error = EIO;
+            return -1;
+        }
+        block = udata.u_offset.o_blkno;
+        block_xfer = dlen >> 9;
+        map = 1;
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 1;
+        map = 0;
+    }
+    block += 2*320;    /* ramdisc starts at 320K in */
+        
+    while (ct < block_xfer) {
+/*        rd_memcpy(is_read, map, dptr, block); */
+        block++;
+        ct++;
+    }
+    return ct;
+}
+
+int rd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor != 0) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(true, rawflag);
+}
+
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(false, rawflag);
+}
+
diff --git a/Kernel/platform-6809test/devrd.h b/Kernel/platform-6809test/devrd.h
new file mode 100644 (file)
index 0000000..6320b26
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __DEVRD_DOT_H__
+#define __DEVRD_DOT_H__
+
+/* public interface */
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_open(uint8_t minor, uint16_t flag);
+
+/* asm banking helper */
+void rd_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block);
+
+#endif /* __DEVRD_DOT_H__ */
+
diff --git a/Kernel/platform-6809test/devtty.c b/Kernel/platform-6809test/devtty.c
new file mode 100644 (file)
index 0000000..2b8b486
--- /dev/null
@@ -0,0 +1,65 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <vt.h>
+#include <tty.h>
+
+#undef  DEBUG                  /* UNdefine to delete debug code sequences */
+
+uint8_t *uarta = (uint8_t *)0xFF04;
+uint8_t *uartb = (uint8_t *)0xFF05;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     /* ttyinq[0] is never used */
+       {NULL, NULL, NULL, 0, 0, 0},
+       {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}
+};
+
+static void nap(void)
+{
+}
+
+/* tty1 is the screen tty2 is the serial port */
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+bool tty_writeready(uint8_t minor)
+{
+       uint8_t c;
+       if (minor == 1)
+               return 1;
+       c = *uartb;
+       return c & 1;
+}
+
+void tty_putc(uint8_t minor, char c)
+{
+       minor;
+#if 0
+       if (minor == 1) {
+               vtoutput(&c, 1);
+               return;
+       }
+#endif 
+       *uarta = c;
+}
+
+void platform_interrupt(void)
+{
+       timer_interrupt();
+}
+
+/* This is used by the vt asm code, but needs to live at the top of the kernel */
+uint16_t cursorpos;
diff --git a/Kernel/platform-6809test/devtty.h b/Kernel/platform-6809test/devtty.h
new file mode 100644 (file)
index 0000000..948cc29
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+extern int nc100_tty_open(uint8_t minor, uint16_t flag);
+extern int nc100_tty_close(uint8_t minor);
+extern void nc100_tty_init(void);
+#endif
diff --git a/Kernel/platform-6809test/kernel.def b/Kernel/platform-6809test/kernel.def
new file mode 100644 (file)
index 0000000..39b9a0e
--- /dev/null
@@ -0,0 +1,5 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      equ 0xF000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           equ 0x300        ; 256+256+256 bytes.
+
diff --git a/Kernel/platform-6809test/libc.c b/Kernel/platform-6809test/libc.c
new file mode 100644 (file)
index 0000000..8b3940b
--- /dev/null
@@ -0,0 +1,34 @@
+#include "cpu.h"
+
+void *memcpy(void *d, void *s, size_t sz)
+{
+  unsigned char *dp, *sp;
+  while(sz--)
+    *dp++=*sp++;
+  return d;
+}
+
+void *memset(void *d, int c, size_t sz)
+{
+  unsigned char *p = d;
+  while(sz--)
+    *p++ = c;
+  return d;
+}
+
+size_t strlen(const char *p)
+{
+  const char *e = p;
+  while(*e++);
+  return e-p-1;
+}
+
+/* Until we pull out the bits of libgcc that are useful instead */
+void abort(void)
+{
+}
+
+void *malloc(size_t size)
+{
+  return 0;
+}
\ No newline at end of file
diff --git a/Kernel/platform-6809test/main.c b/Kernel/platform-6809test/main.c
new file mode 100644 (file)
index 0000000..eb35695
--- /dev/null
@@ -0,0 +1,50 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+/* The uarea is already synched to the stash which is written with the
+   process */
+uint8_t *swapout_prepare_uarea(ptptr p)
+{
+  p;
+  return NULL;
+}
+
+/* The switchin code will move the uarea into the process itself, we just
+   need to fix up the u_page pointer */
+uint8_t *swapin_prepare_uarea(ptptr p)
+{
+  p;
+  return NULL;
+}
+
+void platform_idle(void)
+{
+}
+
+void do_beep(void)
+{
+}
+
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set of pages
+ * with the last page repeated to fill any holes.
+ */
+
+void pagemap_init(void)
+{
+    int i;
+    /* 0/1/2 image, 3/4/5 kernel 6-19 apps */
+    /* Don't add page 6 yet - it's the initial common at boot */
+    for (i = 0x80 + 7; i < 0x80 + 20; i++)
+        pagemap_add(i);
+    /*
+     * The kernel boots with 0x86 as the common, list it last here so it also
+     * gets given to init as the kernel kicks off the init stub. init will then
+     * exec preserving this common and all forks will be copies from it.
+     */
+    pagemap_add(0x86);
+}
+
diff --git a/Kernel/platform-6809test/p6809.s b/Kernel/platform-6809test/p6809.s
new file mode 100644 (file)
index 0000000..9f485a0
--- /dev/null
@@ -0,0 +1,223 @@
+;
+;          6809 Simulation Platform 
+;
+
+            .module p6809
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl interrupt_handler
+            .globl _program_vectors
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+           .globl _di
+           .globl _ei
+           .globl _irqrestore
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+            .globl unix_syscall_entry
+           .globl nmi_handler
+
+            include "kernel.def"
+            include "../kernel09.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+trapmsg:    .ascii "Trapdoor: SP="
+            .db 0
+trapmsg2:   .ascii ", PC="
+            .db 0
+tm_user_sp: .dw 0
+
+_trap_monitor:
+           orcc #0x10
+           bra _trap_monitor
+
+_trap_reboot:
+           lda 0xff90
+           anda #0xfc          ; map in the ROM
+           jmp 0
+
+_di:
+           tfr cc,b            ; return the old irq state
+           orcc #0x10
+           rts
+_ei:
+           andcc #0xef
+           rts
+
+_irqrestore:                   ; B holds the data
+           tfr b,cc
+           rts
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area .text
+
+init_early:
+            rts
+
+init_hardware:
+            ; set system RAM size
+           ldd #256
+           std _ramsize
+           ldd #192
+           std _procmem
+
+           ; Our vectors are in high memory unlike Z80 but we still
+           ; need vectors
+           ldx #0
+            jsr _program_vectors
+
+            rts
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+_program_vectors:
+           ;
+           ; Note: we must install an NMI handler on the NC100 FIXME
+           ;
+
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            orcc #0x10         ; di just to be sure
+
+           jsr map_process
+
+           ldx #0xFFF2
+           ldd #badswi_handler
+           std ,y++
+           std ,y++                    ; SWI2 and 3 both bad SWI
+           ldd #firq_handler
+           std ,y++
+            ldd #interrupt_handler
+           std ,y++
+            ldd #unix_syscall_entry
+           stx ,y++
+           ldd #nmi_handler
+           stx ,y
+           jsr map_kernel
+           rts
+
+;
+;      FIXME:
+;
+firq_handler:
+badswi_handler:
+           rti
+
+;
+;      Userspace mapping pages 7+  kernel mapping pages 3-5, first common 6
+;
+;
+;      All registers preserved
+;
+map_process_always:
+           pshs y,u
+           ldx #U_DATA__U_PAGE
+           jsr map_process_2
+           puls y,u,pc
+;
+;      HL is the page table to use, A is eaten, HL is eaten
+;
+map_process:
+           cmpx #0
+           bne map_process_2
+;
+;      Map in the kernel below the current common, all registers preserved
+;
+map_kernel:
+;
+;      Two MMU mappings is pure luxury
+;
+;      Kernel map was set up by boot loader, just flip to it
+;
+           lda 0xff91                  ; INIT1, use 0xFFA8 maps
+           ora #0x01
+           sta 0xff91
+           rts
+;
+;      User is in the FFA0 map with the top 8K as common
+;
+;      As the core code currently does 16K happily but not 8 we just pair
+;      up pages
+;
+map_process_2:
+           pshs x,y,a
+           ldy #0xffa0                 ; MMU user map. We can fiddle with
+           lda ,x+                     ; this to our hearts content
+           sta ,y+                     ; as it's not live yet
+           inca
+           sta ,y+
+           lda ,x+
+           sta ,y+
+           inca
+           sta ,y+
+           lda ,x+
+           sta ,y+
+           inca
+           sta ,y+
+           lda ,x+
+           sta ,y+
+           inca        
+           sta ,y
+           lda 0xff91
+           anda #0xfe
+           sta 0xff91                  ; new mapping goes live here
+           puls x,y,a,pc               ; so had better include common!
+;
+;      Restore a saved mapping. We are guaranteed that we won't switch
+;      common copy between save and restore. Preserve all registers
+;
+;      We cheat somewhat. We have two mapping sets, so just remember
+;      which space we were in. Note: we could be in kernel in either
+;      space while doing user copies
+;
+map_restore:
+           pshs a
+           lda 0xff91
+           ora saved_map
+           sta 0xff91
+           puls a,pc
+           
+;
+;      Save the current mapping.
+;
+map_save:
+           pshs a
+           lda 0xff91
+           anda #1
+           sta saved_map
+           puls a,pc
+
+saved_map:  .db 0
+           
+
+; outchar: Wait for UART TX idle, then print the char in a
+
+outchar:
+           pshs b
+outcharw:
+           ldb 0xffa0
+           bitb #0x02
+           beq outcharw
+           sta 0xffa1
+           puls b,pc
diff --git a/Kernel/platform-6809test/tricks.s b/Kernel/platform-6809test/tricks.s
new file mode 100644 (file)
index 0000000..3fb76a3
--- /dev/null
@@ -0,0 +1,201 @@
+;
+;      6809 version
+;
+        .module tricks
+
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _dofork
+       .globl _ramtop
+
+
+        include "kernel.def"
+        include "../kernel09.def"
+
+        .area _COMMONMEM
+
+; ramtop must be in common for single process swapping cases
+; and its a constant for the others from before init forks so it'll be fine
+; here
+_ramtop:
+       .dw 0
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+       orcc #0x10              ; irq off
+        jsr _chksigs
+
+        ; save machine state
+        ldd #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+       pshs d
+       sts U_DATA__U_SP
+
+        ; set inint to false
+       lda #0
+       sta _inint
+
+        ; find another process to run (may select this one again) returns it
+        ; in X
+        jsr _getproc
+        jsr _switchin
+        ; we should never get here
+        jsr _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13
+           .db 10
+           .db 0
+
+; new process pointer is in X
+_switchin:
+        orcc #0x10             ; irq off
+
+       ldy P_TAB__P_PAGE_OFFSET+3,x
+       ; FIXME: can we skip the usermaps here ?
+       stx 0xffa6              ; map the process uarea we want
+       adda #1
+       stx 0xffa7
+       stx 0xffaf              ; and include the kernel mapping
+
+       ; ------- No stack -------
+        ; check u_data->u_ptab matches what we wanted
+       cmpx U_DATA__U_PTAB
+        bne switchinfail
+
+       ; wants optimising up a bit
+       lda #P_RUNNING
+       sta P_TAB__P_STATUS_OFFSET,x
+
+       lda #0
+       sta _runticks
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        lds U_DATA__U_SP
+
+        puls x ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+       lda _inint
+        beq swtchdone ; in ISR, leave interrupts off
+       andcc #0xef
+swtchdone:
+        rts
+
+switchinfail:
+       jsr outx
+        ldx #badswitchmsg
+        jsr outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jmp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        orcc #0x10      ; should already be the case ... belt and braces.
+
+       ; new process in X, get parent pid into y
+
+       stx fork_proc_ptr
+       ldy P_TAB__P_PID_OFFSET,x
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        pshs y ; y  has p->p_pid from above, the return value in the parent
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        sts U_DATA__U_SP
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ; --------- we switch stack copies in this call -----------
+       jsr fork_copy                   ; copy 0x000 to udata.u_top and the
+                                       ; uarea and return on the childs
+                                       ; common
+       ; We are now in the kernel child context
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+       puls y
+
+        ldx fork_proc_ptr
+        jsr _newproc
+
+       ; any calls to map process will now map the childs memory
+
+        ; runticks = 0;
+        clr _runticks
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        rts
+
+fork_copy:
+       ldd U_DATA__U_TOP
+       addd #0x0fff            ; + 0x1000 (-1 for the rounding to follow)
+       lsra            
+       lsra
+       lsra
+       lsra
+       lsra                    ; bits 2/1 for 8K pages
+       anda #6                 ; lose bit 0
+       adda #2                 ; and round up to the next bank (but in 8K terms)
+
+       ldx fork_proc_ptr
+       ldy P_TAB__P_PAGE_OFFSET,x
+       ; y now points to the child page pointers
+       ldx U_DATA__U_PAGE
+       ; and x to the parent
+fork_next:
+;      ld a,(hl)
+;      out (0x11), a           ; 0x4000 map the child
+;      ld c, a
+;      inc hl
+;      ld a, (de)
+;      out (0x12), a           ; 0x8000 maps the parent
+;      inc de
+;      exx
+;      ld hl, #0x8000          ; copy the bank
+;      ld de, #0x4000
+;      ld bc, #0x4000          ; we copy the whole bank, we could optimise
+;                              ; further
+;      ldir
+;      exx
+;      call map_kernel         ; put the maps back so we can look in p_tab
+; FIXME: can't map_kernel here - we've been playing with the maps, fix
+; directly
+       suba #1
+       bne fork_next
+
+;      ld a, c
+;      out (0x13), a           ; our last bank repeats up to common
+       ; --- we are now on the stack copy, parent stack is locked away ---
+       rts                     ; this stack is copied so safe to return on
+
+       
diff --git a/Kernel/platform-micropack/Makefile b/Kernel/platform-micropack/Makefile
new file mode 100644 (file)
index 0000000..2b56907
--- /dev/null
@@ -0,0 +1,25 @@
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = crt0.s z80pack.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
diff --git a/Kernel/platform-micropack/README b/Kernel/platform-micropack/README
new file mode 100644 (file)
index 0000000..2be5760
--- /dev/null
@@ -0,0 +1,8 @@
+A FUZIX target for z80pack.
+
+Test environment for a very squashed build to see what we can achieve in
+64K + disk banking and explore ROM banking ideas
+
+Not a useful target, but memory testing stuff
+
+
diff --git a/Kernel/platform-micropack/bootblock.s b/Kernel/platform-micropack/bootblock.s
new file mode 100644 (file)
index 0000000..46f9302
--- /dev/null
@@ -0,0 +1,80 @@
+;
+;      Z80pack cpmsim loads the first (128 byte) sector from the disk
+;      into memory at 0 then executes it
+;      We are a bit tight on space here
+;
+;      Floppy loader: 
+;      Our boot disc is 77 tracks of 26 x 128 byte sectors, and we put
+;      the OS on tracks 60+, which means we can put a file system in the
+;      usual place providing its a bit smaller than a whole disc.
+;
+;
+;      assemble me with zmac
+;
+               .org    0
+
+start:         jr diskload
+
+rootdev:       .dw 0                   ; patched by hand
+swapdev:       .dw 0                   ; ditto
+               .dw 0                   ; spare
+
+progress:      .db '/', '-', '\\', '|'
+
+diskload:      di
+               ld sp, stack
+               ld hl, 0x88
+               exx
+               xor a
+               ld h, a
+               ld b, a
+               out (17), a             ; sector high always 0
+               out (10), a             ; drive always 0
+               ld a, 59                ; start on track 60
+               out (11), a
+               exx
+               ld c, 17                ; number of tracks to load (56Kish)
+load_tracks:   in a, (11)
+               inc a                   ; track
+               out (11), a
+               xor a
+               out (12), a
+               ld b, 26                ; sectors
+load_sectors:  exx
+               ld a, b
+               and 3
+               add progress
+               ld l, a
+               ld a, (hl)
+               out (01), a
+               ld a, 8
+               out (01), a
+               inc b
+               exx
+
+               in a, (12)
+               inc a
+               out (12), a             ; sector
+               ld a, l
+               out (15), a             ; dma low
+               ld a, h
+               out (16), a             ; dma high
+               xor a                   ; read
+               out (13), a             ; go
+               in a, (14)              ; status
+               ld de, 128
+               add hl, de
+               djnz load_sectors       ; 26 sectors = 3328 bytes
+               dec c
+               jr nz, load_tracks
+               ld a, 0xc9              ; to help debug
+               ld (start), a
+               ld a, 13
+               out (1), a
+               ld a, 10
+               out (1), a
+               jp 0x88
+
+               .ds 25
+stack:
+               .db 0xff
\ No newline at end of file
diff --git a/Kernel/platform-micropack/commonmem.s b/Kernel/platform-micropack/commonmem.s
new file mode 100644 (file)
index 0000000..82d17cb
--- /dev/null
@@ -0,0 +1,47 @@
+;
+;      Uarea is not in common on pure swap
+;
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _UDATA
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
diff --git a/Kernel/platform-micropack/config.h b/Kernel/platform-micropack/config.h
new file mode 100644 (file)
index 0000000..614d0a2
--- /dev/null
@@ -0,0 +1,47 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#undef CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+/* Fixed banking */
+#undef CONFIG_BANK_FIXED
+/* Swap only */
+#define CONFIG_SWAP_ONLY
+/* Simple user copies */
+#define CONFIG_USERMEM_C
+#define BANK_KERNEL
+#define BANK_PROCESS
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   1
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0x7D00))  /* Top of program, base of U_DATA */
+#define PROC_SIZE   32           /* Memory needed per process */
+
+#define SWAP_SIZE   0x40       /* 32K in blocks (we actually don't need the low 256) */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0x8000      /* vectors so its a round number of sectors */
+#define MAX_SWAPS      64      /* The full drive would actually be 170! */
+
+#define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  (256 + 1)  /* Device for swapping. (z80pack drive J) */
+#define NBUFS    6        /* Number of block buffers */
+#define NMOUNTS         2        /* Number of mounts at a time */
diff --git a/Kernel/platform-micropack/crt0.s b/Kernel/platform-micropack/crt0.s
new file mode 100644 (file)
index 0000000..30dccdb
--- /dev/null
@@ -0,0 +1,64 @@
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        ; WRS: Note we list all our segments here, even though
+        ; we don't use them all, because their ordering is set
+        ; when they are first seen.
+        .area _CODE
+        .area _CODE2
+        .area _CONST
+        .area _DATA
+        .area _INITIALIZED
+        .area _COMMONMEM
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        ; note that areas below here may be overwritten by the heap at runtime, so
+        ; put initialisation stuff in here
+        .area _INITIALIZER
+        .area _GSINIT
+        .area _GSFINAL
+
+       .area _DISCARD
+       .area _UDATA
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .globl init_hardware
+        .globl s__INITIALIZER
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+        .globl s__DATA
+        .globl l__DATA
+        .globl kstack_top
+
+        ; startup code
+        .area _CODE
+init:
+        di
+        ld sp, #kstack_top
+
+        ; Configure memory map
+        call init_early
+
+       ; zero the data area
+       ld hl, #s__DATA
+       ld de, #s__DATA + 1
+       ld bc, #l__DATA - 1
+       ld (hl), #0
+       ldir
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
diff --git a/Kernel/platform-micropack/devfd.c b/Kernel/platform-micropack/devfd.c
new file mode 100644 (file)
index 0000000..ae34af5
--- /dev/null
@@ -0,0 +1,149 @@
+/* 
+ * z80pack fd driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+__sfr __at 10 fd_drive;
+__sfr __at 11 fd_track;
+__sfr __at 12 fd_sectorl;
+__sfr __at 13 fd_cmd;
+__sfr __at 14 fd_status;
+__sfr __at 15 fd_dmal;
+__sfr __at 16 fd_dmah;
+__sfr __at 17 fd_sectorh;
+
+/* floppies. 26 128 byte sectors, not a nice way to use all of them in 512's */
+static int sectrack[16] = {
+    26, 26, 26, 26,
+    0, 0, 0, 0,
+    128, 128, 0, 0,
+    0, 0, 0, 0
+};
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor, rawflag);
+}
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor + 8, rawflag);
+}
+
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor + 8, rawflag);
+}
+
+/* We will wrap on big disks if we ever try and support the Z80Pack P:
+   that wants different logic */
+static void fd_geom(int minor, blkno_t block)
+{
+    /* Turn block int track/sector 
+       and write to the controller.
+       Forced to do real / and % */
+    int track = block / sectrack[minor];
+    int sector = block % sectrack[minor] + 1;
+    fd_sectorl = sector & 0xFF;
+    fd_sectorh = sector >> 8;
+    fd_track = track;
+}
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t block_xfer;     /* blocks to transfer */
+    uint16_t dptr;
+    uint16_t dlen;
+    uint16_t ct = 0;
+    uint8_t st;
+    int map = 0;
+    uint16_t *page = &udata.u_page;
+
+    if(rawflag == 1) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        block = udata.u_offset >> BLKSHIFT;
+        block_xfer = dlen >> 7;                /* We want this in 128 byte sectors */
+        map = 1;
+    } else if (rawflag == 2) {         /* Swap device special */
+        dlen = swapcnt;
+        dptr = (uint16_t)swapbase;
+        page = &swapproc->p_page;      /* Acting on this task */
+        block = swapblk;
+        block_xfer = dlen >> 7;                /* We want this in 128 byte sectors */
+        map = 1;
+        /*
+         *     In the z80pack case this is simpler than usual. Be very
+         *     careful how you implement the swap device. On most platforms
+         *     we have user space in part of the "common" which means you
+         *     must be prepared to switch common segment as well during
+         *     a swap, or to perform mapping games using the banks
+         */
+    } else { /* rawflag == 0 */
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 4;
+    }
+    block <<= 2;
+    /* Read the disk in four sector chunks. FIXME We ought to cache the geometry
+       and just bump sector checking for a wrap. */
+    while (ct < block_xfer) {
+        fd_drive = minor;
+        fd_geom(minor, block);
+        /* The Z80pack DMA uses the current MMU mappings... beware that
+         * is odd - but most hardware would be PIO (inir/otir etc) anyway */
+        fd_dmal = dptr & 0xFF;
+        fd_dmah = dptr >> 8;
+
+        /* No banking problems in swap only mode */
+        fd_cmd = 1 - is_read;
+
+        st = fd_status;
+        /* Real disks would need retries */
+        if (st) {
+            kprintf("fd%d: block %d, error %d\n", minor, st, block);
+            break;
+        }
+        block++;
+        ct++;
+        dptr += 128;
+    }
+    return ct >> 2;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= 8 || !sectrack[minor]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int hd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= 8 || !sectrack[minor + 8]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
diff --git a/Kernel/platform-micropack/devfd.h b/Kernel/platform-micropack/devfd.h
new file mode 100644 (file)
index 0000000..dba1f6c
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_open(uint8_t minor, uint16_t flag);
+
+void fd_bankcmd(uint16_t cmd, uint16_t *bank);
+
+#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-micropack/devices.c b/Kernel/platform-micropack/devices.c
new file mode 100644 (file)
index 0000000..c60640f
--- /dev/null
@@ -0,0 +1,43 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devfd.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* 0: /dev/fd                Floppy disc block devices  */
+  {  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },
+  /* 1: /dev/hd                Hard disc block devices (absent) */
+  {  hd_open,     no_close,    hd_read,   hd_write,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,      no_close,    sys_read, sys_write, sys_ioctl  },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+  int i;
+  /* Add 64 swaps (4MB) to use the entire J drive */
+  for (i = 0; i < MAX_SWAPS; i++)
+    swapmap_add(i);
+}
diff --git a/Kernel/platform-micropack/devlpr.c b/Kernel/platform-micropack/devlpr.c
new file mode 100644 (file)
index 0000000..65d8c43
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat;                /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag; // shut up compiler
+    return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+    minor; // shut up compiler
+    return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    int c = udata.u_count;
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(c) {
+        /* Note; on real hardware it might well be necessary to
+           busy wait a bit just to get acceptable performance */
+        while (lpstat != 0xFF) {
+//            if (psleep_flags(&clocktick, flag))
+//                return -1;
+        }
+        /* FIXME: tidy up ugetc and sysio checks globally */
+        lpdata = ugetc(p++);
+    }
+    return (-1);
+}
diff --git a/Kernel/platform-micropack/devlpr.h b/Kernel/platform-micropack/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-micropack/devtty.c b/Kernel/platform-micropack/devtty.c
new file mode 100644 (file)
index 0000000..13a001c
--- /dev/null
@@ -0,0 +1,90 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+__sfr __at 0 tty1stat;
+__sfr __at 1 tty1data;
+__sfr __at 40 tty2stat;
+__sfr __at 41 tty2data;
+__sfr __at 42 tty3stat;
+__sfr __at 43 tty3data;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+char tbuf3[TTYSIZ];
+
+struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
+    {   NULL,    NULL,    NULL,    0,        0,       0    },
+    {   tbuf1,   tbuf1,   tbuf1,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf2,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf3,   tbuf3,   tbuf3,   TTYSIZ,   0,   TTYSIZ/2 }
+};
+
+/* Write to system console */
+void kputchar(char c)
+{
+    /* handle CRLF */
+    if(c=='\n')
+        tty_putc(1, '\r');
+    tty_putc(1, c);
+}
+
+static bool tty_writeready(uint8_t minor)
+{
+    uint8_t s;
+
+    if (minor == 1)
+        return 1;
+    if (minor == 2)
+        s = tty2stat;
+    else
+        s = tty3stat;
+    return s & 2;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+    if (minor == 1)
+        tty1data = c;
+    else if (minor == 2)
+        tty2data = c;
+    else
+        tty3data = c;
+}
+
+/* Called every timer tick */
+void tty_pollirq(void)
+{
+    unsigned char c;   /* sdcc bug workaround */
+    while(tty1stat) {
+        c = tty1data;
+        tty_inproc(1, c);
+    }
+    while(tty2stat & 1) {
+        c = tty2data;
+        tty_inproc(2, c);
+    }
+    while(tty3stat & 1) {
+        c = tty3data;
+        tty_inproc(3, c);
+    }
+    if (tty2stat & 2)
+        wakeup(&ttydata[2]);
+    if (tty3stat & 2)
+        wakeup(&ttydata[3]);
+}    
+
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
diff --git a/Kernel/platform-micropack/devtty.h b/Kernel/platform-micropack/devtty.h
new file mode 100644 (file)
index 0000000..4638611
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+void tty_putc(uint8_t minor, unsigned char c);
+bool tty_writeready(uint8_t minor);
+void tty_pollirq(void);
+void tty_setup(uint8_t minor);
+#endif
diff --git a/Kernel/platform-micropack/kernel.def b/Kernel/platform-micropack/kernel.def
new file mode 100644 (file)
index 0000000..de8f590
--- /dev/null
@@ -0,0 +1,4 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0x7D00       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
diff --git a/Kernel/platform-micropack/main.c b/Kernel/platform-micropack/main.c
new file mode 100644 (file)
index 0000000..cf1cd2a
--- /dev/null
@@ -0,0 +1,28 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint8_t *ramtop = PROGTOP;
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  /* We don't want an idle poll and IRQ driven tty poll at the same moment */
+  irqflags_t irq = di();
+  tty_pollirq(); 
+  irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+ tty_pollirq();
+ timer_interrupt();
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
diff --git a/Kernel/platform-micropack/tricks.s b/Kernel/platform-micropack/tricks.s
new file mode 100644 (file)
index 0000000..4b50fca
--- /dev/null
@@ -0,0 +1,223 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl _swapper
+       .globl _swapout
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine for now.
+       ;
+       ld sp, #_swapstack
+       push hl
+       ; We will always swap out the current process
+       ld hl, (U_DATA__U_PTAB)
+       push hl
+       call _swapout
+       pop hl
+       pop hl
+       push de
+       call _swapper
+       pop de
+       pop hl
+       ld a, (hl)
+
+not_swapped:        
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld ix, (U_DATA__U_PTAB)
+        ; next_process->p_status = P_RUNNING
+        ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+
+       ; Fix the moved page pointers
+       ; Just do one byte as that is all we use on this platform
+       ld a, P_TAB__P_PAGE_OFFSET(ix)
+       ld (U_DATA__U_PAGE), a
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ld hl, (U_DATA__U_PTAB)
+       push hl
+       call _swapout
+       pop hl
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+;
+;      We can keep a stack in common because we will complete our
+;      use of it before we switch common block. In this case we have
+;      a true common so it's even easier.
+;
+       .ds 128
+_swapstack:
diff --git a/Kernel/platform-micropack/uzi.lnk b/Kernel/platform-micropack/uzi.lnk
new file mode 100644 (file)
index 0000000..6485af5
--- /dev/null
@@ -0,0 +1,36 @@
+-mwxuy
+-i uzi.ihx
+-b _DISCARD=0x5000
+-b _UDATA=0x5D00
+-b _CODE=0x6000
+-k /usr/share/sdcc/lib/z80
+-l z80
+platform-micropack/crt0.rel
+platform-micropack/commonmem.rel
+platform-micropack/z80pack.rel
+platform-micropack/main.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-micropack/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-micropack/devfd.rel
+platform-micropack/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+simple.rel
+swap.rel
+devsys.rel
+platform-micropack/devlpr.rel
+platform-micropack/devtty.rel
+-e
diff --git a/Kernel/platform-micropack/z80pack.s b/Kernel/platform-micropack/z80pack.s
new file mode 100644 (file)
index 0000000..19814b5
--- /dev/null
@@ -0,0 +1,147 @@
+;
+;      Z80Pack hardware support
+;
+;
+;      This goes straight after udata for common. Because of that the first
+;      256 bytes get swapped to and from disk with the uarea (512 byte disk
+;      blocks). This isn't a problem but don't put any variables in here.
+;
+;      If you make this module any shorter, check what follows next
+;
+
+
+            .module z80pack
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl _program_vectors
+            .globl _system_tick_counter
+
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+
+           .globl unix_syscall_entry
+            .globl null_handler
+           .globl nmi_handler
+            .globl interrupt_handler
+
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (not meaningful on swap only)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_trap_monitor:
+           ld a, #128
+           out (29), a
+           ret
+
+_trap_reboot:
+           ld a, #1
+           out (29), a
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #64
+            ld (_ramsize), hl
+            ld hl, #32                 ; 64K for kernel
+            ld (_procmem), hl
+
+           ld a, #1
+           out (27), a                 ; 100Hz timer on
+
+            ; set up interrupt vectors for the kernel
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ; Set vector for jump to NULL
+            ld (0x0000), a   
+            ld hl, #null_handler  ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+           ; our platform has a "true" common area, if it did not we would
+           ; need to copy the "common" code into the common area of the new
+           ; process.
+
+           ; falls through
+
+           ; Map functions are trivial (but will need bank switchers
+           ; elsewhere)
+map_kernel:
+map_process:
+map_process_always:
+map_save:
+map_restore:
+           ret     
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           out (0x01), a
+            ret
diff --git a/Kernel/platform-nc100/Makefile b/Kernel/platform-nc100/Makefile
new file mode 100644 (file)
index 0000000..a5b416b
--- /dev/null
@@ -0,0 +1,26 @@
+
+CSRCS = devlpr.c devtty.c devrd.c
+CSRCS += devices.c main.c
+
+ASRCS = nc100.s crt0.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
+       dd if=bootblock.cim of=../uzi.bin bs=1 seek=256 conv=notrunc
diff --git a/Kernel/platform-nc100/README b/Kernel/platform-nc100/README
new file mode 100644 (file)
index 0000000..2696edb
--- /dev/null
@@ -0,0 +1,53 @@
+Memory map. All off PCMCIA root, 16K arbitrary banks
+
+No CP/M emulation (due to NMI)
+
+0x0000 Vectors
+0x0100  Application
+0xEFFF  Application end
+0xF000  Common, uarea
+0xFFFF Common top  (including video helpers)
+
+Overlaid with
+
+0x0000 Vectors
+0x0100  Bootstrap code
+0x0213 Kernel
+0xBFFF  End of kernel space
+
+Overlaid at times with
+0x4000-0x7FFF video bank (vram used by ROM OS)
+
+NC200 is similar but CP/M should be possible
+
+On the PCMCIA card the layout looks like
+
+0,1,2          Bootblocks, state, kernel
+3,4,5          Running kernel
+6              Initial common (boot and inherited by init)
+8-19           User pages (12 * 16K)
+20-63          Filesystem
+
+
+To add a filesystem to the card image mycard.img do
+
+mkfs myfs 64 1408
+ucp
+
+then
+
+dd if=myfs of=mycard.img bs=16384 seek=20 conv=notrunc
+
+
+TODO
+
+- baud rate/serial mode setting
+- RTC
+- driver for the power status bits
+- lots of testing
+- control doesn't seem to work ???
+- pick codes for the arrow keys
+- NMI/resume
+- NC200 ?
+- this platform would really benefit from vfork 
+
diff --git a/Kernel/platform-nc100/bootblock.s b/Kernel/platform-nc100/bootblock.s
new file mode 100644 (file)
index 0000000..e9d6208
--- /dev/null
@@ -0,0 +1,55 @@
+;
+;      Boot blocks for UZI+ on the NC100
+;
+;
+;      FIXME: we need a valid NMI vector in the low 0x100 at all times
+;
+
+               .org 0x100
+               di
+               ld a, 0x83      ; map the low 16K of the kernel
+               out (0x10), a
+               ld hl, 0xC000   ; copy ourself into the low 16K
+               ld de, 0x0000
+               ld bc, 0x4000
+               ldir
+               ld a, 0x84
+               out (0x11), a
+               ld a, 0x81
+               out (0x12), a
+               ld hl, 0x8000
+               ld de, 0x4000
+               ld bc, 0x4000
+               ldir
+               ld a, 0x85
+               out (0x11), a
+               ld a, 0x82
+               out (0x12), a
+               ld hl, 0x8000
+               ld de, 0x4000
+               ld bc, 0x4000
+               ldir
+               ld a, 0x84      ; map the other 32K of the kernel
+               out (0x11), a
+               ld a, 0x85
+               out (0x12), a
+               ld a, 0x86
+               jp switch       ; get out of the segment that is going to vanish
+switch:                out (0x13), a   ; map the common
+               jp 0x0213       ; into crt0.s
+
+               .org 0x200
+;
+;      We should hide a logo in here ...
+;
+signature:     .db     "NC100PRG"
+padding2:      .db     0,0,0,0,0,0,0,0
+
+;
+;      At this point we are mapped at 0xC000 so this code is running from
+;      0xC210 in truth. Only at the jp to switch do we end up mapped low
+;
+start:         jp 0xC100
+;
+;      Drops into the copy of the image
+;
diff --git a/Kernel/platform-nc100/commonmem.s b/Kernel/platform-nc100/commonmem.s
new file mode 100644 (file)
index 0000000..d3d30a8
--- /dev/null
@@ -0,0 +1,49 @@
+;
+;      Put the udata at the start of common. We have four 16K banks so we
+; keep the non .common kernel elements below C000 and then keep bank 3 as a
+; true common bank
+;
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _COMMONMEM
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
diff --git a/Kernel/platform-nc100/config.h b/Kernel/platform-nc100/config.h
new file mode 100644 (file)
index 0000000..98e9ac0
--- /dev/null
@@ -0,0 +1,45 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* We use flexible 16K banks so use the helper */
+#define CONFIG_BANK16
+#define MAX_MAPS 16
+/* We want the 4x6 font */
+#define CONFIG_FONT_4X6
+
+/* As reported to user space - 4 banks, 16K page size */
+#define CONFIG_BANKS   4
+
+/* Vt definitions */
+#define VT_WIDTH       120
+#define VT_HEIGHT      10
+#define VT_RIGHT       119
+#define VT_BOTTOM      9
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xF000))  /* Top of program, base of U_DATA */
+//#define PROC_SIZE   64         /* Memory needed per process (for now) */
+
+#define BOOT_TTY (512+1)  /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+#define NDEVS    1        /* Devices 0..NDEVS-1 are capable of being mounted */
+                          /*  (add new mountable devices to beginning area.) */
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         1        /* Number of mounts at a time - nothing mountable! */
diff --git a/Kernel/platform-nc100/crt0.s b/Kernel/platform-nc100/crt0.s
new file mode 100644 (file)
index 0000000..6631d93
--- /dev/null
@@ -0,0 +1,66 @@
+               ; Ordering of segments for the linker.
+               ; WRS: Note we list all our segments here, even though
+               ; we don't use them all, because their ordering is set
+               ; when they are first seen.     
+               .area _CODE
+               .area _CODE2
+               .area _CONST
+               .area _DISCARD
+               .area _DATA
+               .area _INITIALIZED
+               .area _BSEG
+               .area _BSS
+               .area _HEAP
+               ; note that areas below here may be overwritten by the heap at runtime, so
+               ; put initialisation stuff in here
+               .area _INITIALIZER
+               .area _GSINIT
+               .area _GSFINAL
+               .area _COMMONMEM
+
+               ; imported symbols
+               .globl _fuzix_main
+               .globl init_early
+               .globl init_hardware
+               .globl s__DATA
+               .globl l__DATA
+               .globl s__COMMONMEM
+               .globl l__COMMONMEM
+               .globl s__INITIALIZER
+               .globl kstack_top
+
+               ; startup code @0
+               .area _CODE
+
+; This area will be covered by the boot block in the boot image and then
+; copid into the runtime one. We reuse the low 0x80 for vectors
+               .ds     #0x213
+;
+; Execution begins with us correctly mapped and at 0x0213
+;
+;
+;
+;      Our copy of the image is entered here with the system mapped at
+; banks 3,4,5,6 (0-2 hold the bootblock and image for rebooting)
+;
+start:         di
+               ld sp, #kstack_top
+               ; move the common memory where it belongs    
+               ld hl, #s__INITIALIZER
+               ld de, #s__COMMONMEM
+               ld bc, #l__COMMONMEM
+               ldir
+               ; then zero the data area
+               ld hl, #s__DATA
+               ld de, #s__DATA + 1
+               ld bc, #l__DATA - 1
+               ld (hl), #0
+               ldir
+
+               call init_early
+               call init_hardware
+               call _fuzix_main
+               di
+stop:          halt
+               jr stop
+
diff --git a/Kernel/platform-nc100/device.h b/Kernel/platform-nc100/device.h
new file mode 100644 (file)
index 0000000..6f4c1e2
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern void mod_control(uint8_t set, uint8_t clr);
+
+#endif /* __DEVICE_DOT_H__ */
diff --git a/Kernel/platform-nc100/devices.c b/Kernel/platform-nc100/devices.c
new file mode 100644 (file)
index 0000000..c82ede5
--- /dev/null
@@ -0,0 +1,49 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devrd.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <tty.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+  /* 0: /dev/fd                Floppy disc block devices (NC200 only) */
+  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  /* 1: /dev/hd                Hard disc block devices (Really PCMCIA) */
+  {  rd_open,     no_close,    rd_read,   rd_write,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  nc100_tty_open,     nc100_tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,      no_close,    sys_read, sys_write, sys_ioctl  },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+  nc100_tty_init();
+}
+
+__sfr __at 0x30 control;
+static uint8_t control_shadow = 0x10;
+
+/* We need to track the state of the control port */
+void mod_control(uint8_t set, uint8_t clr)
+{
+  control_shadow &= ~clr;
+  control_shadow |= set;
+  control = control_shadow;
+}
diff --git a/Kernel/platform-nc100/devlpr.c b/Kernel/platform-nc100/devlpr.c
new file mode 100644 (file)
index 0000000..17fdba4
--- /dev/null
@@ -0,0 +1,56 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <device.h>
+#include <devlpr.h>
+
+__sfr __at 0xa0 lpstat;
+__sfr __at 0x40 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+       minor;
+       flag;                   // shut up compiler
+       return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+       minor;                  // shut up compiler
+       return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       int c = udata.u_count;
+       char *p = udata.u_base;
+       uint16_t ct;
+
+       minor;
+       rawflag;
+       flag;                   // shut up compiler
+
+       while (c-- > 0) {
+               ct = 0;
+
+               /* Try and balance polling and sleeping */
+               while (lpstat & 2) {
+                       ct++;
+                       if (ct == 10000) {
+                               udata.u_ptab->p_timeout = 3;
+                               if (psleep_flags(NULL, flag)) {
+                                       if (udata.u_count)
+                                               udata.u_error = 0;
+                                       return udata.u_count;
+                               }
+                               ct = 0;
+                       }
+               }
+               /* Data */
+               lpdata = ugetc(p++);
+               /* Strobe */
+               mod_control(0, 0x40);
+               mod_control(0x40, 0);
+       }
+       return udata.u_count;
+}
diff --git a/Kernel/platform-nc100/devlpr.h b/Kernel/platform-nc100/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-nc100/devrd.c b/Kernel/platform-nc100/devrd.c
new file mode 100644 (file)
index 0000000..36243a7
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+ * NC100 RD PCMCIA driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devrd.h>
+
+static int rd_transfer(bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;
+    uint16_t dptr;
+    int dlen;
+    int ct = 0;
+    int map;
+
+    /* FIXME: raw is broken unless nicely aligned */
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        if (dptr & 0x1FF) {
+            udata.u_error = EIO;
+            return -1;
+        }
+        block = udata.u_offset >> 9;
+        block_xfer = dlen >> 9;
+        map = 1;
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 1;
+        map = 0;
+    }
+    block += 2*320;    /* ramdisc starts at 320K in */
+        
+    while (ct < block_xfer) {
+        rd_memcpy(is_read, map, dptr, block);
+        block++;
+        ct++;
+    }
+    return ct;
+}
+
+int rd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor != 0) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(true, rawflag);
+}
+
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;minor;
+    return rd_transfer(false, rawflag);
+}
+
diff --git a/Kernel/platform-nc100/devrd.h b/Kernel/platform-nc100/devrd.h
new file mode 100644 (file)
index 0000000..6320b26
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __DEVRD_DOT_H__
+#define __DEVRD_DOT_H__
+
+/* public interface */
+int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int rd_open(uint8_t minor, uint16_t flag);
+
+/* asm banking helper */
+void rd_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block);
+
+#endif /* __DEVRD_DOT_H__ */
+
diff --git a/Kernel/platform-nc100/devtty.c b/Kernel/platform-nc100/devtty.c
new file mode 100644 (file)
index 0000000..292510a
--- /dev/null
@@ -0,0 +1,261 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <vt.h>
+#include <tty.h>
+
+#undef  DEBUG                  /* UNdefine to delete debug code sequences */
+
+__sfr __at 0xC0 uarta;
+__sfr __at 0xC1 uartb;
+
+__sfr __at 0x90 irqmap;
+
+__sfr __at 0xB0 kmap0;
+__sfr __at 0xB1 kmap1;
+__sfr __at 0xB2 kmap2;
+__sfr __at 0xB3 kmap3;
+__sfr __at 0xB4 kmap4;
+__sfr __at 0xB5 kmap5;
+__sfr __at 0xB6 kmap6;
+__sfr __at 0xB7 kmap7;
+__sfr __at 0xB8 kmap8;
+__sfr __at 0xB9 kmap9;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     /* ttyinq[0] is never used */
+       {NULL, NULL, NULL, 0, 0, 0},
+       {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}
+};
+
+static void nap(void)
+{
+}
+
+/* tty1 is the screen tty2 is the serial port */
+
+int nc100_tty_open(uint8_t minor, uint16_t flag)
+{
+       int err;
+       if (!minor)
+               minor = udata.u_ptab->p_tty;
+
+       err = tty_open(minor, flag);
+       if (err)
+               return err;
+       if (minor == 2)
+               mod_control(0, 0x10);   /* turn on the line driver */
+       nap();
+       mod_control(0x06, 0x01);        /* 9600 baud */
+       return (0);
+}
+
+
+int nc100_tty_close(uint8_t minor)
+{
+       tty_close(minor);
+       if (minor == 2)
+               mod_control(0x10, 0);   /* turn off the line driver */
+       return (0);
+}
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+bool tty_writeready(uint8_t minor)
+{
+       uint8_t c;
+       if (minor == 1)
+               return 1;
+       c = uartb;
+       return c & 1;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       minor;
+       if (minor == 1) {
+               vtoutput(&c, 1);
+               return;
+       }
+       uarta = c;
+}
+
+/* Called to set baud rate etc */
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
+
+#define SER_INIT       0x4F    /*  1 stop,no parity,8bit,16x */
+#define SER_RXTX       0x37
+
+void nc100_tty_init(void)
+{
+  /* Reset the 8251 */
+  mod_control(0x00, 0x08);
+  nap();
+  mod_control(0x08, 0x00);
+  nap();
+  uartb = SER_INIT;
+  nap();
+  uartb = SER_RXTX;
+  nap();
+  uarta;
+  uarta;
+}
+
+static uint8_t keymap[10];
+static uint8_t keyin[10];
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+static uint8_t shiftmask[10] = {
+       3, 3, 2, 0, 0, 0, 0, 0x10, 0, 0
+};
+
+static void keyproc(void)
+{
+       int i;
+       uint8_t key;
+
+       for (i = 0; i < 10; i++) {
+               key = keyin[i] ^ keymap[i];
+               if (key) {
+                       int n;
+                       int m = 128;
+                       for (n = 0; n < 8; n++) {
+                               if ((key & m) && (keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown--;
+                               }
+                               if ((key & m) && !(keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown++;
+                                       keybyte = i;
+                                       keybit = n;
+                                       newkey = 1;
+                               }
+                               m >>= 1;
+                       }
+               }
+               keymap[i] = keyin[i];
+       }
+}
+
+static uint8_t keyboard[10][8] = {
+       {0, 0, 0, 10, '?' /*left */ , 0, 0, 0},
+       {0, '5', 0, 0, ' ', 27, 0, 0},
+       {0, 0, 0, 0, '\t', '1', 0, 0},
+       {'d', 's', 0, 'e', 'w', 'q', '2', '3'},
+       {'f', 'r', 0, 'a', 'x', 'z', 0, '4'},
+       {'c', 'g', 'y', 't', 'v', 'b', 0, 0},
+       {'n', 'h', '/', '#', '?' /*right */ , 127, '?' /*down */ , '6'},
+       {'k', 'm', 'u', 0, '?' /*up */ , '\\', '7', '='},
+       {',', 'j', 'i', '\'', '[', ']', '-', '8'},
+       {'.', 'o', 'l', ';', 'p', 8, '9', '0'}
+};
+
+static uint8_t shiftkeyboard[10][8] = {
+       {0, 0, 0, 10, '?' /*left */ , 0, 0, 0},
+       {0, '%', 0, 0, ' ', 3, 0, 0},
+       {0, 0, 0, 0, '\t', '!', 0, 0},
+       {'D', 'S', 0, 'E', 'W', 'Q', '"', '?' /* pound */ },
+       {'F', 'R', 0, 'A', 'X', 'Z', 0, '$'},
+       {'C', 'G', 'Y', 'T', 'V', 'B', 0, 0},
+       {'N', 'H', '?', '~', '?' /*right */ , 127, '?' /*down */ , '^'},
+       {'K', 'M', 'U', 0, '?' /*up */ , '|', '&', '+'},
+       {'<', 'J', 'I', '@', '{', '}', '_', '*'},
+       {'>', 'O', 'L', ':', 'P', 8, '(', ')'}
+};
+
+static uint8_t capslock = 0;
+
+static void keydecode(void)
+{
+       uint8_t c;
+
+       if (keybyte == 2 && keybit == 7) {
+               capslock = 1 - capslock;
+               return;
+       }
+
+       if (keymap[0] & 3)      /* shift */
+               c = shiftkeyboard[keybyte][keybit];
+       else
+               c = keyboard[keybyte][keybit];
+       if (keymap[1] & 2) {    /* control */
+               if (c > 31 && c < 96)
+                       c &= 31;
+       }
+       if (keymap[1] & 1) {    /* function: not yet used */
+               ;
+       }
+//    kprintf("char code %d\n", c);
+       if (keymap[2] & 1) {    /* symbol */
+               ;
+       }
+       if (capslock && c >= 'a' && c <= 'z')
+               c -= 'a' - 'A';
+       if (keymap[7] & 0x10) { /* menu: not yet used */
+               ;
+       }
+       tty_inproc(1, c);
+}
+
+
+void platform_interrupt(void)
+{
+       uint8_t a = irqmap;
+       uint8_t c;
+       if (!(a & 2))
+               wakeup(&ttydata[2]);
+       if (!(a & 1)) {
+               /* work around sdcc bug */
+               c = uarta;
+               tty_inproc(2, c);
+       }
+       if (!(a & 8)) {
+               keyin[0] = kmap0;
+               keyin[1] = kmap1;
+               keyin[2] = kmap2;
+               keyin[3] = kmap3;
+               keyin[4] = kmap4;
+               keyin[5] = kmap5;
+               keyin[6] = kmap6;
+               keyin[7] = kmap7;
+               keyin[8] = kmap8;
+               keyin[9] = kmap9;       /* This resets the scan for 10mS on */
+
+               newkey = 0;
+               keyproc();
+               if (keysdown < 3 && newkey)
+                       keydecode();
+               timer_interrupt();
+       }
+
+       /* clear the mask */
+       irqmap = a;
+}
+
+/* This is used by the vt asm code, but needs to live at the top of the kernel */
+uint16_t cursorpos;
diff --git a/Kernel/platform-nc100/devtty.h b/Kernel/platform-nc100/devtty.h
new file mode 100644 (file)
index 0000000..948cc29
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+extern int nc100_tty_open(uint8_t minor, uint16_t flag);
+extern int nc100_tty_close(uint8_t minor);
+extern void nc100_tty_init(void);
+#endif
diff --git a/Kernel/platform-nc100/kernel.def b/Kernel/platform-nc100/kernel.def
new file mode 100644 (file)
index 0000000..1189bbe
--- /dev/null
@@ -0,0 +1,5 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xF000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
+
diff --git a/Kernel/platform-nc100/main.c b/Kernel/platform-nc100/main.c
new file mode 100644 (file)
index 0000000..cbc4b4e
--- /dev/null
@@ -0,0 +1,40 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+void platform_idle(void)
+{
+    __asm
+    halt
+    __endasm;
+}
+
+void do_beep(void)
+{
+}
+
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set of pages
+ * with the last page repeated to fill any holes.
+ */
+
+void pagemap_init(void)
+{
+    int i;
+    /* 0/1/2 image, 3/4/5 kernel 6-19 apps */
+    /* Don't add page 6 yet - it's the initial common at boot */
+    for (i = 0x80 + 7; i < 0x80 + 20; i++)
+        pagemap_add(i);
+    /*
+     * The kernel boots with 0x86 as the common, list it last here so it also
+     * gets given to init as the kernel kicks off the init stub. init will then
+     * exec preserving this common and all forks will be copies from it.
+     */
+    pagemap_add(0x86);
+}
+
+void map_init(void)
+{
+}
diff --git a/Kernel/platform-nc100/nc100.s b/Kernel/platform-nc100/nc100.s
new file mode 100644 (file)
index 0000000..050610a
--- /dev/null
@@ -0,0 +1,581 @@
+;
+;          NC100 hardware support
+;
+
+            .module nc100
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl interrupt_handler
+            .globl _program_vectors
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+           ; for the PCMCIA disc driver
+           .globl _rd_memcpy
+
+           ; video driver
+           .globl _scroll_up
+           .globl _scroll_down
+           .globl _plot_char
+           .globl _clear_lines
+           .globl _clear_across
+           .globl _cursor_on
+           .globl _cursor_off
+           .globl _cursorpos
+           ; need the font
+           .globl _font4x6
+           .globl _vtinit
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+            .globl _tty_inproc
+            .globl unix_syscall_entry
+            .globl trap_illegal
+           .globl nmi_handler
+           .globl null_handler
+
+            ; debug symbols
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+trapmsg:    .ascii "Trapdoor: SP="
+            .db 0
+trapmsg2:   .ascii ", PC="
+            .db 0
+tm_user_sp: .dw 0
+
+tm_stack:
+            .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+tm_stack_top:
+
+_trap_monitor:
+           di
+           halt
+           jr _trap_monitor
+
+
+_trap_reboot:
+           xor a
+           out (0x70), a
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #256
+            ld (_ramsize), hl
+            ld hl, #(256-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ; 100Hz timer on
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+           ld a, #0x0B                 ; irqs on except for parallel
+           out (0x60), a               ; set up
+           xor a
+           out (0x90), a
+            im 1 ; set CPU interrupt mode
+            in a, (0xB9)
+           call _vtinit                ; init the console video
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+_program_vectors:
+           ;
+           ; Note: we must install an NMI handler on the NC100 FIXME
+           ;
+
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           ; At this point the common block has already been copied
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ld (0x0000), a   
+            ld hl, #null_handler   ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+           jr map_kernel
+
+;
+;      Userspace mapping pages 7+  kernel mapping pages 3-5, first common 6
+;
+;
+;      All registers preserved
+;
+map_process_always:
+           push hl
+           push af
+           ld hl, #U_DATA__U_PAGE
+           call map_process_2
+           pop af
+           pop hl
+           ret
+;
+;      HL is the page table to use, A is eaten, HL is eaten
+;
+map_process:
+           ld a, h
+           or l
+           jr nz, map_process_2
+;
+;      Map in the kernel below the current common, all registers preserved
+;
+map_kernel:
+           push af
+           ; kernel is in banks 3/4/5, common starts at 6 but then gets
+           ; copied into each task
+           ld a, #0x83
+           out (0x10), a
+           inc a
+           out (0x11), a
+           inc a
+           out (0x12), a
+           pop af
+            ret
+map_process_2:
+           ld a, (hl)
+           out (0x10), a
+           inc hl
+           ld a, (hl)
+           out (0x11), a
+           inc hl
+           ld a, (hl)
+           out (0x12), a
+            ret
+;
+;      Restore a saved mapping. We are guaranteed that we won't switch
+;      common copy between save and restore. Preserve all registers
+;
+map_restore:
+           push hl
+           push af
+           ld hl,#map_savearea
+           call map_process_2
+           pop af
+           pop hl
+           ret
+;
+;      Save the current mapping.
+;
+map_save:
+           push hl
+           push af
+           ld hl, #map_savearea
+           in a, (0x10)
+           ld (hl), a
+           inc hl
+           in a, (0x11)
+           ld (hl), a
+           inc hl
+           in a, (0x12)
+           ld (hl), a
+           inc hl
+           in a, (0x13)
+           ld (hl), a
+           pop af
+           pop hl
+           ret
+
+map_savearea:
+           .db 0,0,0,0
+           
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           push af
+outcharw:
+            in a, (0xC1)
+           bit 0, a
+           jr z, outcharw
+           pop af
+           out (0xC0), a
+            ret
+
+;
+; Disk helper
+;
+; FIXME: raw mode only works for aligned cases. Should probably just drop it
+;
+_rd_memcpy:  push ix
+           ld ix, #0
+           add ix, sp
+           ; 4(ix) = is_read, 5(ix) = map, 6-7(ix) = dptr, 8-9(ix) = block
+            ld l, 6(ix)
+           ld h, 7(ix)
+           ld c, 5(ix)
+            ld e, 8(ix)
+            ld d, 9(ix)
+           ld a, c             ; We want 0 or 3 for the bank effect
+            add a
+            add c
+            ld c, a
+           ld a, h
+           and #0xC0           ; bank bits
+           rlca                ; into 0-1
+           rlca
+           add #0x83           ; kernel base
+           cp #0x86            ; common ??
+           jr z, rd_nomod
+           add c
+rd_nomod:   ld c, a            ; C is now the bank code for dptr
+            ld a, h
+            and #0x3F          ; Remove bank bits from H
+            or #0x80            ; Will be at 0x8000
+            ld h, a            ; HL is now ready
+           ; DE is the block, but we need to work out where that block
+           ; lives in terms of 16K chunks
+           sla e               ; e = e * 2 (will be 512 in a bit)
+           rl d                ; this is OK we won't overflow on a 1MB device
+            ld a, e            ; save a copy
+           sla e
+            rl d
+           sla e
+            rl d               ; D now holds the bank
+            push af
+            ld a, d
+           add #0x80
+            di
+            out (0x11), a      ; 0x4000 is now the ramdisc bank
+           pop af
+           and #0x3F           ; Mask bank
+           or #0x40            ; bank is at 0x4000
+           ld d, a             ; e = e * 256 (so now in byte terms)
+            ld e, #0           ; always aligned
+
+           ld a, c
+            out (0x12), a      ; bank 0x8000 is now the user/kernel buffer
+           bit 0, 4(ix)        ; read or write ?
+           jr z, rd_write
+
+           ex de, hl
+           ;
+           ;   All mapped, and then its simple
+           ;
+rd_write:   ld bc, #512
+           ldir
+            call map_kernel    ; map the kernel and return
+           ei
+           pop ix
+            ret            
+
+;
+;      FIXME: should be safe to drop the di/ei on these
+;
+_scroll_up:
+           ld a, i
+           push af
+           di
+           in a, (0x11)
+           push af
+           ld a, #0x43         ; main memory, bank 3 (video etc)
+           out (0x11), a
+           ld hl, #0x7000 + 384
+           ld de, #0x7000
+           ld bc, #0x1000 - 384 - 1
+           ldir
+           jr vtdone
+
+_scroll_down:
+           ld a, i
+           push af
+           di
+           in a, (0x11)
+           push af
+           ld a, #0x43         ; main memory, bank 3 (video etc)
+           out (0x11), a
+           ld hl, #0x7FFF
+           ld de, #0x7FFF - 384
+           ld bc, #0x1000 - 384 - 1
+           lddr
+vtdone:            pop af
+           out (0x11), a
+           pop af
+           ret po
+           ei
+           ret
+
+;
+;      Turn a co-ordinate pair in DE into an address in DE and map the
+; video. Return B = 1 if this is the right hand char of the pair
+; preserves H, L, C
+;
+addr_de:
+           ld a, #0x43
+           out (0x11), a
+
+           ld a, d     ; X
+           and #1
+           ld b, a     ; save the low bit so we know how to write the char
+           ld a, e     ; turn Y into a pixel row
+           add a
+           ld e, a
+           add a
+            add e      ; E * 6 to get E = pixel row
+           sla d       ; we want 2bits shifted into d but only 1 lost
+           srl a       ; multiple by 64 A into DE
+           rr  d       ; roll two bits into D
+           srl a
+           rr  d
+           add #0x70   ; screen start
+           ld  e, d
+           ld  d, a
+           ret
+;
+;      We rely upon the font data ending up above 0x8000. On the current
+; size that should never be a problem.
+;
+_plot_char:
+           pop hl
+           pop de      ; d, e = co-ords
+           pop bc      ; c = char
+           push bc
+           push de
+           push hl
+           ld a, i
+           push af
+           di
+           in a, (0x11)
+           push af
+           call addr_de
+           push de     ; save while we sort the char out
+           ld  a, c
+           ld  h, #0
+           and #0x7f
+           ld l, a
+           add hl, hl  ; x 2
+           push hl
+           add hl, hl  ; x 4
+           pop de
+           add hl, de  ; x 6
+           ld de, #_font4x6
+           add hl, de  ; font base
+           pop de
+
+noneg:     ex de, hl
+                       ; DE is the source, HL is the dest, B is the mask C
+                       ; the char
+           bit 0, b    ; What side are we doing ?
+           jr nz, right
+
+           ld b, #6
+left:      push bc
+           ld a, (de)
+           inc de
+           bit 7, c
+           jr nz, leftright
+           ; left left
+           and #0xf0
+           jr writeit
+leftright:  and #0x0f
+           rlca
+           rlca
+           rlca
+           rlca
+writeit:    ld b, a            ; stash symbol bits
+
+           ld a, (hl)
+           and #0x0f           ; wipe the left
+           or b                ; add our symbol
+           ld (hl), a
+           push de             ; bump HL on by 64
+           ld de, #64
+           add hl, de
+           pop de
+           pop bc              ; recover count and char
+           djnz left
+           jr vtdone
+right:
+           ld b, #6
+rightloop:  push bc
+           ld a, (de)
+           inc de
+           bit 7, c
+           jr nz, rightright
+           ; right left
+           and #0xf0
+           rrca
+           rrca
+           rrca
+           rrca
+           jr writeitr
+rightright: and #0x0f
+writeitr:   ld b, a            ; stash symbol bits
+
+           ld a, (hl)
+           and #0xf0           ; wipe the right
+           or b                ; add our symbol
+           ld (hl), a
+           push de             ; bump HL on by 64
+           ld de, #64
+           add hl, de
+           pop de
+           pop bc              ; recover count and char
+           djnz rightloop
+           jp vtdone
+
+_clear_lines:
+           pop hl
+           pop de              ; E = y, D = count
+           push de
+           push hl
+           ld a, i
+           push af
+           di
+           in a, (0x11)
+           push af
+           ld c, d
+           ld d, #0
+           call addr_de
+           ld a, c             ; lines
+           or a
+           jp z, vtdone
+lines:
+           ld h, d
+           ld l, e
+           ld (hl), #0x0
+           inc de
+           ld bc, #383
+           ldir
+            dec a
+           jr nz, lines
+           jp vtdone
+
+_clear_across:
+           pop hl
+           pop de              ; E = y, D = x
+           pop bc              ; C = count
+           push bc
+           push de
+           push hl
+           ld a, i
+           push af
+           di
+           in a, (0x11)
+           push af
+           call addr_de
+           ex de, hl
+           ld hl, #64
+           bit 0, b            ; half char ?
+           jr z, nohalf
+           push hl
+           ld b, #6
+halfwipe:
+           ld a, (hl)
+           and #0xF0
+           ld (hl), a
+           add hl, de
+           djnz halfwipe
+           pop hl
+           inc hl
+           dec c
+nohalf:            xor a
+           cp c
+           jp z, vtdone
+           ld a, #6
+lwipe2:            push hl
+lwipe:     ld b, c
+           ld (hl), #0
+           inc hl
+           djnz lwipe
+           pop hl
+           add hl, de
+           dec a
+           jr nz, lwipe2
+           jp vtdone
+       
+_cursor_on:
+           pop hl
+           pop de
+           push de
+           push hl
+cursor_do:
+           ld a, i
+           push af
+            di
+           in a, (0x11)
+           push af
+           ld (_cursorpos), de
+           call addr_de
+           ld c, #0xF0
+           bit 0, b
+            jr z, cleft
+           ld c, #0x0f
+cleft:     ex de, hl
+           ld de, #64
+           ld b, #6
+cursorlines:ld a, (hl)
+           xor c
+           ld (hl), a
+           add hl, de
+           djnz cursorlines
+           jp vtdone
+
+_cursor_off:
+           ld de, (_cursorpos)
+           jr cursor_do
+
diff --git a/Kernel/platform-nc100/nc100emu.s b/Kernel/platform-nc100/nc100emu.s
new file mode 100644 (file)
index 0000000..bc0d396
--- /dev/null
@@ -0,0 +1,43 @@
+;
+;      Test booter for the NC100 emulator, just makes testing life easier
+;
+
+               .org 0x0
+;
+;      Switch to the PCMCIA card as if run by FN-x
+;
+               .ds 0x100
+start:         di
+               ld a, 0x43              ; screen RAM
+               out (0x13),a
+               ld sp, stack
+               ld hl, 0xf000
+               ld de, 0xf001
+               ld (hl), 0xAA
+               ld bc, 0xFFF
+               ldir
+               ld a, 0x80              ; PCMCIA first bank
+               out (0x13), a           ; at C000
+;              xor a
+;              out (0x70),a
+               ld a, 0x86              ; pcmcia mem, line driver on, uart on
+               out (0x30), a           ; 9600 baud
+               ld a, 'U'
+               call chout
+               ld a, 'Z'
+               call chout
+               ld a, 'I'
+               call chout
+               jp 0xC210               ; run
+
+chout:         push af
+choutl:                in a, (0xC1)
+               bit 0, a
+               jr z, choutl
+               pop af
+               out (0xC0), a
+               ret
+
+               .ds 64
+stack:
+               
\ No newline at end of file
diff --git a/Kernel/platform-nc100/tricks.s b/Kernel/platform-nc100/tricks.s
new file mode 100644 (file)
index 0000000..6746888
--- /dev/null
@@ -0,0 +1,240 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl map_kernel
+       .globl _ramtop
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; ramtop must be in common for single process swapping cases
+; and its a constant for the others from before init forks so it'll be fine
+; here
+_ramtop:
+       .dw 0
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+        ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common
+       add hl, de              ; process ptr
+       ld a, (hl)
+       out (0x13), a           ; *CAUTION* our stack just left the building
+
+       ; ------- No stack -------
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld hl, #P_TAB__P_STATUS_OFFSET
+       add hl, de
+       ld (hl), #P_RUNNING
+
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+       ; ---- New task stack ----
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ; --------- we switch stack copies in this call -----------
+       call fork_copy                  ; copy 0x000 to udata.u_top and the
+                                       ; uarea and return on the childs
+                                       ; common
+       ; We are now in the kernel child context
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; The child makes its own new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+       ; any calls to map process will now map the childs memory
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+
+fork_copy:
+       ld hl, (U_DATA__U_TOP)
+       ld de, #0x0fff
+       add hl, de              ; + 0x1000 (-1 for the rounding to follow)
+       ld a, h
+       rlca
+       rlca                    ; get just the number of banks in the bottom
+                               ; bits
+       and #3
+       inc a                   ; and round up to the next bank
+       ld b, a
+       ; we need to copy the relevant chunks
+       ld hl, (fork_proc_ptr)
+       ld de, #P_TAB__P_PAGE_OFFSET
+       add hl, de
+       ; hl now points into the child pages
+       ld de, #U_DATA__U_PAGE
+       ; and de is the parent
+fork_next:
+       ld a,(hl)
+       out (0x11), a           ; 0x4000 map the child
+       ld c, a
+       inc hl
+       ld a, (de)
+       out (0x12), a           ; 0x8000 maps the parent
+       inc de
+       exx
+       ld hl, #0x8000          ; copy the bank
+       ld de, #0x4000
+       ld bc, #0x4000          ; we copy the whole bank, we could optimise
+                               ; further
+       ldir
+       exx
+       call map_kernel         ; put the maps back so we can look in p_tab
+       djnz fork_next
+       ld a, c
+       out (0x13), a           ; our last bank repeats up to common
+       ; --- we are now on the stack copy, parent stack is locked away ---
+       ret                     ; this stack is copied so safe to return on
+
+       
diff --git a/Kernel/platform-nc100/uzi.lnk b/Kernel/platform-nc100/uzi.lnk
new file mode 100644 (file)
index 0000000..c71098d
--- /dev/null
@@ -0,0 +1,38 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0
+-b _COMMONMEM=0xF000
+-k /usr/share/sdcc/lib/z80
+-l z80
+platform-nc100/crt0.rel
+platform-nc100/commonmem.rel
+platform-nc100/nc100.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-nc100/tricks.rel
+platform-nc100/main.rel
+timer.rel
+kdata.rel
+platform-nc100/devrd.rel
+platform-nc100/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_fs.rel
+syscall_proc.rel
+syscall_fs2.rel
+syscall_other.rel
+mm.rel
+swap.rel
+bank16k.rel
+tty.rel
+vt.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+platform-nc100/devlpr.rel
+platform-nc100/devtty.rel
+font4x6.rel
+-e
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/765.s b/Kernel/platform-pcw8256/BOOTBLOCK/765.s
new file mode 100644 (file)
index 0000000..91f4571
--- /dev/null
@@ -0,0 +1,302 @@
+FD_ST          .equ    0
+FD_DT          .equ    1
+stack          .equ    0xF400
+fd765_statbuf  .equ    0xF402
+start          .equ    0x0088          ; start of execution once loaded
+
+               .org 0xF000
+
+;
+;      fd765_cyl must not move without updating the uzi startup code for
+;      this platform
+;
+fd765_lead:    db 0, 0, 40, 9, 2, 1, 0x3, 2
+               db 0, 0, 0, 0, 0, 0, 0, 0
+;
+;      The boot rom calls us right here
+;
+fd765_start:   jp fd_go
+
+fontnum:       db 0x38, 0x6c, 0xc6, 0xd6, 0xc6, 0x6c, 0x38, 0x00
+               db 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00
+               db 0x7c, 0xc6, 0x06, 0x1c, 0x30, 0x66, 0xfe, 0x00
+               db 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00
+               db 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00
+               db 0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0xc6, 0x7c, 0x00
+               db 0x38, 0x60, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00
+               db 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00
+               db 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00
+               db 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00
+; fortunately error is only 3 symbols long
+fonte:         db 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00
+fontr:         db 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00
+fonto:         db 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00
+
+digiprint:
+               ld h, 0xF0              ; font high
+               add a, a
+               add a, a
+               add a, a
+               add fontnum % 256       ; and move to align
+               ld l, a
+ldir8:
+fd765_sensep:  ld bc, 8                ; borrow the 8 to save a byte
+               ldir
+               ret
+
+               
+; bc = length, port
+; hl = command buffer
+fd765_sendcmd:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_sendcmd
+               jp m, fd765_intdatain           ; wtf ???
+               outi                            ; transfer command byte
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               jr nz, fd765_sendcmd
+fd765_intdatain:
+               ret                             ; need to indicate an error
+                                               ; somehow on data in error
+fd765_status:
+               ld hl, fd765_statbuf
+fd765_status_1:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_status_1
+               add a, a
+               ret nc                          ; bit 6 was clear, so done
+               ini
+               ex (sp), hl                     ; waste time for the 765
+               ex (sp), hl                     ; to recover
+               ex (sp), hl
+               ex (sp), hl
+               jr fd765_status_1
+
+;
+;      We rely on this exiting with C = FD_DT
+;
+fd765_intwait:
+               ld bc, 1 * 256 + FD_DT          ; send SENSE INTERRUPT STATUS
+               in a, (0xF8)
+               bit 5, a
+               ret z                           ; wait for the 765 int to go off
+               ld hl, fd765_sensep + 1         ; a suitable 0x08 in the code
+               call fd765_sendcmd
+               call fd765_status
+               ld a, (fd765_statbuf)
+               bit 7, a                        ; error
+               jr nz, fd765_intwait
+               bit 6, a                        ; abnormal
+               ret nz
+               ld b, 0x14                      ; give the controller time
+fd765_wait:    ld a, 0xB3
+fd765_wait_1:  ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               dec a
+               jr nz, fd765_wait_1
+               djnz fd765_wait
+               ret
+               
+               
+;              C points at FD_DT
+fd765_xfer_in:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_in            ; bit 7 clear
+               add a
+               jp p, fd765_boot_error          ; bit 5 clear (short data ???)
+               ini                             ; transfer a byte
+               jr nz, fd765_xfer_in            ; next byte
+               dec e
+               jr nz, fd765_xfer_in
+;
+;              Sector transferred
+;
+fd765_xfer_done:ld a, 5
+               out (0xF8), a                   ; terminate flag set
+               ret
+
+fd_go:
+               di
+               ld sp, stack                    ; so we can bank flip
+               ld a, 0x84                      ; map the screen into bank 4/5
+               out (0xf1), a                   ; and put them at 0x4000/0x8000
+               inc a
+               out (0xf2), a
+               ld hl, 0x4000 + 0x5A00          ; base for roller ram
+               ld de, 0x8000                   ; bank 4 offset 0
+               ld b, 32
+roller_fill:   push bc
+               ld b, 8
+               ld c, e
+roller_8
+               ld (hl), c                      ; fill the low 3 bits 0-7
+               inc hl
+               ld (hl), d                      ; rest is bank and offset
+               inc hl
+               inc c
+               djnz roller_8                   ; do a character line
+               push hl
+               ld hl, 360                      ; avoids the shift
+               add hl, de                      ; Move on 720 bytes
+               ex de, hl                       ; back into de
+               pop hl
+               pop bc                          ; do the scan lines
+               djnz roller_fill                ; Next roller char
+               ld hl, 0x4000                   ; patterned screen
+               ld de, 0x2D0                    ; first set of 8 lines
+whitetop:
+               ld (hl), 0xff
+               inc hl
+               dec de
+               ld a, d
+               or e
+               jr nz, whitetop
+               ld de, 0x5A00 / 2 - 0x2D0       ; pairs of bytes
+greyscreen:
+               ld (hl), 0xAA                   ; layout makes this a doddle
+               inc hl
+               ld (hl), 0x55
+               inc hl
+               dec de
+               ld a, d
+               or e
+               jr nz, greyscreen
+               ld a, 0x81
+               out (0xf1), a                   ; put memory back
+               inc a
+               out (0xf2), a
+               ld a, 0xAD                      ; bank 5 offset D
+               out (0xF5), a
+               xor a
+               out (0xF6), a
+               ld a, 0x07
+               out (0xF8), a
+               ld a, 0x40
+               out (0xF7), a
+
+;
+;      9 * 512 byte sectors/track on the boot image. We load 10 tracks
+;
+fd765_boot     
+               ld a, 0x84              ; map display
+               out (0xf2), a
+               ld a, (fd765_cyl)
+               ld de, 0x8000 + 5760 + 352
+               call digiprint
+               ld a, (fd765_sector)
+               call digiprint
+               ld a, 0x82
+               out (0xf2), a           ; back to main memory
+               call fd765_begin
+               jr nz, fd765_boot_error
+;
+;              Sector loaded ok, we use the first 0x80 bytes of the loaded
+;              code to do the progress bar
+;
+               ld h, 0
+               ld a, 0x84
+               out (0xf2), a           ; map in the screen
+               rst 0
+;              nop
+               ld a, 0x82
+               out (0xf2), a           ; map back the loader
+               ld a, (fd765_sector)
+               inc a
+               cp 10
+               jr nc, fd765_nextcyl
+               ld (fd765_sector), a
+               ld (fd765_seclast), a
+               jr fd765_boot
+fd765_nextcyl:
+               ld a, 1
+               ld (fd765_sector), a
+               ld (fd765_seclast), a
+               ld a, (fd765_cyl)
+               inc a
+               cp 11
+               jr nc, fd765_done
+               ld (fd765_cyl), a
+               ld (fd765_cyl2), a
+               jr fd765_boot
+
+; remap display, print Error message
+fd765_boot_error:
+               ld a, 0x84
+               out (0xf2), a
+               ld hl, fonte
+               ld de, 0x8000 + 5760 + 344 + 720
+               call ldir8
+               ld hl, fontr
+               push hl
+               call ldir8
+               pop hl
+               push hl
+               call ldir8
+               ld hl, fonto
+               call ldir8
+               pop hl
+               call ldir8
+               hlt
+               
+
+fd765_done:    jp start                        ; go go go....
+
+fd765_begin:
+;              The ROM did this bit for us!
+;              call fd765_intwait
+;              ld hl, fd765_setup              ; set up drive parameters
+;              ld bc, #(5 * 256 + FD_DT)       ; 5 byte command
+;              call fd765_sendcmd              ; set up the drive
+;              call fd765_status
+
+               ld a, 6                         ; clear terminal count flag
+               out (0xF8), a
+
+               call fd765_intwait
+               ld hl, fd765_seek
+               ld b, 3                         ; C was set by intwait
+               call fd765_sendcmd
+               call fd765_intwait
+               ld b, 9                         ; READ, C was set by intwait
+               ld hl, fd765_read_data
+               call fd765_sendcmd              ; send the READ DATA command
+               ld de, (codebase)
+               ld hl, 512
+               add hl, de
+               ld (codebase), hl               ; move on 512
+               ex de, hl
+               ld e, 2                         ; 512 bytes
+               ld b, 0
+               call fd765_xfer_in              ; copy the data
+               call fd765_status               ; get the status bits
+               ; failed ?
+               ld a, (fd765_statbuf)
+               and 0xCB
+               ret
+
+codebase:      dw 0x0000
+
+fd765_read_data:
+               db 0x66         ; Normal MFM read
+               db 0            ; Drive 0, head 0
+fd765_cyl:     db 0            ; cylinder
+               db 0            ; head
+fd765_sector:  db 2            ; sector
+               db 2            ; 512 bytes
+fd765_seclast: db 2            ; last sector
+               db 0x2A         ; gap length
+               db 0xFF         ; no room for this byte so we overwrite the
+                               ; jp further down 8)
+fd765_sense    db 0x08         ; Sense interrupt
+fd765_seek     db 0x0F
+               db 0
+fd765_cyl2:    db 0
+               ; Checksum
+checksum:      db 0x3f
\ No newline at end of file
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/765.s.old b/Kernel/platform-pcw8256/BOOTBLOCK/765.s.old
new file mode 100644 (file)
index 0000000..9168ce1
--- /dev/null
@@ -0,0 +1,282 @@
+FD_ST          .equ    0
+FD_DT          .equ    1
+stack          .equ    0xF300
+fd765_statbuf  .equ    0xF300
+
+               .org 0xF000
+
+fd765_lead:    db 0, 0, 40, 9, 2, 1, 0x3, 2
+               db 0, 0, 0, 0, 0, 0, 0, 0
+;
+;      The boot rom calls us right here
+;
+fd765_start:   jp fd_go
+
+fontnum:       db 0x38, 0x6c, 0xc6, 0xd6, 0xc6, 0x6c, 0x38, 0x00
+               db 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00
+               db 0x7c, 0xc6, 0x06, 0x1c, 0x30, 0x66, 0xfe, 0x00
+               db 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00
+               db 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00
+               db 0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0xc6, 0x7c, 0x00
+               db 0x38, 0x60, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00
+               db 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00
+               db 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00
+               db 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00
+; fortunately error is only 3 symbols long
+fonte:         db 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00
+fontr:         db 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00
+fonto:         db 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00
+
+printpos:
+               ld a, 0x84              ; map display
+               out (0xf2), a
+               ld a, (fd765_cyl)
+               ld de, 0x8000 + 5760 + 352
+               call digiprint
+               ld a, (fd765_sector)
+               call digiprint
+               ld a, 0x82
+               out (0xf2), a           ; back to main memory
+               ret
+digiprint:
+               ld h, 0xF0              ; font high
+               add a, a
+               add a, a
+               add a, a
+               add fontnum % 256       ; and move to align
+               ld l, a
+ldir8:
+               ld bc, 8
+               ldir
+               ret
+
+               
+; bc = length, port
+; hl = command buffer
+fd765_sendcmd:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_sendcmd
+               jp m, fd765_intdatain           ; wtf ???
+               outi                            ; transfer command byte
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               jr nz, fd765_sendcmd
+               ret
+fd765_intdatain:
+               ret                             ; need to indicate an error
+                                               ; somehow
+
+fd765_status:
+               ld hl, fd765_statbuf
+fd765_status_1:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_status_1
+               ret p                           ; bit 6 was clear, so done
+               ini
+               ex (sp), hl                     ; waste time for the 765
+               ex (sp), hl                     ; to recover
+               ex (sp), hl
+               ex (sp), hl
+               jr fd765_status_1
+
+fd765_intwait:
+               in a, (0xF8)
+               bit 5, a
+               ret z                           ; wait for the 765 int to go off
+               ld hl, fd765_sensep + 1         ; a suitable 0x08 in the code
+               ld bc, 1 * 256 + FD_DT          ; send SENSE INTERRUPT STATUS
+               call fd765_sendcmd
+               call fd765_status
+               ld a, (fd765_statbuf)
+               bit 7, a                        ; error
+               jr nz, fd765_intwait
+               bit 6, a                        ; abnormal
+               ret nz
+               ld b, 0x14                      ; give the controller time
+fd765_wait:    ld a, 0xB3
+fd765_wait_1:  ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               dec a
+               jr nz, fd765_wait_1
+               djnz fd765_wait
+               ret
+               
+               
+;              C points at FD_DT
+fd765_xfer_in:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_in            ; bit 7 clear
+               add a
+               jp p, fd765_boot_error          ; bit 5 clear (short data ???)
+               ini                             ; transfer a byte
+               jr nz, fd765_xfer_in            ; next byte
+               dec e
+               jr nz, fd765_xfer_in
+;
+;              Sector transferred
+;
+fd765_xfer_done:ld a, 5
+               out (0xF8), a                   ; terminate flag set
+               ret
+
+fd_go:
+               di
+               ld sp, stack                    ; so we can bank flip
+               ld a, 0x84                      ; map the screen into bank 4/5
+               out (0xf1), a                   ; and put them at 0x4000/0x8000
+               inc a
+               out (0xf2), a
+               ld hl, 0x4000 + 0x5A00          ; base for roller ram
+               ld de, 0x8000                   ; bank 4 offset 0
+               ld b, 32
+roller_fill:   push bc
+               ld b, 8
+               ld c, e
+roller_8
+               ld (hl), c                      ; fill the low 3 bits 0-7
+               inc hl
+               ld (hl), d                      ; rest is bank and offset
+               inc hl
+               inc c
+               djnz roller_8                   ; do a character line
+               push hl
+               ld hl, 360                      ; avoids the shift
+               add hl, de                      ; Move on 720 bytes
+               ex de, hl                       ; back into de
+               pop hl
+               pop bc                          ; do the scan lines
+               djnz roller_fill                ; Next roller char
+               ld hl, 0x4000                   ; patterned screen
+               ld de, 0x2D0                    ; first set of 8 lines
+whitetop:
+               ld (hl), 0xff
+               inc hl
+               dec de
+               ld a, d
+               or e
+               jr nz, whitetop
+               ld de, 0x5A00 / 2 - 0x2D0       ; pairs of bytes
+greyscreen:
+               ld (hl), 0xAA                   ; layout makes this a doddle
+               inc hl
+               ld (hl), 0x55
+               inc hl
+               dec de
+               ld a, d
+               or e
+               jr nz, greyscreen
+               ld a, 0x81
+               out (0xf1), a                   ; put memory back
+               inc a
+               out (0xf2), a
+               ld a, 0xAD                      ; bank 5 offset D
+               out (0xF5), a
+               xor a
+               out (0xF6), a
+               ld a, 0x07
+               out (0xF8), a
+               ld a, 0x40
+               out (0xF7), a
+
+;
+;      9 * 512 byte sectors/track on the boot image. We load 10 tracks
+;
+fd765_boot     call printpos
+               call fd765_begin
+               jr nz, fd765_boot_error
+               nop
+               nop
+               ld a, (fd765_sector)
+               inc a
+               cp 10
+               jr nc, fd765_nextcyl
+               ld (fd765_sector), a
+               jr fd765_boot
+fd765_nextcyl:
+               ld a, 1
+               ld (fd765_sector), a
+               ld a, (fd765_cyl)
+               inc a
+fd765_sensep:  cp 8                    ; borrowing the 8 to save a byte
+               jr nc, fd765_done
+               ld (fd765_cyl), a
+               jr fd765_boot
+
+; remap display, print Error message
+fd765_boot_error:
+               ld a, 0x84
+               out (0xf2), a
+               ld hl, fonte
+               ld de, 0x8000 + 5760 + 344
+               call ldir8
+               ld hl, fontr
+               push hl
+               call ldir8
+               pop hl
+               push hl
+               call ldir8
+               ld hl, fonto
+               call ldir8
+               pop hl
+               call ldir8
+               hlt
+               
+
+fd765_done:    jp fd765_done
+
+fd765_begin:
+;              The ROM did this bit for us!
+;              call fd765_intwait
+;              ld hl, fd765_setup              ; set up drive parameters
+;              ld bc, #(5 * 256 + FD_DT)       ; 5 byte command
+;              call fd765_sendcmd              ; set up the drive
+;              call fd765_status
+
+               ld a, 6                         ; clear terminal count flag
+               out (0xF8), a
+
+               call fd765_intwait
+               ld hl, fd765_read_data
+               ld bc, 9 * 256 + FD_DT          ; READ
+               call fd765_sendcmd              ; send the READ DATA command
+               ld de, (codebase)
+               ld hl, 512
+               add hl, de
+               ld (codebase), hl               ; move on 512
+               ex de, hl
+               ld e, 2                         ; 512 bytes
+               ld b, 0
+               call fd765_xfer_in              ; copy the data
+               call fd765_status               ; get the status bits
+               ; failed ?
+               ld a, (fd765_statbuf)
+               and 0xCB
+               ret
+
+codebase:      dw 0x0100
+
+fd765_read_data:
+               db 0x66         ; Normal MFM read
+               db 0            ; Drive 0, head 0
+fd765_cyl:     db 0            ; cylinder
+               db 0            ; head
+fd765_sector:  db 1            ; sector
+               db 2            ; 512 bytes
+               db 1            ; sector count
+               db 0x2A         ; gap length
+               db 0xFF
+
+               ; Space (28 bytes free - could move _sector to f010 to make
+               ; it a whopping 37!)
+               db 0,0,0,0,0,0,0,0,0,0
+               db 0,0,0,0,0,0,0,0,0,0
+               db 0,0,0,0,0,0,0,0
+               ; Checksum
+checksum:      db 0x53
\ No newline at end of file
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/765.s~ b/Kernel/platform-pcw8256/BOOTBLOCK/765.s~
new file mode 100644 (file)
index 0000000..2141d44
--- /dev/null
@@ -0,0 +1,302 @@
+FD_ST          .equ    0
+FD_DT          .equ    1
+stack          .equ    0xF400
+fd765_statbuf  .equ    0xF402
+start          .equ    0x0088          ; start of execution once loaded
+
+               .org 0xF000
+
+;
+;      fd765_cyl must not move without updating the uzi startup code for
+;      this platform
+;
+fd765_lead:    db 0, 0, 40, 9, 2, 1, 0x3, 2
+               db 0, 0, 0, 0, 0, 0, 0, 0
+;
+;      The boot rom calls us right here
+;
+fd765_start:   jp fd_go
+
+fontnum:       db 0x38, 0x6c, 0xc6, 0xd6, 0xc6, 0x6c, 0x38, 0x00
+               db 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00
+               db 0x7c, 0xc6, 0x06, 0x1c, 0x30, 0x66, 0xfe, 0x00
+               db 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00
+               db 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00
+               db 0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0xc6, 0x7c, 0x00
+               db 0x38, 0x60, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00
+               db 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00
+               db 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00
+               db 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00
+; fortunately error is only 3 symbols long
+fonte:         db 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00
+fontr:         db 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00
+fonto:         db 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00
+
+digiprint:
+               ld h, 0xF0              ; font high
+               add a, a
+               add a, a
+               add a, a
+               add fontnum % 256       ; and move to align
+               ld l, a
+ldir8:
+fd765_sensep:  ld bc, 8                ; borrow the 8 to save a byte
+               ldir
+               ret
+
+               
+; bc = length, port
+; hl = command buffer
+fd765_sendcmd:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_sendcmd
+               jp m, fd765_intdatain           ; wtf ???
+               outi                            ; transfer command byte
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               jr nz, fd765_sendcmd
+fd765_intdatain:
+               ret                             ; need to indicate an error
+                                               ; somehow on data in error
+fd765_status:
+               ld hl, fd765_statbuf
+fd765_status_1:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_status_1
+               add a, a
+               ret nc                          ; bit 6 was clear, so done
+               ini
+               ex (sp), hl                     ; waste time for the 765
+               ex (sp), hl                     ; to recover
+               ex (sp), hl
+               ex (sp), hl
+               jr fd765_status_1
+
+;
+;      We rely on this exiting with C = FD_DT
+;
+fd765_intwait:
+               ld bc, 1 * 256 + FD_DT          ; send SENSE INTERRUPT STATUS
+               in a, (0xF8)
+               bit 5, a
+               ret z                           ; wait for the 765 int to go off
+               ld hl, fd765_sensep + 1         ; a suitable 0x08 in the code
+               call fd765_sendcmd
+               call fd765_status
+               ld a, (fd765_statbuf)
+               bit 7, a                        ; error
+               jr nz, fd765_intwait
+               bit 6, a                        ; abnormal
+               ret nz
+               ld b, 0x14                      ; give the controller time
+fd765_wait:    ld a, 0xB3
+fd765_wait_1:  ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               dec a
+               jr nz, fd765_wait_1
+               djnz fd765_wait
+               ret
+               
+               
+;              C points at FD_DT
+fd765_xfer_in:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_in            ; bit 7 clear
+               add a
+               jp p, fd765_boot_error          ; bit 5 clear (short data ???)
+               ini                             ; transfer a byte
+               jr nz, fd765_xfer_in            ; next byte
+               dec e
+               jr nz, fd765_xfer_in
+;
+;              Sector transferred
+;
+fd765_xfer_done:ld a, 5
+               out (0xF8), a                   ; terminate flag set
+               ret
+
+fd_go:
+               di
+               ld sp, stack                    ; so we can bank flip
+               ld a, 0x84                      ; map the screen into bank 4/5
+               out (0xf1), a                   ; and put them at 0x4000/0x8000
+               inc a
+               out (0xf2), a
+               ld hl, 0x4000 + 0x5A00          ; base for roller ram
+               ld de, 0x8000                   ; bank 4 offset 0
+               ld b, 32
+roller_fill:   push bc
+               ld b, 8
+               ld c, e
+roller_8
+               ld (hl), c                      ; fill the low 3 bits 0-7
+               inc hl
+               ld (hl), d                      ; rest is bank and offset
+               inc hl
+               inc c
+               djnz roller_8                   ; do a character line
+               push hl
+               ld hl, 360                      ; avoids the shift
+               add hl, de                      ; Move on 720 bytes
+               ex de, hl                       ; back into de
+               pop hl
+               pop bc                          ; do the scan lines
+               djnz roller_fill                ; Next roller char
+               ld hl, 0x4000                   ; patterned screen
+               ld de, 0x2D0                    ; first set of 8 lines
+whitetop:
+               ld (hl), 0xff
+               inc hl
+               dec de
+               ld a, d
+               or e
+               jr nz, whitetop
+               ld de, 0x5A00 / 2 - 0x2D0       ; pairs of bytes
+greyscreen:
+               ld (hl), 0xAA                   ; layout makes this a doddle
+               inc hl
+               ld (hl), 0x55
+               inc hl
+               dec de
+               ld a, d
+               or e
+               jr nz, greyscreen
+               ld a, 0x81
+               out (0xf1), a                   ; put memory back
+               inc a
+               out (0xf2), a
+               ld a, 0xAD                      ; bank 5 offset D
+               out (0xF5), a
+               xor a
+               out (0xF6), a
+               ld a, 0x07
+               out (0xF8), a
+               ld a, 0x40
+               out (0xF7), a
+
+;
+;      9 * 512 byte sectors/track on the boot image. We load 10 tracks
+;
+fd765_boot     
+               ld a, 0x84              ; map display
+               out (0xf2), a
+               ld a, (fd765_cyl)
+               ld de, 0x8000 + 5760 + 352
+               call digiprint
+               ld a, (fd765_sector)
+               call digiprint
+               ld a, 0x82
+               out (0xf2), a           ; back to main memory
+               call fd765_begin
+               jr nz, fd765_boot_error
+;
+;              Sector loaded ok, we use the first 0x80 bytes of the loaded
+;              code to do the progress bar
+;
+               ld h, 0
+               ld a, 0x84
+               out (0xf2), a           ; map in the screen
+               rst 0
+;              nop
+               ld a, 0x82
+               out (0xf2), a           ; map back the loader
+               ld a, (fd765_sector)
+               inc a
+               cp 10
+               jr nc, fd765_nextcyl
+               ld (fd765_sector), a
+               ld (fd765_seclast), a
+               jr fd765_boot
+fd765_nextcyl:
+               ld a, 1
+               ld (fd765_sector), a
+               ld (fd765_seclast), a
+               ld a, (fd765_cyl)
+               inc a
+               cp 10
+               jr nc, fd765_done
+               ld (fd765_cyl), a
+               ld (fd765_cyl2), a
+               jr fd765_boot
+
+; remap display, print Error message
+fd765_boot_error:
+               ld a, 0x84
+               out (0xf2), a
+               ld hl, fonte
+               ld de, 0x8000 + 5760 + 344 + 720
+               call ldir8
+               ld hl, fontr
+               push hl
+               call ldir8
+               pop hl
+               push hl
+               call ldir8
+               ld hl, fonto
+               call ldir8
+               pop hl
+               call ldir8
+               hlt
+               
+
+fd765_done:    jp start                        ; go go go....
+
+fd765_begin:
+;              The ROM did this bit for us!
+;              call fd765_intwait
+;              ld hl, fd765_setup              ; set up drive parameters
+;              ld bc, #(5 * 256 + FD_DT)       ; 5 byte command
+;              call fd765_sendcmd              ; set up the drive
+;              call fd765_status
+
+               ld a, 6                         ; clear terminal count flag
+               out (0xF8), a
+
+               call fd765_intwait
+               ld hl, fd765_seek
+               ld b, 3                         ; C was set by intwait
+               call fd765_sendcmd
+               call fd765_intwait
+               ld b, 9                         ; READ, C was set by intwait
+               ld hl, fd765_read_data
+               call fd765_sendcmd              ; send the READ DATA command
+               ld de, (codebase)
+               ld hl, 512
+               add hl, de
+               ld (codebase), hl               ; move on 512
+               ex de, hl
+               ld e, 2                         ; 512 bytes
+               ld b, 0
+               call fd765_xfer_in              ; copy the data
+               call fd765_status               ; get the status bits
+               ; failed ?
+               ld a, (fd765_statbuf)
+               and 0xCB
+               ret
+
+codebase:      dw 0x0000
+
+fd765_read_data:
+               db 0x66         ; Normal MFM read
+               db 0            ; Drive 0, head 0
+fd765_cyl:     db 0            ; cylinder
+               db 0            ; head
+fd765_sector:  db 2            ; sector
+               db 2            ; 512 bytes
+fd765_seclast: db 2            ; last sector
+               db 0x2A         ; gap length
+               db 0xFF         ; no room for this byte so we overwrite the
+                               ; jp further down 8)
+fd765_sense    db 0x08         ; Sense interrupt
+fd765_seek     db 0x0F
+               db 0
+fd765_cyl2:    db 0
+               ; Checksum
+checksum:      db 0x40
\ No newline at end of file
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/bootcsum b/Kernel/platform-pcw8256/BOOTBLOCK/bootcsum
new file mode 100755 (executable)
index 0000000..af905aa
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/bootcsum differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/bootcsum.c b/Kernel/platform-pcw8256/BOOTBLOCK/bootcsum.c
new file mode 100644 (file)
index 0000000..7f08432
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+int main(int argc, char *argv[])
+{
+  unsigned char buf[512];
+  unsigned char n = 0;
+  int c;
+  
+  if (read(0, buf, 512) != 512) {
+    fprintf(stderr, "Wrong size\n");
+    exit(1);
+  }
+  
+  for (c = 0x0; c < 0x1ff; c++)
+    n+=buf[c];
+  printf("Checksum byte is %02x, should be %02x\n",
+    buf[0x1ff], 0xff-n);
+  return 0;
+}
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/sector2.s b/Kernel/platform-pcw8256/BOOTBLOCK/sector2.s
new file mode 100644 (file)
index 0000000..fffef33
--- /dev/null
@@ -0,0 +1,60 @@
+;
+;      We have 0x88 bytes before the standard UZI start point, everyone
+;      breathe in
+;      On entry h is set to 0 and the top of screen is banked at 0x8000
+;
+track          .equ 0xF1EA
+               .org 0
+
+progress:      ; top bar
+               ; bank then down 14 character lines
+               ; and 
+               ld de, 0x8000+0x2760+312
+               ld a, font0 % 256
+               rst 0x18        ; choline
+               ; progress bar
+               ld de, 0x8000+0x2760+312+720
+               rst 0x18        ; choline
+               ld de, 0x8000+0x2760+312+720+8
+               ld a, (track)
+               inc a
+               ld b, a
+               ld a, fontX
+               rst 0x28        ; nchout
+               ; bottom bar
+               ld de, 0x8000+0x2760+312+2*720
+choline:       rst 0x20        ; chout at 0x18
+               add a,8
+               ld b, 10
+               rst 0x28        ; nchout
+               jr tail
+chout:         ld l, a         ; chout at 0x20
+               ld bc, 8
+               ldir
+               ret
+               nop             ; and nchout at 0x28
+nchout:                push bc
+               rst 0x20
+               pop bc
+               djnz nchout
+tail2:         add a, 8
+               ret
+tail:          rst 0x20
+               jr tail2
+
+font0:         db      0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+font1:         db      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+font2:         db      0x00, 0x00, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+
+font3:         db      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+font4:         db      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+font5:         db      0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+
+fontX:         db      0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00
+
+font6:         db      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00
+font7:         db      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+font8:         db      0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00
+
+               ; Pad to 0x88 bytes
+               db      0,0,0,0,0
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/sector2.s~ b/Kernel/platform-pcw8256/BOOTBLOCK/sector2.s~
new file mode 100644 (file)
index 0000000..268c2aa
--- /dev/null
@@ -0,0 +1,60 @@
+;
+;      We have 0x88 bytes before the standard UZI start point, everyone
+;      breathe in
+;      On entry h is set to 0 and the top of screen is banked at 0x8000
+;
+track          .equ 0xF1EA
+               .org 0
+
+progress:      ; top bar
+               ; bank then down 14 character lines
+               ; and 
+               ld de, 0x8000+0x2760+312
+               ld a, font0 % 256
+               rst 0x18        ; choline
+               ; progress bar
+               ld de, 0x8000+0x2760+312+720
+               rst 0x18        ; choline
+               ld de, 0x8000+0x2760+312+720+8
+               ld a, (track)
+               inc a
+               ld b, a
+               ld a, fontX
+               rst 0x28        ; nchout
+               ; bottom bar
+               ld de, 0x8000+0x2760+312+2*720
+choline:       rst 0x20        ; chout at 0x18
+               add a,8
+               ld b, 10
+               rst 0x28        ; nchout
+               jr tail
+chout:         ld l, a         ; chout at 0x20
+               ld bc, 8
+               ldir
+               ret
+               nop             ; and nchout at 0x28
+nchout:                push bc
+               rst 0x20
+               pop bc
+               djnz nchout
+tail2:         add a, 8
+               ret
+tail:          rst 0x20
+               jr tail2
+
+font0:         db      0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+font1:         db      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+font2:         db      0x00, 0x00, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+
+font3:         db      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+font4:         db      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+font5:         db      0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+
+fontX:         db      0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00
+
+font6:         db      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00
+font7:         db      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+font8:         db      0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00
+
+               ; Pad to 0x88 bytes
+               db      0,0,0,0,0
\ No newline at end of file
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.ams b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.ams
new file mode 100644 (file)
index 0000000..628686e
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.ams differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.bds b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.bds
new file mode 100644 (file)
index 0000000..7ff480b
--- /dev/null
@@ -0,0 +1,588 @@
+binary-debuggable-source
+0000 0000 d 
+0000 0000 s FD_ST              .equ    0
+0000 0000 d 
+0000 0000 s FD_DT              .equ    1
+0000 0000 d 
+0000 0000 s stack              .equ    0xF400
+0000 0000 d 
+0000 0000 s fd765_statbuf      .equ    0xF402
+0000 0000 d 
+0000 0000 s start              .equ    0x0088          ; start of execution once loaded
+0000 0000 s 
+f000 f000 d 
+f000 f000 s            .org 0xF000
+f000 f000 s 
+f000 f000 s ;
+f000 f000 s ;  fd765_cyl must not move without updating the uzi startup code for
+f000 f000 s ;  this platform
+f000 f000 s ;
+f000 f000 d 0000280902010302
+f000 f000 s fd765_lead:        db 0, 0, 40, 9, 2, 1, 0x3, 2
+f008 f008 d 0000000000000000
+f008 f008 s            db 0, 0, 0, 0, 0, 0, 0, 0
+f010 f010 s ;
+f010 f010 s ;  The boot rom calls us right here
+f010 f010 s ;
+f010 f010 d c3eaf0
+f010 f010 s fd765_start:       jp fd_go
+f013 f013 s 
+f013 f013 d 386cc6d6c66c3800
+f013 f013 s fontnum:   db 0x38, 0x6c, 0xc6, 0xd6, 0xc6, 0x6c, 0x38, 0x00
+f01b f01b d 1838181818187e00
+f01b f01b s            db 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00
+f023 f023 d 7cc6061c3066fe00
+f023 f023 s            db 0x7c, 0xc6, 0x06, 0x1c, 0x30, 0x66, 0xfe, 0x00
+f02b f02b d 7cc6063c06c67c00
+f02b f02b s            db 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00
+f033 f033 d 1c3c6cccfe0c1e00
+f033 f033 s            db 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00
+f03b f03b d fec0c0fc06c67c00
+f03b f03b s            db 0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0xc6, 0x7c, 0x00
+f043 f043 d 3860c0fcc6c67c00
+f043 f043 s            db 0x38, 0x60, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00
+f04b f04b d fec60c1830303000
+f04b f04b s            db 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00
+f053 f053 d 7cc6c67cc6c67c00
+f053 f053 s            db 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00
+f05b f05b d 7cc6c67e060c7800
+f05b f05b s            db 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00
+f063 f063 s ; fortunately error is only 3 symbols long
+f063 f063 d fe6268786862fe00
+f063 f063 s fonte:             db 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00
+f06b f06b d 0000dc766060f000
+f06b f06b s fontr:             db 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00
+f073 f073 d 00007cc6c6c67c00
+f073 f073 s fonto:             db 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00
+f07b f07b s 
+f07b f07b d 
+f07b f07b s digiprint:
+f07b f07b d 26f0
+f07b f07b s            ld h, 0xF0              ; font high
+f07d f07d d 87
+f07d f07d s            add a, a
+f07e f07e d 87
+f07e f07e s            add a, a
+f07f f07f d 87
+f07f f07f s            add a, a
+f080 f080 d c613
+f080 f080 s            add fontnum % 256       ; and move to align
+f082 f082 d 6f
+f082 f082 s            ld l, a
+f083 f083 d 
+f083 f083 s ldir8:
+f083 f083 d 010800
+f083 f083 s fd765_sensep:      ld bc, 8                ; borrow the 8 to save a byte
+f086 f086 d edb0
+f086 f086 s            ldir
+f088 f088 d c9
+f088 f088 s            ret
+f089 f089 s 
+f089 f089 s            
+f089 f089 s ; bc = length, port
+f089 f089 s ; hl = command buffer
+f089 f089 d 
+f089 f089 s fd765_sendcmd:
+f089 f089 d db00
+f089 f089 s            in a, (FD_ST)
+f08b f08b d 87
+f08b f08b s            add a, a
+f08c f08c d 30fb
+f08c f08c s            jr nc, fd765_sendcmd
+f08e f08e d fa99f0
+f08e f08e s            jp m, fd765_intdatain           ; wtf ???
+f091 f091 d eda3
+f091 f091 s            outi                            ; transfer command byte
+f093 f093 d e3
+f093 f093 s            ex (sp), hl
+f094 f094 d e3
+f094 f094 s            ex (sp), hl
+f095 f095 d e3
+f095 f095 s            ex (sp), hl
+f096 f096 d e3
+f096 f096 s            ex (sp), hl
+f097 f097 d 20f0
+f097 f097 s            jr nz, fd765_sendcmd
+f099 f099 d 
+f099 f099 s fd765_intdatain:
+f099 f099 d c9
+f099 f099 s            ret                             ; need to indicate an error
+f09a f09a s                                            ; somehow on data in error
+f09a f09a d 
+f09a f09a s fd765_status:
+f09a f09a d 2102f4
+f09a f09a s            ld hl, fd765_statbuf
+f09d f09d d 
+f09d f09d s fd765_status_1:
+f09d f09d d db00
+f09d f09d s            in a, (FD_ST)
+f09f f09f d 87
+f09f f09f s            add a, a
+f0a0 f0a0 d 30fb
+f0a0 f0a0 s            jr nc, fd765_status_1
+f0a2 f0a2 d 87
+f0a2 f0a2 s            add a, a
+f0a3 f0a3 d d0
+f0a3 f0a3 s            ret nc                          ; bit 6 was clear, so done
+f0a4 f0a4 d eda2
+f0a4 f0a4 s            ini
+f0a6 f0a6 d e3
+f0a6 f0a6 s            ex (sp), hl                     ; waste time for the 765
+f0a7 f0a7 d e3
+f0a7 f0a7 s            ex (sp), hl                     ; to recover
+f0a8 f0a8 d e3
+f0a8 f0a8 s            ex (sp), hl
+f0a9 f0a9 d e3
+f0a9 f0a9 s            ex (sp), hl
+f0aa f0aa d 18f1
+f0aa f0aa s            jr fd765_status_1
+f0ac f0ac s 
+f0ac f0ac s ;
+f0ac f0ac s ;  We rely on this exiting with C = FD_DT
+f0ac f0ac s ;
+f0ac f0ac d 
+f0ac f0ac s fd765_intwait:
+f0ac f0ac d 010101
+f0ac f0ac s            ld bc, 1 * 256 + FD_DT          ; send SENSE INTERRUPT STATUS
+f0af f0af d dbf8
+f0af f0af s            in a, (0xF8)
+f0b1 f0b1 d cb6f
+f0b1 f0b1 s            bit 5, a
+f0b3 f0b3 d c8
+f0b3 f0b3 s            ret z                           ; wait for the 765 int to go off
+f0b4 f0b4 d 2184f0
+f0b4 f0b4 s            ld hl, fd765_sensep + 1         ; a suitable 0x08 in the code
+f0b7 f0b7 d cd89f0
+f0b7 f0b7 s            call fd765_sendcmd
+f0ba f0ba d cd9af0
+f0ba f0ba s            call fd765_status
+f0bd f0bd d 3a02f4
+f0bd f0bd s            ld a, (fd765_statbuf)
+f0c0 f0c0 d cb7f
+f0c0 f0c0 s            bit 7, a                        ; error
+f0c2 f0c2 d 20e8
+f0c2 f0c2 s            jr nz, fd765_intwait
+f0c4 f0c4 d cb77
+f0c4 f0c4 s            bit 6, a                        ; abnormal
+f0c6 f0c6 d c0
+f0c6 f0c6 s            ret nz
+f0c7 f0c7 d 0614
+f0c7 f0c7 s            ld b, 0x14                      ; give the controller time
+f0c9 f0c9 d 3eb3
+f0c9 f0c9 s fd765_wait:        ld a, 0xB3
+f0cb f0cb d e3
+f0cb f0cb s fd765_wait_1:      ex (sp), hl
+f0cc f0cc d e3
+f0cc f0cc s            ex (sp), hl
+f0cd f0cd d e3
+f0cd f0cd s            ex (sp), hl
+f0ce f0ce d e3
+f0ce f0ce s            ex (sp), hl
+f0cf f0cf d 3d
+f0cf f0cf s            dec a
+f0d0 f0d0 d 20f9
+f0d0 f0d0 s            jr nz, fd765_wait_1
+f0d2 f0d2 d 10f5
+f0d2 f0d2 s            djnz fd765_wait
+f0d4 f0d4 d c9
+f0d4 f0d4 s            ret
+f0d5 f0d5 s            
+f0d5 f0d5 s            
+f0d5 f0d5 s ;          C points at FD_DT
+f0d5 f0d5 d 
+f0d5 f0d5 s fd765_xfer_in:
+f0d5 f0d5 d db00
+f0d5 f0d5 s            in a, (FD_ST)
+f0d7 f0d7 d 87
+f0d7 f0d7 s            add a
+f0d8 f0d8 d 30fb
+f0d8 f0d8 s            jr nc, fd765_xfer_in            ; bit 7 clear
+f0da f0da d 87
+f0da f0da s            add a
+f0db f0db d f293f1
+f0db f0db s            jp p, fd765_boot_error          ; bit 5 clear (short data ???)
+f0de f0de d eda2
+f0de f0de s            ini                             ; transfer a byte
+f0e0 f0e0 d 20f3
+f0e0 f0e0 s            jr nz, fd765_xfer_in            ; next byte
+f0e2 f0e2 d 1d
+f0e2 f0e2 s            dec e
+f0e3 f0e3 d 20f0
+f0e3 f0e3 s            jr nz, fd765_xfer_in
+f0e5 f0e5 s ;
+f0e5 f0e5 s ;          Sector transferred
+f0e5 f0e5 s ;
+f0e5 f0e5 d 3e05
+f0e5 f0e5 s fd765_xfer_done:ld a, 5
+f0e7 f0e7 d d3f8
+f0e7 f0e7 s            out (0xF8), a                   ; terminate flag set
+f0e9 f0e9 d c9
+f0e9 f0e9 s            ret
+f0ea f0ea s 
+f0ea f0ea d 
+f0ea f0ea s fd_go:
+f0ea f0ea d f3
+f0ea f0ea s            di
+f0eb f0eb d 3100f4
+f0eb f0eb s            ld sp, stack                    ; so we can bank flip
+f0ee f0ee d 3e84
+f0ee f0ee s            ld a, 0x84                      ; map the screen into bank 4/5
+f0f0 f0f0 d d3f1
+f0f0 f0f0 s            out (0xf1), a                   ; and put them at 0x4000/0x8000
+f0f2 f0f2 d 3c
+f0f2 f0f2 s            inc a
+f0f3 f0f3 d d3f2
+f0f3 f0f3 s            out (0xf2), a
+f0f5 f0f5 d 21009a
+f0f5 f0f5 s            ld hl, 0x4000 + 0x5A00          ; base for roller ram
+f0f8 f0f8 d 110080
+f0f8 f0f8 s            ld de, 0x8000                   ; bank 4 offset 0
+f0fb f0fb d 0620
+f0fb f0fb s            ld b, 32
+f0fd f0fd d c5
+f0fd f0fd s roller_fill:       push bc
+f0fe f0fe d 0608
+f0fe f0fe s            ld b, 8
+f100 f100 d 4b
+f100 f100 s            ld c, e
+f101 f101 d 
+f101 f101 s roller_8
+f101 f101 d 71
+f101 f101 s            ld (hl), c                      ; fill the low 3 bits 0-7
+f102 f102 d 23
+f102 f102 s            inc hl
+f103 f103 d 72
+f103 f103 s            ld (hl), d                      ; rest is bank and offset
+f104 f104 d 23
+f104 f104 s            inc hl
+f105 f105 d 0c
+f105 f105 s            inc c
+f106 f106 d 10f9
+f106 f106 s            djnz roller_8                   ; do a character line
+f108 f108 d e5
+f108 f108 s            push hl
+f109 f109 d 216801
+f109 f109 s            ld hl, 360                      ; avoids the shift
+f10c f10c d 19
+f10c f10c s            add hl, de                      ; Move on 720 bytes
+f10d f10d d eb
+f10d f10d s            ex de, hl                       ; back into de
+f10e f10e d e1
+f10e f10e s            pop hl
+f10f f10f d c1
+f10f f10f s            pop bc                          ; do the scan lines
+f110 f110 d 10eb
+f110 f110 s            djnz roller_fill                ; Next roller char
+f112 f112 d 210040
+f112 f112 s            ld hl, 0x4000                   ; patterned screen
+f115 f115 d 11d002
+f115 f115 s            ld de, 0x2D0                    ; first set of 8 lines
+f118 f118 d 
+f118 f118 s whitetop:
+f118 f118 d 36ff
+f118 f118 s            ld (hl), 0xff
+f11a f11a d 23
+f11a f11a s            inc hl
+f11b f11b d 1b
+f11b f11b s            dec de
+f11c f11c d 7a
+f11c f11c s            ld a, d
+f11d f11d d b3
+f11d f11d s            or e
+f11e f11e d 20f8
+f11e f11e s            jr nz, whitetop
+f120 f120 d 11302a
+f120 f120 s            ld de, 0x5A00 / 2 - 0x2D0       ; pairs of bytes
+f123 f123 d 
+f123 f123 s greyscreen:
+f123 f123 d 36aa
+f123 f123 s            ld (hl), 0xAA                   ; layout makes this a doddle
+f125 f125 d 23
+f125 f125 s            inc hl
+f126 f126 d 3655
+f126 f126 s            ld (hl), 0x55
+f128 f128 d 23
+f128 f128 s            inc hl
+f129 f129 d 1b
+f129 f129 s            dec de
+f12a f12a d 7a
+f12a f12a s            ld a, d
+f12b f12b d b3
+f12b f12b s            or e
+f12c f12c d 20f5
+f12c f12c s            jr nz, greyscreen
+f12e f12e d 3e81
+f12e f12e s            ld a, 0x81
+f130 f130 d d3f1
+f130 f130 s            out (0xf1), a                   ; put memory back
+f132 f132 d 3c
+f132 f132 s            inc a
+f133 f133 d d3f2
+f133 f133 s            out (0xf2), a
+f135 f135 d 3ead
+f135 f135 s            ld a, 0xAD                      ; bank 5 offset D
+f137 f137 d d3f5
+f137 f137 s            out (0xF5), a
+f139 f139 d af
+f139 f139 s            xor a
+f13a f13a d d3f6
+f13a f13a s            out (0xF6), a
+f13c f13c d 3e07
+f13c f13c s            ld a, 0x07
+f13e f13e d d3f8
+f13e f13e s            out (0xF8), a
+f140 f140 d 3e40
+f140 f140 s            ld a, 0x40
+f142 f142 d d3f7
+f142 f142 s            out (0xF7), a
+f144 f144 s 
+f144 f144 s ;
+f144 f144 s ;  9 * 512 byte sectors/track on the boot image. We load 10 tracks
+f144 f144 s ;
+f144 f144 d 
+f144 f144 s fd765_boot 
+f144 f144 d 3e84
+f144 f144 s            ld a, 0x84              ; map display
+f146 f146 d d3f2
+f146 f146 s            out (0xf2), a
+f148 f148 d 3af4f1
+f148 f148 s            ld a, (fd765_cyl)
+f14b f14b d 11e097
+f14b f14b s            ld de, 0x8000 + 5760 + 352
+f14e f14e d cd7bf0
+f14e f14e s            call digiprint
+f151 f151 d 3af6f1
+f151 f151 s            ld a, (fd765_sector)
+f154 f154 d cd7bf0
+f154 f154 s            call digiprint
+f157 f157 d 3e82
+f157 f157 s            ld a, 0x82
+f159 f159 d d3f2
+f159 f159 s            out (0xf2), a           ; back to main memory
+f15b f15b d cdbaf1
+f15b f15b s            call fd765_begin
+f15e f15e d 2033
+f15e f15e s            jr nz, fd765_boot_error
+f160 f160 s ;
+f160 f160 s ;          Sector loaded ok, we use the first 0x80 bytes of the loaded
+f160 f160 s ;          code to do the progress bar
+f160 f160 s ;
+f160 f160 d 2600
+f160 f160 s            ld h, 0
+f162 f162 d 3e84
+f162 f162 s            ld a, 0x84
+f164 f164 d d3f2
+f164 f164 s            out (0xf2), a           ; map in the screen
+f166 f166 d c7
+f166 f166 s            rst 0
+f167 f167 s ;          nop
+f167 f167 d 3e82
+f167 f167 s            ld a, 0x82
+f169 f169 d d3f2
+f169 f169 s            out (0xf2), a           ; map back the loader
+f16b f16b d 3af6f1
+f16b f16b s            ld a, (fd765_sector)
+f16e f16e d 3c
+f16e f16e s            inc a
+f16f f16f d fe0a
+f16f f16f s            cp 10
+f171 f171 d 3008
+f171 f171 s            jr nc, fd765_nextcyl
+f173 f173 d 32f6f1
+f173 f173 s            ld (fd765_sector), a
+f176 f176 d 32f8f1
+f176 f176 s            ld (fd765_seclast), a
+f179 f179 d 18c9
+f179 f179 s            jr fd765_boot
+f17b f17b d 
+f17b f17b s fd765_nextcyl:
+f17b f17b d 3e01
+f17b f17b s            ld a, 1
+f17d f17d d 32f6f1
+f17d f17d s            ld (fd765_sector), a
+f180 f180 d 32f8f1
+f180 f180 s            ld (fd765_seclast), a
+f183 f183 d 3af4f1
+f183 f183 s            ld a, (fd765_cyl)
+f186 f186 d 3c
+f186 f186 s            inc a
+f187 f187 d fe0b
+f187 f187 s            cp 11
+f189 f189 d 302c
+f189 f189 s            jr nc, fd765_done
+f18b f18b d 32f4f1
+f18b f18b s            ld (fd765_cyl), a
+f18e f18e d 32fef1
+f18e f18e s            ld (fd765_cyl2), a
+f191 f191 d 18b1
+f191 f191 s            jr fd765_boot
+f193 f193 s 
+f193 f193 s ; remap display, print Error message
+f193 f193 d 
+f193 f193 s fd765_boot_error:
+f193 f193 d 3e84
+f193 f193 s            ld a, 0x84
+f195 f195 d d3f2
+f195 f195 s            out (0xf2), a
+f197 f197 d 2163f0
+f197 f197 s            ld hl, fonte
+f19a f19a d 11a89a
+f19a f19a s            ld de, 0x8000 + 5760 + 344 + 720
+f19d f19d d cd83f0
+f19d f19d s            call ldir8
+f1a0 f1a0 d 216bf0
+f1a0 f1a0 s            ld hl, fontr
+f1a3 f1a3 d e5
+f1a3 f1a3 s            push hl
+f1a4 f1a4 d cd83f0
+f1a4 f1a4 s            call ldir8
+f1a7 f1a7 d e1
+f1a7 f1a7 s            pop hl
+f1a8 f1a8 d e5
+f1a8 f1a8 s            push hl
+f1a9 f1a9 d cd83f0
+f1a9 f1a9 s            call ldir8
+f1ac f1ac d 2173f0
+f1ac f1ac s            ld hl, fonto
+f1af f1af d cd83f0
+f1af f1af s            call ldir8
+f1b2 f1b2 d e1
+f1b2 f1b2 s            pop hl
+f1b3 f1b3 d cd83f0
+f1b3 f1b3 s            call ldir8
+f1b6 f1b6 d 76
+f1b6 f1b6 s            hlt
+f1b7 f1b7 s            
+f1b7 f1b7 s 
+f1b7 f1b7 d c38800
+f1b7 f1b7 s fd765_done:        jp start                        ; go go go....
+f1ba f1ba s 
+f1ba f1ba d 
+f1ba f1ba s fd765_begin:
+f1ba f1ba s ;          The ROM did this bit for us!
+f1ba f1ba s ;          call fd765_intwait
+f1ba f1ba s ;          ld hl, fd765_setup              ; set up drive parameters
+f1ba f1ba s ;          ld bc, #(5 * 256 + FD_DT)       ; 5 byte command
+f1ba f1ba s ;          call fd765_sendcmd              ; set up the drive
+f1ba f1ba s ;          call fd765_status
+f1ba f1ba s 
+f1ba f1ba d 3e06
+f1ba f1ba s            ld a, 6                         ; clear terminal count flag
+f1bc f1bc d d3f8
+f1bc f1bc s            out (0xF8), a
+f1be f1be s 
+f1be f1be d cdacf0
+f1be f1be s            call fd765_intwait
+f1c1 f1c1 d 21fcf1
+f1c1 f1c1 s            ld hl, fd765_seek
+f1c4 f1c4 d 0603
+f1c4 f1c4 s            ld b, 3                         ; C was set by intwait
+f1c6 f1c6 d cd89f0
+f1c6 f1c6 s            call fd765_sendcmd
+f1c9 f1c9 d cdacf0
+f1c9 f1c9 s            call fd765_intwait
+f1cc f1cc d 0609
+f1cc f1cc s            ld b, 9                         ; READ, C was set by intwait
+f1ce f1ce d 21f2f1
+f1ce f1ce s            ld hl, fd765_read_data
+f1d1 f1d1 d cd89f0
+f1d1 f1d1 s            call fd765_sendcmd              ; send the READ DATA command
+f1d4 f1d4 d ed5bf0f1
+f1d4 f1d4 s            ld de, (codebase)
+f1d8 f1d8 d 210002
+f1d8 f1d8 s            ld hl, 512
+f1db f1db d 19
+f1db f1db s            add hl, de
+f1dc f1dc d 22f0f1
+f1dc f1dc s            ld (codebase), hl               ; move on 512
+f1df f1df d eb
+f1df f1df s            ex de, hl
+f1e0 f1e0 d 1e02
+f1e0 f1e0 s            ld e, 2                         ; 512 bytes
+f1e2 f1e2 d 0600
+f1e2 f1e2 s            ld b, 0
+f1e4 f1e4 d cdd5f0
+f1e4 f1e4 s            call fd765_xfer_in              ; copy the data
+f1e7 f1e7 d cd9af0
+f1e7 f1e7 s            call fd765_status               ; get the status bits
+f1ea f1ea s            ; failed ?
+f1ea f1ea d 3a02f4
+f1ea f1ea s            ld a, (fd765_statbuf)
+f1ed f1ed d e6cb
+f1ed f1ed s            and 0xCB
+f1ef f1ef d c9
+f1ef f1ef s            ret
+f1f0 f1f0 s 
+f1f0 f1f0 d 0000
+f1f0 f1f0 s codebase:  dw 0x0000
+f1f2 f1f2 s 
+f1f2 f1f2 d 
+f1f2 f1f2 s fd765_read_data:
+f1f2 f1f2 d 66
+f1f2 f1f2 s            db 0x66         ; Normal MFM read
+f1f3 f1f3 d 00
+f1f3 f1f3 s            db 0            ; Drive 0, head 0
+f1f4 f1f4 d 00
+f1f4 f1f4 s fd765_cyl: db 0            ; cylinder
+f1f5 f1f5 d 00
+f1f5 f1f5 s            db 0            ; head
+f1f6 f1f6 d 02
+f1f6 f1f6 s fd765_sector:      db 2            ; sector
+f1f7 f1f7 d 02
+f1f7 f1f7 s            db 2            ; 512 bytes
+f1f8 f1f8 d 02
+f1f8 f1f8 s fd765_seclast:     db 2            ; last sector
+f1f9 f1f9 d 2a
+f1f9 f1f9 s            db 0x2A         ; gap length
+f1fa f1fa d ff
+f1fa f1fa s            db 0xFF         ; no room for this byte so we overwrite the
+f1fb f1fb s                            ; jp further down 8)
+f1fb f1fb d 08
+f1fb f1fb s fd765_sense        db 0x08         ; Sense interrupt
+f1fc f1fc d 0f
+f1fc f1fc s fd765_seek db 0x0F
+f1fd f1fd d 00
+f1fd f1fd s            db 0
+f1fe f1fe d 00
+f1fe f1fe s fd765_cyl2:        db 0
+f1ff f1ff s            ; Checksum
+f1ff f1ff f 765.s
+f1ff f1ff d 3f
+f1ff f1ff s checksum:  db 0x3f
+f083 a ldir8
+f0ea a fd_go
+f063 a fonte
+f073 a fonto
+f06b a fontr
+f013 a fontnum
+f1f4 a fd765_cyl
+f101 a roller_8
+f1f0 a codebase
+f1fe a fd765_cyl2
+f1ff a checksum
+f000 a fd765_lead
+f1b7 a fd765_done
+f1fc a fd765_seek
+f118 a whitetop
+f144 a fd765_boot
+f0c9 a fd765_wait
+f07b a digiprint
+f1ba a fd765_begin
+f1fb a fd765_sense
+f010 a fd765_start
+f0cb a fd765_wait_1
+f123 a greyscreen
+f083 a fd765_sensep
+f1f6 a fd765_sector
+f09a a fd765_status
+f0fd a roller_fill
+f089 a fd765_sendcmd
+f0d5 a fd765_xfer_in
+f1f8 a fd765_seclast
+f0ac a fd765_intwait
+f17b a fd765_nextcyl
+f09d a fd765_status_1
+f1f2 a fd765_read_data
+f0e5 a fd765_xfer_done
+f099 a fd765_intdatain
+f193 a fd765_boot_error
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cas b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cas
new file mode 100644 (file)
index 0000000..88dfcf4
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cas differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cim b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cim
new file mode 100644 (file)
index 0000000..abe35e9
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cim differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cmd b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cmd
new file mode 100644 (file)
index 0000000..bf5df3b
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cmd differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.hex b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.hex
new file mode 100644 (file)
index 0000000..041d775
--- /dev/null
@@ -0,0 +1,33 @@
+:10F0000000002809020103020000000000000000C7
+:10F01000C3EAF0386CC6D6C66C3800183818181811
+:10F02000187E007CC6061C3066FE007CC6063C06C8
+:10F03000C67C001C3C6CCCFE0C1E00FEC0C0FC0656
+:10F04000C67C003860C0FCC6C67C00FEC60C18300A
+:10F050003030007CC6C67CC6C67C007CC6C67E0638
+:10F060000C7800FE6268786862FE000000DC766062
+:10F0700060F00000007CC6C6C67C0026F08787874B
+:10F08000C6136F010800EDB0C9DB008730FBFA99A9
+:10F09000F0EDA3E3E3E3E320F0C92102F4DB008712
+:10F0A00030FB87D0EDA2E3E3E3E318F1010101DBDC
+:10F0B000F8CB6FC82184F0CD89F0CD9AF03A02F4F4
+:10F0C000CB7F20E8CB77C006143EB3E3E3E3E33D18
+:10F0D00020F910F5C9DB008730FB87F293F1EDA230
+:10F0E00020F31D20F03E05D3F8C9F33100F43E842F
+:10F0F000D3F13CD3F221009A1100800620C5060806
+:10F100004B712372230C10F9E521680119EBE1C161
+:10F1100010EB21004011D00236FF231B7AB320F8F8
+:10F1200011302A36AA233655231B7AB320F53E81A7
+:10F13000D3F13CD3F23EADD3F5AFD3F63E07D3F8CF
+:10F140003E40D3F73E84D3F23AF4F111E097CD7B01
+:10F15000F03AF6F1CD7BF03E82D3F2CDBAF1203316
+:10F1600026003E84D3F2C73E82D3F23AF6F13CFE4B
+:10F170000A300832F6F132F8F118C93E0132F6F1E0
+:10F1800032F8F13AF4F13CFE0B302C32F4F132FE5D
+:10F19000F118B13E84D3F22163F011A89ACD83F027
+:10F1A000216BF0E5CD83F0E1E5CD83F02173F0CD67
+:10F1B00083F0E1CD83F076C388003E06D3F8CDAC72
+:10F1C000F021FCF10603CD89F0CDACF0060921F267
+:10F1D000F1CD89F0ED5BF0F12100021922F0F1EBA5
+:10F1E0001E020600CDD5F0CD9AF03A02F4E6CBC966
+:10F1F0000000660000000202022AFF080F00003F24
+:0000000000
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.lcas b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.lcas
new file mode 100644 (file)
index 0000000..8616ad2
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/765.lcas differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.ams b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.ams
new file mode 100644 (file)
index 0000000..54b730e
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.ams differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.bds b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.bds
new file mode 100644 (file)
index 0000000..ad53fc3
--- /dev/null
@@ -0,0 +1,122 @@
+binary-debuggable-source
+0000 0000 s ;
+0000 0000 s ;  We have 0x88 bytes before the standard UZI start point, everyone
+0000 0000 s ;  breathe in
+0000 0000 s ;  On entry h is set to 0 and the top of screen is banked at 0x8000
+0000 0000 s ;
+0000 0000 d 
+0000 0000 s track              .equ 0xF1EA
+0000 0000 d 
+0000 0000 s            .org 0
+0000 0000 s 
+0000 0000 d 
+0000 0000 s progress:  ; top bar
+0000 0000 s            ; bank then down 14 character lines
+0000 0000 s            ; and 
+0000 0000 d 1198a8
+0000 0000 s            ld de, 0x8000+0x2760+312
+0003 0003 d 3e33
+0003 0003 s            ld a, font0 % 256
+0005 0005 d df
+0005 0005 s            rst 0x18        ; choline
+0006 0006 s            ; progress bar
+0006 0006 d 1168ab
+0006 0006 s            ld de, 0x8000+0x2760+312+720
+0009 0009 d df
+0009 0009 s            rst 0x18        ; choline
+000a 000a d 1170ab
+000a 000a s            ld de, 0x8000+0x2760+312+720+8
+000d 000d d 3aeaf1
+000d 000d s            ld a, (track)
+0010 0010 d 3c
+0010 0010 s            inc a
+0011 0011 d 47
+0011 0011 s            ld b, a
+0012 0012 d 3e63
+0012 0012 s            ld a, fontX
+0014 0014 d ef
+0014 0014 s            rst 0x28        ; nchout
+0015 0015 s            ; bottom bar
+0015 0015 d 1138ae
+0015 0015 s            ld de, 0x8000+0x2760+312+2*720
+0018 0018 d e7
+0018 0018 s choline:   rst 0x20        ; chout at 0x18
+0019 0019 d c608
+0019 0019 s            add a,8
+001b 001b d 060a
+001b 001b s            ld b, 10
+001d 001d d ef
+001d 001d s            rst 0x28        ; nchout
+001e 001e d 1810
+001e 001e s            jr tail
+0020 0020 d 6f
+0020 0020 s chout:             ld l, a         ; chout at 0x20
+0021 0021 d 010800
+0021 0021 s            ld bc, 8
+0024 0024 d edb0
+0024 0024 s            ldir
+0026 0026 d c9
+0026 0026 s            ret
+0027 0027 d 00
+0027 0027 s            nop             ; and nchout at 0x28
+0028 0028 d c5
+0028 0028 s nchout:            push bc
+0029 0029 d e7
+0029 0029 s            rst 0x20
+002a 002a d c1
+002a 002a s            pop bc
+002b 002b d 10fb
+002b 002b s            djnz nchout
+002d 002d d c608
+002d 002d s tail2:             add a, 8
+002f 002f d c9
+002f 002f s            ret
+0030 0030 d e7
+0030 0030 s tail:              rst 0x20
+0031 0031 d 18fa
+0031 0031 s            jr tail2
+0033 0033 s 
+0033 0033 d 00001f1f1f1f1f1f
+0033 0033 s font0:             db      0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+003b 003b d 0000ffffffffffff
+003b 003b s font1:             db      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+0043 0043 d 0000f8f8f8f8f8f8
+0043 0043 s font2:             db      0x00, 0x00, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+004b 004b s 
+004b 004b d 1f1f1f1f1f1f1f1f
+004b 004b s font3:             db      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+0053 0053 d 0000ffffffff0000
+0053 0053 s font4:             db      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+005b 005b d f8f8f8f8f8f8f8f8
+005b 005b s font5:             db      0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+0063 0063 s 
+0063 0063 d 0000010101010000
+0063 0063 s fontX:             db      0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00
+006b 006b s 
+006b 006b d 1f1f1f1f1f1f0000
+006b 006b s font6:             db      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00
+0073 0073 d ffffffffffff0000
+0073 0073 s font7:             db      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+007b 007b d f8f8f8f8f8f80000
+007b 007b s font8:             db      0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00
+0083 0083 s 
+0083 0083 s            ; Pad to 0x88 bytes
+0083 0083 f sector2.s
+0083 0083 d 0000000000
+0083 0083 s            db      0,0,0,0,0
+0030 a tail
+002d a tail2
+0033 a font0
+003b a font1
+0043 a font2
+004b a font3
+0053 a font4
+005b a font5
+006b a font6
+0073 a font7
+007b a font8
+0020 a chout
+0063 a fontx
+0028 a nchout
+0018 a choline
+0000 a progress
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cas b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cas
new file mode 100644 (file)
index 0000000..bed756c
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cas differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cim b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cim
new file mode 100644 (file)
index 0000000..db433e6
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cim differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cmd b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cmd
new file mode 100644 (file)
index 0000000..17e9845
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cmd differ
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.hex b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.hex
new file mode 100644 (file)
index 0000000..ac3c046
--- /dev/null
@@ -0,0 +1,10 @@
+:100000001198A83E33DF1168ABDF1170AB3AEAF10B
+:100010003C473E63EF1138AEE7C608060AEF1810FA
+:100020006F010800EDB0C900C5E7C110FBC608C9E3
+:10003000E718FA00001F1F1F1F1F1F0000FFFFFF10
+:10004000FFFFFF0000F8F8F8F8F8F81F1F1F1F1F48
+:100050001F1F1F0000FFFFFFFF0000F8F8F8F8F86F
+:10006000F8F8F800000101010100001F1F1F1F1F09
+:100070001F0000FFFFFFFFFFFF0000F8F8F8F8F88F
+:08008000F80000000000000080
+:0000000000
diff --git a/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.lcas b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.lcas
new file mode 100644 (file)
index 0000000..ae4694d
Binary files /dev/null and b/Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.lcas differ
diff --git a/Kernel/platform-pcw8256/Makefile b/Kernel/platform-pcw8256/Makefile
new file mode 100644 (file)
index 0000000..5ee8a06
--- /dev/null
@@ -0,0 +1,25 @@
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS =  crt0.s pcw8256.s
+ASRCS += tricks.s commonmem.s fdc765.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
diff --git a/Kernel/platform-pcw8256/README b/Kernel/platform-pcw8256/README
new file mode 100644 (file)
index 0000000..848da99
--- /dev/null
@@ -0,0 +1,13 @@
+An UZI target for the Amstrad PCW series computers
+
+16K banked memory with flexible bank setting. Programs for now (until brk()
+is done right) get 64K in four consecutive page numbers. The UAREA is mapped
+high at 0xF900 with the process and irq stacks following and a copy of the
+common area beyond (so we have a sort of common code area as needed)
+
+The very top of memory must be free as the top of bank 3 (top of OS kernel
+mapping) is "magically" the keyboard mappings.
+
+Need to try and keep kernel under 48K or so to make it easier to handle the
+screen memory, fonts etc. We need to put the screen (720x256 pixels + roller
+ram table of 512 bytes or so = ~ 24K) in the low 128K
diff --git a/Kernel/platform-pcw8256/commonmem.s b/Kernel/platform-pcw8256/commonmem.s
new file mode 100644 (file)
index 0000000..3cd0aa7
--- /dev/null
@@ -0,0 +1,50 @@
+;
+;      We have four independent 16K banks so we keep common high (and per
+;      process). We avoid the last 16 bytes as on bank 3 thats magically
+;      keyboard data.
+;
+
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _COMMONMEM
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
diff --git a/Kernel/platform-pcw8256/config.h b/Kernel/platform-pcw8256/config.h
new file mode 100644 (file)
index 0000000..de50ee8
--- /dev/null
@@ -0,0 +1,54 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* 16K reported page size */
+#define CONFIG_PAGE_SIZE       16
+/* We use flexible 16K banks so use the helper */
+#define CONFIG_BANK16
+#define MAX_MAPS 16
+#define MAX_SWAPS 16
+
+/* VT layer required */
+#define CONFIG_VT
+/* We want the 8x8 font */
+#define CONFIG_FONT8X8
+/* Vt definitions */
+#define VT_WIDTH       90
+#define VT_HEIGHT      32
+#define VT_RIGHT       89
+#define VT_BOTTOM      31
+
+#define TICKSPERSEC 50   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xF000))  /* Top of program, base of U_DATA */
+#define PROC_SIZE   64   /* Memory needed per process */
+
+#define SWAP_SIZE   0x80       /* 64K in blocks (we actually don't need the low 256) */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0xF000      /* vectors so its a round number of sectors */
+
+#define UDATA_BLOCKS   0       /* We swap the stash not the uarea */
+#define UDATA_SWAPSIZE 0
+
+#define BOOT_TTY       18
+
+#define CMDLINE                NULL
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+#define NDEVS    16       /* Devices 0..NDEVS-1 are capable of being mounted */
+                          /*  (add new mountable devices to beginning area.) */
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  5       /* Device for swapping. */
+#define NBUFS    6        /* Number of block buffers */
+#define NMOUNTS         2        /* Number of mounts at a time */
+
+
+
diff --git a/Kernel/platform-pcw8256/crt0.s b/Kernel/platform-pcw8256/crt0.s
new file mode 100644 (file)
index 0000000..67616cb
--- /dev/null
@@ -0,0 +1,150 @@
+               ; Ordering of segments for the linker.
+               ; WRS: Note we list all our segments here, even though
+               ; we don't use them all, because their ordering is set
+               ; when they are first seen.     
+               .area _CODE
+               .area _CODE2
+               .area _CONST
+               .area _DATA
+               .area _INITIALIZED
+               .area _BSEG
+               .area _BSS
+               .area _HEAP
+               ; note that areas below here may be overwritten by the heap at runtime, so
+               ; put initialisation stuff in here
+               .area _INITIALIZER
+               .area _FONT
+               .area _GSINIT
+               .area _GSFINAL
+               .area _COMMONMEM
+
+               ; imported symbols
+               .globl _fuzix_main
+               .globl init_early
+               .globl init_hardware
+               .globl s__DATA
+               .globl l__DATA
+               .globl s__COMMONMEM
+               .globl l__COMMONMEM
+               .globl s__INITIALIZER
+               .globl kstack_top
+               .globl start
+
+               ; startup code
+               .area _CODE
+;
+;      We have 0x88 bytes before the standard UZI start point, everyone
+;      breathe in
+;
+;      Once the first loader block is called we are called via RST 0 each
+;      block end and we do the gui progress bar bits that wouldn't fit in
+;      the boot block
+;
+;      On entry h is set to 0 and the top of screen is banked at 0x8000
+;
+track          .equ 0xF1F4
+
+progress:      ; top bar
+               ; bank then down 14 character lines
+               ; and 
+               ld de, #(0x8000+0x2760+312)
+               ld a, #font0
+               rst 0x18        ; choline
+               ; progress bar
+               ld de, #(0x8000+0x2760+312+720)
+               rst 0x18        ; choline
+               ld de, #(0x8000+0x2760+312+720+8)
+               ld a, (track)
+               inc a
+               ld b, a
+               ld a, #fontX
+               rst 0x28        ; nchout
+               ; bottom bar
+               ld de, #(0x8000+0x2760+312+2*720)
+choline:       rst 0x20        ; chout at 0x18
+               add a,#8
+               ld b, #10
+               rst 0x28        ; nchout
+               jr tail
+chout:         ld l, a         ; chout at 0x20
+               ld bc, #8
+               ldir
+               ret
+               nop             ; and nchout at 0x28
+nchout:                push bc
+               rst 0x20
+               pop bc
+               djnz nchout
+tail2:         add a, #8
+               ret
+tail:          rst 0x20
+               jr tail2
+
+font0:         .db     0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+font1:         .db     0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+font2:         .db     0x00, 0x00, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+
+font3:         .db     0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
+font4:         .db     0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+font5:         .db     0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8
+
+fontX:         .db     0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00
+
+font6:         .db     0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00
+font7:         .db     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00
+font8:         .db     0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00
+
+               .dw     0, 0
+               ; Pad to 0x88 bytes
+               .db     0
+;
+;      Once the loader completes it jumps here
+;
+;      On entry - stack is somewhere high, video is in bank 4 to middle of
+; bank 5 and the OS is loaded into banks 0-2
+;
+start:
+               ld sp, #kstack_top
+               ;
+               ;       Move the common into place (our build tool
+               ;       moved INITIALIZED ready and then packed common after
+               ;       it)
+               ;
+               ld hl, #s__INITIALIZER
+               ld de, #s__COMMONMEM
+               ld bc, #l__COMMONMEM
+               ldir
+               ;
+               ;       Straight after that is the font. We need the font
+               ;       somewhere accessible when the display is mapped sp
+               ;       put it after the display. hl points at the font data
+               ;       need to copy it from common
+               ;
+               call fontcopy
+               ;
+               ;       Zero the data area
+               ;
+               ld hl, #s__DATA
+               ld de, #s__DATA + 1
+               ld bc, #l__DATA - 1
+               ld (hl), #0
+               ldir
+
+               call init_early
+               call init_hardware
+               call _fuzix_main
+               di
+stop:          halt
+               jr stop
+
+;
+;      Keep this linked low as we will unmap a chunk of kernel to font copy
+;
+fontcopy:      ld a, #0x85
+               out (0xf1), a   ; font is linked high so clear of 16-32K
+               ld de, #23552   ; after roller ram
+               ld bc, #2048    ; 256x8 font
+               ldir
+               ld a, #0x81     ; put the kernel back
+               out (0xf1), a
+               ret             ; and return into it
diff --git a/Kernel/platform-pcw8256/devfd.c b/Kernel/platform-pcw8256/devfd.c
new file mode 100644 (file)
index 0000000..873e0cd
--- /dev/null
@@ -0,0 +1,220 @@
+/* 
+ *     Amstrad PCW8256 Floppy Driver
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+__sfr __at 0xf8 asic_ctrl;
+__sfr __at 0x00 fdc_c;
+__sfr __at 0x01 fdc_d;
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+
+static uint8_t track[2];
+static uint8_t type[2];
+#define TYPE_NONE      0
+#define TYPE_THREE     1
+#define TYPE_THREE_FIVE        2
+static uint8_t motorct;
+static uint8_t devsel = -1;
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor, rawflag);
+}
+
+static int fd_send(uint8_t cmd, int minor)
+{
+    fd765_cmdbuf[1] = minor;
+    fd765_cmdbuf[0] = cmd;
+    return fd765_cmd2();
+}
+
+static void reset_motor_timer(int minor)
+{
+    minor;
+}
+
+static void motor_on(int minor)
+{
+    minor;
+    asic_ctrl = 0x09;
+//FIXME    while(!(fd_send(0x04, minor) & 0x20));
+    kprintf("Motor on %d\n", minor);
+}
+
+static void motor_off(void)
+{
+    asic_ctrl = 0x0A;
+    devsel = -1;
+}
+
+/*
+ *     Turn the block number into geometry and poke it into the
+ *     command buffers
+ */
+static void fd_geom(int minor, blkno_t block)
+{
+    int ntrack = block / 9;
+    int nsector = (block % 9) + 1;
+    fd765_cmdbuf[2] = ntrack;
+    fd765_rw_data[2] = ntrack;
+    fd765_rw_data[3] = 0;              /* single sided for now */
+    fd765_rw_data[4] = nsector;
+    fd765_rw_data[6] = nsector;
+    reset_motor_timer(minor);
+
+    kprintf("fd(%d,%d)\n", ntrack, nsector);
+    if (ntrack == track[minor])
+        return;
+    fd765_cmdbuf[0] = 0x0F;
+    fd765_cmd3();
+
+    if (fd765_intwait() & 0x20)
+        track[minor] = fd765_statbuf[1] & 0x7F;
+
+}
+
+/*
+ *     Select a driver, ensure the motor is on and we are ready
+ *     then set up the command buffers to reflect this device
+ */
+static void fd_select(int minor)
+{
+    if (devsel == minor)
+        return;
+    motor_on(minor);
+    fd765_cmdbuf[1] = minor;
+    fd765_rw_data[1] = minor;
+}
+
+/*
+ *     Block transfer
+ */
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;     /* r/w return value (number of 512 byte blocks transferred) */
+    uint16_t dptr;
+    int dlen;
+    int ct = 0;
+    int st;
+    int tries;
+
+    /* Direct to user space, or kernel buffered I/O ? */
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        block = udata.u_offset >> BLKSHIFT;
+        block_xfer = dlen >> 9;
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 1;
+    }
+    
+    fd_select(minor);          /* Select, motor on */
+    fd765_user = rawflag;      /* Tell the asm which map */
+//    kprintf("To %d:%x for %d\n", rawflag, dptr, block_xfer);
+    while (ct < block_xfer) {  /* For each block */
+        fd_geom(minor, block); /* Map it and set the geometry */
+        fd765_buffer = dptr;
+        for (tries = 0; tries < 3; tries ++) { /* Try 3 times */
+            if (tries != 0)                    /* After a fail recalibrate */
+                fd_send(0x07, minor);
+            if (is_read) {
+                fd765_rw_data[0] = 0x66;       /* MFM 512 byte read */
+                st = fd765_read_sector();
+            } else {
+                fd765_rw_data[0] = 0x65;       /* MFM 512 byte write */
+                st = fd765_write_sector();
+            }
+            /* Did it work ? */
+            if (st == 0)
+                break;
+        }
+        if (tries == 3) {
+            kprintf("fd%d: I/O error %d:%d\n", is_read, block);
+            if (rawflag)
+                break;
+        }
+        block++;
+        ct++;
+        dptr += 512;
+    }
+    return ct;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor > 1 || !type[minor]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+
+static void fd_probe_plus(int d)
+{
+    int du = 2 * d;
+    uint8_t st;
+    motor_on(d);
+    st = fd_send(0x07, du);
+    st = fd765_intwait();
+    st = fd_send(0x04, du);
+    if (!(st & 0x10)) {
+        if (st & 0x40)
+            type[d] = TYPE_THREE;
+        else if (d == 0)
+            type[d] = TYPE_THREE_FIVE;
+        else
+            type[d] = TYPE_NONE;
+    } else {
+        asic_ctrl = 0x10;
+        /* motor wait needed */
+        fd_send(0x04, du);
+        if (st & 0x10)
+            type[d] = TYPE_THREE;
+        else
+            type[d] = TYPE_THREE_FIVE;
+    }
+    /* Motors back off */
+    motor_off();
+}
+
+static char *fdnames[] = {"none", "3\"", "3.5\"" };
+
+void fd_probe(void)
+{
+    int i;
+    uint8_t st;
+    /* Motor off */
+    motor_off();
+    /* Wait for not ready status */
+    do {
+        st = fd_send(0x04, 0);
+    } while (st & 0x20);
+    st = fd_send(0x04, 3);
+    if (st & 0x20) {
+        fd_probe_plus(0);
+        fd_probe_plus(1);
+    }
+    else
+        type[0] = TYPE_THREE;
+    motor_off();
+    for (i = 0; i < 2; i++)
+        kprintf("fd%d: %s\n", i, fdnames[type[i]]);
+}
diff --git a/Kernel/platform-pcw8256/devfd.h b/Kernel/platform-pcw8256/devfd.h
new file mode 100644 (file)
index 0000000..7e5e48f
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+/* asm interface */
+extern uint16_t fd765_buffer;
+extern uint8_t fd765_user;
+extern uint8_t fd765_cmdbuf[3];
+extern uint8_t fd765_rw_data[9];
+extern uint8_t fd765_statbuf[8];
+
+/* Read a sector */
+extern int fd765_read_sector(void);
+/* Write a sector */
+extern int fd765_write_sector(void);
+/* 2 byte command */
+extern int fd765_cmd2(void);
+/* 3 byte command */
+extern int fd765_cmd3(void);
+/* Int wait */
+extern int fd765_intwait(void);
+
+extern void fd_probe(void);
+#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-pcw8256/devices.c b/Kernel/platform-pcw8256/devices.c
new file mode 100644 (file)
index 0000000..d54c4dd
--- /dev/null
@@ -0,0 +1,64 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devmem.h>
+#include <devzero.h>
+#include <devnull.h>
+#include <devproc.h>
+#include <devlpr.h>
+#include <tty.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* Floppy disk block devices  */
+  {  0,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   0   /dev/fd0
+  {  1,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   1   /dev/fd1
+  {  2,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   2   /dev/rd2
+  {  3,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   3   /dev/rd3
+
+  /* Disk devices (not all used) */
+  {  0,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   4   /dev/sd0 
+  {  1,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   5   /dev/sd1 
+  {  2,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   6   /dev/sd2 
+  {  3,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   7   /dev/sd3 
+  {  4,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   8   /dev/sd4 
+  {  5,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   9   /dev/sd5 
+  {  6,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //  10   /dev/sd6 
+  {  7,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //  11   /dev/sd7 
+  {  8,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //  12   /dev/sd8 
+  {  9,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //  13   /dev/sd9 
+  { 10,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //  14   /dev/sd10
+  { 11,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //  15   /dev/sd11
+
+  /* devices below here are not mountable (as per NDEVS) */
+  {  0, lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },  //  16   /dev/lp  
+  {  0, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  17   /dev/tty
+  {  1, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  18   /dev/tty1
+  {  2, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  19   /dev/tty2
+  {  3, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  20   /dev/tty3
+  {  4, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  21   /dev/tty4
+  {  0, no_open,      no_close,    null_read, null_write, no_ioctl  },  //  22   /dev/null
+  {  0, no_open,      no_close,    zero_read, no_rdwr,    no_ioctl  },  //  23   /dev/zero
+  {  0, no_open,      no_close,    mem_read,  mem_write,  no_ioctl  },  //  24   /dev/kmem
+  {  0, no_open,      no_close,    proc_read, no_rdwr, proc_ioctl}      //  25   /dev/proc
+  // {  0,  mt_open,  mt_close, mt_read,  mt_write,   nogood }          // 26 /dev/mt  
+  /* Add more tty channels here if available, incrementing minor# */
+};
+
+bool validdev(uint8_t dev)
+{
+    if(dev >= (sizeof(dev_tab)/sizeof(struct devsw)))
+        return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+  tty_init();
+  fd_probe();
+}
diff --git a/Kernel/platform-pcw8256/devlpr.c b/Kernel/platform-pcw8256/devlpr.c
new file mode 100644 (file)
index 0000000..65d8c43
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat;                /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag; // shut up compiler
+    return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+    minor; // shut up compiler
+    return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    int c = udata.u_count;
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(c) {
+        /* Note; on real hardware it might well be necessary to
+           busy wait a bit just to get acceptable performance */
+        while (lpstat != 0xFF) {
+//            if (psleep_flags(&clocktick, flag))
+//                return -1;
+        }
+        /* FIXME: tidy up ugetc and sysio checks globally */
+        lpdata = ugetc(p++);
+    }
+    return (-1);
+}
diff --git a/Kernel/platform-pcw8256/devlpr.h b/Kernel/platform-pcw8256/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-pcw8256/devtty.c b/Kernel/platform-pcw8256/devtty.c
new file mode 100644 (file)
index 0000000..78a9912
--- /dev/null
@@ -0,0 +1,243 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <tty.h>
+#include <vt.h>
+
+#undef  DEBUG            /* UNdefine to delete debug code sequences */
+
+__sfr __at 0xE0        dart0d;
+__sfr __at 0xE1 dart0c;
+__sfr __at 0xE2        dart1d;
+__sfr __at 0xE3 dart1c;
+__sfr __at 0xE4        ctc0;
+__sfr __at 0xE5 ctc1;
+__sfr __at 0xE7 ctcmode;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+char tbuf3[TTYSIZ];
+
+struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
+    {   NULL,    NULL,    NULL,    0,        0,       0    },
+    {   tbuf1,   tbuf1,   tbuf1,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf2,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf3,   tbuf3,   tbuf3,   TTYSIZ,   0,   TTYSIZ/2 }
+};
+
+/* console driver for errors etc */
+void kputchar(char c)
+{
+    if(c=='\n')
+        tty_putc(1, '\r');
+    tty_putc(1, c);
+}
+
+static uint8_t dartrr(uint8_t minor, uint8_t r)
+{
+    uint8_t irq;
+    uint8_t ch;
+
+    irq = di();
+
+    if (minor == 2) {
+        dart0c = r;
+        ch = dart0c;
+    } else {
+        dart1c = r;
+        ch = dart1c;
+    }
+
+    irqrestore(irq);
+
+    return ch;
+}
+
+static void dartwr(uint8_t minor, uint8_t r, uint8_t v)
+{
+    uint8_t irq;
+    irq = di();
+
+    if (minor == 2) {
+        dart0c = r;
+        dart0c = v;
+    } else {
+        dart1c = r;
+        dart1c = v;
+    }
+    irqrestore(irq);
+}
+
+static bool tty_writeready(uint8_t minor)
+{
+    if (minor == 1)
+        return 1;      /* VT */
+    else
+        return dartrr(minor, 0) & 4;
+}
+
+extern void bugout(uint16_t c);
+
+void tty_putc(uint8_t minor, char c)
+{
+    if (minor == 1) {
+        bugout(c);
+        vtoutput(&c, 1);
+    }
+    else if (minor == 2)
+        dart0d = c;
+    else
+        dart1d = c;
+}
+
+void tty_irq(void)
+{
+    uint8_t s = dartrr(2, 0);
+    uint8_t c;
+    if (s & 1) {
+        c = dart0d;
+        tty_inproc(2, c);
+    }
+    s = dartrr(3, 0);
+    if (s & 1) {
+        c = dart0d;
+        tty_inproc(2, c);
+    }
+}
+
+/* Pending better ioctl bits set up for 9600 8N1 */
+
+void tty_init(void)
+{
+    ctcmode = 0x36;
+    ctc0 = 0x00;
+    ctc0 = 0x0D;
+    ctcmode = 0x76;
+    ctc0 = 0x00;
+    ctc0 = 0x0D;
+    dartwr(2, 0, 0x18);        /* Reset */
+    dartwr(2, 3, 0xE1);        /* 8bit, flow controlled, rx enable */
+    dartwr(2, 4, 0x44);        /* 1 stop, no parity */
+    dartwr(2, 5, 0x66);        /* 8bit tx, tx enable, rts enable, dtr on */
+    dartwr(3, 0, 0x18);        /* Reset */
+    dartwr(3, 3, 0xE1);        /* 8bit, flow controlled, rx enable */
+    dartwr(3, 4, 0x44);        /* 1 stop, no parity */
+    dartwr(3, 5, 0x66);        /* 8bit tx, tx enable, rts enable, dtr on */
+}
+
+
+/*********************** Keyboard **************************/
+
+static uint8_t keymap[12];
+static uint8_t *keyin = (uint8_t *)0xFFF0;
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+static uint8_t shiftmask[12] = {       /* Shift keys */
+    0,0,0x20,0,
+    0,0,0,0,
+    0x40,0,0x80,0                      /* Fixme: shiftlock */
+};
+
+static void keyproc(void)
+{
+       int i;
+       uint8_t key;
+       uint8_t kin;
+
+       /* We have 12 bytes of keys to scan on the PCW, we don't need to
+          touch the extras */
+       for (i = 0; i < 12; i++) {
+               kin = keyin[i];         /* MMIO so changes under us */
+               key = kin ^ keymap[i];
+               if (key) {
+                       /* Scan for changes */
+                       int n;
+                       int m = 128;
+                       for (n = 7; n >= 0; n--) {
+                               if ((key & m) && (keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown--;
+                               }
+                               if ((key & m) && !(keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown++;
+                                       keybyte = i;
+                                       keybit = n;
+                                       newkey = 1;
+                               }
+                               m >>= 1;
+                       }
+               }
+               keymap[i] = kin;
+       }
+}
+
+static uint8_t keyboard[12][8] = {
+       {'2', '3', '6', '9', 0x81 /* paste */ ,0x91, '0', 0x93 /* F3 */},
+       {'1', '5', '4', '8', 0x82 /* copy */, 0x83 /* cut */, 0x84 /* PTR */, 0x85 /* EXIT */},
+       {'+', 189/*half*/, 0, '7', '>', 13, ']', 127},
+       {'.', '?', ';', '<', 'p', '[', '-', '='},
+       {',', 'm', 'k', 'l', 'i', 'o', '9', '0'},
+       {' ', 'n', 'j', 'h', 'y', 'u', '7', '8'},
+       {'v', 'b', 'f', 'g', 't', 'r', 's', '6'},
+       {'x', 'c', 'd', 's', 'w', 'e', '3', '4'},
+       {'z', 0, 'a', '\t', 'q', 27, '2', '1'},
+       {8, 0, 0, 0, 0, 0, 0, 0},       /* FIXME: js line */
+       {0, '.', 13, 97, '-', 85/*cancel*/, 86/*extra*/, 0x95},
+       {0, 0, 0, 0, 0, 0, 0, 0}        /* FIXME: js 2 */
+};
+
+/* FIXME: shift symbols */
+static uint8_t shiftkeyboard[12][8] = {
+       {'2', '3', '6', '9', 0x81 /* paste */ ,0x91, '0', 0x93 /* F3 */},
+       {'1', '5', '4', '8', 0x82 /* copy */, 0x83 /* cut */, 0x84 /* PTR */, 0x85 /* EXIT */},
+       {'+', 189/*half*/, 0, '7', '>', 13, ']', 127},
+       {'.', '?', ';', '<', 'P', '[', '-', '='},
+       {',', 'M', 'K', 'L', 'I', 'O', '9', '0'},
+       {' ', 'N', 'J', 'H', 'Y', 'U', '7', '8'},
+       {'V', 'B', 'F', 'G', 'T', 'R', 'S', '6'},
+       {'X', 'C', 'D', 'S', 'W', 'E', '3', '4'},
+       {'Z', 0, 'A', '\t', 'Q', 27, '2', '1'},
+       {8, 0, 0, 0, 0, 0, 0, 0},       /* FIXME: js line */
+       {0, '.', 13, 97, '-', 85/*cancel*/, 86/*extra*/, 0x95},
+       {0, 0, 0, 0, 0, 0, 0, 0}        /* FIXME: js 2 */
+};
+
+static uint8_t capslock = 0;
+
+static void keydecode(void)
+{
+       uint8_t c;
+
+       if (keybyte == 8 && keybit == 6) {
+               capslock = 1 - capslock;
+               return;
+       }
+       if (keymap[2] & (1 << 5))       /* shift */
+               c = shiftkeyboard[keybyte][7-keybit];
+       else
+               c = keyboard[keybyte][7-keybit];
+       if (keymap[10] & 0x80) {        /* alt */
+               if (c > 31 && c < 96)
+                       c &= 31;
+       }
+       if (capslock && c >= 'a' && c <= 'z')
+               c -= 'a' - 'A';
+        kprintf("ttyinproc %d\n", (int) c);
+       tty_inproc(1, c);
+}
+
+/* FIXME: keyboard repeat
+          floppy motor etc */
+void platform_interrupt(void) 
+{
+    newkey = 0;
+    keyproc();
+    if (keysdown < 3 && newkey)
+        keydecode();
+    timer_interrupt();
+}
+
diff --git a/Kernel/platform-pcw8256/devtty.h b/Kernel/platform-pcw8256/devtty.h
new file mode 100644 (file)
index 0000000..e219ce8
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+void tty_putc(uint8_t minor, char c);
+bool tty_writeready(uint8_t minor);
+void tty_init(void);
+void tty_irq(void);
+#endif
diff --git a/Kernel/platform-pcw8256/fdc765.s b/Kernel/platform-pcw8256/fdc765.s
new file mode 100644 (file)
index 0000000..0777790
--- /dev/null
@@ -0,0 +1,248 @@
+;
+;              765 Floppy Controller Support
+;
+               .module fdc765
+
+               .include "kernel.def"
+               .include "../kernel.def"
+
+               .globl  _fd765_read_sector
+               .globl  _fd765_write_sector
+               .globl  _fd765_cmd2
+               .globl  _fd765_cmd3
+               .globl  _fd765_intwait
+               .globl  _fd765_buffer
+               .globl  _fd765_user
+               .globl  _fd765_rw_data
+               .globl  _fd765_cmdbuf
+               .globl  _fd765_statbuf
+
+               .globl  map_process_always
+               .globl  map_kernel
+
+               .area _COMMONMEM
+
+               FD_ST   .equ    0
+               FD_DT   .equ    1
+
+fd765_sendcmd:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_sendcmd            ; busy
+               jp m, fd765_sendabort           ; not expecting command ??
+               outi                            ; byte out
+               ex (sp), hl                     ; controller time
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               jr nz, fd765_sendcmd            ; next byte ?
+               ret
+fd765_sendabort:
+               or a                            ; NZ
+               ; FIXME
+               ret
+
+fd765_status:
+               ld hl, #_fd765_statbuf
+fd765_status_1:
+               in a, (FD_ST)
+               add a, a
+               jr nc, fd765_status_1
+               add a, a
+               ret nc                          ; bit 6 was clear, so done
+               ini
+               ex (sp), hl                     ; waste time for the 765
+               ex (sp), hl                     ; to recover
+               ex (sp), hl
+               ex (sp), hl
+               jr fd765_status_1
+
+fd765_status_a:
+               call fd765_status
+               ld h, #0
+               ld a, (_fd765_statbuf)
+               ld l, a
+               ret
+
+;
+;      We rely on this exiting with C = FD_DT
+;
+_fd765_intwait:
+               ld bc, #1 * 256 + FD_DT         ; send SENSE INTERRUPT STATUS
+               in a, (0xF8)
+               bit 5, a
+               ret z                           ; wait for the 765 int to go off
+               ld hl, #fd765_sense             ; a suitable 0x08 in the code
+               call fd765_sendcmd
+               call fd765_status_a
+               bit 7, a                        ; error
+               jr nz, _fd765_intwait
+               bit 6, a                        ; abnormal
+               ret nz
+               ld b, #0x14                     ; give the controller time
+fd765_wait:    ld a, #0xB3
+fd765_wait_1:  ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               ex (sp), hl
+               dec a
+               jr nz, fd765_wait_1
+               djnz fd765_wait
+               ret
+
+;              C points at FD_DT
+fd765_xfer_in:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_in            ; bit 7 clear
+fd765_xfer_in2:
+               add a
+               jp p, fd765_xfer_error          ; bit 5 clear (short data ???)
+               ini                             ; transfer a byte
+               jr nz, fd765_xfer_in            ; next byte
+               dec e
+               jr nz, fd765_xfer_in
+;
+;              Sector transferred
+;
+fd765_xfer_done:ld a, #5
+               out (0xF8), a                   ; terminate flag set
+               ret
+fd765_xfer_error:
+               or a                            ; NZ
+               ; FIXME
+               ret
+fd765_xfer_indi:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_indi          ; bit 7 clear
+               di
+               jr fd765_xfer_in2
+
+;              C points at FD_DT
+fd765_xfer_out:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_out           ; bit 7 clear
+fd765_xfer_out2:
+               add a
+               jp p, fd765_xfer_error          ; bit 5 clear (short data ???)
+               ini                             ; transfer a byte
+               jr nz, fd765_xfer_in            ; next byte
+               dec e
+               jr nz, fd765_xfer_in
+;
+;              Sector transferred
+;
+               ld a, #5
+               out (0xF8), a                   ; terminate flag set
+               ret
+
+fd765_xfer_outdi:
+               in a, (FD_ST)
+               add a
+               jr nc, fd765_xfer_outdi         ; bit 7 clear
+               di
+               jr fd765_xfer_out2
+
+_fd765_read_sector:
+               ld a, i
+               push af
+               ld a, (_fd765_user)
+               or a
+               jr z, read_kern
+               call map_process_always
+read_kern:
+               ld a, #6
+               out (0xf8), a
+               call _fd765_intwait             ; wait for controller
+               ld b, #9
+               ld hl, #_fd765_rw_data
+               call fd765_sendcmd
+               jr nz, read_failed
+               ld hl, (_fd765_buffer);
+               ld e, #2
+               ld b, #0                        ; 512 bytes
+               call fd765_xfer_in
+               jr nz, read_failed
+               call fd765_status_a
+               and #0xCB
+               jr nz, read_out
+               ; read ok
+               ld hl, #0
+read_out:
+               call map_kernel
+               pop af
+               ret po
+               ei
+               ret
+read_failed:
+               ld hl, #-1
+               jr read_out
+
+_fd765_write_sector:
+               ld a, i
+               push af
+               ld a, (_fd765_user)
+               or a
+               jr z, write_kern
+               call map_process_always
+write_kern:
+               ld a, #6
+               out (0xf8), a
+               call _fd765_intwait             ; wait for controller
+               ld b, #9
+               ld hl, #_fd765_rw_data
+               call fd765_sendcmd
+               jr nz, read_failed
+               ld hl, (_fd765_buffer);
+               ld e, #2
+               ld b, #0                        ; 512 bytes
+               call fd765_xfer_out
+               jr nz, read_failed
+               call fd765_status_a
+               and #0xCB               ; FIXME - correct error mask ?
+               jr nz, read_out
+               ; write ok
+               ld hl, #0
+               jr read_out
+
+_fd765_cmd2:   call _fd765_intwait
+               ld b, #2
+fd765_cmdop:
+               ld hl, #_fd765_cmdbuf
+               call fd765_sendcmd
+               jr nz, read_failed
+               call fd765_status_a
+               ret
+
+_fd765_cmd3:   call _fd765_intwait
+               ld b, #3
+               jr fd765_cmdop
+
+;
+;      Needs to land in common memory
+;
+
+_fd765_buffer: .dw 0           ; Buffer pointer
+_fd765_user:   .db 0           ; 0 - kernel 1 - user
+
+_fd765_rw_data: .db 0x66       ; Normal MFM read
+               .db 0           ; Drive 0, head 0
+               .db 0           ; cylinder
+               .db 0           ; head
+               .db 2           ; sector
+               .db 2           ; 512 bytes
+               .db 2           ; last sector
+               .db 0x2A        ; gap length
+               .db 0xFF        ; unused
+
+fd765_sense:   .db 0x08        ; Sense interrupt
+
+_fd765_cmdbuf: .db 0x0F
+               .db 0
+               .db 0
+               .db 0
+_fd765_statbuf:
+               .ds 8
+
diff --git a/Kernel/platform-pcw8256/kernel.def b/Kernel/platform-pcw8256/kernel.def
new file mode 100644 (file)
index 0000000..7097f8e
--- /dev/null
@@ -0,0 +1,4 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xF000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
diff --git a/Kernel/platform-pcw8256/main.c b/Kernel/platform-pcw8256/main.c
new file mode 100644 (file)
index 0000000..c5cab6f
--- /dev/null
@@ -0,0 +1,52 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint8_t *ramtop;
+
+/* Kernel is 0-3 screen for now is 4 and bits of 5
+   Apps 6,7,8,9,10,11,12,13,14,15 etc
+   
+   This *will* change once we sort the memory map out sanely so that we are
+   only using 4 for kernel/screen  */
+
+void map_init(void)
+{
+ udata.u_ptab->p_page = 0x8383;
+ udata.u_ptab->p_page2 = 0x8383;
+}
+
+void pagemap_init(void)
+{
+ int i;
+ for (i = 0x86; i < 0x92; i++)
+  pagemap_add(i);
+}
+
+/* The uarea is already synched to the stash which is written with the
+   process */
+uint8_t *swapout_prepare_uarea(ptptr p)
+{
+//  kprintf("swapout prepare %x\n", p);
+  p;
+  return NULL;
+}
+
+/* The switchin code will move the uarea into the process itself, we just
+   need to fix up the u_page pointer */
+uint8_t *swapin_prepare_uarea(ptptr p)
+{
+  p;
+//  kprintf("swapin prepare %x now page %d\n", p, p->p_page);
+  return NULL;
+}
+
+void platform_idle(void)
+{
+ __asm
+  halt
+ __endasm;
+}
+
diff --git a/Kernel/platform-pcw8256/pcw8256.h b/Kernel/platform-pcw8256/pcw8256.h
new file mode 100644 (file)
index 0000000..02c6924
--- /dev/null
@@ -0,0 +1,52 @@
+__sfr __at 0x00        fdc_status;             /* uPD 765A, in PIO mode */
+__sfr __at 0x01 fdc_data;
+__sfr __at 0x88 par0;
+__sfr __at 0x89 par1;
+__sfr __at 0x8A par2;
+__sfr __at 0x8B par3;
+__sfr __at 0x8C par4;
+__sfr __at 0x8D par5;
+__sfr __at 0x8E par6;
+__sfr __at 0x8F par7;
+__sfr __at 0x9F kempjoy;
+__sfr __at 0xA0 amx0;
+__sfr __at 0xA1 amx1;
+__sfr __at 0xA2 amx2;
+__sfr __at 0xA8 gem_data;      /* PC/XT equivalent controller ? */
+__sfr __at 0xA9 gem_cs;
+__sfr __at 0xAA gem_csp;
+__Sfr __at 0xAB gem_dmaint;
+__sfr __at 0xC8 fax;
+__sfr __at 0xD0 kempmouse0;
+__sfr __at 0xD1 kempmouse1;
+__sfr __at 0xD2 kempmouse2;
+__sfr __at 0xD3 kempmouse0;
+__sfr __at 0xE0 dart_data_a;
+__sfr __at 0xE1 dart_ctrl_a;
+__sfr __at 0xE2 dart_data_b;
+__sfr __at 0xE3 data_ctrl_b;
+__sfr __at 0xE4 i8253_c0;
+__sfr __at 0xE5 i8253_c1;
+__sfr __at 0xE7 i8253_mode;
+__sfr __at 0xF0 bank0;         /* Write only so need shadows for kernel/user */
+__sfr __at 0xF1 bank1;
+__sfr __at 0xF2 bank2;
+__sfr __at 0xF3 bank3;
+__sfr __at 0xF4 bank4;
+__sfr __at 0xF4 irq;
+__sfr __at 0xF5 rollerram;
+__sfr __at 0xF6 vscreen;
+__sfr __at 0xF7 screenon;
+__sfr __at 0xF8 irqcheck;              /* Read */
+__sfr __at 0xF8 syscontrol;            /* Write */
+#define SYSCTRL_FLOPPY_NMI     2
+#define SYSCTRL_FLOPPY_IRQ     3
+#define SYSCTRL_FLOPPY_NOIRQ   4
+#define SYSCTRL_FLOPPY_SETTC   5
+#define SYSCTRL_FLOPPY_CLRTC   6
+__sfr __at 0xFC par9512;               /* FIXME: the 9512 are Z180 type decodes */
+__sfr __at 0xFD par9512_b;             /* at 00FC 01FC 00FD */
+__sfr __at 0xFC iomatrix_d;
+__sfr __at 0xFD iomatrix_c;
+__sfr __at 0xFE locolink;
+
diff --git a/Kernel/platform-pcw8256/pcw8256.s b/Kernel/platform-pcw8256/pcw8256.s
new file mode 100644 (file)
index 0000000..0f8953e
--- /dev/null
@@ -0,0 +1,467 @@
+;
+;      PCW8256-9512+ support
+;
+
+            .module pcw8256
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl _program_vectors
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl _kernel_flag
+           .globl map_save
+           .globl map_restore
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl _trap_reboot
+            .globl outchar
+           .globl _bugout
+
+           ; exported video symbols
+           .globl _scroll_up
+           .globl _scroll_down
+           .globl _cursor_on
+           .globl _cursor_off
+           .globl _plot_char
+           .globl _do_beep
+           .globl _clear_lines
+           .globl _clear_across
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+           .globl nmi_handler
+           .globl null_handler
+            .globl interrupt_handler
+            .globl unix_syscall_entry
+           .globl _vtinit
+
+           ; debug symbols
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; VIDEO MEMORY BANK (0x4000-0xBFFF during video work)
+; -----------------------------------------------------------------------------
+
+framebuffer .equ       0x4000
+font8x8            .equ        0x9C00          ; font loaded after framebuffer
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+trapmsg:    .ascii "Trapdoor: SP="
+            .db 0
+trapmsg2:   .ascii ", PC="
+            .db 0
+tm_user_sp: .dw 0
+
+tm_stack:
+            .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+tm_stack_top:
+
+;
+;      Ask the controller to reboot
+;
+_trap_reboot:
+           ld a, #0x01
+           out (0xF8), a
+            ; should never get here
+_trap_monitor:
+           di
+           halt
+           jr _trap_monitor
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+           ld b, #'U'
+           call _bugoutv
+           call _vtinit
+            ret
+
+init_hardware:
+            ; set system RAM size
+           ld b, #'Z'
+           call _bugoutv
+            ld hl, #256
+            ld (_ramsize), hl
+            ld hl, #(256-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ; FIXME 100Hz timer on
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+           ld b, #'I'
+           call _bugoutv
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ld (0x0000), a   
+            ld hl, #null_handler   ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+            ; put the MMU back as it was -- we're in kernel mode so this is predictable
+           call map_kernel
+           ret
+;
+;      We must provide
+;
+;      map_kernel              -       map in the kernel, trashes nothing
+;      map_process_always      -       map in the current process, ditto
+;      map_process             -       map the pages pointed to by hl, eats
+;                                      a, hl
+;
+kmap:      .db 0x80, 0x81, 0x82, 0x83
+
+map_kernel:
+           push af
+           push hl
+           ld hl, #kmap
+           call map_process_1
+            pop hl
+           pop af
+           ret
+
+map_process_always:
+           push af
+           push hl
+           ld hl, #U_DATA__U_PAGE
+           call map_process_1
+           pop hl
+           pop af
+           ret
+
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+map_process_1:
+           ld a, i
+           push af
+           di                  ; ensure we don't take an irq mid update
+           push de
+           push bc
+           ld de, #map_current
+           ld bc, #0x3F0       ; 3 loops starting 0xf0
+                               ; we don't touch common in these functions
+map_loop:
+           ld a, (hl)
+           ld (de), a
+           out (c), a
+           inc hl
+           inc de
+           inc c
+           djnz map_loop
+           pop bc
+           pop de
+           pop af
+           ret po
+           ei
+           ret
+
+map_save:   push hl
+           push de
+           push bc
+           ld hl, #map_current
+           ld de, #map_save_area
+           ldi
+           ldi
+           ldi
+           pop bc
+           pop de
+           pop hl
+           ret
+
+map_restore:push hl
+           push af
+           ld hl, #map_save_area
+            call map_process_1
+           pop af
+            pop hl
+            ret
+;
+;      These are in common, that means that on a system that switches
+; common by task there are multiple copies of this information.
+;
+; Safe IFF we always reload the *full* map when task switching (we do)
+;
+map_current:
+           .db 0               ; need this tracked
+           .db 0               ; hardware ports are write only
+           .db 0
+; Safe because we never task switch from an IRQ while in kernel mode.
+; In user mode we won't restore the saved area anyway
+map_save_area:
+           .db 0
+           .db 0
+           .db 0
+
+
+_bugout:    pop hl
+           pop bc
+           push bc
+           push hl
+           ld b, c
+_bugoutv:
+           ld a, #0x20
+           .dw 0xfeed
+           ret
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+;
+outchar:    push bc
+           ld b, a
+           ld a, #0x20
+           .dw 0xfeed
+           pop bc
+           ret
+
+
+; FIXME: serial version below
+           push af
+outcharl:
+           xor a
+           out (0xE1), a
+           in a, (0xE1)
+           bit 2, a
+           jr z, outcharl
+           pop af
+           out (0xE0), a
+           ret
+
+           .area _CODE
+
+;
+; Video helpers. Video is in banks 4/5 for now
+;
+
+_scroll_up:
+           ld a, (roller)
+           add a, #8
+           ld (roller), a
+            out (0xf6), a
+           ret
+_scroll_down:
+           ld a, (roller)
+           sub a, #8
+           ld (roller), a
+            out (0xf6), a
+           ret
+
+           .area _COMMONMEM
+
+addr_de:    ld a, i
+           push af
+           ld a, (roller)
+           rra                 ; in text lines
+           rra
+           rra
+           and #0x1F
+           ld l, a
+           ld a, e             ; Y
+            add l              ; plus the roller
+           and #31             ; wrap
+           ; Y * 720
+           add a               ; x 2
+           add a               ; x 4
+           add a               ; x 8 ( 31 x 8 fits in 8bits)
+           push bc
+           ld l, a
+           ld h, #0
+           add hl, hl          ; x 16
+           push hl
+           add hl, hl          ; x 32
+           add hl, hl          ; x 64
+           push hl
+           add hl, hl          ; x 128
+           push hl
+           add hl, hl          ; x 256
+           add hl, hl          ; x 512
+           pop bc
+           add hl, bc          ; x 640
+           pop bc
+           add hl, bc          ; x 704
+           pop bc
+           add hl, bc          ; x 720
+           ex de, hl
+           ld l, h
+           ld h, #0
+           add hl, hl
+           add hl, hl
+           add hl, hl          ; X * 8
+           add hl, de
+           ld de, #framebuffer ; the bank base we are using
+           add hl, de
+           ex de, hl
+           ;
+           ; We don't want to take an interrupt midway through
+           ; this lot, or the restore will be of the wrong values
+           ;
+           di
+           ld a, #0x84         ; Map the video memory
+           ld (map_current + 1), a
+           inc a
+           ld (map_current + 2), a
+           out (0xf2), a
+           dec a
+           out (0xf1), a
+           pop bc
+           pop af
+           ret po
+           ei
+           ret
+_plot_char:
+           pop hl
+           pop de      ; d, e = co-ords
+           pop bc      ; c = char
+           push bc
+           push de
+           push hl
+           call addr_de        ;  returns an address in DE and maps the vram
+           ld l, c
+           ld h, #0
+           add hl, hl
+           add hl, hl
+           add hl, hl
+           ld bc, #font8x8     ;  where crt0.s stuck the font
+           add hl, bc
+           ld bc, #8
+           ldir
+           call map_kernel
+           ret
+_cursor_on:
+           pop hl
+           pop de
+           push de
+           push hl
+cursordo:
+           ld (cursorpos), de
+           call addr_de
+           ex de, hl
+            ld b, #8
+cursorl:    ld a, (hl)
+           cpl
+           ld (hl), a
+           inc hl
+           djnz cursorl
+           call map_kernel
+           ret
+_cursor_off:
+           ld de, (cursorpos)
+           jr cursordo
+
+_do_beep:
+           ret
+
+_clear_lines:
+           pop hl
+           pop de      ; E = y, D = count
+           push de
+           push hl
+           ld b, d
+           ld d, #0
+clloop:     push de
+           push bc
+           call addr_de
+           ld h, d
+           ld l, e
+           ld (hl), #0
+           inc de
+           ld bc, #719
+           ldir
+           pop bc
+           pop de
+           inc e
+           call map_kernel
+           djnz clloop
+           ret
+
+_clear_across:
+           pop hl
+           pop de      ; co-ordinates
+           pop bc      ; count in C
+           push bc
+           push de
+           push hl
+           call addr_de
+           ld b, #8
+           xor a
+           ex de, hl
+clearal:
+           ld (hl), a
+           inc hl
+           djnz clearal
+           dec c
+           jr nz, clearal
+           call map_kernel
+           ret
+
+;
+;      Need to live outside of common/code. Take care not to access them
+;      with the video bank mapped
+;
+           .area _DATA
+
+roller:            .db 0
+cursorpos:  .dw 0
diff --git a/Kernel/platform-pcw8256/tricks.s b/Kernel/platform-pcw8256/tricks.s
new file mode 100644 (file)
index 0000000..647a49d
--- /dev/null
@@ -0,0 +1,272 @@
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl dispatch_process_signal
+       .globl map_process
+       .globl map_kernel
+       .globl _swapper
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+       ld a, #'O'
+       call outchar
+       ld hl, (U_DATA__U_PTAB)
+       call outhl
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+        push de ; restore stack
+        push bc ; restore stack
+
+       push de
+       ld a, #'I'
+       call outchar
+       call outde
+       pop de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+
+        ld a, (hl)
+       or a
+       jr nz, not_swapped
+
+       ld a, #'S'
+       call outchar
+       ;
+       ; Run the swapper
+       ;
+       push hl
+       push de
+       call _swapper
+       pop de
+       pop hl
+
+not_swapped:
+       push de
+       call outde
+       pop de
+       ld hl, #P_TAB__P_PAGE_OFFSET + 3
+       add hl, de
+       ld a, (hl)              ; common page
+
+       push af
+       call outcharhex
+       pop af
+       ; ----------- Stack is switched across this instruction
+;FIXME out (0xF3), a
+
+        ; bear in mind that the stack will be switched now, so we can't use it
+       ; to carry values over this point
+
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==HL
+        jr nz, switchinfail
+
+       ld hl, #P_TAB__P_STATUS_OFFSET
+       add hl, de
+        ; next_process->p_status = P_RUNNING
+        ld (hl), #P_RUNNING
+
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+       ; ------------- Stack may be used again ------------
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+        ; --------- copy process ---------
+
+        ld hl, (fork_proc_ptr)
+        ld de, #P_TAB__P_PAGE_OFFSET
+        add hl, de
+        ; load p_page
+        ld c, (hl)
+       ld hl, (U_DATA__U_PTAB)
+       add hl, de
+       ld b, (hl)
+
+       ; in this call we will switch stack to the child copy, which has
+       ; everything below this point from the parent. We will also change
+       ; our common instance
+
+       call fork_copy                  ;       do the bank to bank copy
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+
+fork_copy:
+       ld hl, (U_DATA__U_TOP)
+       ld de, #0x0fff
+       add hl, de              ; + 0x1000 (-1 for the rounding to follow)
+       ld a, h
+       rlca
+       rlca                    ; get just the number of banks in the bottom
+                               ; bits
+       and #3
+       inc a                   ; and round up to the next bank
+       ld b, a
+       ; we need to copy the relevant chunks
+       ld hl, (fork_proc_ptr)
+       ld de, #P_TAB__P_PAGE_OFFSET
+       add hl, de
+       ; hl now points into the child pages
+       ld de, #U_DATA__U_PAGE
+       ; and de is the parent
+fork_next:
+       ld a,(hl)
+       out (0xf1), a           ; 0x4000 map the child
+       ld c, a
+       inc hl
+       ld a, (de)
+       out (0xf2), a           ; 0x8000 maps the parent
+       inc de
+       exx
+       ld hl, #0x8000          ; copy the bank
+       ld de, #0x4000
+       ld bc, #0x4000          ; we copy the whole bank, we could optimise
+                               ; further
+       ldir
+       exx
+       call map_kernel         ; put the maps back so we can look in p_tab
+       djnz fork_next
+       ld a, c
+       out (0xf3), a           ; our last bank repeats up to common
+       ; --- we are now on the stack copy, parent stack is locked away ---
+       ret                     ; this stack is copied so safe to return on
diff --git a/Kernel/platform-trs80/Makefile b/Kernel/platform-trs80/Makefile
new file mode 100644 (file)
index 0000000..b309f39
--- /dev/null
@@ -0,0 +1,25 @@
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = trs80.s crt0.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
diff --git a/Kernel/platform-trs80/README b/Kernel/platform-trs80/README
new file mode 100644 (file)
index 0000000..541ce48
--- /dev/null
@@ -0,0 +1,53 @@
+TRS80 Model 4/4P
+
+Requirements: 
+       128K RAM fitted
+       Hard disk drive (will be used for swap), or a suitable memory
+       expander board could be used with a bit of tweaking (or both!)
+
+Bank mapping on the trash 80 is a bit weird. We want to get two independent
+64K banks, but we can only have
+
+Port 0x84:
+       
+
+       0 / 1
+       0 / 2
+       0 / 3
+       2 / 1
+       3 / 1
+
+So we put the kernel in 0/3 which allows us to put the apps in 2/1. This
+means we need our kernel logic for things like bank copies not in common
+but in the low 32K.
+
+
+Unfortunately for anyone who wants to do expander board hacks the usual
+expander board hacks exchange 2/3 with other banks so unless you've also got
+the HD64180 mod you may be out of luck, and if you have well its not much
+like a Trash80 any more. Anyway if you want try you'd need to extend the
+0x84 port poking to also poke port 0x94 bits 0-4.
+
+Also we have to deal with the mapping maze on the TRS 80, not only are we
+banked but we have modes and also a pop up boot rom
+
+0x9C bit 0 controls the boot prom
+
+0x80 controls the mapping mode (bits 0/1 select a mode)
+
+Boot occurs in mode 0 with RAM at 0x4000-FFFF ready to load
+
+We need to stick it into mode 2 or 3
+
+2 = 0000-F3FF RAM
+    F400-F7FF keyboard
+    F800-FFFF Video
+
+3 = 0-FFFF RAM
+
+(and probably want to be in mode 3 and flip to 2 for video/kbd work)
+
+Need vid and kbd helps out of common therefore and to save/restore video map
+option on an irq while in kernel mode
+
+
diff --git a/Kernel/platform-trs80/commonmem.s b/Kernel/platform-trs80/commonmem.s
new file mode 100644 (file)
index 0000000..75cde2d
--- /dev/null
@@ -0,0 +1,48 @@
+;
+;      We have no real common on the TRS80so just tuck it up at the top of
+;      memory leaving room for the keyboard and video (3K)
+;
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _COMMONMEM
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
diff --git a/Kernel/platform-trs80/config.h b/Kernel/platform-trs80/config.h
new file mode 100644 (file)
index 0000000..e7fc754
--- /dev/null
@@ -0,0 +1,54 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#undef CONFIG_MULTI
+/* Single tasking */
+#define CONFIG_SINGLETASK
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* Simple character addressed device */
+#define CONFIG_VT_SIMPLE
+
+#define CONFIG_BANKS   2       /* 2 x 32K */
+
+/* Vt definitions */
+#define VT_BASE                ((uint8_t *)0xF800)
+#define VT_WIDTH       80
+#define VT_HEIGHT      25
+#define VT_RIGHT       79
+#define VT_BOTTOM      24
+
+#define TICKSPERSEC 60   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xF900))  /* Top of program, base of U_DATA */
+#define PROC_SIZE   64   /* Memory needed per process */
+
+#define SWAP_SIZE   0x80       /* 64K in blocks (we actually don't need quite all) */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0xF400      /* vectors so its a round number of sectors */
+
+#define MAX_SWAPS      8       /* Should be plenty */
+
+#define BOOT_TTY (512 + 1)      /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+#define NDEVS    17       /* Devices 0..NDEVS-1 are capable of being mounted */
+                          /*  (add new mountable devices to beginning area.) */
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  5       /* Device for swapping. */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+
+
+
+
diff --git a/Kernel/platform-trs80/crt0.s b/Kernel/platform-trs80/crt0.s
new file mode 100644 (file)
index 0000000..ddff184
--- /dev/null
@@ -0,0 +1,80 @@
+               ; Ordering of segments for the linker.
+               ; WRS: Note we list all our segments here, even though
+               ; we don't use them all, because their ordering is set
+               ; when they are first seen.     
+               .area _CODE
+               .area _CODE2
+               .area _DISCARD
+               .area _CONST
+               .area _DATA
+               .area _INITIALIZED
+               .area _BSEG
+               .area _BSS
+               .area _HEAP
+               ; note that areas below here may be overwritten by the heap at runtime, so
+               ; put initialisation stuff in here
+               .area _INITIALIZER
+               .area _GSINIT
+               .area _GSFINAL
+               .area _COMMONMEM
+
+               ; imported symbols
+               .globl _fuzix_main
+               .globl init_early
+               .globl init_hardware
+               .globl s__DATA
+               .globl l__DATA
+               .globl s__COMMONMEM
+               .globl l__COMMONMEM
+               .globl s__INITIALIZER
+               .globl kstack_top
+
+               ; startup code
+               .area _CODE
+
+;
+;      Once the loader completes it jumps here
+;
+start:
+               ld sp, #kstack_top
+               ; move the common memory where it belongs    
+               ld hl, #s__INITIALIZER
+               ld de, #s__COMMONMEM
+               ld bc, #l__COMMONMEM
+               ldir
+               ; then zero the data area
+               ld hl, #s__DATA
+               ld de, #s__DATA + 1
+               ld bc, #l__DATA - 1
+               ld (hl), #0
+               ldir
+
+;      TODO: Move the common into the other bank, pain as we may well have
+;      code in low bank and __COMMON packed in high. Needs to be in
+;      .COMMONMEM and map the other page low
+;
+               call init_early
+               call init_hardware
+               call _fuzix_main
+               di
+stop:          halt
+               jr stop
+
+
+
+
+clear:
+               ld a, b
+               or a
+               jr nz, clear_1
+               ld a, c
+               cp #2
+               ret c
+clear_1:
+               dec bc
+               ld (hl), #0
+               ld d, h
+               ld e, l
+               inc de
+               ldir
+               ret
diff --git a/Kernel/platform-trs80/devfd.c b/Kernel/platform-trs80/devfd.c
new file mode 100644 (file)
index 0000000..caabc22
--- /dev/null
@@ -0,0 +1,249 @@
+/* 
+ * TRS80 disk driver (TODO)
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+#define FD_TIMEOUT     100             /* FIXME */
+
+/* Floppy controller */
+__sfr __at 0xF0        fd_command;
+__sfr __at 0xF0        fd_status;
+#define FD_BUSY                1
+#define FD_DRQ         2
+
+#define CMD_RESET      0x0B
+#define CMD_SEEK       0x1B
+#define CMD_READ       0x8C
+#define CMD_WRITE      0xAC
+__sfr __at 0xF1 fd_track;
+__sfr __at 0xF2 fd_sector;
+__sfr __at 0xF3 fd_data;
+/* Drive select */
+__sfr __at 0xF4 fd_select;
+
+/* floppies. 26 128 byte sectors, not a nice way to use all of them in 512's */
+static int sectrack[16] = {
+    18
+};
+
+static uint8_t track[4];       /* only one controller register for all 4 drives */
+static uint8_t curdrive = 0xFF;
+static uint8_t fd_timer;
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+
+/* Replace with proper asm delay */
+static void nap(void)
+{
+    int i;
+    for(i=0;i<16;i++);
+}
+
+/* To write */
+static int fd_wait_idle(void)
+{
+    return 0xFF;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor, rawflag);
+}
+
+static uint8_t fd_seek(uint8_t track)
+{
+    uint8_t status;
+    fd_track = track;
+    nap();
+    fd_command = CMD_SEEK;
+    nap();
+    status = fd_wait_idle();
+    /* FIXME: bits of status */
+    return 0;
+}
+
+static uint8_t fd_writedata(uint8_t *dptr)
+{
+    uint8_t status;
+    irqflags_t irq;
+    uint8_t r;
+    uint16_t a;
+    
+    fd_command = CMD_WRITE;
+    nap();
+    do {
+        r = fd_status;
+        if (r & FD_DRQ) {
+            irq = di();
+            for (a = 0; a < 256; a++) {
+                fd_data = *dptr++;
+            }
+            irqrestore(irq);
+            status = fd_wait_idle();
+            /* bits of status */
+            return status & 0x5C;
+        }
+    }
+    while (r & FD_BUSY);
+    /* Went clear without asking for data */
+    return -1;
+}
+
+static uint8_t fd_readdata(uint8_t *dptr)
+{
+    uint8_t status;
+    irqflags_t irq;
+    uint8_t r;
+    unsigned int a;
+    
+    fd_command = CMD_READ;
+    nap();
+    do {
+        r = fd_status;
+        if (r & FD_DRQ) {
+            irq = di();
+            for (a = 0; a < 256; a++) {
+                *dptr++= fd_data;;
+            }
+            irqrestore(irq);
+            status = fd_wait_idle();
+            /* bits of status */
+            return status & 0x1C;
+        }
+    }
+    while (r & FD_BUSY);
+    /* Went clear without asking for data */
+    return -1;
+}
+
+static uint8_t fd_reset(void)
+{
+    uint8_t status;
+    
+    fd_command = CMD_RESET;
+    nap();
+    status = fd_wait_idle();
+    return 0;
+}
+
+static uint8_t fd_geom(int minor, blkno_t block)
+{
+    /* Turn block int track/sector 
+       and write to the controller.
+       Forced to do real / and % */
+    uint8_t trackw = block / sectrack[minor];
+    uint8_t sectorw = block % sectrack[minor];
+    uint8_t status = 0;
+
+    if (trackw != track[curdrive]) {
+        status = fd_seek(trackw);
+        track[curdrive] = trackw;
+    }
+    fd_sector = sectorw;
+    fd_timer = FD_TIMEOUT;
+    nap();
+    return status & 0x10;
+}
+
+/* Deselect drive, motor off, may be called from an IRQ */
+static void fd_deselect(void)
+{
+    if (curdrive != 0xFF) {
+        track[curdrive] = fd_track;
+        curdrive = 0xFF;
+    }
+    fd_select = 0;
+}
+
+static void sdcc_bug(void)
+{
+}
+
+static void fd_drivesel(uint8_t minor)
+{
+    irqflags_t irq = di();
+    uint8_t sdcc_tmp;
+
+    if (minor != curdrive) {
+        if (curdrive != 0xFF)
+            fd_deselect();
+        track[curdrive] = fd_track;
+        /* nap needed anywhere ? */
+        fd_track = track[minor];
+        curdrive = minor;
+        /* FIXME: check and check for spin up times */
+
+        /* Do this in two steps to stop SDCC 3.4 crashing and
+           we need the dummy call to stop it optimising it back into
+           the broken version */
+        sdcc_tmp = 1 << minor;
+        sdcc_bug();
+        fd_select = sdcc_tmp;
+    }
+    fd_timer = FD_TIMEOUT;
+    irqrestore(irq);
+}
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+    blkno_t block;
+    int block_xfer;     /* r/w return value (number of 512 byte blocks transferred) */
+    uint8_t *dptr;
+    int dlen;
+    int ct = 0;
+    int st;
+    int tries;
+
+    if(rawflag) {
+        dlen = udata.u_count;
+        dptr = udata.u_base;
+        block = udata.u_offset >> 9;
+        block_xfer = dlen >> 8;                /* 256 byte blocks */
+    } else { /* rawflag == 0 */
+        dlen = 512;
+        dptr = udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 2;
+    }
+
+    fd_drivesel(minor);
+    while (ct < block_xfer) {
+        for (tries = 0; tries < 3; tries++) {
+            fd_geom(minor, block);
+            if (tries > 0)
+                fd_reset();
+            if (is_read)
+                st = fd_readdata(dptr);
+            else
+                st = fd_writedata(dptr);
+            if (st == 0)
+                break;
+        }
+        if (tries == 3)
+            kprintf("fd%d: disk error %02X\n", st);
+        block++;
+        ct++;
+        dptr += 256;
+    }
+    return ct/2;
+}
+
+int fd_open(uint8_t minor)
+{
+    if(minor >= 3 || !sectrack[minor]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
diff --git a/Kernel/platform-trs80/devfd.h b/Kernel/platform-trs80/devfd.h
new file mode 100644 (file)
index 0000000..da2a70c
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-trs80/devices.c b/Kernel/platform-trs80/devices.c
new file mode 100644 (file)
index 0000000..c74fdd1
--- /dev/null
@@ -0,0 +1,36 @@
+#include <kernel.h>
+#include <tty.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devsys.h>
+#include <devlpr.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+  /* 0: /dev/fd                Floppy disc block devices */
+  {  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },
+  /* 1: /dev/hd                Hard disc block devices (not yet) */
+  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,      no_close,    sys_read, sys_write, sys_ioctl  },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+}
diff --git a/Kernel/platform-trs80/devlpr.c b/Kernel/platform-trs80/devlpr.c
new file mode 100644 (file)
index 0000000..65d8c43
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat;                /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag; // shut up compiler
+    return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+    minor; // shut up compiler
+    return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    int c = udata.u_count;
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(c) {
+        /* Note; on real hardware it might well be necessary to
+           busy wait a bit just to get acceptable performance */
+        while (lpstat != 0xFF) {
+//            if (psleep_flags(&clocktick, flag))
+//                return -1;
+        }
+        /* FIXME: tidy up ugetc and sysio checks globally */
+        lpdata = ugetc(p++);
+    }
+    return (-1);
+}
diff --git a/Kernel/platform-trs80/devlpr.h b/Kernel/platform-trs80/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-trs80/devtty.c b/Kernel/platform-trs80/devtty.c
new file mode 100644 (file)
index 0000000..f0dbb44
--- /dev/null
@@ -0,0 +1,55 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <stdarg.h>
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
+    {   NULL,    NULL,    NULL,    0,        0,       0    },
+    {   tbuf1,   tbuf1,   tbuf1,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf2,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 }
+};
+
+/* Write to system console */
+void kputchar(char c)
+{
+    if(c=='\n')
+        tty_putc(1, '\r');
+    tty_putc(1, c);
+}
+
+static bool tty_writeready(uint8_t minor)
+{
+    minor;
+    return 1;          /* FIXME !! */
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+    minor;c;
+    /* call vt driver */
+}
+
+void tty_pollirq(void)
+{
+    /* Keyboard scanner */
+}
+
+/* Called to set baud rate etc */
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
+
diff --git a/Kernel/platform-trs80/devtty.h b/Kernel/platform-trs80/devtty.h
new file mode 100644 (file)
index 0000000..bb6f7e6
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _DEVTTY_H
+#define _DEVTTY_H
+
+extern void tty_pollirq(void);
+
+#endif
diff --git a/Kernel/platform-trs80/kernel.def b/Kernel/platform-trs80/kernel.def
new file mode 100644 (file)
index 0000000..5342798
--- /dev/null
@@ -0,0 +1,5 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xF900       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
+
diff --git a/Kernel/platform-trs80/main.c b/Kernel/platform-trs80/main.c
new file mode 100644 (file)
index 0000000..7ba957b
--- /dev/null
@@ -0,0 +1,27 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint8_t *ramtop = PROGTOP;
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  tty_pollirq(); 
+}
+
+void do_beep(void)
+{
+}
+
+void platform_interrupt(void)
+{
+  timer_interrupt();
+}
+
+void map_init(void)
+{
+}
diff --git a/Kernel/platform-trs80/tricks.s b/Kernel/platform-trs80/tricks.s
new file mode 100644 (file)
index 0000000..dbc775f
--- /dev/null
@@ -0,0 +1,192 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl _swapper
+       .globl _swapout
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+        push de ; restore stack
+        push bc ; restore stack
+
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+
+        ld a, (hl)
+       or a
+       jr nz, not_swapped
+
+       push de
+       call _swapper
+       pop de
+
+not_swapped:
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==HL
+        jr nz, switchinfail
+
+       ld hl, #P_TAB__P_STATUS_OFFSET
+       add hl, de
+        ; next_process->p_status = P_RUNNING
+        ld (hl), #P_RUNNING
+       ld de, #P_TAB__P_PAGE_OFFSET - P_TAB__P_STATUS_OFFSET
+       add hl, de
+       ld a, (hl)
+       ld (U_DATA__U_PAGE), a
+
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ld hl, (U_DATA__U_PTAB)
+       push hl
+       call _swapout
+       pop hl
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+
diff --git a/Kernel/platform-trs80/trs80.s b/Kernel/platform-trs80/trs80.s
new file mode 100644 (file)
index 0000000..7262d25
--- /dev/null
@@ -0,0 +1,358 @@
+;
+;          TRS 80  hardware support
+;
+
+            .module trs80
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl interrupt_handler
+            .globl _program_vectors
+            .globl _system_tick_counter
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+            .globl istack_top
+            .globl istack_switched_sp
+            .globl unix_syscall_entry
+            .globl trap_illegal
+            .globl outcharhex
+           .globl nmi_handler
+           .globl null_handler
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+trapmsg:    .ascii "Trapdoor: SP="
+            .db 0
+trapmsg2:   .ascii ", PC="
+            .db 0
+tm_user_sp: .dw 0
+
+tm_stack:
+            .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+tm_stack_top:
+
+_trap_monitor:
+           ld a, #128
+           out (0x28), a
+           ret
+
+_trap_reboot:
+           ld a, #1
+           out (0x28), a
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+_ctc6845:                              ; registers in reverse order
+           .db 99, 80, 85, 10, 25, 4, 24, 24, 0, 9, 101, 9, 0, 0, 0, 0
+init_early:
+           ld a, (_opreg)
+           out (0x84), a
+           ld a, (_modout)
+           out (0xEC), a
+
+            ; load the 6845 parameters
+           ld hl, #_ctc6845
+           ld b, #1588
+ctcloop:    out (c), b                 ; register
+           ld a, (hl)
+           out (0x89), a               ; data
+           inc hl
+           djnz ctcloop
+
+           ; clear screen
+           ld hl, #0xF800
+           ld (hl), #'*'               ; debugging aid in top left
+           inc hl
+           ld de, #0xF802
+           ld bc, #1998
+           ld (hl), #' '
+           ldir
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #128
+            ld (_ramsize), hl
+            ld hl, #(128-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ; 100Hz timer on
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+opsave:            .db 0x36
+_opreg:            .db 0x36    ; kernel map, 80 columns
+_modout:    .db 0x50   ; 80 column, sound enabled, altchars off,
+                       ; external I/O enabled, 4MHz
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ld (0x0000), a   
+            ld hl, #null_handler   ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+;
+;      Fixed mapping set up for the TRS80 4/4P
+;
+;      Kernel runs mode 2, U64K/U32 mapped at L64K/U32
+;
+map_kernel_a:
+           ld a, i
+           push af
+           di
+           ld a, (_opreg)
+           and #0xAC
+           or #0x12
+           ld (_opreg), a
+           out (0x84), a
+           pop af
+           ret po
+           ei
+            ret
+map_kernel:
+           push af
+           call map_kernel_a
+           pop af
+           ret
+;
+;      Userspace mapping is mode 3, U64K/L32 mapped at L64K/L32
+;
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+           call map_process_always_a
+           ret
+
+map_process_always_a:
+           push af
+           ld a, (_opreg)
+           and #0xAC
+           or #0x43
+           ld (_opreg), a
+           out (0x84), a
+           pop af
+            ret
+
+map_process_always:
+           ld a, i
+           push af
+           di
+           call map_process_always_a
+           pop af
+           ret po
+           ei
+           ret
+
+map_save:   push af
+           ld a, (_opreg)
+           and #0x53
+           ld (opsave), a
+           pop af
+           ret
+
+map_restore:
+           push af
+           push bc
+           ld a, (opsave)
+           ld b, a
+           ld a, (_opreg)
+           and #0xAC
+           or b
+           ld (_opreg), a
+           out (0x84), a
+           ret
+           
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+            out (0x01), a
+            ret
+
+nap:
+       ; FIXME
+          ret
+;
+;      Idle the WD1772
+;
+_fd_idle:
+           in a, (0xF0)
+           rra
+           jr c, _fd_idle
+           ld l, a
+           ld h, #0
+           ret
+
+;
+;      See to a given track in C
+;
+_fd_seek:
+           ld a, c
+           out (0xF1), a               ; track #
+           ld a, #0x1B                 ; Seek
+           out (0xF0), a
+           call nap
+           call _fd_idle
+           and #0x10
+           ret
+
+
+;
+;      Write a 256 byte block to disk. Need to add precomp etc to this
+;      HL = pointer to data
+;      A = bank info (0 kernel, !0 user). We don't handle swap to floppy.
+;
+;
+_fd_write:
+           or a
+           jr z, _fd_kwrite
+           call map_process_always
+_fd_kwrite:
+           ld bc, #0x00F3              ; port F3, 256 bytes
+           ld a, i
+           push af
+           ld a, #0xAC                 ; Write
+           out (0xF0), a
+           call nap
+_fd_writel:
+           in a, (0xF0)
+           bit 1, a
+           jr z, _fd_writec
+           di
+_fd_writeb:
+           otir
+           ei
+           call _fd_idle
+           and #0x5C
+fd_wout:
+           ld l, a
+           call map_kernel
+           pop af
+           ret po
+           ei
+           ret
+_fd_writec: 
+           bit 2, a
+           jr nz, _fd_writel
+           ld a, #0xff
+           jr fd_wout
+
+
+
+;
+;      Read a 256 byte block from disk. Need to add precomp etc to this
+;      HL = pointer to data
+;      A = bank info (0 kernel, !0 user). We don't handle swap to floppy.
+;
+;
+_fd_read:
+           or a
+           jr z, _fd_kwrite
+           call map_process_always
+_fd_kread:
+           ld bc, #0x00F3              ; port F3, 256 bytes
+           ld a, i
+           push af
+           ld a, #0x8C                 ; Read
+           out (0xF0), a
+           call nap
+_fd_readl:
+           in a, (0xF0)
+           bit 1, a
+           jr z, _fd_readc
+           di
+_fd_readb:
+           inir
+           ei
+           call _fd_idle
+           and #0x5C
+fd_rout:
+           ld l, a
+           pop af
+           ret po
+           ei
+           ret
+_fd_readc: 
+           bit 2, a
+           jr nz, _fd_readl
+           ld a, #0xff
+           jr fd_rout
+
+_fdc_idle:
+       ; FIXME
+       ret
+;
+;      Restore the current drive to track 0 (error recovery)
+;
+_fd_reset:
+           ld a, #0xB
+           out (0xF0), a
+           call nap
+           call _fdc_idle
+           and #0x10
+           ret
diff --git a/Kernel/platform-trs80/trsfd.s b/Kernel/platform-trs80/trsfd.s
new file mode 100644 (file)
index 0000000..3d506a9
--- /dev/null
@@ -0,0 +1,123 @@
+
+FDCSTAT                .equ    0xF0
+FDCA           .equ    0xF0
+FDCTRK         .equ    0xF1
+FDCSEC         .equ    0xF2
+FDCDAT         .equ    0xF3
+DRVSEL         .equ    0xF4
+
+;
+;      Write a command to the FDC then nap briefly while the
+;      FDC digests it
+;
+writecmd:
+               out (FDCA), a           ; off we go
+cmd_1:                                 ; wait for controller
+               ld b, 18
+               djnz cmd_1
+               ret
+
+
+;
+;      Set the desired track
+;
+;      B = the track we think we are on
+;      C = the sector we will want
+;      D = the track we will want
+;      E = the step rate (0-3) 
+;
+seekto:                call reselect
+               out (FDCTRK), b         ; current track
+               out (FDCSEC), c         ; sector we want
+               out (FDCDATA), d        ; track we want
+               ld a, b
+               cp d                    ; do we think we are there ?
+               ld b, 0x18              ; SEEK
+               jr z, seekto_1
+               ld b, 0x1C              ; SEEK with verify
+seekto_1:      ld a, b
+               or e                    ; step rate
+               call writecmd
+               ret
+
+;
+;      Perform a read transfer once we have been through the selection
+;      process
+;
+;      d = track
+;      
+;
+;
+read_xfer:     ld c, FDCTRK
+               out (c), d              ; track we want
+               
+               call writecmd
+
+               ld bc, FDCDAT           ; 256 bytes/sector, and load c with
+                                       ; our port
+               ld e, 0x16              ; mask of bits we are checking
+;               
+;      Wait for DRQ, and then block transfer the bytes
+;
+wait_drq:      in a, (FDCSTAT)
+               and e
+               jr z, wait_drq
+               ini
+               di
+               ld a, d
+wait_go:       out (DRVSEL), a         ; wait stating
+               ini                     ; byte in
+               jr nz, wait_go          ; repeat
+;
+;      Sector data has landed
+;
+               call fdcwait
+;      status in A
+               ret
+               
+
+fdcwait:
+               in a, (FDCSTAT)
+               bit 0, a                ; need a in return so don't use the rra
+                                       ; shortcut
+               ret z                   ; not busy ???
+               ld a, drvsel
+               out (DRVSEL), a
+               jr fdcwait
+
+
+select:                push bc
+               call reselect
+               ld b, a                 ; save the status
+               rlca                    
+               rla                     ; magic - move bits 6/4 into bits 7/4
+               sraa                    
+               and 0x90
+               ld c, a
+               bit 7, a                ; double density ?
+               jr z, nocomp
+               ld a, precomp_start
+               cp d                    ; track needs precomp ?
+               jr nc, nocomp
+               set 5, c
+               ld a, drivesel
+               and 0x0f
+               or c
+
+               out (DRVSEL), a         ; select drive
+               out (DRVSEL), a         ; in case the trash80 wasn't listening
+               
+               bit 1, b                ; delay time ?
+               call z, fdcspin         ; long
+               call fdcspin            ; short (1/2 long)
+               pop bc
+               ret
+
+fdcspin:       ld b, 0x7f
+               pause...
+               ret
+
+
+
+fdc_
+
diff --git a/Kernel/platform-trs80/uzi.lnk b/Kernel/platform-trs80/uzi.lnk
new file mode 100644 (file)
index 0000000..c153200
--- /dev/null
@@ -0,0 +1,37 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF000
+-k /usr/share/sdcc/lib/z80
+-l z80
+platform-trs80/crt0.rel
+platform-trs80/commonmem.rel
+platform-trs80/trs80.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem.rel
+usermem_std-z80.rel
+platform-trs80/tricks.rel
+platform-trs80/main.rel
+timer.rel
+kdata.rel
+platform-trs80/devfd.rel
+platform-trs80/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+swap.rel
+single.rel
+vt.rel
+devsys.rel
+platform-trs80/devlpr.rel
+platform-trs80/devtty.rel
+-e
diff --git a/Kernel/platform-z80pack-lite/Makefile b/Kernel/platform-z80pack-lite/Makefile
new file mode 100644 (file)
index 0000000..2ce7afd
--- /dev/null
@@ -0,0 +1,25 @@
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = crt0.s z80pack.s
+ASRCS += tricks.s usermem.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(SDAS) $(SDASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
diff --git a/Kernel/platform-z80pack-lite/README b/Kernel/platform-z80pack-lite/README
new file mode 100644 (file)
index 0000000..0f6d3cf
--- /dev/null
@@ -0,0 +1,6 @@
+A minimal UZI target for z80pack.
+
+
+This is used to test the simple single processing mode. We run on Z80pack
+with no swap and with the OS in bank 0 and the userspace in bank 1. Common
+area is owned by the userspace and also holds the uarea.
diff --git a/Kernel/platform-z80pack-lite/bootblock.s b/Kernel/platform-z80pack-lite/bootblock.s
new file mode 100644 (file)
index 0000000..8831d4d
--- /dev/null
@@ -0,0 +1,80 @@
+;
+;      Z80pack cpmsim loads the first (128 byte) sector from the disk
+;      into memory at 0 then executes it
+;      We are a bit tight on space here
+;
+;      Floppy loader: 
+;      Our boot disc is 77 tracks of 26 x 128 byte sectors, and we put
+;      the OS on tracks 60+, which means we can put a file system in the
+;      usual place providing its a bit smaller than a whole disc.
+;
+;
+;      assemble me with zmac
+;
+               .org    0
+
+start:         jr diskload
+
+rootdev:       .dw 0                   ; patched by hand
+swapdev:       .dw 0                   ; ditto
+               .dw 0                   ; spare
+
+progress:      .db '/', '-', '\\', '|'
+
+diskload:      di
+               ld sp, stack
+               ld hl, 0x88
+               exx
+               xor a
+               ld h, a
+               ld b, a
+               out (17), a             ; sector high always 0
+               out (10), a             ; drive always 0
+               ld a, 59                ; start on track 60
+               out (11), a
+               exx
+               ld c, 15                ; number of tracks to load (48Kish)
+load_tracks:   in a, (11)
+               inc a                   ; track
+               out (11), a
+               xor a
+               out (12), a
+               ld b, 26                ; sectors
+load_sectors:  exx
+               ld a, b
+               and 3
+               add progress
+               ld l, a
+               ld a, (hl)
+               out (01), a
+               ld a, 8
+               out (01), a
+               inc b
+               exx
+
+               in a, (12)
+               inc a
+               out (12), a             ; sector
+               ld a, l
+               out (15), a             ; dma low
+               ld a, h
+               out (16), a             ; dma high
+               xor a                   ; read
+               out (13), a             ; go
+               in a, (14)              ; status
+               ld de, 128
+               add hl, de
+               djnz load_sectors       ; 26 sectors = 3328 bytes
+               dec c
+               jr nz, load_tracks
+               ld a, 0xc9              ; to help debug
+               ld (start), a
+               ld a, 13
+               out (1), a
+               ld a, 10
+               out (1), a
+               jp 0x88
+
+               .ds 25
+stack:
+               .db 0xff
\ No newline at end of file
diff --git a/Kernel/platform-z80pack-lite/commonmem.s b/Kernel/platform-z80pack-lite/commonmem.s
new file mode 100644 (file)
index 0000000..8b8684b
--- /dev/null
@@ -0,0 +1,48 @@
+;
+;      Common on z80pack-lite is at 0xF900 to give all we can to user/swap. 
+;
+
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _COMMONMEM
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
diff --git a/Kernel/platform-z80pack-lite/config.h b/Kernel/platform-z80pack-lite/config.h
new file mode 100644 (file)
index 0000000..7b5c3e5
--- /dev/null
@@ -0,0 +1,31 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#undef CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#undef CONFIG_MULTI
+/* Single tasking */
+#define CONFIG_SINGLETASK
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xF000))  /* Top of program, base of U_DATA copy */
+
+#define BOOT_TTY 9        /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+#define NDEVS    17       /* Devices 0..NDEVS-1 are capable of being mounted */
+                          /*  (add new mountable devices to beginning area.) */
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
diff --git a/Kernel/platform-z80pack-lite/crt0.s b/Kernel/platform-z80pack-lite/crt0.s
new file mode 100644 (file)
index 0000000..3941a86
--- /dev/null
@@ -0,0 +1,71 @@
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        ; WRS: Note we list all our segments here, even though
+        ; we don't use them all, because their ordering is set
+        ; when they are first seen.
+        .area _CODE
+        .area _CODE2
+        .area _CONST
+        .area _DATA
+        .area _INITIALIZED
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        ; note that areas below here may be overwritten by the heap at runtime, so
+        ; put initialisation stuff in here
+        .area _INITIALIZER
+        .area _GSINIT
+        .area _GSFINAL
+        .area _COMMONMEM
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .globl init_hardware
+        .globl s__INITIALIZER
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+        .globl s__DATA
+        .globl l__DATA
+        .globl kstack_top
+
+        ; startup code
+        .area _CODE
+init:
+        ld sp, #kstack_top
+
+       ld a, #'*'
+       out (1), a
+        ; Configure memory map
+        call init_early
+
+       ; move the common memory where it belongs    
+       ld hl, #s__INITIALIZER
+       ld de, #s__COMMONMEM
+       ld bc, #l__COMMONMEM
+       ldir
+       ld a, #'*'
+       out (1), a
+       ; then zero the data area
+       ld hl, #s__DATA
+       ld de, #s__DATA + 1
+       ld bc, #l__DATA - 1
+       ld (hl), #0
+       ldir
+       ld a, #'*'
+       out (1), a
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
diff --git a/Kernel/platform-z80pack-lite/devfd.c b/Kernel/platform-z80pack-lite/devfd.c
new file mode 100644 (file)
index 0000000..03b3fd6
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+ * z80pack fd driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+__sfr __at 10 fd_drive;
+__sfr __at 11 fd_track;
+__sfr __at 12 fd_sectorl;
+__sfr __at 13 fd_cmd;
+__sfr __at 14 fd_status;
+__sfr __at 15 fd_dmal;
+__sfr __at 16 fd_dmah;
+__sfr __at 17 fd_sectorh;
+
+/* floppies. 26 128 byte sectors, not a nice way to use all of them in 512's */
+static int sectrack[16] = {
+    26, 26, 26, 26,
+    0, 0, 0, 0,
+    128, 128, 0, 0,
+    0, 0, 0, 0
+};
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor, rawflag);
+}
+
+/* We will wrap on big disks if we ever try and support the Z80Pack P:
+   that wants different logic */
+static void fd_geom(int minor, blkno_t block)
+{
+    /* Turn block int track/sector 
+       and write to the controller.
+       Forced to do real / and % */
+    int track = block / sectrack[minor];
+    int sector = block % sectrack[minor] + 1;
+    fd_sectorl = sector & 0xFF;
+    fd_sectorh = sector >> 8;
+    fd_track = track;
+}
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t block_xfer;     /* blocks to transfer */
+    uint16_t dptr;
+    uint16_t dlen;
+    uint16_t ct = 0;
+    uint8_t st;
+    int map = 0;
+    uint16_t *page = &udata.u_page;
+
+    if(rawflag == 1) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        block = udata.u_offset.o_blkno;
+        block_xfer = dlen >> 7;                /* We want this in 128 byte sectors */
+        map = 1;
+#ifdef SWAPDEV
+    } else if (rawflag == 2) {         /* Swap device special */
+        dlen = swapcnt;
+        dptr = (uint16_t)swapbase;
+        page = &swapproc->p_page;      /* Acting on this task */
+        block = swapblk;
+        block_xfer = dlen >> 7;                /* We want this in 128 byte sectors */
+        map = 1;
+#endif        
+    } else { /* rawflag == 0 */
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 4;
+    }
+    block <<= 2;
+    /* Read the disk in four sector chunks. FIXME We ought to cache the geometry
+       and just bump sector checking for a wrap. */
+    while (ct < block_xfer) {
+        fd_drive = minor;
+        fd_geom(minor, block);
+        /* The Z80pack DMA uses the current MMU mappings... beware that
+         * is odd - but most hardware would be PIO (inir/otir etc) anyway */
+        fd_dmal = dptr & 0xFF;
+        fd_dmah = dptr >> 8;
+
+        if (map == 0)
+            fd_cmd = 1 - is_read;
+        else   /* RAW I/O - switch to user bank and issue command via
+                   a helper in common */
+            fd_bankcmd(1 - is_read, page);
+
+        st = fd_status;
+        /* Real disks would need retries */
+        if (st) {
+            kprintf("fd%d: block %d, error %d\n", minor, st, block);
+            break;
+        }
+        block++;
+        ct++;
+        dptr += 128;
+    }
+    return ct >> 2;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= 16 || !sectrack[minor]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
diff --git a/Kernel/platform-z80pack-lite/devfd.h b/Kernel/platform-z80pack-lite/devfd.h
new file mode 100644 (file)
index 0000000..f29b00a
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+void fd_bankcmd(uint16_t cmd, uint16_t *bank);
+
+#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-z80pack-lite/devices.c b/Kernel/platform-z80pack-lite/devices.c
new file mode 100644 (file)
index 0000000..02b96ec
--- /dev/null
@@ -0,0 +1,50 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devmem.h>
+#include <devzero.h>
+#include <devnull.h>
+#include <devproc.h>
+#include <devlpr.h>
+#include <devtty.h>
+
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* Floppy disc block devices  */
+  {  0,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   0   /dev/fd0
+  {  1,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   1   /dev/fd1
+  {  2,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   2   /dev/rd2
+  {  3,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   3   /dev/rd3
+  /* Hard disc block devices */
+  {  8,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   4   /dev/sd0 
+  {  9,  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   5   /dev/sd1 
+  {  10, fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },   //   6   /dev/sd2 
+  /* Devices below here are not mountable (as per NDEVS) */
+  {  0, lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },  //  7   /dev/lp  
+  {  0, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  8   /dev/tty
+  {  1, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  9   /dev/tty1
+  {  2, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  10   /dev/tty2
+  {  3, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  11   /dev/tty3
+  {  4, tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },  //  12   /dev/tty4
+  {  0, no_open,      no_close,    null_read, null_write, no_ioctl  },  //  13   /dev/null
+  {  0, no_open,      no_close,    zero_read, no_rdwr,    no_ioctl  },  //  14   /dev/zero
+  {  0, no_open,      no_close,    mem_read,  mem_write,  no_ioctl  },  //  15   /dev/kmem
+  {  0, no_open,      no_close,    proc_read, no_rdwr, proc_ioctl}      //  16   /dev/proc
+  /* Add more tty channels here if available, incrementing minor# */
+};
+
+bool validdev(uint8_t dev)
+{
+    if(dev >= (sizeof(dev_tab)/sizeof(struct devsw)))
+        return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+}
diff --git a/Kernel/platform-z80pack-lite/devlpr.c b/Kernel/platform-z80pack-lite/devlpr.c
new file mode 100644 (file)
index 0000000..65d8c43
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat;                /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag; // shut up compiler
+    return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+    minor; // shut up compiler
+    return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    int c = udata.u_count;
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(c) {
+        /* Note; on real hardware it might well be necessary to
+           busy wait a bit just to get acceptable performance */
+        while (lpstat != 0xFF) {
+//            if (psleep_flags(&clocktick, flag))
+//                return -1;
+        }
+        /* FIXME: tidy up ugetc and sysio checks globally */
+        lpdata = ugetc(p++);
+    }
+    return (-1);
+}
diff --git a/Kernel/platform-z80pack-lite/devlpr.h b/Kernel/platform-z80pack-lite/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-z80pack-lite/devtty.c b/Kernel/platform-z80pack-lite/devtty.c
new file mode 100644 (file)
index 0000000..f848779
--- /dev/null
@@ -0,0 +1,78 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+__sfr __at 0 tty1stat;
+__sfr __at 1 tty1data;
+__sfr __at 40 tty2stat;
+__sfr __at 41 tty2data;
+__sfr __at 42 tty3stat;
+__sfr __at 43 tty3data;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+char tbuf3[TTYSIZ];
+
+struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
+    {   NULL,    NULL,    NULL,    0,        0,       0    },
+    {   tbuf1,   tbuf1,   tbuf1,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf2,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 }
+    {   tbuf3,   tbuf3,   tbuf3,   TTYSIZ,   0,   TTYSIZ/2 }
+};
+
+/* Console print */
+void kputchar(char c)
+{
+    /* handle CRLF */
+    if(c=='\n')
+        tty_putc(1, '\r');
+    tty_putc(1, c);
+}
+
+static bool tty_writeready(uint8_t minor)
+{
+    uint8_t s;
+
+    if (minor == 1)
+        return 1;
+    if (minor == 2)
+        s = tty2stat;
+    else
+        s = tty3stat;
+    return s & 2;
+}
+
+void tty_putc(uint8_t minor, char c)
+{
+    if (minor == 1)
+        tty1data = c;
+    else if (minor == 2)
+        tty2data = c;
+    else
+        tty3data = c;
+}
+
+/* Called every timer tick */
+void tty_pollirq(void)
+{
+    unsigned char c;   /* sdcc bug workaround */
+    while(tty1stat) {
+        c = tty1data;
+        tty_inproc(1, c);
+    }
+    while(tty2stat & 1) {
+        c = tty2data;
+        tty_inproc(2, c);
+    }
+    while(tty3stat & 1) {
+        c = tty3data;
+        tty_inproc(3, c);
+    }
+    if (tty2stat & 2)
+        wakeup(&ttydata[2]);
+    if (tty3stat & 2)
+        wakeup(&ttydata[3]);
+}    
diff --git a/Kernel/platform-z80pack-lite/devtty.h b/Kernel/platform-z80pack-lite/devtty.h
new file mode 100644 (file)
index 0000000..5c9830b
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#define TIOCGETP  0
+#define TIOCSETP  1
+#define TIOCSETN  2
+#define TIOCEXCL  3     /** currently not implemented  SN **/
+#define UARTSLOW  4     /* Normal interrupt routine (UZI280) */
+#define UARTFAST  5     /* Fast interrupt routine for modem usage (UZI280) */
+#define TIOCFLUSH 6
+#define TIOCGETC  7
+#define TIOCSETC  8
+              /* UZI280 extensions used by UZI180 in the CP/M 2.2 Emulator */
+#define TIOCTLSET 9     /* Don't parse ctrl-chars */
+#define TIOCTLRES 10    /* Normal Parse */
+
+#define XTABS   0006000
+#define RAW     0000040
+#define CRMOD   0000020
+#define ECHO    0000010
+#define LCASE   0000004
+#define CBREAK  0000002
+#define COOKED  0000000
+
+#define DFLT_MODE  (XTABS|CRMOD|ECHO|COOKED)
+
+#define CTRL(c)  (c & 0x1f)
+
+/* Character Input Queue size */
+#define TTYSIZ 132
+
+struct tty_data {
+    char t_ispeed;
+    char t_ospeed;
+    char t_erase;
+    char t_kill;
+    int  t_flags;
+
+    char t_intr;
+    char t_quit;
+    char t_start;
+    char t_stop;
+    char t_eof;
+
+    char ctl_char;
+};
+
+void tty_echo(uint8_t minor, char c);
+int tty_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int tty_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int tty_open(uint8_t minor, uint16_t flag);
+int tty_close(uint8_t minor);
+int tty_ioctl(uint8_t minor, uint16_t request, char *data);
+void tty_putc_wait(uint8_t minor, char c);
+void tty_inproc(uint8_t minor, char c);
+void tty_outproc(uint8_t minor);
+void tty_putc(uint8_t minor, char c);
+bool tty_writeready(uint8_t minor);
+void tty_pollirq(void);
+#endif
diff --git a/Kernel/platform-z80pack-lite/kernel.def b/Kernel/platform-z80pack-lite/kernel.def
new file mode 100644 (file)
index 0000000..7097f8e
--- /dev/null
@@ -0,0 +1,4 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xF000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
diff --git a/Kernel/platform-z80pack-lite/main.c b/Kernel/platform-z80pack-lite/main.c
new file mode 100644 (file)
index 0000000..911fb01
--- /dev/null
@@ -0,0 +1,14 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  tty_pollirq(); 
+}
+
+/* The simple support does all the rest of the work for us */
\ No newline at end of file
diff --git a/Kernel/platform-z80pack-lite/tricks.s b/Kernel/platform-z80pack-lite/tricks.s
new file mode 100644 (file)
index 0000000..571bb26
--- /dev/null
@@ -0,0 +1,257 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl bankfork
+       .globl _swapper
+       .globl _swapout
+       .globl map_process_a
+       .globl map_process_always
+       .globl map_kernel
+       .globl _ramtop
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; ramtop must be in common for single process swapping cases
+
+_ramtop:
+       .dw 0
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine until now, but isn't safe once we swap as we will
+       ;       page in a stack over the one we are using
+       ;
+       ;       it would be nice to avoid the swapstack, but it's not
+       ;       obvious how at this point.
+       ;
+       ld sp, #_swapstack
+       call map_process_always ; we are going to scribble over the process
+       push de
+       push hl                 ; not the kernel image!
+       push de
+       call _swapper
+       pop de
+       pop hl
+       pop de
+       call map_kernel
+       ld a, #1                ; we are not swapped out
+       ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de
+       ld (hl), a
+not_swapped:
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld hl, #P_TAB__P_STATUS_OFFSET
+       add hl, de
+       ld (hl), #P_RUNNING
+
+       ld (U_DATA__U_PAGE), a  ; save page offset
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+       ld hl, #0
+       add hl, sp
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+        ; --------- copy process ---------
+
+        ld hl, #U_DATA__U_PAGE
+       ld a, (hl)
+       call map_process_a
+       ld hl, (U_DATA__U_PTAB)
+       push hl
+       call _swapout
+       pop de
+       call map_kernel
+       ld a, h
+       or l
+       jr z, forked_ok
+       ;
+       ;       Gone wrong, unwind the stack and return -1
+       ;
+       pop iy
+       pop ix
+       pop hl
+       ld hl, #0xFFFF
+       ret
+
+forked_ok:
+       ; Copy done
+
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+       ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de                      ; de holds parent ptptr
+       ld (hl), #0                     ; mark swapped out
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+
+       .ds 128
+_swapstack:
diff --git a/Kernel/platform-z80pack-lite/usermem.s b/Kernel/platform-z80pack-lite/usermem.s
new file mode 100644 (file)
index 0000000..341a010
--- /dev/null
@@ -0,0 +1,327 @@
+;
+;      We can't flip arbitary pairs of banks into memory so this one
+;      is quite horrid. Defintiely worth optimising
+;
+        .module usermem
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        ; exported symbols
+        .globl _uget
+        .globl _ugetc
+        .globl _ugets
+        .globl _ugetw
+
+        .globl _uput
+        .globl _uputc
+        .globl _uputw
+        .globl _uzero
+
+       .globl bankfork
+;
+;      We need these in common as we don't have flexible banks
+;
+        .area _COMMONMEM
+bouncebuffer:
+       .ds 256
+
+uputget:
+        ; load HL with the source address
+        ld l, 4(ix) ; src address
+        ld h, 5(ix)
+        ; load DE with destination address (in userspace)
+        ld e, 6(ix)
+        ld d, 7(ix)
+        ; load BC with the byte count
+        ld c, 8(ix) ; byte count
+        ld b, 9(ix)
+       ld a, b
+       or c
+       ret
+
+
+;
+;      Copy a block of bytes, length in bc
+;      HL = source, DE = dest, A = dest bank A' = source bank
+;
+;      On return BC trashed, HL = next source to fetch
+;      DE = next dest to use
+;
+copyio:
+       ex af,af
+       out (21), a             ; source bank
+       ex af,af
+       push de
+       ld de, #bouncebuffer
+       push bc
+       ldir
+       out (21), a
+       pop bc
+       pop de
+       push hl
+       ld hl, #bouncebuffer
+       ldir
+       pop hl
+       ret     
+       
+copyblock:
+       inc b
+       dec b                   ; check if B is 0
+       jr z, copytail          ; just a tail
+copyloop:
+       push bc
+       ld bc, #0x100           ; do 256 byte blocks
+       call copyio
+       pop bc
+       djnz copyloop
+copytail:
+       ; on entry B will be 0 already, C will be the residue
+       inc c
+       dec c
+       call nz, copyio
+       xor a
+       out (21), a
+       ret
+
+
+_uputc:
+       pop bc  ;       return
+       pop de  ;       char
+       pop hl  ;       dest
+       push hl
+       push de
+       push bc
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+        ; load HL with destination address (in userspace)
+       ld a, (U_DATA__U_PAGE)          ; we use the first byte for our bank
+       out (21), a                     ; stack gone for a walk
+       ld (hl), e
+uputc_out:
+       xor a
+       out (21), a             ; map kernel back
+       
+       ; Preserve HL as we use this path for ugetc/w returns
+       pop af
+       ret po
+       ei
+       ret
+
+_uputw:
+       pop bc  ;       return
+       pop de  ;       word
+       pop hl  ;       dest
+       push hl
+       push de
+       push bc
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+        ; load HL with destination address (in userspace)
+       ld a, (U_DATA__U_PAGE)          ; we use the first byte for our bank
+       out (21), a                     ; stack gone for a walk
+       ld (hl), e
+       inc hl
+       ld (hl), d
+       jr uputc_out
+
+_ugetc:
+       pop bc  ; return
+       pop hl  ; address
+       push hl
+       push bc
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+        ; load HL with source address (in userspace)
+       ld a, (U_DATA__U_PAGE)          ; we use the first byte for our bank
+       out (21), a                     ; stack gone for a walk
+        ld l, (hl)
+       ld h, #0
+        jr uputc_out
+
+_ugetw:
+       pop bc  ; return
+       pop hl  ; address
+       push hl
+       push bc
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+        ; load HL with source address (in userspace)
+       ld a, (U_DATA__U_PAGE)          ; we use the first byte for our bank
+       out (21), a                     ; stack gone for a walk
+        ld a, (hl)
+       inc hl
+       ld h, (hl)
+       ld l, a
+        jr uputc_out
+
+_uget:
+        push ix
+        ; stack has: ix, return address, source, dest, count. 
+        ;                                ix+4    ix+6  ix+8
+        ld ix, #0   ; load ix with stack pointer
+        add ix, sp
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+       call uputget
+       jp z, uput_out
+       ld a, (U_DATA__U_PAGE)  ; A' is source (process)
+       ex af, af
+       xor a                   ; A is dest (kernel)
+       call copyblock
+       jr uput_out
+
+
+_uput:
+        push ix
+        ; stack has: ix, return address, source, dest, count. 
+        ;                                ix+4    ix+6  ix+8
+        ld ix, #0   ; load ix with stack pointer
+        add ix, sp
+        ; store interrupt state, disable interrupts
+       ; FIXME: may not be reliable on an NMOS Z80 (review erratum)
+        ld a, i
+        di
+        push af
+       call uputget            ; DE = dest, HL = src, BC = count
+       jr z, uput_out
+
+                               ; copy up to 256 bytes into the bounce
+                               ; buffer
+       xor a                   ; A' is source (kernel)
+       ex af, af
+       ld a, (U_DATA__U_PAGE)  ; A is dest (process)
+       call copyblock
+uput_out:
+       pop af
+       pop ix
+       ret po
+       ei
+       ret
+
+;
+;      Crap implementation for now
+;
+;      Given all the bounce buffers needed and the fact that we know
+;      that
+;      a) there is no MMIO to hit
+;      b) the kernel side buffer is always big enough for worst
+;         case
+;
+;      FIXME:
+;      We just block copy the lot. We ought to trim the length according
+;      to userspace end first
+;
+_ugets:
+        push ix
+        ; stack has: ix, return address, source, dest, count. 
+        ;                                ix+4    ix+6  ix+8
+        ld ix, #0   ; load ix with stack pointer
+        add ix, sp
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+       call uputget
+       jr z, uput_out
+       push de                 ; save pointer
+       push bc                 ; save length
+       ld a, (U_DATA__U_PAGE)  ; A' is source (process)
+       ex af, af
+       xor a                   ; A is dest (kernel)
+       call copyblock
+       pop hl                  ; recover them but in HL
+       pop bc
+ugets_0:ld a, (hl)             ; find an end marker
+       or a
+       jr z, ugets_good
+       dec bc
+       ld a, b
+       or c
+       jr nz, ugets_0
+       dec hl
+       ld (hl), #0
+       ld hl, #0xffff                  ; flag as bad
+       jr uput_out
+ugets_good:
+       ld hl, #0                       ; return 0
+       jr uput_out
+;
+;      No bounce buffer needed as we are just filling the target
+;
+_uzero:
+       pop de  ; return
+       pop hl  ; address
+       pop bc  ; size
+       push bc
+       push hl 
+       push de
+       ld a, b ; check for 0 copy
+       or c
+       ret z
+        ; store interrupt state, disable interrupts
+        ld a, i
+        di
+        push af
+       ld a, (U_DATA__U_PAGE)          ; we use the first byte for our bank
+       out (21), a                     ; stack gone for a walk
+       ld (hl), #0
+       dec bc
+       ld a, b
+       or c
+       jp z, uputc_out
+       ld e, l
+       ld d, h
+       inc de
+       ldir
+       jp uputc_out
+
+
+;
+;      This is related so we will keep it here. Copy the process memory
+;      for a fork. a is the page base of the parent, c of the child
+;      (this API will be insufficient once we have chmem and proper use of
+;      banks - as well as needing to support fork to disk)
+;
+;      Assumption - fits into a fixed number of whole 256 byte blocks
+;
+bankfork:
+;      ld bc, #(0xC000 - 768)          ;       48K minus the uarea stash
+
+       ld b, #0xBD             ; C0 x 256 minus 3 sets for the uarea stash
+       ld hl, #0               ; base of memory to fork (vectors included)
+bankfork_1:
+       push bc                 ; Save our counter and also child offset
+       push hl
+       out (21), a             ; switch to parent bank
+       ld de, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the bounce buffer
+       pop de                  ; recover source of copy to bounce
+                               ; as destination in new bank
+       pop bc                  ; recover child port number
+       push bc
+       ld b, a                 ; save the parent bank id
+       ld a, c                 ; switch to the child
+       out (21), a
+       push bc                 ; save the bank pointers
+       ld hl, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the child
+       pop bc                  ; recover the bank pointers
+       ex de, hl               ; destination is now source for next bank
+       ld a, b                 ; parent back is wanted in a
+       pop bc
+       djnz bankfork_1         ; rinse, repeat
+       ret
+
diff --git a/Kernel/platform-z80pack-lite/uzi.lnk b/Kernel/platform-z80pack-lite/uzi.lnk
new file mode 100644 (file)
index 0000000..ebf0d97
--- /dev/null
@@ -0,0 +1,36 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF000
+-k /usr/share/sdcc/lib/z80
+-l z80
+platform-z80pack-lite/crt0.rel
+platform-z80pack-lite/commonmem.rel
+platform-z80pack-lite/z80pack.rel
+platform-z80pack-lite/main.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-z80pack-lite/usermem.rel
+platform-z80pack-lite/tricks.rel
+timer.rel
+kdata.rel
+platform-z80pack-lite/devfd.rel
+platform-z80pack-lite/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_fs.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+single.rel
+devnull.rel
+devzero.rel
+devproc.rel
+devmem.rel
+platform-z80pack-lite/devlpr.rel
+platform-z80pack-lite/devtty.rel
+-e
diff --git a/Kernel/platform-z80pack-lite/z80pack.s b/Kernel/platform-z80pack-lite/z80pack.s
new file mode 100644 (file)
index 0000000..49358b6
--- /dev/null
@@ -0,0 +1,352 @@
+;
+;      Z80Pack hardware support
+;
+;
+;      This goes straight after udata for common. Because of that the first
+;      256 bytes get swapped to and from disk with the uarea (512 byte disk
+;      blocks). This isn't a problem but don't put any variables in here.
+;
+;      If you make this module any shorter, check what follows next
+;
+
+
+            .module z80pack
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl interrupt_handler
+            .globl _program_vectors
+            .globl _system_tick_counter
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_a
+           .globl map_process_always
+           .globl _fd_bankcmd
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+            .globl _inint
+            .globl _tty_inproc
+            .globl istack_top
+            .globl istack_switched_sp
+            .globl dispatch_process_signal
+            .globl unix_syscall_entry
+            .globl trap_illegal
+            .globl _timer_interrupt
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+           .globl nmi_handler
+           .globl _tty_pollirq
+           .globl _ssig
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_trap_monitor:
+           ld a, #128
+           out (29), a
+           ret
+
+_trap_reboot:
+           ld a, #1
+           out (29), a
+
+;
+;      We need the right bank present when we cause the transfer
+;
+_fd_bankcmd:pop de             ; return
+           pop bc              ; command
+           pop hl              ; bank
+           push hl
+           push bc
+           push de             ; fix stack
+           ld a, i
+           di
+           push af             ; save DI state
+           call map_process    ; (HL) holds our bank
+           ld a, c             ; issue the command
+           out (13), a         ;
+           call map_kernel     ; return to kernel mapping
+           pop af
+           ret po
+           ei
+           ret
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+           ld a, #192                  ; 192 * 256 bytes (48K)
+           out (22), a                 ; set up memory banking
+           ld a, #2    
+           out (20), a                 ; 2 segments
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #128
+            ld (_ramsize), hl
+            ld hl, #(128-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ld a, #1
+           out (27), a                 ; 100Hz timer on
+
+            ; set up interrupt vectors for the kernel
+           ; (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page pointer or NULL for kernel
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ; Set vector for jump to NULL
+            ld (0x0000), a   
+            ld hl, #null_handler  ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+           ; our platform has a "true" common area, if it did not we would
+           ; need to copy the "common" code into the common area of the new
+           ; process.
+
+            ; put the MMU back as it was -- we're in kernel mode so this is predictable
+
+           ;
+           ; Map in the kernel
+           ;
+map_kernel:
+           xor a
+           out (21), a
+            ret
+           ;
+           ; Map in the current user process
+           ;
+map_process_always:
+           ld a, #1
+           out (21), a
+           ret
+           ;
+           ; Map in a process. HL pointers to the base of the 4 bytes of
+           ; page data or is NULL for kernel mapping
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+           ld a, (hl)
+           ;
+           ; Map the process page in A. Handy local helper rather than generally
+           ; useful in all cases
+           ;
+map_process_a:
+           out (21), a
+            ret
+
+;
+;      Very simple IRQ handler, we get interrupts at 100Hz and we have to
+;      poll ttys from it. The more logic we could move to common code here the
+;      better. 
+;
+interrupt_handler:
+            ; store machine state
+            ; we arrive here via the trampoline at 0038h with interrupts disabled
+            ; save CPU registers (restored in _IRET)
+            ex af,af'
+            push af
+            ex af,af'
+            exx
+            push bc
+            push de
+            push hl
+            exx
+            push af
+            push bc
+            push de
+            push hl
+            push ix
+            push iy
+
+            ld hl, (_system_tick_counter)
+            inc hl
+            ld (_system_tick_counter), hl
+           ; FIXME: add profil support here (need to keep profil ptrs
+           ; unbanked if so ?)
+
+            ; don't allow us to run re-entrant, we've only got one interrupt stack
+            ld a, (U_DATA__U_ININTERRUPT)
+            or a
+            jp nz, interrupt_return
+            inc a
+            ld (U_DATA__U_ININTERRUPT), a
+
+            ; switch stacks
+            ld (istack_switched_sp), sp
+           ; the istack is not banked (very important!)
+            ld sp, #istack_top
+
+            ; remember MMU mapping
+           in a, (21)
+            push af ; store MMU mapping
+
+            ; do we need to map in the kernel?
+           or a
+           jr z, in_kernel
+
+            ; we're not in kernel mode, check for signals and fault
+           ; might be good to fix all the vectors in this case ?
+           ld a, (0)
+           cp #0xC3            ; should be a jump
+           jr z, nofault
+           ld a, #0xC3         ; put it back
+           ld (0), a
+           ld hl, #11          ; SIGSEGV
+           call trap_signal    ; signal the user with a fault
+           
+nofault:
+           xor a
+           out (21), a
+in_kernel:
+            ; set inint to true
+            ld a, #1
+            ld (_inint), a
+
+           ; our tty devices are polled so we need to check the fifo
+           ; on interrupt
+           call _tty_pollirq
+           ; this may task switch if not within a system call
+           ; if we switch then istack_switched_sp is out of date.
+           ; When this occurs we will exit via the resume path 
+            call _timer_interrupt
+
+            xor a
+            ld (_inint), a
+
+           ; we may have changed mapping once we allow for brk and low
+           ; stack or disk swapping
+            pop af ; recover previous MMU mapping
+           or a   ; kernel mode is always the same
+           jr z, in_kernel_2
+           ld hl, #U_DATA__U_PAGE      ; recover the current mapping
+           ld a, (hl)
+in_kernel_2:
+           out (21), a
+
+            ld sp, (istack_switched_sp)        ; stack back
+
+            xor a
+            ld (U_DATA__U_ININTERRUPT), a
+
+            ld a, (U_DATA__U_INSYS)
+            or a
+            jr nz, interrupt_return
+
+            call dispatch_process_signal
+
+interrupt_return:
+            pop iy
+            pop ix
+            pop hl
+            pop de
+            pop bc
+            pop af
+            exx
+            pop hl
+            pop de
+            pop bc
+            exx
+            ex af, af'
+            pop af
+            ex af, af'
+            ei
+            ret
+
+;  Enter with HL being the signal to send ourself
+trap_signal:
+            push hl
+           ld hl, (U_DATA__U_PTAB);
+            push hl
+            call _ssig
+            pop hl
+            pop hl
+           ret
+
+;  Called from process context (hopefully)
+null_handler:
+           ; kernel jump to NULL is bad
+           in a, (21)
+           or a
+           jp z, trap_illegal
+           ; user is merely not good
+            ld hl, #7
+            push hl
+           ld hl, (U_DATA__U_PTAB)
+            push hl
+           ld hl, #10          ; signal (getpid(), SIGBUS)
+            rst #0x30          ; syscall
+            pop hl
+            pop hl
+            ld hl, #0
+            rst #0x30          ; exit
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           out (0x01), a
+            ret
diff --git a/Kernel/platform-z80pack/Makefile b/Kernel/platform-z80pack/Makefile
new file mode 100644 (file)
index 0000000..2b56907
--- /dev/null
@@ -0,0 +1,25 @@
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = crt0.s z80pack.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
diff --git a/Kernel/platform-z80pack/README b/Kernel/platform-z80pack/README
new file mode 100644 (file)
index 0000000..1c3cf49
--- /dev/null
@@ -0,0 +1,45 @@
+An UZI target for z80pack.
+
+Z80Pack has a simple 4K fixed common and 60K fixed sized banks. We run UZI
+with one application per bank and the memory map currently is
+
+Bank 0:
+
+0000-0080      Vectors
+0081-0084      Saved CP/M command info
+0088           UZI kernel start
+????           UZI kernel end ~= A000
+End of kernel: Common >= 0xF000
+               uarea
+               uarea stack
+               interrupt stack
+               bank switching code
+               user memory access copy
+               bank copy buffer because Z80Pack switching is slow
+               interrupt vectors and glue
+               [Possibly future move the buffers up here to allow for more
+                disk and inode buffer ?]
+FFFF           Hard end of kernel room
+
+Bank 1 to Bank n:
+0000           Vector copy
+0080           free
+0100           Application
+ECFF           Application end
+ED00-EFFF      uarea stash
+
+CP/M emulation size is very limited short of figuring a hack way to have
+a shared emulator in highmem, even then not great.
+
+Disk swap device recommended
+
+
+Put the kernel at the end of a floppy image from cyl 60
+Add the fs in the first 60 cyls (390 blocks)
+Put the bootblock in sector 0
+
+dd the kernel image to offset 199680
+
+ie
+
+dd if=uzi.bin of=drivea.img bs=1 seek=199680 conv=nontruc
diff --git a/Kernel/platform-z80pack/bootblock.s b/Kernel/platform-z80pack/bootblock.s
new file mode 100644 (file)
index 0000000..46f9302
--- /dev/null
@@ -0,0 +1,80 @@
+;
+;      Z80pack cpmsim loads the first (128 byte) sector from the disk
+;      into memory at 0 then executes it
+;      We are a bit tight on space here
+;
+;      Floppy loader: 
+;      Our boot disc is 77 tracks of 26 x 128 byte sectors, and we put
+;      the OS on tracks 60+, which means we can put a file system in the
+;      usual place providing its a bit smaller than a whole disc.
+;
+;
+;      assemble me with zmac
+;
+               .org    0
+
+start:         jr diskload
+
+rootdev:       .dw 0                   ; patched by hand
+swapdev:       .dw 0                   ; ditto
+               .dw 0                   ; spare
+
+progress:      .db '/', '-', '\\', '|'
+
+diskload:      di
+               ld sp, stack
+               ld hl, 0x88
+               exx
+               xor a
+               ld h, a
+               ld b, a
+               out (17), a             ; sector high always 0
+               out (10), a             ; drive always 0
+               ld a, 59                ; start on track 60
+               out (11), a
+               exx
+               ld c, 17                ; number of tracks to load (56Kish)
+load_tracks:   in a, (11)
+               inc a                   ; track
+               out (11), a
+               xor a
+               out (12), a
+               ld b, 26                ; sectors
+load_sectors:  exx
+               ld a, b
+               and 3
+               add progress
+               ld l, a
+               ld a, (hl)
+               out (01), a
+               ld a, 8
+               out (01), a
+               inc b
+               exx
+
+               in a, (12)
+               inc a
+               out (12), a             ; sector
+               ld a, l
+               out (15), a             ; dma low
+               ld a, h
+               out (16), a             ; dma high
+               xor a                   ; read
+               out (13), a             ; go
+               in a, (14)              ; status
+               ld de, 128
+               add hl, de
+               djnz load_sectors       ; 26 sectors = 3328 bytes
+               dec c
+               jr nz, load_tracks
+               ld a, 0xc9              ; to help debug
+               ld (start), a
+               ld a, 13
+               out (1), a
+               ld a, 10
+               out (1), a
+               jp 0x88
+
+               .ds 25
+stack:
+               .db 0xff
\ No newline at end of file
diff --git a/Kernel/platform-z80pack/commonmem.s b/Kernel/platform-z80pack/commonmem.s
new file mode 100644 (file)
index 0000000..c38d8e1
--- /dev/null
@@ -0,0 +1,55 @@
+;
+;      Common on z80pack is at 0xC000 as defined by hardware. We need to
+; look at sensible uses for the rest of it (eg relocating and extending the
+; buffer cache)
+;
+
+        .module commonmem
+
+        ; exported symbols
+        .globl _ub
+        .globl _udata
+        .globl kstack_top
+        .globl istack_top
+        .globl istack_switched_sp
+
+        .area _COMMONMEM
+
+_ub:    ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+        ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+        .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
+;
+;      Padding so we can read/write uarea easily. We have tons of common
+;      free so can be quite relaxed about it all
+;
+       .ds 0x100
diff --git a/Kernel/platform-z80pack/config.h b/Kernel/platform-z80pack/config.h
new file mode 100644 (file)
index 0000000..fa5704a
--- /dev/null
@@ -0,0 +1,47 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 8 60K banks, 1 is kernel */
+#define MAX_MAPS       7
+#define MAP_SIZE       0xF000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   1
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    ((char *)(0x0100))  /* also data base */
+#define PROGTOP     ((char *)(0xED00))  /* Top of program, base of U_DATA copy */
+#define PROC_SIZE   60   /* Memory needed per process */
+
+#define SWAP_SIZE   0x78       /* 60K in blocks (we actually don't need the low 256) */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0xF000      /* vectors so its a round number of sectors */
+#define MAX_SWAPS      64      /* The full drive would actually be 85! */
+
+#define UDATA_BLOCKS   0       /* We swap the stash not the uarea */
+#define UDATA_SWAPSIZE 0
+
+#define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  (256 + 1)  /* Device for swapping. (z80pack drive J) */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
diff --git a/Kernel/platform-z80pack/crt0.s b/Kernel/platform-z80pack/crt0.s
new file mode 100644 (file)
index 0000000..95969bc
--- /dev/null
@@ -0,0 +1,67 @@
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        ; WRS: Note we list all our segments here, even though
+        ; we don't use them all, because their ordering is set
+        ; when they are first seen.
+        .area _CODE
+        .area _CODE2
+       .area _DISCARD          ;        not discarded yet
+        .area _CONST
+        .area _DATA
+        .area _INITIALIZED
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        ; note that areas below here may be overwritten by the heap at runtime, so
+        ; put initialisation stuff in here
+        .area _INITIALIZER
+        .area _GSINIT
+        .area _GSFINAL
+        .area _COMMONMEM
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .globl init_hardware
+        .globl s__INITIALIZER
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+        .globl s__DATA
+        .globl l__DATA
+        .globl kstack_top
+
+        ; startup code
+        .area _CODE
+init:
+        di
+        ld sp, #kstack_top
+
+        ; Configure memory map
+        call init_early
+
+       ; move the common memory where it belongs    
+       ld hl, #s__INITIALIZER
+       ld de, #s__COMMONMEM
+       ld bc, #l__COMMONMEM
+       ldir
+       ; then zero the data area
+       ld hl, #s__DATA
+       ld de, #s__DATA + 1
+       ld bc, #l__DATA - 1
+       ld (hl), #0
+       ldir
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
diff --git a/Kernel/platform-z80pack/devfd.c b/Kernel/platform-z80pack/devfd.c
new file mode 100644 (file)
index 0000000..2399e55
--- /dev/null
@@ -0,0 +1,152 @@
+/* 
+ * z80pack fd driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+__sfr __at 10 fd_drive;
+__sfr __at 11 fd_track;
+__sfr __at 12 fd_sectorl;
+__sfr __at 13 fd_cmd;
+__sfr __at 14 fd_status;
+__sfr __at 15 fd_dmal;
+__sfr __at 16 fd_dmah;
+__sfr __at 17 fd_sectorh;
+
+/* floppies. 26 128 byte sectors, not a nice way to use all of them in 512's */
+static int sectrack[16] = {
+    26, 26, 26, 26,
+    0, 0, 0, 0,
+    128, 128, 0, 0,
+    0, 0, 0, 0
+};
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor, rawflag);
+}
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(true, minor + 8, rawflag);
+}
+
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(false, minor + 8, rawflag);
+}
+
+/* We will wrap on big disks if we ever try and support the Z80Pack P:
+   that wants different logic */
+static void fd_geom(int minor, blkno_t block)
+{
+    /* Turn block int track/sector 
+       and write to the controller.
+       Forced to do real / and % */
+    int track = block / sectrack[minor];
+    int sector = block % sectrack[minor] + 1;
+    fd_sectorl = sector & 0xFF;
+    fd_sectorh = sector >> 8;
+    fd_track = track;
+}
+
+static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t block_xfer;     /* blocks to transfer */
+    uint16_t dptr;
+    uint16_t dlen;
+    uint16_t ct = 0;
+    uint8_t st;
+    int map = 0;
+    uint16_t *page = &udata.u_page;
+
+    if(rawflag == 1) {
+        dlen = udata.u_count;
+        dptr = (uint16_t)udata.u_base;
+        block = udata.u_offset >> BLKSHIFT;
+        block_xfer = dlen >> 7;                /* We want this in 128 byte sectors */
+        map = 1;
+    } else if (rawflag == 2) {         /* Swap device special */
+        dlen = swapcnt;
+        dptr = (uint16_t)swapbase;
+        page = &swapproc->p_page;      /* Acting on this task */
+        block = swapblk;
+        block_xfer = dlen >> 7;                /* We want this in 128 byte sectors */
+        map = 1;
+        /*
+         *     In the z80pack case this is simpler than usual. Be very
+         *     careful how you implement the swap device. On most platforms
+         *     we have user space in part of the "common" which means you
+         *     must be prepared to switch common segment as well during
+         *     a swap, or to perform mapping games using the banks
+         */
+    } else { /* rawflag == 0 */
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        block_xfer = 4;
+    }
+    block <<= 2;
+    /* Read the disk in four sector chunks. FIXME We ought to cache the geometry
+       and just bump sector checking for a wrap. */
+    while (ct < block_xfer) {
+        fd_drive = minor;
+        fd_geom(minor, block);
+        /* The Z80pack DMA uses the current MMU mappings... beware that
+         * is odd - but most hardware would be PIO (inir/otir etc) anyway */
+        fd_dmal = dptr & 0xFF;
+        fd_dmah = dptr >> 8;
+
+        if (map == 0)
+            fd_cmd = 1 - is_read;
+        else   /* RAW I/O - switch to user bank and issue command via
+                   a helper in common */
+            fd_bankcmd(1 - is_read, page);
+
+        st = fd_status;
+        /* Real disks would need retries */
+        if (st) {
+            kprintf("fd%d: block %d, error %d\n", minor, st, block);
+            break;
+        }
+        block++;
+        ct++;
+        dptr += 128;
+    }
+    return ct >> 2;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= 8 || !sectrack[minor]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int hd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= 8 || !sectrack[minor + 8]) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
diff --git a/Kernel/platform-z80pack/devfd.h b/Kernel/platform-z80pack/devfd.h
new file mode 100644 (file)
index 0000000..dba1f6c
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_open(uint8_t minor, uint16_t flag);
+
+void fd_bankcmd(uint16_t cmd, uint16_t *bank);
+
+#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-z80pack/devices.c b/Kernel/platform-z80pack/devices.c
new file mode 100644 (file)
index 0000000..c60640f
--- /dev/null
@@ -0,0 +1,43 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devfd.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+// minor    open         close        read      write       ioctl
+// -----------------------------------------------------------------
+  /* 0: /dev/fd                Floppy disc block devices  */
+  {  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },
+  /* 1: /dev/hd                Hard disc block devices (absent) */
+  {  hd_open,     no_close,    hd_read,   hd_write,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  lpr_open,     lpr_close,   no_rdwr,   lpr_write,  no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,      no_close,    sys_read, sys_write, sys_ioctl  },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+  int i;
+  /* Add 64 swaps (4MB) to use the entire J drive */
+  for (i = 0; i < MAX_SWAPS; i++)
+    swapmap_add(i);
+}
diff --git a/Kernel/platform-z80pack/devlpr.c b/Kernel/platform-z80pack/devlpr.c
new file mode 100644 (file)
index 0000000..65d8c43
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat;                /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag; // shut up compiler
+    return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+    minor; // shut up compiler
+    return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    int c = udata.u_count;
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(c) {
+        /* Note; on real hardware it might well be necessary to
+           busy wait a bit just to get acceptable performance */
+        while (lpstat != 0xFF) {
+//            if (psleep_flags(&clocktick, flag))
+//                return -1;
+        }
+        /* FIXME: tidy up ugetc and sysio checks globally */
+        lpdata = ugetc(p++);
+    }
+    return (-1);
+}
diff --git a/Kernel/platform-z80pack/devlpr.h b/Kernel/platform-z80pack/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-z80pack/devtty.c b/Kernel/platform-z80pack/devtty.c
new file mode 100644 (file)
index 0000000..13a001c
--- /dev/null
@@ -0,0 +1,90 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+__sfr __at 0 tty1stat;
+__sfr __at 1 tty1data;
+__sfr __at 40 tty2stat;
+__sfr __at 41 tty2data;
+__sfr __at 42 tty3stat;
+__sfr __at 43 tty3data;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+char tbuf3[TTYSIZ];
+
+struct  s_queue  ttyinq[NUM_DEV_TTY+1] = {       /* ttyinq[0] is never used */
+    {   NULL,    NULL,    NULL,    0,        0,       0    },
+    {   tbuf1,   tbuf1,   tbuf1,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf2,   tbuf2,   tbuf2,   TTYSIZ,   0,   TTYSIZ/2 },
+    {   tbuf3,   tbuf3,   tbuf3,   TTYSIZ,   0,   TTYSIZ/2 }
+};
+
+/* Write to system console */
+void kputchar(char c)
+{
+    /* handle CRLF */
+    if(c=='\n')
+        tty_putc(1, '\r');
+    tty_putc(1, c);
+}
+
+static bool tty_writeready(uint8_t minor)
+{
+    uint8_t s;
+
+    if (minor == 1)
+        return 1;
+    if (minor == 2)
+        s = tty2stat;
+    else
+        s = tty3stat;
+    return s & 2;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+    if (minor == 1)
+        tty1data = c;
+    else if (minor == 2)
+        tty2data = c;
+    else
+        tty3data = c;
+}
+
+/* Called every timer tick */
+void tty_pollirq(void)
+{
+    unsigned char c;   /* sdcc bug workaround */
+    while(tty1stat) {
+        c = tty1data;
+        tty_inproc(1, c);
+    }
+    while(tty2stat & 1) {
+        c = tty2data;
+        tty_inproc(2, c);
+    }
+    while(tty3stat & 1) {
+        c = tty3data;
+        tty_inproc(3, c);
+    }
+    if (tty2stat & 2)
+        wakeup(&ttydata[2]);
+    if (tty3stat & 2)
+        wakeup(&ttydata[3]);
+}    
+
+void tty_setup(uint8_t minor)
+{
+    minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    minor;
+    return 1;
+}
diff --git a/Kernel/platform-z80pack/devtty.h b/Kernel/platform-z80pack/devtty.h
new file mode 100644 (file)
index 0000000..4638611
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+void tty_putc(uint8_t minor, unsigned char c);
+bool tty_writeready(uint8_t minor);
+void tty_pollirq(void);
+void tty_setup(uint8_t minor);
+#endif
diff --git a/Kernel/platform-z80pack/kernel.def b/Kernel/platform-z80pack/kernel.def
new file mode 100644 (file)
index 0000000..b28696f
--- /dev/null
@@ -0,0 +1,6 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xF000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
+
+U_DATA_STASH               .equ 0xED00       ; BD00-BFFF
\ No newline at end of file
diff --git a/Kernel/platform-z80pack/main.c b/Kernel/platform-z80pack/main.c
new file mode 100644 (file)
index 0000000..1567072
--- /dev/null
@@ -0,0 +1,52 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint8_t *ramtop = PROGTOP;
+
+
+void pagemap_init(void)
+{
+ int i;
+ for (i = 1; i < 8; i++)
+  pagemap_add(i);
+}
+
+/* The uarea is already synched to the stash which is written with the
+   process */
+uint8_t *swapout_prepare_uarea(ptptr p)
+{
+  p;
+  return NULL;
+}
+
+/* The switchin code will move the uarea into the process itself, we just
+   need to fix up the u_page pointer */
+uint8_t *swapin_prepare_uarea(ptptr p)
+{
+  p;
+  return NULL;
+}
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  /* We don't want an idle poll and IRQ driven tty poll at the same moment */
+  irqflags_t irq = di();
+  tty_pollirq(); 
+  irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+ tty_pollirq();
+ timer_interrupt();
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
diff --git a/Kernel/platform-z80pack/tricks.s b/Kernel/platform-z80pack/tricks.s
new file mode 100644 (file)
index 0000000..a987439
--- /dev/null
@@ -0,0 +1,315 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl _swapper
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in.  When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; FIXME: make sure we optimise the switch to self case higher up the stack!
+; 
+; This function can have no arguments or auto variables.
+_switchout:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #0 ; return code set here is ignored, but _switchin can 
+        ; return from either _switchout OR _dofork, so they must both write 
+        ; U_DATA__U_SP with the following on the stack:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+       ; Stash the uarea back into process memory
+       ld hl, (U_DATA__U_PAGE)
+       ld a, l
+       out (21), a
+       ld hl, #U_DATA
+       ld de, #U_DATA_STASH
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       xor a
+       out (21), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+       xor a
+       out (21), a
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine for now.
+       ;
+       ld sp, #_swapstack
+       push hl
+       push de
+       call _swapper
+       pop de
+       pop hl
+       ld a, (hl)
+
+not_swapped:
+       ; Pages please !
+       out (21), a
+
+        ; bear in mind that the stack will be switched now, so we can't use it
+       ; to carry values over this point
+
+       exx                     ; thank goodness for exx 8)
+       ld hl, #U_DATA_STASH
+       ld de, #U_DATA
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       exx
+
+       xor a
+       out (21), a
+        
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld ix, (U_DATA__U_PTAB)
+        ; next_process->p_status = P_RUNNING
+        ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+
+       ; Fix the moved page pointers
+       ; Just do one byte as that is all we use on this platform
+       ld a, P_TAB__P_PAGE_OFFSET(ix)
+       ld (U_DATA__U_PAGE), a
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+;      Called from _fork. We are in a syscall, the uarea is live as the
+;      parent uarea. The kernel is the mapped object.
+;
+_dofork:
+        ; always disconnect the vehicle battery before performing maintenance
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; Save the stack pointer and critical registers.
+        ; When this process (the parent) is switched back in, it will be as if
+        ; it returns with the value of the child's pid.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; save kernel stack pointer -- when it comes back in the parent we'll be in
+        ; _switchin which will immediately return (appearing to be _dofork()
+       ; returning) and with HL (ie return code) containing the child PID.
+        ; Hurray.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+
+       ; Need to write a new 47.25K bank copy here, then copy the live uarea
+       ; into the stash of the new process
+
+        ; --------- copy process ---------
+
+        ld hl, (fork_proc_ptr)
+        ld de, #P_TAB__P_PAGE_OFFSET
+        add hl, de
+        ; load p_page
+        ld c, (hl)
+       ld hl, (U_DATA__U_PAGE)
+       ld a, l
+
+       call bankfork                   ;       do the bank to bank copy
+
+       ; Copy done
+
+       ld hl, (U_DATA__U_PAGE) ; parent memory
+        ld a, l
+       out (21), a             ; Switch context to parent
+
+       ; We are going to copy the uarea into the parents uarea stash
+       ; we must not touch the parent uarea after this point, any
+       ; changes only affect the child
+       ld hl, #U_DATA          ; copy the udata from common into the
+       ld de, #U_DATA_STASH    ; target process
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       xor a
+       out (21), a
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; in the child process, fork() returns zero.
+       ;
+       ; And we exit, with the kernel mapped, the child now being deemed
+       ; to be the live uarea. The parent is frozen in time and space as
+       ; if it had done a switchout().
+        ret
+;
+;      We can keep a stack in common because we will complete our
+;      use of it before we switch common block. In this case we have
+;      a true common so it's even easier.
+;
+       .ds 128
+_swapstack:
+
+;
+;      This is related so we will keep it here. Copy the process memory
+;      for a fork. a is the page base of the parent, c of the child
+;      (this API will be insufficient once we have chmem and proper use of
+;      banks - as well as needing to support fork to disk)
+;
+;      Assumption - fits into a fixed number of whole 256 byte blocks
+;
+bankfork:
+;      ld bc, #(0xC000 - 768)          ;       48K minus the uarea stash
+
+       ld b, #0xBD             ; C0 x 256 minus 3 sets for the uarea stash
+       ld hl, #0               ; base of memory to fork (vectors included)
+bankfork_1:
+       push bc                 ; Save our counter and also child offset
+       push hl
+       out (21), a             ; switch to parent bank
+       ld de, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the bounce buffer
+       pop de                  ; recover source of copy to bounce
+                               ; as destination in new bank
+       pop bc                  ; recover child port number
+       push bc
+       ld b, a                 ; save the parent bank id
+       ld a, c                 ; switch to the child
+       out (21), a
+       push bc                 ; save the bank pointers
+       ld hl, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the child
+       pop bc                  ; recover the bank pointers
+       ex de, hl               ; destination is now source for next bank
+       ld a, b                 ; parent back is wanted in a
+       pop bc
+       djnz bankfork_1         ; rinse, repeat
+       ret
+
+;
+;      For the moment
+;
+bouncebuffer:
+       .ds 256
diff --git a/Kernel/platform-z80pack/uzi.lnk b/Kernel/platform-z80pack/uzi.lnk
new file mode 100644 (file)
index 0000000..1cc32a7
--- /dev/null
@@ -0,0 +1,36 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF000
+-k /usr/share/sdcc/lib/z80
+-l z80
+platform-z80pack/crt0.rel
+platform-z80pack/commonmem.rel
+platform-z80pack/z80pack.rel
+platform-z80pack/main.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem_std-z80.rel
+platform-z80pack/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-z80pack/devfd.rel
+platform-z80pack/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+bankfixed.rel
+swap.rel
+devsys.rel
+platform-z80pack/devlpr.rel
+platform-z80pack/devtty.rel
+-e
diff --git a/Kernel/platform-z80pack/z80pack.s b/Kernel/platform-z80pack/z80pack.s
new file mode 100644 (file)
index 0000000..c89604c
--- /dev/null
@@ -0,0 +1,207 @@
+;
+;      Z80Pack hardware support
+;
+;
+;      This goes straight after udata for common. Because of that the first
+;      256 bytes get swapped to and from disk with the uarea (512 byte disk
+;      blocks). This isn't a problem but don't put any variables in here.
+;
+;      If you make this module any shorter, check what follows next
+;
+
+
+            .module z80pack
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl _program_vectors
+            .globl _system_tick_counter
+
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+           .globl _fd_bankcmd
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+
+           .globl unix_syscall_entry
+            .globl null_handler
+           .globl nmi_handler
+            .globl interrupt_handler
+
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_trap_monitor:
+           ld a, #128
+           out (29), a
+           ret
+
+_trap_reboot:
+           ld a, #1
+           out (29), a
+
+;
+;      We need the right bank present when we cause the transfer
+;
+_fd_bankcmd:pop de             ; return
+           pop bc              ; command
+           pop hl              ; bank
+           push hl
+           push bc
+           push de             ; fix stack
+           ld a, i
+           di
+           push af             ; save DI state
+           call map_process    ; HL alread holds our bank
+           ld a, c             ; issue the command
+           out (13), a         ;
+           call map_kernel     ; return to kernel mapping
+           pop af
+           ret po
+           ei
+           ret
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+           ld a, #240                  ; 240 * 256 bytes (60K)
+           out (22), a                 ; set up memory banking
+           ld a, #8    
+           out (20), a                 ; 8 segments
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #480
+            ld (_ramsize), hl
+            ld hl, #(480-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ld a, #1
+           out (27), a                 ; 100Hz timer on
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ; Set vector for jump to NULL
+            ld (0x0000), a   
+            ld hl, #null_handler  ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+           ; our platform has a "true" common area, if it did not we would
+           ; need to copy the "common" code into the common area of the new
+           ; process.
+
+           ; falls through
+
+            ; put the paging back as it was -- we're in kernel mode so this is predictable
+map_kernel:
+           push af
+           xor a
+           out (21), a
+           pop af
+            ret
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+           ld a, (hl)
+           out (21), a
+            ret
+map_process_always:
+           push af
+           ld a, (U_DATA__U_PAGE)
+           out (21), a
+           pop af
+           ret
+map_save:
+           push af
+           in a, (21)
+           ld (map_store), a
+           pop af
+           ret     
+map_restore:
+           push af
+           ld a, (map_store)
+           out (21), a
+           pop af
+           ret     
+map_store:
+           .db 0
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           out (0x01), a
+            ret
diff --git a/Kernel/process.c b/Kernel/process.c
new file mode 100644 (file)
index 0000000..4f8e5c8
--- /dev/null
@@ -0,0 +1,592 @@
+#undef DEBUG                   /* turn this on to enable syscall tracing */
+#undef DEBUGHARDER             /* report calls to wakeup() that lead nowhere */
+#undef DEBUGREALLYHARD         /* turn on getproc dumping */
+
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+
+/* psleep() puts a process to sleep on the given event.  If another
+ * process is runnable, it switches out the current one and starts the
+ * new one.  Normally when psleep is called, the interrupts have
+ * already been disabled.   An event of 0 means a pause(), while an
+ * event equal to the process's own ptab address is a wait().
+ */
+
+void psleep(void *event)
+{
+       irqflags_t irq = di();
+#ifdef DEBUG
+       kprintf("psleep(0x%x)", event); /* WRS */
+#endif
+
+       switch (udata.u_ptab->p_status) {
+       case P_SLEEP:           // echo output from devtty happens while processes are still sleeping but in-context
+               nready++;       /* We will fix this back up below */
+       case P_RUNNING: // normal process
+               break;
+       default:
+               panic("psleep: voodoo");
+       }
+
+       if (!event)
+               udata.u_ptab->p_status = P_PAUSE;
+       else if (event == (char *) udata.u_ptab)
+               udata.u_ptab->p_status = P_WAIT;
+       else
+               udata.u_ptab->p_status = P_SLEEP;
+       udata.u_ptab->p_wait = event;
+       udata.u_ptab->p_waitno = ++waitno;
+       nready--;
+
+       irqrestore(irq);
+       switchout();            /* Switch us out, and start another process */
+       /* Switchout doesn't return in this context until we have been switched back in, of course. */
+}
+
+
+
+/* wakeup() looks for any process waiting on the event,
+ * and makes it runnable
+ */
+
+void wakeup(void *event)
+{
+       ptptr p;
+       irqflags_t irq;
+
+#ifdef DEBUGHARDER
+       kprintf("wakeup(0x%x)\n", event);
+#endif
+       irq = di();
+       for (p = ptab; p < ptab + maxproc; ++p) {
+               if (p->p_status > P_RUNNING && p->p_wait == event) {
+#ifdef DEBUG
+                       kprintf("wakeup: found proc 0x%x pid %d\n",
+                               p, p->p_pid);
+#endif
+                       p->p_status = P_READY;
+                       p->p_wait = NULL;
+                       nready++;
+               }
+       }
+       irqrestore(irq);
+}
+
+
+void pwake(ptptr p)
+{
+       if (p->p_status > P_RUNNING) {
+               p->p_status = P_READY;
+               p->p_wait = NULL;
+               nready++;
+       }
+}
+
+
+
+/* Getproc returns the process table pointer of a runnable process.
+ * It is actually the scheduler.  If there are none, it loops.
+ * This is the only time-wasting loop in the system.
+ */
+
+ptptr getproc_nextp = &ptab[0];
+
+#ifndef CONFIG_SINGLETASK
+
+ptptr getproc(void)
+{
+       ptptr haltafter;
+#ifdef DEBUG
+#ifdef DEBUGREALLYHARD
+       kputs("getproc start ... ");
+       for (pp = ptab; pp < ptab + maxproc; pp++)
+               kprintf("ptab[0x%x]: pid=%d uid=%d status=%d, page=0x%x\n",
+                       pp, pp->p_pid, pp->p_uid, pp->p_status,
+                       pp->p_page);
+       */
+#endif
+#endif
+           /* yes please, interrupts on. */
+           ei();
+
+       haltafter = getproc_nextp;
+
+       for (;;) {
+               getproc_nextp++;
+               if (getproc_nextp >= ptab + maxproc) {
+                       getproc_nextp = ptab;
+               }
+
+               switch (getproc_nextp->p_status) {
+               case P_RUNNING:
+                       panic("getproc: extra running");
+               case P_READY:
+#ifdef DEBUG
+                       kprintf("[getproc returning %x pid=%d]\n",
+                               getproc_nextp, getproc_nextp->p_pid);
+#endif
+                       return getproc_nextp;
+               }
+               /* Take a nap: not that it makes much difference to power on most
+                  Z80 type devices */
+               if (getproc_nextp == haltafter) {
+                       platform_idle();
+               }
+       }
+}
+
+#else
+/*
+ *     Single tasking mode for small boxes. Keep re-selecting ourself or
+ *     calling idle. When we turn zombie move back to the parent. The wait
+ *     will then clean the slot and the parent continues. Most software will
+ *     be blissfully unaware of its cut down environment.
+ */
+
+ptptr getproc(void)
+{
+       ptptr p = udata.u_ptab;
+
+       /* yes please, interrupts on. */
+       ei();
+
+#ifdef DEBUGREALLYHARD
+       kputs("getproc(");
+       if (udata.u_ininterrupt)
+               kputs("[IRQ]");
+#endif
+       while (1) {
+               switch (p->p_status) {
+               case P_ZOMBIE:
+                       /* If we died go to our parent */
+#ifdef DEBUGREALLYHARD
+                       kprintf("Zombie: move from %x to %x\n", p,
+                               p->p_pptr);
+#endif
+                       p = p->p_pptr;
+               case P_READY:
+                       /* If we are ready run us */
+                       p->p_status = P_RUNNING;
+               case P_RUNNING:
+                       /* If we are running keep running */
+#ifdef DEBUGREALLYHARD
+                       kprintf("%x:%s:%d)\n", p, p->p_name, p->p_page);
+#endif
+                       return p;
+               default:
+                       /* Wait for an I/O operation to let us run, don't run
+                          other tasks */
+                       platform_idle();
+               }
+       }
+}
+#endif
+
+/* Newproc fixes up the tables for the child of a fork but also for init
+ * Call in the processes context!
+ * This process MUST be run immediately (since it sets status P_RUNNING)
+ */
+void newproc(ptptr p)
+{                              /* Passed New process table entry */
+       uint8_t *j;
+       irqflags_t irq;
+
+       irq = di();
+       /* Note that ptab_alloc clears most of the entry */
+       /* calculate base page of process based on ptab table offset */
+       udata.u_page = p->p_page;
+       udata.u_page2 = p->p_page2;
+
+       program_vectors(&p->p_page);    /* set up vectors in new process and
+                                          if needed copy any common code */
+
+       p->p_status = P_RUNNING;
+       nready++;               /* runnable process count */
+
+       p->p_pptr = udata.u_ptab;
+       p->p_ignored = udata.u_ptab->p_ignored;
+       p->p_tty = udata.u_ptab->p_tty;
+       if (!p->p_tty)          /* If no tty, try tty of parent's parent */
+               p->p_tty = udata.u_ptab->p_pptr->p_tty;
+       p->p_uid = udata.u_ptab->p_uid;
+       udata.u_ptab = p;
+
+       memset(&udata.u_utime, 0, 4 * sizeof(clock_t)); /* Clear tick counters */
+
+       rdtime32(&udata.u_time);
+       if (udata.u_cwd)
+               i_ref(udata.u_cwd);
+       if (udata.u_root)
+               i_ref(udata.u_root);
+       udata.u_cursig = 0;
+       udata.u_error = 0;
+
+       /* Set default priority */
+       p->p_priority = MAXTICKS;
+
+       for (j = udata.u_files; j < (udata.u_files + UFTSIZE); ++j) {
+               if (*j != NO_FILE)
+                       ++of_tab[*j].o_refs;
+       }
+       irqrestore(irq);
+}
+
+/* This allocates a new process table slot, and fills in its
+ * p_pid field with a unique number.
+ */
+uint16_t nextpid = 0;
+ptptr ptab_alloc(void)
+{
+       ptptr p, newp;
+       irqflags_t irq;
+
+       newp = NULL;
+       udata.u_error = EAGAIN;
+
+       irq = di();
+       for (p = ptab; p < ptab + maxproc; p++)
+               if (p->p_status == P_EMPTY) {
+                       newp = p;
+                       break;
+               }
+
+       if (newp) {             /* found a slot? */
+               /* zero process structure */
+               memset(newp, 0, sizeof(struct p_tab));
+
+               /* select a unique pid */
+               while (newp->p_pid == 0) {
+                       if (nextpid++ > MAXPID)
+                               nextpid = 20;
+                       newp->p_pid = nextpid;
+                       for (p = ptab; p < ptab + maxproc; p++)
+                               if (p->p_status != P_EMPTY
+                                   && p->p_pid == nextpid)
+                                       newp->p_pid = 0;        /* try again */
+               }
+               if (pagemap_alloc(newp) == 0) {
+                       newp->p_status = P_FORKING;
+                       nproc++;
+               } else
+                       udata.u_error = ENOMEM;
+       }
+       irqrestore(irq);
+       if (newp)
+               udata.u_error = 0;
+       return newp;
+}
+
+/* This is the clock interrupt routine.   Its job is to increment the clock
+ * counters, increment the tick count of the running process, and either
+ * switch it out if it has been in long enough and is in user space or mark
+ * it to be switched out if in system space.  Also it decrements the alarm
+ * clock of processes.
+ *
+ * We are running off the interrupt stack.
+ */
+
+void timer_interrupt(void)
+{
+       /* Increment processes and global tick counters */
+       if (udata.u_ptab->p_status == P_RUNNING)
+               if (udata.u_insys)
+                       udata.u_stime++;
+               else
+                       udata.u_utime++;
+       ticks++;
+
+       /* Do once-per-decisecond things */
+       if (++ticks_this_dsecond == TICKSPERSEC / 10) {
+               static ptptr p;
+
+               /* Update global time counters */
+               ticks_this_dsecond = 0;
+
+               /* Update process alarm clocks and timeouts */
+               for (p = ptab; p < ptab + maxproc; ++p) {
+                       if (p->p_alarm) {
+                               p->p_alarm--;
+                               if (!p->p_alarm)
+                                       ssig(p, SIGALRM);
+                       }
+                       if (p->p_timeout > 1) {
+                               p->p_timeout--;
+                               if (p->p_timeout == 1)
+                                       pwake(p);
+                       }
+               }
+               updatetod();
+       }
+#ifndef CONFIG_SINGLETASK
+       /* Check run time of current process */
+       if ((++runticks >= udata.u_ptab->p_priority)
+           && !udata.u_insys && inint && nready > 1) { /* Time to switch out? */
+#ifdef DEBUG
+               kputs("[preempt]");
+               kprintf("Prio = %d\n", udata.u_ptab->p_priority);
+#endif
+               udata.u_insys = true;
+               udata.u_ptab->p_status = P_READY;
+               switchout();
+               udata.u_insys = false;  /* We have switched back in */
+       }
+#endif
+}
+
+#ifdef DEBUG
+#include "syscall_name.h"
+#endif
+
+int16_t kernel_flag = 1;       /* true when in a syscall etc, maintained by the
+                                  asm interfaces but visible in C */
+
+// Fuzix system call handler
+// we arrive here from syscall.s with the kernel paged in, using the kernel stack, interrupts enabled.
+void unix_syscall(void)
+{
+       // NO LOCAL VARIABLES PLEASE
+       udata.u_insys = true;
+       udata.u_error = 0;
+
+       /* Fuzix saves the Stack Pointer and arguments in the
+        * Assembly Language Function handler in lowlevel.s
+        */
+       if (udata.u_callno >= UZI_SYSCALL_COUNT) {
+               udata.u_error = EINVAL;
+       } else {
+#ifdef DEBUG
+               kprintf("\t\tpid %d: syscall %d\t%s(%x, %x, %x)\n",
+                       udata.u_ptab->p_pid, udata.u_callno,
+                       syscall_name[udata.u_callno], udata.u_argn,
+                       udata.u_argn1, udata.u_argn2);
+#endif
+               // dispatch system call
+               udata.u_retval = (*syscall_dispatch[udata.u_callno]) ();
+
+#ifdef DEBUG
+               kprintf("\t\t\tpid %d: ret syscall %d, ret %x err %d\n",
+                       udata.u_ptab->p_pid, udata.u_callno,
+                       udata.u_retval, udata.u_error);
+#endif
+       }
+       udata.u_ptab->p_timeout = 0;
+       chksigs();
+
+       di();
+       if (runticks >= udata.u_ptab->p_priority && nready > 1) {
+               /* Time to switch out? - we may have overstayed our welcome inside
+                  a syscall so switch straight afterwards */
+               udata.u_ptab->p_status = P_READY;
+               switchout();
+       }
+       ei();
+       udata.u_insys = false;
+}
+
+void sgrpsig(uint16_t pgrp, uint16_t sig)
+{
+       ptptr p;
+       for (p = ptab; p < ptab + maxproc; ++p) {
+               if (-p->p_pgrp == pgrp)
+                       ssig(p, sig);
+       }
+}
+
+/* This sees if the current process has any signals set, and handles them.
+ */
+void chksigs(void)
+{
+       uint8_t j;
+
+       // any signals pending?
+       if (!(udata.u_ptab->p_pending & ~udata.u_ptab->p_held)) {
+               return;
+       }
+       // dispatch the lowest numbered signal
+       for (j = 1; j < NSIGS; ++j) {
+               if (!
+                   (sigmask(j) & udata.u_ptab->p_pending & ~udata.u_ptab->
+                    p_held))
+                       continue;
+               /* This is more complex than in V7 - we have multiple
+                  behaviours (plus the unimplemented as yet core dump) */
+               if (udata.u_sigvec[j] == SIG_DFL) {
+                       /* SIGCONT is subtle - we woke the process to handle
+                          the signal so ignoring here works fine */
+                       if (j == SIGCHLD || j == SIGURG ||
+                           j == SIGIO || j == SIGCONT)
+                               continue;
+                       /* FIXME: core dump on some signals */
+#ifdef DEBUG
+                       kputs("process terminated by signal: ");
+#endif
+                       doexit(0, j);
+               }
+
+               if (udata.u_sigvec[j] != SIG_IGN) {
+                       /* Arrange to call the user routine at return */
+                       udata.u_ptab->p_pending &= ~sigmask(j); // unset the bit
+#ifdef DEBUG
+                       kprintf("about to process signal %d\n", j);
+#endif
+                       udata.u_cursig = j;
+                       /* FIXME: multiple signal processing here and in
+                          lowlevel-$cpu.s */
+                       break;
+               }
+       }
+}
+
+/*
+ *     Send signal, avoid touching uarea
+ */
+void ssig(ptptr proc, uint16_t sig)
+{
+       uint16_t sigm;
+       irqflags_t irq;
+
+       sigm = sigmask(sig);
+
+       irq = di();
+       /* FIXME:
+          SIGCONT needs to wake even if ignored.
+          SIGSTOP needs to actually stop the task once it hits
+          the syscall exit path */
+       if (proc->p_status != P_EMPTY) {        /* Presumably was killed just now */
+               if (sig == SIGCONT || !(proc->p_ignored & sigm)) {
+                       /* Don't wake for held signals */
+                       if (!(proc->p_held & sigm)) {
+                               switch (proc->p_status) {
+                               case P_PAUSE:
+                               case P_WAIT:
+                               case P_SLEEP:
+                                       proc->p_status = P_READY;
+                                       nready++;
+                               default:;
+                               }
+                               proc->p_wait = NULL;
+                       }
+                       proc->p_pending |= sigm;
+               }
+       }
+       irqrestore(irq);
+}
+
+#ifdef CONFIG_ACCT
+void acctexit(ptptr p)
+{
+       struct oft *oftp;
+       inoptr ino;
+
+       if (acct_fh == -1)
+               return;
+
+       oftp = &of_tab[acct_fh];
+       ino = oftp->o_inode;
+
+       /* Reuse the field before we write out accounting data */
+       udata.u_mask = p->p_uid;
+       /* More useful information is u_top */
+       udata.u_break = udata.u_top;
+
+       udata.u_sysio = true;
+       udata.u_base = (char *) &udata.u_mask;
+       udata.u_count = 48;     /* Includes some spare for expansion */
+
+       /* Append to the end of the file */
+       oftp->o_ptr.o_blkno = ino->c_node.i_size.o_blkno;
+       oftp->o_ptr.o_offset = ino->c_node.i_size.o_offset;
+       writei(ino, 0);
+}
+#endif
+
+void doexit(int16_t val, int16_t val2)
+{
+       int16_t j;
+       ptptr p;
+       irqflags_t irq;
+
+#ifdef DEBUG
+       kprintf("process %d exiting\n", udata.u_ptab->p_pid);
+
+       kprintf
+           ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n",
+            udata.u_page, udata.u_ptab, udata.u_ptab->p_page);
+#endif
+       if (udata.u_ptab->p_pid == 1)
+               panic("killed init");
+
+       _sync();                /* Not necessary, but a good idea. */
+
+       irq = di();
+
+       /* Discard our memory before we blow away and reuse the memory */
+       pagemap_free(udata.u_ptab);
+
+       for (j = 0; j < UFTSIZE; ++j) {
+               if (udata.u_files[j] != NO_FILE)
+                       doclose(j);
+       }
+
+
+       udata.u_ptab->p_exitval = (val << 8) | (val2 & 0xff);
+
+       i_deref(udata.u_cwd);
+       i_deref(udata.u_root);
+
+       /* Stash away child's execution tick counts in process table,
+        * overlaying some no longer necessary stuff.
+        *
+        * Pedantically POSIX says we should do this at the point of wait()
+        */
+       udata.u_utime += udata.u_cutime;
+       udata.u_stime += udata.u_cstime;
+       memcpy(&(udata.u_ptab->p_priority), &udata.u_utime,
+              2 * sizeof(clock_t));
+
+       /* See if we have any children. Set child's parents to our parent */
+       for (p = ptab; p < ptab + maxproc; ++p) {
+               if (p->p_status && p->p_pptr == udata.u_ptab
+                   && p != udata.u_ptab)
+                       p->p_pptr = udata.u_ptab->p_pptr;
+       }
+       irqrestore(irq);
+#ifdef DEBUG
+       kprintf
+           ("udata.u_page %u, udata.u_ptab %x, udata.u_ptab->p_page %u\n",
+            udata.u_page, udata.u_ptab, udata.u_ptab->p_page);
+#endif
+#ifdef CONFIG_ACCT
+       acctexit(p);
+#endif
+       /* FIXME: send SIGCLD here */
+       /* FIXME: POSIX.1 says that SIG_IGN for SIGCLD means don't go
+          zombie, just clean up as we go */
+       /* Wake up a waiting parent, if any. */
+       wakeup((char *) udata.u_ptab->p_pptr);
+
+       udata.u_ptab->p_status = P_ZOMBIE;
+       nready--;
+       nproc--;
+
+       switchin(getproc());
+       panic("doexit: won't exit");
+}
+
+void panic(char *deathcry)
+{
+       kputs("\r\npanic: ");
+       kputs(deathcry);
+       trap_monitor();
+}
+
+/* We put this here so that we can blow the start.c code away on exec
+   eventually, but still manage to get the panic() to happen if it fails */
+void exec_or_die(void)
+{
+       kputs("Starting /init\n");
+       _execve();
+       panic("no /init");      /* BIG Trouble if we Get Here!! */
+}
diff --git a/Kernel/select.c b/Kernel/select.c
new file mode 100644 (file)
index 0000000..61216b7
--- /dev/null
@@ -0,0 +1,116 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+/*
+ *     Logic for select
+ *
+ *     Q: where to hide pipe selmaps ?
+ *
+ *     Could have a generic selmap set for 'all pipes' - ugly but keeps
+ *     costs down.
+ */
+
+void seladdwait(struct selmap *s)
+{
+  int16_t p = udata.u_ptab - ptab;
+  s->map[p>>3] |= (1 << (p & 7));
+}
+
+void selrmwait(struct selmap *s)
+{
+  int16_t p = udata.u_ptab - ptab;
+  s->map[p>>3] &= ~(1 << (p & 7));
+}
+
+void selwake(struct selmap *s)
+{
+  p = ptab;
+  for (i = 0; i < maxproc; i++) {
+    if (s->map[i>>3] & (1 << (i & 7)))
+      pwake(p);
+    p++;
+  }
+}
+
+#define nfd (uint16_t)udata.u_argn
+#define base (uint16_t)udata.u_argn1
+
+int _select(void)
+{
+  struct inode *iptr;
+  uint16_t sumo;
+  uint8_t n;
+  uint16_t inr = 0, outr = 0, exr = 0;
+  /* Second 16bits of each spare for expansion */
+  uint16_t in = ugetw(base);
+  uint16_t out = ugetw(base+4);
+  uint16_t ex = ugetw(base+8);
+  
+  uint16_t sum = in | out | ex;
+
+  /* Timeout in 1/10th of a second (BSD api mangling done by libc) */
+  udata.p_tab->p_timeout = ugetw(base + 12);
+
+  do {
+    m = 1;
+    for (i = 0; i < nfd; i++) {
+      if (sum & m) {
+        ino = getinode(i);
+        if (ino == NULLINODE)
+          return -1;
+        switch(getmode(ino)) {
+        case F_BDEV:      
+        case F_REG:
+          outr |= m;
+        case F_DIR:
+          inr |=  m;
+          break;
+        case F_PIPE:
+          /* TODO */
+          break;
+        case F_CDEV:
+          /* Not fatal: counts as read/write ready */
+          if (d_ioctl(ino->c_node.i_addr[0], SELECT_BEGIN, &n) == -1) {
+            udata.u_error = 0;
+            n = SELECT_IN|SELECT_OUT;
+          }
+          if (n & SELECT_IN)
+            inr |= m;
+          if (n & SELECT_OUT)
+            outr |= m;
+          if (n & SELECT_EX)
+            exr |= m;
+          break;
+      }
+    }
+    m << = 1;
+    sumo = inr | outr | exr;
+    if (psleep_flags(&udata.p_tab->p_timeout, 0) == -1)
+      break;
+  }
+  while (!sumo && udata.p_tab->p_timeout != 1);
+  
+  /* FIXME: write back properly */
+  *inp = inr;
+  *outp = outr;
+  *exp = exr;
+
+  m = 1;
+  for (i = 0; i < nfd; i++) {
+    if (sum & m) {
+      ino = getinode(i);
+      if (getmode(ino) == F_CDEV)
+        d_ioctl(ino->c_node.i_addr[0], SELECT_END, NULL);
+      /* FIXME - pipe */
+    }
+    m <<= 1;
+  }
+  return 0;            /* the scan and return of highest fd is done by
+                           user space */
+}
+
+#undef nfd
+#undef base
diff --git a/Kernel/simple.c b/Kernel/simple.c
new file mode 100644 (file)
index 0000000..459e05a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *     Simple swap only system
+ */
+
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+
+#ifdef CONFIG_SWAP_ONLY
+
+void pagemap_free(ptptr p)
+{
+  p->p_page = 0;
+}
+
+int pagemap_alloc(ptptr p)
+{
+  p->p_page = 1;
+  return 0;
+}
+
+int pagemap_realloc(uint16_t size)
+{
+  if (size + 0x100 >= (uint16_t) ramtop)
+    return ENOMEM;
+  return 0;
+}
+
+uint16_t pagemap_mem_used(void)
+{
+  return ((uint16_t)(PROGTOP - PROGBASE)) >> 10;
+}
+
+void pagemap_init(void)
+{
+}
+
+#endif
diff --git a/Kernel/single.c b/Kernel/single.c
new file mode 100644 (file)
index 0000000..f2fa633
--- /dev/null
@@ -0,0 +1,306 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+
+/*
+ *     Support for single tasking systems where there is not enough memory for
+ *     multiple tasks and where there is no suitable swap device. This configuration
+ *     is suitable for systems with over about 96K of RAM and nothing but a floppy
+ *     drive.
+ *
+ *     To use this method of operation you should do the following
+ *
+ *     1. place ramtop in COMMONMEM
+ *     2. base your dofork on the example in platform-socz80-lite/tricks.s
+ *
+ *     If you don't have a "true" common area then your code that calls swap
+ *     helpers while banked will need to copy ramtop between the banks
+ */
+
+
+
+#ifndef CONFIG_MULTI
+
+/*
+ *     Platforms that only have swap and room for one process use
+ *     this common logic. They must also implement forking to disk.
+ *     page is used as a token, 0 means swapped, non zero means present
+ */
+
+void pagemap_free(ptptr p)
+{
+       p->p_page = 0;
+}
+
+int pagemap_alloc(ptptr p)
+{
+       p->p_page = 1;
+       return 0;
+}
+
+int pagemap_realloc(uint16_t size)
+{
+       if (size + 0x100 >= (uint16_t) ramtop)
+               return ENOMEM;
+       udata.u_ptab->p_page = 1;
+       udata.u_page = 1;
+       return 0;
+}
+
+uint16_t pagemap_mem_used(void)
+{
+       uint16_t mem = PROGTOP - ramtop + udata.u_top;
+       return mem >> 10;
+}
+
+void pagemap_init(void)
+{
+}
+
+#ifndef SWAPDEV
+
+/* Force the rest of this file into common */
+
+void dummy(void) __naked
+{
+       __asm.area _COMMONMEM __endasm;
+}
+
+/*
+ *     Swap helpers for simple non swapping systems.
+ *
+ *     We always "swap" ourselves out by swapping a copy of ourself upwards in
+ *     RAM and making the original the child. We are single tasking so swap is
+ *     effectively a stack
+ *
+ *     Compressed swap to debug yet
+ */
+
+__sfr __at 0xc0 ttydata;
+
+static void Xpanic(char *p)
+{
+       p;
+       while (*p)
+               ttydata = *p++;
+}
+
+static void Xoutch(uint16_t v)
+{
+       v;
+       ttydata = "0123456789ABCDEF"[v & 0x0F];
+}
+
+static void Xout(uint16_t v)
+{
+       Xoutch(v >> 12);
+       Xoutch(v >> 8);
+       Xoutch(v >> 4);
+       Xoutch(v);
+}
+
+#if 1
+#define LCODE          0xC7
+#define LCODE_QUOTED   0
+#define LCODE_END      1
+#define LCODE_SPARE    2
+
+static int count(uint8_t ** sp, uint16_t * lp)
+{
+       uint8_t *s = *sp;
+       uint8_t c = *s++;
+       uint8_t ct = 3;
+       uint16_t l = *lp;
+
+       while (*s == c && l > 1 && ct < 255) {
+               s++;
+               ct++;
+               l--;
+       }
+       *lp = l;
+       *sp = s;
+//  Xpanic("L");
+//  Xout(ct);
+       return ct;
+}
+
+static int do_swap_out(uint8_t * s, uint16_t l)
+{
+       uint8_t *p = ramtop - 1;
+
+//  Xpanic("do_swap_out ");
+//  Xout((uint16_t)s);
+//  Xpanic(",");
+//  Xout((uint16_t)l);
+//  Xpanic("\n");  
+       while (l) {
+               if ((uint16_t) p - udata.u_top < 6) {
+                       Xpanic("nofit");
+                       return ENOMEM;
+               }
+               if (l > 4 && *s == s[1] && *s == s[2]) {
+                       uint8_t c = *s;
+                       *p-- = LCODE;
+                       s += 2;
+                       l -= 2;
+                       *p-- = count(&s, &l);
+                       *p-- = c;
+               } else if (*s == LCODE) {
+                       *p-- = LCODE;
+                       *p-- = LCODE_QUOTED;
+                       s++;
+               } else
+                       *p-- = *s++;
+               l--;
+               if (l > 0xFFF0)
+                       Xpanic("overrun");
+       }
+//  Xpanic("E");
+       /* Write an end marker */
+       *p-- = LCODE;
+       *p-- = LCODE_END;
+       /* Write the pointer to the block beginning */
+       *p-- = (uint16_t) ramtop >> 8;
+       *p = (uint16_t) ramtop & 0xFF;
+//  Xpanic("Ramtop was ");
+//  Xout((uint16_t)ramtop);
+       ramtop = p;
+//  Xpanic(" now ");
+//  Xout((uint16_t)ramtop);
+//  Xpanic("\r\n");
+       s;
+       l;
+       return 0;
+}
+
+static void unpack(uint8_t * d, uint8_t * p, uint16_t l)
+{
+       int i;
+       uint8_t c;
+
+       while (l) {
+               if (*p != LCODE) {
+                       *d++ = *p--;
+                       l--;
+                       continue;
+               }
+               p--;
+               if (*p == LCODE_QUOTED) {
+                       *d++ = LCODE;
+                       p--;
+                       l--;
+                       continue;
+               }
+               if (*p == LCODE_END) {
+                       Xpanic("short swap");
+               }
+               c = p[-1];
+               for (i = *p; i > 0; i--) {
+                       *d++ = c;
+                       l--;
+                       if (l == 0) {
+                               Xpanic("bogon by ");
+                               Xout(i);
+                       }
+               }
+               p -= 2;
+       }
+       if (*p != LCODE && p[-1] != LCODE_END)
+               Xpanic("long swap\n");
+}
+
+static void do_swap_in(uint8_t * d, uint16_t l)
+{
+       uint8_t *p = (uint8_t *) (ramtop[0] | (((uint16_t) ramtop[1]) << 8));   /* Recover old base pointer */
+//  Xout(ramtop[1]);
+//  Xout(ramtop[2]);
+//  Xpanic("Entry Ramtop: ");
+//  Xout((uint16_t)ramtop);
+//  Xpanic("New Ramtop: ");
+//  Xout((uint16_t)p);
+       unpack(d, p, l);
+       ramtop = p;
+//  Xpanic("\r\n");
+}
+#endif
+#if 0
+static void Xmemcpy(uint8_t * d, uint8_t * s, uint16_t l)
+{
+       while (l--)
+               *d++ = *s++;
+}
+
+static int do_swap_out(uint8_t * p, uint16_t l)
+{
+       uint16_t room = (uint16_t) ramtop - udata.u_top;
+       uint8_t *d;
+
+       Xpanic("len ");
+       Xout(l);
+       Xpanic(" room ");
+       Xout(room);
+       if (room < l + 2)
+               return -1;
+       ramtop -= l + 2;
+       Xpanic("ramtop now ");
+       Xout((uint16_t) ramtop);
+       d = (uint8_t *) ramtop;
+       d[0] = l & 0xFF;
+       d[1] = l >> 8;
+       Xmemcpy(d + 2, p, l);
+       return 0;
+}
+
+static void do_swap_in(uint8_t * d, uint16_t l)
+{
+       uint8_t *p = (uint8_t *) ramtop;
+       uint16_t sl;
+       //Xpanic("len ");Xout(l);Xpanic(" ramtop ");Xout((uint16_t)ramtop);
+       sl = p[0] | ((uint16_t) p[1] << 8);
+       if (sl != l)
+               Xpanic("ilen");
+       Xmemcpy(d, p + 2, sl);
+       ramtop += 2 + sl;
+       Xpanic(" now ");
+       Xout((uint16_t) ramtop);
+}
+#endif
+
+int swapout(ptptr p)
+{
+       uint8_t *oldtop = ramtop;
+       p;
+//  Xpanic("Swapout");
+//  Xout((uint16_t)udata.u_ptab);
+       if (do_swap_out(0, udata.u_top) == 0
+           && do_swap_out((uint8_t *) & udata, 768) == 0) {
+//    Xpanic("OK");
+               return 0;
+       }
+//  Xpanic("BAD");
+       ramtop = oldtop;
+       return ENOMEM;
+}
+
+ptptr swapneeded(ptptr p, int notself)
+{
+       p;
+       notself;
+       swapout(udata.u_ptab);
+       return udata.u_ptab;
+}
+
+void swapper(ptptr p)
+{
+       /* Get the udata back */
+//  Xpanic("Swapin");
+       do_swap_in((uint8_t *) & udata, 768);
+       if (udata.u_ptab != p)
+               Xpanic("swapin");
+       do_swap_in(0, udata.u_top);
+//  Xpanic("udata proctab");Xout((uint16_t)udata.u_ptab);
+}
+
+#endif
+#endif
diff --git a/Kernel/start.c b/Kernel/start.c
new file mode 100644 (file)
index 0000000..33bde92
--- /dev/null
@@ -0,0 +1,163 @@
+#include <kernel.h>
+#include <version.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <tty.h>
+
+/*
+ *     Put nothing here that cannot be discarded. We will eventually
+ *     make the entire of this disappear after the initial _execve
+ */
+
+void create_init(void)
+{
+       uint8_t *j;
+       /* userspace: 0x100+ 0   1   2   3   4   5   6   7   8   9   A   B   C */
+       const char arg[] =
+           { '/', 'i', 'n', 'i', 't', 0, 0, 1, 1, 0, 0, 0, 0 };
+
+       init_process = ptab_alloc();
+       udata.u_ptab = init_process;
+       udata.u_top = 4096;     /* Plenty for the boot */
+       map_init();
+       newproc(init_process);
+
+       init_process->p_status = P_RUNNING;
+
+       /* wipe file table */
+       for (j = udata.u_files; j < (udata.u_files + UFTSIZE); ++j) {
+               *j = NO_FILE;
+       }
+       /* Poke the execve arguments into user data space so _execve() can read them back */
+       uput(arg, PROGBASE, sizeof(arg));
+
+       /* Set up things to look like the process is calling _execve() */
+       udata.u_argn = (uint16_t) PROGBASE;
+       /* FIXME - should be relative to PROGBASE... */
+       udata.u_argn1 = 0x107;  /* Arguments (just "/init") */
+       udata.u_argn2 = 0x10b;  /* Environment (none) */
+}
+
+void fuzix_main(void)
+{
+       /* setup state */
+       inint = false;
+       udata.u_insys = true;
+
+       ramtop = PROGTOP;
+
+       tty_init();
+
+       if (d_open(TTYDEV, 0) != 0)
+               panic("no tty");
+
+       /* Sign on messages (stashed in a buffer so we can bin them */
+       kprintf((char *)bufpool[0].bf_data, uname_str);
+
+#ifndef SWAPDEV
+#ifdef PROC_SIZE
+       maxproc = procmem / PROC_SIZE;
+       /* Check we don't exceed the process table size limit */
+       if (maxproc > PTABSIZE) {
+               kprintf((char *)bufpool[1].bf_data, maxproc);
+               maxproc = PTABSIZE;
+       }
+#else
+       maxproc = PTABSIZE;
+#endif
+#else
+       maxproc = PTABSIZE;
+#endif
+       /* Parameters message */
+       kprintf((char *)bufpool[2].bf_data, ramsize, procmem, maxproc);
+       /* Now blow away the strings */
+       bufinit();
+       pagemap_init();
+
+       create_init();
+        kprintf("%x:%x\n", udata.u_page, udata.u_page2);
+        kprintf("%x:%x\n", udata.u_ptab->p_page, udata.u_ptab->p_page2);
+       kputs("Enabling interrupts ... ");
+        ei();
+       kputs("ok.\n");
+
+       /* initialise hardware devices */
+       device_init();
+
+       root_dev = DEFAULT_ROOT;
+       if (cmdline && *cmdline) {
+               while (*cmdline == ' ')
+                       ++cmdline;
+               root_dev = *cmdline - '0';
+       } else {
+               kputs("bootdev: ");
+               udata.u_base = bootline;
+               udata.u_sysio = 1;
+               udata.u_count = 2;
+               udata.u_euid = 0;       /* Always begin as superuser */
+
+               cdread(TTYDEV, O_RDONLY);       /* read root filesystem name from tty */
+               if (*bootline >= '0')
+                       root_dev = *bootline - '0';
+       }
+
+       /* Mount the root device */
+       kprintf("Mounting root fs (root_dev=%d): ", root_dev);
+
+       if (fmount(root_dev, NULLINODE, 0))
+               panic("no filesys");
+       root = i_open(root_dev, ROOTINODE);
+       if (!root)
+               panic("no root");
+
+       kputs("OK\n");
+
+       i_ref(udata.u_cwd = root);
+       i_ref(udata.u_root = root);
+       rdtime32(&udata.u_time);
+       exec_or_die();
+}
+
+#ifdef CONFIG_IDUMP
+
+void idump(void)
+{
+       inoptr ip;
+       ptptr pp;
+       extern struct cinode i_tab[];
+
+       kprintf("Err %d root %d\n", udata.u_error, root - i_tab);
+       kputs("\tMAGIC\tDEV\tNUM\tMODE\tNLINK\t(DEV)\tREFS\tDIRTY\n");
+
+       for (ip = i_tab; ip < i_tab + ITABSIZE; ++ip) {
+               kprintf("%d\t%d\t%d\t%u\t0%o\t",
+                       ip - i_tab, ip->c_magic, ip->c_dev, ip->c_num,
+                       ip->c_node.i_mode);
+               kprintf("%d\t%d\t%d\t%d\n",     /* line split for compiler */
+                       ip->c_node.i_nlink, ip->c_node.i_addr[0],
+                       ip->c_refs, ip->c_dirty);
+               if (!ip->c_magic)
+                       break;
+       }
+
+       kputs
+           ("\n\tSTAT\tWAIT\tPID\tPPTR\tALARM\tPENDING\tIGNORED\tCHILD\n");
+       for (pp = ptab; pp < ptab + PTABSIZE /*maxproc */ ; ++pp) {
+               if (pp->p_status == P_EMPTY)
+                       continue;
+               kprintf("%d\t%d\t0x%x\t%d\t",
+                       pp - ptab, pp->p_status, pp->p_wait, pp->p_pid);
+               kprintf("%d\t%d\t0x%lx\t0x%lx\n",
+                       pp->p_pptr - ptab, pp->p_alarm, pp->p_pending,
+                       pp->p_ignored);
+       }
+
+       bufdump();
+
+       kprintf("insys %d ptab %d call %d cwd %d sp 0x%x\n",
+               udata.u_insys, udata.u_ptab - ptab, udata.u_callno,
+               udata.u_cwd - i_tab, udata.u_sp);
+}
+
+#endif
diff --git a/Kernel/swap.c b/Kernel/swap.c
new file mode 100644 (file)
index 0000000..cfb04f4
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *     Very simplistic for now disk swap logic. As we have a fixed
+ *     process size at this point we use a fixed swap size too
+ */
+
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+
+#undef DEBUG
+
+#ifdef SWAPDEV
+
+#ifndef UDATA_SWAPSIZE
+#define UDATA_BLOCKS   0
+#endif
+
+
+char *swapbase;
+unsigned int swapcnt;
+blkno_t swapblk;
+ptptr swapproc;                        /* Target process space */
+
+/* Table of available maps */
+static uint8_t swapmap[MAX_SWAPS];
+static uint8_t swapptr = 0;
+
+void swapmap_add(uint8_t swap)
+{
+       if (swapptr == MAX_SWAPS)
+               panic("maxswap");
+       swapmap[swapptr++] = swap;
+}
+
+static int swapread(uint16_t dev, blkno_t blkno, unsigned int nbytes, char *buf)
+{
+       swapbase = buf;
+       swapcnt = nbytes;
+       swapblk = blkno;
+       return ((*dev_tab[major(dev)].dev_read) (minor(dev), 2, 0));
+}
+
+
+static int swapwrite(uint16_t dev, blkno_t blkno, unsigned int nbytes,
+                    char *buf)
+{
+       swapbase = buf;
+       swapcnt = nbytes;
+       swapblk = blkno;
+       return ((*dev_tab[major(dev)].dev_write) (minor(dev), 2, 0));
+}
+
+/*
+ *     Swap out the memory of a process to make room
+ *     for something else
+ */
+int swapout(ptptr p)
+{
+       uint16_t page = p->p_page;
+       uint16_t blk;
+       uint16_t map;
+#ifdef UDATA_SWAPSIZE
+       uint8_t *ptr;
+#endif
+
+       swapproc = p;
+
+       if (page) {
+#ifdef DEBUG
+               kprintf("Swapping out %x (%d)\n", p, p->p_page);
+#endif
+               /* Are we out of swap ? */
+               if (swapptr == 0)
+                       return ENOMEM;
+               map = swapmap[--swapptr];
+               blk = map * SWAP_SIZE;
+#ifdef UDATA_SWAPSIZE
+               /* Allow the platform to do things like handle the uarea stash */
+               ptr = swapout_prepare_uarea(p);
+               /* Write to disk if the platform asks us */
+               if (ptr)
+                       swapwrite(SWAPDEV, blk, UDATA_SWAPSIZE,
+                                 (char *) p);
+#endif
+               /* Write the app (and possibly the uarea etc..) to disk */
+               swapwrite(SWAPDEV, blk + UDATA_BLOCKS, SWAPTOP - SWAPBASE,
+                         SWAPBASE);
+               pagemap_free(p);
+               p->p_page = 0;
+               p->p_page2 = map;
+#ifdef DEBUG
+               kprintf("%x: swapout done %d\n", p, p->p_page);
+#endif
+       }
+#ifdef DEBUG
+       else
+               kprintf("%x: process already swapped!\n", p);
+#endif
+       return 0;
+}
+
+/*
+ * Swap ourself in: must be on the swap stack when we do this
+ */
+static void swapin(ptptr p)
+{
+       uint16_t blk = p->p_page2 * SWAP_SIZE;
+#ifdef UDATA_SWAPSIZE
+       uint8_t *ptr;
+#endif
+
+#ifdef DEBUG
+       kprintf("Swapin %x, %d\n", p, p->p_page);
+#endif
+       if (!p->p_page) {
+               kprintf("%x: nopage!\n", p);
+               return;
+       }
+
+       /* Return our swap */
+       swapmap[swapptr++] = p->p_page2;
+
+       swapproc = p;           /* always ourself */
+       swapread(SWAPDEV, blk + UDATA_BLOCKS, SWAPTOP - SWAPBASE,
+                SWAPBASE);
+#ifdef UDATA_SWAPSIZE
+       ptr = swapin_prepare_uarea(p);
+       if (ptr)
+               swapread(SWAPDEV, blk, UDATA_SWAPSIZE, (char *) &udata);
+#endif
+#ifdef DEBUG
+       kprintf("%x: swapin done %d\n", p, p->p_page);
+#endif
+}
+
+/*
+ *     Swap out process. As we have them all the same size we ignore
+ *     p for now. For a single memory image system most of this can go!
+ */
+static ptptr swapvictim(ptptr p, int notself)
+{
+#ifdef CONFIG_MULTI
+       ptptr c;
+       ptptr r = NULL;
+       ptptr f = NULL;
+       uint16_t sc = 0;
+       uint16_t s;
+
+       extern ptptr getproc_nextp;     /* Eww.. */
+
+       c = getproc_nextp;
+
+       do {
+               if (c->p_page) {        /* No point swapping someone in swap! */
+                       /* Find the last entry before us */
+                       if (c->p_status == P_READY)
+                               r = c;
+                       if (c->p_status > P_READY
+                           && p->p_status <= P_FORKING) {
+                               /* relative position in order of waits, bigger is longer, can wrap but
+                                  shouldn't really matter to us much if it does */
+                               s = (waitno - c->p_waitno);
+                               if (s >= sc) {
+                                       sc = s;
+                                       f = c;
+                               }
+                       }
+               }
+               c++;
+               if (c > ptab + maxproc)
+                       c = ptab;
+       }
+       while (c != getproc_nextp);
+
+       /* Oldest waiter gets the boot */
+       if (f) {
+#ifdef DEBUG
+               kprintf("swapvictim %x (page %d, state %d\n)", f,
+                       f->p_page, f->p_status);
+#endif
+               return f;
+       }
+       /* No waiters.. the scheduler cycles so we will be the last to run
+          again, failing that the one before us that was ready */
+       if (notself == 0)
+               return udata.u_ptab;
+       return r;
+#else
+       p;
+       if (notself)
+               panic("bad notself\n");
+       return udata.u_ptab;
+#endif
+}
+
+ptptr swapneeded(ptptr p, int notself)
+{
+       ptptr n = swapvictim(p, notself);
+       if (n)
+               if (swapout(n))
+                       n = NULL;
+       return n;
+}
+
+/*
+ *     Called from switchin when we discover that we want to run
+ *     a swapped process. As all our processes are the same size
+ *     for now this remains fairly simple.
+ */
+void swapper(ptptr p)
+{
+       pagemap_alloc(p);       /* May cause a swapout */
+#ifdef DEBUG
+       kprintf("Swapping in %x (page %d), utab.ptab %x\n", p, p->p_page,
+               udata.u_ptab);
+#endif
+       swapin(p);
+#ifdef DEBUG
+       kprintf("Swapped in %x (page %d), udata.ptab %x\n",
+               p, p->p_page, udata.u_ptab);
+#endif
+}
+#endif
diff --git a/Kernel/syscall_fs.c b/Kernel/syscall_fs.c
new file mode 100644 (file)
index 0000000..2d76dfb
--- /dev/null
@@ -0,0 +1,501 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+void updoff(void)
+{
+       /* Update current file pointer */
+       of_tab[udata.u_files[udata.u_argn]].o_ptr = udata.u_offset;
+}
+
+
+/*******************************************
+  seek (file, offset, flag)         Function 9        ?
+  int16_t file;
+  uint32_t *offset;
+  int16_t flag;
+ ********************************************/
+#define file   (uint16_t)udata.u_argn
+#define offset (uint32_t *)udata.u_argn1
+#define flag   (int16_t)udata.u_argn2
+
+/* We copy the 32bit offset in and out rather than passing it
+   as a 32bit OS might */
+int16_t _lseek(void)
+{
+       inoptr ino;
+       struct oft *o;
+       off_t p;
+       off_t n;
+       
+       if (uget(offset, &n, sizeof(n)))
+               return -1;
+
+       if ((ino = getinode(file)) == NULLINODE)
+               return (-1);
+
+       if (getmode(ino) == F_PIPE) {
+               udata.u_error = ESPIPE;
+               return (-1);
+       }
+
+       o = &of_tab[udata.u_files[file]];
+       p = o->o_ptr;
+
+       switch (flag) {
+       case 0:
+               p = n;
+               break;
+       case 1:
+               p += n;
+               break;
+       case 2:
+               p = ino->c_node.i_size + n;
+               break;
+       default:
+                goto bad;
+       }
+       if (p < 0)
+               goto bad;
+        o->o_ptr = p;
+       uput(&p, offset, sizeof(n));
+       return 0;
+bad:
+       udata.u_error = EINVAL;
+       return (-1);
+
+}
+
+#undef file
+#undef offset
+#undef flag
+
+
+
+/*******************************************
+  sync()
+ ********************************************/
+
+int16_t _sync(void)
+{
+       inoptr ino;
+
+       /* Write out modified inodes */
+
+       for (ino = i_tab; ino < i_tab + ITABSIZE; ++ino)
+               if (ino->c_refs > 0 && ino->c_dirty != 0) {
+                       wr_inode(ino);
+                       ino->c_dirty = 0;
+               }
+
+        /* This now also indirectly does the superblocks as they
+           are buffers that are pinned */
+       bufsync();              /* Clear buffer pool */
+
+       return 0;
+}
+
+
+
+
+/*******************************************
+  stat (path, buf)                 Function 15
+  char *path;
+  char *buf;
+ ********************************************/
+#define path (char *)udata.u_argn
+#define buf (char *)udata.u_argn1
+
+int16_t _stat(void)
+{
+       inoptr ino;
+       if (!(ino = n_open(path, NULLINOPTR)))
+               return (-1);
+       stcpy(ino, buf);
+       i_deref(ino);
+       return (0);
+}
+
+#undef path
+#undef buf
+
+
+/*******************************************
+  fstat (fd, buf)                  Function 16
+  int16_t fd;
+  char *buf;
+ ********************************************/
+#define fd (int16_t)udata.u_argn
+#define buf (char *)udata.u_argn1
+
+int16_t _fstat(void)
+{
+       inoptr ino;
+
+       if ((ino = getinode(fd)) == NULLINODE)
+               return (-1);
+
+       return stcpy(ino, buf);
+}
+
+#undef fd
+#undef buf
+
+
+/* Utility for stat and fstat */
+int stcpy(inoptr ino, char *buf)
+{
+       int err = uput((char *) &(ino->c_dev), buf, 12);
+       err |= uput((char *) &(ino->c_node.i_addr[0]), buf + 12, 2);
+       err |= uput((char *) &(ino->c_node.i_size), buf + 14, 16);
+       return err;
+}
+
+
+int16_t dup_op(int fd, int base)
+{
+       int8_t newd;
+
+       if ((newd = uf_alloc_n(base)) == -1)
+               return (-1);
+
+       udata.u_files[newd] = udata.u_files[fd];
+       ++of_tab[udata.u_files[fd]].o_refs;
+
+       return (newd);
+}
+
+/*******************************************
+  dup (oldd)                       Function 17
+  int16_t oldd;
+ ********************************************/
+#define oldd (uint16_t)udata.u_argn
+
+int16_t _dup(void)
+{
+       int8_t newd;
+       if (getinode(oldd) == NULLINODE)
+               return (-1);
+       if ((newd = uf_alloc()) == -1)
+               return (-1);
+
+       udata.u_files[newd] = udata.u_files[oldd];
+       ++of_tab[udata.u_files[oldd]].o_refs;
+
+       return (newd);
+}
+
+#undef oldd
+
+
+/*******************************************
+  dup2 (oldd, newd)                Function 36        ?
+  int16_t oldd;
+  int16_t newd;
+ ********************************************/
+#define oldd (int16_t)udata.u_argn
+#define newd (int16_t)udata.u_argn1
+
+int16_t _dup2(void)
+{
+
+       if (getinode(oldd) == NULLINODE)
+               return (-1);
+
+       if (newd < 0 || newd >= UFTSIZE) {
+               udata.u_error = EBADF;
+               return (-1);
+       }
+
+       if (udata.u_files[newd] != NO_FILE)
+               doclose(newd);
+
+       udata.u_files[newd] = udata.u_files[oldd];
+       ++of_tab[udata.u_files[oldd]].o_refs;
+
+       return (0);
+}
+
+#undef oldd
+#undef newd
+
+
+/*******************************************
+  umask (mask)                     Function 21        ?
+  int mask;
+ ********************************************/
+#define mask (int16_t)udata.u_argn
+
+int16_t _umask(void)
+{
+       int omask;
+
+       omask = udata.u_mask;
+       udata.u_mask = mask & 0777;
+       return (omask);
+}
+
+#undef mask
+
+
+
+/*******************************************
+  ioctl (fd, request, data)        Function 29
+  int  fd;
+  int  request;
+  char *data;
+ ********************************************/
+#define fd (int)udata.u_argn
+#define request (int)udata.u_argn1
+#define data (char *)udata.u_argn2
+
+int16_t _ioctl(void)
+{
+       inoptr ino;
+       uint16_t dev;
+
+       if ((ino = getinode(fd)) == NULLINODE)
+               return (-1);
+
+       if (!(isdevice(ino))) {
+               udata.u_error = ENOTTY;
+               return (-1);
+       }
+
+       if (!(getperm(ino) & OTH_WR)) {
+               udata.u_error = EPERM;
+               return (-1);
+       }
+
+       dev = ino->c_node.i_addr[0];
+
+       /* top bit of request is reserved for kernel originated magic */
+       if (d_ioctl(dev, request & 0x7FFF, data))
+               return (-1);
+       return (0);
+}
+
+#undef fd
+#undef request
+#undef data
+
+
+
+/*******************************************
+close (uindex)                    Function 2
+int16_t uindex;
+********************************************/
+#define uindex (int8_t)udata.u_argn
+
+int16_t _close(void)
+{
+       return (doclose(uindex));
+}
+
+#undef uindex
+
+
+/*******************************************
+pipe (fildes)                    Function 40           ?
+int fildes[];
+********************************************/
+#define fildes (int16_t *)udata.u_argn
+
+int16_t _pipe(void)
+{
+       int8_t u1, u2, oft1, oft2;
+       inoptr ino;
+
+/* bug fix SN */
+       if ((u1 = uf_alloc()) == -1)
+               goto nogood;
+       if ((oft1 = oft_alloc()) == -1)
+               goto nogood;
+       udata.u_files[u1] = oft1;
+
+       if ((u2 = uf_alloc()) == -1)
+               goto nogood2;
+       if ((oft2 = oft_alloc()) == -1)
+               goto nogood2;
+
+       if (!(ino = i_open(root_dev, 0))) {
+               oft_deref(oft2);
+               goto nogood2;
+       }
+
+       udata.u_files[u2] = oft2;
+
+       of_tab[oft1].o_ptr = 0;
+       of_tab[oft1].o_inode = ino;
+       of_tab[oft1].o_access = O_RDONLY;
+
+       of_tab[oft2].o_ptr = 0;
+       of_tab[oft2].o_inode = ino;
+       of_tab[oft2].o_access = O_WRONLY;
+
+       ++ino->c_refs;
+       ino->c_node.i_mode = F_PIPE | 0777;     /* No permissions necessary on pipes */
+       ino->c_node.i_nlink = 0;        /* a pipe is not in any directory */
+
+       // write results to userspace
+       uputw(u1, fildes);
+       uputw(u2, fildes + 1);
+       return (0);
+
+      nogood2:
+       oft_deref(oft1);
+       udata.u_files[u1] = NO_FILE;
+      nogood:
+       return (-1);
+}
+
+#undef fildes
+
+
+/*******************************************
+unlink (path)                     Function 6
+char *path;
+********************************************/
+#define path (char *)udata.u_argn
+
+/* Helper for the bits shared with rename */
+int16_t unlinki(inoptr ino, inoptr pino, char *fname)
+{
+       if (getmode(ino) == F_DIR) {
+               udata.u_error = EISDIR;
+               return -1;
+       }
+
+       /* Remove the directory entry (ch_link checks perms) */
+       if (!ch_link(pino, fname, "", NULLINODE))
+               return -1;
+
+       /* Decrease the link count of the inode */
+       if (!(ino->c_node.i_nlink--)) {
+               ino->c_node.i_nlink += 2;
+               kprintf("_unlink: bad nlink\n");
+       }
+       setftime(ino, C_TIME);
+       return (0);
+}
+
+/* kind of pinned here by unlinki() */
+int16_t _unlink(void)
+{
+       inoptr ino;
+       inoptr pino;
+       int r;
+       char fname[FILENAME_LEN + 1];
+
+       ino = n_open(path, &pino);
+
+       if (!(pino && ino)) {
+               if (pino)       /* parent exist */
+                       i_deref(pino);
+               udata.u_error = ENOENT;
+               return (-1);
+       }
+       filename(path, fname);
+       r = unlinki(ino, pino, fname);
+       i_deref(pino);
+       i_deref(ino);
+       return r;
+}
+
+#undef path
+
+
+
+/*******************************************
+read (d, buf, nbytes)             Function 7
+int16_t  d;
+char   *buf;
+uint16_t nbytes;
+********************************************/
+#define d (int16_t)udata.u_argn
+#define buf (char *)udata.u_argn1
+#define nbytes (susize_t)udata.u_argn2
+
+int16_t _read(void)
+{
+       inoptr ino;
+       uint8_t flag;
+
+       if (!valaddr(buf, nbytes))
+               return -1;
+       /* Set up u_base, u_offset, ino; check permissions, file num. */
+       if ((ino = rwsetup(true, &flag)) == NULLINODE)
+               return -1;      /* bomb out if error */
+
+       readi(ino, flag);
+       updoff();
+
+       return (udata.u_count);
+}
+
+#undef d
+#undef buf
+#undef nbytes
+
+/*******************************************
+getdirent (d, buf, nbytes)       Function 59
+int16_t  d;
+char   *buf;
+uint16_t nbytes;
+********************************************/
+#define d (int16_t)udata.u_argn
+#define buf (char *)udata.u_argn1
+#define nbytes udata.u_argn2
+
+/*
+ *     Trivial helper to isolate directory size changes
+ *     if we make them.
+ */
+int16_t _getdirent(void)
+{
+        if (nbytes < 16) {
+                udata.u_error = ENOSPC;
+                return -1;
+        }
+        nbytes = DIR_LEN;
+        return _read();
+}
+
+#undef d
+#undef buf
+#undef nbytes
+
+
+/*******************************************
+write (d, buf, nbytes)            Function 8
+int16_t  d;
+char   *buf;
+uint16_t nbytes;
+********************************************/
+#define d (int16_t)udata.u_argn
+#define buf (char *)udata.u_argn1
+#define nbytes (susize_t)udata.u_argn2
+
+int16_t _write(void)
+{
+       inoptr ino;
+       uint8_t flag;
+
+       if (!valaddr(buf, nbytes))
+               return -1;
+       /* Set up u_base, u_offset, ino; check permissions, file num. */
+       if ((ino = rwsetup(false, &flag)) == NULLINODE)
+               return (-1);    /* bomb out if error */
+
+       writei(ino, flag);
+       updoff();
+
+       return (udata.u_count);
+}
+
+#undef d
+#undef buf
+#undef nbytes
+
diff --git a/Kernel/syscall_fs2.c b/Kernel/syscall_fs2.c
new file mode 100644 (file)
index 0000000..fe7d917
--- /dev/null
@@ -0,0 +1,656 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+/*
+ *     File system related calls that are not continually used (so
+ *     we can potentially bank them out if we do a 32K/32K mode)
+ */
+
+static int16_t chdiroot_op(inoptr ino, inoptr * p)
+{
+       if (getmode(ino) != F_DIR) {
+               udata.u_error = ENOTDIR;
+               i_deref(ino);
+               return (-1);
+       }
+       i_deref(*p);
+       *p = ino;
+       return 0;
+}
+
+/*******************************************
+  chdir (dir)                      Function 10
+  char *dir;
+ ********************************************/
+#define dir (char *)udata.u_argn
+
+int16_t _chdir(void)
+{
+       inoptr newcwd;
+
+       if (!(newcwd = n_open(dir, NULLINOPTR)))
+               return (-1);
+       return chdiroot_op(newcwd, &udata.u_cwd);
+}
+
+#undef dir
+
+/*******************************************
+  fchdir(fd)                      Function 48
+  int fd;
+ ********************************************/
+#define fd (int16_t)udata.u_argn
+
+int16_t _fchdir(void)
+{
+       inoptr newcwd;
+
+       if ((newcwd = getinode(fd)) == NULLINODE)
+               return (-1);
+       i_ref(newcwd);
+       return chdiroot_op(newcwd, &udata.u_cwd);
+}
+
+#undef fd
+
+/*******************************************
+  chroot (dir)                      Function 46
+  char *dir;
+ ********************************************/
+#define dir (char *)udata.u_argn
+
+int16_t _chroot(void)
+{
+       inoptr newroot;
+
+       if (esuper())
+               return (-1);
+       if (!(newroot = n_open(dir, NULLINOPTR)))
+               return (-1);
+       return chdiroot_op(newroot, &udata.u_root);
+}
+
+#undef dir
+
+
+/*******************************************
+  mknod (name, mode, dev)           Function 4
+  char  *name;
+  int16_t mode;
+  int16_t dev;
+ ********************************************/
+#define name (char *)udata.u_argn
+#define mode (int16_t)udata.u_argn1
+#define dev  (int16_t)udata.u_argn2
+
+int16_t _mknod(void)
+{
+       inoptr ino;
+       inoptr parent;
+       char fname[FILENAME_LEN + 1];
+
+       udata.u_error = 0;
+
+       if (!super() && ((mode & F_MASK) != F_PIPE)) {
+               udata.u_error = EPERM;
+               goto nogood3;
+       }
+       if ((ino = n_open(name, &parent)) != NULL) {
+               udata.u_error = EEXIST;
+               goto nogood;
+       }
+
+       if (!parent) {
+               udata.u_error = ENOENT;
+               return (-1);
+       }
+
+       filename(name, fname);
+       if ((ino = newfile(parent, fname)) != NULL)
+               goto nogood3;   /* parent inode is derefed in newfile. SN */
+
+       /* Initialize mode and dev */
+       ino->c_node.i_mode = mode & ~udata.u_mask;
+       ino->c_node.i_addr[0] = isdevice(ino) ? dev : 0;
+       setftime(ino, A_TIME | M_TIME | C_TIME);
+       wr_inode(ino);
+
+       i_deref(ino);
+       return (0);
+
+      nogood:
+       i_deref(ino);
+       i_deref(parent);
+      nogood3:
+       return (-1);
+}
+
+#undef name
+#undef mode
+#undef dev
+
+/*******************************************
+  access (path, mode)              Function 12        ?
+  char  *path;
+  int16_t mode;
+ ********************************************/
+#define path (char *)udata.u_argn
+#define mode (int16_t)udata.u_argn1
+
+int16_t _access(void)
+{
+       inoptr ino;
+       uint16_t euid;
+       uint16_t egid;
+       uint16_t retval;
+
+       if ((mode & 07) && !ugetc(path)) {
+               udata.u_error = ENOENT;
+               return (-1);
+       }
+
+       /* Temporarily make eff. id real id. */
+       euid = udata.u_euid;
+       egid = udata.u_egid;
+       udata.u_euid = udata.u_ptab->p_uid;
+       udata.u_egid = udata.u_gid;
+
+       if (!(ino = n_open(path, NULLINOPTR))) {
+               retval = -1;
+               goto nogood;
+       }
+
+       retval = 0;
+       if (~getperm(ino) & (mode & 07)) {
+               udata.u_error = EPERM;
+               retval = -1;
+       }
+
+       i_deref(ino);
+      nogood:
+       udata.u_euid = euid;
+       udata.u_egid = egid;
+
+       return (retval);
+}
+
+#undef path
+#undef mode
+
+#define mode (int16_t)udata.u_argn1
+
+static int16_t chmod_op(inoptr ino)
+{
+       if (ino->c_node.i_uid != udata.u_euid && esuper()) {
+               i_deref(ino);
+               return (-1);
+       }
+
+       ino->c_node.i_mode =
+           (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK);
+       setftime(ino, C_TIME);
+       return 0;
+}
+
+#undef mode
+
+/*******************************************
+  chmod (path, mode)               Function 13
+  char  *path;
+  int16_t mode;
+ ********************************************/
+#define path (char *)udata.u_argn
+
+int16_t _chmod(void)
+{
+       inoptr ino;
+       int ret;
+
+       if (!(ino = n_open(path, NULLINOPTR)))
+               return (-1);
+       ret = chmod_op(ino);
+       i_deref(ino);
+       return ret;
+}
+
+#undef path
+
+/*******************************************
+  fchmod (path, mode)               Function 49
+  int fd;
+  int16_t mode;
+ ********************************************/
+#define fd (int16_t)udata.u_argn
+
+int16_t _fchmod(void)
+{
+       inoptr ino;
+
+       if ((ino = getinode(fd)) == NULLINODE)
+               return (-1);
+
+       return chmod_op(ino);
+}
+
+#undef fd
+
+#define owner (int16_t)udata.u_argn1
+#define group (int16_t)udata.u_argn2
+
+static int chown_op(inoptr ino)
+{
+       if (ino->c_node.i_uid != udata.u_euid && esuper()) {
+               i_deref(ino);
+               return (-1);
+       }
+       ino->c_node.i_uid = owner;
+       ino->c_node.i_gid = group;
+       setftime(ino, C_TIME);
+       return 0;
+}
+
+#undef owner
+#undef group
+
+/*******************************************
+  chown (path, owner, group)       Function 14        ?
+  char *path;
+  int  owner;
+  int  group;
+ ********************************************/
+#define path (char *)udata.u_argn
+
+int16_t _chown(void)
+{
+       inoptr ino;
+       int ret;
+
+       if (!(ino = n_open(path, NULLINOPTR)))
+               return (-1);
+       ret = chown_op(ino);
+       i_deref(ino);
+       return ret;
+}
+
+#undef path
+
+/*******************************************
+  fchown (path, owner, group)       Function 50
+  int fd;
+  int  owner;
+  int  group;
+ ********************************************/
+#define fd (int16_t)udata.u_argn
+
+int16_t _fchown(void)
+{
+       inoptr ino;
+
+       if ((ino = getinode(fd)) == NULLINODE)
+               return (-1);
+       return chown_op(ino);
+}
+
+#undef fd
+
+
+/*******************************************
+  utime (file, buf)                Function 43
+  char *file;
+  char *buf;
+ ********************************************/
+#define file (char *)udata.u_argn
+#define buf (char *)udata.u_argn1
+
+int16_t _utime(void)
+{
+       inoptr ino;
+       time_t t[2];
+
+       if (!valaddr(buf, 2 * sizeof(time_t)))
+               return (-1);
+       if (!(ino = n_open(file, NULLINOPTR)))
+               return (-1);
+       if (ino->c_node.i_uid != udata.u_euid && esuper()) {
+               i_deref(ino);
+               return (-1);
+       }
+       uget(buf, t, 2 * sizeof(time_t));
+       /* FIXME: needs updating once we pack top bits
+          elsewhere in the inode */
+       ino->c_node.i_atime = t[0];
+       ino->c_node.i_mtime = t[1];
+       setftime(ino, C_TIME);
+       i_deref(ino);
+       return (0);
+}
+
+#undef file
+#undef buf
+
+/*******************************************
+  acct(fd)                      Function 61
+  int16_t fd;
+  
+  Process accounting. Differs from SYS5 in
+  that we pass an fd and hide the opening
+  in the C library code.
+ *******************************************/
+#define fd (int16_t)udata.u_argn
+
+int16_t _acct(void)
+{
+#ifdef CONFIG_ACCT
+        inoptr inode;
+        if (esuper())
+                return -1;
+        if (acct_fh != -1)
+                oft_deref(acct_fh);
+        if (fd != -1) {
+                if ((inode = getinode(fd)) == NULLINODE)
+                        return -1;
+                if (getmode(inode) != F_REG) {
+                        udata.u_error = EINVAL;
+                        return -1;
+                }
+               acct_fh = udata.u_files[fd];
+               ++of_tab[acct_fh].o_refs;
+        }
+       return 0;
+#else
+        udata.u_error = EINVAL;
+        return -1;
+#endif        
+}
+
+#undef fd
+
+/* Special system call returns super-block of given filesystem
+ * for users to determine free space, etc.  Should be replaced
+ * with a sync() followed by a read of block 1 of the device.
+ */
+/*******************************************
+  getfsys (dev, buf)               Function 22
+  int16_t  dev;
+  struct filesys *buf;
+ ********************************************/
+#define dev (uint16_t)udata.u_argn
+#define buf (struct filesys *)udata.u_argn1
+
+int16_t _getfsys(void)
+{
+        struct mount *m = fs_tab_get(dev);
+       if (dev == NO_DEVICE  || m == NULL) {
+               udata.u_error = ENXIO;
+               return (-1);
+       }
+       uput((char *) m->m_fs, (char *) buf, sizeof(struct filesys));
+       return (0);
+}
+
+#undef dev
+#undef buf
+
+/*******************************************
+open (name, flag, mode)           Function 1
+char *name;
+int16_t flag;
+int16_t mode;
+********************************************/
+#define name (char *)udata.u_argn
+#define flag (uint16_t)udata.u_argn1
+#define mode (uint16_t)udata.u_argn2
+
+int16_t _open(void)
+{
+       int8_t uindex;
+       int8_t oftindex;
+       inoptr ino;
+       int16_t perm;
+       inoptr parent;
+       char fname[FILENAME_LEN + 1];
+       int trunc;
+       int r;
+       int w;
+       int j;
+
+       parent = NULLINODE;
+
+       trunc = flag & O_TRUNC;
+       r = (flag + 1) & 1;
+       w = (flag + 1) & 2;
+
+       if (O_ACCMODE(flag) == 3 || (flag & O_BADBITS)) {
+               udata.u_error = EINVAL;
+               return (-1);
+       }
+       if ((uindex = uf_alloc()) == -1)
+               return (-1);
+
+       if ((oftindex = oft_alloc()) == -1)
+               goto nooft;
+
+       ino = n_open(name, &parent);
+       if (ino) {
+               i_deref(parent);
+               /* O_EXCL test */
+               if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
+                       udata.u_error = EEXIST;
+                       goto idrop;
+               }
+       } else {
+               /* New file */
+               if (!(flag & O_CREAT)) {
+                       udata.u_error = ENOENT;
+                       goto cantopen;
+               }
+               filename(name, fname);
+               /* newfile drops parent for us */
+               if (parent && (ino = newfile(parent, fname))) {
+                       ino->c_node.i_mode =
+                           (F_REG | (mode & MODE_MASK & ~udata.u_mask));
+                       setftime(ino, A_TIME | M_TIME | C_TIME);
+                       wr_inode(ino);
+               } else {
+                       udata.u_error = ENFILE; /* FIXME, should be set in newfile
+                                                  not bodged to a guessed code */
+                       goto cantopen;
+               }
+       }
+       of_tab[oftindex].o_inode = ino;
+
+       perm = getperm(ino);
+       if ((r && !(perm & OTH_RD)) || (w && !(perm & OTH_WR))) {
+               udata.u_error = EPERM;
+               goto cantopen;
+       }
+       if (getmode(ino) == F_DIR && w) {
+               udata.u_error = EISDIR;
+               goto cantopen;
+       }
+       if (isdevice(ino)
+           && d_open((int) ino->c_node.i_addr[0], flag) != 0) {
+               udata.u_error = ENXIO;
+               goto cantopen;
+       }
+       if (trunc && getmode(ino) == F_REG) {
+               f_trunc(ino);
+               for (j = 0; j < OFTSIZE; ++j)
+                       /* Arguably should fix at read/write */
+                       if (of_tab[j].o_inode == ino)
+                               of_tab[j].o_ptr = 0;
+       }
+
+       udata.u_files[uindex] = oftindex;
+
+       of_tab[oftindex].o_ptr = 0;
+       of_tab[oftindex].o_access = flag;       /* Save the low bits only */
+       if (flag & O_CLOEXEC)
+               udata.u_cloexec |= (1 << oftindex);
+       /* FIXME: ATIME ? */
+
+/*
+ *         Sleep process if no writer or reader
+ */
+       if (getmode(ino) == F_PIPE && of_tab[oftindex].o_refs == 1
+           && !(flag & O_NDELAY))
+               psleep(ino);
+
+       return (uindex);
+      idrop:
+       i_deref(ino);
+      cantopen:
+       oft_deref(oftindex);    /* This will call i_deref() */
+      nooft:
+       udata.u_files[uindex] = NO_FILE;
+       return (-1);
+}
+
+#undef name
+#undef flag
+#undef mode
+
+
+
+/*******************************************
+link (name1, name2)               Function 5
+char *name1;
+char *name2;
+********************************************/
+#define name1 (char *)udata.u_argn
+#define name2 (char *)udata.u_argn1
+
+int16_t _link(void)
+{
+       inoptr ino;
+       inoptr ino2;
+       inoptr parent2;
+       char fname[FILENAME_LEN + 1];
+
+       if (!(ino = n_open(name1, NULLINOPTR)))
+               return (-1);
+
+       if (getmode(ino) == F_DIR && esuper())
+               goto nogood;
+
+       /* Make sure file2 doesn't exist, and get its parent */
+       if ((ino2 = n_open(name2, &parent2)) != NULL) {
+               i_deref(ino2);
+               i_deref(parent2);
+               udata.u_error = EEXIST;
+               goto nogood;
+       }
+
+       if (!parent2)
+               goto nogood;
+
+       if (ino->c_dev != parent2->c_dev) {
+               i_deref(parent2);
+               udata.u_error = EXDEV;
+               goto nogood;
+       }
+
+       filename(name2, fname);
+
+       if (!ch_link(parent2, "", fname, ino)) {
+               i_deref(parent2);
+               goto nogood;
+       }
+
+       /* Update the link count. */
+       ++ino->c_node.i_nlink;
+       wr_inode(ino);
+       setftime(ino, C_TIME);
+
+       i_deref(parent2);
+       i_deref(ino);
+       return 0;
+
+      nogood:
+       i_deref(ino);
+       return -1;
+}
+
+#undef name1
+#undef name2
+
+
+/*******************************************
+  fcntl (fd, request, data)        Function 47
+  int  fd;
+  int  request;
+  char *data;
+ ********************************************/
+#define fd (int)udata.u_argn
+#define request (int)udata.u_argn1
+#define data (int)udata.u_argn2
+
+int16_t _fcntl(void)
+{
+       uint8_t *acc;
+       int newd;
+
+       if (getinode(fd) == NULLINODE)
+               return (-1);
+
+       acc = &of_tab[udata.u_files[fd]].o_access;
+       switch (request) {
+       case F_SETFL:
+               *acc =
+                   (*acc & ~(O_APPEND | O_NDELAY)) | (data &
+                                                      (O_APPEND |
+                                                       O_NDELAY));
+               return 0;
+       case F_GETFL:
+               return data;
+       case F_GETFD:
+               return udata.u_cloexec & (1 << fd) ? O_CLOEXEC : 0;
+       case F_SETFD:
+               if (data & O_CLOEXEC)
+                       udata.u_cloexec |= (1 << fd);
+               else
+                       udata.u_cloexec &= (1 << fd);
+               return 0;
+       case F_DUPFD:
+               if ((newd = uf_alloc_n(data)) == -1)
+                       return (-1);
+               udata.u_files[newd] = udata.u_files[fd];
+               ++of_tab[udata.u_files[fd]].o_refs;
+               return 0;
+       default:
+               udata.u_error = EINVAL;
+               return -1;
+       }
+}
+
+#undef fd
+#undef request
+#undef data
+
+/*******************************************
+uname (buf)                      Function 54
+char *buf;
+uint16_t len;
+
+We pass a set of \0 terminated strings, don't bother
+with node name. Rest is up to the libc.
+********************************************/
+
+#define buf (char *)udata.u_argn
+#define len (uint16_t)udata.u_argn1
+
+int16_t _uname(void)
+{
+        uint16_t size = sizeof(sysinfo) + uname_len;
+        if (size > len)
+                size = len;
+       sysinfo.memk = procmem;
+       sysinfo.usedk = pagemap_mem_used();
+       uput(&sysinfo, buf, size);
+       return size;
+}
+
+#undef buf
diff --git a/Kernel/syscall_other.c b/Kernel/syscall_other.c
new file mode 100644 (file)
index 0000000..b46fa5e
--- /dev/null
@@ -0,0 +1,775 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+/*
+ *     More obscure syscalls that it might be useful to pull out of the main
+ *     flow in case we ever need to bank any of them. Avoid putting anything
+ *     that may sleep in here. We want this to potentially be pageable syscall
+ *     helper. Right now its about 3.5K of material
+ */
+
+
+/*******************************************
+rename (src, dst)                Function 59
+char *src;
+char *dst;
+
+Rename a file within a filesystem, can be
+a directory. Don't allow an object to be
+put inside itself!
+********************************************/
+
+#define src (char *)udata.u_argn
+#define dst (char *)udata.u_argn1
+
+int16_t _rename(void)
+{
+       inoptr srci, srcp, dsti, dstp;
+       char fname[FILENAME_LEN + 1];
+       int ret = -1;
+
+       srci = n_open(src, &srcp);
+       /* Source must exist */
+       if (!srci) {
+               if (srcp)
+                       i_deref(srcp);
+               return -1;
+       }
+       /* n_open will wipe u_rename if it walks that inode
+          so it tells us whether we are trying to create a loop */
+       udata.u_rename = srci;
+       /* Destination must not exist, but parent must */
+       filename(dst, fname);
+       dsti = n_open(dst, &dstp);
+       /* Destination not found, but neither is the directory to
+          put the new node in -> so fail */
+       if (dstp == NULLINODE)
+               goto nogood3;
+       /* Can't rename between devices */
+       if (srci->c_dev != dstp->c_dev) {
+               udata.u_error = EXDEV;
+               goto nogood;
+       }
+       /* Can't rename one dir into another */
+       if (udata.u_rename == NULL) {
+               /* dst is within src */
+               udata.u_error = EINVAL;
+               goto nogood;
+       }
+       /* Check we can write the src dir, we don't want to fail on
+          ch_link */
+       if (!(getperm(srcp) & OTH_WR) && esuper()) {
+               udata.u_error = EPERM;
+               goto nogood;
+       }
+       /* Destination exists ? If so we must remove it if possible */
+       if (dsti) {
+               if (unlinki(dsti, dstp, fname) == -1)
+                       goto nogood;
+               /* Drop the reference to the unlinked file */
+               i_deref(dsti);
+       }
+       /* Ok we may proceed: we set up fname earlier */
+       if (!ch_link(dstp, "", fname, srci))
+               goto nogood2;
+       filename(src, fname);
+       /* A fail here is bad */
+       if (!ch_link(srcp, fname, "", NULLINODE)) {
+               kputs("WARNING: rename: unlink fail\n");
+               goto nogood2;
+       }
+       /* get it onto disk - probably overkill */
+       wr_inode(dstp);
+       wr_inode(srcp);
+       _sync();
+       ret = 0;
+      nogood2:
+       i_deref(dstp);
+      nogood3:
+       i_deref(srci);
+       i_deref(srcp);
+       return ret;
+      nogood:
+       if (dsti)
+               i_deref(dsti);
+       goto nogood2;
+}
+
+#undef src
+#undef dst
+
+/*******************************************
+  mkdir (path, mode)           Function 51
+  char *path;
+  int16_t mode;
+ ********************************************/
+
+#define name (char *)udata.u_argn
+#define mode (int16_t)udata.u_argn1
+
+int16_t _mkdir(void)
+{
+       inoptr ino;
+       inoptr parent;
+       char fname[FILENAME_LEN + 1];
+
+       if ((ino = n_open(name, &parent)) != NULL) {
+               udata.u_error = EEXIST;
+               goto nogood;
+       }
+
+       if (!parent) {
+               udata.u_error = ENOENT;
+               return (-1);
+       }
+
+       filename(name, fname);
+
+       i_ref(parent);          /* We need it again in a minute */
+       if (!(ino = newfile(parent, fname))) {
+               i_deref(parent);
+               goto nogood2;   /* parent inode is derefed in newfile. */
+       }
+
+       /* Initialize mode and dev */
+       ino->c_node.i_mode = F_DIR | 0200;      /* so ch_link is allowed */
+       setftime(ino, A_TIME | M_TIME | C_TIME);
+       if (ch_link(ino, "", ".", ino) == 0 ||
+           ch_link(ino, "", "..", parent) == 0)
+               goto cleanup;
+
+       /* Link counts and permissions */
+       ino->c_node.i_nlink = 2;
+       parent->c_node.i_nlink++;
+       ino->c_node.i_mode = ((mode & ~udata.u_mask) & MODE_MASK) | F_DIR;
+       i_deref(parent);
+       wr_inode(ino);
+       i_deref(ino);
+       return (0);
+
+      cleanup:
+       if (!ch_link(parent, fname, "", NULLINODE))
+               kprintf("_mkdir: bad rec\n");
+       /* i_deref will put the blocks */
+       ino->c_node.i_nlink = 0;
+       wr_inode(ino);
+      nogood:
+       i_deref(ino);
+      nogood2:
+       i_deref(parent);
+       return (-1);
+
+}
+
+#undef name
+#undef mode
+
+/*******************************************
+rmdir (path)                     Function 52
+char *path;
+********************************************/
+#define path (char *)udata.u_argn
+
+int16_t _rmdir(void)
+{
+       inoptr ino;
+       inoptr parent;
+       char fname[FILENAME_LEN + 1];
+
+       ino = n_open(path, &parent);
+
+       /* It and its parent must exist */
+       if (!(parent && ino)) {
+               if (parent)     /* parent exist */
+                       i_deref(parent);
+               udata.u_error = ENOENT;
+               return (-1);
+       }
+
+       /* Fixme: check for rmdir of /. - ditto for unlink ? */
+
+       /* Not a directory */
+       if (getmode(ino) != F_DIR) {
+               udata.u_error = ENOTDIR;
+               goto nogood;
+       }
+
+       /* Busy */
+       if (ino->c_node.i_nlink != 2) {
+               udata.u_error = ENOTEMPTY;
+               goto nogood;
+       }
+
+       /* Parent must be writable */
+       if (!getperm(parent) & OTH_WR)
+               goto nogood;
+
+       /* Remove the directory entry */
+       filename(path, fname);
+       if (!ch_link(parent, fname, "", NULLINODE))
+               goto nogood;
+
+       /* We are unused, parent is now one link down (removal of ..) */
+       ino->c_node.i_nlink = 0;
+
+       /* Decrease the link count of the parent inode */
+       if (!(parent->c_node.i_nlink--)) {
+               parent->c_node.i_nlink += 2;
+               kprintf("_rmdir: bad nlink\n");
+       }
+       setftime(ino, C_TIME);
+       wr_inode(parent);
+       wr_inode(ino);
+       i_deref(parent);
+       i_deref(ino);
+       return (0);
+
+      nogood:
+       i_deref(parent);
+       i_deref(ino);
+       return (-1);
+}
+
+#undef path
+
+
+/*******************************************
+  mount (spec, dir, flags)       Function 33
+  char *spec;
+  char *dir;
+  int  flags;
+ ********************************************/
+#define spec (char *)udata.u_argn
+#define dir (char *)udata.u_argn1
+#define flags (int)udata.u_argn2
+
+int16_t _mount(void)
+{
+       inoptr sino, dino;
+       uint16_t dev;
+
+       if (esuper()) {
+               return (-1);
+       }
+
+       if (!(sino = n_open(spec, NULLINOPTR)))
+               return (-1);
+
+       if (!(dino = n_open(dir, NULLINOPTR))) {
+               i_deref(sino);
+               return (-1);
+       }
+
+       if (getmode(sino) != F_BDEV) {
+               udata.u_error = ENOTBLK;
+               goto nogood;
+       }
+
+       if (getmode(dino) != F_DIR) {
+               udata.u_error = ENOTDIR;
+               goto nogood;
+       }
+
+       dev = (int) sino->c_node.i_addr[0];
+
+       if (!validdev(dev) || d_open(dev, (flags & MS_RDONLY) ? O_RDONLY : O_RDWR)) {
+               udata.u_error = ENXIO;
+               goto nogood;
+       }
+
+       if (fs_tab_get(dev) || dino->c_refs != 1 || dino->c_num == ROOTINODE) {
+               udata.u_error = EBUSY;
+               goto nogood;
+       }
+
+       _sync();
+
+       if (fmount(dev, dino, flags)) {
+               udata.u_error = EBUSY;
+               goto nogood;
+       }
+
+       i_deref(dino);
+       i_deref(sino);
+       return (0);
+
+      nogood:
+       i_deref(dino);
+       i_deref(sino);
+       return (-1);
+}
+
+#undef spec
+#undef dir
+#undef flags
+
+
+/*******************************************
+  umount (spec)                    Function 34
+  char *spec;
+ ********************************************/
+#define spec (char *)udata.u_argn
+
+int16_t _umount(void)
+{
+       inoptr sino;
+       uint16_t dev;
+       inoptr ptr;
+       struct mount *mnt;
+
+       if (esuper())
+               return (-1);
+
+       if (!(sino = n_open(spec, NULLINOPTR)))
+               return (-1);
+
+       if (getmode(sino) != F_BDEV) {
+               udata.u_error = ENOTBLK;
+               goto nogood;
+       }
+
+       dev = (int) sino->c_node.i_addr[0];
+       if (!validdev(dev)) {
+               udata.u_error = ENXIO;
+               goto nogood;
+       }
+
+       mnt = fs_tab_get(dev);
+       if (mnt == NULL) {
+               udata.u_error = EINVAL;
+               goto nogood;
+       }
+
+       for (ptr = i_tab; ptr < i_tab + ITABSIZE; ++ptr)
+               if (ptr->c_refs > 0 && ptr->c_dev == dev) {
+                       udata.u_error = EBUSY;
+                       goto nogood;
+               }
+
+       _sync();
+
+       mnt->m_fs->s_mounted = 0;
+       i_deref(mnt->m_fs->s_mntpt);
+       /* Give back the buffer we pinned at mount time */
+       bfree((bufptr)mnt->m_fs, 2);
+       /* Vanish the entry */
+       mnt->m_dev = NO_DEVICE;
+       i_deref(sino);
+       return 0;
+
+      nogood:
+       i_deref(sino);
+       return -1;
+}
+
+#undef spec
+
+
+/* User's execve() call. All other flavors are library routines. */
+/*******************************************
+execve (name, argv, envp)        Function 23
+char *name;
+char *argv[];
+char *envp[];
+********************************************/
+#define name (char *)udata.u_argn
+#define argv (char **)udata.u_argn1
+#define envp (char **)udata.u_argn2
+
+int16_t _execve(void)
+{
+       inoptr ino, emu_ino;
+       unsigned char *buf;
+       blkno_t blk;
+       char **nargv;           /* In user space */
+       char **nenvp;           /* In user space */
+       struct s_argblk *abuf, *ebuf;
+       int16_t (**sigp) ();
+       int argc;
+       uint16_t emu_size, emu_copy;
+       uint8_t *progptr, *emu_ptr, *emu_base;
+       int j;
+       uint16_t top = (uint16_t)ramtop;
+       uint8_t c;
+
+       kputs("execve\n");
+
+       if (!(ino = n_open(name, NULLINOPTR)))
+               return (-1);
+
+       kputs("Found it\n");
+       if (!((getperm(ino) & OTH_EX) &&
+             (ino->c_node.i_mode & F_REG) &&
+             (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) {
+               udata.u_error = EACCES;
+               goto nogood;
+       }
+
+       setftime(ino, A_TIME);
+
+       /* Read in the first block of the new program */
+       buf = bread(ino->c_dev, bmap(ino, 0, 1), 0);
+
+    /****************************************
+     * Get magic number into var magic
+     * C3    : executable file no C/D sep.
+     * 00FF  :     "        "  with C/D sep. (not supported in FUZIX)
+     * other : maybe shell script (nogood2)
+     ****************************************/
+       if ((*buf & 0xff) != EMAGIC) {
+               udata.u_error = ENOEXEC;
+               goto nogood2;
+       }
+       kputs("Magic\n");
+
+       /*
+        *      Executables might be CP/M or Fuzix (we don't support legacy
+        *      UZI binaries).
+        */
+       if (buf[3] == 'F' && buf[4] == 'Z' && buf[5] == 'X' && buf[6] == '1') {
+               top = buf[7] | ((unsigned int)buf[8] << 8);
+               if (top == 0)   /* Legacy 'all space' binary */
+                       top = (uint16_t)ramtop;
+               emu_ino = 0;    // no emulation, thanks
+       } else {
+#ifdef CONFIG_CPM_EMU
+               // open the emulator code on disk
+               emu_ino = kn_open(CPM_EMULATOR_FILENAME, NULLINOPTR);
+               if (!emu_ino) {
+                       kprintf("Cannot load emulator: %s\n",
+                               CPM_EMULATOR_FILENAME);
+                       udata.u_error = ENOEXEC;
+                       goto nogood2;
+               }
+               top = (uint16_t)ramtop;
+#else
+               emu_size;
+               emu_copy;
+               emu_ptr;
+               udata.u_error = ENOEXEC;
+               goto nogood2;
+#endif
+       }
+
+       /* Binary doesn't fit */
+       if (top < ino->c_node.i_size + 1024) {
+               udata.u_error = ENOMEM;
+               goto nogood2;
+       }
+
+       /* Gather the arguments, and put them in temporary buffers. */
+       abuf = (struct s_argblk *) tmpbuf();
+       /* Put environment in another buffer. */
+       ebuf = (struct s_argblk *) tmpbuf();
+
+       /* Read args and environment from process memory */
+       if (rargs(argv, abuf) || rargs(envp, ebuf))
+               goto nogood3;   /* SN */
+
+       /* This must be the last test as it makes changes if it works */
+       if (pagemap_realloc(top))
+               goto nogood3;
+
+       /* From this point on we are commmited to the exec() completing */
+       udata.u_top = top;
+
+       /* setuid, setgid if executable requires it */
+       if (ino->c_node.i_mode & SET_UID)
+               udata.u_euid = ino->c_node.i_uid;
+
+       if (ino->c_node.i_mode & SET_GID)
+               udata.u_egid = ino->c_node.i_gid;
+
+       /* We are definitely going to succeed with the exec,
+        * so we can start writing over the old program
+        */
+       uput(buf, PROGBASE, 512);       /* Move 1st Block to user bank */
+       brelse(buf);
+
+       c = ugetc(PROGBASE);
+       if (c != 0xC3)
+               kprintf("Botched uput\n");
+
+       /* At this point, we are committed to reading in and
+        * executing the program. */
+
+       for (j = 0; j < UFTSIZE; ++j) {
+               if (udata.u_cloexec & (1 << j))
+                       doclose(j);
+       }
+       udata.u_cloexec = 0;
+
+#ifdef CONFIG_CPM_EMU
+       // Load the CP/M emulator if it is required
+       if (emu_ino) {
+               emu_size =
+                   (512 * emu_ino->c_node.i_size.o_blkno) +
+                   emu_ino->c_node.i_size.o_offset;
+               // round up to nearest multiple of 256 bytes, fit it in below ramtop
+               emu_ptr =
+                   (char *) (udata.u_top - ((emu_size + 255) & 0xff00));
+               emu_base = emu_ptr;
+               blk = 0;
+
+               while (emu_size) {
+                       buf = bread(emu_ino->c_dev, bmap(emu_ino, blk, 1), 0);  // read block
+                       emu_copy = min(512, emu_size);
+                       uput(buf, emu_ptr, emu_copy);   // copy to userspace
+                       bufdiscard((bufptr) buf);
+                       brelse((bufptr) buf);   // release block
+                       // adjust pointers
+                       emu_ptr += emu_copy;
+                       emu_size -= emu_copy;
+                       blk++;
+               }
+               // close emulator file
+               i_deref(emu_ino);
+
+               /*
+                * zero out the remainder of memory between the top of the emulator and top
+                * of process memory
+                */
+
+               uzero(emu_ptr, top - emu_ptr);
+       } else
+#endif
+       {
+               emu_base = (uint8_t *)top;
+       }
+
+       /* emu_base now points at the byte after the last byte the program can occupy */
+
+       /*
+        *  Read in the rest of the program, block by block
+        *  We use bufdiscard so that we load the entire app through the
+        *  same buffer to avoid cycling our small cache on this. Indirect blocks
+        *  will still be cached. - Hat tip to Steve Hosgood's OMU for that trick
+        */
+       progptr = PROGBASE + 512;       // we copied the first block already
+       for (blk = 1; blk <= ino->c_node.i_size >> 9; ++blk) {
+               buf = bread(ino->c_dev, bmap(ino, blk, 1), 0);
+               uput(buf, progptr, 512);
+               bufdiscard((bufptr) buf);
+               brelse((bufptr) buf);
+               progptr += 512;
+       }
+       i_deref(ino);
+       udata.u_break = (int) progptr;  //  Set initial break for program
+
+       // zero all remaining process memory above the last block loaded.
+       uzero(progptr, emu_base - progptr);
+
+       // Turn off caught signals
+       for (sigp = udata.u_sigvec; sigp < udata.u_sigvec + NSIGS; ++sigp)
+               *sigp = SIG_DFL;
+
+       // place the arguments, environment and stack at the top of userspace memory,
+
+       // Write back the arguments and the environment
+       nargv = wargs(((char *) emu_base - 2), abuf, &argc);
+       nenvp = wargs((char *) (nargv), ebuf, NULL);
+
+       // Fill in udata.u_name with Program invocation name
+       uget((void *) ugetw(nargv), udata.u_name, 8);
+       memcpy(udata.u_ptab->p_name, udata.u_name, 8);
+
+       brelse(abuf);
+       brelse(ebuf);
+
+       // Shove argc and the address of argv just below envp
+       uputw((uint16_t) nargv, nenvp - 1);
+       uputw((uint16_t) argc, nenvp - 2);
+
+       // Set stack pointer for the program
+       udata.u_isp = nenvp - 2;
+
+       // Start execution (never returns)
+#ifdef CONFIG_CPM_EMU
+       if (emu_ino)
+               doexec(emu_base);
+       else
+#endif
+               doexec(PROGBASE);
+
+       // tidy up in various failure modes:
+      nogood3:
+       brelse(abuf);
+       brelse(ebuf);
+#ifdef CONFIG_CPM_EMU
+       if (emu_ino)
+               i_deref(emu_ino);
+#endif
+      nogood2:
+       brelse(buf);
+      nogood:
+       i_deref(ino);
+       return (-1);
+}
+
+#undef name
+#undef argv
+#undef envp
+
+/* SN    TODO      max (1024) 512 bytes for argv
+               and max  512 bytes for environ
+*/
+
+bool rargs(char **userspace_argv, struct s_argblk * argbuf)
+{
+       char *ptr;              /* Address of base of arg strings in user space */
+       uint8_t c;
+       uint8_t *bufp;
+
+       argbuf->a_argc = 0;     /* Store argc in argbuf */
+       bufp = argbuf->a_buf;
+
+       while ((ptr = (char *) ugetw(userspace_argv++)) != NULL) {
+               ++(argbuf->a_argc);     /* Store argc in argbuf. */
+               do {
+                       *bufp++ = c = ugetc(ptr++);
+                       if (bufp > argbuf->a_buf + 500) {
+                               udata.u_error = E2BIG;
+                               return true;    // failed
+                       }
+               }
+               while (c);
+       }
+       argbuf->a_arglen = bufp - (uint8_t *)argbuf->a_buf;     /*Store total string size. */
+       return false;           // success
+}
+
+
+char **wargs(char *ptr, struct s_argblk *argbuf, int *cnt)     // ptr is in userspace
+{
+       char **argv;            /* Address of users argv[], just below ptr */
+       int argc, arglen;
+       char **argbase;
+       uint8_t *sptr;
+
+       sptr = argbuf->a_buf;
+
+       /* Move them into the users address space, at the very top */
+       ptr -= (arglen = argbuf->a_arglen);
+
+       if (arglen) {
+               uput(sptr, ptr, arglen);
+       }
+
+       /* Set argv to point below the argument strings */
+       argc = argbuf->a_argc;
+       argbase = argv = (char **) ptr - (argc + 1);
+
+       if (cnt) {
+               *cnt = argc;
+       }
+
+       /* Set each element of argv[] to point to its argument string */
+       while (argc--) {
+               uputw((uint16_t) ptr, argv++);
+               if (argc) {
+                       do
+                               ++ptr;
+                       while (*sptr++);
+               }
+       }
+       uputw(0, argv);         /*;;26Feb- Add Null Pointer to end of array */
+       return ((char **) argbase);
+}
+
+/*******************************************
+profil (samples, size, offset, scale) Function 56
+char *samples;
+uint16_t offset;
+uint16_t size;
+uint8_t scale;
+********************************************/
+
+#define samples (char *)udata.u_argn
+#define offset         (usize_t)udata.u_argn1
+#define size   (usize_t)udata.u_argn2
+#define scale  (uint16_t)udata.u_argn3
+
+int16_t _profil(void)
+{
+#ifdef CONFIG_PROFIL
+       /* For performance reasons scale as
+          passed to the kernel is a shift value
+          not a divider */
+       ptptr p = udata.u_ptab;
+
+       if (scale == 0) {
+               p->p_profscale = scale;
+               return 0;
+       }
+
+       if (!valaddr(samples, size >> (scale - 1)))
+               return -1;
+
+       p->p_profscale = scale;
+       p->p_profbuf = samples;
+       p->p_profsize = size;
+       p->p_profoff = offset;
+       return 0;
+#else
+       return -1;
+#endif
+}
+
+#undef samples
+#undef offset
+#undef size
+#undef scale
+
+/*******************************************
+uadmin(cmd, func, ptr)           Function 57
+int16_t cmd;
+int16_t func;
+char *ptr;
+********************************************/
+#define cmd (int16_t)udata.u_argn
+#define func (int16_t)udata.u_argn1
+#define ptr  (char *)udata.u_argn2
+
+int16_t _uadmin(void)
+{
+       if (!esuper())
+               return -1;
+       /* Wants moving into machine specific files */
+       if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP) {
+               _sync();
+               trap_monitor();
+       }
+       /* We don't do SWAPCTL yet */
+       udata.u_error = EINVAL;
+       return -1;
+}
+
+
+/*******************************************
+nice (pri)                     Function 58
+int16_t pri;
+********************************************/
+#define pri (int16_t)udata.u_argn
+
+int16_t _nice(void)
+{
+       ptptr p = udata.u_ptab;
+       int16_t np;
+
+       if (pri < 0 && !esuper())
+               return -1;
+       np = p->p_nice + pri;
+       if (np < -20)
+               np = -20;
+       if (np > 19)
+               np = 19;
+
+       p->p_nice = np;
+       p->p_priority = MAXTICKS - (np >> 2);
+       return 20 + np;         /* avoid errno confusion */
+}
+
+#undef pri
diff --git a/Kernel/syscall_proc.c b/Kernel/syscall_proc.c
new file mode 100644 (file)
index 0000000..aaf0f1e
--- /dev/null
@@ -0,0 +1,539 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+
+#undef DEBUG
+
+/*******************************************
+Getpid ()                        Function 18
+============================================
+Return Process ID Number (PID) to Caller.
+********************************************/
+
+int16_t _getpid(void)
+{
+       return (udata.u_ptab->p_pid);
+}
+
+
+/*******************************************
+Getppid ()                       Function 19
+============================================
+Return Parent's Process ID Number (PPID).
+********************************************/
+
+int16_t _getppid(void)
+{
+       return (udata.u_ptab->p_pptr->p_pid);
+}
+
+
+/*******************************************
+Getuid ()                        Function 20
+============================================
+Return User ID Number (UID) to Caller.
+********************************************/
+
+int16_t _getuid(void)
+{
+       return (udata.u_ptab->p_uid);
+}
+
+
+/*******************************************
+Geteuid ()                       Function 44
+============================================
+Return Effective User ID Number (EUID).
+********************************************/
+
+int16_t _geteuid(void)
+{
+       return (udata.u_euid);
+}
+
+
+/*******************************************
+Getgid ()                        Function 41
+============================================
+Return Group ID Number (GID) to Caller.
+********************************************/
+
+int16_t _getgid(void)
+{
+       return (udata.u_gid);
+}
+
+
+/*******************************************
+Getegid ()                       Function 45
+============================================
+Return Effective Group ID Number (EGID).
+********************************************/
+
+int16_t _getegid(void)
+{
+       return (udata.u_egid);
+}
+
+
+
+/*******************************************
+setuid (uid)                     Function 25        ?
+int uid;
+============================================
+Set User ID Number (UID) of Process.  Must
+be SuperUser or owner, else Error (EPERM).
+********************************************/
+#define uid (int)udata.u_argn
+
+int16_t _setuid(void)
+{
+       if (super() || udata.u_ptab->p_uid == uid) {
+               udata.u_ptab->p_uid = uid;
+               udata.u_euid = uid;
+               return (0);
+       }
+       udata.u_error = EPERM;
+       return (-1);
+}
+
+#undef uid
+
+
+
+/*******************************************
+setgid (gid)                     Function 26        ?
+int gid;
+============================================
+Set Group ID Number (GID).  Must be Super-
+User or in Group to Set, else Error (EPERM).
+********************************************/
+#define gid (int16_t)udata.u_argn
+
+int16_t _setgid(void)
+{
+       if (super() || udata.u_gid == gid) {
+               udata.u_gid = gid;
+               udata.u_egid = gid;
+               return (0);
+       }
+       udata.u_error = EPERM;
+       return (-1);
+}
+
+#undef gid
+
+
+
+/*******************************************
+time (tvec)                      Function 27
+time_t *tvec;
+============================================
+Read Clock Time/Date to User Buffer.
+********************************************/
+#define tvec (time_t *)udata.u_argn
+
+int16_t _time(void)
+{
+       time_t t;
+       rdtime(&t);
+       uput(&t, tvec, sizeof(t));
+       return (0);
+}
+
+#undef tvec
+
+
+
+/*******************************************
+stime (tvec)                     Function 28
+time_t *tvec;
+============================================
+Set Clock Time (Currently unimplemented).
+When active, must be SuperUser to Set Time.
+********************************************/
+#define tvec (time_t *)udata.u_argn
+
+int16_t _stime(void)
+{
+       time_t t;
+       if (uget(&t, tvec, sizeof(t)) || esuper())
+               return -1;
+       wrtime(&t);
+       return (-1);
+}
+
+#undef tvec
+
+
+
+/*******************************************
+times (buf)                      Function 42        ?
+char *buf;
+********************************************/
+#define buf (char *)udata.u_argn
+
+int16_t _times(void)
+{
+       irqflags_t irq;
+
+       irq = di();     
+
+       uput(&udata.u_utime, buf, 4 * sizeof(clock_t));
+       uput(&ticks, buf + 4 * sizeof(clock_t),
+            sizeof(clock_t));
+
+       irqrestore(irq);
+       return 0;
+}
+
+#undef buf
+
+
+
+
+/*******************************************
+brk (addr)                       Function 30
+char *addr;
+********************************************/
+#define addr (char *)udata.u_argn
+
+int16_t _brk(void)
+{
+       /* FIXME: when we start building binaries with the stack embedded in them
+          they will need a different test.. */
+       /* Don't allow break to be set past user's stack pointer */
+    /*** St. Nitschke allow min. of 512 bytes for Stack ***/
+       if (addr >= (char *) (udata.u_syscall_sp) - 512) {
+               kprintf("%d: out of memory\n", udata.u_ptab->p_pid);
+               udata.u_error = ENOMEM;
+               return (-1);
+       }
+       udata.u_break = (unsigned) addr;
+       return (0);
+}
+
+#undef addr
+
+
+
+/*******************************************
+sbrk (incr)                      Function 31
+uint16_t incr;
+********************************************/
+#define incr (uint16_t)udata.u_argn
+
+int16_t _sbrk(void)
+{
+       unsigned oldbrk;
+
+       udata.u_argn += (oldbrk = udata.u_break);
+       if ((unsigned) udata.u_argn < oldbrk)
+               return (-1);
+       if (_brk())             /* brk (udata.u_argn) */
+               return (-1);
+
+       return ((unsigned) oldbrk);
+}
+
+#undef incr
+
+/*******************************************
+waitpid(pid, statloc, options)    Function 55
+int16_t pid;
+int *statloc;
+int options;
+********************************************/
+#define pid     udata.u_argn
+#define statloc (int *)udata.u_argn1
+#define options (int)udata.u_argn2
+
+int16_t _waitpid(void)
+{
+       ptptr p;
+       int retval;
+
+       if (statloc && !valaddr((char *) statloc, sizeof(int))) {
+               udata.u_error = EFAULT;
+               return (-1);
+       }
+
+       /* See if we have any children. */
+       for (p = ptab; p < ptab + maxproc; ++p) {
+               if (p->p_status && p->p_pptr == udata.u_ptab
+                   && p != udata.u_ptab)
+                       goto ok;
+       }
+       udata.u_error = ECHILD;
+       return (-1);
+      ok:
+       if (pid == 0)
+               pid = -udata.u_ptab->p_pgrp;
+       /* Search for an exited child; */
+       for (;;) {
+               chksigs();
+               if (udata.u_cursig) {
+                       udata.u_error = EINTR;
+                       return (-1);
+               }
+               for (p = ptab; p < ptab + maxproc; ++p) {
+                       if (p->p_status == P_ZOMBIE
+                           && p->p_pptr == udata.u_ptab) {
+                               if (pid == -1 || p->p_pid == pid
+                                   || p->p_pgrp == -pid) {
+                                       if (statloc)
+                                               uputw(p->p_exitval,
+                                                     statloc);
+
+                                       retval = p->p_pid;
+                                       p->p_status = P_EMPTY;
+
+                                       /* Add in child's time info.  It was stored on top */
+                                       /* of p_priority in the childs process table entry. */
+                                       udata.u_cutime += ((clock_t *)p->p_priority)[0];
+                                       udata.u_cstime += ((clock_t *)p->p_priority)[1];
+                                       return retval;
+                               }
+                       }
+               }
+               /* Nothing yet, so wait */
+               if (options & WNOHANG)
+                       break;
+               psleep(udata.u_ptab);
+       }
+       return 0;
+}
+
+#undef pid
+#undef statloc
+#undef options
+
+/*******************************************
+_exit (val)                       Function 0
+int16_t val;
+********************************************/
+#define val (int16_t)udata.u_argn
+
+int16_t __exit(void)
+{
+       doexit(val, 0);
+       return 0;               // ... yeah. that might not happen.
+}
+
+#undef val
+
+/*******************************************
+fork ()                          Function 32
+********************************************/
+
+int16_t _fork(void)
+{
+       // allocate new process
+       struct p_tab *new_process;
+       int16_t r;
+       irqflags_t irq;
+
+       new_process = ptab_alloc();
+       if (!new_process)
+               return -1;
+
+       irq = di();
+       // we're going to run our child process next, so mark this process as being ready to run
+       udata.u_ptab->p_status = P_READY;
+       // kick off the new process (the bifurcation happens inside here, we returns in both 
+       // the child and parent contexts)
+       r = dofork(new_process);
+#ifdef DEBUG
+       kprintf("Dofork %x (n %x)returns %d\n", udata.u_ptab,
+               new_process, r);
+       kprintf("udata.u_page %d p_page %d\n", udata.u_page,
+               udata.u_ptab->p_page);
+       kprintf("parent %x\n", udata.u_ptab->p_pptr);
+#endif
+       // if we fail this returns -1
+       if (r == -1) {
+               udata.u_ptab->p_status = P_RUNNING;
+               pagemap_free(new_process);
+               new_process->p_status = P_EMPTY;
+               udata.u_error = ENOMEM;
+               nproc--;
+               nready--;
+       }
+       irqrestore(irq);
+
+       return r;
+}
+
+
+
+/*******************************************
+pause (t)                         Function 37
+uint16_t t;
+********************************************/
+
+#define t (int16_t)udata.u_argn
+
+int16_t _pause(void)
+{
+       /* 0 is a traditional "pause", n is a timeout for doing
+          sleep etc without ugly alarm hacks */
+       if (t)
+               udata.u_ptab->p_timeout = t + 1;
+       psleep(0);
+       /* Were we interrupted ? */
+       if (!t || udata.u_ptab->p_timeout) {
+               udata.u_error = EINTR;
+               /* Our timeout is automatically cleared on syscall exit */
+               return (-1);
+       }
+       return 0;
+}
+
+#undef t
+
+
+/*******************************************
+signal (sig, func)               Function 35        ?
+int16_t sig;
+int16_t (*func)();
+********************************************/
+#define sig (int16_t)udata.u_argn
+#define func (int16_t (*)())udata.u_argn1
+
+int16_t _signal(void)
+{
+       int16_t retval;
+       irqflags_t irq;
+
+       if (sig < 1 || sig >= NSIGS) {
+               udata.u_error = EINVAL;
+               goto nogood;
+       }
+
+       irq = di();
+
+       if (func == SIG_IGN) {
+               if (sig != SIGKILL && sig != SIGSTOP)
+                       udata.u_ptab->p_ignored |= sigmask(sig);
+       } else {
+               if (func != SIG_DFL && !valaddr((char *) func, 1)) {
+                       udata.u_error = EFAULT;
+                       goto nogood;
+               }
+               udata.u_ptab->p_ignored &= ~sigmask(sig);
+       }
+       retval = (int) udata.u_sigvec[sig];
+       if (sig != SIGKILL && sig != SIGSTOP)
+               udata.u_sigvec[sig] = func;
+       irqrestore(irq);
+
+       return (retval);
+
+nogood:
+       return (-1);
+}
+
+#undef sig
+#undef func
+
+/*******************************************
+sigdisp(sig, disp)              Function 59
+int16_t sig;
+int16_t disp;
+*******************************************/
+#define sig (int16_t)udata.u_argn
+#define disp (int16_t)udata.u_argn1
+
+/* Implement sighold/sigrelse */
+int16_t _sigdisp(void)
+{
+       if (sig < 1 || sig >= NSIGS || sig == SIGKILL || sig == SIGSTOP) {
+               udata.u_error = EINVAL;
+               return -1;
+       }
+       if (disp == 1)
+               udata.u_ptab->p_held |= sigmask(sig);
+       else
+               udata.u_ptab->p_held &= ~sigmask(sig);
+       return 0;
+}
+
+#undef sig
+#undef disp
+
+/*******************************************
+kill (pid, sig)                  Function 39
+int16_t pid;
+int16_t sig;
+********************************************/
+#define pid (int16_t)udata.u_argn
+#define sig (int16_t)udata.u_argn1
+
+int16_t _kill(void)
+{
+       ptptr p;
+       int f = 0, s = 0;
+
+       if (sig < 0 || sig > 15) {
+               udata.u_error = EINVAL;
+               return (-1);
+       }
+
+       if (pid == 0)
+               udata.u_argn = -udata.u_ptab->p_pgrp;
+
+       for (p = ptab; p < ptab + maxproc; ++p) {
+               /* No overlap here */
+               if (-p->p_pgrp == pid || p->p_pid == pid) {
+                       f = 1;  /* Found */
+                       if (udata.u_ptab->p_uid == p->p_uid || super()) {
+                               if (sig)
+                                       ssig(p, sig);
+                               s = 1;  /* Signalled */
+                               /* Only one match possible for a process */
+                               if (pid > 0)
+                                       return 0;
+                       }
+               }
+       }
+       if (s)
+               return 0;
+       /* Not found */
+       udata.u_error = ESRCH;
+       /* Found but none signalled */
+       if (f)
+               udata.u_error = EPERM;
+       return (-1);
+}
+
+#undef pid
+#undef sig
+
+
+/*******************************************
+_alarm (secs)                    Function 38
+uint16_t secs;
+********************************************/
+#define secs (int16_t)udata.u_argn
+
+int16_t _alarm(void)
+{
+       int16_t retval;
+
+       retval = udata.u_ptab->p_alarm / 10;
+       udata.u_ptab->p_alarm = secs * 10;
+       return (retval);
+}
+
+#undef secs
+
+/*******************************************
+setpgrp (void)                    Function 53
+********************************************/
+
+int16_t _setpgrp(void)
+{
+       udata.u_ptab->p_pgrp = udata.u_ptab->p_pid;
+       return (0);
+}
diff --git a/Kernel/timer.c b/Kernel/timer.c
new file mode 100644 (file)
index 0000000..09acd70
--- /dev/null
@@ -0,0 +1,63 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <timer.h>
+#include <printf.h>
+
+/* the interrupt handler increments this after every timer interrupt */
+uint16_t system_timer;
+
+/* WRS: timer functions */
+timer_t set_timer_duration(uint16_t duration)
+{
+       if (duration & 0x8000) {
+               kprintf("bad timer duration 0x%x\n", duration);
+       }
+       return (system_timer + duration);
+}
+
+bool timer_expired(timer_t timer_val)
+{
+       if ((timer_val - system_timer) > 0x7fff)
+               return true;
+       return false;
+}
+
+/*-----------------------------------------------------------*/
+/* Read date/time to System location from global variable    */
+void rdtime(time_t *tloc)
+{
+        irqflags_t irq = di();
+        *tloc = tod;
+       irqrestore(irq);
+}
+
+/* These need to go away for most uses by 2038 */
+void rdtime32(uint32_t *tloc)
+{
+        irqflags_t irq = di();
+        *tloc = (uint32_t)tod;
+       irqrestore(irq);
+}
+
+void wrtime(time_t *tloc)
+{
+        irqflags_t irq = di();
+        tod = *tloc;
+#ifdef CONFIG_RTC
+       machine_set_clock(tloc);
+#endif
+       irqrestore(irq);
+}
+
+#ifndef CONFIG_RTC
+static uint8_t tod_deci;
+/* Update software emulated clock. Called ten times
+   a second */
+void updatetod(void)
+{
+       if (++tod_deci != 10)
+               return;
+        tod_deci = 0;
+        tod++;
+}
+#endif                         /* NO_RTC */
diff --git a/Kernel/tools/analysemap.c b/Kernel/tools/analysemap.c
new file mode 100644 (file)
index 0000000..56ee419
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned int code_len, code2_len, data_len, bss_len, init_len, gsfinal, common_addr,
+  initial;
+
+int main(int argc, char *argv[])
+{
+  char buf[512];
+  int addr = 0;
+  int naddr;
+  char name[100];
+  char nname[100];
+  int hogs = 0;
+  
+  if (strstr(argv[0], "memhog"))
+    hogs = 1;
+  
+  while(fgets(buf, 511, stdin)) {
+    char *p1 = strtok(buf," \t\n");
+    char *p2 = NULL;
+    int match = 0;
+    
+    match = memcmp(buf, "     000", 8);
+
+    if (p1)
+      p2 = strtok(NULL, " \t\n");
+
+    if (p1 == NULL || p2 == NULL)
+      continue;
+          
+    if (strcmp(p2, "l__CODE") == 0)
+      sscanf(p1, "%x", &code_len);
+    if (strcmp(p2, "l__CODE2") == 0)
+      sscanf(p1, "%x", &code2_len);
+    if (strcmp(p2, "l__DATA") == 0)
+      sscanf(p1, "%x", &data_len);
+    if (strcmp(p2, "l__BSS") == 0)
+      sscanf(p1, "%x", &bss_len);
+    if (strcmp(p2, "l__INITIALIZED") == 0)
+      sscanf(p1, "%x", &init_len);
+    if (strcmp(p2, "s__GSFINAL") == 0)
+      sscanf(p1, "%x", &gsfinal);
+    if (strcmp(p2, "s__INITIALIZER") == 0)
+      sscanf(p1, "%x", &initial);
+    if (strcmp(p2, "s__COMMONMEM") == 0)
+      sscanf(p1, "%x", &common_addr);
+      
+    if (hogs && match == 0) {
+      if (strstr(p2, "_start")) {
+        sscanf(p1, "%x", &naddr);
+        strcpy(nname, p2);
+        if (addr) {
+          name[strlen(name)-6]=0;
+          printf("%d: %s\n", naddr-addr, name);
+        }
+        addr = naddr;
+        strcpy(name, nname);
+      }
+    }
+  }
+  if (!hogs) {
+    if (code2_len == 0)
+      printf("Code:  %d bytes\n", code_len);
+    else {
+      printf("Code1: %d bytes\n", code_len);
+      printf("Code2: %d bytes\n", code2_len);
+      printf("Code:  %d bytes\n", code_len+code2_len);
+    }
+    printf("Data:  %d bytes\n", data_len);
+    printf("BSS:   %d bytes\n", bss_len);
+    printf("Initialized: %d bytes\n", init_len);
+    printf("Free memory begins at: %04x\n", initial);
+    printf("Common is at: %04x\n", common_addr);
+    printf("Space: %d bytes\n", common_addr - initial);
+    printf("Work room: %d bytes\n", common_addr - initial - init_len);
+  }
+  exit(0);
+}
+
+
+
diff --git a/Kernel/tools/binman.c b/Kernel/tools/binman.c
new file mode 100644 (file)
index 0000000..4967c13
--- /dev/null
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static unsigned char buf[65536];
+
+static unsigned int s__CODE, s__CODE2, s__INITIALIZER, s__DATA, s__INITIALIZED,
+                    s__INITIALIZER, s__COMMONMEM, l__INITIALIZED, l__GSFINAL,
+                    l__GSINIT, l__COMMONMEM, s__FONT, l__FONT, s__DISCARD,
+                    l__DISCARD, l__CODE, l__CODE2;
+                      
+
+static void ProcessMap(FILE *fp)
+{
+  char buf[512];
+  int addr = 0;
+  int naddr;
+  char name[100];
+  char nname[100];
+  int hogs = 0;
+  
+  while(fgets(buf, 511, fp)) {
+    char *p1 = strtok(buf," \t\n");
+    char *p2 = NULL;
+    int match = 0;
+    
+    match = memcmp(buf, "     000", 8);
+
+    if (p1)
+      p2 = strtok(NULL, " \t\n");
+
+    if (p1 == NULL || p2 == NULL)
+      continue;
+          
+    if (strcmp(p2, "s__CODE") == 0)
+      sscanf(p1, "%x", &s__CODE);
+    if (strcmp(p2, "s__CODE2") == 0)
+      sscanf(p1, "%x", &s__CODE2);
+    if (strcmp(p2, "l__CODE") == 0)
+      sscanf(p1, "%x", &l__CODE);
+    if (strcmp(p2, "l__CODE2") == 0)
+      sscanf(p1, "%x", &l__CODE2);
+    if (strcmp(p2, "s__DISCARD") == 0)
+      sscanf(p1, "%x", &s__DISCARD);
+    if (strcmp(p2, "l__DISCARD") == 0)
+      sscanf(p1, "%x", &l__DISCARD);
+    if (strcmp(p2, "s__DATA") == 0)
+      sscanf(p1, "%x", &s__DATA);
+    if (strcmp(p2, "s__INITIALIZED") == 0)
+      sscanf(p1, "%x", &s__INITIALIZED);
+    if (strcmp(p2, "s__INITIALIZER") == 0)
+      sscanf(p1, "%x", &s__INITIALIZER);
+    if (strcmp(p2, "s__COMMONMEM") == 0)
+      sscanf(p1, "%x", &s__COMMONMEM);
+    if (strcmp(p2, "s__FONT") == 0)
+      sscanf(p1, "%x", &s__FONT);
+    if (strcmp(p2, "l__INITIALIZED") == 0)
+      sscanf(p1, "%x", &l__INITIALIZED);
+    if (strcmp(p2, "l__GSFINAL") == 0)
+      sscanf(p1, "%x", &l__GSFINAL);
+    if (strcmp(p2, "l__GSINIT") == 0)
+      sscanf(p1, "%x", &l__GSINIT);
+    if (strcmp(p2, "l__COMMONMEM") == 0)
+      sscanf(p1, "%x", &l__COMMONMEM);
+    if (strcmp(p2, "l__FONT") == 0)
+      sscanf(p1, "%x", &l__FONT);
+  }
+}
+
+
+int main(int argc, char *argv[])
+{
+  FILE *map, *bin;
+  int tail = 0;
+  int start;
+  unsigned int end;
+
+  if (argc != 4) {
+    fprintf(stderr, "%s: [binary] [map] [output]\n", argv[0]);
+    exit(1);
+  }
+  bin = fopen(argv[1], "r");
+  if (bin == NULL) {
+    perror(argv[1]);
+    exit(1);
+  }
+  if (fread(buf, 1, 65536, bin) == 0) {
+    fprintf(stderr, "%s: read error on %s\n", argv[0], argv[1]);
+    exit(1);
+  }
+  fclose(bin);
+  map = fopen(argv[2], "r");
+  if (map == NULL) {
+    perror(argv[2]);
+    exit(1);
+  }
+  ProcessMap(map);
+  fclose(map);
+  
+  if (s__COMMONMEM > 0xFFFF || s__COMMONMEM + l__COMMONMEM > 0xFFFF) {
+   fprintf(stderr, "Move common down by at least %d bytes\n", 
+    s__COMMONMEM + l__COMMONMEM - 0xFFFF);
+   exit(1);
+  }
+  
+  start = s__CODE;
+  /* TODO: Support a proper discardable high discard in other mappings */
+  
+  /* Low discard (pure swap model) */
+  if (s__DISCARD && s__DISCARD < s__CODE) {
+   start = s__DISCARD;
+   if (s__DISCARD + l__DISCARD > s__CODE) {
+    fprintf(stderr, "Move discard down by at least %d bytes\n",
+     s__DISCARD + l__DISCARD - s__CODE);
+     exit(1);
+   }
+   printf("Discard at %04x (%d bytes), space %d\n", 
+    s__DISCARD, l__DISCARD, s__CODE - s__DISCARD - l__DISCARD);
+  }   
+  
+  end = s__INITIALIZER;
+  
+  if (s__CODE2 < 0x10000) {
+   /* Move the initialized data into the right spot rather than sdcc's
+      assumption of being ROM code */
+   memcpy(buf + s__INITIALIZED, buf + s__INITIALIZER, l__INITIALIZED);
+   if (l__GSFINAL || l__GSINIT)
+     fprintf(stderr, "Warning %s contains gs code.\n", argv[1]);
+   /* Pack any common memory on the end of the main code/memory if its
+      relocated */
+   if (!s__DISCARD || s__DISCARD > s__CODE) {
+     tail = l__COMMONMEM;
+     memcpy(buf + s__INITIALIZER, buf + s__COMMONMEM, l__COMMONMEM);
+     /* If we have the font packed high then add it to the image */
+     if (l__FONT && s__FONT > s__INITIALIZER) {
+       memmove(buf + s__INITIALIZER + l__COMMONMEM, buf + s__FONT, l__FONT);
+       tail += l__FONT;
+     }
+     end = s__COMMONMEM + l__COMMONMEM + l__FONT;
+   }
+  
+   printf("Code at 0x%04x (%d bytes)\n", s__CODE, l__CODE);
+   printf("Code2 at 0x%04x (%d bytes)\n", s__CODE2, l__CODE2);
+   printf("Data at 0x%04x (%d bytes)\n", s__DATA, s__INITIALIZER - s__DATA);
+   printf("Common at 0x%04x (%d bytes)\n", s__COMMONMEM, l__COMMONMEM);
+   if (l__FONT)
+    printf("Font at 0x%04x (%d bytes)\n", s__FONT, l__FONT);
+   printf("Discard at 0x%04x (%d bytes)\n", s__DISCARD, l__DISCARD);
+   printf("End at 0x%04x\n", end);
+   printf("\nPacked image %d bytes, for RAM target\n",
+    s__INITIALIZER + tail - start);
+  } else {
+   printf("ROM target: leaving\n");
+   exit(0);
+  }
+  bin = fopen(argv[3], "w");
+  if (bin == NULL) {
+    perror(argv[3]);
+    exit(1);
+  }
+  if (fwrite(buf+start, s__INITIALIZER + tail - start, 1, bin) != 1) {
+   perror(argv[3]);
+   exit(1);
+  }
+  fclose(bin);
+  exit(0);
+}
\ No newline at end of file
diff --git a/Kernel/tools/filesizes.c b/Kernel/tools/filesizes.c
new file mode 100644 (file)
index 0000000..2f27fd9
--- /dev/null
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned int code_len, code2_len, data_len, bss_len, init_len, gsfinal, common_addr,
+  initial;
+
+int main(int argc, char *argv[])
+{
+  char buf[512];
+  char fname[100];
+  unsigned int addr, naddr;  
+  *fname = 0;
+  
+  while(fgets(buf, 511, stdin)) {
+    char *p1 = strtok(buf," \t\n");
+    char *p2;
+    char *p3;
+    int match = 0;
+    
+    match = memcmp(buf, "     000", 8);
+
+    if (p1)
+      p2 = strtok(NULL, " \t\n");
+    if (p2)
+      p3 = strtok(NULL, " \t\n");
+
+    if (match || p1 == NULL || p2 == NULL || p3 == NULL)
+      continue;
+    
+    if (strcmp(p3, fname)) {
+      if (sscanf(p1, "%x", &naddr) == 0)
+        fprintf(stderr, "Bad address '%s'\n", p1);
+      if (*fname)
+        printf("%-24s: %d\n", fname, naddr-addr);
+      addr = naddr;
+      strcpy(fname, p3);
+    }
+  }
+  exit(0);
+}
+
+
+
diff --git a/Kernel/tools/make4x6.c b/Kernel/tools/make4x6.c
new file mode 100644 (file)
index 0000000..1824503
--- /dev/null
@@ -0,0 +1,2170 @@
+#include <stdio.h>
+
+/*
+ *     It's easier to edit the fonts in this format. Tool generates a compacted
+ *     font set
+ */
+
+/* Hand composed "Minuscule" 4x6 font, with binary data generated using
+ * Perl stub.
+ *
+ * Use 'perl -x mini_4x6.c < mini_4x6.c > new_version.c' to regenerate
+ * binary data.
+ *
+ * Created by Kenneth Albanowski.
+ * No rights reserved, released to the public domain.
+ *
+ * Version 1.0
+ */
+
+/*
+
+#!/usr/bin/perl -pn
+
+s{((0x)?[0-9a-fA-F]+)(.*\[([\*\ ]{4})\])}{
+
+       ($num,$pat,$bits) = ($1,$3,$4);
+       
+       $bits =~ s/([^\s0])|(.)/ defined($1) + 0 /ge;
+       
+       $num = ord(pack("B8", $bits));
+       $num |= $num >> 4;
+       $num = sprintf("0x%.2x", $num);
+       
+       #print "$num,$pat,$bits\n";
+       
+       $num . $pat;
+}ge;
+
+__END__;
+*/
+
+/* Note: binary data consists of one byte for each row of each character top
+   to bottom, character 0 to character 255, six bytes per character. Each
+   byte contains the same four character bits in both nybbles.
+   MSBit to LSBit = left to right.
+ */
+
+#define FONTDATAMAX 1536
+
+static const unsigned char data[FONTDATAMAX] = {
+
+       /*{*/
+               /*   Char 0: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 1: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 2: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 3: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 4: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 5: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 6: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 7: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 8: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 9: ' '  */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 10: '' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 11: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 12: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 13: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 14: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 15: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 16: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 17: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 18: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 19: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 20: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 21: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 22: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 23: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 24: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 25: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 26: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 27: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 28: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 29: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 30: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 31: ' ' */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 32: ' ' */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 33: '!' */
+       0x44,   /*=  [ *  ]       */
+       0x44,   /*=  [ *  ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 34: '"' */
+       0xaa,   /*=  [* * ]       */
+       0xaa,   /*=  [* * ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 35: '#' */
+       0xaa,   /*=  [* * ]       */
+       0xff,   /*=  [****]       */
+       0xff,   /*=  [****]       */
+       0xaa,   /*=  [* * ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 36: '$' */
+       0x44,   /*=  [ *  ]       */
+       0x66,   /*=  [ ** ]       */
+       0xee,   /*=  [*** ]       */
+       0xcc,   /*=  [**  ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 37: '%' */
+       0xaa,   /*=  [* * ]       */
+       0x22,   /*=  [  * ]       */
+       0x44,   /*=  [ *  ]       */
+       0x88,   /*=  [*   ]       */
+       0xaa,   /*=  [* * ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 38: '&' */
+       0x66,   /*=  [ ** ]       */
+       0x99,   /*=  [*  *]       */
+       0x66,   /*=  [ ** ]       */
+       0xaa,   /*=  [* * ]       */
+       0xdd,   /*=  [** *]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 39: ''' */
+       0x22,   /*=  [  * ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 40: '(' */
+       0x22,   /*=  [  * ]       */
+       0x44,   /*=  [ *  ]       */
+       0x44,   /*=  [ *  ]       */
+       0x44,   /*=  [ *  ]       */
+       0x22,   /*=  [  * ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 41: ')' */
+       0x44,   /*=  [ *  ]       */
+       0x22,   /*=  [  * ]       */
+       0x22,   /*=  [  * ]       */
+       0x22,   /*=  [  * ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 42: '*' */
+       0x00,   /*=  [    ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 43: '+' */
+       0x00,   /*=  [    ]       */
+       0x44,   /*=  [ *  ]       */
+       0xee,   /*=  [*** ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 44: ',' */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x44,   /*=  [ *  ]       */
+       0x88,   /*=  [*   ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 45: '-' */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0xee,   /*=  [*** ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 46: '.' */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       0x44,   /*=  [ *  ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 47: '/' */
+       0x00,   /*=  [    ]       */
+       0x22,   /*=  [  * ]       */
+       0x44,   /*=  [ *  ]       */
+       0x88,   /*=  [*   ]       */
+       0x00,   /*=  [    ]       */
+       0x00,   /*=  [    ]       */
+       /*}*/
+       /*{*/
+               /*   Char 48: '0'   */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/
+               /*   Char 49: '1'   */
+       0x44,   /*=   [ *  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/
+               /*   Char 50: '2'   */
+       0xcc,   /*=   [**  ]        */
+       0x22,   /*=   [  * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/
+               /*   Char 51: '3'   */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x22,   /*=   [  * ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 52: '4'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 53: '5'   */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 54: '6'   */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 55: '7'   */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 56: '8'   */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 57: '9'   */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 58: ':'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 59: ';'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       /*}*/
+       /*{*/   /*   Char 60: '<'   */
+       0x22,   /*=   [  * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x22,   /*=   [  * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 61: '='   */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 62: '>'   */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x22,   /*=   [  * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 63: '?'   */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 64: '@'   */
+       0x44,   /*=   [ *  ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 65: 'A'   */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 66: 'B'   */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 67: 'C'   */
+       0x66,   /*=   [ ** ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 68: 'D'   */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 69: 'E'   */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 70: 'F'   */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 71: 'G'   */
+       0x66,   /*=   [ ** ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 72: 'H'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 73: 'I'   */
+       0xee,   /*=   [*** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 74: 'J'   */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 75: 'K'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 76: 'L'   */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 77: 'M'   */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 78: 'N'   */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 79: 'O'   */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 80: 'P'   */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 81: 'Q'   */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 82: 'R'   */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 83: 'S'   */
+       0x66,   /*=   [ ** ]        */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x22,   /*=   [  * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 84: 'T'   */
+       0xee,   /*=   [*** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 85: 'U'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 86: 'V'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 87: 'W'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 88: 'X'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 89: 'Y'   */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 90: 'Z'   */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 91: '['   */
+       0x66,   /*=   [ ** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 92: '\'   */
+       0x00,   /*=   [    ]        */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x22,   /*=   [  * ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 93: ']'   */
+       0x66,   /*=   [ ** ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 94: '^'   */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 95: '_'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       /*}*/
+       /*{*/   /*   Char 96: '`'   */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 97: 'a'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 98: 'b'   */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 99: 'c'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0x88,   /*=   [*   ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 100: 'd'   */
+       0x22,   /*=   [  * ]        */
+       0x22,   /*=   [  * ]        */
+       0x66,   /*=   [ ** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 101: 'e'   */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x88,   /*=   [*   ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 102: 'f'   */
+       0x22,   /*=   [  * ]        */
+       0x44,   /*=   [ *  ]        */
+       0xee,   /*=   [*** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 103: 'g'   */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x66,   /*=   [ ** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 104: 'h'   */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 105: 'i'   */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 106: 'j'   */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 107: 'k'   */
+       0x00,   /*=   [    ]        */
+       0x88,   /*=   [*   ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 108: 'l'   */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 109: 'm'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 110: 'n'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 111: 'o'   */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 112: 'p'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x88,   /*=   [*   ]        */
+       /*}*/
+       /*{*/   /*   Char 113: 'q'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0xaa,   /*=   [* * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x22,   /*=   [  * ]        */
+       /*}*/
+       /*{*/   /*   Char 114: 'r'   */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0xaa,   /*=   [* * ]        */
+       0x88,   /*=   [*   ]        */
+       0x88,   /*=   [*   ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 115: 's'   */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0xcc,   /*=   [**  ]        */
+       0x22,   /*=   [  * ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 116: 't'   */
+       0x00,   /*=   [    ]        */
+       0x44,   /*=   [ *  ]        */
+       0xee,   /*=   [*** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 117: 'u'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 118: 'v'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 119: 'w'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 120: 'x'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xaa,   /*=   [* * ]        */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 121: 'y'   */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x22,   /*=   [  * ]        */
+       0xcc,   /*=   [**  ]        */
+       /*}*/
+       /*{*/   /*   Char 122: 'z' */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xcc,   /*=   [**  ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 123: '{' */
+       0x22,   /*=   [  * ]        */
+       0x44,   /*=   [ *  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x22,   /*=   [  * ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 124: '|' */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 125: '}' */
+       0x88,   /*=   [*   ]        */
+       0x44,   /*=   [ *  ]        */
+       0x66,   /*=   [ ** ]        */
+       0x44,   /*=   [ *  ]        */
+       0x88,   /*=   [*   ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 126: '~' */
+       0x55,   /*=   [ * *]        */
+       0xaa,   /*=   [* * ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 127: '\7f' */
+       0x44,   /*=   [ *  ]        */
+       0xaa,   /*=   [* * ]        */
+       0xaa,   /*=   [* * ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 128:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 129:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 130:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 131:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 132:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 133:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 134:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 135:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 136:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 137:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 138:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 139:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 140:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 141:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 142:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 143:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 144:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 145:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 146:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 147:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 148:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 149:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 150:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 151:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 152:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 153:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 154:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 155:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 156:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 157:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 158:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 159:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 160:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 161:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 162:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 163:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 164:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 165:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 166:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 167:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 168:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 169:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 170:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 171:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 172:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 173:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 174:  */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0xcc,   /*=   [**  ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 175:  */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0x66,   /*=   [ ** ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 176:  */
+       0x88,   /*=   [*   ]        */
+       0x22,   /*=   [  * ]        */
+       0x88,   /*=   [*   ]        */
+       0x22,   /*=   [  * ]        */
+       0x88,   /*=   [*   ]        */
+       0x22,   /*=   [  * ]        */
+       /*}*/
+       /*{*/   /*   Char 177:  */
+       0xaa,   /*=   [* * ]        */
+       0x55,   /*=   [ * *]        */
+       0xaa,   /*=   [* * ]        */
+       0x55,   /*=   [ * *]        */
+       0xaa,   /*=   [* * ]        */
+       0x55,   /*=   [ * *]        */
+       /*}*/
+       /*{*/   /*   Char 178:  */
+       0xdd,   /*=   [** *]        */
+       0xbb,   /*=   [* **]        */
+       0xdd,   /*=   [** *]        */
+       0xbb,   /*=   [* **]        */
+       0xdd,   /*=   [** *]        */
+       0xbb,   /*=   [* **]        */
+       /*}*/
+       /*{*/   /*   Char 179:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 180:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 181:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 182:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xee,   /*=   [*** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 183:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 184:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 185:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 186:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 187:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 188:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 189:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 190:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 191:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xcc,   /*=   [**  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 192:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x77,   /*=   [ ***]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 193:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 194:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 195:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x77,   /*=   [ ***]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 196:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 197:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xff,   /*=   [****]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 198:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x77,   /*=   [ ***]        */
+       0x77,   /*=   [ ***]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 199:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x77,   /*=   [ ***]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 200:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x77,   /*=   [ ***]        */
+       0x77,   /*=   [ ***]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 201:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x77,   /*=   [ ***]        */
+       0x77,   /*=   [ ***]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 202:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 203:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 204:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x77,   /*=   [ ***]        */
+       0x77,   /*=   [ ***]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 205:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 206:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 207:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 208:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 209:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 210:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 211:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x77,   /*=   [ ***]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 212:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x77,   /*=   [ ***]        */
+       0x77,   /*=   [ ***]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 213:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x77,   /*=   [ ***]        */
+       0x77,   /*=   [ ***]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 214:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x77,   /*=   [ ***]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 215:  */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0xff,   /*=   [****]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       /*}*/
+       /*{*/   /*   Char 216:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 217:  */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0xcc,   /*=   [**  ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 218:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x77,   /*=   [ ***]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       0x44,   /*=   [ *  ]        */
+       /*}*/
+       /*{*/   /*   Char 219:  */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       /*}*/
+       /*{*/   /*   Char 220:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       /*}*/
+       /*{*/   /*   Char 221:  */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       0xcc,   /*=   [**  ]        */
+       /*}*/
+       /*{*/   /*   Char 222:  */
+       0x33,   /*=   [  **]        */
+       0x33,   /*=   [  **]        */
+       0x33,   /*=   [  **]        */
+       0x33,   /*=   [  **]        */
+       0x33,   /*=   [  **]        */
+       0x33,   /*=   [  **]        */
+       /*}*/
+       /*{*/   /*   Char 223:  */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0xff,   /*=   [****]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 224:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 225:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 226:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 227:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 228:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 229:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 230:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 231:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 232:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 233:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 234:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 235:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 236:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 237:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 238:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 239:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 240:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 241:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 242:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 243:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 244:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 245:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 246:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 247:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 248:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 249:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 250:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 251:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 252:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 253:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 254:  */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       0x66,   /*=   [ ** ]        */
+       0x66,   /*=   [ ** ]        */
+       0x00,   /*=   [    ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+       /*{*/   /*   Char 255:  */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0xee,   /*=   [*** ]        */
+       0x00,   /*=   [    ]        */
+       /*}*/
+};
+
+int main(int argc, char *argv[]) 
+{
+       int i;
+       printf("#include <config.h>\n\n");
+       printf("#ifdef CONFIG_FONT_4X6\n\n");
+       printf("const unsigned char font4x6[] = {\n");
+       for (i = 0; i < 1536/2; i++) {
+               if ((i % 6) == 0)
+                       printf("\t");
+               printf("0x%02x, ", (data[i] & 0xF0) | (data[i+1536/2] & 0x0F));
+               if ((i % 6) == 5)
+                       printf("\n");
+       }
+       printf("};\n\n#endif\n");
+       printf("struct sdcc_is_anal {\n\tint cant_have_an_empty_file;\n};\n");
+       return 0;
+}
diff --git a/Kernel/tty.c b/Kernel/tty.c
new file mode 100644 (file)
index 0000000..2d69cd8
--- /dev/null
@@ -0,0 +1,523 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+
+#undef  DEBUG                  /* UNdefine to delete debug code sequences */
+
+/*
+ *     Minimal Terminal Interface
+ *
+ *     TODO:
+ *     - VTIME timeout support
+ *     - Blocking open
+ *     - Hangup
+ *     - Invoke device side helpers
+ *     - Parity
+ *     - Various misc minor flags
+ *     - Better /dev/tty handling
+ *     - BSD ^Z handling and tty sessions eventually
+ *     - Flow control
+ *
+ *     Add a small echo buffer to each tty
+ */
+
+struct termios ttydata[NUM_DEV_TTY + 1];       /* ttydata[0] is not used */
+uint16_t tty_pgrp[NUM_DEV_TTY + 1];
+
+static struct termios ttydflt = {
+       BRKINT | ICRNL,
+       OPOST | ONLCR,
+       CS8 | B9600 | CREAD | HUPCL,
+       ISIG | ICANON | ECHO | ECHOE | ECHOK | IEXTEN,
+       {CTRL('D'), 0, 127, CTRL('C'),
+        CTRL('U'), CTRL('\\'), CTRL('Q'), CTRL('S'),
+        CTRL('Z'), CTRL('Y'), CTRL('V'), CTRL('O')
+        }
+};
+
+static bool stopflag[NUM_DEV_TTY + 1]; // Flag for ^S/^Q
+static bool flshflag[NUM_DEV_TTY + 1]; // Flag for ^O
+static bool deadflag[NUM_DEV_TTY + 1];  // True if hung up
+
+int tty_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       uint16_t nread;
+       unsigned char c;
+       struct s_queue *q;
+       struct termios *t;
+
+       rawflag;
+       flag;                   // shut up compiler
+
+       /* Minor == 0 means that it is the controlling tty of the process */
+       if (!minor)
+               minor = udata.u_ptab->p_tty;
+       if (!udata.u_ptab->p_tty)
+               udata.u_ptab->p_tty = minor;
+
+       q = &ttyinq[minor];
+       t = &ttydata[minor];
+       nread = 0;
+       while (nread < udata.u_count) {
+               for (;;) {
+                       if (deadflag[minor]) {
+                               udata.u_error = ENXIO;
+                               return -1;
+                        }
+                       if (remq(q, &c)) {
+                               if (udata.u_sysio)
+                                       *udata.u_base = c;
+                               else
+                                       uputc(c, udata.u_base);
+                               break;
+                       }
+                       if (psleep_flags(q, flag))
+                               return -1;
+               }
+
+               ++nread;
+
+               /* return according to mode */
+               if (!(t->c_lflag & ICANON)) {
+                       if (nread >= t->c_cc[VMIN])
+                               break;
+               } else {
+                       if (nread == 1 && (c == t->c_cc[VEOF])) {
+                               /* ^D */
+                               nread = 0;
+                               break;
+                       }
+                       if (c == '\n')
+                               break;
+               }
+
+               ++udata.u_base;
+       }
+       wakeup(&q->q_count);
+       return nread;
+}
+
+
+int tty_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       struct termios *t;
+       int towrite;
+       uint8_t c;
+
+       rawflag;
+       flag;                   // shut up compiler
+
+       /* Minor == 0 means that it is the controlling tty of the process */
+       if (!minor)
+               minor = udata.u_ptab->p_tty;
+       if (!udata.u_ptab->p_tty)
+               udata.u_ptab->p_tty = minor;
+
+       t = &ttydata[minor];
+
+       towrite = udata.u_count;
+
+       while (udata.u_count-- != 0) {
+               for (;;) {      /* Wait on the ^S/^Q flag */
+                       if (deadflag[minor]) {
+                               udata.u_error = ENXIO;
+                               return -1;
+                        }
+                       if (!stopflag[minor])
+                               break;
+                       if (psleep_flags(&stopflag[minor], flag))
+                               return -1;
+               }
+
+               if (!flshflag[minor]) {
+                       if (udata.u_sysio)
+                               c = *udata.u_base;
+                       else
+                               c = ugetc(udata.u_base);
+
+                       if (t->c_oflag & OPOST) {
+                               if (c == '\n' && (t->c_oflag & ONLCR))
+                                       tty_putc_wait(minor, '\r');
+                               if (c == '\r' && (t->c_oflag & OCRNL))
+                                       c = '\n';
+                       }
+                       tty_putc_wait(minor, c);
+               }
+               ++udata.u_base;
+       }
+       return towrite;
+}
+
+int tty_open(uint8_t minor, uint16_t flag)
+{
+       struct termios *t;
+
+       /* FIXME : open/carrier logic is needed here, definitely before we
+          enable ptys */
+       /* Minor == 0 means that it is the controlling tty of the process */
+       /* FIXME: need to propogate this minor change back into the file handle
+          and inode somehow ??? */
+       if (!minor)
+               minor = udata.u_ptab->p_tty;
+       if (minor < 1 || minor > NUM_DEV_TTY + 1) {
+               udata.u_error = ENODEV;
+               return (-1);
+       }
+       /* Hung up but not yet cleared of users */
+       if (deadflag[minor]) {
+               udata.u_error = ENXIO;
+               return -1;
+        }
+
+       t = &ttydata[minor];
+
+       /* If there is no controlling tty for the process, establish it */
+       if (!udata.u_ptab->p_tty && !(flag & O_NOCTTY)) {
+               udata.u_ptab->p_tty = minor;
+               tty_pgrp[minor] = udata.u_ptab->p_pgrp;
+       }
+       tty_setup(minor);
+       if ((t->c_cflag & CLOCAL) || (flag & O_NDELAY))
+               return 0;
+
+        if (!tty_carrier(minor)) {
+                if (psleep_flags(&t->c_cflag, flag))
+                        return -1;
+        }
+        /* Carrier spiked ? */
+        if (deadflag[minor]) {
+                udata.u_error = ENXIO;
+                deadflag[minor] = 0;
+                return -1;
+        }
+        return 0;
+}
+
+int tty_close(uint8_t minor)
+{
+       /* If we are closing the controlling tty, make note */
+       if (minor == udata.u_ptab->p_tty)
+               udata.u_ptab->p_tty = 0;
+        /* If we were hung up then the last opener has gone away */
+        deadflag[minor] = 0;
+       return (0);
+}
+
+int tty_ioctl(uint8_t minor, uint16_t request, char *data)
+{                              /* Data in User Space */
+       if (!minor)
+               minor = udata.u_ptab->p_tty;
+       if (minor < 1 || minor > NUM_DEV_TTY + 1) {
+               udata.u_error = ENODEV;
+               return -1;
+       }
+       if (deadflag[minor]) {
+               udata.u_error = ENXIO;
+               return -1;
+        }
+       switch (request) {
+       case TCGETS:
+               uput(&ttydata[minor], data, sizeof(struct termios));
+               break;
+       case TCSETSW:
+               /* We don't have an output queue really so for now drop
+                  through */
+       case TCSETS:
+       case TCSETSF:
+               uget(data, &ttydata[minor], sizeof(struct termios));
+               if (request == TCSETSF)
+                       clrq(&ttyinq[minor]);
+                tty_setup(minor);
+               break;
+       case TIOCINQ:
+               uput(&ttyinq[minor].q_count, data, 2);
+               break;
+       case TIOCFLUSH:
+               clrq(&ttyinq[minor]);
+               break;
+        case TIOCHANGUP:
+                tty_hangup(minor);
+                return 0;
+       default:
+               udata.u_error = ENOTTY;
+               return (-1);
+       }
+       return (0);
+}
+
+
+/* This routine processes a character in response to an interrupt.  It
+ * adds the character to the tty input queue, echoing and processing
+ * backspace and carriage return.  If the queue contains a full line,
+ * it wakes up anything waiting on it.  If it is totally full, it beeps
+ * at the user.
+ * UZI180 - This routine is called from the raw Hardware read routine,
+ * either interrupt or polled, to process the input character.  HFB
+ */
+
+int tty_inproc(uint8_t minor, unsigned char c)
+{
+       unsigned char oc;
+       struct termios *td;
+       struct s_queue *q = &ttyinq[minor];
+       int canon;
+       uint16_t pgrp = tty_pgrp[minor];
+       uint8_t wr;
+
+       td = &ttydata[minor];
+       canon = td->c_lflag & ICANON;
+
+       if (td->c_iflag & ISTRIP)
+               c &= 0x7f;      /* Strip off parity */
+       if (canon && !c)
+               return 1;       /* Simply quit if Null character */
+
+#ifdef CONFIG_IDUMP
+       if (c == 0x1a)          /* ^Z */
+               idump();        /*   (For debugging) */
+#endif
+#ifdef CONFIG_MONITOR
+       if (c == 0x01)          /* ^A */
+               trap_monitor();
+#endif
+
+       if (c == '\r' && (td->c_iflag & ICRNL))
+               c = '\n';
+       if (c == '\n' && (td->c_iflag & INLCR))
+               c = '\r';
+
+       if (td->c_lflag & ISIG) {
+               if (c == td->c_cc[VINTR]) {     /* ^C */
+                       sgrpsig(pgrp, SIGINT);
+                       clrq(q);
+                       stopflag[minor] = flshflag[minor] = false;
+                       return 1;
+               } else if (c == td->c_cc[VQUIT]) {      /* ^\ */
+                       sgrpsig(pgrp, SIGQUIT);
+                       clrq(q);
+                       stopflag[minor] = flshflag[minor] = false;
+                       return 1;
+               }
+       }
+       if (c == td->c_cc[VDISCARD]) {  /* ^O */
+               flshflag[minor] = !flshflag[minor];
+               return 1;
+       }
+       if (td->c_iflag & IXON) {
+               if (c == td->c_cc[VSTOP]) {     /* ^S */
+                       stopflag[minor] = true;
+                       return 1;
+               }
+               if (c == td->c_cc[VSTART]) {    /* ^Q */
+                       stopflag[minor] = false;
+                       wakeup(&stopflag[minor]);
+                       return 1;
+               }
+       }
+       if (canon) {
+               if (c == td->c_cc[VERASE]) {
+                       if (uninsq(q, &oc)) {
+                               if (oc == '\n' || oc == td->c_cc[VEOL])
+                                       insq(q, oc);    /* Don't erase past nl */
+                               else if (td->c_lflag & ECHOE)
+                                       tty_erase(minor);
+                               return 1;
+                       } else if (c == td->c_cc[VKILL]) {
+                               while (uninsq(q, &oc)) {
+                                       if (oc == '\n'
+                                           || oc == td->c_cc[VEOL]) {
+                                               insq(q, oc);    /* Don't erase past nl */
+                                               break;
+                                       }
+                                       if (td->c_lflag & ECHOK)
+                                               tty_erase(minor);
+                               }
+                               return 1;
+                       }
+               }
+       }
+
+       /* All modes come here */
+       if (c == '\n') {
+               if ((td->c_oflag & OPOST | ONLCR) == OPOST | ONLCR)
+                       tty_echo(minor, '\r');
+       }
+
+       wr = insq(q, c);
+       if (wr)
+               tty_echo(minor, c);
+       else if (minor < PTY_OFFSET)
+               tty_putc_wait(minor, '\007');   /* Beep if no more room */
+
+       if (!canon || c == td->c_cc[VEOL] || c == '\n'
+           || c == td->c_cc[VEOF])
+               wakeup(q);
+       return wr;
+}
+
+/* called when a UART transmitter is ready for the next character */
+void tty_outproc(uint8_t minor)
+{
+       wakeup(&ttydata[minor]);
+}
+
+void tty_echo(uint8_t minor, unsigned char c)
+{
+       if (ttydata[minor].c_lflag & ECHO)
+               tty_putc_wait(minor, c);
+}
+
+void tty_erase(uint8_t minor)
+{
+       tty_putc_wait(minor, '\b');
+       tty_putc_wait(minor, ' ');
+       tty_putc_wait(minor, '\b');
+}
+
+
+void tty_putc_wait(uint8_t minor, unsigned char c)
+{
+#ifdef CONFIG_DEV_PTY
+       if (minor >= PTY_OFFSET)
+               ptty_putc_wait(minor, c);
+       else
+#endif
+       if (!udata.u_ininterrupt) {
+               while (!tty_writeready(minor))
+                       psleep(&ttydata[minor]);
+       }
+       tty_putc(minor, c);
+}
+
+void tty_hangup(uint8_t minor)
+{
+        /* Kill users */
+        sgrpsig(tty_pgrp[minor], SIGHUP);
+        /* Stop any new I/O with errors */
+        deadflag[minor] = 1;
+        /* Wake up read/write */
+        wakeup(&ttyinq[minor]);
+        wakeup(&stopflag[minor]);
+        /* and deadflag will clear when the last user goes away */
+}
+
+void tty_carrier_drop(uint8_t minor)
+{
+        if (ttydata[minor].c_cflag & HUPCL)
+                tty_hangup(minor);
+}
+
+void tty_carrier_raise(uint8_t minor)
+{
+        if (ttydata[minor].c_cflag & HUPCL)
+                wakeup(&ttydata[minor].c_cflag);
+}
+
+void tty_init(void) {
+        struct termios *t = &ttydata[1];
+        int i;
+        for(i = 1; i <= NUM_DEV_TTY; i++) {
+               memcpy(t, &ttydflt, sizeof(struct termios));
+               t++;
+        }
+}
+
+/*
+ *     PTY logic
+ */
+
+#ifdef CONFIG_DEV_PTY
+int ptty_open(uint8_t minor, uint16_t flag)
+{
+       return tty_open(minor + PTY_OFFSET, flag);
+}
+
+int ptty_close(uint8_t minor)
+{
+       return tty_close(minor + PTY_OFFSET);
+}
+
+int ptty_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       return tty_write(minor + PTY_OFFSET, rawflag, flag);
+}
+
+int ptty_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       return tty_read(minor + PTY_OFFSET, rawflag, flag);
+}
+
+int ptty_ioctl(uint8_t minor, uint16_t request, char *data)
+{
+       return tty_ioctl(minor + PTY_OFFSET, rawflag, flag);
+}
+
+int pty_open(uint8_t minor, uint16_t flag)
+{
+       return tty_open(minor + PTY_OFFSET, flag);
+}
+
+int pty_close(uint8_t minor)
+{
+       return tty_close(minor + PTY_OFFSET);
+}
+
+int pty_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       uint16_t nwritten;
+       minor += PTY_OFFSET;
+
+       while (nwritten < udata.u_count) {
+               if (udata.u_sysio)
+                       c = udata.u_base;
+               else
+                       c = ugetc(udata.u_base);
+               if (tty_inproc(minor, c)) {
+                       nwritten++;
+                       udata.u_count++;
+                       continue;
+               }
+               if (nwritten == 0
+                   && psleep_flags(&ttyinq[minor].q_count, flag))
+                       return -1;
+       }
+
+       return nwritten;
+}
+
+int pty_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       struct s_queue q = &ttyinq[minor + PTY_OFFSET + PTY_PAIR];
+       char c;
+
+       while (nread < udata.u_count) {
+               if (remq(q, &c)) {
+                       if (udata.u_sysio)
+                               *udata.u_base = c;
+                       else
+                               uputc(c, udata.u_base);
+                       udata.u_base++;
+                       nread++;
+                       continue;
+               }
+               if (nread == 0 && psleep_flags(q, flag))
+                       return -1;
+       }
+       return nread;
+}
+
+int pty_ioctl(uint8_t minor, uint16_t request, char *data)
+{
+       return tty_ioctl(minor + PTY_OFFSET, rawflag, flag);
+}
+
+void pty_putc_wait(uint8_t minor, char c)
+{
+       struct s_queue q = &ptyq[minor + PTY_OFFSET + PTY_PAIR];
+       /* tty output queue to pty */
+       insq(q, c);
+       wakeup(q);
+}
+#endif
diff --git a/Kernel/unbanked.c b/Kernel/unbanked.c
new file mode 100644 (file)
index 0000000..bffa61f
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ *     Derived from:
+ *     Memory allocator for ELKS. We keep a hole list so we can keep the
+ *     malloc arena data in the kernel not scattered into hard to read 
+ *     user memory.
+ *
+ *     Provide memory management for linear address spaces, either systems
+ *     with base/limit type functionality (eg Z180) or just plain large address
+ *     spaces with no useful bases at all (eg 68000)
+ *
+ *     On Z180 we use linear but we still have banking. On 68K binaries just have
+ *     to be relocated and you can't swap.
+ *
+ *     For Z180 set this up with the memory range present. At the moment we only
+ *     support one linear block but the hole manager can manage multiple non linear
+ *     chunks if need be.
+ *
+ *     We run with common 0 at physical 0x0 holding the vectors (why copy them!)
+ *     The bank area then runs from 0x0100 -> PAGE_TOP. The common 1 area is 
+ *     mapped to the uarea/common of this process. This costs us memory for the
+ *     common code copies but saves us doing the uarea copying dance that
+ *     UZI180 does
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+#ifdef CONFIG_BANK_LINEAR
+
+/*
+ *     Worst case is twice as many as allocations plus 1 I think ?
+ */
+
+#define MAX_SEGMENTS           ((PTABSIZE*2) + 1)
+
+struct hole {
+       uint16_t base;          /* Pages */
+       uint16_t extent;        /* Pages */
+       struct hole *next;      /* Next in list memory order */
+       __u8 flags;             /* So we know if it is free */
+#define HOLE_USED              1
+#define HOLE_FREE              2
+#define HOLE_SPARE             3
+#define HOLE_SWAPPED           8
+};
+
+static struct hole holes[MAX_SEGMENTS];
+
+struct malloc_head {
+       struct hole *holes;
+       int size;
+};
+
+struct malloc_head memmap = { holes, MAX_SEGMENTS };
+
+/*
+ *     Find a spare hole.
+ */
+
+static struct hole *alloc_hole(struct malloc_head *mh)
+{
+       struct hole *m = holes;
+       int ct = MAX_SEGMENTS;
+
+       while (ct--) {
+               if (m->flags == HOLE_SPARE)
+                       return m;
+               m++;
+       }
+       return NULL;
+}
+
+/*
+ *     Split a hole into two
+ */
+
+static int split_hole(struct malloc_head *mh, struct hole *m, uint16_t len)
+{
+       struct hole *n;
+       uint16_t spare = m->extent - len;
+
+       if (!spare)
+               return 0
+                   /*
+                    *      Split into one allocated one free
+                    */
+                   n = alloc_hole();
+       if (n == NULL)
+               return ENOMEM;
+       m->extent = len;
+       n->base = m->base + len;
+       n->extent = spare;
+       n->next = m->next;
+       m->next = n;
+       n->flags = HOLE_FREE;
+       return 0;
+}
+
+/*
+ *     Merge adjacent free holes
+ */
+
+static void sweep_holes(struct malloc_head *mh)
+{
+       struct hole *m = mh->holes;
+
+       while (m != NULL && m->next != NULL) {
+               if (m->flags == HOLE_FREE && m->next->flags == HOLE_FREE &&
+                   m->base + m->extent == m->next->base) {
+                       m->extent += m->next->extent;
+                       m->next->flags = HOLE_SPARE;
+                       m->next = m->next->next;
+               } else
+                       m = m->next;
+       }
+}
+
+#if 0
+
+void dmem(struct malloc_head *mh)
+{
+       struct hole *m;
+       char *status;
+       if (mh)
+               m = mh->holes;
+       else
+               m = memmap.holes;
+       do {
+               switch (m->flags) {
+               case HOLE_SPARE:
+                       status = "SPARE";
+                       break;
+               case HOLE_FREE:
+                       status = "FREE";
+                       break;
+               case HOLE_USED:
+                       status = "USED";
+                       break;
+               default:
+                       status = "DODGY";
+                       break;
+               }
+               printk("HOLE %x size %x next start %x is %s\n", m->base,
+                      m->extent, m->base + m->extent, status);
+               m = m->next;
+       } while (m);
+}
+
+#endif
+
+/*
+ *     Find the nearest fitting hole
+ */
+
+static struct hole *best_fit_hole(struct malloc_head *mh, uint16_t size)
+{
+       struct hole *m = mh->holes;
+       struct hole *best = NULL;
+
+       while (m) {
+               if (m->flags == HOLE_FREE && m->extent >= size)
+                       if (!best || best->extent > m->extent)
+                               best = m;
+               m = m->next;
+       }
+       return best;
+}
+
+static struct hole *mm_alloc(uint16_t pages)
+{
+       /*
+        *      Which hole fits best ?
+        */
+       struct hole *m;
+
+       m = best_fit_hole(&memmap, pages);
+       if (m == NULL)
+               return NULL;
+
+       /*
+        *      The hole is (probably) too big
+        */
+
+       if (split_hole(&memmap, m, pages))
+               return NULL;
+
+       m->flags = HOLE_USED;
+       m->refcount = 1;
+
+       return m;
+}
+
+static int maps_needed(uint16_t size)
+{
+       uint16_t banks = (size + 255) >> 8 + COMMON_BANKS;
+       /* 3 for uarea + common code copy */
+       return banks;
+}
+
+/*
+ * Try and swap stuff out if we can. If we run out of holes we will also swap
+ * which should tidy up the space no end.
+ */
+static uint16_t pagemap_do_alloc(ptptr p, uint16_t size)
+{
+       uint16_t hole;
+#ifdef SWAPDEV
+       while ((hole = mm_alloc(maps_needed(size))) == 0) {
+               if (swapneeded(p, 1) == NULL)
+                       return 0;
+       }
+#else
+       hole = mm_alloc(maps_needed(size));
+#endif
+       return hole;
+}
+
+int pagemap_alloc(ptptr p)
+{
+       uint16_t hole = pagemap_do_alloc(p, udata.u_top);
+       if (hole == 0)
+               return ENOMEM;
+       p->p_page = hole;
+       return 0;
+}
+
+static int pagemap_can_alloc(uint16_t size)
+{
+       uint16_t hole = pagemap_do_alloc(p, size);
+       if (hole) {
+               mm_free(hole);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ *     Realloc our buffer. Naïve implementation.
+ */
+int pagemap_realloc(uint16_t size)
+{
+       if (size == udata.u_top)
+               return 0;
+       if (size > udata.u_top && pagemap_can_alloc(size))
+               return ENOMEM;
+       pagemap_free(udata.u_page);
+       pagemap_do_alloc(udata.u_ptab, size);
+       /* Our vectors are below the base/limit ranges so don't get touched and
+          our uarea is above so that's fine too */
+       /* Propogate the new allocation into our uarea */
+       udata.u_page = udata.u_ptab->p_page;
+       return 0;
+}
+
+/*
+ *     Free a segment.
+ */
+
+void pagemap_free(ptptr p)
+{
+       struct hole *m = (struct hole *) p->page;
+       if (m->flags != HOLE_USED)
+               panic("double free");
+       m->flags = HOLE_FREE;
+       sweep_holes(mh);
+}
+
+/*
+ *     This is the only spot which cares what size a "block" is. For now its 256
+ *     bytes because that makes shifting it really cheap!
+ */
+static unsigned int pagemap_mem_used(void)
+{
+       struct hole *m;
+       unsigned int ret = 0;
+
+       while (m != NULL) {
+               if (m->flags == HOLE_USED)
+                       ret += m->extent;
+               m = m->next;
+       }
+       return ret << 2;
+}
+
+/*
+ *     Initialise the memory manager. Pass the start and end in terms
+ *     of blocks.
+ */
+
+void pagemap_setup(uint16_t start, uint16_t end)
+{
+       struct hole *holep = &holes[MAX_SEGMENTS - 1];
+
+       /*
+        *      Mark pages free.
+        */
+       do {
+               holep->flags = HOLE_SPARE;
+       } while (--holep > holes);
+
+       /*
+        *      Single hole containing all user memory.
+        */
+       holep->flags = HOLE_FREE;
+       holep->base = start;
+       holep->extent = end - start;
+       holep->next = NULL;
+
+}
+
+#endif
diff --git a/Kernel/usermem.c b/Kernel/usermem.c
new file mode 100644 (file)
index 0000000..5619fcb
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *     Implement the usermem services. Can then use either C or asm code for
+ *     the block transfers. This code can be banked as part of the kernel if
+ *     using the asm helpers but must be in commonmem if not
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+
+/* This checks to see if a user-supplied address is legitimate */
+usize_t valaddr(char *base, usize_t size)
+{
+       if (base < (char *)PROGBASE || base + size < base)
+               size = 0;
+       if (base + size > (char *)udata.u_top)
+               size = (char *)udata.u_top - base;
+       if (size == 0)
+               udata.u_error = EFAULT;
+       return size;
+}
+
+int uget(const void *user, void *dst, usize_t count)
+{
+       if (!valaddr(user,count))
+               return -1;
+       return _uget(user,dst,count);
+}
+
+int16_t ugetc(const void *user)
+{
+       if (!valaddr(user, 1))
+               return -1;
+       return _ugetc(user);
+}
+
+uint16_t ugetw(const void *user)
+{
+       if (!valaddr(user, 2))
+               return -1;
+       return _ugetw(user);
+}
+
+/* ugets is a bit odd - we don't know the length of the passed string
+   so we trim to the end of the allowed memory and if we don't find a
+   \0 in time we error */
+int ugets(const void *user, void *dest, usize_t maxlen)
+{
+       int ret;
+       maxlen = valaddr(user, maxlen);
+       if (!maxlen)
+               return -1;
+       ret = _ugets(user, dest, maxlen);
+       if (ret == -1)
+               udata.u_error = EFAULT;
+       return ret;
+}
+
+int uput(const void *source,   void *user, usize_t count)
+{
+       if (!valaddr(user, count))
+               return -1;
+       return _uput(source,user,count);
+}
+
+int uputc(uint16_t value,  void *user)
+{
+       if (!valaddr(user, 1))
+               return -1;
+       /* u16_t so we don't get wacky 8bit stack games on SDCC */
+       return _uputc(value,user);
+}
+
+int uputw(uint16_t value, void *user)
+{
+       if (!valaddr(user, 2))
+               return -1;
+       return _uputw(value,user);
+}
+
+int uzero(void *user, usize_t count)
+{
+       if (!valaddr(user, count))
+               return -1;
+       return _uzero(user,count);
+}
+
+/*
+ *     Optional C language implementation for porting to new processors
+ *     or where asm isn't needed
+ */
+#ifdef CONFIG_USERMEM_C
+
+usize_t _uget(const uint8_t *user, uint8_t *dest, usize_t count)
+{
+       uint8_t tmp;
+       while(count--) {
+               BANK_PROCESS;
+               tmp = *user++;
+               BANK_KERNEL;
+               *dest++ = tmp;
+       }
+       return 0;
+}
+
+int16_t _ugetc(const uint8_t *user)
+{
+       uint8_t tmp;
+       BANK_PROCESS;
+       tmp = *user;
+       BANK_KERNEL;
+       return tmp;
+}
+
+uint16_t _ugetw(const uint16_t *user)
+{
+       uint16_t tmp;
+       BANK_PROCESS;
+       tmp = *user;
+       BANK_KERNEL;
+       return tmp;
+}
+
+int _ugets(const uint8_t *user, uint8_t *dest, usize_t count)
+{
+       uint8_t tmp;
+       while(count--) {
+               BANK_PROCESS;
+               tmp = *user++;
+               BANK_KERNEL;
+               *dest++ = tmp;
+               if (tmp == '\0')
+                       return 0;
+       }
+       /* Ensure terminated */
+       dest[-1] = '\0';
+       return -1;
+}
+
+int _uput(const uint8_t *source, uint8_t *user, usize_t count)
+{
+       uint8_t tmp;
+       while(count--) {
+               tmp = *source++
+               BANK_PROCESS;
+               *user++ = tmp;
+               BANK_KERNEL;
+       }
+       return 0;
+
+}
+
+int _uputc(uint16_t value,  uint8_t *user)
+{
+       BANK_PROCESS;
+       *user = value;
+       BANK_KERNEL;
+       return 0;
+}
+
+int _uputw(uint16_t value,  uint16_t *user)
+{
+       BANK_PROCESS;
+       *user = value;
+       BANK_KERNEL;
+       return 0;
+}
+
+int _uzero(uint8_t *user, usize_t count)
+{
+       BANK_KERNEL;
+       while(count--)
+               *user++=0;
+       BANK_PROCESS;
+       return 0;
+}
+
+#endif
diff --git a/Kernel/usermem_std-6502.s b/Kernel/usermem_std-6502.s
new file mode 100644 (file)
index 0000000..e1d46ef
--- /dev/null
@@ -0,0 +1,6 @@
+       .include "platform/kernel.def"
+        .include "kernel02.def"
+
+;
+;      Uses the C helpers
+;
\ No newline at end of file
diff --git a/Kernel/usermem_std-6809.s b/Kernel/usermem_std-6809.s
new file mode 100644 (file)
index 0000000..cdc34f4
--- /dev/null
@@ -0,0 +1,8 @@
+       .module usermem
+
+       include "platform/kernel.def"
+        include "kernel09.def"
+
+;
+;      Using the C helpers for now
+;
diff --git a/Kernel/usermem_std-z80.s b/Kernel/usermem_std-z80.s
new file mode 100644 (file)
index 0000000..4d6e921
--- /dev/null
@@ -0,0 +1,193 @@
+;
+;      No fancy optimisations here. It's not clear they are worth it once
+;      you have to deal with misaligned transfers that might cross source
+;      or destination banks. One optimisation might be worth doing - that
+;      is 512 byte blocks that don't bank cross ?
+;
+        .module usermem
+
+       .include "platform/kernel.def"
+        .include "kernel.def"
+
+        ; exported symbols
+        .globl __uget
+        .globl __ugetc
+        .globl __ugets
+        .globl __ugetw
+
+       .globl outcharhex
+       .globl outhl
+
+        .globl __uput
+        .globl __uputc
+        .globl __uputw
+        .globl __uzero
+
+       .globl  map_process_always
+       .globl  map_kernel
+;
+;      We need these in common as they bank switch
+;
+        .area _COMMONMEM
+
+uputget:
+        ; load DE with the byte count
+        ld e, 8(ix) ; byte count
+        ld d, 9(ix)
+       ld a, d
+       or e
+       ret z           ; no work
+       dec de          ; we return BC as a count for two 8bit loops
+       ld b, e         ; not a 16bit value
+       inc b           ; See http://map.grauw.nl/articles/fast_loops.php
+       inc d
+       ld c, d
+        ; load HL with the source address
+        ld l, 4(ix) ; src address
+        ld h, 5(ix)
+        ; load DE with destination address (in userspace)
+        ld e, 6(ix)
+        ld d, 7(ix)
+       ld a, b
+       or c
+       ret
+
+__uputc:
+       pop bc  ;       return
+       pop de  ;       char
+       pop hl  ;       dest
+       push hl
+       push de
+       push bc
+       call map_process_always
+       ld (hl), e
+uputc_out:
+       jp map_kernel                   ; map the kernel back below common
+
+__uputw:
+       pop bc  ;       return
+       pop de  ;       word
+       pop hl  ;       dest
+       push hl
+       push de
+       push bc
+       call map_process_always
+       ld (hl), e
+       inc hl
+       ld (hl), d
+       jp map_kernel
+
+__ugetc:
+       pop bc  ; return
+       pop hl  ; address
+       push hl
+       push bc
+       call map_process_always
+        ld l, (hl)
+       ld h, #0
+       jp map_kernel
+
+__ugetw:
+       pop bc  ; return
+       pop hl  ; address
+       push hl
+       push bc
+       call map_process_always
+        ld a, (hl)
+       inc hl
+       ld h, (hl)
+       ld l, a
+       jp map_kernel
+
+__uput:
+       push ix
+       ld ix, #0
+       add ix, sp
+       call uputget                    ; source in HL dest in DE, count in BC
+       jr z, uput_out                  ; but count is at this point magic
+       
+uput_l:        ld a, (hl)
+       inc hl
+       call map_process_always
+       ld (de), a
+       call map_kernel
+       inc de
+       djnz uput_l
+       dec c
+       jr nz, uput_l
+
+uput_out:
+       pop ix
+       ret
+
+
+__uget:
+       push ix
+       ld ix, #0
+       add ix, sp
+       call uputget                    ; source in HL dest in DE, count in BC
+       jr z, uput_out                  ; but count is at this point magic
+       
+uget_l:
+       call map_process_always
+       ld a, (hl)
+       inc hl
+       call map_kernel
+       ld (de), a
+       inc de
+       djnz uget_l
+       dec c
+       jr nz, uget_l
+       jr uput_out
+
+__ugets:
+       push ix
+       ld ix, #0
+       add ix, sp
+       call uputget                    ; source in HL dest in DE, count in BC
+       jr z, ugets_bad                 ; but count is at this point magic
+       
+ugets_l:
+       call map_process_always
+       ld a, (hl)
+       inc hl
+       call map_kernel
+       ld (de), a
+       or a
+       jr z, ugets_good
+       inc de
+       djnz ugets_l
+       dec c
+       jr nz, ugets_l
+       dec de
+       xor a
+       ld (de), a
+ugets_bad:
+       ld hl,  #0xFFFF                 ; flag an error
+       jr uput_out
+ugets_good:
+       ld hl,#0
+       jr uput_out
+
+;
+__uzero:
+       pop de  ; return
+       pop hl  ; address
+       pop bc  ; size
+       push bc
+       push hl 
+       push de
+       ld a, b ; check for 0 copy
+       or c
+       ret z
+       call map_process_always
+       ld (hl), #0
+       dec bc
+       ld a, b
+       or c
+       jp z, uputc_out
+       ld e, l
+       ld d, h
+       inc de
+       ldir
+       jp uputc_out
diff --git a/Kernel/vt.c b/Kernel/vt.c
new file mode 100644 (file)
index 0000000..a5e2434
--- /dev/null
@@ -0,0 +1,238 @@
+#include <kernel.h>
+#include <vt.h>
+
+#ifdef CONFIG_VT
+/*
+ *     Mini vt52 terminal emulation
+ *
+ *     The caller is required to provide
+ *
+ *     cursor_off();
+ *     cursor_on(newy, newx)
+ *     clear_across(y,x,num)
+ *     clear_lines(y,num)
+ *     scroll_up();
+ *     scroll_down();
+ *     plot_char(y, x, c);
+ *
+ *     VT_RIGHT, VT_BOTTOM for the size.
+ *
+ *     For now we don't do region scrolling, status line stuff and the like
+ *     that some vt52 alikes have. If your video memory is banked then
+ *     you probably want to put your helpers in common, but there should
+ *     be no need for any of this logic to be there
+ *
+ *     For the simple case of a vt permanently mapped into the kernel space
+ *     and using character mode the driver can provide all the other logic
+ *     for free.
+ *     
+ *     In that case
+ *     define CONFIG_VT_SIMPLE
+ *     VT_BASE is the base address in kernelspace
+ *     VT_WIDTH is the line width (including padding)
+ *     
+ */
+
+
+static int vtmode;
+static char cursorx;
+static char cursory;
+static int ncursory;
+
+static void cursor_fix(void)
+{
+       if (cursorx < 0) {
+               cursorx = 0;
+               cursory--;
+       }
+       if (cursory < 0)
+               cursory = 0;
+       if (cursorx > VT_RIGHT) {
+               cursorx = 0;
+               cursory++;
+       }
+       if (cursory > VT_BOTTOM) {
+               scroll_up();
+               clear_lines(VT_BOTTOM, 1);
+               cursory--;
+       }
+}
+
+static void charout(unsigned char c)
+{
+       if (c == 7) {
+               do_beep();
+               return;
+       }
+       if (c == 8) {
+               cursorx--;
+               goto fix;
+       }
+       if (c == 9) {
+               do {
+                       charout(' ');
+               } while (cursorx%8);
+               goto fix;
+       }
+       if (c == 10) {
+               cursory++;
+               goto fix;
+       }
+       if (c == 13) {
+               cursorx = 0;
+               return;
+       }
+       if (c == 0x1b) {
+               vtmode = 1;
+               return;
+       }
+       plot_char(cursory, cursorx, c);
+       cursorx++;
+      fix:
+       cursor_fix();
+}
+
+
+static int escout(unsigned char c)
+{
+       if (c == 'A') {
+               if (cursory)
+                       cursory--;
+               return 0;
+       }
+       if (c == 'B') {
+               if (cursory < VT_BOTTOM)
+                       cursory++;
+               return 0;
+       }
+       if (c == 'C') {
+               if (cursorx < VT_RIGHT)
+                       cursorx++;
+               return 0;
+       }
+       if (c == 'D') {
+               if (cursorx)
+                       cursorx--;
+               return 0;
+       }
+       if (c == 'E') {
+               clear_lines(0, VT_HEIGHT);
+               return 0;
+       }
+       if (c == 'H') {
+               cursorx = 0;
+               cursory = 0;
+               return 0;
+       }
+       if (c == 'I') {
+               if (cursory)
+                       cursory--;
+               else {
+                       scroll_down();
+                       clear_lines(0, 1);
+               }
+               return 0;
+       }
+       if (c == 'J') {
+               clear_across(cursory, cursorx, VT_RIGHT - cursorx);
+               clear_lines(cursory + 1, VT_BOTTOM - cursory);
+               return 0;
+       }
+       if (c == 'K') {
+               clear_across(cursory, cursorx, VT_RIGHT - cursorx);
+               return 0;
+       }
+       if (c == 'Y')
+               return 2;
+       return 0;
+}
+
+
+/* VT52 alike functionality */
+void vtoutput(unsigned char *p, unsigned int len)
+{
+       cursor_off();
+       while (len--) {
+               unsigned char c = *p++;
+               if (vtmode == 0) {
+                       charout(c);
+                       continue;
+               }
+               if (vtmode == 1) {
+                       vtmode = escout(c);
+                       continue;
+               }
+               if (vtmode == 2) {
+                       ncursory = c - ' ';
+                       vtmode++;
+                       continue;
+               } else {
+                       int ncursorx = c - ' ';
+                       if (ncursory >= 0 && ncursorx <= VT_BOTTOM)
+                               cursory = ncursory;
+                       if (ncursorx >= 0 && ncursorx <= VT_RIGHT)
+                               cursorx = ncursorx;
+               }
+       }
+       cursor_on(cursory, cursorx);
+}
+
+void vtinit(void)
+{
+       vtmode = 0;
+       clear_lines(0, VT_HEIGHT);
+       cursor_on(0, 0);
+}
+
+
+#ifdef CONFIG_VT_SIMPLE
+
+static unsigned char *cpos;
+static unsigned char csave;
+
+static uint8_t *char_addr(unsigned int y1, unsigned char x1)
+{
+       return VT_BASE + VT_WIDTH * y1 + x1;
+}
+
+void cursor_off(void)
+{
+       *cpos = csave;
+}
+
+void cursor_on(int8_t y, int8_t x)
+{
+       cpos = char_addr(y, x);
+       csave = *cpos;
+       *cpos = '_';
+}
+
+void plot_char(int8_t y, int8_t x, uint16_t c)
+{
+       *char_addr(y, x) = c;
+}
+
+void clear_lines(int8_t y, int8_t ct)
+{
+       unsigned char *s = char_addr(y, 0);
+       memset(s, ' ', ct * VT_WIDTH);
+}
+
+void clear_across(int8_t y, int8_t x, int16_t l)
+{
+       unsigned char *s = char_addr(y, x);
+       memset(s, ' ', l);
+}
+
+void scroll_up(void)
+{
+       memcpy(VT_BASE, VT_BASE + VT_WIDTH, VT_WIDTH * VT_BOTTOM);
+}
+
+void scroll_down(void)
+{
+       memcpy(VT_BASE + VT_WIDTH, VT_BASE, VT_WIDTH * VT_BOTTOM);
+}
+
+#endif
+#endif
diff --git a/LICENSE b/LICENSE
index d6a9326..cc54098 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,6 @@
+[The libraries are LGPL, some files have more permissive licensing]
+
+
 GNU GENERAL PUBLIC LICENSE
                        Version 2, June 1991
 
diff --git a/Library/Makefile b/Library/Makefile
new file mode 100644 (file)
index 0000000..0025278
--- /dev/null
@@ -0,0 +1,5 @@
+# Top level makefile for library
+
+tools/syscall: tools/syscall.c ../Kernel/include/syscall_name.h
+       $(CC) $(CFLAGS) -I../Kernel/include tools/syscall.c -o tools/syscall
+
diff --git a/Library/include/alloc.h b/Library/include/alloc.h
new file mode 100644 (file)
index 0000000..e396a26
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef __MALLOC_H\r
+#include <malloc.h>\r
+#endif\r
diff --git a/Library/include/ar.h b/Library/include/ar.h
new file mode 100644 (file)
index 0000000..6739411
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __AR_H\r
+#define __AR_H\r
+\r
+#define ARMAG "!<arch>\n"\r
+#define SARMAG 8\r
+#define ARFMAG "`\n"\r
+\r
+struct ar_hdr {\r
+       char    ar_name[16],\r
+               ar_date[12],\r
+               ar_uid[6],\r
+               ar_gid[6],\r
+               ar_mode[8],\r
+               ar_size[10],\r
+               ar_fmag[2];\r
+};\r
+\r
+#endif /* __AR_H */\r
diff --git a/Library/include/assert.h b/Library/include/assert.h
new file mode 100644 (file)
index 0000000..4f554c6
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __ASSERT_H\r
+#define __ASSERT_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+/* ANSI compilers only version ! */\r
+\r
+/* If NDEBUG is defined, do nothing.\r
+   If not, and EXPRESSION is zero, print an error message and abort.  */\r
+\r
+#ifdef NDEBUG\r
+\r
+#define assert(expr)           ((void) 0)\r
+\r
+#else /* NDEBUG */\r
+\r
+extern void __assert __P((char *, char *, int));\r
+\r
+#define assert(expr)   \\r
+  ((void) ((expr) || (__assert (__STRING(expr),  __FILE__, __LINE__), 0)))\r
+\r
+#endif /* NDEBUG */\r
+\r
+extern void __errput __P((char *));\r
+\r
+#endif /* __ASSERT_H */\r
+\r
diff --git a/Library/include/ctype.h b/Library/include/ctype.h
new file mode 100644 (file)
index 0000000..cd72e42
--- /dev/null
@@ -0,0 +1,48 @@
+/* ctype.h     Character classification and conversion\r
+ */\r
+#ifndef __CTYPE_H\r
+#define __CTYPE_H\r
+\r
+#include <features.h>\r
+extern unsigned char __ctype[];\r
+\r
+#define __CT_c 0x01            /* control character */\r
+#define __CT_u 0x02            /* upper case */\r
+#define __CT_l 0x04            /* lower case */\r
+#define __CT_d 0x08            /* numeric digit */\r
+#define __CT_s 0x10            /* whitespace */\r
+#define __CT_p 0x20            /* punctuation */\r
+#define __CT_x 0x40            /* hexadecimal */\r
+\r
+#define __CT_a (__CT_u|__CT_l) /* alpha */\r
+\r
+/* always functions ! */\r
+extern int toupper __P((int));\r
+extern int tolower __P((int));\r
+\r
+#define _toupper(c)    (islower(c) ? (c)^0x20 : (c))\r
+#define _tolower(c)    (isupper(c) ? (c)^0x20 : (c))\r
+#define __toupper(c)   ((c)^0x20)\r
+#define __tolower(c)   ((c)^0x20)\r
+#define toascii(c)     ((c)&0x7F)\r
+\r
+#define _CTYPE(c)      (__ctype[(unsigned char)(c)])\r
+\r
+/* Note the '!!' is a cast to 'bool' and even BCC deletes it in an if()  */\r
+#define isascii(c)     (!((c)&~0x7F))\r
+#define isalnum(c)     (!!(_CTYPE(c)&(__CT_a|__CT_d)))\r
+#define isalpha(c)     (!!(_CTYPE(c)&__CT_a))\r
+#define iscntrl(c)     (!!(_CTYPE(c)&__CT_c))\r
+#define isdigit(c)     (!!(_CTYPE(c)&__CT_d))\r
+#define isgraph(c)     (! (_CTYPE(c)&(__CT_c|__CT_s)))\r
+#define islower(c)     (!!(_CTYPE(c)&__CT_l))\r
+#define isprint(c)     (! (_CTYPE(c)&__CT_c))\r
+#define ispunct(c)     (!!(_CTYPE(c)&__CT_p))\r
+#define isspace(c)     (!!(_CTYPE(c)&__CT_s))\r
+#define isupper(c)     (!!(_CTYPE(c)&__CT_u))\r
+#define isxdigit(c)    (!!(_CTYPE(c)&__CT_x))\r
+\r
+#define isdecimal(c)   isdigit(c)\r
+#define isoctal(c)     ((c) >= '0' && (c) <= '7')\r
+\r
+#endif /* __CTYPE_H */\r
diff --git a/Library/include/curses.h b/Library/include/curses.h
new file mode 100644 (file)
index 0000000..3badca8
--- /dev/null
@@ -0,0 +1,229 @@
+/* curses.h - defines macros and prototypes for curses */\r
+\r
+#ifndef CURSES_H\r
+\r
+#define _BIG_MACHINE_\r
+\r
+#include <sgtty.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+\r
+#ifndef _PROTOTYPE\r
+#define _PROTOTYPE(x,y)        x y\r
+#endif\r
+\r
+typedef int bool;\r
+\r
+#define TRUE 1\r
+#define FALSE 0\r
+#define ERR 1          /* general error flag */\r
+#define OK 0           /* general OK flag */\r
+\r
+/* Macros. */\r
+#define box(win,vc,hc) wbox(win,0,0,0,0,vc,hc)\r
+#define addch(ch) waddch(stdscr,ch)\r
+#define mvaddch(y,x,ch) (wmove(stdscr,y,x)==ERR?ERR:waddch(stdscr,ch))\r
+#define mvwaddch(win,y,x,ch) (wmove(win,y,x)==ERR?ERR:waddch(win,ch))\r
+#define getch() wgetch(stdscr)\r
+#define mvgetch(y,x) (wmove(stdscr,y,x)==ERR?ERR:wgetch(stdscr))\r
+#define mvwgetch(win,y,x) (wmove(win,y,x)==ERR?ERR:wgetch(win))\r
+#define addstr(str) waddstr(stdscr,str)\r
+#define mvaddstr(y,x,str) (wmove(stdscr,y,x)==ERR?ERR:waddstr(stdscr,str))\r
+#define mvwaddstr(win,y,x,str) (wmove(win,y,x)==ERR?ERR:waddstr(win,str))\r
+#define getstr(str) wgetstr(stdscr,str)\r
+#define mvgetstr(y,x,str) (wmove(stdscr,y,x)==ERR?ERR:wgetstr(stdscr,str))\r
+#define mvwgetstr(win,y,x,str) (wmove(win,y,x)==ERR?ERR:wgetstr(win,str))\r
+#define move(y,x) wmove(stdscr,y,x)\r
+#define clear() wclear(stdscr)\r
+#define erase() werase(stdscr)\r
+#define clrtobot() wclrtobot(stdscr)\r
+#define mvclrtobot(y,x) (wmove(stdscr,y,x)==ERR?ERR:wclrtobot(stdscr))\r
+#define mvwclrtobot(win,y,x) (wmove(win,y,x)==ERR?ERR:wclrtobot(win))\r
+#define clrtoeol() wclrtoeol(stdscr)\r
+#define mvclrtoeol(y,x) (wmove(stdscr,y,x)==ERR?ERR:wclrtoeol(stdscr))\r
+#define mvwclrtoeol(win,y,x) (wmove(win,y,x)==ERR?ERR:wclrtoeol(win))\r
+#define insertln() winsertln(stdscr)\r
+#define mvinsertln(y,x) (wmove(stdscr,y,x)==ERR?ERR:winsertln(stdscr))\r
+#define mvwinsertln(win,y,x) (wmove(win,y,x)==ERR?ERR:winsertln(win))\r
+#define deleteln() wdeleteln(stdscr)\r
+#define mvdeleteln(y,x) (wmove(stdscr,y,x)==ERR?ERR:wdeleteln(stdscr))\r
+#define mvwdeleteln(win,y,x) (wmove(win,y,x)==ERR?ERR:wdeleteln(win))\r
+#define refresh() wrefresh(stdscr)\r
+#define inch() winch(stdscr)\r
+#define insch(ch) winsch(stdscr,ch)\r
+#define mvinsch(y,x,ch) (wmove(stdscr,y,x)==ERR?ERR:winsch(stdscr,ch))\r
+#define mvwinsch(win,y,x,ch) (wmove(win,y,x)==ERR?ERR:winsch(win,ch))\r
+#define delch() wdelch(stdscr)\r
+#define mvdelch(y,x) (wmove(stdscr,y,x)==ERR?ERR:wdelch(stdscr))\r
+#define mvwdelch(win,y,x) (wmove(win,y,x)==ERR?ERR:wdelch(win))\r
+#define standout() wstandout(stdscr)\r
+#define wstandout(win) (win)->_attrs |= A_STANDOUT\r
+#define standend() wstandend(stdscr)\r
+#define wstandend(win) (win)->_attrs &= ~A_STANDOUT\r
+#define attrset(attrs) wattrset(stdscr, attrs)\r
+#define wattrset(win, attrs) (win)->_attrs = (attrs)\r
+#define attron(attrs) wattron(stdscr, attrs)\r
+#define wattron(win, attrs) (win)->_attrs |= (attrs)\r
+#define attroff(attrs) wattroff(stdscr,attrs)\r
+#define wattroff(win, attrs) (win)->_attrs &= ~(attrs)\r
+#define resetty() stty(1, &_orig_tty)\r
+#define getyx(win,y,x) (y = (win)->_cury, x = (win)->_curx)\r
+\r
+/* Video attribute definitions. */\r
+#define A_BLINK        0x0100\r
+#define A_BLANK        0\r
+#define A_BOLD        0x0200\r
+#define A_DIM         0\r
+#define A_PROTECT      0\r
+#define A_REVERSE      0x0400\r
+#define A_STANDOUT     0x0800\r
+#define A_UNDERLINE    0x1000\r
+#define A_ALTCHARSET   0x2000\r
+\r
+/* Type declarations. */\r
+typedef struct {\r
+  int     _cury;                       /* current pseudo-cursor */\r
+  int     _curx;\r
+  int     _maxy;                       /* max coordinates */\r
+  int     _maxx;\r
+  int     _begy;                       /* origin on screen */\r
+  int     _begx;\r
+  int     _flags;                      /* window properties */\r
+  int     _attrs;                      /* attributes of written characters */\r
+  int     _tabsize;                    /* tab character size */\r
+  bool    _clear;                      /* causes clear at next refresh */\r
+  bool    _leave;                      /* leaves cursor as it happens */\r
+  bool    _scroll;                     /* allows window scrolling */\r
+  bool    _nodelay;                    /* input character wait flag */\r
+  bool    _keypad;                     /* flags keypad key mode active */\r
+  int   **_line;                       /* pointer to line pointer array */\r
+  int    *_minchng;                    /* First changed character in line */\r
+  int    *_maxchng;                    /* Last changed character in line */\r
+  int     _regtop;                     /* Top/bottom of scrolling region */\r
+  int     _regbottom;\r
+} WINDOW;\r
+\r
+/* External variables */\r
+extern int LINES;                      /* terminal height */\r
+extern int COLS;                       /* terminal width */\r
+extern bool NONL;                      /* \n causes CR too ? */\r
+extern WINDOW *curscr;                 /* the current screen image */\r
+extern WINDOW *stdscr;                 /* the default screen window */\r
+extern struct sgttyb _orig_tty, _tty;\r
+\r
+extern unsigned int ACS_ULCORNER;      /* terminal dependent block grafic */\r
+extern unsigned int ACS_LLCORNER;      /* charcters.  Forget IBM, we are */\r
+extern unsigned int ACS_URCORNER;      /* independent of their charset. :-) */\r
+extern unsigned int ACS_LRCORNER;\r
+extern unsigned int ACS_RTEE;\r
+extern unsigned int ACS_LTEE;\r
+extern unsigned int ACS_BTEE;\r
+extern unsigned int ACS_TTEE;\r
+extern unsigned int ACS_HLINE;\r
+extern unsigned int ACS_VLINE;\r
+extern unsigned int ACS_PLUS;\r
+extern unsigned int ACS_S1;\r
+extern unsigned int ACS_S9;\r
+extern unsigned int ACS_DIAMOND;\r
+extern unsigned int ACS_CKBOARD;\r
+extern unsigned int ACS_DEGREE;\r
+extern unsigned int ACS_PLMINUS;\r
+extern unsigned int ACS_BULLET;\r
+extern unsigned int ACS_LARROW;\r
+extern unsigned int ACS_RARROW;\r
+extern unsigned int ACS_DARROW;\r
+extern unsigned int ACS_UARROW;\r
+extern unsigned int ACS_BOARD;\r
+extern unsigned int ACS_LANTERN;\r
+extern unsigned int ACS_BLOCK;\r
+\r
+#ifdef _BIG_MACHINE_\r
+_PROTOTYPE( char *unctrl, (int _c) );\r
+_PROTOTYPE( int baudrate, (void));\r
+_PROTOTYPE( void beep, (void));\r
+_PROTOTYPE( void cbreak, (void));\r
+_PROTOTYPE( void clearok, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( void clrscr, (void));\r
+_PROTOTYPE( void curs_set, (int _visibility) );\r
+_PROTOTYPE( void delwin, (WINDOW *_win) );\r
+_PROTOTYPE( void doupdate, (void));\r
+_PROTOTYPE( void echo, (void));\r
+_PROTOTYPE( int endwin, (void));\r
+_PROTOTYPE( int erasechar, (void));\r
+_PROTOTYPE( void fatal, (char *_s) );\r
+_PROTOTYPE( int fixterm, (void));\r
+_PROTOTYPE( void flash, (void));\r
+_PROTOTYPE( int gettmode, (void));\r
+_PROTOTYPE( void idlok, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( WINDOW *initscr, (void));\r
+_PROTOTYPE( void keypad, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( int killchar, (void));\r
+_PROTOTYPE( void leaveok, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( char *longname, (void));\r
+_PROTOTYPE( void meta, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( int mvcur, (int _oldy, int _oldx, int _newy, int _newx) );\r
+_PROTOTYPE( int mvinch, (int _y, int _x) );\r
+_PROTOTYPE( int mvprintw, (int _y, int _x, char *_fmt, ...) );\r
+_PROTOTYPE( int mvscanw, (int _y, int _x, char *_fmt, char *_A1, int _A2,\r
+                                               int _A3, int _A4, int _A5) );\r
+_PROTOTYPE( int mvwin, (WINDOW *_win, int _begy, int _begx) );\r
+_PROTOTYPE( int mvwinch, (WINDOW *_win, int _y, int _x) );\r
+_PROTOTYPE( int mvwprintw, (WINDOW *_win, int _y, int _x, char *_fmt, ...) );\r
+_PROTOTYPE( int mvwscanw, (WINDOW *_win, int _y, int _x, char *_fmt, char *_A1,\r
+                                       int _A2, int _A3, int _A4, int _A5) );\r
+_PROTOTYPE( WINDOW *newwin, (int _num_lines, int _num_cols, int _y, int _x));\r
+_PROTOTYPE( void nl, (void));\r
+_PROTOTYPE( void nocbreak, (void));\r
+_PROTOTYPE( void nodelay, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( void noecho, (void));\r
+_PROTOTYPE( void nonl, (void));\r
+_PROTOTYPE( void noraw, (void));\r
+_PROTOTYPE( void outc, (int _c) );\r
+_PROTOTYPE( void overlay, (WINDOW *_win1, WINDOW *_win2) );\r
+_PROTOTYPE( void overwrite, (WINDOW *_win1, WINDOW *_win2) );\r
+_PROTOTYPE( void poscur, (int _r, int _c) );\r
+_PROTOTYPE( int printw, (char *fmt, ...) );\r
+_PROTOTYPE( void raw, (void));\r
+_PROTOTYPE( int resetterm, (void));\r
+_PROTOTYPE( int saveoldterm, (void));\r
+_PROTOTYPE( int saveterm, (void));\r
+_PROTOTYPE( int savetty, (void));\r
+_PROTOTYPE( int scanw, (char *_fmt, char *_A1, int _A2, int _A3, int _A4,\r
+                                       int _A5) );\r
+_PROTOTYPE( void scroll, (WINDOW *_win) );\r
+_PROTOTYPE( void scrollok, (WINDOW *_win, bool _flag) );\r
+_PROTOTYPE( int setscrreg, (int _top, int _bottom) );\r
+_PROTOTYPE( int setterm, (char *_type) );\r
+_PROTOTYPE( int setupterm, (void));\r
+_PROTOTYPE( WINDOW *subwin, (WINDOW *_orig, int _nlines, int _ncols, int _y,\r
+                                       int _x));\r
+_PROTOTYPE( int tabsize, (int _ts) );\r
+_PROTOTYPE( void touchwin, (WINDOW *_win) );\r
+_PROTOTYPE( int waddch, (WINDOW *_win, int _c) );\r
+_PROTOTYPE( int waddstr, (WINDOW *_win, char *_str) );\r
+_PROTOTYPE( int wbox, (WINDOW *_win, int _ymin, int _xmin, int _ymax,\r
+                               int _xmax, unsigned int _v, unsigned int _h) );\r
+_PROTOTYPE( void wclear, (WINDOW *_win) );\r
+_PROTOTYPE( int wclrtobot, (WINDOW *_win) );\r
+_PROTOTYPE( int wclrtoeol, (WINDOW *_win) );\r
+_PROTOTYPE( int wdelch, (WINDOW *_win) );\r
+_PROTOTYPE( int wdeleteln, (WINDOW *_win) );\r
+_PROTOTYPE( void werase, (WINDOW *_win) );\r
+_PROTOTYPE( int wgetch, (WINDOW *_win) );\r
+_PROTOTYPE( int wgetstr, (WINDOW *_win, char *_str) );\r
+_PROTOTYPE( int winch, (WINDOW *_win) );\r
+_PROTOTYPE( int winsch, (WINDOW *_win, char _c) );\r
+_PROTOTYPE( int winsertln, (WINDOW *_win) );\r
+_PROTOTYPE( int wmove, (WINDOW *_win, int _y, int _x) );\r
+_PROTOTYPE( void wnoutrefresh, (WINDOW *_win) );\r
+_PROTOTYPE( int wprintw, (WINDOW *win, char *fmt, ...));\r
+_PROTOTYPE( void wrefresh, (WINDOW *_win) );\r
+_PROTOTYPE( int wscanw, (WINDOW *_win, char *_fmt, char *_A1, int _A2, int _A3,\r
+                                                       int _A4, int _A5) );\r
+_PROTOTYPE( int wsetscrreg, (WINDOW *_win, int _top, int _bottom) );\r
+_PROTOTYPE( int wtabsize, (WINDOW *_win, int _ts) );\r
+\r
+#endif\r
+#define CURSES_H\r
+\r
+#endif\r
diff --git a/Library/include/dirent.h b/Library/include/dirent.h
new file mode 100644 (file)
index 0000000..8eb8fee
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __DIRENT_H
+#define __DIRENT_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+
+/* It's 14 for the kernel as it stands but may move to 30 so build
+   that into userspace */
+
+#define MAXNAMLEN      30
+
+/* Directory stream type.  */
+typedef struct {
+       int dd_fd;              /* file descriptor */
+       int dd_loc;             /* offset in buffer */
+       int dd_size;            /* # of valid entries in buffer */
+       struct dirent *dd_buf;  /* -> directory buffer */
+} DIR;                         /* stream data from opendir() */
+
+typedef int (*__dir_select_fn_t) __P ((struct dirent *));
+
+typedef int (*__dir_compar_fn_t) __P ((struct dirent **, struct dirent **));
+
+struct dirent {
+       long            d_ino;          /* Try to be iBCS2 like */
+       off_t           d_off;
+       unsigned short  d_reclen;
+       char            d_name[31];
+};
+
+/* Internal version */
+struct __dirent {
+       long            d_ino;
+       char            d_name[30];
+};
+
+extern DIR *opendir __P ((char *__name));
+extern int closedir __P ((DIR * __dirp));
+extern struct dirent *readdir __P ((DIR * __dirp));
+extern void rewinddir __P ((DIR * __dirp));
+
+extern void seekdir __P ((DIR * __dirp, off_t __pos));
+extern off_t telldir __P ((DIR * __dirp));
+
+/* Scan the directory DIR, calling SELECT on each directory entry.
+   Entries for which SELECT returns nonzero are individually malloc'd,
+   sorted using qsort with CMP, and collected in a malloc'd array in
+   *NAMELIST.  Returns the number of entries selected, or -1 on error.
+ */
+extern int scandir __P ((char *__dir,
+                        struct dirent ***__namelist,
+                        __dir_select_fn_t __select,
+                        __dir_compar_fn_t __compar));
+
+#endif /* dirent.h  */
diff --git a/Library/include/errno.h b/Library/include/errno.h
new file mode 100644 (file)
index 0000000..be61f97
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __ERRNO_H\r
+#define __ERRNO_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+/*
+ * Error codes
+ */
+#define EPERM           1               /* Not owner */
+#define ENOENT          2               /* No such file or directory */
+#define ESRCH           3               /* No such process */
+#define EINTR           4               /* Interrupted System Call */
+#define EIO             5               /* I/O Error */
+#define ENXIO           6               /* No such device or address */
+#define E2BIG           7               /* Arg list too long */
+#define ENOEXEC         8               /* Exec format error */
+#define EBADF           9               /* Bad file number */
+#define ECHILD          10              /* No children */
+#define EAGAIN          11              /* No more processes */
+#define ENOMEM          12              /* Not enough core */
+#define EACCES          13              /* Permission denied */
+#define EFAULT          14              /* Bad address */
+#define ENOTBLK         15              /* Block device required */
+#define EBUSY           16              /* Mount device busy */
+#define EEXIST          17              /* File exists */
+#define EXDEV           18              /* Cross-device link */
+#define ENODEV          19              /* No such device */
+#define ENOTDIR         20              /* Not a directory */
+#define EISDIR          21              /* Is a directory */
+#define EINVAL          22              /* Invalid argument */
+#define ENFILE          23              /* File table overflow */
+#define EMFILE          24              /* Too many open files */
+#define ENOTTY          25              /* Not a typewriter */
+#define ETXTBSY         26              /* Text file busy */
+#define EFBIG           27              /* File too large */
+#define ENOSPC          28              /* No space left on device */
+#define ESPIPE          29              /* Illegal seek */
+#define EROFS           30              /* Read-only file system */
+#define EMLINK          31              /* Too many links */
+#define EPIPE           32              /* Broken pipe */
+
+/* math software */
+#define EDOM            33              /* Argument too large */
+#define ERANGE          34              /* Result too large */
+#define EWOULDBLOCK    35              /* Operation would block */
+#define ENOTEMPTY      36              /* Directory is not empty */
+#define ENAMETOOLONG    37              /* File name too long */
+
+\r
+#define __ERRORS       38\r
+\r
+extern int sys_nerr;\r
+extern char *sys_errlist[];\r
+extern int errno;\r
+\r
+extern char *strerror __P((int _errno));\r
+\r
+#endif\r
+\r
diff --git a/Library/include/fcntl.h b/Library/include/fcntl.h
new file mode 100644 (file)
index 0000000..4c59cd0
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _FCNTL_H\r
+#define _FCNTL_H\r
+\r
+/* Bits 0-7 are saved, bits 8-15 are discard post open. Not all are handled
+   in the kernel yet */
+#define O_RDONLY        0
+#define O_WRONLY        1
+#define O_RDWR          2
+#define O_ACCMODE      3\r
+
+#define O_APPEND       4
+#define O_SYNC         8
+#define O_NDELAY       16
+#define O_CREAT                256
+#define O_EXCL         512
+#define O_TRUNC                1024
+#define O_NOCTTY       2048
+#define O_CLOEXEC      4096
+#define O_SYMLINK      8192    /* Not supported in kernel yet */\r
+\r
+#define FD_CLOEXEC     O_CLOEXEC
+\r
+#define O_BINARY       0       /* not used in Fuzix */\r
+\r
+#define O_NONBLOCK     O_NDELAY\r
+\r
+#define F_GETFL                0
+#define F_SETFL                1
+#define F_GETFD                2
+#define F_SETFD                3
+#define F_DUPFD                4\r
+/* Not current implemented in Fuzix */\r
+#define F_GETLK                5\r
+#define F_SETLK                6\r
+#define F_SETLKW       7\r
+\r
+typedef struct flock {\r
+   short l_type;\r
+   short l_whence;\r
+   long l_start;\r
+   long l_len;\r
+   short l_sysid;\r
+   pid_t l_pid;\r
+} flock_t;
+
+#define FNDELAY                O_NDELAY
+
+#ifndef SEEK_SET\r
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif\r
+\r
+#endif\r
+\r
diff --git a/Library/include/features.h b/Library/include/features.h
new file mode 100644 (file)
index 0000000..69bb963
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __FEATURES_H\r
+#define __FEATURES_H\r
+\r
+#ifndef __STDC__\r
+#ifdef HI_TECH_C\r
+#define __STDC__       1\r
+#endif\r
+#endif\r
+\r
+#ifdef __STDC__\r
+\r
+#ifndef VOID\r
+#define VOID   void\r
+#endif\r
+#ifndef __P\r
+#define __P(a) a\r
+#endif\r
+#define __const const\r
+\r
+#else  /* K&R */\r
+\r
+#ifndef VOID\r
+#define VOID\r
+#endif\r
+#ifndef __P\r
+#define __P(a) ()\r
+#endif\r
+#define __const\r
+#define volatile\r
+#define void   char\r
+\r
+#endif /* __STDC__ */\r
+\r
+#include <sys/cdefs.h>\r
+\r
+#endif\r
+\r
diff --git a/Library/include/float.h b/Library/include/float.h
new file mode 100644 (file)
index 0000000..92703d5
--- /dev/null
@@ -0,0 +1,79 @@
+/*-------------------------------------------------------------------------
+   float.h - ANSI functions forward declarations
+
+   Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net
+
+   This library is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License 
+   along with this library; see the file COPYING. If not, write to the
+   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.
+
+   As a special exception, if you link this library with other files,
+   some of which are compiled with SDCC, to produce an executable,
+   this library does not by itself cause the resulting executable to
+   be covered by the GNU General Public License. This exception does
+   not however invalidate any other reasons why the executable file
+   might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#ifndef __FLOAT_H
+#define __FLOAT_H 1
+
+#include <limits.h>
+
+#define FLT_RADIX       2
+#define FLT_MANT_DIG    24
+#define FLT_EPSILON     1.192092896E-07F
+#define FLT_DIG         6
+#define FLT_MIN_EXP     (-125)
+#define FLT_MIN         1.175494351E-38F
+#define FLT_MIN_10_EXP  (-37)
+#define FLT_MAX_EXP     (+128)
+#define FLT_MAX         3.402823466E+38F
+#define FLT_MAX_10_EXP  (+38)
+
+/* the following deal with IEEE single-precision numbers */
+#define EXCESS         126
+#define SIGNBIT                ((unsigned long)0x80000000)
+#define __INFINITY     ((unsigned long)0x7F800000)
+#define HIDDEN         (unsigned long)(1ul << 23)
+#define SIGN(fp)       (((unsigned long)(fp) >> (8*sizeof(fp)-1)) & 1)
+#define EXP(fp)                (((unsigned long)(fp) >> 23) & (unsigned int) 0x00FF)
+#define MANT(fp)       (((fp) & (unsigned long)0x007FFFFF) | HIDDEN)
+#define NORM            0xff000000
+#define PACK(s,e,m)    ((s) | ((unsigned long)(e) << 23) | (m))
+
+float __uchar2fs (unsigned char);
+float __schar2fs (signed char);
+float __uint2fs (unsigned int);
+float __sint2fs (signed int);
+float __ulong2fs (unsigned long);
+float __slong2fs (signed long);
+unsigned char __fs2uchar (float);
+signed char __fs2schar (float);
+unsigned int __fs2uint (float);
+signed int __fs2sint (float);
+unsigned long __fs2ulong (float);
+signed long __fs2slong (float);
+
+float __fsadd (float, float);
+float __fssub (float, float);
+float __fsmul (float, float);
+float __fsdiv (float, float);
+
+char __fslt (float, float);
+char __fseq (float, float);
+char __fsgt (float, float);
+
+#endif /* __SDC51_FLOAT_H */
+
diff --git a/Library/include/ftw.h b/Library/include/ftw.h
new file mode 100644 (file)
index 0000000..aeb1863
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _FTW_H
+#define _FTW_H
+
+#define FTW_F          0
+#define FTW_D          1
+#define FTW_DNR                2
+#define FTW_NS         3
+
+#endif
diff --git a/Library/include/fuzix.h b/Library/include/fuzix.h
new file mode 100644 (file)
index 0000000..f53c328
--- /dev/null
@@ -0,0 +1,351 @@
+#ifndef _FUZIX_H
+#define _FUZIX_H
+#include <stdlib.h>
+#include <sys/types.h>
+
+/*
+ *     FUZIX constants
+ */     
+
+#define __MAXPID 32000
+#define NSIGS  16
+
+/* Stat */
+
+#define S_IFMT         0170000
+#define S_IFSOCK       0140000         /* Reserved, not used */
+#define S_IFLNK                0120000         /* Reserved, not used */
+#define S_IFREG                0100000
+#define S_IFBLK                0060000
+#define S_IFDIR                0040000
+#define S_IFCHR                0020000
+#define S_IFIFO                0010000
+
+#define S_ISUID                0004000
+#define S_ISGID                0002000
+#define S_ISVTX                0001000         /* Reserved, not used */
+#define S_IRWXU                0000700
+#define S_IRUSR                0000400
+#define S_IWUSR                0000200
+#define S_IXUSR                0000100
+#define S_IRWXG                0000070
+#define S_IRGRP                0000040
+#define S_IWGRP                0000020
+#define S_IXGRP                0000010
+#define S_IRWXO                0000007
+#define S_IROTH                0000004
+#define S_IWOTH                0000002
+#define S_IXOTH                0000001
+
+#define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)     (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m)     (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m)     (((m) & S_IFMT) == S_IFCHR)
+#define S_ISFIFO(m)    (((m) & S_IFMT) == S_IFIFO)
+#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK)
+#define S_ISSOCK(m)    (((m) & S_IFMT) == S_IFSOCK)
+
+#define SIGHUP  1       /* hangup */
+#define SIGINT  2       /* interrupt */
+#define SIGQUIT 3       /* quit */
+#define SIGILL  4       /* illegal instruction (not reset when caught */
+#define SIGTRAP 5       /* trace trap (not reset when caught) */
+#define SIGIOT  6       /* IOT instruction */
+#define SIGEMT  7       /* EMT instruction */
+#define SIGFPE  8       /* floating point exception */
+#define SIGKILL 9       /* kill */
+#define SIGBUS  10      /* bus error */
+#define SIGSEGV 11      /* segmentation violation */
+#define SIGSYS  12      /* bad argument to system call */
+#define SIGPIPE 13      /* write on a pipe with no one to read it */
+#define SIGALRM 14      /* alarm clock */
+#define SIGTERM 15      /* software termination signal from kill */
+
+/* uadmin */
+#define A_SHUTDOWN             1
+#define A_REBOOT               2
+#define A_DUMP                 3
+#define A_FREEZE               4       /* Unimplemented, want for NC100 */
+#define A_SWAPCTL              16      /* Unimplemented */
+#define A_CONFIG               17      /* Unimplemented */
+#define A_FTRACE               18      /* Unimplemented: 
+                                          Hook to the syscall trace debug */
+#define AD_NOSYNC              1       /* Unimplemented */
+
+/* waitpid options */
+#define WNOHANG                1       /* don't support others yet */
+
+
+/* Bits 0-7 are saved, bits 8-15 are discard post open. Not all are handled
+   in the kernel yet */
+#define O_RDONLY        0
+#define O_WRONLY        1
+#define O_RDWR          2
+#define O_ACCMODE(x)   ((x) & 3)
+#define O_APPEND       4
+#define O_SYNC         8
+#define O_NDELAY       16
+#define O_CREAT                256
+#define O_EXCL         512
+#define O_TRUNC                1024
+#define O_NOCTTY       2048
+#define O_CLOEXEC      4096
+
+#define F_GETFL                0
+#define F_SETFL                1
+#define F_GETFD                2
+#define F_SETFD                3
+#define F_DUPFD                4
+
+#define FNDELAY                O_NDELAY
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+/*
+ * Error codes
+ */
+#define EPERM           1               /* Not owner */
+#define ENOENT          2               /* No such file or directory */
+#define ESRCH           3               /* No such process */
+#define EINTR           4               /* Interrupted System Call */
+#define EIO             5               /* I/O Error */
+#define ENXIO           6               /* No such device or address */
+#define E2BIG           7               /* Arg list too long */
+#define ENOEXEC         8               /* Exec format error */
+#define EBADF           9               /* Bad file number */
+#define ECHILD          10              /* No children */
+#define EAGAIN          11              /* No more processes */
+#define ENOMEM          12              /* Not enough core */
+#define EACCES          13              /* Permission denied */
+#define EFAULT          14              /* Bad address */
+#define ENOTBLK         15              /* Block device required */
+#define EBUSY           16              /* Mount device busy */
+#define EEXIST          17              /* File exists */
+#define EXDEV           18              /* Cross-device link */
+#define ENODEV          19              /* No such device */
+#define ENOTDIR         20              /* Not a directory */
+#define EISDIR          21              /* Is a directory */
+#define EINVAL          22              /* Invalid argument */
+#define ENFILE          23              /* File table overflow */
+#define EMFILE          24              /* Too many open files */
+#define ENOTTY          25              /* Not a typewriter */
+#define ETXTBSY         26              /* Text file busy */
+#define EFBIG           27              /* File too large */
+#define ENOSPC          28              /* No space left on device */
+#define ESPIPE          29              /* Illegal seek */
+#define EROFS           30              /* Read-only file system */
+#define EMLINK          31              /* Too many links */
+#define EPIPE           32              /* Broken pipe */
+
+/* math software */
+#define EDOM            33              /* Argument too large */
+#define ERANGE          34              /* Result too large */
+#define EWOULDBLOCK    35              /* Operation would block */
+#define ENOTEMPTY      36              /* Directory is not empty */
+#define ENAMETOOLONG    63              /* File name too long */
+
+/*
+ *     FUZIX structures (_xx forms for ones that don't match the POSIX
+ *     API versions)
+ */
+
+typedef struct {
+  uint16_t t_time;
+  uint16_t t_data;
+} _uzitime_t;
+
+struct _uzitms {
+  _uzitime_t tms_utime;
+  _uzitime_t tms_stime;
+  _uzitime_t tms_cutime;
+  _uzitime_t tms_cstime;
+  _uzitime_t tms_etime;
+};
+
+typedef struct {
+  uint16_t o_blkno;
+  int16_t o_offset;
+} _uzioff_t;
+
+struct  _uzistat
+{
+       int16_t    st_dev;
+       uint16_t   st_ino;
+       uint16_t   st_mode;
+       uint16_t   st_nlink;
+       uint16_t   st_uid;
+       uint16_t   st_gid;
+       uint16_t   st_rdev;
+       _uzioff_t  st_size;
+       _uzitime_t st_atime;
+       _uzitime_t st_mtime;
+       _uzitime_t st_ctime;
+};
+
+typedef void (*sighandler_t)(int);
+#define  SIG_DFL   (sighandler_t)0
+#define  SIG_IGN   (sighandler_t)1
+
+struct _uzisysinfoblk {
+  uint8_t infosize;            /* For expandability */
+  uint8_t banks;               /* Banks in our 64K (and thus pagesize) */
+  uint8_t max_open;
+  uint16_t ticks;              /* Tick rate in HZ */
+  uint16_t memk;               /* Memory in KB */
+  uint16_t usedk;              /* Used memory in KB */
+  uint16_t config;             /* Config flag mask */
+};
+
+/*
+ *     TTY interfaces - may change pending review
+ */
+
+struct tty_data {
+    char t_ispeed;
+    char t_ospeed;
+    char t_erase;
+    char t_kill;
+    int  t_flags;
+};
+
+#define TIOCGETP  0
+#define TIOCSETP  1
+#define TIOCSETN  2
+#define TIOCEXCL  3     /** currently not implemented  SN **/
+#define UARTSLOW  4     /* Normal interrupt routine (UZI280) */
+#define UARTFAST  5     /* Fast interrupt routine for modem usage (UZI280) */
+#define TIOCFLUSH 6
+#define TIOCGETC  7
+#define TIOCSETC  8
+              /* UZI280 extensions used by UZI180 in the CP/M 2.2 Emulator */
+#define TIOCTLSET 9     /* Don't parse ctrl-chars */
+#define TIOCTLRES 10    /* Normal Parse */
+
+#define XTABS   0006000
+#define RAW     0000040
+#define CRMOD   0000020
+#define ECHO    0000010
+#define LCASE   0000004
+#define CBREAK  0000002
+#define COOKED  0000000
+
+/*
+ *     Native structures that are actually created by libc not the kernel
+ */
+
+typedef unsigned long long time_t;
+typedef unsigned long clock_t;
+typedef long off_t;
+typedef uint16_t nlink_t;
+typedef int16_t dev_t;
+typedef uint16_t ino_t;
+struct tms {
+  clock_t tms_utime;
+  clock_t tms_stime;
+  clock_t tms_cutime;
+  clock_t tms_cstime;
+  clock_t tms_etime;
+};
+
+struct stat
+{
+       dev_t      st_dev;
+       ino_t      st_ino;
+       mode_t     st_mode;
+       nlink_t    st_nlink;
+       uid_t      st_uid;
+       gid_t      st_gid;
+       uint16_t   st_rdev;
+       off_t      st_size;
+       time_t     st_atime;
+       time_t     st_mtime;
+       time_t     st_ctime;
+};
+
+struct dirent
+{
+         ino_t d_ino;
+         char  d_name[30];     /* 14 currently used */
+};
+
+extern int errno;
+
+extern int _exit(int code);
+extern int open(const char *path, int flags, ...);
+extern int close(int fd);
+extern int creat(const char *path, mode_t mode);
+extern int link(const char *path, const char *path2);
+extern int unlink(const char *path);
+extern int read(int fd, char *buf, int len);
+extern int write(int fd, const char *buf, int len);
+extern int seek(int fd, int offset, int mode);
+extern int chdir(const char *path);
+extern int sync(void);
+extern int access(const char *path, int way);
+extern int chmod(const char *path, mode_t mode);
+extern int chown(const char *path, uid_t owner, gid_t group);
+extern int dup(int fd);
+extern pid_t getpid(void);
+extern pid_t getppid(void);
+extern uid_t getuid(void);
+extern mode_t umask(mode_t);
+extern int execve(const char *path, const char *argv[], const char *envp[]);
+extern pid_t wait(int *status);
+extern int setuid(uid_t uid);
+extern int setgid(gid_t gid);
+extern int ioctl(int fd, int request,...);
+extern int brk(void *addr);
+extern void *sbrk(intptr_t increment);
+extern pid_t fork(void);
+extern int mount(const char *dev, const char *path, int flags);
+extern int umount(const char *dev);
+extern int signal(int signum, sighandler_t sighandler);
+extern int dup2(int oldfd, int newfd);
+extern int pause(void);
+extern int kill(pid_t pid, int sig);
+extern int pipe(int *pipefds);
+extern gid_t getgid(void);
+extern uid_t geteuid(void);
+extern gid_t getegid(void);
+extern int chroot(const char *path);
+extern int fcntl(int fd, int cmd, ...);
+extern int fchdir(int fd);
+extern int fchmod(int fd, mode_t mode);
+extern int fchown(int fd, uid_t owner, gid_t group);
+extern int mkdir(const char *path);
+extern int rmdir(const char *path);
+extern pid_t setpgrp(void);
+extern int waitpid(pid_t pid, int *status, int options);
+extern int uadmin(int cmd, int ctrl, void *ptr);
+extern int nice(int prio);
+extern int rename(const char *path, const char *newpath);
+
+/* asm syscall hooks with C wrappers */
+extern int _getdirent(int fd, void *buf, int len);
+extern int _stat(const char *path, struct _uzistat *s);
+extern int _fstat(int fd, struct _uzistat *s);
+extern int _getfsys(int dev, char *buf);
+extern int _time(_uzitime_t *t);
+extern int _stime(const _uzitime_t *t);
+extern int _alarm(int16_t decisecs);
+extern int _times(struct _uzitms *t);
+extern int _utime(const char *file, _uzitime_t *buf);
+extern int _uname(struct _uzisysinfoblk *uzib);
+extern int _profil(void *samples, uint16_t offset, uint16_t size, int16_t scale);
+
+/* C library provided syscall emulation */
+extern int stat(const char *path, struct stat *s);
+extern int fstat(int fd, struct stat *s);
+extern int alarm(uint16_t seconds);
+extern time_t time(time_t *t);
+extern int stime(time_t *t);
+extern int times(struct tms *tms);
+extern int utime(const char *filename, const struct utimbuf *utim);
+extern int uname(struct utsname *buf);
+extern int profil(unsigned short *bufbase, size_t bufsize, unsigned long offset,
+                  unsigned int scale);
+
+#endif
diff --git a/Library/include/getopt.h b/Library/include/getopt.h
new file mode 100644 (file)
index 0000000..9130285
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __GETOPT_H\r
+#define __GETOPT_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+extern char *optarg;\r
+extern int opterr;\r
+extern int optind;\r
+\r
+extern int getopt __P((int argc, char **argv, char *shortopts));\r
+\r
+#endif /* __GETOPT_H */\r
diff --git a/Library/include/grp.h b/Library/include/grp.h
new file mode 100644 (file)
index 0000000..a7f58ea
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __GRP_H\r
+#define __GRP_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <stdio.h>\r
+\r
+#define GR_MAX_GROUPS  32\r
+#define GR_MAX_MEMBERS 16\r
+\r
+/* The group structure */\r
+struct group {\r
+       char    *gr_name;       /* Group name.  */\r
+       char    *gr_passwd;     /* Password.    */\r
+       int     gr_gid;         /* Group ID.    */\r
+       char    **gr_mem;       /* Member list. */\r
+};\r
+\r
+extern void setgrent __P((void));\r
+extern void endgrent __P((void));\r
+extern struct group *getgrent __P((void));\r
+\r
+extern struct group *getgrgid __P((const gid_t gid));\r
+extern struct group *getgrnam __P((char * name));\r
+\r
+extern struct group * fgetgrent __P((FILE * file));\r
+\r
+extern int setgroups __P((size_t n, int *groups));\r
+extern int initgroups __P((const char * user, gid_t gid));\r
+\r
+extern struct group * __getgrent __P((int grp_fd));\r
+\r
+extern char *_path_group;\r
+\r
+#endif /* _GRP_H */\r
diff --git a/Library/include/limits.h b/Library/include/limits.h
new file mode 100644 (file)
index 0000000..8f6f5c8
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __LIMITS_H\r
+#define __LIMITS_H\r
+\r
+#define CHAR_MAX       127             /* maximum char value */\r
+#define CHAR_MIN       (-127)          /* mimimum char value */\r
+#define SCHAR_MAX      127             /* maximum signed char value */\r
+#define SCHAR_MIN      (-127)          /* minimum signed char value */\r
+#define CHAR_BIT       8               /* number of bits in a char */\r
+\r
+#define SHRT_MAX       32767           /* maximum (signed) short value */\r
+#define SHRT_MIN       (-32767)        /* minimum (signed) short value */\r
+#define INT_MAX        32767           /* maximum (signed) int value */\r
+#define INT_MIN        (-32767)        /* minimum (signed) int value */\r
+\r
+#define LONG_MAX       2147483647      /* maximum (signed) long value */\r
+#define LONG_MIN       (-2147483647)   /* minimum (signed) long value */\r
+\r
+#define UCHAR_MAX      255             /* maximum unsigned char value */\r
+#define USHRT_MAX      0xffff          /* maximum unsigned short value */\r
+#define UINT_MAX       0xffff          /* maximum unsigned int value */\r
+#define ULONG_MAX      0xffffffff      /* maximum unsigned long value */\r
+\r
+#ifndef RAND_MAX\r
+#define RAND_MAX       INT_MAX\r
+#endif\r
+#endif\r
+\r
+#endif\r
diff --git a/Library/include/malloc.h b/Library/include/malloc.h
new file mode 100644 (file)
index 0000000..9bd901c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __MALLOC_H\r
+#define __MALLOC_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+extern void free __P((void *));\r
+extern void *malloc __P((size_t));\r
+extern void *realloc __P((void *, size_t));\r
+extern void *calloc __P((size_t, size_t));\r
+extern void *alloca __P((size_t));\r
+\r
+#endif\r
diff --git a/Library/include/math.h b/Library/include/math.h
new file mode 100644 (file)
index 0000000..5ad0f60
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+ */\r
+\r
+#ifndef _MATH_H\r
+#define _MATH_H\r
+\r
+extern double fabs(double);\r
+extern double floor(double);\r
+extern double ceil(double);\r
+extern double modf(double, double *);\r
+extern double frexp(double, int *);\r
+extern double ldexp(double, int);\r
+extern double atof(char *);\r
+\r
+extern double sqrt(double);\r
+\r
+extern double sin(double);\r
+extern double cos(double);\r
+extern double tan(double);\r
+extern double asin(double);\r
+extern double acos(double);\r
+extern double atan(double);\r
+extern double atan2(double, double);\r
+extern double sinh(double);\r
+extern double cosh(double);\r
+extern double tanh(double);\r
+\r
+extern double log(double);\r
+extern double log10(double);\r
+extern double pow(double, double);\r
+extern double exp(double);\r
+\r
+extern double eval_poly(double, double *, int);\r
+#endif\r
diff --git a/Library/include/memory.h b/Library/include/memory.h
new file mode 100644 (file)
index 0000000..05041a2
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef __STRING_H\r
+#include <string.h>\r
+#endif\r
diff --git a/Library/include/ncurses.h b/Library/include/ncurses.h
new file mode 100644 (file)
index 0000000..5e275b7
--- /dev/null
@@ -0,0 +1,7 @@
+/*\r
+   ncurses.h\r
+   \r
+   just a fake - equal to curses.h\r
+*/\r
+\r
+#include <curses.h>
\ No newline at end of file
diff --git a/Library/include/paths.h b/Library/include/paths.h
new file mode 100644 (file)
index 0000000..f30ccc6
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __PATHS_H\r
+#define __PATHS_H\r
+\r
+#define _PATH_DEV      "/dev/"\r
+#define _PATH_DEVNULL  "/dev/null"\r
+#define _PATH_CONSOLE  "/dev/console"\r
+#define _PATH_TTY      "/dev/tty"\r
+\r
+#define _PATH_TMP      "/tmp/"\r
+#define _PATH_UTMP     "/var/run/utmp"\r
+\r
+#define _PATH_INIT     "/bin/init"\r
+#define _PATH_LOGIN    "/bin/login"\r
+#define _PATH_BSHELL   "/bin/sh"\r
+#define _PATH_DEFPATH  ".:/bin:/usr/bin:/etc:/usr/local/bin"\r
+\r
+#define _PATH_LIBERR   "/usr/lib/liberror.txt"\r
+\r
+#define _PATH_TERMCAP  "/etc/termcap"\r
+#define _PATH_PASSWD   "/etc/passwd"\r
+#define _PATH_GROUP    "/etc/group"\r
+\r
+#define _PATH_HOME     "/home"\r
+\r
+#define _PATH_HOSTNAME "/etc/hostname"\r
+\r
+#endif /* __PATHS_H */\r
diff --git a/Library/include/poll.h b/Library/include/poll.h
new file mode 100644 (file)
index 0000000..3eff11a
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _POLL_H
+#define _POLL_H
+
+struct pollfd {
+  int fd;
+  short events
+  short revents;
+};
+
+#define POLLIN         0x0001
+#define POLLPRI                0x0002
+#define POLLOUT                0x0004
+#define POLLERR                0x0008
+#define POLLHUP                0x0010
+#define POLLNVAL       0x0020
+
+#endif
diff --git a/Library/include/pwd.h b/Library/include/pwd.h
new file mode 100644 (file)
index 0000000..e6396e1
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __PWD_H\r
+#define __PWD_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <stdio.h>\r
+\r
+/* The passwd structure.  */\r
+struct passwd {\r
+       char    *pw_name;       /* Username */\r
+       char    *pw_passwd;     /* Password */\r
+       uid_t   pw_uid;         /* User ID */\r
+       gid_t   pw_gid;         /* Group ID */\r
+       char    *pw_gecos;      /* Real name */\r
+       char    *pw_dir;        /* Home directory */\r
+       char    *pw_shell;      /* Shell program */\r
+};\r
+\r
+extern void setpwent __P((void));\r
+extern void endpwent __P((void));\r
+extern struct passwd *getpwent __P((void));\r
+\r
+extern int putpwent __P((struct passwd * __p, FILE * __f));\r
+extern int getpw __P((uid_t uid, char *buf));\r
+\r
+extern struct passwd *fgetpwent __P((FILE * file));\r
+\r
+extern struct passwd *getpwuid __P((uid_t __uid));\r
+extern struct passwd *getpwnam __P((char *));\r
+\r
+extern struct passwd * __getpwent __P((int passwd_fd));\r
+\r
+extern char *_path_passwd;\r
+\r
+#define getlogin()     getpwnam(getuid())\r
+\r
+#endif /* pwd.h  */\r
diff --git a/Library/include/regexp.h b/Library/include/regexp.h
new file mode 100644 (file)
index 0000000..263b90a
--- /dev/null
@@ -0,0 +1,27 @@
+/*\r
+ * Definitions etc. for regexp(3) routines.\r
+ *\r
+ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],\r
+ * not the System V one.\r
+ */\r
+#ifndef __REGEXP_H\r
+#define __REGEXP_H\r
+\r
+#define NSUBEXP  10\r
+\r
+typedef struct regexp {\r
+       char    *startp[NSUBEXP];\r
+       char    *endp[NSUBEXP];\r
+       char    regstart;       /* Internal use only. */\r
+       char    reganch;        /* Internal use only. */\r
+       char    *regmust;       /* Internal use only. */\r
+       int     regmlen;        /* Internal use only. */\r
+       char    program[1];     /* Unwarranted chumminess with compiler. */\r
+} regexp;\r
+\r
+extern regexp *regcomp __P((char *));\r
+extern int regexec __P((regexp *prog, char *string));\r
+extern void regsub __P((regexp *prog, char *source, char *dest));\r
+extern void regerror __P((char *));\r
+\r
+#endif\r
diff --git a/Library/include/regmagic.h b/Library/include/regmagic.h
new file mode 100644 (file)
index 0000000..7fd76a5
--- /dev/null
@@ -0,0 +1,5 @@
+/*\r
+ * The first byte of the regexp internal "program" is actually this magic\r
+ * number; the start node begins in the second byte.\r
+ */\r
+#define MAGIC  0234\r
diff --git a/Library/include/search.h b/Library/include/search.h
new file mode 100644 (file)
index 0000000..fbe8228
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __SEARCH_H\r
+#define __SEARCH_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <stddef.h>\r
+\r
+#ifndef __COMPAR_FN_T\r
+#define __COMPAR_FN_T\r
+typedef int (*__compar_fn_t) __P((__ptr_t, __ptr_t));\r
+#endif\r
+\r
+/* for use with hsearch(3) */\r
+\r
+typedef struct entry { char *key; char *data; } ENTRY;\r
+typedef enum { FIND, ENTER } ACTION;\r
+\r
+extern ENTRY * hsearch __P((ENTRY __item, ACTION __action));\r
+extern int     hcreate __P((unsigned __nel));\r
+extern void    hdestroy __P((void));\r
+\r
+/* The tsearch routines are very interesting. They make many\r
+ * assumptions about the compiler. It assumpts that the first field\r
+ * in node must be the "key" field, which points to the datum.\r
+ * Everything depends on that. It is a very tricky stuff. H.J.\r
+ */\r
+/* For tsearch */\r
+typedef enum { preorder, postorder, endorder, leaf } VISIT;\r
+\r
+extern void *tsearch __P((void *__key, void **__rootp, __compar_fn_t compar));\r
+\r
+extern void *tfind __P((void *__key, void ** __rootp, __compar_fn_t compar));\r
+\r
+extern void *tdelete __P((void * __key, void ** __rootp, __compar_fn_t compar));\r
+\r
+#ifndef __ACTION_FN_T\r
+#define __ACTION_FN_T\r
+/* FYI, the first argument should be a pointer to "key".\r
+ * Please read the man page for details.\r
+ */\r
+typedef void (*__action_fn_t) __P((void *__nodep, VISIT __value, int __level));\r
+#endif\r
+\r
+extern void twalk __P((void * __root, __action_fn_t action));\r
+\r
+\r
+extern void * lfind __P((void * __key, void * __base,\r
+                        size_t * __nmemb, size_t __size,\r
+                        __compar_fn_t __compar));\r
+\r
+extern void * lsearch __P((void * __key, void * __base,\r
+                        size_t * __nmemb, size_t __size,\r
+                        __compar_fn_t __compar));\r
+\r
+#endif /* search.h */\r
diff --git a/Library/include/setjmp.h b/Library/include/setjmp.h
new file mode 100644 (file)
index 0000000..e1a3deb
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __SETJMP_H\r
+#define __SETJMP_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+/* FIXME: need to add alt registers */\r
+typedef int jmp_buf[7];\r
+\r
+int setjmp __P((jmp_buf env));\r
+void longjmp __P((jmp_buf env, int rv));\r
+\r
+#endif\r
diff --git a/Library/include/sgtty.h b/Library/include/sgtty.h
new file mode 100644 (file)
index 0000000..3b44eb5
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _SGTTY_H
+#define _SGTTY_H
+
+/* FIXME: should go away to be replaced with termios */
+#define TIOCGETP 0
+#define TIOCSETP 1
+#define TIOCSETN  2
+/**
+#define TIOCEXCL  3
+#define TIOCNXCL  4
+#define TIOCHPCL  5
+**/
+#define TIOCFLUSH 6
+#define TIOCGETC  7
+#define TIOCSETC  8
+#define TIOCTLSET 9
+#define TIOCTLRES 10
+
+#define XTABS  0006000
+#define RAW    0000040
+#define CRMOD   0000020
+#define CRLF   0000020
+#define ECHO   0000010
+#define LCASE  0000004
+#define CBREAK 0000002
+#define COOKED  0000000
+
+
+struct sgttyb {
+       char sg_ispeed, sg_ospeed;
+       char sg_erase, sg_kill;
+       int sg_flags;
+};
+
+struct tchars {
+       char    t_intrc,t_quit,t_start,t_stop,t_eof;
+};
+
+#define stty( fd, s)   (ioctl(fd, TIOCSETP, s))
+#define gtty( fd, s)   (ioctl(fd, TIOCGETP, s))
+
+#endif
diff --git a/Library/include/signal.h b/Library/include/signal.h
new file mode 100644 (file)
index 0000000..b14babc
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __SIGNAL_H
+#define __SIGNAL_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+
+#define NSIGS    32      /* Number of signals <= 32 */
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* signals values */
+typedef enum {
+       __NOTASIGNAL = 0,
+       _SIGLAST = 30000
+} signal_t;
+
+#define sigmask(sig) (1UL<<((sig)-1))  /* signal mask */
+
+typedef uint32_t sigset_t;     /* at least 16 bits: use 32 in user space */
+                               /* for expansion space */
+/* Type of a signal handler.  */
+typedef void (*sighandler_t) __P((signal_t));
+
+#define SIG_DFL ((sighandler_t)0)      /* default signal handling */
+#define SIG_IGN ((sighandler_t)1)      /* ignore signal */
+#define SIG_HOLD ((sighandler_t)2)     /* hold signal */
+#define SIG_ERR ((sighandler_t)-1)     /* error return from signal */
+
+extern char *sys_siglist[];
+
+extern void sighold(int sig);
+extern void sigrelse(int sig);
+extern void sigignore(int sig);
+extern sighandler_t sigset(int sig, sighandler_t disp);
+
+#endif
diff --git a/Library/include/stdio.h b/Library/include/stdio.h
new file mode 100644 (file)
index 0000000..ad92517
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef __STDIO_H\r
+#define __STDIO_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <stdarg.h>\r
+\r
+#define BUFSIZE        512     /* uzix buffer/block size */\r
+#define BUFSIZELOG     9       /* uzix buffer/block size log2 */\r
+#define BUFSIZ         256\r
+#define PATHLEN        512\r
+\r
+#ifndef SEEK_SET\r
+#define SEEK_SET 0\r
+#define SEEK_CUR 1\r
+#define SEEK_END 2\r
+#endif\r
+\r
+#define _IOFBF         0x00    /* full buffering */\r
+#define _IOLBF         0x01    /* line buffering */\r
+#define _IONBF         0x02    /* no buffering */\r
+#define __MODE_BUF     0x03    /* Modal buffering dependent on isatty */\r
+\r
+#define __MODE_FREEBUF 0x04    /* Buffer allocated with malloc, can free */\r
+#define __MODE_FREEFIL 0x08    /* FILE allocated with malloc, can free */\r
+\r
+#define __MODE_READ    0x10    /* Opened in read only */\r
+#define __MODE_WRITE   0x20    /* Opened in write only */\r
+#define __MODE_RDWR    0x30    /* Opened in read/write */\r
+\r
+#define __MODE_READING 0x40    /* Buffer has pending read data */\r
+#define __MODE_WRITING 0x80    /* Buffer has pending write data */\r
+\r
+#define __MODE_EOF     0x100   /* EOF status */\r
+#define __MODE_ERR     0x200   /* Error status */\r
+#define __MODE_UNGOT   0x400   /* Buffer has been polluted by ungetc */\r
+\r
+#define __MODE_IOTRAN  0\r
+\r
+typedef off_t fpos_t;\r
+/* when you add or change fields here, be sure to change the initialization\r
+ * in stdio_init and fopen */\r
+struct __stdio_file {\r
+       uchar   *bufpos;        /* the next byte to write to or read from */\r
+       uchar   *bufread;       /* the end of data returned by last read() */\r
+       uchar   *bufwrite;      /* highest address writable by macro */\r
+       uchar   *bufstart;      /* the start of the buffer */\r
+       uchar   *bufend;        /* the end of the buffer; ie the byte after\r
+                                  the last malloc()ed byte */\r
+       int     fd;             /* the file descriptor associated with the stream */\r
+       int     mode;\r
+       char    unbuf[8];       /* The buffer for 'unbuffered' streams */\r
+       struct __stdio_file * next;\r
+};\r
+\r
+#define EOF    (-1)\r
+#ifndef NULL\r
+#define NULL   (0)\r
+#endif\r
+\r
+typedef struct __stdio_file FILE;\r
+\r
+extern FILE stdin[1];\r
+extern FILE stdout[1];\r
+extern FILE stderr[1];\r
+\r
+#define putc(c, stream) \\r
+       (((stream)->bufpos >= (stream)->bufwrite) ? \\r
+               fputc((c), (stream)) : \\r
+               (uchar) (*(stream)->bufpos++ = (c)))\r
+#define getc(stream)   \\r
+       (((stream)->bufpos >= (stream)->bufread) ? \\r
+               fgetc(stream) : \\r
+               (*(stream)->bufpos++))\r
+\r
+#define putchar(c)     putc((c), stdout)\r
+#define getchar()      getc(stdin)\r
+\r
+extern char *gets __P((char *));\r
+\r
+extern int _putchar __P((int));\r
+extern int _getchar __P((void));\r
+\r
+#define ferror(fp)     (((fp)->mode&__MODE_ERR) != 0)\r
+#define feof(fp)       (((fp)->mode&__MODE_EOF) != 0)\r
+#define clearerr(fp)   ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR))\r
+#define fileno(fp)     ((fp)->fd)\r
+\r
+/* These two call malloc */\r
+extern int setvbuf __P((FILE*, char*, int, size_t));\r
+#define setlinebuf(__fp)       setvbuf((__fp), (char*)0, _IOLBF, 0)\r
+\r
+/* These don't */\r
+extern void setbuffer __P((FILE*, char*, size_t));\r
+#define setbuf(__fp, __buf)    setbuffer((__fp), (__buf), BUFSIZ)\r
+\r
+extern int fgetc __P((FILE*));\r
+extern int fputc __P((int, FILE*));\r
+extern int ungetc __P((int, FILE*));\r
+\r
+extern int fclose __P((FILE*));\r
+extern int fflush __P((FILE*));\r
+#define stdio_pending(fp) ((fp)->bufread > (fp)->bufpos)\r
+extern char *fgets __P((char*, size_t, FILE*));\r
+extern FILE *__fopen __P((const char*, int, FILE*, const char*));\r
+\r
+#define fopen(__file, __mode)        __fopen((__file), -1, (FILE*)0, (__mode))\r
+#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode))\r
+#define fdopen(__file, __mode) __fopen((char*)0, (__file), (FILE*)0, (__mode))\r
+\r
+extern int fputs __P((const void *, FILE*));\r
+extern int puts __P((const void *));\r
+\r
+extern int fread __P((void *, size_t, size_t, FILE *));\r
+extern int fwrite __P((const void *, size_t, size_t, FILE *));\r
+\r
+extern int fseek __P((FILE *fp, long offset, int whence));\r
+extern long ftell __P((FILE *fp));\r
+#define fseeko fseek\r
+#define ftello  ftell\r
+\r
+extern int fgetpos __P((FILE *fp, fpos_t *pos));\r
+extern int fsetpos __P((FILE *fp, fpos_t *pos));\r
+\r
+extern int printf __P((const char*, ...));\r
+extern int fprintf __P((FILE*, const char*, ...));\r
+extern int sprintf __P((char*, const char*, ...));\r
+\r
+extern int vprintf __P((const char*, va_list));\r
+extern int vfprintf __P((FILE*, const char*, va_list));\r
+extern int vsprintf __P((char*, const char*, va_list));\r
+\r
+extern int scanf __P((const char*, ...));\r
+extern int fscanf __P((FILE*, const char*, ...));\r
+extern int sscanf __P((char*, const char*, ...));\r
+\r
+extern int vscanf __P((const char*, va_list));\r
+extern int vfscanf __P((FILE*, const char*, va_list));\r
+extern int vsscanf __P((char*, const char*, va_list));\r
+\r
+extern void perror __P((const char *__s));\r
+extern char *strerror __P((int __errno));\r
+\r
+extern char *tmpnam __P((char *buf));\r
+\r
+extern int rename __P((const char *oldname, const char *newname));\r
+extern void rewind __P((FILE *fp));\r
+extern FILE *popen __P((const char *, const char *));\r
+extern int pclose __P((FILE *));\r
+\r
+#endif /* __STDIO_H */\r
diff --git a/Library/include/stdlib.h b/Library/include/stdlib.h
new file mode 100644 (file)
index 0000000..0b5e538
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __STDLIB_H\r
+#define __STDLIB_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <malloc.h>\r
+#include <syscalls.h>\r
+\r
+/* Don't overwrite user definitions of NULL */\r
+#ifndef NULL\r
+#define NULL ((void *) 0)\r
+#endif\r
+\r
+/* Returned by `div' */\r
+typedef struct {\r
+       int     quot;           /* Quotient */\r
+       int     rem;            /* Remainder */\r
+} div_t;\r
+\r
+/* Returned by `ldiv' */\r
+typedef struct {\r
+       long int quot;          /* Quotient */\r
+       long int rem;           /* Remainder */\r
+} ldiv_t;\r
+\r
+/* For program termination */\r
+#define EXIT_FAILURE 1\r
+#define EXIT_SUCCESS 0\r
+\r
+extern void exit __P((int));\r
+extern void abort __P((void));\r
+\r
+\r
+extern int rand __P((void));\r
+extern void srand __P((uint seed));\r
+\r
+extern char *__longtoa __P((unsigned long, char *, int, char, char));\r
+extern char *itoa __P((int value, char *strP, int radix));\r
+extern char *ultoa __P((unsigned long value, char *strP, int radix));\r
+extern char *ltoa __P((long value, char *strP, int radix));\r
+\r
+extern int atoi __P((char *str));\r
+extern long atol __P((char *strP));\r
+\r
+extern char *_itoa __P((int value));\r
+extern char *_ltoa __P((long value));\r
+extern char *_ultoa __P((unsigned long value));\r
+\r
+extern char *ultostr __P((unsigned long value, int radix));\r
+extern char *ltostr __P((long value, int radix));\r
+\r
+extern long strtol __P ((const char * nptr, char ** endptr, int base));\r
+extern unsigned long strtoul __P ((const char * nptr,\r
+                                  char ** endptr, int base));\r
+#ifndef __HAS_NO_DOUBLES__\r
+extern double strtod __P ((const char * nptr, char ** endptr));\r
+#endif\r
+\r
+extern char **environ;\r
+extern char *getenv __P((char *));\r
+extern int putenv __P((char *));\r
+extern int setenv __P((char *, char *, int));\r
+extern void unsetenv __P((char *));\r
+\r
+typedef void (*atexit_t) __P((int));\r
+typedef void (*onexit_t) __P((int, void *));\r
+extern int atexit __P((atexit_t));\r
+extern int on_exit __P((onexit_t, void *arg));\r
+extern onexit_t __cleanup;\r
+\r
+extern char *crypt __P((char *__key, char *__salt));\r
+\r
+typedef int (*cmp_func_t) __P((void *, void *));\r
+\r
+extern int _bsearch;\r
+extern void *bsearch __P((void *key, void *base, size_t num, size_t size, cmp_func_t cmp));\r
+extern void *lfind __P((void *key, void *base, size_t *num, size_t size, cmp_func_t cmp));\r
+extern void *lsearch __P((void *key, void *base, size_t *num, size_t size, cmp_func_t cmp));\r
+extern void *_qbuf;\r
+extern void qsort __P((void *base, size_t num, size_t size, cmp_func_t cmp));\r
+\r
+extern int opterr;\r
+extern int optind;\r
+extern char *optarg;\r
+extern int getopt __P((int argc, char *argv[], char *optstring));\r
+\r
+extern char *getpass(char *prompt);\r
+\r
+extern int _argc;\r
+extern char **_argv;\r
+\r
+#endif /* __STDLIB_H */\r
diff --git a/Library/include/string.h b/Library/include/string.h
new file mode 100644 (file)
index 0000000..80dc92a
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __STRING_H
+#define __STRING_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+#include <stddef.h>
+
+/* Basic string functions */
+extern size_t strlen __P ((const char* __str));
+
+extern char * strcat __P ((char*, const char*));
+extern char * strcpy __P ((char*, const char*));
+extern int strcmp __P ((const char*, const char*));
+
+extern char * strncat __P ((const char*, const char*, size_t));
+extern char * strncpy __P ((const char*, const char*, size_t));
+extern int strncmp __P((const char*, const char*, size_t));
+
+extern int stricmp __P((const char*, const char*));
+extern strnicmp __P((const char*, const char*, size_t));
+
+extern int strcasecmp __P((const char*, const char*));
+extern strncasecmp __P((const char*, const char*, size_t));
+
+extern char * strchr __P ((const char*, int));
+extern char * strrchr __P ((const char*, int));
+extern char * strdup __P ((const char*));
+
+/* Basic mem functions */
+extern void * memcpy __P ((void*, const void*, size_t));
+extern void * memccpy __P ((void*, const void*, int, size_t));
+extern void * memchr __P ((const void*, int, size_t));
+extern void * memset __P ((void*, int, size_t));
+extern int memcmp __P ((const void*, const void*, size_t));
+
+extern void * memmove __P ((void*, const void*, size_t));
+
+/* BSDisms */
+extern char *index __P ((const char *, int));
+extern char *rindex __P ((const char *, int));
+extern void bcopy __P ((const void*, void*, size_t));
+
+/* Othe common BSD functions */
+extern char *strpbrk __P ((const char *, const char *));
+extern char *strsep __P ((char **, const char *));
+extern char *strstr __P ((const char *, const char *));
+extern char *strtok __P ((char *, const char *));
+extern size_t strcspn __P ((const char *, const char *));
+extern size_t strspn __P ((const char *, const char *));
+
+#ifdef z80
+#pagma inline(memcpy)
+#pagma inline(memset)
+#pagma inline(strcpy)
+#pagma inline(strlen)
+#pagma inline(strcmp)
+#endif
+
+#endif         /* END OF DEFINITION    STRING.H */
diff --git a/Library/include/strings.h b/Library/include/strings.h
new file mode 100644 (file)
index 0000000..05041a2
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef __STRING_H\r
+#include <string.h>\r
+#endif\r
diff --git a/Library/include/sys/cdefs.h b/Library/include/sys/cdefs.h
new file mode 100755 (executable)
index 0000000..d5e0795
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _SYS_CDEFS_H\r
+#define _SYS_CDEFS_H\r
+#ifndef __FEATURES_H\r
+#include <features.h>\r
+#endif\r
+\r
+#ifdef __STDC__\r
+#define __CONCAT(x,y)  x ## y\r
+#define __STRING(x)    #x\r
+#else\r
+#define __CONCAT(x,y)  x/**/y\r
+#define __STRING(x)    #x\r
+#endif /* __STDC__ */\r
+\r
+/* This is not a typedef so `const __ptr_t' does the right thing */\r
+/* For K&R 'void' defined as 'char' */\r
+#define __ptr_t void *\r
+\r
+#endif\r
+\r
diff --git a/Library/include/sys/errno.h b/Library/include/sys/errno.h
new file mode 100644 (file)
index 0000000..08b226c
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __ERRNO_H
+#define __ERRNO_H
+
+#include <features.h>
+
+/*
+ * Error codes
+ */
+#define EPERM           1               /* Not owner */
+#define ENOENT          2               /* No such file or directory */
+#define ESRCH           3               /* No such process */
+#define EINTR           4               /* Interrupted System Call */
+#define EIO             5               /* I/O Error */
+#define ENXIO           6               /* No such device or address */
+#define E2BIG           7               /* Arg list too long */
+#define ENOEXEC         8               /* Exec format error */
+#define EBADF           9               /* Bad file number */
+#define ECHILD          10              /* No children */
+#define EAGAIN          11              /* No more processes */
+#define ENOMEM          12              /* Not enough core */
+#define EACCES          13              /* Permission denied */
+#define EFAULT          14              /* Bad address */
+#define ENOTBLK         15              /* Block device required */
+#define EBUSY           16              /* Mount device busy */
+#define EEXIST          17              /* File exists */
+#define EXDEV           18              /* Cross-device link */
+#define ENODEV          19              /* No such device */
+#define ENOTDIR         20              /* Not a directory */
+#define EISDIR          21              /* Is a directory */
+#define EINVAL          22              /* Invalid argument */
+#define ENFILE          23              /* File table overflow */
+#define EMFILE          24              /* Too many open files */
+#define ENOTTY          25              /* Not a typewriter */
+#define ETXTBSY         26              /* Text file busy */
+#define EFBIG           27              /* File too large */
+#define ENOSPC          28              /* No space left on device */
+#define ESPIPE          29              /* Illegal seek */
+#define EROFS           30              /* Read-only file system */
+#define EMLINK          31              /* Too many links */
+#define EPIPE           32              /* Broken pipe */
+
+/* math software */
+#define EDOM            33              /* Argument too large */
+#define ERANGE          34              /* Result too large */
+#define EWOULDBLOCK    35              /* Operation would block */
+#define ENOTEMPTY      36              /* Directory is not empty */
+#define ENAMETOOLONG    63              /* File name too long */
+
+extern int     errno;
+
+__BEGIN_DECLS
+
+extern void    perror(__const char* __s);
+extern char*   strerror(int __errno);
+
+__END_DECLS
+
+#endif
diff --git a/Library/include/sys/exec.h b/Library/include/sys/exec.h
new file mode 100755 (executable)
index 0000000..e96f948
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _SYS_EXEC_H\r
+#define _SYS_EXEC_H\r
+\r
+#endif\r
diff --git a/Library/include/sys/file.h b/Library/include/sys/file.h
new file mode 100644 (file)
index 0000000..89ad33d
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _SYS_FILE_H
+#define _SYS_FILE_H
+
+#include <features.h>
+#include <fcntl.h>
+
+#ifndef L_SET
+
+#define L_SET           0       /* absolute offset */
+#define L_INCR          1       /* relative to current offset */
+#define L_XTND          2       /* relative to end of file */
+
+#endif
+
+#endif
diff --git a/Library/include/sys/fp.h b/Library/include/sys/fp.h
new file mode 100644 (file)
index 0000000..79f9fb0
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _SYS_FP_H
+#define _SYS_FP_H
+
+#define FP_NO  0
+#define FP_SW  1
+#define FP_HW  2
+
+#endif
diff --git a/Library/include/sys/ioctl.h b/Library/include/sys/ioctl.h
new file mode 100755 (executable)
index 0000000..53f7bc0
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef _SYS_IOCTL_H\r
+#define _SYS_IOCTL_H\r
+\r
+#endif\r
+\r
diff --git a/Library/include/sys/lock.h b/Library/include/sys/lock.h
new file mode 100644 (file)
index 0000000..5723bb3
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _SYS_LOCK_H
+#define _SYS_LOCK_H
+
+/* Not provided by Fuzix */
+
+#endif
\ No newline at end of file
diff --git a/Library/include/sys/mman.h b/Library/include/sys/mman.h
new file mode 100644 (file)
index 0000000..3656d6b
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __SYS_MMAN_H
+#define __SYS_MMAN_H
+#include <features.h>
+
+/* Nothing here for now */
+
+#endif
diff --git a/Library/include/sys/mount.h b/Library/include/sys/mount.h
new file mode 100644 (file)
index 0000000..2b70279
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _SYS_MOUNT_H
+#define _SYS_MOUNT_H
+
+/* Not yet implemented */
+#define MS_RDONLY      0x01
+
+#endif
diff --git a/Library/include/sys/param.h b/Library/include/sys/param.h
new file mode 100644 (file)
index 0000000..8572e02
--- /dev/null
@@ -0,0 +1,14 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#ifndef _PARAM_H
+#define _PARAM_H
+
+#include <limits.h>
+
+/* Historically defined NR_OPEN/NR_FILE, but processes should use
+   sysconf */
+
+#endif
diff --git a/Library/include/sys/resource.h b/Library/include/sys/resource.h
new file mode 100644 (file)
index 0000000..fba82e9
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __SYS_RESOURCE_H
+#define __SYS_RESOURCE_H
+#include <features.h>
+
+/* No rusage on Fuzix yet */
+
+#endif
diff --git a/Library/include/sys/seek.h b/Library/include/sys/seek.h
new file mode 100755 (executable)
index 0000000..94e2d57
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _SYS_SEEK_H\r
+#define _SYS_SEEK_H\r
+\r
+#ifndef SEEK_OSET\r
+#define SEEK_OSET 0\r
+#define SEEK_OCUR 1\r
+#define SEEK_OEND 2\r
+#define SEEK_BSET 3\r
+#define SEEK_BCUR 4\r
+#define SEEK_BEND 5\r
+#endif\r
+\r
+#ifndef SEEK_SET\r
+#define SEEK_SET 0\r
+#define SEEK_CUR 1\r
+#define SEEK_END 2\r
+#endif\r
+\r
+#endif /* __SEEK_H */\r
diff --git a/Library/include/sys/signal.h b/Library/include/sys/signal.h
new file mode 100644 (file)
index 0000000..2e602da
--- /dev/null
@@ -0,0 +1 @@
+#include <signal.h>
diff --git a/Library/include/sys/stat.h b/Library/include/sys/stat.h
new file mode 100755 (executable)
index 0000000..6edf730
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <sys/types.h>
+
+/* Stat */
+
+#define S_IFMT         0170000
+#define S_IFSOCK       0140000         /* Reserved, not used */
+#define S_IFLNK                0120000         /* Reserved, not used */
+#define S_IFREG                0100000
+#define S_IFBLK                0060000
+#define S_IFDIR                0040000
+#define S_IFCHR                0020000
+#define S_IFIFO                0010000
+
+#define S_ISUID                0004000
+#define S_ISGID                0002000
+#define S_ISVTX                0001000         /* Reserved, not used */
+#define S_IRWXU                0000700
+#define S_IRUSR                0000400
+#define S_IWUSR                0000200
+#define S_IXUSR                0000100
+#define S_IRWXG                0000070
+#define S_IRGRP                0000040
+#define S_IWGRP                0000020
+#define S_IXGRP                0000010
+#define S_IRWXO                0000007
+#define S_IROTH                0000004
+#define S_IWOTH                0000002
+#define S_IXOTH                0000001
+
+#define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)     (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m)     (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m)     (((m) & S_IFMT) == S_IFCHR)
+#define S_ISFIFO(m)    (((m) & S_IFMT) == S_IFIFO)
+#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK)
+#define S_ISSOCK(m)    (((m) & S_IFMT) == S_IFSOCK)
+
+#define S_ISDEV(m)     (((m) & S_IFCHR) == S_IFCHR)
+
+/* data structure for stat() */
+struct stat {
+       dev_t   st_dev;         /* device number */
+       ino_t   st_ino;         /* inode number */
+       mode_t  st_mode;        /* file mode */
+       nlink_t st_nlink;       /* number of links */
+       uid_t   st_uid;         /* owner id */
+       gid_t   st_gid;         /* owner group */
+       dev_t   st_rdev;        /* */
+       /* These four have to be fixed up by the wrapper */
+       off_t   st_size;        /* file size */
+       time_t  st_atime;       /* last access time */
+       time_t  st_mtime;       /* last modification time */
+       time_t  st_ctime;       /* file creation time */
+};
+
+#endif
diff --git a/Library/include/sys/statfs.h b/Library/include/sys/statfs.h
new file mode 100644 (file)
index 0000000..8cd46f1
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _SYS_STATFS_H
+#define _SYS_STATFS_H
+
+struct statfs {
+  short        f_fstype;
+  long  f_bsize;
+  long  f_frsze;
+  long  f_blocks;
+  long  f_bfree;
+  long  f_files;
+  long  f_ffree;
+  char f_fname[6];
+  char  f_fpack[6];
+};
+
+#endif
\ No newline at end of file
diff --git a/Library/include/sys/time.h b/Library/include/sys/time.h
new file mode 100644 (file)
index 0000000..76b0d39
--- /dev/null
@@ -0,0 +1 @@
+#include <time.h>
\ No newline at end of file
diff --git a/Library/include/sys/times.h b/Library/include/sys/times.h
new file mode 100644 (file)
index 0000000..dbfbf63
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _SYS_TIMES_H
+#define _SYS_TIMES_H
+
+/* User's structure for times() system call */
+struct tms {
+       time_t  tms_utime;
+       time_t  tms_stime;
+       time_t  tms_cutime;
+       time_t  tms_cstime;
+       time_t  tms_etime;      /* Elapsed real time */
+};
+
+extern int times(struct tms *tms);
+
+#endif
\ No newline at end of file
diff --git a/Library/include/sys/types.h b/Library/include/sys/types.h
new file mode 100644 (file)
index 0000000..61c67ad
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* USER! basic data types */
+/* ! uchar & uint is counterparts and must be declared simultaneously */
+
+#ifndef uchar_is_defined
+#define uchar_is_defined
+typedef unsigned char uchar;
+typedef unsigned int uint;
+#endif
+
+#ifndef __SIZE_T_DEFINED
+#define __SIZE_T_DEFINED
+typedef uint16_t size_t;
+#endif
+
+#if !defined (__STDC__)
+/* C types */
+typedef unsigned long uint32_t;
+typedef signed long int32_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+/* C99 */
+typedef int16_t intptr_t;
+typedef uint16_t uintptr_t;
+#endif
+
+/* Unix historic */
+typedef unsigned char uchar_t;
+typedef unsigned long ulong_t;
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+typedef char * caddr_t;
+typedef long daddr_t;
+typedef long key_t;
+
+/* Unix types for properties */
+typedef uint16_t mode_t;
+typedef int32_t off_t;
+typedef uint16_t dev_t;
+typedef uint16_t gid_t;
+typedef uint16_t uid_t;
+typedef uint16_t nlink_t;
+typedef int16_t pid_t;
+typedef uint16_t ino_t;
+
+typedef int64_t time_t;
+
+#endif
diff --git a/Library/include/sys/utsname.h b/Library/include/sys/utsname.h
new file mode 100755 (executable)
index 0000000..273926c
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _SYS_UTSNAME_H\r
+#define _SYS_UTSNAME_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+struct utsname {\r
+       char sysname[14];\r
+       char nodename[14];\r
+       char release[8];\r
+       char version[8];\r
+       char machine[8];\r
+};\r
+\r
+extern int uname __P ((struct utsname * __utsbuf));\r
+\r
+#endif\r
+\r
diff --git a/Library/include/sys/wait.h b/Library/include/sys/wait.h
new file mode 100755 (executable)
index 0000000..9802ba5
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _SYS_WAIT_H\r
+#define _SYS_WAIT_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+/* Bits in the third argument to `waitpid'.  */\r
+#define WNOHANG        1       /* Don't block waiting.  */\r
+#define WUNTRACED      2       /* Report status of stopped children.  */\r
+\r
+/* Everything extant so far uses these same bits.  */\r
+/* If WIFEXITED(STATUS), the low-order 8 bits of the status.  */\r
+#define WEXITSTATUS(status)    (((status) & 0xff00) >> 8)\r
+\r
+/* If WIFSIGNALED(STATUS), the terminating signal.  */\r
+#define WTERMSIG(status)       ((status) & 0x7f)\r
+\r
+/* If WIFSTOPPED(STATUS), the signal that stopped the child.  */\r
+#define WSTOPSIG(status)       WEXITSTATUS(status)\r
+\r
+/* Nonzero if STATUS indicates normal termination.  */\r
+#define WIFEXITED(status)      (((status) & 0xff) == 0)\r
+\r
+/* Nonzero if STATUS indicates termination by a signal.  */\r
+#define WIFSIGNALED(status)    (((unsigned int)((status)-1) & 0xFFFF) < 0xFF)\r
+\r
+/* Nonzero if STATUS indicates the child is stopped.  */\r
+#define WIFSTOPPED(status)     (((status) & 0xff) == 0x7f)\r
+\r
+/* Nonzero if STATUS indicates the child dumped core.  */\r
+#define WCOREDUMP(status)      ((status) & 0200)\r
+\r
+/* Macros for constructing status values.  */\r
+#define W_EXITCODE(ret, sig)   ((ret) << 8 | (sig))\r
+#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)\r
+\r
+/* Special values for the PID argument to `waitpid' and `wait4'.  */\r
+#define WAIT_ANY       (-1)    /* Any process.  */\r
+#define WAIT_MYPGRP    0       /* Any process in my process group.  */\r
+\r
+extern pid_t waitpid __P((pid_t pid, int *__stat_loc, int options));\r
+\r
+/* Wait for a child to die.  When one does, put its status in *STAT_LOC\r
+   and return its process ID.  For errors, return (pid_t) -1.\r
+ */\r
+#define        wait(statloc)   waitpid(WAIT_ANY, statloc, 0)\r
+\r
+#endif\r
+\1a
\ No newline at end of file
diff --git a/Library/include/syscalls.h b/Library/include/syscalls.h
new file mode 100644 (file)
index 0000000..e551490
--- /dev/null
@@ -0,0 +1,143 @@
+/* SYSCALLS.H
+ */
+#ifndef __SYSCALLS_H
+#define __SYSCALLS_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+#ifndef __SIGNAL_H
+#include <signal.h>
+#endif
+#include <sys/stat.h>
+
+extern int errno;
+extern int syscall(int callno, ...);
+
+struct  _uzistat
+{
+       int16_t    st_dev;
+       uint16_t   st_ino;
+       uint16_t   st_mode;
+       uint16_t   st_nlink;
+       uint16_t   st_uid;
+       uint16_t   st_gid;
+       uint16_t   st_rdev;
+       uint32_t   st_size;
+       uint32_t   st_atime;
+       uint32_t   st_mtime;
+       uint32_t   st_ctime;
+       uint32_t   st_timeh;    /* Time high bytes */
+};
+
+struct _uzisysinfoblk {
+  uint8_t infosize;            /* For expandability */
+  uint8_t banks;               /* Banks in our 64K (and thus pagesize) */
+  uint8_t max_open;
+  uint16_t ticks;              /* Tick rate in HZ */
+  uint16_t memk;               /* Memory in KB */
+  uint16_t usedk;              /* Used memory in KB */
+  uint16_t config;             /* Config flag mask */
+};
+
+/*
+ *     This is actually overlaid over a blkbuf holding the actual
+ *     record in question, and pinned until we umount the fs.
+ */
+#define __FILESYS_TABSIZE 50
+
+struct _uzifilesys {
+    int16_t       s_mounted;
+    uint16_t      s_isize;
+    uint16_t      s_fsize;
+    uint16_t      s_nfree;
+    uint16_t      s_free[__FILESYS_TABSIZE];
+    int16_t       s_ninode;
+    uint16_t      s_inode[__FILESYS_TABSIZE];
+    uint8_t       s_fmod;
+    uint8_t       s_timeh;
+    uint32_t      s_time;
+    uint16_t      s_tfree;
+    uint16_t      s_tinode;
+    uint16_t     s_mntpt;
+};
+
+extern int _exit(int code);
+extern int alarm(int16_t secs);
+extern int open(const char *path, int flags, ...);
+extern int close(int fd);
+extern int creat(const char *path, mode_t mode);
+extern int mknod(const char *path, mode_t mode, dev_t dev);
+extern int link(const char *path, const char *path2);
+extern int unlink(const char *path);
+extern int read(int fd, char *buf, int len);
+extern int write(int fd, const char *buf, int len);
+extern int chdir(const char *path);
+extern int sync(void);
+extern int access(const char *path, int way);
+extern int chmod(const char *path, mode_t mode);
+extern int chown(const char *path, uid_t owner, gid_t group);
+extern int dup(int fd);
+extern pid_t getpid(void);
+extern pid_t getppid(void);
+extern uid_t getuid(void);
+extern mode_t umask(mode_t);
+extern int execve(const char *path, const char *argv[], const char *envp[]);
+extern pid_t wait(int *status);
+extern int setuid(uid_t uid);
+extern int setgid(gid_t gid);
+extern int ioctl(int fd, int request,...);
+extern int brk(void *addr);
+extern void *sbrk(intptr_t increment);
+extern pid_t fork(void);
+extern int mount(const char *dev, const char *path, int flags);
+extern int umount(const char *dev);
+extern sighandler_t signal(int signum, sighandler_t sighandler);
+extern int dup2(int oldfd, int newfd);
+extern int _pause(unsigned int dsecs);
+extern int kill(pid_t pid, int sig);
+extern int pipe(int *pipefds);
+extern gid_t getgid(void);
+extern uid_t geteuid(void);
+extern gid_t getegid(void);
+extern int chroot(const char *path);
+extern int fcntl(int fd, int cmd, ...);
+extern int fchdir(int fd);
+extern int fchmod(int fd, mode_t mode);
+extern int fchown(int fd, uid_t owner, gid_t group);
+extern int mkdir(const char *path, mode_t mode);
+extern int rmdir(const char *path);
+extern pid_t setpgrp(void);
+extern int waitpid(pid_t pid, int *status, int options);
+extern int uadmin(int cmd, int ctrl, void *ptr);
+extern int nice(int prio);
+extern int rename(const char *path, const char *newpath);
+
+/* asm syscall hooks with C wrappers */
+extern int _getdirent(int fd, void *buf, int len);
+extern int _stat(const char *path, struct _uzistat *s);
+extern int _fstat(int fd, struct _uzistat *s);
+extern int _getfsys(int dev, struct _uzifilesys *fs);
+extern int _time(time_t *t);
+extern int _stime(const time_t *t);
+extern int _times(struct tms *t);
+extern int _utime(const char *file, time_t *buf);
+extern int _uname(struct _uzisysinfoblk *uzib, int len);
+extern int _profil(void *samples, uint16_t offset, uint16_t size, int16_t scale);
+extern int _lseek(int fd, off_t *offset, int mode);
+
+/* C library provided syscall emulation */
+extern int stat(const char *path, struct stat *s);
+extern int fstat(int fd, struct stat *s);
+extern int alarm(uint16_t seconds);
+extern time_t time(time_t *t);
+extern int stime(time_t *t);
+extern int times(struct tms *tms);
+extern int utime(const char *filename, const struct utimbuf *utim);
+extern int uname(struct utsname *buf);
+extern int profil(unsigned short *bufbase, size_t bufsize, unsigned long offset,
+                  unsigned int scale);
+
+
+#endif /* __SYSCALLS_H */
+
+
diff --git a/Library/include/termcap.h b/Library/include/termcap.h
new file mode 100644 (file)
index 0000000..7a311f1
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __TERMCAP_H\r
+#define __TERMCAP_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+extern char PC;\r
+extern char *UP;\r
+extern char *BC;\r
+extern int ospeed;\r
+\r
+extern int tgetent __P((char *, char *));\r
+extern int tgetflag __P((char *));\r
+extern int tgetnum __P((char *));\r
+extern char *tgetstr __P((char *, char **));\r
+\r
+extern void tputs __P((char *, int, int (*)(int)));\r
+extern char *tgoto __P((char *, int, int));\r
+extern char *tparam(); /* VARARGS */\r
+\r
+#endif /* _TERMCAP_H */\r
+\1a\r
diff --git a/Library/include/termio.h b/Library/include/termio.h
new file mode 100644 (file)
index 0000000..67a0b1e
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef __TERMIOS_H\r
+#include <termios.h>\r
+#endif\r
diff --git a/Library/include/termios.h b/Library/include/termios.h
new file mode 100644 (file)
index 0000000..2aa76ac
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef __TERMIOS_H
+#define __TERMIOS_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+
+typedef uint16_t tcflag_t;
+typedef uint16_t speed_t;
+typedef uint8_t cc_t;
+
+#define NCCS 12
+struct termios {
+  tcflag_t c_iflag;
+  tcflag_t c_oflag;
+  tcflag_t c_cflag;
+  tcflag_t c_lflag;
+  cc_t c_cc[NCCS];
+};
+
+#define VEOF   0
+#define VEOL   1
+#define VERASE 2
+#define VINTR  3
+#define VKILL  4
+#define VMIN   4
+#define VQUIT  5
+#define VSTART 6
+#define VSTOP  7
+#define VSUSP  8
+#define VTIME  9
+#define VDSUSP 10
+#define VLNEXT 11
+
+#define BRKINT 0x0001
+#define ICRNL  0x0002
+#define IGNBRK 0x0004
+#define IGNCR  0x0008
+#define IGNPAR 0x0010
+#define INLCR  0x0020
+#define INPCK  0x0040
+#define ISTRIP 0x0080
+#define IUCLC  0x0100
+#define IXANY  0x0200
+#define IXOFF  0x0400
+#define PARMRK 0x0800
+
+#define OPOST  0x0001
+#define OLCUC  0x0002
+#define ONLCR  0x0004
+#define OCRNL  0x0008
+#define ONLRET 0x0010
+#define OFILL  0x0020
+#define NLDLY  0x0040
+#define NL0    0x0000
+#define NL1    0x0040
+#define CRDLY  0x0180
+#define CR0    0x0000
+#define CR1    0x0080
+#define CR2    0x0100
+#define CR3    0x0180
+#define TABDLY 0x0600
+#define TAB0   0x0000
+#define TAB1   0x0200
+#define TAB2   0x0400
+#define TAB3   0x0600
+#define BSDLY  0x0800
+#define BS0    0x0000
+#define BS1    0x0800
+#define VTDLY  0x1000
+#define VT0    0x0000
+#define VT1    0x1000
+#define FFDLY  0x2000
+#define FF0    0x0000
+#define FF1    0x2000
+
+#define B0     0x0000
+#define B50    0x0001
+#define B75    0x0002
+#define B110   0x0003
+#define B134   0x0004
+#define B150   0x0005
+#define B300   0x0006
+#define B600   0x0007
+#define B1200  0x0008
+#define B2400  0x0009
+#define B4800  0x000A
+#define B9600   0x000B
+#define B19200 0x000C
+#define B38400 0x000D
+#define B57600 0x000E
+#define B115200        0x000F
+
+#define CSIZE  0x0030
+#define CS5    0x0000
+#define CS6    0x0010
+#define CS7    0x0020
+#define CS8    0x0030
+#define CSTOPB 0x0040
+#define CREAD  0x0080
+#define PARENB 0x0100
+#define PARODD 0x0200
+#define HUPCL  0x0400
+#define CLOCAL 0x0800
+#define CRTSCTS 0x1000
+#define CBAUD  0x000F
+
+#define ECHO   0x0001
+#define ECHOE  0x0002
+#define ECHOK  0x0004
+#define ECHONL 0x0008
+#define ICANON 0x0010
+#define IEXTEN 0x0020
+#define ISIG   0x0040
+#define NOFLUSH        0x0080
+#define TOSTOP 0x0100
+#define XCASE  0x0200
+
+#define TCSANOW                0
+#define TCSADRAIN      1
+#define TCSAFLUSH      2
+
+#define TCIFLUSH       1
+#define TCOFLUSH       2
+#define TCIOFLUSH      3
+
+#define TCIOFF         0
+#define TCION          1
+#define TCOOFF         2
+#define TCOON          3
+
+#define TCGETS         1
+#define TCSETS         2
+#define TCSETSW                3
+#define TCSETSF                4
+#define TIOCINQ                5
+#define TIOCFLUSH      6
+#define TIOCHANGUP     7       /* vhangup() */
+
+
+extern speed_t cfgetispeed __P ((const struct termios *__termios_p));
+extern speed_t cfgetospeed __P ((const struct termios *__termios_p));
+extern int cfsetispeed __P ((struct termios *__termios_p, speed_t __speed));
+extern int cfsetospeed __P ((struct termios *__termios_p, speed_t __speed));
+
+extern void cfmakeraw  __P ((struct termios *__t));
+
+extern int tcsetattr __P ((int __fd, int __opt, const struct termios *__termios_p));
+extern int tcgetattr __P ((int __fildes, struct termios *__termios_p));
+extern int tcdrain __P ((int __fildes));
+extern int tcflow __P ((int __fildes, int __action));
+extern int tcflush __P ((int __fildes, int __queue_selector));
+extern int tcsendbreak __P ((int __fildes, int __duration));
+extern int tcgetpgrp __P ((int __fildes));
+extern int tcsetpgrp __P ((int __fildes, int __pgrp_id));
+
+#endif
diff --git a/Library/include/time.h b/Library/include/time.h
new file mode 100644 (file)
index 0000000..dd388fc
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __TIME_H\r
+#define __TIME_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <stddef.h>\r
+#include <syscalls.h>\r
+\r
+#ifndef CLOCK_T\r
+#define CLOCK_T\r
+typedef long clock_t;\r
+#endif\r
+\r
+struct tm {\r
+       int tm_sec;\r
+       int tm_min;\r
+       int tm_hour;\r
+       int tm_mday;\r
+       int tm_mon;\r
+       int tm_year;\r
+       int tm_wday;\r
+       int tm_yday;\r
+       int tm_isdst;\r
+};\r
+\r
+struct timezone {\r
+       int tz_minuteswest;     /* minutes west of Greenwich */\r
+       int tz_dsttime;         /* type of dst correction */\r
+};\r
+\r
+#define __isleap(year) \\r
+       ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))\r
+\r
+extern char *tzname[2];\r
+extern int daylight;\r
+extern long timezone;\r
+\r
+extern long clock __P ((void));\r
+extern time_t mktime __P ((struct tm * __tp));\r
+extern double difftime __P ((time_t *__time2, time_t *__time1));\r
+\r
+extern time_t *gtime(time_t *tvec);\r
+\r
+extern void __tm_conv __P((struct tm *tmbuf, time_t *t, int offset));\r
+extern void __asctime __P((char *, struct tm *));\r
+extern char *asctime __P ((struct tm * __tp));\r
+extern char *ctime __P ((time_t * __tp));\r
+extern void tzset __P ((void));\r
+\r
+extern struct tm *gmtime __P ((time_t *__tp));\r
+extern struct tm *localtime __P ((time_t * __tp));\r
+extern unsigned long convtime __P ((time_t *time_field));\r
+\r
+#define CLOCKS_PER_SEC 100             /* FIXME: sysconf */\r
+#endif\r
diff --git a/Library/include/types.h b/Library/include/types.h
new file mode 100644 (file)
index 0000000..d6b103e
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __TYPES_H\r
+#define __TYPES_H\r
+\r
+#ifndef __FEATURES_H\r
+#include "features.h"\r
+#endif\r
+#include "stdint.h"\r
+\r
+#include "sys/types.h"\r
+#endif\r
+\r
diff --git a/Library/include/unistd.h b/Library/include/unistd.h
new file mode 100644 (file)
index 0000000..0116954
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef __UNISTD_H
+#define __UNISTD_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+#include <syscalls.h>
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#define STDIN_FILENO   0
+#define STDOUT_FILENO  1
+#define STDERR_FILENO  2
+
+extern long tell __P((int));
+extern off_t lseek __P((int, off_t, int));
+
+extern int isatty __P((int));
+
+extern int lstat __P((const char *, struct stat *));
+extern int readlink __P((const char *, char *, int));
+
+extern unsigned int sleep __P((unsigned int seconds));
+
+extern char **environ;
+
+extern char * _findPath __P((char *pathname));
+extern int execl __P((char *pathname, char *arg0, ...));
+extern int execle __P((char *pathname, char *arg0, ...));
+extern int execlp __P((char *pathname, char *arg0, ...));
+extern int execlpe __P((char *pathname, char *arg0, ...));
+extern int execv __P((char *pathname, char *argv[]));
+extern int exect __P((char *pathname, char *argv[], char *envp[]));
+extern int execvp __P((char *pathname, char *argv[]));
+extern int execvpe __P((char *pathname, char *argv[], char *envp[]));
+
+extern char *ttyname __P((int));
+extern int system __P((char *));
+extern int pause __P((void));
+extern int fork __P((void));
+extern char *getcwd __P((char *, int));
+
+extern long sysconf(int name);
+
+#define _SC_ARG_MAX            1
+#define _SC_CHILD_MAX          2
+#define _SC_HOST_NAME_MAX      3
+#define _SC_LOGIN_NAME_MAX     4
+#define _SC_CLK_TCK            5
+#define _SC_OPEN_MAX           6
+#define _SC_PAGESIZE           7
+#define _SC_RE_DUP_MAX         8
+#define _SC_STREAM_MAX         9
+#define _SC_SYMLOOP_MAX                10
+#define _SC_TTY_NAME_MAX       11
+#define _SC_TZNAME_MAX         12
+#define _SC_VERSION            13
+#define _SC_PHYS_PAGES         14
+#define _SC_AVPHYS_PAGES       15
+#define _SC_NPROCESSORS_CONF   16
+#define _SC_NPROCESSORS_ONLN   17
+/* SYS5 isms: TODO */
+#define _SC_NGROUPS_MAX                18
+#define _SC_JOB_CONTROL                19
+#define _SC_SAVED_IDS          20
+
+extern int gethostname(char *name, size_t len);
+extern int sethostname(const char *name, size_t len);
+
+#ifndef __STDLIB_H
+extern void exit __P((int));
+#endif
+
+#ifndef R_OK
+#define R_OK   4       /* Test for read permission.  */
+#define W_OK   2       /* Test for write permission.  */
+#define X_OK   1       /* Test for execute permission.  */
+#define F_OK   0       /* Test for existence.  */
+#endif
+
+#define F_ULOCK        0
+#define F_LOCK 1
+#define F_TLOCK        2
+#define F_TEST 3
+
+
+#define _PC_LINK_MAX   0
+#define _PC_MAX_CANON  1
+#define _PC_MAX_INPUT  2
+#define _PC_NAME_MAX   3
+#define _PC_PATH_MAX   4
+#define _PC_PIPE_BUF   5
+#define _PC_CHOWN_RESTRICTED   6
+#define _PC_NO_TRUNC   7
+#define _PC_VDISABLE   8
+
+#endif /* __UNISTD_H */
diff --git a/Library/include/utime.h b/Library/include/utime.h
new file mode 100644 (file)
index 0000000..0ebbfd3
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __UTIME_H
+#define __UTIME_H
+#ifndef __TYPES_H
+#include <types.h>
+#endif
+
+struct utimbuf {
+    time_t actime;  /* access time */
+    time_t modtime; /* modification time */
+};
+
+extern int utime __P ((char *__filename, struct utimbuf *__utimebuf));
+
+#endif
diff --git a/Library/include/utmp.h b/Library/include/utmp.h
new file mode 100644 (file)
index 0000000..6c1c660
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __UTMP_H\r
+#define __UTMP_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+#include <paths.h>\r
+#include <time.h>\r
+\r
+#define UT_UNKNOWN 0\r
+#define UT_LINESIZE 12\r
+#define UT_NAMESIZE 8\r
+#define UT_HOSTSIZE 16\r
+\r
+#define RUN_LVL 1\r
+#define BOOT_TIME 2\r
+#define NEW_TIME 3\r
+#define OLD_TIME 4\r
+\r
+#define INIT_PROCESS 5\r
+#define LOGIN_PROCESS 6\r
+#define USER_PROCESS 7\r
+#define DEAD_PROCESS 8\r
+\r
+struct utmp {\r
+       short   ut_type;                /* type of login */\r
+       int     ut_pid;                 /* pid of login-process */\r
+       char    ut_line[UT_LINESIZE];   /* devicename of tty -"/dev/", null-term */\r
+       char    ut_id[2];               /* abbrev. ttyname, as 01, s1 etc. */\r
+       time_t  ut_time;                /* login time */\r
+       char    ut_user[UT_NAMESIZE];   /* username, not null-term */\r
+       char    ut_host[UT_HOSTSIZE];   /* hostname for remote login... */\r
+       long    ut_addr;                /* IP addr of remote host */\r
+};\r
+\r
+extern void            setutent __P((void));\r
+extern void            utmpname __P((char *));\r
+extern struct utmp *   getutent __P((void));\r
+extern struct utmp *   getutid __P((struct utmp *));\r
+extern struct utmp *   getutline __P((struct utmp *));\r
+extern struct utmp *   pututline __P((struct utmp *));\r
+extern void            endutent __P((void));\r
+\r
+struct utmp *          __getutent __P((int));\r
+\r
+#endif /* __UTMP_H */\r
diff --git a/Library/include/utsname.h b/Library/include/utsname.h
new file mode 100644 (file)
index 0000000..18b97dc
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _SYS_UTSNAME_H\r
+#define _SYS_UTSNAME_H\r
+#ifndef __TYPES_H\r
+#include <types.h>\r
+#endif\r
+\r
+struct utsname {\r
+       char sysname[14];\r
+       char nodename[14];\r
+       char release[8];\r
+       char version[8];\r
+       char machine[8];\r
+       char domainname[14];\r
+};\r
+\r
+extern int uname __P ((struct utsname * __utsbuf));\r
+\r
+#endif\r
+\1a\r
diff --git a/Library/include/varargs.h b/Library/include/varargs.h
new file mode 100644 (file)
index 0000000..af9acf7
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __VARARGS_H\r
+#define __VARARGS_H\r
+\r
+#ifndef __STDARG_H\r
+typedef void *va_list;\r
+\r
+#define va_dcl va_list va_alist;\r
+#define va_start(ap) (ap) = (va_list)&va_alist\r
+#define va_arg(ap,t) ((t *)(((char *)(ap)) += sizeof(t)))[-1]\r
+#define va_end(ap) (ap) = NULL\r
+\r
+#endif\r
+#endif\r
+\1a\r
diff --git a/Library/include/wait.h b/Library/include/wait.h
new file mode 100644 (file)
index 0000000..d01b811
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/wait.h>
diff --git a/Library/libs/Makefile b/Library/libs/Makefile
new file mode 100644 (file)
index 0000000..0dbcec6
--- /dev/null
@@ -0,0 +1,83 @@
+CC = sdcc
+ASM = sdasz80
+AR = sdar
+LINKER = sdldz80
+CC_OPT = -mz80 -c --opt-code-size --std-c99 --max-allocs-per-node 2000000 -I../include
+#CC_OPT = -mz80 --std-c99 -c --opt-code-size --max-allocs-per-node 20000 -I../include
+#--oldralloc
+ASM_OPT = -l -o -s
+LINKER_OPT = -m -i -o
+SRC_CRT0 = crt0.s
+OBJ_CRT0 = $(SRC_CRT0:.s=.rel)
+SRC_ASM =
+OBJ_ASM = $(SRC_ASM:.s=.rel)
+SRC_C =  abort.c asctime.c assert.c atexit.c
+SRC_C += bcmp.c bcopy.c bsearch.c bzero.c calloc.c cfree.c clock.c closedir.c
+SRC_C += creat.c crypt.c ctime.c ctype.c difftime.c errno.c error.c execl.c execv.c
+SRC_C += execvp.c exit.c fclose.c fflush.c fgetc.c fgetgrent.c fgetpwent.c
+SRC_C += fgetpos.c fgets.c fopen.c fprintf.c fputc.c fputs.c fread.c free.c
+SRC_C += fsetpos.c ftell.c fwrite.c getcwd.c
+SRC_C += getenv.c __getgrent.c getgrgid.c getgrnam.c getopt.c
+SRC_C += getpw.c __getpwent.c getpwnam.c getpwuid.c gets.c
+SRC_C += gmtime.c grent.c index.c isatty.c itoa.c killpg.c
+SRC_C += localtim.c lseek.c lsearch.c lstat.c ltoa.c ltostr.c malloc.c
+SRC_C += mkfifo.c opendir.c pause.c perror.c
+SRC_C += popen.c printf.c putenv.c putgetch.c putpwent.c pwent.c qsort.c
+SRC_C += raise.c rand.c readdir.c readlink.c realloc.c regerror.c
+SRC_C += regsub.c remove.c rewind.c rindex.c setbuffer.c setenv.c setjmp.c
+SRC_C += setvbuf.c sleep.c sprintf.c stat.c stdio0.c strcasecmp.c
+SRC_C += strdup.c stricmp.c strncasecmp.c
+SRC_C += strnicmp.c strsep.c
+SRC_C += strtod.c strtol.c system.c time.c tmpnam.c ttyname.c
+SRC_C += tzset.c ultoa.c ungetc.c utent.c utsname.c
+SRC_C += vfprintf.c vprintf.c wait.c xitoa.c
+SRC_C += gethostname.c sysconf.c confstr.c memccpy.c getpass.c
+# tty layer
+SRC_C += tcgetattr.c tcsetattr.c tcdrain.c tcflow.c tcflush.c
+SRC_C += cfmakeraw.c cfspeed.c revoke.c
+# scanf
+SRC_C += fscanf.c scanf.c sscanf.c vfscanf.c vscanf.c vsscanf.c
+# Seems to give the compiler a hard time
+#SRC_C += regexp.c
+# Not supported yet
+#SRC_C += initgroups.c
+# Pieces we inherit in this case from the compiler library instead
+#SRC_C += strcpy.c strlen.c abs.c atof.c atoi.c atol.c labs.c
+#SRC_C += strcat.c strchr.c strcmp.c strcspn.c strncat.c strncmp.c
+#SRC_C += strncpy.c strpbrk.c strrchr.c strspn.c strstr.c strtok.c
+#SRC_C += memchr.c memcmp.c memcpy.c memset.c
+
+OBJ_C = $(SRC_C:.c=.rel)
+OBJ_ALL = $(OBJ_ASM) $(OBJ_C)
+
+all: syslib.lib crt0.rel
+
+libc.l:%.l:$(OBJ_ALL)
+       ls $(OBJ_ALL) > libc.l
+
+syscall.l: fuzix/syslib.l
+       (cd fuzix; make)
+       cat fuzix/syslib.l | tr " " "\\n" | sed -e "s/^/fuzix\//" >syscall.l
+
+sdccz80.lib:
+       ../tools/libclean
+
+syslib.lib: syscall.l libc.l sdccz80.lib
+       cat libc.l syscall.l >syslib.l
+       cp sdccz80.lib syslib.lib
+       $(AR) rc syslib.lib @syslib.l
+       $(AR) s syslib.lib
+
+$(OBJ_ASM):%.rel: %.s
+       $(ASM) $(ASM_OPT) $@ $(@:.rel=.s)
+
+$(OBJ_CRT0):%.rel: %.s
+       $(ASM) $(ASM_OPT) $@ $(@:.rel=.s)
+
+$(OBJ_C):%.rel: %.c
+       $(CC) $(CC_OPT) $(@:.rel=.c)
+
+
+clean:
+       rm -rf *.rel *.asm *.sym *.lst *.lib *~ libc.l
+       (cd fuzix; make clean)
diff --git a/Library/libs/README.regexp b/Library/libs/README.regexp
new file mode 100644 (file)
index 0000000..37d6f51
--- /dev/null
@@ -0,0 +1,84 @@
+This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
+It gives C programs the ability to use egrep-style regular expressions, and
+does it in a much cleaner fashion than the analogous routines in SysV.
+
+       Copyright (c) 1986 by University of Toronto.
+       Written by Henry Spencer.  Not derived from licensed software.
+
+       Permission is granted to anyone to use this software for any
+       purpose on any computer system, and to redistribute it freely,
+       subject to the following restrictions:
+
+       1. The author is not responsible for the consequences of use of
+               this software, no matter how awful, even if they arise
+               from defects in it.
+
+       2. The origin of this software must not be misrepresented, either
+               by explicit claim or by omission.
+
+       3. Altered versions must be plainly marked as such, and must not
+               be misrepresented as being the original software.
+
+Barring a couple of small items in the BUGS list, this implementation is
+believed 100% compatible with V8.  It should even be binary-compatible,
+sort of, since the only fields in a "struct regexp" that other people have
+any business touching are declared in exactly the same way at the same
+location in the struct (the beginning).
+
+This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
+software.  Even though U of T is a V8 licensee.  This software is based on
+a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
+here is a complete rewrite and hence is not covered by AT&T copyright).
+The software was nearly complete at the time of arrival of our V8 tape.
+I haven't even looked at V8 yet, although a friend elsewhere at U of T has
+been kind enough to run a few test programs using the V8 regexp(3) to resolve
+a few fine points.  I admit to some familiarity with regular-expression
+implementations of the past, but the only one that this code traces any
+ancestry to is the one published in Kernighan & Plauger (from which this
+one draws ideas but not code).
+
+Simplistically:  put this stuff into a source directory, copy regexp.h into
+/usr/include, inspect Makefile for compilation options that need changing
+to suit your local environment, and then do "make r".  This compiles the
+regexp(3) functions, compiles a test program, and runs a large set of
+regression tests.  If there are no complaints, then put regexp.o, regsub.o,
+and regerror.o into your C library, and regexp.3 into your manual-pages
+directory.
+
+Note that if you don't put regexp.h into /usr/include *before* compiling,
+you'll have to add "-I." to CFLAGS before compiling.
+
+The files are:
+
+Makefile       instructions to make everything
+regexp.3       manual page
+regexp.h       header file, for /usr/include
+regexp.c       source for regcomp() and regexec()
+regsub.c       source for regsub()
+regerror.c     source for default regerror()
+regmagic.h     internal header file
+try.c          source for test program
+timer.c                source for timing program
+tests          test list for try and timer
+
+This implementation uses nondeterministic automata rather than the
+deterministic ones found in some other implementations, which makes it
+simpler, smaller, and faster at compiling regular expressions, but slower
+at executing them.  In theory, anyway.  This implementation does employ
+some special-case optimizations to make the simpler cases (which do make
+up the bulk of regular expressions actually used) run quickly.  In general,
+if you want blazing speed you're in the wrong place.  Replacing the insides
+of egrep with this stuff is probably a mistake; if you want your own egrep
+you're going to have to do a lot more work.  But if you want to use regular
+expressions a little bit in something else, you're in luck.  Note that many
+existing text editors use nondeterministic regular-expression implementations,
+so you're in good company.
+
+This stuff should be pretty portable, given appropriate option settings.
+If your chars have less than 8 bits, you're going to have to change the
+internal representation of the automaton, although knowledge of the details
+of this is fairly localized.  There are no "reserved" char values except for
+NUL, and no special significance is attached to the top bit of chars.
+The string(3) functions are used a fair bit, on the grounds that they are
+probably faster than coding the operations in line.  Some attempts at code
+tuning have been made, but this is invariably a bit machine-specific.
diff --git a/Library/libs/TODO b/Library/libs/TODO
new file mode 100644 (file)
index 0000000..85f219d
--- /dev/null
@@ -0,0 +1,165 @@
+Hot problem items
+-----------------
+__modslonglong is not found from base C lib ?
+
+
+tool to wrap the build and also make a Fuzix binary not a ROM image
+
+- Import other bits we can from BCC libs
+- Longlong in printf (plus other modern bits ?)
+- *nprintf
+- glue for Fuzix syscalls (uname, alarm etc)
+- Propogate "real" time_t into kernel
+- termios into kernel and match up with C library
+- memccpy
+- bits of libbsd
+- rest of opendir (telldir etc)
+Make exec* try via shell if ENOEXEC
+
+
+Add libm, and build stdio fprintf/fscanf and any other bloaty floaty bits
+with a libm define into libm and integer into libc
+
+Missing
+
+terminfo
+streams (intentional)
+X11 (right)
+
+DIR needs dd_loc, dd_size wiring up dirent tweaks in C code
+
+
+Errors: define the full range required by SVID
+
+getpgrp missing definition ?
+
+get/sethostname and domainname via userspace only
+
+sys/fp.h - not really that relevant but might as well have
+
+ieeefp.h ???
+
+sys/ipc.h
+sys/lock.h
+math.h (HUEGVAL)
+sys/msg.h
+
+sys/param.h    (now mostly needs to be via sysconf)
+sys/reg.h      (used for what ? ptrace ? )
+sys/sem.h
+
+setjmp.h       defines for size, sig* version
+
+sys/shm.h
+
+signal.h       signals 16-31 ??
+               sigaction bits need defining plus SA_NOCLDSTOP
+sys/statfs     need to add fakery for it
+
+stdio          _NFILE, L_ctermid, L_cuserid, P_tmpdir, L_tmpnam
+
+stropts.h      (streams)
+
+termios.h      Define struct termio as well, need to double check all
+               flags isted are present + chars (eg VSWTCH, VEOL2)
+               Defines for the initial chars (CNUL, CDEL etc)
+               TCWINSZ + a few other oddments
+
+time.h         sort out CLK_TCK
+
+sys/tiuser     streams
+
+utmp.h         ut_exit ??? ACCOUNTING
+
+API functions
+
+Need
+----
+
+cfree(a,b,c)   -> free(a)
+ecvt()
+fcvt()
+frexp
+gcvt
+getw
+isnand()       'is nan ?'
+ldexp
+memccpy
+putw
+sighold
+sigignore
+sigpause
+sigrelse
+sigset
+ftw()
+poll() wrappers
+siglongjmp/sigsetjmp
+
+For Modern Stuff
+----------------
+snprintf
+sysconf
+pathconf
+
+TCP/IP stuff
+
+
+Commands Required
+-----------------
+cat
+cd
+chgrp
+chmod
+chown
+cmp
+cp
+cpio
+date
+dd
+df
+echo
+ed
+ex
+expr
+false
+find
+grep
+id
+kill
+line
+ln
+logname
+lp
+ls
+mkdir
+mv
+passwd
+pg
+pr
+pwd
+rm
+rmdir
+sed
+sh
+sleep
+sort
+stty
+su
+tail
+tar
+tee
+test
+touch
+tr
+true
+tty
+umask
+uname
+uucp           [duh ???]
+uulog
+uustart
+uux
+vi
+wait
+who
+
diff --git a/Library/libs/__getgrent.c b/Library/libs/__getgrent.c
new file mode 100644 (file)
index 0000000..e5ed3cb
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * __getgrent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+#include "config-getent.h"
+
+/*
+ * This is the core group-file read function.  It behaves exactly like
+ * getgrent() except that it is passed a file descriptor.  getgrent()
+ * is just a wrapper for this function.
+ */
+struct group *
+__getgrent(int grp_fd)
+{
+#ifndef GR_SCALE_DYNAMIC  
+  static char line_buff[GR_MAX_LINE_LEN];
+  static char * members[GR_MAX_MEMBERS];
+#else
+  static char * line_buff;
+  static char ** members;
+  short line_index;
+  short buff_size;
+#endif
+  static struct group group;
+  register char * ptr;
+  char * field_begin;
+  short member_num;
+  char * endptr;
+  int line_len;
+
+
+  /* We use the restart label to handle malformatted lines */
+restart:
+#ifdef GR_SCALE_DYNAMIC
+  line_index=0;
+  buff_size=256;
+#endif
+
+#ifndef GR_SCALE_DYNAMIC
+  /* Read the line into the static buffer */
+  if ((line_len=read(grp_fd, line_buff, GR_MAX_LINE_LEN))<=0)
+    return NULL;
+  field_begin=strchr(line_buff, '\n');
+  if (field_begin!=NULL)
+    lseek(grp_fd, (long) (1+field_begin-(line_buff+line_len)), SEEK_CUR);
+  else /* The line is too long - skip it :-\ */
+    {
+      do { if ((line_len=read(grp_fd, line_buff, GR_MAX_LINE_LEN))<=0)
+       return NULL;
+      } while (!(field_begin=strchr(line_buff, '\n')));
+      lseek(grp_fd, (long) ((field_begin-line_buff)-line_len+1), SEEK_CUR);
+      goto restart;
+    }
+  if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' ||
+      *line_buff=='\t')
+    goto restart;
+  *field_begin='\0';
+
+#else /* !GR_SCALE_DYNAMIC */
+  line_buff=realloc(line_buff, buff_size);
+  while (1)
+    {
+      if ((line_len=read(grp_fd, line_buff+line_index,
+                        buff_size-line_index))<=0)
+         return NULL;
+      field_begin=strchr(line_buff, '\n');
+      if (field_begin!=NULL)
+       {
+         lseek(grp_fd, (long) (1+field_begin-(line_len+line_index+line_buff)),
+               SEEK_CUR);
+         *field_begin='\0';
+         if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' ||
+             *line_buff=='\t')
+           goto restart;
+         break;
+       }
+      else /* Allocate some more space */
+       {
+         line_index=buff_size;
+         buff_size+=256;
+         line_buff=realloc(line_buff, buff_size);
+       }
+    }
+#endif /* GR_SCALE_DYNAMIC */
+
+  /* Now parse the line */
+  group.gr_name=line_buff;
+  ptr=strchr(line_buff, ':');
+  if (ptr==NULL) goto restart;
+  *ptr++='\0';
+
+  group.gr_passwd=ptr;
+  ptr=strchr(ptr, ':');
+  if (ptr==NULL) goto restart;
+  *ptr++='\0';
+
+  field_begin=ptr;
+  ptr=strchr(ptr, ':');
+  if (ptr==NULL) goto restart;
+  *ptr++='\0';
+
+  group.gr_gid=(gid_t) strtoul(field_begin, &endptr, 10);
+  if (*endptr!='\0') goto restart;
+
+  member_num=0;
+  field_begin=ptr;
+
+#ifndef GR_SCALE_DYNAMIC
+  while ((ptr=strchr(ptr, ','))!=NULL)
+    {
+      *ptr='\0';
+      ptr++;
+      members[member_num]=field_begin;
+      field_begin=ptr;
+      member_num++;
+    }
+  if (*field_begin=='\0')
+    members[member_num]=NULL;
+  else
+    {
+      members[member_num]=field_begin;
+      members[member_num+1]=NULL;
+    }
+#else /* !GR_SCALE_DYNAMIC */
+  if (members!=NULL)
+    free (members);
+  members=(char **) malloc(1*sizeof(char *));
+  while ((ptr=strchr(ptr, ','))!=NULL)
+    {
+      *ptr='\0';
+      ptr++;
+      members[member_num]=field_begin;
+      field_begin=ptr;
+      member_num++;
+      members=(char **)realloc((void *)members, (member_num+1)*sizeof(char *));
+    }
+  if (*field_begin=='\0')
+      members[member_num]=NULL;
+  else
+    {
+      members[member_num]=field_begin;
+      members[member_num+1]=NULL;
+    }
+#endif /* GR_SCALE_DYNAMIC */
+
+  group.gr_mem=members;
+  return &group;
+}
diff --git a/Library/libs/__getpwent.c b/Library/libs/__getpwent.c
new file mode 100644 (file)
index 0000000..9836ca7
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+#define PWD_BUFFER_SIZE 256
+
+/* This isn't as flash as my previous version -- it doesn't dynamically
+  scale down the gecos on too-long lines, but it also makes fewer syscalls,
+  so it's probably nicer.  Write me if you want the old version.  Maybe I
+  should include it as a build-time option... ?
+  -Nat <ndf@linux.mit.edu> */
+   
+struct passwd *
+__getpwent(int pwd_fd)
+{
+  static char line_buff[PWD_BUFFER_SIZE];
+  static struct passwd passwd;
+  char * field_begin;
+  char * endptr;
+  char * gid_ptr;
+  char * uid_ptr;
+  int line_len;
+  int i;
+
+  /* We use the restart label to handle malformatted lines */
+restart:
+  /* Read the passwd line into the static buffer using a minimal of
+     syscalls. */
+  if ((line_len=read(pwd_fd, line_buff, PWD_BUFFER_SIZE))<=0)
+    return NULL;
+  field_begin=strchr(line_buff, '\n');
+  if (field_begin!=NULL)
+    lseek(pwd_fd, (long) (1+field_begin-(line_buff+line_len)), SEEK_CUR);
+  else /* The line is too long - skip it. :-\ */
+    {
+      do { if ((line_len=read(pwd_fd, line_buff, PWD_BUFFER_SIZE))<=0)
+       return NULL;
+      } while (!(field_begin=strchr(line_buff, '\n')));
+      lseek(pwd_fd, (long) (field_begin-line_buff)-line_len+1, SEEK_CUR);
+      goto restart;
+    }
+  if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' ||
+      *line_buff=='\t')
+      goto restart;
+  *field_begin='\0';
+
+  /* We've read the line; now parse it. */
+  field_begin=line_buff;
+  for (i=0;i<7;i++)
+    {
+      switch(i)
+       {
+       case 0: passwd.pw_name=field_begin; break;
+       case 1: passwd.pw_passwd=field_begin; break;
+       case 2: uid_ptr=field_begin; break;
+       case 3: gid_ptr=field_begin; break;
+       case 4: passwd.pw_gecos=field_begin; break;
+       case 5: passwd.pw_dir=field_begin; break;
+       case 6: passwd.pw_shell=field_begin; break;
+       }
+      if (i<6)
+       {
+         field_begin=strchr(field_begin, ':');
+         if (field_begin==NULL) goto restart;
+         *field_begin++='\0';
+       }
+    }
+  passwd.pw_gid=(gid_t) strtoul(gid_ptr, &endptr, 10);
+  if (*endptr!='\0') goto restart;
+  
+  passwd.pw_uid=(uid_t) strtoul(uid_ptr, &endptr, 10);
+  if (*endptr!='\0') goto restart;
+
+  return &passwd;
+}
+
+
diff --git a/Library/libs/abort.c b/Library/libs/abort.c
new file mode 100644 (file)
index 0000000..61d9244
--- /dev/null
@@ -0,0 +1,16 @@
+/*\r
+ */  \r
+#include <unistd.h>\r
+#include <stdlib.h>\r
+#include <signal.h>\r
+#include <syscalls.h>\r
+\r
+void abort(void)
+{
+       signal(SIGABRT, SIG_DFL);
+       kill(SIGABRT, getpid());        /* Correct one */
+       pause();                        /* System may just schedule */
+       signal(SIGKILL, SIG_DFL);
+       kill(SIGKILL, getpid());        /* Can't trap this! */
+       _exit(255);                     /* WHAT!! */
+}\r
diff --git a/Library/libs/abs.c b/Library/libs/abs.c
new file mode 100644 (file)
index 0000000..3083925
--- /dev/null
@@ -0,0 +1,7 @@
+#include <string.h>
+#include <sys/types.h>
+
+int abs(int arg1)
+{
+   return arg1>0?arg1:-arg1;
+}
diff --git a/Library/libs/asctime.c b/Library/libs/asctime.c
new file mode 100644 (file)
index 0000000..9170fcc
--- /dev/null
@@ -0,0 +1,54 @@
+#include <time.h>
+#include <string.h>
+
+/*
+ * Internal ascii conversion routine, avoid use of printf, it's a bit big!
+ */
+
+static void hit __P((char *, int));
+
+static void hit(char *buf, int val)
+{
+       *buf = '0' + val % 10;
+}
+
+/* Kept out of function to work around SDCC */
+static char days[] = "SunMonTueWedThuFriSat";
+static char mons[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+void __asctime(char *buffer, struct tm *ptm)
+{
+       int year;
+
+       strcpy(buffer, "Err Err .. ..:..:.. ....\n");
+       if ((ptm->tm_wday >= 0) && (ptm->tm_wday <= 6))
+               memcpy(buffer, days + 3 * (ptm->tm_wday), 3);
+       if ((ptm->tm_mon >= 0) && (ptm->tm_mon <= 11))
+               memcpy(buffer + 4, mons + 3 * (ptm->tm_mon), 3);
+       year = ptm->tm_year + 1900;
+       hit(buffer + 8, ptm->tm_mday / 10);
+       hit(buffer + 9, ptm->tm_mday);
+       hit(buffer + 11, ptm->tm_hour / 10);
+       hit(buffer + 12, ptm->tm_hour);
+       hit(buffer + 14, ptm->tm_min / 10);
+       hit(buffer + 15, ptm->tm_min);
+       hit(buffer + 17, ptm->tm_sec / 10);
+       hit(buffer + 18, ptm->tm_sec);
+       hit(buffer + 20, year / 1000);
+       hit(buffer + 21, year / 100);
+       hit(buffer + 22, year / 10);
+       hit(buffer + 23, year);
+}
+
+/* asctime - convert date and time to ascii.
+ * returns a pointer to the character string containing the date and time.
+ */
+char *asctime(struct tm *timeptr)
+{
+       static char timebuf[26];
+
+       if (timeptr == 0)
+               return 0;
+       __asctime(timebuf, timeptr);
+       return timebuf;
+}
diff --git a/Library/libs/assert.c b/Library/libs/assert.c
new file mode 100644 (file)
index 0000000..76981c9
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+#include <unistd.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <assert.h>\r
+\r
+void __errput(char *str) \r
+{
+       write(2, str, strlen(str));
+}\r
+\r
+void __assert(char *assertion, char *filename, int linenumber) \r
+{
+       __errput("Failed '");
+       __errput(assertion);
+       __errput("', file ");
+       __errput(filename);
+       __errput(", line ");
+       __errput(_itoa(linenumber));
+       __errput(".\n");
+       abort();
+} \r
diff --git a/Library/libs/atexit.c b/Library/libs/atexit.c
new file mode 100644 (file)
index 0000000..816f527
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+/*
+ * This deals with both the atexit and on_exit function calls
+ *
+ * Note: calls installed with atexit are called with the same args as
+ * on_exit fuctions; the void* is given the NULL value.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+/* ATEXIT.H */
+#define MAXONEXIT 10           /* AIUI Posix requires 10 */
+
+typedef void (*vfuncp) (int, void *);
+
+extern struct exit_table {
+       onexit_t called;
+       void *argument;
+} __on_exit_table[MAXONEXIT];
+
+extern int __on_exit_count;
+
+/* End ATEXIT.H */
+int __on_exit_count = 0;
+struct exit_table __on_exit_table[MAXONEXIT];
+
+void __do_exit(int rv)
+{
+       register int count = __on_exit_count - 1;
+       register vfuncp ptr;
+       __on_exit_count = -1;   /* ensure no more will be added */
+
+       /* In reverse order */
+       while (count >= 0) {
+               ptr = (vfuncp) __on_exit_table[count].called;
+               (*ptr) (rv, __on_exit_table[count].argument);
+               --count;
+       }
+}
+
+int on_exit(onexit_t ptr, void *arg)
+{
+       if (__on_exit_count < 0 || __on_exit_count >= MAXONEXIT) {
+               errno = ENOMEM;
+               return -1;
+       }
+       if (ptr) {
+               __on_exit_table[__on_exit_count].called = ptr;
+               __on_exit_table[__on_exit_count].argument = arg;
+               __on_exit_count++;
+       }
+       return 0;
+}
+
+int atexit(atexit_t ptr)
+{
+       return on_exit((onexit_t) ptr, 0);
+}
diff --git a/Library/libs/atof.c b/Library/libs/atof.c
new file mode 100644 (file)
index 0000000..87cfc3a
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) Robert de Bath <robert@debath.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <stdlib.h>
+
+double atof(const char *p)
+{
+   return strtod(p, (char**)0);
+}
diff --git a/Library/libs/atoi.c b/Library/libs/atoi.c
new file mode 100644 (file)
index 0000000..6bd9e09
--- /dev/null
@@ -0,0 +1,11 @@
+/* numeric/string conversions package\r
+ */  \r
+    \r
+#include <stdlib.h>\r
+    \r
+/**************************** atoi.c ****************************/ \r
+int atoi(char *str) \r
+{
+       return (int) strtol(str, NULL, 10);
+}\r
\r
diff --git a/Library/libs/atol.c b/Library/libs/atol.c
new file mode 100644 (file)
index 0000000..3d517f0
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+long atol(char *number)
+{
+   register long   n = 0, neg = 0;
+
+   while (*number <= ' ' && *number > 0)
+      ++number;
+   if (*number == '-')
+   {
+      neg = 1;
+      ++number;
+   }
+   else if (*number == '+')
+      ++number;
+   while (*number>='0' && *number<='9')
+      n = (n * 10) + ((*number++) - '0');
+   return (neg ? -n : n);
+}
diff --git a/Library/libs/bcmp.c b/Library/libs/bcmp.c
new file mode 100644 (file)
index 0000000..4f5f80d
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <sys/types.h>
+
+int bcmp(const void *dest, const void *src, int len)
+{
+   return memcmp(dest, src, len);
+}
diff --git a/Library/libs/bcopy.c b/Library/libs/bcopy.c
new file mode 100644 (file)
index 0000000..93de604
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ *
+ * Fixed to use memmove - AC 2014
+ */
+#include <string.h>
+#include <sys/types.h>
+
+void bcopy(const void *src, void *dest, size_t len)
+{
+   (void)memmove(dest, src, len);
+}
diff --git a/Library/libs/bsearch.c b/Library/libs/bsearch.c
new file mode 100644 (file)
index 0000000..13b8b19
--- /dev/null
@@ -0,0 +1,37 @@
+
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ */
+#include <stdio.h>
+
+static int _bsearch;           /* index of element found, or where to
+                                * insert */
+
+char *bsearch(char *key, char *base, int num, int size,
+             int (*cmp) (char *, char *))
+{
+       int a, b, c, dir;
+
+       a = 0;
+       b = num - 1;
+       while (a <= b) {
+               c = (a + b) >> 1;       /* == ((a + b) / 2) */
+               if (dir = (*cmp) ((base + (c * size)), key)) {
+                       if (dir > 0)
+                               b = c - 1;
+                       else    /* (dir < 0) */
+                               a = c + 1;
+               } else {
+                       _bsearch = c;
+                       return (base + (c * size));
+               }
+       }
+       _bsearch = b;
+       return (NULL);
+}
diff --git a/Library/libs/bzero.c b/Library/libs/bzero.c
new file mode 100644 (file)
index 0000000..64d3d43
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <sys/types.h>
+
+void bzero(void *dest, int len)
+{
+   (void) memset(dest, '\0', len);
+}
diff --git a/Library/libs/calloc.c b/Library/libs/calloc.c
new file mode 100644 (file)
index 0000000..c694984
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ *\r
+ * This is a combined alloca/malloc package. It uses a classic algorithm\r
+ * and so may be seen to be quite slow compared to more modern routines\r
+ * with 'nasty' distributions.\r
+ */  \r
+    \r
+#include "malloc-l.h"\r
+\r
+void *calloc(unsigned int elm, unsigned int sz) \r
+{
+       register unsigned v = elm * sz;
+       register void *ptr = malloc(v);
+       \r
+       if (ptr)
+               memset(ptr, 0, v);
+       return ptr;
+}
diff --git a/Library/libs/cfmakeraw.c b/Library/libs/cfmakeraw.c
new file mode 100644 (file)
index 0000000..e0d24f2
--- /dev/null
@@ -0,0 +1,11 @@
+#include <termios.h>
+#include <unistd.h>
+
+void cfmakeraw(struct termios *p)
+{
+  p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXANY | IXOFF);
+  p->c_oflag &= ~OPOST;
+  p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+  p->c_cflag &= ~(CSIZE | PARENB);
+  p->c_cflag |= CS8;
+}
diff --git a/Library/libs/cfree.c b/Library/libs/cfree.c
new file mode 100644 (file)
index 0000000..bc3b27e
--- /dev/null
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <stdlib.h>
+
+void cfree(void *ptr, size_t nelem, size_t elsize)
+{
+  free(ptr);
+}
diff --git a/Library/libs/cfspeed.c b/Library/libs/cfspeed.c
new file mode 100644 (file)
index 0000000..f7b4d67
--- /dev/null
@@ -0,0 +1,31 @@
+#include <termios.h>
+#include <unistd.h>
+
+speed_t cfgetispeed(const struct termios *p)
+{
+  return p->c_cflag&CBAUD;
+}
+
+speed_t cfgetospeed(const struct termios *p)
+{
+  return p->c_cflag&CBAUD;
+}
+
+int cfsetspeed(struct termios *p, speed_t s)
+{
+  if (s & ~CBAUD)      /* Invalid bits ? */
+    return -1;
+  p->c_cflag &= ~CBAUD;
+  p->c_cflag |= s;
+  return 0;
+}
+
+int cfsetispeed(struct termios *p, speed_t s)
+{
+  return cfsetspeed(p,s);
+}
+
+int cfsetospeed(struct termios *p, speed_t s)
+{
+  return cfsetspeed(p,s);
+}
diff --git a/Library/libs/clock.c b/Library/libs/clock.c
new file mode 100644 (file)
index 0000000..9f9240c
--- /dev/null
@@ -0,0 +1,18 @@
+/*************************** CLOCK ************************************/  \r
+\r
+#include <types.h>\r
+#include <unistd.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include <sys/times.h>\r
+\r
+/* FIXME: CLOCKS_PER_SEC query */\r
+\r
+clock_t clock(void)
+{
+       struct tms __tms;
+       times(&__tms);
+       return (__tms.tms_utime * CLOCKS_PER_SEC);
+}
+
+\r
diff --git a/Library/libs/closedir.c b/Library/libs/closedir.c
new file mode 100644 (file)
index 0000000..98ae649
--- /dev/null
@@ -0,0 +1,24 @@
+/* close.c      closedir implementation
+ *
+ */
+#include <unistd.h>
+#include <alloc.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+int closedir(DIR * dir)
+{
+       if (dir == NULL || dir->dd_buf == NULL || dir->dd_fd == 0) {
+               errno = EFAULT;
+               return -1;
+       }
+       close(dir->dd_fd);
+       free(dir->dd_buf);
+       dir->dd_fd = 0;
+       dir->dd_buf = NULL;
+       free(dir);
+       return 0;
+}
diff --git a/Library/libs/config-getent.h b/Library/libs/config-getent.h
new file mode 100644 (file)
index 0000000..8d9567d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * config-grp.h - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef _CONFIG_GRP_H
+#define _CONFIG_GRP_H
+
+/*
+ * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
+ * so that lines of any length can be used.  On very very small systems,
+ * you may want to leave this undefined becasue it will make the grp functions
+ * somewhat larger (because of the inclusion of malloc and the code necessary).
+ * On larger systems, you will want to define this, because grp will _not_
+ * deal with long lines gracefully (they will be skipped).
+ */
+#define GR_SCALE_DYNAMIC
+
+#ifndef GR_SCALE_DYNAMIC
+/*
+ * If scaling is not dynamic, the buffers will be statically allocated, and
+ * maximums must be chosen.  GR_MAX_LINE_LEN is the maximum number of
+ * characters per line in the group file.  GR_MAX_MEMBERS is the maximum
+ * number of members of any given group.
+ */
+#define GR_MAX_LINE_LEN 128
+/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
+#define GR_MAX_MEMBERS 11
+
+#endif /* !GR_SCALE_DYNAMIC */
+
+
+/*
+ * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
+ * space for it's GID array before calling setgroups().  This is probably
+ * unnecessary scalage, so it's undefined by default.
+ */
+#undef GR_DYNAMIC_GROUP_LIST
+
+#ifndef GR_DYNAMIC_GROUP_LIST
+
+#endif /* !GR_DYNAMIC_GROUP_LIST */
+
+#endif /* !_CONFIG_GRP_H */
diff --git a/Library/libs/config-grp.h b/Library/libs/config-grp.h
new file mode 100644 (file)
index 0000000..159f1c9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * config-grp.h - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef _CONFIG_GRP_H
+#define _CONFIG_GRP_H
+
+/*
+ * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
+ * so that lines of any length can be used.  On very very small systems,
+ * you may want to leave this undefined becasue it will make the grp functions
+ * somewhat larger (because of the inclusion of malloc and the code necessary).
+ * On larger systems, you will want to define this, because grp will _not_
+ * deal with long lines gracefully (they will be skipped).
+ */
+#define GR_SCALE_DYNAMIC
+
+#ifndef GR_SCALE_DYNAMIC
+/*
+ * If scaling is not dynamic, the buffers will be statically allocated, and
+ * maximums must be chosen.  GR_MAX_LINE_LEN is the maximum number of
+ * characters per line in the group file.  GR_MAX_MEMBERS is the maximum
+ * number of members of any given group.
+ */
+#define GR_MAX_LINE_LEN 128
+/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
+#define GR_MAX_MEMBERS 11
+
+#endif /* !GR_SCALE_DYNAMIC */
+
+
+/*
+ * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
+ * space for it's GID array before calling setgroups().  This is probably
+ * unnecessary scalage, so it's undefined by default.
+ */
+#undef GR_DYNAMIC_GROUP_LIST
+
+
+#endif /* !_CONFIG_GRP_H */
diff --git a/Library/libs/confstr.c b/Library/libs/confstr.c
new file mode 100644 (file)
index 0000000..1fedffb
--- /dev/null
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <errno.h>
+
+size_t confstr(int name, char *buf, size_t len)
+{
+  errno = EINVAL;
+  return 0;
+}
diff --git a/Library/libs/creat.c b/Library/libs/creat.c
new file mode 100644 (file)
index 0000000..0348e56
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <unistd.h>
+#include <fcntl.h>
+
+int creat(__const char * file, mode_t mode)
+{
+  return open(file, O_TRUNC|O_CREAT|O_WRONLY, mode);
+}
diff --git a/Library/libs/crt0.s b/Library/libs/crt0.s
new file mode 100644 (file)
index 0000000..daf4f7f
--- /dev/null
@@ -0,0 +1,79 @@
+               .module crt0
+
+               .area _CODE
+               .area _HOME
+               .area _CONST
+               ; The _GS can be blown away after startup. We don't yet
+               ; but we should do FIXME
+               .area _GSINIT
+               .area _GSFINAL
+               .area _INITIALIZED
+               .area _BSEG
+               .area _DATA
+               .area _BSS
+               ; note that the binary builder moves the initialized data
+               ; from initializer
+               .area _INITIALIZER
+
+               .globl ___stdio_init_vars
+               .globl _main
+               .globl _exit
+               .globl _environ
+
+               .globl s__DATA
+               .globl s__BSS
+               .globl l__DATA
+               .globl l__BSS
+
+               .area _CODE
+
+               .ds 0x100
+; start at 0x100
+start:         jp start2
+               .db 'F'
+               .db 'Z'
+               .db 'X'
+               .db '1'
+
+;
+;      Borrowed idea from UMZIX - put the info in known places then
+;      we can write "size" tools
+;
+               .dw 0                   ; chmem ("0 - 'all'")
+               .dw s__DATA             ; gives us code size info
+               .dw s__BSS              ; gives us data size info
+               .dw l__BSS              ; bss size info
+               .dw 0                   ; spare
+
+start2:                ld hl, #l__DATA - 1      ; work around linker limit
+               ld de, #l__BSS
+               add hl, de
+               ld b, h
+               ld c, l
+               ld hl, #s__DATA
+               ld de, #s__DATA+1
+               ld (hl), #0
+               ldir
+               call gsinit
+               pop hl                  ; environ
+               ld (_environ), hl
+               pop de                  ; argv
+               pop bc                  ; argc
+               ld hl, #_exit           ; return vector
+               ex (sp), hl             ; swap it with the provided
+               push bc                 ; return address
+               push de                 ; re-stack arguments
+               jp _main                ; go
+
+               .area _GSINIT
+gsinit:
+               call ___stdio_init_vars
+;
+;      Any gsinit code from other modules will accumulate between here
+;      and _GSFINAL to provide constructors and other ghastly C++isms
+;
+               .area _GSFINAL
+               ret
+
+               .area _DATA
+_environ:      .dw 0
diff --git a/Library/libs/crypt.c b/Library/libs/crypt.c
new file mode 100644 (file)
index 0000000..754e2c8
--- /dev/null
@@ -0,0 +1,69 @@
+/* TEA based crypt(), version 0.0 <ndf@linux.mit.edu>\r
+ * It looks like there are problems with key bits carrying through\r
+ * to the encrypted data, and I want to get rid of that libc call..\r
+ */  \r
+#include <features.h>\r
+#include <stdlib.h>\r
+#include <memory.h>\r
+\r
+char *crypt(char *key, char *salt) \r
+{
+       \r
+           /* n is the number of rounds,\r
+            * delta is a golden # derivative,\r
+            * k is the key,\r
+            * v is the data to be encrypted.\r
+            */ \r
+       static char rkey[4 * sizeof(long)];
+       unsigned long v[2], k[4], sum, delta = 0x9e3779b9UL, *p;
+       unsigned char i, n;
+        \r
+       /* Our constant string will be a string of zeros .. */ \r
+       memset(rkey, 0, sizeof(rkey));
+       memcpy(rkey, salt, 2);
+\r
+       i = 0;
+       while (i < sizeof(rkey) - 2 && key[i]) {
+               rkey[i + 2] = key[i];
+               ++i;
+       }
+       while (key[i]) {
+               rkey[2] += key[i];
+               ++i;
+       }
+       memcpy(k, rkey, sizeof(k));
+       v[0] = v[1] = sum = 0;
+       for (i = 64; i != 0; --i) {
+               sum += delta;
+               v[0] +=
+                   (v[1] << 4) + k[0] ^ v[1] + sum ^ (v[1] >> 5) + k[1];
+               v[1] +=
+                   (v[0] << 4) + k[2] ^ v[0] + sum ^ (v[0] >> 5) + k[3];
+        }
+       \r
+       /* Now we need to unpack the bits and map it to "A-Za-z0-9./"\r
+        * for printing in /etc/passwd\r
+        */ \r
+       p = v;
+       for (i = 2; i < 13; i++) {
+               /* This unpacks the 6 bit data, each cluster into its own byte */ \r
+               if (i == 8) {
+                       v[0] |= v[1] >> 28;
+                       ++p;
+               }
+               n = *p & 0x3F;
+               *p >>= 6;
+               \r
+               /* Now we map to the proper chars */ \r
+               if (n < 12)
+                       n += '.';
+               else if (n < 38)
+                       n += 'A' - 12;
+               else
+                       n += 'a' - 38;
+               rkey[i] = n;
+       }
+       rkey[13] = '\0';
+       return rkey;
+}
+\r
diff --git a/Library/libs/ctime.c b/Library/libs/ctime.c
new file mode 100644 (file)
index 0000000..ece4eeb
--- /dev/null
@@ -0,0 +1,9 @@
+/*************************** CTIME ************************************/  \r
+    \r
+#include <time.h>\r
+#include <string.h>\r
+\r
+char *ctime(time_t * timep) \r
+{
+       return asctime(localtime(timep));
+}
diff --git a/Library/libs/ctype.c b/Library/libs/ctype.c
new file mode 100644 (file)
index 0000000..05efa46
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+ *  CTYPE.C    Character classification and conversion\r
+ */  \r
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */ \r
+#include <types.h>\r
+#include <ctype.h>\r
+    \r
+#undef toupper\r
+#undef tolower\r
+\r
+unsigned char __ctype[256] = { \r__CT_c, __CT_c, __CT_c, __CT_c, /* 0x00..0x03 */ \r
+           __CT_c, __CT_c, __CT_c, __CT_c, /* 0x04..0x07 */ \r
+           __CT_c, __CT_c | __CT_s, __CT_c | __CT_s, __CT_c | __CT_s, /* 0x08..0x0B */ \r
+           __CT_c | __CT_s, __CT_c | __CT_s, __CT_c, __CT_c, /* 0x0C..0x0F */ \r
+           __CT_c, __CT_c, __CT_c, __CT_c, /* 0x10..0x13 */ \r
+           __CT_c, __CT_c, __CT_c, __CT_c, /* 0x14..0x17 */ \r
+           __CT_c, __CT_c, __CT_c, __CT_c, /* 0x18..0x1B */ \r
+           __CT_c, __CT_c, __CT_c, __CT_c, /* 0x1C..0x1F */ \r
+           __CT_s, __CT_p, __CT_p, __CT_p, /* 0x20..0x23 */ \r
+           __CT_p, __CT_p, __CT_p, __CT_p, /* 0x24..0x27 */ \r
+           __CT_p, __CT_p, __CT_p, __CT_p, /* 0x28..0x2B */ \r
+           __CT_p, __CT_p, __CT_p, __CT_p, /* 0x2C..0x2F */ \r
+           __CT_d | __CT_x, __CT_d | __CT_x, __CT_d | __CT_x,
+           __CT_d | __CT_x, /* 0x30..0x33 */ \r
+           __CT_d | __CT_x, __CT_d | __CT_x, __CT_d | __CT_x,
+           __CT_d | __CT_x, /* 0x34..0x37 */ \r
+           __CT_d | __CT_x, __CT_d | __CT_x, __CT_p, __CT_p, /* 0x38..0x3B */ \r
+           __CT_p, __CT_p, __CT_p, __CT_p, /* 0x3C..0x3F */ \r
+           __CT_p, __CT_u | __CT_x, __CT_u | __CT_x, __CT_u | __CT_x, /* 0x40..0x43 */ \r
+           __CT_u | __CT_x, __CT_u | __CT_x, __CT_u | __CT_x, __CT_u, /* 0x44..0x47 */ \r
+           __CT_u, __CT_u, __CT_u, __CT_u, /* 0x48..0x4B */ \r
+           __CT_u, __CT_u, __CT_u, __CT_u, /* 0x4C..0x4F */ \r
+           __CT_u, __CT_u, __CT_u, __CT_u, /* 0x50..0x53 */ \r
+           __CT_u, __CT_u, __CT_u, __CT_u, /* 0x54..0x57 */ \r
+           __CT_u, __CT_u, __CT_u, __CT_p, /* 0x58..0x5B */ \r
+           __CT_p, __CT_p, __CT_p, __CT_p, /* 0x5C..0x5F */ \r
+           __CT_p, __CT_l | __CT_x, __CT_l | __CT_x, __CT_l | __CT_x, /* 0x60..0x63 */ \r
+           __CT_l | __CT_x, __CT_l | __CT_x, __CT_l | __CT_x, __CT_l, /* 0x64..0x67 */ \r
+           __CT_l, __CT_l, __CT_l, __CT_l, /* 0x68..0x6B */ \r
+           __CT_l, __CT_l, __CT_l, __CT_l, /* 0x6C..0x6F */ \r
+           __CT_l, __CT_l, __CT_l, __CT_l, /* 0x70..0x73 */ \r
+           __CT_l, __CT_l, __CT_l, __CT_l, /* 0x74..0x77 */ \r
+           __CT_l, __CT_l, __CT_l, __CT_p, /* 0x78..0x7B */ \r
+           __CT_p, __CT_p, __CT_p, __CT_c /* 0x7C..0x7F */  \r
+};
+
+int toupper(int c) \r
+{
+       return (islower(c) ? (c ^ 0x20) : (c));
+}
+
+int tolower(int c) \r
+{
+       return (isupper(c) ? (c ^ 0x20) : (c));
+}
diff --git a/Library/libs/difftime.c b/Library/libs/difftime.c
new file mode 100644 (file)
index 0000000..fc12a85
--- /dev/null
@@ -0,0 +1,22 @@
+/*************************** DIFFTIME **********************************/ 
+
+#include <time.h>
+#include <string.h>
+
+double difftime(time_t * __time2, time_t * __time1)
+{
+       struct tm tma, tmb;
+       unsigned long tm1, tm2;
+       __tm_conv(&tma, __time1, 0);
+       __tm_conv(&tmb, __time2, 0);
+       
+       /* each year is 365 days plus 8 hours = 365.25 days */ \r
+       tm1 =
+           tma.tm_year * 32227200L + tma.tm_yday * 86400L +
+           tma.tm_hour * 3600 + \rtma.tm_min * 60 + tma.tm_sec;
+       tm2 =
+           tmb.tm_year * 32227200L + tmb.tm_yday * 86400L +
+           tmb.tm_hour * 3600 + \rtmb.tm_min * 60 + tmb.tm_sec;
+       return (tm2 - tm1);
+}
+
diff --git a/Library/libs/errno.c b/Library/libs/errno.c
new file mode 100644 (file)
index 0000000..d013499
--- /dev/null
@@ -0,0 +1,3 @@
+#include <errno.h>
+
+int errno;
diff --git a/Library/libs/error.c b/Library/libs/error.c
new file mode 100644 (file)
index 0000000..a6f3980
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 1996 Robert de Bath <robert@debath.thenet.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+#include <unistd.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <paths.h>\r
+#include <errno.h>\r
+\r
+char **__sys_errlist = 0;
+int __sys_nerr = 0;
+\r
+char *strerror(int err) \r
+{
+       static char retbuf[80];
+       char *p, inbuf[128];
+       int cc, fd;
+       uint i, bufoff = 0;
+       if (__sys_nerr) {       /* sys_errlist preloaded */
+               if (err < 0 || err >= __sys_nerr)
+                       goto UErr;
+               return __sys_errlist[err];
+       }
+       if (err <= 0)
+               goto UErr;      /* NB the <= allows comments in the file */
+       if ((fd = open(_PATH_LIBERR, 0)) < 0)
+               goto UErr;
+       while ((cc = read(fd, inbuf, sizeof(inbuf))) > 0) {
+               i = 0;
+               while (i < cc) {
+                       if (inbuf[i] == '\n') {
+                               retbuf[bufoff] = '\0';
+                               if (err == atoi(retbuf)) {
+                                       if ((p = strchr(retbuf,' ')) == NULL) {
+                                               close(fd);
+                                               goto UErr;
+                                       }
+                                       while (*p == ' ')
+                                               p++;
+                                       close(fd);
+                                       return p;
+                               }
+                               bufoff = 0;
+                       }
+                       else if (bufoff < sizeof(retbuf) - 1)
+                               retbuf[bufoff++] = inbuf[i];
+                       ++i;
+               }
+       }
+UErr:  strcpy(retbuf, "Unknown error ");
+       itoa(err, retbuf + strlen(retbuf), 10);
+       return retbuf;
+}
diff --git a/Library/libs/execl.c b/Library/libs/execl.c
new file mode 100644 (file)
index 0000000..3bd1e6a
--- /dev/null
@@ -0,0 +1,62 @@
+/* execl.c\r
+ *\r
+ * function(s)\r
+ *       execl - load and run a program\r
+ */  \r
+    \r
+#include <unistd.h>\r
+#include <paths.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+    \r
+/* Find file in pathes:\r
+ * 1. /name or ./name or ../name is already qualified names\r
+ * 2. else search in all pathes described in env var PATH (if this\r
+ *    var is not exist, _PATH_DEFPATH is used)\r
+ * 3. else search in current directory\r
+ * 4. else return NULL (execve() interpretes NULL as non existent file!)\r
+ */ \r
+char *_findPath(char *path) \r
+{
+       char *p;\r
+       const char *envp;
+       static char name[PATHLEN + 1];
+       if (*path == '/' || /* qualified name */ *path == '.')
+               return path;
+\r
+       /* search for pathes list */ \r
+       if ((envp = getenv("PATH")) == NULL)
+               envp = _PATH_DEFPATH;
+\r
+       /* lookup all pathes */ \r
+       while (*envp) {
+               p = name;
+               while (*envp && (*p = *envp++) != ':') {
+                       if ((uint) (p - name) >= sizeof(name))
+                               break;
+                       ++p;
+               }
+               if (*--p != '/')
+                       *++p = '/';
+               ++p;
+               if ((p - name) + strlen(path) >= sizeof(name))
+                       break;
+               strcpy(p, path);
+               if (access(name, 0) == 0)
+                       return name;
+       }
+       if (access(path, 0) == 0)       /* file exist in current dir */
+               return name;
+       return NULL;
+}
+
+int execl(char *pathP, char *arg0) \r
+{
+       return execve(pathP, &arg0, environ);
+}
+\r
+int execlp(char *pathP, char *arg0) \r
+{
+       return execve(_findPath(pathP), &arg0, environ);
+}
diff --git a/Library/libs/execv.c b/Library/libs/execv.c
new file mode 100644 (file)
index 0000000..ec9c20b
--- /dev/null
@@ -0,0 +1,15 @@
+/* execv.c\r
+ *\r
+ * function(s)\r
+ *       execv - load and execute a program\r
+ */  \r
+    \r
+#include <unistd.h>\r
+#include <paths.h>\r
+\r
+int execv(char *pathP, char *argv[]) \r
+{
+       return execve(pathP, argv, environ);
+}
+
+\r
diff --git a/Library/libs/execvp.c b/Library/libs/execvp.c
new file mode 100644 (file)
index 0000000..85adcb8
--- /dev/null
@@ -0,0 +1,13 @@
+/* execvp.c\r
+ *\r
+ * function(s)\r
+ *       execvp - load and execute a program\r
+ */  \r
+    \r
+#include <unistd.h>\r
+#include <paths.h>\r
+\r
+int execvp(char *pathP, char *argv[]) \r
+{
+       return execve(_findPath(pathP), argv, environ);
+}
diff --git a/Library/libs/exit.c b/Library/libs/exit.c
new file mode 100644 (file)
index 0000000..c8584c2
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *     Wrapper for clean up and then exit to the kernel
+ *     via _exit
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+extern void __do_exit(int rv);
+
+void exit(int status)
+{
+  __do_exit(status);
+  _exit(status);
+}
\ No newline at end of file
diff --git a/Library/libs/fclose.c b/Library/libs/fclose.c
new file mode 100644 (file)
index 0000000..c9a49cb
--- /dev/null
@@ -0,0 +1,45 @@
+/* stdio.c
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is an implementation of the C standard IO package. */
+
+#include "stdio-l.h"
+
+int fclose(FILE * fp)
+{
+       int rv = 0;
+
+       if (fp == 0) {
+               errno = EINVAL;
+               return EOF;
+       }
+       if (fflush(fp))
+               return EOF;
+       if (close(fp->fd))
+               rv = EOF;
+       fp->fd = -1;
+       if (fp->mode & __MODE_FREEBUF) {
+               free(fp->bufstart);
+               fp->mode &= ~__MODE_FREEBUF;
+               fp->bufstart = fp->bufend = 0;
+       }
+       if (fp->mode & __MODE_FREEFIL) {
+               FILE *ptr = __IO_list, *prev = 0;
+
+               fp->mode = 0;
+               while (ptr && ptr != fp)
+                       ptr = ptr->next;
+               if (ptr == fp) {
+                       if (prev == 0)
+                               __IO_list = fp->next;
+                       else
+                               prev->next = fp->next;
+               }
+               free(fp);
+       } else
+               fp->mode = 0;
+       return rv;
+}
diff --git a/Library/libs/fflush.c b/Library/libs/fflush.c
new file mode 100644 (file)
index 0000000..c4be969
--- /dev/null
@@ -0,0 +1,70 @@
+/* stdio.c
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is an implementation of the C standard IO package. */
+
+#include "stdio-l.h"
+
+int fflush(FILE * fp)
+{
+       unsigned char *bstart;
+       int len, cc, rv = 0;
+
+       if (fp == NULL) {       /* On NULL flush the lot. */
+               if (fflush(stdin) || fflush(stdout) || fflush(stderr))
+                       return EOF;
+               fp = __IO_list;
+               while (fp) {
+                       if (fflush(fp))
+                               return EOF;
+                       fp = fp->next;
+               }
+               return 0;
+       }
+       /* If there's output data pending */
+       if (fp->mode & __MODE_WRITING) {
+               if ((len = fp->bufpos - fp->bufstart) != 0) {
+                       bstart = fp->bufstart;
+                       /* The loop is so we don't get upset by signals
+                        * or partial writes.
+                        */
+                       do {
+                               if ((cc = write(fp->fd, bstart, len)) > 0) {
+                                       bstart += cc;
+                                       len -= cc;
+                               }
+                       } while (cc > 0 || (cc == -1 && errno == EINTR));
+                       /* If we get here with len != 0 there was an error,
+                        * exactly what to do about it is another matter ...
+                        *
+                        * I'll just clear the buffer. */
+                       if (len) {
+                               fp->mode |= __MODE_ERR;
+                               rv = EOF;
+                       }
+               }
+       }
+       /* If there's data in the buffer sychronise the file positions */
+       else if (fp->mode & __MODE_READING) {
+               /* Humm, I think this means sync the file like fpurge() ...
+                * Anyway the user isn't supposed to call this function
+                * when reading
+                */
+               len = fp->bufread - fp->bufpos; /* Bytes buffered but unread */
+               /* If it's a file, make it good */
+               if (len > 0 && lseek(fp->fd, (long) -len, SEEK_CUR) < 0) {
+                       /* Hummm - Not certain here, I don't think this is reported */
+                       /* fp->mode |= __MODE_ERR; return EOF; */
+               }
+       }
+       /* All done, no problem */
+       fp->mode &=
+           (~
+            (__MODE_READING | __MODE_WRITING | __MODE_EOF |
+             __MODE_UNGOT));
+       fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart;
+       return rv;
+}
diff --git a/Library/libs/fgetc.c b/Library/libs/fgetc.c
new file mode 100644 (file)
index 0000000..01f154a
--- /dev/null
@@ -0,0 +1,33 @@
+/* stdio.c
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is an implementation of the C standard IO package. */
+
+#include "stdio-l.h"
+
+int fgetc(FILE * fp)
+{
+       int ch;
+
+       if (fp->mode & __MODE_WRITING)
+               fflush(fp);
+       /* Can't read or there's been an EOF or error then return EOF */
+       if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) !=
+           __MODE_READ)
+               return EOF;
+       /* Nothing in the buffer - fill it up */
+       if (fp->bufpos >= fp->bufread) {
+               fp->bufpos = fp->bufread = fp->bufstart;
+               ch = fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp);
+               if (ch == 0)
+                       return EOF;
+               fp->bufread += ch;
+               fp->mode |= __MODE_READING;
+               fp->mode &= ~__MODE_UNGOT;
+       }
+       ch = *(fp->bufpos++);
+       return ch;
+}
diff --git a/Library/libs/fgetgrent.c b/Library/libs/fgetgrent.c
new file mode 100644 (file)
index 0000000..800236f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * fgetgrent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <grp.h>
+
+struct group *
+fgetgrent(FILE * file)
+{
+  if (file==NULL)
+    {
+      errno=EINTR;
+      return NULL;
+    }
+  
+  return __getgrent(fileno(file));
+}
diff --git a/Library/libs/fgetpos.c b/Library/libs/fgetpos.c
new file mode 100644 (file)
index 0000000..76e1f6a
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int fgetpos(FILE *fp, fpos_t *pos)
+{
+   long l;
+
+   if (fflush(fp) == EOF)
+      return EOF;
+
+   l = lseek(fp->fd, 0L, SEEK_CUR);
+   if (l < 0)
+      return l;
+   *pos = l;
+   return 0;
+}
diff --git a/Library/libs/fgetpwent.c b/Library/libs/fgetpwent.c
new file mode 100644 (file)
index 0000000..e12b890
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * fgetpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <pwd.h>
+
+struct passwd *
+fgetpwent(FILE * file)
+{
+  if (file==NULL)
+    {
+      errno=EINTR;
+      return NULL;
+    }
+
+  return __getpwent(fileno(file));
+}
diff --git a/Library/libs/fgets.c b/Library/libs/fgets.c
new file mode 100644 (file)
index 0000000..d3fe0f7
--- /dev/null
@@ -0,0 +1,30 @@
+/* stdio.c
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is an implementation of the C standard IO package. */
+
+#include "stdio-l.h"
+
+/* Nothing special here ... */
+char *fgets(char *s, size_t count, FILE * f)
+{
+       register size_t i = count;
+       register int ch;
+       char *ret = s;
+
+       while (i-- != 0) {
+               if ((ch = getc(f)) == EOF) {
+                       if (s == ret)
+                               return NULL;
+                       break;
+               }
+               *s++ = (char) ch;
+               if (ch == '\n')
+                       break;
+       }
+       *s = 0;
+       return ferror(f) ? NULL : ret;
+}
diff --git a/Library/libs/fopen.c b/Library/libs/fopen.c
new file mode 100644 (file)
index 0000000..a8ee10b
--- /dev/null
@@ -0,0 +1,110 @@
+/* stdio.c\r
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+/* This is an implementation of the C standard IO package. */ \r
+    \r
+#include "stdio-l.h"\r
+    \r
+/*\r
+ * This Fopen is all three of fopen, fdopen and freopen. The macros in\r
+ * stdio.h show the other names.\r
+ */ \r
+\r
+FILE * __fopen(char *fname, int fd, FILE * fp, char *mode) \r
+{
+       uint open_mode = 0;
+       \r
+       int fopen_mode = 0;
+       FILE * nfp = 0;
+        \r
+       /* If we've got an fp close the old one (freopen) */ \r
+       if (fp) {
+               /* Careful, don't de-allocate it */ \r
+               fopen_mode |= (fp->mode & (__MODE_BUF | __MODE_FREEFIL |__MODE_FREEBUF));
+               fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF);
+               fclose(fp);
+       }
+       \r
+       /* decode the new open mode */ \r
+       while (*mode) {
+               switch (*mode++) {
+               case 'r':
+                       fopen_mode |= __MODE_READ;
+                       break;
+               \rcase 'w':
+                       fopen_mode |= __MODE_WRITE;
+                       open_mode = (O_CREAT | O_TRUNC);
+                       break;
+               \rcase 'a':
+                       fopen_mode |= __MODE_WRITE;
+                       open_mode = (O_CREAT | O_APPEND);
+                       break;
+               \rcase '+':
+                       fopen_mode |= __MODE_RDWR;
+                       break;
+               }
+       }
+\r
+       /* Add in the read/write options to mode for open() */ \r
+       switch (fopen_mode & (__MODE_READ | __MODE_WRITE)) {
+       case 0:
+               return NULL;
+       case __MODE_READ:
+               open_mode |= O_RDONLY;
+               break;
+       case __MODE_WRITE:
+               open_mode |= O_WRONLY;
+               break;
+       default:
+               open_mode |= O_RDWR;
+               break;
+       }
+\r
+       /* Allocate the (FILE) before we do anything irreversable */ \r
+       if (fp == NULL && (nfp = calloc(1, sizeof(FILE))) == NULL)
+               return NULL;
+       \r
+       /* Open the file itself */ \r
+       if (fname)
+               fd = open(fname, open_mode, 0666);
+       if (fd < 0) {           /* Grrrr */
+               if (nfp)
+                       free(nfp);
+               return 0;
+       }
+       \r
+       /* If this isn't freopen create a (FILE) and buffer for it */ \r
+       if (fp == NULL) {
+               fp = nfp;
+               fp->next = __IO_list;
+               __IO_list = fp; /* add to list */
+               fp->mode = __MODE_FREEFIL;
+               if (isatty(fd))
+                       fp->mode |= _IOLBF;
+#if _IOFBF\r
+               else
+                       fp->mode |= _IOFBF;
+               \r
+#endif
+               if ((fp->bufstart = calloc(1, BUFSIZ)) == NULL) {
+                       /* Oops, no mem\r
+                        * Humm, full buffering with a eight(!) byte buffer.\r
+                        */ \r
+                       fp->bufstart = (uchar *) fp->unbuf;
+                       fp->bufend = (uchar *) fp->unbuf + sizeof(fp->unbuf);
+               } else {
+                       fp->bufend = fp->bufstart + BUFSIZ;
+                       fp->mode |= __MODE_FREEBUF;
+               }
+       }
+       \r
+       /* Ok, file's ready clear the buffer and save important bits */ \r
+       fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+       fp->mode |= fopen_mode;
+       fp->fd = fd;
+       return fp;
+}
\r
diff --git a/Library/libs/fprintf.c b/Library/libs/fprintf.c
new file mode 100644 (file)
index 0000000..fbde805
--- /dev/null
@@ -0,0 +1,26 @@
+/* printf.c
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *
+ * Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include "printf.h"
+
+int fprintf(FILE * fp, char *fmt, ...)
+{
+       va_list ptr;
+       int rv;
+
+       va_start(ptr, fmt);
+       rv = vfprintf(fp, fmt, ptr);
+       va_end(ptr);
+       return rv;
+}
diff --git a/Library/libs/fputc.c b/Library/libs/fputc.c
new file mode 100644 (file)
index 0000000..4622a7d
--- /dev/null
@@ -0,0 +1,31 @@
+#include "stdio-l.h"
+
+int fputc(int ch, FILE * fp)
+{
+       register int v;
+
+       v = fp->mode;
+       /* If last op was a read ... */
+       if ((v & __MODE_READING) && fflush(fp))
+               return EOF;
+       /* Can't write or there's been an EOF or error then return EOF */
+       if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)
+               return EOF;
+       /* Buffer is full */
+       if (fp->bufpos >= fp->bufend && fflush(fp))
+               return EOF;
+       /* Right! Do it! */
+       *(fp->bufpos++) = ch;
+       fp->mode |= __MODE_WRITING;
+
+       /* Unbuffered or Line buffered and end of line */
+       if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF)) && fflush(fp))
+               return EOF;
+       /* Can the macro handle this by itself ? */
+       if (v & (__MODE_IOTRAN | _IOLBF | _IONBF))
+               fp->bufwrite = fp->bufstart;    /* Nope */
+       else
+               fp->bufwrite = fp->bufend;      /* Yup */
+       /* Correct return val */
+       return (unsigned char) ch;
+}
diff --git a/Library/libs/fputs.c b/Library/libs/fputs.c
new file mode 100644 (file)
index 0000000..4f4bd29
--- /dev/null
@@ -0,0 +1,14 @@
+#include "stdio-l.h"
+
+int fputs(void *str, FILE * fp)
+{
+       register int n = 0;
+       char *s = str;
+
+       while (*s) {
+               if (putc(*s++, fp) == EOF)
+                       return (EOF);
+               ++n;
+       }
+       return (n);
+}
diff --git a/Library/libs/fread.c b/Library/libs/fread.c
new file mode 100644 (file)
index 0000000..9035d9f
--- /dev/null
@@ -0,0 +1,53 @@
+/* stdio.c
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is an implementation of the C standard IO package. */
+
+#include "stdio-l.h"
+
+/*
+ * fread will often be used to read in large chunks of data calling read()
+ * directly can be a big win in this case. Beware also fgetc calls this
+ * function to fill the buffer.
+ *
+ * This ignores __MODE__IOTRAN; probably exactly what you want.
+ * (It _is_ what fgetc wants)
+ */
+int fread(void *buf, size_t size, size_t nelm, FILE * fp)
+{
+       register int len, v;
+       unsigned bytes, got = 0;
+
+       if (!buf || !size || !nelm || !fp)
+               return 0;
+       v = fp->mode;
+       /* Want to do this to bring the file pointer up to date */
+       if (v & __MODE_WRITING)
+               fflush(fp);
+       /* Can't read or there's been an EOF or error then return zero */
+       if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ)
+               return 0;
+       /* This could be long, doesn't seem much point tho */
+       bytes = size * nelm;
+       len = fp->bufread - fp->bufpos;
+       if (len >= bytes) {     /* Enough buffered */
+               memcpy(buf, fp->bufpos, bytes);
+               fp->bufpos += bytes;
+               return bytes;
+       } else if (len > 0) {   /* Some buffered */
+               memcpy(buf, fp->bufpos, len);
+               got = len;
+       }
+       /* Need more; do it with a direct read */
+       len = read(fp->fd, (char *) buf + got, bytes - got);
+       /* Possibly for now _or_ later */
+       if (len < 0) {
+               fp->mode |= __MODE_ERR;
+               len = 0;
+       } else if (len == 0)
+               fp->mode |= __MODE_EOF;
+       return (got + len) / size;
+}
diff --git a/Library/libs/free.c b/Library/libs/free.c
new file mode 100644 (file)
index 0000000..b8b2734
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ *
+ * This is a combined alloca/malloc package. It uses a classic algorithm
+ * and so may be seen to be quite slow compared to more modern routines
+ * with 'nasty' distributions.
+ */
+
+#include "malloc-l.h"
+
+/* Start the alloca with just the dumb version of malloc */
+void *(*__alloca_alloc) __P((size_t)) = __mini_malloc;
+
+/* the free list is a single list of free blocks. __freed_list points to
+   the highest block (highest address) and each block points to the lower
+   block (lower address). last block points to 0 (initial value of
+   _freed_list)
+*/
+mem *__freed_list = 0;
+
+#ifdef VERBOSE
+/* NB: Careful here, stdio may use malloc - so we can't */
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+static void pstr __P((char *));
+static void phex __P((unsigned));
+static void noise __P((char *, mem *));
+static void pstr(char *str)
+{
+       write(2, str, strlen(str));
+} static void phex(unsigned val)
+{
+       char buf[8];
+       strcpy(buf, "000");
+       ltoa((long) val, buf + 3, 16);
+       pstr(buf + strlen(buf + 4));
+} void __noise(char *y, mem * x)
+{
+       pstr("Malloc ");
+       phex((unsigned) x);
+       pstr(" sz ");
+       phex(x ? (unsigned) m_size(x) : 0);
+       pstr(" nxt ");
+       phex(x ? (unsigned) m_next(x) : 0);
+       pstr(" is ");
+       pstr(y);
+       pstr("\n");
+}
+#endif                         /*  */
+void free(void *ptr)
+{
+       register mem *top, *chk = (mem *) ptr;
+       if (chk == 0)
+               return;         /* free(NULL) - be nice */
+       chk--;
+      try_this:;
+       top = (mem *) sbrk(0);
+       if (m_add(chk, m_size(chk)) >= top) {
+               noise("FREE brk", chk);
+               brk((void *) ((uchar *) top - m_size(chk)));
+
+               /* Adding this code allow free to release blocks in any order;
+                * they can still only be allocated from the top of the heap
+                * tho.
+                */
+#ifdef __MINI_MALLOC__
+               if (__alloca_alloc == __mini_malloc && __freed_list) {
+                       chk = __freed_list;
+                       __freed_list = m_next(__freed_list);
+                       goto try_this;
+               }
+#endif                         /*  */
+       }
+
+       else {                  /* Nope, not sure where this goes, leave it for malloc to deal with */
+
+#ifdef __MINI_MALLOC__
+               /* check if block is already on free list.
+                  if it is, return without doing nothing */
+               top = __freed_list;
+               while (top) {
+                       if (top == chk)
+                               return;
+                       top = m_next(top);
+               }
+
+               /* else add it to free list */
+               if (!__freed_list || chk > __freed_list) {
+
+                       /* null free list or block above free list */
+                       m_next(chk) = __freed_list;
+                       __freed_list = chk;
+               }
+
+               else {
+
+                       /* insert block in free list, ordered by address */
+                       register mem *prev = __freed_list;
+                       top = __freed_list;
+                       while (top && top > chk) {
+                               prev = top;
+                               top = m_next(top);
+                       }
+                       m_next(chk) = top;
+                       m_next(prev) = chk;
+               }
+
+#else                          /*  */
+               m_next(chk) = __freed_list;
+               __freed_list = chk;
+
+#endif                         /*  */
+               noise("ADD LIST", chk);
+       }
+}
+
+void *__mini_malloc(size_t size)
+{
+       register mem *ptr;
+       register unsigned int sz;
+
+       /* First time round this _might_ be odd, But we won't do that! */
+#if 0
+       sz = (unsigned int) sbrk(0);
+       if (sz & (sizeof(struct mem_cell) - 1)) {
+               if (sbrk
+                   (sizeof(struct mem_cell) -
+                    (sz & (sizeof(struct mem_cell) - 1))) < 0)
+                       goto nomem;
+       }
+#endif                         /*  */
+       if (size == 0)
+               return 0;
+
+       /* Minor oops here, sbrk has a signed argument */
+       if (size > (((unsigned) -1) >> 1) - sizeof(struct mem_cell) * 3) {
+             nomem:errno = ENOMEM;
+               return 0;
+       }
+       size += sizeof(struct mem_cell);        /* Round up and leave space for size field */
+       ptr = (mem *) sbrk(size);
+       if ((int) ptr == -1)
+               return 0;
+       m_size(ptr) = size;
+       noise("CREATE", ptr);
+       return ptr + 1;
+}
diff --git a/Library/libs/fscanf.c b/Library/libs/fscanf.c
new file mode 100644 (file)
index 0000000..7152569
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file based on scanf.c from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 19-OCT-88: Dale Schumacher
+ * > John Stanley has again been a great help in debugging, particularly
+ * > with the printf/scanf functions which are his creation.  
+ *
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+
+int fscanf(FILE * fp, const char * fmt, ...)
+{
+  va_list ptr;
+  int rv;
+  va_start(ptr, fmt);
+  rv = vfscanf(fp,fmt,ptr);
+  va_end(ptr);
+  return rv;
+}
diff --git a/Library/libs/fsetpos.c b/Library/libs/fsetpos.c
new file mode 100644 (file)
index 0000000..d8b2791
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int fsetpos(FILE *fp, fpos_t *pos)
+{
+   return fseek(fp, *pos, SEEK_SET);
+}
diff --git a/Library/libs/ftell.c b/Library/libs/ftell.c
new file mode 100644 (file)
index 0000000..8e027db
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <unistd.h>
+
+long ftell(FILE *fp)
+{
+   if (fflush(fp) == EOF)
+      return EOF;
+   return lseek(fp->fd, 0L, SEEK_CUR);
+}
diff --git a/Library/libs/fuzix/Makefile b/Library/libs/fuzix/Makefile
new file mode 100644 (file)
index 0000000..8248571
--- /dev/null
@@ -0,0 +1,82 @@
+# Autogenerated by tools/syscall
+CROSS_AS=sdasz80
+CROSS_LD=sdldz80
+CROSS_AR=sdar
+ASOPTS=
+
+ASYS=syscall.s
+ASRCS = syscall__exit.s
+ASRCS += syscall_open.s
+ASRCS += syscall_close.s
+ASRCS += syscall_rename.s
+ASRCS += syscall_mknod.s
+ASRCS += syscall_link.s
+ASRCS += syscall_unlink.s
+ASRCS += syscall_read.s
+ASRCS += syscall_write.s
+ASRCS += syscall__lseek.s
+ASRCS += syscall_chdir.s
+ASRCS += syscall_sync.s
+ASRCS += syscall_access.s
+ASRCS += syscall_chmod.s
+ASRCS += syscall_chown.s
+ASRCS += syscall__stat.s
+ASRCS += syscall__fstat.s
+ASRCS += syscall_dup.s
+ASRCS += syscall_getpid.s
+ASRCS += syscall_getppid.s
+ASRCS += syscall_getuid.s
+ASRCS += syscall_umask.s
+ASRCS += syscall__getfsys.s
+ASRCS += syscall_execve.s
+ASRCS += syscall__getdirent.s
+ASRCS += syscall_setuid.s
+ASRCS += syscall_setgid.s
+ASRCS += syscall__time.s
+ASRCS += syscall_stime.s
+ASRCS += syscall_ioctl.s
+ASRCS += syscall_brk.s
+ASRCS += syscall_sbrk.s
+ASRCS += syscall_fork.s
+ASRCS += syscall_mount.s
+ASRCS += syscall_umount.s
+ASRCS += syscall_signal.s
+ASRCS += syscall_dup2.s
+ASRCS += syscall__pause.s
+ASRCS += syscall_alarm.s
+ASRCS += syscall_kill.s
+ASRCS += syscall_pipe.s
+ASRCS += syscall_getgid.s
+ASRCS += syscall_times.s
+ASRCS += syscall_utime.s
+ASRCS += syscall_geteuid.s
+ASRCS += syscall_getegid.s
+ASRCS += syscall_chroot.s
+ASRCS += syscall_fcntl.s
+ASRCS += syscall_fchdir.s
+ASRCS += syscall_fchmod.s
+ASRCS += syscall_fchown.s
+ASRCS += syscall_mkdir.s
+ASRCS += syscall_rmdir.s
+ASRCS += syscall_setpgrp.s
+ASRCS += syscall__uname.s
+ASRCS += syscall_waitpid.s
+ASRCS += syscall__profil.s
+ASRCS += syscall_uadmin.s
+ASRCS += syscall_nice.s
+
+
+ASRCALL = $(ASRCS) $(ASYS)
+
+AOBJS = $(ASRCALL:.s=.rel)
+
+syslib.lib: $(AOBJS)
+       echo $(AOBJS) >syslib.l
+       $(CROSS_AR) rc syslib.lib $(AOBJS)
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) -o $*.rel $<
+
+clean:
+       rm -f $(AOBJS) $(ASRCS) syslib.lib *~
+
diff --git a/Library/libs/fuzix/syscall.s b/Library/libs/fuzix/syscall.s
new file mode 100644 (file)
index 0000000..122daf8
--- /dev/null
@@ -0,0 +1,15 @@
+               .globl  __syscall
+               .globl  _errno
+
+__syscall:
+               ex      (sp), hl                ; hl is now return addr
+                                               ; stack is syscall
+               ex      de, hl                  ; save return addr in de
+               rst     #0x30
+               ex      de, hl                  ; undo the magic
+               ex      (sp), hl
+               ex      de, hl                  ; return with HL
+               ret     nc                      ; ok
+               ld      (_errno), hl            ; error path
+               ld      hl, #0xffff
+               ret
diff --git a/Library/libs/fwrite.c b/Library/libs/fwrite.c
new file mode 100644 (file)
index 0000000..c89b540
--- /dev/null
@@ -0,0 +1,68 @@
+/* stdio.c\r
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+/* This is an implementation of the C standard IO package. */ \r
+    \r
+#include "stdio-l.h"\r
+    \r
+/*\r
+ * Like fread, fwrite will often be used to write out large chunks of\r
+ * data; calling write() directly can be a big win in this case.\r
+ *\r
+ * But first we check to see if there's space in the buffer.\r
+ */ \r
+int fwrite(void *buf, size_t size, size_t nelm, FILE * fp) \r
+{
+       int len;
+       register int v;
+       unsigned int bytes, put;
+\r
+       if (!buf || !size || !nelm || !fp)
+               return 0;
+       v = fp->mode;
+       \r
+       /* If last op was a read ... */ \r
+       if ((v & __MODE_READING) && fflush(fp))
+               return 0;
+       \r
+       /* Can't write or there's been an EOF or error then return 0 */ \r
+       if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)
+               return 0;
+       \r
+       /* This could be long, doesn't seem much point tho */ \r
+       bytes = size * nelm;
+       len = fp->bufend - fp->bufpos;
+       \r
+       /* Flush the buffer if not enough room */ \r
+       if (bytes > len && fflush(fp))
+               return 0;
+       len = fp->bufend - fp->bufpos;
+       if (bytes <= len) {     /* It'll fit in the buffer ? */
+               fp->mode |= __MODE_WRITING;
+               memcpy(fp->bufpos, buf, bytes);
+               fp->bufpos += bytes;\r
+\r
+               /* If we're not fully buffered */ \r
+               if (v & (_IOLBF | _IONBF))
+                       fflush(fp);
+               return nelm;
+       }
+       \r
+       /* Too big for the buffer */ \r
+       /* ??? May be leave the rest of data in buffer ? */ \r
+       put = bytes;
+       \r
+       do {
+               if ((len = write(fp->fd, buf, bytes)) > 0) {
+                       buf = (char *) buf + len;
+                       bytes -= len;
+               }
+       } while (len > 0 || (len == -1 && errno == EINTR));
+       if (len < 0)
+               fp->mode |= __MODE_ERR;
+       put -= bytes;
+       return put / size;
+}
diff --git a/Library/libs/getcwd.c b/Library/libs/getcwd.c
new file mode 100644 (file)
index 0000000..1e34868
--- /dev/null
@@ -0,0 +1,99 @@
+/* These functions find the absolute path to the current working directory.\r
+ *\r
+ * They don't use malloc or large amounts of stack space.\r
+ */  \r
+#include <unistd.h>\r
+#include <errno.h>\r
+#include <dirent.h>\r
+#include <string.h>\r
+#include <sys/stat.h>\r
+\r
+static char *search_dir(uint, uint);   /* Routine to find the step back down */
+static char *recurser(void);   /* Routine to go up tree */
+static char *path_buf;
+static int path_size;
+\r
+static uint root_dev;
+static uint root_ino;
+static struct stat st;
+\r
+static char *search_dir(uint this_dev, uint this_ino) \r
+{
+       struct dirent *d;
+       char *ptr;
+       int slen;
+       DIR * dp;
+       unsigned char slow_search = 0;
+\r
+       if (stat(path_buf, &st) < 0)
+               return NULL;
+       if (this_dev != st.st_dev)
+               ++slow_search;
+       slen = strlen(path_buf);
+       ptr = path_buf + slen - 1;
+       if (*ptr != '/') {
+               if (slen + 2 > path_size) {
+                       errno = ERANGE;
+                       return NULL;
+               }\r
+               strcpy(++ptr, "/");
+               ++slen;
+       }
+       ++slen;
+       if ((dp = opendir(path_buf)) == 0)
+               return NULL;
+       while ((d = readdir(dp)) != 0) {
+               if (slow_search || this_ino == d->d_ino) {
+                       if (slen + strlen(d->d_name) > path_size) {
+                               errno = ERANGE;
+                               return NULL;
+                       }\r
+                       strcpy(ptr + 1, d->d_name);
+                       if (stat(path_buf, &st) < 0)
+                               continue;
+                       if (st.st_ino == this_ino && st.st_dev == this_dev) {
+                               closedir(dp);
+                               return path_buf;
+                       }
+               }
+                   /* else ??? */ \r
+       }
+       closedir(dp);
+       errno = ENOENT;
+       return NULL;
+}
+
+static char *recurser(void) \r
+{
+       uint this_dev;
+       uint this_ino;
+\r
+       if (stat(path_buf, &st) < 0)
+               return NULL;
+       this_dev = st.st_dev;
+       this_ino = st.st_ino;
+       if (this_dev == root_dev && this_ino == root_ino) {
+               strcpy(path_buf, "/");
+               return path_buf;
+       }
+       if (strlen(path_buf) + 4 > path_size) {
+               errno = ERANGE;
+               return NULL;
+       }
+       strcat(path_buf, "/..");
+       return recurser()? search_dir(this_dev, this_ino) : NULL;
+}
+
+char *getcwd(char *buf, int size) \r
+{
+       if ((path_size = size) < 3) {
+               errno = ERANGE;
+               return 0;
+       }
+       strcpy(path_buf = buf, ".");
+       if (stat("/", &st) < 0)
+               return NULL;    /* no root */
+       root_dev = st.st_dev;
+       root_ino = st.st_ino;
+       return recurser();
+}
diff --git a/Library/libs/getenv.c b/Library/libs/getenv.c
new file mode 100644 (file)
index 0000000..1140152
--- /dev/null
@@ -0,0 +1,22 @@
+/*********************** getenv.c ***************************\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include "stdlib.h"\r
+#include "string.h"\r
+\r
+char *getenv(char *name) \r
+{
+       register char *p, **ep = environ;
+       register int l = strlen(name);
+       \r
+       if (ep == 0 || l == 0)\r
+               return 0;
+       while ((p = *ep++) != NULL) {
+               if (p[0] == name[0] && p[l] == '=' && memcmp(name, p, l) == 0)
+                       return p + l + 1;
+       }
+       return NULL;
+}
diff --git a/Library/libs/getgrgid.c b/Library/libs/getgrgid.c
new file mode 100644 (file)
index 0000000..c1dd20e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * getgrgid.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+
+struct group *
+getgrgid(const gid_t gid)
+{
+  struct group * group;
+  int grp_fd;
+
+  if ((grp_fd=open("/etc/group", O_RDONLY))<0)
+    return NULL;
+
+  while ((group=__getgrent(grp_fd))!=NULL)
+    if (group->gr_gid==gid)
+      {
+       close(grp_fd);
+       return group;
+      }
+
+  close(grp_fd);
+  return NULL;
+}
+
+
+
+
diff --git a/Library/libs/getgrnam.c b/Library/libs/getgrnam.c
new file mode 100644 (file)
index 0000000..e6c27fc
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * getgrnam.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+
+struct group *
+getgrnam(const char * name)
+{
+  int grp_fd;
+  struct group * group;
+
+  if (name==NULL)
+    {
+      errno=EINVAL;
+      return NULL;
+    }
+
+  if ((grp_fd=open("/etc/group", O_RDONLY))<0)
+    return NULL;
+
+  while ((group=__getgrent(grp_fd))!=NULL)
+    if (!strcmp(group->gr_name, name))
+      {
+       close(grp_fd);
+       return group;
+      }
+
+  close(grp_fd);
+  return NULL;
+}
diff --git a/Library/libs/gethostname.c b/Library/libs/gethostname.c
new file mode 100644 (file)
index 0000000..960c473
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+ *     Emualte Berkley hostname calls
+ */
+
+static int openhostname(int flags, mode_t mode)
+{
+  return open(_PATH_HOSTNAME, flags, mode);
+}
+  
+int gethostname(char *name, size_t len)
+{
+  int got;
+  int fd = openhostname(O_RDONLY, 0);
+  if (fd == -1) {
+    *name = 0;
+    return 0;
+  }
+  got = read(fd, name, len);
+  if (got >= 0)
+    name[got] = 0;
+  else
+    *name = 0;
+  close(fd);
+  return 0;
+}
+
+int sethostname(const char *name, size_t len)
+{
+  int fd = openhostname(O_TRUNC|O_CREAT, 0644);
+  if (fd == -1)
+    return -1;
+  /* Not clear how to handle this */
+  if (write(fd, name, len) != len)
+    return -1;
+  fchmod(fd, 0644);
+  close(fd);
+  return 0;
+}
diff --git a/Library/libs/getopt.c b/Library/libs/getopt.c
new file mode 100644 (file)
index 0000000..abbfabd
--- /dev/null
@@ -0,0 +1,117 @@
+
+/*
+ * From: gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) Newsgroups: net.sources
+ * Subject: getopt library routine Date: 30 Mar 85 04:45:33 GMT
+ */
+/*
+ * getopt -- public domain version of standard System V routine
+ * 
+ * Strictly enforces the System V Command Syntax Standard; provided by D A
+ * Gwyn of BRL for generic ANSI C implementations
+ * 
+ * #define STRICT to prevent acceptance of clustered options with arguments
+ * and ommision of whitespace between option and arg.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int   opterr = 1;              /* error => print message */
+int   optind = 1;              /* next argv[] index */
+const char *optarg = NULL;     /* option parameter if any */
+
+static int Err(const char *name, const char *mess, int c)
+/* returns '?' */
+{
+   if (opterr)
+   {
+      (void) fprintf(stderr,
+                    "%s: %s -- %c\n",
+                    name, mess, c
+         );
+   }
+   return '?';                 /* erroneous-option marker */
+}
+
+/* Moved out of function to stop SDCC generating loads of setup crap */
+static int sp = 1;             /* position within argument */
+
+int getopt(int argc, const char *argv[], const char *optstring)
+                               /* returns letter, '?', EOF */
+{
+   register int osp;           /* saved `sp' for param test */
+#ifndef STRICT
+   register int oind;          /* saved `optind' for param test */
+#endif
+   register int c;             /* option letter */
+   register char *cp;          /* -> option in `optstring' */
+
+   optarg = NULL;
+
+   if (sp == 1)                        /* fresh argument */
+      if (optind >= argc       /* no more arguments */
+         || argv[optind][0] != '-'     /* no more options */
+         || argv[optind][1] == '\0'    /* not option; stdin */
+         )
+        return EOF;
+      else if (strcmp(argv[optind], "--") == 0)
+      {
+        ++optind;              /* skip over "--" */
+        return EOF;            /* "--" marks end of options */
+      }
+
+   c = argv[optind][sp];       /* option letter */
+   osp = sp++;                 /* get ready for next letter */
+
+#ifndef STRICT
+   oind = optind;              /* save optind for param test */
+#endif
+   if (argv[optind][sp] == '\0')/* end of argument */
+   {
+      ++optind;                        /* get ready for next try */
+      sp = 1;                  /* beginning of next argument */
+   }
+
+   if (c == ':' || c == '?'    /* optstring syntax conflict */
+       || (cp = strchr(optstring, c)) == NULL  /* not found */
+       )
+      return Err(argv[0], "illegal option", c);
+
+   if (cp[1] == ':')           /* option takes parameter */
+   {
+#ifdef STRICT
+      if (osp != 1)
+        return Err(argv[0],
+                   "option must not be clustered",
+                   c
+            );
+
+      if (sp != 1)             /* reset by end of argument */
+        return Err(argv[0],
+                   "option must be followed by white space",
+                   c
+            );
+
+#else
+      if (oind == optind)      /* argument w/o whitespace */
+      {
+        optarg = &argv[optind][sp];
+        sp = 1;                /* beginning of next argument */
+      }
+
+      else
+#endif
+      if (optind >= argc)
+        return Err(argv[0],
+                   "option requires an argument",
+                   c
+            );
+
+      else                     /* argument w/ whitespace */
+        optarg = argv[optind];
+
+      ++optind;                        /* skip over parameter */
+   }
+
+   return c;
+}
diff --git a/Library/libs/getpass.c b/Library/libs/getpass.c
new file mode 100644 (file)
index 0000000..07cc276
--- /dev/null
@@ -0,0 +1,58 @@
+/* getpass.c
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+static char *_gets(char *buf, int len)
+{
+       int ch, i = 0;
+
+       while (i < len) {
+               if ((ch = _getchar()) == EOF && i == 0)
+                       return NULL;
+#if 0
+               if (ch >= ' ')
+                       _putchar(ch);
+               else {
+                       _putchar('^');
+                       _putchar(ch + '@');
+               }
+#endif
+               if ((ch == 'C' & 037) || (ch == 'Z' & 037))
+                       return NULL;
+               if (ch == '\n' || ch == '\r')
+                       break;
+               buf[i++] = ch;
+       }
+       buf[i] = 0;
+       return buf;
+}
+
+/* FIXME: should use /dev/tty interface eventually */
+char *getpass(char *prompt)
+{
+       static char result[128];
+       struct termios t;
+       tcflag_t ol;
+       int tv;
+
+       /* display the prompt */
+       fputs(prompt, stdout);
+       fflush(stdout);
+
+       tv = tcgetattr(0, &t);
+       ol = t.c_lflag;
+       t.c_lflag &= ~ECHO|ECHOE|ECHOK;
+       if (tv == 0)
+               tcsetattr(0, TCSANOW, &t);
+       /* read the input */
+       if (_gets(result, sizeof(result) - 1) == NULL)
+               result[0] = 0;
+       t.c_lflag = ol;
+       if (tv == 0)
+               tcsetattr(0, TCSANOW, &t);
+       return result;
+}
diff --git a/Library/libs/getpw.c b/Library/libs/getpw.c
new file mode 100644 (file)
index 0000000..3ca208b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * getpw.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <pwd.h>
+
+int
+getpw(uid_t uid, char *buf)
+{
+  struct passwd * passwd;
+
+  if (buf==NULL)
+    {
+      errno=EINVAL;
+      return -1;
+    }
+  if ((passwd=getpwuid(uid))==NULL) {
+    errno=ENOENT;
+    return -1;
+  }
+
+  if (sprintf(buf, "%s:%s:%u:%u:%s:%s:%s", passwd->pw_name, passwd->pw_passwd,
+         passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos,
+         passwd->pw_dir, passwd->pw_shell)<0)
+    {
+      errno=ENOMEM;
+      return -1;
+    }
+
+  return 0;
+}  
+
+
+
diff --git a/Library/libs/getpwnam.c b/Library/libs/getpwnam.c
new file mode 100644 (file)
index 0000000..85dbc8e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+
+struct passwd *
+getpwnam(const char * name)
+{
+  int passwd_fd;
+  struct passwd * passwd;
+
+  if (name==NULL)
+    {
+      errno=EINVAL;
+      return NULL;
+    }
+
+  if ((passwd_fd=open("/etc/passwd", O_RDONLY))<0)
+    return NULL;
+
+  while ((passwd=__getpwent(passwd_fd))!=NULL)
+    if (!strcmp(passwd->pw_name, name))
+      {
+       close(passwd_fd);
+       return passwd;
+      }          
+
+  close(passwd_fd);
+  return NULL;
+}
diff --git a/Library/libs/getpwuid.c b/Library/libs/getpwuid.c
new file mode 100644 (file)
index 0000000..ffd58c1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+  int passwd_fd;
+  struct passwd * passwd;
+
+  if ((passwd_fd=open("/etc/passwd", O_RDONLY))<0)
+    return NULL;
+
+  while ((passwd=__getpwent(passwd_fd))!=NULL)
+    if (passwd->pw_uid==uid)
+      {
+       close(passwd_fd);
+       return passwd;
+      }
+
+  close (passwd_fd);
+  return NULL;
+}
diff --git a/Library/libs/gets.c b/Library/libs/gets.c
new file mode 100644 (file)
index 0000000..4f2e77e
--- /dev/null
@@ -0,0 +1,31 @@
+/* stdio.c\r
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+/* This is an implementation of the C standard IO package. */ \r
+    \r
+#include "stdio-l.h"\r
+\r
+char *gets(char *str) /* BAD function; DON'T use it! */ \r
+{
+       /* Auwlright it will work but of course _your_ program will crash */ \r
+       /* if it's given a too long line */ \r
+       register int c;
+       register char *p = str;
+\r
+       while (((c = getc(stdin)) != EOF) && (c != '\n'))
+               *p++ = c;
+       *p = '\0';
+       return (((c == EOF) && (p == str)) ? NULL : str);/* NULL == EOF */
+}
+
+int puts(void *str) \r
+{
+       register int n;
+       if (((n = fputs(str, stdout)) == EOF) \r
+              ||(putc('\n', stdout) == EOF))
+               return (EOF);
+       return (++n);
+}
diff --git a/Library/libs/gmtime.c b/Library/libs/gmtime.c
new file mode 100644 (file)
index 0000000..e32145c
--- /dev/null
@@ -0,0 +1,66 @@
+/*************************** GMTIME ************************************/ 
+
+#include <time.h>
+#include <string.h>
+
+static unsigned char __mon_lengths[2][12] = {
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+#define SECS_PER_DAY   86400
+#define SECS_PER_HOUR  3600
+
+void __tm_conv(struct tm *tmbuf, time_t * pt, int offset)
+{
+       register int y;
+       long days;              /* This breaks but not for a while 8) */
+       long rem;
+       unsigned char *ip;
+
+       days = *pt / SECS_PER_DAY;
+       rem = *pt % SECS_PER_DAY;
+       rem += offset;
+       while (rem < 0) {
+               rem += SECS_PER_DAY;
+               --days;
+       }
+       while (rem >= SECS_PER_DAY) {
+               rem -= SECS_PER_DAY;
+               ++days;
+       }
+       tmbuf->tm_hour = rem / SECS_PER_HOUR;
+       rem %= SECS_PER_HOUR;
+       tmbuf->tm_min = rem / 60;
+       tmbuf->tm_sec = rem % 60;
+
+       /* January 1, 1970 was a Thursday.  */
+       tmbuf->tm_wday = (4 + days) % 7;
+       if (tmbuf->tm_wday < 0)
+               tmbuf->tm_wday += 7;
+       y = 1970;
+       while (days >= (rem = __isleap(y) ? 366 : 365)) {
+               ++y;
+               days -= rem;
+       }
+       while (days < 0) {
+               --y;
+               days += __isleap(y) ? 366 : 365;
+       }
+       tmbuf->tm_year = y - 1900;
+       tmbuf->tm_yday = days;
+       ip = __mon_lengths[__isleap(y)];
+       y = 0;
+       while (days >= ip[y])
+               days -= ip[y++];
+       tmbuf->tm_mon = y;
+       tmbuf->tm_mday = days + 1;
+       tmbuf->tm_isdst = -1;
+}
+
+struct tm *gmtime(time_t *timep)
+{
+       static struct tm tmb;
+       __tm_conv(&tmb, timep, (int) (timezone / 60));
+       return &tmb;
+}
diff --git a/Library/libs/grent.c b/Library/libs/grent.c
new file mode 100644 (file)
index 0000000..19d618b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * grent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * setgrent(), endgrent(), and getgrent() are mutually-dependent functions,
+ * so they are all included in the same object file, and thus all linked
+ * in together.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+
+static int grp_fd=-1;
+
+void
+setgrent(void)
+{
+  if (grp_fd!=-1)
+    close(grp_fd);
+  grp_fd=open("/etc/group", O_RDONLY);
+}
+
+void
+endgrent(void)
+{
+ if (grp_fd!=-1)
+   close(grp_fd);
+ grp_fd=-1;
+}
+
+struct group *
+getgrent(void)
+{
+  if (grp_fd==-1)
+    return NULL;
+  return __getgrent(grp_fd);
+}
+
+
diff --git a/Library/libs/index.c b/Library/libs/index.c
new file mode 100644 (file)
index 0000000..221ae32
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <sys/types.h>
+
+char *index(__const char *src, int chr)
+{
+  return strchr(src, chr);
+}
diff --git a/Library/libs/initgroups.c b/Library/libs/initgroups.c
new file mode 100644 (file)
index 0000000..df3ffa8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * initgroups.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <grp.h>
+#include "config-grp.h"
+
+int
+initgroups(__const char * user, gid_t gid)
+{
+  register struct group * group;
+#ifndef GR_DYNAMIC_GROUP_LIST
+  gid_t group_list[GR_MAX_GROUPS];
+#else
+  gid_t * group_list=NULL;
+#endif
+  register char ** tmp_mem;
+  int num_groups;
+  int grp_fd;
+
+
+  if ((grp_fd=open("/etc/group", O_RDONLY))<0)
+    return -1;
+
+  num_groups=0;
+#ifdef GR_DYNAMIC_GROUP_LIST
+  group_list=(gid_t *) realloc(group_list, 1);
+#endif
+  group_list[num_groups]=gid;
+#ifndef GR_DYNAMIC_GROUP_LIST
+  while (num_groups<GR_MAX_GROUPS &&
+        (group=__getgrent(grp_fd))!=NULL)
+#else
+  while ((group=__getgrent(grp_fd))!=NULL)
+#endif      
+    {
+      if (group->gr_gid!=gid);
+        {
+         tmp_mem=group->gr_mem;
+         while(*tmp_mem!=NULL)
+           {
+             if (!strcmp(*tmp_mem, user))
+               {
+                 num_groups++;
+#ifdef GR_DYNAMIC_GROUP_LIST  
+                 group_list=(gid_t *)realloc(group_list,
+                                             num_groups*sizeof(gid_t *));
+#endif           
+                 group_list[num_groups]=group->gr_gid;
+               }
+             tmp_mem++;
+           }
+       }
+    }
+  close(grp_fd);
+  return setgroups(num_groups, group_list);
+}
+
+
+
+
diff --git a/Library/libs/isatty.c b/Library/libs/isatty.c
new file mode 100644 (file)
index 0000000..572da95
--- /dev/null
@@ -0,0 +1,14 @@
+/* isatty.c
+ */
+#include <syscalls.h>
+#include <sys/stat.h>
+
+int isatty(int fd)
+{
+       struct stat stat;
+
+       /* FIXME: should do a tty ioctl */
+       if (fstat(fd, &stat) == -1 || (stat.st_mode & S_IFMT) != S_IFCHR)
+               return 0;
+       return 1;
+}
diff --git a/Library/libs/itoa.c b/Library/libs/itoa.c
new file mode 100644 (file)
index 0000000..f4aa1d9
--- /dev/null
@@ -0,0 +1,22 @@
+/* itoa.c <ndf@linux.mit.edu> */
+#define __MAX_INT_CHARS 7
+
+char *itoa(int i)
+{
+   static char a[__MAX_INT_CHARS];
+   char *b = a + sizeof(a) - 1;
+   int   sign = (i < 0);
+
+   if (sign)
+      i = -i;
+   *b = 0;
+   do
+   {
+      *--b = '0' + (i % 10);
+      i /= 10;
+   }
+   while (i);
+   if (sign)
+      *--b = '-';
+   return b;
+}
diff --git a/Library/libs/killpg.c b/Library/libs/killpg.c
new file mode 100644 (file)
index 0000000..a91c29b
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+int killpg(pid_t pid, int sig)
+{
+   if(pid == 0)
+       pid = getpgrp();
+   if(pid > 1)
+       return kill(-pid, sig);
+   errno = EINVAL;
+   return -1;
+}
diff --git a/Library/libs/labs.c b/Library/libs/labs.c
new file mode 100644 (file)
index 0000000..0d909e5
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+long labs(long arg1)
+{
+   return arg1>0?arg1:-arg1;
+}
diff --git a/Library/libs/localtim.c b/Library/libs/localtim.c
new file mode 100644 (file)
index 0000000..4605d4c
--- /dev/null
@@ -0,0 +1,9 @@
+#include <time.h>
+#include <string.h>
+
+struct tm *localtime(time_t * timep)
+{
+       static struct tm tmb;
+       __tm_conv(&tmb, timep, 0);
+       return &tmb;
+}
diff --git a/Library/libs/lsearch.c b/Library/libs/lsearch.c
new file mode 100644 (file)
index 0000000..2d19dac
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+void *lfind(const void *key, const void *base,
+           size_t *num, size_t size,
+           int (*cmp)(const void *,const void *))
+{
+   register size_t n = *num;
+
+   while (n--)
+   {
+      if ((*cmp) (base, key) == 0)
+        return (base);
+      base = (char *)base + size;
+   }
+   return (NULL);
+}
+
+void *lsearch(const void *key, void *base,
+             size_t *num, size_t size,
+             int (*cmp)(const void *, const void *))
+{
+   void *p;
+
+   if ((p = lfind(key, base, num, size, cmp)) == NULL)
+   {
+      p = memcpy(((char *)base + (size * (*num))), key, size);
+      ++(*num);
+   }
+   return (p);
+}
diff --git a/Library/libs/lseek.c b/Library/libs/lseek.c
new file mode 100644 (file)
index 0000000..b5efdba
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+
+off_t lseek(int fd, off_t pos, int whence)
+{
+  int e;
+  off_t t = pos;
+  e = _lseek(fd, &t, whence);
+  if (e == -1)
+    return (off_t)e;
+  return t;
+}
\ No newline at end of file
diff --git a/Library/libs/lstat.c b/Library/libs/lstat.c
new file mode 100644 (file)
index 0000000..a488bfc
--- /dev/null
@@ -0,0 +1,16 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <syscalls.h>
+
+int lstat(char *name, struct stat *buf)
+{
+       int sts, fd = open(name, O_SYMLINK|O_RDONLY);
+
+       if (fd < 0)
+               sts = stat(name, buf);
+       else {
+               sts = fstat(fd, buf);
+               close(fd);
+       }
+       return sts;
+}
diff --git a/Library/libs/ltoa.c b/Library/libs/ltoa.c
new file mode 100644 (file)
index 0000000..98ade5a
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+
+char * ultoa(unsigned long val)
+{
+   char *p;
+   static char buf[12];
+
+   p = buf+sizeof(buf);
+   *--p = '\0';
+
+   do
+   {
+      *--p = '0' + val%10;
+      val/=10;
+   }
+   while(val);
+   return p;
+}
+
+char * ltoa(long val)
+{
+   char *p;
+   int flg = 0;
+   if( val < 0 ) { flg++; val= -val; }
+   p = ultoa(val);
+   if(flg) *--p = '-';
+   return p;
+}
diff --git a/Library/libs/ltostr.c b/Library/libs/ltostr.c
new file mode 100644 (file)
index 0000000..bb79414
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+static char buf[34];
+
+
+char * ultostr(unsigned long val, int radix)
+{
+   register char *p;
+   register int c;
+
+   if( radix > 36 || radix < 2 ) return 0;
+
+   p = buf+sizeof(buf);
+   *--p = '\0';
+
+   do
+   {
+      c = val%radix;
+      val/=radix;
+      if( c > 9 ) *--p = 'a'-10+c; else *--p = '0'+c;
+   }
+   while(val);
+   return p;
+}
+
+char * ltostr(long val, int radix)
+{
+   char *p;
+   int flg = 0;
+   if( val < 0 ) { flg++; val= -val; }
+   p = ultostr(val, radix);
+   if(p && flg) *--p = '-';
+   return p;
+}
diff --git a/Library/libs/malloc-l.h b/Library/libs/malloc-l.h
new file mode 100644 (file)
index 0000000..42ad35d
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ *\r
+ * This is a combined alloca/malloc package. It uses a classic algorithm\r
+ * and so may be seen to be quite slow compared to more modern routines\r
+ * with 'nasty' distributions.\r
+ */\r
+#include <types.h>\r
+#include <malloc.h>\r
+#include <errno.h>\r
+#include <syscalls.h>\r
+#include <string.h>\r
+\r
+#define __MINI_MALLOC__\r
+\r
+#define MCHUNK         512     /* Allocation unit in 'mem' elements */\r
+#undef LAZY_FREE               /* If set frees can be infinitly defered */\r
+#undef MINALLOC        /* 32 */        /* Smallest chunk to alloc in 'mem's */\r
+#undef VERBOSE                         /* Lots of noise, debuging ? */\r
+\r
+#undef malloc\r
+#define MAX_INT ((int)(((unsigned)-1)>>1))\r
+\r
+#ifdef VERBOSE\r
+#define noise __noise\r
+#else\r
+#define noise(y,x)\r
+#endif\r
+\r
+typedef struct mem_cell {\r
+       struct mem_cell *next;  /* A pointer to the next mem */\r
+       unsigned int size;      /* An int >= sizeof pointer */\r
+       char *depth;            /* For the alloca hack */\r
+} mem;\r
+\r
+#define m_size(p)  ((p)[0].size)               /* For malloc */\r
+#define m_next(p)  ((p)[0].next)               /* For malloc and alloca */\r
+#define m_deep(p)  ((p)[0].depth)              /* For alloca */\r
+#define m_add(x,y) (mem *)((uchar *)x + y)     /* Sum mem* with y bytes */\r
+\r
+extern void *__mini_malloc __P((size_t));\r
+extern void *(*__alloca_alloc) __P((size_t));\r
+extern mem *__freed_list;\r
diff --git a/Library/libs/malloc.c b/Library/libs/malloc.c
new file mode 100644 (file)
index 0000000..9452f07
--- /dev/null
@@ -0,0 +1,281 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ *
+ * This is a combined alloca/malloc package. It uses a classic algorithm
+ * and so may be seen to be quite slow compared to more modern routines
+ * with 'nasty' distributions.
+ */
+
+#include "malloc-l.h"
+
+/* The chunk_list pointer is either NULL or points to a chunk in a
+ * circular list of all the free blocks in memory
+ */
+
+#define Static static
+static mem *chunk_list = 0;
+Static mem *__search_chunk __P((unsigned));
+Static void __insert_chunk __P((mem *));
+void *malloc(size_t size)
+{
+       register unsigned sz;
+       register mem *ptr = 0;
+       if (size == 0)
+               return 0;       /* ANSI STD */
+       sz = size + sizeof(struct mem_cell);
+
+#ifdef MINALLOC
+       if (sz < MINALLOC)
+               sz = MINALLOC;
+
+#endif                         /*  */
+#ifdef VERBOSE
+       {
+               static mem arr[2];
+               m_size(arr) = sz;
+               noise("WANTED", arr);
+       }
+#endif                         /*  */
+       __alloca_alloc = malloc;        /* We'll be messing with the heap now TVM */
+
+#ifdef LAZY_FREE
+       ptr = __search_chunk(sz);
+       if (ptr == 0) {
+
+#endif                         /*  */
+               /* First deal with the freed list */
+               if (__freed_list) {
+                       while (__freed_list) {
+                               ptr = __freed_list;
+                               __freed_list = m_next(__freed_list);
+                               if (m_size(ptr) == sz) {
+
+                                       /* Oh! Well that's lucky ain't it :-) */
+                                       noise("LUCKY MALLOC", ptr);
+                                       return ptr + 1;
+                               }
+                               __insert_chunk(ptr);
+                       }
+                       ptr = m_next(chunk_list);
+                       if (ptr + m_size(ptr) >= (void *) sbrk(0)) {
+
+                               /* Time to free for real */
+                               m_next(chunk_list) = m_next(ptr);
+                               if (ptr == m_next(ptr))
+                                       chunk_list = 0;
+                               free(ptr + 1);
+                       }
+#ifdef LAZY_FREE
+                       ptr = __search_chunk(sz);
+
+#endif                         /*  */
+               }
+#ifndef LAZY_FREE
+               ptr = __search_chunk(sz);
+
+#endif                         /*  */
+               if (ptr == 0) {
+
+#ifdef MCHUNK
+                       unsigned int alloc =
+                           (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1);
+                       if ((ptr = __mini_malloc(alloc)) != NULL)
+                               __insert_chunk(ptr - 1);
+
+                       else {  /* Oooo, near end of RAM */
+                               unsigned int needed = alloc;
+                               alloc /= 2;
+                               while (alloc > 256 && needed) {
+                                       ptr = __mini_malloc(alloc);
+                                       if (ptr) {
+                                               if (alloc > needed)
+                                                       needed = 0;
+
+                                               else
+                                                       needed -= alloc;
+                                               __insert_chunk(ptr - 1);
+                                       }
+
+                                       else
+                                               alloc /= 2;
+                               }
+                       }
+                       ptr = __search_chunk(sz);
+                       if (ptr == 0)
+#endif                         /*  */
+                       {
+
+#ifndef MCHUNK
+                               ptr = __mini_malloc(size);
+
+#endif                         /*  */
+#ifdef VERBOSE
+                               if (ptr == 0)
+                                       noise("MALLOC FAIL", 0);
+
+                               else
+                                       noise("MALLOC NOW", ptr - 1);
+
+#endif                         /*  */
+                               return ptr;
+                       }
+               }
+#ifdef LAZY_FREE
+       }
+#endif                         /*  */
+#ifdef VERBOSE
+       ptr[1].size = 0x5555;
+
+#endif                         /*  */
+       noise("MALLOC RET\n", ptr);
+       return ptr + 1;
+}
+
+
+/* This function takes a pointer to a block of memory and inserts it into
+ * the chain of memory chunks
+ */
+Static void __insert_chunk(mem * mem_chunk)
+{
+       register mem *p1, *p2;
+       if (chunk_list == 0) {  /* Simple case first */
+               m_next(mem_chunk) = chunk_list = mem_chunk;
+               noise("FIRST CHUNK", mem_chunk);
+               return;
+       }
+       p1 = mem_chunk;
+       p2 = chunk_list;
+
+       do {
+               if (p1 > p2) {
+
+                       /* We're at the top of the chain, p1 is higher */
+                       if (m_next(p2) <= p2) {
+                               if (m_add(p2, m_size(p2)) == p1) {
+
+                                       /* Good, stick 'em together */
+                                       noise("INSERT CHUNK", mem_chunk);
+                                       m_size(p2) += m_size(p1);
+                                       noise("JOIN 1", p2);
+                               }
+
+                               else {
+                                       m_next(p1) = m_next(p2);
+                                       m_next(p2) = p1;
+                                       noise("INSERT CHUNK", mem_chunk);
+                                       noise("FROM", p2);
+                               }
+                               return;
+                       }
+                       if (m_next(p2) > p1) {
+
+                               /* In chain, p1 between p2 and next */
+                               m_next(p1) = m_next(p2);
+                               m_next(p2) = p1;
+                               noise("INSERT CHUNK", mem_chunk);
+                               noise("FROM", p2);
+
+                               /* Try to join above */
+                               if (m_add(p1, m_size(p1)) == m_next(p1)) {
+                                       m_size(p1) += m_size(m_next(p1));
+                                       m_next(p1) = m_next(m_next(p1));
+                                       noise("JOIN 2", p1);
+                               }
+
+                               /* Try to join below */
+                               if (m_add(p2, m_size(p2)) == p1) {
+                                       m_size(p2) += m_size(p1);
+                                       m_next(p2) = m_next(p1);
+                                       noise("JOIN 3", p2);
+                               }
+                               chunk_list = p2;        /* Make sure it's valid */
+                               return;
+                       }
+               }
+
+               else if (p1 < p2) {
+                       if (m_next(p2) <= p2 && p1 < m_next(p2)) {
+
+                               /* At top of chain, next is bottom of chain,
+                                * p1 is below next
+                                */
+                               m_next(p1) = m_next(p2);
+                               m_next(p2) = p1;
+                               noise("INSERT CHUNK", mem_chunk);
+                               noise("FROM", p2);
+                               chunk_list = p2;
+                               if (m_add(p1, m_size(p1)) == m_next(p1)) {
+                                       if (p2 == m_next(p1))
+                                               chunk_list = p1;
+                                       m_size(p1) += m_size(m_next(p1));
+                                       m_next(p1) = m_next(m_next(p1));
+                                       noise("JOIN 4", p1);
+                               }
+                               return;
+                       }
+               }
+               chunk_list = p2;        /* Save for search */
+               p2 = m_next(p2);
+       } while (p2 != chunk_list);
+
+       /* If we get here we have a problem, ignore it, maybe it'll go away */
+       noise("DROPPED CHUNK", mem_chunk);
+}
+
+
+/* This function will search for a chunk in memory of at least 'mem_size'
+ * when found, if the chunk is too big it'll be split, and pointer to the
+ * chunk returned. If none is found NULL is returned.
+ */
+Static mem *__search_chunk(unsigned mem_size)
+{
+       register mem *p1, *p2;
+       if (chunk_list == 0)    /* Simple case first */
+               return 0;
+
+       /* Search for a block >= the size we want */
+       p1 = m_next(chunk_list);
+       p2 = chunk_list;
+
+       do {
+               noise("CHECKED", p1);
+               if (m_size(p1) >= mem_size)
+                       break;
+               p2 = p1;
+               p1 = m_next(p1);
+       } while (p2 != chunk_list);
+
+       /* None found, exit */
+       if (m_size(p1) < mem_size)
+               return 0;
+
+       /* If it's exactly right remove it */
+       if (m_size(p1) < mem_size + 2) {
+               noise("FOUND RIGHT", p1);
+               chunk_list = m_next(p2) = m_next(p1);
+               if (chunk_list == p1)
+                       chunk_list = 0;
+               return p1;
+       }
+       noise("SPLIT", p1);
+
+       /* Otherwise split it */
+       m_next(p2) = m_add(p1, mem_size);
+       chunk_list = p2;
+       p2 = m_next(p2);
+       m_size(p2) = m_size(p1) - mem_size;
+       m_next(p2) = m_next(p1);
+       m_size(p1) = mem_size;
+       if (chunk_list == p1)
+               chunk_list = p2;
+
+#ifdef VERBOSE
+       p1[1].size = 0xAAAA;
+
+#endif                         /*  */
+       noise("INSERT CHUNK", p2);
+       noise("FOUND CHUNK", p1);
+       noise("LIST IS", chunk_list);
+       return p1;
+}
diff --git a/Library/libs/memccpy.c b/Library/libs/memccpy.c
new file mode 100644 (file)
index 0000000..273b3e8
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ *     memccpy.c: copy memory until match or end marker
+ */
+
+#include <string.h>
+
+void *memccpy(void *d, const void *s, int c, size_t n)
+{
+  char *s1 = d;
+  const char *s2 = s;
+  while (n) {
+    n--;
+    if ((*s1++ = *s2++) == c)
+      break;
+  }
+  return d;
+}
\ No newline at end of file
diff --git a/Library/libs/memchr.c b/Library/libs/memchr.c
new file mode 100644 (file)
index 0000000..c18f224
--- /dev/null
@@ -0,0 +1,20 @@
+/* memchr.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function memchr ************************************/ \r
+void *memchr(void *str, int c, size_t l) \r
+{
+       register char *p = (char *) str;
+\r
+       while (l-- != 0) {
+               if (*p == c)
+                       return p;
+               p++;
+       }
+       return NULL;
+}
diff --git a/Library/libs/memcmp.c b/Library/libs/memcmp.c
new file mode 100644 (file)
index 0000000..75b2ce0
--- /dev/null
@@ -0,0 +1,61 @@
+/* memcmp.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ *\r
+ * Z80 rewrite from UMZIX\r
+ */\r
\r
+#include <stdlib.h>\r
+\r
+/********************** Function memcmp ************************************/\r
+int memcmp(void *s, void *d, size_t l) __naked\r
+{\r
+__asm\r
+\r
+        push    ix\r
+        ld      ix,#0\r
+        add     ix,sp\r
+\r
+        ; d = BC, s=HL, l=DE\r
+       \r
+        ld      l, 4(ix)\r
+        ld      h, 5(ix)\r
+        ld      c, 6(ix)\r
+        ld      b, 7(ix)\r
+        ld      e, 8(ix)\r
+        ld      d, 9(ix)\r
+        push    bc\r
+        pop     iy      ; IY=d\r
+        ld      bc,#0x0000    ; char1, char2\r
+l_1:      \r
+       ld      a,(hl)\r
+        ld      b,a\r
+        ld      a,(iy)  ; char1 != char 2 ?\r
+        ld      c,a\r
+        cp      b\r
+        jr      nz,l_2\r
+        inc     hl     ; s++\r
+        inc     iy     ; d++\r
+        dec     de     ; l--\r
+        ld      a,d\r
+        or      e\r
+        jp      nz,l_1 ; l != 0, continue\r
+l_2:      \r
+       ld      a,c     ; char1 - char2\r
+        ld      e,a\r
+       rla\r
+       sbc     a,a\r
+       ld      d,a\r
+        ld      a,b\r
+        ld      l,b\r
+       rla\r
+       sbc     a,a\r
+       ld      h,a\r
+       or      a\r
+       sbc     hl,de\r
+\r
+       pop ix\r
+       ret\r
+__endasm;\r
+}\r
diff --git a/Library/libs/memcpy.c b/Library/libs/memcpy.c
new file mode 100644 (file)
index 0000000..d56b275
--- /dev/null
@@ -0,0 +1,31 @@
+#include <string.h>
+
+/* Z80 rewrite from UMZIX */
+
+void *memcpy(void *dst, void *src, size_t count) __naked
+{
+__asm
+        push    ix
+        ld      ix,#0
+        add     ix,sp
+       
+        ld e, 4(ix)
+        ld d, 5(ix)
+        ld l, 6(ix)
+        ld h, 7(ix)
+        ld c, 8(ix)
+        ld b, 9(ix)
+       push de
+        ld      a,b
+        or      c
+        jr      z,_skip
+
+        ldir
+
+_skip:
+       pop hl
+
+       pop ix
+       ret
+__endasm;
+}
diff --git a/Library/libs/memset.c b/Library/libs/memset.c
new file mode 100644 (file)
index 0000000..909d989
--- /dev/null
@@ -0,0 +1,44 @@
+/* memset.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ *\r
+ * Z80 rewrite from UMZIX\r
+ */\r
+\r
+#include <stdlib.h>\r
+\r
+/********************** Function memset ************************************/\r
+void *memset(void *str, int c, size_t l) __naked\r
+{\r
+__asm\r
+        push    ix\r
+        ld      ix,#0\r
+        add     ix,sp\r
+\r
+       ld l, 4(ix)\r
+       ld h, 5(ix)\r
+       ld d, 6(ix)\r
+       ld c, 8(ix)\r
+       ld b, 9(ix)\r
+       ld a,b\r
+       or c    ; l=0? so return\r
+       jr z,_retw\r
+       ld a,d\r
+       ld (hl),a       ; fill first byte\r
+       ld d,h\r
+       ld e,l\r
+       inc de  ; DE=str+1\r
+       dec bc\r
+       ld a,b  ; l=1? so return\r
+       or c\r
+       jr z,_retw\r
+       push hl\r
+       ldir\r
+       pop hl\r
+       \r
+_retw:\r
+       pop ix\r
+       ret\r
+__endasm;\r
+}\r
diff --git a/Library/libs/mkfifo.c b/Library/libs/mkfifo.c
new file mode 100644 (file)
index 0000000..848784c
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int mkfifo(const char *path, mode_t mode)
+{
+   return mknod(path, mode | S_IFIFO, 0);
+}
\ No newline at end of file
diff --git a/Library/libs/opendir.c b/Library/libs/opendir.c
new file mode 100644 (file)
index 0000000..d9f542b
--- /dev/null
@@ -0,0 +1,35 @@
+#include <unistd.h>
+#include <alloc.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+DIR *opendir(char *path)
+{
+       struct stat statbuf;
+       register DIR *dir;
+
+       if (stat(path, &statbuf) != 0)
+               goto Err;
+       if ((statbuf.st_mode & S_IFDIR) == 0) {
+               errno = ENOTDIR;
+               goto Err;
+       }
+       if ((dir = (DIR *) calloc(1, sizeof(DIR))) == NULL) {
+               errno = ENOMEM;
+               goto Err;
+       }
+       if ((dir->dd_buf = calloc(1, sizeof(struct dirent))) == NULL) {
+               free(dir);
+               errno = ENOMEM;
+               goto Err;
+       }
+       if ((dir->dd_fd = open(path, O_RDONLY)) < 0) {
+               free(dir->dd_buf);
+               free(dir);
+             Err:return NULL;
+       }
+       return dir;
+}
diff --git a/Library/libs/pause.c b/Library/libs/pause.c
new file mode 100644 (file)
index 0000000..14d5f2c
--- /dev/null
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+int pause(void)
+{
+  return _pause(0);
+}
diff --git a/Library/libs/perror.c b/Library/libs/perror.c
new file mode 100644 (file)
index 0000000..5e6d638
--- /dev/null
@@ -0,0 +1,26 @@
+/* perror.c
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static void wr2(char *str)
+{
+       char *p = str;
+
+       while (*p)
+               ++p;
+       write(2, str, (unsigned int) (p - str));
+}
+
+void perror(char *str)
+{
+       if (!str)
+               str = "error";
+       wr2(str);
+       wr2(": ");
+       str = strerror(errno);
+       wr2(str);
+       wr2("\n");
+}
diff --git a/Library/libs/popen.c b/Library/libs/popen.c
new file mode 100644 (file)
index 0000000..96dd543
--- /dev/null
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <unistd.h>
+
+FILE *popen(const char *command, const char *rw)
+{
+   int pipe_fd[2];
+   int pid, reading;
+
+   if( pipe(pipe_fd) < 0 ) return NULL;
+   reading = (rw[0] == 'r');
+
+   pid = fork();
+   if( pid < 0 ) { close(pipe_fd[0]); close(pipe_fd[1]); return NULL; }
+   if( pid == 0 )
+   {
+      close(pipe_fd[!reading]);
+      close(reading);
+      if( pipe_fd[reading] != reading )
+      {
+        dup2(pipe_fd[reading], reading);
+         close(pipe_fd[reading]);
+      }
+
+      execl("/bin/sh", "sh", "-c", command, (char*)0);
+      _exit(255);
+   }
+
+   close(pipe_fd[reading]);
+   return fdopen(pipe_fd[!reading], rw);
+}
+
+int pclose(FILE *fd)
+{
+   int waitstat;
+   if( fclose(fd) != 0 ) return EOF;
+   return wait(&waitstat);
+}
diff --git a/Library/libs/printf.c b/Library/libs/printf.c
new file mode 100644 (file)
index 0000000..b0e8b5c
--- /dev/null
@@ -0,0 +1,27 @@
+/* printf.c
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *
+ * Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include "printf.h"
+#include "stdarg.h"
+
+int printf(char *fmt, ...)
+{
+       va_list ptr;
+       int rv;
+
+       va_start(ptr, fmt);
+       rv = vfprintf(stdout, fmt, ptr);
+       va_end(ptr);
+       return rv;
+}
diff --git a/Library/libs/printf.h b/Library/libs/printf.h
new file mode 100644 (file)
index 0000000..68582a5
--- /dev/null
@@ -0,0 +1,20 @@
+/* printf.c
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *
+ * Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+#include <types.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
diff --git a/Library/libs/putenv.c b/Library/libs/putenv.c
new file mode 100644 (file)
index 0000000..6547ffa
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+extern char ** environ;
+#define ADD_NUM 4
+
+int putenv(char *var)
+{
+static char ** mall_env;
+static int extras;
+   char **p, **d;
+   char * r;
+   int len;
+
+   r = strchr(var, '=');
+   if( r == 0 )  len = strlen(var);
+   else          len = r-var;
+
+   for(p=environ; *p; p++)
+   {
+      if( memcmp(var, *p, len) == 0 && (*p)[len] == '=' )
+      {
+         while( p[0] = p[1] ) p++;
+         extras++;
+         break;
+      }
+   }
+   if( r == 0 ) return 0;
+   if( extras <= 0 )   /* Need more space */
+   {
+      d = malloc((p-environ+1+ADD_NUM)*sizeof(char*));
+      if( d == 0 ) return -1;
+
+      memcpy((void*) d, (void*) environ, (p-environ+1)*sizeof(char*));
+      p = d + (p-environ);
+      extras=ADD_NUM;
+
+      if( mall_env ) free(mall_env);
+      environ = d;
+      mall_env = d;
+   }
+   *p++ = var;
+   *p = '\0';
+   extras--;
+
+   return 0;
+}
+
+
diff --git a/Library/libs/putgetch.c b/Library/libs/putgetch.c
new file mode 100644 (file)
index 0000000..7c6fb8f
--- /dev/null
@@ -0,0 +1,22 @@
+/* stdio.c\r
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+/* This is an implementation of the C standard IO package. */ \r
+    \r
+#include "stdio-l.h"\r
+\r
+int _putchar(int ch) \r
+{
+       return write(STDOUT_FILENO, (char *)&ch, 1);
+}
+
+int _getchar(void)
+{
+       unsigned char ch;
+       if (read(STDIN_FILENO, &ch, 1) == 1)
+               return ch;
+       return EOF;
+}
diff --git a/Library/libs/putpwent.c b/Library/libs/putpwent.c
new file mode 100644 (file)
index 0000000..a0035ea
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * putpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+
+int
+putpwent(const struct passwd * passwd, FILE * f)
+{
+  if (passwd == NULL || f == NULL)
+    {
+      errno=EINVAL;
+      return -1;
+    }
+  if (fprintf(f, "%s:%s:%u:%u:%s:%s:%s\n", passwd->pw_name, passwd->pw_passwd,
+         passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos,
+         passwd->pw_dir, passwd->pw_shell)<0)
+      return -1;
+
+  return 0;
+}
diff --git a/Library/libs/pwent.c b/Library/libs/pwent.c
new file mode 100644 (file)
index 0000000..738c87a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * pwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pwd.h>
+#include <fcntl.h>
+
+/*
+ * setpwent(), endpwent(), and getpwent() are included in the same object
+ * file, since one cannot be used without the other two, so it makes sense to
+ * link them all in together.
+ */
+
+/* file descriptor for the password file currently open */
+static int pw_fd = -1;
+
+void
+setpwent(void)
+{
+  if (pw_fd!=-1)
+    close(pw_fd);
+
+  pw_fd=open("/etc/passwd", O_RDONLY);
+}
+
+void
+endpwent(void)
+{
+  if (pw_fd!=-1)
+    close(pw_fd);
+  pw_fd=-1;
+}
+
+struct passwd *
+getpwent(void)
+{
+  if (pw_fd==-1)
+    setpwent();
+  if (pw_fd!=-1)
+    return __getpwent(pw_fd);
+  return NULL;  
+}
+
+
diff --git a/Library/libs/qsort.c b/Library/libs/qsort.c
new file mode 100644 (file)
index 0000000..68c3be0
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ */
+
+/*
+ * Sun Feb  8 21:02:15 EST 1998 claudio@pos.inf.ufpr.br (Claudio Matsuoka)
+ * Changed sort direction
+ */
+
+#include <string.h>
+
+char *_qbuf = 0;               /* pointer to storage for qsort() */
+
+#define        PIVOT                   ((i+j)>>1)
+#define moveitem(dst,src,size) if(dst != src) memcpy(dst, src, size)
+
+static void _wqsort(void *basep, int lo, int hi,
+               int (*cmp)(const void *, const void *))
+{
+   int   k;
+   register int i, j, t;
+   register int *p = &k;
+   char *base = basep;
+
+   while (hi > lo)
+   {
+      i = lo;
+      j = hi;
+      t = PIVOT;
+      *p = base[t];
+      base[t] = base[i];
+      base[i] = *p;
+      while (i < j)
+      {
+        while (((*cmp) ((base + j), p)) <= 0)
+           --j;
+        base[i] = base[j];
+        while ((i < j) && (((*cmp) ((base + i), p)) > 0))
+           ++i;
+        base[j] = base[i];
+      }
+      base[i] = *p;
+      if ((i - lo) < (hi - i))
+      {
+        _wqsort(base, lo, (i - 1), cmp);
+        lo = i + 1;
+      }
+      else
+      {
+        _wqsort(base, (i + 1), hi, cmp);
+        hi = i - 1;
+      }
+   }
+}
+
+static void _lqsort(long *base, int lo, int hi, int (*cmp)(const void *, const void *))
+{
+   long  k;
+   register int i, j, t;
+   register long *p = &k;
+
+   while (hi > lo)
+   {
+      i = lo;
+      j = hi;
+      t = PIVOT;
+      *p = base[t];
+      base[t] = base[i];
+      base[i] = *p;
+      while (i < j)
+      {
+        while (((*cmp) ((base + j), p)) <= 0)
+           --j;
+        base[i] = base[j];
+        while ((i < j) && (((*cmp) ((base + i), p)) > 0))
+           ++i;
+        base[j] = base[i];
+      }
+      base[i] = *p;
+      if ((i - lo) < (hi - i))
+      {
+        _lqsort(base, lo, (i - 1), cmp);
+        lo = i + 1;
+      }
+      else
+      {
+        _lqsort(base, (i + 1), hi, cmp);
+        hi = i - 1;
+      }
+   }
+}
+
+static void _nqsort(void *basep, int lo, int hi, int size,
+              int (*cmp)(const void *, const void *))
+{
+   register int i, j;
+   register char *p = _qbuf;
+   char *base = basep;
+
+   while (hi > lo)
+   {
+      i = lo;
+      j = hi;
+      p = (base + size * PIVOT);
+      moveitem(_qbuf, p, size);
+      moveitem(p, (base + size * i), size);
+      moveitem((base + size * i), _qbuf, size);
+      p = _qbuf;
+      while (i < j)
+      {
+        while (((*cmp) ((base + size * j), p)) <= 0)
+           --j;
+        moveitem((base + size * i), (base + size * j), size);
+        while ((i < j) && (((*cmp) ((base + size * i), p)) > 0))
+           ++i;
+        moveitem((base + size * j), (base + size * i), size);
+      }
+      moveitem((base + size * i), p, size);
+      if ((i - lo) < (hi - i))
+      {
+        _nqsort(base, lo, (i - 1), size, cmp);
+        lo = i + 1;
+      }
+      else
+      {
+        _nqsort(base, (i + 1), hi, size, cmp);
+        hi = i - 1;
+      }
+   }
+}
+
+void qsort(void *base, size_t num, size_t size,
+         int (*cmp)(const void *,const void *))
+{
+   char  _qtemp[128];
+
+   if (_qbuf == 0)
+   {
+      if (size > sizeof(_qtemp))/* records too large! */
+        return;
+      _qbuf = _qtemp;
+   }
+   if (size == 2)
+      _wqsort(base, 0, num - 1, cmp);
+   else if (size == 4)
+      _lqsort(base, 0, num - 1, cmp);
+   else
+      _nqsort(base, 0, num - 1, size, cmp);
+   if (_qbuf == _qtemp)
+      _qbuf = 0;
+}
diff --git a/Library/libs/raise.c b/Library/libs/raise.c
new file mode 100644 (file)
index 0000000..97779b0
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <sys/types.h>
+#include <unistd.h>
+
+int raise(int signo)
+{
+   return kill(getpid(), signo);
+}
diff --git a/Library/libs/rand.c b/Library/libs/rand.c
new file mode 100644 (file)
index 0000000..7d9dec4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * This generator is a combination of three linear congruential generators
+ * with periods or 2^15-405, 2^15-1041 and 2^15-1111. It has a period that
+ * is the product of these three numbers.
+ */
+
+static int seed1 = 1;
+static int seed2 = 1;
+static int seed3 = 1;
+#define MAXINT (((unsigned)-1)>>1)
+
+#define CRANK(a,b,c,m,s)       \
+       q = s/a;                \
+       s = b*(s-a*q) - c*q;    \
+       if(s<0) s+=m;
+
+int rand(void)
+{
+   register int q;
+   CRANK(206, 157,  31, 32363, seed1);
+   CRANK(217, 146,  45, 31727, seed2);
+   CRANK(222, 142, 133, 31657, seed3);
+
+   return seed1^seed2^seed3;
+}
+
+void srand(unsigned int seed)
+{
+   seed &= MAXINT;
+   seed1= seed%32362 + 1;
+   seed2= seed%31726 + 1;
+   seed3= seed%31656 + 1;
+}
+
diff --git a/Library/libs/readdir.c b/Library/libs/readdir.c
new file mode 100644 (file)
index 0000000..e326dfe
--- /dev/null
@@ -0,0 +1,39 @@
+/* readdir.c    readdir implementation
+ *
+ */
+#include <unistd.h>
+#include <alloc.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+struct dirent *readdir(DIR * dir)
+{
+       struct __dirent direntry;
+       register struct dirent *buf;
+       int len;
+
+       if (dir == NULL || dir->dd_buf == NULL || dir->dd_fd == 0) {
+               errno = EFAULT;
+               return NULL;
+       }
+       direntry.d_name[0] = 0;
+       while (direntry.d_name[0] == 0) {
+               len = _getdirent(dir->dd_fd, &direntry, sizeof(direntry));
+               if (len > sizeof(direntry)) {
+                       errno = ERANGE;
+                       return NULL; 
+               }
+               if (len == 0)
+                       return NULL;
+       }
+       buf = dir->dd_buf;
+       buf->d_ino = direntry.d_ino;
+       buf->d_off = -1;        /* FIXME */
+       buf->d_reclen = len + 1;
+       strncpy(buf->d_name, (char *) direntry.d_name, len - 2);
+       buf->d_name[len - 1] = 0;
+       return buf;
+}
diff --git a/Library/libs/readlink.c b/Library/libs/readlink.c
new file mode 100644 (file)
index 0000000..e493145
--- /dev/null
@@ -0,0 +1,16 @@
+/* readlink.c  readlink implementation for UZIX\r
+ */  \r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <syscalls.h>\r
+\r
+int readlink(char *name, char *buf, int size) \r
+{
+       int sts, fd = open(name, O_SYMLINK|O_RDONLY);
+\r
+       if (fd < 0)
+               return -1;
+       sts = read(fd, buf, size);
+       close(fd);
+       return sts;
+}
diff --git a/Library/libs/realloc.c b/Library/libs/realloc.c
new file mode 100644 (file)
index 0000000..f9f0a97
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ *\r
+ * This is a combined alloca/malloc package. It uses a classic algorithm\r
+ * and so may be seen to be quite slow compared to more modern routines\r
+ * with 'nasty' distributions.\r
+ */  \r
+    \r
+#include "malloc-l.h"\r
+\r
+void *realloc(void *ptr, size_t size) \r
+{
+       void *nptr;
+       unsigned int osize;
+       if (ptr == 0)
+               return malloc(size);
+       \r
+       /* ??? what if I really want to free rest of block ? */ \r
+       if (size <= (osize = (m_size(((mem *) ptr) - 1) - 1) * sizeof(mem)))
+               return ptr;
+       if ((nptr = malloc(size)) == NULL)
+               return 0;
+       memcpy(nptr, ptr, osize);
+       free(ptr);
+       return nptr;
+}
+
+\r
diff --git a/Library/libs/regerror.c b/Library/libs/regerror.c
new file mode 100644 (file)
index 0000000..7e62b10
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void regerror(char *s)
+{
+#ifdef ERRAVAIL
+       error("regexp: %s", s);
+#else
+       fprintf(stderr, "regexp(3): %s", s);
+       exit(1);
+#endif
+       /* NOTREACHED */
+}
diff --git a/Library/libs/regexp.c b/Library/libs/regexp.c
new file mode 100644 (file)
index 0000000..8f6b9b0
--- /dev/null
@@ -0,0 +1,1137 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ *     Copyright (c) 1986 by University of Toronto.
+ *     Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *     Permission is granted to anyone to use this software for any
+ *     purpose on any computer system, and to redistribute it freely,
+ *     subject to the following restrictions:
+ *
+ *     1. The author is not responsible for the consequences of use of
+ *             this software, no matter how awful, even if they arise
+ *             from defects in it.
+ *
+ *     2. The origin of this software must not be misrepresented, either
+ *             by explicit claim or by omission.
+ *
+ *     3. Altered versions must be plainly marked as such, and must not
+ *             be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * Modified: ANSIfied for SDCC by Alan Cox.
+ */
+#include <stdio.h>
+#include <regexp.h>
+#include <malloc.h>
+#include <string.h>
+#include "regmagic.h"
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart    char that must begin a match; '\0' if none obvious
+ * reganch     is the match anchored (at beginning-of-line only)?
+ * regmust     string (pointer into program) that match must include, or NULL
+ * regmlen     length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+/* definition  number  opnd?   meaning */
+#define        END     0       /* no   End of program. */
+#define        BOL     1       /* no   Match "" at beginning of line. */
+#define        EOL     2       /* no   Match "" at end of line. */
+#define        ANY     3       /* no   Match any one character. */
+#define        ANYOF   4       /* str  Match any character in this string. */
+#define        ANYBUT  5       /* str  Match any character not in this string. */
+#define        BRANCH  6       /* node Match this alternative, or the next... */
+#define        BACK    7       /* no   Match "", "next" ptr points backward. */
+#define        EXACTLY 8       /* str  Match this string. */
+#define        NOTHING 9       /* no   Match empty string. */
+#define        STAR    10      /* node Match this (simple) thing 0 or more times. */
+#define        PLUS    11      /* node Match this (simple) thing 1 or more times. */
+#define        OPEN    20      /* no   Mark this point in input as start of #n. */
+                       /*      OPEN+1 is number 1, etc. */
+#define        CLOSE   30      /* no   Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH      The set of branches constituting a single choice are hooked
+ *             together with their "next" pointers, since precedence prevents
+ *             anything being concatenated to any individual branch.  The
+ *             "next" pointer of the last BRANCH in a choice points to the
+ *             thing following the whole choice.  This is also where the
+ *             final "next" pointer of each individual branch points; each
+ *             branch starts with the operand node of a BRANCH node.
+ *
+ * BACK                Normal "next" pointers all implicitly point forward; BACK
+ *             exists to make loop structures possible.
+ *
+ * STAR,PLUS   '?', and complex '*' and '+', are implemented as circular
+ *             BRANCH structures using BACK.  Simple cases (one character
+ *             per match) are implemented with STAR and PLUS for speed
+ *             and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE  ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define        OP(p)   (*(p))
+#define        NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define        OPERAND(p)      ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
+#else
+#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
+#endif
+
+#define        FAIL(m) { regerror(m); return(NULL); }
+#define        ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
+#define        META    "^$.[()|?+*\\"
+
+/*
+ * Flags to be passed up and down.
+ */
+#define        HASWIDTH        01      /* Known never to match null string. */
+#define        SIMPLE          02      /* Simple enough to be STAR/PLUS operand. */
+#define        SPSTART         04      /* Starts with * or +. */
+#define        WORST           0       /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regparse;         /* Input-scan pointer. */
+static int regnpar;            /* () count. */
+static char regdummy;
+static char *regcode;          /* Code-emit pointer; &regdummy = don't. */
+static long regsize;           /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define        STATIC  static
+#endif
+STATIC char *reg(int, int *);
+STATIC char *regbranch(int *);
+STATIC char *regpiece(int *);
+STATIC char *regatom(int *);
+STATIC char *regnode(int);
+STATIC char *regnext(char *);
+STATIC void regc(char);
+STATIC void reginsert(char, char *);
+STATIC void regtail(char *, char *);
+STATIC void regoptail(char *, char *);
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *regcomp(char *exp)
+{
+       register regexp *r;
+       register char *scan;
+       register char *longest;
+       register int len;
+       int flags;
+
+       if (exp == NULL)
+               FAIL("NULL argument");
+
+       /* First pass: determine size, legality. */
+       regparse = exp;
+       regnpar = 1;
+       regsize = 0L;
+       regcode = &regdummy;
+       regc(MAGIC);
+       if (reg(0, &flags) == NULL)
+               return(NULL);
+
+       /* Small enough for pointer-storage convention? */
+       if (regsize >= 32767L)          /* Probably could be 65535L. */
+               FAIL("regexp too big");
+
+       /* Allocate space. */
+       r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+       if (r == NULL)
+               FAIL("out of space");
+
+       /* Second pass: emit code. */
+       regparse = exp;
+       regnpar = 1;
+       regcode = r->program;
+       regc(MAGIC);
+       if (reg(0, &flags) == NULL)
+               return(NULL);
+
+       /* Dig out information for optimizations. */
+       r->regstart = '\0';     /* Worst-case defaults. */
+       r->reganch = 0;
+       r->regmust = NULL;
+       r->regmlen = 0;
+       scan = r->program+1;                    /* First BRANCH. */
+       if (OP(regnext(scan)) == END) {         /* Only one top-level choice. */
+               scan = OPERAND(scan);
+
+               /* Starting-point info. */
+               if (OP(scan) == EXACTLY)
+                       r->regstart = *OPERAND(scan);
+               else if (OP(scan) == BOL)
+                       r->reganch++;
+
+               /*
+                * If there's something expensive in the r.e., find the
+                * longest literal string that must appear and make it the
+                * regmust.  Resolve ties in favor of later strings, since
+                * the regstart check works with the beginning of the r.e.
+                * and avoiding duplication strengthens checking.  Not a
+                * strong reason, but sufficient in the absence of others.
+                */
+               if (flags&SPSTART) {
+                       longest = NULL;
+                       len = 0;
+                       for (; scan != NULL; scan = regnext(scan))
+                               if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+                                       longest = OPERAND(scan);
+                                       len = strlen(OPERAND(scan));
+                               }
+                       r->regmust = longest;
+                       r->regmlen = len;
+               }
+       }
+
+       return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *reg(int paren, int *flagp)
+{
+       register char *ret;
+       register char *br;
+       register char *ender;
+       register int parno;
+       int flags;
+
+       *flagp = HASWIDTH;      /* Tentatively. */
+
+       /* Make an OPEN node, if parenthesized. */
+       if (paren) {
+               if (regnpar >= NSUBEXP)
+                       FAIL("too many ()");
+               parno = regnpar;
+               regnpar++;
+               ret = regnode(OPEN+parno);
+       } else
+               ret = NULL;
+
+       /* Pick up the branches, linking them together. */
+       br = regbranch(&flags);
+       if (br == NULL)
+               return(NULL);
+       if (ret != NULL)
+               regtail(ret, br);       /* OPEN -> first. */
+       else
+               ret = br;
+       if (!(flags&HASWIDTH))
+               *flagp &= ~HASWIDTH;
+       *flagp |= flags&SPSTART;
+       while (*regparse == '|') {
+               regparse++;
+               br = regbranch(&flags);
+               if (br == NULL)
+                       return(NULL);
+               regtail(ret, br);       /* BRANCH -> BRANCH. */
+               if (!(flags&HASWIDTH))
+                       *flagp &= ~HASWIDTH;
+               *flagp |= flags&SPSTART;
+       }
+
+       /* Make a closing node, and hook it on the end. */
+       ender = regnode((paren) ? CLOSE+parno : END);   
+       regtail(ret, ender);
+
+       /* Hook the tails of the branches to the closing node. */
+       for (br = ret; br != NULL; br = regnext(br))
+               regoptail(br, ender);
+
+       /* Check for proper termination. */
+       if (paren && *regparse++ != ')') {
+               FAIL("unmatched ()");
+       } else if (!paren && *regparse != '\0') {
+               if (*regparse == ')') {
+                       FAIL("unmatched ()");
+               } else
+                       FAIL("junk on end");    /* "Can't happen". */
+               /* NOTREACHED */
+       }
+
+       return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *regbranch(int *flagp)
+{
+       register char *ret;
+       register char *chain;
+       register char *latest;
+       int flags;
+
+       *flagp = WORST;         /* Tentatively. */
+
+       ret = regnode(BRANCH);
+       chain = NULL;
+       while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
+               latest = regpiece(&flags);
+               if (latest == NULL)
+                       return(NULL);
+               *flagp |= flags&HASWIDTH;
+               if (chain == NULL)      /* First piece. */
+                       *flagp |= flags&SPSTART;
+               else
+                       regtail(chain, latest);
+               chain = latest;
+       }
+       if (chain == NULL)      /* Loop ran zero times. */
+               (void) regnode(NOTHING);
+
+       return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *regpiece(int *flagp)
+{
+       register char *ret;
+       register char op;
+       register char *next;
+       int flags;
+
+       ret = regatom(&flags);
+       if (ret == NULL)
+               return(NULL);
+
+       op = *regparse;
+       if (!ISMULT(op)) {
+               *flagp = flags;
+               return(ret);
+       }
+
+       if (!(flags&HASWIDTH) && op != '?')
+               FAIL("*+ operand could be empty");
+       *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+       if (op == '*' && (flags&SIMPLE))
+               reginsert(STAR, ret);
+       else if (op == '*') {
+               /* Emit x* as (x&|), where & means "self". */
+               reginsert(BRANCH, ret);                 /* Either x */
+               regoptail(ret, regnode(BACK));          /* and loop */
+               regoptail(ret, ret);                    /* back */
+               regtail(ret, regnode(BRANCH));          /* or */
+               regtail(ret, regnode(NOTHING));         /* null. */
+       } else if (op == '+' && (flags&SIMPLE))
+               reginsert(PLUS, ret);
+       else if (op == '+') {
+               /* Emit x+ as x(&|), where & means "self". */
+               next = regnode(BRANCH);                 /* Either */
+               regtail(ret, next);
+               regtail(regnode(BACK), ret);            /* loop back */
+               regtail(next, regnode(BRANCH));         /* or */
+               regtail(ret, regnode(NOTHING));         /* null. */
+       } else if (op == '?') {
+               /* Emit x? as (x|) */
+               reginsert(BRANCH, ret);                 /* Either x */
+               regtail(ret, regnode(BRANCH));          /* or */
+               next = regnode(NOTHING);                /* null. */
+               regtail(ret, next);
+               regoptail(ret, next);
+       }
+       regparse++;
+       if (ISMULT(*regparse))
+               FAIL("nested *?+");
+
+       return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *regatom(int *flagp)
+{
+       register char *ret;
+       int flags;
+
+       *flagp = WORST;         /* Tentatively. */
+
+       switch (*regparse++) {
+       case '^':
+               ret = regnode(BOL);
+               break;
+       case '$':
+               ret = regnode(EOL);
+               break;
+       case '.':
+               ret = regnode(ANY);
+               *flagp |= HASWIDTH|SIMPLE;
+               break;
+       case '[': {
+                       register int class;
+                       register int classend;
+
+                       if (*regparse == '^') { /* Complement of range. */
+                               ret = regnode(ANYBUT);
+                               regparse++;
+                       } else
+                               ret = regnode(ANYOF);
+                       if (*regparse == ']' || *regparse == '-')
+                               regc(*regparse++);
+                       while (*regparse != '\0' && *regparse != ']') {
+                               if (*regparse == '-') {
+                                       regparse++;
+                                       if (*regparse == ']' || *regparse == '\0')
+                                               regc('-');
+                                       else {
+                                               class = UCHARAT(regparse-2)+1;
+                                               classend = UCHARAT(regparse);
+                                               if (class > classend+1)
+                                                       FAIL("invalid [] range");
+                                               for (; class <= classend; class++)
+                                                       regc(class);
+                                               regparse++;
+                                       }
+                               } else
+                                       regc(*regparse++);
+                       }
+                       regc('\0');
+                       if (*regparse != ']')
+                               FAIL("unmatched []");
+                       regparse++;
+                       *flagp |= HASWIDTH|SIMPLE;
+               }
+               break;
+       case '(':
+               ret = reg(1, &flags);
+               if (ret == NULL)
+                       return(NULL);
+               *flagp |= flags&(HASWIDTH|SPSTART);
+               break;
+       case '\0':
+       case '|':
+       case ')':
+               FAIL("internal urp");   /* Supposed to be caught earlier. */
+               break;
+       case '?':
+       case '+':
+       case '*':
+               FAIL("?+* follows nothing");
+               break;
+       case '\\':
+               if (*regparse == '\0')
+                       FAIL("trailing \\");
+               ret = regnode(EXACTLY);
+               regc(*regparse++);
+               regc('\0');
+               *flagp |= HASWIDTH|SIMPLE;
+               break;
+       default: {
+                       register int len;
+                       register char ender;
+
+                       regparse--;
+                       len = strcspn(regparse, META);
+                       if (len <= 0)
+                               FAIL("internal disaster");
+                       ender = *(regparse+len);
+                       if (len > 1 && ISMULT(ender))
+                               len--;          /* Back off clear of ?+* operand. */
+                       *flagp |= HASWIDTH;
+                       if (len == 1)
+                               *flagp |= SIMPLE;
+                       ret = regnode(EXACTLY);
+                       while (len > 0) {
+                               regc(*regparse++);
+                               len--;
+                       }
+                       regc('\0');
+               }
+               break;
+       }
+
+       return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char *regnode(int op)   /* location */
+{
+       register char *ret;
+       register char *ptr;
+
+       ret = regcode;
+       if (ret == &regdummy) {
+               regsize += 3;
+               return(ret);
+       }
+
+       ptr = ret;
+       *ptr++ = op;
+       *ptr++ = '\0';          /* Null "next" pointer. */
+       *ptr++ = '\0';
+       regcode = ptr;
+
+       return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc(char b)
+{
+       if (regcode != &regdummy)
+               *regcode++ = b;
+       else
+               regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void reginsert(char op, char *opnd)
+{
+       register char *src;
+       register char *dst;
+       register char *place;
+
+       if (regcode == &regdummy) {
+               regsize += 3;
+               return;
+       }
+
+       src = regcode;
+       regcode += 3;
+       dst = regcode;
+       while (src > opnd)
+               *--dst = *--src;
+
+       place = opnd;           /* Op node, where operand used to be. */
+       *place++ = op;
+       *place++ = '\0';
+       *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail(char *p, char *val)
+{
+       register char *scan;
+       register char *temp;
+       register int offset;
+
+       if (p == &regdummy)
+               return;
+
+       /* Find last node. */
+       scan = p;
+       for (;;) {
+               temp = regnext(scan);
+               if (temp == NULL)
+                       break;
+               scan = temp;
+       }
+
+       if (OP(scan) == BACK)
+               offset = scan - val;
+       else
+               offset = val - scan;
+       *(scan+1) = (offset>>8)&0377;
+       *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void regoptail(char *p, char *val)
+{
+       /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+       if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+               return;
+       regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput;         /* String-input pointer. */
+static char *regbol;           /* Beginning of input, for ^ check. */
+static char **regstartp;       /* Pointer to startp array. */
+static char **regendp;         /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry(regexp *, char *);
+STATIC int regmatch(char *);
+STATIC int regrepeat(char *);
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump(regexp *);
+STATIC char *regprop(char *);
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int regexec(register regexp *prog, register char *string)
+{
+       register char *s;
+
+       /* Be paranoid... */
+       if (prog == NULL || string == NULL) {
+               regerror("NULL parameter");
+               return(0);
+       }
+
+       /* Check validity of program. */
+       if (UCHARAT(prog->program) != MAGIC) {
+               regerror("corrupted program");
+               return(0);
+       }
+
+       /* If there is a "must appear" string, look for it. */
+       if (prog->regmust != NULL) {
+               s = string;
+               while ((s = strchr(s, prog->regmust[0])) != NULL) {
+                       if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+                               break;  /* Found it. */
+                       s++;
+               }
+               if (s == NULL)  /* Not present. */
+                       return(0);
+       }
+
+       /* Mark beginning of line for ^ . */
+       regbol = string;
+
+       /* Simplest case:  anchored match need be tried only once. */
+       if (prog->reganch)
+               return(regtry(prog, string));
+
+       /* Messy cases:  unanchored match. */
+       s = string;
+       if (prog->regstart != '\0')
+               /* We know what char it must start with. */
+               while ((s = strchr(s, prog->regstart)) != NULL) {
+                       if (regtry(prog, s))
+                               return(1);
+                       s++;
+               }
+       else
+               /* We don't -- general case. */
+               do {
+                       if (regtry(prog, s))
+                               return(1);
+               } while (*s++ != '\0');
+
+       /* Failure. */
+       return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int regtry(regexp *prog, char *string)  /* 0 failure, 1 success */
+{
+       register int i;
+       register char **sp;
+       register char **ep;
+
+       reginput = string;
+       regstartp = prog->startp;
+       regendp = prog->endp;
+
+       sp = prog->startp;
+       ep = prog->endp;
+       for (i = NSUBEXP; i > 0; i--) {
+               *sp++ = NULL;
+               *ep++ = NULL;
+       }
+       if (regmatch(prog->program + 1)) {
+               prog->startp[0] = string;
+               prog->endp[0] = reginput;
+               return(1);
+       } else
+               return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int regmatch(char *prog)/* 0 failure, 1 success */
+{
+       register char *scan;    /* Current node. */
+       char *next;             /* Next node. */
+
+       scan = prog;
+#ifdef DEBUG
+       if (scan != NULL && regnarrate)
+               fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+       while (scan != NULL) {
+#ifdef DEBUG
+               if (regnarrate)
+                       fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+               next = regnext(scan);
+
+               switch (OP(scan)) {
+               case BOL:
+                       if (reginput != regbol)
+                               return(0);
+                       break;
+               case EOL:
+                       if (*reginput != '\0')
+                               return(0);
+                       break;
+               case ANY:
+                       if (*reginput == '\0')
+                               return(0);
+                       reginput++;
+                       break;
+               case EXACTLY: {
+                               register int len;
+                               register char *opnd;
+
+                               opnd = OPERAND(scan);
+                               /* Inline the first character, for speed. */
+                               if (*opnd != *reginput)
+                                       return(0);
+                               len = strlen(opnd);
+                               if (len > 1 && strncmp(opnd, reginput, len) != 0)
+                                       return(0);
+                               reginput += len;
+                       }
+                       break;
+               case ANYOF:
+                       if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+                               return(0);
+                       reginput++;
+                       break;
+               case ANYBUT:
+                       if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+                               return(0);
+                       reginput++;
+                       break;
+               case NOTHING:
+                       break;
+               case BACK:
+                       break;
+               case OPEN+1:
+               case OPEN+2:
+               case OPEN+3:
+               case OPEN+4:
+               case OPEN+5:
+               case OPEN+6:
+               case OPEN+7:
+               case OPEN+8:
+               case OPEN+9: {
+                               register int no;
+                               register char *save;
+
+                               no = OP(scan) - OPEN;
+                               save = reginput;
+
+                               if (regmatch(next)) {
+                                       /*
+                                        * Don't set startp if some later
+                                        * invocation of the same parentheses
+                                        * already has.
+                                        */
+                                       if (regstartp[no] == NULL)
+                                               regstartp[no] = save;
+                                       return(1);
+                               } else
+                                       return(0);
+                       }
+                       break;
+               case CLOSE+1:
+               case CLOSE+2:
+               case CLOSE+3:
+               case CLOSE+4:
+               case CLOSE+5:
+               case CLOSE+6:
+               case CLOSE+7:
+               case CLOSE+8:
+               case CLOSE+9: {
+                               register int no;
+                               register char *save;
+
+                               no = OP(scan) - CLOSE;
+                               save = reginput;
+
+                               if (regmatch(next)) {
+                                       /*
+                                        * Don't set endp if some later
+                                        * invocation of the same parentheses
+                                        * already has.
+                                        */
+                                       if (regendp[no] == NULL)
+                                               regendp[no] = save;
+                                       return(1);
+                               } else
+                                       return(0);
+                       }
+                       break;
+               case BRANCH: {
+                               register char *save;
+
+                               if (OP(next) != BRANCH)         /* No choice. */
+                                       next = OPERAND(scan);   /* Avoid recursion. */
+                               else {
+                                       do {
+                                               save = reginput;
+                                               if (regmatch(OPERAND(scan)))
+                                                       return(1);
+                                               reginput = save;
+                                               scan = regnext(scan);
+                                       } while (scan != NULL && OP(scan) == BRANCH);
+                                       return(0);
+                                       /* NOTREACHED */
+                               }
+                       }
+                       break;
+               case STAR:
+               case PLUS: {
+                               register char nextch;
+                               register int no;
+                               register char *save;
+                               register int min;
+
+                               /*
+                                * Lookahead to avoid useless match attempts
+                                * when we know what character comes next.
+                                */
+                               nextch = '\0';
+                               if (OP(next) == EXACTLY)
+                                       nextch = *OPERAND(next);
+                               min = (OP(scan) == STAR) ? 0 : 1;
+                               save = reginput;
+                               no = regrepeat(OPERAND(scan));
+                               while (no >= min) {
+                                       /* If it could work, try it. */
+                                       if (nextch == '\0' || *reginput == nextch)
+                                               if (regmatch(next))
+                                                       return(1);
+                                       /* Couldn't or didn't -- back up. */
+                                       no--;
+                                       reginput = save + no;
+                               }
+                               return(0);
+                       }
+                       break;
+               case END:
+                       return(1);      /* Success! */
+                       break;
+               default:
+                       regerror("memory corruption");
+                       return(0);
+                       break;
+               }
+
+               scan = next;
+       }
+
+       /*
+        * We get here only if there's trouble -- normally "case END" is
+        * the terminating point.
+        */
+       regerror("corrupted pointers");
+       return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat(char *p)
+{
+       register int count = 0;
+       register char *scan;
+       register char *opnd;
+
+       scan = reginput;
+       opnd = OPERAND(p);
+       switch (OP(p)) {
+       case ANY:
+               count = strlen(scan);
+               scan += count;
+               break;
+       case EXACTLY:
+               while (*opnd == *scan) {
+                       count++;
+                       scan++;
+               }
+               break;
+       case ANYOF:
+               while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+                       count++;
+                       scan++;
+               }
+               break;
+       case ANYBUT:
+               while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+                       count++;
+                       scan++;
+               }
+               break;
+       default:                /* Oh dear.  Called inappropriately. */
+               regerror("internal foulup");
+               count = 0;      /* Best compromise. */
+               break;
+       }
+       reginput = scan;
+
+       return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *regnext(register char *p)
+{
+       register int offset;
+
+       if (p == &regdummy)
+               return(NULL);
+
+       offset = NEXT(p);
+       if (offset == 0)
+               return(NULL);
+
+       if (OP(p) == BACK)
+               return(p-offset);
+       else
+               return(p+offset);
+}
+
+#ifdef DEBUG
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void regdump(regexp *r;
+{
+       register char *s;
+       register char op = EXACTLY;     /* Arbitrary non-END op. */
+       register char *next;
+
+
+       s = r->program + 1;
+       while (op != END) {     /* While that wasn't END last time... */
+               op = OP(s);
+               printf("%2d%s", s-r->program, regprop(s));      /* Where, what. */
+               next = regnext(s);
+               if (next == NULL)               /* Next ptr. */
+                       printf("(0)");
+               else 
+                       printf("(%d)", (s-r->program)+(next-s));
+               s += 3;
+               if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+                       /* Literal string, where present. */
+                       while (*s != '\0') {
+                               putchar(*s);
+                               s++;
+                       }
+                       s++;
+               }
+               putchar('\n');
+       }
+
+       /* Header fields of interest. */
+       if (r->regstart != '\0')
+               printf("start `%c' ", r->regstart);
+       if (r->reganch)
+               printf("anchored ");
+       if (r->regmust != NULL)
+               printf("must have \"%s\"", r->regmust);
+       printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *regprop(char *op)
+{
+       register char *p;
+       static char buf[50];
+
+       (void) strcpy(buf, ":");
+
+       switch (OP(op)) {
+       case BOL:
+               p = "BOL";
+               break;
+       case EOL:
+               p = "EOL";
+               break;
+       case ANY:
+               p = "ANY";
+               break;
+       case ANYOF:
+               p = "ANYOF";
+               break;
+       case ANYBUT:
+               p = "ANYBUT";
+               break;
+       case BRANCH:
+               p = "BRANCH";
+               break;
+       case EXACTLY:
+               p = "EXACTLY";
+               break;
+       case NOTHING:
+               p = "NOTHING";
+               break;
+       case BACK:
+               p = "BACK";
+               break;
+       case END:
+               p = "END";
+               break;
+       case OPEN+1:
+       case OPEN+2:
+       case OPEN+3:
+       case OPEN+4:
+       case OPEN+5:
+       case OPEN+6:
+       case OPEN+7:
+       case OPEN+8:
+       case OPEN+9:
+               sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+               p = NULL;
+               break;
+       case CLOSE+1:
+       case CLOSE+2:
+       case CLOSE+3:
+       case CLOSE+4:
+       case CLOSE+5:
+       case CLOSE+6:
+       case CLOSE+7:
+       case CLOSE+8:
+       case CLOSE+9:
+               sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+               p = NULL;
+               break;
+       case STAR:
+               p = "STAR";
+               break;
+       case PLUS:
+               p = "PLUS";
+               break;
+       default:
+               regerror("corrupted opcode");
+               break;
+       }
+       if (p != NULL)
+               (void) strcat(buf, p);
+       return(buf);
+}
+#endif
+
diff --git a/Library/libs/regexp.h b/Library/libs/regexp.h
new file mode 100644 (file)
index 0000000..73d6bf4
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+#define NSUBEXP  10
+typedef struct regexp {
+       char *startp[NSUBEXP];
+       char *endp[NSUBEXP];
+       char regstart;          /* Internal use only. */
+       char reganch;           /* Internal use only. */
+       char *regmust;          /* Internal use only. */
+       int regmlen;            /* Internal use only. */
+       char program[1];        /* Unwarranted chumminess with compiler. */
+} regexp;
+
+extern regexp *regcomp();
+extern int regexec();
+extern void regsub();
+extern void regerror();
diff --git a/Library/libs/regmagic.h b/Library/libs/regmagic.h
new file mode 100644 (file)
index 0000000..5acf447
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define        MAGIC   0234
diff --git a/Library/libs/regsub.c b/Library/libs/regsub.c
new file mode 100644 (file)
index 0000000..3ba39f6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * regsub
+ *
+ *     Copyright (c) 1986 by University of Toronto.
+ *     Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *     Permission is granted to anyone to use this software for any
+ *     purpose on any computer system, and to redistribute it freely,
+ *     subject to the following restrictions:
+ *
+ *     1. The author is not responsible for the consequences of use of
+ *             this software, no matter how awful, even if they arise
+ *             from defects in it.
+ *
+ *     2. The origin of this software must not be misrepresented, either
+ *             by explicit claim or by omission.
+ *
+ *     3. Altered versions must be plainly marked as such, and must not
+ *             be misrepresented as being the original software.
+ *
+ *     Modified: ANSIfied for SDCC Alan Cox 2014
+ */
+#include <stdio.h>
+#include <string.h>
+#include <regexp.h>
+#include "regmagic.h"
+
+#ifndef CHARBITS
+#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
+#else
+#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void regsub(regexp *prog, char *source, char *dest)
+{
+       char *src;
+       char *dst;
+       char c;
+       int no;
+       int len;
+
+       if (prog == NULL || source == NULL || dest == NULL) {
+               regerror("NULL parm to regsub");
+               return;
+       }
+       if (UCHARAT(prog->program) != MAGIC) {
+               regerror("damaged regexp fed to regsub");
+               return;
+       }
+
+       src = source;
+       dst = dest;
+       while ((c = *src++) != '\0') {
+               if (c == '&')
+                       no = 0;
+               else if (c == '\\' && '0' <= *src && *src <= '9')
+                       no = *src++ - '0';
+               else
+                       no = -1;
+
+               if (no < 0) {   /* Ordinary character. */
+                       if (c == '\\' && (*src == '\\' || *src == '&'))
+                               c = *src++;
+                       *dst++ = c;
+               } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+                       len = prog->endp[no] - prog->startp[no];
+                       (void) strncpy(dst, prog->startp[no], len);
+                       dst += len;
+                       if (len != 0 && *(dst-1) == '\0') {
+                                                       /* strncpy hit NUL. */
+                               regerror("damaged match string");
+                               return;
+                       }
+               }
+       }
+       *dst++ = '\0';
+}
diff --git a/Library/libs/remove.c b/Library/libs/remove.c
new file mode 100644 (file)
index 0000000..10f0ea7
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+int remove(__const char *src)
+{
+   int er = errno;
+   int rv = unlink(src);
+   if( rv < 0 && errno == EISDIR )
+      rv = rmdir(src);
+   if( rv >= 0 ) errno = er;
+   return rv;
+}
diff --git a/Library/libs/revoke.c b/Library/libs/revoke.c
new file mode 100644 (file)
index 0000000..a5fae4f
--- /dev/null
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <termios.h>
+
+int frevoke(int fd)
+{
+  return ioctl(fd, TIOCHANGUP, 0);
+}
diff --git a/Library/libs/rewind.c b/Library/libs/rewind.c
new file mode 100644 (file)
index 0000000..5dc65ac
--- /dev/null
@@ -0,0 +1,43 @@
+/* stdio.c\r
+ * Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+/* This is an implementation of the C standard IO package. */ \r
+    \r
+#include "stdio-l.h"\r
+\r
+void rewind(FILE * fp) \r
+{
+       fseek(fp, 0L, SEEK_SET);
+       clearerr(fp);
+}\r
+\r
+int fseek(FILE * fp, long offset, int ref) \r
+{
+       /* if __MODE_READING and no ungetc ever done can just move pointer */ \r
+       /* This needs testing! */ \r
+       if ((fp->mode & (__MODE_READING | __MODE_UNGOT)) ==
+               __MODE_READING && \r(ref == SEEK_SET || ref == SEEK_CUR)) {
+               off_t fpos = lseek(fp->fd, 0L, SEEK_CUR);
+               if (fpos == -1L)
+                       return EOF;
+               if (ref == SEEK_CUR) {
+                       ref = SEEK_SET;
+                       offset += fpos + (fp->bufpos - fp->bufread);
+               }
+               if (ref == SEEK_SET) {
+                       if (offset < fpos && /* ??? */\r
+                               offset >= fpos + (fp->bufstart - fp->bufread)) {
+                               fp->bufpos = (int) (offset - fpos) + fp->bufread;
+                               return 0;
+                       }
+               }
+       }
+\r
+       /* Use fflush to sync the pointers */ \r
+       if (fflush(fp) == EOF || lseek(fp->fd, offset, ref) < 0)
+               return EOF;
+       return 0;
+}
diff --git a/Library/libs/rindex.c b/Library/libs/rindex.c
new file mode 100644 (file)
index 0000000..d25435c
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <sys/types.h>
+
+char *rindex(__const char *src, int chr)
+{
+  return strrchr(src, chr);
+}
diff --git a/Library/libs/scanf.c b/Library/libs/scanf.c
new file mode 100644 (file)
index 0000000..be70a75
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file based on scanf.c from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 19-OCT-88: Dale Schumacher
+ * > John Stanley has again been a great help in debugging, particularly
+ * > with the printf/scanf functions which are his creation.  
+ *
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+
+int scanf(const char * fmt, ...)
+{
+  va_list ptr;
+  int rv;
+  va_start(ptr, fmt);
+  rv = vfscanf(stdin,fmt,ptr);
+  va_end(ptr);
+  return rv;
+}
diff --git a/Library/libs/setbuffer.c b/Library/libs/setbuffer.c
new file mode 100644 (file)
index 0000000..ed0be11
--- /dev/null
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void setbuffer(FILE * fp, char * buf, unsigned int size)
+{
+   fflush(fp);
+   if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart);
+   fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF);
+
+   if( buf == 0 )
+   {
+      fp->bufstart = fp->unbuf;
+      fp->bufend = fp->unbuf + sizeof(fp->unbuf);
+      fp->mode |= _IONBF;
+   }
+   else
+   {
+      fp->bufstart = buf;
+      fp->bufend = buf+size;
+      fp->mode |= _IOFBF;
+   }
+   fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+}
diff --git a/Library/libs/setenv.c b/Library/libs/setenv.c
new file mode 100644 (file)
index 0000000..013edc1
--- /dev/null
@@ -0,0 +1,79 @@
+/**************************** setenv.c ****************************/
+/* Copyright (C) 1992, 1995 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+int setenv(char *name, char *value, int replace)
+{
+       register char **ep;
+       register size_t size = 0;
+       size_t namelen = strlen(name);
+       size_t vallen = strlen(value);
+       char *p;
+       ep = environ;
+       while ((p = *ep++) != NULL) {
+               if (!memcmp(p, name, namelen) && p[namelen] == '=')
+                       break;
+               ++size;
+       }
+       if (p == NULL) {
+               static char **last_environ;
+               char **new_environ =
+                   (char **) malloc((size + 2) * sizeof(char *));
+               if (new_environ == NULL) {
+                     Err:errno = ENOMEM;
+                       return -1;
+               }
+               memcpy(new_environ, environ, size * sizeof(char *));
+               if ((p = malloc(namelen + 1 + vallen + 1)) == NULL) {
+                       free(new_environ);
+                       goto Err;
+               }
+               memcpy(p, name, namelen);
+               p[namelen] = '=';
+               memcpy(&p[namelen + 1], value, vallen + 1);
+               new_environ[size] = p;
+               new_environ[size + 1] = NULL;
+               if (last_environ != NULL)
+                       free((void *) last_environ);
+               last_environ = new_environ;
+               environ = new_environ;
+       } else if (replace) {
+               /* var exists and replaceing it contents is desired */
+               size_t len = strlen(p);
+
+               /* no room for new var and its contents. alloc space
+                  for name and new content and copy them */
+               if (len < namelen + 1 + vallen) {
+                       char *new = malloc(namelen + 1 + vallen + 1);
+                       if (new == NULL)
+                               goto Err;
+                       memcpy(new, name, namelen);     /* name */
+                       new[namelen] = '=';
+                       *--ep = p = new;
+                       /* next step: put new content */
+               }
+
+               /* if len(old_value)>len(new_value), so we can just
+                  copy the new value over the old one */
+               memcpy(&p[namelen + 1], value, vallen + 1);
+       }
+       return 0;
+}
+
+void unsetenv(char *name)
+{
+       register char **ep, **dp, *p;
+       size_t namelen = strlen(name);
+       dp = ep = environ;
+       while ((p = *ep++) != NULL) {
+               if (memcmp(p, name, namelen) || p[namelen] != '=')
+                       *dp++ = p;
+       }
+       *dp = NULL;
+}
diff --git a/Library/libs/setjmp.c b/Library/libs/setjmp.c
new file mode 100644 (file)
index 0000000..2ead945
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * setjmp.c for UZIX
+ * by A&L Software, 08/07/99
+ *
+ * FIXME: Add alt register saves
+ */
+#include <setjmp.h>
+
+static int _lngjmprv = 1;
+
+int setjmp (jmp_buf env) __naked /* int jmp_buf[7] */
+{
+__asm
+        push    ix
+        ld      ix,#0
+        add     ix,sp
+
+        ; DE = env
+       ld e, 4(ix)
+       ld d, 5(ix)
+        ; dont use stack here!
+
+        .db    0xFD,0x7D       ; LD A,IYl      - saves IY
+        ld      (de),a
+        inc     de
+        .db    0xFD,0x7C       ; LD A,IYh
+        ld      (de),a
+        inc     de
+        .db    0xDD,0x7D       ; LD A,IXl      - saves IX
+        ld      (de),a
+        inc     de
+        .db    0xDD,0x7C       ; LD A,IXh
+        ld      (de),a
+        inc     de
+        ld      a,c             ;               - saves BC
+        ld      (de),a
+        inc     de
+        ld      a,b
+        ld      (de),a
+        inc     de
+        ld      a,e             ;               - saves DE
+        ld      (de),a
+        inc     de
+        ld      a,d
+        ld      (de),a
+        inc     de
+        ld      a,l             ;               - saves HL
+        ld      (de),a
+        inc     de
+        ld      a,h
+        ld      (de),a
+        inc     de
+        ld      hl,#0x0000
+        add     hl,sp           ; HL = SP
+        inc     hl              ; skip return address to after setjmp call
+        inc     hl              ; (it is saved below)
+        ld      a,l             ;               - saves SP
+        ld      (de),a
+        inc     de
+        ld      a,h
+        ld      (de),a
+        inc     de
+        pop     hl              ; HL = return address after setjmp call
+        push    hl
+        ld      a,l             ;               - saves PC
+        ld      (de),a
+        inc     de
+        ld      a,h
+        ld      (de),a
+        ld      hl,#0x0000
+
+       pop ix
+       ret
+__endasm;
+}
+
+void longjmp (jmp_buf env, int rv) __naked
+{
+__asm
+        push    ix
+        ld      ix,#0
+        add     ix,sp
+
+        ; BC = rv, DE = env
+       
+       ld e, 4(ix)
+       ld d, 5(ix)
+       ld c, 6(ix)
+       ld b, 7(ix)
+
+        ; dont use stack here!
+        .globl  __lngjmprv
+
+        ld      (__lngjmprv),bc
+        ld      hl,#0x0012
+        add     hl,de
+        ld      b,(hl)
+        dec     hl
+        ld      c,(hl)          ; BC = return address after setjmp call
+        dec     hl
+        ld      a,(hl)
+        dec     hl
+        ld      l,(hl)
+        ld      h,a             ; HL = saved SP in env
+        ld      sp,hl           ;               - restores SP
+        push    bc              ; put return address in stack
+        ld      a,(de)
+        .db    0xFD,0x6F       ; LD IYl,A      - restores IY
+        inc     de
+        ld      a,(de)
+        .db    0xFD,0x67       ; LD IYh,A
+        inc     de
+        ld      a,(de)
+        .db    0xDD,0x6F       ; LD IXl,A      - restores IX
+        inc     de
+        ld      a,(de)
+        .db    0xDD,0x67       ; LD IXh,A
+        inc     de
+        ld      a,(de)
+        ld      c,a             ;               - restores BC
+        inc     de
+        ld      a,(de)
+        ld      b,a
+        inc     de
+        ld      a,(de)
+        ;ld     e,a             ;               - restores DE
+        inc     de
+        ;ld     a,(de)
+        ;ld     d,a             ; DE is the pointer, it cant be restored.
+        inc     de              ; anyway, it doesnt matter for lonjmp/setjmp
+        ;ld     a,(de)
+        ;ld     l,a             ;               - restores HL
+        inc     de
+        ;ld     a,(de)          ; HL is the return value, it dont need to be
+        ;ld     h,a             ; restored, because it will be overwritten.
+        ld      hl,(__lngjmprv) ; return value
+        ld      a,h             ; zero?
+
+       pop ix
+
+        or      l
+        ret     nz              ; return it if not
+        ld      hl,#0x0001
+        ret                     ; else return 1
+__endasm;
+}
+
diff --git a/Library/libs/setvbuf.c b/Library/libs/setvbuf.c
new file mode 100644 (file)
index 0000000..5b30c4a
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int setvbuf(FILE *fp, char *buf, int mode, size_t size)
+{
+   int rv = 0;
+   fflush(fp);
+   if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart);
+   fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF);
+   fp->bufstart = fp->unbuf;
+   fp->bufend = fp->unbuf + sizeof(fp->unbuf);
+   fp->mode |= _IONBF;
+
+   if( mode == _IOFBF || mode == _IOLBF )
+   {
+      if( size <= 0  ) size = BUFSIZ;
+      if( buf == 0 )
+      {
+         if( (buf = malloc(size)) != 0 )
+           fp->mode |= __MODE_FREEBUF;
+         else rv = EOF;
+      }
+      if( buf )
+      {
+         fp->bufstart = buf;
+         fp->bufend = buf+size;
+         fp->mode &= ~__MODE_BUF;
+         fp->mode |= mode;
+      }
+   }
+   fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+   return rv;
+}
diff --git a/Library/libs/sleep.c b/Library/libs/sleep.c
new file mode 100644 (file)
index 0000000..b016399
--- /dev/null
@@ -0,0 +1,17 @@
+/* sleep.c
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <syscalls.h>
+
+unsigned int sleep(unsigned int seconds)
+{
+       time_t end, now;
+       _time(&end);
+       end += seconds;
+       if (_pause(seconds * 10) == 0)
+               return 0;
+       _time(&now);
+       return (int)(end - now);
+}
diff --git a/Library/libs/sprintf.c b/Library/libs/sprintf.c
new file mode 100644 (file)
index 0000000..09ad93d
--- /dev/null
@@ -0,0 +1,37 @@
+/* printf.c
+ *    Dale Schumacher                        399 Beacon Ave.
+ *    (alias: Dalnefre')                     St. Paul, MN  55104
+ *    dal@syntel.UUCP                        United States of America
+ *
+ * Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include <stdarg.h>
+#include "printf.h"
+
+/* Moved out of struct to keep SDCC generating what we want */
+static FILE string[1] = {
+       {0, 0, /* TODO sdcc bug (unsigned char *)-1 */ 0xffff,
+        0, (unsigned char *) -1, -1,
+        _IOFBF | __MODE_WRITE}
+};
+
+
+int sprintf(char *sp, char *fmt, ...)
+{
+       va_list ptr;
+       int rv;
+
+       va_start(ptr, fmt);
+       string->bufpos = (unsigned char *) sp;
+       rv = vfprintf(string, fmt, ptr);
+       va_end(ptr);
+       *(string->bufpos) = 0;
+       return rv;
+}
diff --git a/Library/libs/sscanf.c b/Library/libs/sscanf.c
new file mode 100644 (file)
index 0000000..56b23ec
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * This file based on scanf.c from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 19-OCT-88: Dale Schumacher
+ * > John Stanley has again been a great help in debugging, particularly
+ * > with the printf/scanf functions which are his creation.  
+ *
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+
+int sscanf(char * sp, const char * fmt, ...)
+{
+static FILE  string[1] =
+{
+   {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
+    _IOFBF | __MODE_READ}
+};
+
+  va_list ptr;
+  int rv;
+  va_start(ptr, fmt);
+  string->bufpos = sp;
+  rv = vfscanf(string,fmt,ptr);
+  va_end(ptr);
+  return rv;
+}
diff --git a/Library/libs/stat.c b/Library/libs/stat.c
new file mode 100644 (file)
index 0000000..e366cc6
--- /dev/null
@@ -0,0 +1,36 @@
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int statfix(struct stat *st, struct _uzistat *s)
+{
+  st->st_dev = s->st_dev;
+  st->st_ino = s->st_ino;
+  st->st_mode = s->st_mode;
+  st->st_nlink = s->st_nlink;
+  st->st_uid = s->st_uid;
+  st->st_gid = s->st_gid;
+  st->st_rdev = s->st_rdev;
+  st->st_size = s->st_size;
+  /* FIXME: these 3 will change when the kernel API is fixed to pass
+     some "high bits" stuffed somewhere else */
+  st->st_atime = s->st_atime;
+  st->st_mtime = s->st_mtime;
+  st->st_ctime = s->st_ctime;
+  return 0;
+}
+
+int fstat(int fd, struct stat *st)
+{
+  struct _uzistat s;
+  if (_fstat(fd, &s) != 0)
+    return -1;
+  return statfix(st, &s);
+}
+
+int stat(const char *path, struct stat *st)
+{
+  struct _uzistat s;
+  if (_stat(path, &s) != 0)
+    return -1;
+  return statfix(st, &s);
+}
diff --git a/Library/libs/stdio-l.h b/Library/libs/stdio-l.h
new file mode 100644 (file)
index 0000000..5471573
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _STDIO_L_H
+#define _STDIO_L_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <types.h>
+#include <malloc.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef STATIC
+#define STATIC
+#endif
+
+extern FILE *__IO_list;         /* For fflush at exit */
+
+void __stdio_init_vars(void);
+
+#endif
diff --git a/Library/libs/stdio0.c b/Library/libs/stdio0.c
new file mode 100644 (file)
index 0000000..69c96ea
--- /dev/null
@@ -0,0 +1,50 @@
+#include "stdio-l.h"
+
+/* TODO sdcc err #define buferr (unsigned char *)(stderr->unbuf)*//* Stderr is unbuffered */
+
+FILE *__IO_list = NULL;                /* For fflush at exit */
+
+static unsigned char bufin[BUFSIZ];
+static unsigned char bufout[BUFSIZ];
+#ifndef buferr
+static unsigned char buferr[BUFSIZ];
+#endif
+FILE stdin[1] = {
+       {bufin, bufin, bufin, bufin, bufin + sizeof(bufin),
+        0, _IOFBF | __MODE_READ | __MODE_IOTRAN}
+};
+
+FILE stdout[1] = {
+       {bufout, bufout, bufout, bufout, bufout + sizeof(bufout),
+        1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN}
+};
+
+FILE stderr[1] = {
+       {buferr, buferr, buferr, buferr, buferr + sizeof(buferr),
+        2, _IONBF | __MODE_WRITE | __MODE_IOTRAN}
+};
+
+/* Call the stdio initialiser; it's main job it to call atexit */
+
+STATIC void __stdio_close_all(VOID)
+{
+       FILE *fp = __IO_list;
+
+       fflush(stdout);
+       fflush(stderr);
+       while (fp) {
+               fflush(fp);
+               close(fp->fd);
+               /* Note we're not de-allocating the memory */
+               /* There doesn't seem to be much point :-) */
+               fp->fd = -1;
+               fp = fp->next;
+       }
+}
+
+STATIC void __stdio_init_vars()
+{
+       if (isatty(1))
+               stdout->mode |= _IOLBF;
+       atexit((atexit_t) __stdio_close_all);
+}
diff --git a/Library/libs/strcasecmp.c b/Library/libs/strcasecmp.c
new file mode 100644 (file)
index 0000000..0a8c4c6
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strcasecmp(const char *s, const char *d)
+{
+   for(;;)
+   {
+      if( *s != *d )
+      {
+        if( tolower(*s) != tolower(*d) )
+           return *s - *d;
+      }
+      else if( *s == '\0' ) break;
+      s++; d++;
+   }
+   return 0;
+}
+
diff --git a/Library/libs/strcat.c b/Library/libs/strcat.c
new file mode 100644 (file)
index 0000000..f87818a
--- /dev/null
@@ -0,0 +1,14 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function strcat ************************************/ \r
+char *strcat(char *d, char *s) \r
+{
+       strcpy(d + strlen(d), s);
+       return d;
+}
diff --git a/Library/libs/strchr.c b/Library/libs/strchr.c
new file mode 100644 (file)
index 0000000..fa8c69e
--- /dev/null
@@ -0,0 +1,22 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+\r
+/* FIXME: asm version ?? */    \r
+/********************** Function strchr ************************************/ \r
+char *strchr(char *s, int c) \r
+{
+       register char ch;
+       \r
+       for (;;) {
+               if ((ch = *s) == c)
+                       return s;
+               if (ch == 0)
+                       return 0;
+               s++;
+       }
+}
diff --git a/Library/libs/strcmp.c b/Library/libs/strcmp.c
new file mode 100644 (file)
index 0000000..870384d
--- /dev/null
@@ -0,0 +1,16 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function strcmp ************************************/ \r
+int strcmp(char *d, char *s) \r
+{
+       register char *s1 = (char *) d, *s2 = (char *) s, c1, c2;
+\r
+       while ((c1 = *s1++) == (c2 = *s2++) && c1);
+       return c1 - c2;
+}
diff --git a/Library/libs/strcpy.c b/Library/libs/strcpy.c
new file mode 100644 (file)
index 0000000..eab28a7
--- /dev/null
@@ -0,0 +1,13 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function strcpy ************************************/ \r
+char *strcpy(char *d, char *s) \r
+{
+       return memcpy(d, s, strlen(s) + 1);
+}
diff --git a/Library/libs/strcspn.c b/Library/libs/strcspn.c
new file mode 100644 (file)
index 0000000..ab2efbc
--- /dev/null
@@ -0,0 +1,30 @@
+/* strcspn.c */
+
+/* from Schumacher's Atari library, improved */
+
+#include <string.h>
+
+size_t strcspn(char *string, char *set)
+/*
+ *     Return the length of the sub-string of <string> that consists
+ *     entirely of characters not found in <set>.  The terminating '\0'
+ *     in <set> is not considered part of the match set.  If the first
+ *     character if <string> is in <set>, 0 is returned.
+ */
+{
+    register char *setptr;
+    char *start;
+
+    start = string;
+    while (*string)
+    {
+       setptr = set;
+       do
+           if (*setptr == *string)
+               goto break2;
+       while (*setptr++);
+       ++string;
+    }
+break2:
+    return string - start;
+}
diff --git a/Library/libs/strdup.c b/Library/libs/strdup.c
new file mode 100644 (file)
index 0000000..18e4f8e
--- /dev/null
@@ -0,0 +1,21 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <malloc.h>\r
+#include "string.h"\r
+    \r
+/********************** Function strdup ************************************/ \r
+char *strdup(char *s) \r
+{
+       register size_t len = strlen(s) + 1;
+       register char *p = (char *) malloc(len);
+\r
+       if (p)
+               memcpy(p, s, len);      /* Faster than strcpy */
+       return p;
+}
+
+\r
diff --git a/Library/libs/stricmp.c b/Library/libs/stricmp.c
new file mode 100644 (file)
index 0000000..b664926
--- /dev/null
@@ -0,0 +1,23 @@
+/* string.c
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include "string.h"
+#include <ctype.h>
+
+/********************** Function stricmp ************************************/
+int stricmp(char *s, char *d)
+{
+       for (;;) {
+               unsigned char sc = *(uchar *) s++, dc = *(uchar *) d++;
+
+               if (sc != dc) {
+                       if (_tolower(sc) != _tolower(dc))
+                               return (int) (char) (sc - dc);
+               } else if (sc == '\0')
+                       break;
+       }
+       return 0;
+}
diff --git a/Library/libs/strlen.c b/Library/libs/strlen.c
new file mode 100644 (file)
index 0000000..a643115
--- /dev/null
@@ -0,0 +1,25 @@
+/* string.c
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+
+/********************** Function strlen ************************************/
+size_t strlen(char *str) __naked
+{
+__asm
+        pop     bc
+        pop     hl
+        push    hl
+        push    bc
+        xor     a, a
+        ld      b, a
+        ld      c, a
+        cpir
+        ld      hl, #-1
+        sbc     hl, bc  ; C flag still cleared from xor above.
+        ret
+__endasm;
+}
diff --git a/Library/libs/strncasecmp.c b/Library/libs/strncasecmp.c
new file mode 100644 (file)
index 0000000..afafa76
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strncasecmp(const char *s, const char *d, size_t l)
+{
+   while(l>0)
+   {
+      if( *s != *d )
+      {
+        if( tolower(*s) != tolower(*d) )
+           return *s - *d;
+      }
+      else
+        if( *s == '\0' ) return 0;
+      s++; d++; l--;
+   }
+   return 0;
+}
+
diff --git a/Library/libs/strncat.c b/Library/libs/strncat.c
new file mode 100644 (file)
index 0000000..9db164f
--- /dev/null
@@ -0,0 +1,22 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function strncat ************************************/ \r
+char *strncat(char *d, char *s, size_t l) \r
+{
+       register char *s1 = d + strlen(d), *s2 = memchr(s, 0, l);
+\r
+       if (s2)
+               memcpy(s1, s, s2 - s + 1);\r
+       else {
+               memcpy(s1, s, l);
+               s1[l] = '\0';
+       }
+       return d;
+}
+\r
diff --git a/Library/libs/strncpy.c b/Library/libs/strncpy.c
new file mode 100644 (file)
index 0000000..81dd2db
--- /dev/null
@@ -0,0 +1,26 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function strncpy ************************************/ \r
+char *strncpy(char *d, char *s, size_t l) \r
+{
+       register char *s1 = d, *s2 = s;\r
+\r
+       while (l) {
+               l--;
+               if ((*s1++ = *s2++) == '\0')
+                       break;
+       }
+\r
+       /* This _is_ correct strncpy is supposed to zap */ \r
+       while (l-- != 0)
+               *s1++ = '\0';
+       return d;
+}
+
+\r
diff --git a/Library/libs/strnicmp.c b/Library/libs/strnicmp.c
new file mode 100644 (file)
index 0000000..d32a938
--- /dev/null
@@ -0,0 +1,24 @@
+/* string.c
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include "string.h"
+#include <ctype.h>
+
+/********************** Function strnicmp ************************************/
+
+int strnicmp(char *s, char *d, size_t l)
+{
+       while (l-- != 0) {
+               unsigned char sc = *(uchar *) s++, dc = *(uchar *) d++;
+
+               if (sc != dc) {
+                       if (_tolower(sc) != _tolower(dc))
+                               return (int) (char) (sc - dc);
+               } else if (sc == '\0')
+                       break;
+       }
+       return 0;
+}
diff --git a/Library/libs/strpbrk.c b/Library/libs/strpbrk.c
new file mode 100644 (file)
index 0000000..3459870
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+
+/* This uses strchr, strchr should be in assembler */
+
+char *strpbrk(const char *str, const char *set)
+{
+  while (*str != '\0')
+    if (strchr(set, *str) == 0)
+      ++str;
+    else
+      return (char *) str;
+
+  return 0;
+}
diff --git a/Library/libs/strrchr.c b/Library/libs/strrchr.c
new file mode 100644 (file)
index 0000000..a58ee8b
--- /dev/null
@@ -0,0 +1,22 @@
+/* string.c\r
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>\r
+ * This file is part of the Linux-8086 C library and is distributed\r
+ * under the GNU Library General Public License.\r
+ */  \r
+    \r
+#include <string.h>\r
+    \r
+/********************** Function strrchr ************************************/ \r
+char *strrchr(char *s, int c) \r
+{
+       register char *p = s + strlen(s);
+        \r
+       /* For null it's just like strlen */ \r
+       if (c == '\0')
+               return p;
+       while (p != s) {
+               if (*--p == c)
+                       return p;
+       }
+       return NULL;
+}
diff --git a/Library/libs/strsep.c b/Library/libs/strsep.c
new file mode 100644 (file)
index 0000000..fe93128
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <string.h>
+
+char *strsep(char **pp, char *delim)
+{
+  char *p, *q;
+
+  if (!(p = *pp))
+    return 0;
+  if (q = strpbrk (p, delim))
+    {
+      *pp = q + 1;
+      *q = '\0';
+    }
+  else
+    *pp = 0;
+  return p;
+}
diff --git a/Library/libs/strspn.c b/Library/libs/strspn.c
new file mode 100644 (file)
index 0000000..d654d38
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <string.h>
+
+/* Return the length of the maximum initial segment
+   of S which contains only characters in ACCEPT.  */
+size_t strspn(const char *s, const char *accept)
+{
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = accept; *a != '\0'; ++a)
+       if (*p == *a)
+         break;
+      if (*a == '\0')
+       return count;
+      else
+       ++count;
+    }
+
+  return count;
+}
diff --git a/Library/libs/strstr.c b/Library/libs/strstr.c
new file mode 100644 (file)
index 0000000..093fe5b
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+
+/* We've now got a nice fast strchr and memcmp use them */
+
+char *strstr(const char *s1, const char *s2)
+{
+   int l = strlen(s2);
+   char * p = s1;
+
+   if( l==0 ) return p;
+
+   while (p = strchr(p, *s2))
+   {
+      if( memcmp(p, s2, l) == 0 )
+         return p;
+      p++;
+   }
+   return (char *) 0;
+}
+
diff --git a/Library/libs/strtod.c b/Library/libs/strtod.c
new file mode 100644 (file)
index 0000000..514cc1f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * strtod.c - This file is part of the libc-8086 package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <stdlib.h>
+#include <ctype.h>
+
+double strtod(const char *nptr, char ** endptr)
+{
+  unsigned short negative;
+  double number;
+  double fp_part;
+  int exponent;
+  unsigned short exp_negative;
+
+  *endptr = NULL;
+
+  /* advance beyond any leading whitespace */
+  while (isspace(*nptr))
+    nptr++;
+
+  /* check for optional '+' or '-' */
+  negative=0;
+  if (*nptr=='-')
+    {
+      negative=1;
+      nptr++;
+    }
+  else
+    if (*nptr=='+')
+      nptr++;
+
+  number=0;
+  while (isdigit(*nptr))
+    {
+      number=number*10+(*nptr-'0');
+      nptr++;
+    }
+
+  if (*nptr=='.')
+    {
+      nptr++;
+      fp_part=0;
+      while (isdigit(*nptr))
+       {
+         fp_part=fp_part/10.0 + (*nptr-'0')/10.0;
+         nptr++;
+       }
+      number+=fp_part;
+    }
+
+  if (*nptr=='e' || *nptr=='E')
+    {
+      nptr++;
+      exp_negative=0;
+      if (*nptr=='-')
+       {
+         exp_negative=1;
+         nptr++;
+       }
+      else
+       if (*nptr=='+')
+         nptr++;
+
+      exponent=0;
+      while (isdigit(*nptr))
+       {
+         exponent=exponent*10+(*nptr-'0');
+         exponent++;
+         nptr++;
+       }
+    }
+
+  while (exponent)
+    {
+      if (exp_negative)
+       number/=10;
+      else
+       number*=10;
+      exponent--;
+    }
+  *endptr = (char *)nptr;
+  return (negative ? -number:number);
+}
diff --git a/Library/libs/strtok.c b/Library/libs/strtok.c
new file mode 100644 (file)
index 0000000..cb4cd5c
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <string.h>
+
+
+static char *olds = 0;
+
+/* Parse S into tokens separated by characters in DELIM.
+   If S is NULL, the last string strtok() was called with is
+   used.  For example:
+       char s[] = "-abc=-def";
+       x = strtok(s, "-");             // x = "abc"
+       x = strtok(NULL, "=-");         // x = "def"
+       x = strtok(NULL, "=");          // x = NULL
+               // s = "abc\0-def\0"
+*/
+char *strtok(char *s, const char *delim)
+{
+  char *token;
+
+  if (s == 0)
+    {
+      if (olds == 0)
+       {
+         return 0;
+       }
+      else
+       s = olds;
+    }
+
+  /* Scan leading delimiters.  */
+  s += strspn(s, delim);
+  if (*s == '\0')
+    {
+      olds = 0;
+      return 0;
+    }
+
+  /* Find the end of the token.  */
+  token = s;
+  s = strpbrk(token, delim);
+  if (s == 0)
+    /* This token finishes the string.  */
+    olds = 0;
+  else
+    {
+      /* Terminate the token and make OLDS point past it.  */
+      *s = '\0';
+      olds = s + 1;
+    }
+  return token;
+}
diff --git a/Library/libs/strtol.c b/Library/libs/strtol.c
new file mode 100644 (file)
index 0000000..25ea0ea
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * strtol.c - This file is part of the libc-8086 package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ * 
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* TODO: This needs range clamping and setting errno when it's done. */
+
+#include <ctype.h>
+#include <stdlib.h>
+
+long int
+strtol(const char *nptr, char **endptr, int base)
+{
+  const char * ptr;
+  unsigned short negative;
+  long int number;
+
+  ptr=nptr;
+
+  while (isspace(*ptr))
+    ptr++;
+
+  negative=0;
+  if (*ptr=='-')
+    negative=1;
+
+  number=(long int)strtoul(nptr, endptr, base);
+
+  return (negative ? -number:number);
+}
+
+unsigned long int
+strtoul(const char *nptr, char **endptr, int base)
+{
+  unsigned long int number;
+
+  /* Sanity check the arguments */
+  if (base==1 || base>36 || base<0)
+    base=0;
+  
+  /* advance beyond any leading whitespace */
+  while (isspace(*nptr))
+    nptr++;
+
+  /* check for optional '+' or '-' */
+  if (*nptr=='-')
+      nptr++;
+  else
+    if (*nptr=='+')
+      nptr++;
+
+  /* If base==0 and the string begins with "0x" then we're supposed
+     to assume that it's hexadecimal (base 16). */
+  if (base==0 && *nptr=='0')
+    {
+      if (toupper(*(nptr+1))=='X')
+       {
+         base=16;
+         nptr+=2;
+       }
+  /* If base==0 and the string begins with "0" but not "0x",
+     then we're supposed to assume that it's octal (base 8). */
+      else
+       {
+         base=8;
+         nptr++;
+       }
+    }
+
+  /* If base is still 0 (it was 0 to begin with and the string didn't begin
+     with "0"), then we are supposed to assume that it's base 10 */
+  if (base==0)
+    base=10;
+
+  number=0;
+  while (isascii(*nptr) && isalnum(*nptr))
+    {
+      int ch = *nptr;
+      if (islower(ch)) ch = toupper(ch);
+      ch -= (ch<='9' ? '0' : 'A'-10);
+      if (ch>base)
+       break;
+
+      number= (number*base)+ch;
+      nptr++;
+    }
+
+  /* Some code is simply _impossible_ to write with -Wcast-qual .. :-\ */
+  if (endptr!=NULL)
+    *endptr=(char *)nptr;
+
+  /* All done */
+  return number;
+}
+
+
diff --git a/Library/libs/sysconf.c b/Library/libs/sysconf.c
new file mode 100644 (file)
index 0000000..62a6d0d
--- /dev/null
@@ -0,0 +1,60 @@
+#include <unistd.h>
+#include <errno.h>
+
+long sysconf(int name)
+{
+  struct _uzisysinfoblk info;
+  int psize;
+  int pscale;
+  
+  _uname(&info, sizeof(info));
+  psize = 65536/info.banks;
+  pscale = psize/1024;
+  
+  switch(name) {
+    case _SC_ARG_MAX:
+      return 512;
+    case _SC_CHILD_MAX:
+      /* nproc -1 ? */
+    case _SC_HOST_NAME_MAX:
+      /* we will implement get/sethostname and domain name in userspace */
+      return 256;
+    case _SC_LOGIN_NAME_MAX:
+      return 32;
+    case _SC_CLK_TCK:
+      /* query via unameinfo */
+      return info.ticks;
+    case _SC_OPEN_MAX:
+      /* query via unameinfo */
+      return info.max_open;
+    case _SC_PAGESIZE:
+      /* query via unameinfo */
+      return psize;
+    case _SC_RE_DUP_MAX:
+      /* FIXME: read the regexp code */
+      return 4;
+    case _SC_STREAM_MAX:
+      /* In theory down to RAM */
+      return 256;
+    case _SC_SYMLOOP_MAX:
+      /* Not supported yet */
+      return 1;
+    case _SC_TTY_NAME_MAX:
+      return 9;
+    case _SC_TZNAME_MAX:
+      return 6;
+    /* Don't provide _SC_VERSION - we don't really meet POSIX! */
+    case _SC_VERSION:
+      return 0;
+    case _SC_PHYS_PAGES:
+      return info.memk/pscale;
+    case _SC_AVPHYS_PAGES:
+      return (info.memk-info.usedk)/pscale;
+    case _SC_NPROCESSORS_CONF:
+    case _SC_NPROCESSORS_ONLN:
+      return 1;
+    default:
+      errno = EINVAL;
+      return -1;
+  }
+}
diff --git a/Library/libs/system.c b/Library/libs/system.c
new file mode 100644 (file)
index 0000000..fcba5c3
--- /dev/null
@@ -0,0 +1,48 @@
+
+#include <stddef.h>
+#include <signal.h>
+#include <unistd.h>
+
+int system(const char *command)
+{
+   int wait_val, wait_ret, pid;
+   sighandler_t save_quit;
+   sighandler_t save_int;
+
+   if( command == 0 ) return 1;
+
+   save_quit = signal(SIGQUIT, SIG_IGN);
+   save_int  = signal(SIGINT,  SIG_IGN);
+
+   if( (pid=fork()) < 0 )
+   {
+      signal(SIGQUIT, save_quit);
+      signal(SIGINT,  save_int);
+      return -1;
+   }
+   if( pid == 0 )
+   {
+      signal(SIGQUIT, SIG_DFL);
+      signal(SIGINT,  SIG_DFL);
+
+      execl("/bin/sh", "sh", "-c", command, (char*)0);
+      _exit(127);
+   }
+   /* Signals are not absolutly guarenteed with vfork */
+   signal(SIGQUIT, SIG_IGN);
+   signal(SIGINT,  SIG_IGN);
+
+   do
+   {
+      if( (wait_ret = wait(&wait_val)) == -1 )
+      {
+         wait_val = -1;
+        break;
+      }
+   }
+   while( wait_ret != pid );
+
+   signal(SIGQUIT, save_quit);
+   signal(SIGINT,  save_int);
+   return wait_val;
+}
diff --git a/Library/libs/tcdrain.c b/Library/libs/tcdrain.c
new file mode 100644 (file)
index 0000000..52b796f
--- /dev/null
@@ -0,0 +1,10 @@
+#include <termios.h>
+#include <unistd.h>
+
+int tcdrain(int fd)
+{
+  struct termios t;
+  if (ioctl(fd, TCGETS, &t))
+    return -1;
+  return ioctl(fd, TCSETSW, &t);
+}
diff --git a/Library/libs/tcflow.c b/Library/libs/tcflow.c
new file mode 100644 (file)
index 0000000..c517773
--- /dev/null
@@ -0,0 +1,7 @@
+#include <termios.h>
+#include <unistd.h>
+
+int tcflush(int fd, int q)
+{
+  return ioctl(fd, TIOCFLUSH, q);
+}
diff --git a/Library/libs/tcflush.c b/Library/libs/tcflush.c
new file mode 100644 (file)
index 0000000..c517773
--- /dev/null
@@ -0,0 +1,7 @@
+#include <termios.h>
+#include <unistd.h>
+
+int tcflush(int fd, int q)
+{
+  return ioctl(fd, TIOCFLUSH, q);
+}
diff --git a/Library/libs/tcgetattr.c b/Library/libs/tcgetattr.c
new file mode 100644 (file)
index 0000000..7310f7d
--- /dev/null
@@ -0,0 +1,8 @@
+#include <termios.h>
+#include <unistd.h>
+
+
+int tcgetattr(int fd, struct termios *termios_p)
+{
+  return ioctl(fd, TCGETS, termios_p);
+}
diff --git a/Library/libs/tcsetattr.c b/Library/libs/tcsetattr.c
new file mode 100644 (file)
index 0000000..de42ea5
--- /dev/null
@@ -0,0 +1,14 @@
+#include <termios.h>
+#include <unistd.h>
+
+
+int tcsetattr(int fd, int oa, const struct termios *termios_p)
+{
+  int op = TCSETS;
+  if (oa == TCSADRAIN)
+    op = TCSETSW;
+  if (oa == TCSAFLUSH)
+    op = TCSETSF;
+  return ioctl(fd, op, termios_p);
+}
+
diff --git a/Library/libs/time.c b/Library/libs/time.c
new file mode 100644 (file)
index 0000000..096d08f
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <unistd.h>
+
+/*
+ *     Wrap the kernel time call so that it also
+ *     returns a time_t (longlong). The kernel ABI
+ *     doesn't deal in 64bit return values.
+ */
+time_t time(time_t *t)
+{
+  time_t tmp;
+  if (t) {
+    _time(t);
+    return *t;
+  }
+  _time(&tmp);
+  return tmp;
+}
diff --git a/Library/libs/tmpnam.c b/Library/libs/tmpnam.c
new file mode 100644 (file)
index 0000000..674d4b2
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * (C) Shane Kerr <kerr@wizard.net> under terms of LGPL
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifndef P_tmpdir
+#define P_tmpdir "/tmp"
+#endif 
+
+#ifndef L_tmpnam
+#define L_tmpnam 20
+#endif 
+
+/* Keep these out of the function because SDCC 3.4 generates hideous
+   bloated crap for in function static initializers */
+
+static char uniq_ch[] =
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+static char ret_val[L_tmpnam];
+static char c1;
+static char c2;
+static char c3;
+
+char *tmpnam(char *s)
+{
+    struct stat stbuf;
+
+    do {
+        sprintf(ret_val, "%s/%05d%c%c%c", P_tmpdir, getpid(), 
+            uniq_ch[c1], uniq_ch[c2], uniq_ch[c3]);
+        if (++c1 >= 62) {
+           c1 = 0;
+           if (++c2 >= 62) {
+               c2 = 0;
+               if (++c3 >= 62) {
+                   errno = EEXIST;
+                   return 0;
+               }
+           }
+        }
+    } while (stat(ret_val, &stbuf) == 0);
+
+    if (s != 0) {
+       strcpy(s, ret_val);
+       return s;
+    } else {
+       return ret_val;
+    }
+}
+
diff --git a/Library/libs/ttyname.c b/Library/libs/ttyname.c
new file mode 100644 (file)
index 0000000..674aee3
--- /dev/null
@@ -0,0 +1,48 @@
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+
+static char dev[] = "/dev";
+
+char *ttyname(int fd)
+{
+   struct stat st, dst;
+   DIR  *fp;
+   struct dirent *d;
+   static char name[16]; /* should be MAXNAMLEN but that's overkill */
+   int noerr = errno;
+
+   if (fstat(fd, &st) < 0)
+      return 0;
+   if (!isatty(fd))
+   {
+      errno = ENOTTY;
+      return 0;
+   }
+
+   fp = opendir(dev);
+   if (fp == 0)
+      return 0;
+   strcpy(name, dev);
+   strcat(name, "/");
+
+   while ((d = readdir(fp)) != 0)
+   {
+      if( strlen(d->d_name) > sizeof(name) - sizeof(dev) - 1)
+         continue;
+      strcpy(name + sizeof(dev), d->d_name);
+      if (stat(name, &dst) == 0
+         && st.st_dev == dst.st_dev && st.st_ino == dst.st_ino)
+      {
+        closedir(fp);
+        errno = noerr;
+        return name;
+      }
+   }
+   closedir(fp);
+   errno = noerr;
+   return 0;
+}
diff --git a/Library/libs/tzset.c b/Library/libs/tzset.c
new file mode 100644 (file)
index 0000000..a323e1c
--- /dev/null
@@ -0,0 +1,29 @@
+/*************************** TZSET ************************************/  \r
+    \r
+#include <time.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+char *tzname[2] = { "GMT", "\0\0\0" };
+
+int daylight;
+long timezone;
\r
+/* tzset expects fo find a environment string of the form TZ=...\r
+ * ??? need to correct!\r
+ */ \r
+void tzset(VOID)
+{
+       char *tz = getenv("TZ");
+\r
+       if (tz == NULL) {
+               memcpy(tzname[1], "GMT", 3);
+               timezone = 0 * 60 * 60L;        /* London */
+       } else {
+               int v;
+               \r
+               memcpy(tzname[1], tz, 3);
+               v = atoi(tz + 3);
+               timezone = -((v / 100) * 60 + (v % 100)) * 60L;
+       }\r
+} \r
diff --git a/Library/libs/ultoa.c b/Library/libs/ultoa.c
new file mode 100644 (file)
index 0000000..52ffa28
--- /dev/null
@@ -0,0 +1,16 @@
+/* numeric/string conversions package
+ */
+
+#include "stdlib.h"
+
+/**************************** ultoa.c ****************************/
+char *ultoa(unsigned long value, char *strP, int radix)
+{
+       char hex = 'A';
+
+       if (radix < 0) {
+               hex = 'a';
+               radix = -radix;
+       }
+       return __longtoa(value, strP, radix, 0, hex);
+}
diff --git a/Library/libs/ungetc.c b/Library/libs/ungetc.c
new file mode 100644 (file)
index 0000000..74989ef
--- /dev/null
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int ungetc(int c, FILE *fp)
+{
+   if (fp->mode & __MODE_WRITING)
+      fflush(fp);
+
+   /* Can't read or there's been an error then return EOF */
+   if ((fp->mode & (__MODE_READ | __MODE_ERR)) != __MODE_READ)
+      return EOF;
+
+   /* Can't do fast fseeks */
+   fp->mode |= __MODE_UNGOT;
+
+   if( fp->bufpos > fp->bufstart )
+      return *--fp->bufpos = (unsigned char) c;
+   else if( fp->bufread == fp->bufstart )
+      return *fp->bufread++ = (unsigned char) c;
+   else
+      return EOF;
+}
diff --git a/Library/libs/utent.c b/Library/libs/utent.c
new file mode 100644 (file)
index 0000000..f4c2ebc
--- /dev/null
@@ -0,0 +1,150 @@
+/* utent.c <ndf@linux.mit.edu> */
+/* Let it be known that this is very possibly the worst standard ever.  HP-UX
+   does one thing, someone else does another, linux another... If anyone
+   actually has the standard, please send it to me.
+
+   Note that because of the way this stupid stupid standard works, you
+   have to call endutent() to close the file even if you've not called
+   setutent -- getutid and family use the same file descriptor. */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <errno.h>
+#include <string.h>
+#include <utmp.h>
+
+static const char * ut_name=_PATH_UTMP;
+
+static int ut_fd=-1;
+
+struct utmp *
+getutent(void)
+{
+  static struct utmp utmp;
+  if (ut_fd==-1) setutent();
+  if (ut_fd==-1) return NULL;
+
+  if (read(ut_fd, (char *) &utmp, sizeof(struct utmp))!=sizeof(struct utmp))
+    return NULL;
+  return &utmp;
+}
+
+void
+setutent(void)
+{
+  int xerrno = errno;
+  if (ut_fd!=-1)
+    close(ut_fd); /* ... Should this be an Lseek ? */
+
+  if ((ut_fd=open(ut_name, O_RDWR))<0)
+    {
+      if (errno!=EACCES || (ut_fd=open(ut_name, O_RDONLY))<0)
+        {
+          /* No, this is a library function, it should not do this! */
+           /* perror("setutent: Can't open utmp file"); */
+           ut_fd=-1;
+        }
+    }
+  if (ut_fd!= -1) errno=xerrno;
+}
+
+void
+endutent(void)
+{
+  if (ut_fd!=-1)
+    close(ut_fd);
+  ut_fd=-1;
+}
+
+struct utmp *
+getutid(const struct utmp * utmp_entry)
+{
+  struct utmp * utmp;
+  
+  while ((utmp=getutent())!=NULL)
+    {
+      if ((utmp_entry->ut_type==RUN_LVL   ||
+          utmp_entry->ut_type==BOOT_TIME ||
+          utmp_entry->ut_type==NEW_TIME  ||
+          utmp_entry->ut_type==OLD_TIME) &&
+         utmp->ut_type==utmp_entry->ut_type)
+       return utmp;
+      if ((utmp_entry->ut_type==INIT_PROCESS ||
+          utmp_entry->ut_type==DEAD_PROCESS ||
+          utmp_entry->ut_type==LOGIN_PROCESS ||
+          utmp_entry->ut_type==USER_PROCESS) &&
+         !strncmp(utmp->ut_id, utmp_entry->ut_id,sizeof(utmp->ut_id)))
+       return utmp;
+    }
+
+  return NULL;
+}
+
+struct utmp *
+getutline(const struct utmp * utmp_entry)
+{
+  struct utmp * utmp;
+
+#if 0 /* This is driving me nuts.  It's not an implementation problem -
+        it's a matter of how things _SHOULD_ behave.  Groan. */
+  if (ut_fd!=-1)
+     lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR);
+#endif
+
+  while ((utmp=getutent())!=NULL)
+    {
+      if ((utmp->ut_type==USER_PROCESS  ||
+          utmp->ut_type==LOGIN_PROCESS) &&
+         !strcmp(utmp->ut_line, utmp_entry->ut_line))
+       return utmp;
+    }
+
+  return NULL;
+}
+
+struct utmp *
+pututline(const struct utmp * utmp_entry)
+{
+  struct utmp * ut;
+  int xerrno=errno;
+
+#if 0
+  /* Ignore the return value.  That way, if they've already positioned
+     the file pointer where they want it, everything will work out. */
+  if (ut_fd!=-1)
+  (void) lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR);
+#endif
+
+  if ((ut=getutid(utmp_entry))!=NULL)
+      lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR);
+  else if( ut_fd==-1 )
+      return NULL;
+  else
+      lseek(ut_fd, (off_t) 0, SEEK_END);
+
+  /*
+   * At this point I could make sure the offset we're at is an exact multiple
+   * of the sizeof struct utmp. Should I? Up or down?  --RdB
+   */
+
+  if (write(ut_fd, (char *) utmp_entry, sizeof(struct utmp))
+      != sizeof(struct utmp))
+    return NULL;
+
+  /* I think this final lseek gets the result Nat was after ... RdB */
+  lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR);
+
+  /* Ignoring untrapped errors */
+  errno=xerrno;
+  return utmp_entry;
+}
+
+void
+utmpname(const char * new_ut_name)
+{
+  endutent();
+
+  if (new_ut_name!=NULL)
+    ut_name=new_ut_name;
+}
diff --git a/Library/libs/utsname.c b/Library/libs/utsname.c
new file mode 100644 (file)
index 0000000..c7a8143
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * utsname.c for UZIX
+ * by A&L Software 1999
+ *
+ *
+ * FIXME: rewrite for fuzix string packing
+ */
+
+#include <utsname.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+/* FIXME */
+int uname(struct utsname *__utsbuf)
+{
+
+#if 0
+       struct s_kdata kdata;
+       int i;
+       getfsys(GI_KDAT, &kdata);
+       strcpy(__utsbuf->sysname, kdata.k_name);
+       strcpy(__utsbuf->nodename, kdata.k_name);
+       for (i = 0; i < strlen(__utsbuf->nodename); i++)
+               __utsbuf->nodename[i] = tolower(__utsbuf->nodename[i]);
+       strcpy(__utsbuf->release, kdata.k_release);
+       strcpy(__utsbuf->version, kdata.k_version);
+       strcpy(__utsbuf->machine, kdata.k_machine);
+       strcpy(__utsbuf->domainname, "(localhost)");
+       return 0;
+
+#endif                         /*  */
+}
diff --git a/Library/libs/vfprintf.c b/Library/libs/vfprintf.c
new file mode 100644 (file)
index 0000000..15175aa
--- /dev/null
@@ -0,0 +1,267 @@
+/* printf.c
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *
+ * Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include "printf.h"
+
+#ifdef BUILD_LIBM
+extern void _fnum(double val, char fmt, int prec, char *ptmp);
+#endif
+
+/*
+ * Output the given field in the manner specified by the arguments. Return
+ * the number of characters output.
+ */
+static int prtfld(FILE * op, unsigned char *buf, int ljustf, char sign,
+                 char pad, int width, int preci, int buffer_mode)
+{
+       register unsigned char ch;
+       register int cnt = 0, len = strlen(buf);
+
+       if (*buf == '-')
+               sign = *buf++;
+       else if (sign)
+               len++;
+       if ((preci != -1) && (len > preci))     /* limit max data width */
+               len = preci;
+       if (width < len)        /* flexible field width or width overflow */
+               width = len;
+       /* at this point: width = total field width, len = actual data width
+        * (including possible sign character)
+        */
+       cnt = width;
+       width -= len;
+       while (width || len) {
+               if (!ljustf && width) { /* left padding */
+                       if (len && sign && (pad == '0'))
+                               goto showsign;
+                       ch = pad;
+                       --width;
+               } else if (len) {
+                       if (sign) {
+                             showsign:ch = sign;
+                                               /* sign */
+                               sign = '\0';
+                       } else
+                               ch = *buf++;    /* main field */
+                       --len;
+               } else {
+                       ch = pad;       /* right padding */
+                       --width;
+               }
+               putc(ch, op);
+               if (ch == '\n' && buffer_mode == _IOLBF)
+                       fflush(op);
+       }
+       return (cnt);
+}
+
+static int vfprintf(FILE * op, char *fmt, va_list ap)
+{
+       register int i, ljustf, lval, preci, dpoint, width, radix, cnt = 0;
+       char pad, sign, hash;
+       register char *ptmp, *add;
+       unsigned long val;
+       char tmp[64];
+       int buffer_mode;
+
+       /* This speeds things up a bit for unbuffered */
+       buffer_mode = (op->mode & __MODE_BUF);
+       op->mode &= (~__MODE_BUF);
+       while (*fmt) {
+               if (*fmt == '%') {
+                       if (buffer_mode == _IONBF)
+                               fflush(op);
+                       ljustf = 0;     /* left justify flag */
+                       sign = '\0';    /* sign char & status */
+                       pad = ' ';      /* justification padding char */
+                       width = -1;     /* min field width */
+                       dpoint = 0;     /* found decimal point */
+                       preci = -1;     /* max data width */
+                       radix = 10;     /* number base */
+                       ptmp = tmp;     /* pointer to area to print */
+                       hash = 0;
+                       lval = (sizeof(int) == sizeof(long));   /* long value flaged */
+                     fmtnxt:for (i = 0, ++fmt;;
+                            ++fmt) {
+                               if (*fmt < '0' || *fmt > '9')
+                                       break;
+                               i *= 10;
+                               i += (*fmt - '0');
+                               if (dpoint)
+                                       preci = i;
+                               else if (!i && (pad == ' ')) {
+                                       pad = '0';
+                                       goto fmtnxt;
+                               } else
+                                       width = i;
+                       }
+                       switch (*fmt) {
+                       case '\0':      /* early EOS */
+                               --fmt;
+                               goto charout;
+
+                       case '-':       /* left justification */
+                               ljustf = 1;
+                               goto fmtnxt;
+
+                       case ' ':
+                       case '+':       /* leading sign flag */
+                               sign = *fmt;
+                               goto fmtnxt;
+
+                       case '#':
+                               hash = 1;
+                               goto fmtnxt;
+
+                       case '*':       /* parameter width value */
+                               i = va_arg(ap, int);
+                               if (dpoint)
+                                       preci = i;
+                               else if ((width = i) < 0) {
+                                       ljustf = 1;
+                                       width = -i;
+                               }
+                               goto fmtnxt;
+
+                       case '.':       /* secondary width field */
+                               dpoint = 1;
+                               goto fmtnxt;
+
+                       case 'l':       /* long data */
+                               lval = 1;
+                               goto fmtnxt;
+
+                       case 'h':       /* short data */
+                               lval = 0;
+                               goto fmtnxt;
+
+                       case 'd':       /* Signed decimal */
+                       case 'i':
+                               ptmp = ltoa((long) ((lval) ?
+                                                   va_arg(ap, long) :
+                                                   va_arg(ap, short)),
+                                           tmp, 10);
+                               goto printit;
+
+                       case 'b':       /* Unsigned binary */
+                               radix = 2;
+                               goto usproc;
+
+                       case 'o':       /* Unsigned octal */
+                               radix = 8;
+                               goto usproc;
+
+                       case 'p':       /* Pointer */
+                               lval = (sizeof(char *) == sizeof(long));
+                               pad = '0';
+                               width = 5;
+                               preci = 8;
+                               /* fall thru */
+
+                       case 'X':       /* Unsigned hexadecimal 'ABC' */
+                               radix = 16;
+                               goto usproc;
+
+                       case 'x':       /* Unsigned hexadecimal 'abc' */
+                               radix = -16;
+                               /* fall thru */
+
+                       case 'u':       /* Unsigned decimal */
+                             usproc:val = lval ? va_arg(ap, unsigned long) :
+                                   va_arg(ap,
+                                          unsigned short);
+                               ptmp = ultoa(val, tmp + 4, radix);
+                               add = "";
+                               if (hash) {
+                                       if (radix == 2)
+                                               add = "0b";
+                                       else if (radix == 8) {
+                                               if (val != 0)
+                                                       add = "0";
+                                       } else if (radix == 16)
+                                               add = "0x";
+                                       else if (radix == -16)
+                                               add = "0X";
+                                       if (*add) {
+                                               pad = '\0';
+                                               strcpy(tmp, add);
+                                               ptmp = strcat(tmp, ptmp);
+                                       }
+                               }
+                               goto printit;
+
+                       case '!':       /* inline Character */
+                               if ((i = fmt[1]) != 0)
+                                       ++fmt;
+                               goto Chr;
+
+                       case 'c':       /* Character */
+                               i = va_arg(ap, int);
+                             Chr:ptmp[0] =
+                                   i;
+                               ptmp[1] = '\0';
+                               if (hash) {
+                                       pad = *ptmp;
+                                       goto chrpad;
+                               }
+                               goto nopad;
+
+                       case 's':       /* String */
+                               ptmp = va_arg(ap, char *);
+                             nopad:pad =
+                                   ' ';
+                             chrpad:sign =
+                                   '\0';
+                             printit:cnt +=
+                                   prtfld(op, (unsigned char *) ptmp,
+                                          ljustf, sign, pad, width, preci,
+                                          buffer_mode);
+                               break;
+
+#ifdef BUILD_LIBM
+                       case 'e':       /* float */
+                       case 'f':
+                       case 'g':
+                       case 'E':
+                       case 'G':
+                               _fnum(va_arg(ap, double),
+                                     *fmt, preci, ptmp);
+                               /* double arg;
+                                  char fmt;  (e/f/g/E/G)
+                                  int preci; (width, -1 if no)
+                                  char *ptmp; (where to print)
+                                */
+                               preci = -1;
+                               goto printit;
+                               /* FALLTHROUGH if no floating printf available */
+#endif
+                       default:        /* unknown character */
+                               goto charout;
+                       }
+               } else {
+                     charout:putc(*fmt, op);
+                                       /* normal char out */
+                       ++cnt;
+                       if (*fmt == '\n' && buffer_mode == _IOLBF)
+                               fflush(op);
+               }
+               ++fmt;
+       }
+       op->mode |= buffer_mode;
+       if (buffer_mode == _IONBF)
+               fflush(op);
+       if (buffer_mode == _IOLBF)
+               op->bufwrite = op->bufstart;
+       return (cnt);
+}
diff --git a/Library/libs/vfscanf.c b/Library/libs/vfscanf.c
new file mode 100644 (file)
index 0000000..d52dfb0
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * This file based on scanf.c from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 19-OCT-88: Dale Schumacher
+ * > John Stanley has again been a great help in debugging, particularly
+ * > with the printf/scanf functions which are his creation.  
+ *
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ *
+ * The fp_scan function is taken from ucLinux libc and is LGPL v2 plus
+ * some extensions to hopefully get it working like the full version
+ * (but rather less tested)
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+
+/* #define     skip()  do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/
+
+#define        skip()  while(isspace(c)) { if ((c=getc(fp))<1) goto done; }
+
+/* fp scan actions */
+#define F_NADA 0       /* just change state */
+#define F_SIGN 1       /* set sign */
+#define F_ESIGN        2       /* set exponent's sign */
+#define F_INT  3       /* adjust integer part */
+#define F_FRAC 4       /* adjust fraction part */
+#define F_EXP  5       /* adjust exponent part */
+#define F_QUIT 6
+
+#define NSTATE 8
+#define FS_INIT                0       /* initial state */
+#define FS_SIGNED      1       /* saw sign */
+#define FS_DIGS                2       /* saw digits, no . */
+#define FS_DOT         3       /* saw ., no digits */
+#define FS_DD          4       /* saw digits and . */
+#define FS_E           5       /* saw 'e' */
+#define FS_ESIGN       6       /* saw exp's sign */
+#define FS_EDIGS       7       /* saw exp's digits */
+
+#define FC_DIG         0
+#define FC_DOT         1
+#define FC_E           2
+#define FC_SIGN                3
+
+/* given transition,state do what action? */
+int fp_do[][NSTATE] = {
+       {F_INT,F_INT,F_INT,
+        F_FRAC,F_FRAC,
+        F_EXP,F_EXP,F_EXP},    /* see digit */
+       {F_NADA,F_NADA,F_NADA,
+        F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},   /* see '.' */
+       {F_QUIT,F_QUIT,
+        F_NADA,F_QUIT,F_NADA,
+        F_QUIT,F_QUIT,F_QUIT}, /* see e/E */
+       {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
+        F_ESIGN,F_QUIT,F_QUIT},        /* see sign */
+};
+/* given transition,state what is new state? */
+int fp_ns[][NSTATE] = {
+       {FS_DIGS,FS_DIGS,FS_DIGS,
+        FS_DD,FS_DD,
+        FS_EDIGS,FS_EDIGS,FS_EDIGS},   /* see digit */
+       {FS_DOT,FS_DOT,FS_DD,
+        },     /* see '.' */
+       {0,0,
+        FS_E,0,FS_E,
+       },      /* see e/E */
+       {FS_SIGNED,0,0,0,0,
+        FS_ESIGN,0,0}, /* see sign */
+};
+/* which states are valid terminators? */
+int fp_sval[NSTATE] = {
+       0,0,1,0,1,0,0,1
+};
+
+#ifdef BUILD_LIBM
+double fp_scan(int neg, int eneg, int n, int frac, int expo, int fraclen)
+{
+  double f;
+  f = frac;
+  while (fraclen-->0)
+    f /= 10;
+  f += n;
+
+  /* This is not going to be very fast but hopefully nobody does a lot of
+     FP on a 4MHz Z80 anyway */  
+  if (expo && !eneg) {
+     while(expo-->0)
+         f *= 10;
+  }
+    
+  if (expo && eneg) {
+     while(expo-->0)
+         f /= 10;
+  }
+        
+  if (neg)
+    f = -f;
+  return f;
+}
+
+#endif
+
+int vfscanf(FILE *fp, char *fmt, va_list ap)
+{
+   long n;
+   int c, width, lval, cnt = 0;
+   int   store, neg, base, wide1, endnull, rngflag, c2;
+   unsigned char *p;
+   unsigned char delim[128], digits[17], *q;
+#ifdef BUILD_LIBM
+   long  frac, expo;
+   int   eneg, fraclen, fstate, trans;
+   double fx;
+#endif
+
+   if (!*fmt)
+      return (0);
+
+   c = getc(fp);
+   while (c > 0)
+   {
+      store = 0;
+      if (*fmt == '%')
+      {
+        n = 0;
+        width = -1;
+        wide1 = 1;
+        base = 10;
+        lval = (sizeof(long) == sizeof(int));
+        store = 1;
+        endnull = 1;
+        neg = -1;
+
+        strcpy(delim, "\011\012\013\014\015 ");
+        strcpy(digits, "0123456789ABCDEF");
+
+        if (fmt[1] == '*')
+        {
+           endnull = store = 0;
+           ++fmt;
+        }
+
+        while (isdigit(*++fmt))/* width digit(s) */
+        {
+           if (width == -1)
+              width = 0;
+           wide1 = width = (width * 10) + (*fmt - '0');
+        }
+        --fmt;
+       fmtnxt:
+        ++fmt;
+        switch (tolower(*fmt)) /* tolower() is a MACRO! */
+        {
+        case '*':
+           endnull = store = 0;
+           goto fmtnxt;
+
+        case 'l':              /* long data */
+           lval = 1;
+           goto fmtnxt;
+        case 'h':              /* short data */
+           lval = 0;
+           goto fmtnxt;
+
+        case 'i':              /* any-base numeric */
+           base = 0;
+           goto numfmt;
+
+        case 'b':              /* unsigned binary */
+           base = 2;
+           goto numfmt;
+
+        case 'o':              /* unsigned octal */
+           base = 8;
+           goto numfmt;
+
+        case 'x':              /* unsigned hexadecimal */
+           base = 16;
+           goto numfmt;
+
+        case 'd':              /* SIGNED decimal */
+           neg = 0;
+           /* FALL-THRU */
+
+        case 'u':              /* unsigned decimal */
+         numfmt:skip();
+
+           if (isupper(*fmt))
+              lval = 1;
+
+           if (!base)
+           {
+              base = 10;
+              neg = 0;
+              if (c == '%')
+              {
+                 base = 2;
+                 goto skip1;
+              }
+              else if (c == '0')
+              {
+                 c = getc(fp);
+                 if (c < 1)
+                    goto savnum;
+                 if ((c != 'x')
+                     && (c != 'X'))
+                 {
+                    base = 8;
+                    digits[8] = '\0';
+                    goto zeroin;
+                 }
+                 base = 16;
+                 goto skip1;
+              }
+           }
+
+           if ((neg == 0) && (base == 10)
+               && ((neg = (c == '-')) || (c == '+')))
+           {
+            skip1:
+              c = getc(fp);
+              if (c < 1)
+                 goto done;
+           }
+
+           digits[base] = '\0';
+           p = ((unsigned char *)
+                strchr(digits, toupper(c)));
+
+           if ((!c || !p) && width)
+              goto done;
+
+           while (p && width-- && c)
+           {
+              n = (n * base) + (p - digits);
+              c = getc(fp);
+            zeroin:
+              p = ((unsigned char *)
+                   strchr(digits, toupper(c)));
+           }
+         savnum:
+           if (store)
+           {
+              if (neg == 1)
+                 n = -n;
+              if (lval)
+                 *va_arg(ap, long*) = n;
+              else
+                 *va_arg(ap, short*) = n;
+              ++cnt;
+           }
+           break;
+#ifdef BUILD_LIBM
+        case 'e':              /* float */
+        case 'f':
+        case 'g':
+           skip();
+
+           if (isupper(*fmt))
+              lval = 1;
+
+           fstate = FS_INIT;
+           neg = 0;
+           eneg = 0;
+           n = 0;
+           frac = 0;
+           expo = 0;
+           fraclen = 0;
+
+           while (c && width--)
+           {
+              if (c >= '0' && c <= '9')
+                 trans = FC_DIG;
+              else if (c == '.')
+                 trans = FC_DOT;
+              else if (c == '+' || c == '-')
+                 trans = FC_SIGN;
+              else if (tolower(c) == 'e')
+                 trans = FC_E;
+              else
+                 goto fdone;
+
+              switch (fp_do[trans][fstate])
+              {
+              case F_SIGN:
+                 neg = (c == '-');
+                 break;
+              case F_ESIGN:
+                 eneg = (c == '-');
+                 break;
+              case F_INT:
+                 n = 10 * n + (c - '0');
+                 break;
+              case F_FRAC:
+                 frac = 10 * frac + (c - '0');
+                 fraclen++;
+                 break;
+              case F_EXP:
+                 expo = 10 * expo + (c - '0');
+                 break;
+              case F_QUIT:
+                 goto fdone;
+              }
+              fstate = fp_ns[trans][fstate];
+              c = getc(fp);
+           }
+
+         fdone:
+           if (!fp_sval[fstate])
+              goto done;
+           if (store)
+           {
+              fx = fp_scan(neg, eneg, n, frac, expo, fraclen);
+              if (lval)
+                 *va_arg(ap, double *) = fx;
+              else
+                 *va_arg(ap, float *) = fx;
+              ++cnt;
+           }
+           break;
+#endif
+        case 'c':              /* character data */
+           width = wide1;
+           lval = endnull = 0;
+           delim[0] = '\0';
+           goto strproc;
+
+        case '[':              /* string w/ delimiter set */
+
+           /* get delimiters */
+           p = delim;
+
+           if (*++fmt == '^')
+           {
+              fmt++;
+              lval = 0;
+           }
+           else
+              lval = 1;
+
+           rngflag = 2;
+           if ((*fmt == ']') || (*fmt == '-'))
+           {
+              *p++ = *fmt++;
+              rngflag = 0;
+           }
+
+           while (*fmt != ']')
+           {
+              if (*fmt == '\0')
+                 goto done;
+              switch (rngflag)
+              {
+              case 1:
+                 c2 = *(p - 2);
+                 if (c2 <= *fmt)
+                 {
+                    p -= 2;
+                    while (c2 < *fmt)
+                       *p++ = c2++;
+                    rngflag = 2;
+                    break;
+                 }
+                 /* fall thru intentional */
+
+              case 0:
+                 rngflag = (*fmt == '-');
+                 break;
+
+              case 2:
+                 rngflag = 0;
+              }
+
+              *p++ = *fmt++;
+           }
+
+           *p = '\0';
+           goto strproc;
+
+        case 's':              /* string data */
+           lval = 0;
+           skip();
+         strproc:
+           /* process string */
+           p = va_arg(ap, unsigned char *);
+
+           /* if the 1st char fails, match fails */
+           if (width)
+           {
+              q = ((unsigned char *)
+                   strchr(delim, c));
+              if ((c < 1) || lval == (q==0))
+              {
+                 if (endnull)
+                    *p = '\0';
+                 goto done;
+              }
+           }
+
+           for (;;)            /* FOREVER */
+           {
+              if (store)
+                 *p++ = c;
+              if (((c = getc(fp)) < 1) ||
+                  (--width == 0))
+                 break;
+
+              q = ((unsigned char *)
+                   strchr(delim, c));
+              if (lval == (q==0))
+                 break;
+           }
+
+           if (store)
+           {
+              if (endnull)
+                 *p = '\0';
+              ++cnt;
+           }
+           break;
+
+        case '\0':             /* early EOS */
+           --fmt;
+           /* FALL THRU */
+
+        default:
+           goto cmatch;
+        }
+      }
+      else if (isspace(*fmt))  /* skip whitespace */
+      {
+        skip();
+      }
+      else
+      {                                /* normal match char */
+       cmatch:
+        if (c != *fmt)
+           break;
+        c = getc(fp);
+      }
+
+      if (!*++fmt)
+        break;
+   }
+
+ done:                         /* end of scan */
+   if ((c == EOF) && (cnt == 0))
+      return (EOF);
+
+   if( c != EOF )
+      ungetc(c, fp);
+   return (cnt);
+}
+
+
diff --git a/Library/libs/vprintf.c b/Library/libs/vprintf.c
new file mode 100644 (file)
index 0000000..2c3b896
--- /dev/null
@@ -0,0 +1,20 @@
+/* printf.c
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *
+ * Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ *  sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include "printf.h"
+
+int vprintf(char *fmt, va_list ap)
+{
+       return vfprintf(stdout, fmt, ap);
+}
diff --git a/Library/libs/vscanf.c b/Library/libs/vscanf.c
new file mode 100644 (file)
index 0000000..fe935c9
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * This file based on scanf.c from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 19-OCT-88: Dale Schumacher
+ * > John Stanley has again been a great help in debugging, particularly
+ * > with the printf/scanf functions which are his creation.  
+ *
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+
+int vscanf(const char *fmt, va_list ap)
+{
+  return vfscanf(stdin,fmt,ap);
+}
diff --git a/Library/libs/vsscanf.c b/Library/libs/vsscanf.c
new file mode 100644 (file)
index 0000000..5b2f498
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * This file based on scanf.c from 'Dlibs' on the atari ST  (RdeBath)
+ *
+ * 19-OCT-88: Dale Schumacher
+ * > John Stanley has again been a great help in debugging, particularly
+ * > with the printf/scanf functions which are his creation.  
+ *
+ *    Dale Schumacher                         399 Beacon Ave.
+ *    (alias: Dalnefre')                      St. Paul, MN  55104
+ *    dal@syntel.UUCP                         United States of America
+ *  "It's not reality that's important, but how you perceive things."
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+
+int vsscanf(char * sp, const char *fmt, va_list ap)
+{
+static FILE  string[1] =
+{
+   {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
+    _IOFBF | __MODE_READ}
+};
+
+  string->bufpos = sp;
+  return vfscanf(string,fmt,ap);
+}
diff --git a/Library/libs/wait.c b/Library/libs/wait.c
new file mode 100644 (file)
index 0000000..865bd47
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+pid_t wait(int *status)
+{
+  return waitpid(-1, status, 0);
+}
\ No newline at end of file
diff --git a/Library/libs/xitoa.c b/Library/libs/xitoa.c
new file mode 100644 (file)
index 0000000..d13ed42
--- /dev/null
@@ -0,0 +1,10 @@
+/* numeric/string conversions package\r
+ */  \r
+    \r
+#include <stdlib.h>\r
+    \r
+/*********************** xitoa.c ***************************/ \r
+char *_itoa(int i) \r
+{
+       return ltostr((long) i, 10);
+} \r
diff --git a/Library/tools/TODO b/Library/tools/TODO
new file mode 100644 (file)
index 0000000..9c72407
--- /dev/null
@@ -0,0 +1,9 @@
+fcc
+---
+
+Fix the link ordering (do c -> o first ?)
+Build in temporary space to hide all the crap files (do cpp phase in real
+dir then build in a tmp dir ?)
+Rename .rel/.o back and forth in tmp space to hide the noise
+Support multiple .c files in one go
+
diff --git a/Library/tools/binman.c b/Library/tools/binman.c
new file mode 100644 (file)
index 0000000..3daca8f
--- /dev/null
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ *     This is a close relative of the kernel binman but produces
+ *     user space binaries and doesn't have common packing magic or all
+ *     the magic segments in the kernel
+ */
+
+static unsigned char buf[65536];
+
+static unsigned int s__INITIALIZER, s__INITIALIZED;
+static unsigned int l__INITIALIZER;
+
+static unsigned int s__DATA;
+
+                      
+
+static void ProcessMap(FILE *fp)
+{
+  char buf[512];
+  int addr = 0;
+  int naddr;
+  char name[100];
+  char nname[100];
+  int hogs = 0;
+  
+  while(fgets(buf, 511, fp)) {
+    char *p1 = strtok(buf," \t\n");
+    char *p2 = NULL;
+    int match = 0;
+    
+    match = memcmp(buf, "     000", 8);
+
+    if (p1)
+      p2 = strtok(NULL, " \t\n");
+
+    if (p1 == NULL || p2 == NULL)
+      continue;
+          
+    if (strcmp(p2, "s__DATA") == 0)
+      sscanf(p1, "%x", &s__DATA);
+    if (strcmp(p2, "s__INITIALIZED") == 0)
+      sscanf(p1, "%x", &s__INITIALIZED);
+    if (strcmp(p2, "s__INITIALIZER") == 0)
+      sscanf(p1, "%x", &s__INITIALIZER);
+    if (strcmp(p2, "l__INITIALIZER") == 0)
+      sscanf(p1, "%x", &l__INITIALIZER);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+  FILE *map, *bin;
+  int tail;
+
+  if (argc != 4) {
+    fprintf(stderr, "%s: [binary] [map] [output]\n", argv[0]);
+    exit(1);
+  }
+  bin = fopen(argv[1], "r");
+  if (bin == NULL) {
+    perror(argv[1]);
+    exit(1);
+  }
+  if (fread(buf, 1, 65536, bin) == 0) {
+    fprintf(stderr, "%s: read error on %s\n", argv[0], argv[1]);
+    exit(1);
+  }
+  fclose(bin);
+  map = fopen(argv[2], "r");
+  if (map == NULL) {
+    perror(argv[2]);
+    exit(1);
+  }
+  ProcessMap(map);
+  fclose(map);
+  
+  bin = fopen(argv[3], "w");
+  if (bin == NULL) {
+    perror(argv[3]);
+    exit(1);
+  }
+  /* Write out everything that is data, omit everything that will 
+     be zapped */
+  if (fwrite(buf + 0x100, s__DATA - 0x100, 1, bin) != 1) {
+   perror(argv[3]);
+   exit(1);
+  }
+  fclose(bin);
+  exit(0);
+}
diff --git a/Library/tools/fcc.c b/Library/tools/fcc.c
new file mode 100644 (file)
index 0000000..844de34
--- /dev/null
@@ -0,0 +1,458 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ *     Wrap the sdcc compiler tools into something more Unixlike and without
+ *     spraying support files everwhere
+ */
+
+
+#define MODE_LINK              0
+#define MODE_OBJ               1
+#define MODE_CPP               2
+#define MODE_ASM               3
+static int mode = MODE_LINK;
+static char *workdir;          /* Working directory */
+
+static int verbose = 0;
+
+struct arglist {
+  struct arglist *next;
+  char p[0];
+};
+
+static void not_null(const char *p)
+{
+  if (p == NULL) {
+    fprintf(stderr, "required option parameter missing at end of command line.\n");
+    exit(1);
+  }
+}
+
+static struct arglist *arg_make(const char *p)
+{
+  struct arglist *x;
+
+  not_null(p);  
+
+  x = malloc(sizeof(struct arglist) + strlen(p) + 1);
+  if (x == NULL) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+  x->next = NULL;
+  strcpy(x->p, p);
+  return x;
+}
+
+struct arglist *srchead, *srctail;
+
+static void add_source(const char *p)
+{
+  struct arglist *a = arg_make(p);
+  if (srchead == NULL)
+    srchead = a;
+  else
+    srctail->next = a;
+  srctail = a;
+}
+
+struct arglist *libphead, *libptail;
+
+static void add_library_path(const char *p)
+{
+  struct arglist *a = arg_make(p);
+  if (libphead == NULL)
+    libphead = a;
+  else
+    libptail->next = a;
+  libptail = a;
+}
+
+struct arglist *libhead, *libtail;
+
+static void add_library(const char *p)
+{
+  struct arglist *a = arg_make(p);
+  if (libhead == NULL)
+    libhead = a;
+  else
+    libtail->next = a;
+  libtail = a;
+}
+
+struct arglist *includehead, *includetail;
+
+static void add_include_path(const char *p)
+{
+  struct arglist *a = arg_make(p);
+  if (includehead == NULL)
+    includehead = a;
+  else
+    includetail->next = a;
+  includetail = a;
+}
+
+static char *target;
+
+static void set_target(const char *p)
+{
+  not_null(p);
+  if (target != NULL) {
+    fprintf(stderr, "-o cannot be used twice.\n");
+    exit(1);
+  }
+  target = strdup(p);
+}
+
+static const char *opt;
+static int optcode;
+
+static void set_optimize(const char *p)
+{
+  not_null(p);
+  if (opt != NULL) {
+    fprintf(stderr, "fcc: -O cannot be used twice.\n");
+    exit(1);
+  }
+  opt = strdup(p);
+  if (*opt && sscanf(opt, "%d", &optcode) != 1) {
+    fprintf(stderr, "fcc: -O requires a value\n");
+    exit(1);
+  }
+  if (*opt == 0)
+    optcode = 1;
+}
+
+static const char *map;
+
+static void set_map(const char *p)
+{
+  not_null(p);
+  if (map != NULL) {
+    fprintf(stderr, "-M cannot be used twice.\n");
+    exit(1);
+  }
+  map = strdup(p);
+}
+
+static const char *cpu;
+
+static void set_cpu(const char *p)
+{
+  not_null(p);
+  if (cpu != NULL) {
+    fprintf(stderr, "-m cannot be used twice.\n");
+    exit(1);
+  }
+  cpu = strdup(p);
+  if (strcmp(cpu, "z80") && strcmp(cpu, "z180")) {
+    fprintf(stderr,"fcc: only z80 and z180 targets currently handled.\n");
+    exit(1);
+  }
+}
+
+static int debug;
+static int pedantic;
+static int werror;
+static int unschar;
+
+
+static char *rebuildname(const char *r, const char *i, char *ext)
+{
+  char *p = malloc(strlen(r) + strlen(i) + strlen(ext) + 2);
+  char *t;
+  if (p == NULL) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+  strcpy(p, r);
+  strcat(p, i);
+  t = strrchr(p, '.');
+  if (t)
+    strcpy(t + 1, ext);
+  else {
+    strcat(p, ".");
+    strcat(p, ext);
+  }
+  return p;
+}
+
+static char *chopname(const char *i)
+{
+  char *p = strdup(i);
+  char *t;
+  if (p == NULL) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+  t = strrchr(p, '.');
+  if (t)
+    *t = 0;
+  return p;
+}
+
+static void autotarget(void)
+{
+  char *x;
+  if (srchead == NULL)
+    return;
+
+  if (mode == MODE_LINK) {
+    target = rebuildname("", srchead->p, "ihx");
+    return;
+  }
+  if (mode != MODE_OBJ)
+    return;
+  target = rebuildname("", srchead->p, "rel");
+}
+
+#define MAX_ARG 256
+static char *argvec[MAX_ARG+1];
+static int argp = 0;
+
+static void add_argument(const char *p)
+{
+  if (argp == MAX_ARG) {
+    fprintf(stderr, "fcc: Too many arguments.\n");
+    exit(1);
+  }
+  argvec[argp++] = (char *)p;
+  if (verbose)
+    printf("[%s] ", p);
+}
+
+static void add_option(const char *a, const char *b)
+{
+  char *x = malloc(strlen(a) + strlen(b) + 1);
+  if (x == NULL) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+  strcpy(x, a);
+  strcat(x, b);
+  add_argument(x);
+}
+
+static void add_argument_list(struct arglist *l)
+{
+  while(l) {
+    add_argument(l->p);
+    l = l->next;
+  }
+}
+
+static void add_option_list(const char *a, struct arglist *l)
+{
+  while(l) {
+    add_option(a, l->p);
+    l = l->next;
+  }
+}  
+
+static int do_command(void)
+{
+  pid_t pid, w;
+  int status;
+  
+  if (verbose)
+    printf("\n\n");
+  argvec[argp] = NULL;
+  pid = fork();
+  switch (pid) {
+    case 0:
+      execvp(argvec[0], argvec);
+      perror(argvec[0]);
+      _exit(0);
+    case -1:
+      perror("fork");
+      exit(1);
+    default:
+      while((w = wait(&status)) != pid);
+  }
+  return (WEXITSTATUS(status));
+}
+    
+/*
+ *     Stitch together an sdcc command.
+ */
+
+static void build_command(void)
+{
+  add_argument("sdcc");
+  /* Set up the basic parameters we will inflict on the user */
+  add_argument("--std-c99");
+  add_option("-m", cpu?cpu:"z80");
+  if (mode == MODE_LINK) {
+    add_argument("--no-std-crt0");
+    add_argument("--nostdlib");
+    add_argument("--code-loc");
+    add_argument("0x0");
+    add_argument("--data-loc");
+    add_argument("0x0");
+  }
+  /* Parse the specials */
+  if (pedantic == 0)
+    add_argument("--less-pedantic");
+  if (werror == 1)
+    add_argument("-Werror");
+  if (unschar == 1)
+    add_argument("-funsigned-char");
+  if (debug == 1)
+    add_argument("--debug");
+  /* Turn -O1/2/3 into something meanngful */
+  if (opt != NULL) {
+    if (optcode > 0)
+      add_argument("--max-allocs-per-node");
+    if (optcode == 1)
+      add_argument("30000");
+    if (optcode == 2)
+      add_argument("100000");
+    if (optcode == 3)
+      add_argument("250000");
+  }
+  /* Always size optimise */
+  add_argument("--opt-code-size");
+  /* Paths */
+  add_option_list("-I", includehead);
+  if (mode == MODE_LINK)
+    add_option_list("-L", libphead);
+  if (mode == MODE_CPP)
+    add_argument("-E");
+  if (mode == MODE_ASM)
+    add_argument("-S");
+  if (mode == MODE_OBJ) {
+    if (srchead == NULL || srchead->next != NULL) {
+      fprintf(stderr, "The -c option can only accept a single input right now.\n");
+      exit(1);
+    }
+    add_argument("-c");
+  }
+  if (target == NULL)
+    autotarget();
+  add_option("-o", target);
+  if (mode == MODE_LINK) {
+    add_argument("/opt/fcc/lib/crt0.rel");
+  }
+  if (srchead)
+    add_argument_list(srchead);
+  else {
+    fprintf(stderr, "fcc: No sources specified.\n");
+    exit(1);
+  }
+  if (mode == MODE_LINK)
+    add_option_list("-l", libhead);
+}
+
+int main(int argc, const char *argv[]) {
+  const char *p;
+  char *t;
+  int i;
+  int ret;
+  
+  for(i = 1; i < argc; i++) {
+    p = argv[i];
+    if (*p != '-')
+      add_source(p);
+    else {
+      switch(p[1]) {
+        case 'V':
+          verbose = 1;
+          break;
+        /* What are we doing */
+        case 'c':
+          mode = MODE_OBJ;
+          break;
+        case 'E':
+          mode = MODE_CPP;
+          break;
+        case 'S':
+          mode = MODE_ASM;
+          break;
+        case 'v':
+          printf("fcc: front end to sdcc\n");
+          add_argument("sdcc");
+          add_argument("-v");
+          do_command();
+          exit(0);
+        case 'l':
+          add_library(p+2);
+          break;
+        case 'L':
+          if (p[2] == 0)
+            add_library_path(argv[++i]);
+          else
+            add_library_path(p+2);
+          break;
+        case 'I':
+          if (p[2] == 0)
+            add_include_path(argv[++i]);
+          else
+            add_include_path(p+2);
+          break;
+        case 'o':
+          if (p[2] == 0)
+            set_target(argv[++i]);
+          else
+            set_target(p + 2);
+          break;
+        case 'O':
+          set_optimize(p + 2);
+          break;
+        case 'm':
+          if (p[2] == 0)
+            set_cpu(argv[++i]);
+          else
+            set_cpu(p + 2);
+          break;
+        case 'M':
+          if (p[2] == 0)
+            set_map(argv[++i]);
+          else
+            set_map(p + 2);
+          break;
+        case 'g':
+          debug = 1;
+          break;
+        default:
+          if (strcmp(p, "-Werror") == 0)
+            werror = 1;
+          else if (strcmp(p, "-funsigned-char") == 0)
+            unschar = 1;
+          else if (strcmp(p, "-pedantic") == 0)
+            pedantic = 1;
+          else {
+            fprintf(stderr, "fcc: Unknown option '%s'.\n", p);
+            exit(1);
+          }
+      }
+    }
+  }
+  add_include_path("/opt/fcc/include/");
+  add_library_path("/opt/fcc/lib/");
+  add_library("c");
+
+  build_command();
+  ret = do_command();
+  if (mode != MODE_LINK || ret)
+    exit(ret);
+  argp = 0;
+  add_argument("makebin");
+  add_argument("-p");
+  add_argument("-s");
+  add_argument("65535");
+  add_argument(target);
+  add_argument(t = rebuildname("", target, "bin"));
+  ret = do_command();
+  if (ret)
+    exit(ret);
+  argp = 0;
+  add_argument("/opt/fcc/bin/binman");
+  add_argument(t);
+  add_argument(rebuildname("", target, "map"));
+  add_argument(chopname(target));
+  ret = do_command();
+  exit(ret);
+}
diff --git a/Library/tools/fsize.c b/Library/tools/fsize.c
new file mode 100644 (file)
index 0000000..c1307a6
--- /dev/null
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+unsigned int z8016(const unsigned char *buf)
+{
+  unsigned int r = buf[1];
+  r <<= 8;
+  r |= buf[0];
+  return r;
+}
+
+int main(int argc, char *argv[])
+{
+  FILE *f;
+  unsigned char buf[16];
+  unsigned int cs, ds, bs, cm;
+
+  while(*++argv) {
+    f = fopen(*argv, "r");
+    if (f == NULL) {
+      perror(*argv);
+      exit(1);
+    }
+    if (fread(buf, 16, 1, f) != 1) {
+      perror("fread");
+      exit(1);
+    }
+    fclose(f);
+    if (buf[0] != 0xC3 || memcmp(buf+3, "FZX1", 4)) {
+      fprintf(stderr, "%s: not a valid Fuzix binary.\n", *argv);
+      continue;
+    }
+    cm = z8016(buf + 7);
+    cs = z8016(buf + 9) - 0x100;
+    ds = z8016(buf + 11) - cs;
+    bs = z8016(buf + 13);
+    
+    printf("%s: Code %d, Data %d, BSS %d, Chmem %d, Total %d\n",
+      *argv, cs, ds, bs, cm, cs + ds + bs);
+      
+  }
+  exit(0);
+}
+    
\ No newline at end of file
diff --git a/Library/tools/libclean b/Library/tools/libclean
new file mode 100755 (executable)
index 0000000..12df92c
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+#      Clean the supplied SDCC library of stuff we don't want. This
+#      IMHO beats forking the library or building a private copy.
+#
+#
+cp /opt/sdcc/share/sdcc/lib/z80/z80.lib tmp.lib
+#
+#      Scrub the functions we don't want to inherit
+#      Need to review setjmp and maybe a couple of others
+#
+#
+sdar d tmp.lib putchar.rel heap.rel fstubs.rel setjmp.rel errno.rel
+sdar d tmp.lib rand.rel _calloc.rel _malloc.rel _realloc.rel _free.rel
+sdar d tmp.lib printf_large.rel puts.rel gets.rel assert.rel time.rel
+sdar d tmp.lib tolower.rel toupper.rel
+mv tmp.lib sdccz80.lib
diff --git a/Library/tools/syscall.c b/Library/tools/syscall.c
new file mode 100644 (file)
index 0000000..ba00232
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *     Generate the syscall functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "syscall_name.h"
+
+static char namebuf[128];
+
+static void write_call(int n)
+{
+  FILE *fp;
+  snprintf(namebuf, 128, "fuzix/syscall_%s.s", syscall_name[n]);
+  fp = fopen(namebuf, "w");
+  if (fp == NULL) {
+    perror(namebuf);
+    exit(1);
+  }
+  fprintf(fp, "\t.area _CODE\n\n");
+  fprintf(fp, "\t.globl __syscall\n");
+  fprintf(fp, "\t.globl _%s\n\n", syscall_name[n]);
+  fprintf(fp, "_%s:\n\tld hl, #%d\n", syscall_name[n], n);
+  fprintf(fp, "\tjp __syscall\n");
+  fclose(fp);
+}
+
+static void write_call_table(void)
+{
+  int i;
+  for (i = 0; i < NR_SYSCALL; i++)
+    write_call(i);
+}
+
+static void write_makefile(void)
+{
+  int i;
+  FILE *fp = fopen("fuzix/Makefile", "w");
+  if (fp == NULL) {
+    perror("Makefile");
+    exit(1);
+  }
+  fprintf(fp, "# Autogenerated by tools/syscall\n");
+  fprintf(fp, "CROSS_AS=sdasz80\nCROSS_LD=sdldz80\nCROSS_AR=sdar\n");
+  fprintf(fp, "ASOPTS=\n\n");
+  fprintf(fp, "ASYS=syscall.s\n");
+  fprintf(fp, "ASRCS = syscall_%s.s\n", syscall_name[0]);
+  for (i = 1; i < NR_SYSCALL; i++)
+    fprintf(fp, "ASRCS += syscall_%s.s\n", syscall_name[i]);
+  fprintf(fp, "\n\nASRCALL = $(ASRCS) $(ASYS)\n");
+  fprintf(fp, "\nAOBJS = $(ASRCALL:.s=.rel)\n\n");
+  fprintf(fp, "syslib.lib: $(AOBJS)\n");
+  fprintf(fp, "\techo $(AOBJS) >syslib.l\n");
+  fprintf(fp, "\t$(CROSS_AR) rc syslib.lib $(AOBJS)\n\n");
+  fprintf(fp, "$(AOBJS): %%.rel: %%.s\n");
+  fprintf(fp, "\t$(CROSS_AS) $(ASOPTS) -o $*.rel $<\n\n");
+  fprintf(fp, "clean:\n");
+  fprintf(fp, "\trm -f $(AOBJS) $(ASRCS) syslib.lib *~\n\n");
+  fclose(fp);
+}
+
+int main(int argc, char *argv[])
+{
+  write_makefile();
+  write_call_table();
+  exit(0);
+}