From 49f510d2d60129526832bfcd9c0f4049962bc80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20B=C3=B6hm?= Date: Mon, 18 May 2009 20:53:42 +0200 Subject: move stuff around and create initial source structure --- demo-funktionen.txt | 53 ---------- doc/demo-funktionen.txt | 53 ++++++++++ doc/ebnf.py | 152 +++++++++++++++++++++++++++ doc/mylang.ebnf | 33 ++++++ ebnf.py | 152 --------------------------- mylang.ebnf | 33 ------ src/back/__init__.py | 0 src/emu/.gitignore | 3 + src/emu/Makefile | 19 ++++ src/emu/TODO | 4 + src/emu/asm.c | 33 ++++++ src/emu/asm.h | 8 ++ src/emu/cpu.c | 237 ++++++++++++++++++++++++++++++++++++++++++ src/emu/cpu.h | 29 ++++++ src/emu/log.h | 33 ++++++ src/emu/mem.c | 3 + src/emu/mem.h | 8 ++ src/emu/opc.c | 63 +++++++++++ src/emu/opc.h | 68 ++++++++++++ src/emu/riscas.c | 40 +++++++ src/emu/risci.c | 134 ++++++++++++++++++++++++ src/emu/syscall.c | 23 ++++ src/emu/syscall.h | 16 +++ src/emu/test.S | 15 +++ src/front/__init__.py | 0 src/front/inter/__init__.py | 0 src/front/lexer/__init__.py | 0 src/front/parser/__init__.py | 0 src/front/symbols/__init__.py | 0 29 files changed, 974 insertions(+), 238 deletions(-) delete mode 100644 demo-funktionen.txt create mode 100644 doc/demo-funktionen.txt create mode 100644 doc/ebnf.py create mode 100644 doc/mylang.ebnf delete mode 100644 ebnf.py delete mode 100644 mylang.ebnf create mode 100644 src/back/__init__.py create mode 100644 src/emu/.gitignore create mode 100644 src/emu/Makefile create mode 100644 src/emu/TODO create mode 100644 src/emu/asm.c create mode 100644 src/emu/asm.h create mode 100644 src/emu/cpu.c create mode 100644 src/emu/cpu.h create mode 100644 src/emu/log.h create mode 100644 src/emu/mem.c create mode 100644 src/emu/mem.h create mode 100644 src/emu/opc.c create mode 100644 src/emu/opc.h create mode 100644 src/emu/riscas.c create mode 100644 src/emu/risci.c create mode 100644 src/emu/syscall.c create mode 100644 src/emu/syscall.h create mode 100644 src/emu/test.S create mode 100644 src/front/__init__.py create mode 100644 src/front/inter/__init__.py create mode 100644 src/front/lexer/__init__.py create mode 100644 src/front/parser/__init__.py create mode 100644 src/front/symbols/__init__.py diff --git a/demo-funktionen.txt b/demo-funktionen.txt deleted file mode 100644 index ad16f4b..0000000 --- a/demo-funktionen.txt +++ /dev/null @@ -1,53 +0,0 @@ - -fun fib[a] - if a < 2 - @1 - @( fib[a-1] + fib[a-2] ) -end - -# main function -fun main[] - sum = 0 - i = 0 - while (i < 10) - sum = sum + fib[i = i + 1] - end - @sum -end - -#------------------------------------------------- alex - -0 : "fib" -1 : "a" - - <[> <]> - - - <(> <[> <]> <[> <]> <)> - - -... - - -#------------------------------------------------- michael - -PROGRAM -| -+- FUNCTION -| + <[> <]> STATEMENT -| + EXPRESSION STATEMENT -| + EXPRESSION OPERATOR EXPRESSION + .... -| + + + -+- FUNCTION -... - -#------------------------------------------------- nutz - - -zwischencode zeug mit annotiertem baum -3-Adress-Code - -#-------------------------------------------------- jana - - -maschinencode / endprodukt diff --git a/doc/demo-funktionen.txt b/doc/demo-funktionen.txt new file mode 100644 index 0000000..ad16f4b --- /dev/null +++ b/doc/demo-funktionen.txt @@ -0,0 +1,53 @@ + +fun fib[a] + if a < 2 + @1 + @( fib[a-1] + fib[a-2] ) +end + +# main function +fun main[] + sum = 0 + i = 0 + while (i < 10) + sum = sum + fib[i = i + 1] + end + @sum +end + +#------------------------------------------------- alex + +0 : "fib" +1 : "a" + + <[> <]> + + + <(> <[> <]> <[> <]> <)> + + +... + + +#------------------------------------------------- michael + +PROGRAM +| ++- FUNCTION +| + <[> <]> STATEMENT +| + EXPRESSION STATEMENT +| + EXPRESSION OPERATOR EXPRESSION + .... +| + + + ++- FUNCTION +... + +#------------------------------------------------- nutz + + +zwischencode zeug mit annotiertem baum +3-Adress-Code + +#-------------------------------------------------- jana + + +maschinencode / endprodukt diff --git a/doc/ebnf.py b/doc/ebnf.py new file mode 100644 index 0000000..1989118 --- /dev/null +++ b/doc/ebnf.py @@ -0,0 +1,152 @@ +import string + +class EBNF: + IDENT = 0 + LITERAL = 2 + LPAREN = 3 + LBRAK = 4 + LBRACE = 5 + BAR = 6 + EQL = 7 + RPAREN = 8 + RBRAK = 9 + RBRACE = 10 + PERIOD = 11 + OTHER = 12 + + __input__ = None + __char__ = None + __symbol__ = None + __data__ = None + + def __init__(self, input): + self.__input__ = input + self.__get_char__() + + def __get_char__(self): + self.__char__ = self.__input__.read(1) + if self.__char__ == '': + raise EOFError + return self.__char__ + + def __get_sym__(self): + self.__data__ = None + + while self.__char__ in string.whitespace: + self.__get_char__() + + if self.__char__ in string.letters + "_": + self.__symbol__ = self.IDENT + self.__data__ = self.__char__ + while self.__get_char__() in string.letters + "_": + self.__data__ += self.__char__ + return + + elif self.__char__ == '"': + self.__symbol__ = self.LITERAL + self.__data__ = "" + while self.__get_char__() != '"': + self.__data__ += self.__char__ + + elif self.__char__ == '=': + self.__symbol__ = self.EQL + elif self.__char__ == '(': + self.__symbol__ = self.LPAREN + elif self.__char__ == ')': + self.__symbol__ = self.RPAREN + elif self.__char__ == '[': + self.__symbol__ = self.LBRAK + elif self.__char__ == ']': + self.__symbol__ = self.RBRAK + elif self.__char__ == '{': + self.__symbol__ = self.LBRACE + elif self.__char__ == '}': + self.__symbol__ = self.RBRACE + elif self.__char__ == '|': + self.__symbol__ = self.BAR + elif self.__char__ == '.': + self.__symbol__ = self.PERIOD + else: + self.__symbol__ = self.OTHER + + self.__get_char__() + + def __error__(self, num): + pos = self.__input__.tell() + if pos > self.__lastpos__ + 2: + print "ERROR: pos=%d, err=%d, sym=%d" % (pos, num, self.__symbol__) + self.__lastpos__ = pos + + def __expression__(self): + self.__term__() + while self.__symbol__ == self.BAR: + self.__get_sym__() + self.__term__() + + def __term__(self): + self.__factor__() + while self.__symbol__ < self.BAR: + self.__factor__() + + def __factor__(self): + if self.__symbol__ == self.IDENT: + print "record(TO, '%s', 1)" % (self.__data__,) + self.__get_sym__() + elif self.__symbol__ == self.LITERAL: + print "record(T1, '%s', 0)" % (self.__data__,) + self.__get_sym__() + elif self.__symbol__ == self.LPAREN: + self.__get_sym__() + self.__expression__() + if self.__symbol__ == self.RPAREN: + self.__get_sym__() + else: + self.__error__(2) + elif self.__symbol__ == self.LBRAK: + self.__get_sym__() + self.__expression__() + if self.__symbol__ == self.RBRAK: + self.__get_sym__() + else: + self.__error__(3) + elif self.__symbol__ == self.LBRACE: + self.__get_sym__() + self.__expression__() + if self.__symbol__ == self.RBRACE: + self.__get_sym__() + else: + self.__error__(4) + else: + self.__error__(5) + + def __production__(self): + self.__get_sym__() + + if self.__symbol__ == self.EQL: + self.__get_sym__() + else: + self.__error__(7) + + self.__expression__() + + if self.__symbol__ == self.PERIOD: + self.__get_sym__() + else: + self.__error__(8) + + def __syntax__(self): + while self.__symbol__ == self.IDENT: + self.__production__() + + def compile(self): + try: + self.__lastpos__ = 0 + self.__get_sym__() + self.__syntax__() + except EOFError: + return + +if __name__ == '__main__': + import sys + ebnf = EBNF(sys.stdin) + ebnf.compile() diff --git a/doc/mylang.ebnf b/doc/mylang.ebnf new file mode 100644 index 0000000..53be3a4 --- /dev/null +++ b/doc/mylang.ebnf @@ -0,0 +1,33 @@ +lowercaseLetter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z". +uppercaseLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z". +letter = lowercaseLetter | uppercaseLetter. + +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9". +nl = "\n". + +ident = letter { letter | digit }. +integer = digit { digit }. + +factor = ident | integer | "(" expression ")" | "~" factor. +term = factor {("*" | "/" | "%" | "&&") factor}. +simple_expression = ["+" | "-"] term {("+" | "-" | "||") term}. +expression = simple_expression [ ( "==" | "!=" | ">=" | "<=" | ">" | "<" ) simple_expression ]. + +ident_list = ident { "," ident }. +expression_list = expression { "," expression }. + +program = function { function }. +function = "fun" ident "[" [ ident_list ] "]" statements "end". + +statement = [ if_statement | while_statement | assignment | function_call | return_statement ]. +statements = statement { nl statement }. + +if_statement = "if" expression statements [ "else" statements ] "end". +while_statement = "while" expression statements "end". +return_statement = "@" expression. +assignment = ident "=" expression. +function_call = ident "[" [ expression_list ] "]". + + + + diff --git a/ebnf.py b/ebnf.py deleted file mode 100644 index 1989118..0000000 --- a/ebnf.py +++ /dev/null @@ -1,152 +0,0 @@ -import string - -class EBNF: - IDENT = 0 - LITERAL = 2 - LPAREN = 3 - LBRAK = 4 - LBRACE = 5 - BAR = 6 - EQL = 7 - RPAREN = 8 - RBRAK = 9 - RBRACE = 10 - PERIOD = 11 - OTHER = 12 - - __input__ = None - __char__ = None - __symbol__ = None - __data__ = None - - def __init__(self, input): - self.__input__ = input - self.__get_char__() - - def __get_char__(self): - self.__char__ = self.__input__.read(1) - if self.__char__ == '': - raise EOFError - return self.__char__ - - def __get_sym__(self): - self.__data__ = None - - while self.__char__ in string.whitespace: - self.__get_char__() - - if self.__char__ in string.letters + "_": - self.__symbol__ = self.IDENT - self.__data__ = self.__char__ - while self.__get_char__() in string.letters + "_": - self.__data__ += self.__char__ - return - - elif self.__char__ == '"': - self.__symbol__ = self.LITERAL - self.__data__ = "" - while self.__get_char__() != '"': - self.__data__ += self.__char__ - - elif self.__char__ == '=': - self.__symbol__ = self.EQL - elif self.__char__ == '(': - self.__symbol__ = self.LPAREN - elif self.__char__ == ')': - self.__symbol__ = self.RPAREN - elif self.__char__ == '[': - self.__symbol__ = self.LBRAK - elif self.__char__ == ']': - self.__symbol__ = self.RBRAK - elif self.__char__ == '{': - self.__symbol__ = self.LBRACE - elif self.__char__ == '}': - self.__symbol__ = self.RBRACE - elif self.__char__ == '|': - self.__symbol__ = self.BAR - elif self.__char__ == '.': - self.__symbol__ = self.PERIOD - else: - self.__symbol__ = self.OTHER - - self.__get_char__() - - def __error__(self, num): - pos = self.__input__.tell() - if pos > self.__lastpos__ + 2: - print "ERROR: pos=%d, err=%d, sym=%d" % (pos, num, self.__symbol__) - self.__lastpos__ = pos - - def __expression__(self): - self.__term__() - while self.__symbol__ == self.BAR: - self.__get_sym__() - self.__term__() - - def __term__(self): - self.__factor__() - while self.__symbol__ < self.BAR: - self.__factor__() - - def __factor__(self): - if self.__symbol__ == self.IDENT: - print "record(TO, '%s', 1)" % (self.__data__,) - self.__get_sym__() - elif self.__symbol__ == self.LITERAL: - print "record(T1, '%s', 0)" % (self.__data__,) - self.__get_sym__() - elif self.__symbol__ == self.LPAREN: - self.__get_sym__() - self.__expression__() - if self.__symbol__ == self.RPAREN: - self.__get_sym__() - else: - self.__error__(2) - elif self.__symbol__ == self.LBRAK: - self.__get_sym__() - self.__expression__() - if self.__symbol__ == self.RBRAK: - self.__get_sym__() - else: - self.__error__(3) - elif self.__symbol__ == self.LBRACE: - self.__get_sym__() - self.__expression__() - if self.__symbol__ == self.RBRACE: - self.__get_sym__() - else: - self.__error__(4) - else: - self.__error__(5) - - def __production__(self): - self.__get_sym__() - - if self.__symbol__ == self.EQL: - self.__get_sym__() - else: - self.__error__(7) - - self.__expression__() - - if self.__symbol__ == self.PERIOD: - self.__get_sym__() - else: - self.__error__(8) - - def __syntax__(self): - while self.__symbol__ == self.IDENT: - self.__production__() - - def compile(self): - try: - self.__lastpos__ = 0 - self.__get_sym__() - self.__syntax__() - except EOFError: - return - -if __name__ == '__main__': - import sys - ebnf = EBNF(sys.stdin) - ebnf.compile() diff --git a/mylang.ebnf b/mylang.ebnf deleted file mode 100644 index 53be3a4..0000000 --- a/mylang.ebnf +++ /dev/null @@ -1,33 +0,0 @@ -lowercaseLetter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z". -uppercaseLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z". -letter = lowercaseLetter | uppercaseLetter. - -digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9". -nl = "\n". - -ident = letter { letter | digit }. -integer = digit { digit }. - -factor = ident | integer | "(" expression ")" | "~" factor. -term = factor {("*" | "/" | "%" | "&&") factor}. -simple_expression = ["+" | "-"] term {("+" | "-" | "||") term}. -expression = simple_expression [ ( "==" | "!=" | ">=" | "<=" | ">" | "<" ) simple_expression ]. - -ident_list = ident { "," ident }. -expression_list = expression { "," expression }. - -program = function { function }. -function = "fun" ident "[" [ ident_list ] "]" statements "end". - -statement = [ if_statement | while_statement | assignment | function_call | return_statement ]. -statements = statement { nl statement }. - -if_statement = "if" expression statements [ "else" statements ] "end". -while_statement = "while" expression statements "end". -return_statement = "@" expression. -assignment = ident "=" expression. -function_call = ident "[" [ expression_list ] "]". - - - - diff --git a/src/back/__init__.py b/src/back/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/emu/.gitignore b/src/emu/.gitignore new file mode 100644 index 0000000..44067fa --- /dev/null +++ b/src/emu/.gitignore @@ -0,0 +1,3 @@ +riscas +risci +test diff --git a/src/emu/Makefile b/src/emu/Makefile new file mode 100644 index 0000000..86d4aba --- /dev/null +++ b/src/emu/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CFLAGS = -std=c99 -D_GNU_SOURCE -Wall -Wextra -pedantic -ggdb3 +LDFLAGS = -lreadline + +all: risci riscas + +risci: asm.c cpu.c mem.c opc.c syscall.c + +riscas: asm.c opc.c + +test: riscas test.S + ./riscas test.S test + +check: risci test + ./risci -d test + +clean: + rm -f test + rm -f riscas risci diff --git a/src/emu/TODO b/src/emu/TODO new file mode 100644 index 0000000..e3445bc --- /dev/null +++ b/src/emu/TODO @@ -0,0 +1,4 @@ +- define application binary interface +- add some more usefull system calls +- enhance trap handling +- check arithmetic operations for overflow and signed correctness diff --git a/src/emu/asm.c b/src/emu/asm.c new file mode 100644 index 0000000..caca72a --- /dev/null +++ b/src/emu/asm.c @@ -0,0 +1,33 @@ +#include +#include + +#include "cpu.h" +#include "log.h" +#include "opc.h" + +uint32_t compile(const char *line) +{ + char mnem[4]; + int32_t a = 0, b = 0, c = 0; + + /* arithmetic & logic */ + if (sscanf(line, "%3s r%2d, r%2d, r%2d", mnem, &a, &b, &c) == 4) + return mnemonic2opc(mnem) | ((a & 0x1F) << 21) | ((b & 0x1F) << 16) | ((c & 0x1F) << 11); + + /* load/store & branch */ + if (sscanf(line, "%3s r%2d, r%2d, %d", mnem, &a, &b, &c) == 4) + return mnemonic2opc(mnem) | ((a & 0x1F) << 21) | ((b & 0x1F) << 16) | (c & 0xFFFF); + + if (sscanf(line, "%3s r%2d, %d", mnem, &b, &c) == 3) + return mnemonic2opc(mnem) | ((b & 0x1F) << 16) | (c & 0xFFFF); + + /* jump */ + if (sscanf(line, "%3s r%2d", mnem, &a) == 2) + return mnemonic2opc(mnem) | ((a & 0x1F) << 21); + + /* misc */ + if (sscanf(line, "%3s", mnem) == 1) + return mnemonic2opc(mnem); + + return 0xFFFFFFFF; +} diff --git a/src/emu/asm.h b/src/emu/asm.h new file mode 100644 index 0000000..9a4fd37 --- /dev/null +++ b/src/emu/asm.h @@ -0,0 +1,8 @@ +#ifndef _ASM_H +#define _ASM_H + +#include + +uint32_t compile(const char *line); + +#endif diff --git a/src/emu/cpu.c b/src/emu/cpu.c new file mode 100644 index 0000000..b0664cd --- /dev/null +++ b/src/emu/cpu.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "log.h" +#include "mem.h" +#include "opc.h" +#include "syscall.h" + +// program counter +uint32_t PC; + +// status bits +bool N, Z; + +// 32 general purpose registers +uint32_t GPR[32]; + +/* extract operands from the instruction regiter */ +static inline +uint32_t __OPEXT(uint32_t IR, uint8_t start, uint8_t length) +{ + return (IR >> start) & ((1 << length) - 1); +} + +#define OPEXT(start, length) __OPEXT(IR, start, length) + +/* operands */ +#define OPCODE OPEXT(26, 6) +#define REGa OPEXT(21, 5) +#define REGb OPEXT(16, 5) +#define REGc OPEXT(11, 5) +#define IMMc OPEXT(0, 16) + +/* cpu traps */ +void trap(int num) +{ + switch (num) { + case TRP_UNALIGNED: + raise(SIGSEGV); + break; + case TRP_DIVBYZERO: + raise(SIGFPE); + break; + case TRP_SYSCALL: + do_syscall(); + break; + case TRP_ILL: + raise(SIGILL); + break; + } +} + +void execute(uint32_t IR) +{ + /* decode op-code */ + uint8_t opcode = OPCODE; + int32_t a, b, c; + + if (opcode < OPC_MOV) { + /* arithmetic & logic */ + a = REGa; + b = REGb; + c = REGc; + + debug("PC@%#08x: %-3s r%i, r%i, r%i", PC, + opc2mnemonic(IR), a, b, c); + } + + else if (opcode < OPC_J) { + /* load/store & branch */ + a = REGa; + b = REGb; + c = IMMc; + + /* sign extension */ + if (c >= 0x8000) + c -= 0x10000; + + if (opcode < OPC_LB) { + debug("PC@%#08x: %-3s r%i, %i", PC, + opc2mnemonic(IR), b, c); + } else { + debug("PC@%#08x: %-3s r%i, r%i, %i", PC, + opc2mnemonic(IR), a, b, c); + } + } + + else if (opcode < OPC_SYS) { + /* jump */ + a = REGa; + b = c = 0; + + debug("PC@%#08x: %-3s r%i", PC, + opc2mnemonic(IR), a); + } + + else { + /* misc */ + a = b = c = 0; + + debug("PC@%#08x: %-3s", PC, + opc2mnemonic(IR)); + } + + // make sure r0 is zero + GPR[0] = 0; + + // buffer for load/store instructions + uint8_t tmp8; + uint16_t tmp16; + uint32_t tmp32; + + switch (opcode) { + case OPC_ADD: + // XXX: signed/unsigned? + GPR[a] = GPR[b] + GPR[c]; + break; + case OPC_SUB: + // XXX: signed/unsigned? + GPR[a] = GPR[b] - GPR[c]; + break; + case OPC_MUL: + // XXX: signed/unsigned? + GPR[a] = GPR[b] * GPR[c]; + break; + case OPC_DIV: + // XXX: signed/unsigned? + if (GPR[c] == 0) + trap(TRP_DIVBYZERO); + else + GPR[a] = GPR[b] / GPR[c]; + break; + case OPC_MOD: + // XXX: signed/unsigned? + GPR[a] = GPR[b] % GPR[c]; + break; + case OPC_SHL: + // XXX: signed/unsigned? + GPR[a] = GPR[b] << GPR[c]; + break; + case OPC_SHR: + // XXX: signed/unsigned? + GPR[a] = GPR[b] >> GPR[c]; + break; + case OPC_AND: + GPR[a] = GPR[b] & GPR[c]; + break; + case OPC_OR: + GPR[a] = GPR[b] | GPR[c]; + break; + case OPC_XOR: + GPR[a] = GPR[b] ^ GPR[c]; + break; + case OPC_NOR: + GPR[a] = ~(GPR[b] & GPR[c]); + break; + case OPC_MOV: + GPR[b] = c; + break; + case OPC_LB: + memcpy(&tmp8, &MEM[GPR[a] + c], sizeof(uint8_t)); + GPR[b] = tmp8; + break; + case OPC_LH: + if ((GPR[a] + c) & 0x1) + trap(TRP_UNALIGNED); + memcpy(&tmp16, &MEM[GPR[a] + c], sizeof(uint16_t)); + GPR[b] = tmp16; + break; + case OPC_LW: + if ((GPR[a] + c) & 0x2) + trap(TRP_UNALIGNED); + memcpy(&tmp32, &MEM[GPR[a] + c], sizeof(uint32_t)); + GPR[b] = tmp32; + break; + case OPC_SB: + tmp8 = GPR[b]; + memcpy(&MEM[GPR[a] + c], &tmp8, sizeof(uint8_t)); + break; + case OPC_SH: + if ((GPR[a] + c) & 0x1) + trap(TRP_UNALIGNED); + tmp16 = GPR[b]; + memcpy(&MEM[GPR[a] + c], &tmp16, sizeof(uint16_t)); + break; + case OPC_SW: + if ((GPR[a] + c) & 0x2) + trap(TRP_UNALIGNED); + tmp32 = GPR[b]; + memcpy(&MEM[GPR[a] + c], &tmp32, sizeof(uint32_t)); + break; + case OPC_CMP: + Z = (GPR[b] == (uint32_t) c); + N = (GPR[b] < (uint32_t) c); + break; + case OPC_BEQ: + if (Z) + PC += c * sizeof(uint32_t); + break; + case OPC_BNE: + if (!Z) + PC += c * sizeof(uint32_t); + break; + case OPC_BLT: + if (N) + PC += c * sizeof(uint32_t); + break; + case OPC_BGE: + if (!N) + PC += c * sizeof(uint32_t); + break; + case OPC_BLE: + if (Z || N) + PC += c * sizeof(uint32_t); + break; + case OPC_BGT: + if (!Z && !N) + PC += c * sizeof(uint32_t); + case OPC_J: + PC = GPR[a]; + break; + case OPC_JAL: + GPR[31] = PC + sizeof(uint32_t); + PC = GPR[a]; + case OPC_SYS: + trap(TRP_SYSCALL); + break; + default: + /* illegal instruction */ + trap(TRP_ILL); + } +} diff --git a/src/emu/cpu.h b/src/emu/cpu.h new file mode 100644 index 0000000..43ccf00 --- /dev/null +++ b/src/emu/cpu.h @@ -0,0 +1,29 @@ +#ifndef _CPU_H +#define _CPU_H + +#include +#include + +/* cpu traps */ +enum { + TRP_UNALIGNED, + TRP_DIVBYZERO, + TRP_SYSCALL, + TRP_ILL, +}; + +void trap(int num); + +/* program counter */ +extern uint32_t PC; + +/* status bits */ +extern bool N, Z; + +/* 32 general purpose registers */ +extern uint32_t GPR[32]; + +/* main cpu execution function */ +void execute(uint32_t IR); + +#endif diff --git a/src/emu/log.h b/src/emu/log.h new file mode 100644 index 0000000..6660c66 --- /dev/null +++ b/src/emu/log.h @@ -0,0 +1,33 @@ +#ifndef _LOG_H +#define _LOG_H + +#include +#include + +extern bool is_debug; + +#define debug(...) do { \ + if (is_debug) { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ +} while (0) + +#define error(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) + +#define die(...) do { \ + error(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while (0) + +#define pdie(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, ": "); \ + perror(NULL); \ + exit(EXIT_FAILURE); \ +} while (0) + +#endif diff --git a/src/emu/mem.c b/src/emu/mem.c new file mode 100644 index 0000000..e102eaf --- /dev/null +++ b/src/emu/mem.c @@ -0,0 +1,3 @@ +#include "mem.h" + +uint8_t MEM[4096]; diff --git a/src/emu/mem.h b/src/emu/mem.h new file mode 100644 index 0000000..34b13fa --- /dev/null +++ b/src/emu/mem.h @@ -0,0 +1,8 @@ +#ifndef _MEM_H +#define _MEM_H + +#include + +extern uint8_t MEM[]; + +#endif diff --git a/src/emu/opc.c b/src/emu/opc.c new file mode 100644 index 0000000..870a272 --- /dev/null +++ b/src/emu/opc.c @@ -0,0 +1,63 @@ +#include +#include + +#include "opc.h" + +typedef struct opc_mapping { + const char *name; + uint32_t opcode; +} opc_mapping_t; + +opc_mapping_t opc_map[] = { + { "ADD", OPC_ADD }, + { "SUB", OPC_SUB }, + { "MUL", OPC_MUL }, + { "DIV", OPC_DIV }, + { "MOD", OPC_MOD }, + { "SHL", OPC_SHL }, + { "SHR", OPC_SHR }, + { "AND", OPC_AND }, + { "OR", OPC_OR }, + { "XOR", OPC_XOR }, + { "NOR", OPC_NOR }, + { "MOV", OPC_MOV }, + { "LB", OPC_LB }, + { "LH", OPC_LH }, + { "LW", OPC_LW }, + { "SB", OPC_SB }, + { "SH", OPC_SH }, + { "SW", OPC_SW }, + { "CMP", OPC_CMP }, + { "BEQ", OPC_BEQ }, + { "BNE", OPC_BNE }, + { "BLT", OPC_BLT }, + { "BGE", OPC_BGE }, + { "BLE", OPC_BLE }, + { "BGT", OPC_BGT }, + { "J", OPC_J }, + { "JAL", OPC_JAL }, + { "SYS", OPC_SYS }, + { NULL, 0 } +}; + +uint32_t mnemonic2opc(const char *mnemonic) +{ + for (uint8_t i = 0; opc_map[i].name; i++) { + if (strcmp(opc_map[i].name, mnemonic) == 0) + return opc_map[i].opcode << 26; + } + + return ~0; +} + +const char *opc2mnemonic(uint32_t IR) +{ + uint32_t opcode = IR >> 26; + + for (uint8_t i = 0; opc_map[i].name; i++) { + if (opc_map[i].opcode == opcode) + return opc_map[i].name; + } + + return NULL; +} diff --git a/src/emu/opc.h b/src/emu/opc.h new file mode 100644 index 0000000..45d21a8 --- /dev/null +++ b/src/emu/opc.h @@ -0,0 +1,68 @@ +#ifndef _OPC_H +#define _OPC_H + +#include + +/* instructions formats: + * --------------------- + * + * arithmetic: + * |000|xxx|aaaaa|bbbbb|ccccc|00000000000| + * logic: + * |001|xxx|aaaaa|bbbbb|ccccc|00000000000| + * load & store: + * |010|xxx|aaaaa|bbbbb|cccccccccccccccc| + * branch: + * |011|xxx|aaaaa|bbbbb|cccccccccccccccc| + * jump: + * |100|xxx|aaaaa|000000000000000000000| + * misc: + * |111|xxx|??????????????????????????| + * + */ + +/* arithmetic */ +#define OPC_ADD 000 +#define OPC_SUB 001 +#define OPC_MUL 002 +#define OPC_DIV 003 +#define OPC_MOD 004 +#define OPC_SHL 005 +#define OPC_SHR 006 + +/* logic */ +#define OPC_AND 010 +#define OPC_OR 011 +#define OPC_XOR 012 +#define OPC_NOR 013 + +/* load & store */ +#define OPC_MOV 020 +#define OPC_LB 021 +#define OPC_LH 022 +#define OPC_LW 023 +#define OPC_SB 024 +#define OPC_SH 025 +#define OPC_SW 026 + +/* branch instructions */ +#define OPC_CMP 030 +#define OPC_BEQ 031 +#define OPC_BNE 032 +#define OPC_BLT 033 +#define OPC_BGE 034 +#define OPC_BLE 035 +#define OPC_BGT 036 + +/* jump instructions */ +#define OPC_J 040 +#define OPC_JAL 041 + +/* misc */ +#define OPC_SYS 070 + +/* conversion functions */ +uint32_t mnemonic2opc(const char *mnemonic); +const char *opc2mnemonic(uint32_t IR); + +#endif diff --git a/src/emu/riscas.c b/src/emu/riscas.c new file mode 100644 index 0000000..e4180b2 --- /dev/null +++ b/src/emu/riscas.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "asm.h" +#include "log.h" + +static +void usage(int rc) +{ + fprintf(stderr, "Usage: riscas \n"); + exit(rc); +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + usage(EXIT_FAILURE); + } + + FILE *sfd; + if ((sfd = fopen(argv[1], "r")) == NULL) + pdie("could not open source %s", argv[1]); + + FILE *pfd; + if ((pfd = fopen(argv[2], "w")) == NULL) + pdie("could not open program %s", argv[2]); + + char line[128]; + while (fgets(line, 128, sfd)) { + uint32_t IR = compile(line); + + if (IR == 0xFFFFFFFF) + die("illegal instruction: %s", line); + + fwrite(&IR, sizeof(uint32_t), 1, pfd); + } + + return 0; +} diff --git a/src/emu/risci.c b/src/emu/risci.c new file mode 100644 index 0000000..8c4e30f --- /dev/null +++ b/src/emu/risci.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asm.h" +#include "cpu.h" +#include "log.h" +#include "opc.h" + +bool is_debug = false; +bool is_interactive = false; + +/* global program buffer */ +uint8_t *P = NULL; + +static +void usage(int rc) +{ + fprintf(stderr, "Usage: risci [-dhi] \n"); + exit(rc); +} + +static +void signal_handler(int sig) +{ + switch (sig) { + case SIGILL: + /* SIGILL is raised by the cpu for an unknown instruction */ + error("ERROR: illegal instruction."); + if (!is_interactive) + exit(-1); + break; + case SIGSEGV: + /* SIGSEGV is raised for unaligned memory access */ + error("ERROR: unaligned memory access."); + if (!is_interactive) + exit(-1); + break; + case SIGFPE: + /* SIGFPE is raised by devision with zero */ + error("ERROR: division by zero."); + exit(-1); + break; + } +} + +static +void read_program(const char *program) +{ + struct stat sb; + if (lstat(program, &sb) == -1) + pdie("cannot stat program"); + + if (sb.st_size % sizeof(uint32_t)) + die("program does not align to op-code size of %u bytes", sizeof(uint32_t)); + + int pfd; + if ((pfd = open(program, O_RDONLY)) == -1) + pdie("could not open program"); + + P = malloc(sb.st_size + sizeof(uint32_t)); + if (read(pfd, P, sb.st_size) != sb.st_size) + die("premature end of program"); + + memset(P + sb.st_size, 0xFF, sizeof(uint32_t)); +} + +static +uint32_t next_instruction(void) +{ + if (is_interactive) { + /* read next instruction from stdin */ + printf("%03d", PC/4); + return compile(readline("> ")); + } + + uint32_t tmp; + memcpy(&tmp, &P[PC], sizeof(uint32_t)); + return tmp; +} + +int main(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "dhi")) != -1) { + switch (ch) { + case 'd': + is_debug = true; + break; + case 'h': + usage(EXIT_SUCCESS); + case 'i': + is_interactive = true; + break; + case '?': + default: + usage(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + + /* catch cpu signal traps */ + signal(SIGILL, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + + /* load program from file if we're not in interactive mode */ + if (!is_interactive) { + if (argc < 1) + usage(EXIT_FAILURE); + + read_program(argv[0]); + } + + /* reset program counter to first instruction */ + PC = 0; + + /* start instruction loop */ + while (1) { + execute(next_instruction()); + PC += 4; + } + + /* not reached, program is terminated by signal traps from the cpu */ +} diff --git a/src/emu/syscall.c b/src/emu/syscall.c new file mode 100644 index 0000000..fe0d83e --- /dev/null +++ b/src/emu/syscall.c @@ -0,0 +1,23 @@ +#include +#include + +#include "cpu.h" +#include "mem.h" +#include "syscall.h" + +void do_syscall(void) +{ + switch (GPR[1]) { + case SYS_exit: + exit(GPR[2]); + break; + case SYS_read: + GPR[2] = read(GPR[2], &MEM[GPR[3]], GPR[4]); + break; + case SYS_write: + GPR[2] = write(GPR[2], &MEM[GPR[3]], GPR[4]); + break; + default: + GPR[2] = -1; + } +} diff --git a/src/emu/syscall.h b/src/emu/syscall.h new file mode 100644 index 0000000..7c7265c --- /dev/null +++ b/src/emu/syscall.h @@ -0,0 +1,16 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +/* calling convention: + * - pass syscall number in GPR[1] + * - pass arguments in GPR[2]-GPR[9] + * - return code is passed in GPR[2] + */ + +#define SYS_exit 0x00 +#define SYS_read 0x01 +#define SYS_write 0x02 + +void do_syscall(void); + +#endif diff --git a/src/emu/test.S b/src/emu/test.S new file mode 100644 index 0000000..747295f --- /dev/null +++ b/src/emu/test.S @@ -0,0 +1,15 @@ +MOV r1, 102 +SB r0, r1, 0 +MOV r1, 111 +SB r0, r1, 1 +SB r0, r1, 2 +MOV r1, 10 +SB r0, r1, 3 +MOV r1, 2 +MOV r2, 0 +MOV r3, 0 +MOV r4, 4 +SYS +MOV r1, 0 +MOV r2, 1 +SYS diff --git a/src/front/__init__.py b/src/front/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/front/inter/__init__.py b/src/front/inter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/front/lexer/__init__.py b/src/front/lexer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/front/parser/__init__.py b/src/front/parser/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/front/symbols/__init__.py b/src/front/symbols/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3