[libre-riscv-dev] [Bug 286] New: DataPointer concept: long-immediate references

bugzilla-daemon at libre-soc.org bugzilla-daemon at libre-soc.org
Tue Apr 14 18:02:03 BST 2020


https://bugs.libre-soc.org/show_bug.cgi?id=286

            Bug ID: 286
           Summary: DataPointer concept: long-immediate references
           Product: Libre-SOC's first SoC
           Version: unspecified
          Hardware: PC
                OS: Linux
            Status: CONFIRMED
          Severity: enhancement
          Priority: ---
         Component: Specification
          Assignee: lkcl at lkcl.net
          Reporter: lkcl at lkcl.net
                CC: libre-riscv-dev at lists.libre-riscv.org
   NLnet milestone: ---

original discussion at:
https://groups.google.com/d/msg/comp.arch/DeGUdZhh1Jc/LzRc61JSAQAJ


i raised an alternative idea last year: a Data Pointer.  similar to a
Program Counter and/or Stack Pointer, the Data Pointer is incremented
implicitly by each operation requiring an immediate, and, in extreme
versions, that may be incremented *bit-wise* rather than on byte, word
or dword boundaries.

opcodes requiring immediates then specify the number of *bits* they wish to
use. the Data Pointer automatically increments such that the next instruction
loads from the subsequent memory address, not the same one.

as an off-the-wall concept, i never thought through how you would actually
*set* the Data Pointer in the first place, nor how loops would be dealt with.

L1-cacheing of the constants (and reading them and including them in the
I-stream) is not a big deal.  however separating them from actual instructions
does actually become a bit of a bind.  perhaps the D-cache could be used
(treat them as data).

loops are the biggest bugbear.  however an idea just occurred to me.
with only a few bits being needed to specify how *much* of the memory pointed
to by the Data Pointer is to be used as an immediate, the remaining (spare)
bits can be taken as an offset by which the Data Pointer is to be "wound back"
(or forward).

perhaps even some mode-bits could be used to indicate, "New Data Pointer Starts
Here and there is a block of immediates of size NN following this instruction":

addi R0, R1, {dpencoding}

dpencoding:

11 10 9 8 7    | 7 6        | 5 4 3 2 1 0  |
immblocklen x4 | immbytelen | immjump x4   |

something like that.

* immblocklen x 32 is the space reserved following this instruction,
  to which the Data Pointer is to be immediately set (zero indicates
  "no change").  thus the PC *knows* that it must add 4ximmblocklen
  bytes to the PC
* immbytelen - the length (in bytes? maybe bits?) of the immediate,
  0b000=8, 0b001=16 etc. etc.  after the immediate is read (immediately)
  from the DataPointer address, the DataPointer must be incremented
  by this amount, only if immjump == 0
* immjump - a signed number of words that (rounded) the DataPointer
  must "jump" by (forward or backwards) *INSTEAD* of incrementing
  by immbytelen.

that should probably do the trick for a first iteration.

analysis:

* compared to standard immediate-loading: for small immediates it's not
  as nice because you have to use the 12-bit immediate space as a pointer
  therefore, simple solution to that: only use this for long immediates,
  or, use 1 extra bit to indicate "11-bit immediate or DataPointer"
  encoding

* with no "construction" of long immediates using 32-bit stuff, it's
  definitely much more compact.


variants include that immjump is *always* set, and is always relative
to DataPointer.  this would actually be better because if we assume
that when the DP is set (immblocklen != 0) that instruction wants
the *first* item @DP, we no longer need both immblocklen and immjump:

7    | 6 5 4 3 2       | 1 0    |
mode | DPlen_or_DPoffs | immlen |

* mode == 0: DPlen x 4 bytes of "offsets" follow this instruction.
             - set DP = PC + 4
             - assume DPoffs = 0.
             - immed = @[DP] of length immlen (bytes? words?
             - add DPlen x 4 to PC

* mode == 1: DPoffs is in bytes 6:2.
             - PC increments as normal (+4)
             - DP does *NOT CHANGE*
             - immed = @[DP + DPoffs*4] of length immlen (bytes? words?)

this gives relatively few bits, and it would not be unreasonable to snarf
a few bits out of a "normal" 12-bit immediate range:

12 11 10 9 8 |   7 6 5 4 3 2 1 0
1  1   1 1 1 | { dpencoding }
N  N   N N N     N N N N N N N N - "normal" immediate


the only complexity would be compiler-side creation of tables that initialise
correctly and in reasonable proximity.

also you'd either lose one main register (one as normal SP, one now as DP)
or it would be required to add a special register (CSR), plus context-saving
to ensure it's not corrupted during interrupts.

l.




assume the 2nd scheme in the latter part of what i wrote (absolute-addressed
DataPointer rather than the incremental-version):

# some prior code which happened already to set DP
# or we just have to have a dummy instruction.
0000 0000    mvi  r0,  DPlen=2   ; r0 discarded in this example
0000 0004    LongConst1          ; could be 64 bit or 128 or 256 bit
0000 0008    LongConst2          ; could be 64 bit or 128 or 256 bit
0000 000c    bne   x,  0, sety2
0000 0010    mvi   y, @DP#0   ; DP was set to 0000 0004 earlier
0000 0014    jmp   end
0000 0018    mvi   y, @DP#2   ; sety2
0000 001c    ....             ; end

the alternative, to save "wasting" an instruction (if there really
are no other prior immediates) is to actually set y unconditionally,
just to get the DataPointer set up then *conditionally* overwrite it.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the libre-riscv-dev mailing list