From 48480dcae5323a9200771a5e26ad6206ddd60a21 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Jun 2019 16:12:36 +0200 Subject: [PATCH 01/13] Fix a tiny ackbuilder bug where you can't set properties to false. --- first/ackbuilder.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua index 81e86b528..616c805d2 100644 --- a/first/ackbuilder.lua +++ b/first/ackbuilder.lua @@ -7,6 +7,7 @@ -- is = { set of rule types which made the target } -- } +local posix = require("posix") local emitter = {} local rules = {} local targets = {} @@ -544,7 +545,7 @@ local function definerule(rulename, types, cb) local args = {} for propname, typespec in pairs(types) do - if not e[propname] then + if e[propname] == nil then if not typespec.optional and (typespec.default == nil) then error(string.format("missing mandatory property '%s'", propname)) end From 3f938d651b9c9441770e6fa83fca4abf264c18aa Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Jun 2019 18:33:04 +0200 Subject: [PATCH 02/13] EM requires 2-alignment in structures, sadly. --- plat/cpm/descr | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plat/cpm/descr b/plat/cpm/descr index 58fef69d5..2dea09e10 100644 --- a/plat/cpm/descr +++ b/plat/cpm/descr @@ -3,19 +3,19 @@ # $Revision$ var w=2 -var wa=1 +var wa=2 var p=2 -var pa=1 +var pa=2 var s=2 -var sa=1 +var sa=2 var l=4 -var la=1 +var la=2 var f=4 -var fa=1 +var fa=2 var d=8 -var da=1 +var da=2 var x=8 -var xa=1 +var xa=2 var ARCH=i80 var PLATFORM=cpm var PLATFORMDIR={EM}/share/ack/{PLATFORM} From d0967e683b286e01fce486ddfb53d6013ed67c03 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Jun 2019 23:54:23 +0200 Subject: [PATCH 03/13] Extend the CP/M libsys with a full set of (hopefully correct) 2.2 BDOS calls. --- plat/cpm/boot.s | 47 +++++++++-- plat/cpm/include/cpm.h | 168 ++++++++++++++++++++++++-------------- plat/cpm/libsys/_bdos.s | 62 ++++---------- plat/cpm/libsys/_trap.s | 24 ++---- plat/cpm/libsys/brk.c | 13 +-- plat/cpm/libsys/build.lua | 63 +++++++++++++- plat/cpm/libsys/read.c | 8 +- plat/cpm/libsys/write.c | 19 +---- 8 files changed, 240 insertions(+), 164 deletions(-) diff --git a/plat/cpm/boot.s b/plat/cpm/boot.s index 40ab0d775..a1e99ed00 100644 --- a/plat/cpm/boot.s +++ b/plat/cpm/boot.s @@ -27,7 +27,7 @@ begtext: mov c, a ! c = high byte of BDOS address mov a, b ! a = high byte of _end cmp c - jnc __exit ! emergency exit if a >= c + rnc ! emergency exit if a >= c ! We have to clear the bss. (argify requires it.) @@ -46,6 +46,9 @@ begtext: ! Set up the stack (now it's been cleared, since it's in the BSS). + lxi h, 0 + dad sp + shld saved_sp ! save old stack pointer lxi sp, stack + STACKSIZE ! Initialise the rsts (if desired). @@ -54,8 +57,13 @@ begtext: call .rst_init #endif + ! Now the 'heap'. + + lxi h, __end + shld _cpm_ram + ! C-ify the command line at 0x0080. - + lxi h, 0x0080 mov a, m ! a = length of command line cpi 0x7F ! 127-byte command lines... @@ -119,16 +127,39 @@ end_of_argify: lhld argc ! slightly evil mvi h, 0 push h - call __m_a_i_n - ! FALLTHROUGH + push h ! return address is 0 + jmp __m_a_i_n + +.define _cpm_fastexit +_cpm_fastexit: +saved_sp = _cpm_fastexit + 1 + lxi sp, 0 ! patched on startup + ret ! Emergency exit routine. -.define EXIT, __exit -EXIT: -__exit: - rst 0 +.define EXIT, __exit, _cpm_exit +EXIT = 0 +__exit = 0 +_cpm_exit = 0 +! Special CP/M stuff. + +.define _cpm_fcb +_cpm_fcb = 0x005c + +.define _cpm_ram +.comm _cpm_ram, 2 +.define _cpm_ramtop +_cpm_ramtop = 0x0001 + +.define _cpm_default_dma +_cpm_default_dma = 0x0080 + +.define _cpm_cmdlinelen, _cpm_cmdline +_cpm_cmdlinelen = 0x0080 +_cpm_cmdline = 0x0081 + ! Define symbols at the beginning of our various segments, so that we can find ! them. (Except .text, which has already been done.) diff --git a/plat/cpm/include/cpm.h b/plat/cpm/include/cpm.h index bdda5ed23..9a354eb03 100644 --- a/plat/cpm/include/cpm.h +++ b/plat/cpm/include/cpm.h @@ -1,66 +1,114 @@ -/* - * unistd.h - standard system calls - */ -/* $Id$ */ - -#ifndef _CPM_H -#define _CPM_H +#ifndef CPM_H +#define CPM_H #include -/* These interface provides a very bare-bones interface to the CP/M BDOS. Set - * the following four variables as you wish, call cpm_bdos(), and the contents - * of the variables will have been updated accordingly. */ - -extern uint8_t cpm_a_register; -extern uint16_t cpm_bc_register; -extern uint16_t cpm_de_register; -extern uint16_t cpm_hl_register; - -extern void cpm_bdos(void); - -/* Describes the available CP/M BDOS calls. They're a fairly conservative set - * taken from the CP/M 2.0 manual. */ - -enum +typedef struct { - CPM_BDOS_SYSTEM_RESET, - CPM_BDOS_CONSOLE_INPUT, - CPM_BDOS_CONSOLE_OUTPUT, - CPM_BDOS_READER_INPUT, - CPM_BDOS_PUNCH_OUTPUT, - CPM_BDOS_LIST_OUTPUT, - CPM_BDOS_CONSOLE_IO, - CPM_BDOS_GET_IO_BYTE, - CPM_BDOS_SET_IO_BYTE, - CPM_BDOS_PRINT_STRING, - CPM_BDOS_READ_CONSOLE_BUFFER, - CPM_BDOS_GET_CONSOLE_STATUS, - CPM_BDOS_GET_VERSION_NUMBER, - CPM_BDOS_RESET_DISK_SYSTEM, - CPM_BDOS_SELECT_DISK, - CPM_BDOS_OPEN_FILE, - CPM_BDOS_CLOSE_FILE, - CPM_BDOS_SEARCHFIRST, - CPM_BDOS_SEARCHNEXT, - CPM_BDOS_DELETE_FILE, - CPM_BDOS_READ_SEQ, - CPM_BDOS_WRITE_SEQ, - CPM_BDOS_MAKE_FILE, - CPM_BDOS_RENAME_FILE, - CPM_BDOS_GET_LOGIN_VECTOR, - CPM_BDOS_GET_CURRENT_DISK, - CPM_BDOS_SET_DMA_ADDRESS, - CPM_BDOS_GET_ALLOC_VECTOR, - CPM_BDOS_WRITE_PROTECT, - CPM_BDOS_GET_RO_VECTOR, - CPM_BDOS_SET_FILE_ATTR, - CPM_BDOS_GET_DISK_PARMS, - CPM_BDOS_SETGET_USER, - CPM_BDOS_READ_RANDOM, - CPM_BDOS_WRITE_RANDOM, - CPM_BDOS_GET_FILE_SIZE, - CPM_BDOS_SET_RANDOM -}; + uint8_t dr; + uint8_t f[11]; + uint8_t ex; + uint8_t s1; + uint8_t s2; + uint8_t rc; + uint8_t d[16]; + uint8_t cr; + uint16_t r; + uint8_t r2; +} +FCB; + +typedef struct +{ + uint8_t dr; + uint8_t src[11]; + uint8_t _padding[5]; + uint8_t dest[11]; +} +RCB; + +typedef struct +{ + uint8_t us; + uint8_t f[11]; + uint8_t ex; + uint8_t s[2]; + uint8_t rc; + union + { + uint8_t al8[16]; + uint16_t al16[8]; + } + al; +} +DIRE; + +typedef struct +{ + uint16_t spt; /* number of 128-byte sectors per track */ + uint8_t bsh; /* block shift; 3=1kB, 4=2kB, 5=4kB etc */ + uint8_t blm; /* block mask; 0x07=1kB, 0x0f=2kB, 0x1f=4k etc */ + uint8_t exm; /* extent mask */ + uint16_t dsm; /* maximum block number */ + uint16_t drm; /* maximum directory entry number */ + uint16_t al; /* directory allocation bitmap */ + uint16_t cks; /* checksum vector size */ + uint16_t off; /* number of reserved tracks */ +} +DPB; + +extern FCB cpm_fcb; /* primary FCB */ +extern FCB cpm_fcb2; /* secondary FCB (special purpose) */ +extern uint8_t cpm_iobyte; + +extern uint8_t cpm_default_dma[128]; /* also contains the parsed command line */ +extern uint8_t* cpm_ram; +extern uint8_t* cpm_ramtop; +extern uint8_t cpm_cmdlinelen; +extern char cpm_cmdline[0x7f]; + +/* Special: longjmps out of the program. Don't use if you've overwritten the + * CCP. */ +extern void cpm_fastexit(void); + +/* 0 */ extern void cpm_exit(void); +/* 1 */ extern uint8_t cpm_conin(void); +/* 2 */ extern void cpm_conout(uint8_t b); +/* 3 */ extern uint8_t cpm_auxin(void); +/* 4 */ extern void cpm_auxout(uint8_t b); +/* 5 */ extern void cpm_lstout(uint8_t b); +/* 6 */ extern uint8_t cpm_conio(uint8_t b); +/* 7 */ extern uint8_t cpm_get_iobyte(void); +/* 8 */ extern void cpm_set_iobyte(uint8_t iob); +/* 9 */ extern void cpm_printstring(const char* s); /* $-terminated */ +/* 10 */ extern uint8_t cpm_readline(uint8_t* buffer); +/* 11 */ extern uint8_t cpm_const(void); +/* 12 */ extern uint16_t cpm_get_version(void); +/* 13 */ extern void cpm_reset_disk_system(void); +/* 14 */ extern void cpm_select_disk(uint8_t disk); +/* 15 */ extern uint8_t cpm_open_file(FCB* fcb); +/* 16 */ extern uint8_t cpm_close_file(FCB* fcb); +/* 17 */ extern uint8_t cpm_findfirst(FCB* fcb); +/* 18 */ extern uint8_t cpm_findnext(FCB* fcb); +/* 19 */ extern uint8_t cpm_delete_file(FCB* fcb); +/* 20 */ extern uint8_t cpm_read_sequential(FCB* fcb); +/* 21 */ extern uint8_t cpm_write_sequential(FCB* fcb); +/* 22 */ extern uint8_t cpm_make_file(FCB* fcb); +/* 23 */ extern uint8_t cpm_rename_file(RCB* rcb); +/* 24 */ extern uint16_t cpm_get_login_vector(void); +/* 25 */ extern uint8_t cpm_get_current_drive(void); +/* 26 */ extern void cpm_set_dma(void* ptr); +/* 27 */ extern uint8_t* cpm_get_allocation_vector(void); +/* 28 */ extern void cpm_write_protect_drive(void); +/* 29 */ extern uint16_t cpm_get_readonly_vector(void); +/* 30 */ extern uint8_t cpm_set_file_attributes(FCB* fcb); +/* 31 */ extern DPB* cpm_get_dpb(void); +/* 32 */ extern uint8_t cpm_get_set_user(uint8_t user); +/* 33 */ extern uint8_t cpm_read_random(FCB* fcb); +/* 34 */ extern uint8_t cpm_write_random(FCB* fcb); +/* 35 */ extern void cpm_seek_to_end(FCB* fcb); +/* 36 */ extern void cpm_seek_to_seq_pos(FCB* fcb); +/* 37 */ extern uint8_t cpm_reset_drives(uint16_t drive_bitmap); +/* 40 */ extern uint8_t cpm_write_random_filled(FCB* fcb); #endif diff --git a/plat/cpm/libsys/_bdos.s b/plat/cpm/libsys/_bdos.s index 4a05dfcdf..9e136925e 100644 --- a/plat/cpm/libsys/_bdos.s +++ b/plat/cpm/libsys/_bdos.s @@ -1,55 +1,21 @@ # -! $Source$ -! $State$ -! $Revision$ +#include "asm.h" -! Declare segments (the order is important). +! Calls a BDOS routine and returns the result. +! a = BDOS opcode -.sect .text -.sect .rom -.sect .data -.sect .bss +.define call_bdos +call_bdos: + pop h ! pop return address + pop d ! pop parameter (possibly junk) + push d + push h -.sect .text - -! Calls a BDOS routine. - -.define _cpm_bdos -_cpm_bdos: - push b + push b ! save FP as the BDOS will corrupt it + mov c, a ! move opcode to C + call 0x0005 + pop b ! restore FP - lda _cpm_a_register - - lhld _cpm_bc_register - mov b, h - mov c, l - - lhld _cpm_de_register mov d, h mov e, l - - lhld _cpm_hl_register - - call 5 - - shld _cpm_hl_register - - mov h, d - mov l, e - shld _cpm_de_register - - mov h, b - mov l, c - shld _cpm_bc_register - - sta _cpm_a_register - - pop b - ret - -.sect .bss -.define _cpm_a_register, _cpm_bc_register, _cpm_de_register, _cpm_hl_register -.comm _cpm_a_register, 1 -.comm _cpm_bc_register, 2 -.comm _cpm_de_register, 2 -.comm _cpm_hl_register, 2 + ret \ No newline at end of file diff --git a/plat/cpm/libsys/_trap.s b/plat/cpm/libsys/_trap.s index a3836c998..678b9cc7f 100644 --- a/plat/cpm/libsys/_trap.s +++ b/plat/cpm/libsys/_trap.s @@ -3,12 +3,8 @@ ! $State$ ! $Revision$ -! Declare segments (the order is important). - -.sect .text -.sect .rom -.sect .data -.sect .bss +# +#include "asm.h" .define .trp .define earray, erange, eset, eiovfl, efovfl, efunfl, eidivz, eidivz @@ -16,8 +12,6 @@ .define ecase, ememflt, ebadptr, ebadpc, ebadlae, ebadmon, ebadlin, ebadgto .define eunimpl -.sect .text - ! Trap routine ! Expects trap number on stack. ! Just returns if trap has to be ignored. @@ -206,15 +200,11 @@ eunimpl:lxi h,EUNIMPL pop d ret 1: - lxi h, 6 - push h - lxi h, text - push h - lxi h, 1 - push h - call _write - jmp EXIT + lxi d, text + mvi c, 9 ! write $-terminated string + call 0x0005 + rst 0 ! abend .sect .rom -text: .ascii "TRAP!\n" +text: .ascii "TRAP!\r\n$" diff --git a/plat/cpm/libsys/brk.c b/plat/cpm/libsys/brk.c index 6c139dd2a..e9f13c1e6 100644 --- a/plat/cpm/libsys/brk.c +++ b/plat/cpm/libsys/brk.c @@ -1,8 +1,4 @@ -/* $Source$ - * $State$ - * $Revision$ - */ - +#include #include #include #include @@ -11,7 +7,6 @@ #define STACK_BUFFER 128 /* number of bytes to leave for stack */ extern char _end[1]; -static char* current = _end; int brk(void* newend) { @@ -24,7 +19,7 @@ int brk(void* newend) (p < _end)) return -1; - current = p; + cpm_ram = p; return 0; } @@ -34,9 +29,9 @@ void* sbrk(int increment) char* new; if (increment == 0) - return current; + return cpm_ram; - old = current; + old = cpm_ram; new = old + increment; if ((increment > 0) && (new <= old)) diff --git a/plat/cpm/libsys/build.lua b/plat/cpm/libsys/build.lua index c2a75a4c3..780dea626 100644 --- a/plat/cpm/libsys/build.lua +++ b/plat/cpm/libsys/build.lua @@ -1,12 +1,73 @@ +acklibrary { + name = "internal", + hdrs = { "./*.h" } +} + +local bdos_calls = { + [ 0] = "cpm_exit", + [ 1] = "cpm_conin", + [ 2] = "cpm_conout", + [ 3] = "cpm_auxin", + [ 4] = "cpm_auxout", + [ 5] = "cpm_lstout", + [ 6] = "cpm_conio", + [ 7] = "cpm_get_iobyte", + [ 8] = "cpm_set_iobyte", + [ 9] = "cpm_printstring", + [10] = "cpm_readline", + [11] = "cpm_const", + [12] = "cpm_get_version", + [13] = "cpm_reset_disk_system", + [14] = "cpm_select_disk", + [15] = "cpm_open_file", + [16] = "cpm_close_file", + [17] = "cpm_findfirst", + [18] = "cpm_findnext", + [19] = "cpm_delete_file", + [20] = "cpm_read_sequential", + [21] = "cpm_write_sequential", + [22] = "cpm_make_file", + [23] = "cpm_rename_file", + [24] = "cpm_get_login_vector", + [25] = "cpm_get_current_drive", + [26] = "cpm_set_dma", + [27] = "cpm_get_allocation_vector", + [28] = "cpm_write_protect_drive", + [29] = "cpm_get_readonly_vector", + [30] = "cpm_set_file_attributes", + [31] = "cpm_get_dpb", + [32] = "cpm_get_set_user", + [33] = "cpm_read_random", + [34] = "cpm_write_random", + [35] = "cpm_seek_to_end", + [36] = "cpm_seek_to_seq_pos", + [37] = "cpm_reset_drives", + [40] = "cpm_write_random_filled", +} + +local generated = {} +for n, name in pairs(bdos_calls) do + generated[#generated+1] = normalrule { + name = name, + ins = { "./make_bdos_call.sh" }, + outleaves = { name..".s" }, + commands = { + "%{ins[1]} "..n.." "..name.." > %{outs}" + } + } +end + acklibrary { name = "lib", srcs = { "./*.c", "./*.s", + generated }, deps = { "lang/cem/libcc.ansi/headers+headers", - "plat/cpm/include+headers", + "plat/cpm/include+headers", + "+internal", }, vars = { plat = "cpm" diff --git a/plat/cpm/libsys/read.c b/plat/cpm/libsys/read.c index df4a3ef3b..b04a13ee5 100644 --- a/plat/cpm/libsys/read.c +++ b/plat/cpm/libsys/read.c @@ -36,18 +36,14 @@ ssize_t read(int fd, void* buffer, size_t count) /* Read one line from the console. */ ((unsigned char*)buffer)[-2] = before_n; - cpm_bc_register = CPM_BDOS_READ_CONSOLE_BUFFER; - cpm_de_register = (uint16_t)(char*)buffer - 2; - cpm_bdos(); + cpm_readline((uint8_t*)buffer - 2); before_n = ((unsigned char*)buffer)[-1]; ((char*)buffer)[before_n] = '\n'; /* Append '\n'. */ ((short*)buffer)[-1] = save; /* Give back borrowed bytes. */ /* Echo '\n' to console. */ - cpm_bc_register = CPM_BDOS_PRINT_STRING; - cpm_de_register = (uint16_t)"\r\n$"; - cpm_bdos(); + cpm_printstring("\r\n$"); return (int)before_n + 1; } diff --git a/plat/cpm/libsys/write.c b/plat/cpm/libsys/write.c index 21dbc90c0..768e9b2eb 100644 --- a/plat/cpm/libsys/write.c +++ b/plat/cpm/libsys/write.c @@ -10,16 +10,9 @@ void _sys_write_tty(char c) { - cpm_bc_register = CPM_BDOS_CONSOLE_OUTPUT; - cpm_de_register = c; - cpm_bdos(); - + cpm_conout(c); if (c == '\n') - { - cpm_bc_register = CPM_BDOS_CONSOLE_OUTPUT; - cpm_de_register = '\r'; - cpm_bdos(); - } + cpm_conout(c); } ssize_t write(int fd, void* buffer, size_t count) @@ -37,13 +30,9 @@ ssize_t write(int fd, void* buffer, size_t count) /* Write all data. */ - i = 0; - while (i < count) - { + i = count; + while (i--) _sys_write_tty(*p++); - - i++; - } /* No failures. */ From ec2ea1feffa85f1138e5b091fcea164dbfbf7979 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Jun 2019 23:57:43 +0200 Subject: [PATCH 04/13] Add missing file. --- plat/cpm/libsys/make_bdos_call.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 plat/cpm/libsys/make_bdos_call.sh diff --git a/plat/cpm/libsys/make_bdos_call.sh b/plat/cpm/libsys/make_bdos_call.sh new file mode 100755 index 000000000..949523007 --- /dev/null +++ b/plat/cpm/libsys/make_bdos_call.sh @@ -0,0 +1,10 @@ +#!/bin/sh +cat < Date: Tue, 11 Jun 2019 00:12:00 +0200 Subject: [PATCH 05/13] Generate traps procedurally. For some reason they always keep getting pulled in, though... --- plat/cpm/libsys/_trap.s | 124 ++--------------------------------- plat/cpm/libsys/build.lua | 37 +++++++++++ plat/cpm/libsys/make_trap.sh | 12 ++++ 3 files changed, 53 insertions(+), 120 deletions(-) create mode 100755 plat/cpm/libsys/make_trap.sh diff --git a/plat/cpm/libsys/_trap.s b/plat/cpm/libsys/_trap.s index 678b9cc7f..ec6208a72 100644 --- a/plat/cpm/libsys/_trap.s +++ b/plat/cpm/libsys/_trap.s @@ -11,6 +11,10 @@ .define efdivz, eiund, efund, econv, estack, eheap, eillins, eoddz .define ecase, ememflt, ebadptr, ebadpc, ebadlae, ebadmon, ebadlin, ebadgto .define eunimpl +.define EARRAY, ERANGE, ESET, EIOVFL, EFOVFL, EFUNFL, EIDIVZ, EIDIVZ +.define EFDIVZ, EIUND, EFUND, ECONV, ESTACK, EHEAP, EILLINS, EODDZ +.define ECASE, EMEMFLT, EBADPTR, EBADPC, EBADLAE, EBADMON, EBADLIN, EBADGTO +.define EUNIMPL ! Trap routine ! Expects trap number on stack. @@ -45,126 +49,6 @@ EBADGTO = 27 EUNIMPL = 63 ! unimplemented em-instruction called -earray: lxi h,EARRAY - push h - call .trp - ret - -erange: lxi h,ERANGE - push h - call .trp - ret - -eset: lxi h,ESET - push h - call .trp - ret - -eiovfl: lxi h,EIOVFL - push h - call .trp - ret - -efovfl: lxi h,EFOVFL - push h - call .trp - ret - -efunfl: lxi h,EFUNFL - push h - call .trp - ret - -eidivz: lxi h,EIDIVZ - push h - call .trp - ret - -efdivz: lxi h,EFDIVZ - push h - call .trp - ret - -eiund: lxi h,EIUND - push h - call .trp - ret - -efund: lxi h,EFUND - push h - call .trp - ret - -econv: lxi h,ECONV - push h - call .trp - ret - -estack: lxi h,ESTACK - push h - call .trp - ret - -eheap: lxi h,EHEAP - push h - call .trp - ret - -eillins:lxi h,EILLINS - push h - call .trp - ret - -eoddz: lxi h,EODDZ - push h - call .trp - ret - -ecase: lxi h,ECASE - push h - call .trp - ret - -ememflt:lxi h,EMEMFLT - push h - call .trp - ret - -ebadptr:lxi h,EBADPTR - push h - call .trp - ret - -ebadpc: lxi h,EBADPC - push h - call .trp - ret - -ebadlae:lxi h,EBADLAE - push h - call .trp - ret - -ebadmon:lxi h,EBADMON - push h - call .trp - ret - -ebadlin:lxi h,EBADLIN - push h - call .trp - ret - -ebadgto:lxi h,EBADGTO - push h - call .trp - ret - -eunimpl:lxi h,EUNIMPL - push h - call .trp - ret - .trp: pop h xthl diff --git a/plat/cpm/libsys/build.lua b/plat/cpm/libsys/build.lua index 780dea626..f9cd9a96e 100644 --- a/plat/cpm/libsys/build.lua +++ b/plat/cpm/libsys/build.lua @@ -45,6 +45,33 @@ local bdos_calls = { [40] = "cpm_write_random_filled", } +local trap_calls = { + "EARRAY", + "ERANGE", + "ESET", + "EIOVFL", + "EFOVFL", + "EFUNFL", + "EIDIVZ", + "EFDIVZ", + "EIUND", + "EFUND", + "ECONV", + "ESTACK", + "EHEAP", + "EILLINS", + "EODDZ", + "ECASE", + "EMEMFLT", + "EBADPTR", + "EBADPC", + "EBADLAE", + "EBADMON", + "EBADLIN", + "EBADGTO", + "EUNIMPL", +} + local generated = {} for n, name in pairs(bdos_calls) do generated[#generated+1] = normalrule { @@ -56,6 +83,16 @@ for n, name in pairs(bdos_calls) do } } end +for _, name in pairs(trap_calls) do + generated[#generated+1] = normalrule { + name = name, + ins = { "./make_trap.sh" }, + outleaves = { name..".s" }, + commands = { + "%{ins[1]} "..name:lower().." "..name.." > %{outs}" + } + } +end acklibrary { name = "lib", diff --git a/plat/cpm/libsys/make_trap.sh b/plat/cpm/libsys/make_trap.sh new file mode 100755 index 000000000..25562fa2a --- /dev/null +++ b/plat/cpm/libsys/make_trap.sh @@ -0,0 +1,12 @@ +#!/bin/sh +cat < Date: Tue, 11 Jun 2019 00:12:10 +0200 Subject: [PATCH 06/13] Allow building one plat at a time. --- build.lua | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/build.lua b/build.lua index d7eb0829f..ccd113f1a 100644 --- a/build.lua +++ b/build.lua @@ -27,17 +27,8 @@ vars.plats_with_tests = { "pc86", } -local plat_packages = {} -local test_packages = {} -for _, p in ipairs(vars.plats) do - plat_packages[#plat_packages+1] = "plat/"..p.."+pkg" -end -for _, p in ipairs(vars.plats_with_tests) do - test_packages[#test_packages+1] = "plat/"..p.."/tests+tests" -end - installable { - name = "ack", + name = "ack-common", map = { "lang/basic/src+pkg", "lang/cem/cemcom.ansi+pkg", @@ -53,6 +44,31 @@ installable { "util/led+pkg", "util/misc+pkg", "util/opt+pkg", + }, +} + +local plat_packages = {} +local test_packages = {} +for _, p in ipairs(vars.plats) do + local pkg = "plat/"..p.."+pkg" + plat_packages[#plat_packages+1] = pkg + + installable { + name = "ack-"..p, + map = { + "+ack-common", + pkg, + }, + } +end +for _, p in ipairs(vars.plats_with_tests) do + test_packages[#test_packages+1] = "plat/"..p.."/tests+tests" +end + +installable { + name = "ack", + map = { + "+ack-common", "examples+pkg", plat_packages }, From f58d7e7d3090a8480ead93a53424b20102814c8e Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Jun 2019 19:40:46 +0200 Subject: [PATCH 07/13] Add missing file. --- plat/cpm/libsys/asm.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 plat/cpm/libsys/asm.h diff --git a/plat/cpm/libsys/asm.h b/plat/cpm/libsys/asm.h new file mode 100644 index 000000000..f86b91104 --- /dev/null +++ b/plat/cpm/libsys/asm.h @@ -0,0 +1,13 @@ +#ifndef ASM_H +#define ASM_H + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +#endif From 4e90de00e946a60fb9f0c133878dda5378ce2867 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Jun 2019 19:47:42 +0200 Subject: [PATCH 08/13] Don't pull in all the trap handlers every time. --- plat/cpm/libsys/_trap.s | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plat/cpm/libsys/_trap.s b/plat/cpm/libsys/_trap.s index ec6208a72..bb541932f 100644 --- a/plat/cpm/libsys/_trap.s +++ b/plat/cpm/libsys/_trap.s @@ -7,10 +7,6 @@ #include "asm.h" .define .trp -.define earray, erange, eset, eiovfl, efovfl, efunfl, eidivz, eidivz -.define efdivz, eiund, efund, econv, estack, eheap, eillins, eoddz -.define ecase, ememflt, ebadptr, ebadpc, ebadlae, ebadmon, ebadlin, ebadgto -.define eunimpl .define EARRAY, ERANGE, ESET, EIOVFL, EFOVFL, EFUNFL, EIDIVZ, EIDIVZ .define EFDIVZ, EIUND, EFUND, ECONV, ESTACK, EHEAP, EILLINS, EODDZ .define ECASE, EMEMFLT, EBADPTR, EBADPC, EBADLAE, EBADMON, EBADLIN, EBADGTO From 3feb79ad0c7bfbe484859f94d276e3b3474b79ea Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Jun 2019 20:02:03 +0200 Subject: [PATCH 09/13] Simplify the .trp API to make it a bit smaller. --- mach/i80/ncg/table | 5 +++-- plat/cpm/boot.s | 6 ++---- plat/cpm/libsys/_trap.s | 12 ++++++------ plat/cpm/libsys/make_trap.sh | 6 ++---- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/mach/i80/ncg/table b/mach/i80/ncg/table index 74c85f89e..783500195 100644 --- a/mach/i80/ncg/table +++ b/mach/i80/ncg/table @@ -2475,5 +2475,6 @@ with hlreg gen shld {label,".reghp"} pat trp -kills ALL -gen Call {label,".trp"} + with areg + kills ALL + gen Call {label,".trp"} diff --git a/plat/cpm/boot.s b/plat/cpm/boot.s index a1e99ed00..64f85fd2a 100644 --- a/plat/cpm/boot.s +++ b/plat/cpm/boot.s @@ -170,8 +170,7 @@ _cpm_cmdline = 0x0081 ! Some magic data. All EM systems need these. -.define .trppc, .ignmask, _errno -.comm .trppc, 2 +.define .ignmask, _errno .comm .ignmask, 2 .comm _errno, 2 @@ -184,11 +183,10 @@ envp: .space 2 ! envp array (always empty, must be after argv) ! These are used specifically by the i80 code generator. -.define .trapproc, .retadr, .retadr1 +.define .retadr, .retadr1 .define .bcreg, .areg .define .tmp1, .fra, block1, block2, block3 -.comm .trapproc, 2 .comm .retadr, 2 ! used to save return address .comm .retadr1, 2 ! reserve .comm .bcreg, 2 diff --git a/plat/cpm/libsys/_trap.s b/plat/cpm/libsys/_trap.s index bb541932f..cd561fa65 100644 --- a/plat/cpm/libsys/_trap.s +++ b/plat/cpm/libsys/_trap.s @@ -13,7 +13,8 @@ .define EUNIMPL ! Trap routine -! Expects trap number on stack. +! Expects trap number in A, and must be called directly from the code +! where execution should resume (for those traps which support it). ! Just returns if trap has to be ignored. ! Otherwise it calls a user-defined trap handler if provided. ! When no user-defined trap handler is provided or when the user-defined @@ -46,9 +47,6 @@ EUNIMPL = 63 ! unimplemented em-instruction called .trp: - pop h - xthl - push h ! trap number and return address exchanged mov a,l cpi 16 jnc 3f ! jump if trap cannot be ignored @@ -66,10 +64,12 @@ ret ! OGEN DICHT EN ... SPRING!!! 3: - lhld .trapproc ! user defined trap handler? +.define .trapproc +.trapproc = . + 1 + lxi h, 0 ! user defined trap handler held inline here mov a,l ora h - jz 1f ! jump if there was not + jz 1f ! jump if there was not xra a sta .trapproc ! .trapproc := 0 sta .trapproc+1 diff --git a/plat/cpm/libsys/make_trap.sh b/plat/cpm/libsys/make_trap.sh index 25562fa2a..1c09388ae 100755 --- a/plat/cpm/libsys/make_trap.sh +++ b/plat/cpm/libsys/make_trap.sh @@ -4,9 +4,7 @@ cat < Date: Tue, 11 Jun 2019 20:32:00 +0200 Subject: [PATCH 10/13] Miscellaneous byte shaving; you can now choose whether or not you want the CCP overwritten or not, and cpm_exit() does the right thing. --- plat/cpm/boot.s | 44 ++++++++++++++++------------- plat/cpm/include/cpm.h | 11 +++++--- plat/cpm/libsys/brk.c | 17 +++++------ plat/cpm/libsys/cpm_overwrite_ccp.s | 12 ++++++++ 4 files changed, 51 insertions(+), 33 deletions(-) create mode 100644 plat/cpm/libsys/cpm_overwrite_ccp.s diff --git a/plat/cpm/boot.s b/plat/cpm/boot.s index 64f85fd2a..1330e8309 100644 --- a/plat/cpm/boot.s +++ b/plat/cpm/boot.s @@ -22,12 +22,13 @@ begtext: ! BDOS and crash CP/M. We cheat by comparing only high bytes ! of each address. - lxi b, __end lda 0x0007 - mov c, a ! c = high byte of BDOS address - mov a, b ! a = high byte of _end + mov c, a ! c = high byte of BDOS address + lda _cpm_ram+1 ! a = high byte of top of BSS, a.k.a. _end cmp c - rnc ! emergency exit if a >= c + lxi d, noroom + mvi c, 9 + jnc 0x0005 ! print error and exit if a >= c ! We have to clear the bss. (argify requires it.) @@ -59,8 +60,10 @@ begtext: ! Now the 'heap'. - lxi h, __end - shld _cpm_ram + lhld 0x0006 ! BDOS entry point + lxi d, -0x806 ! offset to start of CCP + dad d + shld _cpm_ramtop ! C-ify the command line at 0x0080. @@ -127,31 +130,29 @@ end_of_argify: lhld argc ! slightly evil mvi h, 0 push h - push h ! return address is 0 - jmp __m_a_i_n - -.define _cpm_fastexit -_cpm_fastexit: -saved_sp = _cpm_fastexit + 1 + call __m_a_i_n +.define _cpm_exit, EXIT, __exit +_cpm_exit: +EXIT: +__exit: + stc ! set carry bit + jnc _cpm_warmboot ! warm boot if not set +saved_sp = . + 1 lxi sp, 0 ! patched on startup ret ! Emergency exit routine. -.define EXIT, __exit, _cpm_exit -EXIT = 0 -__exit = 0 -_cpm_exit = 0 +.define _cpm_warmboot +_cpm_warmboot = 0 ! Special CP/M stuff. .define _cpm_fcb _cpm_fcb = 0x005c -.define _cpm_ram -.comm _cpm_ram, 2 .define _cpm_ramtop -_cpm_ramtop = 0x0001 +.comm _cpm_ramtop, 2 .define _cpm_default_dma _cpm_default_dma = 0x0080 @@ -197,5 +198,10 @@ block1: .space 4 ! used by 32 bits divide and block2: .space 4 ! multiply routines block3: .space 4 ! must be contiguous (.comm doesn't guarantee this) +.sect .data +.define _cpm_ram +_cpm_ram: .data2 __end + .sect .rom progname: .asciz 'ACKCPM' +noroom: .ascii 'No room$' diff --git a/plat/cpm/include/cpm.h b/plat/cpm/include/cpm.h index 9a354eb03..81dfa5dab 100644 --- a/plat/cpm/include/cpm.h +++ b/plat/cpm/include/cpm.h @@ -67,11 +67,14 @@ extern uint8_t* cpm_ramtop; extern uint8_t cpm_cmdlinelen; extern char cpm_cmdline[0x7f]; -/* Special: longjmps out of the program. Don't use if you've overwritten the - * CCP. */ -extern void cpm_fastexit(void); +/* Special: if the CCP hasn't been overwritten, returns to it; otherwise does + * a warmboot. */ +extern void cpm_exit(void); -/* 0 */ extern void cpm_exit(void); +/* Extends cpm_ramtop over the CCP, for a little extra space. */ +extern void cpm_overwrite_ccp(void); + +/* 0 */ extern void cpm_warmboot(void); /* 1 */ extern uint8_t cpm_conin(void); /* 2 */ extern void cpm_conout(uint8_t b); /* 3 */ extern uint8_t cpm_auxin(void); diff --git a/plat/cpm/libsys/brk.c b/plat/cpm/libsys/brk.c index e9f13c1e6..5debaa5ff 100644 --- a/plat/cpm/libsys/brk.c +++ b/plat/cpm/libsys/brk.c @@ -1,32 +1,29 @@ #include +#include #include #include #include #define OUT_OF_MEMORY (void*)(-1) /* sbrk returns this on failure */ -#define STACK_BUFFER 128 /* number of bytes to leave for stack */ -extern char _end[1]; +extern uint8_t _end[1]; int brk(void* newend) { - /* We determine the amount of free memory by looking at the address of the - * BDOS vector at 0x0006. */ - char* memtop = (char*) ((*(unsigned char*)0x0007)<<8); - char* p = newend; + uint8_t* p = newend; - if ((p >= memtop) || + if ((p >= cpm_ramtop) || (p < _end)) return -1; - cpm_ram = p; + cpm_ram = (uint8_t*)p; return 0; } void* sbrk(int increment) { - char* old; - char* new; + uint8_t* old; + uint8_t* new; if (increment == 0) return cpm_ram; diff --git a/plat/cpm/libsys/cpm_overwrite_ccp.s b/plat/cpm/libsys/cpm_overwrite_ccp.s new file mode 100644 index 000000000..78083b770 --- /dev/null +++ b/plat/cpm/libsys/cpm_overwrite_ccp.s @@ -0,0 +1,12 @@ +# +#include "asm.h" + +.define _cpm_overwrite_ccp +_cpm_overwrite_ccp: + mvi a, 0xaf ! 0xaf = xor a = clear carry bit + sta _cpm_exit + lhld _cpm_ramtop + lxi d, 0x800 + dad d + shld _cpm_ramtop + ret From 3fe9a05adc223a4aaabf7e68a92ce9c5fbe7ece2 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Jun 2019 21:33:23 +0200 Subject: [PATCH 11/13] Ignore .vscode directory. --- .hgignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgignore b/.hgignore index 231210b94..de1136d12 100644 --- a/.hgignore +++ b/.hgignore @@ -1,3 +1,5 @@ .obj .sass-cache _site +.vscode + From 0607529df280c3440eb0245fefb88891d8dda950 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Jun 2019 21:33:57 +0200 Subject: [PATCH 12/13] Miscellaneous bugfixed and renamings. --- plat/cpm/boot.s | 6 +++++- plat/cpm/include/cpm.h | 2 +- plat/cpm/libsys/_bdos.s | 3 +-- plat/cpm/libsys/build.lua | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/plat/cpm/boot.s b/plat/cpm/boot.s index 1330e8309..4b33dbfab 100644 --- a/plat/cpm/boot.s +++ b/plat/cpm/boot.s @@ -148,8 +148,9 @@ _cpm_warmboot = 0 ! Special CP/M stuff. -.define _cpm_fcb +.define _cpm_fcb, _cpm_fcb2 _cpm_fcb = 0x005c +_cpm_fcb2 = 0x006c .define _cpm_ramtop .comm _cpm_ramtop, 2 @@ -157,6 +158,9 @@ _cpm_fcb = 0x005c .define _cpm_default_dma _cpm_default_dma = 0x0080 +.define _cpm_iobyte +_cpm_iobyte = 3 + .define _cpm_cmdlinelen, _cpm_cmdline _cpm_cmdlinelen = 0x0080 _cpm_cmdline = 0x0081 diff --git a/plat/cpm/include/cpm.h b/plat/cpm/include/cpm.h index 81dfa5dab..197ef3b10 100644 --- a/plat/cpm/include/cpm.h +++ b/plat/cpm/include/cpm.h @@ -88,7 +88,7 @@ extern void cpm_overwrite_ccp(void); /* 11 */ extern uint8_t cpm_const(void); /* 12 */ extern uint16_t cpm_get_version(void); /* 13 */ extern void cpm_reset_disk_system(void); -/* 14 */ extern void cpm_select_disk(uint8_t disk); +/* 14 */ extern void cpm_select_drive(uint8_t disk); /* 15 */ extern uint8_t cpm_open_file(FCB* fcb); /* 16 */ extern uint8_t cpm_close_file(FCB* fcb); /* 17 */ extern uint8_t cpm_findfirst(FCB* fcb); diff --git a/plat/cpm/libsys/_bdos.s b/plat/cpm/libsys/_bdos.s index 9e136925e..fd6b53de5 100644 --- a/plat/cpm/libsys/_bdos.s +++ b/plat/cpm/libsys/_bdos.s @@ -16,6 +16,5 @@ call_bdos: call 0x0005 pop b ! restore FP - mov d, h - mov e, l + xchg ! DE = HL ret \ No newline at end of file diff --git a/plat/cpm/libsys/build.lua b/plat/cpm/libsys/build.lua index f9cd9a96e..9091a6917 100644 --- a/plat/cpm/libsys/build.lua +++ b/plat/cpm/libsys/build.lua @@ -18,7 +18,7 @@ local bdos_calls = { [11] = "cpm_const", [12] = "cpm_get_version", [13] = "cpm_reset_disk_system", - [14] = "cpm_select_disk", + [14] = "cpm_select_drive", [15] = "cpm_open_file", [16] = "cpm_close_file", [17] = "cpm_findfirst", From 784fc67596efa91badc62c2b083698fb22bf7916 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 11 Jun 2019 22:33:25 +0200 Subject: [PATCH 13/13] Alignment issues mean we can't access 16-bit CP/M structure elements directly. --- plat/cpm/include/cpm.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plat/cpm/include/cpm.h b/plat/cpm/include/cpm.h index 197ef3b10..3ea9f6e09 100644 --- a/plat/cpm/include/cpm.h +++ b/plat/cpm/include/cpm.h @@ -3,6 +3,9 @@ #include +/* EM requires 2-byte alignment, even on the i80, so we can't declare these + * structures to contain uint16_ts. Use U16() to access them. */ + typedef struct { uint8_t dr; @@ -13,8 +16,7 @@ typedef struct uint8_t rc; uint8_t d[16]; uint8_t cr; - uint16_t r; - uint8_t r2; + uint8_t r[3]; } FCB; @@ -34,29 +36,27 @@ typedef struct uint8_t ex; uint8_t s[2]; uint8_t rc; - union - { - uint8_t al8[16]; - uint16_t al16[8]; - } - al; + uint8_t al[16]; } DIRE; typedef struct { - uint16_t spt; /* number of 128-byte sectors per track */ + uint8_t spt[2]; /* number of 128-byte sectors per track */ uint8_t bsh; /* block shift; 3=1kB, 4=2kB, 5=4kB etc */ uint8_t blm; /* block mask; 0x07=1kB, 0x0f=2kB, 0x1f=4k etc */ uint8_t exm; /* extent mask */ - uint16_t dsm; /* maximum block number */ - uint16_t drm; /* maximum directory entry number */ - uint16_t al; /* directory allocation bitmap */ - uint16_t cks; /* checksum vector size */ - uint16_t off; /* number of reserved tracks */ + uint8_t dsm[2]; /* maximum block number */ + uint8_t drm[2]; /* maximum directory entry number */ + uint8_t al[2]; /* directory allocation bitmap */ + uint8_t cks[2]; /* checksum vector size */ + uint8_t off[2]; /* number of reserved tracks */ } DPB; +/* Access an unaligned field (see above). */ +#define U16(ptr) (*(uint16_t*)(ptr)) + extern FCB cpm_fcb; /* primary FCB */ extern FCB cpm_fcb2; /* secondary FCB (special purpose) */ extern uint8_t cpm_iobyte;