Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cortex_m: Add core peripherals #295

Merged
merged 7 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ pub fn MicroBuild(port_select: PortSelect) type {
const b = mb.dep.builder;

const target = options.target;
const zig_target = mb.dep.builder.resolveTargetQuery(target.chip.cpu);
const zig_target = b.resolveTargetQuery(target.chip.cpu);
const cpu = Cpu.init(zig_target.result);

// TODO: let the user override which ram section to use the stack on,
Expand All @@ -293,7 +293,7 @@ pub fn MicroBuild(port_select: PortSelect) type {
} else @panic("no ram memory region found for setting the end-of-stack address");
};

const config = mb.dep.builder.addOptions();
const config = b.addOptions();
config.addOption(bool, "has_hal", options.hal != null or target.hal != null);
config.addOption(bool, "has_board", options.board != null or target.board != null);

Expand Down
223 changes: 96 additions & 127 deletions core/src/cpus/cortex_m.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,8 @@ const microzig = @import("microzig");
const mmio = microzig.mmio;
const root = @import("root");

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-M33",
@"ARM Cortex-M4",
};

const core: type = blk: {
const cortex_m = std.meta.stringToEnum(Core, 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-M33" => @import("cortex_m/m33.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 scb.ICSR.read().VECTACTIVE != 0;
return peripherals.scb.ICSR.read().VECTACTIVE != 0;
}

pub fn enable_interrupts() void {
Expand Down Expand Up @@ -184,115 +141,127 @@ fn create_interrupt_vector(
};
}

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 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");

const core = blk: {
const Core = enum {
cortex_m0,
cortex_m0p,
cortex_m3,
cortex_m33,
cortex_m4,
};

const cortex_m = std.meta.stringToEnum(Core, microzig.config.cpu_name) orelse
@panic(std.fmt.comptimePrint("Unrecognized Cortex-M core name: {s}", .{microzig.config.cpu_name}));

break :blk switch (cortex_m) {
.cortex_m0 => @import("cortex_m/m0"),
.cortex_m0p => @import("cortex_m/m0plus.zig"),
.cortex_m3 => @import("cortex_m/m3.zig"),
.cortex_m33 => @import("cortex_m/m33.zig"),
.cortex_4 => @import("cortex_m/m4.zig"),
};
};

pub const peripherals = struct {
/// System Tick Timer
pub const SysTick = @as(*volatile types.peripherals.SysTick, @ptrFromInt(0xe000e010));
/// System Control Block (SCB).
pub const scb: *volatile types.peripherals.SystemControlBlock = @ptrFromInt(scb_base);

/// System Control Space
pub const NVIC = @compileError("TODO"); // @ptrFromInt(*volatile types.peripherals.NVIC, 0xe000e100);
/// Nested Vector Interrupt Controller (NVIC).
pub const nvic: *volatile types.peripherals.NestedVectorInterruptController = @ptrFromInt(nvic_base);

/// System Control Block
pub const SCB = @as(*volatile types.peripherals.SCB, @ptrFromInt(0xe000ed00));
/// System Timer (SysTick).
pub const systick: *volatile types.peripherals.SysTick = @ptrFromInt(systick_base);

/// Memory Protection Unit (MPU).
pub const mpu: *volatile types.peripherals.MemoryProtectionUnit = if (mpu_present)
@ptrFromInt(mpu_base)
else
@compileError("This chip does not have a MPU.");
};

pub const types = struct {
pub const peripherals = struct {
/// System Tick Timer
/// System Control Block (SCB).
pub const SystemControlBlock = core.SystemControlBlock;

/// Nested Vector Interrupt Controller (NVIC).
pub const NestedVectorInterruptController = core.NestedVectorInterruptController;

/// System Timer (SysTick).
pub const SysTick = extern struct {
/// SysTick Control and Status Register
/// Control and Status Register.
CTRL: mmio.Mmio(packed struct(u32) {
/// Enables the counter:
/// 0 = counter disabled.
/// 1 = counter enabled.
ENABLE: u1,
/// Enables SysTick exception request:
/// 0 = counting down to zero does not assert the SysTick exception request
/// 1 = counting down to zero asserts the SysTick exception request.
///
/// Software can use COUNTFLAG to determine if SysTick has ever counted to zero.
TICKINT: u1,
/// Indicates the clock source:
/// 0 = external clock
/// 1 = processor clock.
CLKSOURCE: u1,
reserved16: u13,
reserved0: u13,
/// Returns 1 if timer counted to 0 since last time this was read.
COUNTFLAG: u1,
padding: u15,
reserved1: u15,
}),
/// SysTick Reload Value Register
/// Reload Value Register.
LOAD: mmio.Mmio(packed struct(u32) {
/// Value to load into the VAL register when the counter is enabled and when it reaches 0.
RELOAD: u24,
padding: u8,
reserved0: u8,
}),
/// SysTick Current Value Register
/// Current Value Register.
VAL: mmio.Mmio(packed struct(u32) {
/// Reads return the current value of the SysTick counter.
/// A write of any value clears the field to 0, and also clears the CTRL.COUNTFLAG bit to 0.
CURRENT: u24,
padding: u8,
reserved0: u8,
}),
/// SysTick Calibration Register
/// Calibration Register.
CALIB: mmio.Mmio(packed struct(u32) {
/// Reload value for 10ms (100Hz) timing, subject to system clock skew errors. If the value
/// reads as zero, the calibration value is not known.
TENMS: u24,
reserved30: u6,
reserved0: u6,
/// Indicates whether the TENMS value is exact.
/// 0 = TENMS value is exact
/// 1 = TENMS value is inexact, or not given.
///
/// An inexact TENMS value can affect the suitability of SysTick as a software real time clock.
SKEW: u1,
/// Indicates whether the device provides a reference clock to the processor:
/// 0 = reference clock provided
/// 1 = no reference clock provided.
/// If your device does not provide a reference clock, the SYST_CSR.CLKSOURCE bit reads-as-one
/// and ignores writes.
NOREF: u1,
}),
};

/// System Control Block
pub const SCB = extern struct {
CPUID: mmio.Mmio(packed struct(u32) {
REVISION: u4,
PARTNO: u12,
ARCHITECTURE: u4,
VARIANT: u4,
IMPLEMENTER: u8,
}),
/// Interrupt Control and State Register
ICSR: mmio.Mmio(packed struct(u32) {
VECTACTIVE: u9,
reserved12: u3,
VECTPENDING: u9,
reserved22: u1,
ISRPENDING: u1,
ISRPREEMPT: u1,
reserved25: u1,
PENDSTCLR: u1,
PENDSTSET: u1,
PENDSVCLR: u1,
PENDSVSET: u1,
reserved31: u2,
NMIPENDSET: u1,
}),
/// Vector Table Offset Register
VTOR: mmio.Mmio(packed struct(u32) {
reserved8: u8,
TBLOFF: u24,
}),
/// Application Interrupt and Reset Control Register
AIRCR: mmio.Mmio(packed struct(u32) {
reserved1: u1,
VECTCLRACTIVE: u1,
SYSRESETREQ: u1,
reserved15: u12,
ENDIANESS: u1,
VECTKEY: u16,
}),
/// System Control Register
SCR: mmio.Mmio(packed struct(u32) {
reserved1: u1,
SLEEPONEXIT: u1,
SLEEPDEEP: u1,
reserved4: u1,
SEVONPEND: u1,
padding: u27,
}),
/// Configuration Control Register
CCR: mmio.Mmio(packed struct(u32) {
reserved3: u3,
UNALIGN_TRP: u1,
reserved9: u5,
STKALIGN: u1,
padding: u22,
}),
reserved28: [4]u8,
/// System Handlers Priority Registers. [0] is RESERVED
SHP: u32,
reserved36: [4]u8,
/// System Handler Control and State Register
SHCSR: mmio.Mmio(packed struct(u32) {
reserved15: u15,
SVCALLPENDED: u1,
padding: u16,
}),
};
/// Memory Protection Unit (MPU).
pub const MemoryProtectionUnit = if (@hasDecl(core, "MemoryProtectionUnit"))
core.MemoryProtectionUnit
else
@compileError("This cpu does not have a MPU.");
};
};
Loading
Loading