use std::collections::VecDeque;
use crate::{pub_outs_collector::PubOutsCollector, BuiltinCounters, PrecompileCounters};
use proofman_fields::PrimeField64;
use zisk_common::DataBusTrait;
use zisk_common::{BusDeviceMetrics, BusId, PayloadType, MEM_BUS_ID, OPERATION_BUS_ID, OP_TYPE};
use zisk_core::{
MemDataSection, ARITH_OP_TYPE_ID, BINARY_E_OP_TYPE_ID, BINARY_OP_TYPE_ID, DMA_OP_TYPE_ID,
EVM_OP_TYPE_ID, PUB_OUT_OP_TYPE_ID,
};
use zisk_precomp_common::MemCounterProcessor;
use zisk_precomp_dma::DmaCounterInputGen;
use zisk_precomp_evm::JumpDestCounterInputGen;
use zisk_sm_arith::ArithCounterInputGen;
use zisk_sm_binary::BinaryCounter;
use zisk_sm_mem_common::MemCounters;
pub struct StaticDataBus<D, F: PrimeField64> {
process_only_operation_bus: bool,
pub_outs_collector: PubOutsCollector,
mem_counter: (usize, Option<MemCounters>),
arith_counter: (usize, ArithCounterInputGen),
binary_counter: (usize, BinaryCounter),
dma_counter: (usize, DmaCounterInputGen),
jump_dest_counter: (usize, JumpDestCounterInputGen),
precompiles: PrecompileCounters<F>,
pending_transfers: VecDeque<(BusId, Vec<D>, Vec<D>)>,
}
impl<F: PrimeField64> StaticDataBus<PayloadType, F> {
pub fn build(is_asm_emulator: bool, mem_sections: Option<&dyn MemDataSection>) -> Self {
let builtins = BuiltinCounters::build::<F>(is_asm_emulator, mem_sections);
let precompiles = PrecompileCounters::<F>::build(is_asm_emulator);
Self {
process_only_operation_bus: is_asm_emulator,
pub_outs_collector: PubOutsCollector::new(),
mem_counter: builtins.mem,
arith_counter: builtins.arith,
binary_counter: builtins.binary,
dma_counter: builtins.dma,
jump_dest_counter: builtins.jump_dest,
precompiles,
pending_transfers: VecDeque::new(),
}
}
#[inline]
pub fn take_pub_outs(&mut self) -> PubOutsCollector {
std::mem::take(&mut self.pub_outs_collector)
}
#[inline(always)]
fn route_data(
&mut self,
bus_id: BusId,
data: &[PayloadType],
data_ext: &[PayloadType],
) -> bool {
match bus_id {
MEM_BUS_ID => {
let mut _continue = true;
if !self.process_only_operation_bus {
if let Some(mem_counter) = self.mem_counter.1.as_mut() {
_continue &= mem_counter.process_data(&bus_id, data);
}
}
_continue
}
OPERATION_BUS_ID => match data[OP_TYPE] as u32 {
PUB_OUT_OP_TYPE_ID => {
self.pub_outs_collector.process_data(data);
true
}
BINARY_OP_TYPE_ID | BINARY_E_OP_TYPE_ID => {
self.binary_counter.1.process_data(&bus_id, data)
}
ARITH_OP_TYPE_ID => {
self.arith_counter.1.process_data(&bus_id, data, &mut self.pending_transfers)
}
DMA_OP_TYPE_ID => self.dma_counter.1.process_data(
&bus_id,
data,
data_ext,
&mut MemCounterProcessor::new(self.mem_counter.1.as_mut()),
),
EVM_OP_TYPE_ID => self.jump_dest_counter.1.process_data(
&bus_id,
data,
data_ext,
&mut MemCounterProcessor::new(self.mem_counter.1.as_mut()),
),
op => self.precompiles.dispatch_op(op, &bus_id, data, self.mem_counter.1.as_mut()),
},
_ => true,
}
}
}
impl<F: PrimeField64> DataBusTrait<PayloadType, Box<dyn BusDeviceMetrics>>
for StaticDataBus<PayloadType, F>
{
#[inline(always)]
fn write_to_bus(
&mut self,
bus_id: BusId,
data: &[PayloadType],
data_ext: &[PayloadType],
) -> bool {
let mut _continue = self.route_data(bus_id, data, data_ext);
while let Some((bus_id, data, data_ext)) = self.pending_transfers.pop_front() {
_continue &= self.route_data(bus_id, &data, &data_ext);
}
_continue
}
fn on_close(&mut self) {
if let Some(mem_counter) = self.mem_counter.1.as_mut() {
mem_counter.close();
}
}
fn into_devices(mut self, execute_on_close: bool) -> Vec<(usize, Box<dyn BusDeviceMetrics>)> {
if execute_on_close {
self.on_close();
}
let mut counters: Vec<(usize, Box<dyn BusDeviceMetrics>)> = vec![
(self.binary_counter.0, Box::new(self.binary_counter.1)),
(self.arith_counter.0, Box::new(self.arith_counter.1)),
];
counters.extend(self.precompiles.into_device_entries());
counters.push((self.dma_counter.0, Box::new(self.dma_counter.1)));
counters.push((self.jump_dest_counter.0, Box::new(self.jump_dest_counter.1)));
if let Some(mem_counter) = self.mem_counter.1 {
counters.insert(0, (self.mem_counter.0, Box::new(mem_counter)));
}
counters
}
}