Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSR: use data.Struct instead of deprecated rec.Record. README: warn users about old yosys version. #51

Merged
merged 8 commits into from
Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions doc/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,12 @@ file build/$PROJ_NAME.elf # make sure it exists

#### Dependencies

For `Ubuntu 22.04` and newer:
* yosys
* nextpnr-ice40
* fpga-icestorm

```sh
sudo apt-get install yosys nextpnr-ice40 fpga-icestorm
```

For different distros follow the instructions in project references.
In theory `yosys` and `nextpnr` are available to install as `apt-get install` from Ubuntu 22.04 and newer, however it ships a very old version.
I recommend compiling it from sources instead. Using old `yosys` may cause too much resources being used and `mtkcpu` won't synthesize at all!

#### Bitstream generation

Expand Down Expand Up @@ -104,4 +103,4 @@ Info: ICESTORM_SPRAM: 0/ 4 0%

If you run the command above with additional `--program` param, it will program your board after build succeeded.

And this is it, your board is blinking happily!
And this is it, your board is blinking happily!
2 changes: 2 additions & 0 deletions mtkcpu/cli/top.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ def generate_bsp():
dev_mode=False,
with_debug=True,
pc_reset_value=0xdeadbeef,
with_virtual_memory=False,
)

cpu = get_board_cpu(elf_path=None, cpu_config=cpu_config)
platform = get_platform()
dummy_elaborate(cpu, platform)
Expand Down
7 changes: 4 additions & 3 deletions mtkcpu/cpu/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from amaranth import Mux, Cat, Signal, Const, Record, Elaboratable, Module, Memory, signed
from amaranth.hdl.rec import Layout

from mtkcpu.units.csr import CsrUnit, match_csr
from mtkcpu.units.csr.csr import CsrUnit, match_csr
from mtkcpu.units.exception import ExceptionUnit
from mtkcpu.utils.common import EBRMemConfig
from mtkcpu.units.adder import AdderUnit, match_adder_unit
Expand Down Expand Up @@ -150,6 +150,7 @@ def __init__(

self.running_state = CpuRunningState()
self.running_state_interface = CpuRunningStateExternalInterface()
self.running_state_interface._MustUse__used = True


def elaborate(self, platform):
Expand Down Expand Up @@ -262,8 +263,8 @@ def prev(sig: Signal) -> Signal:
single_step_is_active = Signal()
just_resumed = self.just_resumed = Signal()
just_halted = self.just_halted = Signal()
dcsr = self.csr_unit.reg_by_addr(CSRIndex.DCSR).rec.r
dpc = self.csr_unit.reg_by_addr(CSRIndex.DPC).rec.r
dcsr = self.csr_unit.dcsr
dpc = self.csr_unit.dpc

with m.If(just_resumed):
sync += single_step_is_active.eq(dcsr.step)
Expand Down
152 changes: 22 additions & 130 deletions mtkcpu/cpu/priv_isa.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,135 +92,6 @@ class IrqCause(IntEnum):
S_EXTERNAL_INTERRUPT = 9
M_EXTERNAL_INTERRUPT = 11


# CSR layouts

flat_layout = [
("value", 32),
]


class MisaExtensionBit(IntEnum):
INTEGER_BASE_ISA = 1 << 8
MULDIV = 1 << 12

class MisaRXL(IntEnum):
RV32 = 1
RV64 = 2

class MtvecModeBits(IntEnum):
DIRECT = 0 # All exceptions set pc to BASE.
VECTORED = 1 # Asynchronous interrupts set pc to BASE+4×cause.

misa_layout = [
("extensions", 26),
("zero", 4),
("mxl", 2),
]

mstatus_layout = [
("uie", 1), # User Interrupt Enable
("sie", 1), # Supervisor Interrupt Enable
("zero0", 1),
("mie", 1), # Machine Interrupt Enable
("upie", 1), # User Previous Interrupt Enable
("spie", 1), # Supervisor Previous Interrupt Enable
("zero1", 1),
("mpie", 1), # Machine Previous Interrupt Enable
("spp", 1), # Supervisor Previous Privilege
("zero2", 2),
("mpp", 2), # Machine Previous Privilege
("fs", 2), # FPU Status
("xs", 2), # user-mode eXtensions Status
("mprv", 1), # Modify PRiVilege
("sum", 1), # Supervisor User Memory access
("mxr", 1), # Make eXecutable Readable
("tvm", 1), # Trap Virtual Memory
("tw", 1), # Timeout Wait
("tsr", 1), # Trap SRET
("zero3", 8),
("sd", 1), # State Dirty (set if XS or FS are set to dirty)
]

mtvec_layout = [
("mode", 2),
("base", 30),
]

mip_layout = [
("usip", 1),
("ssip", 1),
("zero0", 1),
("msip", 1),
("utip", 1),
("stip", 1),
("zero1", 1),
("mtip", 1),
("ueip", 1),
("seip", 1),
("zero2", 1),
("meip", 1),
("zero3", 20),
]


mie_layout = [
("usie", 1),
("ssie", 1),
("zero0", 1),
("msie", 1),
("utie", 1),
("stie", 1),
("zero1", 1),
("mtie", 1),
("ueie", 1),
("seie", 1),
("zero2", 1),
("meie", 1),
("zero3", 20),
]


mcause_layout = [
("ecode", 31),
("interrupt", 1),
]


dcsr_layout = [
("prv", 2),
("step", 1),
("nmip", 1),
("mprven", 1),
("v", 1),
("cause", 3),
("stoptime", 1),
("stopcount", 1),
("stepie", 1),
("ebreaku", 1),
("ebreaks", 1),
("zero1", 1),
("ebreakm", 1),
("ebreakvu", 1),
("ebreakvs", 1),
("zero2", 10),
("debugver", 4),
]


tdata1_layout = [
("data", 27),
("dmode", 1),
("type", 4),
]


satp_layout = [
("ppn", 22),
("asid", 9),
("mode", 1),
]

pte_layout = [
("v", 1),
("r", 1),
Expand All @@ -239,4 +110,25 @@ class MtvecModeBits(IntEnum):
("page_offset", 12),
("vpn0", 10),
("vpn1", 10),
]
]

