From: Alan Cox Date: Sat, 16 Feb 2019 22:12:09 +0000 (+0000) Subject: v85: intial merge of the port X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=2761304388c0dcf441d58ba56d2511d46531237e;p=FUZIX.git v85: intial merge of the port --- diff --git a/Kernel/platform-v85/Makefile b/Kernel/platform-v85/Makefile new file mode 100644 index 00000000..4ac258b3 --- /dev/null +++ b/Kernel/platform-v85/Makefile @@ -0,0 +1,55 @@ +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 diff --git a/Kernel/platform-v85/README b/Kernel/platform-v85/README new file mode 100644 index 00000000..d366d45f --- /dev/null +++ b/Kernel/platform-v85/README @@ -0,0 +1,4 @@ +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. + diff --git a/Kernel/platform-v85/commonmem.s b/Kernel/platform-v85/commonmem.s new file mode 100644 index 00000000..30bec328 --- /dev/null +++ b/Kernel/platform-v85/commonmem.s @@ -0,0 +1,8 @@ +#include "../kernel-8080.def" + +! +! Common on z80pack is at 0xF000 as defined by hardware. +! +.sect .common + +#include "../cpu-8080/std-commonmem.s" diff --git a/Kernel/platform-v85/config.h b/Kernel/platform-v85/config.h new file mode 100644 index 00000000..3c869e5d --- /dev/null +++ b/Kernel/platform-v85/config.h @@ -0,0 +1,61 @@ +/* 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() diff --git a/Kernel/platform-v85/crt0.s b/Kernel/platform-v85/crt0.s new file mode 100644 index 00000000..06455171 --- /dev/null +++ b/Kernel/platform-v85/crt0.s @@ -0,0 +1,71 @@ +#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 diff --git a/Kernel/platform-v85/devices.c b/Kernel/platform-v85/devices.c new file mode 100644 index 00000000..317f270d --- /dev/null +++ b/Kernel/platform-v85/devices.c @@ -0,0 +1,42 @@ +#include +#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/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(); +} diff --git a/Kernel/platform-v85/devtty.c b/Kernel/platform-v85/devtty.c new file mode 100644 index 00000000..3863368b --- /dev/null +++ b/Kernel/platform-v85/devtty.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include + +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'); +} diff --git a/Kernel/platform-v85/devtty.h b/Kernel/platform-v85/devtty.h new file mode 100644 index 00000000..44a10067 --- /dev/null +++ b/Kernel/platform-v85/devtty.h @@ -0,0 +1,6 @@ +extern void tty_poll(void); +extern void ttyout(uint8_t c); + +extern uint16_t acia_poll(void); + + diff --git a/Kernel/platform-v85/end.s b/Kernel/platform-v85/end.s new file mode 100644 index 00000000..ae8ac45f --- /dev/null +++ b/Kernel/platform-v85/end.s @@ -0,0 +1,12 @@ +#include "../kernel-8080.def" + +.sect .common + +.define commonend + +commonend: + +.sect .bss +.define bssend + +bssend: diff --git a/Kernel/platform-v85/kernel.def b/Kernel/platform-v85/kernel.def new file mode 100644 index 00000000..4077bba4 --- /dev/null +++ b/Kernel/platform-v85/kernel.def @@ -0,0 +1,11 @@ +! 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 diff --git a/Kernel/platform-v85/main.c b/Kernel/platform-v85/main.c new file mode 100644 index 00000000..62b4bb8b --- /dev/null +++ b/Kernel/platform-v85/main.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include + +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 +} + diff --git a/Kernel/platform-v85/platform_ide.h b/Kernel/platform-v85/platform_ide.h new file mode 100644 index 00000000..a147c6a0 --- /dev/null +++ b/Kernel/platform-v85/platform_ide.h @@ -0,0 +1,18 @@ +#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 diff --git a/Kernel/platform-v85/target.mk b/Kernel/platform-v85/target.mk new file mode 100644 index 00000000..2173acaf --- /dev/null +++ b/Kernel/platform-v85/target.mk @@ -0,0 +1 @@ +export CPU = 8080 diff --git a/Kernel/platform-v85/tricks.s b/Kernel/platform-v85/tricks.s new file mode 100644 index 00000000..66623cd0 --- /dev/null +++ b/Kernel/platform-v85/tricks.s @@ -0,0 +1,84 @@ +# + +#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 diff --git a/Kernel/platform-v85/v85.s b/Kernel/platform-v85/v85.s new file mode 100644 index 00000000..3a6b96e2 --- /dev/null +++ b/Kernel/platform-v85/v85.s @@ -0,0 +1,418 @@ +# +! +! 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