Skip to content

A new implementation of the Maize Virtual CPU in C++ on CMake. This will target both Windows and Linux. It is MUCH, MUCH faster than the initial .NET version.

Notifications You must be signed in to change notification settings

paulmooreparks/Maize

Repository files navigation

The Maize Virtual Machine

This project implements a 64-bit virtual machine called "Maize." This is an outgrowth of my Tortilla project, which began life as an x86 emulator implemented in C# on .NET and then later became a virtual CPU of my own making.

The near-term goal for the Maize project is to implement a set of devices to bridge from the virtual environment to the host machine, create a "BIOS" layer above the virtual devices, and implement a simple OS and a subset of Unix/Linux system calls (interrupt $80),

What It Is, Basically

  • A 64-bit virtual machine implemented in C++ that executes a custom byte code
  • An assembly language that represents the byte code
  • An assembler implemented in C++ that generates byte code from the assembly language
  • A very simple BIOS and OS that bridges the VM and the underlying machine
  • An execution environment implemented in C++ that so far runs on Windows and Linux and could easily be ported to other platforms

Yeah, but... WHY?

It's a long story.

In 2016 I had a contract working on an ARM system, and I wasn't too familiar with ARM assembly. I had an idea to write an ARM emulator, since I've always believed that the best way to understand a system is to try to build one. After getting stuck with the ARM emulator, I decided to first build an x86 emulator and then go back to ARM. While I knew x86 assembly well enough to debug it, I wasn't really an expert at it, and I didn't know the lowest levels of machine language. I thought that tackling an ISA I knew would help me get the basics sorted out, and I'd come back to ARM later.

I got the x86 emulator working well enough to run code generated by standard compilers, but by then I wasn't working on ARM anymore, and I was more interested in learning about how CPUs work. I also found Ben Eater's Youtube! channel, where he builds an 8-bit computer from scratch, and I decided to use those as guidance for building a virtual CPU of my own design. The first implementation of that was the Tortilla project.

With Tortilla, I wrote code for every single cycle of each instruction, as if the CPU were moving data around the buses like a physical CPU. That was fun and enlightening, but it was also terribly inefficient. I decided to rewrite the entire thing in C++ and make the virtual machine more of a byte-code execution environment rather than a simulation of a CPU, and that became the Maize project. The idea is to be able to compile any language to Maize byte code and run it on any system that can run the Maize VM.

No, I never got back around to the ARM emulator, and at this point I doubt I will.

Uses for Maize

Honestly, it's mainly a toy to learn about a few concepts:

  • How byte-code virtual machines work
  • The construction of an assembly language and corresponding assemblers and disassemblers
  • Porting compiler back-ends to a new architecture
  • Learning how to write an OS and BIOS for a new architecture
  • Learning how systems integrate with hardware.

It's been really useful for all of the above, but what I'm most excited about is the promise of compiling any language to Maize byte code and running it anywhere that can run the Maize VM.

How To Use Maize

Maize is implemented in standard C++ and will run on Windows and Linux. The primary executable is maize, which accepts a path to a binary file to execute. You may generate a binary from Maize assembly with the mazm executable, which accepts a path to an assembly file and outputs a BIN file that can then be executed with maize.

I haven't finished porting all of the instructions from the .NET implementation yet, but now that I've finished restructuring the code it shouldn't take too long to complete them.

The assembler is still VERY bare-bones, but it's enough to generate usable executables.

Project Status

As I said in the original .NET implementation, it's very early days for Maize, so don't expect too much in the way of application usability... yet! I'm still porting the basic text-mode console for input and output. Next, I'll start creating a file-system device. I am currently porting QBE to output Maize assembly so that I can write Maize binaries with standard C and eventually port Linux to the virtual CPU.

In the short term, I'm implementing a very basic OS over a simple BIOS (core.asm). It will provide a basic character-mode CLI to allow building and running simple Maize programs from within the virtual CPU environment.

So far, this implementation in C++ is MUCH faster and MUCH tighter than the .NET version.

The near-term road map is as follows:

  • Finish implementing all of the instructions documented below (in progress)
  • Add a Maize back end to CProc and build Maize BIOS & OS in standard C (in progress)
  • Implement a linker so that binaries can be built independently and linked together
  • Introduce "devices," which were partially implemented in the .NET version
  • Clean up the assembler (mazm) and introduce some proper error checking
  • Make the assembler read Unicode source files
  • Implement floating-point arithmetic
  • Add a Maize backend to GCC and port GNU tools to Maize.

Hello, World!

Here is a simple "Hello, World!" application written in Maize assembly.

; **********************************************************************************
; The entry point. Execution begins at segment $00000000, address $00000000

$0000`0000:             ; The back-tick (`)  is used as a number separator. 
                        ; Underscore (_) and comma (,) may also be used as separators.
    CALL main
    HALT                ; For now, HALT exits the Maize interpreter, but in the 
                        ; future it will pause the CPU and wait for an interrupt.

; **********************************************************************************
; The output message

hw_string:
    STRING "Hello, world!\0"

; **********************************************************************************
; Return the length of a zero-terminated string. Equivalent to the following C code:
;
;   int strlen(char const *str) {
;       int len = 0;
;       while (str[len]) {
;           ++len;
;       }
;       return len;
;   }
;
; Parameters:
;   R0.H0: Address of string
; Return: 
;   RV: Length of string

strlen:
    PUSH BP                 ; Save the base pointer
    CP SP BP                ; Copy the stack pointer to the base pointer
    SUB $04 SP              ; Make room for a 32-bit (4-byte) counter on the stack
    LEA $-04 BP RT.H0       ; Load the address of the counter's stack location into RT.H0
    ST $00 @RT.H0           ; Set the counter to zero.
loop_condition:
    LEA @RT.H0 R0.H0 R1.H0  ; Add the counter value to the address and put the result into H.H0.
    LD @R1.H0 R1.B4         ; Load the character value at the address in R1.H0 into R1.B4.
    JZ loop_exit            ; LD sets the zero flag if the value copied to R1.B4 is zero.
loop_body:
    LD @RT.H0 RT.H1         ; Load the counter value at the address in RT.H0 into RT.H1
    INC RT.H1               ; Add 1 to the temporary
    ST RT.H1 @RT.H0         ; Store the new value back into the counter's address
    JMP loop_condition      ; ...and continue the loop.
loop_exit:
    LD @RT.H0 RV            ; Load the (sign-extended) counter value into RV, the return register.
    CP BP SP                ; Restore the stack
    POP BP                  ; Restore the base pointer
    RET                     ; Pop return address from stack and place into PC.

; **********************************************************************************
; The main function

main:
    CP hw_string R0.H0      ; Copy the address of the message string into R0.H0
    CALL strlen             ; Call strlen function to get the string length
    CP $01 R0               ; $01 in R0 indicates output to stdout
    CP hw_string R1.H0      ; R1.H0 holds address of message to output
    CP RV R2                ; Put the string length into R2
    SYS $01                 ; Call output function implemented in Maize VM
    CP $0 RV                ; Set return value for main
    RET                     ; Leave main

