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

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