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