Skip to content

Commit 0608119

Browse files
committed
Use a unified interface for IO and SRAM
1 parent 2262289 commit 0608119

File tree

7 files changed

+165
-282
lines changed

7 files changed

+165
-282
lines changed

sim/aviron/src/lib/Cpu.zig

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const Flash = io_mod.Flash;
88
const RAM = io_mod.RAM;
99
const EEPROM = io_mod.EEPROM;
1010
const IO = io_mod.IO;
11+
const Device = io_mod.Device;
1112

1213
const Cpu = @This();
1314

@@ -59,10 +60,10 @@ code_model: CodeModel,
5960
instruction_set: InstructionSet,
6061
sio: SpecialIoRegisters,
6162
flash: Flash,
62-
sram: RAM,
6363
sram_base: u16,
64-
eeprom: EEPROM,
65-
io: IO,
64+
sram_size: usize,
65+
eeprom_size: usize,
66+
io_dev: Device,
6667
data: memory.MemorySpace,
6768
io_space: memory.MemorySpace,
6869

@@ -115,17 +116,17 @@ pub fn dump_system_state(cpu: *Cpu) void {
115116
}
116117

117118
// Dump SRAM using absolute addresses based on configured base
118-
const sram_end: u16 = cpu.sram_base + @as(u16, @truncate(cpu.sram.size - 1));
119-
std.debug.print("\nSRAM DUMP (0x{X:0>4}-0x{X:0>4}, {d} bytes):\n", .{ cpu.sram_base, sram_end, cpu.sram.size });
119+
const sram_end: u16 = cpu.sram_base + @as(u16, @truncate(cpu.sram_size - 1));
120+
std.debug.print("\nSRAM DUMP (0x{X:0>4}-0x{X:0>4}, {d} bytes):\n", .{ cpu.sram_base, sram_end, cpu.sram_size });
120121

121122
const row_width = 16;
122123
var prev_row: ?[row_width]u8 = null;
123124
var prev_len: usize = 0;
124125
var elided = false;
125126

