-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Memory Mapped IO for 32-bit ARM #1834
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
Comments
Thanks for the report! Do you have a repo that demonstrates your point? |
Not yet. I am still working on blinking an LED. Once I get LED blinking and maybe DMA working, then I will have a repo. |
This seems related to what I'm trying to get working. I want to write mmio code in this style for an armv6m board: https://gist.github.com/nic-donaldson/21abc0f0b9a83d3f4e96a5bbb55c9290 Problem is the generated code isn't great so I need to revert to the less clear This seems to fall under "Some way to guarantee that control registers are read/written one word (32-bits) at a time" and "Ability to read/write multiple fields of a control register at one time". I'm trying to get an LED blinking too so I'll link that code if I get it working. |
Thanks for the writeup. I think we can make some improvements to the language based on this use case here. Related to the endianness stuff: #649 |
Related to volatile semantics: #1664 |
The problem appears to have gone away according to this godbolt link: https://zig.godbolt.org/z/onwpqy I don't see the multiple stores on either the 3.0 or trunk. |
Still only one store under debug at least as far as I can tell on my tiny phone screen. |
@vegecode after closer review, it seems that @nic-donaldson was compiling for armv6m, which is reflected in the following disassembly: https://zig.godbolt.org/z/TONjH1 |
LLVM IR generated is the following: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 inttoptr (i32 16 to i8*), i8* align 1 bitcast (%SIM_COPC_t* @0 to i8*), i32 4, i1 true), !dbg !112 |
Allow me to offer some work I did on this in the D programming language to make memory-mapped IO for ARM microcontrollers more convenient and robust: https://github.com/JinShil/stm32f42_discovery_demo The memory-mapped IO library can be found at https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/stm32f42/mmio.d and you can see its usage in the various peripheral libraries at https://github.com/JinShil/stm32f42_discovery_demo/tree/master/source/stm32f42 It has a number of features similar to those described by the OP. It achieves this using some unique D features such as compile-time execution, I hope this will be helpful for whatever Zig decides to do. Good luck, and don't make me count bits 😉 |
I'm not an expert in IR. I see that the pointers are i8* though. Also the volatile flag is set. Maybe this is relevant: Would the memcpy produce different assembly is the pointers were i32 or the alignment were specified as being align 4? Maybe the hardcoded pointers should automatically get the highest alignment that they naturally qualify for? |
Add I tried to assign the alignment to the type instead and the compiler failed an assert:
With a hardcoded address, maybe the compiler should assign it the highest alignment possible if it is a pointer to a single item? If it is a pointer to an unknown number of items, maybe it should assign the alignment as the lowest of the addresses alignment or the items size. So if there were a pointer to a I see the docs have a lot of TODOs for the packed struct section. Maybe these should get fleshed out now that questions are being asked. I don't know what the intention is. I don't think having to add the EDIT: alignment changed from 8 to 16. Woops. |
Also, you could easily add the alignment using vim macros in just a few minutes for an entire file. |
This should be well supported now that #5049 is implemented and packed structs use the same semantics as their backing integer type. |
Summary
In 32-bit ARM, peripheral control is achieved through control registers that are mapped into the processor's address space. These control registers must be read/written in 32-bit, 4-byte aligned chunks. Most control registers have multiple fields that can each be modified independently through a read, modify, write cycle.
Desired Features
Optional Features
Bit-banding support. ARM Cortex-M processors have memory and control registers mapped to two different address ranges. The normal address range is accessed like normal memory. Reading a 32-bit, word-aligned location will load 32-bits into a register; writing a 32-bit, word-aligned location will write 32-bits from a register. The bit-banding address range maps each bit from the normal address range to a 32-bit, word-aligned location. The bit-banded word reads or writes a single bit from the normal address range as either 0x00000000 or 0x00000001. This is useful to avoid a read, modify, write when setting a 1-bit field in a control register.
Summary
Bit fields in Zig seem to be a well thought out feature, but they have some limitations that make it so that they cannot be used for memory-mapped IO on 32-bit ARM processors. All cases where bit fields cannot be used can be done with []u32 and bit masking, though this can be error prone.
Generally, Zig does a good job providing safe(ish) features to write low-level code, but bit fields cannot currently be used for memory mapped IO on 32-bit ARM.
The text was updated successfully, but these errors were encountered: