Skip to content

Commit e1f8316

Browse files
authored
Unify interface, add memory mapping (#704)
1 parent b97db90 commit e1f8316

File tree

8 files changed

+849
-340
lines changed

8 files changed

+849
-340
lines changed

sim/aviron/build.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,17 @@ fn add_test_suite(
135135
});
136136
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
137137

138+
// Run unit tests for low-level library components (e.g., bus.zig)
139+
const memory_tests = b.addTest(.{
140+
.root_module = b.createModule(.{
141+
.root_source_file = b.path("src/lib/bus.zig"),
142+
.target = host_target,
143+
.optimize = optimize,
144+
}),
145+
.use_llvm = true,
146+
});
147+
test_step.dependOn(&b.addRunArtifact(memory_tests).step);
148+
138149
const testrunner_exe = b.addExecutable(.{
139150
.name = "aviron-test-runner",
140151
.root_module = b.createModule(.{

sim/aviron/src/lib/Cpu.zig

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
const std = @import("std");
22
const isa = @import("decoder.zig");
3-
const io_mod = @import("io.zig");
3+
const bus = @import("bus.zig");
44

5-
const Flash = io_mod.Flash;
6-
const RAM = io_mod.RAM;
7-
const EEPROM = io_mod.EEPROM;
8-
const IO = io_mod.IO;
5+
const Flash = bus.Flash;
6+
const IO = bus.IO;
7+
const DataBus = bus.DataBus;
8+
const IOBus = bus.IOBus;
99

1010
const Cpu = @This();
1111

@@ -57,9 +57,8 @@ code_model: CodeModel,
5757
instruction_set: InstructionSet,
5858
sio: SpecialIoRegisters,
5959
flash: Flash,
60-
sram: RAM,
61-
eeprom: EEPROM,
62-
io: IO,
60+
data: DataBus,
61+
io: IOBus,
6362

6463
// State
6564
pc: u24 = 0,
@@ -180,21 +179,26 @@ fn fetch_code(cpu: *Cpu) u16 {
180179
}
181180

182181
fn push(cpu: *Cpu, val: u8) void {
182+
// AVR PUSH: Write to [SP] first, then decrement SP
183+
// SP points to the first unused location
183184
const sp = cpu.get_sp();
184-
cpu.sram.write(sp, val);
185+
cpu.data.write(sp, val);
185186
cpu.set_sp(sp -% 1);
186187
}
187188

188189
fn pop(cpu: *Cpu) u8 {
190+
// AVR POP: Increment SP first, then read from [SP]
189191
const sp = cpu.get_sp() +% 1;
190192
cpu.set_sp(sp);
191-
return cpu.sram.read(sp);
193+
return cpu.data.read(sp);
192194
}
193195

194196
fn push_code_loc(cpu: *Cpu, val: u24) void {
195197
const pc: u24 = val;
196198
const mask: u24 = @intFromEnum(cpu.code_model);
197199

200+
// AVR pushes return address bytes so that RET pops low byte first.
201+
// With write-then-decrement PUSH, we push least significant byte first.
198202
if ((mask & 0x0000FF) != 0) {
199203
cpu.push(@truncate(pc >> 0));
200204
}
@@ -219,7 +223,6 @@ fn pop_code_loc(cpu: *Cpu) u24 {
219223
if ((mask & 0x0000FF) != 0) {
220224
pc |= (@as(u24, cpu.pop()) << 0);
221225
}
222-
223226
return pc;
224227
}
225228

@@ -258,9 +261,9 @@ fn write_wide_reg(cpu: *Cpu, reg: WideReg, value: u24, comptime mode: IndexRegWr
258261
cpu.regs[reg.base() + 1] = parts[1];
259262
if (mode == .ramp) {
260263
switch (reg) {
261-
.x => if (cpu.sio.ramp_x) |ramp| cpu.io.write(ramp, parts[2]),
262-
.y => if (cpu.sio.ramp_y) |ramp| cpu.io.write(ramp, parts[2]),
263-
.z => if (cpu.sio.ramp_z) |ramp| cpu.io.write(ramp, parts[2]),
264+
.x => if (cpu.sio.ramp_x) |ramp| cpu.io.write(ramp, 0xFF, parts[2]),
265+
.y => if (cpu.sio.ramp_y) |ramp| cpu.io.write(ramp, 0xFF, parts[2]),
266+
.z => if (cpu.sio.ramp_z) |ramp| cpu.io.write(ramp, 0xFF, parts[2]),
264267
}
265268
}
266269
}
@@ -768,7 +771,7 @@ const instructions = struct {
768771
/// Stores data from register Rr in the Register File to I/O Space (Ports, Timers, Configuration Registers, etc.).
769772
inline fn out(cpu: *Cpu, info: isa.opinfo.a6r5) void {
770773
// I/O(A) ← Rr
771-
cpu.io.write(info.a, cpu.regs[info.r.num()]);
774+
cpu.io.write(info.a, 0xFF, cpu.regs[info.r.num()]);
772775
}
773776

774777
/// IN - Load an I/O Location to Register
@@ -783,14 +786,14 @@ const instructions = struct {
783786
/// addresses 0-31.
784787
inline fn cbi(cpu: *Cpu, info: isa.opinfo.a5b3) void {
785788
// I/O(A,b) ← 0
786-
cpu.io.write_masked(info.a, info.b.mask(), 0x00);
789+
cpu.io.write(info.a, info.b.mask(), 0x00);
787790
}
788791

789792
/// SBI – Set Bit in I/O Register
790793
/// Sets a specified bit in an I/O Register. This instruction operates on the lower 32 I/O Registers – addresses 0-31.
791794
inline fn sbi(cpu: *Cpu, info: isa.opinfo.a5b3) void {
792795
// I/O(A,b) ← 1
793-
cpu.io.write_masked(info.a, info.b.mask(), 0xFF);
796+
cpu.io.write(info.a, info.b.mask(), 0xFF);
794797
}
795798

796799
// Branching:
@@ -1041,8 +1044,8 @@ const instructions = struct {
10411044
const z = cpu.read_wide_reg(.z, .ramp);
10421045

10431046
const Rd = cpu.regs[info.r.num()];
1044-
const mem = cpu.sram.read(z);
1045-
cpu.sram.write(z, Rd);
1047+
const mem = cpu.data.read(z);
1048+
cpu.data.write(z, Rd);
10461049
cpu.regs[info.r.num()] = mem;
10471050
}
10481051

@@ -1060,8 +1063,8 @@ const instructions = struct {
10601063
const z = cpu.read_wide_reg(.z, .ramp);
10611064

10621065
const Rd = cpu.regs[info.r.num()];
1063-
const mem = cpu.sram.read(z);
1064-
cpu.sram.write(z, (0xFF - Rd) & mem);
1066+
const mem = cpu.data.read(z);
1067+
cpu.data.write(z, (0xFF - Rd) & mem);
10651068
cpu.regs[info.r.num()] = mem;
10661069
}
10671070

@@ -1079,8 +1082,8 @@ const instructions = struct {
10791082
const z = cpu.read_wide_reg(.z, .ramp);
10801083

10811084
const Rd = cpu.regs[info.r.num()];
1082-
const mem = cpu.sram.read(z);
1083-
cpu.sram.write(z, Rd | mem);
1085+
const mem = cpu.data.read(z);
1086+
cpu.data.write(z, Rd | mem);
10841087
cpu.regs[info.r.num()] = mem;
10851088
}
10861089

@@ -1097,8 +1100,8 @@ const instructions = struct {
10971100
const z = cpu.read_wide_reg(.z, .ramp);
10981101

10991102
const Rd = cpu.regs[info.r.num()];
1100-
const mem = cpu.sram.read(z);
1101-
cpu.sram.write(z, Rd ^ mem);
1103+
const mem = cpu.data.read(z);
1104+
cpu.data.write(z, Rd ^ mem);
11021105
cpu.regs[info.r.num()] = mem;
11031106
}
11041107

@@ -1117,7 +1120,7 @@ const instructions = struct {
11171120
inline fn lds(cpu: *Cpu, info: isa.opinfo.d5) void {
11181121
// Rd ← (k)
11191122
const addr = cpu.extend_direct_address(cpu.fetch_code());
1120-
cpu.regs[info.d.num()] = cpu.sram.read(addr);
1123+
cpu.regs[info.d.num()] = cpu.data.read(addr);
11211124
}
11221125

11231126
const IndexOpMode = enum { none, post_incr, pre_decr, displace };
@@ -1150,7 +1153,7 @@ const instructions = struct {
11501153
.rd = .ramp,
11511154
.wb = .ramp,
11521155
});
1153-
cpu.regs[d.num()] = cpu.sram.read(address);
1156+
cpu.regs[d.num()] = cpu.data.read(address);
11541157
}
11551158

11561159
/// LD – Load Indirect from Data Space to Register using Index X
@@ -1307,7 +1310,7 @@ const instructions = struct {
13071310
.rd = .ramp,
13081311
.wb = .ramp,
13091312
});
1310-
cpu.sram.write(address, cpu.regs[r.num()]);
1313+
cpu.data.write(address, cpu.regs[r.num()]);
13111314
}
13121315

13131316
/// ST – Store Indirect From Register to Data Space using Index X
@@ -1422,7 +1425,7 @@ const instructions = struct {
14221425
inline fn sts(cpu: *Cpu, info: isa.opinfo.d5) void {
14231426
// (k) ← Rr
14241427
const addr = cpu.extend_direct_address(cpu.fetch_code());
1425-
cpu.sram.write(addr, cpu.regs[info.d.num()]);
1428+
cpu.data.write(addr, cpu.regs[info.d.num()]);
14261429
}
14271430

14281431
/// PUSH – Push Register on Stack
@@ -1659,9 +1662,8 @@ fn get_sp(cpu: *Cpu) u16 {
16591662
fn set_sp(cpu: *Cpu, value: u16) void {
16601663
const lo: u8 = @truncate(value >> 0);
16611664
const hi: u8 = @truncate(value >> 8);
1662-
1663-
cpu.io.write(cpu.sio.sp_l, lo);
1664-
cpu.io.write(cpu.sio.sp_h, hi);
1665+
cpu.io.write(cpu.sio.sp_l, 0xFF, lo);
1666+
cpu.io.write(cpu.sio.sp_h, 0xFF, hi);
16651667
}
16661668

16671669
fn compose24(hi: u8, mid: u8, lo: u8) u24 {

sim/aviron/src/lib/aviron.zig

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
const std = @import("std");
22
const builtin = @import("builtin");
3-
const io = @import("io.zig");
3+
const bus = @import("bus.zig");
44
const isa = @import("isa");
55

66
pub const Cpu = @import("Cpu.zig");
77

8-
pub const Flash = io.Flash;
9-
pub const RAM = io.RAM;
10-
pub const EEPROM = io.EEPROM;
11-
pub const IO = io.IO;
8+
pub const Flash = bus.Flash;
9+
pub const IO = bus.IO;
10+
pub const Bus = bus.Bus;
11+
pub const IOBus = bus.IOBus;
12+
13+
pub const FixedSizedMemory = bus.FixedSizedMemory;
14+
15+
pub const mcu = @import("mcu.zig");
1216

1317
pub const Register = isa.Register;

0 commit comments

Comments
 (0)