SML simulator
This is the simulator for "Simple Machine Language", an abstract machine
defined in the Brookshear's textbook Chapter 2 Data Manipulation and
Appendix C. Students can write a SML program and run it.
The SML machine has 256 bytes of memory. It has 16 registers.
Each register is 8 bits. Each instruction occupies 2 bytes (16 bits).
The instruction has two forms:
op:4 r:4 s:4 t:4
op:4 r:4 xy:8
SML instructions
load r xy // r <- M[xy]
load r #xy // r <- xy
store r xy // r ->
M[xy]
move s t //
s -> t
add r s t // r
<- s + t
addf r s t // not
implement
or r s t //
r <- s bit-OR t
and r s t // r
<- s bit-AND t
xor r s t // r
<- s bit-XOR t
ror r x
// r <- rotate-right(r) by x bits
jeq r xy //
if r == r0 PC <- xy
jgt r xy // if r > r0 PC <- xy
jmp xy // PC <- xy, unconditional jump
halt
// stop
To write SML programs, I define "Assembly language" for it. Instead of
writing in numbers, one can write in mnemonics, a simplified instruction
notation. You will be writing numbers in base 10 (decimal). It is easier
this way. The display in the simulator is hexadecimal (base 16) to be
similar to the textbook.
Simplified mnemonic
L load
S store
M move
A add
O or
N and
X xor
R ror
J jeq
G jgt
B jmp
H halt
register: r, s, t, is 0..15 (registers)
constant: xy is 0..255 (address and constant)
I have included two new instructions (extended the textbook):
G r xy compare r with r0 and make a jump
to xy if r > r0
B xy unconditional jump to xy
They are used to make if..then..else kind of construct in a high level
programming language.
Sample session
Three examples
a) add two numbers. The first number is in the memory location
100, the second is at 101. The result is stored to location 102.
We use two registers to keep the values: r1, r2.
L 1 100
; load the first value
L 2 101 ; load the second value
A 1 1 2 ; add r1 r2, the result in r1
S 1 102 ; store result to memory
H
and we initialise the memory location by
D 100 10
D 101 20
E
and end the assembly program by E. Let us write this program to a file
"add.txt". First step is to translate this program into a machine
code. We use "asm.exe" to do that. The output is store in the
file "add.obj".
To run the "asm.exe", we use "cmd". You click "start" -> "run" then
type "cmd". A terminal will pop up. Change directory to your target
directory where "asm.exe" and your "add.txt" reside.
c:sml\test>
Do assemble:
c:sml\test> asm < add.txt > add.obj
The second step is to run the machine code under the simulator "sml.exe".
c:sml\test> sml < add.obj
The output will look like this on your terminal.
00 1164
02 1265
04 5112
06 3166
08 C000
64 0A
65 14
The first few lines are the machine code. Next the simulator shows each step
of running the machine code. Each line shows the program counter, the
instruction register then the value of each registers (show only 8
registers) then the value of the memory between 100..110.
PC:00 IR:1164 load
R 0:00 1:0A 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 0A 14 00 00 00 00 00 00 00 00 00 00
PC:02 IR:1265 load
R 0:00 1:0A 2:14 3:00 4:00 5:00 6:00 7:00
M[64] 0A 14 00 00 00 00 00 00 00 00 00 00
PC:04 IR:5112 add
R 0:00 1:1E 2:14 3:00 4:00 5:00 6:00 7:00
M[64] 0A 14 00 00 00 00 00 00 00 00 00 00
PC:06 IR:3166 store
R 0:00 1:1E 2:14 3:00 4:00 5:00 6:00 7:00
M[64] 0A 14 1E 00 00 00 00 00 00 00 00 00
PC:08 IR:C000 halt
R 0:00 1:1E 2:14 3:00 4:00 5:00 6:00 7:00
M[64] 0A 14 1E 00 00 00 00 00 00 00 00 00
execute 5 instructions
c:sml\test>
You can see that we add M[100] with M[101] and store it to M[102]. So,
it is 10+20 (0A, 14 in hexidecimal). The result is 30 (1E).
b) move data in the memory 100,101, to location 102,103
Use r1 to keep data. Let the file be "move.txt".
L 1
100 ; load r1 with
M[100]
S 1 102 ; store it
to M[102]
L 1 101 ; do the
same with M[101]
S 1 103
H
D 100 11 ; initialise
M[100] with 11
D 101 22 ; M[101] = 22
E
c:sml\test> asm < move.txt > move.obj
c:sml\test> sml < move.obj
00 1164
02 3166
04 1165
06 3167
08 C000
64 0B
65 16
PC:00 IR:1164 load
R 0:00 1:0B 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 0B 16 00 00 00 00 00 00 00 00 00 00
PC:02 IR:3166 store
R 0:00 1:0B 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 0B 16 0B 00 00 00 00 00 00 00 00 00
PC:04 IR:1165 load
R 0:00 1:16 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 0B 16 0B 00 00 00 00 00 00 00 00 00
PC:06 IR:3167 store
R 0:00 1:16 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 0B 16 0B 16 00 00 00 00 00 00 00 00
PC:08 IR:C000 halt
R 0:00 1:16 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 0B 16 0B 16 00 00 00 00 00 00 00 00
execute 5 instructions
c:sml\test>
In the final step, you can observe the memory location 102,103 (0B,16) are
the copy of location 100,101.
c) In this example, a decision is made and the program reaches a
"branch". One way is chosen if the test is true. The other is
chosen when the test is false. We use a sequence of branches to achieve this
effect. When consider the destination of branch, remember that each
instruction occupies two locations (two bytes) in the memory.
We will do a simple decision. If the value at the memory location 100
is equal 5, then we set r1 to 1 else we set it to 0. We use r0 to keep 5 and
use it to compare with M[100]. r2 is used to keep the value of M[100].
The instruction jump-if-equal (J) compare r with r0 if they are equal then
the jump is made.
L 0 #5 ; set r0 = 5
L 2 100 ; get value from M[100]
J 2 10 ; if it is 5 then
goto instruction at 8
L 1 #0 ; set r1 = 0 (they
are not equal)
B 12 ; goto
location 12
(H)
L 1 #1 ; set r1 = 1 (they
are equal)
H
D 100 5 ; M[100] is set to 5
E
Note about location of jump, remember that each instruction occupies 2
bytes, so J 2 10, jump if equal to location 10, refer to instruction L 1
#1. And B 12 refers to instruction at location 12 which is H.
c:sml\test> asm < compare.txt > compare.obj
c:sml\test> sml < compare.obj
PC:00 IR:2005 load#
R 0:05 1:00 2:00 3:00 4:00 5:00 6:00 7:00
M[64] 05 00 00 00 00 00 00 00 00 00 00 00
PC:02 IR:1264 load
R 0:05 1:00 2:05 3:00 4:00 5:00 6:00 7:00
M[64] 05 00 00 00 00 00 00 00 00 00 00 00
PC:04 IR:B20A jeq
R 0:05 1:00 2:05 3:00 4:00 5:00 6:00 7:00
M[64] 05 00 00 00 00 00 00 00 00 00 00 00
PC:0A IR:2101 load#
R 0:05 1:01 2:05 3:00 4:00 5:00 6:00 7:00
M[64] 05 00 00 00 00 00 00 00 00 00 00 00
PC:0C IR:C000 halt
R 0:05 1:01 2:05 3:00 4:00 5:00 6:00 7:00
M[64] 05 00 00 00 00 00 00 00 00 00 00 00
execute 5 instructions
You can observe the sequence of "jump". The result in r1 is 1.
Meta command
Help to setup the memory content
D xy v ; M[xy] = v
E
; end of section
The assembler
The source contains code section and optional data section. The comment
starts with ";" to the end of line. The last command of the code section
must be "H". The last meta command of the data section must be
"E". This is a simple example of a source of SML program.
; a simple example
L 1 100
; load r1 with M[100]
L 2 101
; load r2 with M[101]
A 3 1 2
; add r1 r2
H
; halt
D 100 20 ;
data section M[100] = 20
D 101 30 ;
M[101] = 30
E
; end
The assembler reads the source program in SML language and outputs a machine
language file. The code starts at address 0. Run it from the command line:
C:>asm < source > object
The output object file of the above example is:
00 1164
02 1265
04 5312
06 C000
FF
64 14
65 1E
FF
The first column is the address. The first section is the code. The
second section is the data. The "FF" marks the end of each section.
The simulator
Start the simulator, reading the object file and execute it. Start execute
at PC = 0 and run until HALT (or execute more than 100 instructions)
C:>sml < object
Tools
The SML package (source and executable for simulator and
assembler): sml2-2014.zip
(update version)
Just unzip and look for the executable files in the subdirectory
/test
last update 23 March 2014