This is at the 'gee it compiled' stage.
--- /dev/null
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c libc.c
+
+ASRCS = p68000.S crt0.S
+ASRCS += tricks.S
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.S=.o)
+OBJS = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.o) $(ASRCS:.S=.o)
+
+all: $(OBJS)
+
+$(COBJS): %.o: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.o: %.S
+ $(CROSS_AS) $(ASOPTS) $< -o $*.o
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~
+
+image:
+ $(CROSS_LD) -M -o ../fuzix.bin \
+ crt0.o \
+ p68000.o ../start.o ../version.o ../lowlevel-68000.o \
+ tricks.o main.o ../timer.o ../kdata.o devfd.o devices.o \
+ ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+ ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o ../flat.o \
+ ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec32.o \
+ ../usermem_std-68000.o devlpr.o devtty.o libc.o ../vt.o ../malloc.o \
+ /usr/lib/gcc/m68k-linux-gnu/4.9.1/libgcc.a >../fuzix.map
--- /dev/null
+This is an initial 'gee it compiles' work in progress initial 68000 port
+
+Don't expect it to do anything !
+
+
+Notes:
+ Memory below $0800 is supervisor only (traps)
+
+Need to support 'resident' style binaries
+Start of disk boot block info ?
+
+Tidy up di/ei usage - we don't want to turn on hblank at random in our ei
+stuff!!!
+
+First boot sector loaded into buffer. must checksum to $1234
+then executed. Must be PI
+
+Eventually need multi-segment executables
+
+
+Interrupts
+
+2 - hblank
+4 - vblank
+6 - mfp (but is magic)
+
+$100 - mfp parallel
+$104 - mfp rs232 carrier det
+$108 - mfp rs232 cts
+$10c - mfp blitter done
+$110 - mfp timer d
+$114 - mfp timer c (200Hz)
+$118 - mfp midi/kbd
+$11c - floppy/hd req
+$120 - hblank counter (timer B)
+$124 - rs232 tx error
+$128 - rs232 tx empty
+$12c - rs232 rx error
+$130 - rs232 rx full
+$134 - mfp timer a
+$138 - rs232 ring det
+$13c - mono/colour detect
+
+
--- /dev/null
+/* 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 - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+/* 32bit with flat memory */
+#define CONFIG_FLAT
+#define CONFIG_32BIT
+#define CONFIG_BANKS 1 /* FIXME */
+#define CONFIG_USERMEM_DIRECT
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* Simple text mode */
+#define CONFIG_VT_SIMPLE
+/* Vt definitions */
+#define VT_BASE (uint8_t *)0x6000 /* Default video text mode base */
+#define VT_WIDTH 32
+#define VT_HEIGHT 16
+#define VT_RIGHT 31
+#define VT_BOTTOM 15
+#define VT_INITIAL_LINE 4
+
+#define TICKSPERSEC 100 /* Ticks per second */
+
+#define BOOT_TTY (512 + 1) /* 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 2
+#define NDEVS 2 /* 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 */
--- /dev/null
+/*
+ * Need to wipe BSS etc once we figure out our preferred boot method
+ */
+ .globl _start
+
+.mri 1
+
+_start:
+ or #$0700,sr
+ /* FIXME: hard coded ugly */
+ move.l uarea_block+508,a7
+ jsr init_early
+ jsr init_hardware
+ jsr fuzix_main
+ or #$0700,sr
+stop: bra stop
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+#define MAX_FD 4
+
+#define OPDIR_NONE 0
+#define OPDIR_READ 1
+#define OPDIR_WRITE 2
+
+#define FD_READ 0x88 /* 2797 needs 0x88, 1797 needs 0x80 */
+#define FD_WRITE 0xA8 /* Likewise A8 v A0 */
+
+static uint8_t motorct;
+static uint8_t fd_selected = 0xFF;
+static uint8_t fd_tab[MAX_FD];
+
+static void fd_motor_busy(void)
+{
+ motorct++;
+}
+
+static void fd_motor_idle(void)
+{
+ motorct--;
+ // if (motorct == 0) ... start timer */
+}
+
+static void fd_motor_timeout(void)
+{
+ fd_selected = 0xff;
+// fd_motor_off();
+}
+
+/*
+ * We only support normal block I/O because otherwise we'd need
+ * bounce buffers - which would make it just as pointless!
+ *
+ * The Dragon and COCO have 18 x 256 byte sectors per track. We
+ * use them in pairs. We assume an even sectors per track. This is fine
+ * for our usage but would break for single density media.
+ */
+
+/* static uint8_t selmap[4] = { 0x01, 0x02, 0x04, 0x40 }; - COCO */
+static uint8_t selmap[4] = {0x00, 0x01, 0x02, 0x03 };
+
+static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+ blkno_t block;
+ uint32_t dptr;
+ int ct = 0;
+ int tries;
+ uint8_t err;
+ uint8_t *driveptr = fd_tab + minor;
+ uint8_t cmd[6];
+
+ if(rawflag)
+ goto bad2;
+
+ fd_motor_busy(); /* Touch the motor timer first so we don't
+ go and turn it off as we are doing this */
+ if (fd_selected != minor) {
+// uint8_t err = fd_motor_on(selmap[minor]);
+// if (err)
+// goto bad;
+ }
+
+ dptr = (uint32_t)udata.u_buf->bf_data;
+ block = udata.u_buf->bf_blk;
+
+// kprintf("Issue command: drive %d\n", minor);
+ cmd[0] = is_read ? FD_READ : FD_WRITE;
+ cmd[1] = block / 9; /* 2 sectors per block */
+ cmd[2] = ((block % 9) << 1) + 1; /*eww.. */
+ cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE;
+ cmd[4] = dptr >> 8;
+ cmd[5] = dptr & 0xFF;
+
+ while (ct < 2) {
+ for (tries = 0; tries < 4 ; tries++) {
+// err = fd_operation(cmd, driveptr);
+// if (err == 0)
+// break;
+// if (tries > 1)
+// fd_reset(driveptr);
+ }
+ /* FIXME: should we try the other half and then bale out ? */
+ if (tries == 3)
+ goto bad;
+ cmd[4]++; /* Move on 256 bytes in the buffer */
+ cmd[2]++; /* Next sector for 2nd block */
+ ct++;
+ }
+ fd_motor_idle();
+ return 1;
+bad:
+ kprintf("fd%d: error %x\n", minor, err);
+bad2:
+ fd_motor_idle();
+ udata.u_error = EIO;
+ return -1;
+
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+ if(minor >= MAX_FD) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return fd_transfer(minor, true, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return fd_transfer(minor, false, rawflag);
+}
+
--- /dev/null
+#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);
+
+/* low level interface */
+uint8_t fd_reset(uint8_t *drive);
+uint8_t fd_operation(uint8_t *cmd, uint8_t *drive);
+uint8_t fd_motor_on(uint8_t drive);
+uint8_t fd_motor_off(void);
+
+#endif /* __DEVFD_DOT_H__ */
+
--- /dev/null
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern void mod_control(uint8_t set, uint8_t clr);
+
+#endif /* __DEVICE_DOT_H__ */
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <tty.h>
+#include <vt.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) */
+ { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, vt_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)
+{
+}
+
--- /dev/null
+#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)
+{
+ return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+ return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ int c = udata.u_count;
+ unsigned char *p = udata.u_base;
+ uint16_t ct;
+
+ 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;
+}
--- /dev/null
+#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
--- /dev/null
+
+;;; gcc for m6809 : Oct 1 2014 11:32:32
+;;; 4.6.4 (gcc6809lw)
+;;; ABI version 1
+;;; -mint16
+ .module devlpr.c
+ .area .text2
+ .globl _lpr_open
+_lpr_open:
+ pshs u
+ leau ,s
+ ldx #0
+ puls u,pc
+ .globl _lpr_close
+_lpr_close:
+ pshs u
+ leau ,s
+ ldx #0
+ puls u,pc
+ .globl _lpr_write
+_lpr_write:
+ pshs y,u
+ leas -6,s
+ leau ,s
+ ldy _udata+96
+ ldx _udata+94
+ stx 2,u
+ cmpy #0 ;cmphi:
+ ble L8
+ leay -1,y
+ sty 4,u
+L14:
+ ldb [_lpstat]
+ clra ;zero_extendqihi: R:b -> R:d
+ std ,u
+ anda #0
+ andb #2
+ cmpd #0 ;cmphi:
+ beq L16
+ ldy _udata
+ ldd #3
+ std 36,y
+ ldb 13,u
+ ldx #0
+ jsr __far_call_handler ;old style
+ .dw _psleep_flags
+ .db
+ cmpx #0 ;cmphi:
+ beq L14
+ ldy _udata+96
+ beq L8
+ ldd #0
+ std _udata+12
+L8:
+ leax ,y
+ leas 6,s
+ puls y,u,pc
+L16:
+ ldy _lpdata
+ ldx 2,u
+ leax 1,x
+ stx ,u
+ ldx 2,u
+ jsr __far_call_handler ;old style
+ .dw _ugetc
+ .db
+ tfr x,d
+ stb ,y ;movlsbqihi: R:d -> ,y
+ ldx 4,u
+ leax -1,x
+ stx 4,u
+ cmpx #-1 ;cmphi:
+ beq L17
+ ldx ,u
+ stx 2,u
+ jmp L14
+L17:
+ ldy _udata+96
+ bra L8
+ .globl _lpdata
+ .area .data
+_lpdata:
+ .word -255
+ .globl _lpstat
+_lpstat:
+ .word -256
--- /dev/null
+#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 *uart_data = (uint8_t *)0xFF04; /* ACIA data */
+uint8_t *uart_status = (uint8_t *)0xFF05; /* ACIA status */
+uint8_t *uart_command = (uint8_t *)0xFF06; /* ACIA command */
+uint8_t *uart_control = (uint8_t *)0xFF07; /* ACIA control */
+
+unsigned char tbuf1[TTYSIZ];
+unsigned 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}
+};
+
+/* 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 = *uart_status;
+ return c & 16; /* TX DATA empty */
+}
+
+/* For DragonPlus we should perhaps support both monitors 8) */
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ if (minor == 1) {
+ vtoutput(&c, 1);
+ } else
+ *uart_data = c; /* Data */
+}
+
+void tty_setup(uint8_t minor)
+{
+ if (minor == 2) {
+ /* FIXME: do proper mode setting */
+ *uart_command = 0x01; /* DTR high, IRQ enabled, TX irq disabled 8N1 */
+ *uart_control = 0x1E; /* 9600 baud */
+ }
+}
+
+int tty_carrier(uint8_t minor)
+{
+ /* The serial DCD is status bit 5 but not wired */
+ return 1;
+}
+
+void tty_interrupt(void)
+{
+ uint8_t r = *uart_status;
+ if (r & 0x8) {
+ r = *uart_data;
+ tty_inproc(2,r);
+ }
+}
+
+uint8_t keymap[8];
+static uint8_t keyin[8];
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+static uint8_t shiftmask[8] = {
+ 0, 0x40, 0, 0, 0, 0, 0, 0x40
+};
+
+static uint8_t rbit[8] = {
+ 0xFE,
+ 0xFD,
+ 0xFB,
+ 0xF7,
+ 0xEF,
+ 0xDF,
+ 0xBF,
+ 0x7F,
+};
+
+/* Row inputs: multiplexed with the joystick */
+static volatile uint8_t *pia_row = (uint8_t *)0xFF00;
+/* Columns for scanning: multiplexed with the printer port */
+static volatile uint8_t *pia_col = (uint8_t *)0xFF02;
+/* Control */
+static volatile uint8_t *pia_ctrl = (uint8_t *)0xFF03;
+
+static void keyproc(void)
+{
+ int i;
+ uint8_t key;
+
+ for (i = 0; i < 8; i++) {
+ /* We do the scan in software on the Dragon */
+ *pia_col = rbit[i];
+ keyin[i] = ~*pia_row;
+ key = keyin[i] ^ keymap[i];
+ if (key) {
+ int n;
+ int m = 1;
+ for (n = 0; n < 7; 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 += m;
+ }
+ }
+ keymap[i] = keyin[i];
+ }
+}
+
+uint8_t keyboard[8][7] = {
+ { '0', '8', '@', 'h', 'p', 'x', 10 },
+ { '1', '9', 'a', 'i', 'q', 'y', 0 /* clear - used as ctrl*/ },
+ { '2', ':', 'b', 'j', 'r', 'z', 27 /* break (used for esc) */ },
+ { '3', ';', 'c', 'k', 's', '^' /* up */, 0 /* NC */ },
+ { '4', ',', 'd', 'l', 't', '|' /* down */, 0 /* NC */ },
+ { '5', '-', 'e', 'm', 'u', 8 /* left */, 0 /* NC */ },
+ { '6', '.', 'f', 'n', 'v', '\t' /* right */, 0 /* NC */ },
+ { '7', '/', 'g', 'o', 'w', ' ', 0 /* shift */ },
+};
+
+uint8_t shiftkeyboard[8][7] = {
+ { '_', '(', '\\', 'H', 'P', 'X', 10 },
+ { '!', ')', 'A', 'I', 'Q', 'Y', 0 /* clear */ },
+ { '"', '*', 'B', 'J', 'R', 'Z', 3 /* break */ },
+ { '#', '+', 'C', 'K', 'S', '[' /* up */, 0 /* NC */ },
+ { '$', '<', 'D', 'L', 'T', ']' /* down */, 0 /* NC */ },
+ { '%', '=', 'E', 'M', 'U', '{' /* left */, 0 /* NC */ },
+ { '&', '>', 'F', 'N', 'V', '}' /* right */, 0 /* NC */ },
+ { '\'', '?', 'G', 'O', 'W', ' ', 0 /* shift */ },
+};
+
+static void keydecode(void)
+{
+ uint8_t c;
+
+ if (keymap[7] & 64) /* shift */
+ c = shiftkeyboard[keybyte][keybit];
+ else
+ c = keyboard[keybyte][keybit];
+ if (keymap[1] & 64) { /* control */
+ if (c > 31 && c < 96)
+ c &= 31;
+ }
+ tty_inproc(1, c);
+}
+
+void platform_interrupt(void)
+{
+ uint8_t i = *pia_ctrl;
+ if (i & 0x80) {
+ *pia_col;
+ newkey = 0;
+ keyproc();
+ if (keysdown < 3 && newkey)
+ keydecode();
+ timer_interrupt();
+ }
+}
+
+/* This is used by the vt asm code, but needs to live at the top of the kernel */
+uint16_t cursorpos;
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#define KEY_ROWS 8
+#define KEY_COLS 7
+extern uint8_t keymap[8];
+extern uint8_t keyboard[8][7];
+extern uint8_t shiftkeyboard[8][7];
+
+#endif
--- /dev/null
+; 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.
+
+
+SAM_USER macro
+ sta 0xFFD4
+ endm
+
+SAM_KERNEL macro
+ sta 0xFFD5
+ endm
+
+SAM_SAVE macro
+ ldy 4
+ endm
+
+SAM_RESTORE macro
+ sta ,y
+ endm
+
--- /dev/null
+#include "cpu.h"
+
+void *memcpy(void *d, const void *s, size_t sz)
+{
+ unsigned char *dp = d;
+ const unsigned char *sp = s;
+ 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;
+}
+
+int memcmp(const void *a, const void *b, size_t n)
+{
+ const uint8_t *ap = a;
+ const uint8_t *bp = b;
+ while(n--) {
+ if (*ap < *bp)
+ return -1;
+ if (*ap != *bp)
+ return 1;
+ ap++;
+ bp++;
+ }
+ return 0;
+}
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+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)
+{
+}
+
+void map_init(void)
+{
+}
+
+unsigned char vt_mangle_6847(unsigned char c)
+{
+ if (c >= 96)
+ c -= 32;
+ c &= 0x3F;
+ return c;
+}
+
+u_block uarea_block[PTABSIZE];
+uaddr_t ramtop;
\ No newline at end of file
--- /dev/null
+/*
+ * 68000 Atari ST
+ *
+ * We need pretty much nothing here as we don't do page mapping.
+ */
+
+ .globl trap_reboot
+ .globl init_early
+ .globl init_hardware
+ .globl program_vectors
+ .globl outchar
+ .globl trap_reboot, trap_monitor
+.mri 1
+trap_reboot:
+trap_monitor:
+ or #0700,sr
+ bra trap_monitor
+init_early:
+ rts
+
+init_hardware:
+ ; set system RAM size
+ move.w #512,ramsize
+ move.w #448,procmem ; guesses for now
+ rts
+
+
+; Nothing to do in 68000 - all set up once at boot
+;
+program_vectors:
+ rts
+
+;
+; All mapped all the time
+;
+map_process_always:
+map_process:
+map_kernel:
+map_restore:
+map_save:
+ rts
+
+; outchar: Wait for UART TX idle, then print the char in d0
+
+outchar:
+ move.w d0,-(sp)
+outcharw:
+ move.b $FFFFFA13,d0
+ btst #2,d0
+ beq outcharw
+ move.w (sp)+,d0
+ move.b d0,$FFFFFA2D
+ rts
+
+.section data
+
+_kernel_flag: byte 1
--- /dev/null
+#include "../kernel-68000.def"
+
+
+.globl switchout,switchin,dofork
+
+.mri 1
+
+; 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().
+;
+; This function can have no arguments or auto variables.
+switchout:
+ or #$0700,sr
+ bsr chksigs
+ ; save machine state
+
+ clr.w -(sp) ; 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:
+ movem.l a0-a4/a6/d0-d7,-(sp) ; FIXME: trim to callee saves
+ move.l sp,U_DATA__U_SP(a5) ; this is where the SP is restored in _switchin
+
+ ; set inint to false
+ clr.b inint
+
+ ; find another process to run (may select this one again)
+ bsr getproc
+
+ move.l a0,-(sp) ; CHECK compiler call/return rules
+ bsr switchin
+
+ ; we should never get here
+ jmp trap_monitor
+
+badswitchmsg: ascii "_switchin: FAIL"
+ byte 13,10,0
+swapped: ascii "_switchin: SWAPPED"
+ byte 13,10,0
+
+switchin:
+ or #$0700,sr
+ move.l 4(sp),a0 ; task to switch to
+ move.l P_TAB__P_UDATA_OFFSET(a0),a5
+
+ ; check u_data->u_ptab matches what we wanted
+ move.l 4(sp),d0
+ cmp.l U_DATA__U_PTAB(a5),d0
+ bne switchinfail
+
+ ; wants optimising up a bit
+ move.b #P_RUNNING,P_TAB__P_STATUS_OFFSET(a0)
+
+ ; runticks = 0
+ clr.w runticks
+
+ ; restore machine state -- note we may be returning from either
+ ; _switchout or _dofork
+ move.l U_DATA__U_SP(a5),sp
+ movem.l (sp)+,a0-a4/a6/d0-d7 ; FIXME: trim to callee saves here too
+ add #2,sp ; drop return code dummy
+
+ tst.b inint
+ beq keepoff ; in ISR, leave interrupts off
+ and #$F8FF,sr
+keepoff:
+ rts ; return with interrupts on
+
+switchinfail:
+ bsr outa0hex
+ lea badswitchmsg,a0
+ bsr outstring
+ ; something went wrong and we didn't switch in what we asked for
+ bra trap_monitor
+
+
+;
+; Called from _fork. We are in a syscall, the uarea is live as the
+; parent uarea. The kernel is the mapped object.
+;
+; We don't support fork() proper only vfork()
+;
+dofork:
+ ; always disconnect the vehicle battery before performing maintenance
+ or #$0700,sr ; should already be the case ... belt and braces.
+
+ move.l 4(sp),a0
+ move.l a0,fork_proc_ptr
+
+ ; prepare return value in parent process -- HL = p->p_pid;
+ move.w P_TAB__P_PID_OFFSET(a0),d0
+ move.w d0,-(sp)
+ movem.l a0-a6/d0-d7,-(sp) ; FIXME - callees !
+
+ ; 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.
+
+ move.l sp,U_DATA__U_SP(a5)
+ move.l a5,P_TAB__P_UDATA_OFFSET(a0)
+
+ ; now we're in a safe state for _switchin to return in the parent
+ ; process.
+
+ ; FIXME: allocation heap walk/copy for chains
+
+ bsr bankfork ; do the bank to bank copy
+
+ ; Returns with a5 set for the new process
+
+ ; now the copy operation is complete we can get rid of the stuff
+ ; _switchin will be expecting from our copy of the stack.
+
+ add.l #58,sp ; FIXME: adjut when adjust movem's
+
+ ; Make a new process table entry, etc.
+ move.l fork_proc_ptr,-(sp)
+ jsr newproc
+ add.l #4,sp
+
+ clr.w runticks
+ ; in the child process, fork() returns zero.
+ clr.w d0
+ ;
+ ; 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
+
+;
+; This is related so we will keep it here. Copy the process memory
+; for a fork. Walk the heap allocations for this process and duplicate
+; them. We need to allow this to fail and ripple the error back nicely
+;
+bankfork:
+ rts
+
+fork_proc_ptr: long 0 ; (C type is struct p_tab *) -- address of child process p_tab entry