from amaranth.lib import data
from amaranth import unsigned

class PTE_Layout(data.Struct):
v : unsigned(1)
r : unsigned(1)
w : unsigned(1)
x : unsigned(1)
u : unsigned(1)
g : unsigned(1)
a : unsigned(1)
d : unsigned(1)
rsw : unsigned(2)
ppn0 : unsigned(10)
ppn1 : unsigned(12)

class Virt_Addr_Layout(data.Struct):
page_offset : unsigned(12)
vpn0 : unsigned(10)
vpn1 : unsigned(10)
31 changes: 12 additions & 19 deletions mtkcpu/tests/test_address_translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from mtkcpu.utils.tests.memory import MemoryContents
from mtkcpu.utils.tests.registers import RegistryContents
from mtkcpu.utils.tests.utils import (MemTestCase, MemTestSourceType, mem_test)
from mtkcpu.units.csr.types import MSTATUS_Layout, SATP_Layout

from mtkcpu.cpu.priv_isa import PrivModeBits, pte_layout, satp_layout
from mtkcpu.units.csr import RegisterResetValue
from amaranth import Signal

# page tables phys. addresses must be aligned to 4K == 0x1000 bytes
root_pt_offset = 0x2000
Expand All @@ -14,22 +14,15 @@
root_pt_addr = MEM_START_ADDR + root_pt_offset
leaf_pt_addr = MEM_START_ADDR + leaf_pt_offset

def get_flat_value_generator(layout):
return lambda fields: RegisterResetValue.calc_reset_value(fields, layout)

def get_field_values_generator(layout):
return lambda value: RegisterResetValue.value_to_fields(value, layout)

satp_get_flat_value = get_flat_value_generator(satp_layout)
satp_get_field_values = get_field_values_generator(satp_layout)

pte_get_flat_value = get_flat_value_generator(pte_layout)
pte_get_fields_values = get_field_values_generator(pte_layout)

satp_value = satp_get_flat_value({
satp_value = SATP_Layout.const({
"mode": 1, # enable address translation in user mode
"ppn": root_pt_addr >> 12,
})
}).value

pte_const = lambda fields: PTE_Layout.const(fields).value

# https://github.com/amaranth-lang/amaranth/issues/786
mpp_offset_in_MSTATUS = MSTATUS_Layout(Signal(32))._View__layout._fields["mpp"].offset

virt_addr_high = 0x111
virt_addr_low = 0x222
Expand Down Expand Up @@ -66,7 +59,7 @@ def get_field_values_generator(layout):

