home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol164 / pdl80.mac < prev    next >
Encoding:
Text File  |  1984-04-29  |  33.8 KB  |  1,119 lines

  1.  
  2. ;    =======================================================
  3. ;    REC module for the operators and predicates pertaining
  4. ;    to the pushdown list, other than the most important
  5. ;    ones already contained in the REC nucleus.  They are
  6. ;
  7. ;        arithmetic
  8. ;
  9. ;            +    sum modulo 2**16
  10. ;            -    difference modulo 2**16
  11. ;            *    product modulo 2**16
  12. ;            /    remainder, quotient
  13. ;            =    equality
  14. ;            ~    complement or negative
  15. ;            d    decrement, false on zero
  16. ;            ^    increment
  17. ;            N    comparison
  18. ;
  19. ;        modification of arguments
  20. ;
  21. ;            H    hex ASCII string to binary
  22. ;            !    binary to hex ASCII string
  23. ;            %    restrict argument to one byte
  24. ;            \    embed argument in two bytes
  25. ;            &    exchange top arguments
  26. ;            |    concatinate top arguments
  27. ;
  28. ;        block movements
  29. ;
  30. ;            G    fetch a block from memory
  31. ;            g    address fetch
  32. ;            r    replace address by contents
  33. ;            u    incrementing byte fetch
  34. ;            y    incrementing word fetch
  35. ;            P    put buffer block in memory
  36. ;            S    store block in memory
  37. ;            s    store into buffer
  38. ;            v    incrementing byte store
  39. ;            m    move arg to end of PDL space
  40. ;            n    recover arg from end of PDL
  41. ;
  42. ;        generate pointers
  43. ;
  44. ;            c    reserve block, generate pointer
  45. ;            p    put px, py-px on PDL
  46. ;            l    put pz on PDL
  47. ;            $    form addr of variable cell
  48. ;
  49. ;    -------------------------------------------------------
  50. ;    Version of REC released during the summer school, 1980
  51. ;    -------------------------------------------------------
  52. ;
  53. ;             PDL80  -  Copyright (C) 1980
  54. ;            Universidad Autonoma de Puebla
  55. ;                 All Rights Reserved
  56. ;
  57. ;              [Harold V. McIntosh, 28 August 1980]
  58. ;
  59. ;    May 20, 1983 - Predicate N for comparison
  60. ;    May 22, 1983 - Multiple purpose arithmetic
  61. ;    May 28, 1983 - & exchanges arguments of any length
  62. ;    May 28, 1983 - ~ discontinued: use m&n instead
  63. ;    May 28, 1983 - ~ for complement or negative
  64. ;    July 7, 1983 - $ with char arg yields subroutine addr
  65. ;    =======================================================
  66.  
  67. ;    Often used constant.
  68.  
  69. ze    equ    0000H
  70.  
  71. ;    Addresses located in REC's RAM area.
  72.  
  73.     ext    px,py,pz        ;pushdown pointers
  74.  
  75. ;    Service routines located in the REC nucleus.
  76.  
  77.     ext    mduc,miuc
  78.     ext    narg,oarg,rarg
  79.     ext    psiz,ucl,cucl
  80.     ext    skp,sieq,rer,rr1,rtn,rnd,vrt
  81.  
  82. ;    =======================================================
  83. ;    A collection of subroutines for two-byte arithmetic,
  84. ;    including loading and storage of the 8080 registers
  85. ;    from the pushdown list.
  86. ;    =======================================================
  87.  
  88. ;    -------------------------------------------------------
  89. ;    Load and store subroutines for 2-byte arithmetic.
  90. ;    -------------------------------------------------------
  91.  
  92. ;    Arithmetic Load Negative.  Load the negative of the
  93. ;    top argument into BC, erase it from PDL, load the
  94. ;    second into DE, but hold the space it occupied to
  95. ;    write an eventual result.  Place zero in HL.  Used
  96. ;    principally by subtraction and division.
  97.  
  98. arln::    lhld    px    ;pointer to the top argument
  99.     mov    a,m    ;fetch low order byte
  100.     cma        ;complement it
  101.     mov    c,a    ;place the result in register C
  102.     inx    h    ;advance to high order byte
  103.     mov    a,m    ;fetch it into accumulator
  104.     cma        ;complement it
  105.     mov    b,a    ;and place it in register B
  106.     inx    b    ;negative is complement plus one
  107.     call    ucl    ;erase top argument conserving BC
  108.     mov    e,m    ;HL now points to second argument
  109.     inx    h    ;which will be loaded into DE
  110.     mov    d,m    ;one byte at a time
  111.     lxi    h,ze    ;load zero into HL
  112.     ret
  113.  
  114. ;    Arithmetic Store.  Reuses the two bytes left by the
  115. ;    last argument in an arithmetic operation. That avoids
  116. ;    closing off the previous argument and verifying that
  117. ;    space is available, which would have to be done if a
  118. ;    new argument were to be formed. Use ARST if the result
  119. ;    lies in HL; ARSU if it lies in DE.
  120.  
  121. arst::    xchg        ;put the result in DE
  122. arsu::    lhld    px    ;get the address of the PDL
  123.     mov    m,e    ;save the low order byte
  124.     inx    h    ;advance the pointer
  125.     mov    m,d    ;store the high order byte
  126.     inx    h    ;pointer always shows next free space
  127.     shld    py    ;pointer to end of argument
  128.     ret
  129.  
  130. ;    Push a one-byte value onto the PDL.  The value to be
  131. ;    pushed should be placed on the 8080's stack in the
  132. ;    low byte position (say by using <push psw>) before
  133. ;    calling PUON.
  134.  
  135. puon::    lxi    b,01H    ;one byte is required
  136.     call    narg    ;close old variable, reserve space
  137.     xchg        ;put destination into DE for now
  138.     pop    h    ;source was pushed before calling
  139.     xthl        ;but it lies under the return address
  140.     xchg        ;destination ought to be in HL
  141.     mov    m,e    ;store byte, which is low order
  142.     inx    h    ;pointer to next byte
  143.     shld    py    ;close new argument
  144.     ret
  145.  
  146. ;    Push a two-byte value onto the PDL.  The value to be
  147. ;    pushed should be placed on the 8080's stack before
  148. ;    calling PUTW.
  149.  
  150. putw::    lxi    b,02H    ;two bytes are required
  151.     call    narg    ;close old variable, reserve space
  152.     xchg        ;put destination into DE
  153.     pop    h    ;source was pushed before calling
  154.     xthl        ;but it lies under the return address
  155.     xchg        ;destination ought to be in HL
  156.     mov    m,e    ;store low order byte
  157.     inx    h    ;on to high order destination
  158.     mov    m,d    ;store high order byte
  159.     inx    h    ;always leave pointer in good condition
  160.     shld    py    ;close top argument
  161.     ret
  162.  
  163. ;    (&) Exchange top two arguments. Using m and n additional
  164. ;    permutations are possible: for three arguments use the
  165. ;    following table.
  166. ;
  167. ;        (123)        ;no movement
  168. ;        (132)    m&n    ;exchange second two
  169. ;        (213)    &    ;exchange top two
  170. ;        (231)    &m&n    ;cyclic exchange
  171. ;        (312)    m&n&    ;anticyclic exchange
  172. ;        (321)    &m&n&    ;exchange first and third
  173.  
  174. exch::    lhld    py    ;end of top argument
  175.     xchg        ;
  176.     lhld    px    ;beginning of top argument
  177.     mov    a,e    ;their difference is length
  178.     sub    l    ;which we get byte by byte
  179.     mov    c,a    ;
  180.     mov    a,d    ;
  181.     sbb    h    ;
  182.     mov    b,a    ;BC = py-px
  183.     dcx    h    ;uncover under argument
  184.     mov    d,m    ;high byte
  185.     dcx    h    ;then low byte
  186.     mov    e,m    ;DE = old px, HL = old py
  187.     mov    a,e    ;is under argument present?
  188.     ora    d    ;not if DE holds 0000
  189.     cz    rer    ;no argument
  190.     mov    a,l    ;length of under argument
  191.     sub    e    ;also byte by byte
  192.     mov    l,a    ;
  193.     mov    a,h    ;
  194.     sbb    d    ;
  195.     mov    h,a    ;HL = old py-px
  196.     mov    a,l    ;are lengths equal?
  197.     sub    c    ;check byte by byte
  198.     jnz    xtne    ;cant' be, go xtne
  199.     mov    a,h    ;compare high bytes
  200.     sbb    b    ;
  201.     jnz    xtne    ;xtne if not same length
  202.     lhld    px    ;HL=top px, DE=under px, BC=size
  203. xteq:    mov    a,c    ;loop when arguments have same size
  204.     ora    b    ; because they can be exchanged in
  205.     rz        ; place
  206.     dcx    b    ;
  207.     push    b    ;
  208.     mov    c,m    ;
  209.     ldax    d    ;
  210.     mov    m,a    ;
  211.     mov    a,c    ;
  212.     stax    d    ;
  213.     inx    h    ;
  214.     inx    d    ;
  215.     pop    b    ;
  216.     jmp    xteq    ;
  217.  
  218. ;    If the arguments are of different lengths, we copy the
  219. ;    under argument as a new argument on top of the pushdown
  220. ;    list, then move what was the top argument down to fill
  221. ;    the space vacated, and finally move the under argument
  222. ;    back down on top of that so that no holes are left.
  223.  
  224. xtne:    push    h    ;under size
  225.     push    h    ;
  226.     lhld    px    ;HL=top origin
  227.     xthl        ;HL=under size, PD=top origin
  228.     push    b    ;top size
  229.     push    d    ;under origin
  230.     push    d    ;under origin
  231.     mov    c,l    ;BC=under size
  232.     mov    b,h    ;
  233.     call    narg    ;be sure there's space, new px
  234.     pop    d    ;under origin
  235.     call    miuc    ;make duplicate of under arg
  236.     pop    h    ;under org is now destination
  237.     pop    b    ;top size
  238.     pop    d    ;top origin
  239.     push    h    ;under origin
  240.     call    miuc    ;overwrite under arg w/ top arg
  241.     pop    d    ;under origin
  242.     mov    m,e    ;pointer spanning new under arg
  243.     inx    h    ; has to be put in place before
  244.     mov    m,d    ; we can establish the new top arg
  245.     inx    h    ;
  246.     push    h    ;org of new top arg
  247.     lhld    px    ;org of copy of old under arg
  248.     xthl        ;exchange them
  249.     shld    px    ;update px, it is now dest
  250.     pop    d    ;copy of old under is now source
  251.     pop    b    ;old under size
  252.     call    miuc    ;old under is on top and in place
  253.     shld    py    ;its end is now py
  254.     ret
  255.  
  256. ;    Load top three arguments into BC,DE,HL.  In
  257. ;    reality so many permutations exist for places to put
  258. ;    the arguments as they are taken off the REC stack that
  259. ;    they are simply transferred to the 8080 stack, to be
  260. ;    popped into the desired registers on return from the
  261. ;    corresponding call.  It is assumed that all quantities
  262. ;    involved in these transactions are of two bytes.  A
  263. ;    sequence of entry points is provided so as to pop off
  264. ;    one, two, or three arguments.
  265.  
  266. thrg::    lhld    px    ;get pointer to top argument
  267. thrl::    mov    e,m    ;enter here if HL already loaded
  268.     inx    h    ;low byte loaded, advance to high
  269.     mov    d,m    ;DE holds two bytes loaded indirectly
  270.     xchg        ;place them in HL
  271.     xthl        ;thence to 8080 stack under top address
  272.     push    h    ;keep the return address on the stack
  273.     call    ucl    ;pop top argument, load HL from px
  274. twol::    mov    e,m    ;continue, or entry for two args
  275.     inx    h    ;low byte loaded, advance to high
  276.     mov    d,m    ;DE has two bytes loaded through HL
  277.     xchg        ;place them in HL
  278.     xthl        ;tuck them onto 8080 stack
  279.     push    h    ;beneath return address
  280.     call    ucl    ;pop argument, put px in HL
  281. onel::    mov    e,m    ;continue, or entry for one argument
  282.     inx    h    ;low byte loaded, advance to high
  283.     mov    d,m    ;two bytes in DE loaded through HL
  284.     xchg        ;pass them to HL
  285.     xthl        ;and onto the 8080 stack
  286.     push    h    ;keep the 8080 return address on top
  287.     jmp    ucl    ;pop the last argument, quit
  288.  
  289. ;    Transfer px, py-px to 8080's stack.
  290.  
  291. arpo:    pop    b    ;set aside the return address
  292.     lhld    px    ;load px
  293.     xchg        ;put it in DE
  294.     lhld    py    ;load py
  295.     mov    a,l    ;HL = py-px
  296.     sub    e    ;
  297.     mov    l,a    ;
  298.     mov    a,h    ;
  299.     sbb    d    ;
  300.     mov    h,a    ;
  301.     push    d    ;put px on stack first
  302.     push    h    ;then py-px
  303.     push    b    ;put return where it can be used
  304.     ret        ;and use it
  305.  
  306. ;    Load up the 8080's registers with data for the two
  307. ;    arguments of a binary operator. Only the top argument
  308. ;    is popped, supposing that the other argument will be
  309. ;    reused to hold the result. Taking 1 as the top argument
  310. ;    and 2 as the second, BC holds their common size, HL
  311. ;    holds org1 and DE org2. RER is called if the sizes
  312. ;    are different, or if the common size exceeds 255. The
  313. ;    low byte of the size is placed in A.
  314.  
  315. args:    call    arpo    ;put org1, siz1 on 8080's stack
  316.     call    ucl    ;pop top argument
  317.     call    arpo    ;put org2, siz2 on 8080's stack
  318.     pop    b    ;siz 1
  319.     pop    h    ;org 1
  320.     pop    d    ;siz 2
  321.     mov    a,e    ;compare lengths
  322.     sub    c    ;
  323.     mov    a,d    ;
  324.     sbb    b    ;
  325.     cnz    rer    ;arguments not same length
  326.     mov    a,b    ;
  327.     ora    a    ;
  328.     cnz    rer    ;unreasonable length
  329.     pop    d    ;org 2
  330.     mov    a,c    ;length into A
  331.     ret
  332.  
  333. ;    -------------------------------------------------------
  334. ;    Two-byte arithmetic according to the four operations.
  335. ;    -------------------------------------------------------
  336.  
  337. ;    (+)  Add top registers on pdl: <a,b,+> leaves (a+b).
  338. ;    The sum is calculated modulo 2**16, no evidence of any
  339. ;    overflow remains behind. However, if the arguments are
  340. ;    one byte in length, their logical OR is calculated.
  341.  
  342. sum::    call    args    ;load 8080 registers with arg pointers
  343.     cpi    01    ;
  344.     jz    sum1    ;single byte argument means OR
  345.     cpi    02    ;
  346.     jz    sum2    ;double byte argument means sum
  347.     call    rer    ;unrecognized argument type
  348.  
  349. sum1:    ldax    d    ;fetch arg1
  350.     ora    m    ;OR it to arg2
  351.     mov    m,a    ;reuse arg2 for result
  352.     ret
  353.  
  354. sum2:    ldax    d    ;fetch arg1
  355.     add    m    ;add arg2
  356.     mov    m,a    ;reuse arg2 for result
  357.     inx    d    ;repeat for second byte
  358.     inx    h    ;
  359.     ldax    d    ;
  360.     adc    m    ;taking carry into account
  361.     mov    m,a    ;
  362.     ret
  363.  
  364. ;    (-)  Subtract top from next: <a,b,-> leaves (a-b).
  365. ;    Reverse subtraction can be accomplished by exchanging
  366. ;    arguments: write <a,b,&,-> to get (b-a).  Subtraction
  367. ;    is carried out modulo 2**16; thus -1 = FFFF hex. If
  368. ;    the arguments are one byte in length, their exclusive
  369. ;    or, XOR, is calculated.
  370.  
  371. dif::    call    args    ;load 8080 registers with arg pointers
  372.     cpi    01    ;1-byte argument is logical, take XOR
  373.     jz    dif1    ;
  374.     cpi    02    ;2-byte arg is arithmetic, take diff
  375.     jz    dif2    ;
  376.     call    rer    ;other arg is error
  377. dif1:    ldax    d    ;XOR bytes
  378.     xra    m    ;
  379.     mov    m,a    ;
  380.     ret
  381. dif2:    xchg        ;subreact byte pairs
  382.     ldax    d    ;
  383.     sub    m    ;
  384.     stax    d    ;
  385.     inx    d    ;
  386.     inx    h    ;
  387.     ldax    d    ;
  388.     sbb    m    ;
  389.     stax    d    ;
  390.     ret
  391.  
  392. ;    (*)  Multiply top: <a,b,*> leaves (a*b).  The product
  393. ;    is for integer arithmetic, modulo 2**16, and so is not
  394. ;    directly suitable for a 32-bit product.  Should it turn
  395. ;    out that both arguments are one byte in length, their
  396. ;    logical AND is calculated.
  397.  
  398. mpy::    call    args    ;load 8080 registers with arg pointers
  399.     cpi    01    ;1-byte argument, take AND
  400.     jz    mpy1    ;
  401.     cpi    02    ;2-byte arguments are multiplied
  402.     jz    mpy2    ;
  403.     call    rer    ;unrecognized argument type
  404. mpy1:    ldax    d    ;AND of single bytes
  405.     ana    m    ;
  406.     mov    m,a    ;
  407.     ret
  408. mpy2:    mov    c,m    ;one factor in BC
  409.     inx    h    ;
  410.     mov    b,m    ;
  411.     xchg        ;
  412.     mov    e,m    ;other factor in DE
  413.     inx    h    ;
  414.     mov    d,m    ;
  415.     lxi    h,0000    ;initial HL = 0000
  416.     call    pr    ;HL=BC*DE
  417.     jmp    arst    ;store product
  418.  
  419. ;    (/)  Divide top: <a,b,/> leaves rem(a/b), int(a/b).
  420. ;    Reverse division is possible by exchanging arguments;
  421. ;    thus <b,a,&,/> leaves rem(b/a), int(b/a).  If just
  422. ;    the remainder is required, write <a,b,/,L>, while if
  423. ;    only the quotient is desired, write <a,b,/,&,L>, and
  424. ;    finally, if the order of the remainder and quotient is
  425. ;    not satisfactory, they can be exchanged.  The division
  426. ;    is unsigned integer division.  It can also be used to
  427. ;    split a two-byte word into two parts through division
  428. ;    by the corresponding power of two.
  429.  
  430. dvd::    call    arln    ;-b into BC, a into DE, 0 into HL
  431.     call    qn    ;quotient with args in 8080 registers
  432.     push    d    ;put quotient to one side
  433.     call    arst    ;store remainder over a from HL
  434.     call    rarg    ;close argument, ready to reuse next
  435.     pop    d    ;recover quotient
  436.     jmp    arsu    ;store quotient over b from DE
  437.  
  438. ;    (~)  Complement or negate the top of the pushdown list
  439.  
  440. comp::    call    arpo    ;px and py-px to 8080 stack
  441.     pop    b    ;py-px to BC
  442.     pop    h    ;and px to HL
  443.     mov    a,b    ;test argument length
  444.     ora    a    ;
  445.     cz    rer    ;reject 2-byte length
  446.     mov    a,c    ;
  447.     cpi    01    ;logical complement of single byte
  448.     jz    com1    ;
  449.     cpi    02    ;negative of double byte
  450.     jz    com2    ;
  451.     call    rer    ;reject other lengths
  452. com1:    mov    a,m    ;complement
  453.     cma        ;
  454.     mov    m,a    ;
  455.     ret
  456. com2:    mov    a,m    ;negatve
  457.     cma        ;
  458.     mov    e,a    ;
  459.     inx    h    ;
  460.     mov    a,m    ;
  461.     cma        ;
  462.     mov    d,a    ;
  463.     inx    d    ;
  464.     mov    m,d    ;
  465.     dcx    h    ;
  466.     mov    m,e    ;
  467.     ret
  468.  
  469. ;    (^)  Increment the top of the pushdown list.
  470.  
  471. incr::    lhld    px    ;pointer to argument
  472.     mov    a,m    ;fetch low byte
  473.     adi    01H    ;increment (inr doesn't affect carry)
  474.     mov    m,a    ;replace low byte
  475.     inx    h    ;advance pointer
  476.     mov    a,m    ;fetch high byte
  477.     aci    ze    ;high byte of increment
  478.     mov    m,a    ;replace high byte
  479.     ret
  480.  
  481. ;    (d)  Decrement top of PDL if it is not zero; otherwise
  482. ;    FALSE, erasing the counter.  Equivalent to ((0=;1-)).
  483.  
  484. decr::    lhld    px    ;fetch pointer to argument
  485.     mov    a,m    ;low byte of counter
  486.     sui    01H    ;decrement counter - dcr doesn't work
  487.     mov    m,a    ;replace low byte
  488.     inx    h    ;advance pointer
  489.     mov    a,m    ;fetch high byte
  490.     sbi    ze    ;high byte of decrement
  491.     mov    m,a    ;replace high byte
  492.     jnc    skp    ;no carry means TRUE
  493.     jmp    ucl    ;when FALSE, erase counter
  494.  
  495. ;    (N) Numerical comparison of top two elements on PDL. <a,b,N>
  496. ;    is true if a .LE. b; both arguments are erased irrespective
  497. ;    of the result.  Assuming numerical arguments means they are
  498. ;    two byte integers in the machine representation of addresses.
  499. ;    In the case of single byte arguments, their logical AND is
  500. ;    calculated, but they are both popped from the pushdown list.
  501. ;    N is FALSE if the AND is zero, meaning that if the bit tested
  502. ;    in one argument by using the other as a mask was zero, then
  503. ;    N failed.
  504.  
  505. ucn::    call    args    ;load 8080 registers with arg pointers
  506.     cpi    01    ;TEST one-byte arguments
  507.     jz    un1    ;
  508.     cpi    02    ;COMPARE two-byte arguments
  509.     jz    un2    ;
  510.     call    rer    ;reject others
  511. un1:    ldax    d    ;TEST
  512.     ana    m    ;
  513.     jz    ucl    ;
  514.     jmp    cucl    ;
  515. un2:    ldax    d    ;COMPARE
  516.     sub    m    ;
  517.     inx    d    ;
  518.     inx    h    ;
  519.     ldax    d    ;
  520.     sbb    m    ;
  521.     jc    ucl    ;
  522.     jmp    cucl    ;
  523.  
  524. ;    Carry out the modular product of two 16-bit numbers.
  525. ;    On entry, BC holds one factor, DE the other, and
  526. ;    HL should be zero.  On exit, BC is zero, DE is
  527. ;    unchanged, while HL holds the 16 bit modular product
  528. ;    which is the result of the multiplication.
  529.  
  530. pr:    mvi    a,10H    ;we want a 16 bit product
  531. pr1:    dad    h    ;shift partial product left
  532.     push    h    ;save it
  533.     mov    l,c    ;shift the factor in BC left
  534.     mov    h,b    ;can only be done placing it in HL
  535.     dad    h    ;high bit goes into carry flag
  536.     mov    c,l    ;shifted factor back into BC
  537.     mov    b,h    ;
  538.     pop    h    ;recover partial product
  539.     jnc    pr2    ;add 2nd factor according
  540.     dad    d    ;to high bit of 1st
  541. pr2:    dcr    a    ;counter for 16 bit product
  542.     jnz    pr1    ;repeat cycle
  543.     ret
  544.  
  545. ;    Calculate remainder, quotient of two 16-bit numbers. On
  546. ;    entry, BC holds the negative of the denominator, DE
  547. ;    holds the numerator, and HL should be zero. On exit,
  548. ;    BC is unchanged, DE holds the 16 bit quotient, and
  549. ;    HL holds the 16 bit remainder.
  550.  
  551. qn:    mvi    a,10H    ;we have a 16-bit quotient
  552. qn1:    dad    h    ;shift partial remainder left
  553.     xchg        ;we have to shift num/quot too
  554.     dad    h    ;
  555.     xchg        ;
  556.     jnc    qn2    ;bytes shifting out of DE enter HL
  557.     inx    h    ;
  558. qn2:    push    h    ;save partial numerator/remainder
  559.     dad    b    ;trial subtraction of denominator
  560.     pop    h    ;recover num/rem
  561.     jnc    qn3    ;if we can't subtract, just shift
  562.     dad    b    ;subtract the denominator
  563.     inx    d    ;add one to quotient low bit
  564. qn3:    dcr    a    ;count out 16 bits
  565.     jnz    qn1    ;repeat the cycle
  566.     ret
  567.  
  568. ;    -------------------------------------------------------
  569. ;    Conversion between binary and hexadecimal ASCII strings
  570. ;    -------------------------------------------------------
  571.  
  572. ;    Return if not hexadecimal. A unchanged if not hex, else
  573. ;    reduced to binary.
  574.  
  575. rnh::    cpi    'G'    ;no hex characters beyond F
  576.     jnc    rtn    ;
  577.     cpi    'A'    ;hex letters equal A or beyond
  578.     jc    rnd    ;otherwise test for decimal digit
  579.     sui    '7'    ;compensate the gap between 9 and A
  580.     ret
  581.  
  582. ;    Cummulation to convert a hex ASCII string to binary.
  583.  
  584. hxp::    dad    h    ;shift left 4 bits
  585.     dad    h    ;
  586.     dad    h    ;
  587.     dad    h    ;
  588.     ora    l    ;or in the nibble in the accumulator
  589.     mov    l,a    ;return it to HL
  590.     ret
  591.  
  592. ;    (H) Convert a hex ASCII string on the PDL into binary.
  593. ;    Whatever the length of the argument, conversion will be
  594. ;    made to a two-byte binary number.  Thus, if more than
  595. ;    four hex digits are present, the result will be reduced
  596. ;    modulo 2**16.  It should be noted that the conversion
  597. ;    starts with the first byte of the argument and procedes
  598. ;    onward.
  599.  
  600. he::    lxi    b,02H    ;two bytes required for result
  601.     call    oarg    ;check if they are available
  602.     lhld    py    ;fetch terminal address of string
  603.     mvi    m,ze    ;zero signals its end
  604.     lhld    px    ;fetch beginning of string
  605.     xchg        ;place pointer in DE
  606.     lxi    h,ze    ;place zero in HL to prime conversion
  607. h1:    ldax    d    ;fetch ASCII character
  608.     inx    d    ;ready for the next one
  609.     ora    a    ;check the terminator byte
  610.     jz    h2    ;when end reached, close off argument
  611.     call    rnh    ;if not hex digit, forget it all
  612.     call    hxp    ;otherwise times 16 plus new digit
  613.     jmp    h1    ;repeat the cycle
  614. h2:    xchg        ;binary number into DE
  615.     lhld    px    ;place to store the result
  616.     mov    m,e    ;store low byte
  617.     inx    h    ;on to high byte
  618.     mov    m,d    ;store high byte
  619.     inx    h    ;pointer must always be one ahead
  620.     shld    py    ;store terminal address
  621.     jmp    skp    ;TRUE return from predicate
  622.  
  623. ;    (!)  Convert a two-byte binary number into an ASCII
  624. ;    string.  A one-byte number will also be converted, but
  625. ;    into two nibbles rather than four, to serve in some
  626. ;    applications where the leading zeroes are not wanted.
  627.  
  628. hx::    call    psiz    ;decide whether it's one or two bytes
  629.     mov    a,c    ;suppose length less than 256
  630.     cpi    01H    ;see if it's one byte
  631.     jnz    hs    ;if not, continue elsewhere
  632. hn:    lxi    b,02H    ;two nibble result for 1 byte
  633.     call    oarg    ;see that there's that much space
  634.     lhld    px    ;pointer to argument
  635.     mov    e,m    ;load low bit
  636.     jmp    hsi    ;
  637. hs::    lxi    b,04H    ;four nibble result for 2 bytes
  638.     call    oarg    ;be sure there's space for it
  639.     lhld    px    ;pointer to first byte
  640.     mov    e,m    ;load low byte
  641.     inx    h    ;advance pointer
  642.     mov    d,m    ;load high byte
  643.     dcx    h    ;put pointer back to beginning
  644.     mov    a,d    ;separate high byte first
  645.     call    hsa    ;write out left nibble
  646.     mov    a,d    ;high byte again
  647.     call    hsb    ;write out right nibble
  648. hsi:    mov    a,e    ;separate low byte
  649.     call    hsa    ;write out left nibble
  650.     mov    a,e    ;low byte second trip
  651.     call    hsb    ;write out right nibble
  652.     shld    py    ;store end of argument
  653.     ret
  654.  
  655. hsa:    rrc        ;shift byte right four bits
  656.     rrc        ;
  657.     rrc        ;
  658.     rrc        ;
  659. hsb:    ani    0FH    ;mask in right nibble
  660.     adi    90H    ;prepare for some carries from <daa>
  661.     daa        ;create gap if nibble beyond 10
  662.     aci    40H    ;code for @ if we have a letter
  663.     daa        ;decide 3 for digit, 4 for letter
  664.     mov    m,a    ;record the ASCII digit
  665.     inx    h    ;pointer ready for next deposit
  666.     ret
  667.  
  668. ;    -------------------------------------------------------
  669. ;    Fetch and store bytes, addresses, and blocks to and fro
  670. ;    between the PDL and the memory.  The following chart
  671. ;    shows the relation between all the different operators
  672. ;    which are available.
  673. ;
  674. ;                byte    word    block
  675. ;                ----    ----    -----
  676. ;
  677. ;    replace            -    r    G
  678. ;    fetch, nonincrement    g    -    -
  679. ;    fetch, increment    u    y    -
  680. ;
  681. ;    store            -    -    S
  682. ;    store, increment    -    -    v
  683. ;    store w.r.t. limit    -    -    s
  684. ;    store into buffer    -    -    P
  685. ;
  686. ;    variable head cell    -    $    -
  687. ;
  688. ;    The main operators for saving and fetching variables
  689. ;    are G and S.  The remainder were especially chosen
  690. ;    on the one hand to scrutinize the memory under REC
  691. ;    control, and on the other to give the widest possible
  692. ;    latitude in defining variables in applications of REC.
  693. ;
  694. ;    The following chart shows how to employ variables:
  695. ;
  696. ;        'data' n$ S        define 2-byte variable
  697. ;         n$ r        fetch 2-byte variable
  698. ;        'data' ml n$ S    save fixed variable
  699. ;         n$ ryG        fetch fixed variable
  700. ;        'data' n$rs        redefine existing fixed var
  701. ;         kc Lml n$ S    create k-byte buffered variable
  702. ;         kc n$ S        alternative k-byte buffered var
  703. ;        'data' n$r P    redefine buffered variable
  704. ;         n$ ryLyG        fetch buffered variable
  705. ;
  706. ;    Memory can be examined bytewise with the following
  707. ;    combinations:
  708. ;
  709. ;        org g        fetch a byte, keep origin
  710. ;        org u        autoincrementing byte fetch
  711. ;        org v        autoincrementing byte store
  712. ;        org (g ... v:;)    read, modify, store, ready next
  713. ;        o1 o2 (u~...v&:;)    move from o1 to o2
  714. ;
  715. ;    -------------------------------------------------------
  716.  
  717. ;    (g) (u)  Fetch a byte from memory and leave on PDL. The
  718. ;    sequence <org, g> leaves <org, (org)[1 byte]> on PDL.
  719. ;    The sequence <org, u> leaves <org+1, (org)[1 byte]> on
  720. ;    PDL.
  721.  
  722. gb::    lhld    px    ;/g/ pointer to top argument
  723.     mov    e,m    ;fetch low byte of origin
  724.     inx    h    ;increment pointer
  725.     mov    d,m    ;fetch high byte of origin
  726.     jmp    gbj    ;if the origin is not to be incremented
  727. gbi::    lhld    px    ;/u/ pointer to arg, which is org
  728.     mov    a,m    ;fetch low byte of origin
  729.     mov    e,a    ;keep it as low byte of (DE)
  730.     adi    01H    ;increment A (inr doesn't change carry)
  731.     mov    m,a    ;replace incremented origin low byte
  732.     inx    h    ;move on to high byte
  733.     mov    a,m    ;load high byte in accumulator
  734.     mov    d,a    ;keep it as high byte of (DE)
  735.     aci    ze    ;now add in a carry if there was one
  736.     mov    m,a    ;and repl in memry as incrmented origin
  737. gbj:    push    d    ;save the original origin
  738.     lxi    b,01H    ;require space for one byte
  739.     call    narg    ;close old arg, check space, open new
  740.     pop    d    ;here's the origin we saved
  741.     ldax    d    ;fetch the byte there
  742.     mov    m,a    ;store on the PDL
  743.     inx    h    ;pointer always ready for next byte
  744.     shld    py    ;right deliniter of argument
  745.     ret
  746.  
  747. ;    (y)  Fetch two bytes from memory and leave on PDL.
  748. ;    The sequence <org, y> leaves <org+2, (org)[2 bytes]>
  749. ;    on PDL.
  750.  
  751. gw::    lhld    px    ;/ / pointer to the argument
  752.     mov    e,m    ;low byte of origin
  753.     inx    h    ;on to high byte
  754.     mov    d,m    ;now (DE) holds origin
  755.     jmp    gwj    ;common continuation of gw, gwi
  756. gwi::    lhld    px    ;/y/ pointer to the argument
  757.     mov    a,m    ;place low byte in A
  758.     mov    e,a    ;and also in E
  759.     adi    02H    ;origin to be incremented by 2
  760.     mov    m,a    ;and returned to the PDL
  761.     inx    h    ;move on to high byte
  762.     mov    a,m    ;load it into accumulator
  763.     mov    d,a    ;while keeping the original value in D
  764.     aci    ze    ;add in any carry from low byte
  765.     mov    m,a    ;incremented origin into memory
  766. gwj:    push    d    ;save the origin for later use
  767.     lxi    b,02H    ;require space for two bytes
  768.     call    narg    ;close old arg, check space, open new
  769.     pop    d    ;now we're ready for that origin
  770.     ldax    d    ;fetch the byte sitting there
  771.     mov    m,a    ;and store it on PDL
  772.     inx    d    ;there are two bytes to be moved
  773.     inx    h    ;and to be stored
  774.     ldax    d    ;fetch the second byte
  775.     mov    m,a    ;store it too
  776.     inx    h    ;keep the pointer moving along
  777.     shld    py    ;value's finished, store its end
  778.     ret
  779.  
  780. ;    (G)  Fetch a block from memory, leave on PDL.
  781. ;    <org,siz, G> leaves (org, ..., org+siz-1) on PDL.
  782.  
  783. ga::    call    bcld    ;load siz into (BC)
  784.     call    oarg    ;reuse the argument, but with siz bytes
  785.     lhld    px    ;fetch the destination address
  786.     mov    e,m    ;but the source address is stored there
  787.     inx    h    ;high byte of source address
  788.     mov    d,m    ;(DE) will hold the source address
  789.     dcx    h    ;(HL) will hold the destination address
  790.     call    miuc    ;block move subroutine
  791.     shld    py    ;(HL) holds the destination terminator
  792.     ret
  793.  
  794. ;    (S)  Store a block forward from the designated memory
  795. ;    location.  <'data' org S> stores 'data' starting at
  796. ;    org; leaves no residue on the PDL.
  797.  
  798. sa::    call    bcld    ;fetch destination origin
  799.     push    b    ;save it for a while
  800.     call    psiz    ;set up data length (BC), source (DE)
  801.     pop    h    ;put destination in (HL)
  802.     call    miuc    ;move by increment until count
  803.     jmp    ucl    ;pop the second argument too
  804.  
  805. ;    (v)  Store a block, leaving incremented address.
  806. ;    <org,'data' v> leaves org+size['data'] on PDL, stores
  807. ;    'data' starting from org.
  808.  
  809. sai::    call    psiz    ;determine length of data
  810.     push    d    ;set the source origin aside for moment
  811.     call    ucl    ;pop top argument, exposing second
  812.     mov    e,m    ;(HL) has px, which is destn address
  813.     inx    h    ;after loading low byte, go for high
  814.     mov    d,m    ;(DE) now has destination address
  815.     xchg        ;destination origin into (HL)
  816.     push    h    ;it will be needed later
  817.     dad    b    ;add siz to get destination end
  818.     xchg        ;put that into (DE), px into (HL)
  819.     mov    m,d    ;high byte of org+siz
  820.     dcx    h    ;on to low byte
  821.     mov    m,e    ;PDL now holds org+siz
  822.     pop    h    ;destination origin
  823.     pop    d    ;source origin
  824.     jmp    miuc    ;block move
  825.  
  826. ;    (s)  Store into an area of limited size. The sequence
  827. ;    <'data' org s> will store 'data' beginning at org+2,
  828. ;    supposing that siz('data') is less than or equal to
  829. ;    (org, org+1).  In either event no residue is left, but
  830. ;    an error notation is generated if the data doesn't fit.
  831. ;    No data at all is stored if all will not fit.  If it
  832. ;    matters to know how much of the space was used, the
  833. ;    operator P should probably be used instead.
  834.  
  835. lcs::    call    bcld    ;fetch destination origin
  836.     push    b    ;save it while calling psiz
  837.     call    psiz    ;determine length of data
  838.     pop    h    ;destination in (HL)
  839.     mov    a,m    ;low byte of capacity
  840.     inx    h    ;
  841.     sub    c    ;subtract low byte of data length
  842.     mov    a,m    ;high byte of capacity
  843.     inx    h    ;
  844.     sbb    b    ;subtract high byte of data length
  845.     cc    rer    ;note error, return if it won't fit
  846.     call    miuc    ;move by increment until count
  847.     jmp    ucl    ;pop second argument
  848.  
  849. ;    (P)  Store into a buffer and note length.  Used to
  850. ;    store data of variable length into an area whose
  851. ;    maximum length is fixed.  The buffer has the form
  852. ;
  853. ;       /available/used/data/data/.../data/.../end/
  854. ;
  855. ;    The sequence <'data' org P> will store the data
  856. ;    in the buffer beginning at org. (org, org+1) holds
  857. ;    the maximum length of data that may be stored in the
  858. ;    buffer, (org+2, org+3) is siz('data'), and 'data' is
  859. ;    stored from org+4 onward if it will fit.  If it will
  860. ;    not, P is a noop and error is set.
  861.  
  862. ucp::    call    bcld    ;pointer to destination
  863.     push    b    ;save destination while calling psiz
  864.     call    psiz    ;load (BC) with length of data
  865.     inx    b    ;data has to appear two bytes larger
  866.     inx    b    ;to include cell showing its size
  867.     pop    h    ;pointer to destination buffer header
  868.     mov    a,m    ;low byte of destination capacity
  869.     inx    h    ;
  870.     sub    c    ;subtract low byte of size
  871.     mov    a,m    ;high byte of destination capacity
  872.     inx    h    ;
  873.     sbb    b    ;subtract high byte of size
  874.     cc    rer    ;capacity exceeded: mark error, return
  875.     dcx    b    ;we want to store the true size
  876.     dcx    b    ;subtract out the two byte margin
  877.     mov    m,c    ;low byte into usage cell
  878.     inx    h    ;just keep moving along
  879.     mov    m,b    ;high byte usage cell
  880.     inx    h    ;ready to start moving data
  881.     call    miuc    ;move by increment until count
  882.     jmp    ucl    ;lift second argument, leave nothing
  883.  
  884. ;    (r)  Replace address on top of pdl by its contents.
  885.  
  886. ind::    lhld    px    ;pointer to top argument
  887.     mov    e,m    ;load low byte
  888.     inx    h    ;advance
  889.     mov    d,m    ;load high byte
  890.     xchg        ;(HL) now has top argument
  891.     mov    e,m    ;low byte of indirect address
  892.     inx    h    ;next byte
  893.     mov    d,m    ;high byte of indirect address
  894.     lhld    px    ;address of top argument again
  895.     mov    m,e    ;store low indirect byte
  896.     inx    h    ;to second byte
  897.     mov    m,d    ;store high indirect byte
  898.     ret
  899.  
  900. ;    ($)  Generate the address of the nth cell in the array
  901. ;    of variables, which is a block of two-byte addresses.
  902. ;    These cells may be used to store data directly - for
  903. ;    example counters or addresses - or indirectly through
  904. ;    pointers to the actual location of the data.  A one-byte
  905. ;    argument will get the location of a subroutine address.
  906. ;    This program has the structure that it does because the
  907. ;    variable table and the subroutine table are adjacent.
  908.  
  909. vble::    call    psiz    ;get argument length
  910.     mov    a,c    ;and put it in A
  911.     cpi    02H    ;2 bytes means variable
  912.     jz    vblf    ;so take care of it
  913.     lxi    b,02H    ;longer result than argument
  914.     call    oarg    ;so reserve another byte
  915.     lhld    px    ;get the argument
  916.     mov    e,m    ;
  917.     mvi    d,00H    ;and extend it with zeroes
  918.     jmp    vblg    ;go on to table lookup
  919. vblf:    lhld    px    ;pointer to argument
  920.     mov    e,m    ;fetch low byte of variable number
  921.     inx    h    ;advance pointer
  922.     mov    d,m    ;high byte of variable number
  923. vblg:    lhld    vrt    ;base address of variable table
  924.     dad    d    ;add variable's number
  925.     dad    d    ;add it again to multiply by 2
  926.     xchg        ;address of variable cell in table
  927.     lhld    px    ;location of argument on PDL
  928.     mov    m,e    ;store low byte
  929.     inx    h    ;return to low byte
  930.     mov    m,d    ;store high byte
  931.     inx    h    ;
  932.     shld    py    ;
  933.     ret
  934.  
  935. ;    (l)  Load pz onto PDL.  The combination ly is equivalent
  936. ;    to p or q in the sense that they identify an interval in
  937. ;    some structure.
  938.  
  939. lcl::    lhld    pz    ;fetch pz
  940.     push    h    ;putw requires arg on 8080 stack
  941.     call    putw    ;record two-byte argument
  942.     ret        ;can't use simply <jmp putw>
  943.  
  944. ;    (m)  Set aside top argument on PDL.  It is moved to the
  945. ;    other end of the array reserved for the PDL, which can
  946. ;    be used as a temporary storage stack without name.  The
  947. ;    mechanism by which pz is moved and the block size is
  948. ;    recorded makes this an attractive mechanism to create
  949. ;    storage space for REC variables.
  950.  
  951. lcm::    call    psiz    ;get length of top argument
  952.     push    b    ;save length
  953.     push    h    ;save source origin = py
  954.     call    ucl    ;pop top argument
  955.     pop    d    ;recover source origin
  956.     lhld    pz    ;load destination origin
  957.     call    mduc    ;block move from high addresses down
  958.     dcx    h    ;
  959.     pop    b    ;recover length
  960.     mov    m,b    ;store high byte of length
  961.     dcx    h    ;
  962.     mov    m,c    ;store low byte of length
  963.     shld    pz    ;record new PDL end
  964.     ret
  965.  
  966. ;    (n)  Recover segment which was set aside.
  967.  
  968. lcn::    lxi    b,ze    ;there won't be any net length change
  969.     call    narg    ;close old argument, ready for new
  970.     xchg        ;place destination origin in (DE)
  971.     lhld    pz    ;place source origin in (HL)
  972.     mov    c,m    ;place low byte of length in (BC)
  973.     inx    h    ;advance to high byte
  974.     mov    b,m    ;high byte completes length in (BC)
  975.     inx    h    ;the actual source origin
  976.     xchg        ;source in (DE), destination in (HL)
  977.     call    miuc    ;move by increment until count
  978.     shld    py    ;end of destination is end of argument
  979.     xchg        ;end of source is old pz
  980.     shld    pz    ;update pz
  981.     ret
  982.  
  983. ;    (|)  Concatinate the top arguments on the PDL.
  984.  
  985. conc::    call    psiz    ;get length of top argument
  986.     push    d    ;set it aside
  987.     call    ucl    ;pop top argument, set up pntrs to next
  988.     xchg        ;new py is destination
  989.     pop    d    ;old px is source
  990.     call    miuc    ;block move
  991.     shld    py    ;record new terminal address
  992.     ret
  993.  
  994. ;    (%)  Restrict multiple-byte argument to one byte.
  995.  
  996. pe::    call    psiz    ;get length of argument
  997.     mov    a,c    ;low order byte of length
  998.     ora    b    ;high order byte of length
  999.     rz        ;leave a null argument in peace
  1000.     xchg        ;put px into (HL)
  1001.     inx    h    ;add one to it
  1002.     shld    py    ;store as limit to the argument
  1003.     ret
  1004.  
  1005. ;    (\)  Embed a single byte in a pair.
  1006.  
  1007. ip::    lxi    b,02H    ;we want to have two bytes
  1008.     call    oarg    ;verify that that much space remains
  1009.     lhld    px    ;pointer to argument
  1010.     inx    h    ;pass over first byte
  1011.     mvi    m,ze    ;make high byte zero
  1012.     inx    h    ;pass on to next byte
  1013.     shld    py    ;record end of argument
  1014.     ret
  1015.  
  1016. ;    (p)  Put px and siz on the pushdown list.
  1017.  
  1018. gxs::    call    psiz    ;calculate length of top argument
  1019.     push    b    ;put length on 8080 stack
  1020.     push    d    ;put origin on 8080 stack
  1021.     call    putw    ;put top of 8080 stack on REC PDL
  1022.     call    putw    ;put the next item there too
  1023.     ret        ;can't combine <call, ret> into <jmp>
  1024.  
  1025. ;    (c) Reserve a block on the pushdown list. <n,c> creates
  1026. ;    a block of length n, then a pointer to itself. If n is
  1027. ;    2 or larger, n-2 is stored in the first two bytes of the
  1028. ;    block as a size indicator; no other initialization is
  1029. ;    made. Such an arrangement is useful if the block is to
  1030. ;    be used as a buffer. 
  1031.  
  1032. blok::    lhld    px    ;pointer to argument
  1033.     mov    a,m    ;fetch low byte
  1034.     mov    c,a    ;it will be used in (BC)
  1035.     sui    02H    ;subtract 2 for header
  1036.     mov    m,a    ;store low byte of header
  1037.     inx    h    ;on to second byte of argument
  1038.     mov    a,m    ;fetch high byte to accumulator
  1039.     mov    b,a    ;making up the rest of (BC)
  1040.     sbi    00H    ;take care of a possible borrow
  1041.     mov    m,a    ;store high byte of header
  1042.     call    oarg    ;is there enough space to reuse arg?
  1043.     shld    py    ;increment in (HL), it goes into py
  1044.     lhld    px    ;px has origin of block just formed
  1045.     push    h    ;putw expects argument on 8080 stack
  1046.     call    putw    ;record block origin as new argument
  1047.     ret        ;can't replace <call putw, ret> by jmp
  1048.  
  1049. ;    Load a single variable into (BC) from the pushdown
  1050. ;    list.  No register is sure to be preserved.
  1051.  
  1052. bcld::    lhld    px    ;pointer to argument
  1053.     mov    c,m    ;fetch low order byte
  1054.     inx    h    ;advance pointer
  1055.     mov    b,m    ;fetch high order byte
  1056.     jmp    ucl    ;erase argument [(BC) is unchanged]
  1057.  
  1058. ;    Load register pair (DE) from the pushdown list.
  1059. ;    (BC) will be preserved, (HL) not.
  1060.  
  1061. deld::    lhld    px    ;pointer to argument
  1062.     mov    e,m    ;fetch low order byte
  1063.     inx    h    ;advance pointer
  1064.     mov    d,m    ;fetch high order byte
  1065.     push    d    ;save (DE) on the 8080 stack
  1066.     call    ucl    ;erase argument
  1067.     pop    d    ;restore (DE) since UCL modified it
  1068.     ret
  1069.  
  1070. ;    (=)  Test the two top arguments on the pushdown list
  1071. ;    for equality.  The arguments may be of any length, but
  1072. ;    will be equal only when of the same length and composed
  1073. ;    of the same sequence of bytes. The top argument will be
  1074. ;    popped whatever the outcome, but when equality is true
  1075. ;    both will be popped.
  1076.  
  1077. eql::    call    psiz    ;obtain length of top argument
  1078.     push    d    ;save beginning of top argument
  1079.     call    ucl    ;lift top argument
  1080.     push    h    ;save beginning of under argument
  1081.     call    sieq    ;compare lengths
  1082.     pop    h    ;clean up 8080 stack
  1083.     pop    h    ;by popping two pushes
  1084.     ret        ;FALSE return for inequality
  1085.     mov    c,l    ;limit goes into (BC)
  1086.     mov    b,h    ;
  1087.     pop    d    ;under argument for comparison
  1088.     pop    h    ;over argument for comparison
  1089. ciul:    mov    a,c    ;check whether limit has been reached
  1090.     cmp    e    ;compare low bytes
  1091.     jnz    cil    ;low bytes disagree, can't be limit
  1092.     mov    a,b    ;compare high bytes
  1093.     cmp    d    ;
  1094.     jz    cucl    ;both agree, erase second arg, TRUE
  1095. cil:    ldax    d    ;fetch byte of one  argument
  1096.     cmp    m    ;compare byte of other argument
  1097.     rnz        ;disagree so FALSE
  1098.     inx    d    ;on to next byte
  1099.     inx    h    ;for both arguments
  1100.     jmp    ciul    ;repeat the cycle
  1101.  
  1102. ;    -------------------------------------------------------
  1103. ;    Some of the service routines which are likely to be
  1104. ;    external references in other modules are:
  1105. ;
  1106. ;        arln    arithmetic load negative same pair
  1107. ;        arst    arithmetic store from (HL)
  1108. ;        arsu    arithmetic store from (DE)
  1109. ;        puon    push one byte on PDL
  1110. ;        putw    push address on PDL
  1111. ;        thrl    load  three arguments onto 8080 stack
  1112. ;        twol    load two arguments onto 8080 stack
  1113. ;        onel    load one argument onto 8080 stack
  1114. ;        bcld    load (BC) from PDL, pop PDL
  1115. ;        deld    load (DE) from PDL, pop PDL
  1116. ;    -------------------------------------------------------
  1117.  
  1118.     end
  1119.