OpC_00 0F - Nakazoto/CenturionComputer GitHub Wiki

OpCodes 0x00 ~ 0x0F

Quick Jump Table

X'00' HLT = Halt X'01' NOP = No operation X'02' SF = Set fault X'03' RF = Reset fault
X'04' EI = Enable interrupt X'05' DI = Disable interrupt X'06' SL = Set link/carry X'07' RL = Reset link/carry
X'08' CL = Complement/invert link/carry X'09' RSR = Return from subroutine X'0A' RI = Return from interrupt X'0B' Illegal
X'0C' SYN = Flash the abort light X'0D' PCX = Transfer PC to X DLY = 4.55 ms delay X'0F' RSV = Return from SVC

Click here to return to Instructions page.

0x00: HLT

Halts the CPU (CPU5/CPU6)

The HLT instruction will check the current interrupt level. If the interrupt level is 15, then the CPU6 enters the Halt state which can be exited with a backplane interrupt or DMA interrupt, or by toggling the R or I dip switches. If the interrupt level is not 15, then HLT will trigger an abort trap with value 1.

Example:

      XFR=     X'00FF',Z    ; Load Z reg. with a value of FF
      CLR      X            ; Clear X register to zero
TOP   INR      X            ; Increment X reg. by one
      XFR      X,Y          ; Transfer counter into Y
      SUB      Z,Y          ; Subtracts Z-Y
      BNZ      TOP          ; Branch if Not Zero to TOP
      HLT                   ; If Zero, restart whole program

This is a simple loop that initially sets Z to a value of 0x00FF and clears the X register to 0. It then copies X to Y and subtracts Y from. It then tests if the result is 0, and if it is not zero (ie. Z is not equal to Y), it jumps back to TOP, increments X and tests again. If the result is zero, it skips to HLT which will Halt the CPU. This illuminate the HALT LED on the front panel and the system must be restarted from there.

0x01: NOP

No operation (CPU5/CPU6)

NOP does not have any microcode, the initial instruction decoding provides the microcode address for the start of the instruction loop.

Example:

     NOP

It's just a no operation, about the most common assembly instruction out there.

0x02: SF

Set the fault flag (CPU5/CPU6)

Other flags are unaffected. Otherwise, pretty much does what it says on the tin.

Example:

     SF                  ; Set the fault flag.

It literally just sets the fault flag, there is not much else that can be explained here...

0x03: RF

Reset the Fault flag to zero

Other flags are unaffected. Otherwise, pretty much does what it says on the tin.

Example:

     RF                  ; Reset the fault flag.

It literally just resets the fault flag, there is not much else that can be explained here...

0x04: EI

Enable Interrupt (CPU5/CPU6)

Enables the interrupt system. This is vital for handling things like MUX or DSK interrupts.

Example:

INITINT   STX-      S-        ; Push X to the stack.
          LDB=      DEFINT    ; B = address of default interrupt handler.
          LDX=      X'001C'   ; X = interrupt level 1 C register.
          LDA=      X'010C'   ; A = one set of registers past the end.
          XAY                 ; A -> Y.
          CLA                 ; A = 0 (page map 0).
II1       STA+      X+        ; Store A to C register, move X to P register.
          STB+      X+        ; Store B to P register, move X to next level A.
          INR       X,12      ; Move X to C register.
          XFR       X,Z       ; X -> Z.
          SUB       Y,Z       ; Z = Y - Z.
          BNZ       II1       ; Loop if not equal.
          LDA=      MUXINT    ; A = address of MUX interrupt handler.
          STA/      (MUXLVL*16)+14 ; A -> MUX level P register.
          LDA=      MUXLVL    ; A = MUX interrupt level.
          STAB/     X'F20A'   ; Set interrupt level in MUX0.
          STAB/     X'F21A'   ; Set interrupt level in MUX1.
          STAB/     X'F20E'   ; Enable MUX0 interrupts (value of AL irrelevant).
          STAB/     X'F21E'   ; Enable MUX1 interrupts (value of AL irrelevant).
          LDA=      TIMERINT  ; A = address of timer interrupt handler.
          STA/      (TIMERLVL*16)+14 ; A -> timer level P register.
          LDA=      ABORTINT  ; A = address of abort interrupt handler.
          STA/      (ABORTLVL*16)+14 ; A -> abort level P register.
          LDX+      S+        ; Pop X from the stack.
          ECK                 ; Enable clock.
          EI                  ; Enable interrupts.
          RSR                 ; Return.

