Skip to content

Adds new cpu architectures propeller1 and propeller2.#21563

Merged
andrewrk merged 2 commits intoziglang:masterfrom
ikskuh:work/21559_propeller
Oct 4, 2024
Merged

Adds new cpu architectures propeller1 and propeller2.#21563
andrewrk merged 2 commits intoziglang:masterfrom
ikskuh:work/21559_propeller

Conversation

@ikskuh
Copy link
Contributor

@ikskuh ikskuh commented Oct 1, 2024

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

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
@ikskuh ikskuh requested a review from Snektron as a code owner October 1, 2024 19:16
@ikskuh
Copy link
Contributor Author

ikskuh commented Oct 1, 2024

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

../stage3/bin/zig build-exe -target propeller1-freestanding -ofmt=c demo.zig 
../stage3/bin/zig build-exe -target propeller2-freestanding -ofmt=c demo.zig 

both commands work and seem to emit reasonable C code, so i guess we're good to go with experimentation now :)

Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,
Copy link
Member

@alexrp alexrp Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, this should be resolved now.

Copy link
Member

@alexrp alexrp Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@alexrp
Copy link
Member

alexrp commented Oct 1, 2024

If you haven't already, I recommend running

  • zig run tools/generate_c_size_and_align_checks.zig -- propeller-freestanding-none | propeller-elf-gcc -fsyntax-only -x c -
  • zig run tools/generate_c_size_and_align_checks.zig -- propeller2-freestanding-none | propeller-elf-gcc -mp2 -fsyntax-only -x c -

to ensure that we actually have the correct C type size/alignment values in std.Target.

@ikskuh
Copy link
Contributor Author

ikskuh commented Oct 1, 2024

If you haven't already, I recommend running

  • zig run tools/generate_c_size_and_align_checks.zig -- propeller-freestanding-none | propeller-elf-gcc -fsyntax-only -x c -
  • zig run tools/generate_c_size_and_align_checks.zig -- propeller2-freestanding-none | propeller-elf-gcc -mp2 -fsyntax-only -x c -

to ensure that we actually have the correct C type size/alignment values in std.Target.

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

@alexrp
Copy link
Member

alexrp commented Oct 1, 2024

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 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.

@ikskuh
Copy link
Contributor Author

ikskuh commented Oct 1, 2024

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

@alexrp
Copy link
Member

alexrp commented Oct 1, 2024

That is kind of a bold assumption 🤣 Afaik, only propeller1 has an official gcc port while P2 hasn't.

Hmm, are you sure? Their GCC port has an -mp2 switch which is supposed to generate Propeller 2 code. 🤔

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
@ikskuh ikskuh force-pushed the work/21559_propeller branch from 4ad1768 to 55b0813 Compare October 2, 2024 12:00
@alexrp
Copy link
Member

alexrp commented Oct 2, 2024

powerpc64,
powerpc64le,
propeller1,
propeller2,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's wait until we have all toolchains tested if they agree on the C type sizes

Copy link
Member

@andrewrk andrewrk Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 :(

@andrewrk andrewrk merged commit 7c74ede into ziglang:master Oct 4, 2024
@ikskuh
Copy link
Contributor Author

ikskuh commented Oct 5, 2024

@alexrp i guess we have to do our refines in a later MR 😆

@andrewrk
Copy link
Member

andrewrk commented Oct 5, 2024

Sorry, it looks like I jumped the gun. Well, at least nobody will create conflicts with what you have so far, right? :)

@ikskuh
Copy link
Contributor Author

ikskuh commented Oct 7, 2024

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

bernardassan pushed a commit to bernardassan/zig that referenced this pull request Oct 8, 2024
* 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>
richerfu pushed a commit to richerfu/zig that referenced this pull request Oct 28, 2024
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New Architecture: Parallax Propeller

3 participants