• Re: Split instruction and immediate stream

    From MitchAlsup1@21:1/5 to Robert Finch on Sun Mar 9 19:23:04 2025
    On Sun, 9 Mar 2025 12:03:22 +0000, Robert Finch wrote:


    One thought I had a while ago using a similar technique to glyph's was
    to place constants at the beginning or the end of a cache line. Then the immediate base register is not needed. The relative offsets would be in
    terms of the current cache line. It has a couple of drawbacks though,
    one being the need to branch around the constant data; could be done by carefully maintaining the next fetch address. Another drawback is the
    code is repositionable only at cache-line boundaries. Might make
    assembling / linking code interesting.

    If you put the constants at the end of the cache line, you will have
    accessed the constants while decoding the instructions and you can
    figure out when to jump to the next cache line without branching.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to mitchalsup@aol.com on Sun Mar 9 19:38:46 2025
    MitchAlsup1 <mitchalsup@aol.com> schrieb:
    On Sun, 9 Mar 2025 12:03:22 +0000, Robert Finch wrote:


    One thought I had a while ago using a similar technique to glyph's was
    to place constants at the beginning or the end of a cache line. Then the
    immediate base register is not needed. The relative offsets would be in
    terms of the current cache line. It has a couple of drawbacks though,
    one being the need to branch around the constant data; could be done by
    carefully maintaining the next fetch address. Another drawback is the
    code is repositionable only at cache-line boundaries. Might make
    assembling / linking code interesting.

    If you put the constants at the end of the cache line, you will have
    accessed the constants while decoding the instructions and you can
    figure out when to jump to the next cache line without branching.

    Did I mention I would not like to write an assembler for that? :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From George Neuner@21:1/5 to tkoenig@netcologne.de on Sun Mar 9 15:59:57 2025
    On Sun, 9 Mar 2025 07:17:31 -0000 (UTC), Thomas Koenig
    <tkoenig@netcologne.de> wrote:

    Robert Finch <robfi680@gmail.com> schrieb:

    I think splitting the code and constant into separate streams requires
    another port(s) on the I$. The port may already be present if
    jump-through-table, JTT, is supported.

    There is also the problem of additional cache (page, ...) misses with
    the instruction stream. Maybe an extra "constant data" cache?
    That would depend on how far the extra data is from the code.

    But branches are going to be more expensive because it is not
    only the PC that needs to changed, but also the data pointer.

    It looks similar to using a constant pool in virtual machine code,
    except that the access is not random but (more or less) sequential as
    straight line code executes.


    Thinking about this a bit more... conceptually, this is not so far
    off from the /360 base pointer addressing mode, but with the base
    pointer implied instead of explicit.

    I guess that the constant tables for a subroutine would be placed either
    before or after a subroutine.

    Like what was usually done for the /360, I believe.

    But much more "fun" could be had if the base pointer was supplied
    by the caller. Want a routine that does something different,
    just call it with a different constant stream for instructions.
    (OK, you could also pass an argument, but that would offer less
    possibilities for quasi self-modifying code).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From EricP@21:1/5 to Robert Finch on Sun Mar 9 17:02:44 2025
    Robert Finch wrote:
    On 2025-03-08 9:21 a.m., Thomas Koenig wrote:
    There was a recent post to the gcc mailing list which showed
    interesting concept of dealing with large constants in an ISA:
    Splitting a the instruction and constant stream. It can be found
    at https://github.com/michaeljclark/glyph/ , and is named "glyph".

    I think the problem the author is trying to solve is better addressed by
    My 66000 (and I would absolutely _hate_ to write an assembler for it).
    Still, I thought it worth mentioning.

    I think it is better to use a constant prefix / postfix instruction to
    encode larger constants in the instruction stream. Or use a wider
    instruction format. In Q+ constant postfixes can be used to override a register spec, allowing immediate constants to be used with many more instructions.

    Yes a kind of prefix instruction that say "here comes an immediate value"
    and loads a 2, 4, or 8 byte immediate with all the sign or zero extend
    options into a special constant register in the Decoder and marks it valid.
    The next instruction just says add immediate "ADDI rd, rs" and it implies
    the constant it just stashed.

    That relieves the consumer opcodes from having to encode all the
    different variable immediate formats.

    It could easily extend to multiple immediate prefix instructions so
    one can have instructions like store immediate STD [rd+imm1], imm2
    by just adding a second constant register to the Decoder.

    The only complication I can see is if the instruction producer-consumer
    pair straddle pages and their is a page fault on the second.
    I wouldn't want to have to save the stashed constant as "thread context"
    so it should roll back to the start of the immediate instruction.
    In which case the faulting RIP is the first instruction and the
    faulting address is someplace in the second.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From MitchAlsup1@21:1/5 to EricP on Sun Mar 9 21:19:41 2025
    On Sun, 9 Mar 2025 21:02:44 +0000, EricP wrote:

    Robert Finch wrote:
    On 2025-03-08 9:21 a.m., Thomas Koenig wrote:
    There was a recent post to the gcc mailing list which showed
    interesting concept of dealing with large constants in an ISA:
    Splitting a the instruction and constant stream. It can be found
    at https://github.com/michaeljclark/glyph/ , and is named "glyph".

    I think the problem the author is trying to solve is better addressed by >>> My 66000 (and I would absolutely _hate_ to write an assembler for it).
    Still, I thought it worth mentioning.

    I think it is better to use a constant prefix / postfix instruction to
    encode larger constants in the instruction stream. Or use a wider
    instruction format. In Q+ constant postfixes can be used to override a
    register spec, allowing immediate constants to be used with many more
    instructions.

    Yes a kind of prefix instruction that say "here comes an immediate
    value"
    and loads a 2, 4, or 8 byte immediate with all the sign or zero extend options into a special constant register in the Decoder and marks it
    valid.
    The next instruction just says add immediate "ADDI rd, rs" and it
    implies
    the constant it just stashed.

    That relieves the consumer opcodes from having to encode all the
    different variable immediate formats.

    It could easily extend to multiple immediate prefix instructions so
    one can have instructions like store immediate STD [rd+imm1], imm2
    by just adding a second constant register to the Decoder.

    The only complication I can see is if the instruction producer-consumer
    pair straddle pages and their is a page fault on the second.
    I wouldn't want to have to save the stashed constant as "thread context"
    so it should roll back to the start of the immediate instruction.

    Execute the instruction and the (preceding) constant as a single
    instruction, so any fault leaves IP pointing at the constant.

    In which case the faulting RIP is the first instruction and the
    faulting address is someplace in the second.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From MitchAlsup1@21:1/5 to Thomas Koenig on Sun Mar 9 21:21:31 2025
    On Sun, 9 Mar 2025 19:38:46 +0000, Thomas Koenig wrote:

    MitchAlsup1 <mitchalsup@aol.com> schrieb:
    On Sun, 9 Mar 2025 12:03:22 +0000, Robert Finch wrote:


    One thought I had a while ago using a similar technique to glyph's was
    to place constants at the beginning or the end of a cache line. Then the >>> immediate base register is not needed. The relative offsets would be in
    terms of the current cache line. It has a couple of drawbacks though,
    one being the need to branch around the constant data; could be done by
    carefully maintaining the next fetch address. Another drawback is the
    code is repositionable only at cache-line boundaries. Might make
    assembling / linking code interesting.

    If you put the constants at the end of the cache line, you will have
    accessed the constants while decoding the instructions and you can
    figure out when to jump to the next cache line without branching.

    Did I mention I would not like to write an assembler for that? :-)

    What no masochism today ??

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From EricP@21:1/5 to All on Sun Mar 9 17:37:25 2025
    MitchAlsup1 wrote:
    On Sun, 9 Mar 2025 21:02:44 +0000, EricP wrote:

    Robert Finch wrote:
    On 2025-03-08 9:21 a.m., Thomas Koenig wrote:
    There was a recent post to the gcc mailing list which showed
    interesting concept of dealing with large constants in an ISA:
    Splitting a the instruction and constant stream. It can be found
    at https://github.com/michaeljclark/glyph/ , and is named "glyph".

    I think the problem the author is trying to solve is better
    addressed by
    My 66000 (and I would absolutely _hate_ to write an assembler for it). >>>> Still, I thought it worth mentioning.

    I think it is better to use a constant prefix / postfix instruction to
    encode larger constants in the instruction stream. Or use a wider
    instruction format. In Q+ constant postfixes can be used to override a
    register spec, allowing immediate constants to be used with many more
    instructions.

    Yes a kind of prefix instruction that say "here comes an immediate
    value"
    and loads a 2, 4, or 8 byte immediate with all the sign or zero extend
    options into a special constant register in the Decoder and marks it
    valid.
    The next instruction just says add immediate "ADDI rd, rs" and it
    implies
    the constant it just stashed.

    That relieves the consumer opcodes from having to encode all the
    different variable immediate formats.

    It could easily extend to multiple immediate prefix instructions so
    one can have instructions like store immediate STD [rd+imm1], imm2
    by just adding a second constant register to the Decoder.

    The only complication I can see is if the instruction producer-consumer
    pair straddle pages and their is a page fault on the second.
    I wouldn't want to have to save the stashed constant as "thread context"
    so it should roll back to the start of the immediate instruction.

    Execute the instruction and the (preceding) constant as a single
    instruction, so any fault leaves IP pointing at the constant.

    Yes, that was implied.
    Decode doesn't spit out a uOp for the producer immediate instruction(s)
    and does for the consumer but with the total length for all.
    Retire adds the total to the committed RIP once for the whole sequence.

    In which case the faulting RIP is the first instruction and the
    faulting address is someplace in the second.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Marcus@21:1/5 to All on Sun Mar 23 13:12:25 2025
    Den 2025-03-23 kl. 04:06, skrev Robert Finch:
    On 2025-03-22 11:04 a.m., Thomas Koenig wrote:
    Marcus <m.delete@this.bitsnbites.eu> schrieb:

    Then we have the page-crossing issue. Is it better to force the
    compiler/assembler to align such instructions so that they never cross
    page boundaries?

    Power 10 chose to do so; actually, larger instructions cannot
    cross a (likely) Cache line size there.  According to the Power
    ISA Version 3.1, section 1.6:

    "Prefixed instructions do not cross 64-byte instruction address
    boundaries. When a prefixed instruction crosses a 64-byte boundary,
    the system alignment error handler is invoked."

    In the latest test project, the LB650 similar to a PowerPC, large
    constants are encoded at the end of the cache line. So, there is a
    similar issue of code running into the constant area.

    I have the assembler moving the code that overlaps to the next cache line.

    It is confusing to look at listing files, as there are constants output inline with the code. Makes it look like the code should not work. How
    does it know where to go for the next instruction? Is the question that
    comes to mind.

    For now, the hardware decoder takes the cheezy approach of marking instructions fetched in the constant area as invalid. The constant area
    gets fetched and loaded into the pipeline, but as NOPs.

    It is quite a trick getting the assembler to place constants at the end
    of the cache line and generate references to the constants. It is
    interesting because I have *constants* being relocated by the assembler
    / linker. Normally there would not be a relocation associated with a constant. A relocation reference to the constant is spit out by the assembler, and the linker updates the index to the constant in the code.

    It does not quite work yet. Constants are placed and code is moved, but
    the linked program does not have the correct references yet.

    Experimental, but looking like things will work.


    Although I have not tried any of these techniques, here are my thoughts.

    Why not always place the constant next to (right after) the instruction
    that references it, instead of at an offset within the cache line?

    The effect should be very similar, but now you have a simpler offset
    (it's always zero) and you eliminate the problem with having to keep
    track of where the constants are in order to prevent the PC/IP from
    running into the constant area.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to Robert Finch on Sun Mar 23 13:44:23 2025
    Robert Finch <robfi680@gmail.com> schrieb:

    In the latest test project, the LB650 similar to a PowerPC, large
    constants are encoded at the end of the cache line. So, there is a
    similar issue of code running into the constant area.

    What is your motivation for this?

    If you have an instruction including constant(s) which no longer
    fits your cache line (say, 8 bytes left and 12 bytes needed)
    it does not matter where you put the constants and where you
    put the instructions - it will not fit, and you have to start
    a new cache line.

    I am not seeing an advantage over what Power 10 does, which is
    just to add a NOP at the end if things don't fit on a cacheline.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From EricP@21:1/5 to Marcus on Sun Mar 23 09:44:04 2025
    Marcus wrote:
    Den 2025-03-09 kl. 22:19, skrev MitchAlsup1:
    On Sun, 9 Mar 2025 21:02:44 +0000, EricP wrote:

    Robert Finch wrote:
    On 2025-03-08 9:21 a.m., Thomas Koenig wrote:
    There was a recent post to the gcc mailing list which showed
    interesting concept of dealing with large constants in an ISA:
    Splitting a the instruction and constant stream. It can be found
    at https://github.com/michaeljclark/glyph/ , and is named "glyph".

    I think the problem the author is trying to solve is better
    addressed by
    My 66000 (and I would absolutely _hate_ to write an assembler for it). >>>>> Still, I thought it worth mentioning.

    I think it is better to use a constant prefix / postfix instruction to >>>> encode larger constants in the instruction stream. Or use a wider
    instruction format. In Q+ constant postfixes can be used to override a >>>> register spec, allowing immediate constants to be used with many more
    instructions.

    Yes a kind of prefix instruction that say "here comes an immediate
    value"
    and loads a 2, 4, or 8 byte immediate with all the sign or zero extend
    options into a special constant register in the Decoder and marks it
    valid.
    The next instruction just says add immediate "ADDI rd, rs" and it
    implies
    the constant it just stashed.

    That relieves the consumer opcodes from having to encode all the
    different variable immediate formats.

    It could easily extend to multiple immediate prefix instructions so
    one can have instructions like store immediate STD [rd+imm1], imm2
    by just adding a second constant register to the Decoder.

    The only complication I can see is if the instruction producer-consumer
    pair straddle pages and their is a page fault on the second.
    I wouldn't want to have to save the stashed constant as "thread context" >>> so it should roll back to the start of the immediate instruction.

    Execute the instruction and the (preceding) constant as a single
    instruction, so any fault leaves IP pointing at the constant.

    Then we have the page-crossing issue. Is it better to force the compiler/assembler to align such instructions so that they never cross
    page boundaries?


    In which case the faulting RIP is the first instruction and the
    faulting address is someplace in the second.

    Its an unnecessary restriction as I point out above and in another msg,
    the core doesn't increment the committed RIP for the constant instruction
    size and adds its size to the following consumer instruction,
    effectively turning the pair into a variable length instruction.
    And straddle faults can already happen with variable length instructions.
    If it faults on a straddle then the RIP rolls back to point at the
    constant and the faulting address points at the next page.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From MitchAlsup1@21:1/5 to Marcus on Sun Mar 23 16:51:40 2025
    On Sun, 23 Mar 2025 12:12:25 +0000, Marcus wrote:

    Den 2025-03-23 kl. 04:06, skrev Robert Finch:
    On 2025-03-22 11:04 a.m., Thomas Koenig wrote:
    Marcus <m.delete@this.bitsnbites.eu> schrieb:

    Then we have the page-crossing issue. Is it better to force the
    compiler/assembler to align such instructions so that they never cross >>>> page boundaries?

    Power 10 chose to do so; actually, larger instructions cannot
    cross a (likely) Cache line size there.  According to the Power
    ISA Version 3.1, section 1.6:

    "Prefixed instructions do not cross 64-byte instruction address
    boundaries. When a prefixed instruction crosses a 64-byte boundary,
    the system alignment error handler is invoked."

    In the latest test project, the LB650 similar to a PowerPC, large
    constants are encoded at the end of the cache line. So, there is a
    similar issue of code running into the constant area.

    I have the assembler moving the code that overlaps to the next cache
    line.

    It is confusing to look at listing files, as there are constants output
    inline with the code. Makes it look like the code should not work. How
    does it know where to go for the next instruction? Is the question that
    comes to mind.

    For now, the hardware decoder takes the cheezy approach of marking
    instructions fetched in the constant area as invalid. The constant area
    gets fetched and loaded into the pipeline, but as NOPs.

    It is quite a trick getting the assembler to place constants at the end
    of the cache line and generate references to the constants. It is
    interesting because I have *constants* being relocated by the assembler
    / linker. Normally there would not be a relocation associated with a
    constant. A relocation reference to the constant is spit out by the
    assembler, and the linker updates the index to the constant in the code.

    It does not quite work yet. Constants are placed and code is moved, but
    the linked program does not have the correct references yet.

    Experimental, but looking like things will work.


    Although I have not tried any of these techniques, here are my thoughts.

    Why not always place the constant next to (right after) the instruction
    that references it, instead of at an offset within the cache line?

    The effect should be very similar, but now you have a simpler offset
    (it's always zero) and you eliminate the problem with having to keep
    track of where the constants are in order to prevent the PC/IP from
    running into the constant area.

    You also don't need to worry about cache line (i.e., artificial)
    boundaries.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From MitchAlsup1@21:1/5 to Robert Finch on Sun Mar 23 20:02:59 2025
    On Sun, 23 Mar 2025 17:54:19 +0000, Robert Finch wrote:

    On 2025-03-23 8:12 a.m., Marcus wrote:
    Den 2025-03-23 kl. 04:06, skrev Robert Finch:
    On 2025-03-22 11:04 a.m., Thomas Koenig wrote:
    Marcus <m.delete@this.bitsnbites.eu> schrieb:

    It does not quite work yet. Constants are placed and code is moved,
    but the linked program does not have the correct references yet.

    Experimental, but looking like things will work.


    Although I have not tried any of these techniques, here are my thoughts.

    Why not always place the constant next to (right after) the instruction
    that references it, instead of at an offset within the cache line?

    That is a very good idea. It is the same thing almost as using a
    variable length instruction.

    LB650 uses a smaller constant packet (16-bits) than the instruction. So, instructions would need to be able to be aligned at 16-bit boundaries.
    LB650 instruction are fixed 32-bit. There is also the possibility of
    sharing the same constants, although slim.

    Consider stack pointer displacements:: local x is always [SP,offset(X)]
    since these are mostly 16-bit displacements, they are already optimal.

    But consider local-static data:: displacement( x ) varies with IP,
    unless the compiler 'eats' an instruction to load the address--which
    is generally not that great of an idea.

    Then consider extern-global data:: you are likely using 32-bit
    (tiny-medium model) or 64-bit (large and huge model). The 32-bit
    form is arguably IP-relative, the 64-bit form can be argued either
    way.

    My overall argument is that there are unlikely to be "all that many"
    exactly equal constants in a dozen instructions that is that cache
    line.

    The effect should be very similar, but now you have a simpler offset
    (it's always zero) and you eliminate the problem with having to keep
    track of where the constants are in order to prevent the PC/IP from
    running into the constant area.

    I wish I had thought of that last night. But I have coded things now.

    Never let a done (but mediocre) solution prevent better solutions--
    that is for your Boss to decide.

    Got the compiler / assembler going. The listings are a few percent
    shorter than the PowerPC. It may be due to bugs yet. I think the
    difference may be the PowerPC burns up bits using pairs of instructions
    for high/low halves of the constant.

    The vbcc compiler for the PowerPC was modified.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anton Ertl@21:1/5 to Robert Finch on Mon Mar 24 06:47:42 2025
    Robert Finch <robfi680@gmail.com> writes:
    On 2025-03-23 8:12 a.m., Marcus wrote:
    Why not always place the constant next to (right after) the instruction
    that references it, instead of at an offset within the cache line?

    That is a very good idea. It is the same thing almost as using a
    variable length instruction.

    b16 (both b16-dsp and b16-small) puts 4 5-bit instructions in a 16-bit
    word (for an instruction in slot 0, 4 of the 5 bits are 0, so it can
    only be either a nop or a call).

    The lit and litc instructions take their operands from the next word
    in the instruction stream (it seems to me that litc,which only takes
    one byte from the instruction stream, makes sense only if there are
    two litc's in one instruction word, because the program counter has to
    be 16-bit-aligned on the next instruction fetch.

    Control-flow instructions take take their target address from the rest
    of the instruction word (i.e., a call in the first slot has a 15-bit
    target, a jump in slot 2 has a 5-bit target); a control-flow
    instruction in slot 3 (no bits left in the instruction word) takes the
    address from the stack.

    This is all designed for scrictly sequential decoding and processing,
    with no pipielining. Bernd Paysan reports 200MHz for b16-dsp and
    150MHz for b16-small in XC035, a 0.35um process. For comparison, the
    P54C (Pentium) reached up to 200MHz and Klamath (Pentium II) up to
    300M in 0.35um, but with pipelining, but also providing lots of performance-enhancing features; and they were 32-bit CPUs, while b16
    is 16-bit.

    Various information on the b16 can be found at <https://bernd-paysan.de/b16.html>.

    - anton
    --
    'Anyone trying for "industrial quality" ISA should avoid undefined behavior.'
    Mitch Alsup, <c17fcd89-f024-40e7-a594-88a85ac10d20o@googlegroups.com>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)