enable = <6
pri = 5
stopint = 0320          # location of display stop interrupt vector

.=0400                  # past all interrupt vectors
placate:
      point
      200;  600         # invisible
      statsa ital1 sync
      char int1
      'Scrolling, cursor positionable terminal program.'
      point
      200; 500
      char
      'LOADING -- please wait.'
      .even
#     point
#     100;  100
#     statsa ital0
#     char int7
#     'Copyright (c) 1978, Georgia Institute of Technology'
#     # written by Jack Waugh
#     .even
      djmp; placate
main: .=dpc
      placate
.=main
start':
      reset             # stop display
      jmp   entry

. = 01000         # leaving 0400 bytes or 128. words for the stack
entry:
      mov   $entry, sp
      clr   r0
      mov   (pc)+, (r0)+; jmp *(pc)+      # place jump in loc. 0
      mov   sp, (r0)+                     #     to entry
      mov   $disaster, (r0)+
      mov   $7<pri, (r0)+
1h:   clr   (r0)+
      cmp   r0, sp
      blo   1b
main:  . = data
disaster:
      clr   *$beep
      halt
      reset
      clr   pc

# ivsetup --- set up an interrupt vector
#     call: jsr r5, ivsetup; vec address; service routine; psw image
#     registers: r0 garbaged, others saved.
ivsetup:
      mov   (r5)+, r0         # vector address
      mov   (r5)+, (r0)+      # service routine address
      mov   (r5)+, *r0        # psw image (including priority)
      rts   r5                # thats it!

data:  .=main                   # resume main line of code

      mov   $ivsetup, r1
      jsr r5, *r1; stopint; dstop_service; 4<pri
      jsr r5, *r1; 0330; disaster; 7<pri
      # Above trap occours on a bus timeout to the DPU or on an
      # illegal shifted out character.
      jsr r5, *r1; 060; kbd_service; 0<pri
      jsr r5, *r1; 0300; rcvr_service; 6<pri

      mov   $highest, r0
1h:   clr   -(r0)
      cmp   r0, $end_of_initialized
      bhi   1b

      clr   -(sp)                   # have a scratch place on the stack

# regular housekeeping done.  Now, initialize application.

CRLF = CR < 8 + LF
ROWS = 32
EXTRA = 32                          # number of invisible rows
COLS = 73
.struct line.     line.crlf 2, line.text COLS + 1, line.stop 2
1h = ROWS + EXTRA
.reserve bss      buf 1b * line.    # buffer for lines of text
endbuf = bss
.reserve bss      curline 2         # pointer to line being modified
.reserve bss      botline 2         # pointer to bottom line
.reserve bss      topline 2         # pointer to top line
.reserve bss      disline 2         # line actually being displayed
.reserve bss      charbuf 1024      # buffer for characters received
charbuf.end = bss
.reserve bss      charbuf.out 2     # read pointer
charbuf.in = r4                     # write pointer
.reserve bss      curcol  2         # column number of cursor
.reserve bss      currow 2          # row number of cursor (top is 0)
.reserve bss      precursor 2, cursor line., postcursor 2
next_display = r5

      mov   $charbuf, charbuf.in    # set up character queue
      mov   charbuf.in, charbuf.out # initially empty
      mov   $enable, *$rcsr         # now safe to receive characters
      mov   $enable, *$kcsr         # and send them, too

      mov   $buf, r0                # set up display buffer
1h:   mov   $CRLF, line.crlf (r0)
      mov   r0, *sp                 # put argument on top of stack
      jsr   pc, clrtxt
      mov   $dstop, line.stop (r0)
      add   $line., r0
      cmp   r0, $endbuf
      blo   1b

      mov   $char blkon, precursor
      mov   $CR, cursor + line.crlf # no LF, only CR
      mov   $char blkoff, cursor + line.stop
      mov   $dstop, postcursor
      mov   $cursor, *sp
      jsr   pc, clrtxt

      mov   $buf, topline
