U-code improved

This is a gentle refinement of u-code in som v.4.0.  A few more immediate mode instructions are added.  Two load index instructions with argument on AC are added.  A bit of change of "case" format to one argument. Read the original u-code specification here.  The improved u-code has 50 instructions.

The instruction set

bop    :  add sub mul div band bor bxor mod
          eq ne lt le gt ge shl shr
bim    :  addi subi bandi bori eqi lti lei shli shri
data   :  ld st get put lit
vector :  ldx/ stx/ ldy/ sty/ ldxa ldya
control:  jmp jt jf jle/ case call callt ret
extra  :  fun/ sys inc dec not push

Total  50 instructions.  The additional instructions are :  shl shr bandi bori eqi lti lei ldxa ldya.  The suffix / indicates the instruction with two arguments.

The ldxa ldya are added because it can shorten "putting" the result into a temporary register (called cascading). Not all the immediate mode is added.  That will make the instruction set too fat. The logical one: nei, gti, gei can be emulate by the inverse. The others are rarely used: muli divi xori modi. shl and shr are added to make the instruction set complete. They have been omitted from the original u-code. ads is retired.  It is used only to relocate the data segment. pusha is removed, it can be replaced by push 0 where 0 signifies that AC is the argument.

Format

  one-address  op:32  arg:32
 two-address  op:32  a:24,b:8

Semantic

v is M[fp+v]

bop v      ::  AC = AC op v
bim a      ::  AC = AC op a

data

lit a      ::  AC = a
ld a       ::  AC = M[a]
st a       ::  M[a] = AC
get v      ::  AC = v
put v      ::  v = AC


vector

ldy a,v    ::  AC = M[M[a]+v]
sty a,v    ::  M[M[a]+v] = AC
ldx v1,v2  ::  AC = M[v1+v2]
stx v1,v2  ::  M[v1+v2] = AC
ldxa v     ::  AC = M[v+AC]
ldya a     ::  AC = M[M[a]+AC]

control

jt a       ::  if AC != 0 pc = a
jf a       ::  if AC == 0 pc = a
jle a,v    ::  if AC <= v pc = a
call a     ::  if arity(a) > 0 pusha passing the last parameter if any
               create a new activation record
ret size   ::  delete current activation record
case lo; lit hi ::  if lo <= AC <= hi skip 4+2*(AC-lo)

extra

inc v      ::  v++, AC = v
dec v      ::  v--, AC = v
push v     ::  sp++, if(v == 0) M[sp] = AC else M[sp] = v
fun arity,size    a place holder for arity,size

usage

for loop
...
inc i
jle v loop

case
<index in AC>
case lo
lit hi
jmp else
jmp case1
...
jmp casen

u-code encoding

1   add sub mul div band bor bxor mod eq
10  ne lt le gt ge shl shr addi subi bandi
20  bori eqi lti lei shli shri inc dec lit sys
30  not push get put ld st ldxa ldya call ret
40  callt jmp jt jf case ldx/ stx/ ldy/ sty/ jle/
50  fun/

Comment

Upon analysing v4 vs v31 compiler (see som-v4-bm/doc/v4-vs-v31-compile.txt) many possible improvements to u-code come to mind.  The first is the immediate mode.  The second is to use "cascade" AC to reduce "put" (using AC as argument in some instruction). However, adding everything will make u-code unattractively large.  The aim to include more instruction into u-code is to improve the performance without undue increase in complexity to the instruction set.

For "case", the previous form is correct in sense of being one instruction without any continuation so its semantic is clear. VM does not behave differently from executing other instruction. VM does not fetch any argument from the next instruction. The proposed "case":
case lo, lit hi, jump ...
is faster but its semantic is not consistent with the rest of the instruction set. It fetches the next instruction to be used in deciding the transfer of control. So, the question is, what do we prefer, clean semantic or performance?

last update 24 June 2010