Introducing the Instruction Set Part 1

From Intellivision Wiki
Revision as of 04:58, 8 October 2007 by Mr z (talk | contribs) (Register Mode Instructions)
Jump to: navigation, search

This tutorial focuses primarily on introducing the CP1610's instruction set. The instructions divide up into multiple categories that we will explore briefly below. You can visit the various instruction pages for details on specific instructions.

Primary Instructions

The CP1610 has 7 primary instructions. The primary instructions have the most flexibility in terms of where they draw their inputs from. The 7 primary instructions are:

  MVI  "MoVe In": Read a value into a register
  MVO  "MoVe Out": Write a value from a register to memory
  ADD  Add two values together
  SUB  Subtract two values
  CMP  Compare two values by subtracting them
  AND  Bitwise logical AND
  XOR  Bitwise logical XOR

Each instruction takes two operands. The first operand is a source operand. The second is both source and destination, except in the case of CMP, which doesn't write a result. (CMP does, however, set flags.)

The primary instructions are available in 4 forms, each with a different addressing mode. The mnemonics for each form differs slightly from the others:

  Register Mode    Direct Mode    Indirect Mode    Immediate Mode  
  MOVR    MVI    MVI@    MVII  
--  MVO    MVO@    MVOI  
  ADDR    ADD    ADD@    ADDI  
  SUBR    SUB    SUB@    SUBI  
  CMPR    CMP    CMP@    CMPI  
  ANDR    AND    AND@    ANDI  
  XORR    XOR    XOR@    XORI  

Register Mode Instructions

Register mode instructions operate on two different registers. For instance, "ADDR R0, R1" adds the value in R0 to the value in R1, and writes the result to R1. It's equivalent to the expression "R1 = R0 + R1".

The move instructions are the simplest. "Move" is something of a misnomer, though. Move instructions really copy values from one place into another. For example, "MOVR R0, R1" copies the value in R0 to R1. After the CPU runs this instruction, both R0 and R1 will have the same value. The CPU will also set the Sign Flag and Zero Flag based on the value of the number it copied.

Move instructions are sometimes used with the program counter. "MOVR R5, R7" will jump to the location whose address is in R5. The assembler offers a pseudonym for this, "JR". The instruction "JR R5" is equivalent to "MOVR R5, R7."


   ADDR R0, R1   ;  Adds R0 to R1, leaving the result in R1
   MOVR R2, R3   ;  Copies the value in R2 to R3
   CMPR R1, R2   ;  Subtracts R1 from R2 setting flags.  Does not change either of R1 or R2.

Direct Mode Instructions

Direct mode instructions operate on a value in memory. For all but MVO, they read a value from the named location. The instruction "ADD $123, R0" reads the value from location $123 and adds it to R0. The MVO instruction works in the opposite direction: It copies the value from a register into a memory location. "MVO R0, $123" writes the value that's in R0 to location $123.

The address can either be a bare address, as shown above, or a label. Labeled addresses are much easier to read. For example, suppose the label "LIVES" points to the number of lives your player has remaining. You could read that value from memory into R0 with:


You'll see this technique used heavily in assembly programs of appreciable size. It makes programs easier to write, read and follow.

Indirect Mode Instructions

Indirect mode instructions also operate on a value in memory. However, rather than specifying the address directly in the instruction, they instead get the address from a register. This is useful for reading through a range of memory. For example, the instruction "ADD@ R1, R2" reads from the memory location pointed to by R1, and adds that value into R2. As with direct mode, the MVO@ instruction works in the opposite direction by writing a value to memory. "MVO@ R0, R1" writes the value of R0 to the location pointed to by R1.

Indirect mode behaves specially when using R4, R5 or R6 as the pointer register. For R4 and R5, the CPU will increment their value after using it. This makes it easy to step through an array in memory. The instruction "MVI@ R4, R0" will copy the value in memory pointed to by R4 into R0, and then it will increment R4.


   ;  Read memory pointed to by R3,
   ;  and put the value in R0
   MVI@ R3, R0
   ;  Read memory pointed to by R2, 
   ;  and add the value to R1, leaving the result in R1
   ADD@ R2, R1
   ;  Read memory pointed to by R4, 
   ;  subtract the value from R3 writing the difference to R3.  
   ;  Then, increment R4.
   SUB@ R4, R3

R6 works even more specially. When reading via R6, the CPU will decrement R6 *before* using it. When writing via R6, the CPU will increment R6 *after* using it. This behavior is what makes R6 useful as a stack pointer. The instructions "PSHR" and "PULR" are just pseudonyms for MVI@ and MVO@ using R6. Thus "PSHR R0" means the same as "MVO@ R0, R6", and "PULR R0" means the same as "MVI@ R6, R0".

The stack pointer can be used with other instructions as well. The instruction "ADD@ R6, R0" reads the value from the top of stack and adds it to R0. This can eliminate many PULR instructions. If you've ever used a stack-based calculator (such as one of HP's RPN calculators), you may find this style of programming intuitive.

Indirect mode has one limitation: You can't use R0 as the indirect register. Therefore "MVI@ R0, R1" is illegal, as is "MVO@ R1, R0".

Immediate Mode Instructions

Immediate mode instructions operate on a constant value. "MVII #1234, R0" copies the number 1234 into R0. These are useful for adding or subtracting constants from registers, setting up values in registers and so on. Note that the instruction "MVOI" generally doesn't do anything useful. You can safely ignore it.


   ; Puts the value 1234 into R0
   MVII #1234, R0
   ; Bitwise ANDs $FF with R1, leaving result in R1
   ANDI #$FF, R1

Special Note: Compare Instructions

The CMP instruction bears special mention. Regardless of their addressing mode, the ADD, SUB and CMP instructions all set the flags based on the result of the computation. ADD and SUB also write the computed value back to a register. CMP works like SUB, but it doesn't write the result of the subtraction anywhere. Rather, it only sets flags. Its primary use is to control conditional branch instructions.