mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: support compilation of logic operators to VM opcodes
The compiler will use the following template for compiling expressions that involve comparisons: 00 push op1 01 push op2 02 je/jg/jl true_label 03 push_0 04 jmp done_label 05 true_label: 06 push_1 07 done_label: The jmp instruction type used for L02 depends on the AML opcode that is compiled. To conserve space, the ACPI spec only defines opcodes for the following comparison operations: equal, less, greater. All other comparisons are constructed by combining one of the above opcodes with a logical not opcode (e.g. greaterOrEqual = !(less)). The VM opcode exploits the fact the comparison expressions always push a 0/1 value on the stack and uses bitwise operations to emulate some additional logic opcodes: - logic not: 0/1 (on stack) XOR 1 - logic and: 0/1 (left expr on stack) AND 0/1 (right expr on stack) - logic or : 0/1 (left expr on stack) OR 0/1 (right expr on stack)
This commit is contained in:
parent
b80c337bc7
commit
be6cd181b1
@ -65,6 +65,15 @@ func newCompilerContext(rootNS entity.Container) *compilerContext {
|
|||||||
entity.OpNot: {opNot, compileUnaryOperator},
|
entity.OpNot: {opNot, compileUnaryOperator},
|
||||||
entity.OpFindSetLeftBit: {opFindSlb, compileUnaryOperator},
|
entity.OpFindSetLeftBit: {opFindSlb, compileUnaryOperator},
|
||||||
entity.OpFindSetRightBit: {opFindSrb, compileUnaryOperator},
|
entity.OpFindSetRightBit: {opFindSrb, compileUnaryOperator},
|
||||||
|
// Logic opcodes
|
||||||
|
entity.OpLEqual: {opJe, compileLogicOperator},
|
||||||
|
entity.OpLGreater: {opJg, compileLogicOperator},
|
||||||
|
entity.OpLLess: {opJl, compileLogicOperator},
|
||||||
|
entity.OpLnot: {opXor, compileLogicNotOperator},
|
||||||
|
// Logic and/or is modelled as a bitwise AND/OR on the output
|
||||||
|
// of two logic expressions
|
||||||
|
entity.OpLand: {opAnd, compileBinaryOperator},
|
||||||
|
entity.OpLor: {opOr, compileBinaryOperator},
|
||||||
}
|
}
|
||||||
|
|
||||||
return compCtx
|
return compCtx
|
||||||
@ -246,6 +255,65 @@ func compileBinaryOperator(compCtx *compilerContext, vmOp uint8, ent entity.Enti
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compileLogicOperator generates a stream of conditional jump opcodes that
|
||||||
|
// implement a logic operator.
|
||||||
|
func compileLogicOperator(compCtx *compilerContext, vmJmpOp uint8, ent entity.Entity) *kernel.Error {
|
||||||
|
operands := ent.Args()
|
||||||
|
if len(operands) < 2 {
|
||||||
|
return &kernel.Error{
|
||||||
|
Module: "acpi_aml_compiler",
|
||||||
|
Message: "unexpected operand count for logic operator " + ent.Opcode().String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To emulate the logic operation the following sequence of
|
||||||
|
// instructions gets generated:
|
||||||
|
//
|
||||||
|
// push op1
|
||||||
|
// push op2
|
||||||
|
// vmJmpOp true_label ; IP += 11
|
||||||
|
// push_0 ; cmp evaluated to false
|
||||||
|
// jmp done_label ; IP += 6
|
||||||
|
// true_label: push_1 ; cmp evaluated to true
|
||||||
|
// done_label:
|
||||||
|
for opIndex := 0; opIndex < 2; opIndex++ {
|
||||||
|
if err := compileOperand(compCtx, operands[opIndex], opDirectionIn); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit32(compCtx, vmJmpOp, uint32(len(compCtx.vmCtx.bytecode))+11)
|
||||||
|
emit8(compCtx, opPushZero)
|
||||||
|
emit32(compCtx, opJmp, uint32(len(compCtx.vmCtx.bytecode))+6)
|
||||||
|
emit8(compCtx, opPushOne)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// compileLogicNotOperator generates the appropriate opcode stream for toggling
|
||||||
|
// the top-most stack entry between 0 and 1.
|
||||||
|
func compileLogicNotOperator(compCtx *compilerContext, _ uint8, ent entity.Entity) *kernel.Error {
|
||||||
|
operands := ent.Args()
|
||||||
|
if len(operands) < 1 {
|
||||||
|
return &kernel.Error{
|
||||||
|
Module: "acpi_aml_compiler",
|
||||||
|
Message: "unexpected operand count for operator " + ent.Opcode().String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile operand
|
||||||
|
if err := compileOperand(compCtx, operands[0], opDirectionIn); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The top of the stack will now be a 0/1 value. By XOR-ing with 1
|
||||||
|
// we can toggle the value
|
||||||
|
emit8(compCtx, opPushOne)
|
||||||
|
emit8(compCtx, opXor)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// compileDivisionOperator generates the appropriate opcode stream for a
|
// compileDivisionOperator generates the appropriate opcode stream for a
|
||||||
// division operator that optionally stores the remainder and the quotient to
|
// division operator that optionally stores the remainder and the quotient to
|
||||||
// the optional third and fourth operands.
|
// the optional third and fourth operands.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user