private static OpcodeDescriptor Add(uint number, string name, uint argumentSize, params OperandKind[] operandKinds) { var descriptor = new OpcodeDescriptor(number, name, argumentSize, operandKinds.ToImmutableList()); s_table.Add(number, descriptor); return(descriptor); }
public static bool TryGetOpcode(uint number, out OpcodeDescriptor opcode) { return(s_table.TryGetValue(number, out opcode)); }
public void BindInstruction( OpcodeDescriptor opcode, ImmutableList <Operand> loadOperands, ImmutableList <Operand> storeOperands, int address, int length) { // We create a label at every address. Unused labels will be pruned by the AstBodyBuilder later. var label = GetOrCreateLabel(address); this.bodyBuilder.MarkLabel(label); var nextAddress = address + length; switch (opcode.Number) { case Opcodes.op_add: BindAdd( leftOp: loadOperands[0], rightOp: loadOperands[1], storeOp: storeOperands[0]); break; case Opcodes.op_aload: BindRead( baseAddressOp: loadOperands[0], offsetOp: loadOperands[1], storeOp: storeOperands[0], size: ValueSize.DWord); break; case Opcodes.op_aloadb: BindRead( baseAddressOp: loadOperands[0], offsetOp: loadOperands[1], storeOp: storeOperands[0], size: ValueSize.Byte); break; case Opcodes.op_aloads: BindRead( baseAddressOp: loadOperands[0], offsetOp: loadOperands[1], storeOp: storeOperands[0], size: ValueSize.Word); break; case Opcodes.op_astore: BindWrite( baseAddressOp: loadOperands[0], offsetOp: loadOperands[1], valueOp: loadOperands[2], size: ValueSize.DWord); break; case Opcodes.op_astoreb: BindWrite( baseAddressOp: loadOperands[0], offsetOp: loadOperands[1], valueOp: loadOperands[2], size: ValueSize.Byte); break; case Opcodes.op_astores: BindWrite( baseAddressOp: loadOperands[0], offsetOp: loadOperands[1], valueOp: loadOperands[2], size: ValueSize.Word); break; case Opcodes.op_call: BindCall( addressOp: loadOperands[0], argumentCountOp: loadOperands[1], storeOp: storeOperands[0]); break; case Opcodes.op_callf: BindCall0( addressOp: loadOperands[0], storeOp: storeOperands[0]); break; case Opcodes.op_callfi: BindCall1( addressOp: loadOperands[0], arg1Op: loadOperands[1], storeOp: storeOperands[0]); break; case Opcodes.op_callfii: BindCall2( addressOp: loadOperands[0], arg1Op: loadOperands[1], arg2Op: loadOperands[2], storeOp: storeOperands[0]); break; case Opcodes.op_callfiii: BindCall3( addressOp: loadOperands[0], arg1Op: loadOperands[1], arg2Op: loadOperands[2], arg3Op: loadOperands[3], storeOp: storeOperands[0]); break; case Opcodes.op_copy: BindCopy( targetOp: loadOperands[0], storeOp: storeOperands[0], size: ValueSize.DWord); break; case Opcodes.op_div: BindDivide( leftOp: loadOperands[0], rightOp: loadOperands[1], storeOp: storeOperands[0]); break; case Opcodes.op_getmemsize: BindGetMemorySize( storeOp: storeOperands[0]); break; case Opcodes.op_glk: BindGlk( identifierOp: loadOperands[0], argumentCountOp: loadOperands[1], storeOperands: storeOperands[0]); break; case Opcodes.op_jeq: BindJumpIfEqual( leftOp: loadOperands[0], rightOp: loadOperands[1], jumpOffsetOp: loadOperands[2], nextAddress: nextAddress); break; case Opcodes.op_jge: BindJumpIfGreaterThanOrEqual( leftOp: loadOperands[0], rightOp: loadOperands[1], jumpOffsetOp: loadOperands[2], nextAddress: nextAddress); break; case Opcodes.op_jgt: BindJumpIfGreaterThan( leftOp: loadOperands[0], rightOp: loadOperands[1], jumpOffsetOp: loadOperands[2], nextAddress: nextAddress); break; case Opcodes.op_jle: BindJumpIfLessThanOrEqual( leftOp: loadOperands[0], rightOp: loadOperands[1], jumpOffsetOp: loadOperands[2], nextAddress: nextAddress); break; case Opcodes.op_jlt: BindJumpIfLessThan( leftOp: loadOperands[0], rightOp: loadOperands[1], jumpOffsetOp: loadOperands[2], nextAddress: nextAddress); break; case Opcodes.op_jne: BindJumpIfNotEqual( leftOp: loadOperands[0], rightOp: loadOperands[1], jumpOffsetOp: loadOperands[2], nextAddress: nextAddress); break; case Opcodes.op_jnz: BindJumpIfNotEqualToZero( leftOp: loadOperands[0], jumpOffsetOp: loadOperands[1], nextAddress: nextAddress); break; case Opcodes.op_jump: BindJump( jumpOffsetOp: loadOperands[0], nextAddress: nextAddress); break; case Opcodes.op_jz: BindJumpIfEqualToZero( leftOp: loadOperands[0], jumpOffsetOp: loadOperands[1], nextAddress: nextAddress); break; case Opcodes.op_mod: BindModulo( leftOp: loadOperands[0], rightOp: loadOperands[1], storeOp: storeOperands[0]); break; case Opcodes.op_mul: BindMultiply( leftOp: loadOperands[0], rightOp: loadOperands[1], storeOp: storeOperands[0]); break; case Opcodes.op_quit: BindQuit(); break; case Opcodes.op_restoreundo: BindRestoreUndo(); break; case Opcodes.op_return: BindReturn( expressionOp: loadOperands[0]); break; case Opcodes.op_stkcopy: BindStackCopy( countOp: loadOperands[0]); break; case Opcodes.op_streamchar: BindStreamChar( characterOp: loadOperands[0]); break; case Opcodes.op_streamnum: BindStreamNumber( numberOp: loadOperands[0]); break; case Opcodes.op_streamstr: BindStreamString( addressOp: loadOperands[0]); break; case Opcodes.op_sub: BindSubtract( leftOp: loadOperands[0], rightOp: loadOperands[1], storeOp: storeOperands[0]); break; default: throw new NotSupportedException($"Unsupported opcode: {opcode}"); } }
private static (ImmutableList <Operand> loadOps, ImmutableList <Operand> storeOps) ReadOperands(MemoryScanner scanner, OpcodeDescriptor opcode) { var loadOpsBuilder = ImmutableList.CreateBuilder <Operand>(); var storeOpsBuilder = ImmutableList.CreateBuilder <Operand>(); var count = opcode.OperandCount; if (count > 0) { var typesLength = count / 2; if (count % 2 != 0) { typesLength++; } var dataScanner = scanner.Memory.CreateScanner(scanner.Address + typesLength); for (int i = 0; i < count; i += 2) { var opsBuilder = opcode.OperandKinds[i] == OperandKind.Load ? loadOpsBuilder : storeOpsBuilder; var typeByte = scanner.NextByte(); var type = (byte)(typeByte & 0x0f); var operand = ReadOperand(dataScanner, type); opsBuilder.Add(operand); if (i + 1 < count) { opsBuilder = opcode.OperandKinds[i + 1] == OperandKind.Load ? loadOpsBuilder : storeOpsBuilder; type = (byte)(typeByte >> 4); operand = ReadOperand(dataScanner, type); opsBuilder.Add(operand); } } scanner.SetAddress(dataScanner.Address); } return(loadOpsBuilder.ToImmutable(), storeOpsBuilder.ToImmutable()); }