use crate::gas_cost::FastCost;
pub struct GasSimulator {
reg_done: [u32; 13],
cycle: u32,
decode_used: u8,
max_done: u32,
}
impl GasSimulator {
pub fn new() -> Self {
Self {
reg_done: [0; 13],
cycle: 0,
decode_used: 0,
max_done: 0,
}
}
#[inline]
pub fn feed(&mut self, cost: &FastCost) {
self.decode_used += cost.decode_slots;
if self.decode_used > 4 {
self.cycle += 1;
self.decode_used = cost.decode_slots;
}
if cost.is_move_reg {
let src_reg = cost.src_mask.trailing_zeros() as usize;
let dst_reg = cost.dst_mask.trailing_zeros() as usize;
if src_reg < 13 && dst_reg < 13 {
self.reg_done[dst_reg] = self.reg_done[src_reg];
}
return;
}
let mut start = self.cycle;
let mut src = cost.src_mask;
while src != 0 {
let r = src.trailing_zeros() as usize;
src &= src - 1;
if r < 13 {
start = start.max(self.reg_done[r]);
}
}
let done = start + cost.cycles as u32;
let mut dst = cost.dst_mask;
while dst != 0 {
let r = dst.trailing_zeros() as usize;
dst &= dst - 1;
if r < 13 {
self.reg_done[r] = done;
}
}
self.max_done = self.max_done.max(done);
}
#[inline]
pub fn flush_and_get_cost(&self) -> u32 {
if self.max_done > 3 { self.max_done - 3 } else { 1 }
}
#[inline]
pub fn reset(&mut self) {
self.reg_done = [0; 13];
self.cycle = 0;
self.decode_used = 0;
self.max_done = 0;
}
}