https://bugs.libre-soc.org/show_bug.cgi?id=985
[libreriscv.git] / simple_v_extension / specification / mv.x.rst
index bd668abaaf2809ce84753d07ec91cbc2588514b7..e3c7745a3769251a162d288b2355d57fb28c6bc6 100644 (file)
@@ -1,9 +1,10 @@
-[[!tag standards]]
+[[!tag oldstandards]]
 
 MV.X and MV.swizzle
 ===================
 
-swizzle needs a MV.  see below for a potential way to use the funct7 to do a swizzle in rs2.
+swizzle needs a MV (there are 2 of them: swizzle and swizzle2).
+see below for a potential way to use the funct7 to do a swizzle in rs2.
 
 +---------------+-------------+-------+----------+----------+--------+----------+--------+--------+
 | Encoding      | 31:27       | 26:25 | 24:20    | 19:15    | 14:12  | 11:7     | 6:2    | 1:0    |
@@ -105,6 +106,13 @@ potential MV.X?  register-version of MV-swizzle?
 
 question: do we need a swizzle MV.X as well?
 
+MV.X with 3 operands
+====================
+
+regs[rd] = regs[rs1 + regs[rs2]]
+
+Similar to LD/ST with the same twin predication rules
+
 macro-op fusion
 ===============
 
@@ -180,3 +188,205 @@ Transforms for DCT
 
 <https://opencores.org/websvn/filedetails?repname=mpeg2fpga&path=%2Fmpeg2fpga%2Ftrunk%2Frtl%2Fmpeg2%2Fidct.v>
 
