浏览代码

Added RiscV32/64 target, from a cleaned up version of branches/laksen/riscv/trunk.

git-svn-id: branches/laksen/riscv_new@39474 -
Jeppe Johansen 7 年之前
父节点
当前提交
ceb38833f2
共有 100 个文件被更改,包括 13255 次插入25 次删除
  1. 114 1
      .gitattributes
  2. 7 7
      compiler/aoptobj.pas
  3. 8 0
      compiler/cgbase.pas
  4. 4 1
      compiler/cgutils.pas
  5. 6 2
      compiler/entfile.pas
  6. 24 0
      compiler/fpcdefs.inc
  7. 14 2
      compiler/globals.pas
  8. 26 2
      compiler/options.pas
  9. 13 0
      compiler/pp.pas
  10. 80 0
      compiler/ppcriscv64.lpi
  11. 3 3
      compiler/psub.pas
  12. 8 0
      compiler/psystem.pas
  13. 581 0
      compiler/riscv/aasmcpu.pas
  14. 240 0
      compiler/riscv/agrvgas.pas
  15. 694 0
      compiler/riscv/cgrv.pas
  16. 217 0
      compiler/riscv/hlcgrv.pas
  17. 418 0
      compiler/riscv/nrvadd.pas
  18. 178 0
      compiler/riscv/nrvcnv.pas
  19. 131 0
      compiler/riscv/nrvcon.pas
  20. 244 0
      compiler/riscv/nrvinl.pas
  21. 153 0
      compiler/riscv/nrvset.pas
  22. 126 0
      compiler/riscv/rgcpu.pas
  23. 77 0
      compiler/riscv32/aoptcpu.pas
  24. 115 0
      compiler/riscv32/aoptcpub.pas
  25. 40 0
      compiler/riscv32/aoptcpuc.pas
  26. 40 0
      compiler/riscv32/aoptcpud.pas
  27. 641 0
      compiler/riscv32/cgcpu.pas
  28. 426 0
      compiler/riscv32/cpubase.pas
  29. 135 0
      compiler/riscv32/cpuinfo.pas
  30. 47 0
      compiler/riscv32/cpunode.pas
  31. 550 0
      compiler/riscv32/cpupara.pas
  32. 123 0
      compiler/riscv32/cpupi.pas
  33. 84 0
      compiler/riscv32/cputarg.pas
  34. 61 0
      compiler/riscv32/hlcgcpu.pas
  35. 140 0
      compiler/riscv32/itcpugas.pas
  36. 56 0
      compiler/riscv32/nrv32add.pas
  37. 51 0
      compiler/riscv32/nrv32cal.pas
  38. 151 0
      compiler/riscv32/nrv32cnv.pas
  39. 135 0
      compiler/riscv32/nrv32mat.pas
  40. 41 0
      compiler/riscv32/rarv32.pas
  41. 771 0
      compiler/riscv32/rarv32gas.pas
  42. 67 0
      compiler/riscv32/rrv32con.inc
  43. 67 0
      compiler/riscv32/rrv32dwa.inc
  44. 2 0
      compiler/riscv32/rrv32nor.inc
  45. 67 0
      compiler/riscv32/rrv32num.inc
  46. 67 0
      compiler/riscv32/rrv32rni.inc
  47. 67 0
      compiler/riscv32/rrv32sri.inc
  48. 67 0
      compiler/riscv32/rrv32sta.inc
  49. 67 0
      compiler/riscv32/rrv32std.inc
  50. 67 0
      compiler/riscv32/rrv32sup.inc
  51. 77 0
      compiler/riscv32/rv32reg.dat
  52. 216 0
      compiler/riscv32/symcpu.pas
  53. 178 0
      compiler/riscv64/aoptcpu.pas
  54. 116 0
      compiler/riscv64/aoptcpub.pas
  55. 40 0
      compiler/riscv64/aoptcpuc.pas
  56. 40 0
      compiler/riscv64/aoptcpud.pas
  57. 477 0
      compiler/riscv64/cgcpu.pas
  58. 436 0
      compiler/riscv64/cpubase.pas
  59. 136 0
      compiler/riscv64/cpuinfo.pas
  60. 54 0
      compiler/riscv64/cpunode.pas
  61. 593 0
      compiler/riscv64/cpupara.pas
  62. 116 0
      compiler/riscv64/cpupi.pas
  63. 85 0
      compiler/riscv64/cputarg.pas
  64. 78 0
      compiler/riscv64/hlcgcpu.pas
  65. 157 0
      compiler/riscv64/itcpugas.pas
  66. 98 0
      compiler/riscv64/nrv64add.pas
  67. 56 0
      compiler/riscv64/nrv64cal.pas
  68. 136 0
      compiler/riscv64/nrv64cnv.pas
  69. 57 0
      compiler/riscv64/nrv64ld.pas
  70. 163 0
      compiler/riscv64/nrv64mat.pas
  71. 42 0
      compiler/riscv64/rarv.pas
  72. 770 0
      compiler/riscv64/rarv64gas.pas
  73. 67 0
      compiler/riscv64/rrv32con.inc
  74. 67 0
      compiler/riscv64/rrv32dwa.inc
  75. 2 0
      compiler/riscv64/rrv32nor.inc
  76. 67 0
      compiler/riscv64/rrv32num.inc
  77. 67 0
      compiler/riscv64/rrv32rni.inc
  78. 67 0
      compiler/riscv64/rrv32sri.inc
  79. 67 0
      compiler/riscv64/rrv32sta.inc
  80. 67 0
      compiler/riscv64/rrv32std.inc
  81. 67 0
      compiler/riscv64/rrv32sup.inc
  82. 77 0
      compiler/riscv64/rv32reg.dat
  83. 220 0
      compiler/riscv64/symcpu.pas
  84. 8 2
      compiler/systems.inc
  85. 12 3
      compiler/systems.pas
  86. 142 0
      compiler/systems/i_linux.pas
  87. 19 0
      compiler/systems/t_linux.pas
  88. 8 0
      compiler/utils/fpc.pp
  89. 8 2
      compiler/utils/ppuutils/ppudump.pp
  90. 6 0
      compiler/version.pas
  91. 16 0
      rtl/inc/system.inc
  92. 45 0
      rtl/inc/systemh.inc
  93. 10 0
      rtl/linux/osdefs.inc
  94. 1 0
      rtl/linux/riscv32/bsyscall.inc
  95. 139 0
      rtl/linux/riscv32/cprt0.as
  96. 80 0
      rtl/linux/riscv32/dllprt0.as
  97. 118 0
      rtl/linux/riscv32/gprt0.as
  98. 85 0
      rtl/linux/riscv32/prt0.as
  99. 44 0
      rtl/linux/riscv32/sighnd.inc
  100. 47 0
      rtl/linux/riscv32/sighndh.inc

