TTY     TITLE   "Z80 BCPL Run Time System  -  Section TTY"
        GET     "HEADER"
        GET     "SCBHDR"
        LAYOUT
;  This section contains all the routines to handle buffered line I/O
;  for the console device.  It requires C.RDCH and C.WRCH to do the raw
;  I/O to the console hardware.
        LAYOUT
        REF     C.RDCH
        REF     C.WRCH

        DEF     C.FNDI
        DEF     C.FNDO
        LAYOUT
        RELOCATABLE

        ORG     0

TTY     DEFB    'BCPL'                  ;  Entry flag for BCPL module
        DEFW    TTYE-TTY                ;  Length of module in bytes
        LAYOUT
;  FINDINPUT
;  ---------
;
;    Console "findinput" routine.  Load the address of the prototype SCB,
;    and join the common code.


C.FNDI  LD      DE,ISCB                 ;  Load address of SCB
        LD      BC,ISCBL                ;  Length of SCB
        JP      FIND                    ;  Join common code
        LAYOUT
;  FINDOUTPUT
;  ----------
;
;    Console "findoutput" routine.  Load the address of the prototype SCB,
;    and join the common code


C.FNDO  LD      DE,OSCB                 ;  Load address of SCB
        LD      BC,OSCBL                ;  Length of SCB
        JP      FIND                    ;  Join common code
        LAYOUT
;  Prototype SCB layouts for input and output
;  ------------------------------------------


ISCB    DEFB    B.IN+B.BUF+B.INT        ;  Flags
        DEFB    0                       ;  POS field
        DEFB    0                       ;  END field
        DEFW    BUFR                    ;  Buffer READ routine
        DEFW    ERR                     ;  Buffer WRITE routine
        DEFW    BINR                    ;  Binary READ routine
        DEFW    ERR                     ;  Binary WRITE routine
        DEFW    CLOSE                   ;  CLOSE routine
        DEFW    0                       ;  Arg1
        DEFW    0                       ;  Arg2
ISCBL   EQU     $-ISCB                  ;  Length of SCB


OSCB    DEFB    B.OUT+B.BUF+B.INT       ;  Flags
        DEFB    0                       ;  POS field
        DEFB    S.SIZE                  ;  END field
        DEFW    ERR                     ;  Buffer READ routine
        DEFW    BUFW                    ;  Buffer WRITE routine
        DEFW    ERR                     ;  Binary READ routine
        DEFW    BINW                    ;  Binary WRITE routine
        DEFW    CLOSE                   ;  CLOSE routine
        DEFW    0                       ;  Arg1
        DEFW    0                       ;  Arg2
OSCBL   EQU     $-OSCB                  ;  Length of SCB
        LAYOUT
;  FIND
;  ----
;
;    Common code to execute a stream open.  We enter here with HL pointing
;    to the prototype SCB and BC containing its length.  IX points to the
;    store allocated for the SCB.


FIND    EX      DE,HL                   ;  Swap source and destination pointers
        LDIR                            ;  Copy values across

        PUSH    IX                      ;  Save pointer to SCB
        POP     HL                      ;  Set result from function
        RET                             ;  And return
        LAYOUT
;  BUFREAD
;  -------
;
;    Console buffer read function.  This is called from "rdch" whenever the
;    buffer associated with the current input stream is empty.  On entry
;    IX is a pointer to associated SCB.  On exit, the number of characters
;    read is returned in A.


BUFR    PUSH    IX                      ;  Save pointer to SCB
        POP     HL                      ;  And store it in HL
        LD      DE,S.BUFF               ;  Offset of buffer
        ADD     HL,DE                   ;  Get pointer to buffer

        XOR     A                       ;  Set character count to zero

;  Main loop to read characters from the console.  First, check that the
;  buffer still has some room in it, and return otherwise.  If we have room,
;  then we get a new character, and process it.

BUFR0   CP      S.SIZE                  ;  Is the buffer full ?
        RET     Z                       ;  Yes, so no more to read

        PUSH    AF                      ;  Save character count
        CALL    C.RDCH                  ;  Read character from the console
        RES     7,A                     ;  Strip parity

        CP      RUBOUT                  ;  Is it a rubout character ?
        JP      Z,BUFR1                 ;  Yes, so handle it.

;  Now, we should reflect the character, and store it in the buffer.  After
;  that, check to see if it is one of the "line terminating" characters, and
;  if so, return.

        CP      STARC                   ;  Is it carriage return ?
        JP      NZ,BUFR3                ;  No, so no translation
        LD      A,STARN                 ;  Translate CR to newline

BUFR3   LD      (HL),A                  ;  Store the character
        CALL    REFLECT                 ;  Reflect the character
        INC     HL                      ;  Increment buffer pointer

        CP      STARE                   ;  Escape character ?
        JP      Z,BUFR4                 ;  Yes, so return
        CP      STARN                   ;  Newline character ?
        JP      Z,BUFR4                 ;  Yes, so return

