Compare commits

...

3 Commits

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (riscemu)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (riscemu)" project-jdk-type="Python SDK" />
</project>

@ -10,7 +10,7 @@
<excludeFolder url="file://$MODULE_DIR$/riscemu.egg-info" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (riscemu)" jdkType="Python SDK" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -1,5 +1,21 @@
# Changelog
## Upcoming 2.0.6
**Planned:**
- Add a floating point unit
- Add a crt0.s
- Add `mmap2` syscall with code 192
## 2.0.5
- Added unlimited register mode with `-o unlimited_regs`
## 2.0.4
- Bugfix: fix a sign issue in instruction parsing for `rd, rs, rs` format
- Bugfix: respect `conf.debug_instruction` setting
## 2.0.3 - 2022-04-18
- Syscalls: cleaned up formatting and added instructions for extensions

@ -281,14 +281,3 @@ class MMU:
return sec.context
return InstructionContext()
def report_addr(self, addr: T_AbsoluteAddress):
sec = self.get_sec_containing(addr)
if not sec:
print("addr is in no section!")
return
owner = [b for b in self.programs if b.name == sec.owner]
if owner:
print("owned by: {}".format(owner[0]))
print("{}: 0x{:0x} + 0x{:0x}".format(name, val, addr - val))

@ -269,9 +269,10 @@ class RV32I(InstructionSet):
def instruction_jalr(self, ins: 'Instruction'):
ASSERT_LEN(ins.args, 2)
reg = ins.get_reg(0)
addr = ins.get_imm(1)
base = ins.get_reg(1)
addr = ins.get_imm(2)
self.regs.set(reg, Int32(self.pc))
self.pc = addr
self.pc = self.regs.get(base).unsigned_value + addr
def instruction_ret(self, ins: 'Instruction'):
ASSERT_LEN(ins.args, 0)

@ -6,8 +6,10 @@ SPDX-License-Identifier: MIT
import sys
from dataclasses import dataclass
from math import log2, ceil
from typing import Dict, IO
from .types import BinaryDataMemorySection, MemoryFlags
from .colors import FMT_SYSCALL, FMT_NONE
from .types import Int32, CPU
from .types.exceptions import InvalidSyscallException
@ -16,6 +18,7 @@ SYSCALLS = {
63: 'read',
64: 'write',
93: 'exit',
192: 'mmap2',
1024: 'open',
1025: 'close',
}
@ -27,6 +30,18 @@ dictionary and implement a method with the same name on the SyscallInterface
class.
"""
ADDITIONAL_SYMBOLS = {
'MAP_PRIVATE': 1<<0,
'MAP_SHARED': 1<<1,
'MAP_ANON': 1<<2,
'MAP_ANONYMOUS': 1<<2,
'PROT_READ': 1<<0,
'PROT_WRITE': 1<<1,
}
"""
A set of additional symbols that are used by various syscalls.
"""
OPEN_MODES = {
0: 'rb',
1: 'wb',
@ -56,7 +71,7 @@ class Syscall:
self.id, self.name
)
def ret(self, code):
def ret(self, code: int | Int32):
self.cpu.regs.set('a0', Int32(code))
@ -66,10 +81,14 @@ def get_syscall_symbols():
:return: dictionary of all syscall symbols (SCALL_<name> -> id)
"""
return {
items: Dict[str, int] = {
('SCALL_' + name.upper()): num for num, name in SYSCALLS.items()
}
items.update(ADDITIONAL_SYMBOLS)
return items
class SyscallInterface:
"""
@ -198,6 +217,57 @@ class SyscallInterface:
scall.cpu.halted = True
scall.cpu.exit_code = scall.cpu.regs.get('a0').value
def mmap2(self, scall: Syscall):
"""
mmap2 syscall:
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
Only supported modes:
addr = <any>
prot = either PROT_READ or PROT_READ | PROT_WRITE
flags = MAP_PRIVATE | MAP_ANONYMOUS
fd = <ignored>
off_t = <ignored>
"""
addr = scall.cpu.regs.get('a0').unsigned_value
size = scall.cpu.regs.get('a1').unsigned_value
prot = scall.cpu.regs.get('a2').unsigned_value
flags = scall.cpu.regs.get('a3').unsigned_value
# error out if prot is not 1 or 3:
# 1 = PROT_READ
# 3 = PROT_READ | PROT_WRITE
if prot != 1 and prot != 3:
return scall.ret(-1)
# round size up to multiple of 4096
size = 4096 * ceil(size / 4096)
section = BinaryDataMemorySection(
bytearray(size),
'.data.runtime-allocated',
None,
'system',
base=addr,
flags=MemoryFlags(read_only=prot != 3, executable=False)
)
# try to insert section
if scall.cpu.mmu.load_section(section, addr != 0):
return scall.ret(section.base)
# if that failed, and we tried to force an address,
# try again at any address
elif addr != 0:
section.base = 0
if scall.cpu.mmu.load_section(section):
return scall.ret(section.base)
# if that didn't work, return error
return scall.ret(-1)
def __repr__(self):
return "{}(\n\tfiles={}\n)".format(
self.__class__.__name__,

@ -1,12 +1,16 @@
import typing
from abc import ABC, abstractmethod
from typing import List, Type, Callable, Set, Dict
from typing import List, Type, Callable, Set, Dict, TYPE_CHECKING
from ..registers import Registers
from ..config import RunConfig
from ..colors import FMT_RED, FMT_NONE, FMT_ERROR, FMT_CPU
from . import T_AbsoluteAddress, Instruction, Program, ProgramLoader
if TYPE_CHECKING:
from .. import MMU
from ..instructions import InstructionSet
class CPU(ABC):
# static cpu configuration

Loading…
Cancel
Save