summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorp4bl0 <r _at_ uzy .dot. me>2018-01-10 12:44:42 (CET)
committerp4bl0 <r _at_ uzy .dot. me>2018-01-10 12:44:42 (CET)
commit7d86787ac7ea55c68a547f445c58f18fd76b5352 (patch)
tree4f22248f75488b46b150f20c9e96d509af6dc317
downloadseselab-7d86787ac7ea55c68a547f445c58f18fd76b5352.zip
seselab-7d86787ac7ea55c68a547f445c58f18fd76b5352.tar.gz
initial commit
-rw-r--r--.gitignore1
-rw-r--r--bench.py33
-rw-r--r--bignum.asm402
-rw-r--r--compiler.py221
-rw-r--r--cpu.py152
-rw-r--r--exn.py21
-rw-r--r--memory.py39
-rw-r--r--probe.py22
8 files changed, 891 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/bench.py b/bench.py
new file mode 100644
index 0000000..353070f
--- /dev/null
+++ b/bench.py
@@ -0,0 +1,33 @@
+import sys
+import signal
+from random import randint
+from compiler import Compiler
+from cpu import CPU
+
+def inject (sig, frame):
+ where = input('\n> Inject fault? (r = fault register, s = skip instruction, q = quit) ')
+ if where == 'q':
+ sys.exit(1)
+ elif where == 's':
+ skip = int(input('> How many instruction to skip? '))
+ cpu._ip += skip
+ print('! ' + str(skip) + ' instructions skipped')
+ elif where == 'r':
+ reg = int(input('> Which register? (0-'+str(cpu._reg._size)+') '))
+ what = input('> Zero or random? (z = zero, r = random) ')
+ if what == 'z':
+ cpu._reg._mem[reg] = 0
+ print('! r' + str(reg) + ' zeroized')
+ elif what == 'r':
+ cpu._reg._mem[reg] = randint(0, cpu._ram._size)
+ print('! r' + str(reg) + ' randomized')
+ print('> Resuming…')
+
+if sys.argv[1] == '-i':
+ signal.signal(signal.SIGINT, inject)
+ sys.argv.pop(1)
+
+program = Compiler().compile(sys.argv[1])
+
+cpu = CPU(1048576, 32, program, sys.argv[2])
+cpu.run()
diff --git a/bignum.asm b/bignum.asm
new file mode 100644
index 0000000..3e2134d
--- /dev/null
+++ b/bignum.asm
@@ -0,0 +1,402 @@
+;;; General information:
+;;; ;;;;;;;;;;;;;;;;;;;;
+;;; r31 is the return address (ra)
+;;; r30 is the stack pointer (sp)
+;;; r25 to r29 are temporary and always overridable
+;;; r20 to r24 are used for passing arguments and should be saved if overridden
+;;; ;;;;;;;;;;;;;;;;;;;;
+;;; bignums are represented in base 256
+;;; for the endianness coherency, most significant digits are at smaller indices
+;;; e.g. if the number 0x12ab34cd is stored at address 100 :
+;;; value: 12 ab 34 cd 4
+;;; address: 96 97 98 99 100
+
+push_tmp_registers_1:
+ sub r30 r30 #1 ; decr sp
+ mov !r30,#0 r25 ; push r25
+ ret
+
+pop_tmp_registers_1:
+ mov r25 !r30,#0 ; pop r25
+ add r30 r30 #1 ; incr sp
+ ret
+
+push_tmp_registers_2:
+ sub r30 r30 #2 ; decr sp
+ mov !r30,#0 r25 ; push r25
+ mov !r30,#1 r26 ; push r26
+ ret
+
+pop_tmp_registers_2:
+ mov r26 !r30,#1 ; pop r26
+ mov r25 !r30,#0 ; pop r25
+ add r30 r30 #2 ; incr sp
+ ret
+
+push_tmp_registers_3:
+ sub r30 r30 #3 ; decr sp
+ mov !r30,#0 r25 ; push r25
+ mov !r30,#1 r26 ; push r26
+ mov !r30,#2 r27 ; push r27
+ ret
+
+pop_tmp_registers_3:
+ mov r27 !r30,#2 ; pop r27
+ mov r26 !r30,#1 ; pop r26
+ mov r25 !r30,#0 ; pop r25
+ add r30 r30 #3 ; incr sp
+ ret
+
+push_tmp_registers_4:
+ sub r30 r30 #4 ; decr sp
+ mov !r30,#0 r25 ; push r25
+ mov !r30,#1 r26 ; push r26
+ mov !r30,#2 r27 ; push r27
+ mov !r30,#3 r28 ; push r28
+ ret
+
+pop_tmp_registers_4:
+ mov r28 !r30,#3 ; pop r28
+ mov r27 !r30,#2 ; pop r27
+ mov r26 !r30,#1 ; pop r26
+ mov r25 !r30,#0 ; pop r25
+ add r30 r30 #4 ; incr sp
+ ret
+
+push_tmp_registers_5:
+ sub r30 r30 #5 ; decr sp
+ mov !r30,#0 r25 ; push r25
+ mov !r30,#1 r26 ; push r26
+ mov !r30,#2 r27 ; push r27
+ mov !r30,#3 r28 ; push r28
+ mov !r30,#4 r29 ; push r29
+ ret
+
+pop_tmp_registers_5:
+ mov r29 !r30,#4 ; pop r29
+ mov r28 !r30,#3 ; pop r28
+ mov r27 !r30,#2 ; pop r27
+ mov r26 !r30,#1 ; pop r26
+ mov r25 !r30,#0 ; pop r25
+ add r30 r30 #5 ; incr sp
+ ret
+
+print_newline:
+ prc #10 ; 10 is \n
+ ret
+
+bignum_print:
+ ;; print r20
+ sub r25 r20 !r20 ; most significant byte address
+_bn_print__loop:
+ prx !r25 ; print digit
+ add r25 r25 #1 ; incr address
+ bne _bn_print__loop r25 r20 ; loop until final byte
+ sub r30 r30 #1 ; decr sp
+ mov !r30 r31 ; push ra
+ cal print_newline
+ mov r31 !r30 ; pop ra
+ add r30 r30 #1 ; incr sp
+ ret
+
+bignum_init:
+ ;; initialize a number of size r21 at address r20
+ mov !r20 r21 ; number size
+ sub r25 r20 r21 ; most significant byte address
+_bn_init__loop:
+ mov !r25 #0 ; init byte
+ add r25 r25 #1 ; incr address
+ bne _bn_init__loop r25 r20 ; loop until least significant byte
+ ret
+
+bignum_cleanup:
+ sub r25 r20 !r20
+_bn_cleanup__loop:
+ bne _bn_cleanup__end !r25 #0
+ beq _bn_cleanup__zero r25 r20
+ add r25 r25 #1
+ sub !r20 !r20 #1
+ jmp _bn_cleanup__loop
+_bn_cleanup__zero:
+ mov !r20 #1
+_bn_cleanup__end:
+ ret
+
+bignum_zero:
+ ;; set length to 0 if bignum = 0
+ ;; a bignum is zero if its lsB is 0 and its length is 1
+ cmp r25 !r20 #1 ; compare length to 1
+ bne _bn_zero_no r25 #0 ; if not it is not 0
+ bne _bn_zero_no !r20,#-1 #0 ; idem if lsb is not 0
+ mov !r20 #0
+_bn_zero_no:
+ ret
+
+bignum_clear:
+ ;; reset r20
+ sub r25 r20 !r20 ; most significant byte address
+_bn_clear__loop:
+ mov !r25 #0 ; reset byte
+ add r25 r25 #1 ; incr address
+ bne _bn_clear__loop r25 r20 ; loop until least significant byte
+ ret
+
+bignum_copy:
+ ;; r20 = r21
+ beq _bn_copy__cp !r20 #0
+ sub r30 r30 #1 ; decr sp
+ mov !r30 r31 ; push ra
+ cal bignum_clear
+ mov r31 !r30 ; pop ra
+ add r30 r30 #1 ; incr sp
+_bn_copy__cp:
+ mov !r20 !r21
+ sub r25 #0 !r20
+ beq _bn_copy__end r25 #0
+_bn_copy__loop:
+ mov !r20,r25 !r21,r25
+ add r25 r25 #1
+ bne _bn_copy__loop r25 #0
+_bn_copy__end:
+ ret
+
+bignum_cmp:
+ ;; cmp r20 r21 r24
+ beq _bn_cmp_same r21 r24
+ cmp r20 !r21 !r24
+ bne _bn_cmp_done r20 #0
+ sub r25 #0 !r21 ; r25 = -len
+_bn_cmp_loop:
+ beq _bn_cmp_same r25 #0
+ cmp r20 !r21,r25 !r24,r25
+ bne _bn_cmp_done r20 #0
+ add r25 r25 #1
+ jmp _bn_cmp_loop
+_bn_cmp_same:
+ mov r20 #0
+_bn_cmp_done:
+ ret
+
+bignum_sub:
+ ;; r20 = r20 - r24 (with r20 >= r24)
+ mov r25 #0
+ mov r26 #0 ; borrow
+_bn_sub_loop:
+ sub r25 r25 #1
+ sub !r20,r25 !r20,r25 !r24,r25
+ sub !r20,r25 !r20,r25 r26
+ cmp r27 !r20,r25 #0
+ beq _bn_sub_neg r27 #1
+ mov r26 #0
+ jmp _bn_sub_endloop
+_bn_sub_neg:
+ add !r20,r25 !r20,r25 #256
+ mov r26 #1
+_bn_sub_endloop:
+ add r27 r25 !r24
+ beq _bn_sub_end r27 #0
+ jmp _bn_sub_loop
+_bn_sub_end:
+ sub r25 r25 #1
+ sub !r20,r25 !r20,r25 r26
+ sub r30 r30 #1 ; decr sp
+ mov !r30 r31 ; push ra
+ cal bignum_cleanup
+ mov r31 !r30 ; pop ra
+ add r30 r30 #1 ; incr sp
+ ret
+
+bignum_add:
+ ;; r20 = r21 + r22 mod r24
+ ;; init r20
+ sub r30 r30 #2 ; decr sp
+ mov !r30,#1 r21 ; push r21
+ mov !r30 r31 ; push ra
+ cmp r25 !r21 !r22
+ beq _bn_add__lt r25 #1
+ add r21 !r21 #1
+ jmp _bn_add__init
+_bn_add__lt:
+ add r21 !r22 #1
+_bn_add__init:
+ cal bignum_init
+ mov r31 !r30 ; pop ra
+ mov r21 !r30,#1 ; pop r21
+ add r30 r30 #2 ; incr sp
+_bn_add__add:
+ sub r28 #0 !r20 ; number size
+ mov r25 #0 ; counter
+ mov r26 #0 ; carry
+_bn_add__loop:
+ sub r25 r25 #1 ; decr counter
+ add r27 !r21,r25 !r22,r25 ; tmp add byte
+ add r27 r27 r26 ; tmp add carry
+ mod !r20,r25 r27 #256 ; new byte
+ div r26 r27 #256 ; new carry
+ bne _bn_add__loop r25 r28 ; continue as long as bytes exist
+ ;; modulus
+ sub r30 r30 #1 ; decr sp
+ mov !r30 r31 ; push ra
+ mov r25 r20
+ mov r21 r20
+ cal push_tmp_registers_1
+ cal bignum_cleanup
+ cal pop_tmp_registers_1
+ cal push_tmp_registers_3
+ cal bignum_cmp
+ cal pop_tmp_registers_3
+ beq _bn_add_end r20 #1
+ mov r20 r25
+ cal push_tmp_registers_3
+ cal bignum_sub
+ cal pop_tmp_registers_3
+_bn_add_end:
+ mov r31 !r30 ; pop ra
+ add r30 r30 #1 ; incr sp
+ mov r20 r25
+ ret
+
+bignum_rshift:
+ ;; r20 = r20 >> r21
+ div r26 r21 #8 ; number of complete bytes to shift (n)
+ sub r25 r20 #1
+ sub r25 r25 r26 ; address of future least significant byte (flsB)
+ sub r27 r20 !r20 ; address of most significant byte (msB)
+ cmp r28 r27 r25 ; continue only if flsB > msB (r28 is 1)
+ beq _bn_rshift__zero r28 #-1 ; if flsB < msB we're done
+_bn_rshift__bytes:
+ beq _bn_rshift__bits r28 #0 ; else if flsB = msB go shift bits
+ mov !r25,r26 !r25 ; else shift flsB of n bytes
+ cmp r28 r25 r27 ; continue only if flsB > msB (r28 is 1)
+ sub r25 r25 #1 ; decr address
+ jmp _bn_rshift__bytes
+_bn_rshift__bits:
+ add r26 r27 r26 ; msB after shift of bytes
+ mod r25 r21 #8 ; number of bits to shift (n)
+ beq _bn_rshift__clean r25 #0 ; n = 0
+_bn_rshift__b:
+ mov r29 r20
+_bn_rshift__B:
+ sub r29 r29 #1 ; current byte (B)
+ lsr !r29 !r29 #1 ; B >> 1
+ and r28 !r29,#-1 #1 ; lsb of previous byte (b)
+ lsl r28 r28 #7 ; b << 7
+ orr !r29 !r29 r28 ; B = B | b
+ bne _bn_rshift__B r29 r26
+ sub r25 r25 #1
+ bne _bn_rshift__b r25 #0
+ jmp _bn_rshift__clean
+_bn_rshift__zero: ; completely reset number
+ sub r26 r20 #1 ; erase until lsB
+_bn_rshift__clean:
+ beq _bn_rshift__end r26 r27
+ mov !r27 #0
+ add r27 r27 #1
+ jmp _bn_rshift__clean
+_bn_rshift__end:
+ sub r30 r30 #1 ; decr sp
+ mov !r30 r31 ; push ra
+ cal bignum_cleanup
+ mov r31 !r30 ; pop ra
+ add r30 r30 #1 ; incr sp
+ ret
+
+bignum_mul:
+ ;; r20 = r21 * r22 mod r24
+ ;; backup arguments and ra
+ sub r30 r30 #4 ; decr sp
+ mov !r30 r31 ; push ra
+ mov !r30,#1 r20 ; push r20 (r)
+ mov !r30,#2 r21 ; push r21 (b)
+ mov !r30,#3 r22 ; push r22 (e)
+
+ ;; init r25 (res), r26 (base), r27 (exp), r28 (tmp)
+ mov r25 r20 ; r25 points on res (r20)
+ mov r29 r21 ; r29 backups b (r21)
+ add r21 !r29 !r22 ; init len(res) to len(b) + len(e)
+ cal push_tmp_registers_1
+ cal bignum_init ; res = 0
+ cal pop_tmp_registers_1
+
+ mov r26 #900000 ; base is stored at @900000
+ mov r20 r26 ; r20 is base
+ mov r21 r29 ; r21 is b
+ cal push_tmp_registers_1
+ cal bignum_copy ; base = b
+ cal pop_tmp_registers_1
+_bn_mul_mod_base:
+ mov r21 r26
+ ;; mov r20 r26
+ ;; cal bignum_print
+ cal push_tmp_registers_3
+ cal bignum_cmp
+ cal pop_tmp_registers_3
+ beq _bn_mul_mod_base_end r20 #1
+ mov r20 r26
+ cal push_tmp_registers_3
+ cal bignum_sub
+ cal pop_tmp_registers_3
+ jmp _bn_mul_mod_base
+_bn_mul_mod_base_end:
+
+ mov r27 #910000 ; exp is stored at @910000
+ mov r20 r27 ; r20 is exp
+ mov r21 r22 ; r21 is e (r22)
+ cal push_tmp_registers_1
+ cal bignum_copy ; exp = e
+ cal pop_tmp_registers_1
+
+ mov r28 #920000 ; tmp is stored at @920000
+ mov r20 r28 ; r20 is tmp
+ add r21 !r26 !r27 ; init len(tmp) to len(base) + len(exp)
+ cal push_tmp_registers_1
+ cal bignum_init ; tmp = 0
+ cal pop_tmp_registers_1
+
+_bn_mul__loop:
+ mov r20 r27
+ cal push_tmp_registers_1
+ cal bignum_zero
+ cal pop_tmp_registers_1
+ beq _bn_mul__end !r27 #0 ; if exp = 0: multiplication finished
+ and r29 !r27,#-1 #1 ; otherwise: r28 = lsb of exp
+ bne _bn_mul__double r29 #1
+_bn_mul__add:
+ mov r20 r28 ; r20 is tmp
+ mov r21 r25 ; r21 is res
+ cal push_tmp_registers_1
+ cal bignum_copy ; tmp = res
+ cal pop_tmp_registers_1
+ mov r20 r25 ; r20 is res
+ mov r21 r28 ; r21 is tmp
+ mov r22 r26 ; r22 is base
+ cal push_tmp_registers_4
+ cal bignum_add ; res = tmp + base
+ cal pop_tmp_registers_4
+_bn_mul__double:
+ mov r20 r28 ; r20 is tmp
+ mov r21 r26 ; r21 is base
+ cal push_tmp_registers_1
+ cal bignum_copy ; tmp = base
+ cal pop_tmp_registers_1
+ mov r20 r26 ; r20 is base
+ mov r21 r28 ; r21 is tmp
+ mov r22 r28 ; r22 is tmp
+ cal push_tmp_registers_4
+ cal bignum_add ; base = tmp + tmp
+ cal pop_tmp_registers_4
+_bn_mul__shift:
+ mov r20 r27 ; r20 is exp
+ mov r21 #1 ; r21 is 1
+ cal push_tmp_registers_5
+ cal bignum_rshift ; exp = exp >> 1
+ cal pop_tmp_registers_5
+ jmp _bn_mul__loop
+_bn_mul__end:
+ ;; restore arguments and ra
+ mov r22 !r30,#3 ; pop r22
+ mov r20 !r30,#2 ; pop r21
+ mov r20 !r30,#1 ; pop r20
+ mov r31 !r30 ; pop ra
+ add r30 r30 #4 ; incr sp
+ ret
diff --git a/compiler.py b/compiler.py
new file mode 100644
index 0000000..ea9c4b2
--- /dev/null
+++ b/compiler.py
@@ -0,0 +1,221 @@
+import sys
+import os
+from exn import *
+
+class Compiler:
+
+ def __init__ (self):
+ self._linum = []
+ self._files = []
+ self._count = 0
+ self._labels = {}
+ self._code = []
+
+ def err (self, msg):
+ raise ParseError(msg, self._files[-1], self._linum[-1])
+
+ def arit (self, i, a):
+ if len(i) != a + 1:
+ self.err('arity')
+
+ def addr (self, a, noref = False):
+ if a[0] == 'r':
+ if a[1:].isdigit():
+ return ('reg', int(a[1:]))
+ else:
+ self.err('register')
+ if a[0] == '@':
+ if a[1:].isdigit():
+ return ('mem', int(a[1:]))
+ else:
+ self.err('memory')
+ if a[0] == '!' and not noref:
+ if ',' in a:
+ r = a[1:].split(',', 1)
+ return ('ref', self.val(r[0], True), self.val(r[1], True))
+ else:
+ return ('ref', self.val(a[1:], True))
+ if noref:
+ self.err('reference')
+ self.err('address')
+
+ def val (self, v, noref = False):
+ if v[0] == '#':
+ try:
+ return ('imm', int(v[1:]))
+ except:
+ self.err('immediate')
+ else:
+ return self.addr(v, noref)
+
+ def lbl (self, l):
+ if l.isidentifier():
+ return ('lbl', l)
+ else:
+ return self.val(l)
+
+ def instr (self, line):
+ line = line.split(';', 1)[0].strip()
+ if line == '':
+ return None
+
+ if ':' in line:
+ line = line.split(':', 1)
+ self._labels[line[0].strip()] = self._count
+ line = line[1]
+
+ line = line.split(';', 1)[0].strip()
+ if line == '':
+ return None
+
+ i = line.split()
+
+ if i[0] == 'nop':
+ self.arit(i, 0)
+ return [i[0]]
+
+ if i[0] == 'ret':
+ self.arit(i, 0)
+ return [i[0]]
+
+ if i[0] == 'cal':
+ self.arit(i, 1)
+ return [i[0], self.lbl(i[1])]
+
+ if i[0] == 'jmp':
+ self.arit(i, 1)
+ return [i[0], self.lbl(i[1])]
+
+ if i[0] == 'dbg':
+ self.arit(i, 1)
+ return [i[0], i[1]]
+
+ if i[0] == 'prn':
+ self.arit(i, 1)
+ return [i[0], self.val(i[1])]
+
+ if i[0] == 'prx':
+ self.arit(i, 1)
+ return [i[0], self.val(i[1])]
+
+ if i[0] == 'prX':
+ self.arit(i, 1)
+ return [i[0], self.val(i[1])]
+
+ if i[0] == 'prc':
+ self.arit(i, 1)
+ return [i[0], self.val(i[1])]
+
+ if i[0] == 'prs':
+ self.arit(i, 2)
+ return [i[0], self.val(i[1]), self.val(i[2])]
+
+ if i[0] == 'mov':
+ self.arit(i, 2)
+ return [i[0], self.addr(i[1]), self.val(i[2])]
+
+ if i[0] == 'not':
+ self.arit(i, 2)
+ return [i[0], self.addr(i[1]), self.val(i[2])]
+
+ if i[0] == 'beq':
+ self.arit(i, 3)
+ return [i[0], self.lbl(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'bne':
+ self.arit(i, 3)
+ return [i[0], self.lbl(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'and':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'orr':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'xor':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'lsl':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'lsr':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'min':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'max':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'add':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'sub':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'mul':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'div':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'mod':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ if i[0] == 'cmp':
+ self.arit(i, 3)
+ return [i[0], self.addr(i[1]), self.val(i[2]), self.val(i[3])]
+
+ self.err('opcode')
+
+ def compile_file (self, path):
+ inp = open(path, 'r')
+ self._files.append(os.path.basename(path))
+ self._linum.append(1)
+ for l in inp:
+ if '.include' in l:
+ self.compile_file(l.split('.include', 1)[1].strip())
+ else:
+ a = self.instr(l)
+ if a is not None:
+ self._code.append([a, (self._files[-1], self._linum[-1])])
+ self._count += 1
+ self._linum[-1] += 1
+ self._files.pop()
+ self._linum.pop()
+ inp.close()
+
+ def compile (self, path):
+ try:
+ self._code.append([['jmp', ('lbl', 'main')], ('_', -1)])
+ self._count += 1
+ self.compile_file(path)
+ for instr in self._code:
+ if instr[0][0] in ('cal', 'jmp', 'beq', 'bne'):
+ if instr[0][1][0] == 'lbl':
+ lbl = instr[0][1][1]
+ if lbl in self._labels:
+ instr[0][1] = 'imm', self._labels[lbl]
+ instr[1] = instr[1][0], instr[1][1], lbl
+ else:
+ raise LabelError(lbl)
+ return self._code
+
+ except ParseError as e:
+ print('Parse error: ' + e.err + ' in ' + e.file + ' on line ' + str(e.line))
+ except LabelError as e:
+ print('Label not found: ' + e.lbl)
+
+ sys.exit(1)
diff --git a/cpu.py b/cpu.py
new file mode 100644
index 0000000..fac0919
--- /dev/null
+++ b/cpu.py
@@ -0,0 +1,152 @@
+import sys
+from memory import Memory
+from probe import Probe
+from exn import *
+
+class CPU:
+
+ def __init__ (self, ram_size, reg_count, code, consolog):
+ self._ram = Memory(ram_size)
+ self._reg = Memory(reg_count)
+ self.__ra = reg_count - 1
+ self.__sp = reg_count - 2
+ self._code = code
+ self._probe = Probe(consolog)
+
+ def value (self, val):
+ if val[0] == 'imm':
+ return val[1]
+ if val[0] == 'reg':
+ return self._reg[val[1]]
+ if val[0] == 'mem':
+ return self._ram[val[1]]
+ if val[0] == 'ref':
+ v = self.value(val[1])
+ if len(val) == 3:
+ v += self.value(val[2])
+ return self._ram[v]
+
+ def write (self, addr, val):
+ if addr[0] == 'imm':
+ raise WriteError
+ if addr[0] == 'reg':
+ self._reg[addr[1]] = val
+ if addr[0] == 'mem':
+ self._ram[addr[1]] = val
+ if addr[0] == 'ref':
+ a = self.value(addr[1])
+ if len(addr) == 3:
+ a += self.value(addr[2])
+ self._ram[a] = val
+
+ def cycle (self, ip):
+ instr = self._code[ip][0]
+ opcode = instr[0]
+
+ # opcodes with no arguments
+ if opcode == 'nop':
+ pass
+ elif opcode == 'ret':
+ return self.value(('reg', self.__ra))
+ else:
+ # opcode with 1 argument
+ dst = instr[1]
+ if opcode == 'cal':
+ self.write(('reg', self.__ra), ip + 1)
+ return self.value(dst)
+ if opcode == 'jmp':
+ return self.value(dst)
+ if opcode == 'dbg':
+ self._probe.dbg(dst)
+ elif opcode == 'prn':
+ print(self.value(dst), end='')
+ elif opcode == 'prx':
+ print(format(self.value(dst), '02x'), end='')
+ elif opcode == 'prX':
+ print(format(self.value(dst), '04x'), end='')
+ elif opcode == 'prc':
+ print(chr(self.value(dst)), end='')
+ else:
+ # opcodes with 2 arguments
+ val1 = instr[2]
+ if opcode == 'prs':
+ ptr = self.value(dst)
+ for i in range(0, self.value(val1)):
+ print(chr(self._ram[ptr+i]), end='')
+ print('')
+ elif opcode == 'mov':
+ self.write(dst, self.value(val1))
+ elif opcode == 'not':
+ self.write(dst, 0xffff ^ self.value(val1))
+ else:
+ # opcodes with 3 arguments
+ val2 = instr[3]
+ if opcode == 'beq':
+ if self.value(val1) == self.value(val2):
+ return self.value(dst)
+ elif opcode == 'bne':
+ if self.value(val1) != self.value(val2):
+ return self.value(dst)
+ elif opcode == 'and':
+ self.write(dst, self.value(val1) & self.value(val2))
+ elif opcode == 'orr':
+ self.write(dst, self.value(val1) | self.value(val2))
+ elif opcode == 'xor':
+ self.write(dst, self.value(val1) ^ self.value(val2))
+ elif opcode == 'lsl':
+ self.write(dst, self.value(val1) << self.value(val2))
+ elif opcode == 'lsr':
+ self.write(dst, self.value(val1) >> self.value(val2))
+ elif opcode == 'min':
+ self.write(dst, min(self.value(val1), self.value(val2)))
+ elif opcode == 'max':
+ self.write(dst, max(self.value(val1), self.value(val2)))
+ elif opcode == 'add':
+ self.write(dst, self.value(val1) + self.value(val2))
+ elif opcode == 'sub':
+ self.write(dst, self.value(val1) - self.value(val2))
+ elif opcode == 'mul':
+ self.write(dst, self.value(val1) * self.value(val2))
+ elif opcode == 'div':
+ self.write(dst, self.value(val1) // self.value(val2))
+ elif opcode == 'mod':
+ self.write(dst, self.value(val1) % self.value(val2))
+ elif opcode == 'cmp':
+ v1 = self.value(val1)
+ v2 = self.value(val2)
+ if v1 < v2:
+ self.write(dst, 1)
+ elif v1 > v2:
+ self.write(dst, -1)
+ else:
+ self.write(dst, 0)
+
+ return None
+
+ def run (self):
+ try:
+ max_ip = len(self._code)
+ self._reg[self.__sp] = self._ram._size # init stack pointer
+ self._reg[self.__ra] = max_ip # init return address
+ self._ip = 0 # init instruction pointer
+ while self._ip >= 0 and self._ip < max_ip:
+ ip = self.cycle(self._ip)
+ if ip is not None:
+ self._ip = ip
+ else:
+ self._ip += 1
+ self._probe.read(self._ram.get_activity())
+ self._probe.read(self._reg.get_activity())
+ self._probe.output_activity()
+ sys.stdout.flush()
+
+ except AddrError as e:
+ print('Invalid address ' + str(e.addr) + self.dbg(self._ip))
+ except ValError as e:
+ print('Invalid value ' + str(e.val) + self.dbg(self._ip))
+ except WriteError:
+ print('Invalid write ' + self.dbg(self._ip))
+
+ def dbg (self, ip):
+ return (' on line ' + str(self._code[ip][1][1]) +
+ ' of file ' + self._code[ip][1][0])
diff --git a/exn.py b/exn.py
new file mode 100644
index 0000000..cefb983
--- /dev/null
+++ b/exn.py
@@ -0,0 +1,21 @@
+class ParseError (Exception):
+ def __init__ (self, err, file, line):
+ self.err = err
+ self.file = file
+ self.line = line
+
+class LabelError (Exception):
+ def __init__ (self, lbl):
+ self.lbl = lbl
+
+class AddrError (Exception):
+ def __init__ (self, addr):
+ self.addr = addr
+
+class ValError (Exception):
+ def __init__ (self, val):
+ self.val = val
+
+class WriteError (Exception):
+ def __init__ (self):
+ pass
diff --git a/memory.py b/memory.py
new file mode 100644
index 0000000..5854f75
--- /dev/null
+++ b/memory.py
@@ -0,0 +1,39 @@
+from exn import *
+
+def hw (n):
+ return format(n, 'b').count('1')
+
+class Memory:
+
+ def __init__ (self, size):
+ self._size = size
+ self._mem = [0 for x in range(0, size)]
+ self._addr = 0 # address bus
+ self._hw = 0 # total Hamming weight
+ self._hd = 0 # current cycle Hamming distance
+
+ def __setitem__ (self, addr, val):
+ if addr < 0 or addr >= self._size:
+ raise AddrError(addr)
+
+ self._hw -= hw(self._mem[addr])
+ self._hw += hw(val)
+
+ self._hd += hw(self._mem[addr] ^ val)
+
+ self._addr = addr
+
+ self._mem[addr] = val
+
+ def __getitem__ (self, addr):
+ if addr < 0 or addr >= self._size:
+ raise AddrError(addr)
+
+ self._addr = addr
+
+ return self._mem[addr]
+
+ def get_activity (self):
+ activity = (self._hw // 2) + self._hd + hw(self._addr)
+ self._hd = 0
+ return activity
diff --git a/probe.py b/probe.py
new file mode 100644
index 0000000..5f97ff0
--- /dev/null
+++ b/probe.py
@@ -0,0 +1,22 @@
+import os
+
+class Probe:
+
+ def __init__ (self, path):
+ self._probe = open(path, 'w')
+ self._activity = 0
+ self._dbg = 0
+
+ def output_activity (self):
+ self._probe.write(str(self._activity) + "\t" + str(self._dbg) + "\n")
+ self._activity = 0
+ self._dbg = 0
+
+ def dbg (self, val):
+ self._dbg = val
+
+ def read (self, activity):
+ self._activity += activity
+
+ def __del__ (self):
+ self._probe.close()
Pablo Rauzy — generated by cgit