======Vircon32 ASM Reference Guide====== This document is based on Vircon32 DevTools **v24.02.04**; older versions will contain inconsistencies. ^ Token ^ Value | | VirconVersion | 1 | | VirconRevision | 0 | | FramesPerSecond | 60 | | CyclesPerSecond | 15000000 | | CyclesPerFrame | CyclesPerSecond / FramesPerSecond | | ScreenWidth | 640 | | ScreenHeight | 360 | | ScreenPixels | ScreenWidth * ScreenHeight | | GPUTextureSize | 1024 | | GPUMaximumCartridgeTextures | 256 | | GPURegionsPerTexture | 4096 | | GPUPixelCapacityPerFrame | 9 * ScreenPixels | | GPUClearScreenPenalty | -0.50f | | GPUScalingPenalty | +0.15f | | GPURotationPenalty | +0.25f | | SPUMaximumCartridgeSounds | 1024 | | SPUMaximumCartridgeSamples | 1024 * 1024 * 256 | | SPUMaximumBiosSamples | 1024 * 1024 * 1 | | SPUSoundChannels | 16 | | SPUSamplingRate | 44100 | | SPUSamplesPerFrame | SPUSamplingRate / FramesPerSecond | | MaximumCartridgeProgramROM | 1024 * 1024 * 128 | | MaximumBiosProgramROM | 1024 * 1024 * 1 | | RAMSize | 1024 * 1024 * 4 | | MemoryCardSize | 1024 * 256 | | MemoryBusSlaves | 4 | | ControlBusSlaves | 8 | | GamepadPorts | 4 | =====Assembler Data Directives (ROM)===== ^ keyword ^ description | | integer | specify one or more integers | | float | specify one or more floats | | string | specify string sequence(s?) | | pointer | specify pointer(s?) | | datafile | specify datafile(s?) | Use commas to separate values (create "array" of values) =====Vircon32 Instruction Set===== ^ control ^ branch ^ compare ^ data ^ convert ^ logic ^ int arithmetic ^ float arithmetic ^ float math | | [[#HLT|HLT]] | [[#JMP|JMP]] | [[#IEQ|IEQ]] | [[#MOV|MOV]] | [[#CIF|CIF]] | [[#NOT|NOT]] | [[#IADD|IADD]] | [[#FADD|FADD]] | [[#FLR|FLR]] | | [[#WAIT|WAIT]] | [[#CALL|CALL]] | [[#INE|INE]] | [[#LEA|LEA]] | [[#CFI|CFI]] | [[#AND|AND]] | [[#ISUB|ISUB]] | [[#FSUB|FSUB]] | [[#CEIL|CEIL]] | | | [[#RET|RET]] | [[#IGT|IGT]] | [[#PUSH|PUSH]] | [[#CIB|CIB]] | [[#OR|OR]] | [[#IMUL|IMUL]] | [[#FMUL|FMUL]] | [[#ROUND|ROUND]] | | | [[#JT|JT]] | [[#IGE|IGE]] | [[#POP|POP]] | [[#CFB|CFB]] | [[#XOR|XOR]] | [[#IDIV|IDIV]] | [[#FDIV|FDIV]] | [[#SIN|SIN]] | | | [[#JF|JF]] | [[#ILT|ILT]] | [[#IN|IN]] | | [[#BNOT|BNOT]] | [[#IMOD|IMOD]] | [[#FMOD|FMOD]] | [[#ACOS|ACOS]] | | | | [[#ILE|ILE]] | [[#OUT|OUT]] | | [[#SHL|SHL]] | [[#ISGN|ISGN]] | [[#FSGN|FSGN]] | [[#ATAN2|ATAN2]] | | | | [[#FEQ|FEQ]] | [[#MOVS|MOVS]] | | | [[#IMIN|IMIN]] | [[#FMIN|FMIN]] | [[#LOG|LOG]] | | | | [[#FNE|FNE]] | [[#SETS|SETS]] | | | [[#IMAX|IMAX]] | [[#FMAX|FMAX]] | [[#POW|POW]] | | | | [[#FGT|FGT]] | [[#CMPS|CMPS]] | | | [[#IABS|IABS]] | [[#FABS|FABS]] | | | | | [[#FGE|FGE]] | | | | | | | | | | [[#FLT|FLT]] | | | | | | | | | | [[#FLE|FLE]] | | | | | | | =====Vircon32 Memory Map===== ^ Name ^ Address/Range ^ Description | | RAMFirstAddress | 0x00000000-0x003FFFFF | read/write memory (16MB) | | stack init address | 0x003FFFFF | default location of SP (last RAM address) | | BiosProgramROMFirstAddress | 0x10000000 | Vircon32 BIOS | | CartridgeProgramROMFirstAddress | 0x20000000 | Cartridge Data | | MemoryCardRAMFirstAddress | 0x30000000 | Memory Card Data | =====Vircon32 I/O Port Layout===== ^ Port Address ^ Vircon32 ID ^ Description | | 0x000 | [[#TIME|TIM_FirstPort]] | time related functionality | | 0x100 | [[#RNG|RNG_FirstPort]] | random number generator | | 0x200 | [[#GPU|GPU_FirstPort]] | graphics | | 0x300 | [[#SPU|SPU_FirstPort]] | sound processing | | 0x400 | [[#INPUT|INP_FirstPort]] | input (game controllers) | | 0x500 | [[#CARTRIDGE|CAR_FirstPort]] | cartridge interface | | 0x600 | [[#MEMCARD|MEM_FirstPort]] | memory card | =====IOPorts===== ====TIME==== ^ Type ^ Port ^ Name ^ Description | | IN | 0x000 | TIM_CurrentDate | retrieve current date | | IN | 0x001 | TIM_CurrentTime | retrieve current time | | IN | 0x002 | TIM_FrameCounter | retrieve current frame count | | IN | 0x003 | TIM_CycleCounter | retrieve current cycle count | ===example: get current frame count=== in R0, TIM_FrameCounter ; load current frame count into R0 ====RNG==== ^ Type ^ Port ^ Name ^ Description | | IN | 0x100 | RNG_CurrentValue | obtain pseudorandom value | | OUT | 0x100 | RNG_CurrentValue | Seed random number generator | ====GPU==== ^ Type ^ Port ^ Name ^ Description | | OUT | 0x200 | GPU_Command | perform GPU operation | | ??? | 0x201 | GPU_RemainingPixels | ??? | | OUT | 0x202 | GPU_ClearColor | color to clear the screen with | | ??? | 0x203 | GPU_MultiplyColor | ??? | | ??? | 0x204 | GPU_ActiveBlending | ??? | | OUT | 0x204 | GPU_SelectedTexture | texture ID to select (-1 for BIOS) | | OUT | 0x205 | GPU_SelectedRegion | region ID to select | | OUT | 0x206 | GPU_DrawingPointX | set X position to draw selected region | | OUT | 0x207 | GPU_DrawingPointY | set Y position to draw selected region | | ??? | 0x208 | GPU_DrawingScaleX | sets X scaling with a float as input | | ??? | 0x209 | GPU_DrawingScaleY | sets Y scaling with a float as input | | ??? | 0x20A | GPU_DrawingAngle | ??? | | OUT | 0x20B | GPU_RegionMinX | set Min X coordinate for region | | OUT | 0x20C | GPU_RegionMinY | set Min Y coordinate for region | | OUT | 0x20D | GPU_RegionMaxX | set Max X coordinate for region | | OUT | 0x20E | GPU_RegionMaxY | set Max Y coordinate for region | | OUT | 0x20F | GPU_RegionHotspotX | set region Hotspot X coordinate | | OUT | 0x210 | GPU_RegionHotspotY | set region Hotspot Y coordinate | ===GPU Commands=== Commands that can be issued to the GPU: ^ value ^ name ^ description | | 0x10 | GPUCommand_ClearScreen | clears the screen using current clear color | | 0x11 | GPUCommand_DrawRegion | draws the selected region: Rotation off, Zoom off | | 0x12 | GPUCommand_DrawRegionZoomed | draws the selected region: Rotation off, Zoom on | | 0x13 | GPUCommand_DrawRegionRotated | draws the selected region: Rotation on , Zoom off | | 0x14 | GPUCommand_DrawRegionRotozoomed | draws the selected region: Rotation on , Zoom on | ===GPU Active Blending Port Commands=== Active blending: ^ value ^ name ^ description | | 0x20 | GPUBlendingMode_Alpha | default rendering, uses alpha channel as transparency | | 0x21 | GPUBlendingMode_Add | colors are added (light effect), also called linear dodge | | 0x22 | GPUBlendingMode_Subtract | colors are subtracted (shadow effect), also called difference | ====SPU==== ^ Type ^ Port ^ Name ^ Description | | ??? | 0x300 | SPU_Command | ??? | | ??? | 0x301 | SPU_GlobalVolume | ??? | | OUT | 0x302 | SPU_SelectedSound | ??? | | OUT | 0x303 | SPU_SelectedChannel | ??? | | ??? | 0x304 | SPU_SoundLength | ??? | | ??? | 0x305 | SPU_SoundPlayWithLoop | ??? | | ??? | 0x306 | SPU_SoundLoopStart | ??? | | ??? | 0x307 | SPU_SoundLoopEnd | ??? | | ??? | 0x308 | SPU_ChannelState | ??? | | ??? | 0x309 | SPU_ChannelAssignedSound | ??? | | ??? | 0x30A | SPU_ChannelVolume | ??? | | ??? | 0x30B | SPU_ChannelSpeed | ??? | | ??? | 0x30C | SPU_ChannelLoopEnabled | ??? | | ??? | 0x30D | SPU_ChannelPosition | ??? | ===SPU Commands=== Commands for the SPU: ^ value ^ name ^ description | | 0x30 | SPUCommand_PlaySelectedChannel | if paused, it is resumed; if already playing, it is retriggered | | 0x31 | SPUCommand_PauseSelectedChannel | no effect if the channel was not playing | | 0x32 | SPUCommand_StopSelectedChannel | position is rewinded to sound start | | 0x33 | SPUCommand_PauseAllChannels | same as applying PauseChannel to all channels | | 0x34 | SPUCommand_ResumeAllChannels | same as applying PlayChannel to all paused channels | | 0x35 | SPUCommand_StopAllChannels | same as applying StopChannel to all channels | ===SPU Channel States=== States of the sound channels: ^ value ^ name ^ description | | 0x40 | SPUChannelState_Stopped | channel is not playing, and will begin new reproduction on play | | 0x41 | SPUChannelState_Paused | channel is paused, and will resume reproduction on play | | 0x42 | SPUChannelState_Playing | channel is currently playing, until its assigned sound ends | ====INPUT==== ^ Type ^ Port ^ Name ^ Description | | IN | 0x400 | INP_SelectedGamepad | Which gamepad is selected (0-3) | | OUT | 0x400 | INP_SelectedGamepad | Select indicated gamepad (0-3) | | ??? | 0x401 | INP_GamepadConnected | ??? | | IN | 0x402 | INP_GamepadLeft | Left Key input | | IN | 0x403 | INP_GamepadRight | Right Key input | | IN | 0x404 | INP_GamepadUp | Up key input | | IN | 0x405 | INP_GamepadDown | Down key input | | IN | 0x406 | INP_GamepadButtonStart | Enter key input | | IN | 0x407 | INP_GamepadButtonA | X key input | | IN | 0x408 | INP_GamepadButtonB | Z key input | | IN | 0x409 | INP_GamepadButtonX | S key input | | IN | 0x40A | INP_GamepadButtonY | A key input | | IN | 0x40B | INP_GamepadButtonL | Q key input | | IN | 0x40C | INP_GamepadButtonR | W key input | ====CARTRIDGE==== ^ Type ^ Port ^ Name ^ Description | | IN? | 0x500 | CAR_Connected | status of cartridge being connected | | IN? | 0x501 | CAR_ProgramROMSize | size of program ROM | | IN? | 0x502 | CAR_NumberOfTextures | number of cartridge textures | | IN? | 0x503 | CAR_NumberOfSounds | number of cartridge sounds | ====MEMCARD==== ^ Type ^ Port ^ Name ^ Description | | IN? | 0x600 | MEM_Connected | status of memory card being connected | =====Instructions===== There are 64 CPU opcodes, so instructions encode them in 6 bits. No invalid opcodes can exist. HLT is opcode 0 for safety: if an empty or invalid instruction is found, the CPU will stop execution. ^ opcode ^ mneumonic ^ category ^ description | | 0x00 | [[#HLT|HLT]] | control | halt processing | | 0x01 | [[#WAIT|WAIT]] | control | pause processing, wait for next frame | | 0x02 | [[#JMP|JMP]] | branch | unconditional jump to address | | 0x03 | [[#CALL|CALL]] | branch | call subroutine | | 0x04 | [[#RET|RET]] | branch | return from subroutine | | 0x05 | [[#JT|JT]] | branch | jump if true (1) | | 0x06 | [[#JF|JF]] | branch | jump if false (0) | | 0x07 | [[#IEQ|IEQ]] | compare | integer equal | | 0x08 | [[#INE|INE]] | compare | integer not equal | | 0x09 | [[#IGT|IGT]] | compare | integer greater than | | 0x0A | [[#IGE|IGE]] | compare | integer greater than or equal | | 0x0B | [[#ILT|ILT]] | compare | integer less than | | 0x0C | [[#ILE|ILE]] | compare | integer less than or equal | ====HLT==== ====WAIT==== ====JMP==== Unconditional jump. Forcibly redirect program flow to indicated address. The address is somewhere else in the program logic, likely identified by some set label. ===Structure and variants=== * Variant 1: JMP { ImmediateValue } * Variant 2: JMP { Register1 } ===Processing actions=== * Variant 1: InstructionPointer = ImmediateValue * Variant 2: InstructionPointer = Register1 ===Description=== JMP performs an unconditional jump to the address specified by its operand. After processing this instruction the CPU will continue execution at the new address. ===Examples=== Jumping to a label (memory address/offset): jmp _label ... _label: Jumping to address stored in register: jmp R0 ====CALL==== ====RET==== ====JT==== Jump if True: a conditional jump typically used following a comparison instruction, should the queried register contain a true (1) value, jump to indicated address. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 ===Structure and variants=== * Variant 1: JT { Register1 }, { ImmediateValue } * Variant 2: JT { Register1 }, { Register2 } ===Effect=== * Variant 1: if Register1 != 0 then InstructionPointer = ImmediateValue * Variant 2: if Register1 != 0 then InstructionPointer = Register2 ===Description=== JT performs a jump only if its first operand is true, i.e. non zero when taken as an integer. In that case its behavior is the same as an unconditional jump. Otherwise it has no effect. ====JF==== Jump if False: a conditional jump typically used following a comparison instruction, should the queried register contain a false (0) value, jump to indicated address. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 ===Structure and variants=== * Variant 1: JF { Register1 }, { ImmediateValue } * Variant 2: JF { Register1 }, { Register2 } ===Effect=== * Variant 1: if Register1 == 0 then InstructionPointer = ImmediateValue * Variant 2: if Register1 == 0 then InstructionPointer = Register2 ===Description=== JF performs a jump only if its first operand is false, i.e. zero when taken as an integer. In that case its behavior is the same as an unconditional jump. Otherwise it has no effect. ====IEQ==== Integer Compare Equality: comparisons allow us typically to evaluate two values, in accordance with some relational operation, resulting in a true (1) or false (0) result. Should the first operand contain the same information as the second operand, the result will be true. Otherwise, false. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 There are six relational operations: * is equal to * is not equal to * is less than * is than or equal to * is greater than * is greater than or equal to ===Structure and variants=== * Variant 1: IEQ { Register1 }, { ImmediateValue } * Variant 2: IEQ { Register1 }, { Register2 } ===Processing actions=== * Variant 1: if Register1 == ImmediateValue then Register1 = 1 else Register1 = 0 * Variant 2: if Register1 == Register2 then Register1 = 1 else Register1 = 0 ===Description=== IEQ takes two operands interpreted as integers, and checks if they are equal. It will store the boolean result in the first operand, which is always a register. ====INE==== Integer Not Equal: comparisons allow us typically to evaluate two values, in accordance with some relational operation, resulting in a true (1) or false (0) result. Here, we test to see if the first operand is not equal to the second operand. If they are equal, the result is false, otherwise, not being equal yields a result of true. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 There are six relational operations: * is equal to * is not equal to * is less than * is than or equal to * is greater than * is greater than or equal to ===Structure and variants=== * Variant 1: INE { Register1 }, { ImmediateValue } * Variant 2: INE { Register1 }, { Register2 } ===Processing actions=== * Variant 1: if Register1 != ImmediateValue then Register1 = 1 else Register1 = 0 * Variant 2: if Register1 != Register2 then Register1 = 1 else Register1 = 0 ===Description=== INE takes two operands interpreted as integers, and checks if they are different. It will store the boolean result in the first operand, which is always a register. ====IGT==== Integer Greater Than: comparisons allow us typically to evaluate two values, in accordance with some relational operation, resulting in a true (1) or false (0) result. In this case, we are testing if the first operand is greater than the second operand. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 There are six relational operations: * is equal to * is not equal to * is less than * is than or equal to * is greater than * is greater than or equal to ===Structure and variants=== * Variant 1: IGT { Register1 }, { ImmediateValue } * Variant 2: IGT { Register1 }, { Register2 } ===Processing actions=== * Variant 1: if Register1 > ImmediateValue then Register1 = 1 else Register1 = 0 * Variant 2: if Register1 > Register2 then Register1 = 1 else Register1 = 0 ===Description=== IGT takes two operands interpreted as integers, and checks if the first one is greater than the second. It will store the boolean result in the first operand, which is always a register. ====IGE==== Integer Greater Than Or Equal: comparisons allow us typically to evaluate two values, in accordance with some relational operation, resulting in a true (1) or false (0) result. In this case, we are testing if the first operand is greater than or equal to the second operand. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 There are six relational operations: * is equal to * is not equal to * is less than * is than or equal to * is greater than * is greater than or equal to ===Structure and variants=== * Variant 1: IGE { Register1 }, { ImmediateValue } * Variant 2: IGE { Register1 }, { Register2 } ===Processing actions=== * Variant 1: if Register1 >= ImmediateValue then Register1 = 1 else Register1 = 0 * Variant 2: if Register1 >= Register2 then Register1 = 1 else Register1 = 0 ===Description=== IGE takes two operands interpreted as integers, and checks if the first one is greater or equal to the second. It will store the boolean result in the first operand, which is always a register. ====ILT==== Integer Less Than: comparisons allow us typically to evaluate two values, in accordance with some relational operation, resulting in a true (1) or false (0) result. In this case, we are testing if the first operand is less than the second operand. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 There are six relational operations: * is equal to * is not equal to * is less than * is than or equal to * is greater than * is greater than or equal to ===Structure and variants=== * Variant 1: ILT { Register1 }, { ImmediateValue } * Variant 2: ILT { Register1 }, { Register2 } ===Processing actions=== * Variant 1: if Register1 < ImmediateValue then Register1 = 1 else Register1 = 0 * Variant 2: if Register1 < Register2 then Register1 = 1 else Register1 = 0 ===Description=== ILT takes two operands interpreted as integers, and checks if the first one is less than the second. It will store the boolean result in the first operand, which is always a register. ====ILE==== Integer Less Than Or Equal: comparisons allow us typically to evaluate two values, in accordance with some relational operation, resulting in a true (1) or false (0) result. In this case, we are testing if the first operand is less than or equal to the second operand. ===NOTE=== For the purposes of comparisons and conditional jumps on Vircon32: * true is 1 (technically non-zero) * false is 0 There are six relational operations: * is equal to * is not equal to * is less than * is than or equal to * is greater than * is greater than or equal to ===Structure and variants=== * Variant 1: ILE { Register1 }, { ImmediateValue } * Variant 2: ILE { Register1 }, { Register2 } ===Processing actions=== * Variant 1: if Register1 <= ImmediateValue then Register1 = 1 else Register1 = 0 * Variant 2: if Register1 <= Register2 then Register1 = 1 else Register1 = 0 ===Description=== ILE takes two operands interpreted as integers, and checks if the first one is less or equal to the second. It will store the boolean result in the first operand, which is always a register. ====FEQ==== ====FNE==== ====FGT==== ====FGE==== ====FLT==== ====FLE==== ====MOV==== MOVE: your general purpose data-copying instruction. ===Addressing=== MOVE, like other data-centric instructions, makes use of various addressing modes: * **register**: source/destination is an inbuilt CPU register * **immediate**: some literal constant (be it data or a memory address) * **indirect**: value isn't the data, but a memory address to where the data is. Think pointer dereference. It comes in 3 varieties: * **indexed**: an offset to some existing piece of data. * **immediate**: a literal constant (data or memory address) * **indexed**: used with immediate/register, but we can do additional math to get an offset from the address. Think pointer dereference on an array. * **register**: a CPU register Indirect processing is accomplished with the **[ ]** (square brackets) surrounding the value we wish to dereference (we're not interested in the direct thing, but indirectly in what that thing contains). ===Structure and variants=== * Variant 1: MOV { Register1 }, { ImmediateValue } * Variant 2: MOV { Register1 }, { Register2 } * Variant 3: MOV { Register1 }, [ { ImmediateValue } ] * Variant 4: MOV { Register1 }, [ { Register2 } ] * Variant 5: MOV { Register1 }, [ { Register2 } + { ImmediateValue } ] * Variant 6: MOV [ { ImmediateValue } ], { Register2 } * Variant 7: MOV [ { Register1 } ], { Register2 } * Variant 8: MOV [ { Register1 } + { ImmediateValue } ], { Register2 } ===Processing actions=== ==Register Destination== * Immediate: Register1 = ImmediateValue * Register: Register1 = Register2 * Indirect with Immediate reference: Register1 = Memory[ImmediateValue] * Indirect with Register reference: Register1 = Memory[Register2] * Indirect Indexed with Register: Register1 = Memory[Register2 + ImmediateValue] ==Memory Destination== * Indirect with Immediate reference: Memory[ImmediateValue] = Register2 * Indirect with Register reference: Memory[Register1] = Register2 * Indirect with Indexed reference: Memory[Register1 + ImmediateValue] = Register2 ===Description=== MOV copies the value indicated in its second operand into the register or memory address indicated by its first operand. MOV is the most complex instruction to process because it needs to distinguish between 8 different addressing modes. The instruction specifies which of the 8 modes to use in its “Addressing mode” field, being the possible values interpreted as follows: ==MOV Addressing modes== ^ Binary ^ Destination ^ Source | | 000 | Register 1 | Immediate Value | | 001 | Register 1 | Register 2 | | 010 | Register 1 | Memory [Immediate Value] | | 011 | Register 1 | Memory [Register 2] | | 100 | Register 1 | Memory [Register 2 + Immediate Value] | | 101 | Memory[Immediate Value] | Register 2 | | 110 | Memory[Register 1] | Register 2 | | 111 | Memory[Register 1 + Immediate Value] | Register 2 | ====LEA==== Load Effective Address of a memory position. ===Addressing=== MOVE, like other data-centric instructions, makes use of various addressing modes: * **register**: source/destination is an inbuilt CPU register * **immediate**: some literal constant (be it data or a memory address) * **indirect**: value isn't the data, but a memory address to where the data is. Think pointer dereference. It comes in 3 varieties: * **indexed**: an offset to some existing piece of data. * **immediate**: a literal constant (data or memory address) * **indexed**: used with immediate/register, but we can do additional math to get an offset from the address. Think pointer dereference on an array. * **register**: a CPU register Indirect processing is accomplished with the **[ ]** (square brackets) surrounding the value we wish to dereference (we're not interested in the direct thing, but indirectly in what that thing contains). ===Structure and variants=== * Variant 1: LEA { Register1 }, [ { Register2 } ] * Variant 2: LEA { Register1 }, [ { Register2 } + { ImmediateValue } ] ===Processing actions=== * Register: Register1 = Register2 * Indexed: Register1 = Register2 + ImmediateValue ===Description=== LEA takes a memory address as second operand. It stores that address (not its contents) into the register given as first operand. The most useful case is when the address is given in the form pointer + offset, since the addition is automatically performed. ====PUSH==== Save to top of stack ===Structure and variants=== * PUSH { Register1 } ===Processing actions=== * Stack.Push(Register1) ===Description=== PUSH uses the CPU hardware stack to add the value contained in the given register at the top of the stack. When you PUSH a value onto the stack, the STACK POINTER (SP) is adjusted downward by one address offset (stack grows down). ====POP==== Load from top of stack ===Structure and variants=== * POP { Register1 } ===Processing actions=== * Register1 = Stack.Pop() ===Description=== POP uses the CPU hardware stack to remove a value from the top of the stack and write it in the given register. When you POP a value off the stack, the STACK POINTER (SP) is adjusted upward by one address offset (stack grows down, shrinks up). IN, // Read from an I/O port OUT, // Write to an I/O port // string operations MOVS, // Copy string (HW memcpy) SETS, // Set string (HW memset) CMPS, // Compare string (HW memcmp) // data conversion CIF, // Convert Integer to Float CFI, // Convert Float to Integer CIB, // Convert Integer to Boolean CFB, // Convert Float to Boolean // binary operations NOT, // Bitwise NOT AND, // Bitwise AND OR, // Bitwise OR XOR, // Bitwise XOR BNOT, // Boolean NOT SHL, // Bit shift left // integer arithmetic IADD, // Integer Addition ISUB, // Integer Subtraction IMUL, // Integer Multiplication IDIV, // Integer Division IMOD, // Integer Modulus ISGN, // Integer Sign change IMIN, // Integer Minimum IMAX, // Integer Maximum IABS, // Integer Absolute value // float arithmetic FADD, // Float Addition FSUB, // Float Subtraction FMUL, // Float Multiplication FDIV, // Float Division FMOD, // Float Modulus FSGN, // Float Sign change FMIN, // Float Minimum FMAX, // Float Maximum FABS, // Float Absolute value // extended float operations FLR, // Round down CEIL, // Round up ROUND, // Round to nearest integer SIN, // Sine ACOS, // Arc cosine ATAN2, // Arc Tangent from x and y LOG, // Natural logarithm POW // Raise to a Power }; // ----------------------------------------------------------------------------- enum class CPURegisters: int { // all 16 general-purpose registers Register00 = 0, Register01, Register02, Register03, Register04, Register05, Register06, Register07, Register08, Register09, Register10, Register11, Register12, Register13, Register14, Register15, // alternate names for specific registers CountRegister = 11, SourceRegister = 12, DestinationRegister = 13, BasePointer = 14, StackPointer = 15 }; // ----------------------------------------------------------------------------- enum class AddressingModes : unsigned int { RegisterFromImmediate = 0, // syntax: MOV R1, 25 RegisterFromRegister, // syntax: MOV R1, R2 RegisterFromImmediateAddress, // syntax: MOV R1, [25] RegisterFromRegisterAddress, // syntax: MOV R1, [R2] RegisterFromAddressOffset, // syntax: MOV R1, [R2+25] ImmediateAddressFromRegister, // syntax: MOV [25], R2 RegisterAddressFromRegister, // syntax: MOV [R1], R2 AddressOffsetFromRegister // syntax: MOV [R1+25], R2 }; // ----------------------------------------------------------------------------- enum class CPUErrorCodes: uint32_t { InvalidMemoryRead = 0, InvalidMemoryWrite, InvalidPortRead, InvalidPortWrite, StackOverflow, StackUnderflow, DivisionError, ArcCosineError, ArcTangent2Error, LogarithmError, PowerError }; }