QuAC ISA V0.2

This document is the definitive source of the QuAC1 instruction set that we will be implementing in this course. If another source contradicts this document, this takes precedance.

Memory

  • Minimum addressable unit is 16-bit words
  • 16-bit addressed
  • Total addressable memory is 128 kb (64k words)

Registers

All registers start initalised to 0x0000, and are 16-bits wide.

Code Mnemonic Meaning Behaviour
000 rz Zero Register Always read zero, writes have no effect.
001 r1 Register 1 General purpose register.
010 r2 Register 2 General purpose register.
011 r3 Register 3 General purpose register.
100 r4 Register 4 General purpose register.
101 fl Flag register Stores the flags from ALU whenever an ALU instruction is executed. Any operation can read this register. Write is undefined.
110 - undefined Any operation with this register is undefined.
111 pc Program Counter General purpose register. Also stores the address of the current instruction being executed, and (unless the current instruction would overwrite it) is incremented to the next address after the current instruction is executed.
  • rz is the zero register, hard-wired to always have the value of zero. Reading from the zero register returns the value 0x0000. Writing to the zero register has no effect.2
  • r1, r2, r3, and r4 are the general purpose registers. You may write to them, and they will store a value. Reading from a general purpose register returns the last value written to them.

  • fl is the flag register, which stores the flags generated by the ALU whenever any ALU instruction is successfully executed. This means that if a non-ALU instruction (str/ldr/movl/seth) is executed, the flag register is left unchanged. If a ALU instruction is executed (add/sub/and/orr) is executed, the flags are updated appropriately (see the QuAC Instruction Description for details.) If a conditional ALU instruction is executed (addz/subz/andz/orrz), and the Z flag is set, the flags are updated as per usual. If the Z flag is cleared (the instruction fails to execute), the flag register is left unchanged. The flag register may be read from like any other general purpose register. Writing to the flag register is undefined behaviour.3

  • pc is the program counter. It stores the address of the current instruction being executed, as well as being a general purpose register that can be a source or target for any instruction, same as r1/r2/r3/r4. After an instruction is executed, the program counter is incremented (pc := pc+1) unless the pc would be overwritten by the current instruction being executed.4

Instruction Encoding

Each instruction in QuAC has one of two formats, Register Operands Format (R-Mode) or Immediate Format (I-Mode).5

Register Operands Format (R-Mode)

op z rd x ra x rb
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Immediate Format (I-Mode)

op z rd imm8
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Definitions

All Modes

  • op (bits 15:12) Opcode, a 4-bit code used to specify which instruction is being executed.

  • z (bit 11) Conditionally Execute on Zero

    • If the bit z is set to zero, the instruction is always executed.
    • If the bit z is set to one, the instruction is only executed if the zero bit in the flag register is set to one. Else, executing the current instruction does nothing. Used by all instructions.
  • rd (bits 10:8) Destination/Data register, indicates where the result of the current instruction (if any) is to be written to, or is used as the data to store to memory when executing str.6

R-Mode only

  • x (bit 7) Reserved, Set to zero. Behaviour is undefined if set to one.7

  • ra (bits 6:4) First Operand register/Address register, indicates the first operand for the current instruction, , as well as the register used for the address for executing str and ldr instructions.

  • x (bit 3) Reserved, Set to zero. Behaviour is undefined if set to one.7

  • rb (bits 2:0) Second Operand register, indicates the second operand for the current instruction, if one exists.

I-Mode Only

  • imm8 (bits 7:0) 8-bit Immediate, an 8-bit immediate value n in the range 0n255 used for the movl and seth instructions. Used for I-Mode instructions.

Hardware Instructions

The undefined instructions leave room for your own expansion of the base ISA. No tests of the undefined instructions will be performed. There’s nothing enforcing the current choice of machine code format for the undefined instructions, so you can choose a different format (or even add your own format for your extension instructions).

More details on what each instruction does, and how they affect the flags, can be found here.

Syntax Semantic Machine Code
I-Mode Instructions
movl{z} rd, imm8 rd := #imm8 0000 z<rd> <imm8>
seth{z} rd, imm8 See below 0001 z<rd> <imm8>
- - 0010 xxxx xxxx xxxx
- - 0011 xxxx xxxx xxxx
R-Mode Memory Instructions
str{z} rd, [ra] [ra] := rd 0100 z<rd> 0<ra> 0000
ldr{z} rd, [ra] rd := [ra] 0101 z<rd> 0<ra> 0000
- - 0110 xxxx xxxx xxxx
- - 0111 xxxx xxxx xxxx
R-Mode ALU Instructions
add{z} rd,ra,rb rd := ra+rb 1000 z<rd> 0<ra> 0<rb>
sub{z} rd,ra,rb rd := ra-rb 1001 z<rd> 0<ra> 0<rb>
and{z} rd,ra,rb rd := ra&rb 1010 z<rd> 0<ra> 0<rb>
orr{z} rd,ra,rb rd := ra|rb 1011 z<rd> 0<ra> 0<rb>
- - 1100 xxxx xxxx xxxx
- - 1101 xxxx xxxx xxxx
- - 1110 xxxx xxxx xxxx
- - 1111 xxxx xxxx xxxx

