home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / trace.asm < prev    next >
Assembly Source File  |  1995-06-25  |  15KB  |  715 lines

  1. version    equ    1
  2. ;History:697,1
  3.  
  4.     include    defs.asm
  5.  
  6. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  7.  
  8. ;   This program is free software; you can redistribute it and/or modify
  9. ;   it under the terms of the GNU General Public License as published by
  10. ;   the Free Software Foundation, version 1.
  11. ;
  12. ;   This program is distributed in the hope that it will be useful,
  13. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. ;   GNU General Public License for more details.
  16. ;
  17. ;   You should have received a copy of the GNU General Public License
  18. ;   along with this program; if not, write to the Free Software
  19. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. code    segment word public
  22.     assume    cs:code, ds:code
  23.  
  24.     org    2ch
  25. phd_env    label    word
  26.  
  27.     org    5ch
  28. phd_fcb1    label    byte
  29.  
  30.     org    6ch
  31. phd_fcb2    label    byte
  32.  
  33.     org    80h
  34. phd_dioa    label    byte
  35.  
  36.     org    100h
  37. start:
  38.     jmp    start_1
  39.  
  40. stack    label    byte
  41.  
  42. comment /
  43.  
  44. Plan:
  45.  
  46. Keep a circular queue of events.  The size of the queue is a settable
  47. parameter.  Discard events that fall off the end.  Remember how many events
  48. were discarded.  Remember when the events occurred.
  49.  
  50. Type of events to remember:
  51.     calls to the packet driver
  52.     upcalls to the receiver handler (both kinds)
  53.  
  54. /
  55.  
  56. ; In addition to the function numbers specified in the FTP Software
  57. ; packet driver spec, the following pseudo-functions are defined:
  58.  
  59. EVENT_RECEIVE    equ    255        ;receiver upcall.
  60.  
  61. event_struc    struc
  62. event_length    dw    ?        ;length of this event.
  63. event_function    db    ?        ;the event function number.
  64. event_time    dw    ?,?        ;timer tick at the time of the call.
  65. event_error    db    ?        ;set to value of dh after the SWI.
  66. event_struc    ends
  67.  
  68. di_struc    struc
  69.         db    (size event_struc) dup (?)
  70. di_version    dw    ?
  71. di_class    db    ?
  72. di_type        dw    ?
  73. di_number    db    ?
  74. di_basic    db    ?
  75. di_struc    ends
  76.  
  77. at_struc    struc
  78.         db    (size event_struc) dup (?)
  79. at_if_class    db    ?
  80. at_if_type    dw    ?
  81. at_if_number    db    ?
  82. at_typelen    dw    ?
  83. at_handle    dw    ?
  84. at_struc    ends
  85.  
  86. handle_struc    struc
  87.         db    (size event_struc) dup (?)
  88. event_handle    dw    ?
  89. handle_struc    ends
  90.  
  91. ga_struc    struc
  92.         db    (size event_struc) dup (?)
  93. ga_handle    dw    ?
  94. ga_length    dw    ?
  95. ga_struc    ends
  96.  
  97. srm_struc    struc
  98.         db    (size event_struc) dup (?)
  99. srm_mode    dw    ?
  100. srm_handle    dw    ?
  101. srm_struc    ends
  102.  
  103. queue_length    dw    10000,?        ;length of the queue.
  104. queue_tail    dw    ?        ;points after the last item in the queue.
  105. queue_ptr    dw    ?        ;points to the new item in the queue.
  106. queue_head    dw    ?        ;points to the first item in the queue.
  107. queue_end    dw    ?        ;points to the end of the queue, but
  108.                     ;there is room for one more event after
  109.                     ;this one.
  110.  
  111. entry_point    db    ?,0,0,0
  112.  
  113. parm    dw    0
  114. parm2    dw    their_dioa,?
  115. parm3    dw    phd_fcb1,?
  116. parm4    dw    phd_fcb2,?
  117.  
  118. comspec_env_str    db    "COMSPEC="
  119. comspec_env_len    equ    $-comspec_env_str
  120.  
  121. program        db    64 dup(?)
  122. their_dioa    db    0,0dh,128-2 dup(?)
  123.  
  124. saved_ax    label    word
  125. saved_al    db    ?
  126. saved_ah    db    ?
  127. saved_bx    dw    ?
  128. saved_ds    dw    ?
  129. saved_f        dw    ?
  130.  
  131. functions    label    word
  132.     dw    f_driver_info        ;function 1
  133.     dw    f_access_type
  134.     dw    f_release_type
  135.     dw    f_send_pkt
  136.     dw    f_terminate
  137.     dw    f_get_address
  138.     dw    f_reset_interface    ;function 7
  139.     dw    f_set_rcv_mode        ;function 20
  140.     dw    f_get_rcv_mode
  141.     dw    f_set_multicast_list
  142.     dw    f_get_multicast_list
  143.     dw    f_get_statistics
  144.     dw    f_set_address        ;function 25
  145.  
  146. their_isr    dd    ?
  147.  
  148. our_isr:
  149.     jmp    our_isr_0        ;the required signature.
  150.     db    'PKT DRVR',0
  151.  
  152. our_isr_0:
  153.     assume    ds:nothing
  154.     mov    saved_ds,ds
  155.     mov    saved_bx,bx
  156.     mov    saved_ax,ax
  157.     cld
  158.  
  159.     mov    bx,sp
  160.     mov    bx,ss:[bx+4]        ;get the original flags.
  161.     mov    saved_f,bx
  162.  
  163.  
  164.     mov    bx,cs            ;set up ds.
  165.     mov    ds,bx
  166.     assume    ds:code
  167.  
  168. ;the following code runs with ax, bx, ds, and flags saved in save_*.
  169. ;otherwise, all the registers are the same as those we were called with.
  170.  
  171.     mov    bl,ah            ;jump to the correct function.
  172.     mov    bh,0
  173.     cmp    bx,7            ;highest function is 7.
  174.     jbe    our_isr_3
  175.     cmp    bx,20
  176.     jb    our_isr_bad
  177.     cmp    bx,25
  178.     ja    our_isr_bad
  179.     sub    bx,20-7-1        ;map 20 right after 7.
  180. our_isr_3:
  181.     add    bx,bx            ;*2
  182.     jmp    functions-2[bx]        ;table starts at 1.
  183.  
  184. our_isr_bad:
  185.     call    do_their_isr
  186.     jmp    our_isr_done
  187.  
  188. f_driver_info:
  189.     mov    bx,(size di_struc)
  190.     call    queue_advance
  191.     call    do_their_isr
  192.     jc    f_driver_info_1
  193.  
  194.     mov    ax,saved_bx
  195.     mov    [bx].di_version,ax
  196.     mov    [bx].di_class,ch
  197.     mov    [bx].di_type,dx
  198.     mov    [bx].di_number,cl
  199.     mov    al,saved_al
  200.     mov    [bx].di_basic,al
  201. ;we ignore the name -- too much work.
  202. f_driver_info_1:
  203.     jmp    our_isr_done
  204.  
  205. f_get_statistics:
  206. ;strictly speaking, we should remember the statistics, but I'm not going to now.
  207. f_terminate:
  208. f_reset_interface:
  209. f_release_type:
  210. f_get_rcv_mode:
  211.     mov    bx,(size handle_struc)
  212.     call    queue_advance
  213.     mov    ax,saved_bx
  214.     mov    [bx].event_handle,ax
  215.     call    do_their_isr
  216.     jmp    our_isr_done
  217.  
  218. f_access_type:
  219.     mov    bx,(size at_struc)
  220.     call    queue_advance
  221.     mov    al,saved_al
  222.     mov    [bx].at_if_class,al
  223.     mov    ax,saved_bx
  224.     mov    [bx].at_if_type,ax
  225.     mov    [bx].at_if_number,dl
  226.     mov    [bx].at_typelen,cx
  227.     mov    their_recv.segm,es
  228.     mov    their_recv.offs,di
  229.     mov    ax,cs            ;and stick our receiver in.
  230.     mov    es,ax
  231.     mov    di,offset our_recv
  232.     call    do_their_isr
  233.     jc    f_access_type_1
  234.     mov    ax,saved_ax
  235.     mov    [bx].at_handle,ax
  236. f_access_type_1:
  237.     les    di,their_recv        ;now restore ds and si.
  238.     jmp    our_isr_done
  239.  
  240.  
  241. f_send_pkt:
  242.     mov    bx,(size event_struc)
  243.     add    bx,cx
  244.     call    queue_advance
  245. ;make a copy of their packet.
  246.     push    cx
  247.     push    si
  248.     push    di
  249.     push    ds
  250.     push    es
  251.     lea    di,[bx] + (size event_struc)
  252.     mov    ax,cs
  253.     mov    es,ax
  254.     mov    ds,saved_ds
  255.     rep    movsb
  256.     pop    es
  257.     pop    ds
  258.     pop    di
  259.     pop    si
  260.     pop    cx
  261.     call    do_their_isr
  262.     jmp    our_isr_done
  263.  
  264. f_get_address:
  265.     mov    bx,(size ga_struc)
  266.     add    bx,cx
  267.     call    queue_advance
  268.     mov    ax,saved_bx        ;save their handle
  269.     mov    [bx].ga_handle,ax
  270.     call    do_their_isr
  271.     jc    f_get_address_1
  272. ;make a copy of their address.
  273.     mov    [bx].ga_length,cx    ;we need to save this because it
  274.                     ;might be less than the total allocated.
  275.     push    cx
  276.     push    si
  277.     push    di
  278.     push    ds
  279.     push    es
  280.     mov    si,di            ;get es:di into ds:si
  281.     mov    ax,es
  282.     mov    ds,ax
  283.     lea    di,[bx] + (size ga_struc)    ;get our pointer into es:di.
  284.     mov    ax,cs
  285.     mov    es,ax
  286.     rep    movsb
  287.     pop    es
  288.     pop    ds
  289.     pop    di
  290.     pop    si
  291.     pop    cx
  292. f_get_address_1:
  293.     jmp    our_isr_done
  294.  
  295.  
  296. f_set_rcv_mode:
  297.     mov    bx,(size srm_struc)
  298.     add    bx,2
  299.     call    queue_advance
  300.     mov    ax,saved_bx        ;save their handle.
  301.     mov    [bx].srm_handle,ax
  302.     mov    [bx].srm_mode,cx    ;save their mode.
  303.     call    do_their_isr
  304.     jmp    our_isr_done
  305.  
  306. f_set_multicast_list:
  307. f_get_multicast_list:
  308. f_set_address:
  309.     mov    bx,(size event_struc)
  310.     call    queue_advance
  311.     call    do_their_isr
  312.  
  313. our_isr_done:
  314.     push    saved_f            ;restore their flags, see [2]
  315.     popf
  316.  
  317.     mov    ax,saved_ax
  318.     mov    bx,saved_bx
  319.     mov    ds,saved_ds        ;restore the two registers we destroyed.
  320.     assume    ds:nothing
  321.  
  322.     retf    2            ;return, popping their old flags, [2].
  323.     assume    ds:code
  324.  
  325.  
  326. ;do_their_isr executes their isr with the original registers.
  327. ;called with all their registers except f, ds, and bx.
  328. ;exits with all their registers except ds, ax, and bx.  bx is queue_ptr
  329. do_their_isr:
  330.  
  331. ;setup their context.
  332.     mov    ax,saved_f        ;restore their flags, see [1]
  333.     and    ax,not 200h        ;clear the interrupt flag, as required
  334.     push    ax            ;  when faking an interrupt.
  335.     mov    ax,saved_ax
  336.     mov    bx,saved_bx
  337.     mov    ds,saved_ds        ;restore the two registers we destroyed.
  338.     assume    ds:nothing
  339.  
  340. ;    [1] we pushed the flags earlier.
  341.     call    their_isr        ;now fake their interrupt.
  342.  
  343. ;save their context.
  344.     mov    saved_ax,ax        ;save the new registers.
  345.     mov    saved_bx,bx
  346.     mov    saved_ds,ds
  347.     mov    ax,cs            ;set up a pointer to the next event.
  348.     mov    ds,ax
  349.     assume    ds:code
  350.     pushf                ;save the new flags.
  351.     pop    ax
  352.     and    saved_f,200h        ;merge the interrupt flag in saved_f
  353.     or    saved_f,ax        ;  with the new flags.
  354.  
  355. ;remember whether it succeeded or not.
  356.     mov    bx,queue_ptr
  357.     mov    [bx].event_error,NO_ERROR    ;assume that all was okay.
  358.     jnc    our_isr_1
  359.     mov    [bx].event_error,dh    ;it wasn't.
  360. our_isr_1:
  361.     ret
  362.  
  363.  
  364. their_recv    dd    ?
  365.  
  366. our_recv:
  367.     assume    ds:nothing
  368.     mov    saved_ds,ds
  369.     mov    saved_bx,bx
  370.     mov    saved_ax,ax
  371.     cld
  372.  
  373.     mov    bx,cs            ;set up ds.
  374.     mov    ds,bx
  375.     assume    ds:code
  376.  
  377.     or    ax,ax            ;first call or second?
  378.     je    our_recv_first
  379.  
  380.     mov    bx,(size handle_struc)
  381.     add    bx,cx
  382.     call    queue_advance
  383.     mov    [bx].event_function,EVENT_RECEIVE    ;not a real function.
  384.     mov    [bx].event_error,0        ;no errors possible.
  385.     mov    ax,saved_bx
  386.     mov    [bx].event_handle,ax    ;remember which handle it was.
  387.  
  388.     push    cx
  389.     push    si
  390.     push    di
  391.     push    ds
  392.     push    es
  393.     lea    di,[bx] + (size handle_struc)
  394.     mov    ax,cs
  395.     mov    es,ax
  396.     mov    ds,saved_ds
  397.     rep    movsb
  398.     pop    es
  399.     pop    ds
  400.     pop    di
  401.     pop    si
  402.     pop    cx
  403.  
  404.     jmp    short our_recv_done
  405. our_recv_first:
  406. ;ignore the first upcall.
  407. our_recv_done:
  408.     mov    ax,saved_ax
  409.     mov    bx,saved_bx
  410.     mov    ds,saved_ds        ;restore the two registers we destroyed.
  411.     assume    ds:nothing
  412.  
  413.     jmp    their_recv
  414.     assume    ds:code
  415.  
  416.  
  417. queue_advance:
  418. ;enter with bx = number of bytes that we require in the queue.
  419. ;exit with bx,queue_ptr set to a pointer to our entry.
  420. ;preserve everything but ds, bx, and the flags.
  421. queue_advance_3:
  422.     mov    ax,queue_tail
  423.     add    ax,bx
  424.     cmp    ax,queue_head        ;if we don't overlap the head, we're
  425.     jbe    queue_advance_1        ;  okay.
  426.  
  427.     xchg    bx,queue_head        ;get queue_head and save bx.
  428.     add    bx,[bx].event_length
  429.     cmp    bx,queue_end        ;see if we hit the end.
  430.     xchg    queue_head,bx        ;store queue_head and restore bx.
  431.     jb    queue_advance_3        ;if we're less than the end, continue.
  432. ;we have to wrap here.
  433.     push    bx
  434.     mov    bx,queue_tail
  435.     mov    ax,queue_end        ;make an event length that's too large.
  436.     sub    ax,offset queue_begin
  437.     mov    [bx].event_length,ax
  438.     mov    bx,offset queue_begin    ;and restart from the beginning.
  439.     mov    queue_tail,bx        ;ensure that we nuke some more.
  440.     mov    queue_head,bx
  441.     pop    bx
  442.     jmp    queue_advance_3
  443. queue_advance_1:
  444.     xchg    ax,queue_tail        ;update the tail and get this ptr.
  445.     mov    queue_ptr,ax        ;save this pointer.
  446.     xchg    ax,bx
  447.     mov    [bx].event_length,ax    ;store the length of this entry here.
  448.  
  449.     mov    ah,saved_ah        ;store their function value.
  450.     mov    [bx].event_function,ah
  451.  
  452. ;remember when it happened.
  453.     push    dx
  454.     push    ds
  455.     mov    ax,40h
  456.     mov    ds,ax
  457.     mov    ax,ds:6ch        ;get the timer tick count.
  458.     mov    dx,ds:6eh
  459.     pop    ds
  460.     mov    [bx].event_time+0,ax
  461.     mov    [bx].event_time+2,dx
  462.     pop    dx
  463.  
  464.     ret
  465.  
  466.  
  467. copyleft_msg    label    byte
  468.  db "Packet driver tracer version ",'0'+(majver / 10),'0'+(majver mod 10),'.',version+'0'," copyright 1988-92, Russell Nelson.",CR,LF
  469.  db "This program is free software; see the file COPYING for details.",CR,LF
  470.  db "NO WARRANTY; see the file COPYING for details.",CR,LF
  471. crlf_msg    db    CR,LF,'$'
  472.  
  473. entry_point_name    db    "Packet interrupt number ",'$'
  474. buffer_size_name    db    "Buffer size ",'$'
  475.  
  476. before_exec_msg    db    "Now run your network software and type 'exit' when finished",CR,LF,'$'
  477. run_dump_msg    db    "Now run 'dump' to interpret 'trace.out'",CR,LF,'$'
  478.  
  479. disk_full_msg    db    "Disk Full!",'$'
  480.  
  481. already_msg    db    CR,LF,"There is no packet driver at ",'$'
  482. packet_int_msg    db    CR,LF
  483.         db    "Error: <packet_int_no> should be in the range 0x60 to 0x80"
  484.         db    '$'
  485.  
  486. usage_msg    db    "usage: trace entry_point <buffer_size>",'$'
  487.  
  488. queue_error_msg    db    "Error: <buffer_size> should be larger than 2000 and less than 64000",'$'
  489.  
  490. trace_out    db    "TRACE.OUT",0    ;filename that we write the dump to.
  491.  
  492. usage_error:
  493.     mov    dx,offset usage_msg
  494. error:
  495.     mov    ah,9
  496.     int    21h
  497.     int    20h
  498.  
  499. already_error:
  500.     mov    dx,offset already_msg
  501.     mov    di,offset entry_point
  502.     call    print_number
  503.     int    20h
  504.  
  505. start_1:
  506.     mov    sp,offset stack
  507.  
  508.     mov    dx,offset copyleft_msg
  509.     mov    ah,9
  510.     int    21h
  511.  
  512.     mov    si,offset phd_dioa+1
  513.     cmp    byte ptr [si],CR    ;end of line?
  514.     je    usage_error
  515.  
  516.     mov    di,offset entry_point    ;parse the packet interrupt number
  517.     call    get_number        ;  for them.
  518.  
  519.     mov    di,offset queue_length    ;parse the packet interrupt number
  520.     call    get_number        ;  for them.
  521.  
  522.     cmp    byte ptr [si],CR    ;end of line?
  523.     jne    usage_error
  524.  
  525.     cmp    queue_length+2,0
  526.     jne    start_3
  527.     cmp    queue_length,2000
  528.     ja    start_2
  529. start_3:
  530.     mov    dx,offset queue_error_msg
  531.     jmp    error
  532. start_2:
  533.  
  534.     mov    di,offset entry_point    ;parse the packet interrupt number
  535.     mov    dx,offset entry_point_name
  536.     call    print_number        ;  for them.
  537.  
  538.     mov    di,offset queue_length    ;parse the packet interrupt number
  539.     mov    dx,offset buffer_size_name
  540.     call    print_number        ;  for them.
  541.  
  542. ;initialize the queue
  543.     mov    bx,offset queue_begin
  544.     mov    queue_tail,bx
  545.     add    bx,queue_length
  546.     mov    queue_end,bx        ;initialize the head of the queue.
  547.     mov    [bx].event_length,1    ;anything >0 will ensure that we're >end.
  548.     mov    queue_head,bx
  549.  
  550. ;do some error checking.
  551.     cmp    entry_point,60h    ;make sure that the packet interrupt
  552.     jae    pkt_int_ok        ;  number is in range.
  553.     cmp    entry_point,80h
  554.     jbe    pkt_int_ok
  555.     mov    dx,offset packet_int_msg
  556.     jmp    error
  557. pkt_int_ok:
  558.  
  559.     mov    al,entry_point    ;is there a packet driver there?
  560.     call    chk_int
  561.     je    start_4            ;yes, so we can trace it.
  562.     jmp    already_error        ;no, give them an error.
  563. start_4:
  564.     mov    their_isr.offs,bx
  565.     mov    their_isr.segm,es
  566.  
  567.     mov    ah,25h            ;install our packet interrupt
  568.     mov    dx,offset our_isr
  569.     int    21h
  570.  
  571.     mov    dx,offset before_exec_msg
  572.     mov    ah,9
  573.     int    21h
  574.  
  575. ;
  576. ; Now free the memory we don't need.
  577. ;
  578.     mov    bx,queue_end
  579.     add    bx,size event_struc    ;leave room for one more.
  580.     add    bx,0fh            ;round up to next highest paragraph.
  581.     mov    cl,4
  582.     shr    bx,cl
  583.     movseg    es,cs
  584.     mov    ah,4ah
  585.     int    21h
  586.  
  587. ; Now we execute command.com
  588.  
  589.     mov    ax,cs
  590.     mov    word ptr parm2+2,ax
  591.     mov    word ptr parm3+2,ax
  592.     mov    word ptr parm4+2,ax
  593.  
  594.     mov    si,offset their_dioa+1    ;re-parse the two fcbs.
  595.     mov    di,offset phd_fcb1
  596.     movseg    es,ds
  597.     mov    ax,2901h
  598.     int    21h
  599.  
  600.     mov    di,offset phd_fcb2
  601.     mov    ax,2901h
  602.     int    21h
  603.  
  604.     mov    si,offset comspec_env_str    ;see if this is the one.
  605.     mov    cx,comspec_env_len
  606.     call    getenv
  607.  
  608.     mov    si,offset program
  609. copyname:
  610.     mov    al,es:[di]
  611.     mov    ds:[si],al
  612.     inc    si
  613.     inc    di
  614.     or    al,al
  615.     jne    copyname
  616.  
  617.     movseg    es,cs
  618.  
  619.     mov    ah,4bh
  620.     mov    bx,offset parm
  621.     mov    dx,offset program
  622.     mov    al,0
  623.     int    21h
  624.  
  625.     mov    bx,cs            ;restore our segment registers.
  626.     mov    ds,bx
  627.     mov    es,bx
  628.     mov    ss,bx
  629.     mov    sp,offset stack
  630.  
  631. ; Give up our packet interception.
  632.  
  633.     mov    al,entry_point    ;release our_isr.
  634.     mov    ah,25h
  635.     push    ds
  636.     lds    dx,their_isr
  637.     int    21h
  638.     pop    ds
  639.  
  640. ; Now we write our captured information out to disk.
  641.  
  642.     mov    dx,offset trace_out    ;create "trace.out".
  643.     mov    ah,3ch
  644.     mov    cx,0
  645.     int    21h
  646.  
  647.     mov    bx,ax
  648.  
  649.     mov    si,queue_head
  650. write_out:
  651.     mov    dx,si
  652.     mov    cx,[si].event_length    ;write this event out.
  653.     add    si,cx            ;is this the end of the queue?
  654.     cmp    si,queue_end        ;
  655.     ja    write_out_1
  656.  
  657.     mov    ah,40h
  658.     int    21h
  659.     cmp    ax,cx
  660.     jne    write_out_full
  661.  
  662.     jmp    write_out
  663.  
  664. write_out_1:
  665.     mov    si,offset queue_begin    ;yes.
  666. write_out_2:
  667.     cmp    si,queue_tail        ;quit when we hit the tail.
  668.     jae    write_out_3
  669.  
  670.     mov    dx,si            ;set dx for the file write below.
  671.     mov    cx,[si].event_length    ;write this event out.
  672.     add    si,cx
  673.  
  674.     mov    ah,40h
  675.     int    21h
  676.     cmp    ax,cx
  677.     jne    write_out_full
  678.  
  679.     jmp    write_out_2
  680. write_out_3:
  681.     mov    ah,3eh            ;close the file.
  682.     int    21h
  683.  
  684.     mov    dx,offset run_dump_msg
  685.     mov    ah,9
  686.     int    21h
  687.  
  688.     int    20h
  689.  
  690. write_out_full:
  691.     mov    ah,9
  692.     mov    dx,offset disk_full_msg
  693.     int    21h
  694.     int    20h
  695.  
  696.  
  697.     include    intchk.asm
  698.     include    getnum.asm
  699.     include    printnum.asm
  700.     include    skipblk.asm
  701.     include    getdig.asm
  702.     include    decout.asm
  703.     include    digout.asm
  704.     include    chrout.asm
  705.     include    getenv.asm
  706.     include    crlf.asm
  707.  
  708. end_code    label    byte
  709.  
  710. queue_begin    label    byte
  711.  
  712. code    ends
  713.  
  714.     end    start
  715.