126127
var i: usize = 0;
127-
while (i < cpu.sram.size) : (i += @min(row_width, cpu.sram.size - i)) {
128-
const row_len: usize = @min(row_width, cpu.sram.size - i);
128+
while (i < cpu.sram_size) : (i += @min(row_width, cpu.sram_size - i)) {
129+
const row_len: usize = @min(row_width, cpu.sram_size - i);
129130
var cur_row: [row_width]u8 = undefined;
130131

131132
var j: usize = 0;
@@ -269,7 +270,7 @@ pub fn run(cpu: *Cpu, mileage: ?u64, break_pc: ?u24) RunError!RunResult {
269270
}
270271

271272
// Check if the program requested exit via I/O
272-
if (cpu.io.check_exit()) |exit_code| {
273+
if (cpu.io_dev.check_exit()) |exit_code| {
273274
_ = exit_code; // The exit code is stored in the IO context for main() to use
274275
return .program_exit;
275276
}

sim/aviron/src/lib/aviron.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub const Flash = io.Flash;
99
pub const RAM = io.RAM;
1010
pub const EEPROM = io.EEPROM;
1111
pub const IO = io.IO;
12+
pub const Device = io.Device;
1213
pub const memory = @import("memory.zig");
1314

1415
pub const mcu = @import("mcu.zig");

sim/aviron/src/lib/io.zig

Lines changed: 68 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -97,75 +97,41 @@ pub const Flash = struct {
9797
pub const RAM = struct {
9898
pub const Address = u24;
9999

100-
ctx: ?*anyopaque,
101-
vtable: *const VTable,
102-
103-
/// Size of the RAM memory space in bytes.
104-
size: usize,
105-
106-
pub fn read(mem: RAM, index: Address) u8 {
107-
// Index is a 0-based array index, not a data-space address.
108-
return mem.vtable.readFn(mem.ctx, index);
109-
}
110-
111-
pub fn write(mem: RAM, index: Address, value: u8) void {
112-
// Index is a 0-based array index, not a data-space address.
113-
return mem.vtable.writeFn(mem.ctx, index, value);
114-
}
115-
116-
pub const VTable = struct {
117-
readFn: *const fn (ctx: ?*anyopaque, index: Address) u8,
118-
writeFn: *const fn (ctx: ?*anyopaque, index: Address, value: u8) void,
119-
};
120-
121-
pub const empty = RAM{
122-
.ctx = null,
123-
.size = 0,
124-
.vtable = &VTable{ .readFn = empty_read, .writeFn = empty_write },
125-
};
126-
127-
fn empty_read(ctx: ?*anyopaque, index: Address) u8 {
128-
_ = index;
129-
_ = ctx;
130-
return 0;
131-
}
132-
133-
fn empty_write(ctx: ?*anyopaque, index: Address, value: u8) void {
134-
_ = value;
135-
_ = index;
136-
_ = ctx;
137-
}
138-
139100
pub fn Static(comptime size: comptime_int) type {
140101
return struct {
141102
const Self = @This();
142103

143104
data: [size]u8 align(2) = .{0} ** size,
144105

145-
pub fn memory(self: *Self) RAM {
146-
return RAM{
147-
.ctx = self,
148-
.vtable = &vtable,
149-
.size = size,
150-
};
106+
pub fn device(self: *Self) Device {
107+
return Device{ .ctx = self, .vtable = &dev_vtable };
151108
}
152109

153-
pub const vtable = VTable{
154-
.readFn = mem_read,
155-
.writeFn = mem_write,
110+
pub const dev_vtable = Device.VTable{
111+
.read8 = dev_read8,
112+
.write8 = dev_write8,
113+
.write_masked = dev_write_masked,
114+
.check_exit = null,
156115
};
157116

158-
fn mem_read(ctx: ?*anyopaque, index: Address) u8 {
159-
const mem: *Self = @ptrCast(@alignCast(ctx.?));
117+
fn dev_read8(ctx: *anyopaque, index: usize) u8 {
118+
const mem: *Self = @ptrCast(@alignCast(ctx));
160119
std.debug.assert(index < size);
161120
return mem.data[index];
162121
}
163122

164-
fn mem_write(ctx: ?*anyopaque, index: Address, value: u8) void {
165-
const mem: *Self = @ptrCast(@alignCast(ctx.?));
123+
fn dev_write8(ctx: *anyopaque, index: usize, value: u8) void {
124+
const mem: *Self = @ptrCast(@alignCast(ctx));
166125
std.debug.assert(index < size);
167126
mem.data[index] = value;
168127
}
128+
129+
fn dev_write_masked(ctx: *anyopaque, index: usize, mask: u8, value: u8) void {
130+
const mem: *Self = @ptrCast(@alignCast(ctx));
131+
std.debug.assert(index < size);
132+
const old = mem.data[index];
133+
mem.data[index] = (old & ~mask) | (value & mask);
134+
}
169135
};
170136
}
171137

@@ -187,29 +153,34 @@ pub const RAM = struct {
187153
self.allocator.free(self.data);
188154
}
189155

190-
pub fn memory(self: *Self) RAM {
191-
return RAM{
192-
.ctx = self,
193-
.vtable = &vtable,
194-
.size = self.data.len,
195-
};
156+
pub fn device(self: *Self) Device {
157+
return Device{ .ctx = self, .vtable = &dev_vtable };
196158
}
197159

198-
pub const vtable = VTable{
199-
.readFn = mem_read,
200-
.writeFn = mem_write,
160+
pub const dev_vtable = Device.VTable{
161+
.read8 = dev_read8,
162+
.write8 = dev_write8,
163+
.write_masked = dev_write_masked,
164+
.check_exit = null,
201165
};
202166

203-
fn mem_read(ctx: ?*anyopaque, index: Address) u8 {
204-
const mem: *Self = @ptrCast(@alignCast(ctx.?));
205-
std.debug.assert(index < mem.data.len);
206-
return mem.data[index];
167+
fn dev_read8(ctx: *anyopaque, idx: usize) u8 {
168+
const mem: *Self = @ptrCast(@alignCast(ctx));
169+
std.debug.assert(idx < mem.data.len);
170+
return mem.data[idx];
207171
}
208172

209-
fn mem_write(ctx: ?*anyopaque, index: Address, value: u8) void {
210-
const mem: *Self = @ptrCast(@alignCast(ctx.?));
211-
std.debug.assert(index < mem.data.len);
212-
mem.data[index] = value;
173+
fn dev_write8(ctx: *anyopaque, idx: usize, v: u8) void {
174+
const mem: *Self = @ptrCast(@alignCast(ctx));
175+
std.debug.assert(idx < mem.data.len);
176+
mem.data[idx] = v;
177+
}
178+
179+
fn dev_write_masked(ctx: *anyopaque, idx: usize, mask: u8, v: u8) void {
180+
const mem: *Self = @ptrCast(@alignCast(ctx));
181+
std.debug.assert(idx < mem.data.len);
182+
const old = mem.data[idx];
183+
mem.data[idx] = (old & ~mask) | (v & mask);
213184
}
214185
};
215186
}
@@ -275,6 +246,33 @@ pub const IO = struct {
275246
_ = ctx;
276247
return null;
277248
}
249+
};
250+
251+
// Unified byte-addressable device interface used by MemorySpace for RAM and IO
252+
pub const Device = struct {
253+
ctx: *anyopaque,
254+
vtable: *const VTable,
278255

279-
// no translate in new design
256+
pub const VTable = struct {
257+
read8: *const fn (ctx: *anyopaque, idx: usize) u8,
258+
write8: *const fn (ctx: *anyopaque, idx: usize, v: u8) void,
259+
write_masked: *const fn (ctx: *anyopaque, idx: usize, mask: u8, v: u8) void,
260+
check_exit: ?*const fn (ctx: *anyopaque) ?u8 = null,
261+
};
262+
263+
pub fn read8(self: *const Device, idx: usize) u8 {
264+
return self.vtable.read8(self.ctx, idx);
265+
}
266+
267+
pub fn write8(self: *const Device, idx: usize, v: u8) void {
268+
self.vtable.write8(self.ctx, idx, v);
269+
}
270+
271+
pub fn write_masked(self: *const Device, idx: usize, mask: u8, v: u8) void {
272+
self.vtable.write_masked(self.ctx, idx, mask, v);
273+
}
274+
275+
pub fn check_exit(self: *const Device) ?u8 {
276+
if (self.vtable.check_exit) |f| return f(self.ctx) else return null;
277+
}
280278
};

sim/aviron/src/lib/mcu.zig

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,21 @@ pub const Spaces = struct {
5151
pub fn build_spaces(
5252
alloc: std.mem.Allocator,
5353
cfg: Config,
54-
ram: *io_mod.RAM,
55-
io_mem: *io_mod.IO,
54+
sram_dev: io_mod.Device,
55+
io_dev: io_mod.Device,
5656
) !Spaces {
5757
// IO window size
5858
const io_size: usize = @intCast(cfg.io_window_end - cfg.io_window_base + 1);
5959

6060
// Data space: IO window mapped into data space (at base), then SRAM at sram_base
6161
var data_seg_buf: [2]memory.Segment = undefined;
62-
data_seg_buf[0] = .{ .at = cfg.io_window_base, .size = io_size, .backend = memory.Backend.fromIO(io_mem) };
63-
data_seg_buf[1] = .{ .at = @as(usize, cfg.sram_base), .size = ram.size, .backend = memory.Backend.fromRAM(ram) };
62+
data_seg_buf[0] = .{ .at = cfg.io_window_base, .size = io_size, .backend = io_dev };
63+
data_seg_buf[1] = .{ .at = @as(usize, cfg.sram_base), .size = cfg.sram_size, .backend = sram_dev };
6464
const data_space = try memory.MemorySpace.init(alloc, data_seg_buf[0..]);
6565

6666
// IO space: IO addresses starting at 0
6767
var io_seg_buf: [1]memory.Segment = undefined;
68-
io_seg_buf[0] = .{ .at = 0, .size = io_size, .backend = memory.Backend.fromIO(io_mem) };
68+
io_seg_buf[0] = .{ .at = 0, .size = io_size, .backend = io_dev };
6969
const io_space = try memory.MemorySpace.init(alloc, io_seg_buf[0..]);
7070

7171
return .{ .data = data_space, .io = io_space };
@@ -166,9 +166,9 @@ pub const atmega2560 = Config{
166166
pub const xmega128a4u = Config{
167167
.name = "ATxmega128A4U",
168168
.flash_size = 131072, // 128 KiB
169-
.sram_size = 8192, // 8 KiB
170-
.sram_base = 0x2000, // XMEGA SRAM typically starts at 0x2000
171-
.eeprom_size = 2048, // 2 KiB
169+
.sram_size = 8192, // 8 KiB
170+
.sram_base = 0x2000, // XMEGA SRAM typically starts at 0x2000
171+
.eeprom_size = 2048, // 2 KiB
172172
.code_model = .code22,
173173
.instruction_set = .avrxmega,
174174
.special_io = .{

0 commit comments

Comments
 (0)