seth moves an 8-bit constant (imm8) into the high byte of the destination register rd, leaving the low byte of rd unchanged. Formally, rd = (#imm8 << 8) | (rd & 0xff).

Pseudo-Instructions

These instructions are special cases of instruction that already exist in the ISA, but make writing assembly a bit easier. By implementing the base ISA instructions, the pseudo-instructions are obtained for free.

Syntax Meaning Machine Code
mov{z} rd, ra rd := ra 1000 z<rd> 0<ra> 0000
jpr{z} ra pc := ra 1000 z111 0<ra> 0000
cmp{z} ra, rb ra - rb 1001 z000 0<ra> 0<rb>
nop Do nothing 0000 0000 0000 0000
jpm{z} [ra] pc := [ra] 0101 z111 0<ra> 0000
jp{z} imm8 pc := imm8 0000 z111 <imm8>
jp{z} <label> pc := <label> Up to the assembler

The compare instruction cmp is useful for comparing the values between two registers. It is synthesised as a subtraction with rz as the destination register (cmp{z} ra, rb is equivalent to sub{z} rz, ra, rb), which means the result of the subtraction is discarded, but the flags are still set.

cmp r1, r2   ; if r1 == r2:
movlz r3, 1  ;     r3 = 1

Flag Register

  • The flag register may be read from like any other register.
  • Writing to the flag register is undefined behaviour.8
  • The flag register is written to by the flags the ALU generated, whenever any ALU instruction (ADD/SUB/AND/ORR) is executed9. If any other instruction is executed, the ALU is ignored and flag register should be left unchanged.
  • The register code for the flag register is 101, with mnemonic FL.
  • The flag register is 16 bits wide, and the flags are stored as follows.
x x x x x x x x x x x x V C N Z
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Condition Codes

  • Z (Zero) This bit is set if the result of the previous operation result was zero (all bits are zero)
  • N (Negative) This bit is set if bit 15 of the previous operation result was one (the number is negative when interpreted as a signed 16-bit number using two’s complement. )
  • C (Carry) Set in the following ways:
    • For an addition, C is set to 1 if and only if the addition produced a carry (an unsigned overflow)
    • For a subtraction, C is set to 1 if and only if the subtraction produced a borrow (an unsigned underflow)
    • For non-addition/subtraction ALU operations, set to zero.
  • V (oVerflow) Set in the following ways:
    • For addition or subtraction, V is set to 1 if and only if the arithmetic operation produced a signed overflow (interpreting the operands and result as two’s complement signed integers)
    • For non-addition/subtraction ALU operations, set to zero.

See lab 2 for details on when these are set.

The base ISA only supports conditional execution with the zero flag, but other conditions can be emulated in software by reading out the bits in the flag register manually, or by adding extensions to the ISA.

                 ; conditional jump on the carry bit
movl r1, 0b100   ; mask for the carry bit
orr rz, fl, r1   ; bitwise OR the mask with the flag, sets Z flag
jpz <label>      ; if carry was set, Z is now set, jump

                 ; conditional jump greater than
                 ; greater than: Z = 0 and N = 0
movl r1, 0b11    ; mask for Z and N
orr rz, fl, r1   ; bitwise OR the mask with flag, sets Z flag
jpz <label>      ; if greater than, jump
  1. Quarel-Akram-Connor, after the designers Shoaib Akram, Jon Connor and David Quarel. 

  2. Sacrificing an entire register to always be zero might seem expensive, but this allows for a slew of pseudo-instructions like mov (register move), cmp (compare) and jp (jump) to be defined as a special case of existing instructions. 

  3. The reason why writing to the flag register is undefined is to make the base ISA as compatible as possible with extensions, as well as make the implemention easier. You might decide that writing to FL has no effect, or that it can be written to like any other register. Both are compatible with the spec. You might also want to define a meaning for the other bits in the flag register (usually called control bits), and the CPU behaves differently depending on the value of those bits set by the user. 

  4. This allows for the synthesis of many other instructions. For instance, we can use the following code to skip over a small piece of code.

    movl r2, 2  ; r2 := 2
    add pc, r2  ; pc jumps two addresses forward
    movl r1, 1  ; this instruction gets skipped
    movl r3, 3  ; this instruction gets executed
    

    Or (stranger still) to load the machine code of an instruction itself, and use it as data

    ldr r1, [pc]  ; r1 := 0x5710
    

  5. Though there’s nothing stopping you from adding extra formats for new instruction when you extend the ISA. 

  6. All instruction in QuAC except for str write a result to a destination register, except for str which uses rd as the data to store to memory. While a little confusing, this makes the implemention in hardware a bit easier to deal with. 

  7. You may want to define a meaning for the reserved bits when you implement an extension to the base ISA.  2

  8. Though you may allow this if it makes implementtion easier for you. 

  9. This matters for conditional execution. Executing addz r1, r2, #2 should have no effect on the flags if the Z bit in the flag register is cleared. 

Updated:    07 Feb 2023 / Responsible Officer:    Director, School of Computing / Page Contact:    Shoaib Akram