This is a large selection of code from the CPU5 version of Cnake which enables interrupts. The code is well documented, but makes use of many other operations as well.

0x05: DI

Disable Interrupt (CPU5/CPU6)

Disables the interrupt system. This will prevent things like the MUX or DSK from interrupting the CPU for whatever reason.

Example:

SELECT    STB-      S-        ; Push B to the stack.
          DI                  ; Disable interrupts.
          DCK                 ; Disable clock.
          STA/ (TIMERLVL*16)+8 ; A -> timer level Z (the time until interrupt).
          LDA=      SELTIMINT ; A = timer interrupt handler.
          STA/ (TIMERLVL*16)+14 ; A -> timer level P register.
          STA/ (TIMERLVL*16)+0 ; A -> timer level A (some non-0 value).
          ECK                 ; Enable clock.
          EI                  ; Enable interrupts.
          LDA=      MUXBUFF   ; A = MUX buffer.
          LDB       CURRCRT   ; B = Current CRT#.
          AAB                 ; B = A + B. B = address of curr CRT MUX buffer.
SELLOOP   LDAB+     B         ; AL = curr CRT character.
          BNZ       SELCHAR   ; If not 0, there is a character pending.
          LDA/      (TIMERLVL*16)+0 ; Timer level A -> A.
          XFR       A,A       ; A -> A.
          BNZ       SELLOOP   ; Loop if timer not expired.
          JMP       SELDONE   ; If expired, A = 0 and we are done.
SELCHAR   XFRB      AL,AU     ; AL -> AU.
          CLAB                ; AL = 0.
          STAB/     (TIMERLVL*16)+9 ; Zero the timer level ZL - back to normal.
          XFRB      AU,AL     ; AU -> AL.
SELDONE   STA-      S-        ; Push A to the stack.
          LDA=      MAXCRTS   ; A = length of buffer.
          LDB=      MUXBUFF   ; B = buffer.
          JSR/      MVSSF     ; Fill buffer
          DB        0         ; with zeros.
          LDA+      S+        ; Pop A from the stack.
          LDB+      S+        ; Pop B from the stack.
          RSR                 ; Return.

This is a large selection of code from the CPU5 version of Cnake. It waits for the current MUX to have input pending up to the the given timeout (in AL) in 1/60ths of a second (US, max 0x7F = ~2.1 sec) or 1/50ths of a second (non-US, max 0x7F = ~2.5 sec). Returns the character pressed (without high bit set) in AL unless the timeout was hit, in which case 0 is returned in AL. All pending key presses from all CRTs are cleared regardless of the return.

0x06: SL

Set the Link/Carry flag (CPU5/CPU6)

Other flags are unaffected. Otherwise, pretty much does what it says on the tin.

Example:

     SL                  ; Set the link flag.

It literally just sets the link flag, there is not much else that can be explained here...

0x07: RL

Reset the Link/Carry flag to zero (CPU5/CPU6)

Other flags are unaffected. Otherwise, pretty much does what it says on the tin.

Example:

     RL                  ; Reset the link flag.

It literally just resets the link flag, there is not much else that can be explained here...

0x08: CL

Complement/invert link/carry (CPU5/CPU6)

Sets or resets the link/carry flag to the opposite of its current value. If the link is set, it will reset, if it is reset, it will set.

Example:

     CL                  ; Complement the link flag.

It literally just inverts the link flag, there is not much else that can be explained here...

0x09: RSR

Return from SubRoutine (CPU5/CPU6)

When a Jump SubRoutine instruction is run, the X register is pushed to the stack to save its current value, the PC is copied to X, and the effective address (EA) is then copied to the PC. When the program hits the Return from SubRoutine instruction, X is copied into the PC and then X is popped from the stack to restore it's original value.

  • Sets PC to X.
  • Pops X from the stack.

There is a lot more going on behind the scenes, but from a programmer's perspective, this can be thought of as mostly standard subroutine control behavior.

Example:

      CLR      X,1          ; Clears X register and initializes with a 1
LOOP  XFR      X,Y          ; Transfer X register into Y
      JSR/     DELY         ; Jump to DELY subroutine
      INR      X            ; Increment X value
      JMP      LOOP         ; Jump to LOOP label
