[comp.arch] Instruction Restart and I/O

baum@Apple.COM (Allen J. Baum) (09/09/89)

[]
There seems to be a problem with instruction restart and memory mapped I/O.,
for example, in article <blahblahblah> deraadt@enme3.UUCP(Theo Deraadt) writes:
>Gad. How about a hardware FIFO? How about a serial receive buffer on
>your generic serial chip?

If you re-execute, then you might dump something into the FIFO twice.
Or, (more likely), you'll take something out twice.

This is only because of a design practice that should be abolished, which is
side-effects upon reading. Without this mis-feature, extraneous reads do not
change state, and the problems don't occur.

Writes generally will not get re-executed anyway, since if you execute
the write, then you've sucessfully completed the instruction and you
don't have to do it again.  --
		  baum@apple.com		(408)974-3385
{decwrl,hplabs}!amdahl!apple!baum

jonah@db.toronto.edu (Jeffrey Lee) (09/11/89)

baum@Apple.COM (Allen J. Baum) writes:
>There seems to be a problem with instruction restart and memory mapped I/O.,
>for example, in article <blahblahblah> deraadt@enme3.UUCP(Theo Deraadt) writes:
>>Gad. How about a hardware FIFO? How about a serial receive buffer on
>>your generic serial chip?

>If you re-execute, then you might dump something into the FIFO twice.
>Or, (more likely), you'll take something out twice.

>This is only because of a design practice that should be abolished, which is
>side-effects upon reading. Without this mis-feature, extraneous reads do not
>change state, and the problems don't occur.

It is probably worth noting that the situation gets much worse when
there are 2 or more memory arguments to an instruction (CISC) or when
there is an instruction pipeline (RISC/CISC).  Ideally you would like
to ensure that an instruction restart or continuation will not cause
any data to be read or written for a second time.  [Note: an
instruction may be fetched twice, but no data should be read or written
twice.]  This may be easier to accomplish on a RISC processor where
there is at most one memory argument per instruction (as in most
load/store RISC processors).

I believe that the following constraints may be sufficient (although
not all necessary) to ensure deterministic exception handling with no
double reads or writes:

    Instructions in the pipeline must be allowed to commit, be
    check-pointed (for continuation), or be aborted (for restart) in
    the order that they were fetched.  An instruction must NOT be
    committed unless all instructions fetched before it have been
    committed.  An instruction that commits need not be restarted.  An
    instruction that aborts must have no net-effect on the processor
    state or on the external memory state.  [Corollary: An instruction
    cannot be aborted if it may have had an effect on the external
    memory state.]  An instruction must not be aborted unless all
    instructions fetched after it can be aborted.  An instruction must
    be check-pointed (for continuation) if it can neither be committed
    nor aborted for any reason.

    If an external memory read, write, or read-modify-write cycle is
    begun on behalf of an instruction, that cycle should be allowed to
    complete BEFORE handling any interrupts or exceptions.  If the
    cycle completes successfully, the associated instruction must be
    allowed to commit or else it must be check-pointed BEFORE handling
    the interrupt or exception.  If the cycle fails to complete
    successfully, the associated instruction shall be deemed to have
    triggered (and raised) the exception (if any) associated with the
    failure.

    If an instruction generates an exception (as opposed to an external
    interrupt), all instructions prior to it should be allowed to
    COMPLETE and all instructions after it must be allowed to abort (or
    be check-pointed) BEFORE beginning the exception processing.  If
    two instructions in a pipeline cause an exception, the exception(s)
    from the instruction fetched first must be handled first.

    No new memory cycles should be begun after an exception is raised
    except to sevice the exception.  Hence, any pending instructions
    that require external memory access to complete must be aborted (if
    possible) or check-pointed.  This means that an instruction MUST
    NOT begin any memory accesses or raise an exception until ALL prior
    instructions have finished their memory accesses and/or exception
    processing (at which point they are free to execute to completion).

    If an external interrupt occurs after an exception is raised,
    the processor should finish preparing for the exception handler
    to execute (completing, aborting or check-pointing instructions)
    before raising the interrupt exception.  Otherwise, an external
    interrupt should cause all pending instructions to be committed,
    check-pointed, or aborted as appropriate.  Once again, completion
    of pending instructions must not require any NEW memory accesses to
    be begun.

    If the processor cannot guarantee that the execution is continuable
    according to these constraints, it must save a status flag to
    indicate that fact.  Further more, the status flag should be saved
    in such a way that it will trigger an exception iff an attempt is
    made to resume execution in that state.  [Ideally a processor
    should be designed to preclude the need for this flag bit.]

These constraints are likely much easier to implement and verify in the
design of a RISC processor than in a CISC processor.  In particular, it
may be possible to avoid the need for instruction check-pointing and
continuation through careful design of the pipeline.  On the other
hand, a CISC processor with multiple memory operands MUST support
instruction continuation in order to satisfy these constraints.

j.

eifert@oakhill.UUCP (Jim Eifert) (09/14/89)

The MC68332 uses "instruction restart."  Most instructions are considered
completed when the write is received by the bus controller.  When a fault
occurs, both the PC of the instruction to execute upon restarting and the
"released" write are stacked (in addition to some other information  -- see
the manual).  Because of this: on a move memory to memory, a write which is
faulted will not cause the read to be rerun.  When the process is continued,
the write will be queued up, and the next instruction started (or
restarted).

Some instructions such as move multiple are continued from a midpoint,
though a larger stack frame is not required.

Note the the CPU of the MC68332 is a new design and the "virtual memory"
implementation is not necessarily similiar to any other present or future
products.

For those unfamiliar with the MC68332, see "The MC68332 Microcontroller"
in the August 1989 issue of IEEE Micro.  Or refer to the May and
June issues of Microprocessor Report.

Jim Eifert