home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol164 / pdl86.asm < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  21.6 KB  |  860 lines

  1.  
  2. ;    =======================================================
  3. ;
  4. ;    REC module for the operators and predicates pertaining
  5. ;    to the pushdown list, other than the most important
  6. ;    ones already contained in the REC nucleus.  These
  7. ;    comprise:
  8. ;
  9. ;        arithmetic
  10. ;
  11. ;            +    sum modulo 2**16
  12. ;            -    difference modulo 2**16
  13. ;            *    product modulo 2**16
  14. ;            /    remainder, quotient
  15. ;            =    equality
  16. ;            ~    complement or negative
  17. ;            d    decrement, false on zero
  18. ;            ^    increment
  19. ;            N    comparison of top 2 args
  20. ;
  21. ;        modification of arguments
  22. ;
  23. ;            H    hex ASCII string to binary
  24. ;            !    binary to hex ASCII string
  25. ;            %    restrict argument to one byte
  26. ;            \    embed argument in two bytes
  27. ;            &    exchange top arguments
  28. ;            |    concatinate top arguments
  29. ;
  30. ;        block movements
  31. ;
  32. ;            G    fetch a block from memory
  33. ;            g    address fetch
  34. ;            r    replace address by contents
  35. ;            u    incrementing byte fetch
  36. ;            y    incrementing word fetch
  37. ;            P    put buffer block in memory
  38. ;            S    store block in memory
  39. ;            s    store into buffer
  40. ;            v    incrementing byte store
  41. ;            m    move arg to end of PDL space
  42. ;            n    recover arg from end of PDL
  43. ;
  44. ;        generate pointers
  45. ;
  46. ;            c    reserve block, generate pointer
  47. ;            p    put px, py-px on PDL
  48. ;            l    put pz on PDL
  49. ;            $    form addr of variable cell
  50. ;
  51. ;    -------------------------------------------------------
  52. ;    Version of REC released during the summer school, 1980
  53. ;    -------------------------------------------------------
  54. ;
  55. ;         PDL86  -  Copyright (C) 1982
  56. ;        Universidad Autonoma de Puebla
  57. ;             All Rights Reserved
  58. ;
  59. ;         [Harold V. McIntosh, 25 April 1982]
  60. ;
  61. ;    May 29, 1983 - & exchanges arbitrary arguments
  62. ;    May 29, 1983 - ~ discontinued; use m&n instead
  63. ;    May 29, 1983 - ~ Complement or Negate top element
  64. ;    May 29, 1983 - N for Numerical comparison on PDL
  65. ;    July 7, 1983 - $ with char arg gets subroutine addr
  66. ;    =======================================================
  67.  
  68. ;    =======================================================
  69. ;    A collection of subroutines for two-byte arithmetic,
  70. ;    including loading and storage of the 8080 registers
  71. ;    from the pushdown list.
  72. ;    =======================================================
  73.  
  74. ;    -------------------------------------------------------
  75. ;    Load and store subroutines for 2-byte arithmetic.
  76. ;    -------------------------------------------------------
  77.  
  78. ;    Push a one-byte value onto the PDL.  The value to be
  79. ;    pushed should be placed on the 8080's stack in the
  80. ;    low byte position (say by using <push psw>) before
  81. ;    calling PUON.
  82.  
  83. PUON:    ld    cx,#1        ;one byte is required
  84.     call    NARG        ;close old variable, reserve space
  85.     pop    bp        ;source was pushed before calling
  86.     pop    ax
  87.     sto    al,[bx]        ;store byte, which is low order
  88.     inc    bx        ;pointer to next byte
  89.     sto    bx,PY        ;close new argument
  90.     jmp    bp
  91.  
  92. ;    Push a two-byte value onto the PDL.  The value to be
  93. ;    pushed should be placed on the 8080's stack before
  94. ;    calling PUTW.
  95.  
  96. PUTW:    ld    cx,#2        ;two bytes are required
  97.     call    NARG        ;close old variable, reserve space
  98.     mov    bp,sp
  99.     ld    ax,[bp+2]
  100.     sto    ax,[bx]        ;store low order byte
  101.     inc    bx        ;on to high order destination
  102.     inc    bx        ;always leave pointer in good condition
  103.     sto    bx,PY        ;close top argument
  104.     ret    2
  105.  
  106. ;    (&) Exchange top two arguments, assumed two-byte.
  107.  
  108. EXCH:    ld    ax,PY
  109.     ld    bx,PX        ;org1
  110.     sub    ax,bx        ;siz1
  111.     ld    dx,[bx-2]    ;org2
  112.     lea    cx,[bx-2]
  113.     sub    cx,dx        ;siz2
  114.     cmp    ax,cx
  115.     jnz    XTNE
  116.     jcxz    XTRE
  117. XTEQ:    ld    al,[bx]
  118.     xchg    bx,dx
  119.     ld    ah,[bx]
  120.     sto    al,[bx]
  121.     xchg    bx,dx
  122.     sto    ah,[bx]
  123.     inc    bx
  124.     inc    dx
  125.     loop    XTEQ
  126. XTRE:    ret
  127. XTNE:    push    cx
  128.     push    dx
  129.     push    bx
  130.     push    ax
  131.     push    dx
  132.     call    NARG
  133.     mov    ax,ds
  134.     mov    es,ax
  135.     cld
  136.     mov    di,bx
  137.     pop    si
  138.     rep
  139.     movsb
  140.     pop    cx
  141.     pop    si
  142.     pop    di
  143.     push    di
  144.     rep
  145.     movsb
  146.     pop    [di]
  147.     lea    di,[di+2]
  148.     ld    si,PX
  149.     sto    di,PX
  150.     pop    cx
  151.     rep
  152.     movsb
  153.     sto    di,PY
  154.     ret
  155.  
  156. ;    Load top three arguments into (cx),(dx),(bx).  In
  157. ;    reality so many permutations exist for places to put
  158. ;    the arguments as they are taken off the REC stack that
  159. ;    they are simply transferred to the 8080 stack, to be
  160. ;    popped into the desired registers on return from the
  161. ;    corresponding call.  It is assumed that all quantities
  162. ;    involved in these transactions are of two bytes.  A
  163. ;    sequence of entry points is provided so as to pop off
  164. ;    one, two, or three arguments.
  165.  
  166. THRG:    ld    bx,PX        ;get pointer to top argument
  167. THRL:    pop    bp        ;enter here if (bx) already loaded
  168.     push    [bx]
  169.     push    bp
  170.     call    UCL        ;pop top argument, load (bx) from px
  171. TWOL:    pop    bp        ;continue, or entry for two args
  172.     push    [bx]
  173.     push    bp
  174.     call    UCL        ;pop argument, put px in (bx)
  175. ONEL:    pop    bp        ;continue, or entry for one argument
  176.     push    [bx]
  177.     push    bp
  178.     jmp    UCL        ;pop the last argument, quit
  179.  
  180. ;    Load up pointers to top two arguments.
  181.  
  182. ARGG:    ld    di,PX        ;org1
  183.     ld    cx,[di-2]
  184.     jcxz    arge        ;no second argument
  185.     ld    ax,PY
  186.     sub    ax,di        ;siz1
  187.     mov    bx,cx        ;org2
  188.     lea    dx,[di-2]
  189.     mov    cx,dx
  190.     sub    cx,bx        ;siz2
  191.     cmp    cx,ax
  192.     jnz    arge        ;arguments not same length
  193.     ret
  194. ARGE:    call    rer
  195. ARGS:    call    ARGG
  196.     sto    bx,PX
  197.     sto    dx,PY
  198.     ret
  199.  
  200. ;    -------------------------------------------------------
  201. ;    Two-byte arithmetic according to the four operations.
  202. ;    -------------------------------------------------------
  203.  
  204. ;    (+)  Add top registers on pdl: <a,b,+> leaves (a+b).
  205. ;    The sum is calculated modulo 2**16, no evidence of any
  206. ;    overflow remains behind.
  207.  
  208. SUM:    call    args
  209.     cmp    ax,#01
  210.     jz    SUM1
  211.     cmp    ax,#02
  212.     jz    SUM2
  213.     call    rer
  214. SUM1:    ld    al,[di]
  215.     or    [bx],al
  216.     ret
  217. SUM2:    ld    ax,[di]
  218.     add    [bx],ax
  219.     ret
  220.  
  221. ;    (-)  Subtract top from next: <a,b,-> leaves (a-b).
  222. ;    Reverse subtraction can be accomplished by exchanging
  223. ;    arguments: write <a,b,&,-> to get (b-a).  Subtraction
  224. ;    is carried out modulo 2**16; thus -1 = FFFF hex.
  225.  
  226. DIF:    call    args
  227.     cmp    ax,#01
  228.     jz    DIF1
  229.     cmp    ax,#02
  230.     jz    DIF2
  231.     call    rer
  232. DIF1:    ld    al,[di]
  233.     xor    [bx],al
  234.     ret
  235. DIF2:    ld    ax,[di]
  236.     sub    [bx],ax
  237.     ret
  238.  
  239. ;    (*)  Multiply top: <a,b,*> leaves (a*b).  The product
  240. ;    is for integer arithmetic, modulo 2**16, and so is not
  241. ;    directly suitable for a 32-bit product.
  242.  
  243. MPY:    call    args
  244.     cmp    ax,#01
  245.     jz    MPY1
  246.     cmp    ax,#02
  247.     jz    MPY2
  248.     call    rer
  249. MPY1:    ld    al,[di]
  250.     and    [bx],al
  251.     ret
  252. MPY2:    ld    ax,[di]
  253.     mul    [bx]
  254.     sto    ax,[bx]
  255.     ret
  256.  
  257. ;    (/)  Divide top: <a,b,/> leaves rem(a/b), int(a/b).
  258. ;    Reverse division is possible by exchanging arguments;
  259. ;    thus <b,a,&,/> leaves rem(b/a), int(b/a).  If just
  260. ;    the remainder is required, write <a,b,/,L>, while if
  261. ;    only the quotient is desired, write <a,b,/,&,L>, and
  262. ;    finally, if the order of the remainder and quotient is
  263. ;    not satisfactory, they can be exchanged.  The division
  264. ;    is unsigned integer division.  It can also be used to
  265. ;    split a two-byte word into two parts through division
  266. ;    by the corresponding power of two.
  267.  
  268. DVD:    call    ARGG
  269.     cmp    [di],#0000
  270.     jz    DER
  271.     ld    ax,[bx]
  272.     ld    dx,#0000
  273.     div    [di]
  274.     sto    ax,[di]
  275.     sto    dx,[bx]
  276.     ret
  277. DER:    call    RER
  278.  
  279. ;    (~)  Complement or Negate the top of the pushdown list.
  280.  
  281. comp:    ld    bx,PX
  282.     ld    cx,PY
  283.     sub    cx,bx
  284.     cmp    ax,#01
  285.     jz    com1
  286.     cmp    ax,#02
  287.     jz    com2
  288.     call    rer
  289. com1:    notb    [bx]
  290.     ret
  291. com2:    neg    [bx]
  292.     ret
  293.  
  294. ;    (^)  Increment the top of the pushdown list.
  295.  
  296. INCR:    ld    bx,PX        ;pointer to argument
  297.     inc    [bx]
  298.     ret
  299.  
  300. ;    (d)  Decrement top of PDL if it is not zero; otherwise
  301. ;    FALSE, erasing the counter.  Equivalent to ((0=;1-)).
  302.  
  303. DECR:    ld    bx,PX        ;fetch pointer to argument
  304.     sub    [bx],#1        ;dec won't work because of c flag
  305.     jc    DCF
  306.     jmp    SKP        ;no carry means TRUE
  307. DCF:    jmp    UCL        ;when FALSE, erase counter
  308.  
  309. ;    (N) Numerical comparison of top two elements on PDL. <a,b,N>
  310. ;    is TRUE if a .LE. b; both arguments are erased irrespective
  311. ;    of the result.  Numerical comparison is for integers; for one-
  312. ;    byte arguments the comparison is logical.
  313.  
  314. UCN:    call    args
  315.     cmp    ax,#01
  316.     jz    UN1
  317.     cmp    ax,#02
  318.     jz    UN2
  319.     call    rer
  320. UN1:    ld    al,[di]
  321.     test    al,[bx]
  322.     jz    UNF
  323.     jmp    UNT
  324. UN2:    ld    ax,[di]
  325.     cmp    ax,[bx]
  326.     jz    UNF
  327. UNT:    jmp    CUCL
  328. UNF:    jmp    UCL
  329.  
  330. ;    -------------------------------------------------------
  331. ;    Conversion between binary and hexadecimal ASCII strings
  332. ;    -------------------------------------------------------
  333.  
  334. ;    Return if not hexadecimal. A unchanged if not hex, else
  335. ;    reduced to binary.
  336.  
  337. RNH:    cmp    al,#'G'        ;no hex characters beyond F
  338.     jnc    RH2
  339.     cmp    al,#'A'        ;hex letters equal A or beyond
  340.     jc    RH1
  341.     sub    al,#'7'        ;compensate the gap between 9 and A
  342.     ret
  343. RH1:    jmp    RND
  344. RH2:    inc    sp
  345.     inc    sp
  346.     ret
  347.  
  348. ;    Cummulation to convert a hex ASCII string to binary.
  349.  
  350. HXP:    add    bx,bx        ;shift left 4 bits
  351.     add    bx,bx        ;
  352.     add    bx,bx        ;
  353.     add    bx,bx        ;
  354.     or    bl,al        ;or in the nibble in the accumulator
  355.     ret
  356.  
  357. ;    (H) Convert a hex ASCII string on the PDL into binary.
  358. ;    Whatever the length of the argument, conversion will be
  359. ;    made to a two-byte binary number.  Thus, if more than
  360. ;    four hex digits are present, the result will be reduced
  361. ;    modulo 2**16.  It should be noted that the conversion
  362. ;    starts with the first byte of the argument and procedes
  363. ;    onward.
  364.  
  365. HE:    ld    cx,#2        ;two bytes required for result
  366.     call    OARG        ;check if they are available
  367.     ld    bx,PY        ;fetch terminal address of string
  368.     stob    #ZE,[bx]    ;zero signals its end
  369.     ld    dx,PX        ;fetch beginning of string
  370.     ld    bx,#ZE        ;place zero in (bx) to prime conversion
  371. H1:    xchg    bx,dx
  372.     ld    al,[bx]
  373.     xchg    bx,dx        ;fetch ASCII character
  374.     inc    dx        ;ready for the next one
  375.     or    al,al        ;check the terminator byte
  376.     jz    H2        ;when end reached, close off argument
  377.  
  378.     call    RNH        ;if not hex digit, forget it all
  379.     call    HXP        ;otherwise times 16 plus new digit
  380.     jmp    H1        ;repeat the cycle
  381. H2:    xchg    bx,dx        ;binary number into (dx)
  382.     ld    bx,PX        ;place to store the result
  383.     sto    dx,[bx]        ;store low byte
  384.     inc    bx        ;on to high byte
  385.     inc    bx        ;pointer must always be one ahead
  386.     sto    bx,PY        ;store terminal address
  387.     jmp    SKP        ;TRUE return from predicate
  388.  
  389. ;    (!)  Convert a two-byte binary number into an ASCII
  390. ;    string.  A one-byte number will also be converted, but
  391. ;    into two nibbles rather than four, to serve in some
  392. ;    applications where the leading zeroes are not wanted.
  393.  
  394. HX:    ld    cx,PY
  395.     sub    cx,PX
  396.     cmp    cx,#1        ;see if it's one byte
  397.     jnz    HS        ;if not, continue elsewhere
  398.  
  399. HN:    ld    cx,#2        ;two nibble result for 1 byte
  400.     call    OARG        ;see that there's that much space
  401.     ld    bx,PX
  402.     ld    dl,[bx]        ;load low bit
  403.     jmp    HSI        ;
  404. HS:    ld    cx,#4        ;four nibble result for 2 bytes
  405.     call    OARG        ;be sure there's space for it
  406.     ld    bx,PX        ;pointer to first byte
  407.     ld    dx,[bx]        ;load low byte
  408.     mov    al,dh        ;separate high byte first
  409.     call    HSA        ;write out left nibble
  410.     mov    al,dh        ;high byte again
  411.     call    HSB        ;write out right nibble
  412. HSI:    mov    al,dl        ;separate low byte
  413.     call    HSA        ;write out left nibble
  414.     mov    al,dl        ;low byte second trip
  415.     call    HSB        ;write out right nibble
  416.     sto    bx,PY        ;store end of argument
  417.     ret
  418.  
  419. HSA:    ROR    al        ;shift byte right four bits
  420.     ROR    al        ;
  421.     ROR    al        ;
  422.     ROR    al        ;
  423. HSB:    and    al,#0FH        ;mask in right nibble
  424.     add    al,#90H        ;prepare for some carries from <daa>
  425.     daa            ;create gap if nibble beyond 10
  426.     adc    al,#40H        ;code for @ if we have a letter
  427.     daa            ;decide 3 for digit, 4 for letter
  428.     sto    al,[bx]        ;record the ASCII digit
  429.     inc    bx        ;pointer ready for next deposit
  430.     ret
  431.  
  432. ;    -------------------------------------------------------
  433. ;    Fetch and store bytes, addresses, and blocks to and fro
  434. ;    between the PDL and the memory.  The following chart
  435. ;    shows the relation between all the different operators
  436. ;    which are available.
  437. ;
  438. ;                byte    word    block
  439. ;                ----    ----    -----
  440. ;
  441. ;    replace            -    r    G
  442. ;    fetch, nonincement    g    -    -
  443. ;    fetch, increment    u    y    -
  444. ;
  445. ;    store            -    -    S
  446. ;    store, increment    -    -    v
  447. ;    store w.r.t. limit    -    -    s
  448. ;    store into buffer    -    -    P
  449. ;
  450. ;    variable head cell    -    $    -
  451. ;
  452. ;    The main operators for saving and fetching variables
  453. ;    are G and S.  The remainder were especially chosen
  454. ;    on the one hand to scrutinize the memory under REC
  455. ;    control, and on the other to give the widest possible
  456. ;    latitude in defining variables in applications of REC.
  457. ;
  458. ;    The following chart shows how to employ variables:
  459. ;
  460. ;        'data' n$ S        define 2-byte variable
  461. ;         n$ r        fetch 2-byte variable
  462. ;        'data' ml n$ S    save fixed variable
  463. ;         n$ ryG        fetch fixed variable
  464. ;        'data' n$rs        redefine existing fixed var
  465. ;         kc Lml n$ S    create k-byte buffered variable
  466. ;         kc n$ S        alternative k-byte buffered var
  467. ;        'data' n$r P    redefine buffered variable
  468. ;         n$ ryLyG        fetch buffered variable
  469. ;
  470. ;    Memory can be examined bytewise with the following
  471. ;    combinations:
  472. ;
  473. ;        org g        fetch a byte, keep origin
  474. ;        org u        autoincrementing byte fetch
  475. ;        org v        autoincrementing byte store
  476. ;        org (g  ... v:;)    read, modify, store, ready next
  477. ;        o1 o2 (u~...v&:;)    move from o1 to o2
  478. ;
  479. ;    -------------------------------------------------------
  480.  
  481. ;    (g) (u)  Fetch a byte from memory and leave on PDL. The
  482. ;    sequence <org, g> leaves <org, (org)[1 byte]> on PDL.
  483. ;    The sequence <org, u> leaves <org+1, (org)[1 byte]> on
  484. ;    PDL.
  485.  
  486. GB:    ld    bx,PX        ;/g/ pointer to top argument
  487.     push    [bx]        ;fetch low byte of origin
  488.     jmp    GBJ        ;if the origin is not to be incremented
  489. GBI:    ld    bx,PX        ;/u/ pointer to arg, which is org
  490.     push    [bx]        ;fetch low byte of origin
  491.     inc    [bx]
  492. GBJ:    ld    cx,#1        ;require space for one byte
  493.     call    NARG        ;close old arg, check space, open new
  494.     pop    dx        ;here's the origin we saved
  495.     xchg    bx,dx
  496.     ld    al,[bx]
  497.     xchg    bx,dx        ;fetch the byte there
  498.     sto    al,[bx]        ;store on the PDL
  499.     inc    bx        ;pointer always ready for next byte
  500.     sto    bx,PY        ;right deliniter of argument
  501.     ret
  502.  
  503. ;    (y)  Fetch two bytes from memory and leave on PDL.
  504. ;    The sequence <org, y> leaves <org+2, (org)[2 bytes]>
  505. ;    on PDL.
  506.  
  507. GW:    ld    bx,PX        ;/ / pointer to the argument
  508.     push    [bx]        ;low byte of origin
  509.     jmp    GWJ        ;common continuation of gw, gwi
  510. GWI:    ld    bx,PX        ;/y/ pointer to the argument
  511.     push    [bx]        ;place low byte in A
  512.     add    [bx],#2        ;origin to be incremented by 2
  513. GWJ:    ld    cx,#2        ;require space for two bytes
  514.     call    NARG        ;close old arg, check space, open new
  515.     pop    dx        ;now we're ready for that origin
  516.     xchg    bx,dx
  517.     ld    ax,[bx]
  518.     xchg    bx,dx        ;fetch the byte sitting there
  519.     sto    ax,[bx]        ;and store it on PDL
  520.     inc    bx
  521.     inc    bx        ;keep the pointer moving along
  522.     sto    bx,PY        ;value's finished, store its end
  523.     ret
  524.  
  525. ;    (G)  Fetch a block from memory, leave on PDL.
  526. ;    <org,siz, G> leaves (org, ...) on PDL.
  527.  
  528. GA:    call    CXLD        ;load siz into (cx)
  529.     call    OARG        ;reuse the argument, but with siz bytes
  530.     ld    bx,PX        ;fetch the destination address
  531.     ld    si,[bx]        ;but the source address is stored there
  532.     cld
  533.     mov    di,bx
  534.     mov    ax,ds
  535.     mov    es,ax
  536.     rep
  537.     movsb
  538.     sto    di,PY        ;(bx) holds the destination terminator
  539.     ret
  540.  
  541. ;    (S)  Store a block forward from the designated memory
  542. ;    location.  <'data' org S> stores 'data' starting at
  543. ;    org; leaves no residue on the PDL.
  544.  
  545. SA:    call    CXLD        ;fetch destination origin
  546.     mov    di,cx        ;save it for a while
  547.     ld    si,PX
  548.     ld    cx,PY
  549.     sub    cx,si
  550.     cld
  551.     mov    ax,ds
  552.     mov    es,ax
  553.     rep
  554.     movsb
  555.     jmp    UCL        ;pop the second argument too
  556.  
  557. ;    (v)  Store a block, leaving incremented address.
  558. ;    <org,'data' v> leaves org+size['data'] on PDL, stores
  559. ;    'data' starting from org.
  560.  
  561. SAI:    ld    si,PX
  562.     ld    cx,PY
  563.     sub    cx,si        ;determine length of data
  564.     call    UCL        ;pop top argument, exposing second
  565.     ld    di,[bx]        ;(bx) has px, which is destn address
  566.     mov    ax,ds
  567.     mov    es,ax
  568.     mov    ax,si
  569.     add    ax,cx
  570.     cmp    di,ax
  571.     jc    LVB
  572.     cld
  573.     rep
  574.     movsb
  575.     sto    di,[bx]
  576.     ret
  577. LVB:    std
  578.     add    si,cx
  579.     add    di,cx
  580.     sto    di,[bx]
  581.     dec    si
  582.     dec    di
  583.     rep
  584.     movsb
  585.     ret
  586.  
  587. ;    (s)  Store into an area of limited size. The sequence
  588. ;    <'data' org s> will store 'data' beginning at org+2,
  589. ;    supposing that siz('data') is less than or equal to
  590. ;    (org, org+1).  In either event no residue is left, but
  591. ;    an error notation is generated if the data doesn't fit.
  592. ;    No data at all is stored if all will not fit.  If it
  593. ;    matters to know how much of the space was used, the
  594. ;    operator P should probably be used instead.
  595.  
  596. LCS:    call    CXLD        ;fetch destination origin
  597.     mov    bx,cx        ;save it while calling psiz
  598.     ld    si,PX
  599.     ld    cx,PY
  600.     sub    cx,si        ;determine length of data
  601.     ld    ax,[bx]        ;low byte of capacity
  602.     cmp    ax,cx
  603.     jnc    LST
  604.     call    UCL
  605.     call    RER        ;note error, return if it won't fit
  606. LST:    cld
  607.     inc    bx
  608.     inc    bx
  609.     mov    di,bx
  610.     mov    ax,ds
  611.     mov    es,ax
  612.     rep
  613.     movsb
  614.     jmp    UCL        ;pop second argument
  615.  
  616. ;    (P)  Store into a buffer and note length.  Used to
  617. ;    store data of variable length into an area whose
  618. ;    maximum length is fixed.  The buffer has the form
  619. ;
  620. ;       /available/used/data/data/.../data/.../end/
  621. ;
  622. ;    The sequence <'data' org P> will store the data
  623. ;    in the buffer beginning at org. (org, org+1) holds
  624. ;    the maximum length of data that may be stored in the
  625. ;    buffer, (org+2, org+3) is siz('data'), and 'data' is
  626. ;    stored from org+4 onward if it will fit.  If it will
  627. ;    not, P is a noop and error is set.
  628.  
  629. UCP:    call    CXLD        ;pointer to destination
  630.     mov    bx,cx        ;save destination while calling psiz
  631.     ld    si,PX
  632.     ld    cx,PY
  633.     sub    cx,si        ;load (cx) with length of data
  634.     inc    cx        ;data has to appear two bytes larger
  635.     inc    cx        ;to include cell showing its size
  636.     ld    ax,[bx]        ;low byte of destination capacity
  637.     inc    bx        ;
  638.     inc    bx        ;
  639.     cmp    ax,cx
  640.     jnc    UP1
  641.     call    RER        ;capacity exceeded: mark error, return
  642. UP1:    dec    cx        ;we want to store the true size
  643.     dec    cx        ;subtract out the two byte margin
  644.     sto    cx,[bx]        ;low byte into usage cell
  645.     inc    bx        ;just keep moving along
  646.     inc    bx        ;ready to start moving data
  647.     cld
  648.     mov    di,bx
  649.     mov    ax,ds
  650.     mov    es,ax
  651.     rep
  652.     movsb
  653.     jmp    UCL        ;lift second argument, leave nothing
  654.  
  655. ;    (r)  Replace address on top of pdl by its contents.
  656.  
  657. IND:    ld    bx,PX        ;pointer to top argument
  658.     ld    dx,[bx]        ;load low byte
  659.     xchg    bx,dx        ;(bx) now has top argument
  660.     ld    ax,[bx]        ;low byte of indirect address
  661.     xchg    bx,dx        ;address of top argument again
  662.     sto    ax,[bx]        ;store low indirect byte
  663.     ret
  664.  
  665. ;    ($)  Generate the address of the nth cell in the array
  666. ;    of variables, which is a block of two-byte addresses.
  667. ;    These cells may be used to store data directly - for
  668. ;    example counters or addresses - or indirectly through
  669. ;    pointers to the actual location of the data.  By giving
  670. ;    a one-byte character argument, <'x'$>, the location where
  671. ;    the address of subroutine x is stored may be obtained.
  672.  
  673. VBLE:    ld    bx,PX        ;pointer to argument
  674.     ld    cx,PY
  675.     sub    cx,bx
  676.     cmp    cx,#2
  677.     jz    VBLF
  678.     ld    cx,#2
  679.     call    OARG
  680.     ld    bx,PX
  681.     ld    al,[bx]
  682.     ld    ah,#0
  683.     jmp    VBLG
  684. VBLF:    ld    ax,[bx]
  685. VBLG:    add    ax,ax
  686.     add    ax,VRT
  687.     sto    ax,[bx]
  688.     add    bx,#2
  689.     sto    bx,PY
  690.     ret
  691.  
  692. ;    (l)  Load pz onto PDL.
  693.  
  694. LCL:    push    PZ        ;putw requires arg on 8080 stack
  695.     call    PUTW        ;record two-byte argument
  696.     ret            ;can't use simply <jmp putw>
  697.  
  698. ;    (m)  Set aside top argument on PDL.  It is moved to the
  699. ;    other end of the array reserved for the PDL, which can
  700. ;    be used as a temporary storage stack without name.  The
  701. ;    mechanism by which pz is moved and the block size is
  702. ;    recorded makes this an attractive mechanism to create
  703. ;    storage space for REC variables.
  704.  
  705. LCM:    ld    si,PY
  706.     mov    cx,si
  707.     sub    cx,PX        ;get length of top argument
  708.     push    cx
  709.     call    UCL        ;pop top argument
  710.     ld    di,PZ        ;load destination origin
  711.     std
  712.     dec    si
  713.     dec    di
  714.     mov    ax,ds
  715.     mov    es,ax
  716.     rep
  717.     movsb
  718.     lea    bx,[di-1]
  719.     sto    bx,PZ
  720.     pop    [bx]        ;recover length
  721.     ret
  722.  
  723. ;    (n)  Recover segment which was set aside.
  724.  
  725. LCN:    ld    cx,#ZE        ;there won't be any net length change
  726.     call    NARG        ;close old argument, ready for new
  727.     mov    di,bx        ;place destination origin in (dx)
  728.     ld    bx,PZ        ;place source origin in (bx)
  729.     ld    cx,[bx]        ;place length in cx
  730.     lea    si,[bx+2]
  731.     cld
  732.     mov    ax,ds
  733.     mov    es,ax
  734.     rep
  735.     movsb
  736.     sto    di,PY        ;end of destination is end of argument
  737.     sto    si,PZ        ;update pz
  738.     ret
  739.  
  740. ;    (|)  Concatinate the top arguments on the PDL.
  741.  
  742. CONC:    ld    si,PX
  743.     ld    cx,PY
  744.     sub    cx,si        ;get length of top argument
  745.     call    UCL        ;pop top argument, set up pntrs to next
  746.     mov    di,dx        ;new py is destination
  747.     cld
  748.     mov    ax,ds
  749.     mov    es,ax
  750.     rep
  751.     movsb
  752.     sto    di,PY        ;record new terminal address
  753.     ret
  754.  
  755. ;    (%)  Restrict multiple-byte argument to one byte.
  756.  
  757. PE:    ld    ax,PX
  758.     cmp    ax,PY
  759.     jz    PE1        ;leave a null argument in peace
  760.     inc    ax        ;add one to it
  761.     sto    ax,PY        ;store as limit to the argument
  762. PE1:    ret
  763.  
  764. ;    (\)  Embed a single byte in a pair.
  765.  
  766. IP:    ld    cx,#2        ;we want to have two bytes
  767.     call    OARG        ;verify that that much space remains
  768.     ld    bx,PX        ;pointer to argument
  769.     inc    bx        ;pass over first byte
  770.     stob    #ZE,[bx]    ;make high byte zero
  771.     inc    bx        ;pass on to next byte
  772.     sto    bx,PY        ;record end of argument
  773.     ret
  774.  
  775. ;    (p)  Put px and siz on the pushdown list.
  776.  
  777. GXS:    ld    dx,PX
  778.     ld    bx,PY
  779.     mov    cx,bx
  780.     sub    cx,dx        ;calculate length of top argument
  781.     push    cx        ;put length on 8080 stack
  782.     push    dx        ;put origin on 8080 stack
  783.     call    PUTW        ;put top of 8080 stack on REC PDL
  784.     call    PUTW        ;put the next item there too
  785.     ret            ;can't combine <call, ret> into <jmp>
  786.  
  787. ;    (c) Reserve a block on the pushdown list. <n,c> creates
  788. ;    a block of length n, and puts n-2 at the front of the
  789. ;    block as a size indicator.  Then, if n .ge. 2, it will
  790. ;    be there as a length indicator for a buffer.   <=====maybe change this?
  791.  
  792. BLOK:    ld    bx,PX        ;pointer to argument
  793.     ld    cx,[bx]        ;fetch the argument
  794.     sto    cx,[bx]        ;store header
  795.     sub    [bx],#2
  796.     call    OARG        ;is there enough space to reuse arg?
  797.     sto    bx,PY        ;increment in (bx), it goes into py
  798.     push    PX        ;px has origin of block just formed
  799.     call    PUTW        ;record block origin as new argument
  800.     ret            ;can't replace <call putw, ret> by jmp
  801.  
  802. ;    Load a single variable into (cx) from the pushdown
  803. ;    list.  No register is sure to be preserved.
  804.  
  805. CXLD:    ld    bx,PX        ;pointer to argument
  806.     ld    cx,[bx]        ;fetch low order byte
  807.     jmp    UCL        ;erase argument [(cx) is unchanged]
  808.  
  809. ;    Load register pair (dx) from the pushdown list.
  810. ;    (cx) will be preserved, (bx) not.
  811.  
  812. DXLD:    ld    bx,PX        ;pointer to argument
  813.     push    [bx]        ;fetch word
  814.     call    UCL        ;erase argument
  815.     pop    dx        ;restore (dx) since UCL modified it
  816.     ret
  817.  
  818. ;    (=)  Test the two top arguments on the pushdown list
  819. ;    for equality.  The arguments may be of any length, but
  820. ;    will be equal only when of the same length and composed
  821. ;    of the same sequence of bytes. The top argument will be
  822. ;    popped whatever the outcome, but when equality is true
  823. ;    both will be popped.
  824.  
  825. EQL:    ld    di,PX        ;under argument
  826.     ld    cx,PY
  827.     sub    cx,di        ;obtain length of top argument
  828.     call    UCL        ;lift top argument
  829.     ld    si,PX
  830.     ld    bx,PY
  831.     sub    bx,si
  832.     cmp    bx,cx        ;compare lengths
  833.     jnz    EQF
  834.     cld
  835.     mov    ax,ds
  836.     mov    es,ax
  837.     repz
  838.     cmpsb
  839.     jnz    EQF
  840.     jmp    CUCL        ;both agree, erase second arg, TRUE
  841. EQF:    ret            ;disagree so FALSE
  842.  
  843. ;    -------------------------------------------------------
  844. ;
  845. ;    Some of the service routines which are likely to be
  846. ;    external references in other modules are:
  847. ;
  848. ;        puon    push one byte on PDL
  849. ;        putw    push address on PDL
  850. ;        thrl    load  three arguments onto 8080 stack
  851. ;        twol    load two arguments onto 8080 stack
  852. ;        onel    load one argument onto 8080 stack
  853. ;        bcld    load (cx) from PDL, pop PDL
  854. ;        deld    load (dx) from PDL, pop PDL
  855. ;
  856. ;    -------------------------------------------------------
  857.  
  858.     LINK    MKV86.ASM
  859.  
  860.