	.title	k11pak	packet driver for kermit-11
	.ident	/8.0.01/
	.enabl	gbl

;	Brian Nelson	30-Nov-83  10:20:09
;	Last edit:	02-Jul-85  14:44:32
;
;	Change Software, Toledo, Ohio
;	University of Toledo, Toledo, Ohio
;

	.enabl	lc




;	define macros and things we want for KERMIT-11
;
;	K11MAC.MAC defines all macros and a number of symbols
	.include	/IN:K11DEF.MAC/




	.if ndf, K11INC
	.ift
	.include	/IN:K11MAC.MAC/
	.endc

	.iif ndf, k11inc, .error ; INCLUDE for IN:K11MAC.MAC failed
	.include	/IN:K11DEF.MAC/



	maxpak	==	94.		; maximum packet size-maxsize(checksum)

	mx$try	==	10		; number of times to retry packet
	myquote	==	'#		; quoting
	mypad	==	0		; no padding
	mypchar	==	0		; thus no pad character
	myeol	==	cr		; end-of-line
	mytime	==	12		; time me out after this
	myqbin	==	'&		; 8 bit quoting
	defchk	==	'1
	mychkt	==	defchk		; normal checksumming
	myrept	==	176		; tilde for repeat things
	mycapa	==	capa.a+capa.l	; /42/ Attributes + long packets
	maxtim	==	60		; maximum timeout
	mintim	==	2		; minimum timeout
	badchk	==	377		; psuedo packet type for checksum
	timout	==	'T&137		; psuedo packet type for timeout
	defdly	==	6		; delay for SENDING to start up



	.sbttl	notes on RMS-11

;	RSTS and RSX note:
;
;	 Note that we really  don't need distinct luns for input, output
;	and  directory lookup as we would normally  never have more than
;	one of them active at any given time.  The space used to do this
;	only adds  about 1 KW of  size to the task  so I am not going to
;	worry about it.  There could  always come a time  when the above
;	assumption will not hold.  Most of KERMIT-11 is  sharable anyway
;	due to the linking to RMSRES. The code, all being in PSECT $CODE
;	can always be task built with the /MU switch to  make more of it
;	sharable (RSTS and RSX11M Plus only).
;	 The one thing to note is that LUN.LO must ALWAYS be reserved as
;	logging  and debugging to disk can  be running concurrently with
;	anything else. Also, when the TAKE command is put in another lun
;	will be required for it.


	lun.kb	==	0		; assume if channel 0 --> terminal
	lun.in	==	1		; channel for input files
	lun.ou	==	2		; channel for output files
	lun.lo	==	3		; channel for packet and file logging
	lun.tr	==	3		; same as lun.log
	lun.ta	==	4		; for the TAKE command
	lun.tt	==	5		; for RSX, the normal TI: channel
	lun.sr	==	6		; channel for $search for RMSv2.0
	lun.ti	==	7		; channel number for connected terminal
	lun.xk	==	7		; Ditto, for clarity
	lun.co	==	10		; used as is lin.ti for remote connect
	lun.as	==	11		; used to attach to remote link device
					; to fake a device assignment

	.psect	$pdata

null:	.byte	0,0			; a null packet to send

	.psect	$code


	.sbttl	KERMIT packet format

;				 PACKET FORMAT
;
;The  KERMIT  protocol is built around exchange of packets of the following for-
;mat:
;
;    +------+-----------+-----------+------+------------+-------+
;    ] MARK ] char(LEN) ] char(SEQ) ] TYPE ]    DATA    ] CHECK ]
;    +------+-----------+-----------+------+------------+-------+
;
;where all fields consist of ASCII characters.  The fields are:
;
;MARK   The synchronization character that marks the beginning of  the  packet.
;	This should normally be CTRL-A, but may be redefined.
;
;LEN    The  number  of  ASCII  characters  within  the packet that follow this
;	field, in other words the packet length minus two.  Since  this  number
;	is  transformed  to  a single character via the char() function, packet
;	character counts of 0 to 94 (decimal) are permitted, and  96  (decimal)
;	is  the  maximum total packet length.  The length does not include end-
;	of-line or padding characters, which are outside  the  packet  and  are
;	strictly  for  the benefit of the operating system, but it does include
;	the block check characters.
;
;SEQ    The packet sequence number, modulo 64, ranging from 0 to 63.   Sequence
;	numbers "wrap around" to 0 after each group of 64 packets.
;
;
;TYPE   The  packet type, a single ASCII character.  The following packet types
;	are required:
;
;	 D   Data packet
;	 Y   Acknowledge (ACK)
;	 N   Negative acknowledge (NAK)
;	 S   Send initiate (exchange parameters)
;	 B   Break transmission (EOT)
;	 F   File header
;	 Z   End of file (EOF)
;	 E   Error
;
;
;DATA   The "contents" of the packet, if any contents are required in the given
;	type of packet, interpreted according to  the  packet  type.    Control
;	characters  are  preceded  by a special prefix character, normally "#",
;	and "uncontrollified" via ctl().  A prefixed sequence may not be broken
;	across packets.  Logical records in printable files are delimited  with
;	CRLFs,  suitably prefixed (e.g. "#M#J").  Any prefix characters are in-
;	cluded in the count.  Optional encoding for  8-bit  data  and  repeated
;	characters is described later.
;
;
;CHECK   A block check on the characters in the packet between, but not includ-
;	ing, the mark and the block check itself.  The check for each packet is
;	computed  by  both hosts, and must agree if a packet is to be accepted.
;	A single-character arithmetic checksum is the normal and required block
;	check.    Only  six  bits of the arithmetic sum are included.  In order
;	that all the bits of each data character contribute to  this  quantity,
;	bits  6  and  7  of the final value are added to the quantity formed by
;	bits 0-5.  Thus if s is the arithmetic sum  of  the  ASCII  characters,
;	then
;
;	    check = char((s + ((s AND 192)/64)) AND 63)
;
;	This  is  the  default  block check, and all Kermits must be capable of
;	performing it.  Other optional block check types are described later.
;	The block check is based on the ASCII values of the characters  in  the
;	packet.    Non-ASCII  systems must translate to ASCII before performing
;	the block check calculation.
;
;
;
;	13-Oct-84  14:01:32  BDN	moved SENDSW and RECSW out


	.sbttl	GETCR0	decide where to get the next character from

;	06-Nov-85  11:22:14  BDN	Added Edit 38
;
;	Passed:	r0	LUN
;	Return:	r0	Error code (generally 0 or ER$EOF)
;		r1	Character just read
;
;
;	GETCR0  is  the lowest level entry point called in Kermit to
;	obtain the next character for a  SEND  function  (even  GETC
;	calls  it),  where that it may be a normal file transfer, or
;	a SERVER extended response. The main idea in altering it  is
;	so  that  a  server  dispatch  routine  can  change  the the
;	default (get from a  file)  to,  say,  get  from  an  .ASCIZ
;	string   in   memory   or  switch  to  some  other  kind  of
;	GET_NEXT_CHARACTER routine. This requires that  the  service
;	routine  insert  its  GET_NEXT_CHAR routine address into the
;	global 'GETCROUTINE' and also to reset it to 'FGETCR0'  when
;	the  action  is  complete.  Currenty, REMOTE HELP and REMOTE
;	DIR use this facility. 


getcr0::tst	getcroutine		; /38/is there any routine address set
	bne	10$			; /38/yes
	call	fgetcr0			; /38/no, default to file reading
	br	100$			; /38/exit
10$:	call	@getcroutine		; /38/call currently defined routine
100$:	return


tgetcr::tst	tgetaddr		; /38/Have we ever been inited ?
	beq	90$			; /38/no, return ER$EOF
	movb	@tgetaddr,r1		; /38/yes, get next character please
	beq	90$			; /38/nothing is left to do
	inc	tgetaddr		; /38/text_address++
	clr	r0			; /38/return(no_errors)
	br	100$			; /38/exit
90$:	mov	#ER$EOF	,r0		; /38/return(end_of_file)
	mov	#fgetcr0,getcroutine	; /38/reset to file reading please
100$:	return				; /38/exit

	global	<getcroutine,fgetcr0,tgetcr0,tgetaddr,ER$EOF>


	.sbttl	spack	send packet


;	S P A C K $
;
;	spack$(%val type,%val num,%val len, %loc data)
;
;	input:	@r5	type of packet
;		2(r5)	packet number
;		4(r5)	length of the packet
;		6(r5)	location of the data to send
;	output:	r0	error status

	$ALLSIZ	=	<MAXLNG+<MAXLNG/10>>&177776

spack$::save	<r1,r2,r3,r4>		; Save registers that we may use
	call	spakwa
	call	spakin
	sub	#$ALLSIZ,sp		; /42/ Allocate a LONG buffer
	mov	sp	,r4		; Point to the buffer
	clr	-(sp)			; Count the total length
	tst	prexon			; /53/ Should we prefix all packets
	beq	5$			; /53/ with an XON? If eq, NO
	movb	#'Q&37	,(r4)+		; /53/ Yes, insert one
	inc	@sp			; /53/ Write_length++
