From: Alan Cox Date: Tue, 11 Nov 2014 21:44:45 +0000 (+0000) Subject: dragon: Initial bits towards a Dragon64 port of sorts X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=a2a90d35d1c35156a663789d6edd2524f3c2e668;p=FUZIX.git dragon: Initial bits towards a Dragon64 port of sorts That's if you count replacing the boot ROMs as a "port" --- diff --git a/Kernel/Makefile b/Kernel/Makefile index b9b091c6..bd9d58c1 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -1,4 +1,4 @@ -TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite +TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-dragon #export TARGET= msx1 #export CPU = z80 diff --git a/Kernel/platform-dragon/Makefile b/Kernel/platform-dragon/Makefile new file mode 100644 index 00000000..abc144c6 --- /dev/null +++ b/Kernel/platform-dragon/Makefile @@ -0,0 +1,33 @@ + +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 $*.o + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: + $(CROSS_LD) -o ../fuzix.bin --map=../fuzix.map --script=fuzix.link \ + 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 ../single.o \ + ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec.o \ + ../usermem_std-6809.o devlpr.o devtty.o libc.o ../vt.o diff --git a/Kernel/platform-dragon/README b/Kernel/platform-dragon/README new file mode 100644 index 00000000..0aa3002a --- /dev/null +++ b/Kernel/platform-dragon/README @@ -0,0 +1,13 @@ +Dragon Experimental Build + +Currently we build for a Dragon64 but are not doing anything but initial +boot testing work + +Memory usage: + +The Dragon 64 has 2x32K banks of RAM which isn't sufficient but also 16K +of cartridge space that can appear at 0xC000->0xF??? and two ROMs + + +This is a very experimental build to see what might be possible if we either +replaced the ROM images or used a cartridge or both. diff --git a/Kernel/platform-dragon/commonmem.s b/Kernel/platform-dragon/commonmem.s new file mode 100644 index 00000000..67e7f269 --- /dev/null +++ b/Kernel/platform-dragon/commonmem.s @@ -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 .udata + +_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-dragon/config.h b/Kernel/platform-dragon/config.h new file mode 100644 index 00000000..d8f4a15c --- /dev/null +++ b/Kernel/platform-dragon/config.h @@ -0,0 +1,57 @@ +/* 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 - for now while we get it booting */ +#undef CONFIG_SINGLETASK +/* Use C helpers for usermem */ +#define CONFIG_USERMEM_C +/* Pure swap */ +#define CONFIG_SWAP_ONLY +#define CONFIG_BANKS 1 +/* FIXME */ +#define BANK_PROCESS *((volatile uint8_t *)0xff91) &= ~1 +#define BANK_KERNEL *((volatile uint8_t *)0xff91) |= 1 +/* 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 0x8000 /* uarea 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 +/* Simple text mode */ +#define CONFIG_VT_SIMPLE +/* Vt definitions */ +#define VT_BASE 0x0400 /* Default video text mode base */ +#define VT_WIDTH 32 +#define VT_HEIGHT 24 +#define VT_RIGHT 31 +#define VT_BOTTOM 23 + +#define TICKSPERSEC 100 /* Ticks per second */ +#define PROGBASE ((uint8_t *)(0x8000)) /* also data base */ +#define PROGTOP ((uint8_t *)(0xff00)) /* Top of program */ + +#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 3 /* Number of mounts at a time */ diff --git a/Kernel/platform-dragon/crt0.s b/Kernel/platform-dragon/crt0.s new file mode 100644 index 00000000..df550ecf --- /dev/null +++ b/Kernel/platform-dragon/crt0.s @@ -0,0 +1,47 @@ + ; 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 .start + jmp start + + .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-dragon/device.h b/Kernel/platform-dragon/device.h new file mode 100644 index 00000000..6f4c1e26 --- /dev/null +++ b/Kernel/platform-dragon/device.h @@ -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-dragon/devices.c b/Kernel/platform-dragon/devices.c new file mode 100644 index 00000000..0cfe40bf --- /dev/null +++ b/Kernel/platform-dragon/devices.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/fd Floppy disc block devices */ + { rd_open, no_close, rd_read, rd_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, 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-dragon/devlpr.c b/Kernel/platform-dragon/devlpr.c new file mode 100644 index 00000000..a0110858 --- /dev/null +++ b/Kernel/platform-dragon/devlpr.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +/* 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-dragon/devlpr.h b/Kernel/platform-dragon/devlpr.h new file mode 100644 index 00000000..7765c187 --- /dev/null +++ b/Kernel/platform-dragon/devlpr.h @@ -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-dragon/devrd.c b/Kernel/platform-dragon/devrd.c new file mode 100644 index 00000000..ddbf8b3c --- /dev/null +++ b/Kernel/platform-dragon/devrd.c @@ -0,0 +1,69 @@ +/* + * NC100 RD PCMCIA driver + * + */ + +#include +#include +#include +#include + +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-dragon/devrd.h b/Kernel/platform-dragon/devrd.h new file mode 100644 index 00000000..6320b269 --- /dev/null +++ b/Kernel/platform-dragon/devrd.h @@ -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-dragon/devtty.c b/Kernel/platform-dragon/devtty.c new file mode 100644 index 00000000..9934028d --- /dev/null +++ b/Kernel/platform-dragon/devtty.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ + +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} +}; + +/* 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 */ +} + +void tty_putc(uint8_t minor, unsigned char c) +{ +#if 0 + if (minor == 1) { + vtoutput(&c, 1); + return; + } +#endif + *uart_data = c; /* Data */ +} + +void tty_setup(uint8_t minor) +{ + /* 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); + } +} + +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-dragon/devtty.h b/Kernel/platform-dragon/devtty.h new file mode 100644 index 00000000..948cc298 --- /dev/null +++ b/Kernel/platform-dragon/devtty.h @@ -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-dragon/fuzix.link b/Kernel/platform-dragon/fuzix.link new file mode 100644 index 00000000..79e548a2 --- /dev/null +++ b/Kernel/platform-dragon/fuzix.link @@ -0,0 +1,12 @@ +section .vectors load 0x0100 +section .discard load 0x2000 +section .data +section .bss +section _COMMONMEM load 0x8000 +section .text2 +section .video +section .romvectors load 0xBFF0 +section .udata load 0x7D00 +section .start load 0xC000 +section .text + diff --git a/Kernel/platform-dragon/kernel.def b/Kernel/platform-dragon/kernel.def new file mode 100644 index 00000000..a49e8762 --- /dev/null +++ b/Kernel/platform-dragon/kernel.def @@ -0,0 +1,5 @@ +; 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-dragon/libc.c b/Kernel/platform-dragon/libc.c new file mode 100644 index 00000000..8b3940ba --- /dev/null +++ b/Kernel/platform-dragon/libc.c @@ -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-dragon/main.c b/Kernel/platform-dragon/main.c new file mode 100644 index 00000000..994c6207 --- /dev/null +++ b/Kernel/platform-dragon/main.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include + +/* 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) +{ +} + +void map_init(void) +{ +} diff --git a/Kernel/platform-dragon/p6809.s b/Kernel/platform-dragon/p6809.s new file mode 100644 index 00000000..5ce13ee2 --- /dev/null +++ b/Kernel/platform-dragon/p6809.s @@ -0,0 +1,188 @@ +; +; 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 #96 + std _ramsize + ldd #32 + std _procmem + rts + + + .area .vectors +; +; At 0x100 as required by the Dragon ROM +; + jmp badswi_handler ; 0x100 + jmp badswi_handler ; 0x103 + jmp unix_syscall_entry ; 0x106 + jmp nmi_handler ; 0x109 + jmp interrupt_handler ; 0x10C + jmp firq_handler ; 0x10F + +; +; Included if we are replacing the basic ROM and magically mapped from +; the ROM top (0xBFF0->FFF0) +; + .area .romvectors + + .dw 0x3634 ; Reserved + .dw 0x0100 + .dw 0x0103 + .dw 0x010f + .dw 0x010c + .dw 0x0106 + .dw 0x0109 + .dw 0xC000 ; Unused (reset) + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + + .area _COMMONMEM + +; +; In the Dragon64 case our vectors live in a fixed block +; +_program_vectors: + rts + +; +; FIXME: +; +firq_handler: +badswi_handler: + rti + +; +; The Dragon mapping is a bit tangled +; +; SAM ffd4/d5 reading turns off/on the upper 32K of RAM at 0x0-0x7FFF +; SAM ffde/ffdf makes it appear at 0x8000-0xffef (ff00... is hardwired) +; PIA 1 B side data reg (ff22) bit 2 switches between the two ROMs +; +; +; +; All registers preserved +; +map_process_always: + pshs a +map_process_2: + lda 0xffdf ; RAM please + lda #0 + sta cart_map + puls a, pc + +map_process: + cmpx #0 + bne map_process_always +; +; Map in the kernel below the current common, all registers preserved +; +map_kernel: + pshs a +map_kernel_2: + lda 0xffde ; RAM out (cart in hopefully) + lda #1 + sta cart_map + puls a, pc + +map_restore: + pshs a + lda saved_map + cmpa #0 + beq map_process_2 + bra map_kernel_2 +; +; Save the current mapping. +; +map_save: + pshs a + lda cart_map + sta saved_map + puls a,pc + +saved_map: .db 0 +cart_map: .db 0 + +; outchar: Wait for UART TX idle, then print the char in a + +outchar: + pshs b +outcharw: + ldb 0xff05 + bitb #0x04 + beq outcharw + sta 0xff04 + puls b,pc diff --git a/Kernel/platform-dragon/setup.s b/Kernel/platform-dragon/setup.s new file mode 100644 index 00000000..0a329b2f --- /dev/null +++ b/Kernel/platform-dragon/setup.s @@ -0,0 +1,66 @@ +; +; Raw machine set up for running in 'ROM' mode +; + .area .startup + + ; Optimise all this to use the direct page register as 0xffxx + orcc #0x10 + ; Memory 64K dynamic (I guess...) + lda 0xffdd + lda 0xffda + ; Memory low map (cartridge high, RAM low) + lda 0xffde ; Map type -> cartridge & rom + ; Serial + lda #0x01 + sta 0xff06 + lda #0x1e + sta 0xff07 + + ; 0.9Mhz + lda 0xffd6 ; R0 + lda 0xffd8 ; R1 + ; Put the video at 0x400 + lda 0xffd2 ; F6 to F1 clear F0 set + lda 0xffd0 + lda 0xffce + lda 0xffcc + lda 0xffca + lda 0xffc8 + lda 0xffc7 + ; SAM into ascii mode + lda 0xffc0 + lda 0xffc2 + lda 0xffc4 + + ; PIA0 A is all input + ; PIA0 B is all output + ; PIA1 A is mixed, both the same (input 0 only) + lda #0x4 ; enable access to DDR registers + sta 0xff01 + sta 0xff03 + sta 0xff21 + sta 0xff23 + lda #0x00 + sta 0xff00 + lda #0xff + sta 0xff02 + lda #0xfe + sta 0xff21 + sta 0xff23 + lda #0x0 ; Disable access to DDR registers + sta 0xff01 + sta 0xff03 + sta 0xff21 + sta 0xff23 + + ; VDG via PIA1 + lda #0x00 + ld 0xff22, a ; Graphics, internal text rom + + ; + ; Say hello + ; + ldx 0x400 + lda #'H' + sta ,x+ + diff --git a/Kernel/platform-dragon/tricks.s b/Kernel/platform-dragon/tricks.s new file mode 100644 index 00000000..3fb76a3f --- /dev/null +++ b/Kernel/platform-dragon/tricks.s @@ -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 + +