2h = ROWS * line.
1h = 2b - line.
      mov   $buf + 1b, botline
      mov   $buf, curline
      clr   currow
      mov   $buf, disline
      clr   curcol
      mov   $buf, next_display
      clr   -(sp)                   # fake an interrupt
      mov   $1f, -(sp)
      jmp   dstop_service
1h:

mainloop:
      jsr   pc, getchar
      tst   r0                      # ignore nulls
      beq   mainloop
                              # now interpret the character
      cmp   r0, $' '                # printable?
      blt   1f
print:      mov   curline, r2       # get current line
            add   $line.text, r2    # point to text part
            add   curcol, r2        # index with curcol
            movb  r0, *r2           # store the character
            inc   curcol            # move cursor along
            cmp   curcol, $COLS
            blt   2f
                  clr   curcol      # wraparound
                  br    newline
      2h:   br    mainloop
1h:   cmp   r0, $BEL                # wasn't printable.
      bne   1f
            clr   *$beep
            br    mainloop
1h:   cmp   r0, $CR                 # carriage return
      bne   1f
            clr   curcol
            br    mainloop
1h:   cmp   r0, $LF                 # line feed
      bne   1f
      newline:
            mov   $curline, *sp
            jsr   pc, bumpln
            inc   currow
            cmp   currow, $ROWS
            blt   2f
                  mov   curline, *sp
                  jsr   pc, clrtxt
      2h:   br    mainloop
1h:   cmp   r0, $BS
      bne   1f
            tst   curcol            # is backspace
            ble   2f
                  dec   curcol
      2h:   br    mainloop
1h:   cmp   r0, $FF
      bne   1f
      2h:   cmp   currow, $ROWS     # form feed: clear screen
            ble   3f                # wait until all scrolling done
                  wait
                  br    2b
      3h:
            mov   $buf, r0
      2h:   mov   r0, *sp
            jsr   pc, clrtxt
            add   $line., r0
            cmp   r0, $endbuf
            blo   2b
home:       mov   topline, curline
            clr   currow
            clr   curcol
            br    mainloop
1h:   cmp   r0, $DC4
      bne   1f
            jsr   pc, clreol        # control-t: clear to end of line
            br    mainloop
1h:   cmp   r0, $ESC
      bne   1f
            jsr   pc, rowpos
            jsr   pc, colpos
            br    mainloop
1h:   cmp   r0, $ACK
      bne   1f
            jsr   pc, rowpos
            br    mainloop
1h:   cmp   r0, $NAK
      bne   1f
            jsr   pc, colpos
            br    mainloop
1h:   mov   $DEL, r0                # garbage character.
      br    print


# colpos --- accept absolute column position from host
#     call: jsr pc, colpos
#     registers:
colpos:
      jsr   pc, getaddr
      tst   r0

      blt   1f
      cmp   r0, $COLS
      bge   1f
            mov   r0, curcol
1h:   rts   pc

# rowpos --- accept absolute row position from host
rowpos:
      jsr   pc, getaddr
      cmp   r0, $ROWS
      bge   1f
      tst   r0
      blt   1f
            jsr   pc, quiet
            mov   topline, curline
            clr   currow
      2h:   cmp   currow, r0
            bge   3f
                  mov   $curline, -(sp)
                  jsr   pc, bumpln
                  tst   (sp)+
                  inc   currow
                  br    2b
      3h:
1h:   rts   pc

# getaddr --- get a row or column address from host
#     return in r0
getaddr:
      jsr   pc, getchar
      sub   $' ', r0             # blank is lowest printing character
      rts pc

# getchar --- get a character from host
#     return it in r0
getchar:
      cmp   charbuf.in, charbuf.out # look for received characters
      bne   1f                      # nothing to do yet?
            mov   curcol, r0        # then mess with cursor
            movb  $'_', cursor + line.text (r0)
      2h:   wait                    # idle
            cmp   charbuf.in, charbuf.out # is there a character now?
            beq   2b                # no, idle some more
            movb  $' ', cursor + line.text (r0) # yes, remove cursor
1h:   movb  *charbuf.out, r0        # get the character
      inc   charbuf.out                # bump the pointer around
      cmp   charbuf.out, $charbuf.end
      blo   1f
            mov   $charbuf, charbuf.out
