home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / asmutl / hd64180a.lbr / EXECCORE.AZM / EXECCORE.ASM
Assembly Source File  |  1991-08-04  |  38KB  |  1,752 lines

  1.     title    'Executive Command Processor - CORE BOARD Version'
  2. ;
  3. ;----------------------------------------------------------------
  4. ;    Executive Command Processor for CORE BOARD
  5. ;
  6. ; This module provides services much in the way that a dos does.
  7. ; It is called by a RESTART or anything else, it interprets
  8. ; register setups and performs the functions specified.
  9. ; This module interfaces into the I/O drivers rather than
  10. ; providing its own I/O.  It does however have some code to
  11. ; provide some of the more general purpose routines.
  12. ;
  13. ; This program is Copyright (C) 1987 by SME Systems P/L
  14. ;                    22 Queen Street Mitcham
  15. ;
  16. ;
  17. ; Written     by Richard Holmes    08/12/1987
  18. ; Last Update by Richard Holmes    19/10/1988
  19. ;
  20. ; Added the price print function 36            05/02/88
  21. ; Added the time print function  37            06/02/88
  22. ; Added ????$HDLR interrupt handlers            20/02/88
  23. ; Added bel$cnt for interrupt driven bell        19/10/88
  24. ;----------------------------------------------------------------
  25. ;
  26.     maclib    z80
  27. ;
  28. ;    maclib    iocmd            ; I/O Driver command library
  29.     public    exec            ; The ONLY entry point.
  30. ;
  31. ; Interrupt handlers
  32.     public    bel$cnt                    ; Delayed int. bell.
  33.     public    con$hdlr,  aux$hdlr            ; Con and aux ints
  34.     public    tmr0$hdlr, tmr1$hdlr            ; Timer ints
  35.     public    int0$hdlr, int1$hdlr, int2$hdlr        ; INT pin ints
  36.     public    csio$hdlr                ; CSIO ints
  37. ;
  38. ; I/O Drivers for the character display devices
  39.     extrn    sys$ini
  40.     extrn    con$ini,con$ist,con$ost,con$inp,con$out,con$cmd    ; Console
  41.     extrn    aux$ini,aux$ist,aux$ost,aux$inp,aux$out,aux$cmd    ; Aux serial
  42.     extrn    lcd$ini,lcd$ost,lcd$out,lcd$cmd            ; Main LCD
  43.     extrn    prn$ini,prn$ost,prn$out                ; Printer
  44. ;
  45.     extrn    ms$delay,clr$wdt
  46. ;
  47.     extrn    clk$rd,clk$wr
  48.     extrn    clr$led,set$led,tog$led,zro$led
  49.     extrn    set$bel,clr$bel
  50. ;
  51.     extrn    hrs,min
  52. ;
  53. cmd$max    equ    69            ; Total of 69 commands allowed max.
  54. max$chn    equ    6            ; Last used channel number
  55. ;
  56. psh$max    equ    5            ; Maximum channel "pushes" allowed
  57. psh$siz    equ    18            ; Bytes to "push" (routines * 3)
  58. ;
  59. cr    equ    0dh
  60. lf    equ    0ah
  61. esc    equ    01bh
  62. ;
  63. ; I/O Commands for intelligent devices to process.
  64. ;
  65. clr$scr    equ    01        ; Clear screen
  66. clr$eos    equ    02        ; Clear to end of screen
  67. clr$eol    equ    03        ; Clear to end of line
  68. cur$adr    equ    04        ; Cursor address
  69. vid$att    equ    05        ; Select video attribute (flash, reverse etc)
  70. gxy$cmd    equ    06        ; Get the current X-Y address
  71. ;
  72.     page
  73. ;----------------------------------------------------------------
  74. ;            The Executive Processor
  75. ;
  76. ; On Entry
  77. ;    C = command number, 
  78. ;    All else are parameters.
  79. ;----------------------------------------------------------------
  80. ;
  81. exec:
  82.     push    h
  83.     push    b
  84.     push    d
  85. ;
  86.     lxi    h,table
  87.     mvi    b,0        ; BC = offset.
  88.     dad    b
  89.     dad    b        ; HL = table base + (2 * offset)
  90. ;
  91.     mov    e,m
  92.     inx    h
  93.     mov    d,m        ; DE = address from table
  94.     xchg            ; Hl -> routine
  95. ; Restore registers and goto routine
  96.     pop    d
  97.     pop    b
  98.     xthl            ; Top stack = address, HL restored
  99.     ret            ; Goes to routine.
  100. ;
  101. ;----------------------------------------------------------------
  102. ; A table of addresses of the routines.
  103. ;----------------------------------------------------------------
  104. ;
  105. table:
  106.     dw    cmd$0        ; Reset hardware
  107.     dw    cmd$1        ;
  108.     dw    cmd$2        ;
  109.     dw    cmd$3        ;
  110.     dw    cmd$4        ;
  111.     dw    cmd$5        ;
  112.     dw    cmd$6        ;
  113.     dw    cmd$7        ;
  114.     dw    cmd$8        ;
  115.     dw    cmd$9        ;
  116. ;
  117.     dw    cmd$10        ;
  118.     dw    cmd$11        ;
  119.     dw    cmd$12        ;
  120.     dw    cmd$13        ;
  121.     dw    cmd$14        ;
  122.     dw    cmd$15        ;
  123.     dw    cmd$16        ;
  124.     dw    cmd$17        ;
  125.     dw    cmd$18        ;
  126.     dw    cmd$19        ;
  127. ;
  128.     dw    cmd$20        ;
  129.     dw    cmd$21        ;
  130.     dw    cmd$22        ;
  131.     dw    cmd$23        ;
  132.     dw    cmd$24        ;
  133.     dw    cmd$25        ;
  134.     dw    cmd$26        ;
  135.     dw    cmd$27        ;
  136.     dw    cmd$28        ;
  137.     dw    cmd$29        ;
  138. ;
  139.     dw    cmd$30        ;
  140.     dw    cmd$31        ;
  141.     dw    cmd$32        ;
  142.     dw    cmd$33        ;
  143.     dw    cmd$34        ;
  144.     dw    cmd$35        ;
  145.     dw    cmd$36        ;
  146.     dw    cmd$37        ;
  147.     dw    cmd$38        ;
  148.     dw    cmd$39        ; Get current X-Y  address
  149. ;
  150.     dw    cmd$40        ;
  151.     dw    cmd$41        ;
  152.     dw    cmd$42        ;
  153.     dw    cmd$43        ;
  154.     dw    cmd$44        ;
  155.     dw    cmd$45        ;
  156.     dw    cmd$46        ;
  157.     dw    cmd$47        ;
  158.     dw    cmd$48        ;
  159.     dw    cmd$49        ; Set bell count
  160. ;
  161.     dw    cmd$50        ; Spare
  162.     dw    cmd$51        ; Spare
  163.     dw    cmd$52        ; Spare
  164.     dw    cmd$53        ;
  165.     dw    cmd$54        ;
  166.     dw    cmd$55        ;
  167.     dw    cmd$56        ; Spare
  168.     dw    cmd$57        ;
  169.     dw    cmd$58        ;
  170.     dw    cmd$59        ;
  171. ;
  172.     dw    cmd$60
  173.     dw    cmd$61
  174.     dw    cmd$62
  175.     dw    cmd$63
  176.     dw    cmd$64
  177.     dw    cmd$65
  178.     dw    cmd$66
  179.     dw    cmd$67
  180.     dw    cmd$68
  181.     dw    cmd$69
  182. ;
  183.     page
  184. ;----------------------------------------------------------------
  185. ;     T H E    C O M M A N D S
  186. ;----------------------------------------------------------------
  187. ;
  188. cmd$0:    ; Reset EXEC, initialize
  189.     call    clr$wdt
  190. ; Init all the interrupt handers to be returns
  191.     mvi    a,(RET)        ; Loads a return into A
  192.     sta    con$hdlr
  193.     sta    aux$hdlr
  194.     sta    tmr0$hdlr
  195.     sta    tmr1$hdlr
  196.     sta    int0$hdlr
  197.     sta    int1$hdlr
  198.     sta    int2$hdlr
  199.     sta    csio$hdlr
  200. ;
  201.     call    clr$wdt
  202.     call    sys$ini        ; Initialize all hardware
  203.     xra    a
  204.     sta    dsp$flg        ; Clear the display the code flag
  205.     sta    exe$dbg        ; Clear the debugging flag
  206.     sta    lzb$mode    ; Print all characters LZB mode
  207.     call    psh$pop$ini
  208. ;
  209. ; Initialize/Reset all I/O channels.
  210.     xra    a        ; Force ALL channel initialize
  211.     call    init$chan    ; Initialize channels routine
  212.     mvi    a,1        ; Main console.
  213.     call    sel$chn        ; Channel select console first time.
  214. ;
  215. ;
  216.     call    zro$led        ; Clear leds
  217.     jmp    exec$end
  218. ;
  219. ;
  220. ;
  221. cmd$1:        ; Select I/O Channel for I/O
  222.     call    sel$chn        ; Select the channel
  223.     jmp    exec$end
  224. ;
  225. cmd$2:        ; Reset One/all i/o channels
  226.     call    init$chan
  227.     jmp    exec$end
  228. ;
  229. cmd$3:        ; Return current channel number
  230.     lda    cur$chn
  231.     jmp    exec$end
  232. ;
  233. cmd$4:        ; Read current channel into accumulator
  234.     call    chn$inp
  235.     jmp    exec$end
  236. ;
  237. cmd$5:        ; Write to current channel
  238.     call    chn$out
  239.     jmp    exec$end
  240. ;
  241. ;
  242. cmd$6:        ; Return channel input status
  243.     call    chn$ist
  244.     jmp    exec$end
  245. ;
  246. cmd$7:        ; Return channel output status
  247.     call    chn$ost
  248.     jmp    exec$end
  249. ;
  250. cmd$8:        ; Print string at mDE
  251.     ldax    d
  252.     inx    d            ; -> next
  253.     ora    a
  254.     jz    exec$end
  255.     call    chn$out            ; Channel output routine
  256.     jr    cmd$8
  257. ;
  258. ;
  259. cmd$9:        ; Print string at return address
  260.     xthl                ; get address of string (ret address)
  261.     push    psw
  262. inline2:
  263.     mov    a,m
  264.     inx    h            ; point to next character
  265.     ora    a
  266.     jrz    inline3
  267.     call    chn$out
  268.     jr    inline2
  269. inline3:
  270.     pop    psw
  271.     xthl                ; load return address after the '$'
  272.     jmp    exec$end
  273. ;
  274. ;
  275. ;
  276. cmd$10:        ; Print X-Y prefixed string at return address
  277.     xthl            ; HL -> string, old hl in stack
  278.     xchg            ; now DE --> string
  279.     call    setxy        ; set it up
  280.     xchg            ; now hl --> string start again
  281.     call    print
  282.     xthl            ; hl = original value, stack = return address
  283.     jmp    exec$end
  284. ;
  285. ;----------------------------------------------------------------
  286. ; Print the string --> by DE. Use the two bytes at the start of it
  287. ; as a screen address.
  288. ;----------------------------------------------------------------
  289. ;
  290. xypstring:
  291.     push    h
  292.     call    setxy            ; set up screen
  293.     xchg                ; now hl --> string start
  294.     call    print
  295.     xchg                ; Restore DE --> past end of string
  296.     pop    h
  297.     ret
  298. ;
  299. ;
  300. ;       ---- Utility to print a string till a $. ----
  301. ; On return HL -> to next byte after the string (code maybe)
  302. ;
  303. print:
  304.     push    psw
  305.     inx    h
  306.     inx    h        ; skip over cursor address
  307. print2:
  308.     mov    a,m
  309.     inx    h        ; Point to next character
  310.     ora    a        ; null is allowed to end a string
  311.     jrz    print3
  312.     call    chn$out
  313.     jr    print2
  314. ;
  315. print3:
  316.     pop    psw
  317.     ret
  318. ;
  319. ;----------------------------------------------------------------
  320. ; Set the cursor up according to two bytes in ram which contain
  321. ; the X and Y addresses in them. The bytes --> by DE.
  322. ;----------------------------------------------------------------
  323. ;
  324. setxy:
  325.     push    d            ; save 
  326.     push    h
  327.     xchg                ; HL --> bytes
  328.     mov    d,m            ; load X value
  329.     inx    h
  330.     mov    e,m
  331.     call    cmd$12            ; Cursor Set up
  332.     pop    h            ; restore all now
  333.     pop    d
  334.     ret
  335. ;
  336. ;----------------------------------------------------------------
  337. ; Print the MENU at mDE. A menu is a list of asciiz strings
  338. ; each prefixed with an X-Y cursor address. This code will
  339. ; put each string at the specified address. The routine is 
  340. ; terminated with an 0FFh byte.
  341. ;----------------------------------------------------------------
  342. ;
  343. cmd$11:        ; Print menu at mDE
  344.     push    d            ; save all
  345.     push    h
  346.     push    psw
  347.     xchg                ; Hl -> menu of X-Y prefixed strings
  348. pmenu2:
  349.     call    clrwdt            ; Reset watchdog
  350.     mov    d,m            ; X address
  351.     inx    h
  352.     mov    e,m
  353.     inx    h
  354.     call    cmd$12            ; Cursor address the string now
  355. pmenu$string:
  356.     mov    a,m
  357.     inx    h            ; -> next byte
  358.     ora    a            ; Is it 00 ?
  359.     jrz    pmenu$eos        ; Exit on 00 to end ofline code
  360.     call    chn$out            ; Send the byte to the channel
  361.     jr    pmenu$string        ; Keep printing till the 00
  362. ;
  363. pmenu$eos:
  364.     mov    a,m            ; Is next byte 0FFh to terminate.
  365.     cpi    0ffh            ; end of menu ??
  366.     jrnz    pmenu2
  367. ;
  368.     pop    psw
  369.     pop    h
  370.     pop    d
  371.     jmp    exec$end
  372. ;
  373. ;
  374. cmd$12:        ; Cursor address the screen/channel
  375.     mvi    c,cur$adr        ; Cursor address command
  376.     call    chn$cmd            ; Process the command via the channel
  377.     jmp    exec$end
  378. ;
  379. cmd$13:        ; Clear screen
  380.     mvi    c,clr$scr        ; Clear all screen code
  381.     call    chn$cmd
  382.     jmp    exec$end
  383. ;
  384. ;
  385. cmd$14:        ; Clear to end of line
  386.     mvi    c,clr$eol        ; Clear to end of line
  387.     call    chn$cmd
  388.     jmp    exec$end
  389. ;
  390. cmd$15:        ; Clear to end of screen
  391.     mvi    c,clr$eos        ; Clear to end of screen code
  392.     call    chn$cmd
  393.     jmp    exec$end
  394. ;
  395. cmd$16:        ; Select visual attribute
  396.     mvi    c,vid$att        ; Set visual attribute 
  397.     call    chn$cmd
  398.     jmp    exec$end
  399. ;
  400. cmd$17:        ; Print accumulator as 2 hex digits
  401. prhex:
  402.     push    psw
  403.     rrc
  404.     rrc
  405.     rrc
  406.     rrc
  407.     call    phexl
  408.     pop    psw
  409. phexl:    ani    0fh
  410.     adi    90h
  411.     daa
  412.     aci    40h
  413.     daa
  414.     call    chn$out
  415.     jmp    exec$end
  416. ;
  417. ;
  418. cmd$18:        ; Print accumulator as decimal
  419.     push    h
  420.     push    b
  421.     push    d
  422.     push    psw
  423.     mov    e,a
  424.     mvi    d,0
  425.     lxi    h,?result
  426.     call    hexbcd
  427.     lda    ?result + 1
  428.     mvi    c,0            ; LZB status register clear
  429.     call    ccoe            ; Print hundreds digit
  430. ; Second top
  431.     lda    ?result
  432.     push    psw
  433.     rar
  434.     rar
  435.     rar
  436.     rar
  437.     call    ccoe            ; Print tens digit
  438. ;
  439.     pop    psw
  440.     call    nibasc
  441.     call    chn$out            ; print units
  442. ;
  443.     pop    psw
  444.     pop    d
  445.     pop    b
  446.     pop    h
  447.     jmp    exec$end
  448. ;
  449. ;
  450. cmd$19:        ; Print DE as 4 hex digits
  451.     push    psw
  452.     push    d
  453.     mov    a,d
  454.     call    prhex
  455.     mov    a,e
  456.     call    prhex
  457.     pop    d
  458.     pop    psw
  459.     ret
  460.     jmp    exec$end
  461. ;
  462. ;
  463. cmd$20:        ; Print DE as decimal unsigned decimal, with LZB
  464.     push    h
  465.     push    d
  466.     push    b
  467.     lxi    h,?result
  468.     call    hexbcd            ; convert to ascii in internal buffer
  469. ;
  470. ; Now print the 5 digit number. Suppress leading digits.
  471.     lda    lzb$mode
  472.     mov    c,a            ; Load the flag
  473.     lda    ?result+2        ; Get the MSDigit
  474.     ani    0fh
  475.     call    ccoe            ; Conditional output with lzb
  476. ;
  477.     lda    ?result + 1
  478.     push    psw
  479.     rar
  480.     rar
  481.     rar
  482.     rar
  483.     call    ccoe
  484. ;
  485.     pop    psw
  486.     call    ccoe
  487. ;
  488.     lda    ?result            ; Least significant 2 digits
  489.     push    psw
  490.     rar
  491.     rar
  492.     rar
  493.     rar
  494.     call    ccoe
  495. ;
  496.     pop    psw
  497.     call    nibasc            ; Always print last digit
  498.     call    chn$out
  499.     pop    b
  500.     pop    d
  501.     pop    h
  502.     jmp    exec$end
  503. ;
  504. ;================================================================
  505. ;
  506. ;     Print HLDE as a 32 bit decimal number
  507. ;
  508. ;================================================================
  509. ;
  510. cmd$21:        ; Print HLDE as 32 bit unsigned decimal
  511.     push    h
  512.     push    b
  513. ;
  514.     call    convert$hlde
  515. ;
  516. ; ---------------- Now print the result ----------------
  517. ;
  518. ;  Use the specified leading zero print type.
  519. ;
  520.     mvi    b,05            ; bytes = 10 digits
  521.     lda    lzb$mode
  522.     mov    c,a            ; Load leading zero printing type
  523.     lxi    h,?result+4        ; -> MSDigit
  524. lzb$hlde:
  525.     mov    a,m
  526.     rar
  527.     rar
  528.     rar
  529.     rar
  530.     call    ccoe
  531. ; See if last digit and if so, force the number out.
  532.     mov    a,b
  533.     cpi    1
  534.     jnz    lz$hlde1
  535.     mvi    c,080h            ; Force digits out of lz printer
  536. lz$hlde1:
  537.     mov    a,m
  538.     call    ccoe
  539. ;
  540.     dcx    h            ; -> next byte
  541.     djnz    lzb$hlde
  542. ;
  543.     pop    b
  544.     pop    h
  545.     ret
  546. ;
  547. ;----------------------------------------------------------------
  548. ; Convert 32 bits HLDE into 10 ascii decimal digits in the
  549. ; ?result buffer.
  550. ;----------------------------------------------------------------
  551. ;
  552. convert$hlde:
  553.     sded    ?binnum            ; save LSW
  554.     shld    ?binnum + 2        ; Save MSW
  555. ;
  556. ; Do the conversion
  557.     lxi    h,?result        ; -> result buffer
  558.     mvi    b,5            ; bytes to clear
  559. hlde1:
  560.     mvi    m,00
  561.     inx    h
  562.     djnz    hlde1            ; clear 5 bytes = 10 digits
  563. ;
  564.     mvi    b,32            ; 32 bits to convert
  565. hlde$loop:
  566.     lxi    h,?binnum
  567.     mvi    c,4            ; bytes in the binary number
  568.     xra    a            ; clear carry
  569. h$rloop:
  570.     mov    a,m
  571.     ral
  572.     mov    m,a
  573.     inx    h
  574.     dcr    c
  575.     jnz    h$rloop            ; keep rotating till C = 0
  576. ;
  577.     lxi    h,?result        ; restore the result address
  578.     mvi    c,5            ; 5 byte result = 10 digits
  579. ;
  580. h$bloop:
  581.     mov    a,m
  582.     adc    m
  583.     daa
  584.     mov    m,a            ; save
  585.     inx    h
  586.     dcr    c
  587.     jnz    h$bloop
  588. ;
  589.     djnz    hlde$loop        ; do for all bits requited.
  590. ;
  591.     ret
  592. ;
  593. ;----------------------------------------------------------------
  594. ;        Set the LZB Mode
  595. ;
  596. ; LZB modes
  597. ;    00 = normal LZB, default
  598. ;    01 = Force all characters out
  599. ;    02 = Space fill all leading zeros
  600. ;----------------------------------------------------------------
  601. ;
  602. cmd$22:        ; Set leading Zero blanking mode
  603.     push    b
  604.     mvi    c,080h        ; 80 hex internally = nolzbing
  605.     cpi    2
  606.     jrz    cmd$22$do
  607. ;
  608.     mvi    c,040h        ; 40h internally = lzb
  609.     cpi    1
  610.     jrz    cmd$22$do
  611.     mvi    c,0        ; All else = 0 so normal lzbing.
  612. ;
  613. cmd$22$do:
  614.     mov    a,c
  615.     sta    lzb$mode
  616.     pop    b
  617.     jmp    exec$end
  618. ;
  619.     page
  620. ;================================================================
  621. ;    ---- Read a text string ----
  622. ;
  623. ; This routine reads a line of input from the console and puts it into
  624. ; a standard CP/M console buffer pointed to by DE on entry. This is
  625. ; a little nicer that CP/M as it allows buffers to be pre-initialized 
  626. ; so that it is printed when the buffer is input so that defaults can
  627. ; be loaded before entry of data, then edited.
  628. ;
  629. ; On Entry
  630. ;    DE -> console buffer max size byte
  631. ;
  632. ; On Exit
  633. ;    buffer filled from console to max size limit
  634. ;    All registers preserved
  635. ;
  636. ;================================================================
  637. ;
  638. cmd$23:
  639. get$txt:
  640.     push    psw
  641.     ldax    d            ; get buffer size in bytes
  642.     ora    a
  643.     jz    cbuff$end
  644.     push    h
  645.     push    b
  646.     push    d
  647.     xchg                ; put string address into HL
  648.     mov    c,a            ; Now C = buffer maximum size
  649. init:
  650.     mvi    b,00            ; characters read = 0
  651.     inx    h            ; hl -> size of character read now
  652. ;
  653. ; Here we detect if there is some data in the buffer to be pre printed
  654. ; and if there is the we print it.
  655. ;
  656.     mov    a,m            ; get number of chars. in the buffer
  657.     inx    h            ; point to string space now.
  658.     ora    a
  659.     jrz    rdloop
  660. ; Print the initialized character string, save the size for later
  661.     mov    b,a
  662.     push    b            ; save
  663. init2:
  664.     mov    a,m            ; get the character
  665.     inx    h            ; point to next string space byte
  666.     call    dspchr            ; print it, maybe control character
  667.     djnz    init2            ; print all characters
  668.     pop    b            ; restore # of characters
  669. ;
  670. ;
  671. ; On entry here HL-> string space, next free byte, B = number of characters
  672. ; in the string. C = number of bytes in the buffer.
  673. ;
  674. rdloop:
  675.     call    chn$inp            ; Fetch a character
  676.     cpi    0dh            ; end if carriage return
  677.     jrz    exitrd            ; exit
  678.     cpi    0ah
  679.     jrz    exitrd
  680.     cpi    08            ; backspace ??
  681.     jrnz    rdlp1            ; if not then continue
  682.     call    backsp            ; else backspace
  683.     jr    rdloop            ; keep on backspacing
  684. rdlp1:
  685.     cpi    018h            ; delete line ?
  686.     jrnz    rdlp2
  687. del1:
  688.     call    backsp            ; delete a character
  689.     jrnz    del1            ; keep on till all character deaded
  690.     jr    rdloop            ; start again ebonettes
  691. ;
  692. ; If here we check if the buffer is full. If so we ring the bell
  693. rdlp2:
  694.     mov    e,a            ; save the character
  695.     mov    a,b            ; load byte count
  696.     cmp    c            ; is it equal to the maximum ?
  697.     jrc    strch            ; store the character if not full
  698. ;
  699.     mvi    a,7            ; Else load the bell code
  700.     call    chn$out            ; And send to ring the bell
  701.     jr    rdloop            ; get more characters
  702. ;
  703. ; Buffer not full so save the character
  704. strch:
  705.     mov    a,e            ; get character
  706.     mov    m,a            ; save it
  707.     inx    h            ; point to next buffer byte
  708.     inr    b            ; increment byte count
  709.     call    dspchr            ; display the (maybe control) character
  710.     jr    rdloop            ; do again, more characters
  711. ;
  712. ; Display a control character by preceeding it with a  '^'
  713. ;
  714. dspchr:
  715.     cpi    020h            ; was it a space ?
  716.     jnc     chn$out            ; if not then print & return
  717.     mov    e,a            ; else save character
  718.     mvi    a,'^'            ; indicate a control character
  719.     call    chn$out
  720.     mov    a,e            ; restore character
  721.     adi    040h            ; make printable
  722.     jmp     chn$out
  723. ;
  724. ; Send a backspace and detect if at the start of the line.
  725. ;
  726. backsp:
  727.     mov    a,b            ; get character count
  728.     ora    a
  729.     rz                ; return if line empty
  730.     dcx    h            ; decrement byte pointer
  731.     mov    a,m            ; get the character
  732.     cpi    020h            ; is it a control character ?
  733.     jrnc    bsp1            ; if not then delete 1 char only
  734.     call    bsp            ; send a backspace
  735. bsp1:
  736.     call    bsp            ; backspace 1
  737.     dcr    b            ; one less string byte
  738.     ret
  739. ;
  740. ; Send the backspace
  741. bsp:
  742.     mvi    a,08
  743.     call    chn$out            ; Go back a char not req-r for cp/m
  744.     mvi    a,' '            ; erase the character
  745.     call    chn$out
  746.     mvi    a,08
  747.     jmp    chn$out            ; send and return
  748. ;
  749. ; Set the number of bytes read into the buffer byte at DE + 1.
  750. ;
  751. exitrd:
  752.     pop    d            ; restore all registers (buffer addr)
  753.     mov    a,b            ; get # of characters
  754.     inx    d
  755.     stax    d            ; save in characters read byte
  756.     dcx    d            ; restore de
  757. ;
  758.     pop    b
  759.     pop    h
  760. cbuff$end:
  761.     pop    psw
  762.     ora    a            ; Clear carry
  763.     ret
  764. ;
  765. ;
  766. cmd$24:        ; Read a hex number from channel
  767.     call    ihhl            ; Read HEX into HL
  768.     jmp    exec$end
  769. ;
  770. cmd$25:        ; Read a decimal number from channel
  771.     call    idhl            ; Read decimal into HL
  772.     jmp    exec$end
  773. ;
  774. cmd$26:        ; Print a space
  775. space:
  776.     mvi    a,' '
  777.     call    chn$out
  778.     jmp    exec$end
  779. ;
  780. cmd$27:        ; Do a carriage return and line-feed
  781.     mvi    a,cr
  782.     call    chn$out
  783.     mvi    a,lf
  784.     call    chn$out
  785.     jmp    exec$end
  786. ;
  787. cmd$28:        ; Push the current channel
  788.     push    h
  789.     push    b
  790.     push    d
  791. ;
  792.     call    psh$chn
  793. ;
  794.     pop    d
  795.     pop    b
  796.     pop    h
  797. ;
  798.     jmp    exec$end
  799. ;
  800. cmd$29:        ; Pop the current channel
  801.     push    h
  802.     push    b
  803.     push    d
  804. ;
  805.     call    pop$chn
  806. ;
  807.     pop    d
  808.     pop    b
  809.     pop    h
  810.     jmp    exec$end
  811. ;
  812. ;
  813. cmd$30:        ; Read RS-232 channel 0 (console)
  814.     call    con$inp
  815.     jmp    exec$end
  816. ;
  817. cmd$31:        ; Write to RS-232 channel 0 (console)
  818.     call    con$out
  819.     jmp    exec$end
  820. ;
  821. cmd$32:        ; Return RS-232 channel 0 input status
  822.     call    con$ist
  823.     jmp    exec$end
  824. ;
  825. cmd$33:        ; Return RS-232 channel 0 output status
  826.     call    con$ost
  827.     jmp    exec$end
  828. ;
  829. cmd$34:        ; Read real time clock
  830.     call    clk$rd
  831.     jmp    exec$end
  832. ;
  833. cmd$35:        ; Write to real time clock 
  834.     call    clk$wr
  835.     jmp    exec$end
  836. ;
  837. ;----------------------------------------------------------------
  838. ;    ==== Dinos Requirement ====
  839. ;
  840. ; Print an integer as if it were a price.
  841. ;----------------------------------------------------------------
  842. ;
  843. cmd$36:        ; 
  844.     push    h
  845.     push    d
  846.     push    b
  847.     lxi    h,?result
  848.     call    hexbcd            ; convert to ascii in internal buffer
  849. ;
  850.     mvi    a,'$'
  851.     call    chn$out            ; Print leading dollar sign
  852. ; Now print the 5 digit number. Suppress leading digits.
  853.     lda    lzb$mode
  854.     mov    c,a            ; Load the flag
  855.     lda    ?result+2        ; Get the MSDigit
  856.     ani    0fh
  857.     call    ccoe            ; Conditional output with lzb
  858. ;
  859.     lda    ?result + 1
  860.     push    psw
  861.     rar
  862.     rar
  863.     rar
  864.     rar
  865.     call    ccoe
  866. ;
  867.     pop    psw
  868.     call    ccoe
  869. ;
  870. ; Print a '.' then force the last two digits out.
  871.     mvi    a,'.'
  872.     call    chn$out
  873. ;
  874.     call    prn$last2        ; Print last 2 digits
  875.     pop    b
  876.     pop    d
  877.     pop    h
  878.     jmp    exec$end
  879. ;
  880. ;----------------------------------------------------------------
  881. ; Print a time in HH:MM format. This is a DINOS routine
  882. ; that is used a LOT.
  883. ;----------------------------------------------------------------
  884. ;
  885. cmd$37:        ;
  886.     push    h
  887.     push    d
  888.     push    b
  889. ;
  890. ; Do hours
  891.     lda    hrs
  892.     mov    e,a
  893.     mvi    d,0            ; DE = hours now.
  894.     lxi    h,?result
  895.     call    hexbcd            ; convert to ascii in internal buffer
  896.     call    prn$last2
  897. ;
  898.     mvi    a,':'
  899.     call    chn$out            ; Channel output print.
  900. ;
  901. ; Do minutes.
  902.     lda    min
  903.     mov    e,a
  904.     mvi    d,0            ; DE = Minutes now.
  905.     lxi    h,?result
  906.     call    hexbcd            ; convert to ascii in internal buffer
  907.     call    prn$last2
  908. ;
  909.     pop    b
  910.     pop    d
  911.     pop    h
  912.     jmp    exec$end
  913. ;
  914. ; A subroutine to print the least significant 2 digits of a
  915. ; converted number. This is used to force out a time and 
  916. ; for printing a PRICE where the last 2 digits are required.
  917. ;
  918. prn$last2:
  919.     lda    ?result            ; Least significant 2 digits
  920.     push    psw
  921.     rar
  922.     rar
  923.     rar
  924.     rar
  925.     call    nibasc
  926.     call    chn$out            ; Print low nibble. Was high nibble
  927. ;
  928.     pop    psw
  929.     call    nibasc            ; Always print last digit
  930.     jmp    chn$out
  931. ;
  932. ;----------------------------------------------------------------
  933. ;     ---- Print DE as a time. ----
  934. ;
  935. ; On Entry
  936. ;   D = hours
  937. ;   E = minutes
  938. ;----------------------------------------------------------------
  939. ;
  940. cmd$38:        ;
  941.     push    h
  942.     push    d
  943.     push    b
  944. ;
  945.     push    d
  946. ;
  947.     mov    e,d            ; Make E = hours
  948.     mvi    d,0            ; DE = hours now.
  949.     lxi    h,?result
  950.     call    hexbcd            ; convert to ascii in internal buffer
  951.     call    prn$last2
  952. ;
  953.     mvi    a,':'
  954.     call    chn$out            ; Channel output print.
  955. ;
  956. ; Do minutes.
  957.     pop    d
  958.     mvi    d,0            ; DE = Minutes now.
  959.     lxi    h,?result
  960.     call    hexbcd            ; convert to ascii in internal buffer
  961.     call    prn$last2
  962. ;
  963.     pop    b
  964.     pop    d
  965.     pop    h
  966.     jmp    exec$end
  967. ;
  968. ;
  969. cmd$39:        ;
  970.     mvi    c,gxy$cmd        ; Get current X-Y address
  971.     call    chn$cmd
  972.     jmp    exec$end
  973. ;
  974. cmd$40:        ; Clear watchdog
  975.     call    clr$wdt
  976.     jmp    exec$end
  977. ;
  978. cmd$41:        ; Read switch number in (A)
  979.     jmp    exec$end
  980. ;
  981. cmd$42:        ; Clear all leds
  982.     call    zro$led
  983.     jmp    exec$end
  984. ;
  985. cmd$43:        ; Set led number in A
  986.     call    set$led
  987.     jmp    exec$end
  988. ;
  989. cmd$44:        ; Clear led number in A
  990.     call    clr$led
  991.     jmp    exec$end
  992. ;
  993. cmd$45:        ; Toggle led number in A
  994.     call    tog$led
  995.     jmp    exec$end
  996. ;
  997. ;
  998. ; ---- Do a delay of milliseconds in DE ----
  999. ;
  1000. cmd$46:        ; Delay milliseconds in DE
  1001.     call    ms$delay
  1002.     jmp    exec$end
  1003. ;
  1004. cmd$47:        ; Turn on beeper
  1005.     call    set$bel
  1006.     jmp    exec$end
  1007. ;
  1008. cmd$48:        ; Turn off the beeper
  1009.     call    clr$bel
  1010.     jmp    exec$end
  1011. ;
  1012. ; Save DE as 10's of milliseconds of delay time for bell to be
  1013. ; on then turn on the bell. After the time, the bell will be
  1014. ; turned off by the interrupt handler.
  1015. ;
  1016. cmd$49:
  1017.     sded    bel$cnt        ; Load delay time in 10's of Milliseconds
  1018.     call    set$bel        ; Turn on
  1019.     jmp    exec$end
  1020. ;
  1021. ;
  1022. cmd$50:        ; 
  1023.     jmp    exec$end
  1024. ;
  1025. cmd$51:        ; Compare two strings
  1026.     jmp    exec$end
  1027. ;
  1028. cmd$52:        ; Compare string to table of strings
  1029.     jmp    exec$end
  1030. ;
  1031. cmd$53:        ; Index via A into  table of words and retun vaue in A
  1032.     lda    usr$a
  1033.     mov    c,a
  1034.     xchg            ; HL -> table now
  1035.     dad    b        ; HL = HL + offset
  1036.     dad    b        ;           (2 * offset)
  1037.     mov    e,m
  1038.     inx    h
  1039.     mov    d,m
  1040.     xchg            ; HL = the word
  1041.     jmp    exec$end
  1042. ;
  1043. cmd$54:        ; Convert low nibble of A to ascii
  1044. nibasc:
  1045.     ani    0fh
  1046.     adi    090h
  1047.     daa
  1048.     aci    040h
  1049.     daa
  1050.     jmp    exec$end
  1051. ;
  1052. cmd$55:        ; Capitalize accumulator
  1053. caps:
  1054.     cpi    'a'            ; Convert lower case to upper
  1055.     jc    exec$end
  1056.     cpi    'z'+1
  1057.     jnc    exec$end
  1058.     ani    5fh
  1059.     jmp    exec$end
  1060. ;
  1061. cmd$56:        ; Test memory
  1062.     jmp    exec$end
  1063. ;
  1064. cmd$57:        ; Put A into the EXEC code display flag. 00 = off
  1065.     lda    usr$a
  1066.     sta    dsp$flg        ; Save to the display flag
  1067.     jmp    exec$end
  1068. ;
  1069. ;
  1070. cmd$58:        ; Clear cumulatinve checksum
  1071.     push    h
  1072.     lxi    h,0            ; do a clear
  1073.     shld    rem
  1074.     pop    h
  1075.     jmp    exec$end
  1076. ;
  1077. ;
  1078. ;----------------------------------------------------------------
  1079. ; This routine generates a polynomial to generate a 16 bit cyclic-
  1080. ; redundancy checksum. The checksum is able to distinguish between 
  1081. ; two very similar data items since any differences in quickly 
  1082. ; show up in the checksum. This is useful for data integrity checking 
  1083. ; in disk files or over modem lines etc.
  1084. ;
  1085. ; A cyclic-redundancy-check number is generated by the ccitt 
  1086. ; standard polynominal:
  1087. ;   x^16 + x^15 + x^13 + x^7 + x^4 + x^2 + x + 1
  1088. ;
  1089. ; The routine for doing this is in 8080  and comes from the 
  1090. ; 'EDN' magazine June 5 1979 issue Page 84. Written By Fred Gutman.
  1091. ;
  1092. ;            Written        R.C.H.        22/09/83
  1093. ;            Last Update    R.C.H.        26/08/88
  1094. ;----------------------------------------------------------------
  1095. ;
  1096. ; On Entry
  1097. ;    DE -> Memory to be checksummed
  1098. ;    BC = bytes to be checksummed
  1099. ;
  1100. ; On Exit
  1101. ;    HL = result
  1102. ;    psw lost
  1103. ;----------------------------------------------------------------
  1104. ;
  1105. cmd$59: 
  1106.     push    d
  1107.     push    b
  1108.     lhld    rem
  1109. ;
  1110. loop59:
  1111.     call    clr$wdt            ; Stop watchdog
  1112.     ldax    d            ; Get character
  1113.     sta    mess            ; Save character
  1114. ;
  1115.         mov     a,h            ; High 8 bits of remainder
  1116.         ani     128            ; q-bit mask
  1117.         push    psw            ; save status
  1118.         dad     h            ; 2 x r(x)
  1119.         lda     mess            ; message bit in lsb
  1120.         add     l
  1121.         mov     l,a
  1122.         pop     psw
  1123.         jz      qb2            ; if q-bit is zero
  1124. qb:
  1125.     mov     a,h
  1126.     xri     0a0h            ; ms half of gen. poly
  1127.         mov     h,a
  1128.         mov     a,l
  1129.         xri     97h            ; ls half of gen. poly
  1130.         mov     l,a
  1131. qb2:
  1132.     inx    d            ; -> next memory variable
  1133.     dcx    b            ;    Decrement byte count
  1134.     mov    a,b
  1135.     ora    c
  1136.     jnz    loop59            ; Keep on till BC = 0
  1137. ;
  1138.     shld    rem            ; Save result
  1139.     pop    b
  1140.     pop    d
  1141.     jmp    exec$end
  1142. ;
  1143.     page
  1144. ;================================================================
  1145. ;    Interrupt vector routines.
  1146. ;
  1147. ; These routines are used to fill in the jump table in ram
  1148. ; so that an external program can tie into the interrupt system.
  1149. ; The CLR routine loads a simple RETURN into ALL the vectors 
  1150. ; so that they are effectively turned OFF. 
  1151. ;
  1152. ;
  1153. ; On Entry to these routines,
  1154. ;  DE -> Driver address
  1155. ;
  1156. ; On Exit
  1157. ;  ????$hdlr is loaded with a JMP <address>
  1158. ;----------------------------------------------------------------
  1159. ;
  1160. cmd$60:    ; DE-install all interrupt handlers. This is handy.
  1161.     mvi    a,(ret)
  1162.     sta    con$hdlr
  1163.     sta    aux$hdlr
  1164.     sta    tmr0$hdlr
  1165.     sta    tmr1$hdlr
  1166.     sta    int0$hdlr
  1167.     sta    int1$hdlr
  1168.     sta    int2$hdlr
  1169.     sta    csio$hdlr
  1170.     jmp    exec$end
  1171. ;
  1172. cmd$61:
  1173.     sded    con$hdlr+1    ; Save address
  1174.     mvi    a,(JMP)        ; Load a jump instruction
  1175.     sta    con$hdlr
  1176.     jmp    exec$end
  1177. ;
  1178. cmd$62:
  1179.     sded    aux$hdlr+1    ; Save address
  1180.     mvi    a,(JMP)        ; Load a jump instruction
  1181.     sta    aux$hdlr
  1182.     jmp    exec$end
  1183. ;
  1184. ;
  1185. cmd$63:
  1186.     sded    tmr0$hdlr+1    ; Save address
  1187.     mvi    a,(JMP)        ; Load a jump instruction
  1188.     sta    tmr0$hdlr
  1189.     jmp    exec$end
  1190. ;
  1191. ;
  1192. cmd$64:
  1193.     sded    tmr1$hdlr+1    ; Save address
  1194.     mvi    a,(JMP)        ; Load a jump instruction
  1195.     sta    tmr1$hdlr
  1196.     jmp    exec$end
  1197. ;
  1198. ;
  1199. cmd$65:
  1200.     sded    int0$hdlr+1    ; Save address
  1201.     mvi    a,(JMP)        ; Load a jump instruction
  1202.     sta    int0$hdlr
  1203.     jmp    exec$end
  1204. ;
  1205. ;
  1206. cmd$66:
  1207.     sded    int1$hdlr+1    ; Save address
  1208.     mvi    a,(JMP)        ; Load a jump instruction
  1209.     sta    int1$hdlr
  1210.     jmp    exec$end
  1211. ;
  1212. ;
  1213. cmd$67:
  1214.     sded    int2$hdlr+1    ; Save address
  1215.     mvi    a,(JMP)        ; Load a jump instruction
  1216.     sta    int2$hdlr
  1217.     jmp    exec$end
  1218. ;
  1219. ;
  1220. cmd$68:
  1221.     sded    csio$hdlr+1    ; Save address
  1222.     mvi    a,(JMP)        ; Load a jump instruction
  1223.     sta    csio$hdlr
  1224.     jmp    exec$end
  1225. ;
  1226. ;
  1227. ;
  1228. cmd$69:
  1229.     jmp    exec$end
  1230. ;
  1231. ;
  1232. exec$end:            ; All routines EXIT via this point
  1233.     ret
  1234. ;
  1235. ;----------------------------------------------------------------
  1236. ;         Select a channel.
  1237. ;
  1238. ; Do this by moving the addresses of the channel routines
  1239. ; into the channel addresses in ram.
  1240. ;
  1241. ; On Entry
  1242. ;    A = channel number to be used
  1243. ;----------------------------------------------------------------
  1244. ;
  1245. sel$chn:
  1246.     ora    a
  1247.     rz
  1248.     cpi    max$chn + 1
  1249.     rnc
  1250. ;
  1251.     push    h
  1252.     push    b
  1253.     push    d
  1254. ;
  1255.     sta    cur$chn
  1256.     mov    c,a
  1257.     mvi    b,0        ; BC = offset into a table of words
  1258.     lxi    h,ini$tbl    ; -> table of initialization addresses
  1259.     lxi    d,chn$ini    ; The one to be loaded
  1260.     call    load$chn    ; Load words
  1261. ;
  1262.     lxi    h,ist$tbl
  1263.     lxi    d,chn$ist
  1264.     call    load$chn
  1265. ;
  1266.     lxi    h,ost$tbl
  1267.     lxi    d,chn$ost
  1268.     call    load$chn
  1269. ;
  1270.     lxi    h,inp$tbl
  1271.     lxi    d,chn$inp
  1272.     call    load$chn
  1273. ;
  1274.     lxi    h,out$tbl
  1275.     lxi    d,chn$out
  1276.     call    load$chn
  1277. ;
  1278.     lxi    h,iocmd$tbl
  1279.     lxi    d,chn$cmd
  1280.     call    load$chn
  1281.  
  1282.     mvi    a,(jmp)        ; Load a jump instruction
  1283.     sta    chn$ini        ; Channel Initialize
  1284.     sta    chn$ist        ; Channel Input status
  1285.     sta    chn$ost        ; Channel Output status
  1286.     sta    chn$inp        ; Channel Input
  1287.     sta    chn$out        ; Channel Output
  1288.     sta    chn$cmd        ; Channel command processor
  1289.     pop    d
  1290.     pop    b
  1291.     pop    h
  1292.     ret
  1293. ;
  1294. load$chn:
  1295.     push    b
  1296.     dad    b
  1297.     dad    b        ; HL -> word address of routine
  1298. ; HL -> address
  1299. ; DE -> Channel jmp instruction
  1300.     inx    d        ; -> address 
  1301.     lxi    b,2        ; 2 bytes to move
  1302.     ldir            ; Copy address from tyable -> channel vector
  1303.     pop    b
  1304.     ret
  1305. ;
  1306. ;----------------------------------------------------------------
  1307. ;        Tables I/O routines.
  1308. ; Note that this table sets up the order in which the channel
  1309. ; numbers work so that changing the order completely changes
  1310. ; what is called.
  1311. ;
  1312. ; This table has been setup AS;
  1313. ; Channel 1 = Console
  1314. ;         2 = Aux device
  1315. ;         3 = spare
  1316. ;         4 = spare
  1317. ;         5 = Printer
  1318. ;         6 = LCD driver
  1319. ;
  1320. ini$tbl:        ; Channel Initialize
  1321.     dw    dev$null
  1322.     dw    con$ini        ; Console Init required
  1323.     dw    aux$ini        ; AUX init
  1324.     dw    dev$null    ; No spare init required
  1325.     dw    dev$null    ; No spare init required
  1326.     dw    prn$ini        ; No centronic printer init required
  1327.     dw    lcd$ini        ; Initialize the LCD driver
  1328. ;
  1329. ist$tbl:        ; Channel Input status
  1330.     dw    dev$null
  1331.     dw    con$ist        ; Console port
  1332.     dw    aux$ist        ; AUX port
  1333.     dw    dev$null    ; Spare serial 1
  1334.     dw    dev$null    ; Spare serial 2
  1335.     dw    dev$null    ; Printer
  1336.     dw    dev$null    ; LCD
  1337. ;
  1338. ost$tbl:        ; Channel Output status
  1339.     dw    dev$null
  1340.     dw    con$ost        ; Console port
  1341.     dw    aux$ost        ; AUX port
  1342.     dw    dev$null    ; Spare serial 1
  1343.     dw    dev$null    ; Spare serial 2
  1344.     dw    prn$ost        ; Printer ready flag
  1345.     dw    lcd$ost        ; LCD ready fla
  1346. ;
  1347. inp$tbl:        ; Channel Input
  1348.     dw    dev$null
  1349.     dw    con$inp        ; Console port
  1350.     dw    aux$inp        ; AUX port
  1351.     dw    dev$null    ; Spare serial 1
  1352.     dw    dev$null    ; Spare serial 2
  1353.     dw    dev$null    ; Printers dont recrive
  1354.     dw    dev$null    ; LCDs dont receive
  1355. ;
  1356. out$tbl:        ; Channel Output
  1357.     dw    dev$null
  1358.     dw    con$out        ; Console port
  1359.     dw    aux$out        ; AUX port
  1360.     dw    dev$null    ; Spare serial 1
  1361.     dw    dev$null    ; Spare serial 2
  1362.     dw    prn$out        ; Printer output
  1363.     dw    lcd$out        ; LCD output
  1364. ;
  1365. iocmd$tbl:        ; Channel I/O Command processors
  1366.     dw    dev$null
  1367.     dw    con$cmd        ; Console port
  1368.     dw    aux$cmd        ; AUX port
  1369.     dw    dev$null    ; Spare serial 1
  1370.     dw    dev$null    ; Spare serial 2
  1371.     dw    dev$null    ; No Printer command processor
  1372.     dw    lcd$cmd        ; LCD output command processor
  1373. ;
  1374. ; The null driver. Simple return/no function.
  1375. ;
  1376. dev$null:
  1377.     ret
  1378. ;
  1379. ;----------------------------------------------------------------
  1380. ;        Push / Pop Initialize
  1381. ;
  1382. ; Setup push / pop counter and the next save address pointer.
  1383. ;
  1384. ;         Push Channel
  1385. ;
  1386. ; Take all the channel jump addresses and save them into the 
  1387. ; "push" stack in ram.
  1388. ;
  1389. ;        POP Channel
  1390. ; Do the reverse. Copy the saved jumps back into the ram area.
  1391. ;
  1392. ;----------------------------------------------------------------
  1393. ;
  1394. psh$pop$ini:
  1395.     xra    a
  1396.     sta    psh$cnt        ; No pushes yet
  1397.     lxi    h,psh$stk    ; -> stack to push into
  1398.     shld    psh$ptr        ; Save as a push pointer
  1399.     ret
  1400. ;
  1401. ; -- Push a channel by copying to ram. --
  1402. ;
  1403. psh$chn:
  1404.     lda    psh$cnt
  1405.     cpi    psh$max        ; At max ?
  1406.     jrz    psh$pop$err
  1407.     inr    a
  1408.     sta    psh$cnt        ; Flags another push done
  1409. ; Do the push
  1410.     lxi    b,psh$siz    ; Push size
  1411.     lded    psh$ptr        ; DESTINATION -> next free ram
  1412.     lxi    h,channels    ;      SOURCE -> channel routines.
  1413.     ldir            ; Copy channels -> ram
  1414.     sded    psh$ptr        ; Saves the new pointer
  1415.     jmp    psh$pop$ok    ; Exit with an "ok" flag.
  1416. ;
  1417. ; Get from stack area to the jump vectors
  1418. ;
  1419. pop$chn:
  1420.     lda    psh$cnt
  1421.     ora    a
  1422.     jz    psh$pop$err
  1423.     dcr    a
  1424.     sta    psh$cnt        ; One less to pop later.
  1425. ;
  1426. ; Move data from stack area back to the jump vectors
  1427.     lhld    psh$ptr             ; Get the source address
  1428.     dcx    h             ; -> last USED byte in the "stack"
  1429.     lxi    d,channels + psh$siz - 1 ; -> Destination
  1430.     lxi    b,psh$siz         ; Bytes
  1431.     lddr                 ; Move DOWN
  1432.     inx    h             ; Adjust to -> next free
  1433.     shld    psh$ptr             ; Save end pointer
  1434. ;
  1435. psh$pop$ok:
  1436.     xra    a
  1437.     ora    a
  1438.     ret
  1439. ;
  1440. ; -- On an error, return a carry --
  1441. ;
  1442. psh$pop$err:
  1443.     xra    a
  1444.     stc            ; CARRY = error
  1445.     ret
  1446. ;
  1447. ;----------------------------------------------------------------
  1448. ;     Initialize I/O Channels.
  1449. ;
  1450. ; On Entry
  1451. ;    If A = 0 
  1452. ;      initialize all I/O channels
  1453. ;
  1454. ;       > 0
  1455. ;      only initialize the required channel.
  1456. ;----------------------------------------------------------------
  1457. ;
  1458. init$chan:
  1459.     ora    a
  1460.     jnz    chn$ini        ; > 0 and initialize current channel only
  1461. ;
  1462. ; ELSE...
  1463. ;     ---- Initialize ALL the I/O Channels in the system ----
  1464. ;
  1465. init$chan$all:
  1466.     push    h
  1467.     push    b
  1468.     mvi    c,1        ; Starting channel
  1469.     mvi    b,6        ; Total channels
  1470. icl:
  1471.     call    clr$wdt
  1472.     mov    a,c        ; Channel number
  1473.     push    b
  1474.     call    sel$chn        ; Select a channel
  1475.     call    chn$ini        ; Initialize channel.
  1476.     pop    b
  1477.     inr    c
  1478.     call    clr$wdt
  1479.     djnz    icl
  1480. ;
  1481.     pop    b
  1482.     pop    b
  1483.     ret
  1484. ;
  1485. ;================================================================
  1486. ; The following two entry points read ascii from the KEYBOARD
  1487. ; and convert to a number into the HL register pair.
  1488. ;
  1489. ; 1) IDHL    Read a DECIMAL number into HL. Note that the result 
  1490. ;        is HEX still so that it can be used as a counter 
  1491. ;        ie. 100 input returns HL = 64.
  1492. ; 2) IHHL    Read a HEX number into HL
  1493. ;
  1494. ; Both routines return zero in A if the last character read was a legal
  1495. ; digit else A will contain the error character.
  1496. ;================================================================
  1497. ;
  1498. idhl:
  1499.     call    get$buf            ; load the buffer from console
  1500.     lxi    h,0
  1501.     lda    bufsiz
  1502.     ora    a
  1503.     rz                ; quit if nothing read
  1504. ; Now read the buffer, condition, put into HL.
  1505.     push    b            ; save
  1506.     push    d
  1507.     mov    b,a            ; use as a counter
  1508. idhl2:
  1509.     call    get$chr            ; Get a character
  1510. ; Convert to a binary value now of 0..9
  1511.     sui    '0'            
  1512.     jrc    inp$err         ; Error since a non number
  1513.     cpi    9 + 1            ; Check if greater than 9
  1514.     jrnc    inp$err
  1515. ; Now shift the result to the right by multiplying by 10 then add in this digit
  1516.     mov    d,h            ; copy HL -> DE
  1517.     mov    e,l
  1518.     dad    h            ; * 2
  1519.     dad    h            ; * 4
  1520.     dad    d            ; * 5
  1521.     dad    h            ; * 10 total now
  1522. ; Now add in the digit from the buffer
  1523.     mov    e,a
  1524.     mvi    d,00
  1525.     dad    d            ; all done now
  1526. ; Loop on till all characters done
  1527.     djnz    idhl2            ; do next character from buffer
  1528.     jr    inp$end            ; all done
  1529. ;
  1530. ;
  1531. ;----------------------------------------------------------------
  1532. ; Read a HEX number into HL from the keyboard.
  1533. ;----------------------------------------------------------------
  1534. ;
  1535. ihhl:
  1536.     call    get$buf
  1537.     lxi    h,00
  1538.     lda    bufsiz
  1539.     ora    a
  1540.     rz                ; return if no character read
  1541. ;
  1542.     push    b
  1543.     push    d            ; save
  1544.     mov    b,a
  1545. ;
  1546. ihhl2:
  1547.     call    get$chr            ; get a character
  1548. ; Now convert the nibble to a hex digit 0..F
  1549.     sui    '0'
  1550.     cpi    9 + 1
  1551.     jrc    ihhl3            ; mask in then
  1552.     sui    'A'-'0'-10
  1553.     cpi    16
  1554.     jrnc    inp$err
  1555. ;
  1556. ; Shift the result left 4 bits and MASK in the digit in A
  1557. ihhl3:
  1558.     dad    h
  1559.     dad    h
  1560.     dad    h
  1561.     dad    h            ; shifted right 4 now
  1562.     ora    l            ; mask in the digit
  1563.     mov    l,a            ; put back
  1564.     djnz    ihhl2            ; keep on till all digits done
  1565. ;
  1566. inp$end:
  1567.     xra    a            ; Zero is a goo exit
  1568. inp$end2:
  1569.     pop    d
  1570.     pop    b
  1571.     ret
  1572. ;
  1573. inp$err:    ; Here when a non digit is encountered
  1574.     lda    buftmp
  1575.     jr    inp$end2
  1576. ;
  1577. ; Subroutines for shared code etc....
  1578. ;
  1579. get$buf:    ; Load the buffer from the screen via CBUFF.
  1580.     push    d
  1581.     mvi    a,6
  1582.     sta    buffer            ; Set up ready for user
  1583.     xra    a
  1584.     sta    buffer+1        ; clear buffer original value
  1585.     lxi    d,buffer
  1586.     call    get$txt            ; Get a text buffer full
  1587.     pop    d
  1588.     lxi    h,buftxt        ; point to the start of text
  1589.     shld    bufadr            ; set up a pointer
  1590.     lxi    h,00            ; clear the result register
  1591.     ret
  1592. ;
  1593. ; Get a character from the buffer, capitalize it on the way
  1594. ;
  1595. get$chr:
  1596.     push    h
  1597.     lhld    bufadr
  1598.     mov    a,m            ; get the character
  1599.     sta    buftmp            ; save the character
  1600.     inx    h            ; point to next character
  1601.     shld    bufadr
  1602.     pop    h            ; restore
  1603. ; Now capitalize it
  1604.     jmp    caps
  1605. ;
  1606. ;================================================================
  1607. ;
  1608. ;     Convert the hex number in DE into DECIMAL in HL
  1609. ;
  1610. ;================================================================
  1611. ;
  1612. hexbcd:
  1613.     sded    ?binnum            ; save the number to convert
  1614.     push    b
  1615.     push    h
  1616. ; Do the conversion
  1617.     mvi    b,3            ; 3 bytes to clear
  1618. hexbcd1:
  1619.     mvi    m,00
  1620.     inx    h
  1621.     djnz    hexbcd1            ; clear 3 bytes
  1622. ;
  1623.     mvi    b,16            ; 16 bits to convert
  1624. cloop:
  1625.     lxi    h,?binnum
  1626.     mvi    c,2            ; bytes in the binary number
  1627.     xra    a            ; clear carry
  1628. rloop:
  1629.     mov    a,m
  1630.     ral
  1631.     mov    m,a
  1632.     inx    h
  1633.     dcr    c
  1634.     jnz    rloop            ; keep rotating till C = 0
  1635. ;
  1636.     pop    h
  1637.     push    h            ; restore the result address
  1638.     mvi    c,3            ; 3 byte result = 6 digits
  1639. ;
  1640. bloop:
  1641.     mov    a,m
  1642.     adc    m
  1643.     daa
  1644.     mov    m,a            ; save
  1645.     inx    h
  1646.     dcr    c
  1647.     jnz    bloop
  1648. ;
  1649.     djnz    cloop            ; do for all bits requited.
  1650. ;
  1651.     pop    h
  1652.     pop    b            ; clear stack
  1653.     ret                ; trick code here boys
  1654. ;
  1655. ;----------------------------------------------------------------
  1656. ; Conditional print of A. This is part of the leading zero 
  1657. ; printing routine. It prints a '0' if register C is > 0.
  1658. ; If the number in A is > 0, register C is set to 80 so
  1659. ; that all following numbers are forced out.
  1660. ;
  1661. ;----------------------------------------------------------------
  1662. ;
  1663. ccoe:
  1664.     ani    0000$1111b        ; Eliminate top 4 bits
  1665.     ora    a            ; Low nibble > 0 ?
  1666.     jrz    ccoe1
  1667.     setb    7,c            ; Set top bit.
  1668. ;
  1669. ccoe1:
  1670.     bit    7,c            ; Forcing number out ?
  1671.     jrz    ccoe$space        ; If not, exit.
  1672.     call    nibasc            ; Else convert A to ascii
  1673.     jmp    chn$out            ; And channel print it.
  1674. ;
  1675. ccoe$space:
  1676.     bit    6,c
  1677.     rz                ; Clea bit 6 = not space fill
  1678.     mvi    a,' '
  1679.     jmp    chn$out            ; Print a channel space
  1680. ;
  1681. ; ================ D A T A ================
  1682. ;
  1683.     dseg
  1684. ;
  1685. bel$cnt    ds    2
  1686. ;
  1687. mess:   db      0       ; char for crc calc
  1688. rem:    dw      0       ;crc remainder storage
  1689. ;
  1690. ?binnum    ds    10
  1691. ?result    ds    10
  1692. buftmp    db    00            ; A temporary character store
  1693. bufadr:    db    00,00
  1694. buffer:    db    6            ; maximum characters
  1695. bufsiz:    db    00            ; characters read
  1696. buftxt:    db    00,00,00,00,00,00    ; text buffer
  1697. ;
  1698. lzb$mode ds    1        ; Leading zero blanking mode
  1699. ;
  1700. cur$chn    ds    1        ; Current output channel
  1701. ;
  1702. dsp$flg    ds    1        ; EXEC display code flag.
  1703. exe$dbg    ds    1        ; EXEC debugging flag.
  1704. ;
  1705. cur$cmd    ds    1        ; Current command
  1706. usr$a    ds    1        ; Saved Accumulator
  1707. usr$sp    ds    2        ; Saved SP
  1708. usr$de    ds    2        ; Saved DE
  1709. usr$hl    ds    2        ; Saved HL
  1710. usr$bc    ds    2        ; Saved BC
  1711. ;
  1712. channels:
  1713. chn$ini    ds    3        ; Channel Initialize
  1714. chn$ist    ds    3        ; Channel Input status
  1715. chn$ost    ds    3        ; Channel Output status
  1716. chn$inp    ds    3        ; Channel Input
  1717. chn$out    ds    3        ; Channel Output
  1718. chn$cmd    ds    3        ; Channel COMMAND Processor
  1719. ;
  1720. ; The following are the flags and buffer to impliment the push/pop
  1721. ; facility that allows the user to push and pop channel pointers.
  1722. ;
  1723. psh$ptr    ds    2        ; -> next free byte in "push" stack
  1724. psh$cnt    ds    1        ; Push counter
  1725. ;
  1726. psh$stk    ds    psh$max * psh$siz     ; Channel push stack
  1727. ;
  1728. ; Interrupt handlers. These are either RET or JMP instructions. The
  1729. ; exec routines are provided to select either.
  1730. ;
  1731. con$hdlr:
  1732.     ds    3
  1733. aux$hdlr:
  1734.     ds    3
  1735. tmr0$hdlr:
  1736.     ds    3
  1737. tmr1$hdlr:
  1738.     ds    3
  1739. int0$hdlr:
  1740.     ds    3
  1741. int1$hdlr;
  1742.     ds    3
  1743. int2$hdlr:
  1744.     ds    3
  1745. csio$hdlr:
  1746.     ds    3
  1747. ;
  1748. ;
  1749.     end
  1750. ;
  1751. ;