Of my four big software/hardware projects, I have decided to build a new processor architecture. This is not a RISC architecture, but a hybrid architecture- a hybrid CISC-VLIW- full 64-bit data and address lines, and a 512-bit VLIW for packetization. It’s a two-ring (user/supervisor) processor, where the instruction set will be open-source, without a single piece of legacy instructions or seeking backward compatibility at all.
The 512-but packetization allows compiling several operations into one instruction for parallel processing, if the developer sees it as needed. This allows compilers written on AURORA the ability to make operations more efficient.
Here is the guide to the instruction set so far:
AURORA v0.13 defines 32 scalar instructions, plus the optional 512-bit packet format that bundles those same instructions. I checked the source archive’s ISA specification, assembler, decoder, and emulator. The reference below distinguishes the architectural rules from limitations in the current implementation.
Machine model and instruction encoding
AURORA is a little-endian, byte-addressed architecture with 64-bit integer registers, addresses, and program counter.
| Component | Definition |
|---|---|
| General-purpose registers | 32 registers, R0–R31, each 64 bits |
| Zero register | None; R0 is writable |
| Stack pointer | Conventionally R30; remains an ordinary register |
| Link register | Conventionally R31; CALL and RET explicitly use it |
| Program counter | 64-bit PC |
| Arithmetic condition flags | No carry, zero, sign, or overflow flags defined |
| Scalar alignment | Instructions may start at any byte address |
| Scalar lengths | Currently 1, 3, 4, 5, or 10 bytes; packet slot lengths can represent 1–15 |
| Packet alignment | Mandatory 64-byte alignment |
| Integer byte order | Little-endian, including instruction immediates |
| Privilege modes | User and Supervisor |
| Floating-point/vector registers | Not defined in the current instruction set |
Each scalar instruction begins with a one-byte opcode. Each register operand occupies one byte: bits 4–0 select the register, and bits 7–5 must be zero.
In the tables below, Rd is a destination register, Rs a source, and Ra/Rb additional sources. Instruction lengths include the opcode byte. All opcode values are hexadecimal.
Data movement — 2 instructions
| Opcode | Instruction | Bytes | Operation |
|---|---|---|---|
10 | MOV Rd, Rs | 3 | Copy all 64 bits of Rs into Rd. |
11 | MOVI Rd, imm64 | 10 | Load a full 64-bit immediate into Rd. |
Encodings:
MOV: opcode, destination, source
MOVI: opcode, destination, immediate64
MOVI can load an entire 64-bit constant or address in one instruction:
MOVI R1, 0x123456789ABCDEF0
MOV R2, R1
There are no separate high-half/low-half immediate instructions. The assembler supports symbol relocations for scalar MOVI, allowing the linker to fill in a 64-bit address.
Integer arithmetic and logic — 8 instructions
| Opcode | Instruction | Bytes | Operation |
|---|---|---|---|
20 | ADD Rd, Ra, Rb | 4 | Rd = Ra + Rb, modulo \(2^{64}\). |
21 | SUB Rd, Ra, Rb | 4 | Rd = Ra − Rb, modulo \(2^{64}\). |
22 | AND Rd, Ra, Rb | 4 | Bitwise AND. |
23 | OR Rd, Ra, Rb | 4 | Bitwise OR. |
24 | XOR Rd, Ra, Rb | 4 | Bitwise exclusive OR. |
25 | MUL Rd, Ra, Rb | 4 | Low 64 bits of the product. |
26 | SHL Rd, Rs, imm8 | 4 | Logical left shift by imm8 & 63. |
27 | SHR Rd, Rs, imm8 | 4 | Logical right shift by imm8 & 63. |
The first six use this encoding:
opcode, destination, source_a, source_b
The shifts use:
opcode, destination, source, shift_immediate
Arithmetic wraps without setting flags or raising an integer-overflow exception. MUL is specified as the low half of an unsigned product; the low 64-bit result also matches two’s-complement signed multiplication.
Both shifts introduce zero bits. SHR is not an arithmetic, sign-preserving right shift. Shift counts are masked to six bits, so a count of 64 becomes zero.
There are no immediate forms of ADD, SUB, or the bitwise operations. A constant must first be placed in a register:
MOVI R2, 1
ADD R1, R1, R2
Memory access — 8 instructions
All memory instructions are five bytes long and use a base register plus a signed 16-bit byte displacement:\[ \text{address} = R_\text{base} + \operatorname{signExtend}(\text{disp16}) \]
The displacement range is −32,768 through +32,767 bytes.
| Opcode | Instruction | Access width | Operation |
|---|---|---|---|
30 | LD64 Rd, [Rb+disp16] | 64 bits | Load a complete 64-bit value. |
31 | ST64 Rs, [Rb+disp16] | 64 bits | Store a complete 64-bit value. |
32 | LD8U Rd, [Rb+disp16] | 8 bits | Load a byte and zero-extend to 64 bits. |
33 | ST8 Rs, [Rb+disp16] | 8 bits | Store the low 8 bits of Rs. |
34 | LD16U Rd, [Rb+disp16] | 16 bits | Load and zero-extend to 64 bits. |
35 | ST16 Rs, [Rb+disp16] | 16 bits | Store the low 16 bits of Rs. |
36 | LD32U Rd, [Rb+disp16] | 32 bits | Load and zero-extend to 64 bits. |
37 | ST32 Rs, [Rb+disp16] | 32 bits | Store the low 32 bits of Rs. |
Their binary layout is:
opcode, data_register, base_register, displacement16
Natural alignment is required:
| Width | Required address alignment |
|---|---|
| 8 bits | 1 byte |
| 16 bits | 2 bytes |
| 32 bits | 4 bytes |
| 64 bits | 8 bytes |
For example:
LD64 R3, [R10+16]
LD8U R4, [R10+1]
ST32 R5, [R10+8]
The assembler also accepts memory-first store syntax, such as ST32 [R10+8], R5.
There are no signed narrow-load instructions, indexed/scaled addressing modes, auto-increment addressing, or direct memory-to-memory moves. More elaborate address calculations use ordinary register arithmetic.
Control flow — 5 instructions
| Opcode | Instruction | Bytes | Operation |
|---|---|---|---|
40 | JMP rel32 | 5 | Unconditional PC-relative jump. |
41 | BRZ Rs, rel16 | 4 | Branch if the full 64-bit source register equals zero. |
42 | BRNZ Rs, rel16 | 4 | Branch if the source register is nonzero. |
43 | CALL rel32 | 5 | Save the following instruction’s address in R31, then branch. |
44 | RET | 1 | Set PC to R31. |
All relative offsets are measured from the first byte after the instruction:
target = instruction_address + instruction_length + signed_offset
JMP and CALL have signed 32-bit byte displacements; BRZ and BRNZ have signed 16-bit byte displacements.
There is no CMP instruction or condition-code register. Equality can be tested by subtracting or XORing two values and branching on the result:
XOR R3, R1, R2
BRZ R3, equal
CALL does not push a return address onto the stack. Nested functions must preserve R31 explicitly; the initial C compiler does this for functions containing calls.
The current ISA has no dedicated general-register indirect jump or indirect call. RET provides register-directed control transfer specifically through R31.
An assembler detail matters here: a symbolic operand such as CALL function resolves to a target address, but a numeric operand such as JMP 16 is interpreted as a relative displacement, not an absolute address.
System and privilege instructions — 6 instructions
| Opcode | Instruction | Bytes | Operation |
|---|---|---|---|
50 | SVC | 1 | Enter the Supervisor exception handler. |
51 | ERET | 1 | Return from an exception using saved status and PC. |
52 | WFI | 1 | Advance PC and wait for an interrupt. |
53 | MFSR Rd, csr8 | 3 | Read a system register into a GPR. |
54 | MTSR csr8, Rs | 3 | Write a GPR value to a system register. |
55 | TLBINV | 1 | Invalidate all cached address translations. |
ERET, MFSR, MTSR, and TLBINV are Supervisor-only. The current emulator does not impose a Supervisor-only check on WFI.
SVC has no immediate syscall-number operand. Selecting a service and passing arguments are responsibilities of the operating-system ABI.
On exception entry, the processor:
- Saves
STATUSinESTATUS. - Exchanges
R30andKSPif entering from User mode. - Records the return/restart address in
EPCand exception information inCAUSEandBADADDR. - Clears the User and interrupt-enable bits.
- Transfers execution to
EVEC.
For SVC, EPC points to the next instruction. ERET restores STATUS from ESTATUS, returns to EPC, and reverses the stack exchange when returning to User mode.
WFI allows device and timer activity to continue while the core is idle. An enabled pending interrupt wakes it.
TLBINV currently flushes the entire TLB. Writing PTBR or ASID does not implicitly flush it.
System-register map
The CSR selector is one byte, with these ten selectors implemented:
| ID | Name | Meaning and behavior |
|---|---|---|
0 | STATUS | Current interrupt-enable, MMU-enable, and privilege bits. |
1 | EVEC | Exception-handler entry address. |
2 | EPC | Exception return/restart address. |
3 | CAUSE | Exception or interrupt cause. |
4 | BADADDR | Address associated with a fault. |
5 | PTBR | Physical page-table root address; low 12 bits are cleared on write. |
6 | ASID | Address-space identifier used to tag translations. |
7 | KSP | Stack-exchange register for User/Supervisor transitions. |
8 | ESTATUS | Saved status restored by ERET. |
9 | TICKS | Reference emulator cycle counter; writes are ignored. |
STATUS and ESTATUS use:
| Bit | Meaning |
|---|---|
0 | Interrupt enable |
1 | MMU enable |
2 | User mode |
Other bits are discarded on writes in the current implementation. Unsupported CSR selectors raise an illegal-instruction exception.
The assembler currently expects numeric CSR selectors:
MFSR R1, 0
MTSR 5, R2
TLBINV
Execution and debugging — 3 instructions
| Opcode | Instruction | Bytes | Operation |
|---|---|---|---|
00 | NOP | 1 | No operation. |
01 | HALT | 1 | Stop the core; Supervisor-only. |
FF | BREAK | 1 | Debugger breakpoint operation. |
In the reference emulator, BREAK sets the breakpoint indicator and halts execution. Although the ISA document describes it as a breakpoint trap, it does not currently enter the guest exception handler.
512-bit VLIW packet format
Packetization adds a container and scheduling metadata, not another set of arithmetic instructions.
Every packet is exactly 64 bytes, starts at a 64-byte-aligned address, and contains an eight-byte header followed by up to 56 bytes of instruction payload.
| Byte offset | Contents |
|---|---|
0 | Packet marker F0 |
1, bits 3–0 | Format number; currently 0 |
1, bits 7–4 | Number of active slots minus one |
2 | Stop mask: bit n places a stop after slot n |
3 | Flags; must currently be zero |
4 | Slot 0 length in low nibble; slot 1 length in high nibble |
5 | Slot 2 and slot 3 lengths |
6 | Slot 4 and slot 5 lengths |
7 | Slot 6 and slot 7 lengths |
8–63 | Scalar instructions followed by zero padding |
A packet contains one through eight instructions. The sum of their lengths must not exceed 56 bytes. Nested packets are illegal.
Stop bits divide the packet into issue groups. Every instruction within a group reads the register values present at the beginning of that group. Register results become visible at the group boundary. The last active slot always ends a group.
For example:
.packet
ADD R5, R1, R2
XOR R6, R3, R4
.stop
MUL R7, R5, R6
.endpacket
The ADD and XOR can execute independently. The stop makes their results available to MUL.
Without that stop, MUL would read the old values of R5 and R6. Two instructions in the same group may not write the same GPR.
Packetization does not guarantee eight operations per cycle. An implementation may execute a group serially or in parallel, provided it preserves the group’s architectural semantics.
Current packet eligibility
| Instruction family | v0.13 reference emulator |
|---|---|
NOP, MOV, MOVI | Supported |
| All eight arithmetic/logic instructions | Supported |
LD64, LD8U, LD16U, LD32U | Supported |
ST64 | Supported |
ST8, ST16, ST32 | Rejected during packet execution |
| Jumps, conditional branches, calls, returns | Prohibited |
| All six system instructions | Prohibited |
HALT, BREAK | Prohibited |
There are two material implementation gaps:
- Narrow stores: the assembler can encode them inside packets, but the emulator rejects them.
- Memory ordering and exceptions: the specification calls for slot-ordered memory behavior and precise slot-order retirement. The emulator instead evaluates a group and defers its stores until the group ends. It therefore does not fully implement same-group store-to-load forwarding or the specified precise restart behavior.
For current programs, potentially aliasing memory operations should be placed in separate groups. Packet exception handling still needs development before treating it as a complete production implementation.
Address translation and exceptions
Version 0.13 retains the same instruction opcodes while expanding the MMU to cover the full 64-bit virtual address space.
| Property | v0.13 definition |
|---|---|
| Virtual address width | 64 bits |
| Architectural physical address width | 64 bits |
| Page size | 4 KiB |
| Page-table levels | Six |
| Address decomposition | 7/9/9/9/9/9 index bits, then 12 offset bits |
| Canonical-address restriction | None |
| Reference TLB | 64 entries, ASID-tagged |
| Unimplemented physical destinations | Fault rather than truncate the address |
The defined exception causes are:
| Cause | Meaning |
|---|---|
1 | Supervisor call |
2 | Illegal instruction |
3 | Alignment fault |
4 | Instruction-fetch page fault |
5 | Load page fault |
6 | Store page fault |
7 | Privilege fault |
8 | Bus fault |
0x100 + irq_line | Hardware interrupt |
Device access uses memory-mapped I/O; there are no separate IN or OUT instructions.
Instructions not yet defined
The current instruction set does not include division/remainder, high-half multiplication, carry/borrow arithmetic, arithmetic right shift, register-count shifts, rotates, signed narrow loads, ordered comparisons, conditional moves, dedicated stack operations, atomic read-modify-write operations, memory fences, floating point, SIMD, cryptographic instructions, or matrix operations.
The ISA reserves opcode range 80–EF and packet formats 1–15 for future expansion, but those reservations are not implemented extensions. Likewise, AURORA’s hardware-integrity goals do not yet introduce any additional instructions into this 32-opcode ISA.

Leave a Reply