+ 114 - 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,7 @@ 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/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 +661,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
@@ -9614,6 +9686,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
@@ -10221,6 +10315,25 @@ 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/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/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

+ 7 - 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
@@ -1390,7 +1390,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 +1408,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 +1425,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 +1446,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 +1477,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

+ 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 - 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_rv64imafd;
+        optimizecputype : cpu_rv64imafd;
+        asmcputype : cpu_none;
+        fputype : fpu_fd;
+  {$endif riscv64}
 {$endif not GENERIC_CPU}
         asmmode : asmmode_standard;
 {$ifndef jvm}

+ 26 - 2
compiler/options.pas

@@ -695,6 +695,12 @@ begin
 {$ifdef sparc64}
       's',
 {$endif}
+{$ifdef riscv32}
+      'R',
+{$endif}
+{$ifdef riscv64}
+      'r',
+{$endif}
 {$ifdef avr}
       'V',
 {$endif}
@@ -3581,6 +3587,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 +4035,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

+ 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}

+ 80 - 0
compiler/ppcriscv64.lpi

@@ -0,0 +1,80 @@
+<?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>
+      <local>
+        <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+      </local>
+      <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"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 3 - 3
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 = (
         [],
@@ -1002,7 +1002,7 @@ implementation
       begin
         tg:=tgobjclass.create;
 
-{$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)}
 {$if defined(arm)}
         { frame and stack pointer must be always the same on arm thumb so it makes no
           sense to fiddle with a frame pointer }
@@ -1100,7 +1100,7 @@ implementation
 {$endif defined(arm)}
               end;
           end;
-{$endif defined(x86) or defined(arm)}
+{$endif defined(x86) or defined(arm) or defined(riscv32) or defined(riscv64)}
         { set the start offset to the start of the temp area in the stack }
         set_first_temp_offset;
       end;

+ 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);

+ 581 - 0
compiler/riscv/aasmcpu.pas

@@ -0,0 +1,581 @@
+{
+    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 = class(tai_cpu_abstract_sym)
+         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_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 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_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;
+
+
+{ ****************************** 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.
+

+ 240 - 0
compiler/riscv/agrvgas.pas

@@ -0,0 +1,240 @@
+{
+    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^);
+        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).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;
+{$ifdef cpu64bitaddr}
+        Replace(result,'$ARCH','-m64')
+{$else cpu64bitaddr}
+        Replace(result,'$ARCH','-m32');
+{$endif cpu64bitaddr}
+      end;
+
+
+  const
+    as_riscv_gas_info : tasminfo =
+       (
+         id     : as_gas;
+
+         idtxt  : 'AS';
+         asmbin : 'as';
+         asmcmd : '-o $OBJ $EXTRAOPT $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.

+ 694 - 0
compiler/riscv/cgrv.pas

@@ -0,0 +1,694 @@
+{
+    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 = 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_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;
+
+        { 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;
+      protected
+        function  fixref(list: TAsmList; var ref: treference): boolean;
+      end;
+
+  const
+    TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_NONE,
+                         C_LT,C_GE,C_None,C_NE,C_NONE,C_LT,C_GE,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
+        tmpreg: TRegister;
+        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,[]);
+
+        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;
+        list.concat(taicpu.op_reg_reg_ref(A_JALR,NR_RETURN_ADDRESS_REG,tmpreg,href));
+
+         {if not(weak) then
+           list.concat(taicpu.op_reg_sym(A_JAL,NR_RETURN_ADDRESS_REG,current_asmdata.RefAsmSymbol(s,AT_FUNCTION)))
+         else
+           list.concat(taicpu.op_reg_sym(A_JAL,NR_RETURN_ADDRESS_REG,current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)));}
+       { not assigned while generating external wrappers }
+       if assigned(current_procinfo) then
+         include(current_procinfo.flags,pi_do_call);
+      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;
+
+        if (TOpCG2AsmConstOp[op]<>A_None) and
+           is_imm12(a) then
+          list.concat(taicpu.op_reg_reg_const(TOpCG2AsmConstOp[op],dst,src,a))
+        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
+        case op of
+          OP_NOT:
+            list.concat(taicpu.op_reg_reg_const(A_XORI,dst,src1,-1));
+          OP_NEG:
+            list.concat(taicpu.op_reg_reg_reg(A_SUB,dst,NR_X0,src1));
+          OP_MOVE:
+            a_load_reg_reg(list,size,size,src1,dst);
+        else
+          list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOp[op],dst,src2,src1));
+        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;
+
+            href.base:=NR_NO;
+            href.refaddr:=addr_hi20;
+            list.concat(taicpu.op_reg_ref(A_LUI,r,href));
+            href.refaddr:=addr_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 (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,[]);
+            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);
+
+            current_asmdata.getaddrlabel(l);
+
+            a_label(list,l);
+
+            b:=href.base;
+            href.base:=NR_NO;
+
+            href.refaddr:=addr_hi20;
+            href.relsymbol:=l;
+            list.concat(taicpu.op_reg_ref(A_LUI,tmpreg,href));
+            href.refaddr:=addr_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 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,[]);
+            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);
+      var
+        reg1: TRegister;
+        ai: taicpu;
+      begin
+        if a=0 then
+          begin
+            reg1:=NR_X0;
+            if TOpCmp2AsmCond[cmp_op]=C_None then
+              begin
+                cmp_op:=swap_opcmp(cmp_op);
+                reg1:=reg;
+                reg:=NR_X0;
+              end;
+
+            ai:=taicpu.op_reg_reg_sym_ofs(A_Bxx,reg,reg1,l,0);
+            ai.is_jmp:=true;
+            ai.condition:=TOpCmp2AsmCond[cmp_op];
+            list.concat(ai);
+          end
+        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.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,[]);
+          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));
+      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
+          list.concat(taicpu.op_reg_reg(convOp[fromsize,tosize],reg2,reg1))
+        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,[]);
+          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,[]);
+          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
+          begin
+            exit;
+          end;
+
+        if assigned(ref.symbol) then
+          begin
+            reference_reset_symbol(href,ref.symbol,ref.offset,ref.alignment,[]);
+            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,[]);
+            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,[]);
+          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;
+
+end.

