[libre-riscv-dev] spike-sv non-default element widths

Jacob Lifshay programmerjake at gmail.com
Thu Oct 11 08:30:30 BST 2018


On Thu, Oct 11, 2018 at 12:09 AM lkcl <lkcl at libre-riscv.org> wrote:

> On Wed, Oct 10, 2018 at 10:02 PM lkcl <lkcl at libre-riscv.org> wrote:
> >
> > On Wed, Oct 10, 2018 at 9:34 PM Jacob Lifshay <programmerjake at gmail.com>
> wrote:
> > >
> > > On Wed, Oct 10, 2018 at 7:45 AM Luke Kenneth Casson Leighton <
> lkcl at lkcl.net>
> > > wrote:
> > >
> > > > .... actually.. ah.... for signed and unsigned integers, is it
> > > > _actually_ the case that the size of the type will affect the answer,
> > > > if typecast down to e.g. int16_t/uint16_t or int8_t/uint8_t?
> > > >
> > > >  by that i mean:
> > > >
> > > >  uint64_t x = 0..255;
> > > >  uint64_t y = 0..255;
> > > >  uint8_t x1 = (uint8_t)x;
> > > >  uint8_t y1 = (uint8_t)y;
> > > >
> > > >  assert (x / y) == (x1 / y1)
> > > >
> > > > or any other operator.  will that hold for all possible values of x
> > > > and y?  i mean, i _could_ write a for-loop to check... :)
> > > >
> > > Assuming the compare only operates on the lower 8 bits, it holds for
> > > mul/add/sub/bitwise-logic/left-shift. It doesn't hold for div/mod or
> > > right-shift. That's why there are only 1 of add/sub/and/or/xor/mul in
> RV
> > > instead of a signed/unsigned version of each of them.
> > >
> > > It works similarly for any wider bitwidth simulating a narrower
> bitwidth as
> > > long as the upper bits of the results are ignored.
>
>
> https://git.libre-riscv.org/?p=riscv-isa-sim.git;a=blob;f=operators/operators.t.cc;h=b5ac0185adba82ad8424401a50807f63ecb383ea;hb=c3d43aa1e221c74936adac7673f1923cbec5fdd0
>
>  ok so for all possible int8_t values 0-255 on +-*/% >> << when first
> typecast to uint8_t into a uint16_t, a uint16_t answer is correct
>
>             int8_t x=0, y=0;
>             int16_t x1, y1;
>             int8_t z = x op y;
>             x1 = (uint8_t)x;
>             y1 = (uint8_t)y;
>             uint16_t z1 = x1 op y1;
>
> all answers match.
>
Actually, it doesn't work. The reason is that C/C++ specifies everything
smaller than int is promoted to int before the arithmetic is done, so to
check properly you would need to cast the result of each operation to the
type the operation was supposed to be done in. Like:

int8_t x, y;
auto z = (int8_t)(x * y);

Since Rust doesn't cast between integer types unless you explicitly tell it
to, it may be a more appropriate language for testing out
arithmetical/logical operations.

I tried to translate what I think you intended in your code snippet to rust
which you can view the output generated on Compiler Explorer:
https://rust.godbolt.org/z/ydX-JH

>
> so i believe it would be safe to do the following algorithm (for integers)
>
> * work out the maximum bitwidth of RS1 and RS2, called MB
> * take RS1 of width N (8/16/32)
> * typecast it to unsigned integer of width N
> * sign-extend from N bitwidth to MB bitwidth
> * return it in reg_t (which is a uint64_t)
> * likewise with RS2 (for its own version of N)
> * carrry out the answer
> * let sign-extending take place (sext32)
> * on storing in RD, truncate answer to bitwidth M
>
> all three bitwidths *may* be different.
>
> l.
>
> _______________________________________________
> libre-riscv-dev mailing list
> libre-riscv-dev at lists.libre-riscv.org
> http://lists.libre-riscv.org/mailman/listinfo/libre-riscv-dev
>


More information about the libre-riscv-dev mailing list