A little look at disassembly of #ziglang

I thought I’d see if I could peek and poke memory addresses for my mcu. Here, for example, is how to set or clear a GPIO pin on my STM32:

fn gpio_clr(comptime pin: Pin) void {    
    const bits: u32 = @intCast(u32, 1) <<  @intCast(u5, pin.num + 16);
    put32(pin.base_addr + 0x18, bits);

fn gpio_set(comptime pin: Pin) void {
    const bits: u32 = @intCast(u32, 1) <<  @intCast(u5, pin.num);
    put32(pin.base_addr + 0x18, bits);

“pin” should have its parameter declared as comptime. If you don’t do that, then the program computes the bit pattern at runtime, and incorporates a panic call. If you do it at comptime then everything can be calculated ahead of time. It’s a speed vs size trade-off. Zig would have to create multiple instances of gpio_clr(0 and gpio_set(), though, to account for the different offsets. You wouldn’t have this option in C though, because the computation would have to be done.

Here is how I’ve set up the pins:

const GPIOA_baseAddr = 0x40020000;
const GPIOC_baseAddr = 0x40020800;

const Pin = struct {
    base_addr: u32,
    num: u32,

const PC13 = Pin{.base_addr = GPIOC_baseAddr, .num = 13};

const led = PC13;

Here’s a simple pause() implementation:

fn pause(ticks:u32) void {
        var i: u32 = 0;
        while (i < ticks) {
            asm volatile ("nop");
            i += 1;

Here’s its disassembly:

0800020c <pause>:
 800020c:       b580            push    {r7, lr}
 800020e:       466f            mov     r7, sp
 8000210:       b084            sub     sp, #16
 8000212:       9002            str     r0, [sp, #8]
 8000214:       2000            movs    r0, #0
 8000216:       9003            str     r0, [sp, #12]
 8000218:       e7ff            b.n     800021a <pause+0xe>
 800021a:       9803            ldr     r0, [sp, #12]
 800021c:       9902            ldr     r1, [sp, #8]
 800021e:       4288            cmp     r0, r1
 8000220:       d208            bcs.n   8000234 <pause+0x28>
 8000222:       e7ff            b.n     8000224 <pause+0x18>
 8000224:       bf00            nop
 8000226:       9903            ldr     r1, [sp, #12]
 8000228:       1c48            adds    r0, r1, #1
 800022a:       4602            mov     r2, r0
 800022c:       9201            str     r2, [sp, #4]
 800022e:       4288            cmp     r0, r1
 8000230:       d302            bcc.n   8000238 <pause+0x2c>
 8000232:       e008            b.n     8000246 <pause+0x3a>
 8000234:       b004            add     sp, #16
 8000236:       bd80            pop     {r7, pc}
 8000238:       f240 7040       movw    r0, #1856       ; 0x740
 800023c:       f6c0 0000       movt    r0, #2048       ; 0x800
 8000240:       2100            movs    r1, #0
 8000242:       f7ff fefd       bl      8000040 <std.builtin.default_panic>
 8000246:       9801            ldr     r0, [sp, #4]
 8000248:       9003            str     r0, [sp, #12]
 800024a:       e7e6            b.n     800021a <pause+0xe>

Well, I’m rubbish at assembly, but it looks like it does an overflow check for “i+=1”, and panics if necessary. But “i” can never overflow due to the way that the loop is constructed.

About mcturra2000

Computer programmer living in Scotland.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s