2
0
Эх сурвалжийг харах

Merged riscv_new branch

git-svn-id: trunk@39813 -
florian 6 жил өмнө
parent
commit
a34d4e715c
100 өөрчлөгдсөн 13334 нэмэгдсэн , 219 устгасан
  1. 125 1
      .gitattributes
  2. 49 3
      Makefile
  3. 6 0
      Makefile.fpc
  4. 120 6
      compiler/Makefile
  5. 25 3
      compiler/Makefile.fpc
  6. 8 0
      compiler/aasmtai.pas
  7. 1 1
      compiler/aggas.pas
  8. 12 7
      compiler/aoptobj.pas
  9. 8 0
      compiler/cgbase.pas
  10. 10 0
      compiler/cgobj.pas
  11. 4 1
      compiler/cgutils.pas
  12. 6 4
      compiler/dbgdwarf.pas
  13. 6 2
      compiler/entfile.pas
  14. 24 0
      compiler/fpcdefs.inc
  15. 14 2
      compiler/globals.pas
  16. 1 1
      compiler/globtype.pas
  17. 1 0
      compiler/msg/errore.msg
  18. 1 1
      compiler/msgidx.inc
  19. 167 166
      compiler/msgtxt.inc
  20. 1 1
      compiler/nadd.pas
  21. 2 1
      compiler/ncal.pas
  22. 4 0
      compiler/ncgcal.pas
  23. 19 8
      compiler/ninl.pas
  24. 29 4
      compiler/nutils.pas
  25. 5 2
      compiler/optcse.pas
  26. 59 3
      compiler/options.pas
  27. 13 0
      compiler/pp.pas
  28. 86 0
      compiler/ppcriscv32.lpi
  29. 78 0
      compiler/ppcriscv64.lpi
  30. 1 1
      compiler/psub.pas
  31. 8 0
      compiler/psystem.pas
  32. 16 0
      compiler/raatt.pas
  33. 8 1
      compiler/rautils.pas
  34. 624 0
      compiler/riscv/aasmcpu.pas
  35. 253 0
      compiler/riscv/agrvgas.pas
  36. 758 0
      compiler/riscv/cgrv.pas
  37. 260 0
      compiler/riscv/hlcgrv.pas
  38. 417 0
      compiler/riscv/nrvadd.pas
  39. 178 0
      compiler/riscv/nrvcnv.pas
  40. 131 0
      compiler/riscv/nrvcon.pas
  41. 341 0
      compiler/riscv/nrvinl.pas
  42. 154 0
      compiler/riscv/nrvset.pas
  43. 126 0
      compiler/riscv/rgcpu.pas
  44. 77 0
      compiler/riscv32/aoptcpu.pas
  45. 115 0
      compiler/riscv32/aoptcpub.pas
  46. 40 0
      compiler/riscv32/aoptcpuc.pas
  47. 40 0
      compiler/riscv32/aoptcpud.pas
  48. 641 0
      compiler/riscv32/cgcpu.pas
  49. 428 0
      compiler/riscv32/cpubase.pas
  50. 135 0
      compiler/riscv32/cpuinfo.pas
  51. 50 0
      compiler/riscv32/cpunode.pas
  52. 550 0
      compiler/riscv32/cpupara.pas
  53. 123 0
      compiler/riscv32/cpupi.pas
  54. 84 0
      compiler/riscv32/cputarg.pas
  55. 61 0
      compiler/riscv32/hlcgcpu.pas
  56. 141 0
      compiler/riscv32/itcpugas.pas
  57. 56 0
      compiler/riscv32/nrv32add.pas
  58. 51 0
      compiler/riscv32/nrv32cal.pas
  59. 151 0
      compiler/riscv32/nrv32cnv.pas
  60. 135 0
      compiler/riscv32/nrv32mat.pas
  61. 41 0
      compiler/riscv32/rarv32.pas
  62. 771 0
      compiler/riscv32/rarv32gas.pas
  63. 67 0
      compiler/riscv32/rrv32con.inc
  64. 67 0
      compiler/riscv32/rrv32dwa.inc
  65. 2 0
      compiler/riscv32/rrv32nor.inc
  66. 67 0
      compiler/riscv32/rrv32num.inc
  67. 67 0
      compiler/riscv32/rrv32rni.inc
  68. 67 0
      compiler/riscv32/rrv32sri.inc
  69. 67 0
      compiler/riscv32/rrv32sta.inc
  70. 67 0
      compiler/riscv32/rrv32std.inc
  71. 67 0
      compiler/riscv32/rrv32sup.inc
  72. 77 0
      compiler/riscv32/rv32reg.dat
  73. 216 0
      compiler/riscv32/symcpu.pas
  74. 387 0
      compiler/riscv64/aoptcpu.pas
  75. 116 0
      compiler/riscv64/aoptcpub.pas
  76. 40 0
      compiler/riscv64/aoptcpuc.pas
  77. 40 0
      compiler/riscv64/aoptcpud.pas
  78. 642 0
      compiler/riscv64/cgcpu.pas
  79. 462 0
      compiler/riscv64/cpubase.pas
  80. 139 0
      compiler/riscv64/cpuinfo.pas
  81. 55 0
      compiler/riscv64/cpunode.pas
  82. 545 0
      compiler/riscv64/cpupara.pas
  83. 116 0
      compiler/riscv64/cpupi.pas
  84. 85 0
      compiler/riscv64/cputarg.pas
  85. 78 0
      compiler/riscv64/hlcgcpu.pas
  86. 157 0
      compiler/riscv64/itcpugas.pas
  87. 98 0
      compiler/riscv64/nrv64add.pas
  88. 56 0
      compiler/riscv64/nrv64cal.pas
  89. 124 0
      compiler/riscv64/nrv64cnv.pas
  90. 57 0
      compiler/riscv64/nrv64ld.pas
  91. 163 0
      compiler/riscv64/nrv64mat.pas
  92. 50 0
      compiler/riscv64/rarv.pas
  93. 840 0
      compiler/riscv64/rarv64gas.pas
  94. 67 0
      compiler/riscv64/rrv32con.inc
  95. 67 0
      compiler/riscv64/rrv32dwa.inc
  96. 2 0
      compiler/riscv64/rrv32nor.inc
  97. 67 0
      compiler/riscv64/rrv32num.inc
  98. 67 0
      compiler/riscv64/rrv32rni.inc
  99. 67 0
      compiler/riscv64/rrv32sri.inc
  100. 67 0
      compiler/riscv64/rrv32sta.inc

+ 125 - 1
.gitattributes

@@ -185,7 +185,7 @@ compiler/fppu.pas svneol=native#text/plain
 compiler/gendef.pas svneol=native#text/plain
 compiler/generic/cpuinfo.pas svneol=native#text/plain
 compiler/generic/symcpu.pas svneol=native#text/plain
-compiler/globals.pas -text svneol=native#text/plain
+compiler/globals.pas svneol=native#text/plain
 compiler/globstat.pas svneol=native#text/pascal
 compiler/globtype.pas svneol=native#text/plain
 compiler/hlcg2ll.pas svneol=native#text/plain
@@ -641,6 +641,8 @@ compiler/ppcmips.lpi svneol=native#text/plain
 compiler/ppcmipsel.lpi svneol=native#text/plain
 compiler/ppcppc.lpi svneol=native#text/plain
 compiler/ppcppc64.lpi svneol=native#text/plain
+compiler/ppcriscv32.lpi svneol=native#text/plain
+compiler/ppcriscv64.lpi svneol=native#text/plain
 compiler/ppcsparc.lpi svneol=native#text/plain
 compiler/ppcsparc64.lpi svneol=native#text/plain
 compiler/ppcx64.lpi svneol=native#text/plain
@@ -660,6 +662,77 @@ compiler/rautils.pas svneol=native#text/plain
 compiler/rescmn.pas svneol=native#text/plain
 compiler/rgbase.pas svneol=native#text/plain
 compiler/rgobj.pas svneol=native#text/plain
+compiler/riscv/aasmcpu.pas svneol=native#text/plain
+compiler/riscv/agrvgas.pas svneol=native#text/plain
+compiler/riscv/cgrv.pas svneol=native#text/plain
+compiler/riscv/hlcgrv.pas svneol=native#text/plain
+compiler/riscv/nrvadd.pas svneol=native#text/plain
+compiler/riscv/nrvcnv.pas svneol=native#text/plain
+compiler/riscv/nrvcon.pas svneol=native#text/plain
+compiler/riscv/nrvinl.pas svneol=native#text/plain
+compiler/riscv/nrvset.pas svneol=native#text/plain
+compiler/riscv/rgcpu.pas svneol=native#text/plain
+compiler/riscv32/aoptcpu.pas svneol=native#text/plain
+compiler/riscv32/aoptcpub.pas svneol=native#text/plain
+compiler/riscv32/aoptcpuc.pas svneol=native#text/plain
+compiler/riscv32/aoptcpud.pas svneol=native#text/plain
+compiler/riscv32/cgcpu.pas svneol=native#text/plain
+compiler/riscv32/cpubase.pas svneol=native#text/plain
+compiler/riscv32/cpuinfo.pas svneol=native#text/plain
+compiler/riscv32/cpunode.pas svneol=native#text/plain
+compiler/riscv32/cpupara.pas svneol=native#text/plain
+compiler/riscv32/cpupi.pas svneol=native#text/plain
+compiler/riscv32/cputarg.pas svneol=native#text/plain
+compiler/riscv32/hlcgcpu.pas svneol=native#text/plain
+compiler/riscv32/itcpugas.pas svneol=native#text/plain
+compiler/riscv32/nrv32add.pas svneol=native#text/plain
+compiler/riscv32/nrv32cal.pas svneol=native#text/plain
+compiler/riscv32/nrv32cnv.pas svneol=native#text/plain
+compiler/riscv32/nrv32mat.pas svneol=native#text/plain
+compiler/riscv32/rarv32.pas svneol=native#text/plain
+compiler/riscv32/rarv32gas.pas svneol=native#text/plain
+compiler/riscv32/rrv32con.inc svneol=native#text/plain
+compiler/riscv32/rrv32dwa.inc svneol=native#text/plain
+compiler/riscv32/rrv32nor.inc svneol=native#text/plain
+compiler/riscv32/rrv32num.inc svneol=native#text/plain
+compiler/riscv32/rrv32rni.inc svneol=native#text/plain
+compiler/riscv32/rrv32sri.inc svneol=native#text/plain
+compiler/riscv32/rrv32sta.inc svneol=native#text/plain
+compiler/riscv32/rrv32std.inc svneol=native#text/plain
+compiler/riscv32/rrv32sup.inc svneol=native#text/plain
+compiler/riscv32/rv32reg.dat svneol=native#text/plain
+compiler/riscv32/symcpu.pas svneol=native#text/plain
+compiler/riscv64/aoptcpu.pas svneol=native#text/plain
+compiler/riscv64/aoptcpub.pas svneol=native#text/plain
+compiler/riscv64/aoptcpuc.pas svneol=native#text/plain
+compiler/riscv64/aoptcpud.pas svneol=native#text/plain
+compiler/riscv64/cgcpu.pas svneol=native#text/plain
+compiler/riscv64/cpubase.pas svneol=native#text/plain
+compiler/riscv64/cpuinfo.pas svneol=native#text/plain
+compiler/riscv64/cpunode.pas svneol=native#text/plain
+compiler/riscv64/cpupara.pas svneol=native#text/plain
+compiler/riscv64/cpupi.pas svneol=native#text/plain
+compiler/riscv64/cputarg.pas svneol=native#text/plain
+compiler/riscv64/hlcgcpu.pas svneol=native#text/plain
+compiler/riscv64/itcpugas.pas svneol=native#text/plain
+compiler/riscv64/nrv64add.pas svneol=native#text/plain
+compiler/riscv64/nrv64cal.pas svneol=native#text/plain
+compiler/riscv64/nrv64cnv.pas svneol=native#text/plain
+compiler/riscv64/nrv64ld.pas svneol=native#text/plain
+compiler/riscv64/nrv64mat.pas svneol=native#text/plain
+compiler/riscv64/rarv.pas svneol=native#text/plain
+compiler/riscv64/rarv64gas.pas svneol=native#text/plain
+compiler/riscv64/rrv32con.inc svneol=native#text/plain
+compiler/riscv64/rrv32dwa.inc svneol=native#text/plain
+compiler/riscv64/rrv32nor.inc svneol=native#text/plain
+compiler/riscv64/rrv32num.inc svneol=native#text/plain
+compiler/riscv64/rrv32rni.inc svneol=native#text/plain
+compiler/riscv64/rrv32sri.inc svneol=native#text/plain
+compiler/riscv64/rrv32sta.inc svneol=native#text/plain
+compiler/riscv64/rrv32std.inc svneol=native#text/plain
+compiler/riscv64/rrv32sup.inc svneol=native#text/plain
+compiler/riscv64/rv32reg.dat svneol=native#text/plain
+compiler/riscv64/symcpu.pas svneol=native#text/plain
 compiler/scandir.pas svneol=native#text/plain
 compiler/scanner.pas svneol=native#text/plain
 compiler/sparc/aoptcpud.pas svneol=native#text/plain
@@ -9627,6 +9700,28 @@ rtl/linux/powerpc64/syscallh.inc svneol=native#text/plain
 rtl/linux/powerpc64/sysnr.inc svneol=native#text/plain
 rtl/linux/pthread.inc svneol=native#text/plain
 rtl/linux/ptypes.inc svneol=native#text/plain
+rtl/linux/riscv32/bsyscall.inc svneol=native#text/plain
+rtl/linux/riscv32/cprt0.as svneol=native#text/plain
+rtl/linux/riscv32/dllprt0.as svneol=native#text/plain
+rtl/linux/riscv32/gprt0.as svneol=native#text/plain
+rtl/linux/riscv32/prt0.as svneol=native#text/plain
+rtl/linux/riscv32/sighnd.inc svneol=native#text/plain
+rtl/linux/riscv32/sighndh.inc svneol=native#text/plain
+rtl/linux/riscv32/stat.inc svneol=native#text/plain
+rtl/linux/riscv32/syscall.inc svneol=native#text/plain
+rtl/linux/riscv32/syscallh.inc svneol=native#text/plain
+rtl/linux/riscv32/sysnr.inc svneol=native#text/plain
+rtl/linux/riscv64/bsyscall.inc svneol=native#text/plain
+rtl/linux/riscv64/cprt0.as svneol=native#text/plain
+rtl/linux/riscv64/dllprt0.as svneol=native#text/plain
+rtl/linux/riscv64/gprt0.as svneol=native#text/plain
+rtl/linux/riscv64/prt0.as svneol=native#text/plain
+rtl/linux/riscv64/sighnd.inc svneol=native#text/plain
+rtl/linux/riscv64/sighndh.inc svneol=native#text/plain
+rtl/linux/riscv64/stat.inc svneol=native#text/plain
+rtl/linux/riscv64/syscall.inc svneol=native#text/plain
+rtl/linux/riscv64/syscallh.inc svneol=native#text/plain
+rtl/linux/riscv64/sysnr.inc svneol=native#text/plain
 rtl/linux/rtldefs.inc svneol=native#text/plain
 rtl/linux/si_c.pp svneol=native#text/plain
 rtl/linux/si_c21.pp svneol=native#text/plain
@@ -10234,6 +10329,27 @@ rtl/qnx/qnx.inc svneol=native#text/plain
 rtl/qnx/rtldefs.inc svneol=native#text/plain
 rtl/qnx/signal.inc svneol=native#text/plain
 rtl/qnx/system.pp svneol=native#text/plain
+rtl/riscv32/cpuh.inc svneol=native#text/plain
+rtl/riscv32/int64p.inc svneol=native#text/plain
+rtl/riscv32/makefile.cpu svneol=native#text/plain
+rtl/riscv32/math.inc svneol=native#text/plain
+rtl/riscv32/riscv32.inc svneol=native#text/plain
+rtl/riscv32/set.inc svneol=native#text/plain
+rtl/riscv32/setjump.inc svneol=native#text/plain
+rtl/riscv32/setjumph.inc svneol=native#text/plain
+rtl/riscv32/strings.inc svneol=native#text/plain
+rtl/riscv32/stringss.inc svneol=native#text/plain
+rtl/riscv64/cpuh.inc svneol=native#text/plain
+rtl/riscv64/int64p.inc svneol=native#text/plain
+rtl/riscv64/makefile.cpu svneol=native#text/plain
+rtl/riscv64/math.inc svneol=native#text/plain
+rtl/riscv64/mathu.inc svneol=native#text/plain
+rtl/riscv64/riscv64.inc svneol=native#text/plain
+rtl/riscv64/set.inc svneol=native#text/plain
+rtl/riscv64/setjump.inc svneol=native#text/plain
+rtl/riscv64/setjumph.inc svneol=native#text/plain
+rtl/riscv64/strings.inc svneol=native#text/plain
+rtl/riscv64/stringss.inc svneol=native#text/plain
 rtl/solaris/Makefile svneol=native#text/plain
 rtl/solaris/Makefile.fpc svneol=native#text/plain
 rtl/solaris/errno.inc svneol=native#text/plain
@@ -11853,6 +11969,14 @@ tests/test/cg/obj/linux/powerpc64/tcext3.o -text
 tests/test/cg/obj/linux/powerpc64/tcext4.o -text
 tests/test/cg/obj/linux/powerpc64/tcext5.o -text
 tests/test/cg/obj/linux/powerpc64/tcext6.o -text
+tests/test/cg/obj/linux/riscv64/cpptcl1.o -text
+tests/test/cg/obj/linux/riscv64/cpptcl2.o -text
+tests/test/cg/obj/linux/riscv64/ctest.o -text
+tests/test/cg/obj/linux/riscv64/tcext3.o -text
+tests/test/cg/obj/linux/riscv64/tcext4.o -text
+tests/test/cg/obj/linux/riscv64/tcext5.o -text
+tests/test/cg/obj/linux/riscv64/tcext6.o -text
+tests/test/cg/obj/linux/riscv64/ttasm1.obj -text svneol=unset#application/octet-stream
 tests/test/cg/obj/linux/sparc/cpptcl1.o -text
 tests/test/cg/obj/linux/sparc/cpptcl2.o -text
 tests/test/cg/obj/linux/sparc/ctest.o -text

+ 49 - 3
Makefile

@@ -1,8 +1,8 @@
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2018/07/20]
 #
 default: help
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -332,7 +332,7 @@ FPCFPMAKE=$(FPC)
 endif
 endif
 override PACKAGE_NAME=fpc
-override PACKAGE_VERSION=3.3.1
+override PACKAGE_VERSION=3.1.1
 REQUIREDVERSION=3.0.4
 REQUIREDVERSION2=3.0.2
 ifndef inOS2
@@ -391,6 +391,12 @@ endif
 ifeq ($(CPU_TARGET),aarch64)
 PPSUF=a64
 endif
+ifeq ($(CPU_TARGET),riscv32)
+PPSUF=rv32
+endif
+ifeq ($(CPU_TARGET),riscv64)
+PPSUF=rv64
+endif
 ifdef CROSSCOMPILE
 ifneq ($(CPU_TARGET),jvm)
 PPPRE=ppcross
@@ -733,6 +739,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override TARGET_DIRS+=compiler rtl utils packages installer
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
 override INSTALL_FPCPACKAGE=y
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
@@ -2507,6 +2525,34 @@ TARGET_DIRS_UTILS=1
 TARGET_DIRS_PACKAGES=1
 TARGET_DIRS_INSTALLER=1
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
 ifdef TARGET_DIRS_COMPILER
 compiler_all:
 	$(MAKE) -C compiler all

+ 6 - 0
Makefile.fpc

@@ -85,6 +85,12 @@ endif
 ifeq ($(CPU_TARGET),aarch64)
 PPSUF=a64
 endif
+ifeq ($(CPU_TARGET),riscv32)
+PPSUF=rv32
+endif
+ifeq ($(CPU_TARGET),riscv64)
+PPSUF=rv64
+endif
 
 # cross compilers uses full cpu_target, not just ppc-suffix
 # (except if the target cannot run a native compiler)

+ 120 - 6
compiler/Makefile

@@ -1,8 +1,8 @@
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2018/07/20]
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -332,9 +332,9 @@ FPCFPMAKE=$(FPC)
 endif
 endif
 override PACKAGE_NAME=compiler
-override PACKAGE_VERSION=3.3.1
+override PACKAGE_VERSION=3.1.1
 unexport FPC_VERSION FPC_COMPILERINFO
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64
 ALLTARGETS=$(CYCLETARGETS)
 ifdef POWERPC
 PPC_TARGET=powerpc
@@ -381,6 +381,12 @@ endif
 ifdef AARCH64
 PPC_TARGET=aarch64
 endif
+ifdef RISCV32
+PPC_TARGET=riscv32
+endif
+ifdef RISCV64
+PPC_TARGET=riscv64
+endif
 ifndef PPC_TARGET
 PPC_TARGET=$(CPU_TARGET)
 endif
@@ -483,6 +489,12 @@ endif
 ifeq ($(CPC_TARGET),aarch64)
 CPUSUF=a64
 endif
+ifeq ($(CPC_TARGET),riscv32)
+CPUSUF=rv32
+endif
+ifeq ($(CPC_TARGET),riscv64)
+CPUSUF=rv64
+endif
 NOCPUDEF=1
 MSGFILE=msg/error$(FPCLANG).msg
 SVNVERSION:=$(firstword $(wildcard $(addsuffix /svnversion$(SRCEXEEXT),$(SEARCHPATH))))
@@ -544,6 +556,12 @@ endif
 ifeq ($(PPC_TARGET),i8086)
 override LOCALOPT+=-Fux86
 endif
+ifeq ($(PPC_TARGET),riscv32)
+override LOCALOPT+=-Furiscv
+endif
+ifeq ($(PPC_TARGET),riscv64)
+override LOCALOPT+=-Furiscv
+endif
 OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
 OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
 ifneq ($(findstring $(OS_TARGET),darwin linux dragonfly freebsd solaris),)
@@ -834,6 +852,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override TARGET_DIRS+=utils
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override TARGET_DIRS+=utils
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override TARGET_PROGRAMS+=pp
 endif
@@ -1089,6 +1119,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override TARGET_PROGRAMS+=pp
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override TARGET_PROGRAMS+=pp
+endif
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
@@ -1345,6 +1387,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
@@ -1600,6 +1654,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_TARGETDIR+=.
 endif
@@ -1855,6 +1921,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override COMPILER_TARGETDIR+=.
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_TARGETDIR+=.
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_TARGETDIR+=.
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_TARGETDIR+=.
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_TARGETDIR+=.
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
@@ -2110,6 +2188,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 endif
@@ -3030,6 +3120,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 REQUIRE_PACKAGES_RTL=1
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
 ifdef REQUIRE_PACKAGES_RTL
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 ifneq ($(PACKAGEDIR_RTL),)
@@ -3930,6 +4032,18 @@ endif
 ifeq ($(FULL_TARGET),sparc64-linux)
 TARGET_DIRS_UTILS=1
 endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+TARGET_DIRS_UTILS=1
+endif
 ifdef TARGET_DIRS_UTILS
 utils_all:
 	$(MAKE) -C utils all
@@ -4058,7 +4172,7 @@ INSTALLEXEFILE=$(PPCROSSNAME)
 else
 INSTALLEXEFILE=$(EXENAME)
 endif
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64
 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 .PHONY: $(PPC_TARGETS) $(INSTALL_TARGETS)$(SYMLINKINSTALL_TARGETS)
@@ -4293,7 +4407,7 @@ cvstest:
 ifeq ($(OS_SOURCE),win64)
   EXCLUDE_80BIT_TARGETS=1
 endif
-ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64),)
+ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64 riscv32 riscv64),)
   EXCLUDE_80BIT_TARGETS=1
 endif
 full: fullcycle

+ 25 - 3
compiler/Makefile.fpc

@@ -32,7 +32,7 @@ fpcdir=..
 unexport FPC_VERSION FPC_COMPILERINFO
 
 # Which platforms are ready for inclusion in the cycle
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64
 
 # All supported targets used for clean
 ALLTARGETS=$(CYCLETARGETS)
@@ -83,6 +83,12 @@ endif
 ifdef AARCH64
 PPC_TARGET=aarch64
 endif
+ifdef RISCV32
+PPC_TARGET=riscv32
+endif
+ifdef RISCV64
+PPC_TARGET=riscv64
+endif
 
 # Default is to generate a compiler for the same
 # platform as CPU_TARGET (a native compiler)
@@ -213,6 +219,12 @@ endif
 ifeq ($(CPC_TARGET),aarch64)
 CPUSUF=a64
 endif
+ifeq ($(CPC_TARGET),riscv32)
+CPUSUF=rv32
+endif
+ifeq ($(CPC_TARGET),riscv64)
+CPUSUF=rv64
+endif
 
 # Do not define the default -d$(CPU_TARGET) because that
 # will conflict with our -d$(CPC_TARGET)
@@ -315,6 +327,16 @@ ifeq ($(PPC_TARGET),i8086)
 override LOCALOPT+=-Fux86
 endif
 
+# RiscV32 specific
+ifeq ($(PPC_TARGET),riscv32)
+override LOCALOPT+=-Furiscv
+endif
+
+# RiscV64 specific
+ifeq ($(PPC_TARGET),riscv64)
+override LOCALOPT+=-Furiscv
+endif
+
 OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
 OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
 # symbol liveness WPO requires nm, smart linking and no stripping (the latter
@@ -432,7 +454,7 @@ endif
 # CPU targets
 #####################################################################
 
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64
 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 
@@ -802,7 +824,7 @@ ifeq ($(OS_SOURCE),win64)
   EXCLUDE_80BIT_TARGETS=1
 endif
 
-ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64),)
+ifneq ($(findstring $(CPU_SOURCE),aarch64 arm avr jvm m68k mips mipsel powerpc powerpc64 sparc sparc64 riscv32 riscv64),)
   EXCLUDE_80BIT_TARGETS=1
 endif
 

+ 8 - 0
compiler/aasmtai.pas

@@ -262,6 +262,10 @@ interface
        ,top_para
        ,top_asmlist
 {$endif llvm}
+{$if defined(riscv32) or defined(riscv64)}
+       ,top_fenceflags
+       ,top_roundingmode
+{$endif defined(riscv32) or defined(riscv64)}
        );
 
       { kinds of operations that an instruction can perform on an operand }
@@ -463,6 +467,10 @@ interface
             top_para   : (paras: tfplist);
             top_asmlist : (asmlist: tasmlist);
         {$endif llvm}
+        {$if defined(riscv32) or defined(riscv64)}
+            top_fenceflags : (fenceflags : TFenceFlags);
+            top_roundingmode : (roundingmode : TRoundingMode);
+        {$endif defined(riscv32) or defined(riscv64)}
         end;
         poper=^toper;
 

+ 1 - 1
compiler/aggas.pas

@@ -211,7 +211,7 @@ implementation
 { vtable for a class called Window:                                       }
 { .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat    }
 { TODO: .data.ro not yet working}
-{$if defined(arm) or defined(powerpc)}
+{$if defined(arm) or defined(riscv64) or defined(powerpc)}
           '.rodata',
 {$else arm}
           '.data',

+ 12 - 7
compiler/aoptobj.pas

@@ -383,8 +383,8 @@ Unit AoptObj;
 
     function JumpTargetOp(ai: taicpu): poper; inline;
       begin
-{$if defined(MIPS)}
-        { MIPS branches can have 1,2 or 3 operands, target label is the last one. }
+{$if defined(MIPS) or defined(riscv64) or defined(riscv32)}
+        { MIPS or RiscV branches can have 1,2 or 3 operands, target label is the last one. }
         result:=ai.oper[ai.ops-1];
 {$elseif defined(SPARC64)}
         if ai.ops=2 then
@@ -1342,7 +1342,12 @@ Unit AoptObj;
 {$if defined(arm) or defined(aarch64)}
           (hp.condition=c_None) and
 {$endif arm or aarch64}
+{$if defined(riscv32) or defined(riscv64)}          
           (hp.ops>0) and
+          (hp.oper[0]^.reg=NR_X0) and
+{$else riscv}
+          (hp.ops>0) and
+{$endif riscv}
           (JumpTargetOp(hp)^.typ = top_ref) and
           (JumpTargetOp(hp)^.ref^.symbol is TAsmLabel);
       end;
@@ -1390,7 +1395,7 @@ Unit AoptObj;
        to avoid endless loops with constructs such as "l5: ; jmp l5"           }
 
       var p1: tai;
-          {$if not defined(MIPS) and not defined(JVM)}
+          {$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
           p2: tai;
           l: tasmlabel;
           {$endif}
@@ -1408,7 +1413,7 @@ Unit AoptObj;
               if { the next instruction after the label where the jump hp arrives}
                  { is unconditional or of the same type as hp, so continue       }
                  IsJumpToLabelUncond(taicpu(p1))
-{$if not defined(MIPS) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
 { for MIPS, it isn't enough to check the condition; first operands must be same, too. }
                  or
                  conditions_equal(taicpu(p1).condition,hp.condition) or
@@ -1425,7 +1430,7 @@ Unit AoptObj;
                    (IsJumpToLabelUncond(taicpu(p2)) or
                    (conditions_equal(taicpu(p2).condition,hp.condition))) and
                   SkipLabels(p1,p1))
-{$endif not MIPS and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM}
                  then
                 begin
                   { quick check for loops of the form "l5: ; jmp l5 }
@@ -1446,7 +1451,7 @@ Unit AoptObj;
                   JumpTargetOp(hp)^.ref^.symbol:=JumpTargetOp(taicpu(p1))^.ref^.symbol;
                   tasmlabel(JumpTargetOp(hp)^.ref^.symbol).increfs;
                 end
-{$if not defined(MIPS) and not defined(JVM)}
+{$if not defined(MIPS) and not defined(riscv64) and not defined(riscv32) and not defined(JVM)}
               else
                 if conditions_equal(taicpu(p1).condition,inverse_cond(hp.condition)) then
                   if not FindAnyLabel(p1,l) then
@@ -1477,7 +1482,7 @@ Unit AoptObj;
                       if not GetFinalDestination(hp,succ(level)) then
                         exit;
                     end;
-{$endif not MIPS and not JVM}
+{$endif not MIPS and not RV64 and not RV32 and not JVM}
           end;
         GetFinalDestination := true;
       end;

+ 8 - 0
compiler/cgbase.pas

@@ -93,6 +93,14 @@ interface
          addr_low_call,    // counterpart of two above, generate call_hi16 and call_lo16 relocs
          addr_high_call
          {$ENDIF}
+         {$if defined(RISCV32) or defined(RISCV64)}
+         ,
+         addr_hi20,
+         addr_lo12,
+         addr_pcrel_hi20,
+         addr_pcrel_lo12,
+         addr_pcrel
+         {$endif RISCV}
          {$IFDEF AVR}
          ,addr_lo8
          ,addr_lo8_gs

+ 10 - 0
compiler/cgobj.pas

@@ -446,6 +446,10 @@ unit cgobj;
             generic version is suitable for 3-address CPUs }
           procedure g_div_const_reg_reg(list:tasmlist; size: TCgSize; a: tcgint; src,dst: tregister); virtual;
 
+          { some CPUs do not support hardware fpu exceptions, this procedure is called after instructions which
+            might set FPU exception related flags, so it has to check these flags if needed and throw an exeception }
+          procedure g_check_for_fpu_exception(list: TAsmList); virtual;
+
          protected
           function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;virtual;
        end;
@@ -2876,6 +2880,12 @@ implementation
       end;
 
 
+    procedure tcg.g_check_for_fpu_exception(list: TAsmList);
+      begin
+        { empty by default }
+      end;
+
+
 {*****************************************************************************
                                     TCG64
 *****************************************************************************}

+ 4 - 1
compiler/cgutils.pas

@@ -74,7 +74,10 @@ unit cgutils;
          base,
          index       : tregister;
          refaddr     : trefaddr;
-         scalefactor : byte;
+         scalefactor : byte;     
+{$if defined(riscv32) or defined(riscv64)}
+         symboldata  : tlinkedlistitem;
+{$endif riscv32/64}
 {$ifdef arm}
          symboldata  : tlinkedlistitem;
          signindex   : shortint;

+ 6 - 4
compiler/dbgdwarf.pas

@@ -3774,10 +3774,12 @@ implementation
                     asmline.concat(tai_comment.Create(strpnew('['+tostr(currfileinfo.line)+':'+tostr(currfileinfo.column)+']')));
 
                     if (prevlabel = nil) or
-                       { darwin's assembler cannot create an uleb128 of the difference }
-                       { between to symbols                                            }
-                       { same goes for Solaris native assembler                        }
-                       (target_info.system in systems_darwin) or
+                       { darwin's assembler cannot create an uleb128 of the difference
+                         between to symbols
+                         same goes for Solaris native assembler
+                         ... and riscv }
+
+                       (target_info.system in systems_darwin+[system_riscv32_linux,system_riscv64_linux]) or
                        (target_asm.id=as_solaris_as) then
                       begin
                         asmline.concat(tai_const.create_8bit(DW_LNS_extended_op));

+ 6 - 2
compiler/entfile.pas

@@ -153,7 +153,9 @@ const
     { 15 } 16 {'i8086'},
     { 16 } 64 {'aarch64'},
     { 17 } 32 {'wasm'},
-    { 18 } 64 {'sparc64'}
+    { 18 } 64 {'sparc64'},
+    { 19 } 32 {'riscv32'},
+    { 20 } 64 {'riscv64'}
     );
   CpuAluBitSize : array[tsystemcpu] of longint =
     (
@@ -175,7 +177,9 @@ const
     { 15 } 16 {'i8086'},
     { 16 } 64 {'aarch64'},
     { 17 } 64 {'wasm'},
-    { 18 } 64 {'sparc64'}
+    { 18 } 64 {'sparc64'},
+    { 19 } 32 {'riscv32'},
+    { 20 } 64 {'riscv64'}
     );
 {$endif generic_cpu}
 

+ 24 - 0
compiler/fpcdefs.inc

@@ -273,6 +273,30 @@
   {$define SUPPORT_GET_FRAME}
 {$endif aarch64}
 
+{$ifdef riscv32}
+  {$define cpu32bit}
+  {$define cpu32bitaddr}
+  {$define cpu32bitalu}
+  {$define cpufpemu}
+  {$define cputargethasfixedstack}
+  {$define cpuneedsmulhelper}
+  {$define cpuneedsdivhelper}
+  {$define cpucapabilities}
+  {$define cpurequiresproperalignment}
+{$endif riscv32}
+
+{$ifdef riscv64}
+  {$define cpu64bit}
+  {$define cpu64bitaddr}
+  {$define cpu64bitalu}
+  {$define cpufpemu}
+  {$define cputargethasfixedstack}
+  {$define cpuneedsmulhelper}
+  {$define cpuneedsdivhelper}
+  {$define cpucapabilities}
+  {$define cpurequiresproperalignment}
+{$endif riscv64}
+
 {$IFDEF MACOS}
 {$DEFINE USE_FAKE_SYSUTILS}
 {$ENDIF MACOS}

+ 14 - 2
compiler/globals.pas

@@ -54,8 +54,8 @@ interface
          [m_delphi,m_class,m_objpas,m_result,m_string_pchar,
           m_pointer_2_procedure,m_autoderef,m_tp_procvar,m_initfinal,m_default_ansistring,
           m_out,m_default_para,m_duplicate_names,m_hintdirective,
-          m_property,m_default_inline,m_except,m_advanced_records,
-          m_array_operators];
+          m_property,m_default_inline,m_except,m_advanced_records,
+          m_array_operators];
        delphiunicodemodeswitches = delphimodeswitches + [m_systemcodepage,m_default_unicodestring];
        fpcmodeswitches =
          [m_fpc,m_string_pchar,m_nested_comment,m_repeat_forward,
@@ -529,6 +529,18 @@ interface
         asmcputype : cpu_none;
         fputype : fpu_x87;
   {$endif i8086}
+  {$ifdef riscv32}
+        cputype : cpu_rv32imafd;
+        optimizecputype : cpu_rv32imafd;
+        asmcputype : cpu_none;
+        fputype : fpu_fd;
+  {$endif riscv32}
+  {$ifdef riscv64}
+        cputype : cpu_rv64imafdc;
+        optimizecputype : cpu_rv64imafdc;
+        asmcputype : cpu_none;
+        fputype : fpu_fd;
+  {$endif riscv64}
 {$endif not GENERIC_CPU}
         asmmode : asmmode_standard;
 {$ifndef jvm}

+ 1 - 1
compiler/globtype.pas

@@ -148,7 +148,7 @@ interface
          cs_full_boolean_eval,cs_typed_const_writable,cs_allow_enum_calc,
          cs_do_inline,cs_fpu_fwait,cs_ieee_errors,
          cs_check_low_addr_load,cs_imported_data,
-         cs_excessprecision,
+         cs_excessprecision,cs_check_fpu_exceptions,
          { mmx }
          cs_mmx,cs_mmx_saturation,
          { parser }

+ 1 - 0
compiler/msg/errore.msg

@@ -3814,6 +3814,7 @@ S*2Aas_Assemble using GNU AS
 **2Cc<x>_Set default calling convention to <x>
 **2CD_Create also dynamic library (not supported)
 **2Ce_Compilation with emulated floating point opcodes
+**2CE_Generate FPU code which can raise exceptions
 **2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for possible values
 **2CF<x>_Minimal floating point constant precision (default, 32, 64)
 **2Cg_Generate PIC code

+ 1 - 1
compiler/msgidx.inc

@@ -1105,7 +1105,7 @@ const
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 82541;
+  MsgTxtSize = 82592;
 
   MsgIdxMax : array[1..20] of longint=(
     28,106,349,126,98,59,142,34,221,67,

+ 167 - 166
compiler/msgtxt.inc

@@ -1,8 +1,8 @@
 const msgtxt_codepage=20127;
 {$ifdef Delphi}
-const msgtxt : array[0..000343] of string[240]=(
+const msgtxt : array[0..000344] of string[240]=(
 {$else Delphi}
-const msgtxt : array[0..000343,1..240] of char=(
+const msgtxt : array[0..000344,1..240] of char=(
 {$endif Delphi}
   '01000_T_Compiler: $1'#000+
   '01001_D_Compiler OS: $1'#000+
@@ -1463,222 +1463,223 @@ const msgtxt : array[0..000343,1..240] of char=(
   '**2Cc<x>_Set default calling convention to <x>'#010+
   '**2CD_Create also dynamic library (not supported)'#010+
   '**2','Ce_Compilation with emulated floating point opcodes'#010+
+  '**2CE_Generate FPU code which can raise exceptions'#010+
   '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
   'possible values'#010+
-  '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
+  '**2CF<x>_Minimal floating point constant precision ','(default, 32, 64)'+
+  #010+
   '**2Cg_Generate PIC code'#010+
-  '**2Ch<n>[',',m]_<n> bytes min heap size (between 1023 and 67107840) and'+
-  ' optionally [m] max heap size'#010+
+  '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
+  'ptionally [m] max heap size'#010+
   '**2Ci_IO-checking'#010+
   'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
   '**2Cn_Omit linking stage'#010+
-  'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
-  '**2Co_Chec','k overflow of integer operations'#010+
+  'P*2C','N_Generate nil-pointer checks (AIX-only)'#010+
+  '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
   '**2Cp<x>_Select instruction set; see fpc -i or fpc -ic for possible va'+
   'lues'#010+
-  '**2CP<x>=<y>_ packing settings'#010+
-  '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or',' DEFAULT or NORMAL, 2, '+
-  '4 and 8'#010+
+  '**2CP<x>=<y>_ packing set','tings'#010+
+  '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
+  'and 8'#010+
   '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
   'L'#010+
   '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, 2,'+
-  ' 4, 8, 16 and 32'#010+
+  ' 4, 8, 16 and 32',#010+
   '**2Cr_Range checking'#010+
-  '**2CR_Verify object method ca','ll validity'#010+
+  '**2CR_Verify object method call validity'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
   '**2Ct_Stack checking (for testing only, see manual)'#010+
   '8*2CT<x>_Target-specific code generation options'#010+
-  '3*2CT<x>_Target-specific code generation options'#010+
-  '4*2CT<x>_Target-specific code generati','on options'#010+
+  '3*2CT<x>_Target-specific code genera','tion options'#010+
+  '4*2CT<x>_Target-specific code generation options'#010+
   'p*2CT<x>_Target-specific code generation options'#010+
   'P*2CT<x>_Target-specific code generation options'#010+
   'J*2CT<x>_Target-specific code generation options'#010+
-  'A*2CT<x>_Target-specific code generation options'#010+
-  'p*3CTsmalltoc_ Generate smaller T','OCs at the expense of execution spe'+
-  'ed (AIX)'#010+
+  'A*2CT<x>_Target-specific code g','eneration options'#010+
+  'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
+  ' (AIX)'#010+
   'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
   ' (AIX)'#010+
-  'J*3CTautogetterprefix=X_  Automatically create getters for properties '+
+  'J*3CTautogetterprefix=X_  Automatically create getters for propertie','s'+
+  ' with prefix X (empty string disables)'#010+
+  'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
   'with prefix X (empty string disables)'#010+
-  'J*3CTautose','tterprefix=X_  Automatically create setters for propertie'+
-  's with prefix X (empty string disables)'#010+
   '8*3CTcld_                 Emit a CLD instruction before using the x86 '+
   'string instructions'#010+
-  '3*3CTcld_                 Emit a CLD instruction befo','re using the x8'+
+  '3*','3CTcld_                 Emit a CLD instruction before using the x8'+
   '6 string instructions'#010+
   '4*3CTcld_                 Emit a CLD instruction before using the x86 '+
   'string instructions'#010+
-  '8*3CTfarprocspushoddbp_       Increment BP before pushing it in the pr'+
-  'ologue of far functions'#010+
-  'J*3CTcompactintarra','yinit_ Generate smaller (but potentially slower) '+
-  'code for initializing integer array constants'#010+
+  '8*3CTfarprocspushoddbp_       Increment BP before pushing it i','n the '+
+  'prologue of far functions'#010+
+  'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
+  'de for initializing integer array constants'#010+
   'J*3CTenumfieldinit_       Initialize enumeration fields in constructor'+
-  's to enumtype(0), after calling inherited constructors'#010+
-  'J*3CTinitlocals_    ','      Initialize local variables that trigger a '+
-  'JVM bytecode verification error if used uninitialized (slows down code'+
-  ')'#010+
-  'J*3CTlowercaseprocstart_  Lowercase the first character of procedure/f'+
-  'unction/method names'#010+
-  'A*3CTthumbinterworking_ Gener','ate Thumb interworking-safe code if pos'+
-  'sible'#010+
+  's to enumtype(0), after ','calling inherited constructors'#010+
+  'J*3CTinitlocals_          Initialize local variables that trigger a JV'+
+  'M bytecode verification error if used uninitialized (slows down code)'#010+
+  'J*3CTlowercaseprocstart_  Lowercase the first character of procedure/',
+  'function/method names'#010+
+  'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
+  'ble'#010+
   'J*2Cv_Var/out parameter copy-out checking'#010+
   '**2CX_Create also smartlinked library'#010+
   '**1d<x>_Defines the symbol <x>'#010+
   '**1D_Generate a DEF file'#010+
-  '**2Dd<x>_Set description to <x>'#010+
-  '**2Dv<x>_Set DLL version to',' <x>'#010+
+  '**2Dd<x>','_Set description to <x>'#010+
+  '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
   '**1e<x>_Set path to executable'#010+
   '**1E_Same as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1F<x>_Set file names and paths:'#010+
-  '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
-  'sed'#010+
+  '**2Fa<x>[,y]_(for a program) load units <x> and [y] before us','es is p'+
+  'arsed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
-  '**2','FC<x>_Set RC compiler binary name to <x>'#010+
+  '**2FC<x>_Set RC compiler binary name to <x>'#010+
   '**2Fd_Disable the compiler'#039's internal directory cache'#010+
   '**2FD<x>_Set the directory where to search for compiler utilities'#010+
-  '**2Fe<x>_Redirect error output to <x>'#010+
-  '**2Ff<x>_Add <x> to framework path (Darwi','n only)'#010+
+  '**2Fe<x>_Redirect error outp','ut to <x>'#010+
+  '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2Fi<x>_Add <x> to include path'#010+
   '**2Fl<x>_Add <x> to library path'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
-  '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
-  'r'#010+
-  '**2FM<x>_Set the d','irectory where to search for unicode binary files'#010+
+  '**2Fm<x>_Load unicode conversion table ','from <x>.txt in the compiler '+
+  'dir'#010+
+  '**2FM<x>_Set the directory where to search for unicode binary files'#010+
   '**2FN<x>_Add <x> to list of default unit scopes (namespaces)'#010+
   '**2Fo<x>_Add <x> to object path'#010+
   '**2Fr<x>_Load error message file <x>'#010+
-  '**2FR<x>_Set resource (.res) linker to <x>'#010+
-  '**2Fu<x>_Add <x> ','to unit path'#010+
+  '**2FR<x>_','Set resource (.res) linker to <x>'#010+
+  '**2Fu<x>_Add <x> to unit path'#010+
   '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
-  '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
-  'om <x>'#010+
-  '*g1g_Generate debug informatio','n (default format for target)'#010+
+  '**2Fw<x>_Load previously stored whole-program optimizati','on feedback '+
+  'from <x>'#010+
+  '*g1g_Generate debug information (default format for target)'#010+
   '*g2gc_Generate checks for pointers (experimental, only available on so'+
   'me targets, might generate false positive)'#010+
-  '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
-  '*g2gl_Use line info unit (show mo','re info with backtraces)'#010+
+  '*g2gh_Use heaptrace unit (for memory leak/corr','uption debugging)'#010+
+  '*g2gl_Use line info unit (show more info with backtraces)'#010+
   '*g2gm_Generate Microsoft CodeView debug information (experimental)'#010+
   '*g2go<x>_Set debug information options'#010+
-  '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
-  'aks gdb < 6.5)'#010+
-  '*g3gostabsabsincludes_ Store abs','olute/full include file paths in Sta'+
-  'bs'#010+
+  '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information ','(b'+
+  'reaks gdb < 6.5)'#010+
+  '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
+  #010+
   '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
   'ame'#010+
   '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
-  '*g3godwarfomflinnum_ Generate line number information in OMF LINNUM re'+
-  'co','rds in MS LINK format in addition to the DWARF debug information ('+
+  '*g3godwarfomflinnum_ ','Generate line number information in OMF LINNUM '+
+  'records in MS LINK format in addition to the DWARF debug information ('+
   'Open Watcom Debugger/Linker compatibility)'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
-  '*g2gs_Generate Stabs debug information'#010+
-  '*g2gt_Trash local variables (to detect uninitializ','ed uses; multiple '+
-  #039't'#039' changes the trashing value)'#010+
+  '*g2gs_Generate Stabs debug information',#010+
+  '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
+  't'#039' changes the trashing value)'#010+
   '*g2gv_Generates programs traceable with Valgrind'#010+
   '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
-  '*g2gw2_Generate DWARFv2 debug information'#010+
+  '*g2gw2_Generate DWARFv2 debug info','rmation'#010+
   '*g2gw3_Generate DWARFv3 debug information'#010+
-  '*','g2gw4_Generate DWARFv4 debug information (experimental)'#010+
+  '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
   '**1i_Information'#010+
   '**2iD_Return compiler date'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
-  '**2iTP_Return target processor'#010+
-  '**2iV_Return short co','mpiler version'#010+
+  '*','*2iTP_Return target processor'#010+
+  '**2iV_Return short compiler version'#010+
   '**2iW_Return full compiler version'#010+
   '**2ia_Return list of supported ABI targets'#010+
   '**2ic_Return list of supported CPU instruction sets'#010+
-  '**2if_Return list of supported FPU instruction sets'#010+
-  '**2ii_Return list of supported inline assem','bler modes'#010+
+  '**2if_Return list of supported FPU instructi','on sets'#010+
+  '**2ii_Return list of supported inline assembler modes'#010+
   '**2io_Return list of supported optimizations'#010+
   '**2ir_Return list of recognized compiler and RTL features'#010+
   '**2it_Return list of supported targets'#010+
-  '**2iu_Return list of supported microcontroller types'#010+
-  '**2iw_Return list of supported who','le program optimizations'#010+
+  '**2iu_Return list of supported micro','controller types'#010+
+  '**2iw_Return list of supported whole program optimizations'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
   '**1M<x>_Set language mode to <x>'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
-  '**2Mobjfpc_FPC mode with Object Pascal support'#010+
-  '**2Mdelphi_Delphi ','7 compatibility mode'#010+
+  '**2Mobjfpc_FPC',' mode with Object Pascal support'#010+
+  '**2Mdelphi_Delphi 7 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**2Miso_ISO 7185 mode'#010+
   '**2Mextendedpascal_ISO 10206 mode'#010+
-  '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
-  '**1n_Do not ','read the default config files'#010+
+  '**2Mdelphiunicode_De','lphi 2009 and later compatibility mode'#010+
+  '**1n_Do not read the default config files'#010+
   '**1o<x>_Change the name of the executable produced to <x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
-  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
-  '**2O2_Level 2 optimizations (-O1 + quick op','timizations)'#010+
+  '**2O1_Level 1 optimizations (quick and debugger fr','iendly)'#010+
+  '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
   '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
   'pected side effects)'#010+
   '**2Oa<x>=<y>_Set alignment'#010+
-  '**2Oo[NO]<x>_Enable or disable optimizations; see fpc ','-i or fpc -io '+
+  '**2','Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io '+
   'for possible values'#010+
   '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
   'ible values'#010+
   '**2OW<x>_Generate whole-program optimization feedback for optimization'+
-  ' <x>; see fpc -i or fpc -iw for possible values'#010+
-  '**2Ow<','x>_Perform whole-program optimization <x>; see fpc -i or fpc -'+
-  'iw for possible values'#010+
+  ' <x','>; see fpc -i or fpc -iw for possible values'#010+
+  '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
+  ' for possible values'#010+
   '**2Os_Optimize for size rather than speed'#010+
   '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
-  'F*1P<x>_Target CPU / compiler related options:'#010+
-  'F*2PB_','Show default compiler binary'#010+
+  'F*','1P<x>_Target CPU / compiler related options:'#010+
+  'F*2PB_Show default compiler binary'#010+
   'F*2PP_Show default target cpu'#010+
   'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
   'l,powerpc,powerpc64,sparc,x86_64)'#010+
-  '**1R<x>_Assembler reading style:'#010+
-  '**2Rdefault_Use default assembler for target',#010+
+  '**1R<x>_Assembler reading ','style:'#010+
+  '**2Rdefault_Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '4*2Ratt_Read AT&T style assembler'#010+
   '4*2Rintel_Read Intel style assembler'#010+
   '8*2Ratt_Read AT&T style assembler'#010+
-  '8*2Rintel_Read Intel style assembler'#010+
-  '6*2RMOT_Read Motorola styl','e assembler'#010+
+  '8*2Rintel_Re','ad Intel style assembler'#010+
+  '6*2RMOT_Read Motorola style assembler'#010+
   '**1S<x>_Syntax options:'#010+
   '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#010+
-  '**2Se<x>_Error options. <x> is a combination of the following:'#010+
-  '**3*_<n> : Compiler h','alts after the <n> errors (default is 1)'#010+
+  '**2Se<x>_Error options. <x> is a ','combination of the following:'#010+
+  '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
   '**3*_w : Compiler also halts after warnings'#010+
   '**3*_n : Compiler also halts after notes'#010+
   '**3*_h : Compiler also halts after hints'#010+
-  '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
-  'ir ','for possible values)'#010+
+  '**2Sf_Enable certain f','eatures in compiler and RTL; see fpc -i or fpc'+
+  ' -ir for possible values)'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
   '**2Sh_Use reference counted strings (ansistring by default) instead of'+
   ' shortstrings'#010+
-  '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
-  '**2Sj_Al','lows typed constants to be writeable (default in all modes)'#010+
+  '**2Si_Turn on inlining of',' procedures/functions declared as "inline"'#010+
+  '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**3SIcom_COM compatible interface (default)'#010+
-  '**3SIcorba_CORBA compatible interface'#010+
+  '**3SIcorba_CORBA compatib','le interface'#010+
   '**2Sm_Support macros like C (global)'#010+
-  '*','*2So_Same as -Mtp'#010+
+  '**2So_Same as -Mtp'#010+
   '**2Sr_Transparent file names in ISO mode'#010+
   '**2Ss_Constructor name must be init (destructor must be done)'#010+
-  '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
-  'e)'#010+
-  '**2Sx_Enable exception keywords (default in De','lphi/ObjFPC modes)'#010+
+  '**2Sv_Support vector processing (use CPU vector extensions if availa','b'+
+  'le)'#010+
+  '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
   '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
   '**1s_Do not call assembler and linker'#010+
   '**2sh_Generate script to link on host'#010+
-  '**2st_Generate script to link on target'#010+
-  '**2sr_Skip register allocation phase (use with -alr',')'#010+
+  '**2st_Generate script to link on target'#010,
+  '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
   '3*2Tandroid_Android'#010+
   '3*2Taros_AROS'#010+
@@ -1686,25 +1687,25 @@ const msgtxt : array[0..000343,1..240] of char=(
   '3*2Tdarwin_Darwin/Mac OS X'#010+
   '3*2Tembedded_Embedded'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
-  '3*2Tfreebsd_FreeBSD'#010+
-  '3*2Tgo32v2_Version 2 of DJ Delorie DOS',' extender'#010+
+  '3*2Tfre','ebsd_FreeBSD'#010+
+  '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Thaiku_Haiku'#010+
   '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+
   'win)'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
   '3*2Tnetbsd_NetBSD'#010+
-  '3*2Tnetware_Novell Netware Module (clib)'#010+
-  '3*2Tnetwlibc_Novell Ne','tware Module (libc)'#010+
+  '3*2Tnetware_','Novell Netware Module (clib)'#010+
+  '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tsymbian_Symbian OS'#010+
   '3*2Tsolaris_Solaris'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
-  '3*2Twin32_Windows 32 Bit'#010+
+  '3*2Twin3','2_Windows 32 Bit'#010+
   '3*2Twince_Windows CE'#010+
-  '4*2Taros_AROS',#010+
+  '4*2Taros_AROS'#010+
   '4*2Tdarwin_Darwin/Mac OS X'#010+
   '4*2Tdragonfly_DragonFly BSD'#010+
   '4*2Tembedded_Embedded'#010+
@@ -1713,8 +1714,8 @@ const msgtxt : array[0..000343,1..240] of char=(
   '4*2Tlinux_Linux'#010+
   '4*2Tnetbsd_NetBSD'#010+
   '4*2Topenbsd_OpenBSD'#010+
-  '4*2Tsolaris_Solaris'#010+
-  '4*2Twin64_Win64 (64 bit Windows system','s)'#010+
+  '4*2Tsol','aris_Solaris'#010+
+  '4*2Twin64_Win64 (64 bit Windows systems)'#010+
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tembedded_Embedded'#010+
@@ -1723,9 +1724,9 @@ const msgtxt : array[0..000343,1..240] of char=(
   '6*2Tmacos_Mac OS'#010+
   '6*2Tpalmos_PalmOS'#010+
   '8*2Tembedded_Embedded'#010+
-  '8*2Tmsdos_MS-DOS (and compatible)'#010+
+  '8*2Tmsdos_MS-DOS (and',' compatible)'#010+
   '8*2Twin16_Windows 16 Bit'#010+
-  'A*2Tandroid_A','ndroid'#010+
+  'A*2Tandroid_Android'#010+
   'A*2Taros_AROS'#010+
   'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
   'A*2Tembedded_Embedded'#010+
@@ -1734,10 +1735,10 @@ const msgtxt : array[0..000343,1..240] of char=(
   'A*2Tnds_Nintendo DS'#010+
   'A*2Tnetbsd_NetBSD'#010+
   'A*2Tpalmos_PalmOS'#010+
-  'A*2Tsymbian_Symbian'#010+
+  'A*2Tsymbian_Symbia','n'#010+
   'A*2Twince_Windows CE'#010+
   'a*2Tdarwin_Darwin/iOS'#010+
-  'a*2Tli','nux_Linux'#010+
+  'a*2Tlinux_Linux'#010+
   'J*2Tandroid_Android'#010+
   'J*2Tjava_Java'#010+
   'm*2Tandroid_Android'#010+
@@ -1747,10 +1748,10 @@ const msgtxt : array[0..000343,1..240] of char=(
   'M*2Tlinux_Linux'#010+
   'P*2Taix_AIX'#010+
   'P*2Tamiga_AmigaOS'#010+
-  'P*2Tdarwin_Darwin/Mac OS X'#010+
+  'P*2Tdarwin_Darwin/M','ac OS X'#010+
   'P*2Tembedded_Embedded'#010+
   'P*2Tlinux_Linux'#010+
-  'P*2Tm','acos_Mac OS (classic)'#010+
+  'P*2Tmacos_Mac OS (classic)'#010+
   'P*2Tmorphos_MorphOS'#010+
   'P*2Tnetbsd_NetBSD'#010+
   'P*2Twii_Wii'#010+
@@ -1760,147 +1761,147 @@ const msgtxt : array[0..000343,1..240] of char=(
   'p*2Tlinux_Linux'#010+
   'S*2Tlinux_Linux'#010+
   'S*2Tsolaris_Solaris'#010+
-  's*2Tlinux_Linux'#010+
+  's*2T','linux_Linux'#010+
   'V*2Tembedded_Embedded'#010+
-  '**1u<x>_Undefines',' the symbol <x>'#010+
+  '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
-  '**2Us_Compile a system unit'#010+
-  '**1v<x>_Be verbose. <x> is a combination of the f','ollowing letters:'#010+
+  '**2Us_Compile a system uni','t'#010+
+  '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
-  '**2*_n : Show notes                  t : Show tried/used files'#010+
-  '**2*_h : Show hints              ','    c : Show conditionals'#010+
+  '**2*_n : Show notes                  t : Show',' tried/used files'#010+
+  '**2*_h : Show hints                  c : Show conditionals'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_s : Show time stamps            q : Show message numbers'#010+
-  '**2*_a : Show everything ','            x : Show info about invoked too'+
-  'ls'#010+
+  '**2*_s : Show time stamps           ',' q : Show message numbers'#010+
+  '**2*_a : Show everything             x : Show info about invoked tools'+
+  #010+
   '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
   'e'#010+
   '**2*_    with full path              v : Write fpcdebug.txt with'#010+
-  '**2*_z : Write output to stderr          lots of debuggin','g info'#010+
+  '**2*_z',' : Write output to stderr          lots of debugging info'#010+
   '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
   'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
   'or version)'#010+
   '**1W<x>_Target-specific options (targets)'#010+
-  '3*2WA_Specify native type application (Windows)'#010+
-  '4*2WA_Speci','fy native type application (Windows)'#010+
+  '3*2WA_Sp','ecify native type application (Windows)'#010+
+  '4*2WA_Specify native type application (Windows)'#010+
   'A*2WA_Specify native type application (Windows)'#010+
   '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'p*2Wb_Create a bundle instead of a library (Darwin)',#010+
+  'P*2Wb_Create a bundle instead of a library (Darwin)'#010,
+  'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '4*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  '3*2WB<x>_Set image base to <x> ','(Windows, Symbian)'#010+
+  '3*2WB_Create a relocatable image',' (Windows, Symbian)'#010+
+  '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
   '4*2WB_Create a relocatable image (Windows)'#010+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
   'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
-  '3*2WC_Specify console type applicat','ion (EMX, OS/2, Windows)'#010+
+  'A*2WB<x>_Set image base to <x> (Wi','ndows, Symbian)'#010+
+  '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   '4*2WC_Specify console type application (Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
-  '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)',#010+
+  '3*2WD_Use ','DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
-  '4*2We_Use external resources (Darwin)'#010+
+  '4*2We_Use external resourc','es (Darwin)'#010+
   'a*2We_Use external resources (Darwin)'#010+
-  'A','*2We_Use external resources (Darwin)'#010+
+  'A*2We_Use external resources (Darwin)'#010+
   'P*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
   '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
-  '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
-  '4*2WG_Specif','y graphic type application (Windows)'#010+
+  '3*2WG_Specify graphic',' type application (EMX, OS/2, Windows)'#010+
+  '4*2WG_Specify graphic type application (Windows)'#010+
   'A*2WG_Specify graphic type application (Windows)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
-  '4*2Wi_Use internal resources (Darwin)'#010+
-  'a*2Wi_Use internal res','ources (Darwin)'#010+
+  '4*2Wi_Use',' internal resources (Darwin)'#010+
+  'a*2Wi_Use internal resources (Darwin)'#010+
   'A*2Wi_Use internal resources (Darwin)'#010+
   'P*2Wi_Use internal resources (Darwin)'#010+
   'p*2Wi_Use internal resources (Darwin)'#010+
   '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
-  '4*2WI_Turn on/off the usage of import sections (Windo','ws)'#010+
+  '4*','2WI_Turn on/off the usage of import sections (Windows)'#010+
   'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
   'e segment)'#010+
   '8*2Wm<x>_Set memory model'#010+
-  '8*3WmTiny_Tiny memory model'#010+
+  '8*3WmTiny_Tiny memory',' model'#010+
   '8*3WmSmall_Small memory model (default)'#010+
-  '8*3W','mMedium_Medium memory model'#010+
+  '8*3WmMedium_Medium memory model'#010+
   '8*3WmCompact_Compact memory model'#010+
   '8*3WmLarge_Large memory model'#010+
   '8*3WmHuge_Huge memory model'#010+
-  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
+  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darw',
+  'in)'#010+
+  '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
-  '4*2WM<x>_Minimum Mac OS X deployment version: 1','0.4, 10.5.1, ... (Dar'+
-  'win)'#010+
   'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
   'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
-  '3*2WN_Do not generate relocation code, needed for debugging (Windows',')'+
-  #010+
+  '3*2WN_Do not gene','rate relocation code, needed for debugging (Windows'+
+  ')'#010+
   '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
-  'le values'#010+
-  'm*2Wp<x>_Specify t','he controller type; see fpc -i or fpc -iu for poss'+
+  'A*2Wp<x>_Specify the controller type; see fpc -','i or fpc -iu for poss'+
   'ible values'#010+
+  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+  'le values'#010+
   'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+
-  '4*2WP<x>_Minimum iOS deployme','nt version: 8.0, 8.0.2, ... (iphonesim)'+
+  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5','.0.1, ... (iphonesim)'+
   #010+
+  '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
   'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
   'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
-  '3*2WR_Generate relocation code (Windows)'#010+
-  '4*2WR_Generate relocation c','ode (Windows)'#010+
+  '3*2WR_Generate re','location code (Windows)'#010+
+  '4*2WR_Generate relocation code (Windows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
   '8*2Wt<x>_Set the target executable format'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#010+
-  '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+
-  'P*2WT_Specify MPW tool type application ','(Classic Mac OS)'#010+
+  '8*3Wtcom_Create a DOS .COM file (requires tiny mem','ory model)'#010+
+  'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   '**2WX_Enable executable stack (Linux)'#010+
   '**1X_Executable options:'#010+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '9.1 (Linux)'#010+
-  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
-  'ux)'#010+
-  '**2X','d_Do not search default library path (sometimes required for cro'+
-  'ss-compiling when not using -XR)'#010+
+  '**2Xc_Pass --shared/-dynami','c to the linker (BeOS, Darwin, FreeBSD, L'+
+  'inux)'#010+
+  '**2Xd_Do not search default library path (sometimes required for cross'+
+  '-compiling when not using -XR)'#010+
   '**2Xe_Use external linker'#010+
   '**2Xf_Substitute pthread library name for linking (BSD)'#010+
-  '**2Xg_Create debuginfo in a separate file and add a debuglink',' sectio'+
+  '**2Xg_Crea','te debuginfo in a separate file and add a debuglink sectio'+
   'n to executable'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
   '**2XLA_Define library substitutions for linking'#010+
-  '**2XLO_Define order of library linking'#010+
-  '**2XLD_Exclude default order of stan','dard libraries'#010+
+  '**2XLO_Define order of l','ibrary linking'#010+
+  '**2XLD_Exclude default order of standard libraries'#010+
   '**2Xm_Generate link map'#010+
   '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
   's '#039'main'#039')'#010+
   '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
   #010+
-  'F*2Xp<x>_First search for the compiler binary in the direc','tory <x>'#010+
+  'F*2Xp<x','>_First search for the compiler binary in the directory <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
   '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
-  'ile, see the ld manual for more information) (BeOS, Linux)'#010+
-  '**2XR<x>_Prepend <x> to all linker search paths (B','eOS, Darwin, FreeB'+
-  'SD, Linux, Mac OS, Solaris)'#010+
+  'ile, see the ld manual for more information) (BeOS, Linux)',#010+
+  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
+  ', Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
   '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
-  '**2Xt_Link with static libraries (-static is passed to linker)'#010+
-  '**2Xv_Generate table ','for Virtual Entry calls'#010+
+  '**2Xt_Link with static libraries ','(-static is passed to linker)'#010+
+  '**2Xv_Generate table for Virtual Entry calls'#010+
   '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#010+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+
-  '**1h_Shows this help without waiting'
+  '**1h','_Shows this help without waiting'
 );

+ 1 - 1
compiler/nadd.pas

@@ -1095,7 +1095,7 @@ implementation
                     end;
                   end
                 { short to full boolean evalution possible and useful? }
-                else if not(might_have_sideeffects(right)) and not(cs_full_boolean_eval in localswitches) then
+                else if not(might_have_sideeffects(right,[mhs_exceptions])) and not(cs_full_boolean_eval in localswitches) then
                   begin
                     case nodetype of
                       andn,orn:

+ 2 - 1
compiler/ncal.pas

@@ -56,7 +56,8 @@ interface
          cnf_call_never_returns, { information for the dfa that a subroutine never returns }
          cnf_call_self_node_done,{ the call_self_node has been generated if necessary
                                    (to prevent it from potentially happening again in a wrong context in case of constant propagation or so) }
-         cnf_ignore_visibility   { internally generated call that should ignore visibility checks }
+         cnf_ignore_visibility,  { internally generated call that should ignore visibility checks }
+         cnf_check_fpu_exceptions { after the call fpu exceptions shall be checked }
        );
        tcallnodeflags = set of tcallnodeflag;
 

+ 4 - 0
compiler/ncgcal.pas

@@ -1272,6 +1272,10 @@ implementation
          { release temps of paras }
          release_para_temps;
 
+         { check for fpu exceptions }
+         if cnf_check_fpu_exceptions in callnodeflags then
+           cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+
          { perhaps i/o check ? }
          if (cs_check_io in current_settings.localswitches) and
             (po_iocheck in procdefinition.procoptions) and

+ 19 - 8
compiler/ninl.pas

@@ -4028,7 +4028,7 @@ implementation
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        first_arctan_real := ccallnode.createintern('fpc_arctan_real',
+        result := ccallnode.createintern('fpc_arctan_real',
                 ccallparanode.create(left,nil));
         left := nil;
       end;
@@ -4037,8 +4037,9 @@ implementation
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        first_abs_real := ctypeconvnode.create(ccallnode.createintern('fpc_abs_real',
+        result := ctypeconvnode.create(ccallnode.createintern('fpc_abs_real',
                 ccallparanode.create(left,nil)),resultdef);
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4051,8 +4052,9 @@ implementation
 {$endif cpufpemu}
         { create the call to the helper }
         { on entry left node contains the parameter }
-        first_sqr_real := ctypeconvnode.create(ccallnode.createintern('fpc_sqr_real',
+        result := ctypeconvnode.create(ccallnode.createintern('fpc_sqr_real',
                 ccallparanode.create(left,nil)),resultdef);
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4084,15 +4086,16 @@ implementation
             else
               internalerror(2014052101);
             end;
-            first_sqrt_real:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
+            result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
                ctypeconvnode.create_internal(left,fdef),nil)),resultdef);
           end
         else
           begin
             { create the call to the helper }
             { on entry left node contains the parameter }
-            first_sqrt_real := ctypeconvnode.create(ccallnode.createintern('fpc_sqrt_real',
+            result := ctypeconvnode.create(ccallnode.createintern('fpc_sqrt_real',
                 ccallparanode.create(left,nil)),resultdef);
+            include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
           end;
         left := nil;
       end;
@@ -4101,8 +4104,9 @@ implementation
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        first_ln_real := ccallnode.createintern('fpc_ln_real',
+        result := ccallnode.createintern('fpc_ln_real',
                 ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4110,8 +4114,9 @@ implementation
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        first_cos_real := ccallnode.createintern('fpc_cos_real',
+        result := ccallnode.createintern('fpc_cos_real',
                 ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4119,8 +4124,9 @@ implementation
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        first_sin_real := ccallnode.createintern('fpc_sin_real',
+        result := ccallnode.createintern('fpc_sin_real',
                 ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4129,6 +4135,7 @@ implementation
         { create the call to the helper }
         { on entry left node contains the parameter }
         result := ccallnode.createintern('fpc_exp_real',ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4137,6 +4144,7 @@ implementation
         { create the call to the helper }
         { on entry left node contains the parameter }
         result := ccallnode.createintern('fpc_int_real',ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4145,6 +4153,7 @@ implementation
         { create the call to the helper }
         { on entry left node contains the parameter }
         result := ccallnode.createintern('fpc_frac_real',ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4153,6 +4162,7 @@ implementation
         { create the call to the helper }
         { on entry left node contains the parameter }
         result := ccallnode.createintern('fpc_round_real',ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 
@@ -4161,6 +4171,7 @@ implementation
         { create the call to the helper }
         { on entry left node contains the parameter }
         result := ccallnode.createintern('fpc_trunc_real',ccallparanode.create(left,nil));
+        include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         left := nil;
       end;
 

+ 29 - 4
compiler/nutils.pas

@@ -54,6 +54,14 @@ interface
                             then the parent node is processed again }
                           pm_postandagain);
 
+
+    tmhs_flag = (
+      { exceptions (overflow, sigfault etc.) are considered as side effect }
+      mhs_exceptions
+    );
+    tmhs_flags = set of tmhs_flag;
+    pmhs_flags = ^tmhs_flags;
+
     foreachnodefunction = function(var n: tnode; arg: pointer): foreachnoderesult of object;
     staticforeachnodefunction = function(var n: tnode; arg: pointer): foreachnoderesult;
 
@@ -117,7 +125,7 @@ interface
     function genloadfield(n: tnode; const fieldname: string): tnode;
 
     { returns true, if the tree given might have side effects }
-    function might_have_sideeffects(n : tnode) : boolean;
+    function might_have_sideeffects(n : tnode;const flags : tmhs_flags = []) : boolean;
 
     { count the number of nodes in the node tree,
       rough estimation how large the tree "node" is }
@@ -153,6 +161,10 @@ interface
     { include or exclude cs from p.localswitches }
     procedure node_change_local_switch(p : tnode;cs : tlocalswitch;enable : boolean);
 
+    { returns true, if p is a node which shall be short boolean evaluated,
+      if it is not an orn/andn with boolean operans, the result is undefined }
+    function doshortbooleval(p : tnode) : Boolean;
+
 implementation
 
     uses
@@ -1334,13 +1346,19 @@ implementation
              in_finalize_x,in_new_x,in_dispose_x,in_exit,in_copy_x,in_initialize_x,in_leave,in_cycle,
              in_and_assign_x_y,in_or_assign_x_y,in_xor_assign_x_y,in_sar_assign_x_y,in_shl_assign_x_y,
              in_shr_assign_x_y,in_rol_assign_x_y,in_ror_assign_x_y,in_neg_assign_x,in_not_assign_x])
+          ) or
+          ((mhs_exceptions in pmhs_flags(arg)^) and
+           ((n.nodetype in [derefn,vecn,subscriptn]) or
+            ((n.nodetype in [addn,subn,muln,divn,slashn,unaryminusn]) and (n.localswitches*[cs_check_overflow,cs_check_range]<>[]))
+           )
           ) then
           result:=fen_norecurse_true;
       end;
 
-    function might_have_sideeffects(n : tnode) : boolean;
+
+    function might_have_sideeffects(n : tnode; const flags : tmhs_flags) : boolean;
       begin
-        result:=foreachnodestatic(n,@check_for_sideeffect,nil);
+        result:=foreachnodestatic(n,@check_for_sideeffect,@flags);
       end;
 
     var
@@ -1445,7 +1463,8 @@ implementation
           exclude(p.localswitches, plocalswitchchange(plsc)^.cs);
         result:=fen_true;
      end;
-   
+
+
     procedure node_change_local_switch(p : tnode;cs : tlocalswitch;enable : boolean);
       var
         lsc : tlocalswitchchange;
@@ -1455,4 +1474,10 @@ implementation
         foreachnodestatic(p,@do_change_local_settings,@lsc);
       end;
 
+
+    function doshortbooleval(p : tnode) : Boolean;
+      begin
+        Result:=(p.nodetype in [orn,andn]) and ((nf_short_bool in taddnode(p).flags) or not(cs_full_boolean_eval in p.localswitches));
+      end;
+
 end.

+ 5 - 2
compiler/optcse.pas

@@ -298,9 +298,9 @@ unit optcse;
             if not(csedomain) then
               begin
                 { try to transform the tree to get better cse domains, consider:
-                       +
+                       +   (1)
                       / \
-                     +   C
+                (2)  +   C
                     / \
                    A   B
 
@@ -329,6 +329,9 @@ unit optcse;
                    (is_set(n.resultdef))
                    ) then
                   while (n.nodetype=tbinarynode(n).left.nodetype) and
+                    { if node (1) is fully boolean evaluated and node (2) not, we cannot do the swap as is might result in B being evaluated always,
+                      the other way round is no problem, C is still evaluated only if needed }
+                    (not(is_boolean(n.resultdef)) or not(n.nodetype in [andn,orn]) or doshortbooleval(n) or not(doshortbooleval(tbinarynode(n).left))) and
                         { the resulttypes of the operands we'll swap must be equal,
                           required in case of a 32x32->64 multiplication, then we
                           cannot swap out one of the 32 bit operands for a 64 bit one

+ 59 - 3
compiler/options.pas

@@ -135,7 +135,8 @@ const
                         + [system_i386_GO32V2]
                         + [system_i386_freebsd]
                         + [system_i386_netbsd]
-                        + [system_i386_wdosx];
+                        + [system_i386_wdosx]
+                        + [system_riscv32_linux,system_riscv64_linux];
 
   suppported_targets_x_smallr = systems_linux + systems_solaris
                              + [system_i386_haiku]
@@ -695,6 +696,12 @@ begin
 {$ifdef sparc64}
       's',
 {$endif}
+{$ifdef riscv32}
+      'R',
+{$endif}
+{$ifdef riscv64}
+      'r',
+{$endif}
 {$ifdef avr}
       'V',
 {$endif}
@@ -1186,6 +1193,11 @@ begin
                            include(init_settings.moduleswitches,cs_fp_emulation);
                        end;
 {$endif cpufpemu}
+                    'E' :
+                      If UnsetBool(More, j, opt, false) then
+                        exclude(init_settings.localswitches,cs_check_fpu_exceptions)
+                      Else
+                        include(init_settings.localswitches,cs_check_fpu_exceptions);
                     'f' :
                       begin
                         s:=upper(copy(more,j+1,length(more)-j));
@@ -3581,6 +3593,23 @@ procedure read_arguments(cmd:TCmdStr);
         def_system_macro('FPC_COMP_IS_INT64');
       {$endif aarch64}
 
+      {$ifdef riscv32}
+        def_system_macro('CPURISCV');
+        def_system_macro('CPURISCV32');
+        def_system_macro('CPU32');
+        def_system_macro('FPC_CURRENCY_IS_INT64');
+        def_system_macro('FPC_COMP_IS_INT64');
+        def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
+      {$endif riscv32}
+      {$ifdef riscv64}
+        def_system_macro('CPURISCV');
+        def_system_macro('CPURISCV64');
+        def_system_macro('CPU64');
+        def_system_macro('FPC_CURRENCY_IS_INT64');
+        def_system_macro('FPC_COMP_IS_INT64');
+        def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
+      {$endif riscv64}
+
       {$if defined(cpu8bitalu)}
         def_system_macro('CPUINT8');
       {$elseif defined(cpu16bitalu)}
@@ -4012,12 +4041,13 @@ begin
   if not(option.FPUSetExplicitly) and
      ((target_info.system in [system_arm_wince,system_arm_gba,
          system_m68k_amiga,system_m68k_atari,
-         system_arm_nds,system_arm_embedded])
+         system_arm_nds,system_arm_embedded,
+         system_riscv32_embedded,system_riscv64_embedded])
 {$ifdef arm}
       or (target_info.abi=abi_eabi)
 {$endif arm}
      )
-{$if defined(arm) or defined (m68k)}
+{$if defined(arm) or defined(riscv32) or defined(riscv64) or defined (m68k)}
      or (init_settings.fputype=fpu_soft)
 {$endif arm or m68k}
   then
@@ -4121,6 +4151,32 @@ begin
     def_system_macro('CPUTHUMB2');
 {$endif arm}
 
+{$if defined(riscv32) or defined(riscv64)}
+  { ARMHF defaults }
+  if (target_info.abi = abi_riscv_hf) then
+    { set default cpu type to ARMv7a for ARMHF unless specified otherwise }
+    begin
+      if not option.CPUSetExplicitly then
+        init_settings.cputype:=cpu_rv64imafdc;
+      if not option.OptCPUSetExplicitly then
+        init_settings.optimizecputype:=cpu_rv64imafdc;
+
+      { Set FPU type }
+      if not(option.FPUSetExplicitly) then
+        begin
+          init_settings.fputype:=fpu_fd;
+        end
+      else
+        begin
+          if not (init_settings.fputype in [fpu_fd]) then
+            begin
+              Message(option_illegal_fpu_eabihf);
+              StopOptions(1);
+            end;
+        end;
+    end;
+{$endif defined(riscv32) or defined(riscv64)}
+
 {$ifdef jvm}
   { set default CPU type to Dalvik when targeting Android }
   if target_info.system=system_jvm_android32 then

+ 13 - 0
compiler/pp.pas

@@ -37,6 +37,7 @@ program pp;
   MIPSEL              generate a compiler for the MIPSEL (Littel Endian)
   POWERPC             generate a compiler for the PowerPC
   POWERPC64           generate a compiler for the PowerPC64 architecture
+  RISCV64             generate a compiler for the RiscV64 architecture
   SPARC               generate a compiler for SPARC
   SPARC64             generate a compiler for SPARC64
   X86_64              generate a compiler for the AMD x86-64 architecture
@@ -163,6 +164,18 @@ program pp;
   {$endif CPUDEFINED}
   {$define CPUDEFINED}
 {$endif AARCH64}
+{$ifdef RISCV32}
+  {$ifdef CPUDEFINED}
+    {$fatal ONLY one of the switches for the CPU type must be defined}
+  {$endif CPUDEFINED}
+  {$define CPUDEFINED}
+{$endif RISCV32}
+{$ifdef RISCV64}
+  {$ifdef CPUDEFINED}
+    {$fatal ONLY one of the switches for the CPU type must be defined}
+  {$endif CPUDEFINED}
+  {$define CPUDEFINED}
+{$endif RISCV64}
 
 {$ifndef CPUDEFINED}
   {$fatal A CPU type switch must be defined}

+ 86 - 0
compiler/ppcriscv32.lpi

@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <LRSInOutputDirectory Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="ppcrv32"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default">
+          <local>
+            <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+          </local>
+        </Mode0>
+      </Modes>
+    </RunParams>
+    <Units Count="4">
+      <Unit0>
+        <Filename Value="pp.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="riscv32\aasmcpu.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="riscv32\aoptcpu.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit2>
+      <Unit3>
+        <Filename Value="aopt.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit3>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="riscv32\pp"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="riscv32;riscv"/>
+      <OtherUnitFiles Value="riscv32;riscv;systems"/>
+      <UnitOutputDirectory Value="riscv32\lazbuild"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <CStyleOperator Value="False"/>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <Other>
+      <Verbosity>
+        <ShowWarn Value="False"/>
+        <ShowNotes Value="False"/>
+        <ShowHints Value="False"/>
+      </Verbosity>
+      <ConfigFile>
+        <StopAfterErrCount Value="50"/>
+      </ConfigFile>
+      <CustomOptions Value="-driscv32
+-Sew"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 78 - 0
compiler/ppcriscv64.lpi

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <LRSInOutputDirectory Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="ppcriscv64"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default">
+          <local>
+            <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+          </local>
+        </Mode0>
+      </Modes>
+    </RunParams>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="pp.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="sparc64\aasmcpu.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit1>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="riscv64\pp"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="riscv;riscv64"/>
+      <OtherUnitFiles Value="riscv;riscv64;systems"/>
+      <UnitOutputDirectory Value="riscv64\lazbuild"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <CStyleOperator Value="False"/>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <Other>
+      <Verbosity>
+        <ShowWarn Value="False"/>
+        <ShowNotes Value="False"/>
+        <ShowHints Value="False"/>
+      </Verbosity>
+      <ConfigFile>
+        <StopAfterErrCount Value="50"/>
+      </ConfigFile>
+      <CustomOptions Value="-driscv64
+-Sew"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 1 - 1
compiler/psub.pas

@@ -990,7 +990,7 @@ implementation
       end;
 
 
-{$if defined(i386) or defined(x86_64) or defined(arm)}
+{$if defined(i386) or defined(x86_64) or defined(arm) or defined(riscv32) or defined(riscv64)}
     const
       exception_flags: array[boolean] of tprocinfoflags = (
         [],

+ 8 - 0
compiler/psystem.pas

@@ -346,6 +346,14 @@ implementation
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
 {$endif mips}
+{$ifdef riscv32}
+        create_fpu_types;
+        s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif riscv32}
+{$ifdef riscv64}
+        create_fpu_types;
+        s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif riscv64}
 {$ifdef jvm}
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);

+ 16 - 0
compiler/raatt.pas

@@ -330,6 +330,22 @@ unit raatt;
                end;
            end;
 {$endif aarch64}
+{$if defined(riscv32) or defined(riscv64)}
+           {
+             amo* instructions contain a postfix with size, and optionally memory ordering
+             fence* can contain memory type identifier
+             floating point instructions contain size, and optionally rounding mode
+           }
+           case c of
+             '.':
+               begin
+                 repeat
+                   actasmpattern:=actasmpattern+c;
+                   c:=current_scanner.asmgetchar;
+                 until not(c in ['a'..'z','A'..'Z','.']);
+               end;
+           end;
+{$endif riscv}
            { Opcode ? }
            If is_asmopcode(upper(actasmpattern)) then
             Begin

+ 8 - 1
compiler/rautils.pas

@@ -45,7 +45,7 @@ type
   TOprType=(OPR_NONE,OPR_CONSTANT,OPR_SYMBOL,OPR_LOCAL,
             OPR_REFERENCE,OPR_REGISTER,OPR_COND,OPR_REGSET,
             OPR_SHIFTEROP,OPR_MODEFLAGS,OPR_SPECIALREG,
-            OPR_REGPAIR);
+            OPR_REGPAIR,OPR_FENCEFLAGS);
 
   TOprRec = record
     case typ:TOprType of
@@ -81,6 +81,9 @@ type
 {$ifdef aarch64}
       OPR_SHIFTEROP : (shifterop : tshifterop);
       OPR_COND      : (cc : tasmcond);
+{$endif aarch64}
+{$if defined(riscv32) or defined(riscv64)}
+      OPR_FENCEFLAGS: (fenceflags : TFenceFlags);
 {$endif aarch64}
   end;
 
@@ -1295,6 +1298,10 @@ end;
              OPR_COND:
                ai.loadconditioncode(i-1,cc);
 {$endif arm or aarch64}
+{$if defined(riscv32) or defined(riscv64)}
+             OPR_FENCEFLAGS:
+               ai.loadfenceflags(i-1,fenceflags);
+{$endif riscv32 or riscv64}
               { ignore wrong operand }
               OPR_NONE:
                 ;

+ 624 - 0
compiler/riscv/aasmcpu.pas

@@ -0,0 +1,624 @@
+{
+    Copyright (c) 1999-2002 by Jonas Maebe and Thomas Schatzl
+
+    Contains the assembler object for the Risc-V 32 and Risc-V 64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aasmcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,verbose,
+  aasmbase,aasmtai,aasmdata,aasmsym,
+  cpubase,cgbase,cgutils;
+
+    const
+      { "mov reg,reg" source operand number }
+      O_MOV_SOURCE = 1;
+      { "mov reg,reg" source operand number }
+      O_MOV_DEST = 0;
+
+
+    type
+
+      { taicpu }
+
+      taicpu = class(tai_cpu_abstract_sym)
+         memoryordering: TMemoryOrdering;
+         constructor op_none(op : tasmop);
+
+         constructor op_reg(op : tasmop;_op1 : tregister);
+         constructor op_const(op : tasmop;_op1 : aint);
+
+         constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+         constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+         constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
+         constructor op_const_reg(op:tasmop; _op1: aint; _op2: tregister);
+
+         constructor op_const_const(op : tasmop;_op1,_op2 : aint);
+
+         constructor op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint);
+
+         constructor op_reg_reg_roundingmode(op : tasmop;_op1,_op2 : tregister; _op3: TRoundingMode);
+         constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+         constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
+         constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: aint);
+         constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+         constructor op_const_reg_reg(op : tasmop;_op1 : aint;_op2, _op3 : tregister);
+         constructor op_const_reg_const(op : tasmop;_op1 : aint;_op2 : tregister;_op3 : aint);
+         constructor op_const_const_const(op : tasmop;_op1 : aint;_op2 : aint;_op3 : aint);
+
+         constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+         constructor op_reg_bool_reg_reg(op : tasmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+         constructor op_reg_bool_reg_const(op : tasmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: aint);
+
+         constructor op_reg_reg_reg_const(op : tasmop; _op1, _op2, _op3 : tregister; _op4 : aint);
+         constructor op_reg_reg_reg_const_const(op : tasmop;_op1,_op2,_op3 : tregister;_op4,_op5 : aint);
+         constructor op_reg_reg_const_const_const(op : tasmop;_op1,_op2 : tregister;_op3,_op4,_op5 : aint);
+
+
+         { this is for Jmp instructions }
+         constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+         constructor op_const_const_sym(op : tasmop;_op1,_op2 : aint;_op3: tasmsymbol);
+
+
+         constructor op_sym(op : tasmop;_op1 : tasmsymbol);
+         constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint);
+         constructor op_reg_sym(op : tasmop;_op1 : tregister;_op2:tasmsymbol);
+         constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : aint);
+         constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint;const _op2 : treference);
+
+         procedure loadroundingmode(opidx:aint;_roundmode:TRoundingMode);
+         procedure loadfenceflags(opidx:aint;_flags:TFenceFlags);
+         procedure loadbool(opidx:aint;_b:boolean);
+
+         function is_same_reg_move(regtype: Tregistertype):boolean; override;
+
+         { register spilling code }
+         function spilling_get_operation_type(opnr: longint): topertype;override;
+         function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override;
+      end;
+
+      tai_align = class(tai_align_abstract)
+        { nothing to add }
+      end;
+
+    procedure InitAsm;
+    procedure DoneAsm;
+
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+
+implementation
+
+uses cutils, cclasses;
+
+{*****************************************************************************
+                                 taicpu Constructors
+*****************************************************************************}
+
+    procedure taicpu.loadbool(opidx:aint;_b:boolean);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx]^ do
+         begin
+           if typ=top_ref then
+            dispose(ref);
+           b:=_b;
+           typ:=top_bool;
+         end;
+      end;
+
+
+    constructor taicpu.op_none(op : tasmop);
+      begin
+         inherited create(op);
+      end;
+
+
+    constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadreg(0,_op1);
+      end;
+
+
+    constructor taicpu.op_const(op : tasmop;_op1 : aint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadconst(0,_op1);
+      end;
+
+
+    constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+    constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+     constructor taicpu.op_const_reg(op:tasmop; _op1: aint; _op2: tregister);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
+    constructor taicpu.op_const_const(op : tasmop;_op1,_op2 : aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_reg_const_const(op: tasmop; _op1, _op2: tregister; _op3, _op4: aint);
+      begin
+        inherited create(op);
+        ops := 4;
+        loadreg(0, _op1);
+        loadreg(1, _op2);
+        loadconst(2, _op3);
+        loadconst(3, _op4);
+      end;
+
+
+    constructor taicpu.op_reg_reg_roundingmode(op: tasmop; _op1, _op2: tregister; _op3: TRoundingMode);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadroundingmode(2,_op3);
+      end;
+
+
+    constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+     constructor taicpu.op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+     constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: aint);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadsymbol(2,_op3,_op3ofs);
+      end;
+
+     constructor taicpu.op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+       begin
+         inherited create(op);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadref(2,_op3);
+      end;
+
+    constructor taicpu.op_const_reg_reg(op : tasmop;_op1 : aint;_op2, _op3 : tregister);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+     constructor taicpu.op_const_reg_const(op : tasmop;_op1 : aint;_op2 : tregister;_op3 : aint);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+
+     constructor taicpu.op_const_const_const(op : tasmop;_op1 : aint;_op2 : aint;_op3 : aint);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+         loadconst(2,_op3);
+      end;
+
+
+     constructor taicpu.op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_bool_reg_reg(op : tasmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadbool(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_bool_reg_const(op : tasmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: aint);
+      begin
+         inherited create(op);
+         ops:=4;
+         loadreg(0,_op1);
+         loadbool(0,_op2);
+         loadreg(0,_op3);
+         loadconst(0,cardinal(_op4));
+      end;
+
+     constructor taicpu.op_reg_reg_reg_const(op : tasmop; _op1, _op2, _op3 : tregister; _op4 : aint);
+      begin
+        inherited create(op);
+	ops := 4;
+	loadreg(0, _op1);
+	loadreg(1, _op2);
+	loadreg(2, _op3);
+	loadconst(3, cardinal(_op4));
+      end;
+
+     constructor taicpu.op_reg_reg_reg_const_const(op : tasmop;_op1,_op2,_op3 : tregister;_op4,_op5 : aint);
+      begin
+         inherited create(op);
+         ops:=5;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadconst(3,cardinal(_op4));
+         loadconst(4,cardinal(_op5));
+      end;
+
+     constructor taicpu.op_reg_reg_const_const_const(op : tasmop;_op1,_op2 : tregister;_op3,_op4,_op5 : aint);
+      begin
+         inherited create(op);
+         ops:=5;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,_op3);
+         loadconst(3,_op4);
+         loadconst(4,_op5);
+      end;
+
+    constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         condition:=cond;
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+     constructor taicpu.op_const_const_sym(op : tasmop;_op1,_op2 : aint; _op3: tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,_op1);
+         loadconst(1,_op2);
+         loadsymbol(2,_op3,0);
+      end;
+
+
+    constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,_op1ofs);
+      end;
+
+    constructor taicpu.op_reg_sym(op: tasmop; _op1: tregister; _op2: tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadsymbol(1,_op2,0);
+      end;
+
+
+     constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : aint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadsymbol(1,_op2,_op2ofs);
+      end;
+
+
+    constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:aint;const _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadsymbol(0,_op1,_op1ofs);
+         loadref(1,_op2);
+      end;
+
+
+    procedure taicpu.loadroundingmode(opidx: aint; _roundmode: TRoundingMode);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_roundingmode then
+             clearop(opidx);
+           roundingmode:=_roundmode;
+           typ:=top_roundingmode;
+         end;
+      end;
+
+
+    procedure taicpu.loadfenceflags(opidx: aint; _flags: TFenceFlags);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_fenceflags then
+             clearop(opidx);
+           fenceflags:=_flags;
+           typ:=top_fenceflags;
+         end;
+      end;
+
+
+{ ****************************** newra stuff *************************** }
+
+    function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
+      begin
+        case regtype of
+          R_INTREGISTER:
+            result:=
+               (opcode=A_ADDI) and
+               (oper[0]^.reg=oper[1]^.reg) and
+               (oper[2]^.val=0);
+          R_FPUREGISTER:
+            result:=
+               (opcode in [A_FSGNJ_S,A_FSGNJ_D]) and
+               (oper[0]^.reg=oper[1]^.reg) and
+               (oper[0]^.reg=oper[2]^.reg);
+        end;
+      end;
+
+
+    function taicpu.spilling_get_operation_type(opnr: longint): topertype;
+      begin
+        result := operand_read;
+        case opcode of
+          // U type
+          A_LUI,
+          A_AUIPC:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+
+          // UJ type
+          A_JAL:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+
+          // I type
+          A_JALR,
+          A_LB,A_LH,A_LW,A_LBU,A_LHU,
+          A_ADDI,A_SLTI,A_SLTIU,
+          A_XORI,A_ORI,A_ANDI,
+          A_SLLI,A_SRLI,A_SRAI,
+
+          A_FENCE,A_FENCE_I,
+          A_ECALL,A_EBREAK,
+          A_CSRRW,A_CSRRS,A_CSRRC,A_CSRRWI,A_CSRRSI,A_CSRRCI,
+
+          A_FRCSR,A_FRRM,A_FRFLAGS,A_FSCSR,A_FSRM,
+          A_FSFLAGS,A_FSRMI,A_FSFLAGSI:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+
+          A_FLW,
+          A_FLD:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+
+          // SB type
+          A_Bxx:
+            result:=operand_read;
+
+          // S type
+          A_SB,A_SH,A_SW,
+
+          A_FSW,
+          A_FSD:
+            result:=operand_read;
+
+          // R type
+          A_ADD,A_SUB,A_SLL,A_SLT,A_SLTU,
+          A_XOR,A_OR,A_AND,A_SRL,A_SRA,
+
+          A_MUL,A_MULH,A_MULHSU,A_MULHU,
+          A_DIV,A_DIVU,A_REM,A_REMU,
+
+          A_LR_W,A_SC_W,A_AMOSWAP_W,A_AMOADD_W,A_AMOXOR_W,A_AMOAND_W,
+          A_AMOOR_W,A_AMOMIN_W,A_AMOMAX_W,A_AMOMINU_W,A_AMOMAXU_W,
+
+          A_FADD_S,A_FSUB_S,A_FMUL_S,A_FDIV_S,
+          A_FSQRT_S,A_FSGNJ_S,A_FSGNJN_S,A_FSGNJX_S,
+          A_FMIN_S,A_FMAX_S,
+          A_FMV_X_S,A_FEQ_S,A_FLT_S,A_FLE_S,A_FCLASS_S,
+          A_FCVT_W_S,A_FCVT_WU_S,A_FCVT_S_W,A_FCVT_S_WU,
+          A_FMV_S_X,
+
+          A_FADD_D,A_FSUB_D,A_FMUL_D,A_FDIV_D,
+          A_FSQRT_D,A_FSGNJ_D,A_FSGNJN_D,A_FSGNJX_D,
+          A_FMIN_D,A_FMAX_D,
+          A_FEQ_D,A_FLT_D,A_FLE_D,A_FCLASS_D,
+          A_FCVT_D_S,A_FCVT_S_D,
+          A_FCVT_W_D,A_FCVT_WU_D,A_FCVT_D_W,A_FCVT_D_WU:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+
+          // R4 type
+          A_FMADD_S,A_FMSUB_S,A_FNMSUB_S,A_FNMADD_S,
+
+          A_FMADD_D,A_FMSUB_D,A_FNMSUB_D,A_FNMADD_D:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+{$ifdef RISCV64}
+          A_LR_D,A_SC_D,A_AMOSWAP_D,A_AMOADD_D,A_AMOXOR_D,A_AMOAND_D,
+          A_AMOOR_D,A_AMOMIN_D,A_AMOMAX_D,A_AMOMINU_D,A_AMOMAXU_D,
+
+          A_MULW,
+          A_DIVW,A_DIVUW,A_REMW,A_REMUW,
+
+          A_FCVT_L_S,A_FCVT_LU_S,
+          A_FCVT_S_L,A_FCVT_S_LU,
+
+          A_FCVT_L_D,A_FCVT_LU_D,A_FMV_X_D,
+          A_FCVT_D_L,A_FCVT_D_LU,A_FMV_D_X,
+
+          A_ADDIW,A_SLLIW,A_SRLIW,A_SRAIW,
+          A_ADDW,A_SLLW,A_SRLW,A_SUBW,A_SRAW,
+          A_LD,A_LWU:
+            if opnr=0 then
+              result:=operand_write
+            else
+              result:=operand_read;
+
+          A_SD:
+            result:=operand_read;
+{$endif RISCV64}
+        end;
+      end;
+
+
+    function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;
+      begin
+        result := operand_read;
+      end;
+
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+      begin
+        case getregtype(r) of
+          R_INTREGISTER:
+{$ifdef cpu64bitalu}
+            result:=taicpu.op_reg_ref(A_LD,r,ref);
+{$else cpu64bitalu}
+            result:=taicpu.op_reg_ref(A_LW,r,ref);
+{$endif cpu64bitalu}
+          R_FPUREGISTER:
+            result:=taicpu.op_reg_ref(A_FLD,r,ref);
+          else
+            internalerror(2005123101);
+        end;
+      end;
+
+
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+      begin
+        case getregtype(r) of
+          R_INTREGISTER:
+{$ifdef cpu64bitalu}
+            result:=taicpu.op_reg_ref(A_SD,r,ref);
+{$else cpu64bitalu}
+            result:=taicpu.op_reg_ref(A_SW,r,ref);
+{$endif cpu64bitalu}
+          R_FPUREGISTER:
+            result:=taicpu.op_reg_ref(A_FSD,r,ref);
+          else
+            internalerror(2005123102);
+        end;
+      end;
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+
+begin
+  cai_align:=tai_align;
+  cai_cpu:=taicpu;
+end.
+

+ 253 - 0
compiler/riscv/agrvgas.pas

@@ -0,0 +1,253 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit the GAS asm writers for Risc-V32/Risc-V64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{****************************************************************************}
+{                  Helper routines for Instruction Writer                    }
+{****************************************************************************}
+
+unit agrvgas;
+
+{$i fpcdefs.inc}
+
+  interface
+  
+    uses
+       systems,aasmbase,
+       aasmtai,aasmdata,
+       aggas,
+       assemble,
+       cpubase,cgutils,
+       globtype;
+
+  type
+    TRVInstrWriter=class(TCPUInstrWriter)
+       procedure WriteInstruction(hp : tai);override;
+    end;
+
+    TRVGNUAssembler=class(TGNUassembler)
+      constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+      function MakeCmdLine: TCmdStr; override;
+    end;
+
+  implementation
+
+    uses
+       cutils,globals,verbose,
+       cgbase,
+       itcpugas,cpuinfo,
+       aasmcpu;
+
+
+    function getreferencestring(asminfo: pasminfo; var ref : treference) : string;
+    var
+      s : string;
+    begin
+       with ref do
+        begin
+          if ((offset < -2048) or (offset > 2047)) and
+             (refaddr = addr_no) then
+            internalerror(2006052501);
+          case refaddr of
+            addr_no:
+              s := '';
+            addr_pic_no_got:
+              internalerror(2016060501);
+            else
+              begin
+                s :='';
+                s := s+'(';
+                if assigned(symbol) then
+                  begin
+                    if asminfo^.dollarsign<>'$' then
+                      begin
+                        s:=s+ReplaceForbiddenAsmSymbolChars(symbol.name);
+                        if assigned(relsymbol) then
+                          s:=s+'-'+ReplaceForbiddenAsmSymbolChars(relsymbol.name)
+                      end
+                    else
+                      begin
+                        s:=s+symbol.name;
+                        if assigned(relsymbol) then
+                          s:=s+'-'+relsymbol.name;
+                      end;
+                  end;
+              end;
+          end;
+          if offset<0 then
+           s:=s+tostr(offset)
+          else
+           if (offset>0) then
+            begin
+              if assigned(symbol) then
+                s:=s+'+'+tostr(offset)
+              else
+                s:=s+tostr(offset);
+            end;
+
+           if not(refaddr in [addr_no,addr_pic_no_got]) then
+             begin
+               s := s+')';
+             end;
+{$ifdef cpu64bitaddr}
+           if (refaddr=addr_pic) then
+             s := s + '@got';
+{$endif cpu64bitaddr}
+
+           if (index=NR_NO) then
+             begin
+                if offset=0 then
+                  begin
+                    if not (assigned(symbol)) then
+                      s:=s+'0';
+                  end;
+                if (base<>NR_NO) then
+                  s:=s+'('+gas_regname(base)+')'
+                else if not assigned(symbol) then
+                  s:=s+'(0)';
+             end
+           else if (index<>NR_NO) and (base<>NR_NO) then
+             begin
+               if (offset=0) then
+                 s:=s+gas_regname(base)+','+gas_regname(index)
+               else
+                 internalerror(2006052502);
+             end;
+
+           case refaddr of
+             addr_lo12: s:='%lo'+s;
+             addr_hi20: s:='%hi'+s;
+             addr_pcrel_lo12: s:='%pcrel_lo'+s;
+             addr_pcrel_hi20: s:='%pcrel_hi'+s;
+           end;
+        end;
+      getreferencestring:=s;
+    end;
+
+
+    function getopstr(asminfo: pasminfo; const o:toper) : string;
+    var
+      hs : string;
+    begin
+      case o.typ of
+        top_reg:
+          getopstr:=gas_regname(o.reg);
+        top_const:
+          getopstr:=tostr(longint(o.val));
+        top_ref:
+          if o.ref^.refaddr=addr_full then
+            begin
+              hs:=o.ref^.symbol.name;
+              if asminfo^.dollarsign<>'$' then
+                hs:=ReplaceForbiddenAsmSymbolChars(hs);
+              if o.ref^.offset>0 then
+               hs:=hs+'+'+tostr(o.ref^.offset)
+              else
+               if o.ref^.offset<0 then
+                hs:=hs+tostr(o.ref^.offset);
+              getopstr:=hs;
+            end
+          else
+            getopstr:=getreferencestring(asminfo,o.ref^);
+        top_fenceflags:
+          begin
+            getopstr:='';
+            if ffI in o.fenceflags then getopstr:=getopstr+'i';
+            if ffO in o.fenceflags then getopstr:=getopstr+'o';
+            if ffR in o.fenceflags then getopstr:=getopstr+'r';
+            if ffW in o.fenceflags then getopstr:=getopstr+'w';
+          end;
+        top_roundingmode:
+          getopstr:=roundingmode2str[o.roundingmode];
+        else
+          internalerror(2002070604);
+      end;
+    end;
+
+
+    Procedure TRVInstrWriter.WriteInstruction(hp : tai);
+    var op: TAsmOp;
+        s: string;
+        i: byte;
+        sep: string[3];
+    begin
+      s:=#9+gas_op2str[taicpu(hp).opcode];
+
+      if taicpu(hp).condition<>C_None then
+        s:=s+cond2str[taicpu(hp).condition];
+
+      if taicpu(hp).memoryordering<>[] then
+        begin
+          s:=s+'.';
+          if moAq in taicpu(hp).memoryordering then s:=s+'aq';
+          if moRl in taicpu(hp).memoryordering then s:=s+'rl';
+        end;
+
+      if taicpu(hp).ops<>0 then
+        begin
+          sep:=#9;
+          for i:=0 to taicpu(hp).ops-1 do
+            begin
+               s:=s+sep+getopstr(owner.asminfo,taicpu(hp).oper[i]^);
+               sep:=',';
+            end;
+        end;
+
+      owner.writer.AsmWriteLn(s);
+    end;
+
+
+{****************************************************************************}
+{                         GNU RiscV Assembler writer                           }
+{****************************************************************************}
+
+    constructor TRVGNUAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited;
+        InstrWriter := TRVInstrWriter.create(self);
+      end;
+
+
+    function TRVGNUAssembler.MakeCmdLine: TCmdStr;
+      begin
+        result := inherited MakeCmdLine;
+        Replace(result,'$ARCH',lower(cputypestr[current_settings.cputype]));
+      end;
+
+
+  const
+    as_riscv_gas_info : tasminfo =
+       (
+         id     : as_gas;
+
+         idtxt  : 'AS';
+         asmbin : 'as';
+         asmcmd : '-o $OBJ $EXTRAOPT -march=$ARCH $ASM';
+         supported_targets : [system_riscv32_linux,system_riscv64_linux];
+         flags : [af_needar,af_smartlink_sections];
+         labelprefix : '.L';
+         comment : '# ';
+         dollarsign: '$';
+       );
+
+begin
+  RegisterAssembler(as_riscv_gas_info,TRVGNUAssembler);
+end.

+ 758 - 0
compiler/riscv/cgrv.pas

@@ -0,0 +1,758 @@
+{
+    Copyright (c) 2006 by Florian Klaempfl
+
+    This unit implements the common part of the code generator for the Risc-V
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cgrv;
+
+{$i fpcdefs.inc}
+  interface
+
+    uses
+       globtype,symtype,symdef,
+       cgbase,cgobj,
+       aasmbase,aasmcpu,aasmtai,aasmdata,
+       cpubase,cpuinfo,cgutils,rgcpu,
+       parabase;
+
+    type
+
+      { tcgrv }
+
+      tcgrv = class(tcg)
+        procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
+
+        procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
+
+        procedure a_call_reg(list : TAsmList;reg: tregister); override;
+        procedure a_call_name(list : TAsmList;const s : string; weak: boolean); override;
+
+        procedure a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); override;
+        procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize; reg: tregister; const ref: treference); override;
+        procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+        procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;            
+
+        procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
+        procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
+
+        procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister); override;
+        procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
+
+        procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
+
+        procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; l : tasmlabel); override;
+        procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
+
+        procedure a_jmp_name(list : TAsmList;const s : string); override;
+        procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;          
+
+        procedure g_save_registers(list: TAsmList); override;
+        procedure g_restore_registers(list: TAsmList); override;
+
+        procedure g_profilecode(list: TAsmList); override;
+
+        { fpu move instructions }
+        procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
+        procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
+        procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
+
+        procedure g_check_for_fpu_exception(list: TAsmList); override;
+      protected
+        function  fixref(list: TAsmList; var ref: treference): boolean;
+        procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+      end;
+
+  const
+    TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_NONE,
+                         C_LT,C_GE,C_None,C_NE,C_NONE,C_LTU,C_GEU,C_NONE);
+
+  const
+    TOpCG2AsmConstOp: Array[topcg] of TAsmOp = (A_NONE,
+          A_NONE,A_ADDI,A_ANDI,A_NONE,A_NONE,A_NONE,A_NONE,
+          A_None,A_None,A_ORI,A_SRAI,A_SLLI,A_SRLI,A_NONE,A_XORI,A_None,A_None);
+    TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,
+          A_NONE,A_ADD,A_AND,A_DIVU,A_DIV,A_MUL,A_MUL,
+          A_None,A_None,A_OR,A_SRA,A_SLL,A_SRL,A_SUB,A_XOR,A_None,A_None);
+
+
+  implementation
+
+    uses
+       {$ifdef extdebug}sysutils,{$endif}
+       globals,verbose,systems,cutils,
+       symconst,symsym,symtable,fmodule,
+       rgobj,tgobj,cpupi,procinfo,paramgr;
+
+
+    procedure tcgrv.a_call_name(list : TAsmList;const s : string; weak: boolean);
+      var
+        href: treference;
+        l: TAsmLabel;
+      begin
+        if not(weak) then
+          reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[])
+        else
+          reference_reset_symbol(href,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+
+        current_asmdata.getjumplabel(l);
+
+        a_label(list,l);
+
+        href.refaddr:=addr_pcrel_hi20;
+        list.concat(taicpu.op_reg_ref(A_AUIPC,NR_RETURN_ADDRESS_REG,href));
+
+        reference_reset_symbol(href,l,0,0,[]);
+        href.refaddr:=addr_pcrel_lo12;
+        list.concat(taicpu.op_reg_reg_ref(A_JALR,NR_RETURN_ADDRESS_REG,NR_RETURN_ADDRESS_REG,href));
+
+        { not assigned while generating external wrappers }
+        if assigned(current_procinfo) then
+          include(current_procinfo.flags,pi_do_call);
+      end;
+
+
+    procedure tcgrv.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
+      begin
+        if a=0 then
+          a_load_reg_ref(list,size,size,NR_X0,ref)
+        else
+          inherited a_load_const_ref(list, size, a, ref);
+      end;
+
+
+    procedure tcgrv.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara);
+      var
+        ref: treference;
+        tmpreg: tregister;
+
+      begin
+        paraloc.check_simple_location;
+        paramanager.allocparaloc(list,paraloc.location);
+        case paraloc.location^.loc of
+           LOC_REGISTER,LOC_CREGISTER:
+             a_loadaddr_ref_reg(list,r,paraloc.location^.register);
+           LOC_REFERENCE:
+             begin
+               reference_reset(ref,paraloc.alignment,[]);
+               ref.base := paraloc.location^.reference.index;
+               ref.offset := paraloc.location^.reference.offset;
+               tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
+               a_loadaddr_ref_reg(list,r,tmpreg);
+               a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
+             end;
+           else
+             internalerror(2002080701);
+        end;
+      end;
+
+
+    procedure tcgrv.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
+      begin
+        internalerror(2016060401);
+      end;       
+
+
+    procedure tcgrv.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
+      begin
+        a_op_const_reg_reg(list,op,size,a,reg,reg);
+      end;
+
+
+    procedure tcgrv.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
+      begin
+        a_op_reg_reg_reg(list,op,size,src,dst,dst);
+      end;
+
+
+    procedure tcgrv.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
+      var
+        tmpreg: TRegister;
+      begin
+        optimize_op_const(size,op,a);
+
+        if op=OP_NONE then
+          begin
+            a_load_reg_reg(list,size,size,src,dst);
+            exit;
+          end;
+
+        if op=OP_SUB then
+          begin
+            op:=OP_ADD;
+            a:=-a;
+          end;
+
+{$ifdef RISCV64}
+        if (op=OP_SHL) and
+               (size=OS_S32) then
+          begin
+            list.concat(taicpu.op_reg_reg_const(A_SLLIW,dst,src,a));
+            maybeadjustresult(list,op,size,dst);
+          end
+        else if (op=OP_SHR) and
+               (size=OS_S32) then
+          begin
+            list.concat(taicpu.op_reg_reg_const(A_SRLIW,dst,src,a));
+            maybeadjustresult(list,op,size,dst);
+          end
+        else if (op=OP_SAR) and
+               (size=OS_S32) then
+          begin
+            list.concat(taicpu.op_reg_reg_const(A_SRAIW,dst,src,a));
+            maybeadjustresult(list,op,size,dst);
+          end
+        else
+{$endif RISCV64}
+        if (TOpCG2AsmConstOp[op]<>A_None) and
+           is_imm12(a) then
+          begin
+            list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a));
+            maybeadjustresult(list,op,size,dst);
+          end
+        else
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_const_reg(list,size,a,tmpreg);
+            a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
+          end;
+      end;   
+
+
+    procedure tcgrv.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
+      begin
+        if op=OP_NOT then
+          begin
+            list.concat(taicpu.op_reg_reg_const(A_XORI,dst,src1,-1));
+            maybeadjustresult(list,op,size,dst);
+          end
+        else if op=OP_NEG then
+          begin
+            list.concat(taicpu.op_reg_reg_reg(A_SUB,dst,NR_X0,src1));
+            maybeadjustresult(list,op,size,dst);
+          end
+        else
+          case op of
+            OP_MOVE:
+              a_load_reg_reg(list,size,size,src1,dst);
+          else
+{$ifdef RISCV64}
+            if (op=OP_SHL) and
+               (size=OS_S32) then
+              begin
+                list.concat(taicpu.op_reg_reg_reg(A_SLLW,dst,src2,src1));
+                maybeadjustresult(list,op,size,dst);
+              end
+            else if (op=OP_SHR) and
+               (size=OS_S32) then
+              begin
+                list.concat(taicpu.op_reg_reg_reg(A_SRLW,dst,src2,src1));
+                maybeadjustresult(list,op,size,dst);
+              end
+            else if (op=OP_SAR) and
+               (size=OS_S32) then
+              begin
+                list.concat(taicpu.op_reg_reg_reg(A_SRAW,dst,src2,src1));
+                maybeadjustresult(list,op,size,dst);
+              end
+            else
+{$endif RISCV64}
+              begin
+                list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
+                maybeadjustresult(list,op,size,dst);
+              end;
+          end;
+      end;
+
+
+    procedure tcgrv.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
+      var
+        href: treference;
+        b, tmpreg: TRegister;
+        l: TAsmLabel;
+      begin
+        href:=ref;
+        fixref(list,href);
+
+        if (not assigned(href.symbol)) and
+           (href.offset=0) then
+          a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r)
+        else if (assigned(href.symbol) or
+            (not is_imm12(href.offset))) and
+           (href.base<>NR_NO) then
+          begin
+            b:= href.base;
+
+            current_asmdata.getjumplabel(l);
+            a_label(list,l);
+
+            href.base:=NR_NO;
+            href.refaddr:=addr_pcrel_hi20;
+            list.concat(taicpu.op_reg_ref(A_AUIPC,r,href));
+
+            reference_reset_symbol(href,l,0,0,ref.volatility);
+            href.refaddr:=addr_pcrel_lo12;
+            list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,r,href));
+
+            list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
+          end
+        else if is_imm12(href.offset) and
+           (href.base<>NR_NO) then
+          begin
+            list.concat(taicpu.op_reg_reg_const(A_ADDI,r,href.base,href.offset));
+          end
+        else if (href.refaddr=addr_pcrel) then
+          begin                     
+            tmpreg:=getintregister(list,OS_ADDR);
+
+            b:=href.base;
+            href.base:=NR_NO;
+                                        
+            current_asmdata.getjumplabel(l);
+            a_label(list,l);
+
+            href.refaddr:=addr_pcrel_hi20;
+            list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+
+            reference_reset_symbol(href,l,0,0,ref.volatility);
+            href.refaddr:=addr_pcrel_lo12;
+            list.concat(taicpu.op_reg_reg_ref(A_ADDI,r,tmpreg,href));
+
+            if b<>NR_NO then
+              list.concat(taicpu.op_reg_reg_reg(A_ADD,r,r,b));
+          end
+        else
+          internalerror(2016060504);
+      end;                
+
+
+    procedure tcgrv.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
+      begin
+        if a=0 then
+          a_cmp_reg_reg_label(list,size,cmp_op,NR_X0,reg,l)
+        else
+          inherited;
+      end;
+
+
+    procedure tcgrv.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp; reg1,reg2 : tregister;l : tasmlabel);
+      var
+        tmpreg: TRegister;
+        ai: taicpu;
+      begin
+        if TOpCmp2AsmCond[cmp_op]=C_None then
+          begin
+            cmp_op:=swap_opcmp(cmp_op);
+            tmpreg:=reg1;
+            reg1:=reg2;
+            reg2:=tmpreg;
+          end;
+
+        ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,reg2,reg1,l,0);
+        ai.is_jmp:=true;
+        ai.condition:=TOpCmp2AsmCond[cmp_op];
+        list.concat(ai);
+      end;
+
+
+    procedure tcgrv.a_jmp_name(list : TAsmList;const s : string);
+      var
+        ai: taicpu;
+        href: treference;
+        tmpreg: TRegister;
+        l: TAsmLabel;
+      begin
+        reference_reset_symbol(href,current_asmdata.RefAsmSymbol(s,AT_FUNCTION),0,0,[]);
+
+        tmpreg:=getintregister(list,OS_ADDR);
+
+        current_asmdata.getjumplabel(l);
+        a_label(list,l);
+
+        href.refaddr:=addr_pcrel_hi20;
+        list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+        reference_reset_symbol(href,l,0,0,[]);
+        href.refaddr:=addr_pcrel_lo12;
+        ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+        ai.is_jmp:=true;
+        list.concat(ai);
+
+        //ai:=taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(s));
+        //ai.is_jmp:=true;
+      end;
+
+
+    procedure tcgrv.a_jmp_always(list : TAsmList;l: tasmlabel);
+      var
+        ai: taicpu;
+        {href: treference;
+        tmpreg: TRegister;}
+      begin
+        {reference_reset_symbol(href,l,0,0);
+
+        tmpreg:=getintregister(list,OS_ADDR);    
+
+        current_asmdata.getjumplabel(l);
+        a_label(list,l);
+
+        href.refaddr:=addr_pcrel_hi20;
+        list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+        reference_reset_symbol(href,l,0,0);
+        href.refaddr:=addr_pcrel_lo12;
+        ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+        ai.is_jmp:=true;
+        list.concat(ai);}
+
+        ai:=taicpu.op_reg_sym(A_JAL,NR_X0,l);
+        ai.is_jmp:=true;
+        list.concat(ai);
+       end;
+
+
+    procedure tcgrv.g_save_registers(list: TAsmList);
+      begin
+      end;
+
+
+    procedure tcgrv.g_restore_registers(list: TAsmList);
+      begin
+      end;
+
+
+    procedure tcgrv.g_profilecode(list: TAsmList);
+      begin
+        if target_info.system in [system_riscv32_linux,system_riscv64_linux] then
+          begin
+            list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_X10,NR_RETURN_ADDRESS_REG,0));
+            a_call_name(list,'_mcount',false);
+          end
+        else
+          internalerror(2018092201);
+      end;
+
+
+    procedure tcgrv.a_call_reg(list : TAsmList;reg: tregister);
+      begin
+        list.concat(taicpu.op_reg_reg(A_JALR,NR_RETURN_ADDRESS_REG,reg));
+        include(current_procinfo.flags,pi_do_call);
+      end;
+
+
+    procedure tcgrv.a_load_reg_ref(list: TAsmList; fromsize, tosize: TCGSize;
+        reg: tregister; const ref: treference);
+
+      const
+        StoreInstr: array[OS_8..OS_INT] of TAsmOp =
+        (A_SB,A_SH,A_SW
+{$ifdef cpu64bitalu}
+         ,
+         A_SD
+{$endif cpu64bitalu}
+         );
+      var
+        ref2: TReference;
+        tmpreg: tregister;
+        op: TAsmOp;
+      begin
+        if not (fromsize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2002090904);
+        if not (tosize in [OS_8..OS_INT,OS_S8..OS_SINT]) then
+          internalerror(2002090905);
+
+        tosize:=tcgsize2unsigned[tosize];
+
+        ref2 := ref;
+        fixref(list, ref2);
+
+        op := storeinstr[tcgsize2unsigned[tosize]];
+        list.concat(taicpu.op_reg_ref(op, reg,ref2));
+      end;
+
+
+    procedure tcgrv.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+      var
+        href: treference;
+        op: TAsmOp;
+        tmpreg: TRegister;
+      begin
+        href:=ref;
+        fixref(list,href);
+
+        if href.refaddr=addr_pcrel then
+          begin
+            tmpreg:=getintregister(list,OS_ADDR);
+            a_loadaddr_ref_reg(list,href,tmpreg);
+            reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+          end;
+
+        case fromsize of
+          OS_8: op:=A_LBU;
+          OS_16: op:=A_LHU;
+          OS_S8: op:=A_LB;
+          OS_S16: op:=A_LH;
+{$ifdef RISCV64}
+          OS_32: op:=A_LWU;
+          OS_S32: op:=A_LW;
+          OS_64,
+          OS_S64: op:=A_LD;
+{$else}
+          OS_32,
+          OS_S32: op:=A_LW;
+{$endif}
+        else
+          internalerror(2016060502);
+        end;
+
+        list.concat(taicpu.op_reg_ref(op,reg,href));
+        if (fromsize<>tosize) and (not (tosize in [OS_SINT,OS_INT])) then
+          a_load_reg_reg(list,fromsize,tosize,reg,reg);
+      end;
+
+
+    procedure tcgrv.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
+      begin
+        if a=0 then
+          a_load_reg_reg(list,size,size,NR_X0,register)
+        else
+          begin
+            if is_imm12(a) then
+              list.concat(taicpu.op_reg_reg_const(A_ADDI,register,NR_X0,a))
+            else if is_lui_imm(a) then
+              list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF))
+            else
+              begin
+                if (a and $800)<>0 then
+                  list.concat(taicpu.op_reg_const(A_LUI,register,((a shr 12)+1) and $FFFFF))
+                else
+                  list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF));
+
+                list.concat(taicpu.op_reg_reg_const(A_ADDI,register,register,SarSmallint(a shl 4,4)));
+              end;
+          end;
+      end;
+
+
+    procedure tcgrv.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+      var
+        op: TAsmOp;
+        ai: taicpu;
+
+      const
+        convOp: array[OS_F32..OS_F64,OS_F32..OS_F64] of TAsmOp =
+        ((A_None,A_FCVT_D_S),
+         (A_FCVT_S_D,A_None));
+
+      begin
+        if fromsize<>tosize then
+          begin
+            list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1));
+            g_check_for_fpu_exception(list);
+          end
+        else
+          begin
+            if tosize=OS_F32 then
+              op:=A_FSGNJ_S
+            else
+              op:=A_FSGNJ_D;
+
+            ai:=taicpu.op_reg_reg_reg(op,reg2,reg1,reg1);
+            list.concat(ai);
+            rg[R_FPUREGISTER].add_move_instruction(ai);
+          end;
+      end;
+
+
+    procedure tcgrv.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
+      var
+        href: treference;
+        op: TAsmOp;
+        tmpreg: TRegister;
+        l: TAsmLabel;
+      begin
+        href:=ref;
+        fixref(list,href);      
+
+        if href.refaddr=addr_pcrel then
+          begin
+            tmpreg:=getintregister(list,OS_ADDR);
+            a_loadaddr_ref_reg(list,href,tmpreg);
+            reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+          end;
+
+        if fromsize=OS_F32 then
+          op:=A_FLW
+        else
+          op:=A_FLD;
+
+        list.concat(taicpu.op_reg_ref(op,reg,href));
+
+        if fromsize<>tosize then
+          a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
+      end;
+
+
+    procedure tcgrv.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
+      var
+        href: treference;
+        op: TAsmOp;
+        tmpreg: TRegister;
+      begin
+        href:=ref;
+        fixref(list,href);    
+
+        if href.refaddr=addr_pcrel then
+          begin
+            tmpreg:=getintregister(list,OS_ADDR);
+            a_loadaddr_ref_reg(list,href,tmpreg);
+            reference_reset_base(href,tmpreg,0,ctempposinvalid,0,ref.volatility);
+          end;
+
+        if fromsize<>tosize then
+          begin
+            tmpreg:=getfpuregister(list,tosize);
+            a_loadfpu_reg_reg(list,fromsize,tosize,reg,tmpreg);
+            reg:=tmpreg;
+          end;
+
+        if tosize=OS_F32 then
+          op:=A_FSW
+        else
+          op:=A_FSD;
+
+        list.concat(taicpu.op_reg_ref(op,reg,href));
+      end;
+
+
+    function tcgrv.fixref(list: TAsmList; var ref: treference): boolean;
+      var
+        tmpreg: TRegister;
+        href: treference;
+        l: TAsmLabel;
+      begin
+        result:=true;
+
+        if ref.refaddr=addr_pcrel then
+          exit;
+
+        if assigned(ref.symbol) then
+          begin
+            reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,ref.volatility);
+            ref.symbol:=nil;
+            ref.offset:=0;
+
+            tmpreg:=getintregister(list,OS_INT);
+
+            current_asmdata.getaddrlabel(l);
+            a_label(list,l);
+
+            href.refaddr:=addr_pcrel_hi20;
+            list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+            reference_reset_symbol(href,l,0,0,ref.volatility);
+            href.refaddr:=addr_pcrel_lo12;
+            list.concat(taicpu.op_reg_reg_ref(A_ADDI,tmpreg,tmpreg,href));
+
+            if (ref.index<>NR_NO) and
+               (ref.base<>NR_NO) then
+              begin
+                a_op_reg_reg(list,OP_ADD,OS_INT,ref.base,tmpreg);
+                ref.base:=tmpreg;
+              end
+            else if (ref.index=NR_NO) and
+               (ref.base<>NR_NO) then
+              ref.index:=tmpreg
+            else
+              ref.base:=tmpreg;
+          end
+        else if (ref.index=NR_NO) and
+                (ref.base=NR_NO) then
+          begin              
+            tmpreg:=getintregister(list,OS_INT);
+
+            a_load_const_reg(list, OS_ADDR,ref.offset,tmpreg);
+
+            reference_reset_base(ref,tmpreg,0,ctempposinvalid,ref.alignment,ref.volatility);
+          end;
+
+        if (ref.index<>NR_NO) and
+           (ref.base=NR_NO) then
+          begin
+            ref.base:=ref.index;
+            ref.index:=NR_NO;
+          end;
+
+        if not is_imm12(ref.offset) then
+          begin
+            tmpreg:=getintregister(list,OS_INT);
+            a_load_const_reg(list,OS_INT,ref.offset,tmpreg);
+
+            ref.offset:=0;
+
+            if (ref.index<>NR_NO) and
+               (ref.base<>NR_NO) then
+              begin
+                a_op_reg_reg(list,OP_ADD,OS_INT,ref.index,tmpreg);
+                ref.index:=tmpreg;
+              end
+            else
+              ref.index:=tmpreg;
+          end;
+
+        if (ref.index<>NR_NO) and
+           (ref.base<>NR_NO) then
+          begin
+            tmpreg:=getaddressregister(list);
+            list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
+            ref.base:=tmpreg;
+            ref.index:=NR_NO;
+          end;
+      end;
+
+
+    procedure tcgrv.maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister);
+      const
+        overflowops = [OP_MUL,OP_IMUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
+      begin
+        if (op in overflowops) and
+           (size in [OS_8,OS_S8,OS_16,OS_S16{$ifdef RISCV64},OS_32,OS_S32{$endif RISCV64}]) then
+          a_load_reg_reg(list,OS_INT,size,dst,dst)
+      end;
+
+
+    procedure tcgrv.g_check_for_fpu_exception(list: TAsmList);
+      var
+        r : TRegister;
+        ai: taicpu;
+        l: TAsmLabel;
+      begin
+        if cs_check_fpu_exceptions in current_settings.localswitches then
+          begin
+            r:=getintregister(list,OS_INT);
+            list.concat(taicpu.op_reg(A_FRFLAGS,r));
+            current_asmdata.getjumplabel(l);
+            ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,r,NR_X0,l,0);
+            ai.is_jmp:=true;
+            ai.condition:=C_EQ;
+            list.concat(ai);
+            alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+            cg.a_call_name(current_asmdata.CurrAsmList,'FPC_THROWFPUEXCEPTION',false);
+            dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+            a_label(list,l);
+          end;
+      end;
+
+end.

+ 260 - 0
compiler/riscv/hlcgrv.pas

@@ -0,0 +1,260 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit contains routines high-level code generator support shared by
+    riscv32 and riscv64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit hlcgrv;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globals,
+  aasmdata,
+  symtype,symdef,
+  cgbase,cgutils,hlcgobj,hlcg2ll, parabase;
+
+type
+
+  { thlcgriscv }
+
+  thlcgriscv = class(thlcg2ll)
+   protected
+    procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
+   public
+    procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+    procedure g_external_wrapper(list: TAsmList; procdef: tprocdef; const wrappername, externalname: string; global: boolean); override;
+  end;
+
+implementation
+
+  uses
+    verbose,
+    systems,fmodule,
+    symconst, symsym,
+    aasmbase,aasmtai,aasmcpu,
+    cpubase,globtype,
+    procinfo,cpupi,cgobj,cgrv,
+    defutil;
+
+{ thlcgriscv }
+
+  procedure thlcgriscv.a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tdef; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister);
+    var
+      fromsreg, tosreg: tsubsetregister;
+      restbits: byte;
+    begin
+      { the code below is only valid for big endian }
+      if target_info.endian=endian_little then
+        begin
+         inherited;
+         exit
+        end;
+      restbits:=(sref.bitlen-(loadbitsize-sref.startbit));
+      if is_signed(subsetsize) then
+        begin
+         { sign extend }
+         a_op_const_reg(list,OP_SHL,osuinttype,AIntBits-loadbitsize+sref.startbit,valuereg);
+         a_op_const_reg(list,OP_SAR,osuinttype,AIntBits-sref.bitlen,valuereg);
+        end
+      else
+        begin
+          a_op_const_reg(list,OP_SHL,osuinttype,restbits,valuereg);
+          { mask other bits }
+          if (sref.bitlen<>AIntBits) then
+            a_op_const_reg(list,OP_AND,osuinttype,(aword(1) shl sref.bitlen)-1,valuereg);
+        end;
+      { use subsetreg routine, it may have been overridden with an optimized version }
+      fromsreg.subsetreg:=extra_value_reg;
+      fromsreg.subsetregsize:=OS_INT;
+      { subsetregs always count bits from right to left }
+      fromsreg.startbit:=loadbitsize-restbits;
+      fromsreg.bitlen:=restbits;
+
+      tosreg.subsetreg:=valuereg;
+      tosreg.subsetregsize:=OS_INT;
+      tosreg.startbit:=0;
+      tosreg.bitlen:=restbits;
+
+      a_load_subsetreg_subsetreg(list,subsetsize,subsetsize,fromsreg,tosreg);
+    end;
+
+
+  procedure thlcgriscv.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+    procedure loadvmttor12;
+      var
+        tmpref,
+        href : treference;
+        l : TAsmLabel;
+      begin
+        reference_reset_base(href,voidpointertype,NR_X10,0,ctempposinvalid,sizeof(pint),[]);
+        cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_X5);
+      end;
+
+
+    procedure op_onr12methodaddr;
+      var
+        tmpref,
+        href : treference;
+        l : TAsmLabel;
+      begin
+        if (procdef.extnumber=$ffff) then
+          Internalerror(200006139);
+
+        reference_reset_base(href,voidpointertype,NR_X5,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),ctempposinvalid, sizeof(pint),[]);
+        cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_X5);
+
+        list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_X5));
+      end;
+
+    var
+      make_global : boolean;
+      tmpref , href: treference;
+      l : TAsmLabel;
+      hsym: tsym;
+      paraloc: PCGParaLocation;
+      tmpreg: TRegister;
+    begin
+      if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
+        Internalerror(200006137);
+      if not assigned(procdef.struct) or
+         (procdef.procoptions*[po_classmethod, po_staticmethod,
+           po_methodpointer, po_interrupt, po_iocheck]<>[]) then
+        Internalerror(200006138);
+      if procdef.owner.symtabletype<>ObjectSymtable then
+        Internalerror(200109191);
+
+      make_global:=false;
+      if (not current_module.is_unit) or
+         create_smartlink or
+         (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
+        make_global:=true;
+
+      if make_global then
+        list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0,voidcodepointertype))
+      else
+        list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0,voidcodepointertype));
+
+      { the wrapper might need aktlocaldata for the additional data to
+        load the constant }
+      current_procinfo:=cprocinfo.create(nil);
+
+      { set param1 interface to self  }
+      procdef.init_paraloc_info(callerside);
+      hsym:=tsym(procdef.parast.Find('self'));
+      if not(assigned(hsym) and
+        (hsym.typ=paravarsym)) then
+        internalerror(2010103101);
+      paraloc:=tparavarsym(hsym).paraloc[callerside].location;
+      if assigned(paraloc^.next) then
+        InternalError(2013020101);
+
+      case paraloc^.loc of
+        LOC_REGISTER:
+          begin
+            if is_imm12(ioffset) then
+              cg.a_op_const_reg(list,OP_SUB, paraloc^.size,ioffset,paraloc^.register)
+            else
+              begin
+                cg.a_load_const_reg(list, paraloc^.size, ioffset, NR_X6);
+                cg.a_op_reg_reg(list, OP_SUB, paraloc^.size, NR_X6, paraloc^.register);
+              end;
+          end;
+      else
+        internalerror(2010103102);
+      end;
+
+      { case 4 }
+      if (po_virtualmethod in procdef.procoptions) and
+          not is_objectpascal_helper(procdef.struct) then
+        begin
+          loadvmttor12;
+          op_onr12methodaddr;
+        end
+      else
+        begin                      
+          reference_reset_symbol(href,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION),0,0,[]);
+
+          tmpreg:=NR_X5;
+
+          current_asmdata.getjumplabel(l);
+
+          cg.a_label(list, l);
+
+          href.refaddr:=addr_pcrel_hi20;
+          list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+
+          reference_reset_symbol(href,l,0,0,[]);
+          href.refaddr:=addr_pcrel_lo12;
+          list.concat(taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href));
+
+          //list.concat(taicpu.op_reg_sym(A_JAL,NR_X0,current_asmdata.RefAsmSymbol(procdef.mangledname)));
+        end;
+      list.concatlist(current_procinfo.aktlocaldata);
+
+      current_procinfo.Free;
+      current_procinfo:=nil;
+
+      list.concat(Tai_symbol_end.Createname(labelname));
+    end;
+
+  procedure thlcgriscv.g_external_wrapper(list: TAsmList; procdef: tprocdef; const wrappername, externalname: string; global: boolean);
+    var
+      sym: tasmsymbol;   
+      ai: taicpu;
+      href: treference;
+      tmpreg: TRegister;
+      l: TAsmLabel;
+    begin
+      maybe_new_object_file(list);
+      new_section(list,sec_code,wrappername,target_info.alignment.procalign);
+      if global then
+        begin
+          sym:=current_asmdata.DefineAsmSymbol(wrappername,AB_GLOBAL,AT_FUNCTION,procdef);
+          list.concat(Tai_symbol.Create_global(sym,0));
+        end
+      else
+        begin
+          sym:=current_asmdata.DefineAsmSymbol(wrappername,AB_LOCAL,AT_FUNCTION,procdef);
+          list.concat(Tai_symbol.Create(sym,0));
+        end;
+
+      reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname,AT_FUNCTION),0,0,[]);
+
+      tmpreg:=NR_X5;
+
+      current_asmdata.getjumplabel(l);
+      a_label(list,l);
+
+      href.refaddr:=addr_pcrel_hi20;
+      list.concat(taicpu.op_reg_ref(A_AUIPC,tmpreg,href));
+      reference_reset_symbol(href,l,0,0,[]);
+      href.refaddr:=addr_pcrel_lo12;
+      ai:=taicpu.op_reg_reg_ref(A_JALR,NR_X0,tmpreg,href);
+      ai.is_jmp:=true;
+      list.concat(ai);
+
+      list.concat(Tai_symbol_end.Create(sym));
+    end;
+
+end.
+

+ 417 - 0
compiler/riscv/nrvadd.pas

@@ -0,0 +1,417 @@
+{
+    Copyright (c) 2000-2006 by Florian Klaempfl and Jonas Maebe
+
+    Code generation for add nodes on the Risc-V (32 and 64 bit generic)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit nrvadd;
+
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       node,nadd,ncgadd,cpubase;
+
+    type
+      trvaddnode = class(tcgaddnode)
+        function pass_1: tnode; override;
+      protected                            
+        procedure Cmp(signed: boolean);      
+
+        procedure second_cmpsmallset;override;
+        procedure second_cmpordinal;override;
+        procedure second_cmp64bit; override;
+
+        procedure second_addordinal; override;
+
+        procedure pass_left_and_right;  
+
+        function use_fma: boolean; override;
+
+        procedure second_addfloat;override;
+        procedure second_cmpfloat;override;
+      end;
+
+
+implementation
+
+    uses
+      globtype,systems,
+      cutils,verbose,globals,
+      symconst,symdef,paramgr,
+      aasmbase,aasmtai,aasmdata,aasmcpu,defutil,htypechk,
+      cgbase,cpuinfo,pass_1,pass_2,
+      cpupara,cgcpu,cgutils,procinfo,
+      ncon,nset,
+      ncgutil,tgobj,rgobj,rgcpu,cgobj,hlcgobj;
+
+    procedure trvaddnode.Cmp(signed: boolean);
+      var
+        flabel,tlabel: tasmlabel;
+        op, opi: TAsmOp;
+      begin
+        pass_left_right;
+
+        force_reg_left_right(true,true);
+
+        if nf_swapped in flags then
+          swapleftright;
+
+        location_reset(location,LOC_REGISTER,OS_INT);
+        location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+
+        if signed then op:=A_SLT else op:=A_SLTU;
+        if signed then opi:=A_SLTI else opi:=A_SLTIU;
+
+        case nodetype of
+          equaln:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_imm12(-right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_ADDI,location.register,left.location.register,-right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SUB,location.register,left.location.register,right.location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,location.register,1));
+            end;
+          unequaln:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_imm12(-right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_ADDI,location.register,left.location.register,-right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SUB,location.register,left.location.register,right.location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_SLTU,location.register,NR_X0,location.register));
+            end;
+          ltn:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_imm12(right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,left.location.register,right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+            end;
+          gtn:
+            begin
+              if not (right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if (left.location.loc=LOC_CONSTANT) and
+                 (not is_imm12(left.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if left.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,right.location.register,left.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,right.location.register,left.location.register));
+            end;
+
+          lten:
+            begin
+              if not (right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if (left.location.loc=LOC_CONSTANT) and
+                 (not is_imm12(left.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if left.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,right.location.register,left.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,right.location.register,left.location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,location.register,1));
+            end;
+          gten:
+            begin
+              if not (left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+              if (right.location.loc=LOC_CONSTANT) and
+                 (not is_imm12(right.location.value)) then
+                hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+
+              if right.location.loc=LOC_CONSTANT then
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(opi,location.register,left.location.register,right.location.value))
+              else
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,location.register,1));
+            end;
+        else
+          Internalerror(2016061101);
+        end;
+      end;       
+
+
+    procedure trvaddnode.second_cmpsmallset;
+      begin
+        Cmp(true);
+      end;
+
+
+    procedure trvaddnode.second_cmpordinal;
+      var
+        unsigned: Boolean;
+      begin
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+
+        Cmp(not unsigned);
+      end;
+
+
+    procedure trvaddnode.second_cmp64bit;
+      var
+        unsigned: Boolean;
+      begin
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+
+        Cmp(not unsigned);
+      end;                  
+
+
+    procedure trvaddnode.second_addordinal;
+      var
+        unsigned: boolean;
+      begin
+        { 32x32->64 multiplication }
+        if (nodetype=muln) and
+           is_32bit(left.resultdef) and
+           is_32bit(right.resultdef) and
+           is_64bit(resultdef) then
+          begin
+            unsigned:=not(is_signed(left.resultdef)) or
+                      not(is_signed(right.resultdef));
+            pass_left_right;
+            force_reg_left_right(true,true);
+            { force_reg_left_right can leave right as a LOC_CONSTANT (we can't
+              say "a constant register is okay, but an ordinal constant isn't) }
+            if right.location.loc=LOC_CONSTANT then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true);
+            location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+            location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(A_MUL,location.register,left.location.register,right.location.register));
+          end
+        else
+          inherited second_addordinal;
+      end;
+
+
+    function trvaddnode.pass_1: tnode;
+      begin
+        if (nodetype=muln) and
+           (left.resultdef.typ=orddef) and (left.resultdef.typ=orddef) and
+           (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype])
+{$ifdef cpu32bitalu}
+           and (not (is_64bit(left.resultdef) or
+                     is_64bit(right.resultdef)))
+{$endif cpu32bitalu}
+           then
+          begin
+            result:=nil;
+
+            firstpass(left);
+            firstpass(right);
+
+            expectloc:=LOC_REGISTER;
+          end
+        else if (nodetype=muln) and
+           (not (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype])) and
+           (is_64bit(left.resultdef) or
+            is_64bit(right.resultdef)) then
+          begin
+            result:=first_add64bitint;
+          end
+        else
+          Result:=inherited pass_1;
+
+        if expectloc=LOC_FLAGS then
+          expectloc:=LOC_REGISTER;
+      end;
+
+
+    procedure trvaddnode.pass_left_and_right;
+      begin
+        { calculate the operator which is more difficult }
+        firstcomplex(self);
+
+        { in case of constant put it to the left }
+        if (left.nodetype=ordconstn) then
+         swapleftright;
+
+        secondpass(left);
+        secondpass(right);
+      end;
+
+
+    function trvaddnode.use_fma: boolean;
+      begin
+        Result:=current_settings.fputype in [fpu_fd];
+      end;
+
+
+    procedure trvaddnode.second_addfloat;
+      var
+        op    : TAsmOp;
+        cmpop,
+        singleprec , inv: boolean;
+      begin
+        pass_left_and_right;
+        if (nf_swapped in flags) then
+          swapleftright;
+
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
+
+        cmpop:=false;
+        singleprec:=tfloatdef(left.resultdef).floattype=s32real;
+        inv:=false;
+        case nodetype of
+          addn :
+            if singleprec then
+              op:=A_FADD_S
+            else
+              op:=A_FADD_D;
+          muln :
+            if singleprec then
+              op:=A_FMUL_S
+            else
+            op:=A_FMUL_D;
+          subn :
+            if singleprec then
+              op:=A_FSUB_S
+            else
+              op:=A_FSUB_D;
+          slashn :
+            if singleprec then
+              op:=A_FDIV_S
+            else
+             op:=A_FDIV_D;
+          equaln:
+            begin
+              if singleprec then
+                op:=A_FEQ_S
+              else
+                op:=A_FEQ_D;
+              cmpop:=true;
+            end;
+          unequaln:
+            begin
+              if singleprec then
+                op:=A_FEQ_S
+              else
+                op:=A_FEQ_D;
+              inv:=true;
+              cmpop:=true;
+            end;
+          ltn:
+            begin
+              if singleprec then
+                op:=A_FLT_S
+              else
+                op:=A_FLT_D;
+              cmpop:=true;
+            end;
+          lten:
+            begin
+              if singleprec then
+                op:=A_FLE_S
+              else
+                op:=A_FLE_D;
+              cmpop:=true;
+            end;
+          gtn:
+            begin
+              if singleprec then
+                op:=A_FLT_S
+              else
+                op:=A_FLT_D;
+              swapleftright;
+              cmpop:=true;
+            end;
+          gten:
+            begin
+              if singleprec then
+                op:=A_FLE_S
+              else
+                op:=A_FLE_D;
+              swapleftright;
+              cmpop:=true;
+            end;
+          else
+            internalerror(200403182);
+        end;
+
+        // put both operands in a register
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
+        hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+
+        // initialize de result
+        if not cmpop then
+          begin
+            location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+            location.register := cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+          end
+        else
+         begin
+           location_reset(location,LOC_REGISTER,OS_8);
+           location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+         end;
+
+        // emit the actual operation
+        if not cmpop then
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+            cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+          end
+        else
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+            cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+
+            if inv then
+              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_const(A_XORI,location.register,location.register,1));
+          end;
+      end;
+
+    procedure trvaddnode.second_cmpfloat;
+      begin
+        second_addfloat;
+      end;
+
+end.

+ 178 - 0
compiler/riscv/nrvcnv.pas

@@ -0,0 +1,178 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Risc-V assembler for type converting nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrvcnv;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,ncnv,ncgcnv;
+
+    type
+       trvtypeconvnode = class(tcgtypeconvnode)
+         protected
+         { procedure second_int_to_int;override; }
+         { procedure second_string_to_string;override; }
+         { procedure second_cstring_to_pchar;override; }
+         { procedure second_string_to_chararray;override; }
+         { procedure second_array_to_pointer;override; }
+         { function first_int_to_real: tnode; override; }
+         { procedure second_pointer_to_array;override; }
+         { procedure second_chararray_to_string;override; }
+         { procedure second_char_to_string;override; }
+         { procedure second_int_to_real;override; }
+         { procedure second_real_to_real;override; }
+         { procedure second_cord_to_pointer;override; }
+         { procedure second_proc_to_procvar;override; }
+         { procedure second_bool_to_int;override; }
+          procedure second_int_to_bool;override;
+         { procedure second_load_smallset;override;  }
+         { procedure second_ansistring_to_pchar;override; }
+         { procedure second_pchar_to_string;override; }
+         { procedure second_class_to_intf;override; }
+         { procedure second_char_to_char;override; }
+       end;
+
+
+implementation
+
+   uses
+      verbose,globtype,globals,systems,
+      symconst,symdef,aasmbase,aasmtai,aasmdata,
+      defutil,
+      cgbase,cgutils,pass_1,pass_2,
+      ncgutil,procinfo,
+      cpubase,aasmcpu,
+      rgobj,tgobj,cgobj,hlcgobj;
+
+
+    procedure trvtypeconvnode.second_int_to_bool;
+      var
+        hreg1, hreg2: tregister;
+        opsize: tcgsize;
+        hlabel: tasmlabel;
+        newsize  : tcgsize;
+        href: treference;
+      begin
+        secondpass(left);
+        if codegenerror then
+          exit;
+
+        { Explicit typecasts from any ordinal type to a boolean type }
+        { must not change the ordinal value                          }
+        if (nf_explicit in flags) and
+           not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
+          begin
+             location_copy(location,left.location);
+             newsize:=def_cgsize(resultdef);
+             { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
+             if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
+                ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
+               hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
+             else
+               location.size:=newsize;
+             exit;
+          end;
+
+        location_reset(location, LOC_REGISTER, def_cgsize(resultdef));
+        opsize := def_cgsize(left.resultdef);
+
+        if (left.location.loc in [LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF]) then
+          hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
+
+        case left.location.loc of
+          LOC_CREFERENCE, LOC_REFERENCE, LOC_REGISTER, LOC_CREGISTER:
+          begin
+            if left.location.loc in [LOC_CREFERENCE, LOC_REFERENCE] then
+            begin
+              hreg2 := cg.getintregister(current_asmdata.CurrAsmList, opsize);
+{$ifndef cpu64bitalu}
+              if left.location.size in [OS_64,OS_S64] then
+                begin
+                  cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,left.location.reference,hreg2);
+                  hreg1:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+                  href:=left.location.reference;
+                  inc(href.offset,4);
+                  cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,href,hreg1);
+                  cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,hreg1,hreg2,hreg2);
+                end
+                else
+{$endif not cpu64bitalu}
+                  cg.a_load_ref_reg(current_asmdata.CurrAsmList, opsize, opsize, left.location.reference, hreg2);
+            end
+            else
+              begin
+                hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+{$ifndef cpu64bitalu}
+                if left.location.size in [OS_64,OS_S64] then
+                  begin
+                    hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
+                    cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.register64.reghi,left.location.register64.reglo,hreg2);
+                   end
+                 else
+{$endif not cpu64bitalu}
+                   cg.a_load_reg_reg(current_asmdata.CurrAsmList,opsize,opsize,left.location.register,hreg2);
+               end;
+             hreg1 := cg.getintregister(current_asmdata.CurrAsmList, opsize);
+             current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SLTU, hreg1, NR_X0, hreg2));
+          end;
+          LOC_JUMP:
+          begin
+            hreg1 := cg.getintregister(current_asmdata.CurrAsmList, OS_INT);
+            current_asmdata.getjumplabel(hlabel);
+            cg.a_label(current_asmdata.CurrAsmList, left.location.truelabel);
+            cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 1, hreg1);
+            cg.a_jmp_always(current_asmdata.CurrAsmList, hlabel);
+            cg.a_label(current_asmdata.CurrAsmList, left.location.falselabel);
+            cg.a_load_const_reg(current_asmdata.CurrAsmList, OS_INT, 0, hreg1);
+            cg.a_label(current_asmdata.CurrAsmList, hlabel);
+          end;
+          LOC_FLAGS:
+          begin
+            Internalerror(2016060403);
+          end
+          else
+            internalerror(10062);
+        end;
+        { Now hreg1 is either 0 or 1. For C booleans it must be 0 or -1. }
+        if is_cbool(resultdef) then
+          cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,OS_SINT,hreg1,hreg1);
+
+{$ifndef cpu64bitalu}
+        if (location.size in [OS_64,OS_S64]) then
+          begin
+            location.register64.reglo:=hreg1;
+            location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
+            if (is_cbool(resultdef)) then
+             { reglo is either 0 or -1 -> reghi has to become the same }
+                cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,location.register64.reglo,location.register64.reghi)
+             else
+             { unsigned }
+               cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,location.register64.reghi);
+             end
+             else
+{$endif not cpu64bitalu}
+               location.Register := hreg1;
+      end;
+
+end.

+ 131 - 0
compiler/riscv/nrvcon.pas

@@ -0,0 +1,131 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Code generation for const nodes on the Risc-V
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrvcon;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      ncgcon,cpubase;
+
+    type
+      trvrealconstnode = class(tcgrealconstnode)
+        procedure pass_generate_code;override;
+      end;
+
+
+implementation
+
+    uses
+      verbose,
+      globtype,globals,
+      cpuinfo,
+      aasmbase,aasmtai,aasmdata,symdef,
+      defutil,
+      cgbase,cgutils,
+      procinfo,
+      ncon;
+
+{*****************************************************************************
+                           TARMREALCONSTNODE
+*****************************************************************************}
+
+    procedure trvrealconstnode.pass_generate_code;
+      { I suppose the parser/pass_1 must make sure the generated real  }
+      { constants are actually supported by the target processor? (JM) }
+      const
+        floattype2ait:array[tfloattype] of tairealconsttype=
+          (aitrealconst_s32bit,aitrealconst_s64bit,aitrealconst_s80bit,aitrealconst_s80bit,aitrealconst_s64comp,aitrealconst_s64comp,aitrealconst_s128bit);
+      var
+         lastlabel : tasmlabel;
+         realait : tairealconsttype;
+
+      begin
+        location_reset_ref(location,LOC_CREFERENCE,def_cgsize(resultdef),4);
+        lastlabel:=nil;
+        realait:=floattype2ait[tfloatdef(resultdef).floattype];
+        { const already used ? }
+        if not assigned(lab_real) then
+          begin
+            current_asmdata.getjumplabel(lastlabel);
+            lab_real:=lastlabel;
+            current_procinfo.aktlocaldata.concat(Tai_label.Create(lastlabel));
+            location.reference.symboldata:=current_procinfo.aktlocaldata.last;
+            case realait of
+              aitrealconst_s32bit :
+                begin
+                  current_procinfo.aktlocaldata.concat(tai_realconst.create_s32real(ts32real(value_real)));
+                  { range checking? }
+                  if floating_point_range_check_error and
+                    (tai_realconst(current_procinfo.aktlocaldata.last).value.s32val=MathInf.Value) then
+                    Message(parser_e_range_check_error);
+                end;
+
+              aitrealconst_s64bit :
+                begin
+                  current_procinfo.aktlocaldata.concat(tai_realconst.create_s64real(ts64real(value_real)));
+
+                  { range checking? }
+                  if floating_point_range_check_error and
+                    (tai_realconst(current_procinfo.aktlocaldata.last).value.s64val=MathInf.Value) then
+                    Message(parser_e_range_check_error);
+               end;
+
+              aitrealconst_s80bit :
+                begin
+                  current_procinfo.aktlocaldata.concat(tai_realconst.create_s80real(value_real,tfloatdef(resultdef).size));
+
+                  { range checking? }
+                  if floating_point_range_check_error and
+                    (tai_realconst(current_procinfo.aktlocaldata.last).value.s80val=MathInf.Value) then
+                    Message(parser_e_range_check_error);
+                end;
+{$ifdef cpufloat128}
+              aitrealconst_s128bit :
+                begin
+                  current_procinfo.aktlocaldata.concat(tai_realconst.create_s128real(value_real));
+
+                  { range checking? }
+                  if floating_point_range_check_error and
+                    (tai_realconst(current_procinfo.aktlocaldata.last).value.s128val=MathInf.Value) then
+                    Message(parser_e_range_check_error);
+                end;
+{$endif cpufloat128}
+
+              { the round is necessary for native compilers where comp isn't a float }
+              aitrealconst_s64comp :
+                if (value_real>9223372036854775807.0) or (value_real<-9223372036854775808.0) then
+                  message(parser_e_range_check_error)
+                else
+                  current_procinfo.aktlocaldata.concat(tai_realconst.create_s64compreal(round(value_real)));
+            else
+              internalerror(2005092401);
+            end;
+          end;
+        location.reference.symbol:=lab_real;
+        location.reference.refaddr:=addr_pcrel;
+      end;
+
+begin
+  crealconstnode:=trvrealconstnode;
+end.

+ 341 - 0
compiler/riscv/nrvinl.pas

@@ -0,0 +1,341 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Risc-V32/64 inline nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrvinl;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       cpubase,
+       node,ninl,ncginl;
+
+    type
+
+       { trvinlinenode }
+
+       trvinlinenode = class(tcginlinenode)
+          { first pass override
+            so that the code generator will actually generate
+            these nodes.
+          }
+          function first_sqrt_real: tnode; override;
+          function first_abs_real: tnode; override;
+          function first_sqr_real: tnode; override;
+          function first_round_real: tnode; override;
+          function first_trunc_real: tnode; override;
+
+          function first_fma: tnode; override;
+
+          procedure second_sqrt_real; override;
+          procedure second_abs_real; override;
+          procedure second_sqr_real; override;
+          procedure second_round_real; override;
+          procedure second_trunc_real; override;
+
+          procedure second_fma; override;
+       protected
+          procedure load_fpu_location;
+       end;
+
+implementation
+
+    uses
+      ncal,
+      cutils,globals,verbose,globtype,
+      aasmtai,aasmdata,aasmcpu,
+      symconst,symdef,
+      defutil,
+      cgbase,pass_2,
+      cpuinfo,ncgutil,
+      hlcgobj,cgutils,cgobj,rgobj,tgobj;
+
+
+{*****************************************************************************
+                              trvinlinenode
+*****************************************************************************}
+
+     function trvinlinenode.first_sqrt_real : tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_sqrt_real := nil;
+           end
+         else
+           result:=inherited first_sqrt_real;
+       end;
+
+
+     function trvinlinenode.first_abs_real : tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_abs_real := nil;
+           end
+         else
+           result:=inherited first_abs_real;
+       end;
+
+
+     function trvinlinenode.first_sqr_real : tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_sqr_real := nil;
+           end
+         else
+           result:=inherited first_sqr_real;
+       end;
+
+
+     function trvinlinenode.first_round_real: tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_round_real := nil;
+           end
+         else
+           result:=inherited first_round_real;
+       end;
+
+
+     function trvinlinenode.first_trunc_real: tnode;
+       begin
+         if (current_settings.fputype >= fpu_fd) then
+           begin
+             expectloc:=LOC_FPUREGISTER;
+             first_trunc_real := nil;
+           end
+         else
+           result:=inherited first_trunc_real;
+       end;
+
+
+     function trvinlinenode.first_fma: tnode;
+       begin
+         Result:=nil;
+       end;
+
+
+     { load the FPU into the an fpu register }
+     procedure trvinlinenode.load_fpu_location;
+       begin
+         location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location.loc := LOC_FPUREGISTER;
+         location.register := cg.getfpuregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
+       end;
+
+
+    procedure trvinlinenode.second_sqrt_real;
+      begin
+        location.loc:=LOC_FPUREGISTER;
+        load_fpu_location;
+        case left.location.size of
+          OS_F32:
+            begin
+              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_S,location.register,
+                left.location.register));
+              cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+            end;
+          OS_F64:
+            begin
+              current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_D,location.register,
+                left.location.register));
+              cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+             end
+          else
+            inherited;
+        end;
+      end;
+
+
+     procedure trvinlinenode.second_abs_real;
+       var
+         op: TAsmOp;
+       begin
+         location.loc:=LOC_FPUREGISTER;
+         load_fpu_location;
+         if (left.location.size = OS_F32) then
+           op := A_FSGNJX_S
+         else
+           op := A_FSGNJX_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
+       end;
+
+
+     procedure trvinlinenode.second_sqr_real;
+       var
+         op: tasmop;
+       begin
+         location.loc:=LOC_FPUREGISTER;
+         load_fpu_location;
+         if (left.location.size = OS_F32) then
+           op := A_FMUL_S
+         else
+           op := A_FMUL_D;
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register));
+         cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure trvinlinenode.second_round_real;
+       var
+         op: TAsmOp;
+       begin
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+         { convert to signed integer rounding towards zero (there's no "round to
+           integer using current rounding mode") }
+
+{$ifdef RISCV32}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_W_S
+         else
+           op := A_FCVT_W_D;
+{$else}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_L_S
+         else
+           op := A_FCVT_L_D;
+{$endif}
+
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register));
+         cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure trvinlinenode.second_trunc_real;
+       var
+         op: TAsmOp;
+       begin
+         secondpass(left);
+         hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+         { convert to signed integer rounding towards zero (there's no "round to
+           integer using current rounding mode") }
+
+{$ifdef RISCV32}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_W_S
+         else
+           op := A_FCVT_W_D;
+{$else}
+         if (left.location.size = OS_F32) then
+           op := A_FCVT_L_S
+         else
+           op := A_FCVT_L_D;
+{$endif}
+
+         current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_roundingmode(op,location.register,left.location.register,RM_RTZ));
+         cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+       end;
+
+
+     procedure trvinlinenode.second_fma;
+       const
+         op : array[os_f32..os_f64,false..true,false..true] of TAsmOp =
+           (
+            (
+             (A_FMADD_S,A_FMSUB_S),
+             (A_FNMADD_S,A_FNMSUB_S)
+            ),
+            (
+             (A_FMADD_D,A_FMSUB_D),
+             (A_FNMADD_D,A_FNMSUB_D)
+            )
+           );
+       var
+         paraarray : array[1..3] of tnode;
+         i : integer;
+         negop3,
+         negproduct : boolean;
+       begin
+         if current_settings.fputype in [fpu_fd] then
+           begin
+             negop3:=false;
+             negproduct:=false;
+             paraarray[1]:=tcallparanode(tcallparanode(tcallparanode(parameters).nextpara).nextpara).paravalue;
+             paraarray[2]:=tcallparanode(tcallparanode(parameters).nextpara).paravalue;
+             paraarray[3]:=tcallparanode(parameters).paravalue;
+
+             { check if a neg. node can be removed
+               this is possible because changing the sign of
+               a floating point number does not affect its absolute
+               value in any way
+             }
+             if paraarray[1].nodetype=unaryminusn then
+               begin
+                 paraarray[1]:=tunarynode(paraarray[1]).left;
+                 { do not release the unused unary minus node, it is kept and release together with the other nodes,
+                   only no code is generated for it }
+                 negproduct:=not(negproduct);
+               end;
+
+             if paraarray[2].nodetype=unaryminusn then
+               begin
+                 paraarray[2]:=tunarynode(paraarray[2]).left;
+                 { do not release the unused unary minus node, it is kept and release together with the other nodes,
+                   only no code is generated for it }
+                 negproduct:=not(negproduct);
+               end;
+
+             if paraarray[3].nodetype=unaryminusn then
+               begin
+                 paraarray[3]:=tunarynode(paraarray[3]).left;
+                 { do not release the unused unary minus node, it is kept and release together with the other nodes,
+                   only no code is generated for it }
+                 negop3:=true;
+               end;
+
+              for i:=1 to 3 do
+               secondpass(paraarray[i]);
+
+             { no memory operand is allowed }
+             for i:=1 to 3 do
+               begin
+                 if not(paraarray[i].location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
+                   hlcg.location_force_fpureg(current_asmdata.CurrAsmList,paraarray[i].location,paraarray[i].resultdef,true);
+               end;
+
+             location_reset(location,LOC_FPUREGISTER,paraarray[1].location.size);
+             location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
+
+             current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(op[def_cgsize(resultdef), negproduct,negop3],location.register,paraarray[1].location.register,paraarray[2].location.register,paraarray[2].location.register));
+             cg.g_check_for_fpu_exception(current_asmdata.CurrAsmList);
+           end
+         else
+           internalerror(2014032301);
+       end;
+
+
+begin
+   cinlinenode:=trvinlinenode;
+end.

+ 154 - 0
compiler/riscv/nrvset.pas

@@ -0,0 +1,154 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl and Carl Eric Codere
+
+    Generate Risc-V32/64 assembler for in set/case nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrvset;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       node,nset,ncgset,cpubase,cgbase,cgobj,aasmbase,aasmtai,aasmdata,globtype;
+
+    type
+       trvcasenode = class(tcgcasenode)
+         protected
+           procedure optimizevalues(var max_linear_list : aint; var max_dist : aword);override;
+           function  has_jumptable : boolean;override;
+           procedure genjumptable(hp : pcaselabel;min_,max_ : aint);override;
+       end;
+
+
+implementation
+
+    uses
+      systems,
+      verbose,globals,constexp,
+      symconst,symdef,defutil,
+      paramgr,
+      cpuinfo,
+      pass_2,cgcpu,
+      ncon,
+      tgobj,ncgutil,rgobj,aasmcpu,
+      procinfo,
+      cgutils;
+
+{*****************************************************************************
+                            TCGCASENODE
+*****************************************************************************}
+
+
+    procedure trvcasenode.optimizevalues(var max_linear_list : aint; var max_dist : aword);
+      begin
+        max_linear_list := 3;
+      end;
+    
+
+    function trvcasenode.has_jumptable : boolean;
+      begin
+        has_jumptable:=true;
+      end;
+
+
+    procedure trvcasenode.genjumptable(hp : pcaselabel;min_,max_ : aint);
+      var
+        table : tasmlabel;
+        last : TConstExprInt;
+        indexreg : tregister;
+        href : treference;
+
+        procedure genitem(list:TAsmList;t : pcaselabel);
+          var
+            i : TConstExprInt;
+          begin
+            if assigned(t^.less) then
+              genitem(list,t^.less);
+            { fill possible hole }
+            i:=last+1;
+            while i<=t^._low-1 do
+              begin
+                list.concat(Tai_const.Create_rel_sym(aitconst_32bit,table,elselabel));
+                i:=i+1;
+              end;
+            i:=t^._low;
+            while i<=t^._high do
+              begin
+                list.concat(Tai_const.Create_rel_sym(aitconst_32bit,table,blocklabel(t^.blockid)));
+                i:=i+1;
+              end;
+            last:=t^._high;
+            if assigned(t^.greater) then
+              genitem(list,t^.greater);
+          end;
+
+      begin
+        last:=min_;
+
+        {
+        .l
+          auipc x,hi(tbl-.l)
+          addi x,x,lo(tbl-.l)
+          sll idx,idx,2
+          add idx,idx,x
+          lw idx,idx,lo(tbl-.l)
+          add idx,idx,x
+          jalr x0,idx
+        }
+
+        { make it a 32bit register }
+        // allocate base and index registers register
+        indexreg:= cg.makeregsize(current_asmdata.CurrAsmList, hregister, OS_INT);
+        { indexreg := hregister; }
+        cg.a_load_reg_reg(current_asmdata.CurrAsmList, def_cgsize(opsize), OS_INT, hregister, indexreg);
+        { a <= x <= b <-> unsigned(x-a) <= (b-a) }
+        cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,OS_INT,aint(min_),indexreg);
+        if not(jumptable_no_range) then
+          begin
+             { case expr greater than max_ => goto elselabel }
+             cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_A,aint(max_)-aint(min_),indexreg,elselabel);
+          end;
+        current_asmdata.getjumplabel(table);
+        { create reference, indexreg := indexreg * sizeof(jtentry) (= 4) }
+        cg.a_op_const_reg(current_asmdata.CurrAsmList, OP_MUL, OS_INT, 4, indexreg);
+        reference_reset_symbol(href, table, 0, 4,[]);
+
+        hregister:=cg.getaddressregister(current_asmdata.CurrAsmList);
+        cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,hregister);
+        reference_reset_base(href,hregister,0,ctempposinvalid,4,[]);
+        href.index:=indexreg;
+        indexreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
+        { load table entry }
+        cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,indexreg);
+        { add table base }
+        cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,hregister,indexreg);
+        { jump }
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_JALR,NR_X0, indexreg));
+
+        { generate jump table }
+        current_asmdata.CurrAsmList.concat(cai_align.Create(4));
+        current_asmdata.CurrAsmList.concat(Tai_label.Create(table));
+        genitem(current_asmdata.CurrAsmList,hp);
+      end;
+
+
+begin
+   ccasenode:=trvcasenode;
+end.

+ 126 - 0
compiler/riscv/rgcpu.pas

@@ -0,0 +1,126 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the Risc-V specific class for the register
+    allocator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit rgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+     uses
+       aasmbase,aasmtai,aasmdata,aasmcpu,
+       cgbase,cgutils,
+       cpubase,
+       rgobj;
+
+     type
+       trgcpu = class(trgobj)
+         procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
+         procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
+       end;
+
+       trgintcpu = class(trgcpu)
+       end;
+
+  implementation
+
+    uses
+      verbose, cutils,globtype,
+      cgobj,
+      procinfo;
+
+
+    procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
+      var
+        tmpref : treference;
+        helplist : TAsmList;
+        hreg : tregister;
+        helpins: Taicpu;
+      begin
+        if not is_imm12(spilltemp.offset) then
+          begin
+            helplist:=tasmlist.create;
+
+            if getregtype(tempreg)=R_INTREGISTER then
+              hreg:=tempreg
+            else
+              hreg:=cg.getintregister(helplist,OS_ADDR);
+
+            if (spilltemp.offset and $800)<>0 then
+              helplist.concat(taicpu.op_reg_const(A_LUI,hreg,((spilltemp.offset shr 12)+1) and $FFFFF))
+            else
+              helplist.concat(taicpu.op_reg_const(A_LUI,hreg,(spilltemp.offset shr 12) and $FFFFF));
+            helplist.concat(taicpu.op_reg_reg_const(A_ADDI,hreg,hreg,SarSmallint(spilltemp.offset shl 4,4)));
+
+            helplist.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,hreg,spilltemp.base));
+
+            reference_reset_base(tmpref,hreg,0,ctempposinvalid,sizeof(aint),[]);
+
+            helpins:=spilling_create_load(tmpref,tempreg);
+            helplist.concat(helpins);
+            list.insertlistafter(pos,helplist);
+            helplist.free;
+          end
+        else
+          inherited;
+      end;
+
+
+    procedure trgcpu.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
+      var
+        tmpref   : treference;
+        helplist : tasmlist;
+        hreg     : tregister;
+      begin
+        if not is_imm12(spilltemp.offset) then
+          begin
+            helplist:=tasmlist.create;
+
+            if getregtype(tempreg)=R_INTREGISTER then
+              hreg:=getregisterinline(helplist,[R_SUBWHOLE])
+            else
+              hreg:=cg.getintregister(helplist,OS_ADDR);
+
+            if (spilltemp.offset and $800)<>0 then
+              helplist.concat(taicpu.op_reg_const(A_LUI,hreg,((spilltemp.offset shr 12)+1) and $FFFFF))
+            else
+              helplist.concat(taicpu.op_reg_const(A_LUI,hreg,(spilltemp.offset shr 12) and $FFFFF));
+            helplist.concat(taicpu.op_reg_reg_const(A_ADDI,hreg,hreg,SarSmallint(spilltemp.offset shl 4,4)));
+
+            helplist.concat(taicpu.op_reg_reg_reg(A_ADD,hreg,hreg,spilltemp.base));
+
+            reference_reset_base(tmpref,hreg,0,ctempposinvalid,sizeof(aint),[]);
+
+            helplist.concat(spilling_create_store(tempreg,tmpref));
+            if getregtype(tempreg)=R_INTREGISTER then
+              ungetregisterinline(helplist,hreg);
+
+            list.insertlistafter(pos,helplist);
+            helplist.free;
+          end
+        else
+          inherited;
+      end;
+
+
+end.

+ 77 - 0
compiler/riscv32/aoptcpu.pas

@@ -0,0 +1,77 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit implements the Risc-V32 optimizer object
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+
+Unit aoptcpu;
+
+Interface
+
+{$i fpcdefs.inc}
+
+uses cpubase, aoptobj, aoptcpub, aopt, aasmtai,aasmdata, aasmcpu;
+
+Type
+  TCpuAsmOptimizer = class(TAsmOptimizer)
+    { uses the same constructor as TAopObj }
+    function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+
+    function PostPeepHoleOptsCpu(var p: tai): boolean; override;
+  End;
+
+Implementation
+
+  uses
+    cutils, verbose, cgbase, cgcpu, cgobj;
+
+
+  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+    var
+      next1, next2: tai;
+      l1, l2, shlcount: longint;
+    begin
+      result := false;
+      case p.typ of
+        ait_instruction:
+          begin
+            {case taicpu(p).opcode of
+            end;}
+          end;
+      end;
+    end;
+
+
+  function TCpuAsmOptimizer.PostPeepHoleOptsCpu(var p: tai): boolean;
+    var
+      next1: tai;
+    begin
+      result := false;
+      case p.typ of
+        ait_instruction:
+          begin
+          end;
+      end;
+    end;
+
+begin
+  casmoptimizer:=TCpuAsmOptimizer;
+End.

+ 115 - 0
compiler/riscv32/aoptcpub.pas

@@ -0,0 +1,115 @@
+ {
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains several types and constants necessary for the
+    optimizer to work on the 80x86 architecture
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+Unit aoptcpub; { Assembler OPTimizer CPU specific Base }
+
+{$i fpcdefs.inc}
+
+
+{ enable the following define if memory references can have a scaled index }
+{ define RefsHaveScale}
+
+{ enable the following define if memory references can have a segment }
+{ override                                                            }
+{ define RefsHaveSegment}
+
+Interface
+
+Uses
+  aasmcpu,AOptBase, cpubase;
+
+Type
+
+{ type of a normal instruction }
+  TInstr = Taicpu;
+  PInstr = ^TInstr;
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+{ Info about the conditional registers                                      }
+  TCondRegs = Object
+    Constructor Init;
+    Destructor Done;
+  End;
+
+{ ************************************************************************* }
+{ **************************** TAoptBaseCpu ******************************* }
+{ ************************************************************************* }
+
+  TAoptBaseCpu = class(TAoptBase)
+  End;
+
+
+{ ************************************************************************* }
+{ ******************************* Constants ******************************* }
+{ ************************************************************************* }
+Const
+
+{ the maximum number of things (registers, memory, ...) a single instruction }
+{ changes                                                                    }
+
+  MaxCh = 3;
+
+{ the maximum number of operands an instruction has }
+
+  MaxOps = 5;
+
+{Oper index of operand that contains the source (reference) with a load }
+{instruction                                                            }
+
+  LoadSrc = 1;
+
+{Oper index of operand that contains the destination (register) with a load }
+{instruction                                                                }
+
+  LoadDst = 0;
+
+{Oper index of operand that contains the source (register) with a store }
+{instruction                                                            }
+
+  StoreSrc = 0;
+
+{Oper index of operand that contains the destination (reference) with a load }
+{instruction                                                                 }
+
+  StoreDst = 1;
+
+
+  aopt_uncondjmp = A_JAL;
+  aopt_condjmp = A_Bxx;
+
+Implementation
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+Constructor TCondRegs.init;
+Begin
+End;
+
+Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
+Begin
+End;
+
+End.

+ 40 - 0
compiler/riscv32/aoptcpuc.pas

@@ -0,0 +1,40 @@
+ {
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the processor specific implementation of the
+    assembler optimizer common subexpression elimination object.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aoptcpuc;
+
+Interface
+
+{$i fpcdefs.inc}
+
+Uses
+  AOptCs;
+
+Type
+  TRegInfoCpu = Object(TRegInfo)
+  End;
+
+
+Implementation
+
+End.

+ 40 - 0
compiler/riscv32/aoptcpud.pas

@@ -0,0 +1,40 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the processor specific implementation of the
+    assembler optimizer data flow analyzer.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+Unit aoptcpud;
+
+{$i fpcdefs.inc}
+
+Interface
+
+uses
+  AOptDA;
+
+Type
+  TAOptDFACpu = class(TAOptDFA)
+  End;
+
+Implementation
+
+
+End.

+ 641 - 0
compiler/riscv32/cgcpu.pas

@@ -0,0 +1,641 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the code generator for the Risc-V32
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,symtype,symdef,
+       cgbase,cgobj,cgrv,
+       aasmbase,aasmcpu,aasmtai,aasmdata,
+       cpubase,cpuinfo,cgutils,cg64f32,rgcpu,
+       parabase;
+
+    type
+      tcgrv32 = class(tcgrv)
+        procedure init_register_allocators;override;
+        procedure done_register_allocators;override;
+
+        { move instructions }
+        procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
+
+        { 32x32 to 64 bit multiplication }
+        procedure a_mul_reg_reg_pair(list: TAsmList;size: tcgsize; src1,src2,dstlo,dsthi: tregister); override;
+
+        procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
+        procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
+
+        procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+        procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
+
+        procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
+     end;
+
+     tcg64frv = class(tcg64f32)
+       procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
+       procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
+       procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
+       procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
+     end;
+
+  procedure create_codegen;
+
+  implementation
+
+    uses
+       symtable,
+       globals,verbose,systems,cutils,
+       symconst,symsym,fmodule,
+       rgobj,tgobj,cpupi,procinfo,paramgr;
+
+
+    procedure tcgrv32.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+        rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+          [RS_X10,RS_X11,RS_X12,RS_X13,RS_X14,RS_X15,RS_X16,RS_X17,
+           RS_X31,RS_X30,RS_X29,RS_X28,
+           RS_X5,RS_X6,RS_X7,
+           RS_X3,RS_X4,
+           RS_X9,RS_X27,RS_X26,RS_X25,RS_X24,RS_X23,RS_X22,
+           RS_X21,RS_X20,RS_X19,RS_X18],first_int_imreg,[]);
+        rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
+          [RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,RS_F16,RS_F17,
+           RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
+           RS_F28,RS_F29,RS_F30,RS_F31,
+           RS_F8,RS_F9,
+           RS_F27,
+           RS_F26,RS_F25,RS_F24,RS_F23,RS_F22,RS_F21,RS_F20,RS_F19,RS_F18],first_fpu_imreg,[]);
+      end;
+
+
+    procedure tcgrv32.done_register_allocators;
+      begin
+        rg[R_INTREGISTER].free;
+        rg[R_FPUREGISTER].free;
+        inherited done_register_allocators;
+      end;
+
+
+    procedure tcgrv32.a_load_reg_reg(list : TAsmList;fromsize, tosize : tcgsize;reg1,reg2 : tregister);
+      var
+        ai: taicpu;
+      begin
+        if (fromsize=tosize) or
+           ((tcgsize2unsigned[fromsize]=tcgsize2unsigned[tosize]) and
+            (tcgsize2unsigned[fromsize]=OS_32)) then
+          begin
+            ai:=taicpu.op_reg_reg_const(A_ADDI,reg2,reg1,0);
+            list.concat(ai);
+            rg[R_INTREGISTER].add_move_instruction(ai);
+          end
+        else if fromsize=OS_8 then
+          begin
+            list.Concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$FF))
+          end
+        else
+          begin
+            if tcgsize2size[tosize]<tcgsize2size[fromsize] then
+              fromsize:=tosize;
+
+            if tcgsize2unsigned[fromsize]<>OS_32 then
+              list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(4-tcgsize2size[fromsize])))
+            else
+              a_load_reg_reg(list,fromsize,fromsize,reg1,reg2);
+
+            if tcgsize2unsigned[fromsize]=fromsize then
+              list.Concat(taicpu.op_reg_reg_const(A_SRLI,reg2,reg2,8*(4-tcgsize2size[fromsize])))
+            else
+              list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(4-tcgsize2size[fromsize])));
+          end;
+      end;
+
+
+    procedure tcgrv32.a_mul_reg_reg_pair(list: TAsmList;size: tcgsize; src1,src2,dstlo,dsthi: tregister);
+      var
+        op: tasmop;
+      begin
+        case size of
+          OS_INT:  op:=A_MULHU;
+          OS_SINT: op:=A_MULH;
+        else
+          InternalError(2014061501);
+        end;
+        if (dsthi<>NR_NO) then
+          list.concat(taicpu.op_reg_reg_reg(op,dsthi,src1,src2));
+        { low word is always unsigned }
+        if (dstlo<>NR_NO) then
+          list.concat(taicpu.op_reg_reg_reg(A_MUL,dstlo,src1,src2));
+      end;
+
+
+    procedure tcgrv32.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
+      var
+        regs, fregs: tcpuregisterset;
+        r: TSuperRegister;
+        href: treference;
+        stackcount: longint;
+      begin
+        if not(nostackframe) then
+          begin
+            a_reg_alloc(list,NR_STACK_POINTER_REG);
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              a_reg_alloc(list,NR_FRAME_POINTER_REG);
+
+            reference_reset_base(href,NR_STACK_POINTER_REG,-4,ctempposinvalid,0,[]);
+
+            { Int registers }
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+            if (pi_do_call in current_procinfo.flags) then
+              regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+            stackcount:=0;
+            for r:=RS_X0 to RS_X31 do
+              if r in regs then
+                inc(stackcount,4);
+
+            { Float registers }
+            fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                inc(stackcount,8);
+
+            inc(localsize,stackcount);
+            if not is_imm12(-localsize) then
+              begin
+                if not (RS_RETURN_ADDRESS_REG in regs) then
+                  begin
+                    include(regs,RS_RETURN_ADDRESS_REG);
+                    inc(localsize,4);
+                  end;
+              end;
+
+            stackcount:=0;
+            for r:=RS_X0 to RS_X31 do
+              if r in regs then
+                begin
+                  list.concat(taicpu.op_reg_ref(A_SW,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+                  dec(href.offset,4);
+                end;
+
+            { Float registers }
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                begin
+                  list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+                  dec(href.offset,8);
+                end;              
+
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,0));
+
+            if localsize>0 then
+              begin
+                localsize:=align(localsize,4);
+
+                if is_imm12(-localsize) then
+                  list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
+                else
+                  begin
+                    a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+                    list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+                  end;
+              end;
+          end;
+      end;
+
+
+    procedure tcgrv32.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
+      var
+        r: tsuperregister;
+        regs, fregs: tcpuregisterset;
+        stackcount, localsize: longint;
+        href: treference;
+      begin
+        if not(nostackframe) then
+          begin
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+            if (pi_do_call in current_procinfo.flags) then
+              regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+            stackcount:=0;
+            reference_reset_base(href,NR_STACK_POINTER_REG,-4,ctempposinvalid,0,[]);
+            for r:=RS_X31 downto RS_X0 do
+              if r in regs then
+                dec(href.offset,4);
+
+            { Float registers }
+            fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                dec(stackcount,8);
+
+            localsize:=current_procinfo.calc_stackframe_size+(-href.offset-4);
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,0))
+            else if localsize>0 then
+              begin                     
+                localsize:=align(localsize,4);
+
+                if is_imm12(localsize) then
+                  list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
+                else
+                  begin
+                    if not (RS_RETURN_ADDRESS_REG in regs) then
+                      begin
+                        include(regs,RS_RETURN_ADDRESS_REG);
+                        dec(href.offset,4);
+                        inc(localsize,4);
+                      end;
+
+                    a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+                    list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+                  end;
+              end;
+
+            { Float registers }
+            for r:=RS_F31 downto RS_F0 do
+              if r in fregs then
+                begin
+                  inc(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+                end;
+
+            for r:=RS_X31 downto RS_X0 do
+              if r in regs then
+                begin
+                  inc(href.offset,4);
+                  list.concat(taicpu.op_reg_ref(A_LW,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+                  inc(stackcount);
+                end;
+          end;
+
+        list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
+      end;
+
+
+    procedure tcgrv32.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+      var
+        paraloc1, paraloc2, paraloc3: TCGPara;
+        pd: tprocdef;
+      begin
+        pd:=search_system_proc('MOVE');
+        paraloc1.init;
+        paraloc2.init;
+        paraloc3.init;
+        paramanager.getintparaloc(list, pd, 1, paraloc1);
+        paramanager.getintparaloc(list, pd, 2, paraloc2);
+        paramanager.getintparaloc(list, pd, 3, paraloc3);
+        a_load_const_cgpara(list, OS_SINT, len, paraloc3);
+        a_loadaddr_ref_cgpara(list, dest, paraloc2);
+        a_loadaddr_ref_cgpara(list, Source, paraloc1);
+        paramanager.freecgpara(list, paraloc3);
+        paramanager.freecgpara(list, paraloc2);
+        paramanager.freecgpara(list, paraloc1);
+        alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+        alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+        a_call_name(list, 'FPC_MOVE', false);
+        dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+        dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+        paraloc3.done;
+        paraloc2.done;
+        paraloc1.done;
+      end;
+
+
+    procedure tcgrv32.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
+      var
+        tmpreg1, hreg, countreg: TRegister;
+        src, dst, src2, dst2: TReference;
+        lab:      tasmlabel;
+        Count, count2: aint;
+
+        function reference_is_reusable(const ref: treference): boolean;
+          begin
+            result:=(ref.base<>NR_NO) and (ref.index=NR_NO) and
+               (ref.symbol=nil) and
+               is_imm12(ref.offset);
+          end;
+
+      begin
+        src2:=source;
+        fixref(list,src2);
+
+        dst2:=dest;
+        fixref(list,dst2);
+
+        if len > high(longint) then
+          internalerror(2002072704);
+        { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
+          allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
+          i.e. before secondpass. Other internal procedures request correct stack frame
+          by setting pi_do_call during firstpass, but for this particular one it is impossible.
+          Therefore, if the current procedure is a leaf one, we have to leave it that way. }
+
+        { anybody wants to determine a good value here :)? }
+        if (len > 100) and
+           assigned(current_procinfo) and
+           (pi_do_call in current_procinfo.flags) then
+          g_concatcopy_move(list, src2, dst2, len)
+        else
+        begin
+          Count := len div 4;
+          if (count<=4) and reference_is_reusable(src2) then
+            src:=src2
+          else
+            begin
+              reference_reset(src,sizeof(aint),[]);
+              { load the address of src2 into src.base }
+              src.base := GetAddressRegister(list);
+              a_loadaddr_ref_reg(list, src2, src.base);
+            end;
+          if (count<=4) and reference_is_reusable(dst2) then
+            dst:=dst2
+          else
+            begin
+              reference_reset(dst,sizeof(aint),[]);
+              { load the address of dst2 into dst.base }
+              dst.base := GetAddressRegister(list);
+              a_loadaddr_ref_reg(list, dst2, dst.base);
+            end;
+          { generate a loop }
+          if Count > 4 then
+          begin
+            countreg := GetIntRegister(list, OS_INT);
+            tmpreg1  := GetIntRegister(list, OS_INT);
+            a_load_const_reg(list, OS_INT, Count, countreg);
+            current_asmdata.getjumplabel(lab);
+            a_label(list, lab);
+            list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
+            list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
+            list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 4));
+            list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 4));
+            list.concat(taicpu.op_reg_reg_const(A_ADDI, countreg, countreg, -1));
+            a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_X0,countreg,lab);
+            len := len mod 4;
+          end;
+          { unrolled loop }
+          Count := len div 4;
+          if Count > 0 then
+          begin
+            tmpreg1 := GetIntRegister(list, OS_INT);
+            for count2 := 1 to Count do
+            begin
+              list.concat(taicpu.op_reg_ref(A_LW, tmpreg1, src));
+              list.concat(taicpu.op_reg_ref(A_SW, tmpreg1, dst));
+              Inc(src.offset, 4);
+              Inc(dst.offset, 4);
+            end;
+            len := len mod 4;
+          end;
+          if (len and 4) <> 0 then
+          begin
+            hreg := GetIntRegister(list, OS_INT);
+            a_load_ref_reg(list, OS_32, OS_32, src, hreg);
+            a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
+            Inc(src.offset, 4);
+            Inc(dst.offset, 4);
+          end;
+          { copy the leftovers }
+          if (len and 2) <> 0 then
+          begin
+            hreg := GetIntRegister(list, OS_INT);
+            a_load_ref_reg(list, OS_16, OS_16, src, hreg);
+            a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
+            Inc(src.offset, 2);
+            Inc(dst.offset, 2);
+          end;
+          if (len and 1) <> 0 then
+          begin
+            hreg := GetIntRegister(list, OS_INT);
+            a_load_ref_reg(list, OS_8, OS_8, src, hreg);
+            a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
+          end;
+        end;
+      end;
+
+
+    procedure tcgrv32.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
+      begin
+
+      end;
+
+
+    procedure tcg64frv.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
+      var
+        tmpreg1: TRegister;
+      begin
+        case op of
+          OP_NOT:
+            begin
+              cg.a_op_reg_reg(list,OP_NOT,OS_32,regsrc.reglo,regdst.reglo);
+              cg.a_op_reg_reg(list,OP_NOT,OS_32,regsrc.reghi,regdst.reghi);
+            end;
+          OP_NEG:
+            begin
+              tmpreg1 := cg.GetIntRegister(list, OS_INT);
+              list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reglo, NR_X0, regsrc.reglo));
+              list.concat(taicpu.op_reg_reg_reg(A_SLTU, tmpreg1, NR_X0, regdst.reglo));
+              list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, NR_X0, regsrc.reghi));
+              list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, regdst.reghi, tmpreg1));
+            end;
+          else
+            a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
+        end;
+      end;
+
+
+    procedure tcg64frv.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
+      begin
+        a_op64_const_reg_reg(list,op,size,value,reg,reg);
+      end;
+
+
+    procedure tcg64frv.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
+      var
+        signed: Boolean;
+        tmplo, carry, tmphi, hreg: TRegister;
+      begin
+        case op of
+          OP_AND,OP_OR,OP_XOR:
+            begin
+              cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
+              cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
+            end;
+          OP_ADD:
+            begin
+              signed:=(size in [OS_S64]);
+              tmplo := cg.GetIntRegister(list,OS_S32);
+              carry := cg.GetIntRegister(list,OS_S32);
+              // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
+              list.concat(taicpu.op_reg_reg_reg(A_ADD, tmplo, regsrc2.reglo, regsrc1.reglo));
+              list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmplo, regsrc2.reglo));
+              cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
+              if signed then
+                begin
+                  list.concat(taicpu.op_reg_reg_reg(A_ADD, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
+                  list.concat(taicpu.op_reg_reg_reg(A_ADD, regdst.reghi, regdst.reghi, carry));
+                end
+              else
+                begin
+                  tmphi:=cg.GetIntRegister(list,OS_INT);
+                  hreg:=cg.GetIntRegister(list,OS_INT);
+                  cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
+                  // first add carry to one of the addends
+                  list.concat(taicpu.op_reg_reg_reg(A_ADD, tmphi, regsrc2.reghi, carry));
+                  list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regsrc2.reghi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+                  // then add another addend
+                  list.concat(taicpu.op_reg_reg_reg(A_ADD, regdst.reghi, tmphi, regsrc1.reghi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regdst.reghi, tmphi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+                end;
+            end;
+          OP_SUB:
+            begin
+              signed:=(size in [OS_S64]);
+              tmplo := cg.GetIntRegister(list,OS_S32);
+              carry := cg.GetIntRegister(list,OS_S32);
+              // destreg.reglo could be regsrc1.reglo or regsrc2.reglo
+              list.concat(taicpu.op_reg_reg_reg(A_SUB, tmplo, regsrc2.reglo, regsrc1.reglo));
+              list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reglo,tmplo));
+              cg.a_load_reg_reg(list,OS_INT,OS_INT,tmplo,regdst.reglo);
+              if signed then
+                begin
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, regsrc2.reghi, regsrc1.reghi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, regdst.reghi, carry));
+                end
+              else
+                begin
+                  tmphi:=cg.GetIntRegister(list,OS_INT);
+                  hreg:=cg.GetIntRegister(list,OS_INT);
+                  cg.a_load_const_reg(list,OS_INT,$80000000,hreg);
+                  // first subtract the carry...
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, tmphi, regsrc2.reghi, carry));
+                  list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, regsrc2.reghi, tmphi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+                  // ...then the subtrahend
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, regdst.reghi, tmphi, regsrc1.reghi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SLTU, carry, tmphi, regdst.reghi));
+                  list.concat(taicpu.op_reg_reg_reg(A_SUB, carry, hreg, carry));
+                end;
+            end;
+          else
+            internalerror(2002072801);
+        end;
+      end;
+
+
+    procedure tcg64frv.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
+      var
+        tmplo,carry: TRegister;
+        hisize: tcgsize;
+      begin
+        carry:=NR_NO;
+        if (size in [OS_S64]) then
+          hisize:=OS_S32
+        else
+          hisize:=OS_32;
+
+        case op of
+          OP_AND,OP_OR,OP_XOR:
+            begin
+              cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
+              cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
+            end;
+
+          OP_ADD:
+            begin
+              if lo(value)<>0 then
+                begin
+                  tmplo:=cg.GetIntRegister(list,OS_32);
+                  carry:=cg.GetIntRegister(list,OS_32);
+
+                  if is_imm12(aint(lo(value))) then
+                    list.concat(taicpu.op_reg_reg_const(A_ADDI,tmplo,regsrc.reglo,aint(lo(value))))
+                  else
+                    begin
+                      cg.a_load_const_reg(list,OS_INT,aint(lo(value)),tmplo);
+                      list.concat(taicpu.op_reg_reg_reg(A_ADD,tmplo,tmplo,regsrc.reglo))
+                    end;
+                  list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,tmplo,regsrc.reglo));
+                  cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
+                end
+              else
+                cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
+
+              { With overflow checking and unsigned args, this generates slighly suboptimal code
+               ($80000000 constant loaded twice). Other cases are fine. Getting it perfect does not
+               look worth the effort. }
+              cg.a_op_const_reg_reg(list,OP_ADD,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi);
+              if carry<>NR_NO then
+                cg.a_op_reg_reg_reg(list,OP_ADD,hisize,carry,regdst.reghi,regdst.reghi);
+            end;
+
+          OP_SUB:
+            begin
+              carry:=NR_NO;
+              if lo(value)<>0 then
+                begin
+                  tmplo:=cg.GetIntRegister(list,OS_32);
+                  carry:=cg.GetIntRegister(list,OS_32);
+
+                  if is_imm12(-aint(lo(value))) then
+                    list.concat(taicpu.op_reg_reg_const(A_ADDI,tmplo,regsrc.reglo,-aint(lo(value))))
+                  else
+                    begin
+                      cg.a_load_const_reg(list,OS_INT,aint(lo(value)),tmplo);
+                      list.concat(taicpu.op_reg_reg_reg(A_SUB,tmplo,tmplo,regsrc.reglo))
+                    end;
+                  list.concat(taicpu.op_reg_reg_reg(A_SLTU,carry,regsrc.reglo,tmplo));
+                  cg.a_load_reg_reg(list,OS_32,OS_32,tmplo,regdst.reglo);
+                end
+              else
+                cg.a_load_reg_reg(list,OS_32,OS_32,regsrc.reglo,regdst.reglo);
+
+              cg.a_op_const_reg_reg(list,OP_SUB,hisize,aint(hi(value)),regsrc.reghi,regdst.reghi);
+              if carry<>NR_NO then
+                cg.a_op_reg_reg_reg(list,OP_SUB,hisize,carry,regdst.reghi,regdst.reghi);
+            end;
+        else
+          InternalError(2013050301);
+        end;
+      end;
+
+
+    procedure create_codegen;
+      begin
+        cg := tcgrv32.create;
+        cg64 :=tcg64frv.create;
+      end;
+
+end.

+ 428 - 0
compiler/riscv32/cpubase.pas

@@ -0,0 +1,428 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Contains the base types for the Risc-V32
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+{ This Unit contains the base types for the Risc-V32
+}
+unit cpubase;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  strings,globtype,
+  cutils,cclasses,aasmbase,cpuinfo,cgbase;
+
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+    type
+      TAsmOp=(A_None,
+        { Pseudo instructions }
+        A_NOP,
+        { normal opcodes }
+        A_LUI,A_AUIPC,A_JAL,A_JALR,
+        A_Bxx,A_LB,A_LH,A_LW,A_LBU,A_LHU,
+        A_SB,A_SH,A_SW,
+        A_ADDI,A_SLTI,A_SLTIU,
+        A_XORI,A_ORI,A_ANDI,
+        A_SLLI,A_SRLI,A_SRAI,
+        A_ADD,A_SUB,A_SLL,A_SLT,A_SLTU,
+        A_XOR,A_SRL,A_SRA,A_OR,A_AND,
+        A_FENCE,A_FENCE_I,
+        A_ECALL,A_EBREAK,
+        A_CSRRW,A_CSRRS,A_CSRRC,A_CSRRWI,A_CSRRSI,A_CSRRCI,
+
+        { M-extension }
+        A_MUL,A_MULH,A_MULHSU,A_MULHU,
+        A_DIV,A_DIVU,A_REM,A_REMU,
+
+        { A-extension }
+        A_LR_W,A_SC_W,A_AMOSWAP_W,A_AMOADD_W,A_AMOXOR_W,A_AMOAND_W,
+        A_AMOOR_W,A_AMOMIN_W,A_AMOMAX_W,A_AMOMINU_W,A_AMOMAXU_W,
+
+        { F-extension }
+        A_FLW,A_FSW,
+        A_FMADD_S,A_FMSUB_S,A_FNMSUB_S,A_FNMADD_S,
+        A_FADD_S,A_FSUB_S,A_FMUL_S,A_FDIV_S,
+        A_FSQRT_S,A_FSGNJ_S,A_FSGNJN_S,A_FSGNJX_S,
+        A_FMIN_S,A_FMAX_S,
+        A_FMV_X_S,A_FEQ_S,A_FLT_S,A_FLE_S,A_FCLASS_S,
+        A_FCVT_W_S,A_FCVT_WU_S,A_FCVT_S_W,A_FCVT_S_WU,
+        A_FMV_S_X,
+        A_FRCSR,A_FRRM,A_FRFLAGS,A_FSCSR,A_FSRM,
+        A_FSFLAGS,A_FSRMI,A_FSFLAGSI,
+
+        { D-extension }
+        A_FLD,A_FSD,
+        A_FMADD_D,A_FMSUB_D,A_FNMSUB_D,A_FNMADD_D,
+        A_FADD_D,A_FSUB_D,A_FMUL_D,A_FDIV_D,
+        A_FSQRT_D,A_FSGNJ_D,A_FSGNJN_D,A_FSGNJX_D,
+        A_FMIN_D,A_FMAX_D,
+        A_FEQ_D,A_FLT_D,A_FLE_D,A_FCLASS_D,
+        A_FCVT_D_S,A_FCVT_S_D,
+        A_FCVT_W_D,A_FCVT_WU_D,A_FCVT_D_W,A_FCVT_D_WU,
+
+        { Machine mode }
+        A_MRET,A_HRET,A_SRET,A_URET,
+        A_WFI,
+
+        { Supervisor }
+        A_SFENCE_VM
+        );
+
+      {# This should define the array of instructions as string }
+      op2strtable=array[tasmop] of string[8];
+
+    Const
+      {# First value of opcode enumeration }
+      firstop = low(tasmop);
+      {# Last value of opcode enumeration  }
+      lastop  = high(tasmop);
+
+
+{*****************************************************************************
+                                  Registers
+*****************************************************************************}
+
+    type
+      { Number of registers used for indexing in tables }
+      tregisterindex=0..{$i rrv32nor.inc}-1;
+      totherregisterset = set of tregisterindex;
+
+    const
+      maxvarregs = 32-6; { 32 int registers - r0 - stackpointer - r2 - 3 scratch registers }
+      maxfpuvarregs = 28; { 32 fpuregisters - some scratch registers (minimally 2) }
+      { Available Superregisters }
+      {$i rrv32sup.inc}
+
+      { No Subregisters }
+      R_SUBWHOLE=R_SUBNONE;
+
+      { Available Registers }
+      {$i rrv32con.inc}
+
+      { Integer Super registers first and last }
+      first_int_imreg = $20;
+
+      { Float Super register first and last }
+      first_fpu_imreg     = $20;
+
+      { MM Super register first and last }
+      first_mm_imreg     = $20;
+
+{ TODO: Calculate bsstart}
+      regnumber_count_bsstart = 64;
+
+      regnumber_table : array[tregisterindex] of tregister = (
+        {$i rrv32num.inc}
+      );
+
+      regstabs_table : array[tregisterindex] of shortint = (
+        {$i rrv32sta.inc}
+      );
+
+      regdwarf_table : array[tregisterindex] of shortint = (
+        {$i rrv32dwa.inc}
+      );
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+    type
+      TAsmCond = (C_None { unconditional jumps },
+        C_LT,C_LTU,C_GE,C_GEU,C_NE,C_EQ);
+
+    const
+      cond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+        { conditions when not using ctr decrement etc}
+        'lt','ltu','ge','geu','ne','eq');
+
+      uppercond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+        { conditions when not using ctr decrement etc}
+        'LT','LTU','GE','GEU','NE','EQ');
+
+
+{*****************************************************************************
+                                   Flags
+*****************************************************************************}
+
+    type
+      TResFlagsEnum = (F_EQ,F_NE,F_LT,F_LTU,F_GE,F_GEU);
+
+{*****************************************************************************
+                                Reference
+*****************************************************************************}
+
+{*****************************************************************************
+                                Operand Sizes
+*****************************************************************************}
+
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      max_operands = 5;
+
+
+{*****************************************************************************
+                          Default generic sizes
+*****************************************************************************}
+
+      {# Defines the default address size for a processor, }
+      OS_ADDR = OS_32;
+      {# the natural int size for a processor,
+         has to match osuinttype/ossinttype as initialized in psystem }
+      OS_INT = OS_32;
+      OS_SINT = OS_S32;
+      {# the maximum float size for a processor,           }
+      OS_FLOAT = OS_F64;
+      {# the size of a vector register for a processor     }
+      OS_VECTOR = OS_M128;
+
+{*****************************************************************************
+                               GDB Information
+*****************************************************************************}
+
+
+      stab_regindex : array[tregisterindex] of shortint = (
+        {$i rrv32sta.inc}
+      );
+
+
+{*****************************************************************************
+                          Generic Register names
+*****************************************************************************}
+
+      {# Stack pointer register }
+      NR_STACK_POINTER_REG = NR_X2;
+      RS_STACK_POINTER_REG = RS_X2;
+      {# Frame pointer register }
+      NR_FRAME_POINTER_REG = NR_X8;
+      RS_FRAME_POINTER_REG = RS_X8;
+
+      NR_PIC_OFFSET_REG = NR_X3;
+      { Return address of a function }
+      NR_RETURN_ADDRESS_REG = NR_X1;
+      RS_RETURN_ADDRESS_REG = RS_X1;
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_X10;
+      RS_FUNCTION_RETURN_REG = RS_X10;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_X10;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_X10;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_X11;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_X11;
+      { The value returned from a function is available in this register }
+      NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
+      RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
+      { The lowh part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
+      RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
+      { The high part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
+      RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
+
+      NR_FPU_RESULT_REG = NR_F10;
+      NR_MM_RESULT_REG = NR_NO;
+
+      NR_DEFAULTFLAGS = NR_NO;
+      RS_DEFAULTFLAGS = RS_NO;
+
+
+{*****************************************************************************
+                       GCC /ABI linking information
+*****************************************************************************}
+
+      {# Registers which must be saved when calling a routine declared as
+         cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
+         saved should be the ones as defined in the target ABI and / or GCC.
+
+         This value can be deduced from CALLED_USED_REGISTERS array in the
+         GCC source.
+      }
+      saved_standard_registers : array[0..12] of tsuperregister = (
+        RS_X2,
+        RS_X8,RS_X9,
+        RS_X18,RS_X19,
+        RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27
+      );
+
+      { this is only for the generic code which is not used for this architecture }
+      saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID);
+      saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID);
+
+      {# Required parameter alignment when calling a routine declared as
+         stdcall and cdecl. The alignment value should be the one defined
+         by GCC or the target ABI.
+
+         The value of this constant is equal to the constant
+         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
+      }
+      std_param_align = 4;  { for 32-bit version only }
+
+
+{*****************************************************************************
+                            CPU Dependent Constants
+*****************************************************************************}
+
+      maxfpuregs = 8;
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    function is_imm12(value: aint): boolean;
+    function is_lui_imm(value: aint): boolean;
+
+    function is_calljmp(o:tasmop):boolean;
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+    { Returns the tcgsize corresponding with the size of reg.}
+    function reg_cgsize(const reg: tregister) : tcgsize;
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+    function std_regnum_search(const s:string):Tregister;
+    function std_regname(r:Tregister):string;
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+    function dwarf_reg(r:tregister):shortint;
+
+    function conditions_equal(const c1,c2: TAsmCond): boolean;
+
+implementation
+
+    uses
+      rgbase,verbose;
+
+    const
+      std_regname_table : TRegNameTable = (
+        {$i rrv32std.inc}
+      );
+
+      regnumber_index : array[tregisterindex] of tregisterindex = (
+        {$i rrv32rni.inc}
+      );
+
+      std_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rrv32sri.inc}
+      );
+
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    function is_imm12(value: aint): boolean;
+      begin
+        result:=(value >= -2048) and (value <= 2047);
+      end;
+
+
+    function is_lui_imm(value: aint): boolean;
+      begin
+        result:=SarInt64((value and $FFFFF000) shl 32, 32) = value;
+      end;
+
+
+    function is_calljmp(o:tasmop):boolean;
+      begin
+       is_calljmp:=false;
+        case o of
+          A_JAL,A_JALR,A_Bxx:
+            is_calljmp:=true;
+        end;
+      end;
+
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      const
+        inv_condflags:array[TAsmCond] of TAsmCond=(C_None,
+          C_GE,C_GEU,C_LT,C_LTU,C_EQ,C_NE);
+      begin
+        result := inv_condflags[c];
+      end;
+
+
+    function reg_cgsize(const reg: tregister): tcgsize;
+      begin
+        case getregtype(reg) of
+          R_INTREGISTER :
+            result:=OS_32;
+          R_MMREGISTER:
+            result:=OS_M128;
+          R_FPUREGISTER:
+            result:=OS_F64;
+          else
+            internalerror(200303181);
+        end;
+      end;
+
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+      begin
+        cgsize2subreg:=R_SUBWHOLE;
+      end;
+
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+      begin
+        result:=rgBase.findreg_by_number_table(r,regnumber_index);
+      end;
+
+
+    function std_regnum_search(const s:string):Tregister;
+      begin
+        result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
+      end;
+
+
+    function std_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number_table(r,regnumber_index);
+        if p<>0 then
+          result:=std_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+
+    function dwarf_reg(r:tregister):shortint;
+      begin
+        result:=regdwarf_table[findreg_by_number(r)];
+        if result=-1 then
+          internalerror(200603251);
+      end;
+
+    function conditions_equal(const c1, c2: TAsmCond): boolean;
+      begin
+        result:=c1=c2;
+      end;
+
+end.

+ 135 - 0
compiler/riscv32/cpuinfo.pas

@@ -0,0 +1,135 @@
+{
+    Copyright (c) 1998-2002 by the Free Pascal development team
+
+    Basic Processor information for the Risc-V32
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+Unit CPUInfo;
+
+Interface
+
+  uses
+    globtype;
+
+Type
+   bestreal = double;
+{$if FPC_FULLVERSION>20700}
+   bestrealrec = TDoubleRec;
+{$endif FPC_FULLVERSION>20700}
+   ts32real = single;
+   ts64real = double;
+   ts80real = extended;
+   ts128real = extended;
+   ts64comp = comp;
+
+   pbestreal=^bestreal;
+
+   { possible supported processors for this target }
+   tcputype =
+      (cpu_none,
+       cpu_rv32imafd,
+       cpu_rv32ima,
+       cpu_rv32im,
+       cpu_rv32i
+      );
+
+   tfputype =
+     (fpu_none,  
+      fpu_libgcc,
+      fpu_soft,
+      fpu_fd
+     );
+
+   tcontrollertype =
+     (ct_none
+     );
+
+   tcontrollerdatatype = record
+      controllertypestr, controllerunitstr: string[20];
+      cputype: tcputype; fputype: tfputype;
+      flashbase, flashsize, srambase, sramsize, eeprombase, eepromsize, bootbase, bootsize: dword;
+   end;
+
+
+Const
+   { Is there support for dealing with multiple microcontrollers available }
+   { for this platform? }
+   ControllerSupport = false;
+
+   { We know that there are fields after sramsize
+     but we don't care about this warning }
+   {$PUSH}
+    {$WARN 3177 OFF}
+   embedded_controllers : array [tcontrollertype] of tcontrollerdatatype =
+   (
+      (controllertypestr:''; controllerunitstr:''; cputype:cpu_none; fputype:fpu_none; flashbase:0; flashsize:0; srambase:0; sramsize:0));
+   {$POP}
+
+   { calling conventions supported by the code generator }
+   supported_calling_conventions : tproccalloptions = [
+     pocall_internproc,
+     pocall_stdcall,
+     { the difference to stdcall is only the name mangling }
+     pocall_cdecl,
+     { the difference to stdcall is only the name mangling }
+     pocall_cppdecl,
+     { pass all const records by reference }
+     pocall_mwpascal
+   ];
+
+   cputypestr : array[tcputype] of string[10] = ('',
+     'RV32IMAFD',
+     'RV32IMA',
+     'RV32IM',
+     'RV32I'
+   );
+
+   fputypestr : array[tfputype] of string[8] = (         
+     'LIBGCC',
+     'NONE',
+     'SOFT',
+     'FD'
+   );
+
+   { Supported optimizations, only used for information }
+   supported_optimizerswitches = genericlevel1optimizerswitches+
+                                 genericlevel2optimizerswitches+
+                                 genericlevel3optimizerswitches-
+                                 { no need to write info about those }
+                                 [cs_opt_level1,cs_opt_level2,cs_opt_level3]+
+                                 [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+                                  cs_opt_tailrecursion,cs_opt_reorder_fields,cs_opt_fastmath,
+                                  cs_opt_stackframe];
+
+   level1optimizerswitches = genericlevel1optimizerswitches;
+   level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + [cs_opt_regvar,cs_opt_nodecse,cs_opt_tailrecursion];
+   level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+   level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [cs_opt_stackframe]; 
+
+ type
+   tcpuflags =
+      (CPURV_HAS_MUL,
+       CPURV_HAS_ATOMIC,
+       CPURV_HAS_COMPACT
+      );
+
+ const
+   cpu_capabilities : array[tcputype] of set of tcpuflags =
+     ( { cpu_none      } [],
+       { cpu_rv32imafd } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+       { cpu_rv32ima   } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+       { cpu_rv32im    } [CPURV_HAS_MUL],
+       { cpu_rv32i     } []     
+     );
+
+Implementation
+
+end.

+ 50 - 0
compiler/riscv32/cpunode.pas

@@ -0,0 +1,50 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl
+
+    Includes the Risc-V32 code generator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cpunode;
+
+{$i fpcdefs.inc}
+
+  interface
+
+  implementation
+
+    uses
+       { generic nodes }
+       ncgbas,ncgld,ncgflw,ncgcnv,ncgmem,ncgcon,ncgcal,ncgset,ncginl,ncgopt,
+       ncgobjc,
+       { symtable }
+       symcpu,
+       aasmdef,
+       { to be able to only parts of the generic code,
+         the processor specific nodes must be included
+         after the generic one (FK)
+       }
+       nrv32add,
+       nrv32cal,
+       nrvset,
+       nrvinl,
+       nrv32mat,
+       nrv32cnv
+//       ,nrvcon
+       ;
+
+end.

+ 550 - 0
compiler/riscv32/cpupara.pas

@@ -0,0 +1,550 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    Risc-V32 specific calling conventions
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ****************************************************************************
+}
+unit cpupara;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,
+       aasmtai,aasmdata,
+       cpubase,
+       symconst,symtype,symdef,symsym,
+       paramgr,parabase,cgbase,cgutils;
+
+    type
+       tcpuparamanager = class(tparamanager)
+          function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
+          function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
+          function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
+
+          procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
+          function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
+          function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
+          function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
+         private
+          procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+          function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
+              var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
+       end;
+
+  implementation
+
+    uses
+       cpuinfo,globals,
+       verbose,systems,
+       defutil,symtable,
+       procinfo,cpupi;
+
+
+    function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
+      begin
+        result:=[RS_X0..RS_X31]-[RS_X2,RS_X8..RS_X9,RS_X18..RS_X27];
+      end;
+
+
+    function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
+      begin
+        result:=[RS_F0..RS_F31]-[RS_F8..RS_F9,RS_F18..RS_F27];
+      end;
+
+
+    procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
+      var
+        paraloc : pcgparalocation;
+        psym : tparavarsym;
+        pdef : tdef;
+      begin
+        psym:=tparavarsym(pd.paras[nr-1]);
+        pdef:=psym.vardef;
+        if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
+          pdef:=cpointerdef.getreusable_no_free(pdef);
+        cgpara.reset;
+        cgpara.size:=def_cgsize(pdef);
+        cgpara.intsize:=tcgsize2size[cgpara.size];
+        cgpara.alignment:=get_para_align(pd.proccalloption);
+        cgpara.def:=pdef;
+        paraloc:=cgpara.add_location;
+        with paraloc^ do
+         begin
+           size:=def_cgsize(pdef);
+           def:=pdef;
+           if (nr<=8) then
+             begin
+               if nr=0 then
+                 internalerror(200309271);
+               loc:=LOC_REGISTER;
+               register:=newreg(R_INTREGISTER,RS_X10+nr,R_SUBWHOLE);
+             end
+           else
+             begin
+               loc:=LOC_REFERENCE;
+               paraloc^.reference.index:=NR_STACK_POINTER_REG;
+               reference.offset:=sizeof(pint)*(nr);
+             end;
+          end;
+      end;
+
+
+
+    function getparaloc(p : tdef) : tcgloc;
+
+      begin
+         { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
+           if push_addr_param for the def is true
+         }
+         case p.typ of
+            orddef:
+              result:=LOC_REGISTER;
+            floatdef:
+              if (cs_fp_emulation in current_settings.moduleswitches) or
+                 (current_settings.fputype in [fpu_soft]) then
+                result := LOC_REGISTER
+              else
+                result := LOC_FPUREGISTER;
+            enumdef:
+              result:=LOC_REGISTER;
+            pointerdef:
+              result:=LOC_REGISTER;
+            formaldef:
+              result:=LOC_REGISTER;
+            classrefdef:
+              result:=LOC_REGISTER;
+            procvardef:
+              if (p.size = sizeof(pint)) then
+                result:=LOC_REGISTER
+              else
+                result:=LOC_REFERENCE;
+            recorddef:
+              if (p.size > 4) then
+                result:=LOC_REFERENCE
+              else
+                result:=LOC_REGISTER;
+            objectdef:
+              if is_object(p) then
+                result:=LOC_REFERENCE
+              else
+                result:=LOC_REGISTER;
+            stringdef:
+              if is_shortstring(p) or is_longstring(p) then
+                result:=LOC_REFERENCE
+              else
+                result:=LOC_REGISTER;
+            filedef:
+              result:=LOC_REGISTER;
+            arraydef:
+              if is_dynamic_array(p) then
+                getparaloc:=LOC_REGISTER
+              else
+                result:=LOC_REFERENCE;
+            setdef:
+              if is_smallset(p) then
+                result:=LOC_REGISTER
+              else
+                result:=LOC_REFERENCE;
+            variantdef:
+              result:=LOC_REFERENCE;
+            { avoid problems with errornous definitions }
+            errordef:
+              result:=LOC_REGISTER;
+            else
+              internalerror(2002071001);
+         end;
+      end;
+
+
+    function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
+      begin
+        result:=false;
+        { var,out,constref always require address }
+        if varspez in [vs_var,vs_out,vs_constref] then
+          begin
+            result:=true;
+            exit;
+          end;
+        case def.typ of
+          variantdef,
+          formaldef :
+            result:=true;
+          { regular procvars must be passed by value, because you cannot pass
+            the address of a local stack location when calling e.g.
+            pthread_create with the address of a function (first of all it
+            expects the address of the function to execute and not the address
+            of a memory location containing that address, and secondly if you
+            first store the address on the stack and then pass the address of
+            this stack location, then this stack location may no longer be
+            valid when the newly started thread accesses it.
+
+            However, for "procedure of object" we must use the same calling
+            convention as for "8 byte record" due to the need for
+            interchangeability with the TMethod record type.
+          }
+          procvardef :
+            result:=
+              (def.size <> sizeof(pint));
+          recorddef :
+            result := (def.size > 8) or (varspez = vs_const);
+          arraydef:
+            result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
+                             is_open_array(def) or
+                             is_array_of_const(def) or
+                             is_array_constructor(def);
+          objectdef :
+            result:=is_object(def);
+          setdef :
+            result:=not is_smallset(def);
+          stringdef :
+            result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
+        end;
+      end;
+
+
+    procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+      begin
+        cur_stack_offset:=0;
+        curintreg:=RS_X10;
+        curfloatreg:=RS_F10;
+        curmmreg:=RS_NO;
+      end;
+
+
+    function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+      var
+        paraloc : pcgparalocation;
+        retcgsize  : tcgsize;
+      begin
+        if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
+          exit;
+
+        paraloc:=result.add_location;
+        { Return in FPU register? }
+        if result.def.typ=floatdef then
+          begin
+            paraloc^.loc:=LOC_FPUREGISTER;
+            paraloc^.register:=NR_FPU_RESULT_REG;
+            paraloc^.size:=retcgsize;
+            paraloc^.def:=result.def;
+          end
+        else
+         { Return in register }
+          begin
+            if retcgsize in [OS_64,OS_S64] then
+             begin
+               { low 32bits }
+               paraloc^.loc:=LOC_REGISTER;
+               if side=callerside then
+                 paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
+               else
+                 paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
+               paraloc^.size:=OS_32;
+               paraloc^.def:=u32inttype;
+               { high 32bits }
+               paraloc:=result.add_location;
+               paraloc^.loc:=LOC_REGISTER;
+               if side=callerside then
+                 paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
+               else
+                 paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
+               paraloc^.size:=OS_32;
+               paraloc^.def:=u32inttype;
+             end
+            else
+             begin
+               paraloc^.loc:=LOC_REGISTER;
+               if side=callerside then
+                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
+               else
+                 paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
+               paraloc^.size:=retcgsize;
+               paraloc^.def:=result.def;
+             end;
+          end;
+      end;
+
+
+    function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
+
+      var
+        cur_stack_offset: aword;
+        curintreg, curfloatreg, curmmreg: tsuperregister;
+      begin
+        init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
+
+        result := create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,false);
+
+        create_funcretloc_info(p,side);
+      end;
+
+
+
+    function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
+               var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
+      var
+         stack_offset: longint;
+         paralen: aint;
+         nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
+         locdef,
+         fdef,
+         paradef : tdef;
+         paraloc : pcgparalocation;
+         i  : integer;
+         hp : tparavarsym;
+         loc : tcgloc;
+         paracgsize: tcgsize;
+         firstparaloc: boolean;
+
+      begin
+{$ifdef extdebug}
+         if po_explicitparaloc in p.procoptions then
+           internalerror(200411141);
+{$endif extdebug}
+
+         result:=0;
+         nextintreg := curintreg;
+         nextfloatreg := curfloatreg;
+         nextmmreg := curmmreg;
+         stack_offset := cur_stack_offset;
+         maxfpureg := RS_F17;
+
+          for i:=0 to paras.count-1 do
+            begin
+              hp:=tparavarsym(paras[i]);
+              paradef := hp.vardef;
+              { Syscall for Morphos can have already a paraloc set }
+              if (vo_has_explicit_paraloc in hp.varoptions) then
+                begin
+                  if not(vo_is_syscall_lib in hp.varoptions) then
+                    internalerror(200412153);
+                  continue;
+                end;
+              hp.paraloc[side].reset;
+              { currently only support C-style array of const }
+              if (p.proccalloption in cstylearrayofconst) and
+                 is_array_of_const(paradef) then
+                begin
+                  paraloc:=hp.paraloc[side].add_location;
+                  { hack: the paraloc must be valid, but is not actually used }
+                  paraloc^.loc := LOC_REGISTER;
+                  paraloc^.register := NR_X0;
+                  paraloc^.size := OS_ADDR;
+                  paraloc^.def:=voidpointertype;
+                  break;
+                end;
+
+              if push_addr_param(hp.varspez,paradef,p.proccalloption) then
+                begin
+                  paradef:=cpointerdef.getreusable_no_free(paradef);
+                  loc:=LOC_REGISTER;
+                  paracgsize := OS_ADDR;
+                  paralen := tcgsize2size[OS_ADDR];
+                end
+              else
+                begin
+                  if not is_special_array(paradef) then
+                    paralen := paradef.size
+                  else
+                    paralen := tcgsize2size[def_cgsize(paradef)];
+                  paracgsize:=def_cgsize(paradef);
+                  { for things like formaldef }
+                  if (paracgsize=OS_NO) then
+                    begin
+                      paracgsize:=OS_ADDR;
+                      paralen := tcgsize2size[OS_ADDR];
+                    end;
+                end;
+
+              loc := getparaloc(paradef);
+
+              hp.paraloc[side].alignment:=std_param_align;
+              hp.paraloc[side].size:=paracgsize;
+              hp.paraloc[side].intsize:=paralen;
+              hp.paraloc[side].def:=paradef;
+{$ifndef cpu64bitaddr}
+              if (is_64bit(paradef)) and
+                 odd(nextintreg-RS_X10) then
+                inc(nextintreg);
+{$endif not cpu64bitaddr}
+              if (paralen = 0) then
+                if (paradef.typ = recorddef) then
+                  begin
+                    paraloc:=hp.paraloc[side].add_location;
+                    paraloc^.loc := LOC_VOID;
+                  end
+                else
+                  internalerror(2005011310);
+              locdef:=paradef;
+              firstparaloc:=true;
+              { can become < 0 for e.g. 3-byte records }
+              while (paralen > 0) do
+                begin
+                  paraloc:=hp.paraloc[side].add_location;
+                  { In case of po_delphi_nested_cc, the parent frame pointer
+                    is always passed on the stack. }
+                  if (loc = LOC_REGISTER) and
+                     (nextintreg <= RS_X17) and
+                     (not(vo_is_parentfp in hp.varoptions) or
+                      not(po_delphi_nested_cc in p.procoptions)) then
+                    begin
+                      paraloc^.loc := loc;
+                      { make sure we don't lose whether or not the type is signed }
+                      if (paradef.typ<>orddef) then
+                        begin
+                          paracgsize:=int_cgsize(paralen);
+                          locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
+                        end;
+                      if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
+                        begin
+                          paraloc^.size:=OS_INT;
+                          paraloc^.def:=u32inttype;
+                        end
+                      else
+                        begin
+                          paraloc^.size:=paracgsize;
+                          paraloc^.def:=locdef;
+                        end;
+                      { aix requires that record data stored in parameter
+                        registers is left-aligned }
+                      if (target_info.system in systems_aix) and
+                         (paradef.typ = recorddef) and
+                         (paralen < sizeof(aint)) then
+                        begin
+                          paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
+                          paraloc^.size := OS_INT;
+                          paraloc^.def := u32inttype;
+                        end;
+                      paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
+                      inc(nextintreg);
+                      dec(paralen,tcgsize2size[paraloc^.size]);
+                    end
+                  else if (loc = LOC_FPUREGISTER) and
+                          (nextintreg <= RS_X17) then
+                    begin
+                      paraloc^.loc:=loc;
+                      paraloc^.size := paracgsize;
+                      paraloc^.def := paradef;
+                      paraloc^.register:=newreg(R_FPUREGISTER,nextintreg,R_SUBWHOLE);
+                      inc(nextintreg);
+                      dec(paralen,tcgsize2size[paraloc^.size]);
+                    end
+                  else { LOC_REFERENCE }
+                    begin
+                       paraloc^.loc:=LOC_REFERENCE;
+                       case loc of
+                         LOC_FPUREGISTER:
+                           begin
+                             paraloc^.size:=int_float_cgsize(paralen);
+                             case paraloc^.size of
+                               OS_F32: paraloc^.def:=s32floattype;
+                               OS_F64: paraloc^.def:=s64floattype;
+                               else
+                                 internalerror(2013060124);
+                             end;
+                           end;
+                         LOC_REGISTER,
+                         LOC_REFERENCE:
+                           begin
+                             paraloc^.size:=int_cgsize(paralen);
+                             if paraloc^.size<>OS_NO then
+                               paraloc^.def:=cgsize_orddef(paraloc^.size)
+                             else
+                               paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
+                           end;
+                         else
+                           internalerror(2006011101);
+                       end;
+                       if (side = callerside) then
+                         paraloc^.reference.index:=NR_STACK_POINTER_REG
+                       else
+                         begin
+                           paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+
+                           { create_paraloc_info_intern might be also called when being outside of
+                             code generation so current_procinfo might be not set }
+                           if assigned(current_procinfo) then
+                             trv32procinfo(current_procinfo).needs_frame_pointer := true;
+                         end;
+
+                       paraloc^.reference.offset:=stack_offset;
+
+                       inc(stack_offset,align(paralen,4));
+                       while (paralen > 0) and
+                             (nextintreg < RS_X18) do
+                          begin
+                            inc(nextintreg);
+                            dec(paralen,sizeof(pint));
+                          end;
+                       paralen := 0;
+                    end;
+                  firstparaloc:=false;
+                end;
+            end;
+         curintreg:=nextintreg;
+         curfloatreg:=nextfloatreg;
+         curmmreg:=nextmmreg;
+         cur_stack_offset:=stack_offset;
+         result:=stack_offset;
+      end;
+
+
+    function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
+      var
+        cur_stack_offset: aword;
+        parasize, l: longint;
+        curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
+        i : integer;
+        hp: tparavarsym;
+        paraloc: pcgparalocation;
+      begin
+        init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
+        firstfloatreg:=curfloatreg;
+
+        result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
+        if (p.proccalloption in cstylearrayofconst) then
+          { just continue loading the parameters in the registers }
+          begin
+            result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true);
+           end
+        else
+          begin
+            parasize:=cur_stack_offset;
+            for i:=0 to varargspara.count-1 do
+              begin
+                hp:=tparavarsym(varargspara[i]);
+                hp.paraloc[callerside].alignment:=4;
+                paraloc:=hp.paraloc[callerside].add_location;
+                paraloc^.loc:=LOC_REFERENCE;
+                paraloc^.size:=def_cgsize(hp.vardef);
+                paraloc^.def:=hp.vardef;
+                paraloc^.reference.index:=NR_STACK_POINTER_REG;
+                l:=push_size(hp.varspez,hp.vardef,p.proccalloption);
+                paraloc^.reference.offset:=parasize;
+                parasize:=parasize+l;
+              end;
+            result:=parasize;
+          end;
+        if curfloatreg<>firstfloatreg then
+          include(varargspara.varargsinfo,va_uses_float_reg);
+      end;
+
+begin
+   paramanager:=tcpuparamanager.create;
+end.

+ 123 - 0
compiler/riscv32/cpupi.pas

@@ -0,0 +1,123 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    This unit contains the CPU specific part of tprocinfo
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{ This unit contains the CPU specific part of tprocinfo. }
+unit cpupi;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       cutils,globtype,
+       cgbase,aasmdata,
+       procinfo,cpuinfo,psub;
+
+    type
+      trv32procinfo = class(tcgprocinfo)
+          { for arm thumb, we need to know the stackframe size before
+            starting procedure compilation, so this contains the stack frame size, the compiler
+            should assume
+            if this size is too little the procedure must be compiled again with a larger value }
+          stackframesize,
+          floatregstart : aint;
+          stackpaddingreg: TSuperRegister;
+
+          needs_frame_pointer: boolean;
+          // procedure handle_body_start;override;
+          // procedure after_pass1;override;            
+          constructor create(aparent: tprocinfo); override;
+          procedure set_first_temp_offset;override;
+          function calc_stackframe_size:longint;override;
+      end;
+
+
+  implementation
+
+    uses
+       globals,systems,
+       cpubase,
+       tgobj,
+       symconst,symtype,symsym,symcpu,paramgr,
+       cgutils,
+       cgobj,
+       defutil,
+       aasmcpu;     
+
+
+    constructor trv32procinfo.create(aparent: tprocinfo);
+      begin
+        inherited create(aparent);
+        maxpushedparasize := 0;
+      end;
+
+
+    procedure trv32procinfo.set_first_temp_offset;
+      begin
+        if (po_nostackframe in procdef.procoptions) then
+          begin
+             { maxpushedparasize sghould be zero,
+               if not we will get an error later. }
+             tg.setfirsttemp(maxpushedparasize);
+             exit;
+          end;
+
+        if tg.direction = -1 then
+          tg.setfirsttemp(-(1+12)*4)
+        else
+          tg.setfirsttemp(maxpushedparasize);
+      end;
+
+
+    function trv32procinfo.calc_stackframe_size:longint;
+      var
+         firstfloatreg,lastfloatreg,
+         r : byte;
+         floatsavesize : aword;
+         regs: tcpuregisterset;
+      begin
+        maxpushedparasize:=align(maxpushedparasize,max(current_settings.alignment.localalignmin,4));
+        floatsavesize:=0;
+        case current_settings.fputype of
+          fpu_fd:
+            begin
+              floatsavesize:=0;
+              regs:=cg.rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+              for r:=RS_F0 to RS_F31 do
+                if r in regs then
+                  inc(floatsavesize,8);
+            end;
+        end;
+        floatsavesize:=align(floatsavesize,max(current_settings.alignment.localalignmin,4));
+        result:=Align(tg.direction*tg.lasttemp,max(current_settings.alignment.localalignmin,4))+maxpushedparasize+aint(floatsavesize);
+
+        if tg.direction=1 then
+          floatregstart:=result-aint(floatsavesize)
+        else
+          floatregstart:=-result+maxpushedparasize;
+      end;
+
+
+begin
+   cprocinfo:=trv32procinfo;
+end.
+

+ 84 - 0
compiler/riscv32/cputarg.pas

@@ -0,0 +1,84 @@
+{
+    Copyright (c) 2001-2002 by Peter Vreman
+
+    Includes the Risc-V32 dependent target units
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cputarg;
+
+{$i fpcdefs.inc}
+
+interface
+
+
+implementation
+
+    uses
+      systems { prevent a syntax error when nothing is included }
+
+{**************************************
+             Targets
+**************************************}
+
+    {$ifndef NOTARGETLINUX}
+      ,t_linux
+    {$endif}
+    {$ifndef NOTARGETEMBEDDED}
+      ,t_embed
+    {$endif}
+
+{**************************************
+             Assemblers
+**************************************}
+
+    {$ifndef NOAGRVGAS}
+      ,agrvgas
+    {$endif}
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+  {$ifndef NoRaRVGas}
+       ,rarv32gas
+  {$endif NoRaRVGas}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoDbgStabs}
+      ,dbgstabs
+  {$endif NoDbgStabs}
+  {$ifndef NoDbgStabx}
+      ,dbgstabx
+  {$endif NoDbgStabx}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+
+{**************************************
+             Optimizer
+**************************************}
+
+    {$ifndef NOOPT}
+      , aoptcpu
+    {$endif NOOPT}
+      ;
+
+end.

+ 61 - 0
compiler/riscv32/hlcgcpu.pas

@@ -0,0 +1,61 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit contains high-level code generator support for Risc-V32
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit hlcgcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+  uses
+    aasmdata,
+    symtype,
+    cgbase,cgutils,hlcgobj,hlcgrv;
+
+  type
+    thlcgcpu = class(thlcgriscv)
+    end;
+
+  procedure create_hlcodegen;
+
+implementation
+
+  uses
+    verbose,
+    cpubase,aasmcpu,
+    defutil,
+    cgobj,cgcpu;
+
+
+
+  procedure create_hlcodegen;
+    begin
+      hlcg:=thlcgcpu.create;
+      create_codegen;
+    end;
+
+
+begin
+  chlcgobj:=thlcgcpu;
+end.
+

+ 141 - 0
compiler/riscv32/itcpugas.pas

@@ -0,0 +1,141 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit contains the Risc-V32 GAS instruction tables
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit itcpugas;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cpubase,cgbase;
+
+    const
+      gas_op2str: array[tasmop] of string[14] = ('<none>',
+        'nop',
+        'lui','auipc','jal','jalr',
+        'b','lb','lh','lw','lbu','lhu',
+        'sb','sh','sw',
+        'addi','slti','sltiu',
+        'xori','ori','andi',
+        'slli','srli','srai',
+        'add','sub','sll','slt','sltu',
+        'xor','srl','sra','or','and',
+        'fence','fence.i',
+        'ecall','ebreak',
+        'csrrw','csrrs','csrrc','csrrwi','csrrsi','csrrci',
+
+        { m-extension }
+        'mul','mulh','mulhsu','mulhu',
+        'div','divu','rem','remu',
+
+        { a-extension }
+        'lr.w','sc.w','amoswap.w','amoadd.w','amoxor.w','amoand.w',
+        'amoor.w','amomin.w','amomax.w','amominu.w','amomaxu.w',
+
+        { f-extension }
+        'flw','fsw',
+        'fmadd.s','fmsub.s','fnmsub.s','fnmadd.s',
+        'fadd.s','fsub.s','fmul.s','fdiv.s',
+        'fsqrt.s','fsgnj.s','fsgnjn.s','fsgnjx.s',
+        'fmin.s','fmax.s',
+        'fmv.x.s','feq.s','flt.s','fle.s','fclass.s',
+        'fcvt.w.s','fcvt.wu.s','fcvt.s.w','fcvt.s.wu',
+        'fmv.s.x',
+        'frcsr','frrm','frflags','fscsr','fsrm',
+        'fsflags','fsrmi','fsflagsi',
+
+        { d-extension }
+        'fld','fsd',
+        'fmadd.d','fmsub.d','fnmsub.d','fnmadd.d',
+        'fadd.d','fsub.d','fmul.d','fdiv.d',
+        'fsqrt.d','fsgnj.d','fsgnjn.d','fsgnjx.d',
+        'fmin.d','fmax.d',
+        'feq.d','flt.d','fle.d','fclass.d',
+        'fcvt.d.s','fcvt.s.d',
+        'fcvt.w.d','fcvt.wu.d','fcvt.d.w','fcvt.d.wu',
+
+        { Machine mode }
+        'mret','hret','sret','uret',
+        'wfi',
+
+        { Supervisor mode }
+        'sfence.vm'
+        );
+
+    function gas_regnum_search(const s:string):Tregister;
+    function gas_regname(r:Tregister):string;
+
+
+implementation
+
+    uses
+      globtype,globals,aasmbase,
+      cutils,verbose, systems,
+      rgbase;
+
+    const
+      gas_regname_table : TRegNameTable = (
+        {$i rrv32std.inc}
+      );
+
+      gas_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rrv32sri.inc}
+      );
+
+
+    function findreg_by_gasname(const s:string):tregisterindex;
+      var
+        i,p : tregisterindex;
+      begin
+        {Binary search.}
+        p:=0;
+        i:=regnumber_count_bsstart;
+        repeat
+          if (p+i<=high(tregisterindex)) and (gas_regname_table[gas_regname_index[p+i]]<=s) then
+            p:=p+i;
+          i:=i shr 1;
+        until i=0;
+        if gas_regname_table[gas_regname_index[p]]=s then
+          findreg_by_gasname:=gas_regname_index[p]
+        else
+          findreg_by_gasname:=0;
+      end;
+
+
+    function gas_regnum_search(const s:string):Tregister;
+      begin
+        result:=regnumber_table[findreg_by_gasname(s)];
+      end;
+
+
+    function gas_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number(r);
+        if p<>0 then
+          result:=gas_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+end.

+ 56 - 0
compiler/riscv32/nrv32add.pas

@@ -0,0 +1,56 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
+
+    Code generation for add nodes on the Risc-V32
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv32add;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      node, ncgadd, aasmbase, nrvadd, cpubase;
+
+    type
+      trv32addnode = class(trvaddnode)
+      protected
+        function use_generic_mul32to64: boolean; override;
+      end;
+
+  implementation
+
+    uses
+      systems,
+      cutils,verbose,
+      paramgr,procinfo,
+      aasmtai,aasmdata,aasmcpu,defutil,
+      cgbase,cgcpu,cgutils,nadd,
+      cpupara,
+      ncon,nset,
+      hlcgobj, ncgutil,cgobj;
+
+    function trv32addnode.use_generic_mul32to64: boolean;
+      begin
+        result:=true;
+      end;
+
+begin
+   caddnode:=trv32addnode;
+end.

+ 51 - 0
compiler/riscv32/nrv32cal.pas

@@ -0,0 +1,51 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    Implements the Risc-V32 specific part of call nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv32cal;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      symdef,node,ncal,ncgcal;
+
+    type
+       trv32callnode = class(tcgcallnode)
+       end;
+
+
+implementation
+
+    uses
+      globtype,systems,
+      cutils,verbose,globals,
+      symconst,symbase,symsym,symcpu,symtable,defutil,paramgr,parabase,
+      cgbase,pass_2,
+      cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
+      nmem,nld,ncnv,
+      ncgutil,cgutils,cgobj,tgobj,rgobj,rgcpu,
+      cg64f32,cgcpu,cpupi,procinfo;
+
+
+begin
+   ccallnode:=trv32callnode;
+end.

+ 151 - 0
compiler/riscv32/nrv32cnv.pas

@@ -0,0 +1,151 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Risc-V32 assembler for type converting nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv32cnv;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,ncnv,ncgcnv,nrvcnv;
+
+    type
+       trv32typeconvnode = class(trvtypeconvnode)
+         protected
+         { procedure second_int_to_int;override; }
+         { procedure second_string_to_string;override; }
+         { procedure second_cstring_to_pchar;override; }
+         { procedure second_string_to_chararray;override; }
+         { procedure second_array_to_pointer;override; }
+          function first_int_to_real: tnode; override;
+         { procedure second_pointer_to_array;override; }
+         { procedure second_chararray_to_string;override; }
+         { procedure second_char_to_string;override; }
+          procedure second_int_to_real;override;
+         { procedure second_real_to_real;override; }
+         { procedure second_cord_to_pointer;override; }
+         { procedure second_proc_to_procvar;override; }
+         { procedure second_bool_to_int;override; }
+         { procedure second_int_to_bool;override; }
+         { procedure second_set_to_set;override;  }
+         { procedure second_ansistring_to_pchar;override; }
+         { procedure second_pchar_to_string;override; }
+         { procedure second_class_to_intf;override; }
+         { procedure second_char_to_char;override; }
+       end;
+
+implementation
+
+   uses
+      verbose,globtype,globals,systems,
+      symconst,symdef,aasmbase,aasmtai,aasmdata,
+      defutil,symcpu,
+      cgbase,cgutils,pass_1,pass_2,
+      ncon,ncal,
+      ncgutil,procinfo,
+      cpubase,aasmcpu,
+      rgobj,tgobj,cgobj,hlcgobj;
+
+
+{*****************************************************************************
+                             FirstTypeConv
+*****************************************************************************}
+
+    function trv32typeconvnode.first_int_to_real: tnode;
+      var
+        fname: string[19];
+      begin                                                        
+        if (cs_fp_emulation in current_settings.moduleswitches) then
+          result:=inherited first_int_to_real                      
+        { converting a 64bit integer to a float requires a helper }
+        else
+          begin
+            if is_64bitint(left.resultdef) or
+                    is_currency(left.resultdef) then
+              begin
+                { hack to avoid double division by 10000, as it's       }
+                { already done by typecheckpass.resultdef_int_to_real }
+                if is_currency(left.resultdef) then
+                  left.resultdef := s64inttype;
+                if is_signed(left.resultdef) then
+                  fname := 'fpc_int64_to_double'
+                else
+                  fname := 'fpc_qword_to_double';
+                result := ccallnode.createintern(fname,ccallparanode.create(
+                  left,nil));
+                left:=nil;
+                firstpass(result);
+                exit;
+              end
+            else
+              { other integers are supposed to be 32 bit }
+              begin
+                if is_signed(left.resultdef) then
+                  inserttypeconv(left,s32inttype)
+                else
+                  inserttypeconv(left,u32inttype);
+                firstpass(left);
+              end;
+            result := nil;
+            expectloc:=LOC_FPUREGISTER;
+          end;
+      end;
+
+
+{*****************************************************************************
+                             SecondTypeConv
+*****************************************************************************}
+
+    procedure trv32typeconvnode.second_int_to_real;
+      const
+        ops: array[boolean,s32real..s64real] of TAsmOp =
+          ((A_FCVT_S_WU,A_FCVT_D_WU),
+           (A_FCVT_S_W,A_FCVT_D_W));
+      var
+        restype: tfloattype;
+      begin
+        location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
+
+        restype:=tfloatdef(resultdef).floattype;
+
+        location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, tfloat2tcgsize[restype]);
+        if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(ops[is_signed(left.resultdef),restype], location.register, left.location.register));
+          end
+        else
+          begin
+            { Load memory in fpu register }
+            hlcg.location_force_mem(current_asmdata.CurrAsmList, left.location, left.resultdef);
+            cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList, OS_F32, OS_F32, left.location.reference, location.Register);
+            tg.ungetiftemp(current_asmdata.CurrAsmList, left.location.reference);
+
+            case restype of
+              s64real: cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList, OS_F32, OS_F64, location.register, location.Register);
+            end;
+          end;
+      end;
+
+begin
+   ctypeconvnode:=trv32typeconvnode;
+end.
+

+ 135 - 0
compiler/riscv32/nrv32mat.pas

@@ -0,0 +1,135 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Risc-V32 assembler for math nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv32mat;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,nmat, ncgmat,
+      cgbase;
+
+    type
+      trv32moddivnode = class(tcgmoddivnode)
+         procedure emit_div_reg_reg(signed: boolean; denum, num: tregister); override;
+         procedure emit_mod_reg_reg(signed: boolean; denum, num: tregister); override;
+         function first_moddivint: tnode; override;
+      end;
+
+      trv32shlshrnode = class(tcgshlshrnode)
+      end;
+
+      trv32unaryminusnode = class(tcgunaryminusnode)
+      end;
+
+      trv32notnode = class(tcgnotnode)
+        procedure second_boolean; override;
+      end;
+
+implementation
+
+    uses
+      globtype,systems,constexp,
+      cutils,verbose,globals,
+      symconst,symdef,
+      aasmbase,aasmcpu,aasmtai,aasmdata,
+      defutil,
+      cgutils,cgobj,hlcgobj,pass_2,
+      ncon,procinfo,
+      cpubase,
+      ncgutil,cgcpu;
+
+    procedure trv32notnode.second_boolean;
+      var
+        tlabel, flabel: tasmlabel;
+      begin
+        if not handle_locjump then
+          begin
+            secondpass(left);
+            case left.location.loc of
+              LOC_FLAGS :
+                begin
+                  Internalerror(2016060601);
+                  //location_copy(location,left.location);
+                  //inverse_flags(location.resflags);
+                end;
+              LOC_REGISTER, LOC_CREGISTER,
+              LOC_REFERENCE, LOC_CREFERENCE,
+              LOC_SUBSETREG, LOC_CSUBSETREG,
+              LOC_SUBSETREF, LOC_CSUBSETREF:
+                begin
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+                  current_asmdata.getjumplabel(tlabel);
+                  current_asmdata.getjumplabel(flabel);
+
+                  location_reset_jump(location,tlabel,flabel);
+
+                  hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,left.resultdef,OC_EQ,0,left.location.register,tlabel);
+                  hlcg.a_jmp_always(current_asmdata.CurrAsmList,flabel);
+               end;
+              else
+                internalerror(2003042401);
+            end;
+          end;
+      end;
+
+    procedure trv32moddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
+      var
+        op: TAsmOp;
+      begin
+        if signed then
+          op:=A_DIV
+        else
+          op:=A_DIVU;
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,denum,num,denum));
+      end;
+
+    procedure trv32moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
+      var
+        op: TAsmOp;
+      begin
+        if signed then
+          op:=A_REM
+        else
+          op:=A_REMU;
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,denum,num,denum));
+      end;
+
+
+    function trv32moddivnode.first_moddivint: tnode;
+      begin
+        if (not is_64bitint(resultdef)) then
+          Result:=nil
+        else
+          result:=inherited;
+      end;
+
+begin
+   cmoddivnode:=trv32moddivnode;
+   cshlshrnode:=trv32shlshrnode;
+   cunaryminusnode:=trv32unaryminusnode;
+   cnotnode:=trv32notnode;
+end.

+ 41 - 0
compiler/riscv32/rarv32.pas

@@ -0,0 +1,41 @@
+{
+    Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
+
+    Handles the common Risc-V32 assembler reader routines
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit rarv32;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      cpubase,rautils,cclasses;
+
+    type
+      TRVOperand=class(TOperand)
+      end;
+
+      TRVInstruction=class(TInstruction)
+      end;
+
+  implementation
+
+end.

+ 771 - 0
compiler/riscv32/rarv32gas.pas

@@ -0,0 +1,771 @@
+{
+    Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
+
+    Does the parsing for the Risc-V32 GNU AS styled inline assembler.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+Unit rarv32gas;
+
+{$i fpcdefs.inc}
+
+  Interface
+
+    uses
+      raatt,rarv32;
+
+    type
+      trv32attreader = class(tattreader)                             
+        function is_register(const s: string): boolean; override;
+        function is_asmopcode(const s: string):boolean;override;
+        procedure handleopcode;override;
+        procedure BuildReference(oper : trvoperand);
+        procedure BuildOperand(oper : trvoperand);
+        procedure BuildOpCode(instr : trvinstruction);
+        procedure ReadAt(oper : trvoperand);
+        procedure ReadSym(oper : trvoperand);
+      end;
+
+
+  Implementation
+
+    uses
+      { helpers }
+      cutils,
+      { global }
+      globtype,globals,verbose,
+      systems,
+      { aasm }
+      cpubase,aasmbase,aasmtai,aasmdata,aasmcpu,
+      { symtable }
+      symconst,symdef,symsym,
+      { parser }
+      procinfo,
+      rabase,rautils,
+      cgbase,cgobj,cgrv
+      ;
+
+    procedure trv32attreader.ReadSym(oper : trvoperand);
+      var
+         tempstr, mangledname : string;
+         l,k,typesize : tcgint;
+      begin
+        tempstr:=actasmpattern;
+        Consume(AS_ID);
+        { typecasting? }
+        if (actasmtoken=AS_LPAREN) and
+           SearchType(tempstr,typesize) then
+         begin
+           oper.hastype:=true;
+           Consume(AS_LPAREN);
+           BuildOperand(oper);
+           Consume(AS_RPAREN);
+           if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+             oper.SetSize(typesize,true);
+         end
+        else
+         if not oper.SetupVar(tempstr,false) then
+          Message1(sym_e_unknown_id,tempstr);
+        { record.field ? }
+        if actasmtoken=AS_DOT then
+         begin
+           BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
+           if (mangledname<>'') then
+             Message(asmr_e_invalid_reference_syntax);
+           inc(oper.opr.ref.offset,l);
+         end;
+      end;
+
+
+    procedure trv32attreader.ReadAt(oper : trvoperand);
+      begin
+        { check for ...@ }
+        if actasmtoken=AS_AT then
+          begin
+            if (oper.opr.ref.symbol=nil) and
+               (oper.opr.ref.offset = 0) then
+              Message(asmr_e_invalid_reference_syntax);
+            Consume(AS_AT);
+            if actasmtoken=AS_ID then
+              begin
+                {if upper(actasmpattern)='L' then
+                  oper.opr.ref.refaddr:=addr_low
+                else if upper(actasmpattern)='HI' then
+                  oper.opr.ref.refaddr:=addr_high
+                else if upper(actasmpattern)='HA' then
+                  oper.opr.ref.refaddr:=addr_higha
+                else}
+                  Message(asmr_e_invalid_reference_syntax);
+                Consume(AS_ID);
+              end
+            else
+              Message(asmr_e_invalid_reference_syntax);
+          end;
+      end;
+
+
+    Procedure trv32attreader.BuildReference(oper : trvoperand);
+
+      procedure Consume_RParen;
+        begin
+          if actasmtoken <> AS_RPAREN then
+           Begin
+             Message(asmr_e_invalid_reference_syntax);
+             RecoverConsume(true);
+           end
+          else
+           begin
+             Consume(AS_RPAREN);
+             if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
+              Begin
+                Message(asmr_e_invalid_reference_syntax);
+                RecoverConsume(true);
+              end;
+           end;
+        end;
+
+      var
+        l : tcgint;
+        relsym: string;
+        asmsymtyp: tasmsymtype;
+        isflags: tindsymflags;
+
+      begin
+        Consume(AS_LPAREN);
+        Case actasmtoken of
+          AS_INTNUM,
+          AS_MINUS,
+          AS_PLUS:
+            Begin
+              { offset(offset) is invalid }
+              If oper.opr.Ref.Offset <> 0 Then
+               Begin
+                 Message(asmr_e_invalid_reference_syntax);
+                 RecoverConsume(true);
+               End
+              Else
+               Begin
+                 oper.opr.Ref.Offset:=BuildConstExpression(false,true);
+                 Consume(AS_RPAREN);
+                 if actasmtoken=AS_AT then
+                   ReadAt(oper);
+               end;
+              exit;
+            End;
+          AS_REGISTER: { (reg ...  }
+            Begin
+              if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
+                 ((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
+                message(asmr_e_cannot_index_relative_var);
+              oper.opr.ref.base:=actasmregister;
+              Consume(AS_REGISTER);
+              Consume_RParen;
+            end; {end case }
+          AS_ID:
+            Begin
+              ReadSym(oper);
+              case actasmtoken of
+                AS_PLUS:
+                  begin
+                    { add a constant expression? }
+                    l:=BuildConstExpression(true,true);
+                    case oper.opr.typ of
+                      OPR_CONSTANT :
+                        inc(oper.opr.val,l);
+                      OPR_LOCAL :
+                        inc(oper.opr.localsymofs,l);
+                      OPR_REFERENCE :
+                        inc(oper.opr.ref.offset,l);
+                      else
+                        internalerror(200309202);
+                    end;
+                  end;
+                AS_MINUS:
+                  begin
+                    Consume(AS_MINUS);
+                    BuildConstSymbolExpression(false,true,false,l,relsym,asmsymtyp);
+                    if (relsym<>'') then
+                      begin
+                        if (oper.opr.typ = OPR_REFERENCE) then
+                          oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym,AT_DATA)
+                        else
+                          begin
+                            Message(asmr_e_invalid_reference_syntax);
+                            RecoverConsume(false);
+                          end
+                      end
+                    else
+                      begin
+                        case oper.opr.typ of
+                          OPR_CONSTANT :
+                            dec(oper.opr.val,l);
+                          OPR_LOCAL :
+                            dec(oper.opr.localsymofs,l);
+                          OPR_REFERENCE :
+                            dec(oper.opr.ref.offset,l);
+                          else
+                            internalerror(2007092601);
+                        end;
+                      end;
+                  end;
+              end;
+              Consume(AS_RPAREN);
+              if actasmtoken=AS_AT then
+                ReadAt(oper);
+            End;
+          AS_COMMA: { (, ...  can either be scaling, or index }
+            Begin
+              Consume(AS_COMMA);
+              { Index }
+              if (actasmtoken=AS_REGISTER) then
+                Begin
+                  oper.opr.ref.index:=actasmregister;
+                  Consume(AS_REGISTER);
+                  { check for scaling ... }
+                  Consume_RParen;
+                end
+              else
+                begin
+                  Message(asmr_e_invalid_reference_syntax);
+                  RecoverConsume(false);
+                end;
+            end;
+        else
+          Begin
+            Message(asmr_e_invalid_reference_syntax);
+            RecoverConsume(false);
+          end;
+        end;
+      end;
+
+
+    Procedure trv32attreader.BuildOperand(oper : trvoperand);
+      var
+        expr : string;
+        typesize,l : tcgint;
+
+
+        procedure AddLabelOperand(hl:tasmlabel);
+          begin
+            if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
+               is_calljmp(actopcode) then
+             begin
+               oper.opr.typ:=OPR_SYMBOL;
+               oper.opr.symbol:=hl;
+             end
+            else
+             begin
+               oper.InitRef;
+               oper.opr.ref.symbol:=hl;
+             end;
+          end;
+
+
+        procedure MaybeRecordOffset;
+          var
+            mangledname: string;
+            hasdot  : boolean;
+            l,
+            toffset,
+            tsize   : tcgint;
+          begin
+            if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
+             exit;
+            l:=0;
+            hasdot:=(actasmtoken=AS_DOT);
+            if hasdot then
+              begin
+                if expr<>'' then
+                  begin
+                    BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
+                    if (oper.opr.typ<>OPR_CONSTANT) and
+                       (mangledname<>'') then
+                      Message(asmr_e_wrong_sym_type);
+                    inc(l,toffset);
+                    oper.SetSize(tsize,true);
+                  end;
+              end;
+            if actasmtoken in [AS_PLUS,AS_MINUS] then
+              inc(l,BuildConstExpression(true,false));
+            case oper.opr.typ of
+              OPR_LOCAL :
+                begin
+                  { don't allow direct access to fields of parameters, because that
+                    will generate buggy code. Allow it only for explicit typecasting }
+                  if hasdot and
+                     (not oper.hastype) and
+                     (tabstractvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
+                     (current_procinfo.procdef.proccalloption<>pocall_register) then
+                    Message(asmr_e_cannot_access_field_directly_for_parameters);
+                  inc(oper.opr.localsymofs,l)
+                end;
+              OPR_CONSTANT :
+                if (mangledname<>'') then
+                  begin
+                    if (oper.opr.val<>0) then
+                      Message(asmr_e_wrong_sym_type);
+                    oper.opr.typ:=OPR_SYMBOL;
+                    oper.opr.symbol:=current_asmdata.DefineAsmSymbol(mangledname,AB_EXTERNAL,AT_FUNCTION,voidcodepointertype);
+                  end
+                else
+                  inc(oper.opr.val,l);
+              OPR_REFERENCE :
+                inc(oper.opr.ref.offset,l);
+              OPR_SYMBOL:
+                Message(asmr_e_invalid_symbol_ref);
+              else
+                internalerror(200309221);
+            end;
+          end;
+
+
+        function MaybeBuildReference:boolean;
+          { Try to create a reference, if not a reference is found then false
+            is returned }
+          begin
+            MaybeBuildReference:=true;
+            case actasmtoken of
+              AS_INTNUM,
+              AS_MINUS,
+              AS_PLUS:
+                Begin
+                  oper.opr.ref.offset:=BuildConstExpression(True,False);
+                  if actasmtoken<>AS_LPAREN then
+                    Message(asmr_e_invalid_reference_syntax)
+                  else
+                    BuildReference(oper);
+                end;
+              AS_LPAREN:
+                BuildReference(oper);
+              AS_ID: { only a variable is allowed ... }
+                Begin
+                  ReadSym(oper);
+                  case actasmtoken of
+                    AS_END,
+                    AS_SEPARATOR,
+                    AS_COMMA: ;
+                    AS_LPAREN:
+                      BuildReference(oper);
+                  else
+                    Begin
+                      Message(asmr_e_invalid_reference_syntax);
+                      Consume(actasmtoken);
+                    end;
+                  end; {end case }
+                end;
+              else
+               MaybeBuildReference:=false;
+            end; { end case }
+          end;
+
+
+      var
+        tempreg : tregister;
+        hl : tasmlabel;
+        ofs : aint;          
+        refaddr: trefaddr;
+      Begin
+        expr:='';             
+
+        refaddr:=addr_full;
+        if actasmtoken=AS_MOD then
+          begin
+            consume(AS_MOD);
+
+            if actasmtoken<>AS_ID then
+              begin
+                Message(asmr_e_invalid_reference_syntax);
+                RecoverConsume(false);
+              end
+            else
+              begin
+                if lower(actasmpattern)='pcrel_hi' then
+                  refaddr:=addr_pcrel_hi20
+                else if lower(actasmpattern)='pcrel_lo' then
+                  refaddr:=addr_pcrel_lo12
+                else if lower(actasmpattern)='hi' then
+                  refaddr:=addr_hi20
+                else if lower(actasmpattern)='lo' then
+                  refaddr:=addr_lo12
+                else
+                  begin
+                    Message(asmr_e_invalid_reference_syntax);
+                    RecoverConsume(false);
+                  end;
+
+                consume(AS_ID);
+                consume(AS_LPAREN);
+              end;
+          end;
+
+        case actasmtoken of
+          AS_LPAREN: { Memory reference or constant expression }
+            Begin
+              oper.InitRef;
+              BuildReference(oper);
+            end;
+
+          AS_INTNUM,
+          AS_MINUS,
+          AS_PLUS:
+            Begin
+              { Constant memory offset }
+              { This must absolutely be followed by (  }
+              oper.InitRef;
+              oper.opr.ref.offset:=BuildConstExpression(True,False);
+              if actasmtoken<>AS_LPAREN then
+                begin
+                  ofs:=oper.opr.ref.offset;
+                  BuildConstantOperand(oper);
+                  inc(oper.opr.val,ofs);
+                end
+              else
+                BuildReference(oper);
+            end;
+
+          AS_ID: { A constant expression, or a Variable ref.  }
+            Begin
+              { Local Label ? }
+              if is_locallabel(actasmpattern) then
+               begin
+                 CreateLocalLabel(actasmpattern,hl,false);
+                 Consume(AS_ID);
+                 AddLabelOperand(hl);
+               end
+              else
+               { Check for label }
+               if SearchLabel(actasmpattern,hl,false) then
+                begin
+                  Consume(AS_ID);
+                  AddLabelOperand(hl);
+                end
+              else
+               { probably a variable or normal expression }
+               { or a procedure (such as in CALL ID)      }
+               Begin
+                 { is it a constant ? }
+                 if SearchIConstant(actasmpattern,l) then
+                  Begin
+                    if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
+                     Message(asmr_e_invalid_operand_type);
+                    BuildConstantOperand(oper);
+                  end
+                 else
+                  begin
+                    expr:=actasmpattern;
+                    Consume(AS_ID);
+                    { typecasting? }
+                    if (actasmtoken=AS_LPAREN) and
+                       SearchType(expr,typesize) then
+                     begin
+                       oper.hastype:=true;
+                       Consume(AS_LPAREN);
+                       BuildOperand(oper);
+                       Consume(AS_RPAREN);
+                       if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+                         oper.SetSize(typesize,true);
+                     end
+                    else
+                     begin
+                       if oper.SetupVar(expr,false) then
+                         ReadAt(oper)
+                       else
+                        Begin
+                          { look for special symbols ... }
+                          if expr= '__HIGH' then
+                            begin
+                              consume(AS_LPAREN);
+                              if not oper.setupvar('high'+actasmpattern,false) then
+                                Message1(sym_e_unknown_id,'high'+actasmpattern);
+                              consume(AS_ID);
+                              consume(AS_RPAREN);
+                            end
+                          else
+                           if expr = '__RESULT' then
+                            oper.SetUpResult
+                          else
+                           if expr = '__SELF' then
+                            oper.SetupSelf
+                          else
+                           if expr = '__OLDEBP' then
+                            oper.SetupOldEBP
+                          else
+                            Message1(sym_e_unknown_id,expr);
+                        end;
+                     end;
+                  end;
+                  if actasmtoken=AS_DOT then
+                    MaybeRecordOffset;
+                  { add a constant expression? }
+                  if (actasmtoken=AS_PLUS) then
+                   begin
+                     l:=BuildConstExpression(true,false);
+                     case oper.opr.typ of
+                       OPR_CONSTANT :
+                         inc(oper.opr.val,l);
+                       OPR_LOCAL :
+                         inc(oper.opr.localsymofs,l);
+                       OPR_REFERENCE :
+                         inc(oper.opr.ref.offset,l);
+                       else
+                         internalerror(200309202);
+                     end;
+                   end
+               end;
+              { Do we have a indexing reference, then parse it also }
+              if actasmtoken=AS_LPAREN then
+                BuildReference(oper);
+            end;
+
+          AS_REGISTER: { Register, a variable reference or a constant reference  }
+            Begin
+              { save the type of register used. }
+              tempreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
+                  begin
+                    if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
+                      Message(asmr_e_invalid_operand_type);
+                    oper.opr.typ:=OPR_REGISTER;
+                    oper.opr.reg:=tempreg;
+                  end
+              else
+                Message(asmr_e_syn_operand);
+            end;
+          AS_END,
+          AS_SEPARATOR,
+          AS_COMMA: ;
+        else
+          Begin
+            Message(asmr_e_syn_operand);
+            Consume(actasmtoken);
+          end;
+        end; { end case }  
+
+        if refaddr<>addr_full then
+          begin
+            if oper.opr.typ<>OPR_REFERENCE then
+              oper.InitRef;
+
+            oper.opr.ref.refaddr:=refaddr;
+            Consume(AS_RPAREN);
+          end;
+      end;
+
+
+{*****************************************************************************
+                                trv32attreader
+*****************************************************************************}
+
+    procedure trv32attreader.BuildOpCode(instr : trvinstruction);
+      var
+        operandnum : longint;
+      Begin
+        { opcode }
+        if (actasmtoken<>AS_OPCODE) then
+         Begin
+           Message(asmr_e_invalid_or_missing_opcode);
+           RecoverConsume(true);
+           exit;
+         end;
+        { Fill the instr object with the current state }
+        with instr do
+          begin
+            Opcode:=ActOpcode;
+            condition:=ActCondition;
+          end;
+
+        { We are reading operands, so opcode will be an AS_ID }
+        operandnum:=1;
+        Consume(AS_OPCODE);
+        { Zero operand opcode ?  }
+        if actasmtoken in [AS_SEPARATOR,AS_END] then
+         begin
+           operandnum:=0;
+           exit;
+         end;
+        { Read the operands }
+        repeat
+          case actasmtoken of
+            AS_COMMA: { Operand delimiter }
+              Begin
+                if operandnum>Max_Operands then
+                  Message(asmr_e_too_many_operands)
+                else
+                  begin
+                    { condition operands doesn't set the operand but write to the
+                      condition field of the instruction
+                    }
+                    if instr.Operands[operandnum].opr.typ<>OPR_NONE then
+                      Inc(operandnum);
+                  end;
+                Consume(AS_COMMA);
+              end;
+            AS_SEPARATOR,
+            AS_END : { End of asm operands for this opcode  }
+              begin
+                break;
+              end;
+          else
+            BuildOperand(instr.Operands[operandnum] as trvoperand);
+          end; { end case }
+        until false;
+        if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
+          dec(operandnum);
+        instr.Ops:=operandnum;
+      end;
+
+
+    function trv32attreader.is_register(const s: string): boolean;
+      type
+        treg2str = record
+          name : string[3];
+          reg : tregister;
+        end;
+
+      const
+        extraregs : array[0..31] of treg2str = (
+          (name: 'A0'; reg : NR_X10),
+          (name: 'A1'; reg : NR_X11),
+          (name: 'A2'; reg : NR_X12),
+          (name: 'A3'; reg : NR_X13),
+          (name: 'A5'; reg : NR_X14),
+          (name: 'A6'; reg : NR_X15),
+          (name: 'A7'; reg : NR_X16),
+          (name: 'A8'; reg : NR_X17),
+          (name: 'RA'; reg : NR_X1),
+          (name: 'SP'; reg : NR_X2),
+          (name: 'GP'; reg : NR_X3),
+          (name: 'TP'; reg : NR_X4),
+          (name: 'T0'; reg : NR_X5),
+          (name: 'T1'; reg : NR_X6),
+          (name: 'T2'; reg : NR_X7),
+          (name: 'S0'; reg : NR_X8),
+          (name: 'FP'; reg : NR_X8),
+          (name: 'S1'; reg : NR_X9),
+          (name: 'S2'; reg : NR_X18),
+          (name: 'S3'; reg : NR_X19),
+          (name: 'S4'; reg : NR_X20),
+          (name: 'S5'; reg : NR_X21),
+          (name: 'S6'; reg : NR_X22),
+          (name: 'S7'; reg : NR_X23),
+          (name: 'S8'; reg : NR_X24),
+          (name: 'S9'; reg : NR_X25),
+          (name: 'S10';reg : NR_X26),
+          (name: 'S11';reg : NR_X27),
+          (name: 'T3'; reg : NR_X28),
+          (name: 'T4'; reg : NR_X29),
+          (name: 'T5'; reg : NR_X30),
+          (name: 'T6'; reg : NR_X31)
+          );
+
+      var
+        i : longint;
+
+      begin
+        result:=inherited is_register(s);
+        { reg found?
+          possible aliases are always 2 char
+        }
+        if result or (not (length(s) in [2,3])) then
+          exit;
+        for i:=low(extraregs) to high(extraregs) do
+          begin
+            if s=extraregs[i].name then
+              begin
+                actasmregister:=extraregs[i].reg;
+                result:=true;
+                actasmtoken:=AS_REGISTER;
+                exit;
+              end;
+          end;
+      end;
+
+
+    function trv32attreader.is_asmopcode(const s: string):boolean;
+      var
+        cond  : tasmcond;
+        hs : string;
+
+      Begin
+        { making s a value parameter would break other assembler readers }
+        hs:=s;
+        is_asmopcode:=false;
+
+        { clear op code }
+        actopcode:=A_None;
+        { clear condition }
+        fillchar(actcondition,sizeof(actcondition),0);
+
+        { check for direction hint }
+	actopcode := tasmop(ptruint(iasmops.find(hs)));
+        if actopcode <> A_NONE then
+          begin
+            actasmtoken:=AS_OPCODE;
+            is_asmopcode:=true;
+            exit;
+          end;
+        { not found, check branch instructions }
+        if hs[1]='B' then
+          begin
+            { we can search here without an extra table which is sorted by string length
+              because we take the whole remaining string without the leading B }
+            actopcode := A_Bxx;
+            for cond:=low(TAsmCond) to high(TAsmCond) do
+              if copy(hs,2,length(s)-1)=uppercond2str[cond] then
+                begin
+                  actcondition:=cond;
+                  actasmtoken:=AS_OPCODE;
+                  is_asmopcode:=true;
+                  exit;
+                end;
+          end;
+      end;
+
+
+    procedure trv32attreader.handleopcode;
+      var
+        instr : trvinstruction;
+      begin
+        instr:=trvinstruction.Create(trvoperand);
+        BuildOpcode(instr);
+        instr.condition := actcondition;
+        {
+        instr.AddReferenceSizes;
+        instr.SetInstructionOpsize;
+        instr.CheckOperandSizes;
+        }
+        instr.ConcatInstruction(curlist);
+        instr.Free;
+      end;
+
+
+{*****************************************************************************
+                                     Initialize
+*****************************************************************************}
+
+const
+  asmmode_rv32_standard_info : tasmmodeinfo =
+          (
+            id    : asmmode_standard;
+            idtxt : 'STANDARD';
+            casmreader : trv32attreader;
+          );
+
+initialization
+  RegisterAsmMode(asmmode_rv32_standard_info);
+end.

+ 67 - 0
compiler/riscv32/rrv32con.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+NR_NO = tregister($00000000);
+NR_X0 = tregister($01000000);
+NR_X1 = tregister($01000001);
+NR_X2 = tregister($01000002);
+NR_X3 = tregister($01000003);
+NR_X4 = tregister($01000004);
+NR_X5 = tregister($01000005);
+NR_X6 = tregister($01000006);
+NR_X7 = tregister($01000007);
+NR_X8 = tregister($01000008);
+NR_X9 = tregister($01000009);
+NR_X10 = tregister($0100000a);
+NR_X11 = tregister($0100000b);
+NR_X12 = tregister($0100000c);
+NR_X13 = tregister($0100000d);
+NR_X14 = tregister($0100000e);
+NR_X15 = tregister($0100000f);
+NR_X16 = tregister($01000010);
+NR_X17 = tregister($01000011);
+NR_X18 = tregister($01000012);
+NR_X19 = tregister($01000013);
+NR_X20 = tregister($01000014);
+NR_X21 = tregister($01000015);
+NR_X22 = tregister($01000016);
+NR_X23 = tregister($01000017);
+NR_X24 = tregister($01000018);
+NR_X25 = tregister($01000019);
+NR_X26 = tregister($0100001a);
+NR_X27 = tregister($0100001b);
+NR_X28 = tregister($0100001c);
+NR_X29 = tregister($0100001d);
+NR_X30 = tregister($0100001e);
+NR_X31 = tregister($0100001f);
+NR_F0 = tregister($02000000);
+NR_F1 = tregister($02000001);
+NR_F2 = tregister($02000002);
+NR_F3 = tregister($02000003);
+NR_F4 = tregister($02000004);
+NR_F5 = tregister($02000005);
+NR_F6 = tregister($02000006);
+NR_F7 = tregister($02000007);
+NR_F8 = tregister($02000008);
+NR_F9 = tregister($02000009);
+NR_F10 = tregister($0200000a);
+NR_F11 = tregister($0200000b);
+NR_F12 = tregister($0200000c);
+NR_F13 = tregister($0200000d);
+NR_F14 = tregister($0200000e);
+NR_F15 = tregister($0200000f);
+NR_F16 = tregister($02000010);
+NR_F17 = tregister($02000011);
+NR_F18 = tregister($02000012);
+NR_F19 = tregister($02000013);
+NR_F20 = tregister($02000014);
+NR_F21 = tregister($02000015);
+NR_F22 = tregister($02000016);
+NR_F23 = tregister($02000017);
+NR_F24 = tregister($02000018);
+NR_F25 = tregister($02000019);
+NR_F26 = tregister($0200001a);
+NR_F27 = tregister($0200001b);
+NR_F28 = tregister($0200001c);
+NR_F29 = tregister($0200001d);
+NR_F30 = tregister($0200001e);
+NR_F31 = tregister($0200001f);
+NR_FCSR = tregister($05000001);

+ 67 - 0
compiler/riscv32/rrv32dwa.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0

+ 2 - 0
compiler/riscv32/rrv32nor.inc

@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from rv32reg.dat }
+66

+ 67 - 0
compiler/riscv32/rrv32num.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+tregister($00000000),
+tregister($01000000),
+tregister($01000001),
+tregister($01000002),
+tregister($01000003),
+tregister($01000004),
+tregister($01000005),
+tregister($01000006),
+tregister($01000007),
+tregister($01000008),
+tregister($01000009),
+tregister($0100000a),
+tregister($0100000b),
+tregister($0100000c),
+tregister($0100000d),
+tregister($0100000e),
+tregister($0100000f),
+tregister($01000010),
+tregister($01000011),
+tregister($01000012),
+tregister($01000013),
+tregister($01000014),
+tregister($01000015),
+tregister($01000016),
+tregister($01000017),
+tregister($01000018),
+tregister($01000019),
+tregister($0100001a),
+tregister($0100001b),
+tregister($0100001c),
+tregister($0100001d),
+tregister($0100001e),
+tregister($0100001f),
+tregister($02000000),
+tregister($02000001),
+tregister($02000002),
+tregister($02000003),
+tregister($02000004),
+tregister($02000005),
+tregister($02000006),
+tregister($02000007),
+tregister($02000008),
+tregister($02000009),
+tregister($0200000a),
+tregister($0200000b),
+tregister($0200000c),
+tregister($0200000d),
+tregister($0200000e),
+tregister($0200000f),
+tregister($02000010),
+tregister($02000011),
+tregister($02000012),
+tregister($02000013),
+tregister($02000014),
+tregister($02000015),
+tregister($02000016),
+tregister($02000017),
+tregister($02000018),
+tregister($02000019),
+tregister($0200001a),
+tregister($0200001b),
+tregister($0200001c),
+tregister($0200001d),
+tregister($0200001e),
+tregister($0200001f),
+tregister($05000001)

+ 67 - 0
compiler/riscv32/rrv32rni.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+63,
+64,
+65

+ 67 - 0
compiler/riscv32/rrv32sri.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+0,
+33,
+34,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+35,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+36,
+63,
+64,
+37,
+38,
+39,
+40,
+41,
+42,
+65,
+1,
+2,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+3,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+4,
+31,
+32,
+5,
+6,
+7,
+8,
+9,
+10

+ 67 - 0
compiler/riscv32/rrv32sta.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0

+ 67 - 0
compiler/riscv32/rrv32std.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+'INVALID',
+'x0',
+'x1',
+'x2',
+'x3',
+'x4',
+'x5',
+'x6',
+'x7',
+'x8',
+'x9',
+'x10',
+'x11',
+'x12',
+'x13',
+'x14',
+'x15',
+'x16',
+'x17',
+'x18',
+'x19',
+'x20',
+'x21',
+'x22',
+'x23',
+'x24',
+'x25',
+'x26',
+'x27',
+'x28',
+'x29',
+'x30',
+'x31',
+'f0',
+'f1',
+'f2',
+'f3',
+'f4',
+'f5',
+'f6',
+'f7',
+'f8',
+'f9',
+'f10',
+'f11',
+'f12',
+'f13',
+'f14',
+'f15',
+'f16',
+'f17',
+'f18',
+'f19',
+'f20',
+'f21',
+'f22',
+'f23',
+'f24',
+'f25',
+'f26',
+'f27',
+'f28',
+'f29',
+'f30',
+'f31',
+'fcsr'

+ 67 - 0
compiler/riscv32/rrv32sup.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+RS_NO = $00;
+RS_X0 = $00;
+RS_X1 = $01;
+RS_X2 = $02;
+RS_X3 = $03;
+RS_X4 = $04;
+RS_X5 = $05;
+RS_X6 = $06;
+RS_X7 = $07;
+RS_X8 = $08;
+RS_X9 = $09;
+RS_X10 = $0a;
+RS_X11 = $0b;
+RS_X12 = $0c;
+RS_X13 = $0d;
+RS_X14 = $0e;
+RS_X15 = $0f;
+RS_X16 = $10;
+RS_X17 = $11;
+RS_X18 = $12;
+RS_X19 = $13;
+RS_X20 = $14;
+RS_X21 = $15;
+RS_X22 = $16;
+RS_X23 = $17;
+RS_X24 = $18;
+RS_X25 = $19;
+RS_X26 = $1a;
+RS_X27 = $1b;
+RS_X28 = $1c;
+RS_X29 = $1d;
+RS_X30 = $1e;
+RS_X31 = $1f;
+RS_F0 = $00;
+RS_F1 = $01;
+RS_F2 = $02;
+RS_F3 = $03;
+RS_F4 = $04;
+RS_F5 = $05;
+RS_F6 = $06;
+RS_F7 = $07;
+RS_F8 = $08;
+RS_F9 = $09;
+RS_F10 = $0a;
+RS_F11 = $0b;
+RS_F12 = $0c;
+RS_F13 = $0d;
+RS_F14 = $0e;
+RS_F15 = $0f;
+RS_F16 = $10;
+RS_F17 = $11;
+RS_F18 = $12;
+RS_F19 = $13;
+RS_F20 = $14;
+RS_F21 = $15;
+RS_F22 = $16;
+RS_F23 = $17;
+RS_F24 = $18;
+RS_F25 = $19;
+RS_F26 = $1a;
+RS_F27 = $1b;
+RS_F28 = $1c;
+RS_F29 = $1d;
+RS_F30 = $1e;
+RS_F31 = $1f;
+RS_FCSR = $01;

+ 77 - 0
compiler/riscv32/rv32reg.dat

@@ -0,0 +1,77 @@
+;
+; RiscV registers
+;
+; layout
+; <name>,<type>,<subtype>,<value>,<stdname>,<stab idx>,<dwarf idx>
+;
+NO,$00,$00,$00,INVALID,-1,-1
+; Integer registers
+X0,$01,$00,$00,x0,0,0
+X1,$01,$00,$01,x1,1,1
+X2,$01,$00,$02,x2,2,2
+X3,$01,$00,$03,x3,3,3
+X4,$01,$00,$04,x4,4,4
+X5,$01,$00,$05,x5,5,5
+X6,$01,$00,$06,x6,6,6
+X7,$01,$00,$07,x7,7,7
+X8,$01,$00,$08,x8,8,8
+X9,$01,$00,$09,x9,9,9
+X10,$01,$00,$0a,x10,10,10
+X11,$01,$00,$0b,x11,11,11
+X12,$01,$00,$0c,x12,12,12
+X13,$01,$00,$0d,x13,13,13
+X14,$01,$00,$0e,x14,14,14
+X15,$01,$00,$0f,x15,15,15
+X16,$01,$00,$10,x16,16,16
+X17,$01,$00,$11,x17,17,17
+X18,$01,$00,$12,x18,18,18
+X19,$01,$00,$13,x19,19,19
+X20,$01,$00,$14,x20,20,20
+X21,$01,$00,$15,x21,21,21
+X22,$01,$00,$16,x22,22,22
+X23,$01,$00,$17,x23,23,23
+X24,$01,$00,$18,x24,24,24
+X25,$01,$00,$19,x25,25,25
+X26,$01,$00,$1a,x26,26,26
+X27,$01,$00,$1b,x27,27,27
+X28,$01,$00,$1c,x28,28,28
+X29,$01,$00,$1d,x29,29,29
+X30,$01,$00,$1e,x30,30,30
+X31,$01,$00,$1f,x31,31,31
+
+; Float registers
+F0,$02,$00,$00,f0,0,0
+F1,$02,$00,$01,f1,1,1
+F2,$02,$00,$02,f2,2,2
+F3,$02,$00,$03,f3,3,3
+F4,$02,$00,$04,f4,4,4
+F5,$02,$00,$05,f5,5,5
+F6,$02,$00,$06,f6,6,6
+F7,$02,$00,$07,f7,7,7
+F8,$02,$00,$08,f8,8,8
+F9,$02,$00,$09,f9,9,9
+F10,$02,$00,$0a,f10,10,10
+F11,$02,$00,$0b,f11,11,11
+F12,$02,$00,$0c,f12,12,12
+F13,$02,$00,$0d,f13,13,13
+F14,$02,$00,$0e,f14,14,14
+F15,$02,$00,$0f,f15,15,15
+F16,$02,$00,$10,f16,16,16
+F17,$02,$00,$11,f17,17,17
+F18,$02,$00,$12,f18,18,18
+F19,$02,$00,$13,f19,19,19
+F20,$02,$00,$14,f20,20,20
+F21,$02,$00,$15,f21,21,21
+F22,$02,$00,$16,f22,22,22
+F23,$02,$00,$17,f23,23,23
+F24,$02,$00,$18,f24,24,24
+F25,$02,$00,$19,f25,25,25
+F26,$02,$00,$1a,f26,26,26
+F27,$02,$00,$1b,f27,27,27
+F28,$02,$00,$1c,f28,28,28
+F29,$02,$00,$1d,f29,29,29
+F30,$02,$00,$1e,f30,30,30
+F31,$02,$00,$1f,f31,31,31
+
+; Special registers
+FCSR,$05,$00,$01,fcsr,0,0

+ 216 - 0
compiler/riscv32/symcpu.pas

@@ -0,0 +1,216 @@
+{
+    Copyright (c) 2014 by Florian Klaempfl
+
+    Symbol table overrides for Risc-V32
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit symcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  symconst,symtype,symdef,symsym;
+
+type
+  { defs }
+  tcpufiledef = class(tfiledef)
+  end;
+  tcpufiledefclass = class of tcpufiledef;
+
+  tcpuvariantdef = class(tvariantdef)
+  end;
+  tcpuvariantdefclass = class of tcpuvariantdef;
+
+  tcpuformaldef = class(tformaldef)
+  end;
+  tcpuformaldefclass = class of tcpuformaldef;
+
+  tcpuforwarddef = class(tforwarddef)
+  end;
+  tcpuforwarddefclass = class of tcpuforwarddef;
+
+  tcpuundefineddef = class(tundefineddef)
+  end;
+  tcpuundefineddefclass = class of tcpuundefineddef;
+
+  tcpuerrordef = class(terrordef)
+  end;
+  tcpuerrordefclass = class of tcpuerrordef;
+
+  tcpupointerdef = class(tpointerdef)
+  end;
+  tcpupointerdefclass = class of tcpupointerdef;
+
+  tcpurecorddef = class(trecorddef)
+  end;
+  tcpurecorddefclass = class of tcpurecorddef;
+
+  tcpuimplementedinterface = class(timplementedinterface)
+  end;
+  tcpuimplementedinterfaceclass = class of tcpuimplementedinterface;
+
+  tcpuobjectdef = class(tobjectdef)
+  end;
+  tcpuobjectdefclass = class of tcpuobjectdef;
+
+  tcpuclassrefdef = class(tclassrefdef)
+  end;
+  tcpuclassrefdefclass = class of tcpuclassrefdef;
+
+  tcpuarraydef = class(tarraydef)
+  end;
+  tcpuarraydefclass = class of tcpuarraydef;
+
+  tcpuorddef = class(torddef)
+  end;
+  tcpuorddefclass = class of tcpuorddef;
+
+  tcpufloatdef = class(tfloatdef)
+  end;
+  tcpufloatdefclass = class of tcpufloatdef;
+
+  tcpuprocvardef = class(tprocvardef)
+  end;
+  tcpuprocvardefclass = class of tcpuprocvardef;
+
+  tcpuprocdef = class(tprocdef)
+  end;
+  tcpuprocdefclass = class of tcpuprocdef;
+
+  tcpustringdef = class(tstringdef)
+  end;
+  tcpustringdefclass = class of tcpustringdef;
+
+  tcpuenumdef = class(tenumdef)
+  end;
+  tcpuenumdefclass = class of tcpuenumdef;
+
+  tcpusetdef = class(tsetdef)
+  end;
+  tcpusetdefclass = class of tcpusetdef;
+
+  { syms }
+  tcpulabelsym = class(tlabelsym)
+  end;
+  tcpulabelsymclass = class of tcpulabelsym;
+
+  tcpuunitsym = class(tunitsym)
+  end;
+  tcpuunitsymclass = class of tcpuunitsym;
+
+  tcpuprogramparasym = class(tprogramparasym)
+  end;
+  tcpuprogramparasymclass = class(tprogramparasym);
+
+  tcpunamespacesym = class(tnamespacesym)
+  end;
+  tcpunamespacesymclass = class of tcpunamespacesym;
+
+  tcpuprocsym = class(tprocsym)
+  end;
+  tcpuprocsymclass = class of tcpuprocsym;
+
+  tcputypesym = class(ttypesym)
+  end;
+  tcpuypesymclass = class of tcputypesym;
+
+  tcpufieldvarsym = class(tfieldvarsym)
+  end;
+  tcpufieldvarsymclass = class of tcpufieldvarsym;
+
+  tcpulocalvarsym = class(tlocalvarsym)
+  end;
+  tcpulocalvarsymclass = class of tcpulocalvarsym;
+
+  tcpuparavarsym = class(tparavarsym)
+  end;
+  tcpuparavarsymclass = class of tcpuparavarsym;
+
+  tcpustaticvarsym = class(tstaticvarsym)
+  end;
+  tcpustaticvarsymclass = class of tcpustaticvarsym;
+
+  tcpuabsolutevarsym = class(tabsolutevarsym)
+  end;
+  tcpuabsolutevarsymclass = class of tcpuabsolutevarsym;
+
+  tcpupropertysym = class(tpropertysym)
+  end;
+  tcpupropertysymclass = class of tcpupropertysym;
+
+  tcpuconstsym = class(tconstsym)
+  end;
+  tcpuconstsymclass = class of tcpuconstsym;
+
+  tcpuenumsym = class(tenumsym)
+  end;
+  tcpuenumsymclass = class of tcpuenumsym;
+
+  tcpusyssym = class(tsyssym)
+  end;
+  tcpusyssymclass = class of tcpusyssym;
+
+
+const
+   pbestrealtype : ^tdef = @s64floattype;
+
+
+implementation
+
+begin
+  { used tdef classes }
+  cfiledef:=tcpufiledef;
+  cvariantdef:=tcpuvariantdef;
+  cformaldef:=tcpuformaldef;
+  cforwarddef:=tcpuforwarddef;
+  cundefineddef:=tcpuundefineddef;
+  cerrordef:=tcpuerrordef;
+  cpointerdef:=tcpupointerdef;
+  crecorddef:=tcpurecorddef;
+  cimplementedinterface:=tcpuimplementedinterface;
+  cobjectdef:=tcpuobjectdef;
+  cclassrefdef:=tcpuclassrefdef;
+  carraydef:=tcpuarraydef;
+  corddef:=tcpuorddef;
+  cfloatdef:=tcpufloatdef;
+  cprocvardef:=tcpuprocvardef;
+  cprocdef:=tcpuprocdef;
+  cstringdef:=tcpustringdef;
+  cenumdef:=tcpuenumdef;
+  csetdef:=tcpusetdef;
+
+  { used tsym classes }
+  clabelsym:=tcpulabelsym;
+  cunitsym:=tcpuunitsym;
+  cprogramparasym:=tcpuprogramparasym;
+  cnamespacesym:=tcpunamespacesym;
+  cprocsym:=tcpuprocsym;
+  ctypesym:=tcputypesym;
+  cfieldvarsym:=tcpufieldvarsym;
+  clocalvarsym:=tcpulocalvarsym;
+  cparavarsym:=tcpuparavarsym;
+  cstaticvarsym:=tcpustaticvarsym;
+  cabsolutevarsym:=tcpuabsolutevarsym;
+  cpropertysym:=tcpupropertysym;
+  cconstsym:=tcpuconstsym;
+  cenumsym:=tcpuenumsym;
+  csyssym:=tcpusyssym;
+end.
+

+ 387 - 0
compiler/riscv64/aoptcpu.pas

@@ -0,0 +1,387 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit implements the RiscV64 optimizer object
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit aoptcpu;
+
+interface
+
+{$I fpcdefs.inc}
+
+{$define DEBUG_AOPTCPU}
+
+uses
+  cpubase,
+  globals, globtype,
+  cgbase,
+  aoptobj, aoptcpub, aopt,
+  aasmtai, aasmcpu;
+
+type
+
+  TCpuAsmOptimizer = class(TAsmOptimizer)
+    function InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean; override;
+    function RegLoadedWithNewValue(reg: tregister; hp: tai): boolean; override;
+    Function GetNextInstructionUsingReg(Current: tai; Out Next: tai; reg: TRegister): Boolean;
+    { outputs a debug message into the assembler file }
+    procedure DebugMsg(const s: string; p: tai);
+
+    function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+  end;
+
+implementation
+
+  uses
+    cutils;
+
+  function MatchInstruction(const instr: tai; const op: TAsmOps; const AConditions: TAsmConds = []): boolean;
+    begin
+      result :=
+        (instr.typ = ait_instruction) and
+        (taicpu(instr).opcode in op) and
+        ((AConditions=[]) or (taicpu(instr).condition in AConditions));
+    end;
+
+
+  function MatchInstruction(const instr: tai; const op: TAsmOp; const AConditions: TAsmConds = []): boolean;
+    begin
+      result :=
+        (instr.typ = ait_instruction) and
+        (taicpu(instr).opcode = op) and
+        ((AConditions=[]) or (taicpu(instr).condition in AConditions));
+    end;
+
+
+  function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
+    begin
+      result := oper1.typ = oper2.typ;
+
+      if result then
+        case oper1.typ of
+          top_const:
+            Result:=oper1.val = oper2.val;
+          top_reg:
+            Result:=oper1.reg = oper2.reg;
+          {top_ref:
+            Result:=RefsEqual(oper1.ref^, oper2.ref^);}
+          else Result:=false;
+        end
+    end;
+
+
+  function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
+    begin
+      result := (oper.typ = top_reg) and (oper.reg = reg);
+    end;
+
+
+{$ifdef DEBUG_AOPTCPU}
+  procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
+    begin
+      asml.insertbefore(tai_comment.Create(strpnew(s)), p);
+    end;
+{$else DEBUG_AOPTCPU}
+  procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
+    begin
+    end;
+{$endif DEBUG_AOPTCPU}
+
+
+  function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
+    var
+      p: taicpu;
+      i: longint;
+    begin
+      result:=false;
+      if not (assigned(hp) and (hp.typ=ait_instruction)) then
+        exit;
+      p:=taicpu(hp);
+
+      i:=0;
+      while(i<p.ops) do
+        begin
+          case p.oper[I]^.typ of
+            top_reg:
+              result:=(p.oper[I]^.reg=reg) and (p.spilling_get_operation_type(i)<>operand_write);
+            top_ref:
+              result:=
+                (p.oper[I]^.ref^.base=reg);
+          end;
+          if result then exit; {Bailout if we found something}
+          Inc(I);
+        end;
+    end;
+
+
+  function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
+    begin
+      result:=
+        (hp.typ=ait_instruction) and
+        (taicpu(hp).ops>1) and
+        (taicpu(hp).oper[0]^.typ=top_reg) and
+        (taicpu(hp).oper[0]^.reg=reg) and
+        (taicpu(hp).spilling_get_operation_type(0)<>operand_read);
+    end;
+
+
+  function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai; out Next: tai; reg: TRegister): Boolean;
+    begin
+      Next:=Current;
+      repeat
+        Result:=GetNextInstruction(Next,Next);
+      until not (Result) or
+            not(cs_opt_level3 in current_settings.optimizerswitches) or
+            (Next.typ<>ait_instruction) or
+            RegInInstruction(reg,Next) or
+            is_calljmp(taicpu(Next).opcode);
+    end;
+
+
+  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+
+    procedure RemoveInstr(var orig: tai; moveback: boolean = true);
+      var
+        n: tai;
+      begin
+        if moveback and (not GetLastInstruction(orig,n)) then
+          GetNextInstruction(orig,n);
+
+        AsmL.Remove(orig);
+        orig.Free;
+
+        orig:=n;
+      end;
+
+    var
+      hp1: tai;
+    begin
+      result:=false;
+      case p.typ of
+        ait_instruction:
+          begin
+            case taicpu(p).opcode of
+              A_ADDI:
+                begin
+                  {
+                    Changes
+                      addi x, y, #
+                      addi/addiw z, x, #
+                      dealloc x
+                    To
+                      addi z, y, #+#
+                  }
+                  if (taicpu(p).ops=3) and
+                     (taicpu(p).oper[2]^.typ=top_const) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     MatchInstruction(hp1,[A_ADDI,A_ADDIW]) and
+                     (taicpu(hp1).ops=3) and
+                     MatchOperand(taicpu(p).oper[0]^,taicpu(hp1).oper[1]^) and
+                     (taicpu(p).oper[2]^.typ=top_const) and
+                     is_imm12(taicpu(p).oper[2]^.val+taicpu(hp1).oper[2]^.val) and
+                     (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+                     RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                    begin                                                                       
+                      taicpu(hp1).loadreg(1,taicpu(p).oper[1]^.reg);
+                      taicpu(hp1).loadconst(2, taicpu(p).oper[2]^.val+taicpu(hp1).oper[2]^.val);
+
+                      DebugMsg('Peephole AddiAddi2Addi performed', hp1);
+
+                      RemoveInstr(p);
+
+                      result:=true;
+                    end
+                  {
+                    Changes
+                      addi x, x, (ref)
+                      ld/sd y, 0(x)
+                      dealloc x
+                    To
+                      ld/sd y, 0(ref)(x)
+                  }
+                  else if (taicpu(p).ops=3) and
+                     (taicpu(p).oper[2]^.typ=top_ref) and
+                     MatchOperand(taicpu(p).oper[0]^,taicpu(p).oper[1]^) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     MatchInstruction(hp1, [A_LB,A_LBU,A_LH,A_LHU,A_LW,A_LWU,A_LD,
+                                             A_SB,A_SH,A_SW,A_SD]) and
+                     (taicpu(hp1).ops=2) and
+                     (taicpu(hp1).oper[1]^.typ=top_ref) and
+                     (taicpu(hp1).oper[1]^.ref^.base=taicpu(p).oper[0]^.reg) and
+                     (taicpu(hp1).oper[1]^.ref^.offset=0) and
+                     (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+                     RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                    begin
+                      taicpu(hp1).loadref(1,taicpu(p).oper[2]^.ref^);
+                      taicpu(hp1).oper[1]^.ref^.base:=taicpu(p).oper[1]^.reg;
+
+                      DebugMsg('Peephole AddiMem2Mem performed', hp1);
+
+                      RemoveInstr(p);
+
+                      result:=true;
+                    end;
+                end;
+              A_SUB:
+                begin
+                  {
+                    Turn
+                      sub x,y,z
+                      bgeu X0,x,...
+                      dealloc x
+                    Into
+                      bne y,x,...
+                  }
+                  if (taicpu(p).ops=3) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     MatchInstruction(hp1,A_Bxx,[C_GEU,C_EQ]) and
+                     (taicpu(hp1).ops=3) and
+                     MatchOperand(taicpu(hp1).oper[0]^,NR_X0) and
+                     MatchOperand(taicpu(hp1).oper[1]^,taicpu(p).oper[0]^) and
+                     (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+                     (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
+                     RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                    begin
+                      taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
+                      taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
+                      taicpu(hp1).condition:=C_EQ;
+
+                      DebugMsg('Peephole SubBxx2Beq performed', hp1);
+
+                      RemoveInstr(p);
+
+                      result:=true;
+                    end;
+                end;
+              A_SLTU:
+                begin
+                  {
+                    Turn
+                      sltu x,X0,y
+                      beq/bne x, X0, ...
+                      dealloc x
+                    Into
+                      bltu/geu X0, y, ...
+                  }
+                  if (taicpu(p).ops=3) and
+                     MatchOperand(taicpu(p).oper[1]^,NR_X0) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
+                     (taicpu(hp1).ops=3) and
+                     MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
+                     MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
+                     (not RegModifiedBetween(taicpu(p).oper[2]^.reg, p,hp1)) and
+                     RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                    begin    
+                      taicpu(hp1).loadreg(0,NR_X0);
+                      taicpu(hp1).loadreg(1,taicpu(p).oper[2]^.reg);
+
+                      if taicpu(hp1).condition=C_NE then
+                        taicpu(hp1).condition:=C_LTU
+                      else
+                        taicpu(hp1).condition:=C_GEU;
+
+                      DebugMsg('Peephole SltuB2B performed', hp1);
+
+                      RemoveInstr(p);
+
+                      result:=true;
+                    end;
+                end;
+              A_SLTIU:
+                begin
+                  {
+                    Turn
+                      sltiu x,y,1
+                      beq/ne x,x0,...
+                      dealloc x
+                    Into
+                      bne y,x0,...
+                  }
+                  if (taicpu(p).ops=3) and
+                     (taicpu(p).oper[2]^.typ=top_const) and
+                     (taicpu(p).oper[2]^.val=1) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     MatchInstruction(hp1,A_Bxx,[C_NE,C_EQ]) and
+                     (taicpu(hp1).ops=3) and
+                     MatchOperand(taicpu(hp1).oper[0]^,taicpu(p).oper[0]^) and
+                     MatchOperand(taicpu(hp1).oper[1]^,NR_X0) and
+                     (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+                     RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                    begin
+                      taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
+                      taicpu(hp1).condition:=inverse_cond(taicpu(hp1).condition);
+
+                      DebugMsg('Peephole Sltiu0B2B performed', hp1);
+
+                      RemoveInstr(p);
+
+                      result:=true;
+                    end;
+                end;
+              A_SLTI:
+                begin
+                  {
+                    Turn
+                      slti x,y,0
+                      beq/ne x,x0,...
+                      dealloc x
+                    Into
+                      bge/lt y,x0,...
+                  }
+                  if (taicpu(p).ops=3) and
+                     (taicpu(p).oper[2]^.typ=top_const) and
+                     (taicpu(p).oper[2]^.val=0) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     (hp1.typ=ait_instruction) and
+                     (taicpu(hp1).opcode=A_Bxx) and
+                     (taicpu(hp1).ops=3) and
+                     (taicpu(hp1).oper[0]^.typ=top_reg) and
+                     (taicpu(hp1).oper[0]^.reg=taicpu(p).oper[0]^.reg) and
+                     (taicpu(hp1).oper[1]^.typ=top_reg) and
+                     (taicpu(hp1).oper[1]^.reg=NR_X0) and
+                     (taicpu(hp1).condition in [C_NE,C_EQ]) and
+                     (not RegModifiedBetween(taicpu(p).oper[1]^.reg, p,hp1)) and
+                     RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                    begin
+                      taicpu(hp1).loadreg(0,taicpu(p).oper[1]^.reg);
+                      taicpu(hp1).loadreg(1,NR_X0);
+
+                      if taicpu(hp1).condition=C_NE then
+                        taicpu(hp1).condition:=C_LT
+                      else
+                        taicpu(hp1).condition:=C_GE;
+
+                      DebugMsg('Peephole Slti0B2B performed', hp1);
+
+                      RemoveInstr(p);
+
+                      result:=true;
+                    end;
+                end;
+            end;
+          end;
+      end;
+    end;
+
+begin
+  casmoptimizer := TCpuAsmOptimizer;
+end.

+ 116 - 0
compiler/riscv64/aoptcpub.pas

@@ -0,0 +1,116 @@
+{
+   Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+   Development Team
+
+   This unit contains several types and constants necessary for the
+   optimizer to work on the RiscV64 architecture
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+****************************************************************************
+}
+unit aoptcpub; { Assembler OPTimizer CPU specific Base }
+
+{$I fpcdefs.inc}
+
+{ enable the following define if memory references can have a scaled index }
+{ define RefsHaveScale}
+
+{ enable the following define if memory references can have a segment }
+{ override                                                            }
+{ define RefsHaveSegment}
+
+interface
+
+uses
+  aasmcpu, AOptBase, cpubase;
+
+type
+
+  { type of a normal instruction }
+  TInstr = Taicpu;
+  PInstr = ^TInstr;
+
+  { ************************************************************************* }
+  { **************************** TCondRegs ********************************** }
+  { ************************************************************************* }
+  { Info about the conditional registers                                      }
+  TCondRegs = object
+    constructor Init;
+    destructor Done;
+  end;
+
+  { ************************************************************************* }
+  { **************************** TAoptBaseCpu ******************************* }
+  { ************************************************************************* }
+
+  TAoptBaseCpu = class(TAoptBase)
+  end;
+
+  { ************************************************************************* }
+  { ******************************* Constants ******************************* }
+  { ************************************************************************* }
+const
+
+  { the maximum number of things (registers, memory, ...) a single instruction }
+  { changes                                                                    }
+
+  MaxCh = 3;
+
+  { the maximum number of operands an instruction has }
+
+  MaxOps = 5;
+
+  {Oper index of operand that contains the source (reference) with a load }
+  {instruction                                                            }
+
+  LoadSrc = 1;
+
+  {Oper index of operand that contains the destination (register) with a load }
+  {instruction                                                                }
+
+  LoadDst = 0;
+
+  {Oper index of operand that contains the source (register) with a store }
+  {instruction                                                            }
+
+  StoreSrc = 0;
+
+  {Oper index of operand that contains the destination (reference) with a load }
+  {instruction                                                                 }
+
+  StoreDst = 1;
+
+  aopt_uncondjmp = A_JAL;
+  aopt_condjmp = A_Bxx;
+
+implementation
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+
+constructor TCondRegs.init;
+begin
+end;
+
+destructor TCondRegs.Done;
+{$IFDEF inl}inline;
+{$ENDIF inl}
+begin
+end;
+
+end.
+

+ 40 - 0
compiler/riscv64/aoptcpuc.pas

@@ -0,0 +1,40 @@
+{
+   Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+   Development Team
+
+   This unit contains the processor specific implementation of the
+   assembler optimizer common subexpression elimination object.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+****************************************************************************
+}
+unit aoptcpuc;
+
+interface
+
+{$I fpcdefs.inc}
+
+uses
+  AOptCs;
+
+type
+  TRegInfoCpu = object(TRegInfo)
+  end;
+
+implementation
+
+end.
+

+ 40 - 0
compiler/riscv64/aoptcpud.pas

@@ -0,0 +1,40 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit contains the processor specific implementation of the
+    assembler optimizer data flow analyzer.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aoptcpud;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+  AOptDA;
+
+type
+  TAOptDFACpu = class(TAOptDFA)
+  end;
+
+implementation
+
+end.
+

+ 642 - 0
compiler/riscv64/cgcpu.pas

@@ -0,0 +1,642 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the code generator for the RiscV64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cgcpu;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      globtype, symtype, symdef, symsym,
+      cgbase, cgobj,cgrv,
+      aasmbase, aasmcpu, aasmtai,aasmdata,
+      cpubase, cpuinfo, cgutils, rgcpu,
+      parabase;
+
+    type
+      tcgrv64 = class(tcgrv)
+        procedure init_register_allocators; override;
+        procedure done_register_allocators; override;
+
+        { move instructions }
+        procedure a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;     
+        procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister); override;
+
+        procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
+        procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation); override;
+
+        procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
+
+        procedure g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean); override;
+        procedure g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean); override;
+
+        procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+        procedure g_concatcopy(list: TAsmList; const source, dest: treference; len: aint); override;
+      end;
+
+    procedure create_codegen;
+
+implementation
+
+    uses
+      sysutils, cclasses,
+      globals, verbose, systems, cutils,
+      symconst, fmodule, symtable,
+      rgobj, tgobj, cpupi, procinfo, paramgr, cpupara;
+
+
+    procedure tcgrv64.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+        rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+          [RS_X10,RS_X11,RS_X12,RS_X13,RS_X14,RS_X15,RS_X16,RS_X17,
+           RS_X31,RS_X30,RS_X29,RS_X28,
+           RS_X5,RS_X6,RS_X7,
+           RS_X9,RS_X27,RS_X26,RS_X25,RS_X24,RS_X23,RS_X22,
+           RS_X21,RS_X20,RS_X19,RS_X18],first_int_imreg,[]);
+        rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
+          [RS_F10,RS_F11,RS_F12,RS_F13,RS_F14,RS_F15,RS_F16,RS_F17,
+           RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7,
+           RS_F28,RS_F29,RS_F30,RS_F31,
+           RS_F8,RS_F9,
+           RS_F27,
+           RS_F26,RS_F25,RS_F24,RS_F23,RS_F22,RS_F21,RS_F20,RS_F19,RS_F18],first_fpu_imreg,[]);
+      end;
+
+
+    procedure tcgrv64.done_register_allocators;
+      begin
+        rg[R_INTREGISTER].free;
+        rg[R_FPUREGISTER].free;
+        inherited done_register_allocators;
+      end;
+
+
+    procedure tcgrv64.a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);
+      var
+        ai: taicpu;
+      begin
+        list.concat(tai_comment.Create(strpnew('Move '+tcgsize2str(fromsize)+'->'+tcgsize2str(tosize))));
+
+        if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_S32) then
+          list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
+        else if (tosize=OS_S32) and (tcgsize2unsigned[fromsize]=OS_64) then
+          list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
+        else if (tcgsize2unsigned[tosize]=OS_64) and (fromsize=OS_8) then
+          list.Concat(taicpu.op_reg_reg_const(A_ANDI,reg2,reg1,$FF))
+        else if (tcgsize2size[fromsize] > tcgsize2size[tosize]) or
+          ((tcgsize2size[fromsize] = tcgsize2size[tosize]) and (fromsize <> tosize)) or
+          { do we need to mask out the sign when loading from smaller signed to larger unsigned type? }
+          ((tcgsize2unsigned[fromsize]<>fromsize) and ((tcgsize2unsigned[tosize]=tosize)) and
+            (tcgsize2size[fromsize] < tcgsize2size[tosize]) and (tcgsize2size[tosize] <> sizeof(pint)) ) then
+          begin
+            if tcgsize2size[fromsize]<tcgsize2size[tosize] then
+              begin
+                list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(8-tcgsize2size[fromsize])));
+
+                if tcgsize2unsigned[fromsize]<>fromsize then
+                  list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(tcgsize2size[tosize]-tcgsize2size[fromsize])))
+                else
+                  list.Concat(taicpu.op_reg_reg_const(A_SRLI,reg2,reg2,8*(tcgsize2size[tosize]-tcgsize2size[fromsize])));
+              end
+            else if tcgsize2unsigned[tosize]<>OS_64 then
+              list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(8-tcgsize2size[tosize])))
+            else
+              a_load_reg_reg(list,tosize,tosize,reg1,reg2);
+
+            if tcgsize2unsigned[tosize]=tosize then
+              list.Concat(taicpu.op_reg_reg_const(A_SRLI,reg2,reg2,8*(8-tcgsize2size[tosize])))
+            else
+              list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(8-tcgsize2size[tosize])));
+          end
+        else
+          begin
+            ai:=taicpu.op_reg_reg_const(A_ADDI,reg2,reg1,0);
+            list.concat(ai);
+            rg[R_INTREGISTER].add_move_instruction(ai);
+          end;
+      end;
+
+    procedure tcgrv64.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; register: tregister);
+      var
+        l: TAsmLabel;
+        hr: treference;
+      begin
+        if a=0 then
+          a_load_reg_reg(list,size,size,NR_X0,register)
+        else
+          begin
+            if is_imm12(a) then
+              list.concat(taicpu.op_reg_reg_const(A_ADDI,register,NR_X0,a))
+            else if is_lui_imm(a) then
+              list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF))
+            else if (int64(longint(a))=a) then
+              begin
+                if (a and $800)<>0 then
+                  list.concat(taicpu.op_reg_const(A_LUI,register,((a shr 12)+1) and $FFFFF))
+                else
+                  list.concat(taicpu.op_reg_const(A_LUI,register,(a shr 12) and $FFFFF));
+
+                list.concat(taicpu.op_reg_reg_const(A_ADDIW,register,register,SarSmallint(a shl 4,4)));
+              end
+            else
+              begin
+                reference_reset(hr,8,[]);
+
+                current_asmdata.getjumplabel(l);
+                current_procinfo.aktlocaldata.Concat(cai_align.Create(8));
+                cg.a_label(current_procinfo.aktlocaldata,l);
+                hr.symboldata:=current_procinfo.aktlocaldata.last;
+                current_procinfo.aktlocaldata.concat(tai_const.Create_64bit(a));
+
+                hr.symbol:=l;
+                hr.refaddr:=addr_pcrel_hi20;
+
+                current_asmdata.getjumplabel(l);
+                a_label(list,l);
+
+                list.concat(taicpu.op_reg_ref(A_AUIPC,register,hr));
+
+                reference_reset_symbol(hr,l,0,0,[]);
+                hr.refaddr:=addr_pcrel_lo12;
+                hr.base:=register;
+                list.concat(taicpu.op_reg_ref(A_LD,register,hr));
+              end;
+          end;
+      end;
+
+
+    procedure tcgrv64.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
+      var
+        signed: Boolean;
+        l: TAsmLabel;
+        tmpreg: tregister;
+        ai: taicpu;
+      begin
+        if setflags then
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_const_reg(list,size,a,tmpreg);
+            a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
+          end
+        else
+          a_op_const_reg_reg(list,op,size,a,src,dst);
+      end;
+
+
+    procedure tcgrv64.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
+        var
+        signed: Boolean;
+        l: TAsmLabel;
+        tmpreg, tmpreg0: tregister;
+        ai: taicpu;
+      begin
+        signed:=tcgsize2unsigned[size]<>size;
+
+        if setflags then
+          case op of
+            OP_ADD:
+              begin
+                current_asmdata.getjumplabel(l);
+
+                list.Concat(taicpu.op_reg_reg_reg(A_ADD,dst,src2,src1));
+
+                if signed then
+                  begin
+                    {
+                      t0=src1<0
+                      t1=result<src2
+                      overflow if t0<>t1
+                    }
+                    tmpreg0:=getintregister(list,OS_INT);
+                    tmpreg:=getintregister(list,OS_INT);
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,src1,NR_X0));
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src2));
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
+                    ai.condition:=C_EQ;
+                    list.concat(ai);
+                  end
+                else
+                  begin
+                    {
+                      jump if sum>=x
+                    }
+                    if size in [OS_S32,OS_32] then
+                      begin
+                        tmpreg:=getintregister(list,OS_INT);
+                        a_load_reg_reg(list,size,OS_64,dst,tmpreg);
+                        dst:=tmpreg;
+                      end;
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,dst,src2,l,0);
+                    ai.condition:=C_GEU;
+                    list.concat(ai);
+                  end;
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_SUB:
+              begin
+                current_asmdata.getjumplabel(l);
+
+                list.Concat(taicpu.op_reg_reg_reg(A_SUB,dst,src2,src1));
+
+                if signed then
+                  begin
+                    tmpreg0:=getintregister(list,OS_INT);
+                    tmpreg:=getintregister(list,OS_INT);
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg0,NR_X0,src1));
+                    list.Concat(taicpu.op_reg_reg_reg(A_SLT,tmpreg,dst,src2));
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,tmpreg,tmpreg0,l,0);
+                    ai.condition:=C_EQ;
+                    list.concat(ai);
+                  end
+                else
+                  begin
+                    { no overflow if result<=src2 }
+                    if size in [OS_S32,OS_32] then
+                      begin
+                        tmpreg:=getintregister(list,OS_INT);
+                        a_load_reg_reg(list,size,OS_64,dst,tmpreg);
+                        dst:=tmpreg;
+                      end;
+
+                    ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,src2,dst,l,0);
+                    ai.condition:=C_GEU;
+                    list.concat(ai);
+                  end;
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_IMUL:
+              begin
+                { No overflow if upper result is same as sign of result }
+                current_asmdata.getjumplabel(l);
+
+                tmpreg:=getintregister(list,OS_INT);
+                tmpreg0:=getintregister(list,OS_INT);
+                list.Concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2));
+                list.Concat(taicpu.op_reg_reg_reg(A_MULH,tmpreg,src1,src2));
+
+                list.concat(taicpu.op_reg_reg_const(A_SRAI,tmpreg0,dst,63));
+
+                a_cmp_reg_reg_label(list,OS_INT,OC_EQ,tmpreg,tmpreg0,l);
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_MUL:
+              begin
+                { No overflow if upper result is 0 }
+                current_asmdata.getjumplabel(l);
+
+                tmpreg:=getintregister(list,OS_INT);
+                list.Concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2));
+                list.Concat(taicpu.op_reg_reg_reg(A_MULHU,tmpreg,src1,src2));
+
+                a_cmp_reg_reg_label(list,OS_INT,OC_EQ,tmpreg,NR_X0,l);
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+            OP_IDIV:
+              begin
+                { Only overflow if dst is all 1's }
+                current_asmdata.getjumplabel(l);
+
+                tmpreg:=getintregister(list,OS_INT);
+                list.Concat(taicpu.op_reg_reg_reg(A_DIV,dst,src1,src2));
+                list.Concat(taicpu.op_reg_reg_const(A_ADDI,tmpreg,dst,1));
+
+                a_cmp_reg_reg_label(list,OS_INT,OC_NE,tmpreg,NR_X0,l);
+
+                a_call_name(list,'FPC_OVERFLOW',false);
+                a_label(list,l);
+              end;
+          end
+        else
+          a_op_reg_reg_reg(list,op,size,src1,src2,dst);
+      end;
+
+
+    procedure tcgrv64.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
+      begin
+      end;
+
+
+    procedure tcgrv64.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
+      var
+        regs, fregs: tcpuregisterset;
+        r: TSuperRegister;
+        href: treference;
+        stackcount, stackAdjust: longint;
+      begin
+        if not(nostackframe) then
+          begin
+            a_reg_alloc(list,NR_STACK_POINTER_REG);
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              a_reg_alloc(list,NR_FRAME_POINTER_REG);
+
+            reference_reset_base(href,NR_STACK_POINTER_REG,-8,ctempposinvalid,0,[]);
+
+            { Int registers }
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+            if (pi_do_call in current_procinfo.flags) then
+              regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+            stackcount:=0;
+            for r:=RS_X0 to RS_X31 do
+              if r in regs then
+                inc(stackcount,8);
+
+            { Float registers }
+            fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                inc(stackcount,8);  
+
+            inc(localsize,stackcount);
+            if not is_imm12(-(localsize-stackcount)) then
+              begin
+                if not (RS_RETURN_ADDRESS_REG in regs) then
+                  begin
+                    include(regs,RS_RETURN_ADDRESS_REG);
+                    inc(localsize,8);
+                    inc(stackcount,8);
+                  end;
+              end;
+
+            stackAdjust:=0;
+            if (CPURV_HAS_COMPACT in cpu_capabilities[current_settings.cputype]) and
+               (stackcount>0) then
+              begin
+                list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-stackcount));
+                inc(href.offset,stackcount);
+                stackAdjust:=stackcount;
+                dec(localsize,stackcount);
+              end;
+
+            for r:=RS_X0 to RS_X31 do
+              if r in regs then
+                begin
+                  list.concat(taicpu.op_reg_ref(A_SD,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+                  dec(href.offset,8);
+                end;
+
+            { Float registers }
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                begin
+                  list.concat(taicpu.op_reg_ref(A_FSD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+                  dec(href.offset,8);
+                end;   
+
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG,stackAdjust));
+
+            if localsize>0 then
+              begin
+                localsize:=align(localsize,8);
+
+                if is_imm12(-localsize) then
+                  list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,-localsize))
+                else
+                  begin
+                    a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+                    list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+                  end;
+              end;
+          end;
+      end;
+
+
+    procedure tcgrv64.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
+      var
+        r: tsuperregister;
+        regs, fregs: tcpuregisterset;
+        localsize: longint;
+        href: treference;
+      begin
+        if not(nostackframe) then
+          begin
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              regs:=regs+[RS_FRAME_POINTER_REG,RS_RETURN_ADDRESS_REG];
+
+            if (pi_do_call in current_procinfo.flags) then
+              regs:=regs+[RS_RETURN_ADDRESS_REG];
+
+            reference_reset_base(href,NR_STACK_POINTER_REG,-8,ctempposinvalid,0,[]);
+            for r:=RS_X31 downto RS_X0 do
+              if r in regs then
+                dec(href.offset,8);
+
+            { Float registers }
+            fregs:=rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+            for r:=RS_F0 to RS_F31 do
+              if r in fregs then
+                dec(href.offset,8);
+
+            localsize:=current_procinfo.calc_stackframe_size+(-href.offset-8);
+            if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
+              list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG,0))
+            else if localsize>0 then
+              begin                 
+                localsize:=align(localsize,8);
+
+                if is_imm12(localsize) then
+                  list.concat(taicpu.op_reg_reg_const(A_ADDI,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
+                else
+                  begin
+                    if not (RS_RETURN_ADDRESS_REG in regs) then
+                      begin
+                        include(regs,RS_RETURN_ADDRESS_REG);
+                        dec(href.offset,8);
+                        inc(localsize,8);
+                      end;
+
+                    a_load_const_reg(list,OS_INT,localsize,NR_RETURN_ADDRESS_REG);
+                    list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_RETURN_ADDRESS_REG));
+                  end;
+              end;
+
+            { Float registers }
+            for r:=RS_F31 downto RS_F0 do
+              if r in fregs then
+                begin
+                  inc(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_FLD,newreg(R_FPUREGISTER,r,R_SUBWHOLE),href));
+                end;
+
+            for r:=RS_X31 downto RS_X0 do
+              if r in regs then
+                begin
+                  inc(href.offset,8);
+                  list.concat(taicpu.op_reg_ref(A_LD,newreg(R_INTREGISTER,r,R_SUBWHOLE),href));
+                end;
+          end;
+
+        list.concat(taicpu.op_reg_reg(A_JALR,NR_X0,NR_RETURN_ADDRESS_REG));
+      end;
+
+
+    procedure tcgrv64.g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
+      var
+        paraloc1, paraloc2, paraloc3: TCGPara;
+        pd: tprocdef;
+      begin
+        pd:=search_system_proc('MOVE');
+        paraloc1.init;
+        paraloc2.init;
+        paraloc3.init;
+        paramanager.getintparaloc(list, pd, 1, paraloc1);
+        paramanager.getintparaloc(list, pd, 2, paraloc2);
+        paramanager.getintparaloc(list, pd, 3, paraloc3);
+        a_load_const_cgpara(list, OS_SINT, len, paraloc3);
+        a_loadaddr_ref_cgpara(list, dest, paraloc2);
+        a_loadaddr_ref_cgpara(list, Source, paraloc1);
+        paramanager.freecgpara(list, paraloc3);
+        paramanager.freecgpara(list, paraloc2);
+        paramanager.freecgpara(list, paraloc1);
+        alloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+        alloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+        a_call_name(list, 'FPC_MOVE', false);
+        dealloccpuregisters(list, R_FPUREGISTER, paramanager.get_volatile_registers_fpu(pocall_default));
+        dealloccpuregisters(list, R_INTREGISTER, paramanager.get_volatile_registers_int(pocall_default));
+        paraloc3.done;
+        paraloc2.done;
+        paraloc1.done;
+      end;
+
+    procedure tcgrv64.g_concatcopy(list: TAsmList; const source, dest: treference; len: aint);
+      var
+        tmpreg1, hreg, countreg: TRegister;
+        src, dst, src2, dst2: TReference;
+        lab:      tasmlabel;
+        Count, count2: aint;
+      begin
+        src2:=source;
+        fixref(list,src2);
+
+        dst2:=dest;
+        fixref(list,dst2);
+
+        if len > high(longint) then
+          internalerror(2002072704);
+        { A call (to FPC_MOVE) requires the outgoing parameter area to be properly
+          allocated on stack. This can only be done before tmipsprocinfo.set_first_temp_offset,
+          i.e. before secondpass. Other internal procedures request correct stack frame
+          by setting pi_do_call during firstpass, but for this particular one it is impossible.
+          Therefore, if the current procedure is a leaf one, we have to leave it that way. }
+
+        { anybody wants to determine a good value here :)? }
+        if (len > 100) and
+           assigned(current_procinfo) and
+           (pi_do_call in current_procinfo.flags) then
+          g_concatcopy_move(list, src2, dst2, len)
+        else
+        begin
+          Count := len div 8;
+          reference_reset(src,sizeof(aint),[]);
+          { load the address of src2 into src.base }
+          src.base := GetAddressRegister(list);
+          a_loadaddr_ref_reg(list, src2, src.base);
+
+          reference_reset(dst,sizeof(aint),[]);
+          { load the address of dst2 into dst.base }
+          dst.base := GetAddressRegister(list);
+          a_loadaddr_ref_reg(list, dst2, dst.base);
+
+          { generate a loop }
+          if Count > 4 then
+          begin
+            countreg := GetIntRegister(list, OS_INT);
+            tmpreg1  := GetIntRegister(list, OS_INT);
+            a_load_const_reg(list, OS_INT, Count, countreg);
+            current_asmdata.getjumplabel(lab);
+            a_label(list, lab);
+            list.concat(taicpu.op_reg_ref(A_LD, tmpreg1, src));
+            list.concat(taicpu.op_reg_ref(A_SD, tmpreg1, dst));
+            list.concat(taicpu.op_reg_reg_const(A_ADDI, src.base, src.base, 8));
+            list.concat(taicpu.op_reg_reg_const(A_ADDI, dst.base, dst.base, 8));
+            list.concat(taicpu.op_reg_reg_const(A_ADDI, countreg, countreg, -1));
+            a_cmp_reg_reg_label(list,OS_INT,OC_GT,NR_X0,countreg,lab);
+            len := len mod 8;
+          end;
+          { unrolled loop }
+          Count := len div 8;
+          if Count > 0 then
+          begin
+            tmpreg1 := GetIntRegister(list, OS_INT);
+            count2 := 1;
+            while count2 <= Count do
+              begin
+                list.concat(taicpu.op_reg_ref(A_LD, tmpreg1, src));
+                list.concat(taicpu.op_reg_ref(A_SD, tmpreg1, dst));
+                Inc(src.offset, 8);
+                Inc(dst.offset, 8);
+                Inc(count2);
+              end;
+            len := len mod 8;
+          end;
+          if (len and 4) <> 0 then
+          begin
+            hreg := GetIntRegister(list, OS_INT);
+            a_load_ref_reg(list, OS_32, OS_32, src, hreg);
+            a_load_reg_ref(list, OS_32, OS_32, hreg, dst);
+            Inc(src.offset, 4);
+            Inc(dst.offset, 4);
+          end;
+          { copy the leftovers }
+          if (len and 2) <> 0 then
+          begin
+            hreg := GetIntRegister(list, OS_INT);
+            a_load_ref_reg(list, OS_16, OS_16, src, hreg);
+            a_load_reg_ref(list, OS_16, OS_16, hreg, dst);
+            Inc(src.offset, 2);
+            Inc(dst.offset, 2);
+          end;
+          if (len and 1) <> 0 then
+          begin
+            hreg := GetIntRegister(list, OS_INT);
+            a_load_ref_reg(list, OS_8, OS_8, src, hreg);
+            a_load_reg_ref(list, OS_8, OS_8, hreg, dst);
+          end;
+        end;
+      end;
+
+procedure create_codegen;
+begin
+  cg := tcgrv64.create;
+  cg128:=tcg128.create;
+end;
+
+end.

+ 462 - 0
compiler/riscv64/cpubase.pas

@@ -0,0 +1,462 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Contains the base types for the RiscV64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+{ This Unit contains the base types for the RiscV64
+}
+unit cpubase;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+  strings, globtype,
+  cutils, cclasses, aasmbase, cpuinfo, cgbase;
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+type
+      TAsmOp=(A_None,
+        { Pseudo instructions }
+        A_NOP,
+        { normal opcodes }
+        A_LUI,A_AUIPC,A_JAL,A_JALR,
+        A_Bxx,A_LB,A_LH,A_LW,A_LBU,A_LHU,
+        A_SB,A_SH,A_SW,
+        A_ADDI,A_SLTI,A_SLTIU,
+        A_XORI,A_ORI,A_ANDI,
+        A_SLLI,A_SRLI,A_SRAI,
+        A_ADD,A_SUB,A_SLL,A_SLT,A_SLTU,
+        A_XOR,A_SRL,A_SRA,A_OR,A_AND,
+        A_FENCE,A_FENCE_I,
+        A_ECALL,A_EBREAK,
+        A_CSRRW,A_CSRRS,A_CSRRC,A_CSRRWI,A_CSRRSI,A_CSRRCI,
+        { 64-bit }
+        A_ADDIW,A_SLLIW,A_SRLIW,A_SRAIW,
+        A_ADDW,A_SLLW,A_SRLW,A_SUBW,A_SRAW,
+        A_LD,A_SD,A_LWU,
+
+        { M-extension }
+        A_MUL,A_MULH,A_MULHSU,A_MULHU,
+        A_DIV,A_DIVU,A_REM,A_REMU,
+        { 64-bit }
+        A_MULW,
+        A_DIVW,A_DIVUW,A_REMW,A_REMUW,
+
+        { A-extension }
+        A_LR_W,A_SC_W,A_AMOSWAP_W,A_AMOADD_W,A_AMOXOR_W,A_AMOAND_W,
+        A_AMOOR_W,A_AMOMIN_W,A_AMOMAX_W,A_AMOMINU_W,A_AMOMAXU_W,
+        { 64-bit }
+        A_LR_D,A_SC_D,A_AMOSWAP_D,A_AMOADD_D,A_AMOXOR_D,A_AMOAND_D,
+        A_AMOOR_D,A_AMOMIN_D,A_AMOMAX_D,A_AMOMINU_D,A_AMOMAXU_D,
+
+        { F-extension }
+        A_FLW,A_FSW,
+        A_FMADD_S,A_FMSUB_S,A_FNMSUB_S,A_FNMADD_S,
+        A_FADD_S,A_FSUB_S,A_FMUL_S,A_FDIV_S,
+        A_FSQRT_S,A_FSGNJ_S,A_FSGNJN_S,A_FSGNJX_S,
+        A_FMIN_S,A_FMAX_S,
+        A_FMV_X_S,A_FEQ_S,A_FLT_S,A_FLE_S,A_FCLASS_S,
+        A_FCVT_W_S,A_FCVT_WU_S,A_FCVT_S_W,A_FCVT_S_WU,
+        A_FMV_S_X,
+        A_FRCSR,A_FRRM,A_FRFLAGS,A_FSCSR,A_FSRM,
+        A_FSFLAGS,A_FSRMI,A_FSFLAGSI,
+        { 64-bit }
+        A_FCVT_L_S,A_FCVT_LU_S,
+        A_FCVT_S_L,A_FCVT_S_LU,
+
+        { D-extension }
+        A_FLD,A_FSD,
+        A_FMADD_D,A_FMSUB_D,A_FNMSUB_D,A_FNMADD_D,
+        A_FADD_D,A_FSUB_D,A_FMUL_D,A_FDIV_D,
+        A_FSQRT_D,A_FSGNJ_D,A_FSGNJN_D,A_FSGNJX_D,
+        A_FMIN_D,A_FMAX_D,
+        A_FEQ_D,A_FLT_D,A_FLE_D,A_FCLASS_D,
+        A_FCVT_D_S,A_FCVT_S_D,
+        A_FCVT_W_D,A_FCVT_WU_D,A_FCVT_D_W,A_FCVT_D_WU,
+        { 64-bit }
+        A_FCVT_L_D,A_FCVT_LU_D,A_FMV_X_D,
+        A_FCVT_D_L,A_FCVT_D_LU,A_FMV_D_X,
+
+        { Machine mode }
+        A_MRET,A_HRET,A_SRET,A_URET,
+        A_WFI,
+
+        { Supervisor }
+        A_SFENCE_VM
+        );
+
+  TAsmOps = set of TAsmOp;
+
+  {# This should define the array of instructions as string }
+  op2strtable = array[tasmop] of string[8];
+
+const
+  {# First value of opcode enumeration }
+  firstop = low(tasmop);
+  {# Last value of opcode enumeration  }
+  lastop = high(tasmop);
+
+  {*****************************************************************************
+                                    Registers
+  *****************************************************************************}
+
+type
+      { Number of registers used for indexing in tables }
+      tregisterindex=0..{$i rrv32nor.inc}-1;
+      totherregisterset = set of tregisterindex;
+
+    const
+      maxvarregs = 32-6; { 32 int registers - r0 - stackpointer - r2 - 3 scratch registers }
+      maxfpuvarregs = 28; { 32 fpuregisters - some scratch registers (minimally 2) }
+      { Available Superregisters }
+      {$i rrv32sup.inc}
+
+      { No Subregisters }
+      R_SUBWHOLE=R_SUBNONE;
+
+      { Available Registers }
+      {$i rrv32con.inc}
+
+      { Integer Super registers first and last }
+      first_int_imreg = $20;
+
+      { Float Super register first and last }
+      first_fpu_imreg     = $20;
+
+      { MM Super register first and last }
+      first_mm_imreg     = $20;
+
+{ TODO: Calculate bsstart}
+      regnumber_count_bsstart = 64;
+
+      regnumber_table : array[tregisterindex] of tregister = (
+        {$i rrv32num.inc}
+      );
+
+      regstabs_table : array[tregisterindex] of shortint = (
+        {$i rrv32sta.inc}
+      );
+
+      regdwarf_table : array[tregisterindex] of shortint = (
+        {$i rrv32dwa.inc}
+      );
+
+{*****************************************************************************
+                                Operands
+*****************************************************************************}
+    type
+      TMemoryOrderingFlag = (moRl, moAq);
+      TMemoryOrdering = set of TMemoryOrderingFlag;
+
+      TFenceFlag = (ffI, ffO, ffR, ffW);
+      TFenceFlags = set of TFenceFlag;
+
+      TRoundingMode = (RM_Default,
+                       RM_RNE,
+                       RM_RTZ,
+                       RM_RDN,
+                       RM_RUP,
+                       RM_RMM);
+
+    const
+      roundingmode2str : array[TRoundingMode] of string[3] = ('',
+        'rne','rtz','rdn','rup','rmm');
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+    type
+      TAsmCond = (C_None { unconditional jumps },
+        C_LT,C_LTU,C_GE,C_GEU,C_NE,C_EQ);
+
+      TAsmConds = set of TAsmCond;
+
+    const
+      cond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+        { conditions when not using ctr decrement etc}
+        'lt','ltu','ge','geu','ne','eq');
+
+      uppercond2str: Array[TAsmCond] of string[4] = ({cf_none}'',
+        { conditions when not using ctr decrement etc}
+        'LT','LTU','GE','GEU','NE','EQ');
+
+  {*****************************************************************************
+                                     Flags
+  *****************************************************************************}
+
+type
+      TResFlagsEnum = (F_EQ,F_NE,F_LT,F_LTU,F_GE,F_GEU);
+
+{*****************************************************************************
+                              Reference
+*****************************************************************************}
+
+  {*****************************************************************************
+                                  Operand Sizes
+  *****************************************************************************}
+
+  {*****************************************************************************
+                                   Constants
+  *****************************************************************************}
+
+const
+  max_operands = 5;
+
+  {*****************************************************************************
+                            Default generic sizes
+  *****************************************************************************}
+
+  {# Defines the default address size for a processor, }
+  OS_ADDR = OS_64;
+  {# the natural int size for a processor,
+     has to match osuinttype/ossinttype as initialized in psystem }
+  OS_INT = OS_64;
+  OS_SINT = OS_S64;
+  {# the maximum float size for a processor,           }
+  OS_FLOAT = OS_F64;
+  {# the size of a vector register for a processor     }
+  OS_VECTOR = OS_M128;
+
+  {*****************************************************************************
+                                 GDB Information
+  *****************************************************************************}
+
+  stab_regindex: array[tregisterindex] of shortint = (
+{$I rrv32sta.inc}
+    );
+
+  {*****************************************************************************
+                            Generic Register names
+  *****************************************************************************}
+
+      {# Stack pointer register }
+      NR_STACK_POINTER_REG = NR_X2;
+      RS_STACK_POINTER_REG = RS_X2;
+      {# Frame pointer register }
+      NR_FRAME_POINTER_REG = NR_X8;
+      RS_FRAME_POINTER_REG = RS_X8;
+
+      NR_PIC_OFFSET_REG = NR_X3;
+      { Return address of a function }
+      NR_RETURN_ADDRESS_REG = NR_X1;
+      RS_RETURN_ADDRESS_REG = RS_X1;
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_X10;
+      RS_FUNCTION_RETURN_REG = RS_X10;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_X10;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_X10;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_X11;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_X11;
+      { The value returned from a function is available in this register }
+      NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
+      RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
+      { The lowh part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
+      RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
+      { The high part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
+      RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
+
+      NR_FPU_RESULT_REG = NR_F10;
+      NR_MM_RESULT_REG = NR_NO;
+
+      NR_DEFAULTFLAGS = NR_NO;
+      RS_DEFAULTFLAGS = RS_NO;
+
+  {*****************************************************************************
+                         GCC /ABI linking information
+  *****************************************************************************}
+
+  {# Registers which must be saved when calling a routine declared as
+     cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
+     saved should be the ones as defined in the target ABI and / or GCC.
+
+     This value can be deduced from CALLED_USED_REGISTERS array in the
+     GCC source.
+  }
+  saved_standard_registers: array[0..12] of tsuperregister = (
+        RS_X2,
+        RS_X8,RS_X9,
+        RS_X18,RS_X19,
+        RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27
+    );
+
+      { this is only for the generic code which is not used for this architecture }
+      saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID);
+      saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID);
+
+      {# Required parameter alignment when calling a routine declared as
+         stdcall and cdecl. The alignment value should be the one defined
+         by GCC or the target ABI.
+
+         The value of this constant is equal to the constant
+         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
+      }
+      std_param_align = 8;  { for 32-bit version only }
+
+
+{*****************************************************************************
+                            CPU Dependent Constants
+*****************************************************************************}
+
+      maxfpuregs = 8;
+
+  {*****************************************************************************
+                                    Helpers
+  *****************************************************************************}
+
+    function is_imm12(value: aint): boolean;
+    function is_lui_imm(value: aint): boolean;
+
+    function is_calljmp(o:tasmop):boolean;
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+    { Returns the tcgsize corresponding with the size of reg.}
+    function reg_cgsize(const reg: tregister) : tcgsize;
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+    function std_regnum_search(const s:string):Tregister;
+    function std_regname(r:Tregister):string;
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+    function dwarf_reg(r:tregister):shortint;
+
+    function conditions_equal(const c1,c2: TAsmCond): boolean;
+
+implementation
+
+    uses
+      rgbase,verbose;
+
+    const
+      std_regname_table : TRegNameTable = (
+        {$i rrv32std.inc}
+      );
+
+      regnumber_index : array[tregisterindex] of tregisterindex = (
+        {$i rrv32rni.inc}
+      );
+
+      std_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rrv32sri.inc}
+      );
+
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    function is_imm12(value: aint): boolean;
+      begin
+        result:=(value >= -2048) and (value <= 2047);
+      end;
+
+
+    function is_lui_imm(value: aint): boolean;
+      begin
+        result:=SarInt64((value and $FFFFF000) shl 32, 32) = value;
+      end;
+
+
+    function is_calljmp(o:tasmop):boolean;
+      begin
+       is_calljmp:=false;
+        case o of
+          A_JAL,A_JALR,A_Bxx:
+            is_calljmp:=true;
+        end;
+      end;
+
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      const
+        inv_condflags:array[TAsmCond] of TAsmCond=(C_None,
+          C_GE,C_GEU,C_LT,C_LTU,C_EQ,C_NE);
+      begin
+        result := inv_condflags[c];
+      end;
+
+
+    function reg_cgsize(const reg: tregister): tcgsize;
+      begin
+        case getregtype(reg) of
+          R_INTREGISTER :
+            result:=OS_64;
+          R_MMREGISTER:
+            result:=OS_M128;
+          R_FPUREGISTER:
+            result:=OS_F64;
+          else
+            internalerror(200303181);
+        end;
+      end;
+
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+      begin
+        cgsize2subreg:=R_SUBWHOLE;
+      end;
+
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+      begin
+        result:=rgBase.findreg_by_number_table(r,regnumber_index);
+      end;
+
+
+    function std_regnum_search(const s:string):Tregister;
+      begin
+        result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
+      end;
+
+
+    function std_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number_table(r,regnumber_index);
+        if p<>0 then
+          result:=std_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+
+    function dwarf_reg(r:tregister):shortint;
+      begin
+        result:=regdwarf_table[findreg_by_number(r)];
+        if result=-1 then
+          internalerror(200603251);
+      end;
+
+    function conditions_equal(const c1, c2: TAsmCond): boolean;
+      begin
+        result:=c1=c2;
+      end;
+
+end.
+

+ 139 - 0
compiler/riscv64/cpuinfo.pas

@@ -0,0 +1,139 @@
+{
+    Copyright (c) 1998-2002 by the Free Pascal development team
+
+    Basic Processor information for the Risc-V64
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit CPUInfo;
+
+interface
+
+uses
+  globtype;
+
+type
+  bestreal = double;
+{$if FPC_FULLVERSION>20700}
+  bestrealrec = TDoubleRec;
+{$endif FPC_FULLVERSION>20700}
+  ts32real = single;
+  ts64real = double;
+  ts80real = extended;
+  ts128real = extended;
+  ts64comp = comp;
+
+  pbestreal = ^bestreal;
+
+  { possible supported processors for this target }
+  tcputype = (cpu_none,
+    cpu_rv64imafdc,
+    cpu_rv64imafd,
+    cpu_rv64ima,
+    cpu_rv64im,
+    cpu_rv64i
+  );
+
+  tfputype =
+    (fpu_none,
+    fpu_libgcc,
+    fpu_soft,
+    fpu_fd
+    );
+
+   tcontrollertype =
+     (ct_none
+     );
+
+   tcontrollerdatatype = record
+      controllertypestr, controllerunitstr: string[20];
+      cputype: tcputype; fputype: tfputype;
+      flashbase, flashsize, srambase, sramsize, eeprombase, eepromsize, bootbase, bootsize: dword;
+   end;
+
+
+Const
+  { Is there support for dealing with multiple microcontrollers available }
+  { for this platform? }
+  ControllerSupport = false;
+
+  { We know that there are fields after sramsize
+    but we don't care about this warning }
+  {$PUSH}
+   {$WARN 3177 OFF}
+  embedded_controllers : array [tcontrollertype] of tcontrollerdatatype =
+  (
+      (controllertypestr:''; controllerunitstr:''; cputype:cpu_none; fputype:fpu_none; flashbase:0; flashsize:0; srambase:0; sramsize:0));
+  {$POP}
+
+  { calling conventions supported by the code generator }
+  supported_calling_conventions: tproccalloptions = [
+    pocall_internproc,
+    pocall_stdcall,
+    { the difference to stdcall is only the name mangling }
+    pocall_cdecl,
+    { the difference to stdcall is only the name mangling }
+    pocall_cppdecl,
+    { the difference with stdcall is that all const record
+      parameters are passed by reference }
+    pocall_mwpascal
+    ];
+
+  cputypestr: array[tcputype] of string[10] = ('',
+    'RV64IMAFDC',
+    'RV64IMAFD',
+    'RV64IMA',
+    'RV64IM',
+    'RV64I'
+    );
+
+  fputypestr: array[tfputype] of string[8] = ('',
+    'LIBGCC',
+    'SOFT',
+    'FD'
+    );
+
+   { Supported optimizations, only used for information }
+   supported_optimizerswitches = genericlevel1optimizerswitches+
+                                 genericlevel2optimizerswitches+
+                                 genericlevel3optimizerswitches-
+                                 { no need to write info about those }
+                                 [cs_opt_level1,cs_opt_level2,cs_opt_level3]+
+                                 [cs_opt_regvar,cs_opt_loopunroll,cs_opt_nodecse,
+                                  cs_opt_tailrecursion,cs_opt_reorder_fields,cs_opt_fastmath,
+                                  cs_opt_stackframe];
+
+   level1optimizerswitches = genericlevel1optimizerswitches;
+   level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + 
+     [cs_opt_regvar,cs_opt_stackframe,cs_opt_nodecse,cs_opt_tailrecursion];
+   level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+   level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [cs_opt_stackframe];
+
+ type
+   tcpuflags =
+      (CPURV_HAS_MUL,
+       CPURV_HAS_ATOMIC,
+       CPURV_HAS_COMPACT
+      );
+
+ const
+   cpu_capabilities : array[tcputype] of set of tcpuflags =
+     ( { cpu_none       } [],
+       { cpu_rv64imafdc } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC,CPURV_HAS_COMPACT],
+       { cpu_rv64imafd  } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+       { cpu_rv64ima    } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+       { cpu_rv64im     } [CPURV_HAS_MUL],
+       { cpu_rv64i      } []
+     );
+
+implementation
+
+end.
+

+ 55 - 0
compiler/riscv64/cpunode.pas

@@ -0,0 +1,55 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl
+
+    Includes the RiscV64 code generator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cpunode;
+
+{$I fpcdefs.inc}
+
+interface
+
+implementation
+
+uses
+  { generic nodes }
+  ncgbas, ncgld, ncgflw, ncgcnv, ncgmem, ncgcon, ncgcal, ncgset, ncginl, ncgopt,
+  ncgobjc,
+  { symtable }
+  symcpu,           
+  aasmdef,
+  { to be able to only parts of the generic code,
+    the processor specific nodes must be included
+    after the generic one (FK)
+  }
+{$ifndef llvm}
+  nrv64add,
+  nrv64cal,
+  nrvset,
+  nrvinl,
+  nrv64mat,
+  nrv64cnv,
+  nrv64ld
+{$else not llvm}
+  llvmnode
+{$endif not llvm}
+  ;
+
+end.
+

+ 545 - 0
compiler/riscv64/cpupara.pas

@@ -0,0 +1,545 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    RiscV64 specific calling conventions
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ****************************************************************************
+}
+unit cpupara;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      globtype,
+      aasmtai,aasmdata,
+      cpubase,
+      symconst, symtype, symdef, symsym,
+      paramgr, parabase, cgbase, cgutils;
+
+    type
+      tcpuparamanager = class(tparamanager)
+        function get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override;
+        function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override;
+        function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
+        function ret_in_param(def: tdef; pd: tabstractprocdef): boolean; override;
+
+        procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara); override;
+        function create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint; override;
+        function create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist): longint; override;
+        function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
+
+      private
+        procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+        function create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; isVararg : boolean): longint;
+        function parseparaloc(p: tparavarsym; const s: string): boolean; override;
+        procedure create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
+      end;
+
+implementation
+
+    uses
+      verbose, systems,
+      globals, cpuinfo,
+      defutil,symtable,symcpu,
+      procinfo, cpupi;
+
+    function tcpuparamanager.get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset;
+      begin
+        result:=[RS_X0..RS_X31]-[RS_X2,RS_X8..RS_X9,RS_X18..RS_X27];
+      end;
+
+    function tcpuparamanager.get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset;
+      begin
+        result:=[RS_F0..RS_F31]-[RS_F8..RS_F9,RS_F18..RS_F27];
+      end;
+
+    procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara);
+      var
+        paraloc: pcgparalocation;
+        psym: tparavarsym;
+        pdef: tdef;
+      begin
+        psym:=tparavarsym(pd.paras[nr-1]);
+        pdef:=psym.vardef;
+        if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
+          pdef:=cpointerdef.getreusable_no_free(pdef);
+        cgpara.reset;
+        cgpara.size := def_cgsize(pdef);
+        cgpara.intsize := tcgsize2size[cgpara.size];
+        cgpara.alignment := get_para_align(pd.proccalloption);
+        cgpara.def:=pdef;
+        paraloc := cgpara.add_location;
+        with paraloc^ do begin
+          size := def_cgsize(pdef);
+          def := pdef;
+          if (nr <= 8) then begin
+            if (nr = 0) then
+              internalerror(200309271);
+            loc := LOC_REGISTER;
+            register := newreg(R_INTREGISTER, RS_X10 + nr-1, R_SUBWHOLE);
+          end else begin
+            loc := LOC_REFERENCE;
+            paraloc^.reference.index := NR_STACK_POINTER_REG;
+            reference.offset := sizeof(aint) * (nr - 9);
+          end;
+        end;
+      end;
+
+    function getparaloc(p: tdef): tcgloc;
+      begin
+        { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
+          if push_addr_param for the def is true
+        }
+        case p.typ of
+          orddef:
+            result := LOC_REGISTER;
+          floatdef:
+            if (cs_fp_emulation in current_settings.moduleswitches) or
+               (current_settings.fputype in [fpu_soft]) then
+              result := LOC_REGISTER
+            else
+              result := LOC_FPUREGISTER;
+          enumdef:
+            result := LOC_REGISTER;
+          pointerdef:
+            result := LOC_REGISTER;
+          formaldef:
+            result := LOC_REGISTER;
+          classrefdef:
+            result := LOC_REGISTER;
+          procvardef,
+          recorddef:
+            result := LOC_REGISTER;
+          objectdef:
+            if is_object(p) then
+              result := LOC_REFERENCE
+            else
+              result := LOC_REGISTER;
+          stringdef:
+            if is_shortstring(p) or is_longstring(p) then
+              result := LOC_REFERENCE
+            else
+              result := LOC_REGISTER;
+          filedef:
+            result := LOC_REGISTER;
+          arraydef:
+            if is_dynamic_array(p) then
+              getparaloc:=LOC_REGISTER
+            else
+              result := LOC_REFERENCE;
+          setdef:
+            if is_smallset(p) then
+              result := LOC_REGISTER
+            else
+              result := LOC_REFERENCE;
+          variantdef:
+            result := LOC_REFERENCE;
+          { avoid problems with errornous definitions }
+          errordef:
+            result := LOC_REGISTER;
+        else
+          internalerror(2002071001);
+        end;
+      end;
+
+    function tcpuparamanager.push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
+      begin
+        result := false;
+        { var,out,constref always require address }
+        if varspez in [vs_var, vs_out, vs_constref] then
+        begin
+          result := true;
+          exit;
+        end;
+        case def.typ of
+          variantdef,
+          formaldef:
+            result := true;
+          procvardef,
+          recorddef:
+            result := (def.size > 16);
+          arraydef:
+            result := (tarraydef(def).highrange >= tarraydef(def).lowrange) or
+              is_open_array(def) or
+              is_array_of_const(def) or
+              is_array_constructor(def);
+          objectdef:
+            result := is_object(def);
+          setdef:
+            result := not is_smallset(def);
+          stringdef:
+            result := tstringdef(def).stringtype in [st_shortstring, st_longstring];
+        end;
+      end;
+
+    function tcpuparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
+      var
+        tmpdef: tdef;
+      begin
+        if handle_common_ret_in_param(def,pd,result) then
+          exit;
+
+        { general rule: passed in registers -> returned in registers }
+        result:=push_addr_param(vs_value,def,pd.proccalloption);
+      end;
+
+    procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+      begin
+        { register parameter save area begins at 48(r2) }
+        cur_stack_offset := 0;
+        curintreg := RS_X10;
+        curfloatreg := RS_F10;
+        curmmreg := RS_NO;
+      end;
+
+    function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+      var
+        paraloc: pcgparalocation;
+        retcgsize: tcgsize;
+        nextfloatreg, nextintreg, nextmmreg: tsuperregister;
+        stack_offset: aword;
+      begin
+        if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
+          exit;
+
+         { in this case, it must be returned in registers as if it were passed
+           as the first parameter }
+         init_values(nextintreg,nextfloatreg,nextmmreg,stack_offset);
+         create_paraloc_for_def(result,vs_value,result.def,nextfloatreg,nextintreg,stack_offset,false,false,side,p);
+         { sanity check (LOC_VOID for empty records) }
+         if not assigned(result.location) or
+            not(result.location^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_VOID]) then
+           internalerror(2014113001);
+      end;
+
+    function tcpuparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint;
+      var
+        cur_stack_offset: aword;
+        curintreg, curfloatreg, curmmreg : tsuperregister;
+      begin
+        init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
+
+        result := create_paraloc_info_intern(p, side, p.paras, curintreg, curfloatreg, curmmreg, cur_stack_offset, false);
+
+        create_funcretloc_info(p, side);
+      end;
+
+    function tcpuparamanager.create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; isVararg : boolean): longint;
+      var
+        nextintreg, nextfloatreg, nextmmreg : tsuperregister;
+        i: integer;
+        hp: tparavarsym;
+        paraloc: pcgparalocation;
+        delphi_nestedfp: boolean;
+
+      begin
+{$IFDEF extdebug}
+        if po_explicitparaloc in p.procoptions then
+          internalerror(200411141);
+{$ENDIF extdebug}
+
+        result := 0;
+        nextintreg := curintreg;
+        nextfloatreg := curfloatreg;
+        nextmmreg := curmmreg;
+
+        for i := 0 to paras.count - 1 do begin
+          hp := tparavarsym(paras[i]);
+
+          if (vo_has_explicit_paraloc in hp.varoptions) then begin
+            internalerror(200412153);
+          end;
+
+          { currently only support C-style array of const }
+          if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) and
+            is_array_of_const(hp.vardef) then begin
+            paraloc := hp.paraloc[side].add_location;
+            { hack: the paraloc must be valid, but is not actually used }
+            paraloc^.loc := LOC_REGISTER;
+            paraloc^.register := NR_X0;
+            paraloc^.size := OS_ADDR;
+            paraloc^.def := voidpointertype;
+            break;
+          end;
+          delphi_nestedfp:=(vo_is_parentfp in hp.varoptions) and (po_delphi_nested_cc in p.procoptions);
+          create_paraloc_for_def(hp.paraloc[side], hp.varspez, hp.vardef,
+            nextfloatreg, nextintreg, cur_stack_offset, isVararg, delphi_nestedfp, side, p);
+        end;
+
+        curintreg := nextintreg;
+        curfloatreg := nextfloatreg;
+        curmmreg := nextmmreg;
+        result := cur_stack_offset;
+      end;
+
+    procedure tcpuparamanager.create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
+      var
+        paracgsize: tcgsize;
+        loc: tcgloc;
+        paraloc: pcgparalocation;
+        { def to use for all paralocs if <> nil }
+        alllocdef,
+        { def to use for the current paraloc }
+        locdef,
+        tmpdef: tdef;
+        paralen: aint;
+        firstparaloc,
+        paraaligned: boolean;
+      begin
+        alllocdef:=nil;
+        locdef:=nil;
+        para.reset;
+        { have we ensured that the next parameter location will be aligned to the
+          next 8 byte boundary? }
+        paraaligned:=false;
+        if push_addr_param(varspez, paradef, p.proccalloption) then begin
+          paradef := cpointerdef.getreusable_no_free(paradef);
+          loc := LOC_REGISTER;
+          paracgsize := OS_ADDR;
+          paralen := tcgsize2size[OS_ADDR];
+        end else begin
+          if not is_special_array(paradef) then
+            paralen := paradef.size
+          else
+            paralen := tcgsize2size[def_cgsize(paradef)];
+
+          if (paradef.typ=recorddef) and
+             tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(tmpdef) and
+             (tmpdef.typ=floatdef) then
+            begin
+              paradef:=tmpdef;
+              loc:=getparaloc(paradef);
+              paracgsize:=def_cgsize(paradef)
+            end
+          else if (((paradef.typ=arraydef) and not
+               is_special_array(paradef)) or
+              (paradef.typ=recorddef)) then
+            begin
+              { general fallback rule: pass aggregate types in integer registers
+                without special adjustments (incl. Darwin h) }
+              loc:=LOC_REGISTER;
+              paracgsize:=int_cgsize(paralen);
+            end
+          else
+            begin
+              loc:=getparaloc(paradef);
+              paracgsize:=def_cgsize(paradef);
+              { for things like formaldef }
+              if (paracgsize=OS_NO) then
+                begin
+                  paracgsize:=OS_ADDR;
+                  paralen:=tcgsize2size[OS_ADDR];
+                end;
+            end
+        end;
+
+        { patch FPU values into integer registers if we are processing varargs }
+        if (isVararg) and (paradef.typ = floatdef) then begin
+          loc := LOC_REGISTER;
+          if paracgsize = OS_F64 then
+            paracgsize := OS_64
+          else
+            paracgsize := OS_32;
+        end;
+
+
+        para.alignment := std_param_align;
+        para.size := paracgsize;
+        para.intsize := paralen;
+        para.def := paradef;
+        if (paralen = 0) then
+          if (paradef.typ = recorddef) then begin
+            paraloc := para.add_location;
+            paraloc^.loc := LOC_VOID;
+          end else
+            internalerror(2005011310);
+        if not assigned(alllocdef) then
+          locdef:=paradef
+        else
+          begin
+            locdef:=alllocdef;
+            paracgsize:=def_cgsize(locdef);
+          end;
+        firstparaloc:=true;
+
+        // Parameters passed in 2 registers are passed in a register starting with an even number.
+        if isVararg and
+           (paralen > 8) and
+           (loc = LOC_REGISTER) and
+           (nextintreg <= RS_X17) and
+           odd(nextintreg) then
+          inc(nextintreg);
+
+        { can become < 0 for e.g. 3-byte records }
+        while (paralen > 0) do begin
+          paraloc := para.add_location;
+          { In case of po_delphi_nested_cc, the parent frame pointer
+            is always passed on the stack. }
+          if (loc = LOC_REGISTER) and
+             (nextintreg <= RS_X17) and
+             not forceintmem then begin
+            paraloc^.loc := loc;
+
+            { make sure we don't lose whether or not the type is signed }
+            if (paracgsize <> OS_NO) and
+               (paradef.typ <> orddef) and
+               not assigned(alllocdef) then
+              begin
+                paracgsize := int_cgsize(paralen);
+                locdef:=get_paraloc_def(paradef, paralen, firstparaloc);
+              end;
+
+             if (paracgsize in [OS_NO, OS_128, OS_S128]) then
+              begin
+                if (paralen>4) then
+                  begin
+                    paraloc^.size := OS_INT;
+                    paraloc^.def := osuinttype;
+                  end
+                else
+                  begin
+                    { for 3-byte records aligned in the lower bits of register }
+                    paraloc^.size := OS_32;
+                    paraloc^.def := u32inttype;
+                  end;
+              end
+            else
+              begin
+                paraloc^.size := paracgsize;
+                paraloc^.def := locdef;
+              end;
+
+            paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
+            inc(nextintreg);
+            dec(paralen, tcgsize2size[paraloc^.size]);
+          end else if (loc = LOC_FPUREGISTER) and
+            (nextfloatreg <= RS_F17) then begin
+            paraloc^.loc := loc;
+            paraloc^.size := paracgsize;
+            paraloc^.def := locdef;
+            paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
+            { the RiscV ABI says that the GPR index is increased for every parameter, no matter
+              which type it is stored in
+
+               not really, https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#hardware-floating-point-calling-convention says
+               otherwise, gcc doesn't do it either }
+            inc(nextfloatreg);
+            dec(paralen, tcgsize2size[paraloc^.size]);
+          end else if (loc = LOC_MMREGISTER) then begin
+            { no mm registers }
+            internalerror(2018072601);
+          end else begin
+            { either LOC_REFERENCE, or one of the above which must be passed on the
+            stack because of insufficient registers }
+            paraloc^.loc := LOC_REFERENCE;
+            case loc of
+              LOC_FPUREGISTER:
+                begin
+                  paraloc^.size:=int_float_cgsize(paralen);
+                  case paraloc^.size of
+                    OS_F32: paraloc^.def:=s32floattype;
+                    OS_F64: paraloc^.def:=s64floattype;
+                    else
+                      internalerror(2013060122);
+                  end;
+                end;
+              LOC_REGISTER,
+              LOC_REFERENCE:
+                begin
+                  paraloc^.size:=int_cgsize(paralen);
+                  paraloc^.def:=get_paraloc_def(paradef, paralen, firstparaloc);
+                end;
+              else
+                internalerror(2006011101);
+            end;
+            if (side = callerside) then
+              paraloc^.reference.index := NR_STACK_POINTER_REG
+            else begin
+              { during procedure entry, NR_OLD_STACK_POINTER_REG contains the old stack pointer }
+              paraloc^.reference.index := NR_FRAME_POINTER_REG;
+              { create_paraloc_info_intern might be also called when being outside of
+                code generation so current_procinfo might be not set }
+              if assigned(current_procinfo) then
+                trv64procinfo(current_procinfo).needs_frame_pointer := true;
+            end;
+            paraloc^.reference.offset := stack_offset;
+
+            { align temp contents to next register size }
+            if not paraaligned then
+              inc(stack_offset, align(paralen, 8))
+            else
+              inc(stack_offset, paralen);
+            paralen := 0;
+          end;
+          firstparaloc:=false;
+        end;
+      end;
+
+function tcpuparamanager.create_varargs_paraloc_info(p: tabstractprocdef;
+  varargspara: tvarargsparalist): longint;
+var
+  cur_stack_offset: aword;
+  parasize, l: longint;
+  curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
+  i: integer;
+  hp: tparavarsym;
+  paraloc: pcgparalocation;
+begin
+  init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
+  firstfloatreg := curfloatreg;
+
+  result := create_paraloc_info_intern(p, callerside, p.paras, curintreg,
+    curfloatreg, curmmreg, cur_stack_offset, false);
+  if (p.proccalloption in [pocall_cdecl, pocall_cppdecl, pocall_mwpascal]) then begin
+    { just continue loading the parameters in the registers }
+    result := create_paraloc_info_intern(p, callerside, varargspara, curintreg,
+      curfloatreg, curmmreg, cur_stack_offset, true);
+    { varargs routines have to reserve at least 64 bytes for the RiscV ABI }
+    if (result < 64) then
+      result := 64;
+  end else begin
+    parasize := cur_stack_offset;
+    for i := 0 to varargspara.count - 1 do begin
+      hp := tparavarsym(varargspara[i]);
+      hp.paraloc[callerside].alignment := 8;
+      paraloc := hp.paraloc[callerside].add_location;
+      paraloc^.loc := LOC_REFERENCE;
+      paraloc^.size := def_cgsize(hp.vardef);
+      paraloc^.def := hp.vardef;
+      paraloc^.reference.index := NR_STACK_POINTER_REG;
+      l := push_size(hp.varspez, hp.vardef, p.proccalloption);
+      paraloc^.reference.offset := parasize;
+      parasize := parasize + l;
+    end;
+    result := parasize;
+  end;
+  if curfloatreg <> firstfloatreg then
+    include(varargspara.varargsinfo, va_uses_float_reg);
+end;
+
+function tcpuparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
+begin
+  internalerror(200404182);
+  result := true;
+end;
+
+
+begin
+  paramanager := tcpuparamanager.create;
+end.
+

+ 116 - 0
compiler/riscv64/cpupi.pas

@@ -0,0 +1,116 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    This unit contains the CPU specific part of tprocinfo
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{ This unit contains the CPU specific part of tprocinfo. }
+unit cpupi;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      cutils,aasmdata,
+      globtype, cgutils, cgbase,
+      procinfo, cpuinfo, psub;
+
+    type
+      trv64procinfo = class(tcgprocinfo)
+        stackframesize,
+        floatregstart : aint;
+        stackpaddingreg: TSuperRegister;
+
+        needs_frame_pointer: boolean;
+
+        constructor create(aparent: tprocinfo); override;
+        procedure set_first_temp_offset; override;
+        function calc_stackframe_size: longint; override;
+      end;
+
+implementation
+
+    uses
+      globals, systems,
+      cpubase,
+      aasmtai,
+      tgobj,cgobj,
+      symconst, symsym, paramgr, symutil, symtable,
+      verbose,
+      aasmcpu;
+
+
+    constructor trv64procinfo.create(aparent: tprocinfo);
+      begin
+        inherited create(aparent);
+        maxpushedparasize := 0;
+      end;
+
+
+    procedure trv64procinfo.set_first_temp_offset;
+      begin
+        if (po_nostackframe in procdef.procoptions) then
+          begin
+             { maxpushedparasize sghould be zero,
+               if not we will get an error later. }
+             tg.setfirsttemp(maxpushedparasize);
+             exit;
+          end;
+
+        if tg.direction = -1 then
+          tg.setfirsttemp(-(1+12)*8)
+        else
+          tg.setfirsttemp(maxpushedparasize);
+      end;
+
+
+    function trv64procinfo.calc_stackframe_size: longint;
+      var
+         firstfloatreg,lastfloatreg,
+         r : byte;
+         floatsavesize : aword;
+         regs: tcpuregisterset;
+      begin
+        maxpushedparasize:=align(maxpushedparasize,max(current_settings.alignment.localalignmin,8));
+        floatsavesize:=0;
+        case current_settings.fputype of
+          fpu_fd:
+            begin
+              floatsavesize:=0;
+              regs:=cg.rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall);
+              for r:=RS_F0 to RS_F31 do
+                if r in regs then
+                  inc(floatsavesize,8);
+            end;
+        end;
+        floatsavesize:=system.align(floatsavesize,max(current_settings.alignment.localalignmin,8));
+        result:=Align(tg.direction*tg.lasttemp,max(current_settings.alignment.localalignmin,8))+maxpushedparasize+aint(floatsavesize);
+
+        if tg.direction=1 then
+          floatregstart:=result-aint(floatsavesize)
+        else
+          floatregstart:=-result+maxpushedparasize;
+      end;
+
+
+begin
+  cprocinfo := trv64procinfo;
+end.
+

+ 85 - 0
compiler/riscv64/cputarg.pas

@@ -0,0 +1,85 @@
+{
+    Copyright (c) 2001-2002 by Peter Vreman
+
+    Includes the RiscV64 dependent target units
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cputarg;
+
+{$i fpcdefs.inc}
+
+interface
+
+
+implementation
+
+    uses
+      systems { prevent a syntax error when nothing is included }
+
+{**************************************
+             Targets
+**************************************}
+
+    {$ifndef NOTARGETLINUX}
+      ,t_linux
+    {$endif}
+    {$ifndef NOTARGETEMBEDDED}
+      ,t_embed
+    {$endif}
+
+{**************************************
+             Assemblers
+**************************************}
+
+    {$ifndef NOAGRVGAS}
+      ,agrvgas
+    {$endif}
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+  {$ifndef NoRaRVGas}
+       ,rarv64gas
+  {$endif NoRaRVGas}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoDbgStabs}
+      ,dbgstabs
+  {$endif NoDbgStabs}
+  {$ifndef NoDbgStabx}
+      ,dbgstabx
+  {$endif NoDbgStabx}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+
+
+{**************************************
+             Optimizer
+**************************************}
+
+    {$ifndef NOOPT}
+      , aoptcpu
+    {$endif NOOPT}
+      ;
+
+end.

+ 78 - 0
compiler/riscv64/hlcgcpu.pas

@@ -0,0 +1,78 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit contains high-level code generator support for riscv64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit hlcgcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,
+  aasmdata,
+  symtype,
+  cgbase,cgutils,hlcgobj,hlcgrv;
+
+type
+  thlcgcpu = class(thlcgriscv)
+    procedure a_load_const_subsetreg(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sreg: tsubsetregister); override;
+  end;
+
+   procedure create_hlcodegen;
+
+implementation
+
+  uses
+    cpubase,aasmcpu,
+    defutil,
+    cgobj,cgcpu;
+
+  { thlcgcpu }
+
+
+  procedure thlcgcpu.a_load_const_subsetreg(list: TAsmlist; tosubsetsize: tdef; a: tcgint; const sreg: tsubsetregister);
+    var
+      tmpreg : TRegister;
+    begin
+{$ifdef extdebug}
+      list.concat(tai_comment.create(strpnew('a_load_const_subsetreg subsetregsize = ' + cgsize2string(sreg.subsetregsize) + ' subsetsize = ' + cgsize2string(def_cgsize(subsetsize)) + ' startbit = ' + intToStr(sreg.startbit) + ' a = ' + intToStr(a))));
+{$endif}
+      { loading the constant into the lowest bits of a temp register and then inserting is
+        better than loading some usually large constants and do some masking and shifting on riscv64 }
+      tmpreg:=getintregister(list,tosubsetsize);
+      a_load_const_reg(list,tosubsetsize,a,tmpreg);
+      a_load_reg_subsetreg(list,tosubsetsize,tosubsetsize,tmpreg,sreg);
+    end;
+
+
+  procedure create_hlcodegen;
+    begin
+      hlcg:=thlcgcpu.create;
+      create_codegen;
+    end;
+
+
+
+begin
+  chlcgobj:=thlcgcpu;
+end.

+ 157 - 0
compiler/riscv64/itcpugas.pas

@@ -0,0 +1,157 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit contains the RiscV64 GAS instruction tables
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit itcpugas;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      cpubase, cgbase;
+
+    const
+      gas_op2str: array[tasmop] of string[14] = ('<none>',
+        'nop',
+        'lui','auipc','jal','jalr',
+        'b','lb','lh','lw','lbu','lhu',
+        'sb','sh','sw',
+        'addi','slti','sltiu',
+        'xori','ori','andi',
+        'slli','srli','srai',
+        'add','sub','sll','slt','sltu',
+        'xor','srl','sra','or','and',
+        'fence','fence.i',
+        'ecall','ebreak',
+        'csrrw','csrrs','csrrc','csrrwi','csrrsi','csrrci',
+        { 64-bit }
+        'addiw','slliw','srliw','sraiw',
+        'addw','sllw','srlw','subw','sraw',
+        'ld','sd','lwu',
+
+        { m-extension }
+        'mul','mulh','mulhsu','mulhu',
+        'div','divu','rem','remu',
+        { 64-bit }
+        'mulw',
+        'divw','divuw','remw','remuw',
+
+        { a-extension }
+        'lr.w','sc.w','amoswap.w','amoadd.w','amoxor.w','amoand.w',
+        'amoor.w','amomin.w','amomax.w','amominu.w','amomaxu.w',
+        { 64-bit }
+        'lr.d','sc.d','amoswap.d','amoadd.d','amoxor.d','amoand.d',
+        'amoor.d','amomin.d','amomax.d','amominu.d','amomaxu.d',
+
+        { f-extension }
+        'flw','fsw',
+        'fmadd.s','fmsub.s','fnmsub.s','fnmadd.s',
+        'fadd.s','fsub.s','fmul.s','fdiv.s',
+        'fsqrt.s','fsgnj.s','fsgnjn.s','fsgnjx.s',
+        'fmin.s','fmax.s',
+        'fmv.x.s','feq.s','flt.s','fle.s','fclass.s',
+        'fcvt.w.s','fcvt.wu.s','fcvt.s.w','fcvt.s.wu',
+        'fmv.s.x',
+        'frcsr','frrm','frflags','fscsr','fsrm',
+        'fsflags','fsrmi','fsflagsi',
+        { 64-bit }
+        'fcvt.l.s','fcvt.lu.s',
+        'fcvt.s.l','fcvt.s.lu',
+
+        { d-extension }
+        'fld','fsd',
+        'fmadd.d','fmsub.d','fnmsub.d','fnmadd.d',
+        'fadd.d','fsub.d','fmul.d','fdiv.d',
+        'fsqrt.d','fsgnj.d','fsgnjn.d','fsgnjx.d',
+        'fmin.d','fmax.d',
+        'feq.d','flt.d','fle.d','fclass.d',
+        'fcvt.d.s','fcvt.s.d',
+        'fcvt.w.d','fcvt.wu.d','fcvt.d.w','fcvt.d.wu',
+        { 64-bit }
+        'fcvt.l.d','fcvt.lu.d','fmv.x.d',
+        'fcvt.d.l','fcvt.d.lu','fmv.d.x',
+
+        { Machine mode }
+        'mret','hret','sret','uret',
+        'wfi',
+
+        { Supervisor mode }
+        'sfence.vm'
+        );
+
+    function gas_regnum_search(const s: string): Tregister;
+    function gas_regname(r: Tregister): string;
+
+  implementation
+
+    uses
+      globtype,globals,aasmbase,
+      cutils,verbose, systems,
+      rgbase;
+
+    const
+      gas_regname_table : TRegNameTable = (
+        {$i rrv32std.inc}
+      );
+
+      gas_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rrv32sri.inc}
+      );
+
+
+    function findreg_by_gasname(const s:string):tregisterindex;
+      var
+        i,p : tregisterindex;
+      begin
+        {Binary search.}
+        p:=0;
+        i:=regnumber_count_bsstart;
+        repeat
+          if (p+i<=high(tregisterindex)) and (gas_regname_table[gas_regname_index[p+i]]<=s) then
+            p:=p+i;
+          i:=i shr 1;
+        until i=0;
+        if gas_regname_table[gas_regname_index[p]]=s then
+          findreg_by_gasname:=gas_regname_index[p]
+        else
+          findreg_by_gasname:=0;
+      end;
+
+
+    function gas_regnum_search(const s:string):Tregister;
+      begin
+        result:=regnumber_table[findreg_by_gasname(s)];
+      end;
+
+
+    function gas_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number(r);
+        if p<>0 then
+          result:=gas_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+end.
+

+ 98 - 0
compiler/riscv64/nrv64add.pas

@@ -0,0 +1,98 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl and Jonas Maebe
+
+    Code generation for add nodes on the Risc-V64
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv64add;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      node, ncgadd, aasmbase, nrvadd, cpubase;
+
+    type
+      trv64addnode = class(trvaddnode)
+      protected
+        function pass_1: tnode; override;
+
+        procedure second_add64bit; override;
+
+        function use_generic_mul32to64: boolean; override;
+      end;
+
+  implementation
+
+    uses
+      systems,
+      cutils,verbose,
+      paramgr,procinfo,
+      aasmtai,aasmdata,aasmcpu,defutil,
+      cgbase,cgcpu,cgutils,
+      globals,
+      pass_1,
+      CPUInfo,cpupara,
+      ncon,nset,nadd,
+      symconst,
+      hlcgobj, ncgutil,cgobj;
+
+    function trv64addnode.pass_1: tnode;
+      begin
+        if (nodetype=muln) and
+           (left.resultdef.typ=orddef) and (left.resultdef.typ=orddef) and
+           (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype]) then
+          begin
+            result:=nil;
+
+            firstpass(left);
+            firstpass(right);
+
+            expectloc:=LOC_REGISTER;
+          end
+        else if (nodetype=muln) and
+           (not (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype])) and
+           (is_64bit(left.resultdef) or
+            is_64bit(right.resultdef)) then
+          begin
+            result:=first_add64bitint;
+          end
+        else
+          Result:=inherited pass_1;
+
+        if expectloc=LOC_FLAGS then
+          expectloc:=LOC_REGISTER;
+      end;
+
+
+    procedure trv64addnode.second_add64bit;
+      begin
+        second_addordinal;
+      end;
+
+
+    function trv64addnode.use_generic_mul32to64: boolean;
+      begin
+        result:=false;
+      end;
+
+begin
+  caddnode := trv64addnode;
+end.
+

+ 56 - 0
compiler/riscv64/nrv64cal.pas

@@ -0,0 +1,56 @@
+{
+    Copyright (c) 2002 by Florian Klaempfl
+
+    Implements the RiscV64 specific part of call nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv64cal;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+  aasmdata, cgbase,
+  symdef, node, ncal, ncgcal;
+
+type
+
+  trv64callparanode = class(tcgcallparanode)
+  end;
+
+  trv64ccallnode = class(tcgcallnode)
+  end;
+
+implementation
+
+uses
+  globtype, systems,
+  cutils, verbose, globals,
+  symconst, symbase, symsym, symtable, defutil, paramgr, parabase,
+  pass_2,
+  cpuinfo, cpubase, aasmbase, aasmtai, aasmcpu,
+  nmem, nld, ncnv,
+  ncgutil, cgutils, cgobj, tgobj, rgobj, rgcpu,
+  cgcpu, cpupi, procinfo;
+
+begin
+  ccallparanode:=trv64callparanode;
+  ccallnode := trv64ccallnode;
+end.
+

+ 124 - 0
compiler/riscv64/nrv64cnv.pas

@@ -0,0 +1,124 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate RiscV64 assembler for type converting nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv64cnv;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      node, ncnv, ncgcnv, nrvcnv;
+
+    type
+      trv64typeconvnode = class(trvtypeconvnode)
+      protected
+        { procedure second_int_to_int;override; }
+        { procedure second_string_to_string;override; }
+        { procedure second_cstring_to_pchar;override; }
+        { procedure second_string_to_chararray;override; }
+        { procedure second_array_to_pointer;override; }
+        function first_int_to_real: tnode; override;
+        { procedure second_pointer_to_array;override; }
+        { procedure second_chararray_to_string;override; }
+        { procedure second_char_to_string;override; }
+        procedure second_int_to_real; override;
+        { procedure second_real_to_real; override;}
+        { procedure second_cord_to_pointer;override; }
+        { procedure second_proc_to_procvar;override; }
+        { procedure second_bool_to_int;override; }
+        { procedure second_int_to_bool; override; }
+        { procedure second_load_smallset;override;  }
+        { procedure second_ansistring_to_pchar;override; }
+        { procedure second_pchar_to_string;override; }
+        { procedure second_class_to_intf;override; }
+        { procedure second_char_to_char;override; }
+      end;
+
+  implementation
+
+    uses
+      verbose, globtype, globals, systems,
+      symconst, symdef, aasmbase, aasmtai,aasmdata,
+      defutil, symcpu,
+      cgbase, cgutils, pass_1, pass_2,
+      ncon, ncal,procinfo,
+      ncgutil,
+      cpubase, aasmcpu,
+      rgobj, tgobj, cgobj, hlcgobj;
+
+    {*****************************************************************************
+                                 FirstTypeConv
+    *****************************************************************************}
+
+    function trv64typeconvnode.first_int_to_real: tnode;
+      begin                  
+        if (cs_fp_emulation in current_settings.moduleswitches) then
+          result:=inherited first_int_to_real
+        { converting a 64bit integer to a float requires a helper }
+        else
+          begin
+            if (is_currency(left.resultdef)) then begin
+              // hack to avoid double division by 10000, as it's
+              // already done by typecheckpass.resultdef_int_to_real
+              left.resultdef := s64inttype;
+            end else begin
+              // everything that is less than 64 bits is converted to a 64 bit signed
+              // integer - because the int_to_real conversion is faster for 64 bit
+              // signed ints compared to 64 bit unsigned ints.
+              if (not (torddef(left.resultdef).ordtype in [s64bit, u64bit, scurrency])) then begin
+                inserttypeconv(left, s64inttype);
+              end;
+            end;
+            firstpass(left);
+            result := nil;
+            expectloc := LOC_FPUREGISTER;
+          end;
+      end;
+
+    {*****************************************************************************
+                                 SecondTypeConv
+    *****************************************************************************}
+
+    procedure trv64typeconvnode.second_int_to_real;
+      const
+        ops: array[boolean,boolean,s32real..s64real] of TAsmOp = (
+          ((A_FCVT_S_WU,A_FCVT_D_WU),
+           (A_FCVT_S_W,A_FCVT_D_W)),
+          ((A_FCVT_S_LU,A_FCVT_D_LU),
+           (A_FCVT_S_L,A_FCVT_D_L)));
+      var
+        restype: tfloattype;
+      begin
+        location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
+
+        restype:=tfloatdef(resultdef).floattype;
+
+        location.Register := cg.getfpuregister(current_asmdata.CurrAsmList, tfloat2tcgsize[restype]);
+        if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+          hlcg.location_force_reg(current_asmdata.CurrAsmList, left.location, left.resultdef, left.resultdef, true);
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(ops[is_64bit(left.resultdef),is_signed(left.resultdef),restype], location.register, left.location.register));
+      end;
+
+begin
+  ctypeconvnode := trv64typeconvnode;
+end.
+

+ 57 - 0
compiler/riscv64/nrv64ld.pas

@@ -0,0 +1,57 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate riscv64 assembler for nodes that handle loads and assignments
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv64ld;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+  node, ncgld;
+
+type
+  trv64loadnode = class(tcgloadnode)
+    procedure pass_generate_code override;
+  end;
+
+implementation
+
+uses
+  verbose,
+  systems,
+  cpubase,
+  cgutils, cgobj,
+  aasmbase, aasmtai,aasmdata,
+  symconst, symsym,
+  procinfo,
+  nld;
+
+procedure trv64loadnode.pass_generate_code;
+begin
+  inherited pass_generate_code;
+end;
+
+
+begin
+  cloadnode := trv64loadnode;
+end.
+

+ 163 - 0
compiler/riscv64/nrv64mat.pas

@@ -0,0 +1,163 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate RiscV64 assembler for math nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nrv64mat;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      node,nmat, ncgmat,
+      cgbase;
+
+    type
+      trv64moddivnode = class(tcgmoddivnode)
+        function use_moddiv64bitint_helper: boolean; override;
+        procedure emit_div_reg_reg(signed: boolean; denum, num: tregister); override;
+        procedure emit_mod_reg_reg(signed: boolean; denum, num: tregister); override;
+        function first_moddiv64bitint: tnode; override;
+      end;
+
+      trv64shlshrnode = class(tcgshlshrnode)
+      end;
+
+      trv64unaryminusnode = class(tcgunaryminusnode)
+      end;
+
+      trv64notnode = class(tcgnotnode)
+        procedure second_boolean; override;
+      end;
+
+implementation
+
+    uses
+      nadd,ninl,ncal,ncnv,
+      globtype,systems,constexp,
+      cutils,verbose,globals,
+      cpuinfo,
+      symconst,symdef,
+      aasmbase,aasmcpu,aasmtai,aasmdata,
+      defutil,
+      cgutils,cgobj,hlcgobj,
+      pass_1,pass_2,htypechk,
+      ncon,procinfo,
+      cpubase,
+      ncgutil,cgcpu;
+
+    procedure trv64notnode.second_boolean;
+      var
+        tlabel, flabel: tasmlabel;
+      begin
+        if not handle_locjump then
+          begin
+            secondpass(left);
+            case left.location.loc of
+              LOC_FLAGS :
+                begin
+                  Internalerror(2016060601);
+                  //location_copy(location,left.location);
+                  //inverse_flags(location.resflags);
+                end;
+              LOC_REGISTER, LOC_CREGISTER,
+              LOC_REFERENCE, LOC_CREFERENCE,
+              LOC_SUBSETREG, LOC_CSUBSETREG,
+              LOC_SUBSETREF, LOC_CSUBSETREF:
+                begin
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+                  location_reset(location,LOC_REGISTER,OS_INT);
+                  location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,s64inttype);
+
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_const(A_SLTIU,location.register,left.location.register,1));
+               end;
+              else
+                internalerror(2003042401);
+            end;
+          end;
+      end;
+
+
+    function trv64moddivnode.use_moddiv64bitint_helper: boolean;
+      begin
+        Result:=true;
+      end;
+
+
+    procedure trv64moddivnode.emit_div_reg_reg(signed: boolean; denum, num: tregister);
+      var
+        op: TAsmOp;
+      begin
+        if signed then
+          op:=A_DIV
+        else
+          op:=A_DIVU;
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
+      end;
+
+
+    procedure trv64moddivnode.emit_mod_reg_reg(signed: boolean; denum, num: tregister);
+      var
+        op: TAsmOp;
+      begin
+        if signed then
+          op:=A_REM
+        else
+          op:=A_REMU;
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(op,num,num,denum));
+      end;
+
+
+    function trv64moddivnode.first_moddiv64bitint: tnode;
+      var
+        power: longint;
+      begin
+        {We can handle all cases of constant division}
+        if not(cs_check_overflow in current_settings.localswitches) and
+           (right.nodetype=ordconstn) and
+           (nodetype=divn) and
+           ((CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
+            (ispowerof2(tordconstnode(right).value,power) or
+            (tordconstnode(right).value=1) or
+            (tordconstnode(right).value=int64(-1))
+            )
+           ) then
+          result:=nil
+        else if (CPURV_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
+          (nodetype in [divn,modn]) then
+          result:=nil
+        else
+          result:=inherited;
+
+        { we may not change the result type here }
+        if assigned(result) and (torddef(result.resultdef).ordtype<>torddef(resultdef).ordtype) then
+          inserttypeconv(result,resultdef);
+      end;
+
+begin
+  cmoddivnode := trv64moddivnode;
+  cshlshrnode := trv64shlshrnode;
+  cunaryminusnode := trv64unaryminusnode;
+  cnotnode := trv64notnode;
+end.
+

+ 50 - 0
compiler/riscv64/rarv.pas

@@ -0,0 +1,50 @@
+{
+    Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
+
+    Handles the common riscv assembler reader routines
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit rarv;
+
+{$I fpcdefs.inc}
+
+interface
+
+uses
+  aasmbase, aasmtai,aasmdata, aasmcpu,
+  cpubase, rautils, cclasses;
+
+type
+  TRVOperand = class(TOperand)
+  end;
+
+  TRVInstruction = class(TInstruction)
+    ordering: TMemoryOrdering;
+    function ConcatInstruction(p: TAsmList): tai; override;
+  end;
+
+implementation
+
+  function TRVInstruction.ConcatInstruction(p: TAsmList): tai;
+    begin
+      Result:=inherited ConcatInstruction(p);
+      (result as taicpu).memoryordering:=ordering;
+    end;
+
+end.
+

+ 840 - 0
compiler/riscv64/rarv64gas.pas

@@ -0,0 +1,840 @@
+{
+    Copyright (c) 2016 by Jeppe Johansen
+
+    Does the parsing for the RiscV64 GNU AS styled inline assembler.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit rarv64gas;
+
+{$I fpcdefs.inc}
+
+  interface
+
+    uses
+      raatt, rarv,
+      cpubase;
+
+    type
+      trv64attreader = class(tattreader)
+        actmemoryordering: TMemoryOrdering;
+        function is_register(const s: string): boolean; override;
+        function is_asmopcode(const s: string):boolean;override;
+        procedure handleopcode;override;
+        procedure BuildReference(oper : trvoperand);
+        procedure BuildOperand(oper : trvoperand);
+        procedure BuildOpCode(instr : trvinstruction);
+        procedure ReadAt(oper : trvoperand);
+        procedure ReadSym(oper : trvoperand);
+     end;
+
+  implementation
+
+    uses
+      { helpers }
+      cutils,
+      { global }
+      globtype,globals,verbose,
+      systems,
+      { aasm }
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      { symtable }
+      symconst,symsym,symdef,
+      { parser }
+      procinfo,
+      rabase,rautils,
+      cgbase,cgobj,cgrv
+      ;
+
+    procedure trv64attreader.ReadSym(oper : trvoperand);
+      var
+         tempstr, mangledname : string;
+         typesize,l,k : aint;
+      begin
+        tempstr:=actasmpattern;
+        Consume(AS_ID);
+        { typecasting? }
+        if (actasmtoken=AS_LPAREN) and
+           SearchType(tempstr,typesize) then
+         begin
+           oper.hastype:=true;
+           Consume(AS_LPAREN);
+           BuildOperand(oper);
+           Consume(AS_RPAREN);
+           if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+             oper.SetSize(typesize,true);
+         end
+        else
+         if not oper.SetupVar(tempstr,false) then
+          Message1(sym_e_unknown_id,tempstr);
+        { record.field ? }
+        if actasmtoken=AS_DOT then
+         begin
+           BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
+           if (mangledname<>'') then
+             Message(asmr_e_invalid_reference_syntax);
+           inc(oper.opr.ref.offset,l);
+         end;
+      end;
+
+
+    procedure trv64attreader.ReadAt(oper : trvoperand);
+      begin
+        { check for ...@ }
+        if actasmtoken=AS_AT then
+          begin
+            if (oper.opr.ref.symbol=nil) and
+               (oper.opr.ref.offset = 0) then
+              Message(asmr_e_invalid_reference_syntax);
+            Consume(AS_AT);
+            if actasmtoken=AS_ID then
+              begin
+                {if upper(actasmpattern)='L' then
+                  oper.opr.ref.refaddr:=addr_low
+                else if upper(actasmpattern)='HI' then
+                  oper.opr.ref.refaddr:=addr_high
+                else if upper(actasmpattern)='HA' then
+                  oper.opr.ref.refaddr:=addr_higha
+                else}
+                  Message(asmr_e_invalid_reference_syntax);
+                Consume(AS_ID);
+              end
+            else
+              Message(asmr_e_invalid_reference_syntax);
+          end;
+      end;
+
+
+    procedure trv64attreader.BuildReference(oper: trvoperand);
+
+      procedure Consume_RParen;
+        begin
+          if actasmtoken <> AS_RPAREN then
+           Begin
+             Message(asmr_e_invalid_reference_syntax);
+             RecoverConsume(true);
+           end
+          else
+           begin
+             Consume(AS_RPAREN);
+             if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
+              Begin
+                Message(asmr_e_invalid_reference_syntax);
+                RecoverConsume(true);
+              end;
+           end;
+        end;
+
+      var
+        l : aint;
+        relsym: string;
+        asmsymtyp: tasmsymtype;
+        isflags: tindsymflags;
+
+      begin
+        Consume(AS_LPAREN);
+        Case actasmtoken of
+          AS_INTNUM,
+          AS_MINUS,
+          AS_PLUS:
+            Begin
+              { offset(offset) is invalid }
+              If oper.opr.Ref.Offset <> 0 Then
+               Begin
+                 Message(asmr_e_invalid_reference_syntax);
+                 RecoverConsume(true);
+               End
+              Else
+               Begin
+                 oper.opr.Ref.Offset:=BuildConstExpression(false,true);
+                 Consume(AS_RPAREN);
+                 if actasmtoken=AS_AT then
+                   ReadAt(oper);
+               end;
+              exit;
+            End;
+          AS_REGISTER: { (reg ...  }
+            Begin
+              if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
+                 ((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
+                message(asmr_e_cannot_index_relative_var);
+              oper.opr.ref.base:=actasmregister;
+              Consume(AS_REGISTER);
+              Consume_RParen;
+            end; {end case }
+          AS_ID:
+            Begin
+              ReadSym(oper);
+              case actasmtoken of
+                AS_PLUS:
+                  begin
+                    { add a constant expression? }
+                    l:=BuildConstExpression(true,true);
+                    case oper.opr.typ of
+                      OPR_CONSTANT :
+                        inc(oper.opr.val,l);
+                      OPR_LOCAL :
+                        inc(oper.opr.localsymofs,l);
+                      OPR_REFERENCE :
+                        inc(oper.opr.ref.offset,l);
+                      else
+                        internalerror(200309202);
+                    end;
+                  end;
+                AS_MINUS:
+                  begin
+                    Consume(AS_MINUS);
+                    BuildConstSymbolExpression(false,true,false,l,relsym,asmsymtyp);
+                    if (relsym<>'') then
+                      begin
+                        if (oper.opr.typ = OPR_REFERENCE) then
+                          oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym,AT_DATA)
+                        else
+                          begin
+                            Message(asmr_e_invalid_reference_syntax);
+                            RecoverConsume(false);
+                          end
+                      end
+                    else
+                      begin
+                        case oper.opr.typ of
+                          OPR_CONSTANT :
+                            dec(oper.opr.val,l);
+                          OPR_LOCAL :
+                            dec(oper.opr.localsymofs,l);
+                          OPR_REFERENCE :
+                            dec(oper.opr.ref.offset,l);
+                          else
+                            internalerror(2007092601);
+                        end;
+                      end;
+                  end;
+              end;
+              Consume(AS_RPAREN);
+              if actasmtoken=AS_AT then
+                ReadAt(oper);
+            End;
+          AS_COMMA: { (, ...  can either be scaling, or index }
+            Begin
+              Consume(AS_COMMA);
+              { Index }
+              if (actasmtoken=AS_REGISTER) then
+                Begin
+                  oper.opr.ref.index:=actasmregister;
+                  Consume(AS_REGISTER);
+                  { check for scaling ... }
+                  Consume_RParen;
+                end
+              else
+                begin
+                  Message(asmr_e_invalid_reference_syntax);
+                  RecoverConsume(false);
+                end;
+            end;
+        else
+          Begin
+            Message(asmr_e_invalid_reference_syntax);
+            RecoverConsume(false);
+          end;
+        end;
+      end;
+
+
+    procedure trv64attreader.BuildOperand(oper: trvoperand);
+      var
+        expr : string;
+        typesize,l : aint;
+
+
+        procedure AddLabelOperand(hl:tasmlabel);
+          begin
+            if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
+               is_calljmp(actopcode) then
+             begin
+               oper.opr.typ:=OPR_SYMBOL;
+               oper.opr.symbol:=hl;
+             end
+            else
+             begin
+               oper.InitRef;
+               oper.opr.ref.symbol:=hl;
+             end;
+          end;
+
+
+        procedure MaybeRecordOffset;
+          var
+            mangledname: string;
+            hasdot  : boolean;
+            l,
+            toffset,
+            tsize   : aint;
+          begin
+            if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
+             exit;
+            l:=0;
+            hasdot:=(actasmtoken=AS_DOT);
+            if hasdot then
+              begin
+                if expr<>'' then
+                  begin
+                    BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
+                    if (oper.opr.typ<>OPR_CONSTANT) and
+                       (mangledname<>'') then
+                      Message(asmr_e_wrong_sym_type);
+                    inc(l,toffset);
+                    oper.SetSize(tsize,true);
+                  end;
+              end;
+            if actasmtoken in [AS_PLUS,AS_MINUS] then
+              inc(l,BuildConstExpression(true,false));
+            case oper.opr.typ of
+              OPR_LOCAL :
+                begin
+                  { don't allow direct access to fields of parameters, because that
+                    will generate buggy code. Allow it only for explicit typecasting }
+                  if hasdot and
+                     (not oper.hastype) and
+                     (tabstractvarsym(oper.opr.localsym).owner.symtabletype=parasymtable) and
+                     (current_procinfo.procdef.proccalloption<>pocall_register) then
+                    Message(asmr_e_cannot_access_field_directly_for_parameters);
+                  inc(oper.opr.localsymofs,l)
+                end;
+              OPR_CONSTANT :
+                if (mangledname<>'') then
+                  begin
+                    if (oper.opr.val<>0) then
+                      Message(asmr_e_wrong_sym_type);
+                    oper.opr.typ:=OPR_SYMBOL;
+                    oper.opr.symbol:=current_asmdata.DefineAsmSymbol(mangledname,AB_EXTERNAL,AT_FUNCTION,voidcodepointertype);
+                  end
+                else
+                  inc(oper.opr.val,l);
+              OPR_REFERENCE :
+                inc(oper.opr.ref.offset,l);
+              OPR_SYMBOL:
+                Message(asmr_e_invalid_symbol_ref);
+              else
+                internalerror(200309221);
+            end;
+          end;
+
+
+        function MaybeBuildReference:boolean;
+          { Try to create a reference, if not a reference is found then false
+            is returned }
+          begin
+            MaybeBuildReference:=true;
+            case actasmtoken of
+              AS_INTNUM,
+              AS_MINUS,
+              AS_PLUS:
+                Begin
+                  oper.opr.ref.offset:=BuildConstExpression(True,False);
+                  if actasmtoken<>AS_LPAREN then
+                    Message(asmr_e_invalid_reference_syntax)
+                  else
+                    BuildReference(oper);
+                end;
+              AS_LPAREN:
+                BuildReference(oper);
+              AS_ID: { only a variable is allowed ... }
+                Begin
+                  ReadSym(oper);
+                  case actasmtoken of
+                    AS_END,
+                    AS_SEPARATOR,
+                    AS_COMMA: ;
+                    AS_LPAREN:
+                      BuildReference(oper);
+                  else
+                    Begin
+                      Message(asmr_e_invalid_reference_syntax);
+                      Consume(actasmtoken);
+                    end;
+                  end; {end case }
+                end;
+              else
+               MaybeBuildReference:=false;
+            end; { end case }
+          end;
+
+
+        function is_fenceflag(hs : string): boolean;
+          var
+            i: longint;
+            flags: TFenceFlags;
+          begin
+            is_fenceflag := false;
+
+            flags:=[];
+            hs:=lower(hs);
+
+            if (actopcode in [A_FENCE]) and (length(hs) >= 1) then
+              begin
+                for i:=1 to length(hs) do
+                  begin
+                    case hs[i] of
+                      'i':
+                        Include(flags,ffi);
+                      'o':
+                        Include(flags,ffo);
+                      'r':
+                        Include(flags,ffr);
+                      'w':
+                        Include(flags,ffw);
+                    else
+                      exit;
+                    end;
+                  end;
+                oper.opr.typ := OPR_FENCEFLAGS;
+                oper.opr.fenceflags := flags;
+                exit(true);
+              end;
+          end;
+
+
+      var
+        tempreg : tregister;
+        hl : tasmlabel;
+        ofs : aint;
+        refaddr: trefaddr;
+      Begin
+        expr:='';
+
+        refaddr:=addr_full;
+        if actasmtoken=AS_MOD then
+          begin
+            consume(AS_MOD);
+
+            if actasmtoken<>AS_ID then
+              begin
+                Message(asmr_e_invalid_reference_syntax);
+                RecoverConsume(false);
+              end
+            else
+              begin
+                if lower(actasmpattern)='pcrel_hi' then
+                  refaddr:=addr_pcrel_hi20
+                else if lower(actasmpattern)='pcrel_lo' then
+                  refaddr:=addr_pcrel_lo12
+                else if lower(actasmpattern)='hi' then
+                  refaddr:=addr_hi20
+                else if lower(actasmpattern)='lo' then
+                  refaddr:=addr_lo12
+                else
+                  begin
+                    Message(asmr_e_invalid_reference_syntax);
+                    RecoverConsume(false);
+                  end;
+
+                consume(AS_ID);
+                consume(AS_LPAREN);
+              end;
+          end;
+
+        case actasmtoken of
+          AS_LPAREN: { Memory reference or constant expression }
+            Begin
+              oper.InitRef;
+              BuildReference(oper);
+            end;
+
+          AS_INTNUM,
+          AS_MINUS,
+          AS_PLUS:
+            Begin
+              { Constant memory offset }
+              { This must absolutely be followed by (  }
+              oper.InitRef;
+              oper.opr.ref.offset:=BuildConstExpression(True,False);
+              if actasmtoken<>AS_LPAREN then
+                begin
+                  ofs:=oper.opr.ref.offset;
+                  BuildConstantOperand(oper);
+                  inc(oper.opr.val,ofs);
+                end
+              else
+                BuildReference(oper);
+            end;
+
+          AS_ID: { A constant expression, or a Variable ref.  }
+            Begin
+              if is_fenceflag(actasmpattern) then
+                begin
+                  consume(AS_ID);
+                end
+              else
+              { Local Label ? }
+              if is_locallabel(actasmpattern) then
+               begin
+                 CreateLocalLabel(actasmpattern,hl,false);
+                 Consume(AS_ID);
+                 AddLabelOperand(hl);
+               end
+              else
+               { Check for label }
+               if SearchLabel(actasmpattern,hl,false) then
+                begin
+                  Consume(AS_ID);
+                  AddLabelOperand(hl);
+                end
+              else
+               { probably a variable or normal expression }
+               { or a procedure (such as in CALL ID)      }
+               Begin
+                 { is it a constant ? }
+                 if SearchIConstant(actasmpattern,l) then
+                  Begin
+                    if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
+                     Message(asmr_e_invalid_operand_type);
+                    BuildConstantOperand(oper);
+                  end
+                 else
+                  begin
+                    expr:=actasmpattern;
+                    Consume(AS_ID);
+                    { typecasting? }
+                    if (actasmtoken=AS_LPAREN) and
+                       SearchType(expr,typesize) then
+                     begin
+                       oper.hastype:=true;
+                       Consume(AS_LPAREN);
+                       BuildOperand(oper);
+                       Consume(AS_RPAREN);
+                       if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
+                         oper.SetSize(typesize,true);
+                     end
+                    else
+                     begin
+                       if oper.SetupVar(expr,false) then
+                         ReadAt(oper)
+                       else
+                        Begin
+                          { look for special symbols ... }
+                          if expr= '__HIGH' then
+                            begin
+                              consume(AS_LPAREN);
+                              if not oper.setupvar('high'+actasmpattern,false) then
+                                Message1(sym_e_unknown_id,'high'+actasmpattern);
+                              consume(AS_ID);
+                              consume(AS_RPAREN);
+                            end
+                          else
+                           if expr = '__RESULT' then
+                            oper.SetUpResult
+                          else
+                           if expr = '__SELF' then
+                            oper.SetupSelf
+                          else
+                           if expr = '__OLDEBP' then
+                            oper.SetupOldEBP
+                          else
+                            Message1(sym_e_unknown_id,expr);
+                        end;
+                     end;
+                  end;
+                  if actasmtoken=AS_DOT then
+                    MaybeRecordOffset;
+                  { add a constant expression? }
+                  if (actasmtoken=AS_PLUS) then
+                   begin
+                     l:=BuildConstExpression(true,false);
+                     case oper.opr.typ of
+                       OPR_CONSTANT :
+                         inc(oper.opr.val,l);
+                       OPR_LOCAL :
+                         inc(oper.opr.localsymofs,l);
+                       OPR_REFERENCE :
+                         inc(oper.opr.ref.offset,l);
+                       else
+                         internalerror(200309202);
+                     end;
+                   end
+               end;
+              { Do we have a indexing reference, then parse it also }
+              if actasmtoken=AS_LPAREN then
+                BuildReference(oper);
+            end;
+
+          AS_REGISTER: { Register, a variable reference or a constant reference  }
+            Begin
+              { save the type of register used. }
+              tempreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
+                  begin
+                    if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
+                      Message(asmr_e_invalid_operand_type);
+                    oper.opr.typ:=OPR_REGISTER;
+                    oper.opr.reg:=tempreg;
+                  end
+              else
+                Message(asmr_e_syn_operand);
+            end;
+          AS_END,
+          AS_SEPARATOR,
+          AS_COMMA: ;
+        else
+          Begin
+            Message(asmr_e_syn_operand);
+            Consume(actasmtoken);
+          end;
+        end; { end case }
+
+        if refaddr<>addr_full then
+          begin
+            if oper.opr.typ<>OPR_REFERENCE then
+              oper.InitRef;
+
+            oper.opr.ref.refaddr:=refaddr;
+            Consume(AS_RPAREN);
+          end;
+      end;
+
+
+{*****************************************************************************
+                                trv64attreader
+*****************************************************************************}
+
+    procedure trv64attreader.BuildOpCode(instr : trvinstruction);
+      var
+        operandnum : longint;
+      Begin
+        { opcode }
+        if (actasmtoken<>AS_OPCODE) then
+         Begin
+           Message(asmr_e_invalid_or_missing_opcode);
+           RecoverConsume(true);
+           exit;
+         end;
+        { Fill the instr object with the current state }
+        with instr do
+          begin
+            Opcode:=ActOpcode;
+            condition:=ActCondition;
+            ordering:=actmemoryordering;
+          end;
+
+        { We are reading operands, so opcode will be an AS_ID }
+        operandnum:=1;
+        Consume(AS_OPCODE);
+        { Zero operand opcode ?  }
+        if actasmtoken in [AS_SEPARATOR,AS_END] then
+         begin
+           operandnum:=0;
+           exit;
+         end;
+        { Read the operands }
+        repeat
+          case actasmtoken of
+            AS_COMMA: { Operand delimiter }
+              Begin
+                if operandnum>Max_Operands then
+                  Message(asmr_e_too_many_operands)
+                else
+                  begin
+                    { condition operands doesn't set the operand but write to the
+                      condition field of the instruction
+                    }
+                    if instr.Operands[operandnum].opr.typ<>OPR_NONE then
+                      Inc(operandnum);
+                  end;
+                Consume(AS_COMMA);
+              end;
+            AS_SEPARATOR,
+            AS_END : { End of asm operands for this opcode  }
+              begin
+                break;
+              end;
+          else
+            BuildOperand(instr.Operands[operandnum] as trvoperand);
+          end; { end case }
+        until false;
+        if (operandnum=1) and (instr.Operands[operandnum].opr.typ=OPR_NONE) then
+          dec(operandnum);
+        instr.Ops:=operandnum;
+      end;
+
+    function trv64attreader.is_register(const s: string): boolean;
+      type
+        treg2str = record
+          name : string[3];
+          reg : tregister;
+        end;
+
+      const
+        extraregs : array[0..31] of treg2str = (
+          (name: 'A0'; reg : NR_X10),
+          (name: 'A1'; reg : NR_X11),
+          (name: 'A2'; reg : NR_X12),
+          (name: 'A3'; reg : NR_X13),
+          (name: 'A4'; reg : NR_X14),
+          (name: 'A5'; reg : NR_X15),
+          (name: 'A6'; reg : NR_X16),
+          (name: 'A7'; reg : NR_X17),
+          (name: 'RA'; reg : NR_X1),
+          (name: 'SP'; reg : NR_X2),
+          (name: 'GP'; reg : NR_X3),
+          (name: 'TP'; reg : NR_X4),
+          (name: 'T0'; reg : NR_X5),
+          (name: 'T1'; reg : NR_X6),
+          (name: 'T2'; reg : NR_X7),
+          (name: 'S0'; reg : NR_X8),
+          (name: 'FP'; reg : NR_X8),
+          (name: 'S1'; reg : NR_X9),
+          (name: 'S2'; reg : NR_X18),
+          (name: 'S3'; reg : NR_X19),
+          (name: 'S4'; reg : NR_X20),
+          (name: 'S5'; reg : NR_X21),
+          (name: 'S6'; reg : NR_X22),
+          (name: 'S7'; reg : NR_X23),
+          (name: 'S8'; reg : NR_X24),
+          (name: 'S9'; reg : NR_X25),
+          (name: 'S10';reg : NR_X26),
+          (name: 'S11';reg : NR_X27),
+          (name: 'T3'; reg : NR_X28),
+          (name: 'T4'; reg : NR_X29),
+          (name: 'T5'; reg : NR_X30),
+          (name: 'T6'; reg : NR_X31)
+          );
+
+      var
+        i : longint;
+
+      begin
+        result:=inherited is_register(s);
+        { reg found?
+          possible aliases are always 2 char
+        }
+        if result or (not (length(s) in [2,3])) then
+          exit;
+        for i:=low(extraregs) to high(extraregs) do
+          begin
+            if s=extraregs[i].name then
+              begin
+                actasmregister:=extraregs[i].reg;
+                result:=true;
+                actasmtoken:=AS_REGISTER;
+                exit;
+              end;
+          end;
+      end;
+
+
+    function trv64attreader.is_asmopcode(const s: string):boolean;
+      var
+        cond  : tasmcond;
+        hs, postfix : string;
+        l: longint;
+      Begin
+        { making s a value parameter would break other assembler readers }
+        hs:=s;
+        is_asmopcode:=false;
+
+        { clear op code }
+        actopcode:=A_None;
+        { clear condition }
+        fillchar(actcondition,sizeof(actcondition),0);
+
+        { check for direction hint }
+        actopcode := tasmop(ptruint(iasmops.find(hs)));
+        if actopcode <> A_NONE then
+          begin
+            actasmtoken:=AS_OPCODE;
+            is_asmopcode:=true;
+            exit;
+          end;
+        { not found, check branch instructions }
+        if hs[1]='B' then
+          begin
+            { we can search here without an extra table which is sorted by string length
+              because we take the whole remaining string without the leading B }
+            actopcode := A_Bxx;
+            for cond:=low(TAsmCond) to high(TAsmCond) do
+              if copy(hs,2,length(s)-1)=uppercond2str[cond] then
+                begin
+                  actcondition:=cond;
+                  actasmtoken:=AS_OPCODE;
+                  is_asmopcode:=true;
+                  exit;
+                end;
+          end;
+
+        { check atomic instructions }
+        if (pos('AMO',hs)=1) or
+           (pos('LR', hs)=1) or
+           (pos('SC', hs)=1) then
+          begin
+            l := length(hs)-1;
+            while l>1 do
+              begin
+                actopcode := tasmop(ptruint(iasmops.find(copy(hs,1,l))));
+                if actopcode <> A_None then
+                  begin
+                    postfix := copy(hs,l+1,length(hs)-l);
+
+                    if postfix='.AQRL' then actmemoryordering:=[moAq,moRl]
+                    else if postfix='.RL' then actmemoryordering:=[moRl]
+                    else if postfix='.AQ' then actmemoryordering:=[moAq]
+                    else
+                      exit;
+
+                    actasmtoken:=AS_OPCODE;
+                    is_asmopcode:=true;
+                    exit;
+                  end;
+                dec(l);
+              end;
+          end;
+      end;
+
+
+    procedure trv64attreader.handleopcode;
+      var
+        instr : trvinstruction;
+      begin
+        instr:=trvinstruction.Create(trvoperand);
+        BuildOpcode(instr);
+        instr.condition := actcondition;
+        {
+        instr.AddReferenceSizes;
+        instr.SetInstructionOpsize;
+        instr.CheckOperandSizes;
+        }
+        instr.ConcatInstruction(curlist);
+        instr.Free;
+        actmemoryordering:=[];
+      end;
+
+
+{*****************************************************************************
+                                     Initialize
+*****************************************************************************}
+
+    const
+      asmmode_rv64_standard_info : tasmmodeinfo =
+              (
+                id    : asmmode_standard;
+                idtxt : 'STANDARD';
+                casmreader : trv64attreader;
+              );
+
+initialization
+  RegisterAsmMode(asmmode_rv64_standard_info);
+end.
+

+ 67 - 0
compiler/riscv64/rrv32con.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+NR_NO = tregister($00000000);
+NR_X0 = tregister($01000000);
+NR_X1 = tregister($01000001);
+NR_X2 = tregister($01000002);
+NR_X3 = tregister($01000003);
+NR_X4 = tregister($01000004);
+NR_X5 = tregister($01000005);
+NR_X6 = tregister($01000006);
+NR_X7 = tregister($01000007);
+NR_X8 = tregister($01000008);
+NR_X9 = tregister($01000009);
+NR_X10 = tregister($0100000a);
+NR_X11 = tregister($0100000b);
+NR_X12 = tregister($0100000c);
+NR_X13 = tregister($0100000d);
+NR_X14 = tregister($0100000e);
+NR_X15 = tregister($0100000f);
+NR_X16 = tregister($01000010);
+NR_X17 = tregister($01000011);
+NR_X18 = tregister($01000012);
+NR_X19 = tregister($01000013);
+NR_X20 = tregister($01000014);
+NR_X21 = tregister($01000015);
+NR_X22 = tregister($01000016);
+NR_X23 = tregister($01000017);
+NR_X24 = tregister($01000018);
+NR_X25 = tregister($01000019);
+NR_X26 = tregister($0100001a);
+NR_X27 = tregister($0100001b);
+NR_X28 = tregister($0100001c);
+NR_X29 = tregister($0100001d);
+NR_X30 = tregister($0100001e);
+NR_X31 = tregister($0100001f);
+NR_F0 = tregister($02000000);
+NR_F1 = tregister($02000001);
+NR_F2 = tregister($02000002);
+NR_F3 = tregister($02000003);
+NR_F4 = tregister($02000004);
+NR_F5 = tregister($02000005);
+NR_F6 = tregister($02000006);
+NR_F7 = tregister($02000007);
+NR_F8 = tregister($02000008);
+NR_F9 = tregister($02000009);
+NR_F10 = tregister($0200000a);
+NR_F11 = tregister($0200000b);
+NR_F12 = tregister($0200000c);
+NR_F13 = tregister($0200000d);
+NR_F14 = tregister($0200000e);
+NR_F15 = tregister($0200000f);
+NR_F16 = tregister($02000010);
+NR_F17 = tregister($02000011);
+NR_F18 = tregister($02000012);
+NR_F19 = tregister($02000013);
+NR_F20 = tregister($02000014);
+NR_F21 = tregister($02000015);
+NR_F22 = tregister($02000016);
+NR_F23 = tregister($02000017);
+NR_F24 = tregister($02000018);
+NR_F25 = tregister($02000019);
+NR_F26 = tregister($0200001a);
+NR_F27 = tregister($0200001b);
+NR_F28 = tregister($0200001c);
+NR_F29 = tregister($0200001d);
+NR_F30 = tregister($0200001e);
+NR_F31 = tregister($0200001f);
+NR_FCSR = tregister($05000001);

+ 67 - 0
compiler/riscv64/rrv32dwa.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0

+ 2 - 0
compiler/riscv64/rrv32nor.inc

@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from rv32reg.dat }
+66

+ 67 - 0
compiler/riscv64/rrv32num.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+tregister($00000000),
+tregister($01000000),
+tregister($01000001),
+tregister($01000002),
+tregister($01000003),
+tregister($01000004),
+tregister($01000005),
+tregister($01000006),
+tregister($01000007),
+tregister($01000008),
+tregister($01000009),
+tregister($0100000a),
+tregister($0100000b),
+tregister($0100000c),
+tregister($0100000d),
+tregister($0100000e),
+tregister($0100000f),
+tregister($01000010),
+tregister($01000011),
+tregister($01000012),
+tregister($01000013),
+tregister($01000014),
+tregister($01000015),
+tregister($01000016),
+tregister($01000017),
+tregister($01000018),
+tregister($01000019),
+tregister($0100001a),
+tregister($0100001b),
+tregister($0100001c),
+tregister($0100001d),
+tregister($0100001e),
+tregister($0100001f),
+tregister($02000000),
+tregister($02000001),
+tregister($02000002),
+tregister($02000003),
+tregister($02000004),
+tregister($02000005),
+tregister($02000006),
+tregister($02000007),
+tregister($02000008),
+tregister($02000009),
+tregister($0200000a),
+tregister($0200000b),
+tregister($0200000c),
+tregister($0200000d),
+tregister($0200000e),
+tregister($0200000f),
+tregister($02000010),
+tregister($02000011),
+tregister($02000012),
+tregister($02000013),
+tregister($02000014),
+tregister($02000015),
+tregister($02000016),
+tregister($02000017),
+tregister($02000018),
+tregister($02000019),
+tregister($0200001a),
+tregister($0200001b),
+tregister($0200001c),
+tregister($0200001d),
+tregister($0200001e),
+tregister($0200001f),
+tregister($05000001)

+ 67 - 0
compiler/riscv64/rrv32rni.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+63,
+64,
+65

+ 67 - 0
compiler/riscv64/rrv32sri.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+0,
+33,
+34,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+35,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+36,
+63,
+64,
+37,
+38,
+39,
+40,
+41,
+42,
+65,
+1,
+2,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+3,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+4,
+31,
+32,
+5,
+6,
+7,
+8,
+9,
+10

+ 67 - 0
compiler/riscv64/rrv32sta.inc

@@ -0,0 +1,67 @@
+{ don't edit, this file is generated from rv32reg.dat }
+-1,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+0

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно