@@ -122,11 +122,42 @@ pub const BusConfig = struct {
122122 address_type : type ,
123123};
124124
125+ /// IO Bus interface with masked writes as the primary write method
126+ pub fn IOBusInterface (comptime address_type : type ) type {
127+ return struct {
128+ const Self = @This ();
129+ pub const Address = address_type ;
130+
131+ ctx : * anyopaque ,
132+ vtable : * const VTable ,
133+
134+ pub const VTable = struct {
135+ read : * const fn (ctx : * anyopaque , addr : Address ) u8 ,
136+ write : * const fn (ctx : * anyopaque , addr : Address , mask : u8 , v : u8 ) void ,
137+ check_exit : ? * const fn (ctx : * anyopaque ) ? u8 = null ,
138+ };
139+
140+ pub fn read (self : * const Self , addr : Address ) u8 {
141+ return self .vtable .read (self .ctx , addr );
142+ }
143+
144+ /// Write with mask - this is the primary write interface for IO
145+ /// `mask` determines which bits of `value` are written.
146+ pub fn write (self : * const Self , addr : Address , mask : u8 , v : u8 ) void {
147+ self .vtable .write (self .ctx , addr , mask , v );
148+ }
149+
150+ pub fn check_exit (self : * const Self ) ? u8 {
151+ if (self .vtable .check_exit ) | f | return f (self .ctx ) else return null ;
152+ }
153+ };
154+ }
155+
125156/// Standard data bus using 24-bit addressing (for AVR data space)
126157pub const DataBus = Bus (.{ .address_type = u24 });
127158
128159/// Standard IO bus using 12-bit addressing (for AVR IO space)
129- pub const IOBus = Bus (.{ . address_type = IO .Address } );
160+ pub const IOBus = IOBusInterface ( IO.Address );
130161
131162/// Unified byte-addressable bus interface used by MemoryMapping for RAM and IO
132163pub fn Bus (comptime config : BusConfig ) type {
@@ -140,7 +171,6 @@ pub fn Bus(comptime config: BusConfig) type {
140171 pub const VTable = struct {
141172 read : * const fn (ctx : * anyopaque , addr : Address ) u8 ,
142173 write : * const fn (ctx : * anyopaque , addr : Address , v : u8 ) void ,
143- write_masked : * const fn (ctx : * anyopaque , addr : Address , mask : u8 , v : u8 ) void ,
144174 check_exit : ? * const fn (ctx : * anyopaque ) ? u8 = null ,
145175 };
146176
@@ -152,10 +182,6 @@ pub fn Bus(comptime config: BusConfig) type {
152182 self .vtable .write (self .ctx , addr , v );
153183 }
154184
155- pub fn write_masked (self : * const Self , addr : Address , mask : u8 , v : u8 ) void {
156- self .vtable .write_masked (self .ctx , addr , mask , v );
157- }
158-
159185 pub fn check_exit (self : * const Self ) ? u8 {
160186 if (self .vtable .check_exit ) | f | return f (self .ctx ) else return null ;
161187 }
@@ -182,7 +208,6 @@ pub fn FixedSizedMemory(comptime size: comptime_int, comptime bus_config: ?BusCo
182208 pub const bus_vtable = BusType.VTable {
183209 .read = read ,
184210 .write = write ,
185- .write_masked = write_masked ,
186211 .check_exit = null ,
187212 };
188213
@@ -197,13 +222,6 @@ pub fn FixedSizedMemory(comptime size: comptime_int, comptime bus_config: ?BusCo
197222 std .debug .assert (addr < size );
198223 mem .data [addr ] = value ;
199224 }
200-
201- fn write_masked (ctx : * anyopaque , addr : AddressType , mask : u8 , value : u8 ) void {
202- const mem : * Self = @ptrCast (@alignCast (ctx ));
203- std .debug .assert (addr < size );
204- const old = mem .data [addr ];
205- mem .data [addr ] = (old & ~ mask ) | (value & mask );
206- }
207225 };
208226}
209227
@@ -273,14 +291,6 @@ pub fn MemoryMapping(comptime BusType: type) type {
273291 return ;
274292 }
275293
276- pub fn write_masked (self : * const Self , addr : BusType.Address , mask : u8 , v : u8 ) AccessError ! void {
277- const seg = self .find (addr ) orelse return error .Unmapped ;
278- const idx = addr - seg .at ;
279- if (idx >= seg .size ) return error .OutOfRange ;
280- seg .backend .write_masked (idx , mask , v );
281- return ;
282- }
283-
284294 fn find (self : * const Self , addr : BusType.Address ) ? * const Segment {
285295 // Linear scan is fine initially; segments are sorted.
286296 for (self .segments ) | * s | {
@@ -301,7 +311,6 @@ pub fn MemoryMapping(comptime BusType: type) type {
301311 const bus_vtable = BusType.VTable {
302312 .read = bus_read ,
303313 .write = bus_write ,
304- .write_masked = bus_write_masked ,
305314 .check_exit = bus_check_exit ,
306315 };
307316
@@ -323,15 +332,6 @@ pub fn MemoryMapping(comptime BusType: type) type {
323332 };
324333 }
325334
326- fn bus_write_masked (ctx : * anyopaque , addr : BusType.Address , mask : u8 , v : u8 ) void {
327- const self : * const Self = @ptrCast (@alignCast (ctx ));
328- self .write_masked (addr , mask , v ) catch | e | switch (e ) {
329- error .Unmapped = > @panic ("Masked write to unmapped memory address" ),
330- error .OutOfRange = > @panic ("Masked write out of range" ),
331- error .ReadOnly = > @panic ("Masked write to read-only memory" ),
332- };
333- }
334-
335335 fn bus_check_exit (ctx : * anyopaque ) ? u8 {
336336 const self : * const Self = @ptrCast (@alignCast (ctx ));
337337 // Check all segments for exit condition
0 commit comments