Memory and I/O maps, soft reset, and interrupts
Note: the content of this section is subject to change as the specification develops.
untethered release starts to regulate the shared resources among cores, such as interrupts, memory and I/O maps, global timers, etc. A subset of control status register (CSR) space is defined as processor control registers (PCRs), whose values and accesses are shared by all cores and controlled by a global PCR control unit (
PCRControl). The connections of the PCR control units is shown below.
PCR read/write requests (
The CSR file in each core has a dedicated request channel to the global PCR control unit. When a CSR address is identified as a PCR, the CSR request is forwarded to
PCR read/write response (
Upon receiving a request from
pcr_req, the PCR control unit processes the
request and sends back a response through the
pcr_resp port connected to the
requesting core when it is finished. When it is a read request, the PCR value
is sent back in the response.
Broadcast of PCR update (
Operations on some PCRs trigger changes of the global status, such as changing
the I/O map. In this case, the updated PCR is broadcast to all components
potentially affected by this change. In this implementation, every L1 D$ has
ioaddr module for identifying I/O requests. To enforce the address
mapping defined in the memory map, a memory address converter (
added just below the L2 arbiter. Besides CSR modules, all
ioaddr modules and
the memory address converter receive PCR updates to track the changes in I/O
and memory maps.
All cores share the same interrupt sources but they can enable/disable individual interrupts separately. When an interrupt arrives, it is forwarded to all cores who have enabled it.
Soft reset (
When a soft reset is triggered (a write to CSR
reset), a reset signal is
broadcast to all cores and the L2.
All PCRs are readable or writable in machine mode ONLY.
|time||Read Only||0||Global wall clock.|
|tohost||Read/Write||0||Legacy, only used in ISA regression test to identify return value.|
|fromhost||Read/Write||0||Legacy, not used.|
|reset||Read/Write||0||When written, trigger a soft reset. Always reads 0.|
|mem_base0||Read/Write||InitMemBase||Base address of memory section 0.|
|mem_mask0||Read/write||InitMemMask||Address mask of memory section 0.|
|mem_phy0||Read/Write||InitPhyBase||Physical base address of memory section 0.|
|mem_base1||Read/Write||0||Base address of memory section 1.|
|mem_mask1||Read/write||0||Address mask of memory section 1.|
|mem_phy1||Read/Write||0||Physical base address of memory section 1.|
|mem_base2||Read/Write||0||Base address of memory section 2.|
|mem_mask2||Read/write||0||Address mask of memory section 2.|
|mem_phy2||Read/Write||0||Physical base address of memory section 2.|
|mem_base3||Read/Write||0||Base address of memory section 3.|
|mem_mask3||Read/write||0||Address mask of memory section 3.|
|mem_phy3||Read/Write||0||Physical base address of memory section 3.|
|mem_update||Read/Write||0||When written, trigger memory map update. Always reads 0.|
|io_base0||Read/Write||InitIOBase||Base address of I/O section 0.|
|io_mask0||Read/write||InitIOMask||Address mask of I/O section 0.|
|io_base1||Read/Write||0||Base address of I/O section 1.|
|io_mask1||Read/write||0||Address mask of I/O section 1.|
|io_base2||Read/Write||0||Base address of I/O section 2.|
|io_mask2||Read/write||0||Address mask of I/O section 2.|
|io_base3||Read/Write||0||Base address of I/O section 3.|
|io_mask3||Read/write||0||Address mask of I/O section 3.|
|io_update||Read/Write||0||When written, trigger I/O map update. Always reads 0.|
|int_en0||Read/Write||0||IRQ enable for core 0.|
|int_pending0||Read Only||N/A||Pending IRQ for core 0.|
|int_en1||Read/Write||0||IRQ enable for core 1.|
|int_pending1||Read Only||N/A||Pending IRQ for core 1.|
|int_en2||Read/Write||0||IRQ enable for core 2.|
|int_pending2||Read Only||N/A||Pending IRQ for core 2.|
|int_en3||Read/Write||0||IRQ enable for core 3.|
|int_pending3||Read Only||N/A||Pending IRQ for core 3.|
|int_en4||Read/Write||0||IRQ enable for core 4.|
|int_pending4||Read Only||N/A||Pending IRQ for core 4.|
|int_en5||Read/Write||0||IRQ enable for core 5.|
|int_pending5||Read Only||N/A||Pending IRQ for core 5.|
|int_en6||Read/Write||0||IRQ enable for core 6.|
|int_pending6||Read Only||N/A||Pending IRQ for core 6.|
|int_en7||Read/Write||0||IRQ enable for core 7.|
|int_pending7||Read Only||N/A||Pending IRQ for core 7.|
The current wall clock counts at 50MHz. The value of this wall clock is updated to all cores every 20 cycles. The wall clock is not writable.
When a core reads the CSR
time, an actual read of the wall clock is
initiated. However, the timer comparator in each core is compared against the
infrequently updated local copy, which incurs a 20 cycle inaccuracy in the
This pair of registers are kept for legacy reasons. They are used in the ISA regression test only for identifying the end of a test and the return value. Writing
tohost has no effect in FPGA but writing a non-zero value to
fromhost triggers an exception.
Writing any value to
reset triggers a soft reset.
This implementation supports up to 4 separate memory sections. The space of any two sections should not overlap.
For each section,
mem_base defines the base address as seen by the core;
mem_mask defines the actual size of the section;
mem_phy defines the base
address as seen by on-chip interconnects. When
mem_mask is 0, the section is
disabled (size of 0). For any address (
addr), it belongs to a memory section
(addr & ~mem_mask) == mem_base. The translated address to on-chip
(addr & mem_mask) | mem_phy.
The update of a memory section should be an atomic operation. To ease this requirement, any write to a memory map is buffered. The actual update to the memory map is triggered by a write to
This implementation supports up to 4 separate I/O sections. The space of any two sections should not overlap.
For each section,
io_base defines the base address;
io_mask defines the actual size of the section. When
io_mask is 0, the section is disabled (size of 0). For any address (
addr), it belongs to an I/O section if
(addr & ~io_mask) == io_base. There is no address translation for I/O addresses.
Similar to the memory map, the update of an I/O section should be an atomic operation. In the same way, any write to I/O map is buffered. The actual update is triggered by a write to
Up to 64 interrupt sources are supported.
Every core has two PCRs:
int_en defines which IRQ should be notified to the core, while
int_pending identifies any pending IRQs. The actual interrupt sources are latched in the PCR control unit. The value of
int_pending is generated by
int_pending = interrupt & int_en.
When an IRQ is triggered, the responding core can find out the actual IRQ source by reading
int_pending. Currently the responding core needs to access the actual peripheral to resolve a pending IRQ.
In this implementation, interrupt bit 0 is connected to UART and bit 1 is connected to SPI.