;-*- Mode:Text -*-

6/23:
want RD to be clocked at end of D, so the valid RD
can be clocked again on C by the reg-adr select.
No way to get RD before clock at C, so reg-adr select mux change.
Delay IR_DEST and DRET_SEL; mux with RD after that.
Is there time for the two mux delays?

6/6/86: added register between Hram addr mux and Hram

;;;;;;;;;;;;;;;;

Sources are CH state before current instruction's call-hardware operation;
destinations are after.

Frames available as source and destination bases:

Open:
	Frame to store arguments for function that is about to be called.

Active:
	Frame for current function local variables and the arguments
	the function was called with.

Return:
	Frame in which to store values to be returned by the active function.

Global:
	Frame number comes from IR 4-bit immediate combined with frame offset.

Functional Source / Dest ...

;;;;;;;;;;;;;;;;

Definition of instruction cycles:

Cycle 1: PC / IR
IR: (70ns)
	PC is asserted at PC mux output for last 50ns of this cycle.
	Mux inputs must be valid for this time; PC is not latched.
	IR is clocked with valid instruction at end of this cycle.

Cycle 2: Decode / R
Decode: (35ns)
	ALU opcode is computed from IR.
	First call-hardware cycle.  First call-hardware clock is at end.
	Assert values of O, A, R for use as sources for this R and as
	destination for previous W.

R: (35ns)
	Register read for ALU sources.
	Second call-hardware cycle.  Call-hardware op is complete and
	is clocked at end.

Cycle 3: ALU
ALU: (70ns)
	ALU instruction and data inputs are asserted; output is valid
	in time for clock at end.
	clocked at input and output (start of ALU0, end of ALU1).

Cycle 4: W
W: (35ns)
	Register write with ALU dest (or ret-dest).  Register ram is
	addressed by dest from IR for all but RETURN, and by ret-dest
	from Hram for RETURN.  

;;;;;;;;;;;;;;;;

Call-hardware operations specified for R and ALU0:
Must clock new O, A, and R at end of R.
For RETURN, RPC must be valid at clock at start of D, and RD must
be valid before clock at end of R.

INPUT DEFINITIONS:
C, CD, C2: primary machine clocks
IR_CHOP (3): CHOP field from IR
D_CHOP (3): IR_CHOP clocked on C~ (to delay 1/2 cycle)
D2_CHOP (3): IR_CHOP clocked twice on C (delay 2 full cycles)
CH_DIRECT (1): "direct access" call-hardware control-reg mode bit
TRAP_1 (1): asserted during first cycle of trap entry
TRAP_2 (1): asserted during first two cycles of trap entry

CHCLK: 16L8-B (clocks and Hram addr select)
	inputs: IR_CHOP(3), D_CHOP(3), C(1), CD(1), CH_DIRECT(1), TRAP_1(1)
	left: 0 inputs, 0 outputs
	OF_CEN~		;gated with C2
	AF_CEN~		; ""
	RF_CEN~		; ""
	RDRPC_CEN~	; ""  (RD, RPC)
	TOA_FRA_CEN~	; ""  (TO, TA, FRA)
	HADR_SEL (3)	;Hram adr mux select
backup stuff:
	TRAP . CD: assert clock enables to clock OF, AF, RF with OO, OA, OR

;;CHSEL: 16R8-B (mux selects and Hram write enables)
;;	inputs: IR_CHOP(3), CD(1), CH_DIRECT(1), TRAP_1(1)
;;	left: 2 inputs, 2 outputs
;;	clock: C2
;;	enable: always
CHSEL: 16L8-B (mux selects and Hram write enables)
	inputs: IR_CHOP(3), D_CHOP(3), C(1), CD(1), CH_DIRECT(1), TRAP_1(1)
	left: 0 inputs, 0 outputs
	O_A_SEL		;OF, AF
	RD_PC_T_SEL	;RD, RPC, TO, TA
	TR_SEL		;TR
	R_SEL		;RF; normally AF; OR during backup, MFO during trap
	OOAR_OE~	;OO, OA, OR output enables
	HRAM_CS~	;Hram chip select
	;; ..WEN's are clocked on C2 before use.
	HO_HA_WEN	;HO, HA write-enable; gate with C2~ (pos. true if easy)
	HRDPC_WEN	;HRD, HPC write-enable; ""

CHFREE: 16L8-B (freelist)
	inputs: IR_CHOP(3), D2_CHOP(3), C(1), CH_DIRECT(1), TRAP_2(1)
	left: 1 input, 2 outputs
	RDP_CEN~	;read-ptr clock enable
	WRP_CEN~	;write-ptr clock enable
	FR_PE~		;parallel-entry for in/out/nl
	NL_CEP~		;number-left clock enable
	NL_UP		;number-left up (down~)
	FR_WR		;freelist ram write (pos. true if easy)

