Merge pull request #195 from davidgiven/dtrg-cpm
Various CP/M improvement
This commit is contained in:
		
						commit
						3d877ae3f8
					
				
					 17 changed files with 395 additions and 330 deletions
				
			
		| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
.obj
 | 
			
		||||
.sass-cache
 | 
			
		||||
_site
 | 
			
		||||
.vscode
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										36
									
								
								build.lua
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								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
 | 
			
		||||
	},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	jnc __exit		! 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.)
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +47,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 +58,15 @@ begtext:
 | 
			
		|||
		call .rst_init
 | 
			
		||||
	#endif
 | 
			
		||||
 | 
			
		||||
    ! Now the 'heap'.
 | 
			
		||||
 | 
			
		||||
	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.
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	lxi h, 0x0080
 | 
			
		||||
	mov a, m                 ! a = length of command line
 | 
			
		||||
	cpi 0x7F                 ! 127-byte command lines...
 | 
			
		||||
| 
						 | 
				
			
			@ -120,15 +131,40 @@ end_of_argify:
 | 
			
		|||
	mvi h, 0
 | 
			
		||||
	push h
 | 
			
		||||
	call __m_a_i_n
 | 
			
		||||
	! FALLTHROUGH
 | 
			
		||||
.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
 | 
			
		||||
EXIT:
 | 
			
		||||
__exit:
 | 
			
		||||
	rst 0
 | 
			
		||||
.define _cpm_warmboot
 | 
			
		||||
_cpm_warmboot = 0
 | 
			
		||||
	
 | 
			
		||||
! Special CP/M stuff.
 | 
			
		||||
 | 
			
		||||
.define _cpm_fcb, _cpm_fcb2
 | 
			
		||||
_cpm_fcb = 0x005c
 | 
			
		||||
_cpm_fcb2 = 0x006c
 | 
			
		||||
 | 
			
		||||
.define _cpm_ramtop
 | 
			
		||||
.comm _cpm_ramtop, 2
 | 
			
		||||
 | 
			
		||||
.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
 | 
			
		||||
 | 
			
		||||
! Define symbols at the beginning of our various segments, so that we can find
 | 
			
		||||
! them. (Except .text, which has already been done.)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,8 +175,7 @@ __exit:
 | 
			
		|||
 | 
			
		||||
! Some magic data. All EM systems need these.
 | 
			
		||||
 | 
			
		||||
.define .trppc, .ignmask, _errno
 | 
			
		||||
.comm .trppc, 2
 | 
			
		||||
.define .ignmask, _errno
 | 
			
		||||
.comm .ignmask, 2
 | 
			
		||||
.comm _errno, 2
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,11 +188,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
 | 
			
		||||
| 
						 | 
				
			
			@ -168,5 +202,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$'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,66 +1,117 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
/* 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. */
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    uint8_t r[3];
 | 
			
		||||
}
 | 
			
		||||
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;
 | 
			
		||||
    uint8_t al[16];
 | 
			
		||||
}
 | 
			
		||||
DIRE;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    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 */
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
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: if the CCP hasn't been overwritten, returns to it; otherwise does
 | 
			
		||||
 * a warmboot. */
 | 
			
		||||
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);
 | 
			
		||||
/*  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_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);
 | 
			
		||||
/* 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,20 @@
 | 
			
		|||
#
 | 
			
		||||
! $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
 | 
			
		||||
	xchg           ! DE = HL
 | 
			
		||||
	ret
 | 
			
		||||
| 
						 | 
				
			
			@ -3,23 +3,18 @@
 | 
			
		|||
! $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
 | 
			
		||||
.define efdivz, eiund, efund, econv, estack, eheap, eillins, eoddz
 | 
			
		||||
.define ecase, ememflt, ebadptr, ebadpc, ebadlae, ebadmon, ebadlin, ebadgto
 | 
			
		||||
.define eunimpl
 | 
			
		||||
 | 
			
		||||
.sect .text
 | 
			
		||||
.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.
 | 
			
		||||
! 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
 | 
			
		||||
| 
						 | 
				
			
			@ -51,130 +46,7 @@
 | 
			
		|||
	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
 | 
			
		||||
	push h			! trap number and return address exchanged
 | 
			
		||||
	mov a,l
 | 
			
		||||
	cpi 16
 | 
			
		||||
	jnc 3f			! jump if trap cannot be ignored
 | 
			
		||||
| 
						 | 
				
			
			@ -192,10 +64,12 @@ eunimpl:lxi h,EUNIMPL
 | 
			
		|||
	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
 | 
			
		||||
| 
						 | 
				
			
			@ -206,15 +80,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$"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								plat/cpm/libsys/asm.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								plat/cpm/libsys/asm.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -1,42 +1,34 @@
 | 
			
		|||
/* $Source$
 | 
			
		||||
 * $State$
 | 
			
		||||
 * $Revision$
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <cpm.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#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];
 | 
			
		||||
static char* current = _end;
 | 
			
		||||
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;
 | 
			
		||||
		
 | 
			
		||||
	current = 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 current;
 | 
			
		||||
		return cpm_ram;
 | 
			
		||||
		
 | 
			
		||||
	old = current;
 | 
			
		||||
	old = cpm_ram;
 | 
			
		||||
	new = old + increment;
 | 
			
		||||
 | 
			
		||||
	if ((increment > 0) && (new <= old))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,110 @@
 | 
			
		|||
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_drive",
 | 
			
		||||
    [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 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 {
 | 
			
		||||
        name = name,
 | 
			
		||||
        ins = { "./make_bdos_call.sh" },
 | 
			
		||||
        outleaves = { name..".s" },
 | 
			
		||||
        commands = {
 | 
			
		||||
            "%{ins[1]} "..n.." "..name.." > %{outs}"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
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",
 | 
			
		||||
    srcs = {
 | 
			
		||||
        "./*.c",
 | 
			
		||||
        "./*.s",
 | 
			
		||||
        generated
 | 
			
		||||
    },
 | 
			
		||||
	deps = {
 | 
			
		||||
		"lang/cem/libcc.ansi/headers+headers",
 | 
			
		||||
		"plat/cpm/include+headers",
 | 
			
		||||
        "plat/cpm/include+headers",
 | 
			
		||||
        "+internal",
 | 
			
		||||
	},
 | 
			
		||||
    vars = {
 | 
			
		||||
        plat = "cpm"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								plat/cpm/libsys/cpm_overwrite_ccp.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								plat/cpm/libsys/cpm_overwrite_ccp.s
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										10
									
								
								plat/cpm/libsys/make_bdos_call.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								plat/cpm/libsys/make_bdos_call.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
cat <<EOF
 | 
			
		||||
#
 | 
			
		||||
#include "asm.h"
 | 
			
		||||
.define _$2
 | 
			
		||||
_$2:
 | 
			
		||||
    mvi a, $1
 | 
			
		||||
    jmp call_bdos
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								plat/cpm/libsys/make_trap.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								plat/cpm/libsys/make_trap.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
cat <<EOF
 | 
			
		||||
#
 | 
			
		||||
#include "asm.h"
 | 
			
		||||
.define $1
 | 
			
		||||
$1:
 | 
			
		||||
	mvi a, $2
 | 
			
		||||
	jmp .trp
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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,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. */
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue