added global symbol support!
This commit is contained in:
parent
9aaaf7313f
commit
8fc519ee86
8
fibs.asm
8
fibs.asm
@ -4,6 +4,7 @@ fibs: .space 56
|
||||
|
||||
.text
|
||||
main:
|
||||
func_fibs:
|
||||
addi s1, zero, 0 # storage index
|
||||
addi s2, zero, 56 # last storage index
|
||||
addi t0, zero, 1 # t0 = F_{i}
|
||||
@ -19,4 +20,9 @@ loop:
|
||||
addi a0, zero, 0
|
||||
addi a7, zero, 93
|
||||
ebreak # launch debugger
|
||||
scall # exit with code 0
|
||||
scall # exit with code 0
|
||||
|
||||
|
||||
.set test_val, 0xFF
|
||||
|
||||
.global func_fibs
|
@ -44,6 +44,14 @@ def ASSERT_IN(a1, a2):
|
||||
raise ParseException("ASSERTION_FAILED: Expected {} to not be in {}".format(a1, a2), (a1, a2))
|
||||
|
||||
|
||||
class LinkerException(RiscemuBaseException):
|
||||
def __init__(self, msg, data):
|
||||
self.msg = msg
|
||||
self.data = data
|
||||
def message(self):
|
||||
return FMT_PARSE + "{}(\"{}\", data={})".format(self.__class__.__name__, self.msg, self.data) + FMT_NONE
|
||||
|
||||
|
||||
# MMU Exceptions
|
||||
|
||||
class MemoryAccessException(RiscemuBaseException):
|
||||
@ -64,7 +72,7 @@ class MemoryAccessException(RiscemuBaseException):
|
||||
) + FMT_NONE
|
||||
|
||||
|
||||
class OutOfMemoryEsception(RiscemuBaseException):
|
||||
class OutOfMemoryException(RiscemuBaseException):
|
||||
def __init__(self, action):
|
||||
self.action = action
|
||||
|
||||
|
@ -66,15 +66,17 @@ class Executable:
|
||||
sections: Dict[str, MemorySection]
|
||||
symbols: Dict[str, Tuple[str, int]]
|
||||
stack_pref: Optional[int]
|
||||
exported_symbols: List[str]
|
||||
name: str
|
||||
|
||||
def __repr__(self):
|
||||
return "{}(sections = {}, symbols = {}, stack = {}, run_ptr = {})".format(
|
||||
return "{}(sections = {}, symbols = {}, stack = {}, run_ptr = {}, globals={})".format(
|
||||
self.__class__.__name__,
|
||||
" ".join(self.sections.keys()),
|
||||
" ".join(self.symbols.keys()),
|
||||
self.stack_pref,
|
||||
self.run_ptr
|
||||
self.run_ptr,
|
||||
",".join(self.exported_symbols)
|
||||
)
|
||||
|
||||
|
||||
@ -98,8 +100,8 @@ class LoadedInstruction:
|
||||
raise ParseException("Instruction {} expected argument at {} (args: {})".format(self.name, num, self.args))
|
||||
arg = self.args[num]
|
||||
# look up symbols
|
||||
if arg in self.bin.symbols:
|
||||
return self.bin.symbols[arg]
|
||||
if self.bin.has_symb(arg):
|
||||
return self.bin.lookup_symbol(arg)
|
||||
return parse_numeric_argument(arg)
|
||||
|
||||
def get_imm_reg(self, num: int):
|
||||
@ -111,8 +113,8 @@ class LoadedInstruction:
|
||||
arg = self.args[num]
|
||||
ASSERT_IN("(", arg)
|
||||
imm, reg = arg[:-1].split("(")
|
||||
if imm in self.bin.symbols:
|
||||
return self.bin.symbols[imm], reg
|
||||
if self.bin.has_symb(imm):
|
||||
return self.bin.lookup_symbol(imm), reg
|
||||
return parse_numeric_argument(imm), reg
|
||||
|
||||
def get_reg(self, num: int):
|
||||
@ -244,13 +246,17 @@ class LoadedExecutable:
|
||||
symbols: Dict[str, int]
|
||||
run_ptr: int
|
||||
stack_heap: Tuple[int, int] # pointers to stack and heap, are nullptr if no stack/heap is available
|
||||
exported_symbols: Dict[str, int]
|
||||
global_symbol_table: Dict[str, int]
|
||||
|
||||
def __init__(self, exe: Executable, base_addr: int):
|
||||
def __init__(self, exe: Executable, base_addr: int, global_symbol_table: Dict[str, int]):
|
||||
self.name = exe.name
|
||||
self.base_addr = base_addr
|
||||
self.sections = list()
|
||||
self.sections_by_name = dict()
|
||||
self.symbols = dict()
|
||||
self.exported_symbols = dict()
|
||||
self.global_symbol_table = dict()
|
||||
|
||||
# stack/heap if wanted
|
||||
if exe.stack_pref is not None:
|
||||
@ -281,8 +287,14 @@ class LoadedExecutable:
|
||||
curr = align_addr(loaded_sec.size + curr)
|
||||
|
||||
for name, (sec_name, offset) in exe.symbols.items():
|
||||
ASSERT_IN(sec_name, self.sections_by_name)
|
||||
self.symbols[name] = self.sections_by_name[sec_name].base + offset
|
||||
if sec_name == '_static_':
|
||||
self.symbols[name] = offset
|
||||
else:
|
||||
ASSERT_IN(sec_name, self.sections_by_name)
|
||||
self.symbols[name] = self.sections_by_name[sec_name].base + offset
|
||||
|
||||
for name in exe.exported_symbols:
|
||||
self.exported_symbols[name] = self.symbols[name]
|
||||
|
||||
self.size = curr - base_addr
|
||||
|
||||
@ -290,6 +302,14 @@ class LoadedExecutable:
|
||||
run_ptr_sec, run_ptr_off = exe.run_ptr
|
||||
self.run_ptr = self.sections_by_name[run_ptr_sec].base + run_ptr_off
|
||||
|
||||
def lookup_symbol(self, name):
|
||||
if name in self.symbols:
|
||||
return self.symbols[name]
|
||||
if name in self.global_symbol_table:
|
||||
return self.global_symbol_table[name]
|
||||
raise LinkerException('Symbol {} not found!'.format(name), (self,))
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '{}[{}](base=0x{:08X}, size={}bytes, sections={}, run_ptr=0x{:08X})'.format(
|
||||
self.__class__.__name__,
|
||||
@ -299,3 +319,6 @@ class LoadedExecutable:
|
||||
" ".join(self.sections_by_name.keys()),
|
||||
self.run_ptr
|
||||
)
|
||||
|
||||
def has_symb(self, arg):
|
||||
return arg in self.symbols or arg in self.global_symbol_table
|
||||
|
@ -36,7 +36,7 @@ class ExecutableParser:
|
||||
start_ptr = self.symbols['_start']
|
||||
elif 'main' in self.symbols:
|
||||
start_ptr = self.symbols['main']
|
||||
return Executable(start_ptr, self.sections, self.symbols, self.stack_pref, self.tokenizer.name)
|
||||
return Executable(start_ptr, self.sections, self.symbols, self.stack_pref, self.globals, self.tokenizer.name)
|
||||
|
||||
def parse_instruction(self, ins: 'RiscVInstructionToken'):
|
||||
if self.active_section is None:
|
||||
@ -103,7 +103,7 @@ class ExecutableParser:
|
||||
|
||||
def op_global(self, op: 'RiscVPseudoOpToken'):
|
||||
ASSERT_LEN(op.args, 1)
|
||||
name = op.args[1]
|
||||
name = op.args[0]
|
||||
self.globals.append(name)
|
||||
|
||||
def op_set(self, op: 'RiscVPseudoOpToken'):
|
||||
|
@ -1,7 +1,7 @@
|
||||
from .Config import RunConfig
|
||||
from .Executable import Executable, LoadedExecutable, LoadedMemorySection
|
||||
from .helpers import align_addr
|
||||
from .Exceptions import OutOfMemoryEsception
|
||||
from .Exceptions import OutOfMemoryException
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ class MMU:
|
||||
self.binaries = list()
|
||||
self.last_bin = None
|
||||
self.conf = conf
|
||||
self.global_symbols = dict()
|
||||
|
||||
def load_bin(self, bin: Executable):
|
||||
if self.last_bin is None:
|
||||
@ -33,10 +34,10 @@ class MMU:
|
||||
if bin.stack_pref is None:
|
||||
bin.stack_pref = self.conf.preffered_stack_size
|
||||
|
||||
loaded_bin = LoadedExecutable(bin, addr)
|
||||
loaded_bin = LoadedExecutable(bin, addr, self.global_symbols)
|
||||
|
||||
if loaded_bin.size + addr > self.max_size:
|
||||
raise OutOfMemoryEsception('load of executable')
|
||||
raise OutOfMemoryException('load of executable')
|
||||
|
||||
self.binaries.append(loaded_bin)
|
||||
self.last_bin = loaded_bin
|
||||
@ -45,6 +46,8 @@ class MMU:
|
||||
for sec in loaded_bin.sections:
|
||||
self.sections.append(sec)
|
||||
|
||||
self.global_symbols.update(loaded_bin.exported_symbols)
|
||||
|
||||
print("Successfully loaded {}".format(loaded_bin))
|
||||
|
||||
return loaded_bin
|
||||
|
@ -23,7 +23,7 @@ PSEUDO_OPS = [
|
||||
'.data',
|
||||
'.half',
|
||||
'.text',
|
||||
'.word'
|
||||
'.word',
|
||||
'.set',
|
||||
]
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
from .Exceptions import ASSERT_NOT_NULL, ASSERT_LEN, ASSERT_IN, ASSERT_EQ, ASSERT_NOT_IN
|
||||
from .Exceptions import *
|
||||
|
||||
from .Tokenizer import RiscVToken, RiscVInput, RiscVTokenizer, RiscVInstructionToken, RiscVSymbolToken, \
|
||||
RiscVPseudoOpToken, TokenType
|
||||
|
@ -2,6 +2,7 @@ if __name__ == '__main__':
|
||||
from . import *
|
||||
from .helpers import *
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
parser = argparse.ArgumentParser(description='RISC-V Userspace parser and emulator', prog='riscemu')
|
||||
parser.add_argument('file', metavar='file.asm', type=str, help='The assembly file to interpret and run')
|
||||
@ -33,15 +34,21 @@ if __name__ == '__main__':
|
||||
FMT_NONE = ""
|
||||
FMT_PRINT = ""
|
||||
|
||||
tk = RiscVTokenizer(RiscVInput.from_file(args.file))
|
||||
tk.tokenize()
|
||||
try:
|
||||
tk = RiscVTokenizer(RiscVInput.from_file(args.file))
|
||||
tk.tokenize()
|
||||
|
||||
if args.print_tokens:
|
||||
print(FMT_PRINT + "Tokens:" + FMT_NONE)
|
||||
for token in tk.tokens:
|
||||
print(token)
|
||||
if args.print_tokens:
|
||||
print(FMT_PRINT + "Tokens:" + FMT_NONE)
|
||||
for token in tk.tokens:
|
||||
print(token)
|
||||
|
||||
executable = ExecutableParser(tk).parse()
|
||||
executable = ExecutableParser(tk).parse()
|
||||
except RiscemuBaseException as e:
|
||||
print("Error while parsing: {}".format(e.message()))
|
||||
import traceback
|
||||
traceback.print_exception(type(e), e, e.__traceback__)
|
||||
sys.exit(1)
|
||||
|
||||
cpu = CPU(cfg)
|
||||
le = cpu.load(executable)
|
||||
|
Loading…
Reference in New Issue
Block a user