Instruction Description

Numeric values are represented in Maize assembly and Maize documentation in binary, decimal, or hexadecimal formats. The % character precedes binary-encoded values, the # character precedes decimal-encoded values, and the $ character precedes hexadecimal-encoded values.

%00000001   binary value
#123        decimal value
$FFFE1000   hexadecimal value

The underscore, back-tick (`) and comma (,) characters may all be used as numeric separators in all encodings.

Examples:

%0000`0001
%1001_1100
#123,456,789
$0000_FFFF
$FE,DC,BA,98
$1234`5678
#123,456_789`021

Instructions are variable-length encoded and may have zero, one, or two parameters. An instruction opcode is encoded as a single eight-bit byte defining the opcode and instruction flags, and each instruction parameter is defined in an additional byte per parameter. Immediate values are encoded following the opcode and parameter bytes in little-endian format (least-significant bytes are stored lower in memory).

When an instruction has two parameters, the first parameter is the source parameter, and the second parameter is the destination parameter.

Example: Copy the immediate value $01 into register R0.

CP $01 R0

Example: Encoding of "CP $FFCC4411 R3", which copies the immediate value $FFCC4411 into register R3. $41 is the opcode and flags for the instruction which copies an immediate value into a register. $02 is the parameter byte specifying a four-byte immediate value as the source parameter. $3E is the parameter byte specifying the 64-bit register R3 as the destination parameter. The bytes following the parameters bytes are the immediate value in little-endian format.

$41 $02 $3E $11 $44 $CC $FF

Immediate values may used as pointers into memory. This is represented in assembly by the '@' prefix in front of the immediate value.

Example: Copy the 64-bit value at address $0000`1000 into register R1.

CP @$0000`1000 R1

Register values may be used as pointers into memory by adding a '@' prefix in front of the register name.

Example: Store the value $FF into the byte pointed at by the R0.H0 register:

ST $FF @R0.H0

Example: Load the quarter-word located at the address stored in R3.H0 into sub-register RT.Q3:

LD @R3.H0 RT.Q3

Registers

Registers are 64-bits wide (a "word") and are each divided into smaller sub-registers.

R0  General purpose
R1  General purpose
R2  General purpose
R3  General purpose
R4  General purpose
R5  General purpose
R6  General purpose
R7  General purpose
R8  General purpose
R9  General purpose

RT  Temporary register
RV  Return-value register

RF  Flag register
RI  Instruction register
RP  Program execution register
RS  Stack register

Sub-registers

Sub-registers are defined as half-word (H), quarter-word (Q), and byte (B) widths. The full 64-bit value of a register (for example, register R0) may be coded as "R0" or "R0.W0". The register value may also be accessed as separate half-word (32-bit) values, coded as R0.H1 (upper 32 bits) and R0.H0 (lower 32-bits). The 16-bit quarter-words are similarly coded as R0.Q3, R0.Q2, R0.Q1, and R0.Q0. Finally, the individual byte values are coded as R0.B7, R0.B6, R0.B5, R0.B4, R0.B3, R0.B2, R0.B1, and R0.B0.

Shown graphically, the 64-bit value $FEDCBA9876543210 would be stored as follows:

 FE  DC  BA  98  76  54  32  10
[B7][B6][B5][B4][B3][B2][B2][B0]
[Q3    ][Q2    ][Q1    ][Q0    ]
[H1            ][H0            ]
[W0                            ]

In other words, if the following instruction were executed:

CP $FEDCBA9876543210 R0

The value stored in register R0 could then be represented as follows:

R0    = $FEDCBA9876543210
R0.W0 = $FEDCBA9876543210
R0.H1 = $FEDCBA98
R0.H0 = $76543210
R0.Q3 = $FEDC
R0.Q2 = $BA98
R0.Q1 = $7654
R0.Q0 = $3210
R0.B7 = $FE
R0.B6 = $DC
R0.B5 = $BA
R0.B4 = $98
R0.B3 = $76
R0.B2 = $54
R0.B1 = $32
R0.B0 = $10

Special-purpose Registers

There are six special-purpose registers.

RT Temporary register. This is used as temporary storage in a function.

RV Return-value register. Return values from functions are placed into this register.

RF Flags register. FL is an alias for RF.H0, which contains a bit field of individual flags. 
   Flags in RF.H1 may only be set in privileged mode.

RI Instruction register, set by the instruction decoder as instructions and parameters are
   read from memory. This register can only be set by the decoder.

RP Program execution register, which is the pointer to the next instruction to be decoded
   and executed. This is further sub-divided into RP.H1, which is the current code segment,
   and RP.H0, which is the effective program counter within the current segment. RP.H1 may
   only be written to in privileged mode. PC is an alias for RP.H0.

RS Stack register, which is the location within the current segment at which the stack
   starts (growing downward in memory). This is further sub-divided into RS.H1, which is
   the base pointer, and RS.H0, which is the current stack pointer. SP is an alias for RS.H0, 
   and BP is an alias for RS.H1.

Flags

(more coming on this)

Execution

The CPU starts in privileged mode, and the program counter is initially set to segment $00000000, address $00000000. When in privileged mode, the privilege flag is set, and instructions marked as privileged may be executed. When the privilege flag is cleared, instruction execution and memory access are limited to the current segment, and certain flags, registers, and instructions are inaccessible. Program execution may return to privileged mode via hardware interrupts or via software-generated (INT instruction) interrupts.

Opcode Bytes

Opcodes are defined in an 8-bit byte separated into two flag bits and six opcode bits.

%BBxx`xxxx  Flags bit field (bits 6 and 7)
%xxBB`BBBB  Opcode bit field (bits 0 through 5)

When an instruction has a source parameter that may be either a register or an immediate value, then bit 6 is interpreted as follows:

%x0xx`xxxx  source parameter is a register
%x1xx`xxxx  source parameter is an immediate value

When an instruction's source parameter may be either a value or a pointer to a value, then bit 7 is interpreted as follows:

%0xxx`xxxx  source parameter is a value
%1xxx`xxxx  source parameter is a memory address

Instructions

Binary      Hex   Mnemonic  Parameters      Description
----------  ---   --------  ----------      --------------------------------------------------------------------------------------------------------------------------------------
%0000`0000  $00   HALT                      Halt the clock, thereby stopping execution (privileged)

%0000`0001  $01   CP        regVal  reg     Copy source register value into destination register
%0100`0001  $41   CP        immVal  reg     Copy immediate value into destination register

%1000`0001  $81   LD        regAddr reg     Load value at address in source register into destination register
%1100`0001  $C1   LD        immAddr reg     Load value at immediate address into destination register

%0000`0010  $02   ST        regVal  regAddr Store source register value at address in second register
%0100`0010  $42   ST        immVal  regAddr Store immediate value at address in destination register

%0000`0011  $03   ADD       regVal  reg     Add source register value to destination register
%0100`0011  $43   ADD       immVal  reg     Add immediate value to destination register
%1000`0011  $83   ADD       regAddr reg     Add value at address in source register to destination register
%1100`0011  $C3   ADD       immAddr reg     Add value at immediate address to destination register

%0000`0100  $04   SUB       regVal  reg     Subtract source register value from destination register
%0100`0100  $44   SUB       immVal  reg     Subtract immediate value from destination register
%1000`0100  $84   SUB       regAddr reg     Subtract value at address in source register from destination register
%1100`0100  $C4   SUB       immAddr reg     Subtract value at immediate address from destination register

%0000`0101  $05   MUL       regVal  reg     Multiply destination register by source register value
%0100`0101  $45   MUL       immVal  reg     Multiply destination register by immediate value
%1000`0101  $85   MUL       regAddr reg     Multiply destination register by value at address in source register
%1100`0101  $C5   MUL       immAddr reg     Multiply destination register by value at immediate address

%0000`0110  $06   DIV       regVal  reg     Divide destination register by source register value
%0100`0110  $46   DIV       immVal  reg     Divide destination register by immediate value
%1000`0110  $86   DIV       regAddr reg     Divide destination register by value at address in source register
%1100`0110  $C6   DIV       immAddr reg     Divide destination register by value at immediate address

%0000`0111  $07   MOD       regVal  reg     Modulo destination register by source register value
%0100`0111  $47   MOD       immVal  reg     Modulo destination register by immediate value
%1000`0111  $87   MOD       regAddr reg     Modulo destination register by value at address in source register
%1100`0111  $C7   MOD       immAddr reg     Modulo destination register by value at immediate address

%0000`1000  $08   AND       regVal  reg     Bitwise AND destination register with source register value
%0100`1000  $48   AND       immVal  reg     Bitwise AND destination register with immediate value
%1000`1000  $88   AND       regAddr reg     Bitwise AND destination register with value at address in source register
%1100`1000  $C8   AND       immAddr reg     Bitwise AND destination register with value at immediate address

%0000`1001  $09   OR        regVal  reg     Bitwise OR destination register with source register value
%0100`1001  $49   OR        immVal  reg     Bitwise OR destination register with immediate value
%1000`1001  $89   OR        regAddr reg     Bitwise OR destination register with value at address in source register
%1100`1001  $C9   OR        immAddr reg     Bitwise OR destination register with value at immediate address

%0000`1010  $0A   NOR       regVal  reg     Bitwise NOR destination register with source register value
%0100`1010  $4A   NOR       immVal  reg     Bitwise NOR destination register with immediate value
%1000`1010  $8A   NOR       regAddr reg     Bitwise NOR destination register with value at address in source register
%1100`1010  $CA   NOR       immAddr reg     Bitwise NOR destination register with value at immediate address

%0000`1011  $0B   NAND      regVal  reg     Bitwise NAND destination register with source register value
%0100`1011  $4B   NAND      immVal  reg     Bitwise NAND destination register with immediate value
%1000`1011  $8B   NAND      regAddr reg     Bitwise NAND destination register with value at address in source register
%1100`1011  $CB   NAND      immAddr reg     Bitwise NAND destination register with value at immediate address

%0000`1100  $0C   XOR       regVal  reg     Bitwise XOR destination register with source register value
%0100`1100  $4C   XOR       immVal  reg     Bitwise XOR destination register with immediate value
%1000`1100  $8C   XOR       regAddr reg     Bitwise XOR destination register with value at address in source register
%1100`1100  $CC   XOR       immAddr reg     Bitwise XOR destination register with value at immediate address

%0000`1101  $0D   SHL       regVal  reg     Shift value in destination register left by value in source register
%0100`1101  $4D   SHL       immVal  reg     Shift value in destination register left by immediate value
%1000`1101  $8D   SHL       regAddr reg     Shift value in destination register left by value at address in source register
%1100`1101  $CD   SHL       immAddr reg     Shift value in destination register left by value at immediate address

%0000`1110  $0E   SHR       regVal  reg     Shift value in destination register right by value in source register
%0100`1110  $4E   SHR       immVal  reg     Shift value in destination register right by immediate value
%1000`1110  $8E   SHR       regAddr reg     Shift value in destination register right by value at address in source register
%1100`1110  $CE   SHR       immAddr reg     Shift value in destination register right by value at immediate address

%0000`1111  $0F   CMP       regVal  reg     Set flags by subtracting source register value from destination register
%0100`1111  $4F   CMP       immVal  reg     Set flags by subtracting immediate value from destination register
%1000`1111  $8F   CMP       regAddr reg     Set flags by subtracting value at address in source register from destination register
%1100`1111  $CF   CMP       immAddr reg     Set flags by subtracting value at immediate address from destination register

%0001`0000  $10   TEST      regVal  reg     Set flags by ANDing source register value with destination register
%0101`0000  $50   TEST      immVal  reg     Set flags by ANDing immediate value with destination register
%1001`0000  $90   TEST      regAddr reg     Set flags by ANDing value at address in source register with destination register
%1101`0000  $D0   TEST      immAddr reg     Set flags by ANDing value at immediate address with destination register

%0001`0001  $11   CMPXCHG   regVal  reg reg Compare value in operand 2 with value in operand 3. If equal, set zero flag and copy value in operand 1 register into operand 2. Otherwise, clear zero flag and copy value in operand 2 into operand 3.
%0101`0001  $51   CMPXCHG   immVal  reg reg Compare value in operand 2 with value in operand 3. If equal, set zero flag and copy value in operand 1 immediate value into operand 2. Otherwise, clear zero flag and copy value in operand 2 into operand 3.
%1001`0001  $91   CMPXCHG   regAddr reg reg Compare value in operand 2 with value in operand 3. If equal, set zero flag and load value at address in operand 1 register into operand 2. Otherwise, clear zero flag and load value in operand 2 into operand 3.
%1101`0001  $D1   CMPXCHG   immAddr reg reg Compare value in operand 2 with value in operand 3. If equal, set zero flag and load value at address in operand 1 immediate value into operand 2. Otherwise, clear zero flag and load value in operand 2 into operand 3.

%0001`0010  $12   LEA       regVal  reg reg Add register value in operand 1 to value in operand 2 register and store result in operand 3 register
%0101`0010  $52   LEA       immVal  reg reg Add immediate value in operand 1 to value in operand 2 register and store result in operand 3 register
%1001`0010  $92   LEA       regAddr reg reg Add value at address in operand 1 register to value in operand 2 register and store result in operand 3 register
%1101`0010  $D2   LEA       immAddr reg reg Add value at immediate address in operand 1 to value in operand 2 register and store result in operand 3 register

%0001`0011  $13   CPZ       regVal  reg     Copy source register value into destination register with zero extension
%0101`0011  $53   CPZ       immVal  reg     Copy immediate value into destination register with zero extension

%1001`0011  $93   LDZ       regAddr reg     Load value at address in source register into destination register with zero extension
%1101`0011  $D3   LDZ       immAddr reg     Load value at immediate address into destination register with zero extension

%0001`0100  $14   OUT       regVal  imm     Output value in source register to destination port
%0101`0100  $54   OUT       immVal  imm     Output immediate value to destination port
%1001`0100  $94   OUT       regAddr imm     Output value at address in source register to destination port
%1101`0100  $D4   OUT       immAddr imm     Output value at immediate address to destination port

%0001`0101  $15   LNGJMP    regVal          Jump to segment and address in source register and continue execution (privileged)
%0101`0101  $55   LNGJMP    immVal          Jump to immediate segment and address and continue execution (privileged)
%1001`0101  $95   LNGJMP    regAddr         Jump to segment and address pointed to by source register and continue execution (privileged)
%1101`0101  $D5   LNGJMP    immAddr         Jump to segment and address pointed to by immediate value and continue execution (privileged)

%0001`0110  $16   JMP       regVal          Jump to address in source register and continue execution
%0101`0110  $56   JMP       immVal          Jump to immediate address and continue execution
%1001`0110  $96   JMP       regAddr         Jump to address pointed to by source register and continue execution
%1101`0110  $D6   JMP       immAddr         Jump to address pointed to by immediate value and continue execution

%0001`0111  $17   JZ        regVal          If Zero flag is set, jump to address in source register and continue execution
%0101`0111  $57   JZ        immVal          If Zero flag is set, jump to immediate address and continue execution
%1001`0111  $97   JZ        regAddr         If Zero flag is set, jump to address pointed to by source register and continue execution
%1101`0111  $D7   JZ        immAddr         If Zero flag is set, jump to address pointed to by immediate value and continue execution

%0001`1000  $18   JNZ       regVal          If Zero flag is not set, jump to address in source register and continue execution
%0101`1000  $58   JNZ       immVal          If Zero flag is not set, jump to immediate address and continue execution
%1001`1000  $98   JNZ       regAddr         If Zero flag is not set, jump to address pointed to by source register and continue execution
%1101`1000  $D8   JNZ       immAddr         If Zero flag is not set, jump to address pointed to by immediate value and continue execution

%0001`1001  $19   JLT       regVal          If Negative flag is not equal to Overflow flag, jump to address in source register and continue execution
%0101`1001  $59   JLT       immVal          If Negative flag is not equal to Overflow flag, jump to immediate address and continue execution
%1001`1001  $99   JLT       regAddr         If Negative flag is not equal to Overflow flag, jump to address pointed to by source register and continue execution
%1101`1001  $D9   JLT       immAddr         If Negative flag is not equal to Overflow flag, jump to address pointed to by immediate value and continue execution

%0001`1010  $1A   JB        reg             If Carry flag is set, jump to address in source register and continue execution
%0101`1010  $5A   JB        imm             If Carry flag is set, jump to immediate address and continue execution
%1001`1010  $9A   JB        regAddr         If Carry flag is set, jump to address pointed to by source register and continue execution
%1101`1010  $DA   JB        immAddr         If Carry flag is set, jump to address pointed to by immediate value and continue execution

%0001`1011  $1B   JGT       regVal          If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to address in source register and continue execution
%0101`1011  $5B   JGT       immVal          If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to immediate address and continue execution
%1001`1011  $9B   JGT       regAddr         If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to address pointed to by source register and continue execution
%1101`1011  $DB   JGT       immAddr         If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to address pointed to by immediate value and continue execution

%0001`1100  $1C   JA        regVal          If Carry flag is clear and Zero flag is clear, jump to address in source register and continue execution
%0101`1100  $5C   JA        immVal          If Carry flag is clear and Zero flag is clear, jump to immediate address and continue execution
%1001`1100  $9C   JA        regAddr         If Carry flag is clear and Zero flag is clear, jump to address pointed to by source register and continue execution
%1101`1100  $DC   JA        immAddr         If Carry flag is clear and Zero flag is clear, jump to address pointed to by immediate value and continue execution

%0001`1101  $1D   CALL      regVal          Push PC.H0 to stack, jump to address in source register and continue execution until RET is executed
%0101`1101  $5D   CALL      immVal          Push PC.H0 to stack, jump to immediate address and continue execution until RET is executed
%1001`1101  $9D   CALL      regAddr         Push PC.H0 to stack, jump to address pointed to by source register and continue execution until RET is executed
%1101`1101  $DD   CALL      immAddr         Push PC.H0 to stack, jump to address pointed to by immediate value and continue execution until RET is executed

%0001`1110  $1E   OUTR      regVal  reg     Output value in source register to port in destination register
%0101`1110  $5E   OUTR      immVal  reg     Output immediate value to port in destination register
%1001`1110  $9E   OUTR      regAddr reg     Output value at address in source register to port in destination register
%1101`1110  $DE   OUTR      immAddr reg     Output value at immediate address to port in destination register

%0001`1111  $1F   IN        regVal  reg     Read value from port in source register into destination register
%0101`1111  $5F   IN        immVal  reg     Read value from port in immediate value into destination register
%1001`1111  $9F   IN        regAddr reg     Read value from port at address in source register into destination register
%1101`1111  $DF   IN        immAddr reg     Read value from port at immediate address into destination register

%0010`0000  $20   PUSH      regVal          Copy register value into memory at location in RS.H0, decrement RS.H0 by size of register
%0110`0000  $60   PUSH      immVal          Copy immediate value into memory at location in RS.H0, decrement RS.H0 by size of immediate value

%0010`0010  $22   CLR       regVal          Set register to zero (0).

%0010`0100  $24   INT       regVal          Push FL and PC to stack and generate a software interrupt at index stored in register (privileged)
%0110`0100  $64   INT       immVal          Push FL and PC to stack and generate a software interrupt using immediate index (privileged)

%0010`0110  $26   POP       regVal          Increment SP.H0 by size of register, copy value at SP.H0 into register

%0010`0111  $27   RET                       Pop PC.H0 from stack and continue execution at that address. Used to return from CALL.

%0010`1000  $28   IRET                      Pop FL and PC from stack and continue execution at segment/address in PC. Used to return from interrupt (privileged).

%0010`1001  $29   SETINT                    Set the Interrupt flag, thereby enabling hardware interrupts (privileged)

%0010`1011  $2B                             reserved
%0110`1011  $6B                             reserved   
%1010`1011  $AB                             reserved   
%1110`1011  $EB                             reserved   

%0010`1100  $2C                             reserved
%0110`1100  $6C                             reserved   
%1010`1100  $AC                             reserved   
%1110`1100  $EC                             reserved   

%0010`1101  $2D                             reserved
%0110`1101  $6D                             reserved   
%1010`1101  $AD                             reserved   
%1110`1101  $ED                             reserved   

%0010`1110  $2E                             reserved
%0110`1110  $6E                             reserved   
%1010`1110  $AE                             reserved   
%1110`1110  $EE                             reserved   

%0011`0101  $35                             reserved
%0111`0101  $75                             reserved
%1011`0101  $B5                             reserved
%1111`0101  $F5                             reserved

%0011`0110  $36                             reserved
%0111`0110  $76                             reserved
%1011`0110  $B6                             reserved
%1111`0110  $F6                             reserved

%0011`0111  $37                             reserved
%0111`0111  $77                             reserved
%1011`0111  $B7                             reserved
%1111`0111  $F7                             reserved

%0011`1000  $38                             reserved
%0111`1000  $78                             reserved
%1011`1000  $B8                             reserved
%1111`1000  $F8                             reserved

%0011`1001  $39                             reserved
%0111`1001  $79                             reserved
%1011`1001  $B9                             reserved
%1111`1001  $F9                             reserved

%0011`1010  $3A                             reserved
%0111`1010  $7A                             reserved
%1011`1010  $BA                             reserved
%1111`1010  $FA                             reserved

%0011`1011  $3B                             reserved
%0111`1011  $7B                             reserved
%1011`1011  $BB                             reserved
%1111`1011  $FB                             reserved

%0011`1100  $3C                             reserved
%0111`1100  $7C                             reserved
%1011`1100  $BC                             reserved
%1111`1100  $FC                             reserved

%0011`1101  $3D                             reserved
%0111`1101  $7D                             reserved
%1011`1101  $BD                             reserved
%1111`1101  $FD                             reserved

%0011`1110  $3E                             reserved
%0111`1110  $7E                             reserved
%1011`1110  $BE                             reserved
%1111`1110  $FE                             reserved

%0010`1111  $2F   CMPIND    regVal regAddr  Set flags by subtracting source register value from value at address in destination register
%0110`1111  $6F   CMPIND    immVal regAddr  Set flags by subtracting immediate value from value at address in destination register

%0011`0000  $30   TSTIND    regVal regAddr  Set flags by ANDing source register value with value at address in destination register
%0111`0000  $70   TSTIND    immVal regAddr  Set flags by ANDing immediate value with value at address in destination register

%0011`0001  $31   INC       regVal          Increment register by 1.

%0011`0010  $32   DEC       regVal          Decrement register by 1.

%0011`0011  $33   NOT       regVal          Bitwise negate value in register, store result in register.

%0011`0100  $34   SYS       regVal          Execute a system call using the system-call index stored in register (privileged)
%0111`0100  $74   SYS       immVal          Execute a system call using the immediate index (privileged)

%1010`1010  $AA   NOP                       No operation. Used as an instruction placeholder.

%1110`0000  $E0   XCHG      reg     reg     Atomically exchange the values in two registers

%1110`0001  $E1   SETCRY                    Set the Carry flag

%1110`0010  $E2   CLRCRY                    Clear the Carry flag

%1110`0011  $E3   CLRINT                    Clear the Interrupt flag, thereby disabling hardware interrupts (privileged)

%1110`0100  $E4   DUP                       Duplicate the top value on the stack

%1110`0101  $E5   SWAP                      Swap the top two values on the stack

%1111`1111  $FF   BRK                       Trigger a debug break

Register Parameter

Register bit field

%0000`xxxx  $0   R0 register
%0001`xxxx  $1   R1 register
%0010`xxxx  $2   R2 register
%0011`xxxx  $3   R3 register
%0100`xxxx  $4   R4 register
%0101`xxxx  $5   R5 register
%0110`xxxx  $6   R6 register
%0111`xxxx  $7   R7 register
%1000`xxxx  $8   R8 register
%1001`xxxx  $9   R9 register
%1010`xxxx  $A   RT register
%1011`xxxx  $B   RV register
%1100`xxxx  $C   RF register (flags)
%1101`xxxx  $D   RI register (instruction)
%1110`xxxx  $E   RP register (program segment / counter)
%1111`xxxx  $F   RS register (stack pointers)

Sub-register bit field

%xxxx`0000  $0   X.B0 (1-byte data)
%xxxx`0001  $1   X.B1 (1-byte data)
%xxxx`0010  $2   X.B2 (1-byte data)
%xxxx`0011  $3   X.B3 (1-byte data)
%xxxx`0100  $4   X.B4 (1-byte data)
%xxxx`0101  $5   X.B5 (1-byte data)
%xxxx`0110  $6   X.B6 (1-byte data)
%xxxx`0111  $7   X.B7 (1-byte data)
%xxxx`1000  $8   X.Q0 (2-byte data)
%xxxx`1001  $9   X.Q1 (2-byte data)
%xxxx`1010  $A   X.Q2 (2-byte data)
%xxxx`1011  $B   X.Q3 (2-byte data)
%xxxx`1100  $C   X.H0 (4-byte data)
%xxxx`1101  $D   X.H1 (4-byte data)
%xxxx`1110  $E   X    (8-byte data)

Immediate Parameter

Immediate Operation Bit

%xxxx`0xxx       Read immediate value as operand
%xxxx`1xxx       Perform math operation with value (not implemented yet)

Immediate Value Bit Field

%xxxx`x000  $x0  instruction reads 1 byte immediate (8 bits)
%xxxx`x001  $x1  instruction reads 2-byte immediate (16 bits)
%xxxx`x010  $x2  instruction reads 4-byte immediate (32 bits)
%xxxx`x011  $x3  instruction reads 8-byte immediate (64 bits)

Immediate Math Bit Field

%0000`xxxx  $0x  ADD immediate to previous operand
%0001`xxxx  $1x  SUB immediate from previous operand
%0010`xxxx  $2x  MUL previous operand by immediate
%0011`xxxx  $3x  DIV previous operand by immediate
%0100`xxxx  $4x  AND previous operand with immediate
%0101`xxxx  $5x  OR previous operand with immediate
%0110`xxxx  $6x  XOR previous operand with immediate
%0111`xxxx  $7x  NOR previous operand with immediate
%1000`xxxx  $8x  NAND previous operand with immediate
%1001`xxxx  $9x  SHL previous operand by immediate
%1010`xxxx  $Ax  SHR previous operand by immediate
%1011`xxxx  $Bx  reserved
%1100`xxxx  $Cx  reserved
%1101`xxxx  $Dx  reserved
%1110`xxxx  $Ex  reserved
%1111`xxxx  $Fx  reserved

BIOS Interface

BIOS calls will track as closely as possible to the "standard" BIOS routines found on typical x86 PCs. The x86 registers used in BIOS calls will map to Maize registers as follows:

AX -> R0.Q0
   AL -> R0.B0
   AH -> R0.B1
BX -> R0.Q1
   BL -> R0.B2
   BH -> R0.B3
CX -> R0.Q2
   CL -> R0.B4
   CH -> R0.B5
DX -> R0.Q3
   DL -> R0.B6
   DH -> R0.B7

OS ABI

The first ten arguments to OS-level routines will be placed, from left to right, into the R0, R1, R2, R3, R4, R5, R6, R7, R8, and R9 registers. Any remaining arguments will be pushed onto the stack.

For example:

; Call C function "void random_os_function(int32_t a, const char *b, size_t c, int32_t* d)"
CP $0000`1234 R0            ; int32_t a
CP R9.H0 R1                 ; const char* b, assuming the pointer is in R9.H0
CP $0000`00FF R2            ; size_t c
CP R8.H1 R3                 ; int32_t* d, assuming the pointer is in R8.H1
CALL random_os_function

Return values will placed into the RV register. For example:

; Implement C function "int add(int a, int b)"
CP R0 RV
ADD R1 RV
RET

The same standard will be followed for syscall parameters. The syscall number will be placed into the R9 register prior to calling the interrupt.

; Output a string using sys_write
CP $01 R0               ; file descriptor 1 (STDOUT) in register R0
CP hello_world R1.H0    ; string address in register R1
CP hello_world_end R2
SUB hello_world R2      ; string length in register R2
CP $01 R9               ; syscall 1 = sys_write
INT $80                 ; call sys_write

The same syscall may be made with the SYS instruction, which will execute the syscall directly.

; Output a string using sys_write, calling directly via SYS instruction
CP $01 R0               ; file descriptor 1 (STDOUT) in register G
CP hello_world R1.H0    ; string address in register H
CP hello_world_end R2
SUB hello_world R2      ; string length in register J
SYS $01                 ; call sys_write

Assembler Syntax

(This section is incomplete and a bit of a work in progress. Refer to HelloWorld.asm, stdlib.asm, and core.asm for practical examples.)

%00000001   binary
#123        decimal
$FFFE1000   hexadecimal

Other syntax, to be described more fully later:

LABEL labelName labelData | AUTO

DATA dataValue [dataValue] [dataValue] [...]

STRING "stringvalue"

ADDRESS address | labelName

Opcodes Sorted Numerically

Binary      Hex   Mnemonic  Parameters      Description
----------  ---   --------  ----------      --------------------------------------------------------------------------------------------------------------------------------------
%0000`0000  $00   HALT                      Halt the clock, thereby stopping execution (privileged)
%0000`0001  $01   CP        regVal  reg     Copy source register value into destination register
%0000`0010  $02   ST        regVal  regAddr Store source register value at address in second register
%0000`0011  $03   ADD       regVal  reg     Add source register value to destination register
%0000`0100  $04   SUB       regVal  reg     Subtract source register value from destination register
%0000`0101  $05   MUL       regVal  reg     Multiply destination register by source register value
%0000`0110  $06   DIV       regVal  reg     Divide destination register by source register value
%0000`0111  $07   MOD       regVal  reg     Modulo destination register by source register value
%0000`1000  $08   AND       regVal  reg     Bitwise AND destination register with source register value
%0000`1001  $09   OR        regVal  reg     Bitwise OR destination register with source register value
%0000`1010  $0A   NOR       regVal  reg     Bitwise NOR destination register with source register value
%0000`1011  $0B   NAND      regVal  reg     Bitwise NAND destination register with source register value
%0000`1100  $0C   XOR       regVal  reg     Bitwise XOR destination register with source register value
%0000`1101  $0D   SHL       regVal  reg     Shift value in destination register left by value in source register
%0000`1110  $0E   SHR       regVal  reg     Shift value in destination register right by value in source register
%0000`1111  $0F   CMP       regVal  reg     Set flags by subtracting source register value from destination register
%0001`0000  $10   TEST      regVal  reg     Set flags by ANDing source register value with destination register
%0001`0001  $11   CMPXCHG   regVal  reg     Compare value in operand 2 with value in operand 3. If equal, set zero flag and copy value in operand 1 register into operand 2. Otherwise, clear zero flag and copy value in operand 2 into operand 3.
%0001`0010  $12   LEA       regVal  reg reg 
%0001`0011  $13   CPZ       regVal  reg     Copy source register value into destination register with sign extension
%0001`0100  $14   OUT       regVal  imm     Output value in source register to destination port
%0001`0101  $15   LNGJMP    regVal          Jump to segment and address in source register and continue execution (privileged)
%0001`0110  $16   JMP       regVal          Jump to address in source register and continue execution
%0001`0111  $17   JZ        regVal          If Zero flag is set, jump to address in source register and continue execution
%0001`1000  $18   JNZ       regVal          If Zero flag is not set, jump to address in source register and continue execution
%0001`1001  $19   JLT       regVal          If Negative flag is not equal to Overflow flag, jump to address in source register and continue execution
%0001`1010  $1A   JB        reg             If Carry flag is set, jump to address in source register and continue execution
%0001`1011  $1B   JGT       regVal          If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to address in source register and continue execution
%0001`1100  $1C   JA        regVal          If Carry flag is clear and Zero flag is clear, jump to address in source register and continue execution
%0001`1101  $1D   CALL      regVal          Push PC.H0 to stack, jump to address in source register and continue execution until RET is executed
%0001`1110  $1E   OUTR      regVal  reg     Output value in source register to port in destination register
%0001`1111  $1F   IN        regVal  reg     Read value from port in source register into destination register
%0010`0000  $20   PUSH      regVal          Copy register value into memory at location in RS.H0, decrement RS.H0 by size of register
%0010`0001  $21   
%0010`0010  $22   CLR       regVal          Set register to zero (0).
%0010`0011  $23   
%0010`0100  $24   INT       regVal          Push FL and PC to stack and generate a software interrupt at index stored in register (privileged)
%0010`0101  $25   
%0010`0110  $26   POP       regVal          Increment SP.H0 by size of register, copy value at SP.H0 into register
%0010`0111  $27   RET                       Pop PC.H0 from stack and continue execution at that address. Used to return from CALL.
%0010`1000  $28   IRET                      Pop FL and PC from stack and continue execution at segment/address in PC. Used to return from interrupt (privileged).
%0010`1001  $29   SETINT                    Set the Interrupt flag, thereby enabling hardware interrupts (privileged)
%0010`1010  $2A
%0010`1011  $2B                             reserved
%0010`1100  $2C                             reserved
%0010`1101  $2D                             reserved
%0010`1110  $2E                             reserved
%0010`1111  $2F   CMPIND    regVal regAddr  Set flags by subtracting source register value from value at address in destination register
%0011`0000  $30   TSTIND    regVal regAddr  Set flags by ANDing source register value with value at address in destination register
%0011`0001  $31   INC       regVal          Increment register by 1.
%0011`0010  $32   DEC       regVal          Decrement register by 1.
%0011`0011  $33   NOT       regVal          Bitwise negate value in register, store result in register.
%0011`0100  $34   SYS       regVal          Execute a system call using the system-call index stored in register (privileged)
%0011`0101  $35                             reserved
%0011`0110  $36                             reserved
%0011`0111  $37                             reserved
%0011`1000  $38                             reserved
%0011`1001  $39                             reserved
%0011`1010  $3A                             reserved
%0011`1011  $3B                             reserved
%0011`1100  $3C                             reserved
%0011`1101  $3D                             reserved
%0011`1110  $3E                             reserved
%0011`1111  $3F   
%0100`0000  $40   
%0100`0001  $41   CP        immVal  reg     Copy immediate value into destination register
%0100`0010  $42   ST        immVal  regAddr Store immediate value at address in destination register
%0100`0011  $43   ADD       immVal  reg     Add immediate value to destination register
%0100`0100  $44   SUB       immVal  reg     Subtract immediate value from destination register
%0100`0101  $45   MUL       immVal  reg     Multiply destination register by immediate value
%0100`0110  $46   DIV       immVal  reg     Divide destination register by immediate value
%0100`0111  $47   MOD       immVal  reg     Modulo destination register by immediate value
%0100`1000  $48   AND       immVal  reg     Bitwise AND destination register with immediate value
%0100`1001  $49   OR        immVal  reg     Bitwise OR destination register with immediate value
%0100`1010  $4A   NOR       immVal  reg     Bitwise NOR destination register with immediate value
%0100`1011  $4B   NAND      immVal  reg     Bitwise NAND destination register with immediate value
%0100`1100  $4C   XOR       immVal  reg     Bitwise XOR destination register with immediate value
%0100`1101  $4D   SHL       immVal  reg     Shift value in destination register left by immediate value
%0100`1110  $4E   SHR       immVal  reg     Shift value in destination register right by immediate value
%0100`1111  $4F   CMP       immVal  reg     Set flags by subtracting immediate value from destination register
%0101`0000  $50   TEST      immVal  reg     Set flags by ANDing immediate value with destination register
%0101`0001  $51   CMPXCHG   immVal  reg     Compare value in operand 2 with value in operand 3. If equal, set zero flag and copy value in operand 1 immediate value into operand 2. Otherwise, clear zero flag and copy value in operand 2 into operand 3.
%0101`0010  $52   LEA       immVal  reg reg Add immediate value in operand 1 to value in operand 2 register and store result in operand 3 register
%0101`0011  $53   CPZ       immVal  reg     Copy immediate value into destination register with sign extension
%0101`0100  $54   OUT       immVal  imm     Output immediate value to destination port
%0101`0101  $55   LNGJMP    immVal          Jump to immediate segment and address and continue execution (privileged)
%0101`0110  $56   JMP       immVal          Jump to immediate address and continue execution
%0101`0111  $57   JZ        immVal          If Zero flag is set, jump to immediate address and continue execution
%0101`1000  $58   JNZ       immVal          If Zero flag is not set, jump to immediate address and continue execution
%0101`1001  $59   JLT       immVal          If Negative flag is not equal to Overflow flag, jump to immediate address and continue execution
%0101`1010  $5A   JB        imm             If Carry flag is set, jump to immediate address and continue execution
%0101`1011  $5B   JGT       immVal          If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to immediate address and continue execution
%0101`1100  $5C   JA        immVal          If Carry flag is clear and Zero flag is clear, jump to immediate address and continue execution
%0101`1101  $5D   CALL      immVal          Push PC.H0 to stack, jump to immediate address and continue execution until RET is executed
%0101`1110  $5E   OUTR      immVal  reg     Output immediate value to port in destination register
%0101`1111  $5F   IN        immVal  reg     Read value from port in immediate value into destination register
%0110`0000  $60   PUSH      immVal          Copy immediate value into memory at location in RS.H0, decrement RS.H0 by size of immediate value
%0110`0001  $61   
%0110`0010  $62   
%0110`0011  $63   
%0110`0100  $64   INT       immVal          Push FL and PC to stack and generate a software interrupt using immediate index (privileged)
%0110`0101  $65   
%0110`0110  $66   
%0110`0111  $67   
%0110`1000  $68   
%0110`1001  $69   
%0110`1010  $6A   
%0110`1011  $6B                             reserved
%0110`1100  $6C                             reserved
%0110`1101  $6D                             reserved
%0110`1110  $6E                             reserved
%0110`1111  $6F   CMPIND    immVal regAddr  Set flags by subtracting immediate value from value at address in destination register
%0111`0000  $70   TSTIND    immVal regAddr  Set flags by ANDing immediate value with value at address in destination register
%0111`0001  $71   
%0111`0010  $72   
%0111`0011  $73   
%0111`0100  $74   SYS       immVal          Execute a system call using the immediate index (privileged)
%0111`0101  $75                             reserved
%0111`0110  $76                             reserved
%0111`0111  $77                             reserved
%0111`1000  $78                             reserved
%0111`1001  $79                             reserved
%0111`1010  $7A                             reserved
%0111`1011  $7B                             reserved
%0111`1100  $7C                             reserved
%0111`1101  $7D                             reserved
%0111`1110  $7E                             reserved
%0111`1111  $7F   
%1000`0000  $80   
%1000`0001  $81   LD        regAddr reg     Load value at address in source register into destination register
%1000`0010  $82   
%1000`0011  $83   ADD       regAddr reg     Add value at address in source register to destination register
%1000`0100  $84   SUB       regAddr reg     Subtract value at address in source register from destination register
%1000`0101  $85   MUL       regAddr reg     Multiply destination register by value at address in source register
%1000`0110  $86   DIV       regAddr reg     Divide destination register by value at address in source register
%1000`0111  $87   MOD       regAddr reg     Modulo destination register by value at address in source register
%1000`1000  $88   AND       regAddr reg     Bitwise AND destination register with value at address in source register
%1000`1001  $89   OR        regAddr reg     Bitwise OR destination register with value at address in source register
%1000`1010  $8A   NOR       regAddr reg     Bitwise NOR destination register with value at address in source register
%1000`1011  $8B   NAND      regAddr reg     Bitwise NAND destination register with value at address in source register
%1000`1100  $8C   XOR       regAddr reg     Bitwise XOR destination register with value at address in source register
%1000`1101  $8D   SHL       regAddr reg     Shift value in destination register left by value at address in source register
%1000`1110  $8E   SHR       regAddr reg     Shift value in destination register right by value at address in source register
%1000`1111  $8F   CMP       regAddr reg     Set flags by subtracting value at address in source register from destination register
%1001`0000  $90   TEST      regAddr reg     Set flags by ANDing value at address in source register with destination register
%1001`0001  $91   CMPXCHG   regAddr reg     Compare value in operand 2 with value in operand 3. If equal, set zero flag and load value at address in operand 1 register into operand 2. Otherwise, clear zero flag and load value in operand 2 into operand 3.
%1001`0010  $92   LEA       regAddr reg reg Add value at address in operand 1 register to value in operand 2 register and store result in operand 3 register
%1001`0011  $93   LDZ       regAddr reg     Load value at address in source register into destination register with sign extension
%1001`0100  $94   OUT       regAddr imm     Output value at address in source register to destination port
%1001`0101  $95   LNGJMP    regAddr         Jump to segment and address pointed to by source register and continue execution (privileged)
%1001`0110  $96   JMP       regAddr         Jump to address pointed to by source register and continue execution
%1001`0111  $97   JZ        regAddr         If Zero flag is set, jump to address pointed to by source register and continue execution
%1001`1000  $98   JNZ       regAddr         If Zero flag is not set, jump to address pointed to by source register and continue execution
%1001`1001  $99   JLT       regAddr         If Negative flag is not equal to Overflow flag, jump to address pointed to by source register and continue execution
%1001`1010  $9A   JB        regAddr         If Carry flag is set, jump to address pointed to by source register and continue execution
%1001`1011  $9B   JGT       regAddr         If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to address pointed to by source register and continue execution
%1001`1100  $9C   JA        regAddr         If Carry flag is clear and Zero flag is clear, jump to address pointed to by source register and continue execution
%1001`1101  $9D   CALL      regAddr         Push PC.H0 to stack, jump to address pointed to by source register and continue execution until RET is executed
%1001`1110  $9E   OUTR      regAddr reg     Output value at address in source register to port in destination register
%1001`1111  $9F   IN        regAddr reg     Read value from port at address in source register into destination register
%1010`0000  $A0   
%1010`0001  $A1   
%1010`0010  $A2   
%1010`0011  $A3   
%1010`0100  $A4   
%1010`0101  $A5   
%1010`0110  $A6   
%1010`0111  $A7   
%1010`1000  $A8   
%1010`1001  $A9   
%1010`1010  $AA   NOP                       No operation. Used as an instruction placeholder.
%1010`1011  $AB                             reserved
%1010`1100  $AC                             reserved
%1010`1101  $AD                             reserved
%1010`1110  $AE                             reserved
%1010`1111  $AF   
%1011`0000  $B0   
%1011`0001  $B1   
%1011`0010  $B2   
%1011`0011  $B3   
%1011`0100  $B4   
%1011`0101  $B5                             reserved
%1011`0110  $B6                             reserved
%1011`0111  $B7                             reserved
%1011`1000  $B8                             reserved
%1011`1001  $B9                             reserved
%1011`1010  $BA                             reserved
%1011`1011  $BB                             reserved
%1011`1100  $BC                             reserved
%1011`1101  $BD                             reserved
%1011`1110  $BE                             reserved
%1011`1111  $BF   
%1100`0000  $C0   
%1100`0001  $C1   LD        immAddr reg     Load value at immediate address into destination register
%1100`0010  $C2   
%1100`0011  $C3   ADD       immAddr reg     Add value at immediate address to destination register
%1100`0100  $C4   SUB       immAddr reg     Subtract value at immediate address from destination register
%1100`0101  $C5   MUL       immAddr reg     Multiply destination register by value at immediate address
%1100`0110  $C6   DIV       immAddr reg     Divide destination register by value at immediate address
%1100`0111  $C7   MOD       immAddr reg     Modulo destination register by value at immediate address
%1100`1000  $C8   AND       immAddr reg     Bitwise AND destination register with value at immediate address
%1100`1001  $C9   OR        immAddr reg     Bitwise OR destination register with value at immediate address
%1100`1010  $CA   NOR       immAddr reg     Bitwise NOR destination register with value at immediate address
%1100`1011  $CB   NAND      immAddr reg     Bitwise NAND destination register with value at immediate address
%1100`1100  $CC   XOR       immAddr reg     Bitwise XOR destination register with value at immediate address
%1100`1101  $CD   SHL       immAddr reg     Shift value in destination register left by value at immediate address
%1100`1110  $CE   SHR       immAddr reg     Shift value in destination register right by value at immediate address
%1100`1111  $CF   CMP       immAddr reg     Set flags by subtracting value at immediate address from destination register
%1101`0000  $D0   TEST      immAddr reg     Set flags by ANDing value at immediate address with destination register
%1101`0001  $D1   CMPXCHG   immAddr reg     Compare value in operand 2 with value in operand 3. If equal, set zero flag and load value at address in operand 1 immediate value into operand 2. Otherwise, clear zero flag and load value in operand 2 into operand 3.
%1101`0010  $D2   LEA       immAddr reg reg Add value at immediate address in operand 1 to value in operand 2 register and store result in operand 3 register
%1101`0011  $D3   LDZ       immAddr reg     Load value at immediate address into destination register with sign extension
%1101`0100  $D4   OUT       immAddr imm     Output value at immediate address to destination port
%1101`0101  $D5   LNGJMP    immAddr         Jump to segment and address pointed to by immediate value and continue execution (privileged)
%1101`0110  $D6   JMP       immAddr         Jump to address pointed to by immediate value and continue execution
%1101`0111  $D7   JZ        immAddr         If Zero flag is set, jump to address pointed to by immediate value and continue execution
%1101`1000  $D8   JNZ       immAddr         If Zero flag is not set, jump to address pointed to by immediate value and continue execution
%1101`1001  $D9   JLT       immAddr         If Negative flag is not equal to Overflow flag, jump to address pointed to by immediate value and continue execution
%1101`1010  $DA   JB        immAddr         If Carry flag is set, jump to address pointed to by immediate value and continue execution
%1101`1011  $DB   JGT       immAddr         If Zero flag is clear and Negative flag is not equal to Overflow flag, jump to address pointed to by immediate value and continue execution
%1101`1100  $DC   JA        immAddr         If Carry flag is clear and Zero flag is clear, jump to address pointed to by immediate value and continue execution
%1101`1101  $DD   CALL      immAddr         Push PC.H0 to stack, jump to address pointed to by immediate value and continue execution until RET is executed
%1101`1110  $DE   OUTR      immAddr reg     Output value at immediate address to port in destination register
%1101`1111  $DF   IN        immAddr reg     Read value from port at immediate address into destination register
%1110`0000  $E0   XCHG      reg     reg     Atomically exchange the values in two registers
%1110`0001  $E1   SETCRY                    Set the Carry flag
%1110`0010  $E2   CLRCRY                    Clear the Carry flag
%1110`0011  $E3   CLRINT                    Clear the Interrupt flag, thereby disabling hardware interrupts (privileged)
%1110`0100  $E4   DUP                       Duplicate the top value on the stack
%1110`0101  $E5   SWAP                      Swap the top two values on the stack
%1110`0110  $E6   
%1110`0111  $E7   
%1110`1000  $E8   
%1110`1001  $E9   
%1110`1010  $EA   
%1110`1011  $EB                             reserved
%1110`1100  $EC                             reserved
%1110`1101  $ED                             reserved
%1110`1110  $EE                             reserved
%1110`1111  $EF   
%1111`0000  $F0   
%1111`0001  $F1   
%1111`0010  $F2   
%1111`0011  $F3   
%1111`0100  $F4   
%1111`0101  $F5                             reserved
%1111`0110  $F6                             reserved
%1111`0111  $F7                             reserved
%1111`1000  $F8                             reserved
%1111`1001  $F9                             reserved
%1111`1010  $FA                             reserved
%1111`1011  $FB                             reserved
%1111`1100  $FC                             reserved
%1111`1101  $FD                             reserved
%1111`1110  $FE                             reserved
%1111`1111  $FF   BRK                       Trigger a debug break

About

A new implementation of the Maize Virtual CPU in C++ on CMake. This will target both Windows and Linux. It is MUCH, MUCH faster than the initial .NET version.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages