xref: /openssl/crypto/perlasm/riscv.pm (revision 7ed6de99)
1#! /usr/bin/env perl
2# This file is dual-licensed, meaning that you can use it under your
3# choice of either of the following two licenses:
4#
5# Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
6#
7# Licensed under the Apache License 2.0 (the "License"). You can obtain
8# a copy in the file LICENSE in the source distribution or at
9# https://www.openssl.org/source/license.html
10#
11# or
12#
13# Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
14# Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
15# Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com>
16# All rights reserved.
17#
18# Redistribution and use in source and binary forms, with or without
19# modification, are permitted provided that the following conditions
20# are met:
21# 1. Redistributions of source code must retain the above copyright
22#    notice, this list of conditions and the following disclaimer.
23# 2. Redistributions in binary form must reproduce the above copyright
24#    notice, this list of conditions and the following disclaimer in the
25#    documentation and/or other materials provided with the distribution.
26#
27# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39use strict;
40use warnings;
41
42# Set $have_stacktrace to 1 if we have Devel::StackTrace
43my $have_stacktrace = 0;
44if (eval {require Devel::StackTrace;1;}) {
45    $have_stacktrace = 1;
46}
47
48my @regs = map("x$_",(0..31));
49# Mapping from the RISC-V psABI ABI mnemonic names to the register number.
50my @regaliases = ('zero','ra','sp','gp','tp','t0','t1','t2','s0','s1',
51    map("a$_",(0..7)),
52    map("s$_",(2..11)),
53    map("t$_",(3..6))
54);
55
56my %reglookup;
57@reglookup{@regs} = @regs;
58@reglookup{@regaliases} = @regs;
59
60# Takes a register name, possibly an alias, and converts it to a register index
61# from 0 to 31
62sub read_reg {
63    my $reg = lc shift;
64    if (!exists($reglookup{$reg})) {
65        my $trace = "";
66        if ($have_stacktrace) {
67            $trace = Devel::StackTrace->new->as_string;
68        }
69        die("Unknown register ".$reg."\n".$trace);
70    }
71    my $regstr = $reglookup{$reg};
72    if (!($regstr =~ /^x([0-9]+)$/)) {
73        my $trace = "";
74        if ($have_stacktrace) {
75            $trace = Devel::StackTrace->new->as_string;
76        }
77        die("Could not process register ".$reg."\n".$trace);
78    }
79    return $1;
80}
81
82# Read the sew setting(8, 16, 32 and 64) and convert to vsew encoding.
83sub read_sew {
84    my $sew_setting = shift;
85
86    if ($sew_setting eq "e8") {
87        return 0;
88    } elsif ($sew_setting eq "e16") {
89        return 1;
90    } elsif ($sew_setting eq "e32") {
91        return 2;
92    } elsif ($sew_setting eq "e64") {
93        return 3;
94    } else {
95        my $trace = "";
96        if ($have_stacktrace) {
97            $trace = Devel::StackTrace->new->as_string;
98        }
99        die("Unsupported SEW setting:".$sew_setting."\n".$trace);
100    }
101}
102
103# Read the LMUL settings and convert to vlmul encoding.
104sub read_lmul {
105    my $lmul_setting = shift;
106
107    if ($lmul_setting eq "mf8") {
108        return 5;
109    } elsif ($lmul_setting eq "mf4") {
110        return 6;
111    } elsif ($lmul_setting eq "mf2") {
112        return 7;
113    } elsif ($lmul_setting eq "m1") {
114        return 0;
115    } elsif ($lmul_setting eq "m2") {
116        return 1;
117    } elsif ($lmul_setting eq "m4") {
118        return 2;
119    } elsif ($lmul_setting eq "m8") {
120        return 3;
121    } else {
122        my $trace = "";
123        if ($have_stacktrace) {
124            $trace = Devel::StackTrace->new->as_string;
125        }
126        die("Unsupported LMUL setting:".$lmul_setting."\n".$trace);
127    }
128}
129
130# Read the tail policy settings and convert to vta encoding.
131sub read_tail_policy {
132    my $tail_setting = shift;
133
134    if ($tail_setting eq "ta") {
135        return 1;
136    } elsif ($tail_setting eq "tu") {
137        return 0;
138    } else {
139        my $trace = "";
140        if ($have_stacktrace) {
141            $trace = Devel::StackTrace->new->as_string;
142        }
143        die("Unsupported tail policy setting:".$tail_setting."\n".$trace);
144    }
145}
146
147# Read the mask policy settings and convert to vma encoding.
148sub read_mask_policy {
149    my $mask_setting = shift;
150
151    if ($mask_setting eq "ma") {
152        return 1;
153    } elsif ($mask_setting eq "mu") {
154        return 0;
155    } else {
156        my $trace = "";
157        if ($have_stacktrace) {
158            $trace = Devel::StackTrace->new->as_string;
159        }
160        die("Unsupported mask policy setting:".$mask_setting."\n".$trace);
161    }
162}
163
164my @vregs = map("v$_",(0..31));
165my %vreglookup;
166@vreglookup{@vregs} = @vregs;
167
168sub read_vreg {
169    my $vreg = lc shift;
170    if (!exists($vreglookup{$vreg})) {
171        my $trace = "";
172        if ($have_stacktrace) {
173            $trace = Devel::StackTrace->new->as_string;
174        }
175        die("Unknown vector register ".$vreg."\n".$trace);
176    }
177    if (!($vreg =~ /^v([0-9]+)$/)) {
178        my $trace = "";
179        if ($have_stacktrace) {
180            $trace = Devel::StackTrace->new->as_string;
181        }
182        die("Could not process vector register ".$vreg."\n".$trace);
183    }
184    return $1;
185}
186
187# Read the vm settings and convert to mask encoding.
188sub read_mask_vreg {
189    my $vreg = shift;
190    # The default value is unmasked.
191    my $mask_bit = 1;
192
193    if (defined($vreg)) {
194        my $reg_id = read_vreg $vreg;
195        if ($reg_id == 0) {
196            $mask_bit = 0;
197        } else {
198            my $trace = "";
199            if ($have_stacktrace) {
200                $trace = Devel::StackTrace->new->as_string;
201            }
202            die("The ".$vreg." is not the mask register v0.\n".$trace);
203        }
204    }
205    return $mask_bit;
206}
207
208# Helper functions
209
210sub brev8_rv64i {
211    # brev8 without `brev8` instruction (only in Zbkb)
212    # Bit-reverses the first argument and needs two scratch registers
213    my $val = shift;
214    my $t0 = shift;
215    my $t1 = shift;
216    my $brev8_const = shift;
217    my $seq = <<___;
218        la      $brev8_const, Lbrev8_const
219
220        ld      $t0, 0($brev8_const)  # 0xAAAAAAAAAAAAAAAA
221        slli    $t1, $val, 1
222        and     $t1, $t1, $t0
223        and     $val, $val, $t0
224        srli    $val, $val, 1
225        or      $val, $t1, $val
226
227        ld      $t0, 8($brev8_const)  # 0xCCCCCCCCCCCCCCCC
228        slli    $t1, $val, 2
229        and     $t1, $t1, $t0
230        and     $val, $val, $t0
231        srli    $val, $val, 2
232        or      $val, $t1, $val
233
234        ld      $t0, 16($brev8_const) # 0xF0F0F0F0F0F0F0F0
235        slli    $t1, $val, 4
236        and     $t1, $t1, $t0
237        and     $val, $val, $t0
238        srli    $val, $val, 4
239        or      $val, $t1, $val
240___
241    return $seq;
242}
243
244sub sd_rev8_rv64i {
245    # rev8 without `rev8` instruction (only in Zbb or Zbkb)
246    # Stores the given value byte-reversed and needs one scratch register
247    my $val = shift;
248    my $addr = shift;
249    my $off = shift;
250    my $tmp = shift;
251    my $off0 = ($off + 0);
252    my $off1 = ($off + 1);
253    my $off2 = ($off + 2);
254    my $off3 = ($off + 3);
255    my $off4 = ($off + 4);
256    my $off5 = ($off + 5);
257    my $off6 = ($off + 6);
258    my $off7 = ($off + 7);
259    my $seq = <<___;
260        sb      $val, $off7($addr)
261        srli    $tmp, $val, 8
262        sb      $tmp, $off6($addr)
263        srli    $tmp, $val, 16
264        sb      $tmp, $off5($addr)
265        srli    $tmp, $val, 24
266        sb      $tmp, $off4($addr)
267        srli    $tmp, $val, 32
268        sb      $tmp, $off3($addr)
269        srli    $tmp, $val, 40
270        sb      $tmp, $off2($addr)
271        srli    $tmp, $val, 48
272        sb      $tmp, $off1($addr)
273        srli    $tmp, $val, 56
274        sb      $tmp, $off0($addr)
275___
276    return $seq;
277}
278
279# Scalar crypto instructions
280
281sub aes64ds {
282    # Encoding for aes64ds rd, rs1, rs2 instruction on RV64
283    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
284    my $template = 0b0011101_00000_00000_000_00000_0110011;
285    my $rd = read_reg shift;
286    my $rs1 = read_reg shift;
287    my $rs2 = read_reg shift;
288    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
289}
290
291sub aes64dsm {
292    # Encoding for aes64dsm rd, rs1, rs2 instruction on RV64
293    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
294    my $template = 0b0011111_00000_00000_000_00000_0110011;
295    my $rd = read_reg shift;
296    my $rs1 = read_reg shift;
297    my $rs2 = read_reg shift;
298    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
299}
300
301sub aes64es {
302    # Encoding for aes64es rd, rs1, rs2 instruction on RV64
303    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
304    my $template = 0b0011001_00000_00000_000_00000_0110011;
305    my $rd = read_reg shift;
306    my $rs1 = read_reg shift;
307    my $rs2 = read_reg shift;
308    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
309}
310
311sub aes64esm {
312    # Encoding for aes64esm rd, rs1, rs2 instruction on RV64
313    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
314    my $template = 0b0011011_00000_00000_000_00000_0110011;
315    my $rd = read_reg shift;
316    my $rs1 = read_reg shift;
317    my $rs2 = read_reg shift;
318    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
319}
320
321sub aes64im {
322    # Encoding for aes64im rd, rs1 instruction on RV64
323    #                XXXXXXXXXXXX_ rs1 _XXX_ rd  _XXXXXXX
324    my $template = 0b001100000000_00000_001_00000_0010011;
325    my $rd = read_reg shift;
326    my $rs1 = read_reg shift;
327    return ".word ".($template | ($rs1 << 15) | ($rd << 7));
328}
329
330sub aes64ks1i {
331    # Encoding for aes64ks1i rd, rs1, rnum instruction on RV64
332    #                XXXXXXXX_rnum_ rs1 _XXX_ rd  _XXXXXXX
333    my $template = 0b00110001_0000_00000_001_00000_0010011;
334    my $rd = read_reg shift;
335    my $rs1 = read_reg shift;
336    my $rnum = shift;
337    return ".word ".($template | ($rnum << 20) | ($rs1 << 15) | ($rd << 7));
338}
339
340sub aes64ks2 {
341    # Encoding for aes64ks2 rd, rs1, rs2 instruction on RV64
342    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
343    my $template = 0b0111111_00000_00000_000_00000_0110011;
344    my $rd = read_reg shift;
345    my $rs1 = read_reg shift;
346    my $rs2 = read_reg shift;
347    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
348}
349
350sub brev8 {
351    # brev8 rd, rs
352    my $template = 0b011010000111_00000_101_00000_0010011;
353    my $rd = read_reg shift;
354    my $rs = read_reg shift;
355    return ".word ".($template | ($rs << 15) | ($rd << 7));
356}
357
358sub clmul {
359    # Encoding for clmul rd, rs1, rs2 instruction on RV64
360    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
361    my $template = 0b0000101_00000_00000_001_00000_0110011;
362    my $rd = read_reg shift;
363    my $rs1 = read_reg shift;
364    my $rs2 = read_reg shift;
365    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
366}
367
368sub clmulh {
369    # Encoding for clmulh rd, rs1, rs2 instruction on RV64
370    #                XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
371    my $template = 0b0000101_00000_00000_011_00000_0110011;
372    my $rd = read_reg shift;
373    my $rs1 = read_reg shift;
374    my $rs2 = read_reg shift;
375    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
376}
377
378sub rev8 {
379    # Encoding for rev8 rd, rs instruction on RV64
380    #               XXXXXXXXXXXXX_ rs  _XXX_ rd  _XXXXXXX
381    my $template = 0b011010111000_00000_101_00000_0010011;
382    my $rd = read_reg shift;
383    my $rs = read_reg shift;
384    return ".word ".($template | ($rs << 15) | ($rd << 7));
385}
386
387sub roriw {
388    # Encoding for roriw rd, rs1, shamt instruction on RV64
389    #               XXXXXXX_ shamt _ rs1 _XXX_ rd  _XXXXXXX
390    my $template = 0b0110000_00000_00000_101_00000_0011011;
391    my $rd = read_reg shift;
392    my $rs1 = read_reg shift;
393    my $shamt = shift;
394    return ".word ".($template | ($shamt << 20) | ($rs1 << 15) | ($rd << 7));
395}
396
397sub maxu {
398    # Encoding for maxu rd, rs1, rs2 instruction on RV64
399    #               XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
400    my $template = 0b0000101_00000_00000_111_00000_0110011;
401    my $rd = read_reg shift;
402    my $rs1 = read_reg shift;
403    my $rs2 = read_reg shift;
404    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
405}
406
407sub minu {
408    # Encoding for minu rd, rs1, rs2 instruction on RV64
409    #               XXXXXXX_ rs2 _ rs1 _XXX_ rd  _XXXXXXX
410    my $template = 0b0000101_00000_00000_101_00000_0110011;
411    my $rd = read_reg shift;
412    my $rs1 = read_reg shift;
413    my $rs2 = read_reg shift;
414    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
415}
416
417# Vector instructions
418
419sub vadd_vv {
420    # vadd.vv vd, vs2, vs1, vm
421    my $template = 0b000000_0_00000_00000_000_00000_1010111;
422    my $vd = read_vreg shift;
423    my $vs2 = read_vreg shift;
424    my $vs1 = read_vreg shift;
425    my $vm = read_mask_vreg shift;
426    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
427}
428
429sub vadd_vx {
430    # vadd.vx vd, vs2, rs1, vm
431    my $template = 0b000000_0_00000_00000_100_00000_1010111;
432    my $vd = read_vreg shift;
433    my $vs2 = read_vreg shift;
434    my $rs1 = read_reg shift;
435    my $vm = read_mask_vreg shift;
436    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
437}
438
439sub vsub_vv {
440    # vsub.vv vd, vs2, vs1, vm
441    my $template = 0b000010_0_00000_00000_000_00000_1010111;
442    my $vd = read_vreg shift;
443    my $vs2 = read_vreg shift;
444    my $vs1 = read_vreg shift;
445    my $vm = read_mask_vreg shift;
446    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
447}
448
449sub vsub_vx {
450    # vsub.vx vd, vs2, rs1, vm
451    my $template = 0b000010_0_00000_00000_100_00000_1010111;
452    my $vd = read_vreg shift;
453    my $vs2 = read_vreg shift;
454    my $rs1 = read_reg shift;
455    my $vm = read_mask_vreg shift;
456    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
457}
458
459sub vid_v {
460    # vid.v vd
461    my $template = 0b0101001_00000_10001_010_00000_1010111;
462    my $vd = read_vreg shift;
463    return ".word ".($template | ($vd << 7));
464}
465
466sub viota_m {
467    # viota.m vd, vs2, vm
468    my $template = 0b010100_0_00000_10000_010_00000_1010111;
469    my $vd = read_vreg shift;
470    my $vs2 = read_vreg shift;
471    my $vm = read_mask_vreg shift;
472    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vd << 7));
473}
474
475sub vle8_v {
476    # vle8.v vd, (rs1), vm
477    my $template = 0b000000_0_00000_00000_000_00000_0000111;
478    my $vd = read_vreg shift;
479    my $rs1 = read_reg shift;
480    my $vm = read_mask_vreg shift;
481    return ".word ".($template | ($vm << 25) | ($rs1 << 15) | ($vd << 7));
482}
483
484sub vle32_v {
485    # vle32.v vd, (rs1), vm
486    my $template = 0b000000_0_00000_00000_110_00000_0000111;
487    my $vd = read_vreg shift;
488    my $rs1 = read_reg shift;
489    my $vm = read_mask_vreg shift;
490    return ".word ".($template | ($vm << 25) | ($rs1 << 15) | ($vd << 7));
491}
492
493sub vle64_v {
494    # vle64.v vd, (rs1)
495    my $template = 0b0000001_00000_00000_111_00000_0000111;
496    my $vd = read_vreg shift;
497    my $rs1 = read_reg shift;
498    return ".word ".($template | ($rs1 << 15) | ($vd << 7));
499}
500
501sub vlse32_v {
502    # vlse32.v vd, (rs1), rs2
503    my $template = 0b0000101_00000_00000_110_00000_0000111;
504    my $vd = read_vreg shift;
505    my $rs1 = read_reg shift;
506    my $rs2 = read_reg shift;
507    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($vd << 7));
508}
509
510sub vlsseg_nf_e32_v {
511    # vlsseg<nf>e32.v vd, (rs1), rs2
512    my $template = 0b0000101_00000_00000_110_00000_0000111;
513    my $nf = shift;
514    $nf -= 1;
515    my $vd = read_vreg shift;
516    my $rs1 = read_reg shift;
517    my $rs2 = read_reg shift;
518    return ".word ".($template | ($nf << 29) | ($rs2 << 20) | ($rs1 << 15) | ($vd << 7));
519}
520
521sub vlse64_v {
522    # vlse64.v vd, (rs1), rs2
523    my $template = 0b0000101_00000_00000_111_00000_0000111;
524    my $vd = read_vreg shift;
525    my $rs1 = read_reg shift;
526    my $rs2 = read_reg shift;
527    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($vd << 7));
528}
529
530sub vluxei8_v {
531    # vluxei8.v vd, (rs1), vs2, vm
532    my $template = 0b000001_0_00000_00000_000_00000_0000111;
533    my $vd = read_vreg shift;
534    my $rs1 = read_reg shift;
535    my $vs2 = read_vreg shift;
536    my $vm = read_mask_vreg shift;
537    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
538}
539
540sub vmerge_vim {
541    # vmerge.vim vd, vs2, imm, v0
542    my $template = 0b0101110_00000_00000_011_00000_1010111;
543    my $vd = read_vreg shift;
544    my $vs2 = read_vreg shift;
545    my $imm = shift;
546    return ".word ".($template | ($vs2 << 20) | ($imm << 15) | ($vd << 7));
547}
548
549sub vmerge_vvm {
550    # vmerge.vvm vd vs2 vs1
551    my $template = 0b0101110_00000_00000_000_00000_1010111;
552    my $vd = read_vreg shift;
553    my $vs2 = read_vreg shift;
554    my $vs1 = read_vreg shift;
555    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7))
556}
557
558sub vmseq_vi {
559    # vmseq.vi vd vs1, imm
560    my $template = 0b0110001_00000_00000_011_00000_1010111;
561    my $vd = read_vreg shift;
562    my $vs1 = read_vreg shift;
563    my $imm = shift;
564    return ".word ".($template | ($vs1 << 20) | ($imm << 15) | ($vd << 7))
565}
566
567sub vmsgtu_vx {
568    # vmsgtu.vx vd vs2, rs1, vm
569    my $template = 0b011110_0_00000_00000_100_00000_1010111;
570    my $vd = read_vreg shift;
571    my $vs2 = read_vreg shift;
572    my $rs1 = read_reg shift;
573    my $vm = read_mask_vreg shift;
574    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7))
575}
576
577sub vmv_v_i {
578    # vmv.v.i vd, imm
579    my $template = 0b0101111_00000_00000_011_00000_1010111;
580    my $vd = read_vreg shift;
581    my $imm = shift;
582    return ".word ".($template | ($imm << 15) | ($vd << 7));
583}
584
585sub vmv_v_x {
586    # vmv.v.x vd, rs1
587    my $template = 0b0101111_00000_00000_100_00000_1010111;
588    my $vd = read_vreg shift;
589    my $rs1 = read_reg shift;
590    return ".word ".($template | ($rs1 << 15) | ($vd << 7));
591}
592
593sub vmv_v_v {
594    # vmv.v.v vd, vs1
595    my $template = 0b0101111_00000_00000_000_00000_1010111;
596    my $vd = read_vreg shift;
597    my $vs1 = read_vreg shift;
598    return ".word ".($template | ($vs1 << 15) | ($vd << 7));
599}
600
601sub vor_vv {
602    # vor.vv vd, vs2, vs1
603    my $template = 0b0010101_00000_00000_000_00000_1010111;
604    my $vd = read_vreg shift;
605    my $vs2 = read_vreg shift;
606    my $vs1 = read_vreg shift;
607    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
608}
609
610sub vor_vv_v0t {
611    # vor.vv vd, vs2, vs1, v0.t
612    my $template = 0b0010100_00000_00000_000_00000_1010111;
613    my $vd = read_vreg shift;
614    my $vs2 = read_vreg shift;
615    my $vs1 = read_vreg shift;
616    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
617}
618
619sub vse8_v {
620    # vse8.v vd, (rs1), vm
621    my $template = 0b000000_0_00000_00000_000_00000_0100111;
622    my $vd = read_vreg shift;
623    my $rs1 = read_reg shift;
624    my $vm = read_mask_vreg shift;
625    return ".word ".($template | ($vm << 25) | ($rs1 << 15) | ($vd << 7));
626}
627
628sub vse32_v {
629    # vse32.v vd, (rs1), vm
630    my $template = 0b000000_0_00000_00000_110_00000_0100111;
631    my $vd = read_vreg shift;
632    my $rs1 = read_reg shift;
633    my $vm = read_mask_vreg shift;
634    return ".word ".($template | ($vm << 25) | ($rs1 << 15) | ($vd << 7));
635}
636
637sub vssseg_nf_e32_v {
638    # vssseg<nf>e32.v vs3, (rs1), rs2
639    my $template = 0b0000101_00000_00000_110_00000_0100111;
640    my $nf = shift;
641    $nf -= 1;
642    my $vs3 = read_vreg shift;
643    my $rs1 = read_reg shift;
644    my $rs2 = read_reg shift;
645    return ".word ".($template | ($nf << 29) | ($rs2 << 20) | ($rs1 << 15) | ($vs3 << 7));
646}
647
648sub vsuxei8_v {
649   # vsuxei8.v vs3, (rs1), vs2, vm
650   my $template = 0b000001_0_00000_00000_000_00000_0100111;
651   my $vs3 = read_vreg shift;
652   my $rs1 = read_reg shift;
653   my $vs2 = read_vreg shift;
654   my $vm = read_mask_vreg shift;
655   return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($rs1 << 15) | ($vs3 << 7));
656}
657
658sub vse64_v {
659    # vse64.v vd, (rs1)
660    my $template = 0b0000001_00000_00000_111_00000_0100111;
661    my $vd = read_vreg shift;
662    my $rs1 = read_reg shift;
663    return ".word ".($template | ($rs1 << 15) | ($vd << 7));
664}
665
666sub vsetivli__x0_2_e64_m1_tu_mu {
667    # vsetivli x0, 2, e64, m1, tu, mu
668    return ".word 0xc1817057";
669}
670
671sub vsetivli__x0_4_e32_m1_tu_mu {
672    # vsetivli x0, 4, e32, m1, tu, mu
673    return ".word 0xc1027057";
674}
675
676sub vsetivli__x0_4_e64_m1_tu_mu {
677    # vsetivli x0, 4, e64, m1, tu, mu
678    return ".word 0xc1827057";
679}
680
681sub vsetivli__x0_8_e32_m1_tu_mu {
682    # vsetivli x0, 8, e32, m1, tu, mu
683    return ".word 0xc1047057";
684}
685
686sub vsetvli {
687    # vsetvli rd, rs1, vtypei
688    my $template = 0b0_00000000000_00000_111_00000_1010111;
689    my $rd = read_reg shift;
690    my $rs1 = read_reg shift;
691    my $sew = read_sew shift;
692    my $lmul = read_lmul shift;
693    my $tail_policy = read_tail_policy shift;
694    my $mask_policy = read_mask_policy shift;
695    my $vtypei = ($mask_policy << 7) | ($tail_policy << 6) | ($sew << 3) | $lmul;
696
697    return ".word ".($template | ($vtypei << 20) | ($rs1 << 15) | ($rd << 7));
698}
699
700sub vsetivli {
701    # vsetvli rd, uimm, vtypei
702    my $template = 0b11_0000000000_00000_111_00000_1010111;
703    my $rd = read_reg shift;
704    my $uimm = shift;
705    my $sew = read_sew shift;
706    my $lmul = read_lmul shift;
707    my $tail_policy = read_tail_policy shift;
708    my $mask_policy = read_mask_policy shift;
709    my $vtypei = ($mask_policy << 7) | ($tail_policy << 6) | ($sew << 3) | $lmul;
710
711    return ".word ".($template | ($vtypei << 20) | ($uimm << 15) | ($rd << 7));
712}
713
714sub vslidedown_vi {
715    # vslidedown.vi vd, vs2, uimm
716    my $template = 0b0011111_00000_00000_011_00000_1010111;
717    my $vd = read_vreg shift;
718    my $vs2 = read_vreg shift;
719    my $uimm = shift;
720    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
721}
722
723sub vslidedown_vx {
724    # vslidedown.vx vd, vs2, rs1
725    my $template = 0b0011111_00000_00000_100_00000_1010111;
726    my $vd = read_vreg shift;
727    my $vs2 = read_vreg shift;
728    my $rs1 = read_reg shift;
729    return ".word ".($template | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
730}
731
732sub vslideup_vi_v0t {
733    # vslideup.vi vd, vs2, uimm, v0.t
734    my $template = 0b0011100_00000_00000_011_00000_1010111;
735    my $vd = read_vreg shift;
736    my $vs2 = read_vreg shift;
737    my $uimm = shift;
738    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
739}
740
741sub vslideup_vi {
742    # vslideup.vi vd, vs2, uimm
743    my $template = 0b0011101_00000_00000_011_00000_1010111;
744    my $vd = read_vreg shift;
745    my $vs2 = read_vreg shift;
746    my $uimm = shift;
747    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
748}
749
750sub vsll_vi {
751    # vsll.vi vd, vs2, uimm, vm
752    my $template = 0b1001011_00000_00000_011_00000_1010111;
753    my $vd = read_vreg shift;
754    my $vs2 = read_vreg shift;
755    my $uimm = shift;
756    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
757}
758
759sub vsrl_vi {
760    # vsrl.vi vd, vs2, uimm, vm
761    my $template = 0b1010001_00000_00000_011_00000_1010111;
762    my $vd = read_vreg shift;
763    my $vs2 = read_vreg shift;
764    my $uimm = shift;
765    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
766}
767
768sub vsrl_vx {
769    # vsrl.vx vd, vs2, rs1
770    my $template = 0b1010001_00000_00000_100_00000_1010111;
771    my $vd = read_vreg shift;
772    my $vs2 = read_vreg shift;
773    my $rs1 = read_reg shift;
774    return ".word ".($template | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
775}
776
777sub vsse32_v {
778    # vse32.v vs3, (rs1), rs2
779    my $template = 0b0000101_00000_00000_110_00000_0100111;
780    my $vs3 = read_vreg shift;
781    my $rs1 = read_reg shift;
782    my $rs2 = read_reg shift;
783    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($vs3 << 7));
784}
785
786sub vsse64_v {
787    # vsse64.v vs3, (rs1), rs2
788    my $template = 0b0000101_00000_00000_111_00000_0100111;
789    my $vs3 = read_vreg shift;
790    my $rs1 = read_reg shift;
791    my $rs2 = read_reg shift;
792    return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($vs3 << 7));
793}
794
795sub vxor_vv_v0t {
796    # vxor.vv vd, vs2, vs1, v0.t
797    my $template = 0b0010110_00000_00000_000_00000_1010111;
798    my $vd = read_vreg shift;
799    my $vs2 = read_vreg shift;
800    my $vs1 = read_vreg shift;
801    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
802}
803
804sub vxor_vv {
805    # vxor.vv vd, vs2, vs1
806    my $template = 0b0010111_00000_00000_000_00000_1010111;
807    my $vd = read_vreg shift;
808    my $vs2 = read_vreg shift;
809    my $vs1 = read_vreg shift;
810    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
811}
812
813sub vzext_vf2 {
814    # vzext.vf2 vd, vs2, vm
815    my $template = 0b010010_0_00000_00110_010_00000_1010111;
816    my $vd = read_vreg shift;
817    my $vs2 = read_vreg shift;
818    my $vm = read_mask_vreg shift;
819    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vd << 7));
820}
821
822# Vector crypto instructions
823
824## Zvbb and Zvkb instructions
825##
826## vandn (also in zvkb)
827## vbrev
828## vbrev8 (also in zvkb)
829## vrev8 (also in zvkb)
830## vclz
831## vctz
832## vcpop
833## vrol (also in zvkb)
834## vror (also in zvkb)
835## vwsll
836
837sub vbrev8_v {
838    # vbrev8.v vd, vs2, vm
839    my $template = 0b010010_0_00000_01000_010_00000_1010111;
840    my $vd = read_vreg shift;
841    my $vs2 = read_vreg shift;
842    my $vm = read_mask_vreg shift;
843    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vd << 7));
844}
845
846sub vrev8_v {
847    # vrev8.v vd, vs2, vm
848    my $template = 0b010010_0_00000_01001_010_00000_1010111;
849    my $vd = read_vreg shift;
850    my $vs2 = read_vreg shift;
851    my $vm = read_mask_vreg shift;
852    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vd << 7));
853}
854
855sub vror_vi {
856    # vror.vi vd, vs2, uimm
857    my $template = 0b01010_0_1_00000_00000_011_00000_1010111;
858    my $vd = read_vreg shift;
859    my $vs2 = read_vreg shift;
860    my $uimm = shift;
861    my $uimm_i5 = $uimm >> 5;
862    my $uimm_i4_0 = $uimm & 0b11111;
863
864    return ".word ".($template | ($uimm_i5 << 26) | ($vs2 << 20) | ($uimm_i4_0 << 15) | ($vd << 7));
865}
866
867sub vwsll_vv {
868    # vwsll.vv vd, vs2, vs1, vm
869    my $template = 0b110101_0_00000_00000_000_00000_1010111;
870    my $vd = read_vreg shift;
871    my $vs2 = read_vreg shift;
872    my $vs1 = read_vreg shift;
873    my $vm = read_mask_vreg shift;
874    return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
875}
876
877## Zvbc instructions
878
879sub vclmulh_vx {
880    # vclmulh.vx vd, vs2, rs1
881    my $template = 0b0011011_00000_00000_110_00000_1010111;
882    my $vd = read_vreg shift;
883    my $vs2 = read_vreg shift;
884    my $rs1 = read_reg shift;
885    return ".word ".($template | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
886}
887
888sub vclmul_vx_v0t {
889    # vclmul.vx vd, vs2, rs1, v0.t
890    my $template = 0b0011000_00000_00000_110_00000_1010111;
891    my $vd = read_vreg shift;
892    my $vs2 = read_vreg shift;
893    my $rs1 = read_reg shift;
894    return ".word ".($template | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
895}
896
897sub vclmul_vx {
898    # vclmul.vx vd, vs2, rs1
899    my $template = 0b0011001_00000_00000_110_00000_1010111;
900    my $vd = read_vreg shift;
901    my $vs2 = read_vreg shift;
902    my $rs1 = read_reg shift;
903    return ".word ".($template | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7));
904}
905
906## Zvkg instructions
907
908sub vghsh_vv {
909    # vghsh.vv vd, vs2, vs1
910    my $template = 0b1011001_00000_00000_010_00000_1110111;
911    my $vd = read_vreg shift;
912    my $vs2 = read_vreg shift;
913    my $vs1 = read_vreg shift;
914    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15) | ($vd << 7));
915}
916
917sub vgmul_vv {
918    # vgmul.vv vd, vs2
919    my $template = 0b1010001_00000_10001_010_00000_1110111;
920    my $vd = read_vreg shift;
921    my $vs2 = read_vreg shift;
922    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
923}
924
925## Zvkned instructions
926
927sub vaesdf_vs {
928    # vaesdf.vs vd, vs2
929    my $template = 0b101001_1_00000_00001_010_00000_1110111;
930    my $vd = read_vreg  shift;
931    my $vs2 = read_vreg  shift;
932    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
933}
934
935sub vaesdm_vs {
936    # vaesdm.vs vd, vs2
937    my $template = 0b101001_1_00000_00000_010_00000_1110111;
938    my $vd = read_vreg shift;
939    my $vs2 = read_vreg shift;
940    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
941}
942
943sub vaesef_vs {
944    # vaesef.vs vd, vs2
945    my $template = 0b101001_1_00000_00011_010_00000_1110111;
946    my $vd = read_vreg  shift;
947    my $vs2 = read_vreg  shift;
948    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
949}
950
951sub vaesem_vs {
952    # vaesem.vs vd, vs2
953    my $template = 0b101001_1_00000_00010_010_00000_1110111;
954    my $vd = read_vreg  shift;
955    my $vs2 = read_vreg  shift;
956    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
957}
958
959sub vaeskf1_vi {
960    # vaeskf1.vi vd, vs2, uimmm
961    my $template = 0b100010_1_00000_00000_010_00000_1110111;
962    my $vd = read_vreg  shift;
963    my $vs2 = read_vreg  shift;
964    my $uimm = shift;
965    return ".word ".($template | ($uimm << 15) | ($vs2 << 20) | ($vd << 7));
966}
967
968sub vaeskf2_vi {
969    # vaeskf2.vi vd, vs2, uimm
970    my $template = 0b101010_1_00000_00000_010_00000_1110111;
971    my $vd = read_vreg shift;
972    my $vs2 = read_vreg shift;
973    my $uimm = shift;
974    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
975}
976
977sub vaesz_vs {
978    # vaesz.vs vd, vs2
979    my $template = 0b101001_1_00000_00111_010_00000_1110111;
980    my $vd = read_vreg  shift;
981    my $vs2 = read_vreg  shift;
982    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
983}
984
985## Zvknha and Zvknhb instructions
986
987sub vsha2ms_vv {
988    # vsha2ms.vv vd, vs2, vs1
989    my $template = 0b1011011_00000_00000_010_00000_1110111;
990    my $vd = read_vreg shift;
991    my $vs2 = read_vreg shift;
992    my $vs1 = read_vreg shift;
993    return ".word ".($template | ($vs2 << 20)| ($vs1 << 15 )| ($vd << 7));
994}
995
996sub vsha2ch_vv {
997    # vsha2ch.vv vd, vs2, vs1
998    my $template = 0b101110_10000_00000_001_00000_01110111;
999    my $vd = read_vreg shift;
1000    my $vs2 = read_vreg shift;
1001    my $vs1 = read_vreg shift;
1002    return ".word ".($template | ($vs2 << 20)| ($vs1 << 15 )| ($vd << 7));
1003}
1004
1005sub vsha2cl_vv {
1006    # vsha2cl.vv vd, vs2, vs1
1007    my $template = 0b101111_10000_00000_001_00000_01110111;
1008    my $vd = read_vreg shift;
1009    my $vs2 = read_vreg shift;
1010    my $vs1 = read_vreg shift;
1011    return ".word ".($template | ($vs2 << 20)| ($vs1 << 15 )| ($vd << 7));
1012}
1013
1014## Zvksed instructions
1015
1016sub vsm4k_vi {
1017    # vsm4k.vi vd, vs2, uimm
1018    my $template = 0b1000011_00000_00000_010_00000_1110111;
1019    my $vd = read_vreg shift;
1020    my $vs2 = read_vreg shift;
1021    my $uimm = shift;
1022    return ".word ".($template | ($vs2 << 20) | ($uimm << 15) | ($vd << 7));
1023}
1024
1025sub vsm4r_vs {
1026    # vsm4r.vs vd, vs2
1027    my $template = 0b1010011_00000_10000_010_00000_1110111;
1028    my $vd = read_vreg shift;
1029    my $vs2 = read_vreg shift;
1030    return ".word ".($template | ($vs2 << 20) | ($vd << 7));
1031}
1032
1033## zvksh instructions
1034
1035sub vsm3c_vi {
1036    # vsm3c.vi vd, vs2, uimm
1037    my $template = 0b1010111_00000_00000_010_00000_1110111;
1038    my $vd = read_vreg shift;
1039    my $vs2 = read_vreg shift;
1040    my $uimm = shift;
1041    return ".word ".($template | ($vs2 << 20) | ($uimm << 15 ) | ($vd << 7));
1042}
1043
1044sub vsm3me_vv {
1045    # vsm3me.vv vd, vs2, vs1
1046    my $template = 0b1000001_00000_00000_010_00000_1110111;
1047    my $vd = read_vreg shift;
1048    my $vs2 = read_vreg shift;
1049    my $vs1 = read_vreg shift;
1050    return ".word ".($template | ($vs2 << 20) | ($vs1 << 15 ) | ($vd << 7));
1051}
1052
10531;
1054