Extend the CP/M libsys with a full set of (hopefully correct) 2.2 BDOS calls.
This commit is contained in:
parent
3f938d651b
commit
d0967e683b
|
@ -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,6 +57,11 @@ begtext:
|
|||
call .rst_init
|
||||
#endif
|
||||
|
||||
! Now the 'heap'.
|
||||
|
||||
lxi h, __end
|
||||
shld _cpm_ram
|
||||
|
||||
! C-ify the command line at 0x0080.
|
||||
|
||||
lxi h, 0x0080
|
||||
|
@ -119,15 +127,38 @@ 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.)
|
||||
|
|
|
@ -1,66 +1,114 @@
|
|||
/*
|
||||
* unistd.h - standard system calls
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef _CPM_H
|
||||
#define _CPM_H
|
||||
#ifndef CPM_H
|
||||
#define CPM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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
|
||||
push b ! save FP as the BDOS will corrupt it
|
||||
mov c, a ! move opcode to C
|
||||
call 0x0005
|
||||
pop b ! restore FP
|
||||
|
||||
! Calls a BDOS routine.
|
||||
|
||||
.define _cpm_bdos
|
||||
_cpm_bdos:
|
||||
push b
|
||||
|
||||
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
|
||||
|
|
|
@ -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$"
|
||||
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <cpm.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,14 +30,10 @@ 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. */
|
||||
|
||||
return count;
|
||||
|
|
Loading…
Reference in a new issue