1717//!
1818//! ## Column layout (10 columns)
1919//!
20- //! - `ADDRESS`: Byte (register index 0-31 )
20+ //! - `ADDRESS`: Byte (register index 0-255: x0-x31, plus x254/x255 )
2121//! - `TIMESTAMP_0`: Word (low 32 bits)
2222//! - `TIMESTAMP_1`: Word (high 32 bits)
2323//! - `VAL_0`: Word (low 32 bits of register value)
@@ -43,7 +43,7 @@ use stark::trace::TraceTable;
4343
4444use stark:: constraints:: builder:: { ConstraintBuilder , ConstraintSet } ;
4545
46- use super :: bitwise:: { BitwiseOperation , BitwiseOperationType } ;
46+ use super :: bitwise:: { BitwiseHistogram , BitwiseOperation , BitwiseOperationType } ;
4747use super :: memw:: MemwOperation ;
4848use super :: types:: { BusId , FE , GoldilocksExtension , GoldilocksField , VmTable } ;
4949use crate :: constraints:: templates:: emit_is_bit;
@@ -53,7 +53,7 @@ use crate::constraints::templates::emit_is_bit;
5353// =========================================================================
5454
5555pub mod cols {
56- /// Register index (0-31 ). CPU sends base_address = 2*reg_index.
56+ /// Register index (0-255: x0-x31, plus x254/x255 ). CPU sends base_address = 2*reg_index.
5757 pub const ADDRESS : usize = 0 ;
5858
5959 /// Timestamp low 32 bits
@@ -105,7 +105,9 @@ pub mod cols {
105105/// enforced by `is_register_op`; the upper limb is TIMESTAMP_1 = timestamp>>32)
106106#[ derive( Debug , Clone , Copy ) ]
107107pub ( crate ) struct RegRow {
108- address : u64 ,
108+ /// Register index 0..=255 (`base_address / 2`); u16 keeps the struct at
109+ /// 32 bytes — it is the largest persisted array of the walk.
110+ address : u16 ,
109111 timestamp : u64 ,
110112 val0 : u32 ,
111113 val1 : u32 ,
@@ -140,8 +142,12 @@ impl RegRow {
140142 0 ,
141143 "register base_address must be even (got {reg_addr})"
142144 ) ;
145+ debug_assert ! (
146+ reg_addr / 2 <= u16 :: MAX as u64 ,
147+ "register index exceeds u16 (got base_address {reg_addr})"
148+ ) ;
143149 RegRow {
144- address : reg_addr / 2 ,
150+ address : ( reg_addr / 2 ) as u16 ,
145151 timestamp,
146152 val0,
147153 val1,
@@ -210,7 +216,7 @@ pub(crate) fn generate_memw_register_trace_from_rows(
210216
211217 for ( row_idx, r) in rows. iter ( ) . enumerate ( ) {
212218 // ADDRESS = base_address / 2 (already divided in RegRow).
213- table. set_u64 ( row_idx, cols:: ADDRESS , r. address ) ;
219+ table. set_u64 ( row_idx, cols:: ADDRESS , r. address as u64 ) ;
214220 // Timestamp split into lo/hi 32-bit words.
215221 table. set_dword_wl ( row_idx, cols:: TIMESTAMP_0 , r. timestamp ) ;
216222 // Value: registers are DWordWL = 2 words.
@@ -250,13 +256,17 @@ fn memw_register_is_half_lookup(ts_lo: u32, old_ts_lo: u32) -> BitwiseOperation
250256 )
251257}
252258
253- /// IS_HALFWORD bitwise lookups for MEMW_R, computed directly from [`RegRow`]s via
254- /// the shared [`memw_register_is_half_lookup`] helper (the same lookup the MEMW_R
255- /// trace fill uses), so the multiplicities stay consistent with that table.
256- pub ( crate ) fn collect_bitwise_from_memw_register ( rows : & [ RegRow ] ) -> Vec < BitwiseOperation > {
257- rows. iter ( )
258- . map ( |r| memw_register_is_half_lookup ( ( r. timestamp & 0xFFFF_FFFF ) as u32 , r. old_ts_lo ) )
259- . collect ( )
259+ /// IS_HALFWORD bitwise lookups for MEMW_R, bumped straight into the histogram
260+ /// via the shared [`memw_register_is_half_lookup`] helper (the same lookup the
261+ /// MEMW_R trace fill uses), one per row. No intermediate op vector: register
262+ /// rows number in the tens of millions and the histogram is the only consumer.
263+ pub ( crate ) fn collect_bitwise_from_memw_register ( rows : & [ RegRow ] , hist : & mut BitwiseHistogram ) {
264+ for r in rows {
265+ hist. bump ( memw_register_is_half_lookup (
266+ ( r. timestamp & 0xFFFF_FFFF ) as u32 ,
267+ r. old_ts_lo ,
268+ ) ) ;
269+ }
260270}
261271
262272// =========================================================================
0 commit comments