5$:	setpar	sensop	,(r4)+		; Start all packets with control A 
	mov	r4	,r2		; Get address for checksum compute
	inc	@sp			; Packetlength := succ(packetlength)
	mov	4(r5)	,r0		; The length of the packet
	cmp	r0	,#MAXPAK	; Packet too large ?
	blos	15$			; No
	bitb	#CAPA.L,conpar+p.capas	; /43/ Check to see if both sides
	beq	10$			; /43/ REALLY understand long packets
	bitb	#CAPA.L,senpar+p.capas	; /43/ We would normally but it is
	beq	10$			; /43/ possible to SET NOLONG
	tst	senlng			; /42/ Receiver said it can do long
	beq	10$			; /42/ packets? If eq, then no
					; /42/ Otherwise, build ext header.
	mov	r2	,-(sp)		; /42/ Save this
	mov	#40	,-(sp)		; /42/ Accumulate header checksum
	setpar	#40	,(r4)+		; /42/ Length is a space, of course.
	tochar	2(r5)	,r1		; /42/ Packet sequence please
	add	r1	,(sp)		; /42/ Add into header checksum now.
	setpar	r1	,(r4)+		; /42/ Insert it
	movb	(r5)	,r1		; /42/ The packet type is next.
	bicb	#40	,r1		; /42/ Insure always upper case.
	add	r1	,(sp)		; /42/ Add in the checksum
	setpar	r1	,(r4)+		; /42/ And insert that also
	mov	r0	,r3		; /42/ Insert the total packet size
	clr	r2			; /42/ First byte is size/95.
	add	chksiz	,r3		; /42/ Must include checksum size.
	div	#95.	,r2		; /42/ Second byte is size mod 95
	tochar	r2	,r2		; /42/ Convert to character rep
	tochar	r3	,r3		; /42/ Convert to character rep
	setpar	r2	,(r4)+		; /42/ Insert high bits into packet
	add	r2	,(sp)		; /42/ Add into checksum
	setpar	r3	,(r4)+		; /42/ Insert low bits into packet
	add	r3	,(sp)		; /42/ Add into checksum
	mov	(sp)+	,r0		; /42/ Pop the checksum please
	mov	r0	,r2		; /42/ Save it
	bic	#^C300	,r2		; /42/ Compute it as in:
	ash	#-6	,r2		; /42/ Chk=char((s+((s&0300)/0100))&77)
	add	r0	,r2		; /42/ ...
	bic	#^C77	,r2		; /42/ Got it now
	tochar	r2	,r2		; /42/ Convert checksum to character
	setpar	r2	,(r4)+		; /42/ and insert into packet.
	mov	(sp)+	,r2		; /42/ Where to start checksum for rest
	mov	#7	,(sp)		; /42/ We now have seven characters.
	br	20$			; /42/ Add off we go

10$:	mov	#MAXPAK-3,r0		; Yes, reset packet size please
15$:	add	#2	,r0		; + two for number and type
	add	chksiz	,r0		; + the length of the checksum please
	clr	r1			; Accumulated checksum
	tochar	r0	,r1		; Start the checksum out right
	setpar	r1	,(r4)+		; And stuff length into the packet
	inc	@sp			; Packetlength := succ(packetlength)
	tochar	2(r5)	,r0		; Convert the packet number now
	setpar	r0	,(r4)+		; And stuff it into the packet
	inc	@sp			; Packetlength := succ(packetlength)
	movb	@r5	,r0		; Get the packet type now
	bicb	#40	,r0		; Insure UPPER CASE packet type
	setpar	r0	,(r4)+		; Insert the packet type into buffer
	inc	@sp			; Packetlength := succ(packetlength)

20$:	mov	4(r5)	,r1		; Get the data length
	beq	40$			; Nothing to do
	mov	6(r5)	,r3		; Address of the data to send

30$:	clr	r0			; Get the next character
	bisb	(r3)+	,r0		; Next char
	setpar	r0	,(r4)+		; Now move the data byte into the buffer
	inc	@sp			; Packetlength := succ(packetlength)
	sob	r1	,30$		; Next please

40$:	clrb	@r4			; Set .asciz for call to checks
	mov	r2	,-(sp)		; Starting address for checksum field
	call	checks			; Simple
	mov	(sp)+	,r2		; Get the computed checksum now
	call	spakck			; Stuff checksum into buffer now
	add	r0	,@sp		; And the length of the checksum
	setpar	conpar+p.eol,(r4)+	; End of line needed ?
	inc	@sp			; Packetlength := succ(packetlength)
	mov	(sp)+	,r1		; Packet length
	mov	sp	,r4		; Address(buffer)
	calls	pakwri	,<r4,r1,#lun.ti>; And dump the buffer out now
	call	spakfi			; Handle ibm stuff if possible

	add	#$ALLSIZ,sp		; Pop the buffer
	unsave	<r4,r3,r2,r1>		; Pop registers that we used
	return
	
	GLOBAL	<CHKSIZ,CONPAR,DEBUG,SENSOP,RECSOP,SENLNG>
	GLOBAL	<PREXON>					; /53/


	.sbttl	spack routines
	.enabl	lsb


spakin::bit	#log$pa	,trace		; tracing today ?
	beq	5$			; no
	calls	dskdmp	,<#200$,4(r5),@r5,2(r5),6(r5)>

5$:	tst	pauset			; wait a moment ?
	beq	6$			; no
	calls	suspend	,<pauset>	; yes
6$:	mov	#conpar+p.padc,r2	; address of the pad character ?
	clr	r1
	bisb	conpar+p.npad,r1	; send some pad characters ?
	tst	r1
	beq	20$			; no padding
10$:	calls	pakwri	,<r2,#1,#lun.ti>; send some padding
	sob	r1	,10$		; next please

20$:	movb	@r5	,r1		; the packet type next
	cmpb	r1	,#'A&137	; a legitimate packet type ?
	blo	30$			; no
	cmpb	r1	,#'Z&137	; must be in the range A..Z
	bhi	30$			; no good
	 sub	#100	,r1		; convert into range 1..26
	 asl	r1			; and count the packet type
	 asl	r1			; /43/ 32 bits
	 add	#1	,pcnt.s+2(r1)	; /43/ 32 bits, paccnt(type)++
	 adc	pcnt.s+0(r1)		; /43/ 32 bits, the high part
	 add	#1	,pcnt.s+2	; /43/ 32 bits now
	 adc	pcnt.s+0		; /43/ The high order part
30$:	return


	.save
	.psect	$PDATA	,D
200$:	.asciz	/SPACK - /
	.even
	.restore
	.dsabl	lsb




spakck:	clr	r0			; checksum.len := 0
	cmpb	chktyp	,#defchk	; if checklength > 6 bits
	blos	20$			;  then begin
	cmpb	chktyp	,#'3		;   if checktype = CRC16
	bne	10$			;    then begin
	 mov	r2	,r1		;     checkchar1:=tochar(check[12..15])
	 ash	#-14	,r1		;     shift over 12 bits
	 bic	#^C17	,r1		;     mask off the high 12  bits
	 tochar	r1	,@r4
	 setpar	@r4	,(r4)+
	 inc	r0			;     packetlength := succ(packetlength)
					;    end
10$:	 mov	r2	,r1		;   checkchar1 := tochar(check[6..11])
	 ash	#-6	,r1		;   shift over 6 bits
	 bic	#^C77	,r1		;   mask off the higher order bits
	 tochar	r1	,@r4
	 setpar	@r4	,(r4)+
	 inc	r0			;   packetlength := succ(packetlength)
	 bic	#^C77	,r2		;   now drop the high bits from checks
20$:
	tochar	r2	,@r4
	tst	ranerr			; insert random checksum errors?
	beq	40$			; no, please don't
	mov	r0	,-(sp)		;+ test mode
	call	irand			;+ test mode
	tst	r0			;+ test mode
	bne	30$			;+ test mode
	incb	@r4			;+ test mode
30$:	mov	(sp)+	,r0		;+ test mode
40$:	setpar	@r4	,(r4)+
	inc	r0			; packetlength := succ(packetlength)
	return

	global	<chktyp	,pauset	,pcnt.s	,ranerr>



	.sbttl	try to handle half duplex handshake garbage ala IBM (barf)


spakfi:	save	<r2>			; don't do this forever please
	call	200$			; dump raw i/o first please
	unsave	<r2>
	return


200$:	bit	#log$io	,trace		; dumping all i/o out ?
	beq	230$			; no
	save	<r0,r1,r2,r4>		; save these please
	mov	r1	,r2		; anything to do ?
	beq	220$			; no
210$:	clr	r0			; yes, dump ch by ch please
	bisb	(r4)+	,r0		; get the next ch to dump
	mov	#lun.lo	,r1		; the lun to write to
	call	putcr0			; simple
	sob	r2	,210$		; next please
220$:	unsave	<r4,r2,r1,r0>		; pop and exit
230$:	return				; bye

	global	<handch>

	.enabl	lsb

spakwa:	save	<r2>
	tstb	handch			; any paritcular handshake char today?
	beq	100$			; no, just exit please
	scan	@r5	,#200$
	tst	r0
	bne	100$
	mov	#200	,r2		; a limit on looping please
10$:	calls	binrea	,<#lun.ti,#4>	; wait for XON, max 4 seconds please
	tst	r0			; did the read timeout. if so, exit.
	bne	90$			; exit and try to xon the link
	bicb	#200	,r1		; insure no parity is set
	cmpb	r1	,handch		; is this the handshake character
	beq	100$			; no, try again please
	sob	r2	,10$		; not forever, please
	br	100$			; bye

90$:	save	<r0>			; save error flags
	calls	ttxon	,<#ttname,#lun.ti>; get the line turned on again please
	unsave	<r0>			; pop error

100$:	unsave	<r2>			; pop loop index
	return

	.save
	.psect	$PDATA	,D
200$:	.byte	msg$snd
	.byte	msg$ser
	.byte	msg$rcv
	.byte	msg$command
	.byte	msg$generic
	.byte	0
	.even
	.restore
	.dsabl	lsb

	global	<ttname>


	.sbttl	rpack$	read incoming packet


