From 5c9863a44e7fc6d395c3c2f366ec3c72aac92f22 Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Thu, 9 Nov 2023 21:36:34 -0500 Subject: [PATCH] DRAFT: Shady VM early start. --- .../commands/wgsl_library/shady_vm.wgsl | 264 +++++++++++++----- src/gpu/mod.rs | 2 + src/gpu/shady_vm/bytecode_format.rs | 159 +++++++++++ src/gpu/shady_vm/instruction.rs | 138 +++++++++ src/gpu/shady_vm/mod.rs | 3 + 5 files changed, 494 insertions(+), 72 deletions(-) create mode 100644 src/gpu/shady_vm/bytecode_format.rs create mode 100644 src/gpu/shady_vm/instruction.rs create mode 100644 src/gpu/shady_vm/mod.rs diff --git a/src/gpu/compute/commands/wgsl_library/shady_vm.wgsl b/src/gpu/compute/commands/wgsl_library/shady_vm.wgsl index 6020843..37de535 100644 --- a/src/gpu/compute/commands/wgsl_library/shady_vm.wgsl +++ b/src/gpu/compute/commands/wgsl_library/shady_vm.wgsl @@ -7,15 +7,17 @@ * * ``` * Register file: - * r0-r31: 32 x 32-bit registers + * r0-r29: 30 x 32-bit registers, read-write general purpose + * r30: 1 x 32-bit register, read-only, always zero * r32-r79: 48 x 32-bit registers, only usable as source operands - * r80-r95: UNUSED + * r80-r96: UNUSED * * Special registers: - * r96: program counter - * r97: flags register - * r98: call stack depth - * r99-123: UNUSED + * r112: program counter + * r113: flags register + * r114: call stack depth + * r115: error code + * r116-123: UNUSED * * r124: call-stack register 3 * r125: call-stack register 2 @@ -92,7 +94,7 @@ * - 0 => all flags must be set, 1 => any flag must be set * * KK (2 bits) * - branch kind - * - 00 => goto, 01 => call, 10 => return + * - 00 => goto, 01 => call, 10 => return, 11 => end * ``` */ @@ -213,54 +215,109 @@ const SHADY_BCOP_INS_ARITH_KIND_DIV: u32 = 2u; const SHADY_BCOP_INS_ARITH_KIND_MOD: u32 = 3u; /** Immediate instruction kinds. */ -const SHADY_BCOP_INS_IMMED_KIND_SET = 0u; -const SHADY_BCOP_INS_IMMED_KIND_XOR = 1u; -const SHADY_BCOP_INS_IMMED_KIND_AND = 2u; -const SHADY_BCOP_INS_IMMED_KIND_OR = 3u; +const SHADY_BCOP_INS_IMMED_KIND_SET: u32 = 0u; +const SHADY_BCOP_INS_IMMED_KIND_XOR: u32 = 1u; +const SHADY_BCOP_INS_IMMED_KIND_AND: u32 = 2u; +const SHADY_BCOP_INS_IMMED_KIND_OR: u32 = 3u; /** Control flow instruction kinds. */ -const SHADY_BCOP_INS_CFLOW_KIND_GOTO = 0u; -const SHADY_BCOP_INS_CFLOW_KIND_CALL = 1u; -const SHADY_BCOP_INS_CFLOW_KIND_RET = 2u; +const SHADY_BCOP_INS_CFLOW_KIND_GOTO: u32 = 0u; +const SHADY_BCOP_INS_CFLOW_KIND_CALL: u32 = 1u; +const SHADY_BCOP_INS_CFLOW_KIND_RET: u32 = 2u; +const SHADY_BCOP_INS_CFLOW_KIND_END: u32 = 3u; + +/** Flags query kinds. */ +const SHADY_BCOP_CFLOW_QUERY_ALL: u32 = 0u; +const SHADY_BCOP_CFLOW_QUERY_ANY: u32 = 1u; + +/** Flags bit meanings. */ +const SHADY_BCOP_FLAGS_BIT_ZERO: u32 = 1u; +const SHADY_BCOP_FLAGS_BIT_NEGATIVE: u32 = 2u; +const SHADY_BCOP_FLAGS_BIT_POSITIVE: u32 = 4u; +const SHADY_BCOP_FLAGS_BIT_HIGH: u32 = 8u; +const SHADY_BCOP_FLAGS_BIT_ALWAYS: u32 = 16u; + +/** Offsets of special registers. */ +const SHADY_REG_OFFSET_PC: u32 = 96u; +const SHADY_REG_OFFSET_FL: u32 = 97u; +const SHADY_REG_OFFSET_CD: u32 = 98u; +const SHADY_REG_OFFSET_EC: u32 = 99u; + +/** Start offset of the call stack. (callstack grows down) */ +const SHADY_CALLSTACK_OFFSET: u32 = 127u; +const SHADY_CALLDEPTH_MAX: u32 = 4u; + +/** Error codes. */ +const SHADY_EC_NONE: u32 = 0u; +const SHADY_EC_INVALID_INSTRUCTION: u32 = 1u; +const SHADY_EC_CALLSTACK_OVERFLOW: u32 = 2u; +const SHADY_EC_CALLSTACK_UNDERFLOW: u32 = 3u; +const SHADY_EC_SANITY: u32 = 4u; + +/** PC that marks the end of the program. */ +const SHADY_PC_END: u32 = 0xFFFFFFFFu; + /** Access to the register file and call stack. */ -struct ShadyRegistersAndCallStack { - regs: array, - callstack: array, +struct ShadyRegisterFile { + regs: array, +} + +/** Initialize private pointers from a pointer to the full struct. */ +fn shady_init_ptrs( + regfile: ptr, + flags: ptr, + pc: ptr, + cd: ptr +) { + *flags = (*regfile).regs[SHADY_REG_OFFSET_FL]; + *pc = (*regfile).regs[SHADY_REG_OFFSET_PC]; + *cd = (*regfile).regs[SHADY_REG_OFFSET_CD]; +} + +/** Update register file struct. */ +fn shady_writeback_ptrs( + regfile: ptr, + flags: ptr, + pc: ptr, + cd: ptr +) { + (*regfile).regs[SHADY_REG_OFFSET_FL] = *flags; + (*regfile).regs[SHADY_REG_OFFSET_PC] = *pc; + (*regfile).regs[SHADY_REG_OFFSET_CD] = *cd; } /** Execute an instruction. */ fn shady_ins_exec( ins: u32, - regs: ptr, + regfile: ptr, flags: ptr, - pc: ptr -) { + pc: ptr, + cd: ptr +) -> u32 { let fam = shady_bcop_ins_get_insfam(ins); let kind = shady_bcop_ins_get_kind(ins); - switch fam { - case 1u: { - shady_ins_exec_arith(ins, kind, regs, flags, pc); - } - case 2u: { - shady_ins_exec_immed(ins, kind, regs, flags, pc); - } - case 3u: { - shady_ins_exec_cflow(ins, kind, regs, flags, pc); - } - default: { - } + if fam == SHADY_BCOP_INS_ARITH { + return shady_ins_exec_arith(ins, kind, regfile, flags, pc); + } + if fam == SHADY_BCOP_INS_IMMED { + return shady_ins_exec_immed(ins, kind, regfile, flags, pc); } + if fam == SHADY_BCOP_INS_CFLOW { + return shady_ins_exec_cflow(ins, kind, regfile, flags, pc, cd); + } + // Unrecognized instruction family. + return set_error_and_end(regfile, SHADY_EC_INVALID_INSTRUCTION); } /** Execute an arithmetic instruction. */ fn shady_ins_exec_arith( ins: u32, kind: u32, - regs: ptr, + regfile: ptr, flags: ptr, pc: ptr -) { +) -> u32 { let srcreg1 = shady_bcop_ins_get_srcreg1(ins); let srcreg2 = shady_bcop_ins_get_srcreg2(ins); let srcreg2_shift = shady_bcop_ins_get_srcrsh(ins); @@ -273,9 +330,9 @@ fn shady_ins_exec_arith( let flip = shady_bcop_ins_get_flip(ins); let dstreg = shady_bcop_ins_get_dstreg(ins); - var srcval1 = (*regs)[srcreg1]; + var srcval1 = (*regfile).regs[srcreg1]; - var srcval2 = (*regs)[srcreg2]; + var srcval2 = (*regfile).regs[srcreg2]; // Shift and mask. srcval2 = (srcval2 >> srcreg2_shift_bits) & srcreg2_mask_val; // Use the high-bit to sign extend. @@ -297,31 +354,35 @@ fn shady_ins_exec_arith( } var result = 0u; - switch kind { - case 0u: { - result = srcval1 + srcval2; - } - case 1u: { - result = srcval1 * srcval2; - } - case 2u: { - result = srcval1 / srcval2; - } - default: { - result = srcval1 % srcval2; - } + if kind == SHADY_BCOP_INS_ARITH_KIND_ADD { + result = srcval1 + srcval2; + } else if kind == SHADY_BCOP_INS_ARITH_KIND_MUL { + result = srcval1 * srcval2; + } else if kind == SHADY_BCOP_INS_ARITH_KIND_DIV { + result = srcval1 / srcval2; + } else if kind == SHADY_BCOP_INS_ARITH_KIND_MOD { + result = srcval1 % srcval2; + } else { + // Should never get here because of the instruction kind mask. + return set_error_and_end(regfile, SHADY_EC_SANITY); } - (*regs)[dstreg] = result; + (*regfile).regs[dstreg] = result; + + // Update flags. + *flags = calculate_flags_word(result); + + // Go to next instruction. + return *pc + 1u; } /** Execute an immediate instruction. */ fn shady_ins_exec_immed( ins: u32, kind: u32, - regs: ptr, + regfile: ptr, flags: ptr, pc: ptr -) { +) -> u32 { var immval = shady_bcop_ins_get_immval(ins); let immval_sx = shady_bcop_ins_get_sx(ins); let immlsh = shady_bcop_ins_get_immlsh(ins); @@ -335,32 +396,37 @@ fn shady_ins_exec_immed( let immlsh_bits = immlsh << 2u; immval = immval << immlsh_bits; - var result = (*regs)[dstreg]; - switch kind { - case 0u: { - result = immval; - } - case 1u: { - result = result ^ immval; - } - case 2u: { - result = result & immval; - } - default: { - result = result | immval; - } + var result = (*regfile).regs[dstreg]; + if kind == SHADY_BCOP_INS_IMMED_KIND_SET { + result = immval; + } else if kind == SHADY_BCOP_INS_IMMED_KIND_XOR { + result = result ^ immval; + } else if kind == SHADY_BCOP_INS_IMMED_KIND_AND { + result = result & immval; + } else if kind == SHADY_BCOP_INS_IMMED_KIND_OR { + result = result | immval; + } else { + // Should never get here because of the instruction kind mask. + return set_error_and_end(regfile, SHADY_EC_SANITY); } - (*regs)[dstreg] = result; + (*regfile).regs[dstreg] = result; + + // Update flags. + *flags = calculate_flags_word(result); + + // Go to next instruction. + return *pc + 1u; } /** Execute a control flow instruction. */ fn shady_ins_exec_cflow( ins: u32, kind: u32, - regs: ptr, + regfile: ptr, flags: ptr, - pc: ptr -) { + pc: ptr, + cd: ptr +) -> u32 { let brtarg = shady_bcop_ins_get_brtarg(ins); let chk_flags = shady_bcop_ins_get_brflags(ins); let query = shady_bcop_ins_get_brquery(ins); @@ -370,11 +436,65 @@ fn shady_ins_exec_cflow( let flags_set_all = flags_set == chk_flags; let flags_set_any = flags_set > 0u; var do_branch = false; - if query == 0u { + if query == SHADY_BCOP_CFLOW_QUERY_ALL { do_branch = flags_set_all; } else { do_branch = flags_set_any; } - // TODO: implement. + if ! do_branch { + return *pc + 1u; + } + + if kind == SHADY_BCOP_INS_CFLOW_KIND_GOTO { + return brtarg; + } + if kind == SHADY_BCOP_INS_CFLOW_KIND_CALL { + let cd_val = *cd; + if cd_val >= SHADY_CALLDEPTH_MAX { + return set_error_and_end(regfile, SHADY_EC_CALLSTACK_OVERFLOW); + } + (*regfile).regs[SHADY_CALLSTACK_OFFSET - cd_val] = *pc + 1u; + *cd = cd_val + 1u; + return brtarg; + } + if kind == SHADY_BCOP_INS_CFLOW_KIND_RET { + let cd_val = *cd; + if cd_val == 0u { + return set_error_and_end(regfile, SHADY_EC_CALLSTACK_UNDERFLOW); + } + let ret_pc = (*regfile).regs[SHADY_CALLSTACK_OFFSET - cd_val]; + *cd = cd_val - 1u; + return ret_pc; + } + if kind == SHADY_BCOP_INS_CFLOW_KIND_END { + return SHADY_PC_END; + } + // Should never get here because of the instruction kind mask. + return set_error_and_end(regfile, SHADY_EC_SANITY); +} + +fn calculate_flags_word(value: u32) -> u32 { + var flags = SHADY_BCOP_FLAGS_BIT_ALWAYS; + if value == 0u { + flags |= SHADY_BCOP_FLAGS_BIT_ZERO; + } + if value > 0u { + flags |= SHADY_BCOP_FLAGS_BIT_POSITIVE; + } + if value < 0u { + flags |= SHADY_BCOP_FLAGS_BIT_NEGATIVE; + } + if (value >> 31u) > 0u { + flags |= SHADY_BCOP_FLAGS_BIT_HIGH; + } + return flags; } + +fn set_error_and_end( + regfile: ptr, + err: u32, +) -> u32 { + (*regfile).regs[SHADY_REG_OFFSET_EC] = err; + return SHADY_PC_END; +} \ No newline at end of file diff --git a/src/gpu/mod.rs b/src/gpu/mod.rs index 7e25424..22c6f91 100644 --- a/src/gpu/mod.rs +++ b/src/gpu/mod.rs @@ -11,6 +11,8 @@ mod map_buffer; mod seq_buffer; mod world; +mod shady_vm; + pub(crate) mod compute; pub(crate) use self::{ constants::{ GPU_MIN_BUFFER_SIZE, GPU_COPY_BUFFER_ALIGNMENT }, diff --git a/src/gpu/shady_vm/bytecode_format.rs b/src/gpu/shady_vm/bytecode_format.rs new file mode 100644 index 0000000..c64c7aa --- /dev/null +++ b/src/gpu/shady_vm/bytecode_format.rs @@ -0,0 +1,159 @@ + +/** Offset and mask to extract the instruction family. */ +const SHADY_BCOP_OFFSET_INSFAM: u32 = 0u; +const SHADY_BCOP_MASK_INSFAM: u32 = 0x3u; +fn shady_bcop_ins_get_insfam(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_INSFAM) & SHADY_BCOP_MASK_INSFAM; +} + +/** Offset and mask to extract the instruction kind. */ +const SHADY_BCOP_OFFSET_KIND: u32 = 2u; +const SHADY_BCOP_MASK_KIND: u32 = 0x3u; +fn shady_bcop_ins_get_kind(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_KIND) & SHADY_BCOP_MASK_KIND; +} + +/** Offset and mask to extract the destination register. */ +const SHADY_BCOP_OFFSET_DSTREG: u32 = 4u; +const SHADY_BCOP_MASK_DSTREG: u32 = 0x1Fu; +fn shady_bcop_ins_get_dstreg(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_DSTREG) & SHADY_BCOP_MASK_DSTREG; +} + +/** Offset and mask to extract the flip bit. */ +const SHADY_BCOP_OFFSET_FLIP: u32 = 11u; +const SHADY_BCOP_MASK_FLIP: u32 = 0x1u; +fn shady_bcop_ins_get_flip(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_FLIP) & SHADY_BCOP_MASK_FLIP; +} + +/** Offset and mask to extract the negate bit. */ +const SHADY_BCOP_OFFSET_NEGATE: u32 = 12u; +const SHADY_BCOP_MASK_NEGATE: u32 = 0x1u; +fn shady_bcop_ins_get_negate(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_NEGATE) & SHADY_BCOP_MASK_NEGATE; +} + +/** Offset and mask to extract the sign-extend bit. */ +const SHADY_BCOP_OFFSET_SX: u32 = 13u; +const SHADY_BCOP_MASK_SX: u32 = 0x1u; +fn shady_bcop_ins_get_sx(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_SX) & SHADY_BCOP_MASK_SX; +} + +/** Offset and mask to extract the src mask amount. */ +const SHADY_BCOP_OFFSET_SRCMASK: u32 = 14u; +const SHADY_BCOP_MASK_SRCMASK: u32 = 0x7u; +fn shady_bcop_ins_get_srcmask(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_SRCMASK) & SHADY_BCOP_MASK_SRCMASK; +} + +/** Offset and mask to extract the src shift amount. */ +const SHADY_BCOP_OFFSET_SRCRSH: u32 = 17u; +const SHADY_BCOP_MASK_SRCRSH: u32 = 0x7u; +fn shady_bcop_ins_get_srcrsh(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_SRCRSH) & SHADY_BCOP_MASK_SRCRSH; +} + +/** Offset and mask to extract the src register 2. */ +const SHADY_BCOP_OFFSET_SRCREG2: u32 = 20u; +const SHADY_BCOP_MASK_SRCREG2: u32 = 0x7Fu; +fn shady_bcop_ins_get_srcreg2(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_SRCREG2) & SHADY_BCOP_MASK_SRCREG2; +} + +/** Offset and mask to extract the src register 1. */ +const SHADY_BCOP_OFFSET_SRCREG1: u32 = 27u; +const SHADY_BCOP_MASK_SRCREG1: u32 = 0x1Fu; +fn shady_bcop_ins_get_srcreg1(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_SRCREG1) & SHADY_BCOP_MASK_SRCREG1; +} + +/** Offset and mask to extract the immediate left-shift amount. */ +const SHADY_BCOP_OFFSET_IMMLSH: u32 = 9u; +const SHADY_BCOP_MASK_IMMLSH: u32 = 0x7u; +fn shady_bcop_ins_get_immlsh(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_IMMLSH) & SHADY_BCOP_MASK_IMMLSH; +} + +/** Offset and mask to extract the immediate value. */ +const SHADY_BCOP_OFFSET_IMMVAL: u32 = 16u; +const SHADY_BCOP_MASK_IMMVAL: u32 = 0xFFFFu; +fn shady_bcop_ins_get_immval(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_IMMVAL) & SHADY_BCOP_MASK_IMMVAL; +} + +/** Offset and mask to extract the branch target. */ +const SHADY_BCOP_OFFSET_BRTARG: u32 = 16u; +const SHADY_BCOP_MASK_BRTARG: u32 = 0xFFFFu; +fn shady_bcop_ins_get_brtarg(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_BRTARG) & SHADY_BCOP_MASK_BRTARG; +} + +/** Offset and mask to extract the branch condition flags. */ +const SHADY_BCOP_OFFSET_BRFLAGS: u32 = 8u; +const SHADY_BCOP_MASK_BRFLAGS: u32 = 0xFFu; +fn shady_bcop_ins_get_brflags(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_BRFLAGS) & SHADY_BCOP_MASK_BRFLAGS; +} + +/** Offset and mask to extract the branch flags query kind. */ +const SHADY_BCOP_OFFSET_BRQUERY: u32 = 7u; +const SHADY_BCOP_MASK_BRQUERY: u32 = 0x1u; +fn shady_bcop_ins_get_brquery(bcop: u32) -> u32 { + return (bcop >> SHADY_BCOP_OFFSET_BRQUERY) & SHADY_BCOP_MASK_BRQUERY; +} + +/** Instruction family code. */ +const SHADY_BCOP_INS_ARITH: u32 = 1u; +const SHADY_BCOP_INS_IMMED: u32 = 2u; +const SHADY_BCOP_INS_CFLOW: u32 = 3u; + +/** Arithmetic instruction kinds. */ +const SHADY_BCOP_INS_ARITH_KIND_ADD: u32 = 0u; +const SHADY_BCOP_INS_ARITH_KIND_MUL: u32 = 1u; +const SHADY_BCOP_INS_ARITH_KIND_DIV: u32 = 2u; +const SHADY_BCOP_INS_ARITH_KIND_MOD: u32 = 3u; + +/** Immediate instruction kinds. */ +const SHADY_BCOP_INS_IMMED_KIND_SET: u32 = 0u; +const SHADY_BCOP_INS_IMMED_KIND_XOR: u32 = 1u; +const SHADY_BCOP_INS_IMMED_KIND_AND: u32 = 2u; +const SHADY_BCOP_INS_IMMED_KIND_OR: u32 = 3u; + +/** Control flow instruction kinds. */ +const SHADY_BCOP_INS_CFLOW_KIND_GOTO: u32 = 0u; +const SHADY_BCOP_INS_CFLOW_KIND_CALL: u32 = 1u; +const SHADY_BCOP_INS_CFLOW_KIND_RET: u32 = 2u; +const SHADY_BCOP_INS_CFLOW_KIND_END: u32 = 3u; + +/** Flags query kinds. */ +const SHADY_BCOP_CFLOW_QUERY_ALL: u32 = 0u; +const SHADY_BCOP_CFLOW_QUERY_ANY: u32 = 1u; + +/** Flags bit meanings. */ +const SHADY_BCOP_FLAGS_BIT_ZERO: u32 = 1u; +const SHADY_BCOP_FLAGS_BIT_NEGATIVE: u32 = 2u; +const SHADY_BCOP_FLAGS_BIT_POSITIVE: u32 = 4u; +const SHADY_BCOP_FLAGS_BIT_HIGH: u32 = 8u; +const SHADY_BCOP_FLAGS_BIT_ALWAYS: u32 = 16u; + +/** Offsets of special registers. */ +const SHADY_REG_OFFSET_PC: u32 = 96u; +const SHADY_REG_OFFSET_FL: u32 = 97u; +const SHADY_REG_OFFSET_CD: u32 = 98u; +const SHADY_REG_OFFSET_EC: u32 = 99u; + +/** Start offset of the call stack. (callstack grows down) */ +const SHADY_CALLSTACK_OFFSET: u32 = 127u; +const SHADY_CALLDEPTH_MAX: u32 = 4u; + +/** Error codes. */ +const SHADY_EC_NONE: u32 = 0u; +const SHADY_EC_INVALID_INSTRUCTION: u32 = 1u; +const SHADY_EC_CALLSTACK_OVERFLOW: u32 = 2u; +const SHADY_EC_CALLSTACK_UNDERFLOW: u32 = 3u; +const SHADY_EC_SANITY: u32 = 4u; + +/** PC that marks the end of the program. */ +const SHADY_PC_END: u32 = 0xFFFFFFFFu; \ No newline at end of file diff --git a/src/gpu/shady_vm/instruction.rs b/src/gpu/shady_vm/instruction.rs new file mode 100644 index 0000000..ae5f5cb --- /dev/null +++ b/src/gpu/shady_vm/instruction.rs @@ -0,0 +1,138 @@ + +use super::bytecode_format::*; + +pub(crate) enum ShadyInstruction { + Arithmetic(ShadyArithmeticInstruction), + Immediate(ShadyImmediateInstruction), + ControlFLow(ShadyControlFlowInstruction), +} + +pub(crate) struct ShadyRegister(pub(crate) u8); + +/* + * Arithmetic operations: + * TTTT-TSSS SSSS-RRRM MMXN-F??D DDDD-KK01 + * + * * TTTTT (5 bits) + * - source register 1 + * * SSSSSSS (7 bits) + * - source register 2 + * * RRR (3 bits) + * - source register 2 right-shift amount + * - value multiplied by 4 before shift + * * MMM (3 bits) + * - source register 2 mask specifier + * - 0xf, 0xff, 0xfff, 0xffff + * * X (1 bit) + * - if set, sign-extend the source register 2 value + * * N (1 bit) + * - if set, negate source register 2 (after flip) + * * F (1 bit) + * - if set, flip source registers before operation + * * DDDDD (5 bits) + * - destination register + * * KK (2 bits) + * - operation kind + * - 00 => add, 01 => mul, 10 => divide, 11 => modulo + */ +pub(crate) struct ShadyArithmeticInstruction { + pub(crate) src_reg1: ShadyRegister, + pub(crate) src_reg2: ShadyRegister, + pub(crate) src_reg2_rsh: u8, + pub(crate) src_reg2_mask: u8, + pub(crate) src_reg2_sx: bool, + pub(crate) src_reg2_negate: bool, + pub(crate) flip: bool, + pub(crate) dst_reg: ShadyRegister, + pub(crate) kind: ShadyArithmeticKind, +} +impl ShadyArithmeticInstruction { + pub(crate) fn encode(&self) -> u32 { + let mut bcop: u32 = 0; + bcop |= (self.src_reg1.0 as u32) << SHADY_BCOP_OFFSET_SRCREG1; + bcop |= (self.src_reg2.0 as u32) << SHADY_BCOP_OFFSET_SRCREG2; + bcop |= (self.src_reg2_rsh as u32) << SHADY_BCOP_OFFSET_SRCRSH; + bcop |= (self.src_reg2_mask as u32) << SHADY_BCOP_OFFSET_SRCMASK; + bcop |= (self.src_reg2_sx as u32) << SHADY_BCOP_OFFSET_SX; + bcop |= (self.src_reg2_negate as u32) << SHADY_BCOP_OFFSET_NEGATE; + bcop |= (self.flip as u32) << SHADY_BCOP_OFFSET_FLIP; + bcop |= (self.dst_reg.0 as u32) << SHADY_BCOP_OFFSET_DSTREG; + bcop |= (self.kind as u32) << SHADY_BCOP_OFFSET_KIND; + bcop + } +} + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub(crate) enum ShadyArithmeticKind { + Add = 0, + Mul = 1, + Div = 2, + Mod = 3, +} + +/* + * Immediate operations: + * VVVV-VVVV VVVV-VVVV ??X?-LLLD DDDD-KK10 + * + * * VVV...VVV (16-bits) + * - immediate value + * * X (1 bit) + * - if set, sign-extend the value + * * LLL (3 bits) + * - immediate value left-shift amount + * - value multiplied by 4 before shift + * * DDDDD (5 bits) + * - destination register + * * KK (2 bits) + * - accumulation kind + * - 00 => set, 01 => xor, 10 => and, 11 => or + */ +pub(crate) struct ShadyImmediateInstruction { + pub(crate) value: u16, + pub(crate) sx: bool, + pub(crate) lsh: u8, + pub(crate) dst_reg: ShadyRegister, + pub(crate) kind: ShadyImmediateKind, +} + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub(crate) enum ShadyImmediateKind { + Set = 0, + Xor = 1, + And = 2, + Or = 3, +} + +/* + * + * Control flow operations: + * BBBB-BBBB BBBB-BBBB CCCC-CCCC Q???-KK11 + * + * * BBBBB...BBBB (16-bits) + * - branch target (absolute) + * * CCCCCCCC (8 bits) + * - condition flags to check + * * Q (1 bit) + * - flags query kind + * - 0 => all flags must be set, 1 => any flag must be set + * * KK (2 bits) + * - branch kind + * - 00 => goto, 01 => call, 10 => return, 11 => end + */ +pub(crate) struct ShadyControlFlowInstruction { + pub(crate) target: u16, + pub(crate) flags: u8, + pub(crate) query_any: bool, + pub(crate) kind: ShadyControlFlowKind, +} + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub(crate) enum ShadyControlFlowKind { + Goto = 0, + Call = 1, + Return = 2, + End = 3 +} \ No newline at end of file diff --git a/src/gpu/shady_vm/mod.rs b/src/gpu/shady_vm/mod.rs new file mode 100644 index 0000000..dd328c1 --- /dev/null +++ b/src/gpu/shady_vm/mod.rs @@ -0,0 +1,3 @@ + +mod bytecode_format; +mod instruction; \ No newline at end of file