// set 'previous priv.' mstatus's field to user mode
li x4, {PrivModeBits.USER}
slli x4, x4, {get_layout_field_offset(mstatus_layout, 'mpp')}
slli x4, x4, {mpp_offset_in_MSTATUS}
csrw mstatus, x4
// set machine mode trap
la x4, mmode_trap
Expand All @@ -89,13 +82,13 @@ def get_field_values_generator(layout):
# when usermode starts, it's expected to perform address translation
# and jump to MEM_START_ADDR + 0x1000 + offset (address of symbol 'usermode').
mem_init=MemoryContents(memory={
root_page_phys_addr: pte_get_flat_value({
root_page_phys_addr: pte_const({
"v": 1,
# {ppn0, ppn1} is a pointer to the next level pte
"ppn1": hi_pn(leaf_pt_addr >> 12),
"ppn0": lo_pn(leaf_pt_addr >> 12),
}),
leaf_page_phys_addr: pte_get_flat_value({
leaf_page_phys_addr: pte_const({
"v": 1,
"r": 1,
"w": 1,
Expand Down
8 changes: 4 additions & 4 deletions mtkcpu/tests/test_csr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from mtkcpu.utils.tests.registers import RegistryContents
from mtkcpu.utils.tests.utils import (MemTestCase, MemTestSourceType, mem_test)

from mtkcpu.units.csr_handlers import MISA
from mtkcpu.units.csr.csr_handlers import MISA

# some registers (e.g. mcause) are tested in test_exception.py file.
CSR_TESTS = [
Expand Down Expand Up @@ -53,7 +53,7 @@
csrr x3, misa
""",
out_reg=3,
out_val=MISA().reset_value,
out_val=MISA.const(),
timeout=5,
mem_init=MemoryContents.empty(),
reg_init=RegistryContents.fill(),
Expand All @@ -68,7 +68,7 @@
csrr x2, misa
""",
out_reg=2,
out_val=MISA().reset_value,
out_val=MISA.const(),
timeout=5,
mem_init=MemoryContents.empty(),
reg_init=RegistryContents.fill(),
Expand Down Expand Up @@ -269,7 +269,7 @@
# ),

MemTestCase(
name="basic csrrc",
name="basic csrrs - misa",
source_type=MemTestSourceType.RAW,
source=f"""
start:
Expand Down
9 changes: 5 additions & 4 deletions mtkcpu/tests/test_debug_unit.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3

from typing import Sequence
from dataclasses import dataclass

from amaranth.sim import Simulator, Settle
Expand All @@ -15,7 +16,7 @@
from mtkcpu.units.debug.dmi_handlers import DMI_HANDLERS_MAP
from mtkcpu.units.debug.impl_config import PROGBUFSIZE, PROGBUF_MMIO_ADDR
from mtkcpu.units.debug.impl_config import DATASIZE
from mtkcpu.units.csr_handlers import DCSR
from mtkcpu.units.csr.csr_handlers import DCSR

logging = get_color_logging_object()

Expand Down Expand Up @@ -526,7 +527,7 @@ def main_process():
new_pc = pc // 2 + 0x1000
assert new_pc != pc

yield dmi_monitor.cpu.csr_unit.reg_by_addr(CSRIndex.DPC).rec.r.eq(new_pc)
yield dmi_monitor.cpu.csr_unit.dpc.eq(new_pc)

yield from DMCONTROL_setup_basic_fields(dmi_monitor=dmi_monitor, dmi_op=DMIOp.WRITE)
yield dmi_monitor.cur_DMCONTROL.haltreq.eq(0)
Expand Down Expand Up @@ -656,7 +657,7 @@ def mepc():
yield Passive()
while True:
pc = yield cpu.pc
mepc = yield cpu.csr_unit.mepc.value
mepc = yield cpu.csr_unit.mepc.as_value()
instr = yield cpu.instr
print("mepc", hex(mepc), "pc", hex(pc), "instr", hex(instr))
yield
Expand Down Expand Up @@ -687,7 +688,7 @@ def main_process():
yield from few_ticks()

# TODO: hardcoded 'cause' field offset.
expected_dcsr_reset_value = DCSR()._reset_value.value | (DCSR_DM_Entry_Cause.HALTREQ << 6)
expected_dcsr_reset_value = DCSR.const() | (DCSR_DM_Entry_Cause.HALTREQ << 6)

DCSR_ins = instructions.RiscvCsrRegister("dcsr", num=0x7b0)

Expand Down
Loading