constant:
	TR		;clock on C~
	NEW		;clock on C
	OO, OA, OR	;clock on C
	Haddr reg	;clock on C2

to-do:
	HMFI_DIR	;Hram to MFI direction
	OAR_IEN~	;O/A/R / MFI buffer enable
	RDRPC_IEN~	;RD/RPC / MFI buffer enable

backup:
	TRAP_1 is asserted for first C cycle.
	TRAP_1 immediately forces OOAR_OE on and HRAM_CS off;
	selects OO/OA/OR for OF/AF/RF;
	asserts OF_CEN, AF_CEN and RF_CEN during first clock.
	OOAR_OE can turn off during second half of C;
	turn HRAM_CS back on after TRAP_1.

PALs supply OOAR_OE~ and HRAM_CS~
	(go through "none" when switching)
func source/dest decode supplies HMFI_DIR, OAR_IEN~ and RDRPC_IEN~

trap: backup
direct-mode chops:
	(nop): read H(active) HO/HA through MFI
	(nop): read H(active) HRD/HPC through MFI
	(read OOAR): read OO/OA/OR through MFI
	write to func-dest d-oar; select and clock OF/AF/RF at end of R
	write to func-dest d-rdrpc; select and clock RD/RPC at end of R
	(??): read RDP through MFI ... RDP / WRP use same func-source with diff. chops.
	(??): read WRP through MFI
	(??): read NL through MFI (only needs func-source decoding)
	(??): write RDP/WRP/NL from MFO
	(??): write Hram address from MFO; maybe HADDR-DIRECT reg can be removed.
		;;or, most direct Hram address is from OF or AF.
RDP/WRP/NL chop's can overlap other direct-mode chop's
	
;;;;;;;;;;;;;;;;

Sequence is:
	(assume all legal possible preceding instructions left
	 valid defaults set up during D)
	clocked at end of D:
	asserted during R:
	clocked at end of R:
	asserted during ALU0:

defaults, asserted during ALU0 for use by next instruction:
		H(active)
		O <- H(active)
		A <- H(active)
		TO <- O
		TA <- A
		RPC <- PC+1
		RD <- IR:ret-dest
		R <- A
		TR < R
		free-ptr-mode <- count-down

;;;;;;;;;;;;;;;;

6/7:
	move selects back to D and R; (changes CH_SEL from 16R8 to 16L8)
	clocks are still D and R;
	writes are R and ALU0
6/6:
	register on Hram address; means selected address is from before
	clock (C2) at start of write.  ... Means Hram address select must
	be known before clock.

No-op:
	Do nothing; read next RPC and RD from H(active).

	asserted during D:
		Haddr <- A
	clocked at end of D:
	asserted during R:
		RPC, RD <- H(active)		;RPC, RD valid if RETURN follows
		Haddr <- A			;to assert H(active) during ALU0
	clocked at end of R:
		RPC, RD

Open:
	Create a new open frame in preparation for a function call.

	1. allocate a new frame and save open and active in it.
	2. make the new frame be the open frame.

	asserted during D:
		Haddr <- NEW
		TO <- O
		TA <- A
		O <- NEW
	clocked at end of D:
		O, TO, TA
		freelist out-ptr
	asserted during R:
		H(free) <- TO, TA
	clocked at end of R:

Call:
	Call a function.  Make the current open frame become the active frame.
	Set up RPC and RD since RETURN may follow.

	1. copy open frame pointer to active frame.
	2. save the return-PC and return-destination in H(active).

	asserted during D:
		Haddr <- O
		RPC <- PC+1
		RD <- IR:ret-dest
	clocked at end of D:
		RPC, RD
	asserted during R:
		H(open) <- RPC, RD		;RPC, RD valid if RETURN follows
		A <- O				;Haddr
		Haddr <- O			;to assert H(active) during ALU0
	clocked at end of R:
		A

Open-call:
	Create a new open frame, make it the active frame and call a function.
	Set up RPC and RD since RETURN may follow.

	1. allocate a new frame and save open, active, ret-PC and ret-dest in it.
	2. set open and active to the new frame.

	asserted during D:
		Haddr <- NEW
		RPC <- PC+1			;PC+1 is only valid until end of D
		RD <- IR:ret-dest
		TO <- O
		TA <- A
		O <- NEW
	clocked at end of D:
		O, TO, TA, RPC, RD		;RPC, RD valid if RETURN follows
		freelist out-ptr
	asserted during R:
		H(free) <- TO, TA, RPC, RD
		A <- Haddr			;free from D
		Haddr <- O			;to assert H(active) during ALU0
	clocked at end of R:
		A

