added unified instruction parsing
This commit is contained in:
parent
2d378f2e0a
commit
1957e11f62
@ -35,19 +35,19 @@ class CPU:
|
||||
self.instruction_sets: List['InstructionSet'] = list()
|
||||
self.instructions: Dict[str, Callable[[LoadedInstruction], None]] = dict()
|
||||
for set_class in instruction_sets:
|
||||
ins_set = set_class()
|
||||
self.instructions.update(ins_set.load(self))
|
||||
ins_set = set_class(self)
|
||||
self.instructions.update(ins_set.load())
|
||||
self.instruction_sets.append(ins_set)
|
||||
|
||||
# provide global syscall symbols if option is set
|
||||
if conf.include_scall_symbols:
|
||||
self.mmu.global_symbols.update(self.syscall_int.get_syscall_symbols())
|
||||
|
||||
def get_tokenizer(self, input):
|
||||
def get_tokenizer(self, tokenizer_input):
|
||||
"""
|
||||
Returns a tokenizer that respects the language of the CPU
|
||||
"""
|
||||
return RiscVTokenizer(input, self.all_instructions())
|
||||
return RiscVTokenizer(tokenizer_input, self.all_instructions())
|
||||
|
||||
def load(self, e: 'Executable'):
|
||||
"""
|
||||
@ -93,23 +93,6 @@ class CPU:
|
||||
# this should never be reached, as unknown instructions are imparseable
|
||||
raise RuntimeError("Unknown instruction: {}".format(ins))
|
||||
|
||||
def parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]:
|
||||
"""
|
||||
parses both rd, rs1, imm and rd, imm(rs1) arguments and returns (rd, imm+rs1)
|
||||
(so a register and address tuple for memory instructions)
|
||||
"""
|
||||
if len(ins.args) == 3:
|
||||
# handle rd, rs1, imm
|
||||
rs1 = ins.get_reg(1)
|
||||
imm = ins.get_imm(2)
|
||||
else:
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
ASSERT_IN("(", ins.args[1])
|
||||
imm, rs1 = ins.get_imm_reg(1)
|
||||
# handle rd, imm(rs1)
|
||||
rd = ins.get_reg(0)
|
||||
return rd, self.regs.get(rs1) + imm
|
||||
|
||||
def all_instructions(self) -> List[str]:
|
||||
return list(self.instructions.keys())
|
||||
|
||||
|
@ -8,16 +8,19 @@ class InstructionSet(ABC):
|
||||
"""
|
||||
Represents a collection of instructions
|
||||
"""
|
||||
def __init__(self):
|
||||
self.cpu: typing.Optional['CPU'] = None
|
||||
self.mmu: typing.Optional['MMU'] = None
|
||||
self.regs: typing.Optional['Registers'] = None
|
||||
|
||||
def load(self, cpu: 'CPU'):
|
||||
def __init__(self, cpu: 'CPU'):
|
||||
self.cpu = cpu
|
||||
self.mmu = cpu.mmu
|
||||
self.regs = cpu.regs
|
||||
|
||||
def load(self) -> typing.Dict[str, typing.Callable[['LoadedInstruction'], None]]:
|
||||
"""
|
||||
This is called by the CPU once it instantiates this instruction set
|
||||
|
||||
It returns a dictionary of all instructions in this instruction set,
|
||||
pointing to the correct handler for it
|
||||
"""
|
||||
return {
|
||||
name: ins for name, ins in self.get_instructions()
|
||||
}
|
||||
@ -27,24 +30,46 @@ class InstructionSet(ABC):
|
||||
if member.startswith('instruction_'):
|
||||
yield member[12:].replace('_', '.'), getattr(self, member)
|
||||
|
||||
def parse_mem_ins(self, ins: 'LoadedInstruction'):
|
||||
return self.cpu.parse_mem_ins(ins)
|
||||
def parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]:
|
||||
"""
|
||||
parses both rd, rs, imm and rd, imm(rs) arguments and returns (rd, imm+rs1)
|
||||
(so a register and address tuple for memory instructions)
|
||||
"""
|
||||
if len(ins.args) == 3:
|
||||
# handle rd, rs1, imm
|
||||
rs = self.get_reg_content(ins, 1)
|
||||
imm = ins.get_imm(2)
|
||||
else:
|
||||
# handle rd, imm(rs1)
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
ASSERT_IN("(", ins.args[1])
|
||||
imm, rs_name = ins.get_imm_reg(1)
|
||||
rs = self.regs.get(rs_name)
|
||||
rd = ins.get_reg(0)
|
||||
return rd, rs + imm
|
||||
|
||||
def parse_rd_rs_rs(self, ins: 'LoadedInstruction'):
|
||||
def parse_rd_rs_rs(self, ins: 'LoadedInstruction') -> Tuple[str, int, int]:
|
||||
"""
|
||||
Assumes the command is in <name> rd, rs1, rs2 format
|
||||
Returns the name of rd, and the values in rs1 and rs2
|
||||
"""
|
||||
ASSERT_LEN(ins.args, 3)
|
||||
return ins.get_reg(0), self.get_reg_content(ins, 1), self.get_reg_content(ins, 2)
|
||||
|
||||
def parse_rd_rs_imm(self, ins: 'LoadedInstruction'):
|
||||
def parse_rd_rs_imm(self, ins: 'LoadedInstruction') -> Tuple[str, int, int]:
|
||||
"""
|
||||
Assumes the command is in <name> rd, rs, imm format
|
||||
Returns the name of rd, the value in rs and the immediate imm
|
||||
"""
|
||||
ASSERT_LEN(ins.args, 3)
|
||||
return ins.get_reg(0), self.get_reg_content(ins, 1), ins.get_imm(2)
|
||||
|
||||
def get_reg_content(self, ins: 'LoadedInstruction', ind: int):
|
||||
def get_reg_content(self, ins: 'LoadedInstruction', ind: int) -> int:
|
||||
"""
|
||||
get the register name from ins and then return the register contents
|
||||
"""
|
||||
return self.regs.get(ins.get_reg(ind))
|
||||
|
||||
|
||||
@property
|
||||
def pc(self):
|
||||
return self.cpu.pc
|
||||
@ -57,4 +82,4 @@ class InstructionSet(ABC):
|
||||
return "InstructionSet[{}] with {} instructions".format(
|
||||
self.__class__.__name__,
|
||||
len(list(self.get_instructions()))
|
||||
)
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user