Adds new cpu architectures propeller1 and propeller2.#21563
Adds new cpu architectures propeller1 and propeller2.#21563andrewrk merged 2 commits intoziglang:masterfrom
Conversation
These cpu architectures allow targeting the Parallax Propeller 1 and Propeller 2, which are both very special microcontrollers with 512 registers and 8 cpu cores. Resolves ziglang#21559
|
I tested it with the following code: const std = @import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx.
/// Prior SETQ/SETQ2 invokes cog/LUT block transfer.
inline fn wrlong(dst: u32, value: u32 ) void {
asm volatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
extern fn check() bool;
export fn _start() void {
while(check()) {
wrlong(0x100, 1234);
}
}compiled both with both commands work and seem to emit reasonable C code, so i guess we're good to go with experimentation now :) |
lib/std/Target.zig
Outdated
| .propeller1, | ||
| .propeller2, | ||
| => .NONE, |
There was a problem hiding this comment.
This needs to be added to std.elf.EM.
There was a problem hiding this comment.
I'm also adding a P2/PROPELLER2 target taken from here:
https://github.com/ne75/llvm-project/blob/ee801ce165dc3a968ea78d7f793c713a91aabe97/llvm/include/llvm/BinaryFormat/ELF.h#L322C3-L322C15
There was a problem hiding this comment.
Okay, this should be resolved now.
There was a problem hiding this comment.
Hmm... it's a little unfortunate that the LLVM port deviates in a few ways from the precedent established by the binutils/GCC ports much earlier.
The choice of EM_P2 = 300 is particularly problematic; ports that haven't been assigned an ELF machine type "officially" are supposed to use a larger number picked at random, like the ones here, to prevent conflicts.
Further, the binutils port in the propgcc repo differentiates P1 and P2 by some bits in ELF's e_flags field, not by e_machine.
The LLD port also uses elf32p2 as the linker emulation name instead of the established elf32-propeller.
Frankly, I think the binutils port is in the right here, and the LLVM port is doing things differently for no good reason that I can tell. So I think we should omit EM_P2 and just return EM_PROPELLER for both cases, and ideally also engage with the maintainer of the LLVM port and see if they'd be willing to change this to conform to the binutils port.
|
If you haven't already, I recommend running
to ensure that we actually have the correct C type size/alignment values in |
Should i run this against the propeller-elf-gcc or the llvm build? there are several C compilers that may disagree with each other I can try fetching as much of them as possible and do the runs for each of those |
I would hope that they agree on these values as otherwise they're ABI-incompatible, which should be a bug. That said, I'd be more inclined to consider the GCC port authoritative given that it's under the Parallax organization. |
That is kind of a bold assumption 🤣 Afaik, only propeller1 has an official gcc port while P2 hasn't. The available compilers for P1 are (hard to find). Afaik there's at least the Parallax GCC and another random C compiler. For P2 they actually have a tooling list |
Hmm, are you sure? Their GCC port has an See e.g.: |
* Adds std.elf.EM.PROPELLER and std.elf.EM.PROPELLER2 * Fixes missing switch prongs in src/codegen/llvm.zig * Fixes order in std.Target.Arch
4ad1768 to
55b0813
Compare
|
If you feel like it, it would be nice to also add these constants to
But that's just a nice-to-have and not essential for merging this. |
| powerpc64, | ||
| powerpc64le, | ||
| propeller1, | ||
| propeller2, |
There was a problem hiding this comment.
I've thought about this a bit more and I think I'd prefer representing P2 as a CPU feature. My reasoning is that we actually have precedent for this already; for example, MIPS r6 made many backwards-incompatible changes (e.g. reallocated encodings, removed instructions), yet we don't represent that as a distinct Arch tag. I believe PowerPC has also historically removed features, but I can't remember the exact details there.
But let's just get this merged with this approach for now and I'll do a follow-up PR showing what I have in mind.
There was a problem hiding this comment.
I've thought about this a bit more and I think I'd prefer representing P2 as a CPU feature. My reasoning is that we actually have precedent for this already; for example, MIPS r6 made many backwards-incompatible changes (e.g. reallocated encodings, removed instructions), yet we don't represent that as a distinct Arch tag. I believe PowerPC has also historically removed features, but I can't remember the exact details there.
This would mean we have no generic cpu then, but only propeller1 and propeller2? They are neither binary compatible nor instruction compatible, it's more like arm vs. aarch64 than arm vs. thumb
This would also mean you can't check on arch but always have to check on the actual CPU in your code as well, so if you ever need to do something for p1 and p2, it would look like this:
switch(builtin.cpu.arch) {
.propeller => switch(builtin.cpu) {
&std.Target.propeller.cpus.propeller1 => { ... },
&std.Target.propeller.cpus.propeller1 => { ... },
},
...
}I wonder why they made them a CPU/Feature in the gcc port. Probably due to convenience as otherwise you have to use prop1-none-eabi-gcc and prop2-none-eabi-gcc instead of prop-none-eabi-gcc
There was a problem hiding this comment.
This would mean we have no
genericcpu then, but onlypropeller1andpropeller2? They are neither binary compatible nor instruction compatible, it's more like arm vs. aarch64 than arm vs. thumb
Yes; this is no different from the MIPS situation. The "generic" CPU would be arbitrarily defined to be propeller1, just as mips32/mips64 (r1) are arbitrarily defined to be the generic CPUs for MIPS.
This would also mean you can't check on arch but always have to check on the actual CPU
You would check the feature flag that the CPU would imply; specifically, propeller2 would imply p2. That currently looks like std.Target.propeller.featureSetHas(target.cpu.features, .p2) which is indeed too verbose, but I have some ideas for making this API more ergonomic that I plan to get to soon. I think something like target.cpu.features.has(.propeller, .p2) should be possible with some light comptime magic.
I wonder why they made them a CPU/Feature in the gcc port.
From what I saw in GCC and binutils, there's still a decent amount of overlap in instruction encodings, and they don't use wholly separate en/decoding tables or anything. In this way, I don't think the arm vs aarch64 comparison quite works because A64 really is an entirely new instruction set from A32.
There was a problem hiding this comment.
Let's wait until we have all toolchains tested if they agree on the C type sizes
There was a problem hiding this comment.
I think one heuristic to determine whether it should be a CPU feature vs a different arch is whether you would want two different self-hosted backend implementations, or whether you would rather have one that checks the CPU feature. If they would share a lot of implementation code, that is a hint that the same CPU arch would make sense.
Another heurisic would be @sizeOf(usize). This is the only reason x86 and x86_64 are not the same CPU arch for example even though 64bit is a CPU feature that can be enabled for x86 (which doesn't make any sense given this way of doing things), and you would definitely use the same backend logic for both.
There was a problem hiding this comment.
I think one heuristic to determine whether it should be a CPU feature vs a different arch is whether you would want two different self-hosted backend implementations, or whether you would rather have one that checks the CPU feature. If they would share a lot of implementation code, that is a hint that the same CPU arch would make sense.
That's a pretty good heuristic and i think i have to take a deep-dive into codegen for that 😁
They both have basically the same idea behind the instruction encoding and style, but the semantics of basically all except the most basic instructions are different.
It starts with RDLONG which can only read Hub memory on P1 and reads continuous memory on P2.
@sizeOf(usize) would be 32 bit with 23 bit padding for 2 of the 3 address spaces so it's kinda hard to say.
But now i'm super tempted to create a self-hosted backend for the two processors... 🤔
Next steps for me is still getting all the compilers up and running, which sadly takes a lot of time :(
|
@alexrp i guess we have to do our refines in a later MR 😆 |
|
Sorry, it looks like I jumped the gun. Well, at least nobody will create conflicts with what you have so far, right? :) |
Guess so! I think it's better to have it merged as-is right now as i now don't have to distribute my fork to the sole user right now 😆 Alex and me will figure the details out and make it right and nice soon |
* Adds new cpu architectures propeller1 and propeller2. These cpu architectures allow targeting the Parallax Propeller 1 and Propeller 2, which are both very special microcontrollers with 512 registers and 8 cpu cores. Resolves ziglang#21559 * Adds std.elf.EM.PROPELLER and std.elf.EM.PROPELLER2 * Fixes missing switch prongs in src/codegen/llvm.zig * Fixes order in std.Target.Arch --------- Co-authored-by: Felix "xq" Queißner <git@random-projects.net>
* Adds new cpu architectures propeller1 and propeller2. These cpu architectures allow targeting the Parallax Propeller 1 and Propeller 2, which are both very special microcontrollers with 512 registers and 8 cpu cores. Resolves ziglang#21559 * Adds std.elf.EM.PROPELLER and std.elf.EM.PROPELLER2 * Fixes missing switch prongs in src/codegen/llvm.zig * Fixes order in std.Target.Arch --------- Co-authored-by: Felix "xq" Queißner <git@random-projects.net>
These cpu architectures allow targeting the Parallax Propeller 1 and Propeller 2, which are both very special microcontrollers with 512 registers and 8 cpu cores.
Resolves #21559