+ 217 - 0
compiler/riscv/hlcgrv.pas

@@ -0,0 +1,217 @@
+{
+    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 = 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;
+  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;
+
+end.
+

+ 418 - 0
compiler/riscv/nrvadd.pas

@@ -0,0 +1,418 @@
+{
+    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;
+
+        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;
+
+        // get the operands in the correct order, there are no special cases
+        // here, everything is register-based
+        if (nf_swapped in flags) and (not cmpop) then
+          swapleftright;
+
+        // 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))
+          end
+        else
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,right.location.register));
+
+            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.

+ 244 - 0
compiler/riscv/nrvinl.pas

@@ -0,0 +1,244 @@
+{
+    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 = 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_fma: tnode; override;
+
+          procedure second_sqrt_real; override;
+          procedure second_abs_real; override;
+          procedure second_sqr_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_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:
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_S,location.register,
+              left.location.register));
+          OS_F64:
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT_D,location.register,
+              left.location.register));
+          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));
+       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));
+           end
+         else
+           internalerror(2014032301);
+       end;
+
+
+begin
+   cinlinenode:=trvinlinenode;
+end.

+ 153 - 0
compiler/riscv/nrvset.pas

@@ -0,0 +1,153 @@
+{
+    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(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) and $FFFFF))
+            else
+              helplist.concat(taicpu.op_reg_const(A_LUI,hreg,((spilltemp.offset shr 12)+1) 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,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,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.

+ 426 - 0
compiler/riscv32/cpubase.pas

@@ -0,0 +1,426 @@
+{
+    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,
+        { 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.

+ 47 - 0
compiler/riscv32/cpunode.pas

@@ -0,0 +1,47 @@
+{
+    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,
+       { 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.
+

+ 140 - 0
compiler/riscv32/itcpugas.pas

@@ -0,0 +1,140 @@
+{
+    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>',
+        '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,regvars,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,symsym,
+      { parser }
+      procinfo,
+      rabase,rautils,
+      cgbase,cgobj,cgrv
+      ;
+
+    procedure trv32attreader.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 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 : 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)
+                        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 : 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);
+                  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.
+

+ 178 - 0
compiler/riscv64/aoptcpu.pas

@@ -0,0 +1,178 @@
+{
+    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 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;
+
+{$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.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_write);
+    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;
+    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 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
+                     (hp1.typ=ait_instruction) and         
+                     (taicpu(hp1).opcode=A_ADDI) and
+                     (taicpu(hp1).ops=3) 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);
+
+                      GetNextInstruction(p,hp1);
+                      AsmL.Remove(p);
+                      p.Free;
+                      p:=hp1;
+
+                      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
+                     (taicpu(p).oper[0]^.reg=taicpu(p).oper[1]^.reg) and
+                     GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
+                     (hp1.typ=ait_instruction) and
+                     (taicpu(hp1).opcode in [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[0]^.reg;
+
+                      DebugMsg('Peephole AddiMem2Mem performed', hp1);
+
+                      GetNextInstruction(p,hp1);
+                      AsmL.Remove(p);
+                      p.Free;
+                      p:=hp1;
+
+                      result:=true;
+                    end;
+                end;
+              A_ANDI:
+                begin
+
+                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.
+

+ 477 - 0
compiler/riscv64/cgcpu.pas

@@ -0,0 +1,477 @@
+{
+    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 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_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 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
+        if (fromsize=tosize) or
+           ((tcgsize2unsigned[fromsize]=tcgsize2unsigned[tosize]) and
+            (tcgsize2unsigned[fromsize]=OS_64)) 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_S32) then
+          list.Concat(taicpu.op_reg_reg_const(A_ADDIW,reg2,reg1,0))
+        else if (fromsize=OS_8) then
+          list.Concat(taicpu.op_reg_reg_const(A_ANDI,reg2,reg1,$FF))
+        else
+          begin
+            if tcgsize2size[tosize]<tcgsize2size[fromsize] then
+              fromsize:=tosize;
+
+            if tcgsize2unsigned[fromsize]<>OS_64 then
+              list.Concat(taicpu.op_reg_reg_const(A_SLLI,reg2,reg1,8*(8-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*(8-tcgsize2size[fromsize])))
+            else
+              list.Concat(taicpu.op_reg_reg_const(A_SRAI,reg2,reg2,8*(8-tcgsize2size[fromsize])));
+          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 sarlongint(a shl 32,32)=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,4,[]);
+
+                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.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: 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) then
+              begin
+                if not (RS_RETURN_ADDRESS_REG in regs) then
+                  begin
+                    include(regs,RS_RETURN_ADDRESS_REG);
+                    inc(localsize,8);
+                  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_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,0));
+
+            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;
+        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,-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(stackcount,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));
+                  inc(stackcount);
+                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;
+
+        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 create_codegen;
+begin
+  cg := tcgrv64.create;
+  cg128:=tcg128.create;
+end;
+
+end.

+ 436 - 0
compiler/riscv64/cpubase.pas

@@ -0,0 +1,436 @@
+{
+    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,
+        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
+        );
+
+  {# 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_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 = 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.
+

+ 136 - 0
compiler/riscv64/cpuinfo.pas

@@ -0,0 +1,136 @@
+{
+    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_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] = ('',
+    '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_rv64imafd } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+       { cpu_rv64ima   } [CPURV_HAS_MUL,CPURV_HAS_ATOMIC],
+       { cpu_rv64im    } [CPURV_HAS_MUL],
+       { cpu_rv64i     } []
+     );
+
+implementation
+
+end.
+

+ 54 - 0
compiler/riscv64/cpunode.pas

@@ -0,0 +1,54 @@
+{
+    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,
+  { 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.
+

+ 593 - 0
compiler/riscv64/cpupara.pas

@@ -0,0 +1,593 @@
+{
+    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 :=
+              (varspez = vs_const) and
+              (
+               (
+                (not (calloption in [pocall_cdecl, pocall_cppdecl]) and
+                (def.size > 8))
+               ) or
+               (calloption = pocall_mwpascal)
+              );
+          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);
+
+        case def.typ of
+          procvardef:
+            result:=def.size>8;
+          recorddef:
+            result:=true;
+        end;
+      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;
+
+        paraloc:=result.add_location;
+        { Return in FPU register? }
+        if result.def.typ=floatdef then
+          begin
+            if (p.proccalloption in [pocall_softfloat]) or
+               (cs_fp_emulation in current_settings.moduleswitches) or
+               (current_settings.fputype in [fpu_soft]) then
+              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
+            else
+              begin
+                paraloc^.loc:=LOC_FPUREGISTER;
+                paraloc^.register:=NR_FPU_RESULT_REG;
+                paraloc^.size:=retcgsize;
+                paraloc^.def:=result.def;
+              end;
+          end
+        else
+         { Return in register }
+          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;
+
+    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;
+        parashift: byte;
+        tailpadding,
+        firstparaloc,
+        paraaligned: boolean;
+      begin
+        alllocdef:=nil;
+        locdef:=nil;
+        parashift := 0;
+        para.reset;
+        { should the tail be shifted into the most significant bits? }
+        tailpadding:=false;
+        { 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;
+        { 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;
+            paraloc^.shiftval := parashift;
+
+            { 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;
+
+            { Partial aggregate data may have to be left-aligned. If so, add tail
+              padding }
+            if tailpadding and
+               (paralen < sizeof(aint)) then
+              begin
+                paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
+                paraloc^.size := OS_INT;
+                paraloc^.def := u64inttype;
+              end
+            else if (paracgsize in [OS_NO, OS_128, OS_S128]) then
+              begin
+                if (paralen>4) or
+                   (parashift<>0) 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);
+            inc(nextfloatreg);
+            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 }
+            inc(nextintreg);
+            inc(nextfloatreg);
+            dec(paralen, tcgsize2size[paraloc^.size]);
+          end else if (loc = LOC_MMREGISTER) then begin
+            { Altivec not supported }
+            internalerror(200510192);
+          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.
+

+ 136 - 0
compiler/riscv64/nrv64cnv.pas

@@ -0,0 +1,136 @@
+{
+    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 (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(ops[is_64bit(left.resultdef),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 := 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.
+

+ 42 - 0
compiler/riscv64/rarv.pas

@@ -0,0 +1,42 @@
+{
+    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)
+  end;
+
+implementation
+
+end.
+

+ 770 - 0
compiler/riscv64/rarv64gas.pas

@@ -0,0 +1,770 @@
+{
+    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;
+
+    type
+      trv64attreader = 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,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;
+
+
+      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;
+
+
+{*****************************************************************************
+                                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;
+          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: '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 trv64attreader.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 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;
+      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

+ 67 - 0
compiler/riscv64/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/riscv64/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/riscv64/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

+ 220 - 0
compiler/riscv64/symcpu.pas

@@ -0,0 +1,220 @@
+{
+    Copyright (c) 2014 by Florian Klaempfl
+
+    Symbol table overrides 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 symcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  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
+
+  uses
+    symconst, defutil, defcmp;
+
+
+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.
+

+ 8 - 2
compiler/systems.inc

@@ -52,7 +52,9 @@
              cpu_i8086,                    { 15 }
              cpu_aarch64,                  { 16 }
              cpu_wasm,                     { 17 }
-             cpu_sparc64                   { 18 }
+             cpu_sparc64,                  { 18 }
+             cpu_riscv32,                  { 19 }
+             cpu_riscv64                   { 20 }
        );
 
        tasmmode= (asmmode_none
@@ -179,7 +181,11 @@
              system_wasm_wasm32,        { 92 }
              system_sparc64_linux,      { 93 }
              system_sparc64_solaris,    { 94 }
-             system_arm_netbsd          { 95 }
+             system_arm_netbsd,         { 95 }
+             system_riscv32_linux,      { 96 }
+             system_riscv64_linux,      { 97 }
+             system_riscv64_embedded,   { 98 }
+             system_riscv32_embedded    { 99 }
        );
 
      type

+ 12 - 3
compiler/systems.pas

@@ -232,7 +232,8 @@ interface
        systems_android = [system_arm_android, system_i386_android, system_mipsel_android];
        systems_linux = [system_i386_linux,system_x86_64_linux,system_powerpc_linux,system_powerpc64_linux,
                        system_arm_linux,system_sparc_linux,system_sparc64_linux,system_m68k_linux,
-                       system_x86_6432_linux,system_mipseb_linux,system_mipsel_linux,system_aarch64_linux];
+                       system_x86_6432_linux,system_mipseb_linux,system_mipsel_linux,system_aarch64_linux,
+                       system_riscv32_linux,system_riscv64_linux];
        systems_dragonfly = [system_x86_64_dragonfly];
        systems_freebsd = [system_i386_freebsd,
                           system_x86_64_freebsd];
@@ -274,7 +275,7 @@ interface
                            system_mips_embedded,system_arm_embedded,
                            system_powerpc64_embedded,system_avr_embedded,
                            system_jvm_java32,system_mipseb_embedded,system_mipsel_embedded,
-                           system_i8086_embedded];
+                           system_i8086_embedded,system_riscv32_embedded,system_riscv64_embedded];
 
        { all systems that allow section directive }
        systems_allow_section = systems_embedded;
@@ -397,7 +398,7 @@ interface
        cpu2str : array[TSystemCpu] of string[10] =
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
              'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
-             'aarch64', 'wasm', 'sparc64');
+             'aarch64', 'wasm', 'sparc64','riscv32','riscv64');
 
        abiinfo : array[tabi] of tabiinfo = (
          (name: 'DEFAULT'; supported: true),
@@ -1036,6 +1037,14 @@ begin
 {$ifdef wasm}
   default_target(system_wasm_wasm32);
 {$endif}
+
+{$ifdef riscv32}
+  default_target(system_riscv32_linux);
+{$endif riscv32}
+
+{$ifdef riscv64}
+  default_target(system_riscv64_linux);
+{$endif riscv64}
 end;
 
 

+ 142 - 0
compiler/systems/i_linux.pas

@@ -1029,6 +1029,138 @@ unit i_linux;
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64';
           );
 
+       system_riscv32_linux_info : tsysteminfo =
+          (
+            system       : system_riscv32_linux;
+            name         : 'Linux for RISC-V 32';
+            shortname    : 'Linux';
+            flags        : [tf_needs_symbol_size,tf_smartlink_sections,
+                            tf_needs_symbol_type,tf_files_case_sensitive,
+                            tf_requires_proper_alignment,tf_has_winlike_resources];
+            cpu          : cpu_riscv32;
+            unit_env     : 'LINUXUNITS';
+            extradefines : 'UNIX;HASUNIX';
+            exeext       : '';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.s';
+            objext       : '.o';
+            resext       : '.res';
+            resobjext    : '.or';
+            sharedlibext : '.so';
+            staticlibext : '.a';
+            staticlibprefix : 'libp';
+            sharedlibprefix : 'lib';
+            sharedClibext : '.so';
+            staticClibext : '.a';
+            staticClibprefix : 'lib';
+            sharedClibprefix : 'lib';
+            importlibprefix : 'libimp';
+            importlibext : '.a';
+//            p_ext_support : false;
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_gas;
+            assemextern  : as_gas;
+            link         : ld_none;
+            linkextern   : ld_linux;
+            ar           : ar_gnu_ar;
+            res          : res_elf;
+            dbg          : dbg_stabs;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign       : 4;
+                loopalign       : 4;
+                jumpalign       : 0;
+                constalignmin   : 0;
+                constalignmax   : 8;
+                varalignmin     : 0;
+                varalignmax     : 8;
+                localalignmin   : 4;
+                localalignmax   : 8;
+                recordalignmin  : 0;
+                recordalignmax  : 8;
+                maxCrecordalign : 8
+              );
+            first_parm_offset : 0;
+            stacksize    : 32*1024*1024;
+            stackalign   : 8;
+            abi : abi_default;
+            llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64';
+          );
+
+       system_riscv64_linux_info : tsysteminfo =
+          (
+            system       : system_riscv64_linux;
+            name         : 'Linux for RISC-V 64';
+            shortname    : 'Linux';
+            flags        : [tf_needs_symbol_size,tf_smartlink_sections,
+                            tf_needs_symbol_type,tf_files_case_sensitive,
+                            tf_requires_proper_alignment,tf_has_winlike_resources];
+            cpu          : cpu_riscv64;
+            unit_env     : 'LINUXUNITS';
+            extradefines : 'UNIX;HASUNIX';
+            exeext       : '';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.s';
+            objext       : '.o';
+            resext       : '.res';
+            resobjext    : '.or';
+            sharedlibext : '.so';
+            staticlibext : '.a';
+            staticlibprefix : 'libp';
+            sharedlibprefix : 'lib';
+            sharedClibext : '.so';
+            staticClibext : '.a';
+            staticClibprefix : 'lib';
+            sharedClibprefix : 'lib';
+            importlibprefix : 'libimp';
+            importlibext : '.a';
+//            p_ext_support : false;
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_gas;
+            assemextern  : as_gas;
+            link         : ld_none;
+            linkextern   : ld_linux;
+            ar           : ar_gnu_ar;
+            res          : res_elf;
+            dbg          : dbg_dwarf2;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign       : 8;
+                loopalign       : 4;
+                jumpalign       : 0;
+                constalignmin   : 4;
+                constalignmax   : 16;
+                varalignmin     : 4;
+                varalignmax     : 16;
+                localalignmin   : 8;
+                localalignmax   : 16;
+                recordalignmin  : 0;
+                recordalignmax  : 16;
+                maxCrecordalign : 16
+              );
+            first_parm_offset : 8;
+            stacksize    : 10*1024*1024;
+            stackalign   : 16;
+            abi : abi_default;
+            llvmdatalayout : 'E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:64:64-v128:128:128-n32:64';
+          );
+
   implementation
 
 initialization
@@ -1095,4 +1227,14 @@ initialization
     set_source_info(system_mipsel_linux_info);
   {$endif linux}
 {$endif CPUMIPSEL}
+{$ifdef CPURISCV32}
+  {$ifdef linux}
+    set_source_info(system_riscv32_linux_info);
+  {$endif linux}
+{$endif CPURISCV32}
+{$ifdef CPURISCV64}
+  {$ifdef linux}
+    set_source_info(system_riscv64_linux_info);
+  {$endif linux}
+{$endif CPURISCV64}
 end.

+ 19 - 0
compiler/systems/t_linux.pas

@@ -234,6 +234,13 @@ const defdynlinker='/lib/ld-linux-aarch64.so.1';
   const defdynlinker='/lib64/ld-linux.so.2';
 {$endif sparc64}
 
+{$ifdef riscv32}
+  const defdynlinker='/lib32/ld.so.1';
+{$endif riscv32}
+{$ifdef riscv64}
+  const defdynlinker='/lib/ld.so.1';
+{$endif riscv64}
+
 
 procedure SetupDynlinker(out DynamicLinker:string;out libctype:TLibcType);
 begin
@@ -338,6 +345,8 @@ const
                    platform_select='-EB';
   {$endif}
 {$endif}
+{$ifdef riscv32}   platform_select='';{$endif} {unknown :( }
+{$ifdef riscv64}   platform_select='';{$endif} {unknown :( }
 
 var
   platformopt: string;
@@ -1892,5 +1901,15 @@ initialization
   RegisterTarget(system_mipseb_linux_info);
 {$endif MIPSEL}
 {$endif MIPS}
+{$ifdef riscv32}
+  RegisterImport(system_riscv32_linux,timportliblinux);
+  RegisterExport(system_riscv32_linux,texportliblinux);
+  RegisterTarget(system_riscv32_linux_info);
+{$endif riscv32}
+{$ifdef riscv64}
+  RegisterImport(system_riscv64_linux,timportliblinux);
+  RegisterExport(system_riscv64_linux,texportliblinux);
+  RegisterTarget(system_riscv64_linux_info);
+{$endif riscv64}
   RegisterRes(res_elf_info,TWinLikeResourceFile);
 end.

+ 8 - 0
compiler/utils/fpc.pp

@@ -168,6 +168,14 @@ program fpc;
      processorname:='mips';
   {$endif mips}
 {$endif not mipsel}
+{$ifdef riscv32}
+     ppcbin:='ppcrv32';
+     processorname:='riscv32';
+{$endif riscv32}
+{$ifdef riscv64}
+     ppcbin:='ppcrv64';
+     processorname:='riscv64';
+{$endif riscv64}
      versionstr:='';                      { Default is just the name }
      if ParamCount = 0 then
        begin

+ 8 - 2
compiler/utils/ppuutils/ppudump.pp

@@ -80,7 +80,9 @@ const
     { 15 } 'i8086',
     { 16 } 'aarch64',
     { 17 } 'wasm',
-    { 18 } 'sparc64'
+    { 18 } 'sparc64',
+    { 19 } 'riscv32',
+    { 20 } 'riscv64'
     );
 
 { List of all supported system-cpu couples }
@@ -181,7 +183,11 @@ const
   { 92 }  'WebAssembly-wasm',
   { 93 }  'Linux-sparc64',
   { 94 }  'Solaris-sparc64',
-  { 95 }  'NetBSD-arm'
+  { 95 }  'NetBSD-arm',
+  { 96 }  'Linux-RiscV32',
+  { 97 }  'Linux-RiscV64',
+  { 98 }  'Embedded-RiscV32',
+  { 99 }  'Embedded-RiscV64'
   );
 
 const

+ 6 - 0
compiler/version.pas

@@ -74,6 +74,12 @@ interface
 {$ifdef cpuaarch64}
         source_cpu_string = 'aarch64';
 {$endif cpuaarch64}
+{$ifdef cpuriscv64}
+        source_cpu_string = 'riscv64';
+{$endif cpuriscv64}
+{$ifdef cpuriscv32}
+        source_cpu_string = 'riscv32';
+{$endif cpuriscv32}
 
 function version_string:string;
 function full_version_string:string;

+ 16 - 0
rtl/inc/system.inc

@@ -277,6 +277,22 @@ function do_isdevice(handle:thandle):boolean;forward;
   {$define SYSPROCDEFINED}
 {$endif cpuaarch64}
 
+{$ifdef cpuriscv32}
+  {$ifdef SYSPROCDEFINED}
+    {$Error Can't determine processor type !}
+  {$endif}
+  {$i riscv32.inc}  { Case dependent, don't change }
+  {$define SYSPROCDEFINED}
+{$endif cpuriscv32}
+
+{$ifdef cpuriscv64}
+  {$ifdef SYSPROCDEFINED}
+    {$Error Can't determine processor type !}
+  {$endif}
+  {$i riscv64.inc}  { Case dependent, don't change }
+  {$define SYSPROCDEFINED}
+{$endif cpuriscv64}
+
 {$ifndef SYSPROCDEFINED}
   {$Error Can't determine processor type !}
 {$endif}

+ 45 - 0
rtl/inc/systemh.inc

@@ -367,6 +367,51 @@ Type
   FarPointer = Pointer;
 {$endif CPUAARCH64}
 
+{$ifdef CPURISCV32}
+  {$define DEFAULT_DOUBLE}
+
+  {$define SUPPORT_SINGLE}
+  {$define SUPPORT_DOUBLE}
+
+  {$define FPC_INCLUDE_SOFTWARE_MOD_DIV}
+  {$define FPC_INCLUDE_SOFTWARE_MUL}
+  {$define FPC_INCLUDE_SOFTWARE_SHIFT_INT64}
+  {$define FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
+
+  {$ifndef FPUNONE}
+    {$define FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
+    ValReal = Double;
+  {$endif}
+
+  { map comp to int64, but this doesn't mean we compile the comp support in! }
+  Comp = Int64;
+  PComp = ^Comp;
+
+  FarPointer = Pointer;
+{$endif CPURISCV32}
+
+{$ifdef CPURISCV64}
+  {$define DEFAULT_DOUBLE}
+
+  {$define SUPPORT_SINGLE}
+  {$define SUPPORT_DOUBLE}
+
+  {$define FPC_INCLUDE_SOFTWARE_MOD_DIV}
+  {$define FPC_INCLUDE_SOFTWARE_MUL}
+  {$define FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
+
+  {$ifndef FPUNONE}
+    {$define FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE}
+    ValReal = Double;
+  {$endif}
+
+  { map comp to int64, but this doesn't mean we compile the comp support in! }
+  Comp = Int64;
+  PComp = ^Comp;
+
+  FarPointer = Pointer;
+{$endif CPURISCV64}
+
 
 {$ifdef CPU64}
   SizeInt = Int64;

+ 10 - 0
rtl/linux/osdefs.inc

@@ -94,6 +94,16 @@
   {$define FPC_USEGETTIMEOFDAY}
 {$endif cpusparc64}
 
+{$ifdef cpuriscv32}
+  {$define generic_linux_syscalls}
+  {$undef usestime}
+{$endif cpuriscv32}
+
+{$ifdef cpuriscv64}
+  {$define generic_linux_syscalls}
+  {$undef usestime}
+{$endif cpuriscv64}
+
 {$ifdef android}
   {$undef usestime}
   {$undef OLDMMAP}

+ 1 - 0
rtl/linux/riscv32/bsyscall.inc

@@ -0,0 +1 @@
+{ nothing }

+ 139 - 0
rtl/linux/riscv32/cprt0.as

@@ -0,0 +1,139 @@
+/* Startup code for ARM & ELF
+   Copyright (C) 1995, 1996, 1997, 1998, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA. */
+
+/* This is the canonical entry point, usually the first thing in the text
+   segment.
+
+        Note that the code in the .init section has already been run.
+        This includes _init and _libc_init
+
+
+        At this entry point, most registers' values are unspecified, except:
+
+   a1           Contains a function pointer to be registered with `atexit'.
+                This is how the dynamic linker arranges to have DT_FINI
+                functions called for shared libraries that have been loaded
+                before this code runs.
+
+   sp           The stack contains the arguments and environment:
+                0(sp)                   argc
+                4(sp)                   argv[0]
+                ...
+                (4*argc)(sp)            NULL
+                (4*(argc+1))(sp)        envp[0]
+                ...
+                                        NULL
+*/
+
+        .text
+        .globl _start
+        .type _start,function
+_start:
+        /* Clear the frame pointer since this is the outermost frame.  */
+        mov fp, #0
+        ldmia   sp!, {a2}
+
+        /* Pop argc off the stack and save a pointer to argv */
+        ldr ip,=operatingsystem_parameter_argc
+        ldr a3,=operatingsystem_parameter_argv
+        str a2,[ip]
+
+        /* calc envp */
+        add a4,a2,#1
+        add a4,sp,a4,LSL #2
+        ldr ip,=operatingsystem_parameter_envp
+
+        str sp,[a3]
+        str a4,[ip]
+
+        /* Save initial stackpointer */
+        ldr ip,=__stkptr
+        str sp,[ip]
+
+        /* Fetch address of fini */
+        ldr ip, =_fini
+
+        /* argc already loaded to a2*/
+
+        /* load argv */
+        mov a3, sp
+
+        /* Push stack limit */
+        str a3, [sp, #-4]!
+
+        /* Push rtld_fini */
+        str a1, [sp, #-4]!
+
+        /* Set up the other arguments in registers */
+        ldr a1, =PASCALMAIN
+        ldr a4, =_init
+
+        /* Push fini */
+        str ip, [sp, #-4]!
+
+        /* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */
+
+        /* Let the libc call main and exit with its return code.  */
+        bl __libc_start_main
+
+        /* should never get here....*/
+        bl abort
+
+        .globl  _haltproc
+    .type   _haltproc,function
+_haltproc:
+        ldr r0,=operatingsystem_result
+        ldrb r0,[r0]
+        swi 0x900001
+        b _haltproc
+
+        /* Define a symbol for the first piece of initialized data.  */
+        .data
+        .globl __data_start
+__data_start:
+        .long 0
+        .weak data_start
+        data_start = __data_start
+
+.bss
+        .comm __stkptr,4
+
+        .comm operatingsystem_parameter_envp,4
+        .comm operatingsystem_parameter_argc,4
+        .comm operatingsystem_parameter_argv,4
+
+        .section ".comment"
+        .byte 0
+        .ascii "generated by FPC http://www.freepascal.org\0"
+
+/* We need this stuff to make gdb behave itself, otherwise
+   gdb will chokes with SIGILL when trying to debug apps.
+*/
+        .section ".note.ABI-tag", "a"
+        .align 4
+        .long 1f - 0f
+        .long 3f - 2f
+        .long  1
+0:      .asciz "GNU"
+1:      .align 4
+2:      .long 0
+        .long 2,0,0
+3:      .align 4
+
+.section .note.GNU-stack,"",%progbits

+ 80 - 0
rtl/linux/riscv32/dllprt0.as

@@ -0,0 +1,80 @@
+/*
+ * This file is part of the Free Pascal run time library.
+ * Copyright (c) 2011 by Thomas Schatzl,
+ * member of the Free Pascal development team.
+ *
+ * Startup code for shared libraries, ARM version.
+ *
+ * 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.
+ */
+
+.file   "dllprt0.as"
+.text
+        .globl  _startlib
+        .type   _startlib,function
+_startlib:
+        .globl  FPC_SHARED_LIB_START
+        .type   FPC_SHARED_LIB_START,function
+FPC_SHARED_LIB_START:
+        sw x1, -4(x2)
+        sw x8, -8(x2)
+        addi x8, x2, 0
+        addi x2, x2, -8
+
+        /* a1 contains argc, a2 contains argv and a3 contains envp */
+        lui x15, %hi(operatingsystem_parameter_argc)
+        addi x15,x15,%lo(operatingsystem_parameter_argc)
+        sw a1, (x15)
+
+        lui x15, %hi(operatingsystem_parameter_argv)
+        addi x15,x15,%lo(operatingsystem_parameter_argv)
+        sw a2, (x15)
+
+        lui x15, %hi(operatingsystem_parameter_envp)
+        addi x15,x15,%lo(operatingsystem_parameter_envp)
+        sw a3, (x15)
+
+        /* save initial stackpointer */
+        lui x15, %hi(__stklen)
+        addi x15,x15,%lo(__stklen)
+        sw x2, (x15)
+
+        /* call main and exit normally */
+        jal x1, PASCALMAIN
+        lw x8, -8(x8)
+        lw x1, -4(x8)
+
+        jalr x0, x1
+
+        .globl  _haltproc
+        .type   _haltproc,function
+_haltproc:
+        /* reload exitcode */
+        lui x10, %hi(operatingsystem_result)
+        addi x10,x10,%lo(operatingsystem_result)
+        addi x17, x0, 248
+        scall
+        jal x0, _haltproc
+
+.data
+
+        .type operatingsystem_parameters,object
+        .size operatingsystem_parameters,12
+operatingsystem_parameters:
+        .skip 3*4
+        .global operatingsystem_parameter_envp
+        .global operatingsystem_parameter_argc
+        .global operatingsystem_parameter_argv
+        .set operatingsystem_parameter_envp,operatingsystem_parameters+0
+        .set operatingsystem_parameter_argc,operatingsystem_parameters+4
+        .set operatingsystem_parameter_argv,operatingsystem_parameters+8
+
+.bss
+
+        .comm __stkptr,4
+

+ 118 - 0
rtl/linux/riscv32/gprt0.as

@@ -0,0 +1,118 @@
+/*
+   Start-up code for Free Pascal Compiler when linking with C library
+   with profiling support.
+
+   Written by Edmund Grimley Evans in 2015 and released into the public domain.
+*/
+
+	.text
+	.align 2
+
+	.globl _start
+	.type  _start,#function
+_start:
+	/* Initialise FP to zero */
+	mov	x29,#0
+
+	/* This is rtld_fini */
+	mov	x5,x0
+
+	/* Get argc, argv, envp */
+	ldr	x1,[sp]
+	add	x2,sp,#8
+	add	x11,x1,#1
+	add	x11,x2,x11,lsl #3
+
+	/* Save argc, argv, envp, and initial stack pointer */
+	adrp	x10,:got:operatingsystem_parameter_argc
+	ldr	x10,[x10,#:got_lo12:operatingsystem_parameter_argc]
+	str	x1,[x10]
+	adrp	x10,:got:operatingsystem_parameter_argv
+	ldr	x10,[x10,#:got_lo12:operatingsystem_parameter_argv]
+	str	x2,[x10]
+	adrp	x10,:got:operatingsystem_parameter_envp
+	ldr	x10,[x10,#:got_lo12:operatingsystem_parameter_envp]
+	str	x11,[x10]
+	adrp	x10,:got:__stkptr
+	ldr	x10,[x10,#:got_lo12:__stkptr]
+	mov	x6,sp
+	str	x6,[x10]
+
+	/* __libc_start_main(main, argc, argv,
+	                     init, fini, rtld_fini, stack_end) */
+	adrp	x0,:got:main_stub
+	ldr	x0,[x0,#:got_lo12:main_stub]
+	adrp	x3,:got:_init_dummy
+	ldr	x3,[x3,#:got_lo12:_init_dummy]
+	adrp	x4,:got:_fini_dummy
+	ldr	x4,[x4,#:got_lo12:_fini_dummy]
+	bl	__libc_start_main
+
+	/* This should never happen */
+	b	abort
+
+	.globl	_init_dummy
+	.type	_init_dummy,#function
+_init_dummy:
+	ret
+
+	.globl	_fini_dummy
+	.type	_fini_dummy,#function
+_fini_dummy:
+	ret
+
+	.globl	main_stub
+	.type	main_stub,#function
+main_stub:
+	stp	x29,x30,[sp,#-16]!
+
+	/* Save initial stackpointer */
+	mov	x0,sp
+	adrp	x1,:got:__stkptr
+	ldr	x1,[x1,#:got_lo12:__stkptr]
+	str	x0,[x1]
+
+	/* Initialize gmon */
+	adrp	x0,:got:_start
+	ldr	x0,[x0,#:got_lo12:_start]
+	adrp	x1,:got:_etext
+	ldr	x1,[x1,#:got_lo12:_etext]
+	bl	__monstartup
+	adrp	x0,:got:_mcleanup
+	ldr	x0,[x0,#:got_lo12:_mcleanup]
+	bl	atexit
+
+	/* Start the program */
+	bl	 PASCALMAIN
+	b	 abort
+
+	.globl	_haltproc
+	.type	_haltproc,#function
+_haltproc:
+	/* Return to libc */
+	adrp	x1,:got:__stkptr
+	ldr	x1,[x1,#:got_lo12:__stkptr]
+	ldr	x1,[x1]
+	mov	sp,x1
+	ldp	x29,x30,[sp],#16
+	ret
+
+	/* Define a symbol for the first piece of initialized data. */
+	.data
+	.align 3
+	.globl __data_start
+__data_start:
+	.long 0
+	.weak data_start
+	data_start = __data_start
+
+	.bss
+	.align 3
+
+	.comm __stkptr,8
+
+	.comm operatingsystem_parameter_envp,8
+	.comm operatingsystem_parameter_argc,8
+	.comm operatingsystem_parameter_argv,8
+
+	.section .note.GNU-stack,"",%progbits

+ 85 - 0
rtl/linux/riscv32/prt0.as

@@ -0,0 +1,85 @@
+/*
+   Start-up code for Free Pascal Compiler, not in a shared library,
+   not linking with C library.
+
+   Written by Edmund Grimley Evans in 2015 and released into the public domain.
+*/
+
+	.text
+	.align 2
+
+	.globl _dynamic_start
+	.type  _dynamic_start, function
+_dynamic_start:
+	lui	x5,%hi(__dl_fini)
+	addi	x5,x5,%lo(__dl_fini)
+	sw	x10, (x5)
+	jal	x0, _start
+
+	.globl	_start
+	.type	_start, function
+_start:
+	/* Initialise FP to zero */
+	addi	x2,x0,0
+
+	/* Get argc, argv, envp */
+	lw	x5,(x2)
+	addi	x6,x2,8
+	addi	x7,x5,1
+	slli  x7,x7,3
+	add 	x7,x6,x7
+
+	/* Save argc, argv, envp, and initial stack pointer */
+	lui	x8,%hi(operatingsystem_parameter_argc)
+	addi x8,x8,%lo(operatingsystem_parameter_argc)
+	sw	x5,(x8)
+	lui	x8,%hi(operatingsystem_parameter_argv)
+	addi x8,x8,%lo(operatingsystem_parameter_argv)
+	sw	x6,(x8)
+	lui	x8,%hi(operatingsystem_parameter_envp)
+	addi x8,x8,%lo(operatingsystem_parameter_envp)
+	sw	x7,(x8)
+	lui	x5,%hi(__stkptr)
+	addi x5,x8,%lo(__stkptr)
+	addi	x6, x2, 0
+	sw	x6,(x5)
+
+	/* Call main */
+	jal x1, PASCALMAIN
+
+	.globl	_haltproc
+	.type	_haltproc,function
+_haltproc:
+	lui x10,%hi(__dl_fini)
+	addi x10,x10,%lo(__dl_fini)
+	lw	x10,(x10)
+	beq	x10,x0,.Lexit
+	jalr x1,x10
+.Lexit:
+	lui x10,%hi(operatingsystem_result)
+	addi x10,x10,%lo(operatingsystem_result)
+	lw	x10,(x10)
+	addi	x17, x0, 94
+	scall
+	jal x0, _haltproc
+
+	/* Define a symbol for the first piece of initialized data. */
+	.data
+	.align 3
+	.globl __data_start
+__data_start:
+	.long 0
+	.weak data_start
+	data_start = __data_start
+
+	.bss
+	.align 3
+
+	.comm __dl_fini,8
+	.comm __stkptr,8
+
+	.comm operatingsystem_parameter_envp,8
+	.comm operatingsystem_parameter_argc,8
+	.comm operatingsystem_parameter_argv,8
+
+	.section .note.GNU-stack,"",%progbits

+ 44 - 0
rtl/linux/riscv32/sighnd.inc

@@ -0,0 +1,44 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 1999-2000 by Michael Van Canneyt,
+    member of the Free Pascal development team.
+
+    Signal handler is arch dependant due to processor to language
+    exception conversion.
+
+    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.
+
+ **********************************************************************}
+
+procedure SignalToRunerror(Sig: longint; SigInfo: PSigInfo; UContext: PUContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl;
+
+var
+  res : word;
+begin
+  res:=0;
+  case sig of
+    SIGFPE:
+        res:=207;
+    SIGILL:
+        res:=216;
+    SIGSEGV :
+        res:=216;
+    SIGBUS:
+        res:=214;
+    SIGINT:
+        res:=217;
+    SIGQUIT:
+        res:=233;
+  end;
+  reenable_signal(sig);
+  { give runtime error at the position where the signal was raised }
+  if res<>0 then
+    HandleErrorAddrFrame(res,
+      pointer(uContext^.uc_mcontext.pc),
+      pointer(uContext^.uc_mcontext.regs[29]));
+end;

+ 47 - 0
rtl/linux/riscv32/sighndh.inc

@@ -0,0 +1,47 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 1999-2000 by Jonas Maebe,
+    member of the Free Pascal development team.
+
+    TSigContext and associated structures.
+
+    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.
+
+ **********************************************************************}
+
+{$packrecords C}
+
+type
+  PSigContext = ^TSigContext;
+  TSigContext = record
+    fault_address : cULong;
+    regs : array[0..30] of cULong;
+    sp : cULong;
+    pc : cULong;
+    pstate : cULong;
+    __pad : cULong;
+    { The following field should be 16-byte-aligned. Currently the
+      directive for specifying alignment is buggy, so the preceding
+      field was added so that the record has the right size. }
+    __reserved : array[0..4095] of cUChar;
+  end;
+
+  stack_t = record
+    ss_sp : pointer;
+    ss_flags : cInt;
+    ss_size : size_t;
+  end;
+
+  PUContext = ^TUContext;
+  TUContext = record
+    uc_flags : cULong;
+    uc_link : PUContext;
+    uc_stack : stack_t;
+    uc_mcontext : TSigContext;
+    uc_sigmask : sigset_t;
+  end;

部分文件因为文件数量过多而无法显示