Thumb VM AiChip - rosco-pc/propeller-wiki GitHub Wiki

A Thumb-Style VM Implementation for the Propeller Chip

Thumb VM Implementation - Aichip Industries Version - 0.01

All Thumb VM opcodes are 16-bit sized, an 8-bit opcode and an 8-bit operand, or an 8-bit opcode and 24-bit operand for branches and branches to subroutine. The Thumb VM can support up to 32MB of code space.

The Thumb VM provides 256 long registers ($00-$FF) for Thumb VM program use. These are mapped to Cog registers $100-$1FF giving 240 usable registers plus access to the 16 special purpose and hardware registers of the cog. Registers can be used for run-time data or be pre-loaded with long constants.

Most opcodes take the form 'oooooooo rrrrrrrr' where 'o' is an opcode, an 8-bit index into a Cog lookup table ( $0xx-$0FF ), which specifies the native Propeller opcode to execute, and 'r' is an 8-bit register or immediate value to use with that opcode.

The opcode lookup table contains native Propeller opcodes to use but stored in a modified way to indicate how the 'r' should be used. The lower 8 bits of the source register field are used as the address of a handler within the Thumb VM interpreter to create the correct native opcode to use. Note that this means there must be precise knowledge of the VM layout by the Assembler. It is envisaged that an Assembler would generate a .binary or .eeprom which contains the Spin code to launch the VM, the VM itself plus the VM object code and VM opcode lookup table and register initialisation sequences.

There are a number of types of opcode processing which can be applied -

Source Register The bottom 8-bits of the native opcode source register are replaced by the 8-bit 'r' value. This facilitates normal 'mov' from source register and immediate loads. This is used for implementing "mov d,r" and "mov d,#r" VM instructions, where 'd' is defined within the Native Opcode lookup.

Source Indirect As per Source Register but the 'r' value specifies the register whose contents are used as the effective address of the register used in the native instruction. This indirection avoids the need for self-modifying code. This is used for implementing "mov d,[r]" VM instructions where 'd' is defined within the Native Opcode lookup.

Destination Register The bottom 8-bits of the native opcode destination register are moved to the bottom 8-bits of the native source register and the bottom 8-bits of the native opcode destination register are replaced by the 8-bit 'r' value. This facilitates normal 'mov' into destination registers. This is used for implementing "mov r,s" and "mov r,#k" VM instructions where 's' or 'k' are defined within the Native Opcode lookup.

Destination Indirect As per Destination Register but the 'r' value specifies the register whose contents are used as the effective address of the register used in the native instruction. This indirection avoids the need for self-modifying code. This is used for implementing "mov [r],s" and "mov [r],#k" VM instructions where 's' or 'k' are defined within the Native Opcode lookup.

In addition, the opcode types include types for branch (BRA), branch to subroutine (BSR), and return from subroutine (RTS). The actual opcode held in the native opcode lookup table is irrelevant save for the type indicator.

The BRA and BSR VM opcodes have the format 'oooooooo aaaaaaaa aaaaaaaa aaaaaaaa' with the 24-bit address 'a' added to the current pc as a two's complement number. This makes VM code position independent.

The RTS VM opcode has the format 'ooooooo rrrrrrrr'. When the return address is popped the 'r' value is added to it. This allows execution to continue immediately after the BSR or some instruction later. This is convenient for BSR calls which need to behave differently depending upon result -

bsr #TestNumber bra #LessThanZero bra #Zero bra #GreaterThanZero

An Indirect Branch 'bra r' is supported with opcode 'oooooooo rrrrrrrr'. This will cause a branch to the pc which is held within the register 'r'.

The Cog contains a 'hardware stack' to save having to modify hub memory. This is used for subroutine calls but it is possible that VM opcodes can be mapped to native opcodes to manipulate the stack.

Because BRA, BSR and RTS do not actually use any native opcode, a mechanism has to be found to provide conditional execution. This is achieved by creating a VM opcode which maps to the inverse condition to allow execution and adds 2 or 4 to the PC to skip the following instruction. Such VM opcodes will have the format 'oooooooo 00000010' or 'oooooooo 00000100' and will be mapped to native opcode lookup table type 'source register'. The looked-up native opcode will represent 'IF_X add pc,#r'

⚠️ **GitHub.com Fallback** ⚠️