title print program .comment * This program should be loaded as an 'rsx'. Its function is to print a file on the standard listing device while, at the same time, the computer can continue most normal operations. The call is print filename.typ Console read operations are intercepted and listing continues while the main program waits for input. The program is organized as two coroutines. The first being the code intercepting the calls to the bios and the second being the listing program. Switching between the coroutines is carried out by the subroutine 'switch'. * ; rsx print program .z80 ; standard rsx heading serial: db 0,0,0,0,0,0 jp ftest ; entry point next: jp 0 ; jump to next module prev: dw 2 ; previous module remove: db 0 ; set to 0ffh to delete this rsx nonbnk: db 0 ; no bank flag name: db 'print ' ; name - 8 bits loader: db 0 ; loader flag db 0,0 ; reserved ; macros bdce macro ?c,?e ; set c and e, then call bdos ld c,?c ; bdos code ld e,?e ; argument call bdos endm bdcde macro ?c,?de ; set c and de, then call bdos ld c,?c ; bdos code ld de,?de ; argument call bdos endm ftest: ; check if finished ld a,(remove) ; non-zero if finished and a ; set flags jr nz,next ld a,(first) ; check for first time through (first is set to 0 when and a ; set flags \\ other print instructions are complete. jr nz,firstx ; routine for first time through ld a,c ; bdos code cp 10 ; buffer read jr z,rd cp 1 ; check if read jr z,rd cp 6 ; direct io jr nz,next ld a,e cp 0fdh ; code for wait for entry jr z,rd jr next rd: ; keep calling pr until console receives input push bc ; must keep bc,de push de rd1: bdce dcio,0feh ; to get input status and a ; set flags jr nz,exit ; exit if character waiting call switch jr rd1 ; keep running printer if waiting for console entry firstx: push bc ; unconditionally call print coroutine and exit push de call switch exit: pop de ; recover registers pop bc jr next ;------------------------------------------------------------------------------- pr: ; print coroutine ; copy file spec ld hl,5ch ; parsed command string file name ld de,fcb ; where it will be stored ld bc,33 ; number of bytes to be copied ldir ; block copy xor a ; clear a ld hl,fcb ld bc,12 add hl,bc ld (hl),a ; extent ld bc,20 add hl,bc ld (hl),a ; record ; state drive explicitly ld a,(fcb) ; get disk and a ; set flags jr nz,drvsp ; drive specified ld c,rcd ; get current drive call bdos inc a ; for fcb, increment by 1 ld (fcb),a ; store in fcb drvsp: ; open file bdcde open,fcb and a ; set flags jp nz,err3 ; exit if file not opened ; is another file being printed with print? ld hl,(next+1) ; entry of next routine ld (olddma),hl ; keep in olddma search: ld hl,(olddma) ; entry of routine ld de,18 add hl,de ; points to loader flag ld a,(hl) ; get loader flag and a ; set flags jr nz,s4 ; this is the loader - so print not found ld de,-8 add hl,de ; hl now points to module's name ld de,name ; de points to 'print ' ld bc,8 ; number of bytes to be compared s1: ld a,(de) ; get byte from (de) cpi ; compare with byte from (hl), update hl,bc inc de ; advance de jr nz,s3 ; not 'print ' jp pe,s1 ; cycle if iterations are to continue ld hl,(olddma) ; has found another 'print ' module ld de,8 add hl,de ; points to remove flag s2: ld a,(hl) ; remove flag = 0 if module active and a ; set flags jr nz,s4 ; continue with program push hl ; keep address call switch ; wait pop hl jr s2 ; check remove flag s3: ld hl,(olddma) ; to get to next module ld de,4 ; offset to next module address add hl,de ; points to next module address ld e,(hl) ; get next module address to de inc hl ld d,(hl) ld (olddma),de ; store it jr search s4: xor a ; clear a ld (first),a ; clear first time indicator cycle: ; read/print cycle ; get current dma ld a,03ch ; offset in scb ld (scbpb),a ; send it to scb parameter block bdcde gsscb,scbpb ld (olddma),hl ; keep it ; get current multisector count ld a,04ah ; offset in scb ld (scbpb),a ; send it to scb parameter block bdcde gsscb,scbpb ld (oldcnt),a ; keep it ; get current multisector error mode ld a,04bh ; offset in scb ld (scbpb),a ; send it to scb parameter block bdcde gsscb,scbpb ld (oldem),a ; keep it bdcde dma,buff ; set dma bdce count,1 ; set multisector count = 1 bdce errmde,0ffh; set bdos error mode bdcde read,fcb ; read disk push af ; keep a ; reset dma, multisector count, error mode bdcde dma,(olddma) ld a,(oldcnt) bdce count,e ld a,(oldem) bdce errmde,a ; check read status pop af ; recover a cp 1 ; check for end of file jr z,finish and a ; set flags jr nz,err ; read fails ld hl,buff ; buffer location ld b,128 ; counter scan: ; scan buffer ld a,(hl) ; get character and 127 ; delete sign bit cp cntrz ; check for end of file jr z,finish ld c,a ; character to c push hl ; keep hl push bc ; keep bc poll: call switch ld de,42 ; list status offset on jump vector call jmpvec ; call jump vector and a ; set flags jr z,poll ; poll if not ready pop bc ; get character in c push bc ld de,12 ; list offset on jump vector call jmpvec ; call jump vector pop bc pop hl inc hl ; increment buffer address djnz scan ; increment b and scan jp cycle ; get next block jmpvec: ; jump vector access; expect offset in de ld hl,(1) ; jump vector add hl,de ; points to jump jp (hl) ; jump to it ; error message mess1: db cr,lf, '*** disk read error, printing aborted ***' ccb1: dw mess1,43 ; data for print block function err: bdcde lstblk,ccb1 jr finish ; end of print, send bell and formfeed mess2: db bell,ff ccb2: dw mess2,2 finish: bdcde lstblk,ccb2 ld a,0ffh ; to show printing finished & clear rsx ld (remove),a fc: call switch ; main program coroutine jr fc ; keep cycling till grabbed by console mess3: db cr,lf,'file cannot be opened$' err3: bdcde prstr,mess3 ld a,0ffh ; to show printing finished & clear rsx ld (remove),a jp 0 ; return to cpm switch: ; routine to switch between coroutines ld hl,0 ; get stack pointer add hl,sp ld sp,namex ex (sp),hl ; exchange 'namex' and old sp ld sp,hl ; update stack pointer ret buff: ds 128 ; disk buffer fcb: ds 33 ; fcb ds 30 ; auxiliary stack istack: dw pr ; entry point for coroutine namex: dw istack ; points auxiliary stack olddma: ds 2 ; old dma, also used in rsx module search oldcnt: ds 1 ; old count oldem: ds 1 ; old error mode first: db 0ffh ; set to 0 when routine starts scbpb: ds 1 ; scb parameter block, first loc = offset db 0 ; to get a byte or word bell equ 7 ; bell lf equ 0ah ; line feed ff equ 0ch ; form feed cr equ 0dh ; carriage return cntrz equ 1ah ; control z bdos equ next list equ 5 ; list character dcio equ 6 ; direct console io prstr equ 9 ; print string open equ 15 ; open file read equ 20 ; read sequential rcd equ 25 ; return current drive dma equ 26 ; set dma count equ 44 ; multisector count errmde equ 45 ; set bdos error mode gsscb equ 49 ; get/set scb lstblk equ 112 ; list block end