diff --git a/build/build.zig b/build/build.zig index 526343a..6ea3809 100644 --- a/build/build.zig +++ b/build/build.zig @@ -130,6 +130,7 @@ pub fn add_firmware( .target = mz.host_build.resolveTargetQuery(chip.cpu.target), .linkage = .static, .root_source_file = .{ .cwd_relative = mz.microzig_core.builder.pathFromRoot("src/start.zig") }, + .strip = options.strip, }), .target = options.target, .output_files = Firmware.OutputFileMap.init(host_build.allocator), @@ -358,6 +359,8 @@ pub const FirmwareOptions = struct { /// If set, overrides the `linker_script` property of the target. linker_script: ?LazyPath = null, + + strip: bool = false, }; /// Configuration options for firmware installation. diff --git a/core/build.zig b/core/build.zig index 2a3eafc..fe24e6e 100644 --- a/core/build.zig +++ b/core/build.zig @@ -29,7 +29,7 @@ pub const cpus = struct { pub const cortex_m0 = MicroZig.Cpu{ .name = "ARM Cortex-M0", - .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, + .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex_m.zig" }, .target = std.zig.CrossTarget{ .cpu_arch = .thumb, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0 }, @@ -40,7 +40,7 @@ pub const cpus = struct { pub const cortex_m0plus = MicroZig.Cpu{ .name = "ARM Cortex-M0+", - .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, + .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex_m.zig" }, .target = std.zig.CrossTarget{ .cpu_arch = .thumb, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus }, @@ -51,7 +51,7 @@ pub const cpus = struct { pub const cortex_m3 = MicroZig.Cpu{ .name = "ARM Cortex-M3", - .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, + .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex_m.zig" }, .target = std.zig.CrossTarget{ .cpu_arch = .thumb, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m3 }, @@ -62,7 +62,7 @@ pub const cpus = struct { pub const cortex_m4 = MicroZig.Cpu{ .name = "ARM Cortex-M4", - .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex-m.zig" }, + .root_source_file = .{ .path = build_root ++ "/src/cpus/cortex_m.zig" }, .target = std.zig.CrossTarget{ .cpu_arch = .thumb, .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 }, diff --git a/core/src/cpus/cortex-m.zig b/core/src/cpus/cortex_m.zig similarity index 83% rename from core/src/cpus/cortex-m.zig rename to core/src/cpus/cortex_m.zig index 0bd27ea..2cbf31f 100644 --- a/core/src/cpus/cortex-m.zig +++ b/core/src/cpus/cortex_m.zig @@ -3,28 +3,49 @@ const microzig = @import("microzig"); const mmio = microzig.mmio; const root = @import("root"); -pub const regs = struct { - // Interrupt Control and State Register - pub const ICSR: *volatile mmio.Mmio(packed struct { - VECTACTIVE: u9, - reserved0: u2, - RETTOBASE: u1, - VECTPENDING: u9, - reserved1: u1, - ISRPENDING: u1, - ISRPREEMPT: u1, - reserved2: u1, - PENDSTCLR: u1, - PENDSTSET: u1, - PENDSVCLR: u1, - PENDSVSET: u1, - reserved3: u2, - NMIPENDSET: u1, - }) = @ptrFromInt(0xE000ED04); +const scs_base = 0xE000E000; +const itm_base = 0xE0000000; +const dwt_base = 0xE0001000; +const tpi_base = 0xE0040000; +const coredebug_base = 0xE000EDF0; +const systick_base = scs_base + 0x0010; +const nvic_base = scs_base + 0x0100; +const scb_base = scs_base + 0x0D00; +const mpu_base = scs_base + 0x0D90; + +const Core = enum { + @"ARM Cortex-M0", + @"ARM Cortex-M0+", + @"ARM Cortex-M3", + @"ARM Cortex-M4", +}; + +const core: type = blk: { + const cortex_m = std.meta.stringToEnum(microzig.config.cpu_name) orelse @panic(std.fmt.comptimePrint("Unrecognized Cortex-M core name: {s}", .{microzig.config.cpu_name})); + break :blk switch (cortex_m) { + .@"ARM Cortex-M0" => @import("cortex_m/m0"), + .@"ARM Cortex-M0+" => @import("cortex_m/m0plus.zig"), + .@"ARM Cortex-M3" => @import("cortex_m/m3.zig"), + .@"ARM Cortex-M4" => @import("cortex_m/m4.zig"), + }; }; +const properties = microzig.chip.properties; +// TODO: will have to standardize this with regz code generation +const mpu_present = @hasDecl(properties, "__MPU_PRESENT") and std.mem.eql(u8, properties.__MPU_PRESENT, "1"); + +/// System Control Block (SCB) +pub const scb: *volatile core.SystemControlBlock = @ptrFromInt(scb_base); +/// Nested Vector Interrupt Controller (NVIC) +pub const nvic: *volatile core.NestedVectorInterruptController = @ptrFromInt(nvic_base); +/// Memory Protection Unit (MPU) +pub const mpu: *volatile core.MemoryProtectionUnit = if (mpu_present) + @ptrFromInt(mpu_base) +else + @compileError("Cortex-M does not have an MPU"); + pub fn executing_isr() bool { - return regs.ICSR.read().VECTACTIVE != 0; + return scb.ICSR.read().VECTACTIVE != 0; } pub fn enable_interrupts() void { diff --git a/core/src/cpus/cortex_m/m0.zig b/core/src/cpus/cortex_m/m0.zig new file mode 100644 index 0000000..e8808f1 --- /dev/null +++ b/core/src/cpus/cortex_m/m0.zig @@ -0,0 +1,3 @@ +pub const SystemControlBlock = @compileError("TODO"); +pub const NestedVectorInterruptController = @compileError("TODO"); +pub const MemoryProtectionUnit = @compileError("TODO"); diff --git a/core/src/cpus/cortex_m/m0plus.zig b/core/src/cpus/cortex_m/m0plus.zig new file mode 100644 index 0000000..e8808f1 --- /dev/null +++ b/core/src/cpus/cortex_m/m0plus.zig @@ -0,0 +1,3 @@ +pub const SystemControlBlock = @compileError("TODO"); +pub const NestedVectorInterruptController = @compileError("TODO"); +pub const MemoryProtectionUnit = @compileError("TODO"); diff --git a/core/src/cpus/cortex_m/m3.zig b/core/src/cpus/cortex_m/m3.zig new file mode 100644 index 0000000..e8808f1 --- /dev/null +++ b/core/src/cpus/cortex_m/m3.zig @@ -0,0 +1,3 @@ +pub const SystemControlBlock = @compileError("TODO"); +pub const NestedVectorInterruptController = @compileError("TODO"); +pub const MemoryProtectionUnit = @compileError("TODO"); diff --git a/core/src/cpus/cortex_m/m4.zig b/core/src/cpus/cortex_m/m4.zig new file mode 100644 index 0000000..443e260 --- /dev/null +++ b/core/src/cpus/cortex_m/m4.zig @@ -0,0 +1,156 @@ +const microzig = @import("microzig"); +const mmio = microzig.mmio; + +pub const SystemControlBlock = extern struct { + /// CPUID Base Register + CPUID: u32, + /// Interrupt Control and State Register + ICSR: mmio.Mmio(packed struct(u32) { + VECTACTIVE: u9, + reserved0: u2 = 0, + RETTOBASE: u1, + VECTPENDING: u9, + reserved1: u1 = 0, + ISRPENDING: u1, + ISRPREEMPT: u1, + reserved2: u1 = 0, + PENDSTCLR: u1, + PENDSTSET: u1, + PENDSVCLR: u1, + PENDSVSET: u1, + reserved3: u2 = 0, + NMIPENDSET: u1, + }), + /// Vector Table Offset Register + VTOR: u32, + /// Application Interrupt and Reset Control Register + AIRCR: u32, + /// System Control Register + SCR: u32, + /// Configuration Control Register + CCR: mmio.Mmio(packed struct(u32) { + NONBASETHRDENA: u1, + USERSETMPEND: u1, + _reserved0: u1 = 0, + UNALIGN_TRP: u1, + DIV_0_TRP: u1, + _reserved1: u3 = 0, + BFHFNMIGN: u1, + STKALIGN: u1, + _padding: u22 = 0, + }), + /// System Handlers Priority Registers + SHP: [12]u8, + /// System Handler Contol and State Register + SHCSR: u32, + /// Configurable Fault Status Register + CFSR: u32, + /// HardFault Status Register + HFSR: u32, + /// Debug Fault Status Register + DFSR: u32, + /// MemManage Fault Address Register + MMFAR: u32, + /// BusFault Address Register + BFAR: u32, + /// Auxilary Feature Register + AFSR: u32, + /// Processor Feature Register + PFR: [2]u32, + /// Debug Feature Register + DFR: u32, + /// Auxilary Feature Register + ADR: u32, + /// Memory Model Feature Register + MMFR: [4]u32, + /// Instruction Set Attributes Register + ISAR: [5]u32, + RESERVED0: [5]u32, + /// Coprocessor Access Control Register + CPACR: u32, +}; + +pub const NestedVectorInterruptController = extern struct { + ISER: [8]u32, + _reserved0: [24]u32, + ICER: [8]u32, + _reserved1: [24]u32, + ISPR: [8]u32, + _reserved2: [24]u32, + ICPR: [8]u32, + _reserved3: [24]u32, + IABR: [8]u32, + _reserved4: [56]u32, + IP: [240]u8, + _reserved5: [644]u32, + STIR: u32, +}; + +pub const MemoryProtectionUnit = extern struct { + /// MPU Type Register + TYPE: mmio.Mmio(packed struct(u32) { + SEPARATE: u1, + _reserved0: u7, + DREGION: u8, + IREGION: u8, + _reserved1: u8, + }), + /// MPU Control Register + CTRL: mmio.Mmio(packed struct(u32) { + ENABLE: u1, + HFNMIENA: u1, + PRIVDEFENA: u1, + padding: u29, + }), + /// MPU RNRber Register + RNR: mmio.Mmio(packed struct(u32) { + REGION: u8, + padding: u24, + }), + /// MPU Region Base Address Register + RBAR: RBAR, + /// MPU Region Attribute and Size Register + RASR: RASR, + /// MPU Alias 1 Region Base Address Register + RBAR_A1: RBAR, + /// MPU Alias 1 Region Attribute and Size Register + RASR_A1: RASR, + /// MPU Alias 2 Region Base Address Register + RBAR_A2: RBAR, + /// MPU Alias 2 Region Attribute and Size Register + RASR_A2: RASR, + /// MPU Alias 3 Region Base Address Register + RBAR_A3: RBAR, + /// MPU Alias 3 Region Attribute and Size Register + RASR_A3: RASR, + + pub const RBAR = mmio.Mmio(packed struct(u32) { + REGION: u4, + VALID: u1, + ADDR: u27, + }); + + pub const RASR = mmio.Mmio(packed struct(u32) { + /// Region enable bit + ENABLE: u1, + /// Region Size + SIZE: u5, + _reserved0: u2, + /// Sub-Region Disable + SRD: u8, + /// ATTRS.B + B: u1, + /// ATTRS.C + C: u1, + /// ATTRS.S + S: u1, + /// ATTRS.TEX + TEX: u3, + _reserved1: u2, + /// ATTRS.AP + AP: u3, + /// ATTRS.XN + XN: u1, + padding: u4, + }); +}; diff --git a/tools/regz/src/atdf.zig b/tools/regz/src/atdf.zig index 1e1ad46..c6515e3 100644 --- a/tools/regz/src/atdf.zig +++ b/tools/regz/src/atdf.zig @@ -84,6 +84,10 @@ fn load_device(ctx: *Context, node: xml.Node) !void { if (node.find_child(&.{"interrupts"})) |interrupts_node| try load_interrupts(ctx, interrupts_node, id); + var param_it = node.iterate(&.{"parameters"}, &.{"param"}); + while (param_it.next()) |param_node| + try load_param(ctx, param_node, id); + try infer_peripheral_offsets(ctx); try infer_enum_sizes(ctx); @@ -98,11 +102,26 @@ fn load_device(ctx: *Context, node: xml.Node) !void { // events.generators.generator // events.users.user // interfaces.interface.parameters.param - // parameters.param // property-groups.property-group.property } +fn load_param(ctx: *Context, node: xml.Node, device_id: EntityId) !void { + const db = ctx.db; + assert(db.entity_is("instance.device", device_id)); + validate_attrs(node, &.{ + "name", + "value", + }); + + const name = node.get_attribute("name") orelse return error.MissingParamName; + const value = node.get_attribute("value") orelse return error.MissingParamName; + // TODO: do something with caption + _ = node.get_attribute("caption"); + + try db.add_device_property(device_id, name, value); +} + fn load_interrupts(ctx: *Context, node: xml.Node, device_id: EntityId) !void { var interrupt_it = node.iterate(&.{}, &.{"interrupt"}); while (interrupt_it.next()) |interrupt_node|