;-*- 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?