Skip to content

Commit

Permalink
Some more docs, improved CLI parsing and target info
Browse files Browse the repository at this point in the history
  • Loading branch information
Felix "xq" Queißner committed Jan 15, 2024
1 parent bcaf1eb commit 0387120
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 28 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use_nix
15 changes: 15 additions & 0 deletions src/lib/Cpu.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ pub const CodeModel = enum(u24) {
code22 = 0x3F_FFFF,
};

// see: https://en.wikipedia.org/wiki/Atmel_AVR_instruction_set#Instruction_set_inheritance
pub const InstructionSet = enum {
avr1,
avr2,
@"avr2.5",
avr3,
avr4,
avr5,
@"avr5.1",
avr6,
avrxmega,
avrtiny10,
};

const InstructionEffect = enum {
none,

Expand All @@ -37,6 +51,7 @@ trace: bool = false,

// Device:
code_model: CodeModel,
instruction_set: InstructionSet,
sio: SpecialIoRegisters,
flash: Flash,
sram: RAM,
Expand Down
6 changes: 6 additions & 0 deletions src/lib/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub const Flash = struct {

ctx: ?*anyopaque,
vtable: *const VTable,

/// Size of the flash memory in bytes. Is always 2-aligned.
size: usize,

pub fn read(mem: Flash, addr: Address) u16 {
Expand Down Expand Up @@ -60,6 +62,8 @@ pub const RAM = struct {

ctx: ?*anyopaque,
vtable: *const VTable,

/// Size of the RAM memory space in bytes.
size: usize,

pub fn read(mem: RAM, addr: Address) u8 {
Expand Down Expand Up @@ -133,6 +137,8 @@ pub const IO = struct {
pub const Address = u6;

ctx: ?*anyopaque,

/// Size of the EEPROM in bytes.
vtable: *const VTable,

pub fn read(mem: IO, addr: Address) u8 {
Expand Down
111 changes: 83 additions & 28 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,23 @@ pub fn main() !u8 {
var cli = args_parser.parseForCurrentProcess(Cli, allocator, .print) catch return 1;
defer cli.deinit();

if (cli.positionals.len == 0)
@panic("usage: aviron [--trace] <elf>");
if (cli.options.help or (cli.positionals.len == 0 and !cli.options.info)) {
var stderr = std.io.getStdErr();

try args_parser.printHelp(
Cli,
cli.executable_name orelse "aviron",
stderr.writer(),
);

return if (cli.options.help) @as(u8, 0) else 1;
}

// Emulate Atmega382p device size:

// TODO: Add support for more MCUs!
std.debug.assert(cli.options.mcu == .atmega328p);

var flash_storage = aviron.Flash.Static(32768){};
var sram = aviron.RAM.Static(2048){};
var eeprom = aviron.EEPROM.Static(1024){};
Expand All @@ -21,31 +34,6 @@ pub fn main() !u8 {
.sp = 2047,
};

for (cli.positionals) |file_path| {
var elf_file = try std.fs.cwd().openFile(file_path, .{});
defer elf_file.close();

var source = std.io.StreamSource{ .file = elf_file };
var header = try std.elf.Header.read(&source);

var pheaders = header.program_header_iterator(&source);
while (try pheaders.next()) |phdr| {
if (phdr.p_type != std.elf.PT_LOAD)
continue; // Header isn't lodead

const dest_mem = if (phdr.p_vaddr >= 0x0080_0000)
&sram.data
else
&flash_storage.data;

const addr_masked: u24 = @intCast(phdr.p_vaddr & 0x007F_FFFF);

try source.seekTo(phdr.p_offset);
try source.reader().readNoEof(dest_mem[addr_masked..][0..phdr.p_filesz]);
@memset(dest_mem[addr_masked + phdr.p_filesz ..][0 .. phdr.p_memsz - phdr.p_filesz], 0);
}
}

var cpu = aviron.Cpu{
.trace = cli.options.trace,

Expand All @@ -55,6 +43,7 @@ pub fn main() !u8 {
.io = io.memory(),

.code_model = .code16,
.instruction_set = .avr5,

.sio = .{
.ramp_x = null,
Expand All @@ -72,17 +61,83 @@ pub fn main() !u8 {

io.sreg = &cpu.sreg;

if (cli.options.info) {
var stdout = std.io.getStdOut().writer();
try stdout.print("Information for {s}:\n", .{@tagName(cli.options.mcu)});
try stdout.print(" Generation: {s: >11}\n", .{@tagName(cpu.instruction_set)});
try stdout.print(" Code Model: {s: >11}\n", .{@tagName(cpu.code_model)});
try stdout.print(" RAM: {d: >5} bytes\n", .{flash_storage.memory().size});
try stdout.print(" Flash: {d: >5} bytes\n", .{sram.memory().size});
try stdout.print(" EEPROM: {d: >5} bytes\n", .{eeprom.memory().size});
return 0;
}

// Load all provided executables:
for (cli.positionals) |file_path| {
var elf_file = try std.fs.cwd().openFile(file_path, .{});
defer elf_file.close();

var source = std.io.StreamSource{ .file = elf_file };
var header = try std.elf.Header.read(&source);

var pheaders = header.program_header_iterator(&source);
while (try pheaders.next()) |phdr| {
if (phdr.p_type != std.elf.PT_LOAD)
continue; // Header isn't lodead

const dest_mem = if (phdr.p_vaddr >= 0x0080_0000)
&sram.data
else
&flash_storage.data;

const addr_masked: u24 = @intCast(phdr.p_vaddr & 0x007F_FFFF);

try source.seekTo(phdr.p_offset);
try source.reader().readNoEof(dest_mem[addr_masked..][0..phdr.p_filesz]);
@memset(dest_mem[addr_masked + phdr.p_filesz ..][0 .. phdr.p_memsz - phdr.p_filesz], 0);
}
}

const result = try cpu.run(null);

std.debug.print("STOP: {s}\n", .{@tagName(result)});

return 0;
}

// not actually marvel cinematic universe, but microcontroller unit ;
pub const MCU = enum {
atmega328p,
};

const Cli = struct {
help: bool = false,

trace: bool = false,
mcu: MCU = .atmega328p,
info: bool = false,

pub const shorthands = .{
.h = "help",
.t = "trace",
.m = "mcu",
.I = "info",
};
pub const meta = .{
.summary = "[-h] [-t] [-m <mcu>] <elf> ...",
.full_text =
\\AViRon is a simulator for the AVR cpu architecture as well as an basic emulator for several microcontrollers from Microchip/Atmel.
\\
\\Loads at least a single <elf> file into the memory of the system and executes it with the provided MCU.
\\
\\The code can use certain special registers to perform I/O and exit the emulator.
,
.option_docs = .{
.help = "Prints this help text.",
.trace = "Trace all executed instructions.",
.mcu = "Selects the emulated MCU.",
.info = "Prints information about the given MCUs memory.",
},
};
};

const IO = struct {
Expand Down

0 comments on commit 0387120

Please sign in to comment.