From f1b86b9a6f6004e0ae7cabf38594859ba1d5ef04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=22xq=22=20Quei=C3=9Fner?= Date: Sat, 1 Aug 2026 15:13:32 +0200 Subject: [PATCH] Patches some stuff for Ashet development-. --- build.zig.zon | 4 + core/src/cpus/cortex_m.zig | 4 +- port/raspberrypi/rp2xxx/src/hal/dma.zig | 140 ++++++++++++++---- .../rp2xxx/src/hal/pio/assembler.zig | 2 + .../rp2xxx/src/hal/pio/assembler/encoder.zig | 21 ++- .../raspberrypi/rp2xxx/src/hal/pio/common.zig | 27 +++- 6 files changed, 160 insertions(+), 38 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 30dde66c6..f75864ab9 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -46,6 +46,10 @@ .url = "git+https://codeberg.org/mattnite/boxzer.git#4021540de4b07c11102dd4d46383ce0066f838bb", .hash = "boxzer-0.1.0--ed-MPrnAAAQAwXnfMJuSkgAsw4FseHEHKcn7OMKXGZS", }, + .serial = .{ + .url = "git+https://github.com/ZigEmbeddedGroup/serial.git?ref=master#fbd7389ff8bbc9fa362aa74081588755b5d028a0", + .hash = "serial-0.0.1-PoeRzF60AAAN8Iu0yXTIX-t3DVzsnmN7vWHKM2HA2Zbq", + }, }, .paths = .{ "README.md", diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index 2a8e2e425..6c07f71b9 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -693,7 +693,7 @@ pub inline fn enable_fpu() void { /// The RAM vector table used. You can swap interrupt handlers at runtime here. /// Available when using a RAM vector table or a RAM image. -pub var ram_vector_table: VectorTable align(256) = if (using_ram_vector_table or is_ram_image) +pub var ram_vector_table: VectorTable align(128) = if (using_ram_vector_table or is_ram_image) startup_logic.generate_vector_table() else @compileError("`ram_vector_table` is not available. Consider adding .cpu = .{ .ram_vector_table = true }" ++ @@ -834,7 +834,7 @@ pub const startup_logic = struct { fn default_exception_handler(comptime name: []const u8) microzig.interrupt.Handler { return switch (builtin.mode) { .Debug => .{ .c = DebugExceptionHandler(name).handle }, - else => .{ .c = ReleaseExceptionHandler.handle }, + else => .{ .c = DebugExceptionHandler(name).handle }, }; } diff --git a/port/raspberrypi/rp2xxx/src/hal/dma.zig b/port/raspberrypi/rp2xxx/src/hal/dma.zig index e50f7fab8..49ef20d09 100644 --- a/port/raspberrypi/rp2xxx/src/hal/dma.zig +++ b/port/raspberrypi/rp2xxx/src/hal/dma.zig @@ -52,6 +52,69 @@ pub const DMA_WriteTarget = struct { addr: u32, }; +pub const RingConfig = union(enum) { + disabled, + read: RingSize, + write: RingSize, +}; + +pub const TransferMode = enum(u4) { + /// When MODE is 0x0, the transfer count decrements with each transfer, + /// until 0, and then the channel triggers the next channel indicated by + /// CTRL_CHAIN_TO. + default = 0x0, + + /// When MODE is 0x1, the transfer count decrements with each transfer until 0, + /// and then the channel re-triggers itself, in addition to the trigger indicated by + /// CTRL_CHAIN_TO. This is useful for e.g. an endless ring-buffer DMA with + /// periodic interrupts. + trigger_self = 0x1, + + /// When MODE is 0xf, the transfer count does not decrement. The DMA channel + /// performs an endless sequence of transfers, never triggering other channels or + /// raising interrupts, until an ABORT is raised. + endless = 0xF, +}; + +pub const RingSize = enum(u4) { + // disabled = 0, + @"2" = 1, + @"4" = 2, + @"8" = 3, + @"16" = 4, + @"32" = 5, + @"64" = 6, + @"128" = 7, + @"256" = 8, + @"512" = 9, + @"1024" = 10, + @"2048" = 11, + @"4096" = 12, + @"8192" = 13, + @"16384" = 14, + @"32768" = 15, +}; + +pub const IncrementMode = enum { + none, + increment, + decrement, + increment_x2, + + inline fn get_read_value(mode: IncrementMode) u1 { + return switch (mode) { + .none, .increment_x2 => 0, + .increment, .decrement => 1, + }; + } + inline fn get_read_rev_value(mode: IncrementMode) u1 { + return switch (mode) { + .none, .increment => 0, + .decrement, .increment_x2 => 1, + }; + } +}; + pub const ChannelError = error{AlreadyClaimed}; pub const Channel = enum(u4) { @@ -109,18 +172,22 @@ pub const Channel = enum(u4) { trigger: bool = true, data_size: DataSize, enable: bool, - read_increment: bool, - write_increment: bool, + read_increment: IncrementMode, + write_increment: IncrementMode, dreq: Dreq, chain_to: ?Channel = null, high_priority: bool = false, - // TODO: - // chain to - // ring - // byte swapping + ring: RingConfig = .disabled, + swap_bytes: bool = false, + + sniffer_enabled: bool = false, + + irq_quiet: bool = false, + + mode: TransferMode = .default, }; pub fn setup_transfer_raw( @@ -130,31 +197,54 @@ pub const Channel = enum(u4) { count: u32, config: TransferConfig, ) void { + std.debug.assert(config.chain_to != chan); // A channel can never link to itself, use "ENDLESS" count instead. + std.debug.assert(count <= std.math.maxInt(u28)); // Must fit into 28 bits + + const CountField = packed struct(u32) { + count: u28, + mode: TransferMode, + }; + const count_field: CountField = .{ + .count = @intCast(count), + .mode = config.mode, + }; + const count_val: u32 = @bitCast(count_field); + const regs = chan.get_regs(); regs.read_addr = read_addr; regs.write_addr = write_addr; - regs.trans_count = count; + regs.trans_count = count_val; const chain_to = config.chain_to orelse chan; + + const TrigType = @TypeOf(microzig.chip.peripherals.DMA.CH0_CTRL_TRIG).underlying_type; + + const new_cfg: TrigType = .{ + .EN = @intFromBool(config.enable), + .DATA_SIZE = config.data_size, + .INCR_READ = config.read_increment.get_read_value(), + .INCR_READ_REV = config.read_increment.get_read_rev_value(), + .INCR_WRITE = config.write_increment.get_read_value(), + .INCR_WRITE_REV = config.write_increment.get_read_rev_value(), + .TREQ_SEL = config.dreq, + .CHAIN_TO = @intFromEnum(chain_to), + .HIGH_PRIORITY = @intFromBool(config.high_priority), + .RING_SEL = switch (config.ring) { + .disabled, .read => 0, + .write => 1, + }, + .RING_SIZE = switch (config.ring) { + .disabled => .RING_NONE, + .read, .write => |size| @enumFromInt(@intFromEnum(size)), + }, + .BSWAP = @intFromBool(config.swap_bytes), + .SNIFF_EN = @intFromBool(config.sniffer_enabled), + .IRQ_QUIET = @intFromBool(config.irq_quiet), + }; + if (config.trigger) { - regs.ctrl_trig.modify(.{ - .EN = @intFromBool(config.enable), - .DATA_SIZE = config.data_size, - .INCR_READ = @intFromBool(config.read_increment), - .INCR_WRITE = @intFromBool(config.write_increment), - .TREQ_SEL = config.dreq, - .CHAIN_TO = @intFromEnum(chain_to), - .HIGH_PRIORITY = @intFromBool(config.high_priority), - }); + regs.ctrl_trig.write(new_cfg); } else { - regs.al1_ctrl.modify(.{ - .EN = @intFromBool(config.enable), - .DATA_SIZE = config.data_size, - .INCR_READ = @intFromBool(config.read_increment), - .INCR_WRITE = @intFromBool(config.write_increment), - .TREQ_SEL = config.dreq, - .CHAIN_TO = @intFromEnum(chain_to), - .HIGH_PRIORITY = @intFromBool(config.high_priority), - }); + regs.al1_ctrl.write(new_cfg); } } diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig index 1aa48b5da..51faa75c6 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig @@ -31,6 +31,8 @@ pub const Program = struct { wrap: ?u5, pub fn get_mask(program: Program) u32 { + if (program.instructions.len == 32) + return 0xFFFF_FFFF; return (@as(u32, 1) << @as(u5, @intCast(program.instructions.len))) - 1; } }; diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig index 5df0a3bb2..0f64ab066 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig @@ -501,12 +501,23 @@ pub fn Encoder(comptime chip: Chip, comptime options: Options) type { var instr_index: ?u5 = program.origin orelse 0; for (self.tokens[self.index..]) |token| { switch (token.data) { - .label => |label| try program.labels.append(.{ - .name = label.name, - .public = label.public, - .index = instr_index.?, - }), + .label => |label| { + if (instr_index == null) { + diags.* = Diagnostics.init(token.index, "label not addressable (out of instructions)", .{}); + return error.Overflow; + } + try program.labels.append(.{ + .name = label.name, + .public = label.public, + .index = instr_index.?, + }); + }, .instruction, .word => { + if (instr_index == null) { + diags.* = Diagnostics.init(token.index, "out of instructions", .{}); + return error.Overflow; + } + const result, const ov = @addWithOverflow(instr_index.?, 1); instr_index = if (ov != 0) null else result; }, diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig index 8a2a58d9a..f3162ef97 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig @@ -156,12 +156,22 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { } pub fn find_offset_for_program(self: EnumType, program: Program) !u5 { - return if (program.origin) |origin| - if (self.can_add_program_at_offset(program, origin)) - origin - else - error.NoSpace - else for (0..(32 - program.instructions.len)) |i| { + std.log.info("", .{ program.origin, program.instructions.len }); + defer std.log.info("", .{}); + + if (program.origin) |origin| { + if (!self.can_add_program_at_offset(program, origin)) + return error.NoSpace; + return origin; + } + + if (program.instructions.len == 32) { + if (!self.can_add_program_at_offset(program, 0)) + return error.NoSpace; + return 0; + } + + return for (0..(32 - program.instructions.len)) |i| { const offset = @as(u5, @intCast(i)); if (self.can_add_program_at_offset(program, offset)) break offset; @@ -194,6 +204,7 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { //defer lock.unlock(); const offset = try self.find_offset_for_program(program); + std.log.info("add_program offset = {}", .{offset}); try self.add_program_at_offset_unlocked(program, offset); return offset; } @@ -526,9 +537,13 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { const config_count = if (options.pin_mappings.side_set) |side_set| side_set.count() else 0; assert(expected_side_set_pins == config_count); + std.log.info("", .{}); + // TODO: check program settings vs pin mapping const offset = try self.add_program(program); + std.log.info("", .{}); + try self.sm_init(sm, offset, .{ .clkdiv = options.clkdiv, .shift = options.shift,