+Table to evaluate
+=================
+
+swizzle2 takes 2 arguments, interleaving the two vectors depending on a 3rd (the swizzle selector)
+
++-----------+-------+-------+-------+-------+-------+------+
+|           | 31:27 | 26:25 | 24:20 | 19:15 | 14:12 | 11:7 |
++===========+=======+=======+=======+=======+=======+======+
+| swizzle2  | rs3   | 00    | rs2   | rs1   | 000   | rd   |
++-----------+-------+-------+-------+-------+-------+------+
+| fswizzle2 | rs3   | 01    | rs2   | rs1   | 000   | rd   |
++-----------+-------+-------+-------+-------+-------+------+
+| swizzle   | 0     | 10    | rs2   | rs1   | 000   | rd   |
++-----------+-------+-------+-------+-------+-------+------+
+| fswizzle  | 0     | 11    | rs2   | rs1   | 000   | rd   |
++-----------+-------+-------+-------+-------+-------+------+
+| swizzlei  | imm                   | rs1   | 001   | rd   |
++-----------+                       +-------+-------+------+
+| fswizzlei |                       | rs1   | 010   | rd   |
++-----------+-------+-------+-------+-------+-------+------+
+
+More:
+
+swizzlei would still need the 12-bit format due to not having enough immediate bits. we can get away with only 3 i-type funct3s used for [f]swizzlei by having one funct3 for destsubvl 1 through 3 for int and fp versions and a separate one for destsubvl = 4 that's shared between int/fp:
+
++--------+-----------+----+-----------+----------+-------+-------+------+
+| int/fp | DESTSUBVL | 31 | 30:29     | 28:20    | 19:15 | 14:12 | 11:7 |
++========+===========+====+===========+==========+=======+=======+======+
+| int    | 1 to 3    | 0  | DESTSUBVL | selector | rs    | 000   | rd   |
++--------+-----------+----+-----------+----------+-------+-------+------+
+| fp     | 1 to 3    | 1  | DESTSUBVL | selector | rs    | 000   | rd   |
++--------+-----------+----+-----------+----------+-------+-------+------+
+| int    | 4         | selector[11:0]            | rs    | 001   | rd   |
++--------+-----------+---------------------------+-------+-------+------+
+| fp     | 4         | selector[11:0]            | rs    | 010   | rd   |
++--------+-----------+---------------------------+-------+-------+------+
+
+the rest could be encoded as follows:
+
++-----------+-------+-----------+-------+-------+-------+------+
+|           | 31:27 | 26:25     | 24:20 | 19:15 | 14:12 | 11:7 |
++===========+=======+===========+=======+=======+=======+======+
+| swizzle2  | rs3   | DESTSUBVL | rs2   | rs1   | 100   | rd   |
++-----------+-------+-----------+-------+-------+-------+------+
+| swizzle   | rs1   | DESTSUBVL | rs2   | rs1   | 100   | rd   |
++-----------+-------+-----------+-------+-------+-------+------+
+| fswizzle2 | rs3   | DESTSUBVL | rs2   | rs1   | 101   | rd   |
++-----------+-------+-----------+-------+-------+-------+------+
+| fswizzle  | rs1   | DESTSUBVL | rs2   | rs1   | 101   | rd   |
++-----------+-------+-----------+-------+-------+-------+------+
+
+note how for [f]swizzle, rs3 == rs1
+
+so it uses 5 funct3 values overall, which is appropriate, since swizzle is probably right after muladd in usage in graphics shaders.
+
+Alternative immed encoding
+
++--------+-----------+----------+-------+-------+------+
+| int/fp | 31:28     | 27:20    | 19:15 | 14:12 | 11:7 |
++========+===========+==========+=======+=======+======+
+| int    | DESTMASK  | selector | rs    | 000   | rd   |
++--------+-----------+----------+-------+-------+------+
+| fp     | DESTMASK  | selector | rs    | 001   | rd   |
++--------+-----------+----------+-------+-------+------+ 
+| int    | DESTMASK  | constsel | rs    | 010   | rd   |
++--------+-----------+----------+-------+-------+------+
+| fp     | DESTMASK  | constsel | rs    | 011   | rd   |
++--------+-----------+----------+-------+-------+------+
+
+Allows setting of arbitrary dest (xz, yw) without needing register-versions. Saves on instruction count.
+Needs 4 funct3 to express.
+
+Matrix 4x4 Vector mul
+=====================
+
+::
+
+    pfscale,3 F2, F1, F10
+    pfscaleadd,2 F2, F1, F11, F2
+    pfscaleadd,1 F2, F1, F12, F2
+    pfscaleadd,0 F2, F1, F13, F2
+
+pfscale is a 4 vec mv.shuffle followed by a fmul. pfscaleadd is a 4 vec mv.shuffle followed by a fmac.
+
+In effect what this is doing is:
+
+::
+
+    fmul f2, f1.xxxx, f10
+    fmac f2, f1.yyyy, f11, f2
+    fmac f2, f1.zzzz, f12, f2
+    fmac f2, f1.wwww, f13, f2
+
+Where all of f2, f1, and f10-13 are vec4, and f1.x-w are copied (fixed index) where the other vec4 indices progress.
+
+Pseudocode
+==========
+
+Swizzle:
+
+::
+
+    pub trait SwizzleConstants: Copy + 'static {
+        const CONSTANTS: &'static [Self; 4];
+    }
+
+    impl SwizzleConstants for u8 {
+        const CONSTANTS: &'static [Self; 4] = &[0, 1, 0xFF, 0x7F];
+    }
+
+    impl SwizzleConstants for u16 {
+        const CONSTANTS: &'static [Self; 4] = &[0, 1, 0xFFFF, 0x7FFF];
+    }
+
+    impl SwizzleConstants for f32 {
+        const CONSTANTS: &'static [Self; 4] = &[0.0, 1.0, -1.0, 0.5];
+    }
+
+    // impl for other types too...
+
+    pub fn swizzle<Elm, Selector>(
+        rd: &mut [Elm],
+        rs1: &[Elm],
+        rs2: &[Selector],
+        vl: usize,
+        destsubvl: usize,
+        srcsubvl: usize)
+    where
+        Elm: SwizzleConstants,
+        // Selector is a copyable type that can be converted into u64
+        Selector: Copy + Into<u64>,
+    {
+        const FIELD_SIZE: usize = 3;
+        const FIELD_MASK: u64 = 0b111;
+        for vindex in 0..vl {
+            let selector = rs2[vindex].into();
+            // selector's type is u64
+            if selector >> (FIELD_SIZE * destsubvl) != 0 {
+                // handle illegal instruction trap
+            }
+            for i in 0..destsubvl {
+                let mut sel_field = selector >> (FIELD_SIZE * i);
+                sel_field &= FIELD_MASK;
+                let src = if (sel_field & 0b100) == 0 {
+                    &rs1[(vindex * srcsubvl)..]
+                } else {
+                    SwizzleConstants::CONSTANTS
+                };
+                sel_field &= 0b11;
+                if sel_field as usize >= srcsubvl {
+                    // handle illegal instruction trap
+                }
+                let value = src[sel_field as usize];
+                rd[vindex * destsubvl + i] = value;
+            }
+        }
+    }
+
+Swizzle2:
+
+::
+
+    fn swizzle2<Elm, Selector>(
+        rd: &mut [Elm],
+        rs1: &[Elm],
+        rs2: &[Selector],
+        rs3: &[Elm],
+        vl: usize,
+        destsubvl: usize,
+        srcsubvl: usize)
+    where
+        // Elm is a copyable type
+        Elm: Copy,
+        // Selector is a copyable type that can be converted into u64
+        Selector: Copy + Into<u64>,
+    {
+        const FIELD_SIZE: usize = 3;
+        const FIELD_MASK: u64 = 0b111;
+        for vindex in 0..vl {
+            let selector = rs2[vindex].into();
+            // selector's type is u64
+            if selector >> (FIELD_SIZE * destsubvl) != 0 {
+                // handle illegal instruction trap
+            }
+            for i in 0..destsubvl {
+                let mut sel_field = selector >> (FIELD_SIZE * i);
+                sel_field &= FIELD_MASK;
+                let src = if (sel_field & 0b100) != 0 {
+                    rs1
+                } else {
+                    rs3
+                };
+                sel_field &= 0b11;
+                if sel_field as usize >= srcsubvl {
+                    // handle illegal instruction trap
+                }
+                let value = src[vindex * srcsubvl + (sel_field as usize)];
+                rd[vindex * destsubvl + i] = value;
+            }
+        }
+    }
+