1	title	'Requester Network I/O System for CP/NET 1.2'
2	page	54
3
4;***************************************************************
5;***************************************************************
6;**                                                           **
7;**  R e q u e s t e r   N e t w o r k   I / O   S y s t e m  **
8;**                                                           **
9;***************************************************************
10;***************************************************************
11
12;/*
13;  Copyright (C) 1980, 1981, 1982
14;  Digital Research
15;  P.O. Box 579
16;  Pacific Grove, CA 93950
17;
18;  Revised:  October 5, 1982
19;
20;  Modified December 2006 for Z80SIM by Udo Munk
21;*/
22
23false	equ	0
24true	equ	not false
25
26cpnos	equ	false		; cp/net system
27
28always$retry	equ	false	; force continuous retries
29
30ASCII	equ	false
31
32debug	equ	false
33
34	CSEG
35	if	cpnos
36	extrn	BDOS
37	else
38BDOS	equ	0005h
39	endif
40
41NIOS:
42	public	NIOS
43;	Jump vector for SNIOS entry points
44	jmp	ntwrkinit	; network initialization
45	jmp	ntwrksts	; network status
46	jmp	cnfgtbladr	; return config table addr
47	jmp	sendmsg		; send message on network
48	jmp	receivemsg	; receive message from network
49	jmp	ntwrkerror	; network error
50	jmp	ntwrkwboot	; network warm boot
51
52slave$ID	equ	11h	; slave processor ID number
53
54	if	cpnos
55;	Initial Slave Configuration Table
56Initconfigtbl:
57	db	0000$0000b	; network status byte
58	db	slave$ID	; slave processor ID number
59	db	84h,0		; A:  Disk device
60	db	81h,0		; B:   "
61	db	82h,0		; C:   "
62	db	83h,0		; D:   "
63	db	80h,0		; E:   "
64	db	85h,0		; F:   "
65	db	86h,0		; G:   "
66	db	87h,0		; H:   "
67	db	88h,0		; I:   "
68	db	89h,0		; J:   "
69	db	8ah,0		; K:   "
70	db	8bh,0		; L:   "
71	db	8ch,0		; M:   "
72	db	8dh,0		; N:   "
73	db	8eh,0		; O:   "
74	db	8fh,0		; P:   "
75	db	0,0		; console device
76	db	0,0		; list device:
77	db	0		;	buffer index
78	db	0		;	FMT
79	db	0		;	DID
80	db	slave$ID	;	SID
81	db	5		;	FNC
82initcfglen equ	$-initconfigtbl
83	endif
84
85defaultmaster	equ	00h
86
87wboot$msg:			; data for warm boot routine
88	db	'<Warm Boot>'
89	db	'$'
90
91networkerrmsg:
92	db	'Network Error'
93	db	'$'
94
95	page
96	DSEG
97
98;	Slave Configuration Table
99configtbl:
100
101Network$status:
102	ds	1		; network status byte
103	ds	1		; slave processor ID number
104	ds	2		; A:  Disk device
105	ds	2		; B:   "
106	ds	2		; C:   "
107	ds	2		; D:   "
108	ds	2		; E:   "
109	ds	2		; F:   "
110	ds	2		; G:   "
111	ds	2		; H:   "
112	ds	2		; I:   "
113	ds	2		; J:   "
114	ds	2		; K:   "
115	ds	2		; L:   "
116	ds	2		; M:   "
117	ds	2		; N:   "
118	ds	2		; O:   "
119	ds	2		; P:   "
120
121	ds	2		; console device
122
123	ds	2		; list device:
124	ds	1		;	buffer index
125	db	0		;	FMT
126	db	0		;	DID
127	db	Slave$ID	;	SID (CP/NOS must still initialize)
128	db	5		;	FNC
129	ds	1		;	SIZ
130	ds	1		;	MSG(0)  List number
131	ds	128		;	MSG(1) ... MSG(128)
132
133msg$adr:
134	ds	2		; message address
135
136timeout$retries equ 100		; timeout a max of 100 times
137max$retries equ	10		; send message max of 10 times
138retry$count:
139	ds	1
140
141FirstPass:
142	db	0ffh
143
144;	Network Status Byte Equates
145;
146active		equ	0001$0000b	; slave logged in on network
147rcverr		equ	0000$0010b	; error in received message
148senderr		equ	0000$0001b	; unable to send message
149
150;	General Equates
151;
152SOH	equ	01h		; Start of Header
153STX	equ	02h		; Start of Data
154ETX	equ	03h		; End of Data
155EOT	equ	04h		; End of Transmission
156ENQ	equ	05h		; Enquire
157ACK	equ	06h		; Acknowledge
158LF	equ	0ah		; Line Feed
159CR	equ	0dh		; Carriage Return
160NAK	equ	15h		; Negative Acknowledge
161
162conout	equ	2		; console output function
163print	equ	9		; print string function
164rcvmsg	equ	67		; receive message NDOS function
165login	equ	64		; Login NDOS function
166
167;	I/O Equates
168;
169stati	equ	50
170mski	equ	01
171dprti	equ	51
172
173stato	equ	50
174msko	equ	02
175dprto	equ	51
176
177	page
178	CSEG
179;	Utility Procedures
180;
181	if	ASCII
182Nib$out:			; A = nibble to be transmitted in ASCII
183	cpi	10
184	jnc	nibAtoF		; jump if A-F
185	adi	'0'
186	mov	c,a
187	jmp	Char$out
188nibAtoF:
189	adi	'A'-10
190	mov	c,a
191	jmp	Char$out
192	endif
193
194Pre$Char$out:
195	mov	a,d
196	add	c
197	mov	d,a		; update the checksum in D
198
199nChar$out:			; C = byte to be transmitted
200	in	stato
201	ani	msko
202	jz	nChar$out
203
204	mov	a,c
205	out	dprto
206	ret
207;
208Char$out:
209	call	nChar$out
210	ret
211
212	if	ASCII
213Nib$in:				; return nibble in A register
214	call	Char$in
215	rc
216	ani	7fh
217	sui	'0'
218	cpi	10
219	jc	Nib$in$rtn 	; must be 0-9
220	adi	('0'-'A'+10) and 0ffh
221	cpi	16
222	jc	Nib$in$rtn 	; must be 10-15
223	lda	network$status
224	ori	rcverr
225	sta	network$status
226	mvi	a,0
227	stc			; carry set indicating err cond
228	ret
229
230Nib$in$rtn:
231	ora	a		; clear carry & return
232	ret
233	endif
234
235xChar$in:
236	mvi	b,10		; 100 ms  corresponds to longest possible
237	jmp	char$in0 	;wait between master operations
238
239Char$in:			; return byte in A register
240				;  carry set on rtn if timeout
241	mvi	b,10
242Char$in0:
243	in	stati		; busy wait forever, no reasonable
244	ani	mski		; delay implemented yet
245	jz	Char$in0
246Char$in1:
247;	in	stati
248;	ani	mski
249;	jnz	Char$in2
250;	out	delay
251;	dcr	b
252;	jnz	Char$in0
253;	stc			; carry set for err cond = timeout
254;	ret
255Char$in2:
256	in	dprti
257	ret			; rtn with raw char and carry cleared
258
259Net$out:			; C = byte to be transmitted
260				; D = checksum
261	mov	a,d
262	add	c
263	mov	d,a
264
265	if	ASCII
266	mov	a,c
267	mov	b,a
268	rar
269	rar
270	rar
271	rar
272	ani	0FH		; mask HI-LO nibble to LO nibble
273	call	Nib$out
274	mov	a,b
275	ani	0FH
276	jmp	Nib$out
277
278	else
279	jmp	Char$out
280	endif
281
282Msg$in:				; HL = destination address
283				; E  = # bytes to input
284	call	Net$in
285	rc
286	mov	m,a
287	inx	h
288	dcr	e
289	jnz	Msg$in
290	ret
291
292Net$in:				; byte returned in A register
293				; D  = checksum accumulator
294
295	if	ASCII
296	call	Nib$in
297	rc
298	add	a
299	add	a
300	add	a
301	add	a
302	push	psw
303	call	Nib$in
304	pop	b
305	rc
306	ora	b
307
308	else
309	call	Char$in		;receive byte in Binary mode
310	rc
311	endif
312
313chks$in:
314	mov	b,a
315	add	d		; add & update checksum accum.
316	mov	d,a
317	ora	a		; set cond code from checksum
318	mov	a,b
319	ret
320
321Msg$out:			; HL = source address
322				; E  = # bytes to output
323				; D  = checksum
324				; C  = preamble byte
325	mvi	d,0		; initialize the checksum
326	call	Pre$Char$out 	; send the preamble character
327Msg$out$loop:
328	mov	c,m
329	inx	h
330	call	Net$out
331	dcr	e
332	jnz	Msg$out$loop
333	ret
334
335	page
336;	Network Initialization
337ntwrkinit:
338	if	cpnos		; copy down network assignments
339	lxi	h,Initconfigtbl
340	lxi	d,configtbl
341	mvi	c,initcfglen
342initloop:
343	mov	a,m
344	stax	d
345	inx	h
346	inx	d
347	dcr	c
348	jnz	initloop		; initialize config tbl from ROM
349
350	else
351	mvi	a,slave$ID		;initialize slave ID byte
352	sta	configtbl+1		;  in the configuration tablee
353	endif
354
355;	device initialization, as required
356	if	cpnos
357	call	loginpr			; login to a master
358	endif
359
360initok:
361	xra	a			; return code is 0=success
362	ret
363
364
365	page
366;	Network Status
367ntwrksts:
368	lda	network$status
369	mov	b,a
370	ani	not (rcverr+senderr)
371	sta	network$status
372	mov	a,b
373	ret
374
375;	Return Configuration Table Address
376cnfgtbladr:
377	lxi	h,configtbl
378	ret
379
380	page
381;	Send Message on Network
382sendmsg:			; BC = message addr
383	mov	h,b
384	mov	l,c		; HL = message address
385	shld	msg$adr
386re$sendmsg:
387	mvi	a,max$retries
388	sta	retry$count	; initialize retry count
389send:
390	lhld	msg$adr
391	mvi	c,ENQ
392	call	Char$out	; send ENQ to master
393	mvi	d,timeout$retries
394ENQ$response:
395	call	Char$in
396	jnc	got$ENQ$response
397	dcr	d
398	jnz	ENQ$response
399	jmp	Char$in$timeout
400got$ENQ$response:
401	call	get$ACK0
402	mvi	c,SOH
403	mvi	e,5
404	call	Msg$out		; send SOH FMT DID SID FNC SIZ
405	xra	a
406	sub	d
407	mov	c,a
408	call	net$out		; send HCS (header checksum)
409	call	get$ACK
410	dcx	h
411	mov	e,m
412	inx	h
413	inr	e
414	mvi	c,STX
415	call	Msg$out		; send STX DB0 DB1 ...
416	mvi	c,ETX
417	call	Pre$Char$out	; send ETX
418	xra	a
419	sub	d
420	mov	c,a
421	call	Net$out		; send the checksum
422	mvi	c,EOT
423	call	nChar$out	; send EOT
424	call	get$ACK		; (leave these
425	ret			;              two instructions)
426
427get$ACK:
428	call	Char$in
429	jc	send$retry 	; jump if timeout
430get$ACK0:
431	ani	7fh
432	sui	ACK
433	rz
434send$retry:
435	pop	h		; discard return address
436	lxi	h,retry$count
437	dcr	m
438	jnz	send		; send again unles max retries
439Char$in$timeout:
440	mvi	a,senderr
441
442	if	always$retry
443	call	error$return
444	jmp	re$sendmsg
445	else
446	jmp	error$return
447	endif
448
449	page
450;	Receive Message from Network
451receivemsg:			; BC = message addr
452	mov	h,b
453	mov	l,c		; HL = message address
454	shld	msg$adr
455re$receivemsg:
456	mvi	a,max$retries
457	sta	retry$count	; initialize retry count
458re$call:
459	call	receive		; rtn from receive is receive error
460
461receive$retry:
462	lxi	h,retry$count
463	dcr	m
464	jnz	re$call
465receive$timeout:
466	mvi	a,rcverr
467
468	if	always$retry
469	call	error$return
470	jmp	re$receivemsg
471	else
472	jmp	error$return
473	endif
474
475receive:
476	lhld	msg$adr
477	mvi	d,timeout$retries
478receive$firstchar:
479	call	xcharin
480	jnc	got$firstchar
481	dcr	d
482	jnz	receive$firstchar
483	pop	h		; discard receive$retry rtn adr
484	jmp	receive$timeout
485got$firstchar:
486	ani	7fh
487	cpi	ENQ		; Enquire?
488	jnz	receive
489
490	mvi	c,ACK
491	call	nChar$out 	; acknowledge ENQ with an ACK
492
493	call	Char$in
494	rc			; return to receive$retry
495	ani	7fh
496	cpi	SOH		; Start of Header ?
497	rnz			; return to receive$retry
498	mov	d,a		; initialize the HCS
499	mvi	e,5
500	call	Msg$in
501	rc			; return to receive$retry
502	call	Net$in
503	rc			; return to receive$retry
504	jnz	bad$checksum
505	call	send$ACK
506	call	Char$in
507	rc			; return to receive$retry
508	ani	7fh
509	cpi	STX		; Start of Data ?
510	rnz			; return to receive$retry
511	mov	d,a		; initialize the CKS
512	dcx	h
513	mov	e,m
514	inx	h
515	inr	e
516	call	msg$in		; get DB0 DB1 ...
517	rc			; return to receive$retry
518	call	Char$in		; get the ETX
519	rc			; return to receive$retry
520	ani	7fh
521	cpi	ETX
522	rnz			; return to receive$retry
523	add	d
524	mov	d,a		; update CKS with ETX
525	call	Net$in		; get CKS
526	rc			; return to receive$retry
527	call	Char$in		; get EOT
528	rc			; return to receive$retry
529	ani	7fh
530	cpi	EOT
531	rnz			; return to receive$retry
532	mov	a,d
533	ora	a		; test CKS
534	jnz	bad$checksum
535	pop	h		; discard receive$retry rtn adr
536	lhld	msg$adr
537	inx	h
538	lda	configtbl+1
539	sub	m
540	jz	send$ACK 	; jump with A=0 if DID ok
541	mvi	a,0ffh		; return code shows bad DID
542send$ACK:
543	push	psw		; save return code
544	mvi	c,ACK
545	call	nChar$out  	; send ACK if checksum ok
546	pop	psw		; restore return code
547	ret
548
549bad$DID:
550bad$checksum:
551	mvi	c,NAK
552	jmp	Char$out  	; send NAK on bad chksm & not max retries
553;	ret
554
555error$return:
556	lxi	h,network$status
557	ora	m
558	mov	m,a
559	call	ntwrkerror 	; perform any required device re-init.
560	mvi	a,0ffh
561	ret
562
563ntwrkerror:
564				;  perform any required device
565	ret			;     re-initialization
566
567	page
568;
569ntwrkwboot:
570
571;	This procedure is called each time the CCP is
572;  	reloaded from disk.  This version prints "<WARM BOOT>"
573;  	on the console and then returns, but anything necessary
574;       for restart can be put here.
575
576 	mvi	c,9
577	lxi	d,wboot$msg
578	jmp	BDOS
579
580	page
581	if	cpnos
582;
583;	LOGIN to a Master
584;
585; Equates
586;
587buff	equ	0080h
588
589readbf	equ	10
590
591active	equ	0001$0000b
592
593loginpr:
594	mvi	c,initpasswordmsglen
595	lxi	h,initpasswordmsg
596	lxi	d,passwordmsg
597copypassword:
598	mov	a,m
599	stax	d
600	inx	h
601	inx	d
602	dcr	c
603	jnz	copypassword
604	mvi	c,print
605	lxi	d,loginmsg
606	call	BDOS
607	mvi	c,readbf
608	lxi	d,buff-1
609	mvi	a,50h
610	stax	d
611	call	BDOS
612	lxi	h,buff
613	mov	a,m	; get # chars in the command tail
614	ora	a
615	jz	dologin ; default login if empty command tail
616	mov	c,a	; A = # chars in command tail
617	xra	a
618	mov	b,a	; B will accumulate master ID
619scanblnks:
620	inx	h
621	mov	a,m
622	cpi	' '
623	jnz	pastblnks ; skip past leading blanks
624	dcr	c
625	jnz	scanblnks
626	jmp	prelogin ; jump if command tail exhausted
627pastblnks:
628	cpi	'['
629	jz	scanMstrID
630	mvi	a,8
631	lxi	d,passwordmsg+5+8-1
632	xchg
633spacefill:
634	mvi	m,' '
635	dcx	h
636	dcr	a
637	jnz	spacefill
638	xchg
639scanLftBrkt:
640	mov	a,m
641	cpi	'['
642	jz	scanMstrID
643	inx	d
644	stax	d	;update the password
645	inx	h
646	dcr	c
647	jnz	scanLftBrkt
648	jmp	prelogin
649scanMstrID:
650	inx	h
651	dcr	c
652	jz	loginerr
653	mov	a,m
654	cpi	']'
655	jz	prelogin
656	sui	'0'
657	cpi	10
658	jc	updateID
659	adi	('0'-'A'+10) and 0ffh
660	cpi	16
661	jnc	loginerr
662updateID:
663	push	psw
664	mov	a,b
665	add	a
666	add	a
667	add	a
668	add	a
669	mov	b,a	; accum * 16
670	pop	psw
671	add	b
672	mov	b,a
673	jmp	scanMstrID
674
675prelogin:
676	mov	a,b
677
678dologin:
679	lxi	b,passwordmsg+1
680	stax	b
681	dcx	b
682	call	sendmsg
683	inr	a
684	lxi	d,loginfailedmsg
685	jz	printmsg
686	lxi	b,passwordmsg
687	call	receivemsg
688	inr	a
689	lxi	d,loginfailedmsg
690	jz	printmsg
691	lda	passwordmsg+5
692	inr	a
693	jnz	loginOK
694	jmp	printmsg
695
696loginerr:
697	lxi	d,loginerrmsg
698printmsg:
699	mvi	c,print
700	call	BDOS
701	jmp	loginpr		; try login again
702
703loginOK:
704	lxi	h,network$status ; HL = status byte addr
705	mov	a,m
706	ori	active	; set active bit true
707	mov	m,a
708	ret
709
710;
711; Local Data Segment
712;
713loginmsg:
714	db	cr,lf
715	db	'LOGIN='
716	db	'$'
717
718initpasswordmsg:
719	db	00h	; FMT
720	db	00h	; DID Master ID #
721	db	slave$ID ;SID
722	db	40h	; FNC
723	db	7	; SIZ
724	db	'PASSWORD' ; password
725initpasswordmsglen equ	$-initpasswordmsg
726
727
728loginerrmsg:
729	db	lf
730	db	'Invalid LOGIN'
731	db	'$'
732
733loginfailedmsg:
734	db	lf
735	db	'LOGIN Failed'
736	db	'$'
737
738	DSEG
739passwordmsg:
740	ds	1	; FMT
741	ds	1	; DID
742	ds	1	; SID
743	ds	1	; FNC
744	ds	1	; SIZ
745	ds	8	; DAT = password
746	endif
747
748	end
749