;	R P A C K $
;
;	rpack$(%loc data)
;
;	input:	@r5	buffer address
;		2(r5)	data structure of 3 words to contain the
;			returned length, number and type
;
;	output:	r0	error code if < 0, packet type if > 0
;			255 for checksum error
;
	o$len	=	0		; offset for retruned packet length
	o$num	=	2		; offset for returned packet number
	o$type	=	4		; offset for returned packet type
;
;				word	2	packet type
;				word	1	packet number
;	as in:	2(r5)	------>	word	0	packet length
;
;
;
;	local data offsets from r4 (allocated on the stack
;
	.done	=	0		; if <> 0 then we have the packet
	.type	=	2		; current type of packet
	.ccheck	=	4		; computed checksum
	.rcheck	=	6		; received checksum
	.len	=	10		; received pakcet length
	.timeo	=	12		; current timeout
	.num	=	14		; packet number, received
	.size	=	16		; current size of data portion
	.paksi	=	20		; for loop control for data portion
	.cbuff	=	22		; /42/ Mark checksum buffer address
	.hdtype	=	24		; /42/
	.lsize	=	26		; total size of local data


;	internal register usage:
;
;	r0	error return
;	r1	current character just read from remote
;	r3	pointer to temp buffer containing the packet less the SOH
;		and the checksum,  used for computing checksum after  the
;		packet has been read.
;	r4	pointer to local r/w data
;	r5	pointer to argument list

	



	.sbttl	rpack continued

	.iif ndf,$ALLSIZ, $ALLSIZ = <MAXLNG+<MAXLNG/10>>&177776

rpack$::save	<r1,r2,r3,r4>
	clr	recbit			; /43/ Clear bit sum out
	sub	#.lsize	,sp		; allocate space for local data
	mov	sp	,r4		; and point to it please
	sub	#$ALLSIZ,sp		; /42/ Allocate huge buffer

	clr	.num(r4)		; /41/ No fubar numbers on SOH tmo
	clr	.size(r4)		; /41/ No fubar sizes on SOH timeout
	call	waitsoh			; wait for a packet to start
	tst	r0			; did it work or did we timeout
	beq	5$			; yes
	jmp	95$			; we must have timed out then


5$:	mov	sp	,r3		; the packet less SOH and checksum
	mov	sp	,.cbuff(r4)	; /42/ Save start address
	clr	.hdtype(r4)		; /42/
	call	rpakin			; initialize things

10$:	tst	.done(r4)		; while ( !done ) {
	bne	90$			; 
					;
	call	rpakrd			; Read the next character from
	bcs	95$			; packet reader's buffer
	bisb	r1	,recbit		; /43/ So we can determine parity set
	bic	#^C177	,r1		; Insure parity is cleared out
	cmpb	r1	,recsop		; If the character is senders SOH
	beq	80$			; then we have to restart this else
	movb	r1	,(r3)+		; *checkpacket++ = ch ;
	unchar	r1	,r0		; Get the length packet next please
	mov	r0	,.hdtype(r4)	; /42/ Save header type
	cmp	r0	,#2		; /42/ If the length is 0,1 or 2 then
	ble	15$			; /42/ an extended header instead

14$:	sub	#2	,r0		; This is NOT an extended header so we
	sub	chksiz	,r0		; will check to see if the packet can
	bge	15$			; hold at least SEQ+TYPE+CHECK
	clr	r0			; /44/
;-	 add	chksiz	,r0		; Can't, thus we somehow lost the check
;-	 dec	r0			; sum type, so punt and reset it to a
;-	 movb	#defchk	,chktyp		; type one checksum
;-	 mov	#1	,chksiz		; Fix the Checksum length also
15$:	mov	r0	,.len(r4)	; Stuff the packet length

	call	rpakrd			; As before, ask for the next character
	bcs	95$			; and take an error exit if need be
	bisb	r1	,recbit		; /43/ So we can determine parity set
	bic	#^C177	,r1		; Insure parity is cleared out
	cmpb	r1	,recsop		; If this is the sender's START_OF_PAK
	beq	80$			; then it's time to restart the loop.
	movb	r1	,(r3)+		; Insert the sequence number into the
	unchar	r1	,.num(r4)	; checksum packet and save the SEQ

	call	rpakrd			; Read the TYPE field next, exiting
	bcs	95$			; on a read error, of course.
	bisb	r1	,recbit		; /43/ So we can determine parity set
	bic	#^C177	,r1		; Insure parity is cleared out
	cmpb	r1	,recsop		; As always, if we find the sender's
	beq	80$			; START_OF_PACKET, the restart.
	movb	r1	,(r3)+		; Save the TYPE field into the checksum
	mov	r1	,.type(r4)	; and also into the field for return.

	tst	.hdtype(r4)		; /42/ NOW check for extended header.
	bne	19$			; /42/ Not extended header.
	call	rdexhd			; /42/ ReaD EXtended HeaDer
	tst	r0			; /42/ Did this work ok ?
	bgt	80$			; /42/ No, got a RESYNCH
	bmi	96$			; /42/ No, got a timeout or checksum
	

19$:	mov	.len(r4),.paksi(r4)	;   loop for the data, if any
	mov	@r5	,r2		;   point to the buffer now

20$:	tst	.paksi(r4)		;   for i := 1 to len do
	beq	30$			;    begin
	call	rpakrd			;     read(input,ch)
	bcs	95$			;     exit if error
	clrpar	r1			;     ch := ch and chr(177B)
	cmpb	r1	,recsop		;     if ch = SOH then resynch
	beq	80$			;
	cmp	.size(r4),#MAXLNG	;     if currentsize < MAXPAKSIZE
	bhis	25$			;       then 
	movb	r1	,(r2)+		;         data[i]  := ch
	movb	r1	,(r3)+		;         checkpacket++ := ch
					;	end
25$:	inc	.size(r4)		;     currentsize:=succ(currentsize)
	dec	.paksi(r4)		;    nchar_left := nchar_left - 1
	br	20$			;    end

30$:	clrb	@r2			;   data[len] := NULL
	clrb	@r3			;   checkpacket++ := null
	mov	sp	,r3		;   reset base address of checkpacket
	call	rpakck			;   read the checksum now
	bcs	95$			;   exit on line error (like timeout)
	mov	sp	,.done(r4)	; flag that we are done
	br	10$			; check to see if we are done

80$:	br	5$			; synch error, restart the packet


90$:	call	rpakfi			; finish checksum and return the
	br	100$

95$:	mov	2(r5)	,r1		; timeout error, flag no packet
	clr	r0			; nonfatal error for timout
	mov	#timout	,o$type(r1)	; return as psuedo packet type
	mov	#timout	,.type(r4)	; return as psuedo packet type
96$:	call	rpakst			; do stats and disk dumping now

100$:	add	#.lsize+$ALLSIZ,sp	; /42/ Pop local buffers
	unsave	<r4,r3,r2,r1>
	return

	global	<chktyp>



	.sbttl	Read extended header type 0 for long packets

;	Added edit /42/ 08-Jan-86  16:32:59 Brian Nelson

rdexhd:	mov	r5	,-(sp)		; /42/ Need an ODD register for MUL
	mov	r2	,-(sp)		; /42/ Save R2 please
	call	rpakrd			; /42/ Extended header, read the LENX1
	bcs	90$			; /42/ field, exiting on read errors.
	bic	#^C177	,r1		; /42/ Insure parity is cleared out
	cmpb	r1	,recsop		; /42/ Exit if we find the SENDERS
	beq	80$			; /42/ START_OF_HEADER please
	movb	r1	,(r3)+		; /42/ Save into Checksum buffer
	unchar	r1	,r5		; /42/ Get the high order of length
	mul	#95.	,r5		; /42/ Shift over please
	call	rpakrd			; /42/ Extended header, read the LENX2
	bcs	90$			; /42/ field, exiting on read errors.
	bic	#^C177	,r1		; /42/ Insure parity is cleared out
	cmpb	r1	,recsop		; /42/ Exit if we find the SENDERS
	beq	80$			; /42/ START_OF_HEADER please
	movb	r1	,(r3)+		; /42/ Save into Checksum buffer
	unchar	r1	,r1		; /42/ Get the next one
	add	r1	,r5		; /42/ Now we have the EXTENDED length
	sub	chksiz	,r5		; /42/ Drop it by checksum size
	mov	r5	,.len(r4)	; /42/ Save it here, of course

	mov	.cbuff(r4),r5		; /42/ Now, at LAST, get the extended
	mov	#5	,r1		; /42/ header CHECKSUM data
	clr	-(sp)			; /42/ Accum in stack
10$:	clr	r0			; /42/ Use the normal SAFE way to add
	bisb	(r5)+	,r0		; /42/ bytes even though we know for
	add	r0	,(sp)		; /42/ that no sign extends will happen
	sob	r1	,10$		; /42/ Next please
	mov	(sp)+	,r0		; /42/ Pop the checksum please
	mov	r0	,r2		; /42/ Save it
	bic	#^C300	,r2		; /42/ Compute it as in:
	ash	#-6	,r2		; /42/ Chk=char((s+((s&0300)/0100))&77)
	add	r0	,r2		; /42/ ...
	bic	#^C77	,r2		; /42/ Got it now

	call	rpakrd			; /42/ Extended header, read the HCHECK
	bcs	90$			; /42/ field, exiting on read errors.
	bic	#^C177	,r1		; /42/ Insure parity is cleared out
	cmpb	r1	,recsop		; /42/ Exit if we find the SENDERS
	beq	80$			; /42/ START_OF_HEADER please
	movb	r1	,(r3)+		; /42/ Save into Checksum buffer
	unchar	r1	,r1		; /42/ Convert to actual checksum now
	cmpb	r1	,r2		; /42/ Do the CHECKSUMS match ?
	bne	85$			; /42/ No, exit with such set please
	clr	r0			; /42/ It worked, exit normally
	br	100$			; /42/ bye...
	
80$:	mov	#1	,r0		; /42/ Resynch time
	br	100$			; /42/ Exit

85$:	mov	#badchk	,r0		; /42/ Header Checksum error
	br	95$			; /42/ Stuff the error
90$:	mov	#timout	,r0		; /42/ Return timeout error
95$:	mov	2(sp)	,r5		; /42/ Return timeout error
	mov	2(r5)	,r1		; /42/ Get address of result block
	clr	o$len(r1)		; /42/ Clear this also
	mov	r0	,o$type(r1)	; /42/ Return the error
	mov	r0	,.type(r4)	; /42/ Here also please
	mov	#-1	,r0		; /42/ Fatal error
100$:	mov	(sp)+	,r2		; /42/ Pop r2 and
	mov	(sp)+	,r5		; /42/ Restore R5
	return



	.sbttl	subroutines for RPACK only
	.enabl	lsb

rpakrd:	calls	binrea	,<#lun.ti,.timeo(r4)>; read(input,ch)
	tst	r0			; did it work
	bne	110$			; no
	call	rawio			; perhaps raw i/o logging
	bit	#log$rp	,trace		; dump to a local terminal ?
	beq	20$			; no
	cmpb	r1	,recsop		; start of a packet ?
	beq	10$			; yes
	movb	r1	,-(sp)		; yes, stuff the ch onto the stack
	mov	sp	,r1		; point to it
	print	r1	,#1		; dump it
	clr	r1			; restore what we read and exit
	bisb	(sp)+	,r1		; restore it and exit
	br	20$			; bye
10$:	print	#200$			; start of a packet
20$:	clr	r0			; no errors
	clc				; it worked
	return				; bye

110$:	save	<r0>			; save the error code
	calls	ttxon	,<#ttname,#lun.ti>; get the line turned on again please
	unsave	<r0>			; restore the error code
	sec				; flag the error
	return				; bye

	.save
	.psect	$PDATA	,D
200$:	.asciz	<cr><lf>/<SOH>/
	.even
	.restore
	.dsabl	lsb



rpakin:	clr	.done(r4)		; done := false
	clr	.type(r4)		; packettype := 0
	clr	.ccheck(r4)		; checksum := 0
	clr	.rcheck(r4)		; received_checksum := 0
	clr	.len(r4)		; current length := 0
	clr	.num(r4)		; packet_number  := 0
	clr	.timeo(r4)		; timeout := 0
	clr	.size(r4)		; current size of data part of packet
	clr	.paksi(r4)		; loop control for data of packet
	mov	@r5	,r0		; initialize the buffer to null
	mov	#40	,r1
10$:	clrb	(r0)+			; simple
	clrb	(r0)+			; simple
	sob	r1	,10$
	mov	2(r5)	,r0		; return parameters
	clr	(r0)+			; packet.length := 0
	clr	(r0)+			; packet.number := 0
	clr	(r0)+			; packet.type   := 0
	call	settmo
	mov	r0	,.timeo(r4)
	return


settmo:	mov	sertim	,r0		; if waiting for server command
	bne	20$			;  then use that timeout
	clr	r0			;
	bisb	conpar+p.time,r0	; get the remotes timeout
	bne	10$			; ok
	mov	#mytime	,r0		; no good, setup a timeout
10$:	cmpb	r0,setrec+p.time	; use SET TIMEOUT value if >
	bhis	20$			; no, use the timeout as in
	clr	r0			; ok, use the value the user said
	bisb	setrec+p.time,r0	; in the SET TIMEOUT command
	bne	20$			; must be > 0 by now
	mov	#mytime	,r0		; no ??
20$:	return

	global	<conpar	,setrec	,sertim>


	.sbttl	finish up rpack


rpakfi:	mov	r3	,-(sp)		; compute correct checksum type
	call	checks			; simple
	mov	(sp)+	,.ccheck(r4)	; and stuff it in please
	cmpb	.ccheck(r4),.rcheck(r4)	; compare computed checksum with the
	beq	100$			; actual checksum
	mov	#badchk	,.type(r4)	; flag checksum error

100$:	mov	2(r5)	,r1		; where to return some things
	mov	.len(r4),o$len(r1)	; return the packet length
	mov	.type(r4),o$type(r1)	; and the packet type
	mov	.num(r4),o$num(r1)	; and at last, the packet number
	call	rpakst			; do stats and logging now
	call	rpaklo			; possibly log checksum errors?
	return

	.enabl	lsb

rpakst:	cmpb	.type(r4),#'A&137	; count the packet types for stats
	blo	110$			; bad packet type
	cmpb	.type(r4),#'Z&137	; must in the range A..Z
	bhi	110$			; definiately a bad packet
	 movb	.type(r4),r1		; packet is ok, add it to the stats
	 sub	#100	,r1		; convert to 1..26
	 asl	r1			; to word offsets
	 asl	r1			; /43/ Double word offsets
	 add	#1	,pcnt.r+2(r1)	; /43/ 32 bit addition today
	 adc	pcnt.r+0(r1)		; /43/ The high order part of it
	 add	#1	,pcnt.r+2	; /43/ Add it in here also
	 adc	pcnt.r+0		; /43/ High order part

110$:	bit	#log$pa	,trace		; tracing today ?
	beq	120$			; no
	calls	dskdmp	,<#200$,.len(r4),.type(r4),.num(r4),@r5>

120$:	return

	.save
	.psect	$PDATA	,D
200$:	.asciz	/RPACK - /
	.even
	.restore
	.dsabl	lsb
	.enabl	lsb

rpaklo:	save	<r0>
	cmp	.rcheck(r4),.ccheck(r4)	; checksums match ?
	beq	100$			; yes, do nothing then
	bit	#log$io	,trace		; not if in raw i/o mode
	bne	100$			; forget it
	sub	#60	,sp		; dump bad checksums out to disk
	mov	sp	,r1		; point to the buffer
	copyz	#200$	,r1		; a header
	strlen	r1			; length so far
	add	r0	,r1		; point to the end of it
	deccvt	.rcheck(r4),r1		; convert to decimal
	add	#6	,r1		; move along please
	deccvt	.ccheck(r4),r1		; the calculated checksum
	add	#6	,r1		; make it .asciz
	clrb	@r1			; simple
	mov	sp	,r1		; point back to the buffer
	strlen	r1			; get the length
	calls	putrec	,<r1,r0,#lun.lo>; dump buffer to disk
	add	#60	,sp		; pop buffer and exit
100$:	unsave	<r0>			; pop r0 and exit
	return

	.save
	.psect	$PDATA	,D
200$:	.asciz	/?Bad Checksum: rcv,calc are /
	.even
	.restore
	.dsabl	lsb

	global	<pcnt.r	,sertim	,trace>




	.sbttl	read and convert the checksum for RPACK


rpakck:	save	<r3>			;   use r3 for accumulating check
	clr	r3			;   assume zero for now
	call	rpakrd			;   read(input,ch)
	bcs	110$			;   exit if error
	bisb	r1	,recbit		;   recbit |= ch ;
	bic	#^c177	,r1		;   ch := ch and 177B
	unchar	r1	,r3		;   received_check := ch
	cmpb	chktyp	,#defchk	;   if len(checksum) > 8bits
	blos	10$			;    then begin
	 ash	#6	,r3		;     check := check * 64
	 call	rpakrd			;     read(input,ch)
	 bcs	110$			;     exit if error
	 bic	#^c177	,r1		;     ch := ch and 177B
	 unchar	r1	,r1		;     ch := unchar(ch)
	 bisb	r1	,r3		;     rcheck := rcheck + ch
	 cmpb	chktyp	,#'3		;     if checktype = CRC16
	 bne	10$			;      then
	 ash	#6	,r3		;       begin
	 call	rpakrd			;        check := check * 64
	 bcs	110$			;	 check := check + ch
	 bic	#^c177	,r1		;        ch := ch and 177B
	 unchar	r1	,r1		;
	 bisb	r1	,r3		;      end ;
10$:	clc
	br	120$

110$:	sec
120$:	mov	r3	,.rcheck(r4)	;    return the checksum
	unsave	<r3>
	return
	



	.sbttl	parity routines

;	C L R P A R
;
;	input:	2(sp)	the character to clear parity for
;	output:	2(sp)	the result
;
;	caller by CLRPAR macro
;
;	If parity is set to anything but NONE then always
;	clear the parity out else clear it if and only if
;	filetype is not image mode.


clrpar::tstb	parity			; handle nothing please (no parity)
	beq	10$			; yes
	cmpb	parity	,#par$no	; set parity none used ?
	bne	20$			; no, must be some other type
10$:	tst	image			; no parity, image mode today ?
	bne	100$			; yes, leave things alone please
20$:	bic	#^C177	,2(sp)		; no, clear bits 7-15 please
100$:	return				; bye


	global	<parity>
	



	.sbttl	compute proper checksum please

;	C H E C K S
;
;	input:	2(sp)	address of .asciz string to compute checksum for
;	output:	@sp	the computed checksum



checks::save	<r0,r1,r2,r3>		; save registers we may use
	mov	12(sp)	,r2		; point to the string to do it for
	clr	12(sp)			; assume a zero checksum ?

	cmpb	chktyp	,#'3		; CRC-CCITT type today ?
	bne	5$			; no
	strlen	r2			; yes, get the .asciz string length
	calls	crcclc	,<r2,r0>	; compute the CRC16-CCITT
	mov	r0	,r2		; stuff the result into r2 for later
	br	90$			; and exit

5$:	clr	r1			; init the checksum accumulator
10$:	clr	r3			; get the next ch please
	bisb	(r2)+	,r3		; got the next ch now
	beq	20$			; hit the end of the string
	cmpb	parity	,#par$no	; did the packet contain parity?
	beq	15$			; no, leave bit 7 alone
	bic	#^C177	,r3		; yes, please clear bit seven
15$:	bic	#170000	,r1		; /42/ Insure long packet not overflow
	add	r3	,r1		; check := check + ch
	br	10$

20$:	mov	r1	,r2		; checksum := (((checksum and 300B)/64)
	cmpb	chktyp	,#'2		; 12 bit sum type checksum ?
	beq	30$			; yes, just exit
	bic	#^C300	,r2		;              +checksum) and 77B)
	ash	#-6	,r2		;
	add	r1	,r2		;
	bic	#^C77	,r2
	br	90$

30$:	bic	#170000	,r2		; type 2 checksum

90$:	mov	r2	,12(sp)		; return the checksum
	

100$:	unsave	<r3,r2,r1,r0>		; exit
	return


	



	.sbttl	crc calculation

;	This  routine will calculate the CRC for a string, using the
;	CRC-CCIT polynomial. 
;
;	The string should be the fields of the  packet  between  but
;	not  including  the  <mark>  and  the  block check, which is
;	treated as a string of bits with the low order  bit  of  the
;	first  character  first  and  the high order bit of the last
;	character last --  this  is  how  the  bits  arrive  on  the
;	transmission   line.  The  bit  string  is  divided  by  the
;	polynomial 
;
;	x^16+x^12+x^5+1
;
;	The initial value of  the  CRC  is  0.  The  result  is  the
;	remainder   of   this   division,   used   as-is  (i.e.  not
;	complemented). 
;
;	From  20KERMIT.MAC, rewritten  for  PDP11  by  Brian  Nelson
;	13-Jan-84 08:50:43 
;
;	input:	@r5	string address
;		2(r5)	string length
;	output:	r0	crc


crcclc::save	<r1,r2,r3,r4,r5>	; save registers please
	clr	r0			; initialize the CRC to zero
	mov	@r5	,r3		; get the string address now
	mov	2(r5)	,r4		; get the string length
	beq	100$			; oops, nothing to do then

10$:	clr	r1			; get the next character please
	bisb	(r3)+	,r1		; please avoid pdp11 sign extend
	cmpb	parity	,#par$no	; did the packet have parity?
	beq	20$			; no, leave bit seven alone
	bic	#^C177	,r1		; yes, clear bit seven please
20$:	ixor	r0	,r1		; add in with the current CRC
	mov	r1	,r2		; get the high four bits
	ash	#-4	,r2		; and move them over to 3..0
	bic	#^C17	,r2		; drop any bits left over
	bic	#^C17	,r1		; and the low four bits
	asl	r1			; times 2 for word addressing
	asl	r2			; times 2 for word addressing
	mov	crctb2(r1),r1		; get low portion of CRC factor
	ixor	crctab(r2),r1		; simple (limited modes for XOR)
	swab	r0			; shift off a byte from previous crc
	bic	#^C377	,r0		; clear new high byte
	ixor	r1	,r0		; add in the new value
	sob	r4	,10$		; next please

100$:	unsave	<r5,r4,r3,r2,r1>	; pop saved r1-r5
	return


; Data tables for CRC-CCITT generation

	.save
	.psect	$PDATA	,D

crctab:	.word	0
	.word	10201
	.word	20402
	.word	30603
	.word	41004
	.word	51205
	.word	61406
	.word	71607
	.word	102010
	.word	112211
	.word	122412
	.word	132613
	.word	143014
	.word	153215
	.word	163416
	.word	173617

crctb2:	.word	0
	.word	10611
	.word	21422
	.word	31233
	.word	43044
	.word	53655
	.word	62466
	.word	72277
	.word	106110
	.word	116701
	.word	127532
	.word	137323
	.word	145154
	.word	155745
	.word	164576
	.word	174367

	.restore





	.sbttl	clear stats out

;	C L R S T A
;
;	clear out the packet counts by packet type from the last
;	transaction and add them into the total running count by
;	packet type.

clrsta::save	<r0,r1,r2>		; save the registers we use
	mov	#pcnt.r	,r1		; packets received
	mov	totp.r	,r2		; running count so far
	mov	#34	,r0		; number of works to add/clear
10$:	add	2(r1)	,2(r2)		; /43/ Add in the totals
	adc	(r2)			; /43/ The carryover also
	add	(r1)	,(r2)+		; /43/ The HIGH order of it
	tst	(r2)+			; /43/ Get to the next one
	clr	(r1)+			; /43/ Clear of old stuff out
	clr	(r1)+			; /43/ Clear of old stuff out
	sob	r0	,10$		; /43/ Next please
	mov	#pcnt.s	,r1		; now for the packets sent
	mov	totp.s	,r2		; where to add them in
	mov	#34	,r0		; number of words to do
20$:	add	2(r1)	,2(r2)		; /43/ Add in the totals
	adc	(r2)			; /43/ The carryover also
	add	(r1)	,(r2)+		; /43/ The HIGH order of it
	tst	(r2)+			; /43/ Get to the next one
	clr	(r1)+			; /43/ Clear of old stuff out
	clr	(r1)+			; /43/ Clear of old stuff out
	sob	r0	,20$		; /43/ Next please
	clr	pcnt.n			; naks count
	clr	pcnt.n+2		; /43/ rest of it
	clr	pcnt.t			; /44/ Timeouts
	clr	pcnt.t+2		; /44/ Timeouts
	clr	filein+0		; /43/ File data stats
	clr	filein+2		; /43/ File data stats
	clr	fileout+0		; /43/ File data stats
	clr	fileout+2		; /43/ File data stats
	clr	charin+0		; /43/ Physical link stats
	clr	charin+2		; /43/ Physical link stats
	clr	charout+0		; /43/ Physical link stats
	clr	charout+2		; /43/ Physical link stats
	unsave	<r2,r1,r0>		; pop the registers we used
	return				; and exit


incsta::call	seconds			; /43/ Get current seconds since
	mov	#times+4,r2		; /43/ midnight, moving old times
	mov	r0	,(r2)+		; /43/ Insert NEW times first
	mov	r1	,(r2)		; /43/ then subtact off the old
	sub	times+2	,(r2)		; /43/ times from it
	sbc	-(r2)			; /43/ ditto for the carry
	sub	times	,(r2)		; /43/ Incremental is in times+4
	mov	r1	,-(r2)		; /43/ and times+6, new time is in
	mov	r0	,-(r2)		; /43/ times+0 and time+2
	return				; /43/ Exit

	
	global	<pcnt.n	,pcnt.r	,pcnt.s	,totp.r	,totp.s>
	global	<charin,charout,filein,fileout,seconds,times>	; /43/
	global	<pcnt.t>					; /44/


	.sbttl	waitsoh	wait for a packet start (ascii 1, SOH)


;	W A I T S O H
;
;	input:	nothing
;	output:	r0	error code
;		r1	the SOH or NULL if we timed out
;
;
;	As of edit 2.41 (25-Dec-85  13:26:26) from Steve Heflin we will
;	exit Kermit-11 if we find that the first thing we find is a CTL
;	Z (\032). This is desired in case the user accidentilly put the
;	Kermit-11 into server without setting a line.
;	On edit /44/, wait for TWO control z's in a row to exit.

waitsoh:clr	r1			; Start with nothing
	clr	-(sp)			; /56/ Hold virgin copy of data
	mov	#2	,-(sp)		; /44/ Counter for control Z's
10$:	cmpb	r1	,recsop		; wait for a packet header please
	beq	40$			; ok, exit
	call	settmo			; get proper timeout set up
	calls	binrea	,<#lun.ti,r0>	; read with timeout
	mov	r1	,2(sp)		; /56/ Save it
	bic	#^C177	,r1		; /44/ Never want parity here
	tst	r0			; did the read work ?
	bne	30$			; oops, just exit then
	cmpb	r1	,#'Z&37		; /41/ Control Z returned ?
	bne	15$			; /41/ No
	dec	(sp)			; /44/ Should we REALLY exit now?
	bne	20$			; /44/ No, in case we got some NOISE
	call	clostt			; /41/ Yes, drop terminal and exit
	jmp	exit			; /41/ Bye now
15$:	mov	#2	,(sp)		; /44/ Need TWO ^Z's in a row to exit
20$:	call	rawio			; all is not well, perhaps dump packets
	br	10$			; loop back for finding a PACKET start
30$:	clr	r1			; Timeout, return( NULL )
	br	100$			; /56/
40$:	bitb	#200	,2(sp)		; /56/ Parity perhaps?
	beq	100$			; /56/ No
	cmpb	parity	,#PAR$NONE	; /56/ 8bit channel?
	bne	100$			; /56/ No
	inc	incpar			; /56/ Yes, also want message only once
100$:	cmp	(sp)+	,(sp)+		; /56/ Pop control Z counter
	return				; exit


	global	<conpar	,sertim	,clostt	,exit>
	GLOBAL	<incpar>


rawio:	bit	#log$io	,trace		; dumping all i/o today?
	beq	100$			; no
	save	<r0,r1>			; yes, save these please
	clr	r0
	bisb	r1	,r0		; and setup call to putcr0
	mov	#lun.lo	,r1		; the unit to write to
	call	putcr0			; simple
	unsave	<r1,r0>			; pop these now
100$:	return


	.sbttl	initialize repeat count for sending


inirepeat::
	save	<r0,r1>
	clr	dorpt			; assume not doing repeat things
	tst	setrpt			; user disable repeat count processing?
	beq	100$			; yes
	cmpb	#myrept	,#40		; am I doing it ?
	beq	100$			; no, just exit then
	clr	rptcount		; size of repeat if zero
	clr	rptlast			; no last character please (a null)
	mov	#-1	,rptinit	; need to prime the pump please
	movb	conpar+p.rept,r0	; check for doing so
	beq	100$			; no
	cmpb	r0	,#40		; a space also ?
	beq	100$			; yes
	cmpb	r0	,senpar+p.rept	; same ?
	bne	100$			; no
	movb	r0	,rptquo		; yes, save it
	mov	#-1	,dorpt		; and we are indeed doing this
100$:	clc
	unsave	<r1,r0>
	return

	global	<dorpt,rptcount,rptlast,rptquo,rptsave,rptinit,setrpt>
	



	.sbttl	BUFFIL	buffer from the file that is being sent


;	B U F F I L
;
;	input:	@r5	buffer address
;	output:	r0	rms sts error code
;		r1	length of the string

buffil::save	<r2,r3,r4,r5>		; save all registers we may use
	mov	@r5	,r4		; point to the destination address
	clr	r3			; use as a length counter
	clr	r5			;
	bitb	#CAPA.L,conpar+p.capas	; /42/ Check to see if both sides
	beq	4$			; /42/ REALLY understand long packets
	bitb	#CAPA.L,senpar+p.capas	; /42/ We would normally but it is
	beq	4$			; /42/ possible to SET NOLONG
	mov	senlng	,r5		; /42/ Does receiver understand
	bne	5$			; /42/ long packets today?
4$:	bisb	conpar+p.spsiz,r5	; get the recievers maximum size
5$:	sub	#14	,r5		; being overcautious today ?

10$:	tst	dorpt			; are we doing repeat counts
	beq	50$			; no

15$:	call	gnc			;   getnext character ;
	bcs	30$			;   if ( error ) then break ;
	tst	rptinit			;   if ( firsttime )
	beq	20$			;     then
	clr	rptinit			;	rptinit = 0 ;
	clr	rptcount		;	rptcount = 0 ;
	movb	r1	,rptlast	;	rptlast = ch ;
20$:	cmpb	r1	,rptlast	;   if ( ch == rptlast )
	bne	30$			;     then
	cmp	rptcount,#94.		;
	bge	30$
	inc	rptcount		;	rptcount++ ;
	br	15$			;     else break ;

30$:	mov	r1	,rptsave	; save the failed character please
	tst	rptcount		; this may be EOF on first character
	beq	90$			; if so, we simply do nothing at all

	cmp	rptcount,#2		; please don't bother with ONE char.
	bgt	40$			; don't waste the overhead for two
35$:	clr	r1			; avoid sign extension please
	bisb	rptlast	,r1		; get the character to write
	call	200$			; and stuff it into the buffer
	dec	rptcount		; more to insert ?
	bne	35$			; yes
	br	45$			; no, exit

40$:	movb	rptquo	,(r4)+		; insert the repeat count quote
	inc	r3			; count it in the packet size
	tochar	rptcount,(r4)+		; convert the repeat count to a char
	inc	r3			; and count in the packet size
	clr	r1			;
	bisb	rptlast	,r1		; and insert the repeated character
	call	200$			; insert it into the buffer
45$:	movb	rptsave	,rptlast	; make the failing character the one
	clr	rptcount		; in case of EOF, set this please
	tst	r0			; was this the end of file ?
	bne	90$			; yes, we had better leave then
	inc	rptcount		; no, initialize the count please
	br	70$			; and check for overflow in the buffer

50$:	call	gnc			; getnextchar ;
	bcs	90$			; if ( eof ) then break ;
	call	200$			; get the character stuff w/o repeats

70$:	cmp	r3	,r5		; room for the data ?
	blo	10$			; end

90$:	mov	r3	,r1		; return the length please
	beq	100$			; nothing there
	clr	r0			; say read was successful
100$:	unsave	<r5,r4,r3,r2>		; and exit
	return


	.sbttl	actually quote and stuff the character in for BUFFIL


200$:	tst	do8bit			;   exit if status <> success;
	beq	210$			;   if 	   need_8_bit_prefix
	tstb	r1			;      and bit_test(ch,200B)
	bpl	210$			;     then begin
	 movb	ebquot	,(r4)+		;      buffer[i] := eight_bit_quote
	 inc	r3			;      i := succ(i)
	 bicb	#200	,r1		;      ch := bit_clear(ch,200b)
210$:	clr	r2			;     end ;
	bisb	r1	,r2		;   ch0_7 := ch
	bic	#^C177	,r2		;   ch0_7 := ch0_7 and 177B

	cmpb	r2	,#SPACE		;   if ch0_7 < space
	blo	220$			;     or
	cmpb	r2	,#DEL		;       ch0_7 = del
	beq	220$			;     or
	cmpb	r2	,senpar+p.qctl	;       ch0_7 = quote
	beq	220$			;     or
	tst	do8bit			;      ( need_8_bit_prefix )
	beq	215$			;       and ( ch0_7 == binaryquote )
	cmpb	r2	,ebquot		;
	beq	220$			;     or
215$:	tst	dorpt			;      ( doing_repeatcompression )
	beq	230$			;       and ( ch0_7 == repeatquote )
	cmpb	r2	,rptquo		;
	bne	230$			;    then
					;       begin
220$:	movb	senpar+p.qctl,(r4)+	;	 buffer[i] := quote
	inc	r3			;	 length := succ(length)
	cmpb	r2	,#37		;    if ( ch0_7 < SPACE )
	blos	225$			;      or
	cmpb	r2	,#del		;	( ch0_7 == DEL )
	bne	230$			;      then
225$:	ctl	r1	,r1		;	  ch := ctl(ch)
	ctl	r2	,r2		;	  ch0_7 := ctl(ch0_7)
230$:	tst	image			;   if image_mode
	beq	240$			;    then
	movb	r1	,(r4)+		;     buffer[i] := ch
	br	250$			;    else
240$:	movb	r2	,(r4)+		;     buffer[i] := ch0_7
250$:	inc	r3			;   length := succ( length )
	return



gnc:	mov	#lun.in	,r0
	add	#1	,fileout+2	; /43/ Stats on file data
	adc	fileout+0		; /43/ 32 bits
	call	getcr0
	tst	r0
	beq	100$
	sec
	return
100$:	clc
	return


	global	<getcr0	,image	,conpar>




	.sbttl	bufpak	buffil but get data from a buffer


;	input:	@r5	source buffer, .asciz
;	output:	2(r5)	destination buffer
;		r0	zero (ie, no errors are possible)
;		r1	string length
;
;	No 8 bit prefixing  and no repeat counts will be done.
;	This routine is used for encoding string to be sent as
;	generic commands to a server.


bufpak::save	<r2,r3,r4,r5>		; save all registers we may use
	mov	2(r5)	,r4		; point to the destination address
	mov	@r5	,r5		; the source string
	clr	r3			; use as a length counter

10$:	clr	r1			; ch := buffer[i]
	bisb	(r5)+	,r1		; avoid PDP-11 sign extension
	beq	90$			;   
	clr	r2			;
	bisb	r1	,r2		;   ch0_7 := ch '
	bic	#^C177	,r2		;   ch0_7 := ch0_7 and 177B
	cmpb	r2	,#space		;   if ch0_7 < space
	blo	20$			;    or
	cmpb	r2	,#del		;      ch0_7 = del
	beq	20$			;    or
	cmpb	r2	,senpar+p.qctl	;      ch0_7 = quote
	bne	40$			;     then
					;      begin
20$:	movb	senpar+p.qctl,(r4)+	;	buffer[i] := quote
	inc	r3			;	length := succ(length)
	cmpb	r2	,senpar+p.qctl	;	if ch0_7 <> quote
	beq	30$			;	 then begin
	ctl	r1	,r1		;	  ch := ctl(ch)
	ctl	r2	,r2		;	  ch0_7 := ctl(ch0_7) end
30$:					;      end
40$:	tst	image			;   if image_mode
	beq	50$			;    then
	movb	r1	,(r4)+		;     buffer[i] := ch
	br	60$			;    else
50$:	movb	r2	,(r4)+		;     buffer[i] := ch0_7
60$:	inc	r3			;   length := succ( length )

70$:	clr	-(sp)
	bisb	conpar+p.spsiz,@sp	;  exit if length > spsize-8
	bne	80$			;  if spsiz = 0
	 mov	#maxpak	,@sp		;   then maxsize := #maxpak
80$:	sub	#10	,@sp		;
	cmp	r3	,(sp)+		;
	blo	10$			; end


90$:	mov	r3	,r1		; return the length please
	clr	r0			; say read was successful
	unsave	<r5,r4,r3,r2>		; and exit
	return





	.sbttl	bufemp	dump a buffer out to disk

;	B U F E M P
;
;	bufemp(%loc buffer,%val len)
;
;	input:	@r5	buffer address
;		2(r5)	length
;	output:	r0	error


bufemp::save	<r1,r2,r3,r4>		; save temps as usual
	mov	@r5	,r2		; input record address
	mov	2(r5)	,r3		; string length
	clr	r0			; insure no error for a null packet

10$:	tst	r3			; anything left in the record?
	ble	100$			; no
20$:	clr	r0			; get the next character
	bisb	(r2)+	,r0		; into a convienient place
	dec	r3			; chcount-- ;

	mov	#1	,r4		; repeat_count = 1 ;
	tst	dorpt			; are we doing repeat count stuff?
	beq	30$			; no
	cmpb	r0	,rptquo		; yes, is this the aggreed upon prefix?
	bne	30$			; no
	dec	r3			; chcount--
	clr	r4			; yes, get the next character then
	bisb	(r2)+	,r4		; and decode it into a number
	bic	#^C177	,r4		; insure no parity bits are hanging
	unchar	r4	,r4		; simple to do
	clr	r0			; now prime CH with the next character
	bisb	(r2)+	,r0		; so we can check for other types of
	dec	r3			; quoting to be done.
	tst	r4			; insure the count is legitimate
	bgt	30$			; it's ok
	mov	#1	,r4		; it's fubar, fix it

30$:	clr	set8bit			; assume we don't have to set bit 7
	tst	do8bit			; must we do 8 bit unprefixing?
	beq	60$			; no
	cmpb	r0	,ebquot		; yes, is this the 8 bit prefix?
	bne	60$			; no
	mov	sp	,set8bit	; yes, send a flag to set the bit
	clr	r0			; and get the next character
	bisb	(r2)+	,r0		; without sign extension
	dec	r3			; one less character left in buffer

60$:	cmpb	r0	,conpar+p.qctl	; is this a quoted character?
	bne	70$			; no
	clr	r0			; yes, get the next character
	bisb	(r2)+	,r0		; must be one you know
	dec	r3			; chcount := pred(chcount)
	clr	r1			; must avoid sign extension here
	bisb	r0	,r1		; check low 7 bits against quote
	bic	#^C177	,r1		; drop 7..15
	cmpb	r1	,conpar+p.qctl	; if ch <> myquote
	beq	70$			;  then
	cmpb	r1	,#77		;   if   ( ch & 177 ) >= ctl(DEL)
	blo	70$			;    and ( ch & 177 ) <= ctl(del)+40
	cmpb	r1	,#137		;	then
	bhi	70$			;	  ch = ctl(ch) ;
	ctl	r0	,r0		;

70$:	tst	set8bit			; do we need to set the high bit?
	beq	74$			; no
	bisb	#200	,r0		; yes, set the bit on please
74$:	mov	r0	,-(sp)		; and save the character to write
75$:	mov	#lun.ou	,r1		; channel_number := lun.out
	tst	outopn			; is there really something open?
	bne	80$			; yes, put the data to it
	clr	r1			; no, direct the output to a terminal
80$:	mov	@sp	,r0		; restore the character to write out
	call	putcr0			; and do it
	add	#1	,filein+2	; /43/ Stats
	adc	filein+0		; /43/ 32 bits worth
	sob	r4	,75$		; duplicate the character if need be.
	tst	(sp)+			; pop the stack where we saved CH
	br	10$			; next character please

100$:	unsave	<r4,r3,r2,r1>
	return

	global	<do8bit	,ebquot	,putcr0	,outopn	,senpar	,set8bit>
	global	<dorpt	,rptquo	>



	.sbttl	bufunpack	like bufemp, but return data to a buffer


;	input:	@r5	source buffer, .asciz
;	output:	2(r5)	destination buffer
;		r0	zero (ie, no errors are possible)
;		r1	string length
;
;	No 8 bit prefixing  and no repeat counts will be done.
;	This routine is used for decoding strings received for
;	generic commands to the server.



bufunp::save	<r2,r3,r4,r5>		; save temps as usual
	mov	@r5	,r2		; input record address
	clr	r3			; length := 0
	mov	2(r5)	,r4		; resultant string
					;
10$:	clr	r0			; get the next character
	bisb	(r2)+	,r0		; into a convienient place
	beq	100$			; All done
	bic	#^C177	,r0		; /53/ Always seven bit data
	mov	#1	,r5		; /53/ Assume character not repeated
	tst	dorpt			; /53/ Repeat processing off?
	beq	20$			; /53/ Yes, ignore.
	cmpb	r0	,rptquo		; /53/ Is this a repeated char?
	bne	20$			; /53/ No, normal processing
	bisb	(r2)+	,r5		; /53/ Yes, get the repeat count
	bic	#^C177	,r5		; /53/ Always seven bit data
	unchar	r5	,r5		; /53/ Get the value
	tst	r5			; /53/ Good data
	bgt	15$			; /53/ Yes
	mov	#1	,r5		; /53/ No, fix it
15$:	clr	r0			; /53/ Avoid sign extension
	bisb	(r2)+	,r0		; /53/ Now get the real data
	bic	#^C177	,r0		; /53/ Always seven bit data
20$:	cmpb	r0	,senpar+p.qctl	; is this a quoted character?
	bne	30$			; no
	clr	r0			; yes, get the next character
	bisb	(r2)+	,r0		; must be one you know
	clr	r1			; must avoid sign extension here
	bisb	r0	,r1		; check low 7 bits against quote
	bic	#^C177	,r1		; drop 7..15
	cmpb	r1	,senpar+p.qctl	; if ch <> myquote
	beq	30$			;  then
	ctl	r0	,r0		;   ch := ctl(ch);

30$:	movb	r0	,(r4)+		; copy the byte over now
	inc	r3			; length := succ(length)
	sob	r5	,30$		; /53/ Perhaps data was repeated
	br	10$			; next character please

100$:	clrb	@r4			; make the string .asciz
	mov	r3	,r1		; return the length
	clr	r0			; fake no errors please
	unsave	<r5,r4,r3,r2>		; pop registers and exit
	return


	global	<spar	,rpar	,fixchk>


	.sbttl	printm	print message if not remote

;	P R I N T M
;
;	input:	@r5	arg count
;		2(r5)	text for message #1
;		4(r5)	and so on

	.enabl	lsb


printm::save	<r0,r1,r5>		; save registers we will use
	mov	(r5)+	,r1		; get the message count
	beq	100$			; nothing to do
	tst	inserv			; skip if a server
	bne	100$			; bye
	tst	remote			; skip if we are the remote
	bne	100$			; yep
	message
	message	<Kermit: >		; a header
10$:	mov	(r5)+	,r0
	.print	r0			; now loop thru printing the stuff
	sob	r1	,10$		; next please
	message				; a <cr><lf>
	clr	logini			; may need a logging header
100$:	unsave	<r5,r1,r0>		; pop temps
	return				; and exit

	global	<logini,remote>

	.dsabl	lsb





	.sbttl	error message printing

;	E R R O R
;
;	error(%val msgcount,%loc msg1, %loc msg2,....)
;
;	Error sends the message text if we are remote else
;	it prints it out as in the baseline KERMIT.C

	erbfsiz	=	84.

error::	save	<r1,r2,r3,r4,r5>
	tst	remote			; if not remote then printm(...)
	bne	10$			; we are the remote. send errors
	call	printm			; simple
	br	100$			; bye

10$:	mov	(r5)+	,r1		; message count
	beq	100$			; nothing to do ?

	sub	#erbfsiz+2,sp		; remote, allocate a text buffer
	mov	sp	,r4		; and point to it please
	movb	#'%	,(r4)+		; /35/ insert dec style 'warning'
	mov	#erbfsiz-1,r2		; length so far
	mov	#prompt	,r0		; /32/ insert prompt into error text
20$:	movb	(r0)+	,(r4)+		; /32/ copy the prompt text over
	beq	25$			; /32/ all done, found a null (asciz)
	dec	r2			; /32/ one less place to store text
	br	20$			; /32/ next prompt character please
25$:	dec	r4			; /32/ backup to the null we copied.
	cmpb	-1(r4)	,#'>		; /35/ get rid of the trailing '>'
	bne	26$			; /35/ no
	movb	#'-	,-1(r4)		; /35/ change it to form 'Kermit-11-'
26$:	movb	#40	,(r4)+		; /32/ insert a space into buffer
	dec	r2			; /32/ one less available
	tst	r2			; /32/ did we possibly run out of room?
	bgt	30$			; /32/ no
	mov	sp	,r4		; /32/ yes, forget about the prompt.
	mov	#erbfsiz,r2		; /32/ yes, also reset the space avail

30$:	mov	(r5)+	,r3		; get the next message please
40$:	movb	(r3)+	,@r4		; now copy it to the buffer until
	beq	50$			; we get an ascii null (chr(0))
	cmpb	@r4	,#'$		; apparently CPM systems don't like
	bne	45$			; dollar symbols ?
	movb	#'_	,@r4		; so stuff a '_' in instead
45$:	inc	r4
	sob	r2	,40$		; no, go until we get one or run
	br	60$			; out of space to put it
50$:	movb	#40	,(r4)+		; insert a space in there
	dec	r2			; insure sufficient space
	beq	60$			; no
	sob	r1	,30$		; and get the next message

60$:	clrb	@r4			; inaure .asciz
	mov	sp	,r4		; all done, send the ERROR packet
	strlen	r4			; get the length
	spack	#'E,paknum,r0,r4	; and send it
	add	#erbfsiz+2,sp		; deallocate the text buffer

100$:	unsave	<r5,r4,r3,r2,r1>	; and exit
	return

	global	<paknum	,prompt	,remote>

	.sbttl	print received error packet out

;	P R E R R P
;
;	prerrp(%loc msg)
;
;	input:	@r5	address of .asciz string to print

	.enabl	lsb


prerrp::.print	#200$
	.print	@r5
	.newli
	clr	logini
	return

	.save
	.psect	$PDATA	,D
	.enabl	lc
200$:	.asciz	/Aborting with error from remote./<CR><LF>
	.even
	.restore
	.dsabl	lsb

	global	<logini>



	.sbttl	send/print several common types of errors

;	M$TYPE(%val(type),%loc(packet))	unknown packet type recieved
;	M$RETRY				retry abort
;	M$SYNCH				out of synch
;
;	18-Oct-84  17:34:37 BDN		debugging for PRO/RT11 Kermit


m$type::save	<r0>			; save temps that we will use
	clr	-(sp)			; a buffer for the packet type
	movb	@r5	,@sp		; the packet type
	mov	sp	,r0		; point back to the buffer
	calls	error	,<#4,#e$type,r0,#e$hd,2(r5)>
	tst	(sp)+			; pop local buffer
	unsave	<r0>			; pop temp and exit
	return



m$retr::save	<r0>			; save r0 please
	bitb	#200	,recbit		; /44/ Perhaps parity was going ?
	beq	10$			; /44/ No
	cmpb	parity	,#PAR$NO	; /44/ Yes, do we know about parity
	bne	10$			; /44/ Yes we do, normal abort
	calls	error	,<#1,#e$par>	; /44/ No parity, ctl fields have
	br	100$			; /44/ Exit
10$:	calls	error	,<#1,#e$retr>	; send/print the error message
100$:	unsave	<r0>			; pop and exit
	return				; bye


m$sync::save	<r0>			; save r0 please
	calls	error	,<#1,#e$synch>	; send/print the error message
	unsave	<r0>			; pop and exit
	return				; bye


	.save
	.psect	$pdata
e$hd:	.asciz	/ pak: /
e$type:	.asciz	/Fubar pak type: /
e$retr:	.asciz	/Retry limit reached/
e$synch:.asciz	/Hopelessly out of synch with sending Kermit/
e$par:	.asciz	/Retry limit reached, parity is possibly being introduced/
	.even
	.restore




	.sbttl	get next file to send


;	G E T N X T
;
;	input:	srcnam	possibly wildcarded filename
;		index	flag if eq 0 then this is the first time thru
;	output:	filnam	next file to do
;		r0	<> 0 then abort
;	
;	RSTS and RSX11M/M+
;
;	 Lookup uses the RMS version 2 $SEARCH macro to do the directory
;	operation.  For RT11 we will simply  NOP  the $SEARCH since RT11
;	does  not support directory lookup operations in the EXEC.  Thus
;	the error codes ER$NMF (no more files) and ER$FNF are referenced
;	directly here.
	


getnxt::save	<r1>
	calls	lookup	,<#3,#srcnam,#index,#filnam>
	tst	r0			; did it work ?
	beq	100$			; yes
	cmp	r0	,#ER$NMF	; no more files matching name ?
	beq	20$			; yes, we are all done then
	cmp	r0	,#ER$FNF	; how about file not found ?
	bne	30$			; no, print the error message out
20$:	tst	index			; sent any files yet ?
	bne	100$			; yes, that's ok then
	mov	#ER$FNF	,r0		; no, convert ER$NMF to ER$FNF

30$:	mov	r0	,-(sp)		; save r0 please
	calls	syserr	,<r0,#errtxt>	; not so good. Get the error text
	mov	#filnam	,r1		; assume the filename parse worked
	calls	fparse	,<#srcnam,#filnam>; quite possibly it may not have
	tst	r0			; so decide whether to send the
	beq	40$			; origonal name or the expanded
	mov	#srcnam	,r1		; filename in the error packet.
40$:	calls	error	,<#2,#errtxt,r1>; and send/print it out
	mov	(sp)+	,r0		; pop saved error code from lookup

100$:	unsave	<r1>
	return

	global	<er$fnf	,er$nmf	,errtxt	,filnam	,index	,srcnam>


	.sbttl	xor and scanch


l$xor::	save	<r0>
	mov	4(sp)	,r0
	ixor	#100	,r0
	mov	r0	,4(sp)
	unsave	<r0>
	return
	


;	S C A N C H 
;
;	input:	4(sp)	the string address
;		2(sp)	the character to look for
;	output:	r0	position of ch in string


scanch::save	<r2>			; save temps
	mov	6(sp)	,r2		; get address of the string
	clr	r0			; initial found position
10$:	tstb	@r2			; end of the string yet ?
	beq	90$			; yes
	inc	r0			; no, pos := succ(pos)
	cmpb	4(sp)	,(r2)+		; does the ch match the next one?
	bne	10$			; no, try again
	br	100$			; yes, exit loop
90$:	clr	r0			; failure, return postion = 0
100$:	unsave	<r2>			; pop r2
	mov	@sp	,4(sp)		; move return address up
	cmp	(sp)+	,(sp)+		; pop stack
	return				; and exit


;	random things for testing


irand::	tst	testc
	bne	10$
	mov	#1234.	,testc
10$:	mov	testc	,r0
	mov	r1	,-(sp)
	mov	r0	,r1
	ash	#-4	,r1
	bic	#170000	,r1
	xor	r1	,r0
	ash	#13	,r1
	bic	#100000	,r1
	xor	r1	,r0
	bic	#100000	,r0
	mov	r0	,testc
	ash	#-13	,r0
	mov	(sp)+	,r1
	return

	global	<testc>





	.sbttl	compute parity for an outgoing 8 bit link


;	This  is  software  parity generation as some DEC interfaces
;	and some DEC executives don't know how  to  compute  parity.
;	There  are  two  methods given here for ODD and EVEN genera-
;	tion. One is from Frank da Cruz's 20KERMIT.MAC and  does  it
;	by  computing  it.  The other method is from the pascal RT11
;	Kermit (by Phil Murton) and does a table lookup  to  compute
;	the  parity. For the sake of speed and the fact that some RT
;	systems lack certain instructions  we  will  use  the  later
;	method at a slight cost in space. 

	parlok	=	1		; use table lookup method



	.assume	par$od	eq 1		; set parity odd
	.assume	par$ev	eq 2		; set parity even
	.assume	par$ma	eq 3		; set parity mark
	.assume	par$sp	eq 4		; set parity space
	.assume	par$no	eq 5		; set parity none


	.psect	$pdata
pardsp:	.word	none.p,	odd.p,	even.p	,mark.p	,spac.p	,none.p	
	.psect	$code



dopari::save	<r0,r1,r2,r3>		; save things we will use
	mov	parity	,r3		; get the current parity setting
	asl	r3			; times 2
	mov	12(sp)	,r1		; get the character to do it to
	jsr	pc	,@pardsp(r3)	; and dispatch as desired
	mov	r1	,12(sp)		; return the character please
	unsave	<r3,r2,r1,r0>		; pop and exit
	return


none.p:	return				; do nothing

mark.p:	bisb	#200	,r1		; mark means we are always high
	return				; on bit seven

spac.p:	bicb	#200	,r1		; space means we are always low
	return				; on bit seven




	.sbttl	odd/even parity generation

	.if eq	,parlok			; what kind of parity generation
	.ift				; to use


even.p:	bic	#^c177	,r1		; insure no high bits are set
	mov	r1	,r2		; copy
	call	par			; and do it
	return

odd.p:	bic	#^c177	,r1		; insure only bits 0..6
	mov	r1	,r2		; copy it
	bisb	#200	,r2		; and set bit seven
	call	par			; do it
	return				; bye

par:	mov	#200	,r3		; xor instruction is strange
	ash	#-4	,r2		; move the high four bits down
	bic	#^C17	,r2		; clear bit 7's right propagation
	ixor	r1	,r2		; fold source character into one
	bic	#^C17	,r2		; insure we have only 4 bits today
	mov	r2	,r3		; now check if bits 2 and 3 are
	asr	r3			; /2
	asr	r3			; /2
	cmpb	r3	,#3		; both high or both low
	beq	10$			; both high
	tstb	r3			; both low ?
	bne	20$			; no, don't set any parity then
10$:	ixor	#200	,r1		; yes, toggle parity now
20$:	bic	#^C3	,r2		; ok, now see if the low 2 bits are
	cmpb	r2	,#3		; both either on or off
	beq	30$			; both are on, set parity
	tstb	r2			; perhaps only one bit is on?
	bne	40$			; yep
30$:	ixor	#200	,r1		; toggle the bit then
40$:
	return				; bye

	.endc				; if eq, parlok





	.sbttl	odd/even parity generation via lookup

	.if ne	,parlok			; use this method ?
	.ift				; yes


odd.p:	bic	#^c177	,r1
	tstb	partab(r1)
	bne	100$
	bisb	#200	,r1
100$:	return

even.p:	bic	#^c177	,r1
	tstb	partab(r1)
	beq	100$
	bisb	#200	,r1
100$:	return


;	Table of parity setting for ascii 0-177
;	From Phil Murton's RTLINE.PAS

	.save
	.psect	$PDATA	,D

partab:	.byte	0,1,1,0,1,0,0,1		; first 8 ascii characters
	.byte	1,0,0,1,0,1,1,0
	.byte	1,0,0,1,0,1,1,0
	.byte	0,1,1,0,1,0,0,1
	.byte	1,0,0,1,0,1,1,0
	.byte	0,1,1,0,1,0,0,1
	.byte	0,1,1,0,1,0,0,1
	.byte	1,0,0,1,0,1,1,0
	.byte	1,0,0,1,0,1,1,0
	.byte	0,1,1,0,1,0,0,1
	.byte	0,1,1,0,1,0,0,1
	.byte	1,0,0,1,0,1,1,0
	.byte	0,1,1,0,1,0,0,1
	.byte	1,0,0,1,0,1,1,0
	.byte	1,0,0,1,0,1,1,0
	.byte	0,1,1,0,1,0,0,1		; last eight ascii characters (to 177)

	.restore

	.endc				; if ne, parlok






	.end
