diff --git a/build.zig b/build.zig index b395268..c9ca6c0 100644 --- a/build.zig +++ b/build.zig @@ -185,7 +185,7 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source: // - This requires building another tool that runs on the host that compiles those files and emits the linker script. // - src/tools/linkerscript-gen.zig is the source file for this - exe.bundle_compiler_rt = false; + // exe.bundle_compiler_rt = false; switch (backing) { .chip => { diff --git a/src/core/debug.zig b/src/core/debug.zig new file mode 100644 index 0000000..eb2474c --- /dev/null +++ b/src/core/debug.zig @@ -0,0 +1,38 @@ +const std = @import("std"); +const micro = @import("microzig.zig"); + +pub fn busySleep(comptime limit: comptime_int) void { + if (limit <= 0) @compileError("limit must be non-negative!"); + + comptime var bits = 0; + inline while ((1 << bits) <= limit) { + bits += 1; + } + + const I = std.meta.Int(.unsigned, bits); + + var i: I = 0; + while (i < limit) : (i += 1) { + @import("std").mem.doNotOptimizeAway(i); + } +} + +const DebugErr = error{}; +fn writerWrite(ctx: void, string: []const u8) DebugErr!usize { + write(string); + return string.len; +} + +const DebugWriter = std.io.Writer(void, DebugErr, writerWrite); + +pub fn write(string: []const u8) void { + if (!micro.config.has_board) + return; + if (!@hasDecl(micro.board, "debugWrite")) + return; + micro.board.debugWrite(string); +} + +pub fn writer() DebugWriter { + return DebugWriter{ .context = {} }; +} diff --git a/src/core/gpio.zig b/src/core/gpio.zig index bbbe57d..325cfed 100644 --- a/src/core/gpio.zig +++ b/src/core/gpio.zig @@ -57,12 +57,12 @@ pub fn Gpio(comptime pin: type, config: anytype) type { } fn read() State { - return @intToEnum(State, chip.gpio.read(pin.source_pin)); + return chip.gpio.read(pin.source_pin); } // outputs: fn write(state: State) void { - chip.gpio.write(pin.source_pin, @enumToInt(state)); + chip.gpio.write(pin.source_pin, state); } fn setToHigh() void { diff --git a/src/core/microzig.zig b/src/core/microzig.zig index 44ca0c9..4664fc5 100644 --- a/src/core/microzig.zig +++ b/src/core/microzig.zig @@ -30,13 +30,29 @@ pub const Pin = pin.Pin; pub const uart = @import("uart.zig"); pub const Uart = uart.Uart; +pub const debug = @import("debug.zig"); + /// The microzig panic handler. Will disable interrupts and loop endlessly. /// Export this symbol from your main file to enable microzig: /// ``` /// const micro = @import("microzig"); /// pub const panic = micro.panic; /// ``` -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { +pub fn panic(message: []const u8, maybe_stack_trace: ?*std.builtin.StackTrace) noreturn { + var writer = debug.writer(); + writer.print("microzig PANIC: {s}\r\n", .{message}) catch unreachable; + if (maybe_stack_trace) |stack_trace| { + var frame_index: usize = 0; + var frames_left: usize = std.math.min(stack_trace.index, stack_trace.instruction_addresses.len); + + while (frames_left != 0) : ({ + frames_left -= 1; + frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; + }) { + const return_address = stack_trace.instruction_addresses[frame_index]; + writer.print("0x{X:0>8}\r\n", .{return_address}) catch unreachable; + } + } hang(); } diff --git a/src/core/mmio.zig b/src/core/mmio.zig index d6cdf41..a46ca0c 100644 --- a/src/core/mmio.zig +++ b/src/core/mmio.zig @@ -24,11 +24,14 @@ pub fn MMIO(comptime size: u8, comptime PackedT: type) type { pub const underlying_type = PackedT; pub fn read(addr: *volatile Self) PackedT { - return @bitCast(PackedT, addr.*); + return @bitCast(PackedT, addr.raw); } pub fn write(addr: *volatile Self, val: PackedT) void { - addr.* = @bitCast(IntT, val); + // This is a workaround for a compiler bug related to miscompilation + // If the tmp var is not used, result location will fuck things up + var tmp = @bitCast(IntT, val); + addr.raw = tmp; } pub fn modify(addr: *volatile Self, fields: anytype) void { diff --git a/src/core/pin.zig b/src/core/pin.zig index c7c5db4..b46962e 100644 --- a/src/core/pin.zig +++ b/src/core/pin.zig @@ -28,7 +28,7 @@ pub fn Pin(comptime spec: []const u8) type { pub const source_pin = pin; pub fn route(target: pin.Targets) void { - unreachable; + chip.routePin(source_pin, target); } }; } diff --git a/src/modules/boards/mbed-lpc1768/mbed-lpc1768.zig b/src/modules/boards/mbed-lpc1768/mbed-lpc1768.zig index 4994c7f..95358ff 100644 --- a/src/modules/boards/mbed-lpc1768/mbed-lpc1768.zig +++ b/src/modules/boards/mbed-lpc1768/mbed-lpc1768.zig @@ -1,4 +1,35 @@ pub const chip = @import("chip"); +pub const micro = @import("microzig"); + +pub fn debugWrite(string: []const u8) void { + const clk_pin = micro.Pin("DIP5"); + const dat_pin = micro.Pin("DIP6"); + + const clk = micro.Gpio(clk_pin, .{ .mode = .output, .initial_state = .low }); + const dat = micro.Gpio(dat_pin, .{ .mode = .output, .initial_state = .low }); + + clk.init(); + dat.init(); + + micro.debug.busySleep(1_000); + + for (string) |c| { + comptime var i: usize = 128; + inline while (i > 0) : (i = i >> 1) { + if ((c & i) != 0) { + dat.write(.high); + } else { + dat.write(.low); + } + clk.write(.high); + micro.debug.busySleep(1_000); + clk.write(.low); + micro.debug.busySleep(1_000); + } + } + dat.write(.low); + clk.write(.low); +} pub const pin_map = .{ // Onboard-LEDs diff --git a/src/modules/chips/lpc1768/lpc1768.zig b/src/modules/chips/lpc1768/lpc1768.zig index 5d56401..d03809e 100644 --- a/src/modules/chips/lpc1768/lpc1768.zig +++ b/src/modules/chips/lpc1768/lpc1768.zig @@ -11,6 +11,13 @@ pub const memory_regions = [_]micro_linker.MemoryRegion{ micro_linker.MemoryRegion{ .offset = 0x2007C000, .length = 32 * 1024, .kind = .ram }, }; +pub const PinTarget = enum(u2) { + func00 = 0b00, + func01 = 0b01, + func10 = 0b10, + func11 = 0b11, +}; + pub fn parsePin(comptime spec: []const u8) type { const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}.{Pin}\" scheme."; if (spec[0] != 'P') @@ -18,12 +25,17 @@ pub fn parsePin(comptime spec: []const u8) type { const index = std.mem.indexOfScalar(u8, spec, '.') orelse @compileError(invalid_format_msg); - const _port: u3 = std.fmt.parseInt(u3, spec[1..index], 10) catch @compileError(invalid_format_msg); - const _pin: u5 = std.fmt.parseInt(u5, spec[index + 1 ..], 10) catch @compileError(invalid_format_msg); + const _port: comptime_int = std.fmt.parseInt(u3, spec[1..index], 10) catch @compileError(invalid_format_msg); + const _pin: comptime_int = std.fmt.parseInt(u5, spec[index + 1 ..], 10) catch @compileError(invalid_format_msg); + + const sel_reg_name = std.fmt.comptimePrint("PINSEL{d}", .{(2 * _port + _pin / 16)}); const _regs = struct { const name_suffix = std.fmt.comptimePrint("{d}", .{_port}); + const pinsel_reg = @field(registers.PINCONNECT, sel_reg_name); + const pinsel_field = std.fmt.comptimePrint("P{d}_{d}", .{ _port, _pin }); + const dir = @field(registers.GPIO, "DIR" ++ name_suffix); const pin = @field(registers.GPIO, "PIN" ++ name_suffix); const set = @field(registers.GPIO, "SET" ++ name_suffix); @@ -32,13 +44,21 @@ pub fn parsePin(comptime spec: []const u8) type { }; return struct { - pub const port = _port; - pub const pin = _pin; + pub const port: u3 = _port; + pub const pin: u5 = _pin; pub const regs = _regs; const gpio_mask: u32 = (1 << pin); + + pub const Targets = PinTarget; }; } +pub fn routePin(comptime pin: type, function: PinTarget) void { + var val = pin.regs.pinsel_reg.read(); + @field(val, pin.regs.pinsel_field) = @enumToInt(function); + pin.regs.pinsel_reg.write(val); +} + pub const gpio = struct { pub fn setOutput(comptime pin: type) void { pin.regs.dir.raw |= pin.gpio_mask; @@ -47,15 +67,15 @@ pub const gpio = struct { pin.regs.dir.raw &= ~pin.gpio_mask; } - pub fn read(comptime pin: type) u1 { + pub fn read(comptime pin: type) micro.gpio.State { return if ((pin.regs.pin.raw & pin.gpio_mask) != 0) - @as(u1, 1) + micro.gpio.State.high else - 0; + micro.gpio.State.low; } - pub fn write(comptime pin: type, state: u1) void { - if (state == 1) { + pub fn write(comptime pin: type, state: micro.gpio.State) void { + if (state == .high) { pin.regs.set.raw = pin.gpio_mask; } else { pin.regs.clr.raw = pin.gpio_mask; @@ -75,6 +95,7 @@ pub fn Uart(comptime index: usize) type { const Self = @This(); pub fn init(config: micro.uart.Config) !Self { + micro.debug.write("0"); switch (index) { 0 => { registers.SYSCON.PCONP.modify(.{ .PCUART0 = true }); @@ -94,6 +115,7 @@ pub fn Uart(comptime index: usize) type { }, else => unreachable, } + micro.debug.write("1"); UARTn.LCR.write(.{ // 8N1 @@ -118,8 +140,14 @@ pub fn Uart(comptime index: usize) type { .BC = false, .DLAB = true, }); + micro.debug.write("2"); UARTn.FCR.modify(.{ .FIFOEN = false }); + micro.debug.writer().print("clock: {} baud: {} ", .{ + micro.clock.get(), + config.baud_rate, + }) catch {}; + const pclk = micro.clock.get() / 4; const divider = (pclk / (16 * config.baud_rate)); diff --git a/src/modules/cpus/cortex-m3/cortex-m3.zig b/src/modules/cpus/cortex-m3/cortex-m3.zig index 4c82311..29c1414 100644 --- a/src/modules/cpus/cortex-m3/cortex-m3.zig +++ b/src/modules/cpus/cortex-m3/cortex-m3.zig @@ -1,49 +1,42 @@ const std = @import("std"); pub fn sei() void { - __enable_irq(); + asm volatile ("cpsie i"); } pub fn cli() void { - __disable_irq(); -} - -pub fn __enable_irq() void { - asm volatile ("cpsie i"); -} -pub fn __disable_irq() void { asm volatile ("cpsid i"); } -pub fn __enable_fault_irq() void { +pub fn enable_fault_irq() void { asm volatile ("cpsie f"); } -pub fn __disable_fault_irq() void { +pub fn disable_fault_irq() void { asm volatile ("cpsid f"); } -pub fn __NOP() void { +pub fn nop() void { asm volatile ("nop"); } -pub fn __WFI() void { +pub fn wfi() void { asm volatile ("wfi"); } -pub fn __WFE() void { +pub fn wfe() void { asm volatile ("wfe"); } -pub fn __SEV() void { +pub fn sev() void { asm volatile ("sev"); } -pub fn __ISB() void { +pub fn isb() void { asm volatile ("isb"); } -pub fn __DSB() void { +pub fn dsb() void { asm volatile ("dsb"); } -pub fn __DMB() void { +pub fn dmb() void { asm volatile ("dmb"); } -pub fn __CLREX() void { +pub fn clrex() void { asm volatile ("clrex"); } @@ -53,11 +46,11 @@ pub const startup_logic = struct { const VectorTable = extern struct { initial_stack_pointer: u32, reset: InterruptVector, - nmi: InterruptVector = unhandledInterrupt, - hard_fault: InterruptVector = unhandledInterrupt, - mpu_fault: InterruptVector = unhandledInterrupt, - bus_fault: InterruptVector = unhandledInterrupt, - usage_fault: InterruptVector = unhandledInterrupt, + nmi: InterruptVector = makeUnhandledHandler("nmi"), + hard_fault: InterruptVector = makeUnhandledHandler("hard_fault"), + mpu_fault: InterruptVector = makeUnhandledHandler("mpu_fault"), + bus_fault: InterruptVector = makeUnhandledHandler("bus_fault"), + usage_fault: InterruptVector = makeUnhandledHandler("usage_fault"), reserved: u32 = 0, }; @@ -68,8 +61,12 @@ pub const startup_logic = struct { .reset = _start, }; - fn unhandledInterrupt() callconv(.C) noreturn { - @panic("unhandled interrupt"); + fn makeUnhandledHandler(comptime str: []const u8) fn () callconv(.C) noreturn { + return struct { + fn unhandledInterrupt() callconv(.C) noreturn { + @panic("unhandled interrupt: " ++ str); + } + }.unhandledInterrupt; } extern fn microzig_main() noreturn; diff --git a/tests/uart-sync.zig b/tests/uart-sync.zig index 7b61086..7116272 100644 --- a/tests/uart-sync.zig +++ b/tests/uart-sync.zig @@ -7,25 +7,116 @@ pub const panic = micro.panic; const uart_txd_pin = micro.Pin("P0.15"); const uart_rxd_pin = micro.Pin("P0.16"); -pub const cpu_frequency: u32 = 10_000_000; // 10 MHz +const debug_pin = micro.Pin("P0.17"); + +const led1_pin = micro.Pin("P1.18"); +const led2_pin = micro.Pin("P1.20"); +const led3_pin = micro.Pin("P1.21"); +const led4_pin = micro.Pin("P1.23"); + +pub const cpu_frequency: u32 = 100_000_000; // 100 MHz + +const PLL = struct { + fn init() void { + reset_overclocking(); + } + + fn reset_overclocking() void { + overclock_flash(5); // 5 cycles access time + overclock_pll(3); // 100 MHz + } + + fn overclock_flash(timing: u5) void { + micro.chip.registers.SYSCON.FLASHCFG.write(.{ + .FLASHTIM = @intCast(u4, timing - 1), + }); + } + fn feed_pll() callconv(.Inline) void { + micro.chip.registers.SYSCON.PLL0FEED.write(.{ .PLL0FEED = 0xAA }); + micro.chip.registers.SYSCON.PLL0FEED.write(.{ .PLL0FEED = 0x55 }); + } + + fn overclock_pll(divider: u8) void { + // PLL einrichten für RC + micro.chip.registers.SYSCON.PLL0CON.write(.{ + .PLLE0 = false, + .PLLC0 = false, + }); + feed_pll(); + + micro.chip.registers.SYSCON.CLKSRCSEL.write(.{ .CLKSRC = 0 }); // RC-Oszillator als Quelle + micro.chip.registers.SYSCON.PLL0CFG.write(.{ + // SysClk = (4MHz / 2) * (2 * 75) = 300 MHz + .MSEL0 = 74, + .NSEL0 = 1, + }); + // CPU Takt = SysClk / divider + micro.chip.registers.SYSCON.CCLKCFG.write(.{ .CCLKSEL = divider - 1 }); + + feed_pll(); + + micro.chip.registers.SYSCON.PLL0CON.modify(.{ .PLLE0 = true }); // PLL einschalten + feed_pll(); + + var i: usize = 0; + while (i < 1_000) : (i += 1) { + micro.cpu.nop(); + } + + micro.chip.registers.SYSCON.PLL0CON.modify(.{ .PLLC0 = true }); + feed_pll(); + } +}; pub fn main() !void { - var debug_port = try micro.Uart(0).init(.{ + const gpio_init = .{ .mode = .output, .initial_state = .low }; + + const led1 = micro.Gpio(led1_pin, gpio_init); + const led2 = micro.Gpio(led2_pin, gpio_init); + const led3 = micro.Gpio(led3_pin, gpio_init); + const led4 = micro.Gpio(led4_pin, gpio_init); + + const status = micro.Gpio(debug_pin, .{ + .mode = .output, + .initial_state = .high, + }); + status.init(); + led1.init(); + led2.init(); + led3.init(); + led4.init(); + + uart_txd_pin.route(.func01); + uart_rxd_pin.route(.func01); + + PLL.init(); + led1.setToHigh(); + + var debug_port = micro.Uart(1).init(.{ .baud_rate = 9600, .stop_bits = .one, .parity = .none, // { none, even, odd, mark, space } .data_bits = .@"8", // 5, 6, 7, 8, or 9 data bits - }); + }) catch |err| { + led1.write(if (err == error.UnsupportedBaudRate) micro.gpio.State.low else .high); + led2.write(if (err == error.UnsupportedParity) micro.gpio.State.low else .high); + led3.write(if (err == error.UnsupportedStopBitCount) micro.gpio.State.low else .high); + led4.write(if (err == error.UnsupportedWordSize) micro.gpio.State.low else .high); + + micro.hang(); + }; + led2.setToHigh(); var out = debug_port.writer(); var in = debug_port.reader(); try out.writeAll("Please enter a sentence:\r\n"); + led3.setToHigh(); + while (true) { - try out.writeAll("> "); - var line_buffer: [64]u8 = undefined; - const line = (try in.readUntilDelimiterOrEof(&line_buffer, '\r')).?; - try out.writeAll(line); + try out.writeAll("."); + led4.toggle(); + micro.debug.busySleep(100_000); } }