; Program to receive a CP/M file through a serial port ; Accesses port directly, bypassing the BDOS ; Assumes an 8-bit word length and no parity ; ; Version of 9/17/83 ; ; Code Z80 optimized ; Adapted for JOYCE machine, version of 12/3/88 ; ; BOOT equ 0000h ; CP/M reboot address BDOS equ 0005h ; CP/M BDOS entry point TFCB equ 005ch ; FCB for file to be transmitted .drv equ 1 .conin equ 1 .string equ 9 .keysta equ 11 .close equ 16 .delete equ 19 .wrseq equ 21 .make equ 22 .setdma equ 26 bell equ 07h lf equ 0ah cr equ 0dh eol equ '$' NULL equ 00h NXREC equ 01h NEWREC equ 02h EOF equ 03h EOT equ 04h sync equ 30 NOMSB equ 7fh SIOsta equ 0e1h ; SIO status port SIOdat equ 0e0h ; SIO data port iflag equ 00000001b ; Input flag for serial port oflag equ 00000100b ; Output flag for serial port siores equ 00010000b ; Reset bit bufrec equ 128 ; Buffer size (CP/M records) retry equ 4 ; Number of retries before quitting ; _USERF equ 30 ; SA_INIT equ 00b6h SA_PARA equ 00bch ; ; aseg org 0100h ; jp SIOini ; Go to start ; ; Serial port initialization code here ; ; Call XBIOS ; USERF: push hl push de ld hl,(BOOT+1) ; Fetch base of BIOS ld de,3*(_USERF-1) add hl,de ; Build XBIOS vector pop de ex (sp),hl ; Fetch address ret ; Execute it ; ; Set an 8-bit word length and no parity ; SIOini: call USERF dw SA_PARA ; Get current parameters ld l,8 ; Bit length ld h,l ld a,0 ; No handshake ld d,1 ; One stop bit ld e,0 ; No parity call USERF dw SA_INIT ; Set parameters ; RX: ld a,(TFCB+.drv) cp ' ' ; Check for filename jr nz,open ld de,fnmer ; Print erro message and reboot abort: call string ld e,EOT call xmtbyt ; Send EOT character jp BOOT ; Return to CP/M open: ld de,TFCB ld c,.delete call BDOS ; Delete old file if present ld de,TFCB ld c,.make call BDOS ; Make new file inc a ld de,ddfer ; Point at error message jr z,abort ; Print and reboot start: ld b,sync ; Send some NULs first ld e,NULL nuls: call xmtbyt djnz nuls in a,(SIOdat) ; Clear serial data port ready: ld a,(rptctr) cp retry ld e,NXREC jr z,ready1 ; First time for this record inc e ; Change request character to 02H or a ; Test repeat counter jr nz,ready1 ; Try again if not zero endxmt: ld de,eotmsg ; Print EOT message and exit jr abort ready1: call xmtbyt ; Send prompting byte ready2: ld c,.keysta call BDOS ; Cet console status or a jr z,ready3 ; No key presaed ld c,.conin call BDOS cp 'C'-'@' jr z,endxmt ; Terminate if control-C pressed ready3: call recbyt ; Read serial port jr z,ready2 ; Wait for character to be received cp EOF jp z,close ; Flush buffer and close file cp EOT jr z,endxmt ; End transmission cp NXREC jr z,rcvrec ; Receive next record cp NEWREC jr nz,ready2 ; Ignore other characters rcvrec: ld b,bufrec ; Byte count for record ld d,0 ; Initialize checksum ld hl,(datptr) ; Prepare to store data rcvrc1: call rcvbyt ; Get a byte ld (hl),a ; Store in data buffer inc hl add a,d ld d,a ; Update checksum djnz rcvrc1 ; Continue for 128 bytes call rcvbyt ; Get checksum cp d push af ; Save status jr nz,rcvrc2 ; Bad read ld (datptr),hl ; Save new record pointer rcvrc2: ld de,recmsg call string ; Print received record message ld a,(rptctr) cp retry jr z,rcvrc3 ; First try ld de,again call string ; Print 'again' rcvrc3: ld de,crlf call string ; Print CRLF ld hl,rptctr dec (hl) ; Decrement repeat counter pop af jp nz,start ; Unsuccessful read ld a,retry ld (rptctr),a ; Reset counter for next record ld hl,recnum count: inc (hl) ld a,'9' cp (hl) ; Over 9? jr nc,bufchn ld (hl),'0' dec hl ld a,(hl) cp ' ' jr nz,count ld (hl),'0' jr count ; Put '0' in message bufchn: ld hl,(datptr) ld de,-(datbuf+bufrec*bufrec) add hl,de call c,flush ; Flush buffer if full jp ready ; Go look for next record ; ; Flush buffer if full ; flush: ld de,datbuf ; Start at beginning of buffer flush1: ld hl,(datptr) ld a,d ; Compare to see if empty cp h jr nz,flush2 ; More to go ld a,e cp l jr nz,flush2 ld hl,datbuf ld (datptr),hl ; Reset data pointer ret flush2: push de ld c,.setdma call BDOS ; Set DMA address ld de,TFCB ld c,.wrseq call BDOS ; Write record pop de or a jr z,flush3 ; Good write ld de,ddfer ; Disk error jp abort flush3: ld hl,bufrec add hl,de ; Point to next record ex de,hl jr flush1 ; Go write it if present close: call flush ; Flush buffer of data ld de,TFCB ld c,.close call BDOS ; Close file ld de,eofmsg call string ; Print EOF message jp BOOT ; Reboot ; ; Read serial data ; rcvbyt: call cliost in a,(SIOsta) ; Receive byte from serial port and iflag jr z,rcvbyt in a,(SIOdat) ret ; ; Read serial data ; recbyt: call cliost in a,(SIOsta) ; Read serial status port and iflag ret z ; Wait for character to be received in a,(SIOdat) ; Get received character and NOMSB ; Mask off bit 7 for ASCII codes ret ; ; Send data in reg E to SIO ; xmtbyt: call outrdy ; Wait for ready jr z,xmtbyt ld a,e out (SIOdat),a ret ; ; Check COMM ready for data ; outrdy: call cliost ; Reset SIO in a,(SIOsta) ; Get state and oflag ; Test bit ret ; ; Clear the COMM status register ; cliost: ld a,siores out (SIOsta),a ; Simple reset ret ; ; Print standard string thru BDOS ; string: ld c,.string call BDOS ret ; fnmer: db 'File name missing',cr,lf,eol ddfer: db 'Disk or directory full',cr,lf,eol eofmsg: db 'Transfer complete',cr,lf,bell,eol eotmsg: db 'Transfer terminated',cr,lf,bell,eol recmsg: db 'Record #' reccnt: db ' ' recnum: db '1 received',eol; Record # received again: db ' again',eol ; Repeated record crlf: db cr,lf,eol ; CRLF sequence datptr: dw datbuf ; Pointer to next storage location in buffer rptctr: db retry ; Counter for repeated record ; datbuf equ $ ; Data buffer ; end