--- /dev/null
+LIBPATH=../../Library/libs
+LIBC=$(LIBPATH)/libc8080.a $(ACK_ROOT)/share/ack/cpm/libem.a
+
+CSRCS += devices.c main.c devtty.c
+
+DISCARD_DSRCS = ../dev/devide_discard.c
+DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c
+
+CROSS_CCOPTS += -I../dev/
+
+ASRCS = crt0.s commonmem.s v85.s tricks.s end.s
+
+AOBJS = $(ASRCS:.s=.o)
+COBJS = $(CSRCS:.c=.o)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.o, $(DISCARD_DSRCS))
+DOBJS = $(patsubst ../dev/%.c,%.o, $(DSRCS))
+
+OBJS = $(AOBJS) $(COBJS) $(DISCARD_DOBJS) $(DOBJS)
+
+JUNK = *.o *.lst *.asm *.sym *.rst
+
+all: $(OBJS)
+
+$(AOBJS): %.o: %.s
+ $(CROSS_AS) $(ASOPTS) $<
+
+$(COBJS): %.o: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $<
+
+$(DOBJS): %.o: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $<
+
+# Need to make discard work yet
+$(DISCARD_DOBJS): %.o: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $<
+
+tricks.s: ../lib/8080fixedbank.s ../lib/8080fixedbank-core.s
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~ bootblock.bin bootblock
+
+image:
+ $(CROSS_LD) -b0:0x0100 -b4:0xE800 -o fuzix.bin crt0.o devices.o main.o \
+ commonmem.o tricks.o v85.o devtty.o \
+ ../start.o ../version.o ../lowlevel-8080.o \
+ ../bankfixed.o ../timer.o ../kdata.o \
+ ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+ ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o \
+ ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o \
+ ../syscall_fs3.o ../syscall_exec16.o \
+ blkdev.o mbr.o devide.o devide_discard.o \
+ ../usermem_std-8080.o $(LIBC) end.o
+ anm fuzix.bin | ../tools/8080map > ../fuzix.map
+ ../tools/ack2kernel -v fuzix.bin ../fuzix.bin
+ ../tools/check8080 fuzix.bin
--- /dev/null
+This is an emulated platform driver for the V85 virtual 8085. The main goal is
+to see what can be done to improve 8085 over 8080. It also provides a way to test
+the IDE and modern block layer code with ackcc.
+
--- /dev/null
+#include "../kernel-8080.def"
+
+!
+! Common on z80pack is at 0xF000 as defined by hardware.
+!
+.sect .common
+
+#include "../cpu-8080/std-commonmem.s"
--- /dev/null
+/* We have an RTC */
+#undef CONFIG_RTC
+/* And we can read ToD from it */
+#undef CONFIG_RTC_FULL
+/* 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
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 8 48K banks, 1 is kernel */
+#define MAX_MAPS 7
+#define MAP_SIZE 0xC000U
+
+/* Read processes and big I/O direct into process space */
+#define CONFIG_LARGE_IO_DIRECT(x) 1
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS 1
+
+#define TICKSPERSEC 10 /* Ticks per second */
+#define PROGBASE 0x0000 /* also data base */
+#define PROGLOAD 0x0100 /* also data base */
+#define PROGTOP 0xBE00 /* Top of program, base of U_DATA copy */
+#define PROC_SIZE 60 /* Memory needed per process */
+
+#define SWAPDEV (swap_dev) /* A variable for dynamic, or a device major/minor */
+
+#define SWAP_SIZE 0x60 /* 48K in blocks (we actually don't need the low 256) */
+#define SWAPBASE 0x0000 /* We swap the lot in one, include the */
+#define SWAPTOP 0xC000 /* vectors so its a round number of sectors */
+#define MAX_SWAPS 16 /* The full drive would actually be 85! */
+/* Swap will be set up when a suitably labelled partition is seen */
+#define CONFIG_DYNAMIC_SWAP
+
+#define CONFIG_IDE
+#define MAX_BLKDEV 1 /* One IDE */
+
+#define swap_map(x) ((uint8_t *)(x)) /* Simple zero based mapping */
+
+#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 1
+
+#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS 8 /* Number of block buffers */
+#define NMOUNTS 4 /* Number of mounts at a time */
+
+#define platform_discard()
+#define platform_copyright()
--- /dev/null
+#include "../kernel-8080.def"
+
+.sect .text
+.sect .rom
+.sect .data
+datastart:
+.sect .bss
+bssstart:
+.sect .common
+commonstart:
+
+.sect .text
+
+.define init
+
+ .data2 0x8085
+
+init:
+ di
+ lxi sp,kstack_top
+
+ call init_early
+
+
+ lxi h,commonend
+ lxi d,commonstart
+ call calcsize
+
+ lxi h,bssstart
+ lxi d,commonstart
+
+nextbyte:
+ mov a,m
+ stax d
+ inx h
+ inx d
+ dcx b
+ mov a,b
+ ora c
+ jnz nextbyte
+
+! lxi h,bssend ! We should really do this but bssend
+ ! isnt appearing at the end so plan b
+ lxi h,commonstart ! Wipe all the free space
+ lxi d,bssstart
+ call calcsize
+
+ lxi h,bssstart
+wipe:
+ mvi m,0
+ inx h
+ dcx b
+ mov a,b
+ ora c
+ jnz wipe
+
+ call init_hardware
+
+ call _fuzix_main
+ di
+stop: hlt
+ jmp stop
+
+calcsize:
+ mov a,l
+ sub e
+ mov c,a
+ mov a,h
+ sbb d
+ mov b,a
+ ret
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devtty.h>
+#include <devfd.h>
+#include <blkdev.h>
+#include <devide.h>
+
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+// minor open close read write ioctl
+// -----------------------------------------------------------------
+ /* 0: /dev/hd Hard disc block devices */
+ { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl },
+ /* 1: /dev/fd Floppy disc block devices */
+ { no_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 */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 4: /dev/mem etc System devices (one offs) */
+ { no_open, sys_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) - 1)
+ return false;
+ else
+ return true;
+}
+
+void device_init(void)
+{
+ devide_init();
+}
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+static unsigned char tbuf1[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 },
+};
+
+static tcflag_t console_mask[4] = {
+ _ISYS,
+ _OSYS,
+ _CSYS,
+ _LSYS
+};
+
+/* TODO: stty support for the Z180 ports */
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+ NULL,
+ console_mask,
+};
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+ minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+ minor;
+ return 1;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ switch(minor){
+ case 1:
+ ttyout(c);
+ break;
+ }
+}
+
+void tty_sleeping(uint8_t minor)
+{
+ minor;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+ uint8_t r;
+#if 0
+ if (minor == 1)
+ r = ttyready();
+ else
+ r = ttyready2();
+ if (r)
+ return TTY_READY_NOW;
+ return TTY_READY_SOON;
+#endif
+ return TTY_READY_NOW;
+}
+
+void tty_poll(void)
+{
+ uint16_t r;
+ while((r = acia_poll()) != 0xFFFF)
+ tty_inproc(1, r);
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+ tty_putc(TTYDEV & 0xFF, c);
+ if(c == '\n')
+ tty_putc(TTYDEV & 0xFF, '\r');
+}
--- /dev/null
+extern void tty_poll(void);
+extern void ttyout(uint8_t c);
+
+extern uint16_t acia_poll(void);
+
+
--- /dev/null
+#include "../kernel-8080.def"
+
+.sect .common
+
+.define commonend
+
+commonend:
+
+.sect .bss
+.define bssend
+
+bssend:
--- /dev/null
+! UZI mnemonics for memory addresses etc
+
+U_DATA = 0xE800 ! (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE = 0x200 ! 256+256 bytes.
+
+U_DATA_STASH = 0xBE00 ! BE00-BFFF
+
+PROGBASE = 0x0000
+PROGLOAD = 0x0100
+
+CONFIG_SWAP = 1
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <blkdev.h>
+
+uaddr_t ramtop = PROGTOP;
+uint16_t swap_dev = 0xFFFF;
+
+extern uint16_t probe_bank(uint16_t);
+
+void pagemap_init(void)
+{
+ uint8_t i;
+ uint8_t m = 2;
+
+ for (i = 1; i < 8; i++) {
+ if (probe_bank(m) == 0) {
+ pagemap_add(m);
+ ramsize += 48;
+ procmem += 48;
+ }
+ m <<= 1;
+ }
+ if (procmem < 96)
+ panic("insufficient memory");
+}
+
+/* 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_poll();
+ irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+ tty_poll();
+ timer_interrupt();
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
+
+uint8_t platform_param(char *p)
+{
+ used(p);
+ return 0;
+}
+
+/*
+ * This function is called for partitioned devices if a partition is found
+ * and marked as swap type. The first one found will be used as swap. We
+ * only support one swap device.
+ */
+void platform_swap_found(uint8_t letter, uint8_t m)
+{
+ blkdev_t *blk = blk_op.blkdev;
+ uint16_t n;
+ if (swap_dev != 0xFFFF)
+ return;
+ letter -= 'a';
+ kputs("(swap) ");
+ swap_dev = letter << 4 | m;
+
+ if (blk->lba_count[m - 1] > 0xFFFF)
+ n = 0xFFFF;
+ else
+ n = (uint16_t)blk->lba_count[m-1];
+ n /= SWAP_SIZE;
+ if (n > MAX_SWAPS)
+ n = MAX_SWAPS;
+#ifdef SWAPDEV
+ while (n)
+ swapmap_init(n--);
+#endif
+}
+
--- /dev/null
+#define ide_select(x)
+#define ide_deselect()
+
+/*CF card: 8bit, no altstatus/control */
+#define IDE_8BIT_ONLY
+#define IDE_REG_INDIRECT
+
+#define ide_reg_data 0x10
+#define ide_reg_error 0x11
+#define ide_reg_features 0x11
+#define ide_reg_sec_count 0x12
+#define ide_reg_lba_0 0x13
+#define ide_reg_lba_1 0x14
+#define ide_reg_lba_2 0x15
+#define ide_reg_lba_3 0x16
+#define ide_reg_devhead 0x16
+#define ide_reg_command 0x17
+#define ide_reg_status 0x17
--- /dev/null
+export CPU = 8080
--- /dev/null
+#
+
+#include "../kernel-8080.def"
+#include "../lib/8080fixedbank.s"
+
+.sect .common
+
+.define bankfork
+
+bankfork:
+ sta patch1+1
+ mov a,c
+ sta patch2+1
+ lxi h,0
+ dad sp
+ shld copy_done+1 ! patch stack restore in
+
+ ! Go from the break to 0-5
+ lhld U_DATA__U_BREAK
+ lxi d,-6 ! move down 6 for the copier loop
+ dad d
+ sphl
+ mvi a,0xff ! end between 5 and 0 (which is fine)
+ sta patch3+1
+ lxi h,copy_stack
+ jmp copier
+ !
+ ! Go from BE00 to the stack pointer
+ !
+copy_stack:
+ lxi sp,0xBE00-6
+ ! Trickier .. need to work out where to stop
+ lhld U_DATA__U_SYSCALL_SP
+ lxi d,-0x0106 ! 6 for the underrun 0x100 for the round down
+ dad d
+ mov a,h
+ sta patch3+1
+ lxi h,copy_done
+ jmp copier
+copy_done:
+ lxi h,0
+ sphl
+ ret
+
+copier:
+ shld patch4+1
+loop:
+ ! sp points to top of block
+patch1:
+ mvi a,0 ! 7
+ out 0x40 ! source bank 10
+ pop h ! 10
+ pop d ! 10
+ pop b ! 10
+patch2:
+ mvi a,0 ! 7
+ out 0x40 ! dest bank 10
+ push b ! 11
+ push d ! 11
+ push h ! sp now back where it started 11
+ lxi h,-6 ! 10
+ dad sp ! 10
+ sphl ! sp ready for next burst 5
+ mov a,h ! 5
+patch3:
+ cpi 0 ! wrapped to FFFx 7
+ jnz loop ! 10
+
+!
+! 144 cycles per 6 bytes = 24 per byte which is actually not far off
+! a naive Z80 implementation and about half a good one. Still means
+! a second to do the fork() bank copy on a 1MHz 8080. Not quite so bad
+! on a 6MHz 8085 though 8)
+!
+! We halt at somewhere around xx05-xx00 so we have to tidy up by hand
+! or accept an underrun. We go the overlap approach on the grounds
+! it's cheap and our main overcopy is at most 5 bytes in common,
+! whlist the bank to bank overcopy is harmless and small
+!
+!
+ mvi a,1
+ out 0x40
+patch4:
+ jmp 0
--- /dev/null
+#
+!
+! Low level platform support for v8080
+!
+
+ #include "../kernel-8080.def"
+
+.sect .common
+
+.define _platform_monitor
+.define _platform_reboot
+
+_platform_monitor:
+_platform_reboot:
+ di
+ hlt
+
+.define platform_interrupt_all
+
+platform_interrupt_all:
+ mvi a,0x50
+ out 0xFE
+ ret
+
+.sect .text
+
+.define init_early
+
+init_early:
+ ret
+
+.sect .common
+
+
+.define init_hardware
+
+init_hardware:
+ mvi a,8
+ out 20
+ ! Hack for now
+ lxi h,64 ! 1 * 48K + 16K common
+ shld _ramsize
+ lxi h,0
+ shld _procmem
+
+ mvi a,0x40
+ out 0xFE ! 10Hz timer on
+
+ mvi a,0x96 ! Intialize the ACIA
+ out 0
+
+ jmp _program_vectors_k
+
+.define _int_disabled
+_int_disabled:
+ .data1 1
+
+.define _program_vectors
+
+_program_vectors:
+ di
+ pop d
+ pop h
+ push h
+ push d
+ call map_process
+ call _program_vectors_u
+ call map_kernel_di
+ ret
+
+_program_vectors_k:
+ push b
+ call .rst_init
+ pop b
+!
+! The 8085 has some vectors of its own
+! 0x24 is NMI
+! 0x2C/0x34/0x3C are vectored interrupts
+! This also means we need a customised .rst handler to leave room for
+! NMI and RST 5.5 ideally.
+!
+! We have the ACIA on 0x3C (polled for the moment) and the timer
+! on 0x34
+!
+_program_vectors_u:
+ mvi a,0xc3
+ sta 0
+ lxi h,null_handler
+ shld 1
+!
+! FIXME: rst code fouls NMI
+!
+! sta 0x24
+! lxi h,nmi_handler
+! shld 0x25
+ sta 0x30
+ lxi h,unix_syscall_entry
+ shld 0x31
+ sta 0x3c
+ lxi h,acia_interrupt
+ shld 0x3d
+ sta 0x34
+ lxi h,interrupt_handler
+ shld 0x35
+ !
+ ! Just in case
+ !
+ lxi h,unexpected
+! sta 0x2C
+! shld 0x2D
+ sta 0x38
+ shld 0x39
+ ret
+
+unexpected:
+ lxi h,unexpect
+ call outstring
+ ei
+ ret
+
+unexpect:
+ .ascii '[unexpected irq]'
+ .data1 10,0
+!
+! Memory mapping
+!
+.define map_kernel
+.define map_kernel_di
+
+map_kernel:
+map_kernel_di:
+map_buffers:
+ push psw
+ mvi a,1
+ sta curmap
+ out 0x40
+ pop psw
+ ret
+
+.define map_process
+.define map_process_di
+.define map_process_a
+
+map_process:
+map_process_di:
+ mov a,h
+ ora l
+ jz map_kernel
+ mov a,m
+map_for_swap:
+map_process_a:
+ sta curmap
+ out 0x40
+ ret
+
+.define map_process_always
+.define map_process_always_di
+
+map_process_always:
+map_process_always_di:
+ push psw
+ lda U_DATA__U_PAGE
+ sta curmap
+ out 0x40
+ pop psw
+ ret
+
+.define map_save_kernel
+
+map_save_kernel:
+ push psw
+ lda curmap
+ sta map_save
+ mvi a,1
+ sta curmap
+ out 0x40
+ pop psw
+ ret
+
+.define map_restore
+
+map_restore:
+ push psw
+ lda map_save
+ sta curmap
+ out 0x40
+ pop psw
+ ret
+
+.define _probe_bank
+
+_probe_bank:
+ pop d
+ pop h
+ push h
+ push d
+ mov a,l
+ call map_process_a
+ lxi d,-1
+ lxi h,4
+ mvi a,0x55
+ mov m,a
+ cmp m
+ jnz nobank
+ inr m
+ inr a
+ cmp m
+ jnz nobank
+ inx d
+nobank:
+ jmp map_kernel
+
+map_save:
+ .data1 0
+curmap:
+ .data1 1
+.define outchar
+.define _ttyout
+
+!
+! 6850 ACIA
+!
+_ttyout:
+ pop h
+ pop d
+ push d
+ push h
+ mov a,e
+outchar:
+ push psw
+outcharw:
+ in 0
+ ani 2
+ jz outcharw
+ pop psw
+ out 1
+ ret
+
+.define _ttyready
+
+_ttyready:
+ in 0
+ ani 2
+ mov e,a
+ ret
+
+.define _acia_poll
+
+!
+! Call with interrupts off
+!
+_acia_poll:
+ lxi h,acia_queue+1
+ mov a,m ! read pointer
+ mov e,a ! save it
+ dcx h ! queue pointer
+ cmp m ! queue = read + 1 -> empty
+ jz empty
+ inr a
+ inx h ! point back to read
+ mov m,a ! move on one
+ lxi h,acia_rxbuf ! data buffer
+ mvi d,0
+ dad d ! plus offset
+ mov e,m ! return char in DE
+ mvi d,0
+ ret
+empty:
+ lxi d,0xffff ! No luck
+ ret
+
+
+!
+! ACIA interrupt
+!
+acia_interrupt:
+ push psw
+ in 0
+ rar
+ cc acia_rx ! we only do rx interrupts for now
+ pop psw
+ ei
+ ret
+acia_rx:
+ push h
+ push d
+ lxi h,acia_queue
+ mov a,m ! queue pointer
+ mov e,a ! save it
+ inx h ! move on to rx pointer
+ inr a ! move on
+ cmp m ! if we would hit rx pointer we are full
+ jz acia_rx_over ! so bail out
+ dcx h ! back to queue pointer
+ mov m,a ! save new pointer
+ mvi d,0
+ lxi h,acia_rxbuf ! get data offset and save
+ dad d ! could simplify if page aligned...
+ in 1
+ mov m,a
+acia_rx_over:
+ pop d
+ pop h
+ ret
+
+acia_rxbuf:
+ .space 256
+acia_queue:
+ .data1 1 ! queue pointer
+ .data1 0 ! read pointer
+
+!
+! IDE controller
+!
+.sect .common
+
+.define _devide_readb
+.define _devide_writeb
+
+_devide_readb:
+ pop h
+ pop d
+ push d
+ push h
+ mov a,e
+ sta .patch1+1
+.patch1:
+ in 0
+ mov e,a
+ mvi d,0
+ ret
+
+_devide_writeb:
+ lxi h,2
+ dad sp
+ mov a,m
+ sta .patch2+1
+ inx h
+ inx h
+ mov a,m
+.patch2:
+ out 0
+ ret
+
+.define _devide_read_data
+.define _devide_write_data
+
+_devide_read_data:
+ push b
+ lxi h,_blk_op
+ mov e,m
+ inx h
+ mov d,m ! Address
+ inx h
+ mov a,m ! Mapping type
+ cpi 2
+ jnz not_swapin
+ inx h ! Swap page
+ mov a,m
+ call map_for_swap
+ jmp doread
+not_swapin:
+ ora a
+ jz rd_kernel
+ call map_process_always
+ jmp doread
+rd_kernel:
+ call map_buffers
+doread:
+ mvi b,0
+ xchg
+readloop:
+ in 0x10
+ mov m,a
+ inx h
+ in 0x10
+ mov m,a
+ inx h
+ inr b
+ jnz readloop
+ pop b
+ jmp map_kernel
+
+_devide_write_data:
+ push b
+ lxi h,_blk_op
+ mov e,m
+ inx h
+ mov d,m
+ inx h
+ mov a,m
+ cpi 2
+ jnz not_swapout
+ inx h
+ mov a,m
+ call map_for_swap
+ jmp dowrite
+not_swapout:
+ ora a
+ jz wr_kernel
+ call map_process_always
+ jmp dowrite
+wr_kernel:
+ call map_buffers
+dowrite:
+ mvi b,0
+ xchg
+writeloop:
+ mov a,m
+ out 0x10
+ inx h
+ mov a,m
+ out 0x10
+ inx h
+ inr b
+ jnz writeloop
+ pop b
+ jmp map_kernel