Live data from Hacker News

Programming with RISC-V Vector Instructions

gms.tf

31–38 of 38 posts

Re: Programming with RISC-V Vector Instructions

#31
post #20

Irrelevant i know, but: > For the purpose of our example, the exercise is to write vector code that efficiently converts a BCD string such as { 0x12, 0x34, ..., 0xcd, 0xef } to a corresponding ASCII string (e.g. { '1', '2', '3', '4', ..., 'c', 'd', 'e', 'f' }). On a high-level, a solution involves separating the nibbles into single bytes and then converting each byte to the matching ASCII value. If your BCD string ha…

> This code converts a byte string to its hex representation. It has nothing to do with BCD, right? BCD to ASCII is a strict subset of bin to hex ASCII; and in this case there is no runtime cost to supporting both. This also covers nybble-coded octal.

Describing something that produces a hex string from binary as "BCD to ASCII" is unusual and misleading. And claiming that 0xcd and 0xef are BCD is simply incorrect.

Re: Programming with RISC-V Vector Instructions

#32
post #18

Wow, this RISC-V ISA truly is quite brilliant. Having worked on PPC, with a RISC Instruction set the difference between 128 bit vs 256 bit instructions really does eat up the limited opcode space for really trivial differences. Also having written say one fast version of vector array copy can now just be used between different vector version lengths, no need to write different versions to exploit expanded width, and…

The 32 variable length registers don’t overlap; the register grouping is orthogonal to the length of each register. The grouping... sounds “interesting” to implement in an OoOE design. Most obvious would be to have the instruction decoder emit one uop per register in the grouping... but that means vsetvli would have to stall decoding until it’s resolved. But that also seems to be how element size is set, so that woul…

It's absolutely essential to be able to change vsetvli in the middle of a kernel.

It is expected that in a future expanded Vector instruction set with 48 bit or 64 bit opcodes the vtype will be explicitly encoded in every instruction and can change every instruction.

Right now the vsetvli is setting (slightly) persistent state that affects following instructions. You're allowed to put one before every vector instruction if you want, without significant execution penalty -- there will be a little, from extra instruction fetch and decode -- but similar to doing, say, an integer add between each vector instruction.

The natural implementation even now is to have each vector instruction pick up the current vtype when it is decoded and carry it along with it through the pipeline as a few extra bits of opcode.

You certainly don't want to have any stalls or pipeline flushes just because the vtype changes.

Re: Programming with RISC-V Vector Instructions

#33
post #23

Whoa, that's a well designed ISA.

The vector extension yes, the C (compressed) extension is unusual: you can have 32 bits instructions aligned on 16bit, while nice for code density this means that the implementation is much more complex than Thumb/MIPS16 extensions..

Thumb2 -- which is the only ISA available on 32 bit Cortex M devices and the main ISA for a decade now on 32 bit Cortex A devices -- mixes 16 bit and 32 bit opcodes arbitrarily, with 32 bit opcodes frequently on 16 bit boundaries.

It's simply Not That Hard to deal with. You just need to have two 32 bit words in your instruction decode buffer. Sometimes you need the 1st half of the 2nd word and sometimes you don't.

Incidentally, once you've done that, arbitrarily aligned (on halfwords) 48 bit instructions don't need anything extra.

Re: Programming with RISC-V Vector Instructions

#34
post #22

Earlier quoted context omitted.

It gives you a hardware testing environment with system calls for reasonable amounts of wall clock time. If you're simulating actual hardware, e.g., a Verilog description of a RISC-V microprocessor compiled to a cycle-accurate simulation with Verilator, your simulation rate is going to be ~10KHz. You can write useful tests with the Proxy Kernel (or something like it) that run in ~1 million instructions (minutes of wa…

Nitpick: printf is is a libc call.

... and that libc code (usually NewLib[nano]) formats a buffer then calls write(2), which pk provides.

Re: Programming with RISC-V Vector Instructions

#35

Pretty cool. For RISC-V experts out there, can someone explain to me the purpose of the proxy kernel? I can't seem to wrap my head around it. Why not just run a normal kernel (e.g. Linux) on top of the emulator? What advantages/disadvantages does the proxy kernel have?

As well as very slow verilog RTL emulation, pk is also used to allow you to run standard User-mode RISC-V binaries with many kinds of systems call in them on:

- software emulators

- cores implemented in an FPGA

- prototype chips

Whatever it is, you only have to implement the CPU core, some RAM, and some sort of two-way communications channel -- whether a pipe, UART, USB Serial, ethernet or WIFI.

On the other end of the communications channel you run riscv-fesvr (Front End SerVeR)

pk traps systems calls, serializes the arguments, send them to fesvr. fesvr unpacks the arguments, makes the system call on the host Linux machine, serializes the results, and sends them back to the RISC-V core running in that FPGA or prototype chip or Verilator or whatever.

So your test programs get to use not only printf() but also navigate the host filesystem, open files, get the time etc etc.

A proper Linux Kernel on the system under test would require megabytes of RAM, various I/O devices etc.

pk requires only a few kb of RAM and a communications channel.

Re: Programming with RISC-V Vector Instructions

#36
This is a reasonably good example (except it's binary to hex, not just BCD to hex), but it's from the start of the year and based on the already out of date version 0.8 draft spec.

A couple of things need to be changed to bring it up to date:

  -vlbu.v v16, (a1)
  +vle8.v v16, (a1)
  +vzext.vf2 v16, v16

  -vsb.v v24, (a0)
  +vse8.v v24, (a0)
I'd also probably make (or at least compare the speed of) one more change:

  -vrgather.vv v24, v8, v16
  +vmsgtu.vi v0, v16, 9 # set mask-bit if >9
  +vadd.vi v16, v16, '0' # add '0' to each element
  +vadd.vi v16, v16, 'a'-0xA-'0', v0.t # masked add to correct A..F
That's basically the same code as he used to create the lookup table in v8 for the vrgather. I think it might run faster on many machines, and also the vrgather would fail on the smallest machines (with only 32 bits in each vector register) if anyone modified the code to not use m8 (LMUL=8).

For more explanation see my post at https://www.reddit.com/r/RISCV/comments/i5alno/programming_w...

[NB slight cheat -- those vadd.vi immediates are too big to fit .. you'd actually need to put them in integer registers and use vadd.vx, which can be set up outside the loop]

Post reply on HN