Physical devices
The benefit of using virtual addresses is that it allows management software, such as a kernel, to control the view of memory that is presented to software. The kernel can control what memory is visible, the virtual address at which that memory is visible, and what accesses are permitted to that memory. This allows the kernel to sandbox applications (hiding the resources of one application from another application) and to provide abstraction from the underlying hardware [1, Ch. 3].
*----------* *----------* +- devices interface -+
| | | | ___ I/O 0 'boot' regfile |
| 64 KiB | | 64 KiB | ___ I/O 1 'dmac' regfile | ___
| | per-process | | ___ I/O ... regfile | |
| virtual | ___ MMU ___ | physical | ___ I/O 23 regfile | |
| memory | mapping | memory | | |c
| | | | ___ main memory | *------------*
| | | | ___ (I/O references) ___ | _ | persistent |
| | | | | d | storage |
*----------* *----------* +- -+ *------------*
1 Address alignment
16 bit
15 7 0
|------------------|------------------|
| physical address | page offset |
8 bit 8 bit
256 byte page size
A resolved address is the combination of a physical address and an offset [1, Ch. 5]. In this case, there’s an 8 bit physical address and an 8 bit offset, which means the minimum amount of space per physical page is 256 bytes. An offset is left out when passing around physical addresses. Memory is allocated in 256 byte blocks. Section 2 explains strategies for small allocations.
16 bit
15 7 0
|------------------|------------------|
| physical address | page offset |
|-------------------------------------|
| virtual address offset |
A translation of the upper virtual address byte is done to resolve to a 16 bit physical address. The lower byte of the virtual address, the offset, is the same offset in the resolved address in order to perform byte-specific operations on the designated memory page.
Contrary to physical resolved addresses, the 16 bit virtual address is passed around userland in its entirety.
2 MMU: memory management unit
A kernel can only map segments of 256 bytes to a process’ virtual memory. In order to handle multiple smaller allocations efficiently, like 24 byte arrays and a couple of small objects, an allocator layer in userland may be used. A system call is only done when more physical space is necessary for the allocation rather than with every single allocation [2].
The MMU holds a table of virtual segments and their physical address for the userspace. It also holds the flags belonging to the segment [3, Ch. 4] [1, Ch. 4].
- Flags
- Cacheable
- Readonly
- Copy-on-write
- Executable
- Reserved
- Reserved
- Reserved
- Dirty
- Physical address
Currently, the two-byte MMU stride is for a 16 bit physical address.
- Cacheable: an indication that the data doesn’t change outside of write instructions, and can therefore be cached, unlike ever-changing dynamic data provided by I/O regfiles;
- Readonly: a write operation will signal a segmentation fault to the processor;
- Copy-on-write: a write operation will signal a copy-on-write to the processor;
- Executable: a read operation through an execution mode will signal a segmentation fault to the processor;
- Dirty: a read or write triggers a new lookup in physical memory.
3 I/O: input and output
There are 24 total pages mapped to I/O devices. Each page is a 256 byte register file to communicate with the device, and the rest is managed by the main memory port [1, Ch. 3]. Every one of the I/O devices has 4 interrupt pins each, resulting in 96 total external interrupts. There are 32 system calls for a grand total of 128 interrupts. It means exactly one page of 256 bytes are allocated for the interrupt map with a 16 bit address per interrupt. The I/O device address range is from 0x0000
to 0x1700
(6.144 bytes).
Two built-in I/O devices are present in the QCPU microcontroller:
- ‘Boot’ sector ROM device [
0
], - ‘DMAC’ device [
1
].
Interrupts with a lower address have higher priority. An interrupt with address 0 can therefore interrupt the interrupt with address 11. Having two predetermined I/O devices give 8 CPU interrupts, mainly for maintenance and security:
address | name | description |
---|---|---|
0100000 |
reset |
reset pin active (highest priority) |
0100001 |
reserved | |
0100010 |
reserved | |
0100011 |
reserved | |
0100100 |
segv |
on unmapped or unprivileged virtual memory access |
0100101 |
cow |
a memory page is being written to with copy-on-write active |
0100110 |
mmap |
a (physical) map request of an I/O device was received |
0100111 |
timer |
system timer for preemptive multitasking (lowest system priority, higher than I/O) |
System calls are addressed before the system interrupts. I/O devices are addressed after the system interrupts.
An interrupt can come with data depending on the I/O device, which can be read from the I/O register file, usually through a device driver. An I/O device can include multiple physical I/O devices to save register file space and/or manage dynamic devices with a register/unregister system.
Interrupt defers add a 242 cycle buffer in which it’s guaranteed no timer
interrupt is fired. It’s used in critical sections. However, the dfr
instruction can implicitly fire timer
(before the next instruction is executed) if deemed necessary to prevent cyclic usage of this feature.