Shop OBEX P1 Docs P2 Docs Learn Events
P2 PASM Syntax Clarifications (ALTx) — Parallax Forums

P2 PASM Syntax Clarifications (ALTx)

Trying to parse some of the documentation and need some help understanding certain things.

The register indirection section of the reference manual talks about the destination (D) and source (S) registers as if they have both 9 bits, 18 bits, and 32 bits. The encoding in the instruction set reference makes it clear that D and S are encoded as 9 bit direct memory addresses (unless ALTx is used for indirection). But the syntax used in the ref manual includes D[8..0], D[17..9], D[27..19], and D[31..18]. As well, S/# (or {#}S) is specified bit-wise as being 18 bits (%rrr_ddd_sss_RRR_DDD_SSS).

There could be several reasons for this but none are clear. Maybe there's just a need for better notation for the data a memory address vs. the address itself? In my experience, if M is the memory address, [M] is the data stored at that memory address. But in any case, what's the intended meaning here? Why in particular is D shown as 32 bits and S/# is 18 bits and when does each apply?

Comments

  • cgraceycgracey Posts: 14,153

    It works like this:

    The ALTx instructions use the D and S values of their operands (not strictly their nine-bit fields) to affect the fields of the next instruction in the pipeline.

    ALTD affects the 9-bit D field of the next instruction in the pipeline.

    ALTS affects the 9-bit S field of the next instruction in the pipeline.

    ALTI can variably affect different fields (even all fields) of the next instruction in the pipeline.

    ALTR affects the 9-bit-addressable result register of the next instruction, without affecting its 9-bit D field.

    The other ALTx instruction affect various fields of the next instruction.

    In each case, though, the D and S values of the ALTx instructions affect the next instruction in the pipeline in some, or multiple, ways.

  • "The ALTx instructions use the D and S values of their operands (not strictly their nine-bit fields) to affect the fields of the next instruction in the pipeline."

    @cgracey Thanks for the response. What confuses me is the quoted line above, what does 'not strictly their nine-bit fields' mean? Or maybe the better question would be, what do D[a..b] and S[c..d] refer to? Maybe that's where the confusion lies. Anyway I can illustrate a bit.

    So for example, the instruction:

        ALTS    1,#$1ad
    

    ALTS is generally encoded:

    eeee_10011_0_0_1_0_i_DDDDDDDDD_SSSSSSSSS
    

    So the instruction above should be:

    eeee_100110010_i_000000001_110101101
    

    Where %000000001 is D, and $1AD = %110101101 is S. In this example, what is S[17:9]? Does it refer to the hex $1AD (which is the 9-bit encoding) or does it refer to the 32-bit register/cog memory located at address $1AD?


  • There are multiple portions of any referenced D or S and also data from within the original instruction. As you've found, ALTS and ALTD can also control this too. Perhaps the P2 manual may be a little flexible in its various referencing of field bits and widths which may have added to your confusion.

    Normally S is obtained from using the 9 LSBs of the instruction [8:0] to reference either a COG register or a 9 bit immediate, and the D value is read from the register indexed by the next 9 bits [17:9] of the instruction (or another immediate 9 bit value). But there will be some differences once you start use the ALTxx group of instructions (ALTS/ALTD/ALTI etc).

    In your particular example you mentioned, S[17:9] would get zeroed because the S value is computed as the value read from COG location (D+S) & $1ff for ALTS D,#S. So this will go read data at (COG register 1) add it to the constant #$1AD and patch the resulting 9 LSBs from that addition into the S field in the following instruction in the pipeline only. The upper bits of S are essentially thrown away.

  • Just to clarify further: S[x:y] are bits of the *final* source value. For an immediate operand this is often the same as the 9 bits encoded in the source field of the instruction, but for a register it is the full 32 bit contents of the register specified by the 9 source bits. There are special cases (e.g. the AUGS instruction can cause the next instruction to get a full 32 bits immeidate S value).

  • It seems like the best thing to do here would be to use standard addressing mode terminology, and to add better (unambiguous) notation to the documentation.

    Its a bit tricky to fit a unique processor like the Propeller into familiar microprocessor terms, but it's necessary to reach a broader audience. So at the risk of getting it all wrong, this is how I would phrase it.

    The Propeller architecture does not strictly distinguish in most cases between processor registers and built-in processor-specific memory, the dual-purpose and special-purpose registers being the exception (and this all excluding the compiled Spin2 programs which allocate set regions in memory for general purpose registers). The Propeller architecture supports direct memory (or direct register) addressing in its instructions, and it also supports immediate addressing; register indirection is performed with the ALTx instructions.

    The notation S[a..b] is used to refer to two very different things, one being an immediate, the other being the contents of the memory address encoded in the instruction. With this notation, there is no way to refer to the memory address rather than the memory contents. This is a big problem, mostly because of ambiguity and difficulty communicating. Instead, I suggest the notation S and S[a..b] for the address or immediate value (the encoded value) and the notation [S] and [S][a..b] for the contents of a memory/register address. This is unambiguous, improves readability, will be more familiar to newcomers, and is a minimal change from existing notation.

  • evanhevanh Posts: 15,916
    edited 2021-01-26 13:50

    Yes, there is a lack of distinction with the differing meanings of S and D in the hardware document, particularly when it comes to the ALTx group of instructions. It's something I should have brought to Chip's attention a long time ago.

    Those ALTx prefixing instructions all use a working register that can be both modified itself and is the data for field insertion to S and D fields of the following (prefixed) instruction. The working register is the D register of the ALTx instruction.

    Then there is also references to D and S "fields". There is two cases here too. The bit fields of the working register, and the fields of the prefixed instruction. ALTI has the most overloading.

    ALTI is also the most handy for small table work. It's really powerful being able provide a true three operands, and with inc/dec. It makes the 2-clock overhead of prefixing all worth it.

    EDIT: Here's a recent example I posted where I used ALTI for filling a table by working the third (result) operand only - https://forums.parallax.com/discussion/comment/1512250/#Comment_1512250

  • evanhevanh Posts: 15,916

    Examples are the best answer I think. Chip's simple examples in the document helped me a long way make sense of the short descriptions. The questions I then had were resolved with some testing. I've kind of forgotten what they were now.

  • evanhevanh Posts: 15,916

    Actually, reading the document again, it's not so bad. It is quite carefully written. Just there is no key to say that D[..] is always meaning parts of the D working register. Even though in hindsight it has to be that.

    And it clearly states things like "next instruction's fields" in the relevant places.

    Using the term "operand" wouldn't help either. Because, in these cases, there is two sets of operands. One set for the prefixing instruction and another set for the prefixed instruction.

  • cgraceycgracey Posts: 14,153

    We need to make some animations using DEBUG PLOT. They can be made into compact GIFs.

    Sjgallagher, if any of your questions were not answered, could you please restate them?

  • I think we covered everything, thanks. I'm adding small modifications to my reference manual document (adding a syntax key, changing any references to D/S to [D]/[S]). Just a quick search and replace, nothing that can't be undone if it looks ugly or if we decide it's not necessary.

  • sjgallagher2sjgallagher2 Posts: 22
    edited 2021-01-26 17:14

    Note: Specifically, I'm modifying references to registers and memory to follow register transfer language (RTL), which is pretty universal and will help uniformity.

    =EDIT=

    I think I still misunderstood the meaning of D and S when I proposed the syntax change above. Treating the cog RAM as a memory space would make [D] and [S] more appropriate, but treating it as a register space would make D and S appropriate, when referring to the contents of those registers. Parallax prefers the latter interpretation for the documentation so I'm keeping it and only adding syntax notes at the start. This should be in line with RTL still.

  • potatoheadpotatohead Posts: 10,261
    edited 2021-01-26 19:46

    @sjgallagher2 said:

    Treating the cog RAM as a memory space would make [D] and [S] more appropriate, but treating it as a register space would make D and S appropriate, when referring to the contents of those registers.


    Yes. That was a long discussion early on. IMHO, the primary advantage of the register space vision is it tends to emphasize the memory being private to the COG. It also helps, and this is more true on the P1, people understand a program either needs to be loaded into the COG on the P1, or can be loaded into the COG on P2 in order to run independently on that COG.

    Secondly, the idea of self-modifying code in register space is a much different thing than in general RAM, though that no longer totally applies on the P2, given it can run PASM from either a COG or HUB memory program image.

    Given programs can run from the HUB now, [D] and [S] seem to make as much sense as D and S do, and it's more about where one wants to ground their understanding to build on it, again IMHO.

  • potatohead,

    Even when running from hub, D and S still refer to cog memory/registers, so I think it's still makes sense. HubExec code also can't self modify like the old P1, that's part of why we have the family of ALT* instructions.

Sign In or Register to comment.