;-*- Mode:Text -*-

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.

Clocks and H-addr-select (16L8-B):
	inputs: IR_CHOP(3), CHOP_D(3), C(1), CD(1), CH_MODE(1), FORCE_NOP(1)
	   (chop, chop_delayed, clock, clock_delayed, ch_mode, force_nop_during_trap)
	O			;from here ...
	A
	R
	RD, RPC
	TO, TA
	TR			;... to here gated with 2C
	Haddr mux select (2)

O/A/R/RD/RPC/TO/TA/TR
Registered-mux selects (16R8-B):
	inputs: IR_CHOP(3), CD(1), CHMODE(1)
	clock: 2C
	O, A
	RD, RPC, TO, TA
	TR
	R select		;can this be O/A or TR?
	HO, HA write		;gate with 2C*
	HRD, HPC write		;""

other stuff:
	OO, OA, OR clocks	;clock on C, inhibit on TRAP - not in PAL?
	OO, OA, OR output enable
	HO, HA, HRD, HPC output enable
	MFO to HO, HA, HRD, HPC output enables
	free-ptr-mode??
	free-ptr clock?

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

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/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
	asserted during ALU0:

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.

	assumed asserted during D:
		TO <- O
		TA <- A

	asserted during D:
		Haddr <- free
		(Assert freelist output; address by out-ptr)
	clocked at end of D:
		TO, TA
		(Hram addr latch clocks new free frame)
	asserted during R:
		H(free) <- TO, TA
		O <- free(free-ptr)		;free
		free-ptr-mode <- count-up
		Haddr <- (anything)
	clocked at end of R:
		O, free-ptr
		(clock free out-ptr)
	asserted during ALU0:

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).

	assumed asserted during D:
		RPC <- PC+1
		RD <- IR:ret-dest

	asserted during D:
		Haddr <- O
	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			;want to assert H(active) during ALU0
	clocked at end of R:
		A
	asserted during ALU0:

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.

	assumed asserted during D:
		TO <- O
		TA <- A
		RPC <- PC+1			;PC+1 is only valid until end of D
		RD <- IR:ret-dest

	asserted during D:
		Haddr <- free
		(Assert freelist output; address by out-ptr)
	clocked at end of D:
		TO, TA, RPC, RD			;RPC, RD valid if RETURN follows
		(Hram addr latch clocks new free frame)
	asserted during R:
		H(free) <- TO, TA, RPC, RD
		O <- free(free-ptr)		;free
		A <- free(free-ptr)		;Haddr
		free-ptr-mode <- count-up
		Haddr <- free			;to assert H(active) during ALU0
	clocked at end of R:
		O, A, free-ptr
		(clock free out-ptr)
	asserted during ALU0:

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
	clocked at end of D:
	asserted during R:
		TO, TA, RPC, RD <- H(active)
		O <- free(free-ptr)		;free
		free-ptr-mode <- count-up
		Haddr <- free			;to assert H(open) during ALU0
		(Assert freelist output; address by out-ptr)
	clocked at end of R:
		O, TO, TA, RPC, RD, free-ptr
	asserted during ALU0:
		H([open]) <- TO, TA, RPC, RD	;OK; not followed by anything that uses it.

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
	2. copy open to active.

	asserted during D:
		Haddr <- O
	clocked at end of D:
	asserted during R:
		RPC, RD <- H(open)		;RPC, RD valid if RETURN follows
		A <- O				;Haddr
		R <- A
		TR <- R
		free-ptr-mode <- down
		Haddr <- O			;to assert H(active) during ALU0
	clocked at end of R:
		A, RPC, RD, R, TR, free-ptr
	asserted during ALU0:
		free(free-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
		O <- H(active)
		A <- H(active)
		TR <- R
		R <- A
		RPC, RD already valid

	asserted during D:
		Haddr <- HA			;H(active), next return frame
	clocked at end of D:
		O, A, R, TR
	asserted during R:
		free-ptr-mode <- count-down
		Haddr <- A			;to assert next H(active) during ALU0
	clocked at end of R:
		RPC, RD <- H(active)		;RPC, RD valid for RETURN following this RETURN
		free-ptr
	asserted during ALU0:
		free(free-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
	clocked at end of D:
	asserted during R:
		O, A <- H(open)
		TR <- O
		free-ptr-mode <- count-down
		Haddr <- (anything)
	clocked at end of R:
		O, A, TR, free-ptr
	asserted during ALU0:
		free(free-ptr) <- TR


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

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 <- free
		TO <- O
		TA <- A
		O <- free			;free(out-ptr) asserted during D
	clocked at end of D:
		O, TO, TA
	asserted during R:
		H(free) <- TO, TA
	clocked at end of R:
		(clock free out-ptr)

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 <- free
		RPC <- PC+1			;PC+1 is only valid until end of D
		RD <- IR:ret-dest
		TO <- O
		TA <- A
		O <- free
		(Assert freelist output; address by out-ptr)
	clocked at end of D:
		O, TO, TA, RPC, RD		;RPC, RD valid if RETURN follows
		(Hram addr latch clocks new free frame)
	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
		(clock free out-ptr)

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 <- free
		(Assert freelist output; address by out-ptr)
	clocked at end of D:
		O
	asserted during R:
		TO, TA, RPC, RD <- H(active)
		Haddr <- O  ;free		;to assert H(open) during ALU0 (?)
	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 it.
		(clock free out-ptr)

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
	2. copy open to active.

	asserted during D and R:
		(assume TR <- R?)
		TR <- R (tri-state mux?) - can't meet setup time for sep. mux and reg
	asserted during D:
		Haddr <- O
	clocked at end of D:
		TR
	asserted during R:
		RPC, RD <- H(open)		;RPC, RD valid if RETURN follows
		A <- O				;Haddr
		R <- A
		Haddr <- O			;to assert H(active) during ALU0
		write free-list, enable data in (TR)
		(address free-list by in-ptr)
	clocked at end of R:
		R, A, RPC, RD
		(clock free in-ptr)

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
	asserted during R:
		Haddr <- A			;to assert next H(active) during ALU0
		write free-list; enable data in (TR)
		(address free-list by in-ptr)
	clocked at end of R:
		RPC, RD <- H(active)		;RPC, RD valid for RETURN following this RETURN
		(clock free in-ptr)

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
	asserted during R:
		O, A <- H(open)
		write free-list; enable data in (TR)
		(address free-list by in-ptr)
	clocked at end of R:
		O, A
		(clock free in-ptr)

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

	ideal...	in simple gates...
	D	R	D	R
	=	=	=	=
call	O	O	O	O
t-call	O	O	O	O
cancel	O	-	O	O
return	- (HA)	-	O	O

no-op	A	A	A	A
t-open	A	free	A	free
open	free	-	free	-
op-call	free	free	free	free

;;;;

restoring state:
back up call hardware state to that at start of instruction two
instructions back.
theoretical alternative: delay effect of operations by two instructions.

restore:
	Hram
	O, A, R, RPC, RD
	free-ptr
	freelist
RD and RPC are restored from H(active).
O, A, and R are explicitly remembered.
Freelist is a FIFO; in/out pointers are restored.

running call-hardware backwards:

no-op
	inverse is no-op
open
	inverse is cancel-open
call
	?
open-call
	inverse is return
t-open
	inverse is cancel-open
t-call
	?
return
	need values popped from Hram and old values of O, A, R
cancel-open
	inverse is open or t-open
	how to know which?

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

Hram address mux select:
	R	ALU0	DIRECT
t-open	active	free
no-op	active	active
return	active	active
open	free	active

call	open	active
t-call	open	active
cancel	open	active
op-call	free	active

also: select MFO reg -> addr (always sel during direct mode?)
output enables for Hram, MFO -> Hram-data, Old-O/A/R
MFO out-enable can be from MFO decode, or from a control reg.
contention is Hram, OO-OA-OR, MFO.

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

trap timing:

TRAP is the OR of all trap sources, gated with C* and TRAP_EN.  If
asserted at least 10ns before C, the instruction currently in the
Compute cycle is aborted; the write cycle that would normally begin
on C is inhibited, and the call-hardware operations starting at the
next C* edge are inhibited.

1. Can gating with C* cause glitches on C?
2. What happens when TRAP is asserted less than 10ns before C?


TRAP may have to directly inhibit C and the following reg-ram write.
This requires TRAP to occur at just the right time at last just
long enough - rising and falling edge must be synchronized with
clocks and writes that are being inhibited.

Ideally, TRAP is a clock to a reg whose output is used as the inhibit,
but this probably cannot meet the setup time to inhibit C.
Alternative: reg is part of the clock generator.

TRAP can directly inhibit C and C2, but there is time to clock TRAP
on C and use that to inhibit the next reg-ram write and call-hardware
clocks, and then clock that on C* to inhibit the next call-hardware write.

If TRAP is asserted when C starts, TRAP_1 is set for one C cycle
starting at C, and TRAP is inhibited from the end of TRAP_1 until
the trap resume code starts the enable sequence.

Need:

TRAP_EN: Control-reg bit.  If deasserted, TRAP is ignored.
	Reset on first C of trap entry.  May be set by software;
	also set at end of TRAP_OUT sequence.
TRAP_1:   Clocked on C; set for
	exactly one C cycle.  Used to start back-up sequences.
	Possibly used OR'ed with TRAP to meet C-inhibit setup time.
TRAP_IN: Clocked on C; set from first C of trap entry until reset
	by software.  Used to inhibit clocks and writes of registers
	that must be saved by trap-entry code.  Reset by trap-entry
	code when state-saving is complete.
	Most likely, it is split into multiple signals for alu-output-reg,
	alu-input-regs etc.
	Used to gate call-hardare OO/OA/OR clocks.
D_TRAPIN: TRAP_IN delayed one C; possibly AND'ed with TRAP_IN.
	Used at least for trap reg?
TRAP_OUT: Set (as func-dest) by software to start trap-exit sequence.
	Is reset when sequence is complete; TRAP_EN is set at
	the appropriate point.
TRAP_REG: clocked on C up through C after TRAP; is clocked there
	to save the TRAP sources that were asserted.  Clock is inhibited
	at least until software reads and saves it; probably it
	is inhibited with D_TRAPIN.  Read on MFO.  Read-only;
	sources must be reset 

Somewhere in here (variations of TRAP_IN and TRAP_OUT) are the
clock-enables for the ALU input-regs, output-reg and what else?
	
NOTE:
TRAP_EN is software trap-enable bit; is reset on trap entry
and set when trap exit is complete or when traps are recursively enabled.
TRAP_IN indicates trap-entry / backup / state freeze
is in progress; it is reset when entry is complete and real trap code
is running.  TRAP_OUT is set when trap routine is starting trap-exit
sequence; it is reset when exit is complete and TRAP_EN is set again.

;;;;

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?