1h:   bic   $~DEL, r0               # strip parity bit
      rts   pc

# quiet --- wait until scrolling is finished
quiet:
      cmp   currow, $ROWS  # does display stop routine have to scroll?
      bgt   1f             # yes, wait for it
      rts   pc             # no, return

1h:   wait
      br    quiet

# clrtxt --- clear out the text of a line to blanks
#     call:       (pointer to line on stack) jsr pc, clrtxt
#     registers:  all saved.
clrtxt:
clrtxt.ptr = 2                            # stack offset of argument
      mov   r0, -(sp); depth = 2          # save r0
      mov   clrtxt.ptr + depth (sp), r0   # get argument
      add   $line.text, r0                # make point to text portion
      mov   r1, -(sp); depth = 4          # save r1
      mov   r0, r1
      add   $COLS, r1                     # points to end of text
1h:   movb  $' ', (r0)+                   # store blank, point to next
      cmp   r0, r1                        # end of text portion?
      blo   1b                            # no, loop back

      mov   (sp)+, r1; depth = 2          # restore registers and return
      mov   (sp)+, r0; depth = 0
      rts   pc

# clreol --- clear from current column to end of current line
#     call:       jsr pc, clreol
#     registers:  all saved.
clreol:
      mov   r0, -(sp)                     # save r0
      mov   curline,r0                    # get ptr to current line
      add   $line.text, r0                # make point to text portion
      mov   r1, -(sp)                     # save r1
      mov   r0, r1
      add   curcol, r0                    # make point to current col
      add   $COLS, r1                     # points to end of text
1h:   movb  $' ', (r0)+                   # store blank, point to next
      cmp   r0, r1                        # end of text portion?
      blo   1b                            # no, loop back

      mov   (sp)+, r1                     # restore registers and return
      mov   (sp)+, r0
      rts   pc

# bumpln --- point a line pointer to the next line in the buffer
#     call: (pointer to pointer on stack) jsr pc, bumpln
#     registers:  all saved.
bumpln:
arg = 2
      add   $line., *arg (sp)
      cmp   *arg (sp), $endbuf
      bhis  1f
            rts   pc
1h:   mov   $buf, *arg (sp)
      rts   pc


# interrupt service routines

dstop_service:                      # display stopped on dstop
      mov   next_display, *$dpc     # start it up again NOW
      cmp   curline, disline
      bne   1f
            mov   $precursor, next_display
            mov   $2f, *$stopint
            rti
      2h:
            mov   next_display, *$dpc
            mov   $dstop_service, *$stopint
1h:   cmp   botline, disline        # did we just display the last line
      bne   1f
            cmp   currow, $ROWS
            blt   2f
            3h:   dec   currow
                  mov   $topline, -(sp)
                  jsr   pc, bumpln
                  mov   $botline, *sp
                  jsr   pc, bumpln
                  tst   (sp)+
                  cmp   currow, $ROWS + EXTRA
                  bge   3b
      2h:   mov   topline, disline
            mov   disline, frog
            mov   $dfile, next_display
            rti
1h:
      add   $line., disline
      cmp   disline, $endbuf
      blo   1f
            mov   $buf, disline
1h:   mov   disline, next_display
      rti

dfile:
      point
      0;    767;                    # top left corner of screen
      longv int1                    # draw border
      0 intx;     minusy 767
      1023 intx;  0
      0 intx;     767
      minusx 1023 intx; 0
      0;          2    # move up just a bit to make room for one more row
      char int3
      djmp
frog: frog                          # gets changed

kbd_service:                        # key pressed on keyboard
      mov   *$kbuf, *$xbuf          # send it along
      rti

rcvr_service:                       # character received from host
      movb  *$rbuf, (charbuf.in)+   # get from DL11 receiver
      cmp   charbuf.in, $charbuf.end   # and enqueue
      bhis  1f
            rti
1h:   mov   $charbuf, charbuf.in
      rti

# final assignment of code placement symbols
end_of_initialized = data
bss = data
data:    # sole definition in first pass