riscv.pm 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 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. # All rights reserved.
  15. #
  16. # Redistribution and use in source and binary forms, with or without
  17. # modification, are permitted provided that the following conditions
  18. # are met:
  19. # 1. Redistributions of source code must retain the above copyright
  20. # notice, this list of conditions and the following disclaimer.
  21. # 2. Redistributions in binary form must reproduce the above copyright
  22. # notice, this list of conditions and the following disclaimer in the
  23. # documentation and/or other materials provided with the distribution.
  24. #
  25. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  30. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  31. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  33. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  34. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. use strict;
  37. use warnings;
  38. # Set $have_stacktrace to 1 if we have Devel::StackTrace
  39. my $have_stacktrace = 0;
  40. if (eval {require Devel::StackTrace;1;}) {
  41. $have_stacktrace = 1;
  42. }
  43. my @regs = map("x$_",(0..31));
  44. # Mapping from the RISC-V psABI ABI mnemonic names to the register number.
  45. my @regaliases = ('zero','ra','sp','gp','tp','t0','t1','t2','s0','s1',
  46. map("a$_",(0..7)),
  47. map("s$_",(2..11)),
  48. map("t$_",(3..6))
  49. );
  50. my %reglookup;
  51. @reglookup{@regs} = @regs;
  52. @reglookup{@regaliases} = @regs;
  53. # Takes a register name, possibly an alias, and converts it to a register index
  54. # from 0 to 31
  55. sub read_reg {
  56. my $reg = lc shift;
  57. if (!exists($reglookup{$reg})) {
  58. my $trace = "";
  59. if ($have_stacktrace) {
  60. $trace = Devel::StackTrace->new->as_string;
  61. }
  62. die("Unknown register ".$reg."\n".$trace);
  63. }
  64. my $regstr = $reglookup{$reg};
  65. if (!($regstr =~ /^x([0-9]+)$/)) {
  66. my $trace = "";
  67. if ($have_stacktrace) {
  68. $trace = Devel::StackTrace->new->as_string;
  69. }
  70. die("Could not process register ".$reg."\n".$trace);
  71. }
  72. return $1;
  73. }
  74. # Helper functions
  75. sub brev8_rv64i {
  76. # brev8 without `brev8` instruction (only in Zbkb)
  77. # Bit-reverses the first argument and needs two scratch registers
  78. my $val = shift;
  79. my $t0 = shift;
  80. my $t1 = shift;
  81. my $brev8_const = shift;
  82. my $seq = <<___;
  83. la $brev8_const, Lbrev8_const
  84. ld $t0, 0($brev8_const) # 0xAAAAAAAAAAAAAAAA
  85. slli $t1, $val, 1
  86. and $t1, $t1, $t0
  87. and $val, $val, $t0
  88. srli $val, $val, 1
  89. or $val, $t1, $val
  90. ld $t0, 8($brev8_const) # 0xCCCCCCCCCCCCCCCC
  91. slli $t1, $val, 2
  92. and $t1, $t1, $t0
  93. and $val, $val, $t0
  94. srli $val, $val, 2
  95. or $val, $t1, $val
  96. ld $t0, 16($brev8_const) # 0xF0F0F0F0F0F0F0F0
  97. slli $t1, $val, 4
  98. and $t1, $t1, $t0
  99. and $val, $val, $t0
  100. srli $val, $val, 4
  101. or $val, $t1, $val
  102. ___
  103. return $seq;
  104. }
  105. sub sd_rev8_rv64i {
  106. # rev8 without `rev8` instruction (only in Zbb or Zbkb)
  107. # Stores the given value byte-reversed and needs one scratch register
  108. my $val = shift;
  109. my $addr = shift;
  110. my $off = shift;
  111. my $tmp = shift;
  112. my $off0 = ($off + 0);
  113. my $off1 = ($off + 1);
  114. my $off2 = ($off + 2);
  115. my $off3 = ($off + 3);
  116. my $off4 = ($off + 4);
  117. my $off5 = ($off + 5);
  118. my $off6 = ($off + 6);
  119. my $off7 = ($off + 7);
  120. my $seq = <<___;
  121. sb $val, $off7($addr)
  122. srli $tmp, $val, 8
  123. sb $tmp, $off6($addr)
  124. srli $tmp, $val, 16
  125. sb $tmp, $off5($addr)
  126. srli $tmp, $val, 24
  127. sb $tmp, $off4($addr)
  128. srli $tmp, $val, 32
  129. sb $tmp, $off3($addr)
  130. srli $tmp, $val, 40
  131. sb $tmp, $off2($addr)
  132. srli $tmp, $val, 48
  133. sb $tmp, $off1($addr)
  134. srli $tmp, $val, 56
  135. sb $tmp, $off0($addr)
  136. ___
  137. return $seq;
  138. }
  139. # Scalar crypto instructions
  140. sub aes64ds {
  141. # Encoding for aes64ds rd, rs1, rs2 instruction on RV64
  142. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  143. my $template = 0b0011101_00000_00000_000_00000_0110011;
  144. my $rd = read_reg shift;
  145. my $rs1 = read_reg shift;
  146. my $rs2 = read_reg shift;
  147. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  148. }
  149. sub aes64dsm {
  150. # Encoding for aes64dsm rd, rs1, rs2 instruction on RV64
  151. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  152. my $template = 0b0011111_00000_00000_000_00000_0110011;
  153. my $rd = read_reg shift;
  154. my $rs1 = read_reg shift;
  155. my $rs2 = read_reg shift;
  156. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  157. }
  158. sub aes64es {
  159. # Encoding for aes64es rd, rs1, rs2 instruction on RV64
  160. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  161. my $template = 0b0011001_00000_00000_000_00000_0110011;
  162. my $rd = read_reg shift;
  163. my $rs1 = read_reg shift;
  164. my $rs2 = read_reg shift;
  165. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  166. }
  167. sub aes64esm {
  168. # Encoding for aes64esm rd, rs1, rs2 instruction on RV64
  169. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  170. my $template = 0b0011011_00000_00000_000_00000_0110011;
  171. my $rd = read_reg shift;
  172. my $rs1 = read_reg shift;
  173. my $rs2 = read_reg shift;
  174. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  175. }
  176. sub aes64im {
  177. # Encoding for aes64im rd, rs1 instruction on RV64
  178. # XXXXXXXXXXXX_ rs1 _XXX_ rd _XXXXXXX
  179. my $template = 0b001100000000_00000_001_00000_0010011;
  180. my $rd = read_reg shift;
  181. my $rs1 = read_reg shift;
  182. return ".word ".($template | ($rs1 << 15) | ($rd << 7));
  183. }
  184. sub aes64ks1i {
  185. # Encoding for aes64ks1i rd, rs1, rnum instruction on RV64
  186. # XXXXXXXX_rnum_ rs1 _XXX_ rd _XXXXXXX
  187. my $template = 0b00110001_0000_00000_001_00000_0010011;
  188. my $rd = read_reg shift;
  189. my $rs1 = read_reg shift;
  190. my $rnum = shift;
  191. return ".word ".($template | ($rnum << 20) | ($rs1 << 15) | ($rd << 7));
  192. }
  193. sub aes64ks2 {
  194. # Encoding for aes64ks2 rd, rs1, rs2 instruction on RV64
  195. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  196. my $template = 0b0111111_00000_00000_000_00000_0110011;
  197. my $rd = read_reg shift;
  198. my $rs1 = read_reg shift;
  199. my $rs2 = read_reg shift;
  200. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  201. }
  202. sub brev8 {
  203. # brev8 rd, rs
  204. my $template = 0b011010000111_00000_101_00000_0010011;
  205. my $rd = read_reg shift;
  206. my $rs = read_reg shift;
  207. return ".word ".($template | ($rs << 15) | ($rd << 7));
  208. }
  209. sub clmul {
  210. # Encoding for clmul rd, rs1, rs2 instruction on RV64
  211. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  212. my $template = 0b0000101_00000_00000_001_00000_0110011;
  213. my $rd = read_reg shift;
  214. my $rs1 = read_reg shift;
  215. my $rs2 = read_reg shift;
  216. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  217. }
  218. sub clmulh {
  219. # Encoding for clmulh rd, rs1, rs2 instruction on RV64
  220. # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX
  221. my $template = 0b0000101_00000_00000_011_00000_0110011;
  222. my $rd = read_reg shift;
  223. my $rs1 = read_reg shift;
  224. my $rs2 = read_reg shift;
  225. return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7));
  226. }
  227. sub rev8 {
  228. # Encoding for rev8 rd, rs instruction on RV64
  229. # XXXXXXXXXXXXX_ rs _XXX_ rd _XXXXXXX
  230. my $template = 0b011010111000_00000_101_00000_0010011;
  231. my $rd = read_reg shift;
  232. my $rs = read_reg shift;
  233. return ".word ".($template | ($rs << 15) | ($rd << 7));
  234. }
  235. 1;