S21 A Hypothetical 32-bit Processor


This is a typical simple 32-bit CPU.  It has a three-address instruction architecture, with 32 registers and load/store instructions. This document presents only S21 assembly language view. It does not give details about microarchitecture (such as pipeline).

S21 has three-address instruction set.  A general format of an instruction (register to register operations) is:

op r1 r2 r3     means  R[r1] = R[r2] op R[r3]

To pass values between memory and registers, load/store instructions are used.  There are three addressing mode: absolute, indirect and index.

     load means    R <- mem
     store means   mem <- R

ld r1,ads         R[r1] = M[ads]          absolute
ld r1,d(r2)       R[r1] = M[d+R[r2]]      indirect
ld r1,(r2+r3)     R[r1] = M[R[r2]+R[r3]]  index
st r1,ads         M[ads] = R[r1]          absolute
st r1,d(r2)       M[d+R[r2]] = R[r1]      indirect
st r1,(r2+r3)     M[R[r2]+R[r3]] = R[r1]  index

In assembly language, these addressing modes are written as (using the convention op dest <- source):

ld r1,ads         ld r1 ads
ld r1,d(r2)       ld r1 @d r2
ld r1,(r2+r3)     ld r1 +r2 r3
st r1,ads         st ads r1
st r1,d(r2)       st @d r2 r1
st r1,(r2+r3)     st +r2 r3 r1

There are three flags: Zero, Carry, Overflow/underflow.

Instruction type

arith & logic:  add sub mul div  and or xor eq ne lt le gt ge shl shr
control flow:   jmp jt jf jal ret
data:           ld st mv push pop

Instruction meaning

false == 0
true  != 0
R[0] always zero

op r1 r2 r3     is    R[r1] = R[r2] op R[r3]
op r1 r2 #n     is    R[r1] = R[r2] op n

ld r1,ads       is    R[r1] = M[ads]          absolute
ld r1,d(r2)     is    R[r1] = M[d+R[r2]]      indirect
ld r1,(r2+r3)   is    R[r1] = M[R[r2]+R[r3]]  index
st r1,ads       is    M[ads] = R[r1]          absolute
st r1,d(r2)     is    M[d+R[r2]] = R[r1]      indirect
st r1,(r2+r3)   is    M[R[r2]+R[r3]] = R[r1]  index

jmp ads         is    pc = ads
jt r1 ads       is    if R[r1] != 0  pc = ads
jf r1 ads       is    if R[r1] == 0  pc = ads
jal r1,ads      is    R[r1] = PC; PC = ads
                      // jump and link, to subroutine
ret r1          is    PC = R[r1]  
                      // return from subroutine

mv r1 r2        is    R[r1] = R[r2]
mv r1 #n        is    R[r1] = #n
push r1 r2      is    R[r1]++; M[R[r1]] = R[r2]
                      // push r2, r1 as sp   
pop  r1 r2      is    R[r2] = M[R[r1]]; R[r1]--   
                      // pop to r2, r1 as sp

arithmetic

two-complement integer arithmetic

add r1,r2,r3     R[r1] = R[r2] + R[r3]
add r1,r2,#n     R[r1] = R[r2] + sign extended n (n is 17 bits)

add, sub affect Z,C -- C indicates carry (add) or borrow (sub)
mul, div affect Z,O -- O indicates overlow (mul) or underflow (div) and divide by zero

logic (bitwise)

and r1,r2,r3     R[r1] = R[r2] bitand R[r3]
and r1,r2,#n     R[r1] = R[r2] bitand sign extended n
. . .
eq r1,r2,r3      R[r1] = R[r2] == R[r3]
eq r1,r2,#n      R[r1] = R[r2] == #n
. . .
shl r1,r2,r3     R[r1] = R[r2] << R[r3]
shl r1,r2,#n     R[r1] = R[r2] << #n
. . .

affect Z,S bits

trap n           special instruction, n is in r1-field.

trap 0                   stop simulation
trap 1                   print integer in R[30]
trap 2                   print character in R[30]

stack operation

To facilitate passing the parameters to a subroutine and also to save state (link register) for recursive call, two stack operations are defined: push, pop.  r1-field is used as a stack pointer.

Instruction format

L-format    op:5 rd1:5 ads:22
D-format    op:5 rd1:5 rs2:5 disp:17
X-format    op:5 rd1:5 rs2:5 rs3:5 xop:12
(rd dest, rs source, ads and disp sign extended)

Instructions are fixed length at 32-bit.  Register set is 32, with R[0] always return zero. The address space is 32-bit, addressing is word.  Flags are: Z zero, S sign, C carry, O overflow/underflow.

ISA and opcode encoding

mode:
a - absolute
d - displacement
x - index
i - immediate
r - register
r2 - register 2 operands
s - special  1 operand

opcode op mode  format

0 nop
1 ld     a     L    ld r1 ads
2 ld     d     D    ld r1 d(r2)
3 st     a     L    st ads r1
4 st     d     D    st d(r2) r1
5 mv     a     L    mv r1 #n (22 bits)
6 jmp    a     L        r1 = 0
7 jal    a     L    jal r1 ads
8 jt     a     L
9 jf     a     L
10 add   i     D    add r1 r2 #n
11 sub   i     D
12 mul   i     D
13 div   i     D
14 and   i     D
15 or    i     D
16 xor   i     D
17 eq    i     D
18 ne    i     D
19 lt    i     D
20 le    i     D
21 gt    i     D
22 ge    i     D
23 shl   i     D
24 shr   i     D
25..30 undefined
31 xop   -     X

xop
0 add    r     X    add r1 r2 r3
1 sub    r     X
2 mul    r     X
3 div    r     X
4 and    r     X
5 or     r     X
6 xor    r     X
7 eq     r     X
8 ne     r     X
9 lt     r     X
10 le    r     X
11 gt    r     X
12 ge    r     X
13 shl   r     X
14 shr   r     X
15 mv    r2    X    mv r1 r2
16 ld    x     X    ld r1 (r2+r3)
17 st    x     X    st (r2+r3) r1
18 ret   s     X      use r1
19 trap  s     X      use r1 as number of trap
20 push  r2    X        use r1 as stack pointer
21 pop   r2    X        use r1 as stack pointer
22 not   r2    X     
23..4095 undefined

Historical fact

S21 is an extension of S2 in 2007, as a result of my experience in teaching assembly language.  S2 has been used for teaching since 2001.
S2 itself is an "extended" version of S1 (a 16-bit cpu) which is used since 1997.
 
To improve understandability of S2 assembly language, flags are not used.  Instead, new logical instructions that have 3-address are introduced.  They are similar to existing arith instructions.  The result (true/false) is stored in a register.  Two new conditional jumps are introduced "jt", "jf" to make use of the result from logical instructions.  Also to avoid the confusion between absolute addressing and moving between registers, a new instruction "mv" is introduced. (and to make ld/st symmetry, "ld r1 #n" is eliminated.)

The opcode format and assembly language format for S2 follow the tradition dest = source1 op source2 from PDP, VAX and IBM S360. As r0
always is zero, many instructions can be synthesis using r0.

or r1,r2,r0         move r1 <- r2
or r1,r0,r0         clear r1
sub r0,r1,r2        compare r1 r2  affects flags

To complement a register, xor with 0xFFFFFFFF (-1) can be used.

xor r1,r2,#-1       r1 = complement r2

last update 20 Nov 2010