blob: 91276861c91444da15756edbe58e7e50754f0775 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Bind program instructions
#![allow(dead_code)]
bitfield! {
/// Each instruction is a pair of 32 bit unsigned integers divided as
/// follows.
/// lsb msb
/// COAABBBB VVVVVVVV Condition Opcode paramA paramB Value
struct RawInstruction([u32]);
u32;
condition, set_condition: 3, 0;
operation, set_operation: 7, 4;
parameter_a, set_parameter_a: 15, 8;
parameter_b, set_parameter_b: 31, 16;
value, set_value: 63, 32;
}
/// For all conditions (except Always), the operands to the condition
/// are (parameter_b, value) pairs in the final encoding.
#[derive(PartialEq, Eq)]
pub enum Condition {
Always,
Equal(u32, u32),
NotEqual(u32, u32),
GreaterThan(u32, u32),
LessThan(u32, u32),
GreaterThanEqual(u32, u32),
LessThanEqual(u32, u32),
}
pub enum Instruction {
Abort(Condition),
Match(Condition),
Goto(Condition, u32),
Label(u32),
}
fn to_raw_condition(condition: Condition) -> (u32, u32, u32) {
match condition {
Condition::Always => (0, 0, 0),
Condition::Equal(b, v) => (1, b, v),
Condition::NotEqual(b, v) => (2, b, v),
Condition::GreaterThan(b, v) => (3, b, v),
Condition::LessThan(b, v) => (4, b, v),
Condition::GreaterThanEqual(b, v) => (5, b, v),
Condition::LessThanEqual(b, v) => (6, b, v),
}
}
fn to_raw_instruction(instruction: Instruction) -> RawInstruction<[u32; 2]> {
let (c, o, a, b, v) = match instruction {
Instruction::Abort(condition) => {
let (c, b, v) = to_raw_condition(condition);
(c, 0, 0, b, v)
}
Instruction::Match(condition) => {
let (c, b, v) = to_raw_condition(condition);
(c, 1, 0, b, v)
}
Instruction::Goto(condition, a) => {
let (c, b, v) = to_raw_condition(condition);
(c, 2, a, b, v)
}
Instruction::Label(a) => (0, 5, a, 0, 0),
};
let mut raw_instruction = RawInstruction([0, 0]);
raw_instruction.set_condition(c);
raw_instruction.set_operation(o);
raw_instruction.set_parameter_a(a);
raw_instruction.set_parameter_b(b);
raw_instruction.set_value(v);
raw_instruction
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_raw_instruction() {
let mut raw = RawInstruction([0, 0]);
assert_eq!(raw.0[0], 0);
assert_eq!(raw.0[1], 0);
assert_eq!(raw.condition(), 0);
assert_eq!(raw.operation(), 0);
assert_eq!(raw.parameter_a(), 0);
assert_eq!(raw.parameter_b(), 0);
assert_eq!(raw.value(), 0);
raw.set_condition(1);
assert_eq!(raw.0[0], 1);
assert_eq!(raw.0[1], 0);
assert_eq!(raw.condition(), 1);
assert_eq!(raw.operation(), 0);
assert_eq!(raw.parameter_a(), 0);
assert_eq!(raw.parameter_b(), 0);
assert_eq!(raw.value(), 0);
raw.set_operation(2);
assert_eq!(raw.0[0], 1 | (2 << 4));
assert_eq!(raw.0[1], 0);
assert_eq!(raw.condition(), 1);
assert_eq!(raw.operation(), 2);
assert_eq!(raw.parameter_a(), 0);
assert_eq!(raw.parameter_b(), 0);
assert_eq!(raw.value(), 0);
raw.set_parameter_a(3);
assert_eq!(raw.0[0], 1 | (2 << 4) | (3 << 8));
assert_eq!(raw.0[1], 0);
assert_eq!(raw.condition(), 1);
assert_eq!(raw.operation(), 2);
assert_eq!(raw.parameter_a(), 3);
assert_eq!(raw.parameter_b(), 0);
assert_eq!(raw.value(), 0);
raw.set_parameter_b(4);
assert_eq!(raw.0[0], 1 | (2 << 4) | (3 << 8) | (4 << 16));
assert_eq!(raw.0[1], 0);
assert_eq!(raw.condition(), 1);
assert_eq!(raw.operation(), 2);
assert_eq!(raw.parameter_a(), 3);
assert_eq!(raw.parameter_b(), 4);
assert_eq!(raw.value(), 0);
raw.set_value(5);
assert_eq!(raw.0[0], 1 | (2 << 4) | (3 << 8) | (4 << 16));
assert_eq!(raw.0[1], 5);
assert_eq!(raw.condition(), 1);
assert_eq!(raw.operation(), 2);
assert_eq!(raw.parameter_a(), 3);
assert_eq!(raw.parameter_b(), 4);
assert_eq!(raw.value(), 5)
}
#[test]
fn test_abort_value() {
let instruction = Instruction::Abort(Condition::Always);
let raw_instruction = to_raw_instruction(instruction);
assert_eq!(raw_instruction.0[0], 0 << 4);
assert_eq!(raw_instruction.0[1], 0);
assert_eq!(raw_instruction.operation(), 0)
}
#[test]
fn test_match_value() {
let instruction = Instruction::Match(Condition::Always);
let raw_instruction = to_raw_instruction(instruction);
assert_eq!(raw_instruction.0[0], 1 << 4);
assert_eq!(raw_instruction.0[1], 0);
assert_eq!(raw_instruction.operation(), 1)
}
#[test]
fn test_goto_value() {
let instruction = Instruction::Goto(Condition::Always, 0);
let raw_instruction = to_raw_instruction(instruction);
assert_eq!(raw_instruction.0[0], 2 << 4);
assert_eq!(raw_instruction.0[1], 0);
assert_eq!(raw_instruction.operation(), 2)
}
#[test]
fn test_label_value() {
let instruction = Instruction::Label(0);
let raw_instruction = to_raw_instruction(instruction);
assert_eq!(raw_instruction.0[0], 5 << 4);
assert_eq!(raw_instruction.0[1], 0);
assert_eq!(raw_instruction.operation(), 5)
}
#[test]
fn test_complicated_value() {
let instruction = Instruction::Goto(Condition::LessThan(23, 1234), 42);
let raw_instruction = to_raw_instruction(instruction);
assert_eq!(raw_instruction.0[0], 4 | (2 << 4) | (42 << 8) | (23 << 16));
assert_eq!(raw_instruction.0[1], 1234);
assert_eq!(raw_instruction.condition(), 4);
assert_eq!(raw_instruction.operation(), 2);
assert_eq!(raw_instruction.parameter_a(), 42);
assert_eq!(raw_instruction.parameter_b(), 23);
assert_eq!(raw_instruction.value(), 1234)
}
}