;  VMEM.MU -- microcode for VMEM package
;  last modified October 13, 1977  5:55 PM
; R registers required
;$mapbase $Rxx;	base of hash map, must be even
;$mapsptr $Rxx;	map statistics pointer (up to mapbase), or 0
;$mapmask1 $Rxx;	hash table size -2 (e.g. 376, 776)
; Copyright Xerox Corporation 1979
$mmx	$R5;	=SAD, temp for mask bits
$key	$R7;	=XREG, temp for hash key (virtual page #)
$mrx	$R10;	=XH, miscellaneous temp
; Other requirements
;$M	$R40;	the new L register
;!1,20,START;	ROM entry to Nova emulator

;  Constants
$readref	$4;
$writeref	$6;
$notrefbit	$4;
$reprobinc	$30;	use with reprobinc+1  +1
$mamask		$177400;	address part of map entry

;  Predefinitions for labels
!1,2,nempty,empty;	for dispatch on empty entry
!1,2,nomatch,match;	for dispatch on match with key
!1,2,nmaskok,maskok;	for dispatch on ref/dirty bits
!1,2,nclean,clean;	for dispatch on write ref. to clean page
!1,2,noskip,coreaddr;	testing for core address
!1,2,dostat,nostat;	testing mapsptr=0
!1,2,nfull,full;		testing mapsptr=mapbase

;  read/write mapping - v.a. is in AC0, AC1
rref:	L←readref, TASK, :domap;	mask for reading
wref:	L←writeref, TASK, :domap;	mask for writing
domap:	mmx ← L;

;  form hash key from AC0 (8-15) and AC1 (0-7)
	L←T←AC0 OR T;
	key←L LCY 8;		stash key
;  form initial probe
	T←key+T+1;	+1 is noise
probe:	L← mapmask1.T, TASK;
	mrx ← L;		save initial probe for TASK

	T ← mrx;
	L ← MAR ← mapbase+T;
	AC3 ← L;
	L←MD+T+1, BUS=0;	catch memory data,test for empty
	SH=0, T←MD, :nempty;	catch second word of data
				;dispatch on empty,test for match
;  test for match hanging
nempty:	L ← mmx AND T, :nomatch;	dispatch on match, test for r/w
empty:	T ← 377 - 1, :empty1;	override match dispatch
empty1:	L ← AC0 XOR T;
	SH=0, L ← AC1;
	  :noskip;	test for core addr
coreaddr: AC3 ← L, :mstats;
;  testing for masked bits
match:	mrx ← L RSH 1, L ← T, SH=0;	save masked bits
	T ← mamask.T, :nmaskok;	dispatch on bits set or not
nomatch: T← reprobinc + 1;	add in the first 1
	T← mrx+T+1, :probe;	add in the other 1
nmaskok: T← mrx, BUSODD, TASK;	L has 2nd word from hash map
 	mrx ← L, :nclean;	test for write to clean page

maskok:	L← AC1+T, TASK;
	AC3← L, :mstats;

nclean:	MAR← AC3+1;		going to set ref bit to zero
	T ← mrx;
	L ← notrefbit XOR T;
	MD ← M;		rewrite second word
	T ← mamask.T, :maskok;

;  write ref to clean page
clean:	L ← PC, SWMODE, :nskip1;	noskip return with AC3=hashmap ptr
;  page not in core
noskip:	L ← PC, SWMODE, :nskip1;	ditto
; Skip return to Nova emulator
nskip:	L ← PC+1, SWMODE;
nskip1:	PC ← L, :START;

; Log map reference
mstats:	L ← T ← mapsptr;
	L ← mapbase-T, SH=0;	test for no logging
	MAR ← T, SH=0, :dostat;	test for buffer full
nostat:	L ← PC+1;
	SINK ← MD, SWMODE, :nskip1;	discard memory data, do skip return
dostat:	L ← 2+T, :nfull;
full:	L ← mapsptr-1, TASK;	signal buffer overflow with funny AC3
	AC3 ← L, :noskip;
nfull:	MD ← AC0;
	MAR ← L ← mapsptr+1;
	L ← M+1;
	mapsptr ← L, TASK;
	MD ← AC1, :nskip;