use crate::circuit_prices::{RAM_PERMUTATION_COST_IN_ERGS, VM_CYCLE_COST_IN_ERGS};
use super::*;
use ethereum_types::U256;
pub const MAX_OFFSET_TO_DEREF_LOW_U32: u32 = ((1u64 << 32) - 33) as u32;
pub const MAX_OFFSET_TO_DEREF: U256 = U256([MAX_OFFSET_TO_DEREF_LOW_U32 as u64, 0, 0, 0]);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum UMAOpcode {
HeapRead = 0,
HeapWrite,
AuxHeapRead,
AuxHeapWrite,
FatPointerRead,
StaticMemoryRead,
StaticMemoryWrite,
}
pub const UMA_INCREMENT_FLAG_IDX: usize = 0;
impl OpcodeVariantProps for UMAOpcode {
fn all_variants() -> Vec<Self> {
vec![
UMAOpcode::HeapRead,
UMAOpcode::HeapWrite,
UMAOpcode::AuxHeapRead,
UMAOpcode::AuxHeapWrite,
UMAOpcode::FatPointerRead,
UMAOpcode::StaticMemoryRead,
UMAOpcode::StaticMemoryWrite,
]
}
fn max_variant_idx_for_version(version: ISAVersion) -> usize {
match version {
ISAVersion(0) => UMAOpcode::FatPointerRead.variant_index(),
ISAVersion(1) => UMAOpcode::FatPointerRead.variant_index(),
ISAVersion(2) => UMAOpcode::StaticMemoryWrite.variant_index(),
_ => unimplemented!(),
}
}
fn minimal_version(&self) -> ISAVersion {
match self {
UMAOpcode::StaticMemoryRead | UMAOpcode::StaticMemoryWrite => ALL_ISA_VERSIONS[2],
_ => ALL_ISA_VERSIONS[0],
}
}
fn variant_index(&self) -> usize {
(*self as u8) as usize
}
fn from_variant_index_for_version(index: usize, version: &ISAVersion) -> Option<Self> {
match index {
i if i == UMAOpcode::HeapRead.variant_index() => Some(UMAOpcode::HeapRead),
i if i == UMAOpcode::HeapWrite.variant_index() => Some(UMAOpcode::HeapWrite),
i if i == UMAOpcode::AuxHeapRead.variant_index() => Some(UMAOpcode::AuxHeapRead),
i if i == UMAOpcode::AuxHeapWrite.variant_index() => Some(UMAOpcode::AuxHeapWrite),
i if i == UMAOpcode::FatPointerRead.variant_index() => Some(UMAOpcode::FatPointerRead),
i if i == UMAOpcode::StaticMemoryRead.variant_index() => {
if version >= &ALL_ISA_VERSIONS[2] {
Some(UMAOpcode::StaticMemoryRead)
} else {
None
}
}
i if i == UMAOpcode::StaticMemoryWrite.variant_index() => {
if version >= &ALL_ISA_VERSIONS[2] {
Some(UMAOpcode::StaticMemoryWrite)
} else {
None
}
}
_ => None,
}
}
fn ergs_price(&self) -> u32 {
match self {
UMAOpcode::AuxHeapWrite | UMAOpcode::HeapWrite | UMAOpcode::StaticMemoryWrite => {
2 * VM_CYCLE_COST_IN_ERGS + 5 * RAM_PERMUTATION_COST_IN_ERGS
}
UMAOpcode::HeapRead
| UMAOpcode::AuxHeapRead
| UMAOpcode::FatPointerRead
| UMAOpcode::StaticMemoryRead => {
VM_CYCLE_COST_IN_ERGS + 3 * RAM_PERMUTATION_COST_IN_ERGS
}
}
}
}
impl OpcodeProps for UMAOpcode {
fn name(&self) -> &'static str {
"UMA opcode"
}
fn variants_data(&self, version: ISAVersion) -> Vec<OpcodeVariantData> {
match version {
ISAVersion(0) => {
full_variants_product(0..=Self::max_variant_idx_for_version(version), 1, 0)
}
ISAVersion(1) => {
full_variants_product(0..=Self::max_variant_idx_for_version(version), 1, 0)
}
ISAVersion(2) => {
full_variants_product(0..=Self::max_variant_idx_for_version(version), 1, 0)
}
_ => unimplemented!(),
}
}
fn max_variant_idx(&self, version: ISAVersion) -> usize {
match version {
ISAVersion(0) => UMAOpcode::FatPointerRead.variant_index(),
ISAVersion(1) => UMAOpcode::FatPointerRead.variant_index(),
ISAVersion(2) => UMAOpcode::StaticMemoryWrite.variant_index(),
_ => unimplemented!(),
}
}
fn input_operands(&self, version: ISAVersion) -> Vec<Operand> {
match version {
ISAVersion(0) => match self {
UMAOpcode::HeapWrite | UMAOpcode::AuxHeapWrite => {
vec![Operand::RegOnly, Operand::RegOnly]
}
_ => vec![Operand::RegOnly],
},
ISAVersion(1) | ISAVersion(2) => {
match self {
UMAOpcode::HeapWrite
| UMAOpcode::AuxHeapWrite
| UMAOpcode::StaticMemoryWrite => vec![
Operand::RegOrImm(RegOrImmFlags::UseRegOnly),
Operand::RegOnly,
],
UMAOpcode::HeapRead | UMAOpcode::AuxHeapRead | UMAOpcode::StaticMemoryRead => {
vec![Operand::RegOrImm(RegOrImmFlags::UseRegOnly)]
}
UMAOpcode::FatPointerRead => {
vec![Operand::RegOnly]
}
}
}
_ => unimplemented!(),
}
}
fn output_operands(&self, _version: ISAVersion) -> Vec<Operand> {
match self {
UMAOpcode::HeapWrite | UMAOpcode::AuxHeapWrite | UMAOpcode::StaticMemoryWrite => {
vec![Operand::RegOnly]
}
_ => vec![Operand::RegOnly, Operand::RegOnly],
}
}
fn requires_kernel_mode(&self) -> bool {
match self {
UMAOpcode::StaticMemoryRead | UMAOpcode::StaticMemoryWrite => true,
_ => false,
}
}
fn can_be_used_in_static_context(&self) -> bool {
true
}
fn src0_can_be_pointer(&self) -> bool {
true
}
fn src1_can_be_pointer(&self) -> bool {
false
}
}