DELY  DLY                   ; 4.55ms delay
      DCR      Y            ; Decrement Y value
      BNZ      DELY         ; Branch if Not Zero to DELY
      RSR                   ; Return from Subroutine

This is a short loop that initially sets the Y register to 0 and then loops forever. Each iteration the Y register increments, meaning the DELY subroutine loops and delays for longer and longer each time. The RSR instruction at the end tells the subroutine to return to the instruction after JSR that sent it to the subroutine initially and to continue along.

0x0A: RI

Return from Interrupt (CPU5/CPU6)

Returns from an interrupt. Performs the following actions to unwind an interrupt and return execution to the instruction that would have executed next if not for the interrupt:

  • Sets P to PC (in the interrupt level).
  • Captures C to get previous interrupt level).
  • Sets C to context (in the interrupt level).
  • Switches to the previous interrupt level.
  • Restores the previous interrupt level context from C.
  • Restores the previous interrupt level PC from P.

Example:

TIMERLVL  EQU       10        ; Interrupt level of the timer interrupt.
RSTTIMER  CLRB      ZL        ; 0 -> ZL.
          RI                  ; Return from interrupt.
TIMERINT  INR       Y         ; Increment Y.
          BNZ       RSTTIMER  ; Branch if no overflow.
          INR       X         ; Increment X.
          JMP       RSTTIMER  ; Jump to the return.

This is a default timer interrupt handler to increment X and Y as fast as possible.

0x0B: Illegal Operation

Illegal instructions will trigger an abort trap. The instruction 0B has a different initial instruction decoding from the rest of the illegal instructions. On the EE200 this is an RIM instruction. It's possible that this instruction was never used by Centurion and was replaced by a user mode instruction on the CPU5. Possibly it was removed from the CPU6 as it was replaced by another instruction.

0x0C: SYN

Flash the abort light (CPU6)

There are a collection of lights on the front panel of CPU6 equipped machines. The MAP column is labelled 1, 2, 3, ABT from bottom to top. The SYN instruction illuminates the ABT light for 200 nanoseconds, or one clock cycle.

Example:

     SYN                 ; Flash abort.

We haven't particularly come across any source code that utilizes this feature, and so are unclear as to which situation it would be most useful in, or why it was added for CPU6 specifically.

0x0D: PCX

Transfer PC to X (CPU5/CPU6)

The PC, or Program Counter, will be copied over to the X register. The PC and X registers are intrinsically linked as the X register is where the return vector is stored when doing Jumps to Subroutines. Interestingly, when performing an RSR, the first action is takes is to copy the value of X back into the PC, essentially the opposite of this instruction.

Example:

     PCX                 ; PC -> X.

We have yet to come across an example section of code utilizing this instruction, so, uh, you know, you'll have to use your programming prowess to figure out the best use case scenario for it.

0x0E: DLY

4.55 ms delay (CPU5/CPU6)

This instruction literally just delays for 4.55 milliseconds. As I understand it, this actually causes the CPU itself to cease all operations for 4.55ms, which can cause problems if the programmer does not take into account certain things, like the rotational speed of the disk. However, we believe this operation was particularly useful for bit-banging teletypes that have a particularly slow baud rate that may have been initially difficult to generate on the MUX card.

Example:

DELY  DLY                   ; 4.55ms delay
      DCR      Y            ; Decrement Y value
      BNZ      DELY         ; Branch if Not Zero to DELY
      RSR                   ; Return from Subroutine

This is short delay subroutine that counts down the Y value and loops back to the label DELY until the Y value reaches 0, at which point it returns from the subroutine. Each time it loops back to the label, it executes the DLY instruction, which cause the CPU to delay for 4.55ms. If the Y value is 0x0F, the subroutine will loop 16 times, resulting in a delay of 72.8ms.

0x0F: RSV

Return from SVC (CPU6)

Return from service call. Performs the following actions to unwind a service call and return execution to the next instruction after the SVC:

  • Set P to PC.
  • Increments the stack pointer to skip the SVC argument pushed there.
  • Sets PC to X.
  • Pops X from the stack.
  • Pops the context from the stack. See SVC.

Example:

To be added.

Unfortunately, I have not found a good example of an RSV operation within actual code. SVC and RSV are very tightly linked to running within the OpSys, and therefore we need more disassembly and combing through OpSys level programs to find good examples.