-
Notifications
You must be signed in to change notification settings - Fork 1.2k
pioasm: Enhance JSON output with additional program metadata #2799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
pioasm: Enhance JSON output with additional program metadata #2799
Conversation
Adds escaping for JSON strings and includes new fields in the output such as pioASM version, pioVersion, usedGPIORanges, in/out/setCount configurations, movStatus, fifoConfig, clockDiv, codeBlocks, and langOpts. Also uncomments instruction output with disassembly strings and ensures proper escaping for symbol names and other string fields.
|
I have no opinion either way, but maybe it'd be helpful to demonstrate (just a PR-comment, not a comment in the code) what an example JSON output might look both before and after your change? 🙂 Pinging also @byteit101 , as the original author of this code in #1394 |
Otherwise the factory code that adds the output as an option to the CLI never runs.
|
Ah yes, absolutely. Sorry about that miss :) Here is an example where I try to exercise all the different values. Please note that this is closely following the logic in the c-sdk output, where some declarations are omitted if the values match the default behavior. In cases where not changing a setting lands to the expected result this output will choose not to be explicit. BTW, I just uploaded a change to Examples: {
"pioASMVersion": "2.2.1-develop",
"publicSymbols": {
"MY_GLOBAL_CONST": 2
},
"programs": [
{
"name": "all_fields",
"pioVersion": 1,
"wrapTarget": 0,
"wrap": 3,
"origin": 0,
"usedGPIORanges": 0,
"publicSymbols": {
"MY_CONST": 1
},
"publicLabels": {
"loop": 0
},
"in": {"pinCount": 1, "right": true, "autopush": true, "threshold": 8},
"out": {"pinCount": 1, "right": true, "autopull": true, "threshold": 8},
"setCount": 1,
"sideset": {"size": 2, "optional": true, "pindirs": true},
"movStatus": {"type": "STATUS_TX_LESSTHAN", "n": 4},
"fifoConfig": "PIO_FIFO_JOIN_TX",
"clockDiv": {"int": 2, "frac": 128},
"instructions": [
{"hex": "F801", "instruction": "set pins, 1 side 1"},
{"hex": "5001", "instruction": "in pins, 1 side 0"},
{"hex": "7001", "instruction": "out pins, 1 side 0"},
{"hex": "0000", "instruction": "jmp 0"}
],
"codeBlocks": [
{
"lang": "c-sdk",
"contents": "foo\n"
},
{
"lang": "python",
"contents": "bar\n"
}
],
"langOpts": [
{
"lang": "python",
"name": "foo",
"value": "bar"
}
]
}
]
}That's the output for this program: Here is an example of how I use this output to generate, in this case, the output of compiling @raspberrypi/pico-examples/blob/master/pio/hub75/hub75.pio to swift, and hopefully explains why all this values (including import CPicoSDK
// This file is autogenerated by pioasm-swift using pioasm version 2.2.1-develop do not edit! //
public enum hub75_data_rgb888 {
public static let wrap_target: UInt32 = 0
public static let wrap: UInt32 = 15
public static let pio_version: UInt8 = 0
public static let offset_shift1 = 7
public static let offset_entry_point = 0
public static let offset_shift0 = 0
public static nonisolated(unsafe) let instructions: UnsafeBufferPointer<UInt16> = {
let instructions: [UInt16] = [
// shift0:
// entry_point:
0x80A0, // pull block side 0
// .wrap_target
0x40E1, // in osr, 1 side 0
0x6068, // out null, 8 side 0
0x40E1, // in osr, 1 side 0
0x6068, // out null, 8 side 0
0x40E1, // in osr, 1 side 0
0x6060, // out null, 32 side 0
// shift1:
0x80A0, // pull block side 0
0x50E1, // in osr, 1 side 1
0x7068, // out null, 8 side 1
0x50E1, // in osr, 1 side 1
0x7068, // out null, 8 side 1
0x50E1, // in osr, 1 side 1
0x7060, // out null, 32 side 1
0x507A, // in null, 26 side 1
// .wrap
0xB016, // mov pins, ::isr side 1
]
let bufferPointer = UnsafeMutableBufferPointer<UInt16>.allocate(capacity: instructions.count)
let (_, index) = bufferPointer.initialize(from: instructions)
assert(index == instructions.endIndex, "Failed to initialize buffer pointer")
return UnsafeBufferPointer(bufferPointer)
}()
#if !PICO_NO_HARDWARE
public static nonisolated(unsafe) let program_storage = pio_program(
instructions: instructions.baseAddress!,
length: 16,
origin: -1,
pio_version: Self.pio_version,
used_gpio_ranges: 0
)
public static var program: UnsafePointer<pio_program_t> {
// This is safe only because program_storage has a static lifetime
withUnsafePointer(to: program_storage) { $0 }
}
public static func get_default_config(offset: UInt32) -> pio_sm_config {
var c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + Self.wrap_target, offset + Self.wrap)
sm_config_set_sideset(&c, 1, false, false)
return c;
}
#endif
} |
Encloses the movStatus type value in quotes to ensure correct JSON string formatting in the output.
Interesting, so you're going from PIO -> JSON -> Swift, rather than directly from PIO -> JSON ?
It looks like that PIO file has both |
|
@lurch that's correct! I didn't wanted to jump to the assumption that maintainers would be comfortable with This change gives everyone a chance to pickup the JSON output and generate their own outputs as needed. RE your 2nd point, correct as well. I decided to bring just a chunk to avoid bloating the comments even more 😅 |
It's obviously entirely up to you how you implement your pipeline (and of course using JSON as an intermediary format is a good stress-test of that format 😉 ), but note that we've also added community-contributed Ada #135 and Go #1604 output formats to
😆 👍 |
|
Sounds great. Let me polish that implementation a little bit and I'll submit a PR with that change. I'd still consider this change useful, hopefully to create some independence around consuming the output of the compiler, but wonder what's your take. Another approach, more radical, could be changing all the generators to use the same IR. Sounds impractical in the current context and environment, but would probably make it easier to track all changes and ensure all implementations follow the same logic, as the json output provides a closer-to-1:1 mapping of calls and parameters. Again, for the current context is too much, just a thought. |
|
@lurch quick update, I desisted for now from the idea of bringing support into the tool. I'd like to discuss this further with other folks also working on an approach to make this generic enough if that's fine. For now this PR is all I have, also referenced the PR where I'm using it in case it helps giving context on how it's used. I think the most relevant aspect to highlight about this PR, aside from the inclusion of more fields which should not be a breaking change on its own, is the new optional declaration of the field "sideset". @kilograham thanks for tagging this for 2.2.1. Please let me know if there's anything I should look into changing or iterating. Thanks again for your time and consideration! |
Hello,
My primary goal with this PR is to put
json_outputin a position where it could be used to derive any other output without having to modifypioasm.Adds escaping for JSON strings and includes new fields in the output such as
pioASMVersion,pioVersion,usedGPIORanges,in/out/setCountconfigurations,movStatus,fifoConfig,clockDiv,codeBlocks, andlangOpts. Also uncomments the instruction output disassembly and ensures proper escaping for symbol names and other string fields.There is only one spec breaking change:
sidesetmoves to be optional, using the valuenullwhen not specified. This change aims to allow consumers have a clear representation of the input. All the other changes are additive.Please let me know if this direction is aligned with the vision for this output, an alternative could be creating a new raw output to avoid leaking too much information to general consumers of
json_output.Looking forward to your feedback, and appreciate your consideration.