Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Adds new cpu architectures propeller1 and propeller2. - #21563

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

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

Conversation

@ikskuh

Copy link
Copy Markdown
Contributor

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.
Resolvesziglang#21559
@ikskuh
ikskuh requested a review from Snektron as a code ownerOctober 1, 2024 19:16
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

I tested it with the following code:

conststd=@import("std");
/// Write long in D[31:0] to hub address {#}S/PTRx./// Prior SETQ/SETQ2 invokes cog/LUT block transfer.inlinefnwrlong(dst: u32, value: u32 ) void {
asmvolatile(
"wrlong"
:
: [dst] "r" (dst),
[val] "r" (value)
);
}
externfncheck() bool;
exportfn_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 threadlib/std/Target.zig Outdated
Comment on lines 884 to 886
.propeller1,
.propeller2,
=> .NONE,

@alexrpalexrpOct 1, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
ContributorAuthor

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.

@alexrpalexrpOct 2, 2024

Copy link
Copy Markdown
Member

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.

Comment threadlib/std/Target.zig Outdated
@alexrp

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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

alexrp commented Oct 1, 2024

Copy link
Copy Markdown
Member

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
ikskuhforce-pushed the work/21559_propeller branch from 4ad1768 to 55b0813CompareOctober 2, 2024 12:00
@alexrp

Copy link
Copy Markdown
Member

Comment threadlib/std/Target.zig
powerpc64,
powerpc64le,
propeller1,
propeller2,

Copy link
Copy Markdown
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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

@andrewrkandrewrkOct 3, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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:masterOct 4, 2024
@ikskuh

Copy link
Copy Markdown
ContributorAuthor

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

@andrewrk

Copy link
Copy Markdown
Member

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
Copy Markdown
ContributorAuthor

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.
Resolvesziglang#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 freeto 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

@ikskuh@alexrp@andrewrk