style(eeprom): move eeprom code to it's own file
This commit is contained in:
		@@ -2,6 +2,8 @@ const std = @import("std");
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
const log = std.log.scoped(.Backup);
 | 
			
		||||
 | 
			
		||||
const Eeprom = @import("backup/eeprom.zig").Eeprom;
 | 
			
		||||
 | 
			
		||||
const escape = @import("../../util.zig").escape;
 | 
			
		||||
const span = @import("../../util.zig").span;
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +57,7 @@ pub const Backup = struct {
 | 
			
		||||
            .title = title,
 | 
			
		||||
            .save_path = path,
 | 
			
		||||
            .flash = Flash.init(),
 | 
			
		||||
            .eeprom = Eeprom.init(allocator),
 | 
			
		||||
            .eeprom = Eeprom.create(allocator),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (backup.save_path) |p| backup.loadSaveFromDisk(allocator, p) catch |e| log.err("Failed to load save: {}", .{e});
 | 
			
		||||
@@ -300,267 +302,3 @@ const Flash = struct {
 | 
			
		||||
        return if (self.bank == 1) 0x10000 else @as(usize, 0);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Eeprom = struct {
 | 
			
		||||
    const Self = @This();
 | 
			
		||||
 | 
			
		||||
    addr: u14,
 | 
			
		||||
 | 
			
		||||
    kind: Kind,
 | 
			
		||||
    state: State,
 | 
			
		||||
    writer: Writer,
 | 
			
		||||
    reader: Reader,
 | 
			
		||||
 | 
			
		||||
    allocator: Allocator,
 | 
			
		||||
 | 
			
		||||
    const Kind = enum {
 | 
			
		||||
        Unknown,
 | 
			
		||||
        Small, // 512B
 | 
			
		||||
        Large, // 8KB
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const State = enum {
 | 
			
		||||
        Ready,
 | 
			
		||||
        Read,
 | 
			
		||||
        Write,
 | 
			
		||||
        WriteTransfer,
 | 
			
		||||
        RequestEnd,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    fn init(allocator: Allocator) Self {
 | 
			
		||||
        return .{
 | 
			
		||||
            .kind = .Unknown,
 | 
			
		||||
            .state = .Ready,
 | 
			
		||||
            .writer = Writer.init(),
 | 
			
		||||
            .reader = Reader.init(),
 | 
			
		||||
            .addr = 0,
 | 
			
		||||
            .allocator = allocator,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn read(self: *Self) u1 {
 | 
			
		||||
        return self.reader.read();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn dbgRead(self: *const Self) u1 {
 | 
			
		||||
        return self.reader.dbgRead();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write(self: *Self, word_count: u16, buf: *[]u8, bit: u1) void {
 | 
			
		||||
        if (self.guessKind(word_count)) |found| {
 | 
			
		||||
            log.info("EEPROM Kind: {}", .{found});
 | 
			
		||||
            self.kind = found;
 | 
			
		||||
 | 
			
		||||
            // buf.len will not equal zero when a save file was found and loaded.
 | 
			
		||||
            // Right now, we assume that the save file is of the correct size which
 | 
			
		||||
            // isn't necessarily true, since we can't trust anything a user can influence
 | 
			
		||||
            // TODO: use ?[]u8 instead of a 0-sized slice?
 | 
			
		||||
            if (buf.len == 0) {
 | 
			
		||||
                const len: usize = switch (found) {
 | 
			
		||||
                    .Small => 0x200,
 | 
			
		||||
                    .Large => 0x2000,
 | 
			
		||||
                    else => unreachable,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                buf.* = self.allocator.alloc(u8, len) catch |e| {
 | 
			
		||||
                    log.err("Failed to resize EEPROM buf to {} bytes", .{len});
 | 
			
		||||
                    std.debug.panic("EEPROM entered irrecoverable state {}", .{e});
 | 
			
		||||
                };
 | 
			
		||||
                std.mem.set(u8, buf.*, 0xFF);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (self.state == .RequestEnd) {
 | 
			
		||||
            if (bit != 0) log.debug("EEPROM Request did not end in 0u1. TODO: is this ok?", .{});
 | 
			
		||||
            self.state = .Ready;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (self.state) {
 | 
			
		||||
            .Ready => self.writer.requestWrite(bit),
 | 
			
		||||
            .Read, .Write => self.writer.addressWrite(self.kind, bit),
 | 
			
		||||
            .WriteTransfer => self.writer.dataWrite(bit),
 | 
			
		||||
            .RequestEnd => unreachable, // We return early just above this block
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.tick(buf.*);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn guessKind(self: *const Self, word_count: u16) ?Kind {
 | 
			
		||||
        if (self.kind != .Unknown or self.state != .Read) return null;
 | 
			
		||||
 | 
			
		||||
        return switch (word_count) {
 | 
			
		||||
            17 => .Large,
 | 
			
		||||
            9 => .Small,
 | 
			
		||||
            else => blk: {
 | 
			
		||||
                log.err("Unexpected length of DMA3 Transfer upon initial EEPROM read: {}", .{word_count});
 | 
			
		||||
                break :blk null;
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn tick(self: *Self, buf: []u8) void {
 | 
			
		||||
        switch (self.state) {
 | 
			
		||||
            .Ready => {
 | 
			
		||||
                if (self.writer.len() == 2) {
 | 
			
		||||
                    const req = @intCast(u2, self.writer.finish());
 | 
			
		||||
                    switch (req) {
 | 
			
		||||
                        0b11 => self.state = .Read,
 | 
			
		||||
                        0b10 => self.state = .Write,
 | 
			
		||||
                        else => log.err("Unknown EEPROM Request 0b{b:0>2}", .{req}),
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .Read => {
 | 
			
		||||
                switch (self.kind) {
 | 
			
		||||
                    .Large => {
 | 
			
		||||
                        if (self.writer.len() == 14) {
 | 
			
		||||
                            const addr = @intCast(u10, self.writer.finish());
 | 
			
		||||
                            const value = std.mem.readIntSliceLittle(u64, buf[@as(u13, addr) * 8 ..][0..8]);
 | 
			
		||||
 | 
			
		||||
                            self.reader.configure(value);
 | 
			
		||||
                            self.state = .RequestEnd;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    .Small => {
 | 
			
		||||
                        if (self.writer.len() == 6) {
 | 
			
		||||
                            // FIXME: Duplicated code from above
 | 
			
		||||
                            const addr = @intCast(u6, self.writer.finish());
 | 
			
		||||
                            const value = std.mem.readIntSliceLittle(u64, buf[@as(u13, addr) * 8 ..][0..8]);
 | 
			
		||||
 | 
			
		||||
                            self.reader.configure(value);
 | 
			
		||||
                            self.state = .RequestEnd;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    else => log.err("Unable to calculate EEPROM read address. EEPROM size UNKNOWN", .{}),
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .Write => {
 | 
			
		||||
                switch (self.kind) {
 | 
			
		||||
                    .Large => {
 | 
			
		||||
                        if (self.writer.len() == 14) {
 | 
			
		||||
                            self.addr = @intCast(u10, self.writer.finish());
 | 
			
		||||
                            self.state = .WriteTransfer;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    .Small => {
 | 
			
		||||
                        if (self.writer.len() == 6) {
 | 
			
		||||
                            self.addr = @intCast(u6, self.writer.finish());
 | 
			
		||||
                            self.state = .WriteTransfer;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    else => log.err("Unable to calculate EEPROM write address. EEPROM size UNKNOWN", .{}),
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .WriteTransfer => {
 | 
			
		||||
                if (self.writer.len() == 64) {
 | 
			
		||||
                    std.mem.writeIntSliceLittle(u64, buf[self.addr * 8 ..][0..8], self.writer.finish());
 | 
			
		||||
                    self.state = .RequestEnd;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .RequestEnd => unreachable, // We return early in write() if state is .RequestEnd
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Reader = struct {
 | 
			
		||||
        const This = @This();
 | 
			
		||||
 | 
			
		||||
        data: u64,
 | 
			
		||||
        i: u8,
 | 
			
		||||
        enabled: bool,
 | 
			
		||||
 | 
			
		||||
        fn init() This {
 | 
			
		||||
            return .{
 | 
			
		||||
                .data = 0,
 | 
			
		||||
                .i = 0,
 | 
			
		||||
                .enabled = false,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn configure(self: *This, value: u64) void {
 | 
			
		||||
            self.data = value;
 | 
			
		||||
            self.i = 0;
 | 
			
		||||
            self.enabled = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn read(self: *This) u1 {
 | 
			
		||||
            if (!self.enabled) return 1;
 | 
			
		||||
 | 
			
		||||
            const bit = if (self.i < 4) blk: {
 | 
			
		||||
                break :blk 0;
 | 
			
		||||
            } else blk: {
 | 
			
		||||
                const idx = @intCast(u6, 63 - (self.i - 4));
 | 
			
		||||
                break :blk @truncate(u1, self.data >> idx);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            self.i = (self.i + 1) % (64 + 4);
 | 
			
		||||
            if (self.i == 0) self.enabled = false;
 | 
			
		||||
 | 
			
		||||
            return bit;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn dbgRead(self: *const This) u1 {
 | 
			
		||||
            if (!self.enabled) return 1;
 | 
			
		||||
 | 
			
		||||
            const bit = if (self.i < 4) blk: {
 | 
			
		||||
                break :blk 0;
 | 
			
		||||
            } else blk: {
 | 
			
		||||
                const idx = @intCast(u6, 63 - (self.i - 4));
 | 
			
		||||
                break :blk @truncate(u1, self.data >> idx);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return bit;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const Writer = struct {
 | 
			
		||||
        const This = @This();
 | 
			
		||||
 | 
			
		||||
        data: u64,
 | 
			
		||||
        i: u8,
 | 
			
		||||
 | 
			
		||||
        fn init() This {
 | 
			
		||||
            return .{ .data = 0, .i = 0 };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn requestWrite(self: *This, bit: u1) void {
 | 
			
		||||
            const idx = @intCast(u1, 1 - self.i);
 | 
			
		||||
            self.data = (self.data & ~(@as(u64, 1) << idx)) | (@as(u64, bit) << idx);
 | 
			
		||||
            self.i += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn addressWrite(self: *This, kind: Eeprom.Kind, bit: u1) void {
 | 
			
		||||
            if (kind == .Unknown) return;
 | 
			
		||||
 | 
			
		||||
            const size: u4 = switch (kind) {
 | 
			
		||||
                .Large => 13,
 | 
			
		||||
                .Small => 5,
 | 
			
		||||
                .Unknown => unreachable,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const idx = @intCast(u4, size - self.i);
 | 
			
		||||
            self.data = (self.data & ~(@as(u64, 1) << idx)) | (@as(u64, bit) << idx);
 | 
			
		||||
            self.i += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn dataWrite(self: *This, bit: u1) void {
 | 
			
		||||
            const idx = @intCast(u6, 63 - self.i);
 | 
			
		||||
            self.data = (self.data & ~(@as(u64, 1) << idx)) | (@as(u64, bit) << idx);
 | 
			
		||||
            self.i += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn len(self: *const This) u8 {
 | 
			
		||||
            return self.i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn finish(self: *This) u64 {
 | 
			
		||||
            defer self.reset();
 | 
			
		||||
            return self.data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn reset(self: *This) void {
 | 
			
		||||
            self.i = 0;
 | 
			
		||||
            self.data = 0;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										269
									
								
								src/core/bus/backup/eeprom.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								src/core/bus/backup/eeprom.zig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,269 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
 | 
			
		||||
const log = std.log.scoped(.Eeprom);
 | 
			
		||||
 | 
			
		||||
pub const Eeprom = struct {
 | 
			
		||||
    const Self = @This();
 | 
			
		||||
 | 
			
		||||
    addr: u14,
 | 
			
		||||
 | 
			
		||||
    kind: Kind,
 | 
			
		||||
    state: State,
 | 
			
		||||
    writer: Writer,
 | 
			
		||||
    reader: Reader,
 | 
			
		||||
 | 
			
		||||
    allocator: Allocator,
 | 
			
		||||
 | 
			
		||||
    const Kind = enum {
 | 
			
		||||
        Unknown,
 | 
			
		||||
        Small, // 512B
 | 
			
		||||
        Large, // 8KB
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const State = enum {
 | 
			
		||||
        Ready,
 | 
			
		||||
        Read,
 | 
			
		||||
        Write,
 | 
			
		||||
        WriteTransfer,
 | 
			
		||||
        RequestEnd,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    pub fn read(self: *Self) u1 {
 | 
			
		||||
        return self.reader.read();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn dbgRead(self: *const Self) u1 {
 | 
			
		||||
        return self.reader.dbgRead();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write(self: *Self, word_count: u16, buf: *[]u8, bit: u1) void {
 | 
			
		||||
        if (self.guessKind(word_count)) |found| {
 | 
			
		||||
            log.info("EEPROM Kind: {}", .{found});
 | 
			
		||||
            self.kind = found;
 | 
			
		||||
 | 
			
		||||
            // buf.len will not equal zero when a save file was found and loaded.
 | 
			
		||||
            // Right now, we assume that the save file is of the correct size which
 | 
			
		||||
            // isn't necessarily true, since we can't trust anything a user can influence
 | 
			
		||||
            // TODO: use ?[]u8 instead of a 0-sized slice?
 | 
			
		||||
            if (buf.len == 0) {
 | 
			
		||||
                const len: usize = switch (found) {
 | 
			
		||||
                    .Small => 0x200,
 | 
			
		||||
                    .Large => 0x2000,
 | 
			
		||||
                    else => unreachable,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                buf.* = self.allocator.alloc(u8, len) catch |e| {
 | 
			
		||||
                    log.err("Failed to resize EEPROM buf to {} bytes", .{len});
 | 
			
		||||
                    std.debug.panic("EEPROM entered irrecoverable state {}", .{e});
 | 
			
		||||
                };
 | 
			
		||||
                std.mem.set(u8, buf.*, 0xFF);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (self.state == .RequestEnd) {
 | 
			
		||||
            if (bit != 0) log.debug("EEPROM Request did not end in 0u1. TODO: is this ok?", .{});
 | 
			
		||||
            self.state = .Ready;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (self.state) {
 | 
			
		||||
            .Ready => self.writer.requestWrite(bit),
 | 
			
		||||
            .Read, .Write => self.writer.addressWrite(self.kind, bit),
 | 
			
		||||
            .WriteTransfer => self.writer.dataWrite(bit),
 | 
			
		||||
            .RequestEnd => unreachable, // We return early just above this block
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.tick(buf.*);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn create(allocator: Allocator) Self {
 | 
			
		||||
        return .{
 | 
			
		||||
            .kind = .Unknown,
 | 
			
		||||
            .state = .Ready,
 | 
			
		||||
            .writer = Writer.create(),
 | 
			
		||||
            .reader = Reader.create(),
 | 
			
		||||
            .addr = 0,
 | 
			
		||||
            .allocator = allocator,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn guessKind(self: *const Self, word_count: u16) ?Kind {
 | 
			
		||||
        if (self.kind != .Unknown or self.state != .Read) return null;
 | 
			
		||||
 | 
			
		||||
        return switch (word_count) {
 | 
			
		||||
            17 => .Large,
 | 
			
		||||
            9 => .Small,
 | 
			
		||||
            else => blk: {
 | 
			
		||||
                log.err("Unexpected length of DMA3 Transfer upon initial EEPROM read: {}", .{word_count});
 | 
			
		||||
                break :blk null;
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn tick(self: *Self, buf: []u8) void {
 | 
			
		||||
        switch (self.state) {
 | 
			
		||||
            .Ready => {
 | 
			
		||||
                if (self.writer.len() == 2) {
 | 
			
		||||
                    const req = @intCast(u2, self.writer.finish());
 | 
			
		||||
                    switch (req) {
 | 
			
		||||
                        0b11 => self.state = .Read,
 | 
			
		||||
                        0b10 => self.state = .Write,
 | 
			
		||||
                        else => log.err("Unknown EEPROM Request 0b{b:0>2}", .{req}),
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .Read => {
 | 
			
		||||
                switch (self.kind) {
 | 
			
		||||
                    .Large => {
 | 
			
		||||
                        if (self.writer.len() == 14) {
 | 
			
		||||
                            const addr = @intCast(u10, self.writer.finish());
 | 
			
		||||
                            const value = std.mem.readIntSliceLittle(u64, buf[@as(u13, addr) * 8 ..][0..8]);
 | 
			
		||||
 | 
			
		||||
                            self.reader.configure(value);
 | 
			
		||||
                            self.state = .RequestEnd;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    .Small => {
 | 
			
		||||
                        if (self.writer.len() == 6) {
 | 
			
		||||
                            // FIXME: Duplicated code from above
 | 
			
		||||
                            const addr = @intCast(u6, self.writer.finish());
 | 
			
		||||
                            const value = std.mem.readIntSliceLittle(u64, buf[@as(u13, addr) * 8 ..][0..8]);
 | 
			
		||||
 | 
			
		||||
                            self.reader.configure(value);
 | 
			
		||||
                            self.state = .RequestEnd;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    else => log.err("Unable to calculate EEPROM read address. EEPROM size UNKNOWN", .{}),
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .Write => {
 | 
			
		||||
                switch (self.kind) {
 | 
			
		||||
                    .Large => {
 | 
			
		||||
                        if (self.writer.len() == 14) {
 | 
			
		||||
                            self.addr = @intCast(u10, self.writer.finish());
 | 
			
		||||
                            self.state = .WriteTransfer;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    .Small => {
 | 
			
		||||
                        if (self.writer.len() == 6) {
 | 
			
		||||
                            self.addr = @intCast(u6, self.writer.finish());
 | 
			
		||||
                            self.state = .WriteTransfer;
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    else => log.err("Unable to calculate EEPROM write address. EEPROM size UNKNOWN", .{}),
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .WriteTransfer => {
 | 
			
		||||
                if (self.writer.len() == 64) {
 | 
			
		||||
                    std.mem.writeIntSliceLittle(u64, buf[self.addr * 8 ..][0..8], self.writer.finish());
 | 
			
		||||
                    self.state = .RequestEnd;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            .RequestEnd => unreachable, // We return early in write() if state is .RequestEnd
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Reader = struct {
 | 
			
		||||
    const Self = @This();
 | 
			
		||||
 | 
			
		||||
    data: u64,
 | 
			
		||||
    i: u8,
 | 
			
		||||
    enabled: bool,
 | 
			
		||||
 | 
			
		||||
    fn create() Self {
 | 
			
		||||
        return .{
 | 
			
		||||
            .data = 0,
 | 
			
		||||
            .i = 0,
 | 
			
		||||
            .enabled = false,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read(self: *Self) u1 {
 | 
			
		||||
        if (!self.enabled) return 1;
 | 
			
		||||
 | 
			
		||||
        const bit = if (self.i < 4) blk: {
 | 
			
		||||
            break :blk 0;
 | 
			
		||||
        } else blk: {
 | 
			
		||||
            const idx = @intCast(u6, 63 - (self.i - 4));
 | 
			
		||||
            break :blk @truncate(u1, self.data >> idx);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.i = (self.i + 1) % (64 + 4);
 | 
			
		||||
        if (self.i == 0) self.enabled = false;
 | 
			
		||||
 | 
			
		||||
        return bit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn dbgRead(self: *const Self) u1 {
 | 
			
		||||
        if (!self.enabled) return 1;
 | 
			
		||||
 | 
			
		||||
        const bit = if (self.i < 4) blk: {
 | 
			
		||||
            break :blk 0;
 | 
			
		||||
        } else blk: {
 | 
			
		||||
            const idx = @intCast(u6, 63 - (self.i - 4));
 | 
			
		||||
            break :blk @truncate(u1, self.data >> idx);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return bit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn configure(self: *Self, value: u64) void {
 | 
			
		||||
        self.data = value;
 | 
			
		||||
        self.i = 0;
 | 
			
		||||
        self.enabled = true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Writer = struct {
 | 
			
		||||
    const Self = @This();
 | 
			
		||||
 | 
			
		||||
    data: u64,
 | 
			
		||||
    i: u8,
 | 
			
		||||
 | 
			
		||||
    fn create() Self {
 | 
			
		||||
        return .{ .data = 0, .i = 0 };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn requestWrite(self: *Self, bit: u1) void {
 | 
			
		||||
        const idx = @intCast(u1, 1 - self.i);
 | 
			
		||||
        self.data = (self.data & ~(@as(u64, 1) << idx)) | (@as(u64, bit) << idx);
 | 
			
		||||
        self.i += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn addressWrite(self: *Self, kind: Eeprom.Kind, bit: u1) void {
 | 
			
		||||
        if (kind == .Unknown) return;
 | 
			
		||||
 | 
			
		||||
        const size: u4 = switch (kind) {
 | 
			
		||||
            .Large => 13,
 | 
			
		||||
            .Small => 5,
 | 
			
		||||
            .Unknown => unreachable,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const idx = @intCast(u4, size - self.i);
 | 
			
		||||
        self.data = (self.data & ~(@as(u64, 1) << idx)) | (@as(u64, bit) << idx);
 | 
			
		||||
        self.i += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn dataWrite(self: *Self, bit: u1) void {
 | 
			
		||||
        const idx = @intCast(u6, 63 - self.i);
 | 
			
		||||
        self.data = (self.data & ~(@as(u64, 1) << idx)) | (@as(u64, bit) << idx);
 | 
			
		||||
        self.i += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn len(self: *const Self) u8 {
 | 
			
		||||
        return self.i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn finish(self: *Self) u64 {
 | 
			
		||||
        defer self.reset();
 | 
			
		||||
        return self.data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn reset(self: *Self) void {
 | 
			
		||||
        self.i = 0;
 | 
			
		||||
        self.data = 0;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user