Tail-recursive-open:
	Copy the current active frame into a new open frame, in preparation for
	a tail-recursive call, which will throw away the active frame as
	if returning; then start a new call by copying open to active.

	1. copy H(active) into a new frame H(free)
	2. make the new frame be the open frame.

	asserted during D:
		Haddr <- A
		O <- NEW
	clocked at end of D:
		O
		freelist out-ptr
	asserted during R:
		TO, TA, RPC, RD <- H(active)
		Haddr <- O  ;free
	clocked at end of R:
		TO, TA, RPC, RD
	asserted during ALU0:
		H(open) <- TO, TA, RPC, RD	;OK; not followed by anything that uses H(active)

Tail-recursive-call:
	Call a function.  Discard the active frame as if returning, and make the
	current open frame become the active frame.
	Set up RPC and RD since RETURN may follow.

	1. push return onto frame freelist
	2. copy active to return
	3. copy open to active.

	asserted during D:
		Haddr <- O
		TR <- R
	clocked at end of D:
		TR
		freelist in-ptr
	asserted during R:
		RPC, RD <- H(open)		;so RPC, RD valid if RETURN follows
		A <- O				;Haddr
		R <- A
		Haddr <- O			;to assert H(active) during ALU0
	clocked at end of R:
		R, A, RPC, RD
	asserted during ALU0:
		freelist(in-ptr) <- TR

Return:
	Restore the frame environment to that prior to the preceding CALL.
	Dest is H(active) ret-dest dest and offset.
	Set up RPC and RD since RETURN may follow - allows RETURN - RETURN.

	Requires that RPC and RD already contains H(active) RPC and RD
	at the start of this instruction Decode cycle, so RPC can
	immediately be selected as the next PC source.

***	NOTE: If Haddr <- HA path is too slow, the RPC/RD clocked during RETURN
	is invalid.  This is the slowest path from the Hram outputs.  The only
	effect is that RETURN - RETURN can't be used; any other instruction
	following RETURN will compute the correct RPC / RD for a following RETURN.

	1. push return onto frame freelist.
	2. copy active to return.
	3. pop open, active, PC and ret-dest from H(active)

	assumed asserted during D:
		H(active)			;this return frame
		RPC, RD already valid

	asserted during D:
		Haddr <- HA			;H(active), next return frame
		O <- H(active)
		A <- H(active)
		TR <- R
		R <- A
	clocked at end of D:
		O, A, R, TR
		freelist in-ptr
	asserted during R:
		Haddr <- A			;to assert next H(active) during ALU0
		(address free-list by in-ptr)
	clocked at end of R:
		RPC, RD <- H(active)		;RPC, RD valid for RETURN following this RETURN
		freelist(in-ptr) <- TR

Cancel-open-frame:
	Undo an open or a t-open.
	Cannot be followed by RETURN.

	1. push open onto the freelist.
	2. restore active and open from H(open).

	asserted during D:
		Haddr <- O
		TR <- O
	clocked at end of D:
		TR
		freelist in-ptr
	asserted during R:
		O, A <- H(open)
	clocked at end of R:
		O, A
		freelist(in-ptr) <- TR

;;;;

back-up and direct access operations:

back-up frame regs: one cycle; clock OO/OA/OR into O/A/R
back-up freelist: two cycles; run counters backwards

;;;;;;;;;;;;;;;;

call hardware backup:

During TRAP_1, restore O/A/R from OO/OA/OR, and back-up the freelist.
OO/OA/OR don't need to be clocked; just disable the Hram, turn on
the OO/ out-enables, select O/A/R, and clock O/A/R.
Note: can MMI 'LS548 internal clock enables be used?

The two chop's between the instruction that was aborted and the C*
inhibit after TRAP are the two that are backed-up.  The one after
that - that is started on the C* after TRAP - is the back-up chop.
That must be forced with the TRAP_1 input to the CH PALS.  
After that, the chop's are from the valid IR's of the trap entry code.

At worst, two states may be needed for backup.  The first must
be forced with TRAP_1, but the second can depend on the chop from
the first trap entry IR.

Call-hardware needs internal control of Hram OE and OO/OA/OR OE;
how to share control with MFO access and func-dest / func-source decoding?

;;;;

Freelist FIFO:

Easiest way to save pointer values is with MMI '548 double-reg.

Easiest way to do hardware is with 8-bit common-I/O counters,
two MMI '548s, and freelist ram all on common bus, with MFO access.
Common-I/O ram too?

State-save with common counter outputs is easier if counters
are only clocked on C or C*.  If only clocked on C ("end of R"),
only one reg is needed per counter; maybe one '548 can be used for both?

;;;;

backing up last two normal free-list operations:

in-ptr: count-up or hold
out-ptr: count-up or hold
nfree: function of in-ptr and out-ptr