Skip to content

lince_peripherals

The four GR712RC peripherals required to boot RTEMS. Each peripheral is a IPeripheral subclass, and each has a dedicated reference page under Peripherals covering register layouts and behaviour bit by bit.

Source layout

src/peripherals/
├── include/lince/peripherals/
│   ├── irqmp.hpp
│   ├── gptimer.hpp
│   ├── apbuart.hpp
│   ├── memctrl.hpp
│   └── version.hpp
└── src/
    ├── irqmp.cpp
    ├── gptimer.cpp
    ├── apbuart.cpp
    └── memctrl.cpp

Depends on lince_interfaces and lince_bus.

What lives here

Class MMIO base (GR712RC) IRQ Page
IrqMP 0x80000200 IRQMP
GPTimer 0x80000300 8 GPTimer
ApbUart 0x80000100 3 APBUART
MemCtrl 0x80000000 MemCtrl

The base addresses are wired by Emulator::create_default_peripherals during initialize(); they are not stored in EmulatorConfig.

Common patterns

All four peripherals follow the same skeleton:

class FooPeripheral final : public IPeripheral {
public:
    explicit FooPeripheral(PhysAddr base);

    std::string_view name() const override;
    AddressRange     mmio_range() const override;
    void             attach(const PeripheralContext&) override;
    void             reset() override;
    Result<uint32_t> mmio_read (PhysAddr, AccessSize) override;
    Result<void>     mmio_write(PhysAddr, AccessSize, uint32_t) override;
    void             tick(SimTimeNs) override;
    void             publish(IPublisher&) override;
private:
    PhysAddr           base_;
    PeripheralContext  ctx_;
    /* per-peripheral state */
};

The reset contract

reset() returns the peripheral to its power-on state. Per peripheral:

  • IRQMP — masks all interrupts, clears IPEND/IFR, stops asserting any IRQ.
  • GPTimer — disables timers 1–3, but leaves timer 4 in watchdog-armed mode (EN=RS=IE=1, counter=reload=0xFFFF).
  • APBUart — clears the FIFO, clears CTRL, drops any in-flight TX.
  • MemCtrl — restores MCFG1–MCFG4 default values.

The tick contract

tick(SimTimeNs now) is called once per scheduling round. Concretely that means quantum * num_cores * ns_per_insn simulated nanoseconds between calls (default: 1000 × 1 × 20 = 20 µs). Two of the four peripherals do real work in tick:

  • GPTimer decrements its prescaler and sub-timers.
  • MemCtrl does nothing — the call is a no-op.
  • IrqMP does nothing — it reacts to bus writes and external asserts, not to time.
  • ApbUart polls its ICharacterDevice for incoming bytes and pushes them into the RX FIFO.

MMIO size policy

All four peripherals reject non-word accesses with ErrorCode::AlignmentError. Byte and half-word reads/writes are not supported in the MVP (Decision 20). This is stricter than the GR712RC hardware but matches every access RTEMS actually performs.

Custom peripherals

Anything you build follows the same IPeripheral contract — the runtime treats your peripheral exactly like the four built-ins. A fully wired DMA-capable peripheral with an IRQ is shown in examples/demo-dma/ and walked through in the custom peripheral guide.