;  If we drop through here, this was a bog standard character, and we should
;  continue reading.  Increment the count, and loop.

        POP     AF                      ;  Restore character count
        INC     A                       ;  Increment it
        JP      BUFR0                   ;  And enter main loop again

;  If we come here, then the character is a terminating one, and we should
;  return.  Restore the length, increment it, and then return.

BUFR4   POP     AF                      ;  Restore character count
        INC     A                       ;  Increment it
        RET                             ;  And return

;  If we come here, then a rubout character has been read.  We should check
;  the number of characters typed, and if zero, do nothing at all.  If non
;  zero, then we should decrement the count, and rub out the character on
;  the tty.

BUFR1   POP     AF                      ;  Restore length
        OR      A                       ;  Is it already zero ?
        JP      Z,BUFR0                 ;  Yes, so go no further

        DEC     A                       ;  Decrement the count
        PUSH    AF                      ;  And save it
        DEC     HL                      ;  Decrement buffer pointer
        LD      A,(HL)                  ;  Load character being rubbed out

        CP      SPACE                   ;  Is it a control character ?
        JP      NC,BUFR2                ;  No, so rub out only one character

        CALL    BSPACE                  ;  Rubout character
BUFR2   CALL    BSPACE                  ;  And again, if necessary

        POP     AF                      ;  Restore count
        JP      BUFR0                   ;  Enter main loop again
        LAYOUT
;  BUFWRITE
;  --------
;
;    Console buffer write function.  This is called from "wrch" whenever the
;    buffer associated with the current output stream is full.  On entry
;    IX is a pointer to associated SCB, and A is a count of the number of
;    characters in the buffer.


BUFW    PUSH    IX                      ;  Save pointer to SCB
        POP     HL                      ;  And store it in HL
        LD      DE,S.BUFF               ;  Offset of buffer
        ADD     HL,DE                   ;  Get pointer to buffer

BUFW0   OR      A                       ;  Length reached zero yet ?
        RET     Z                       ;  Yes, so return

        PUSH    AF                      ;  Save character count
        LD      A,(HL)                  ;  Load character to be written
        CALL    REFLECT                 ;  Reflect it
        POP     AF                      ;  Restore character count

        INC     HL                      ;  Increment buffer pointer
        DEC     A                       ;  Decrement count
        JP      BUFW0                   ;  Continue looping
        LAYOUT
;  REFLECT
;  -------
;
;    Reflect the character in "A" in a visible form.  Control characters are
;    printed as "^x" and newlines as "CR LF".


REFLECT CP      STARE                   ;  Escape character ?
        RET     Z                       ;  If so, don't reflect

        CP      STARN                   ;  Newline character ?
        JP      Z,REFL0                 ;  Yes, so reflect it

        CP      SPACE                   ;  Control character
        JP      C,REFL1                 ;  Yes, so reflect it

;  If we fall through here, then this is a printable character, which we should
;  reflect forthwith.

        CALL    C.WRCH                  ;  Reflect the character
        RET                             ;  And return

;  Reflect newline character.

REFL0   LD      A,STARC                 ;  Carriage return
        CALL    C.WRCH                  ;  Write it out
        LD      A,STARN                 ;  Line feed
        CALL    C.WRCH                  ;  Write it out
        RET                             ;  And return

;  Reflect control character.

REFL1   PUSH    AF                      ;  Save character
        LD      A,'^'                   ;  Control prefix
        CALL    C.WRCH                  ;  Write it out
        POP     AF                      ;  Restore character
        OR      '@'                     ;  Make printable character
        CALL    C.WRCH                  ;  Write it out
        RET                             ;  And return
        LAYOUT
;  BSPACE
;  ------
;
;    Backspace over the character on the line.


BSPACE  LD      A,STARB                 ;  Backspace character
        CALL    C.WRCH                  ;  Write it out
        LD      A,SPACE                 ;  Space character
        CALL    C.WRCH                  ;  Write it out
        LD      A,STARB                 ;  Backspace character
        CALL    C.WRCH                  ;  Write it out
        RET                             ;  And return
        LAYOUT
;  BINREAD
;  -------
;
;    Binary read.  Call C.RDCH to read a console character.


BINR    CALL    C.RDCH                  ;  Call console read routine
        LD      H,0                     ;  High byte of result
        LD      L,A                     ;  Low byte of result
        RET                             ;  And return
        LAYOUT
;  BINWRITE
;  --------
;
;    Binary write.  Call C.WRCH to write a console character.


BINW    LD      A,L                     ;  Low byte of character
        CALL    C.WRCH                  ;  Call console write routine
        RET                             ;  And return
        LAYOUT
;  CLOSE
;  -----
;
;    Dummy close routine, called from "endread" or "endwrite" when a stream
;    is closed.


CLOSE   RET
        LAYOUT
;  ERROR
;  -----
;
;    Enter here if the user attempts to muck around with the routines in the
;    stream control block.


ERR     ERRTRAP                         ;  Enter the debugger
        RET                             ;  And return
        LAYOUT
        ALIGN

        DEFW    0                       ;  End of global list
        DEFW    0                       ;  HRG
        LAYOUT
TTYE    END


