diff options
author | laksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2018-07-20 08:21:15 +0000 |
---|---|---|
committer | laksen <laksen@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2018-07-20 08:21:15 +0000 |
commit | ce49a20c9d88883a4f10798bcaf4d3f36f0155c8 (patch) | |
tree | c9adb5e00e610f17557f0ac90e1b037189ab069e | |
parent | a499e2d25bba1e81c7e3ebc1853f7093cae2b764 (diff) | |
download | fpc-ce49a20c9d88883a4f10798bcaf4d3f36f0155c8.tar.gz |
Added RiscV32/64 target, from a cleaned up version of branches/laksen/riscv/trunk.
git-svn-id: https://svn.freepascal.org/svn/fpc/branches/laksen@39474 3ad0048d-3df7-0310-abae-a5850022a9f2
136 files changed, 15951 insertions, 72 deletions
diff --git a/riscv_new/compiler/aoptobj.pas b/riscv_new/compiler/aoptobj.pas index b9aed768e1..885b9ee64c 100644 --- a/riscv_new/compiler/aoptobj.pas +++ b/riscv_new/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; diff --git a/riscv_new/compiler/cgbase.pas b/riscv_new/compiler/cgbase.pas index 325e8fdfdf..e7abf39926 100644 --- a/riscv_new/compiler/cgbase.pas +++ b/riscv_new/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 diff --git a/riscv_new/compiler/cgutils.pas b/riscv_new/compiler/cgutils.pas index 0c1374b69a..3e2475ced6 100644 --- a/riscv_new/compiler/cgutils.pas +++ b/riscv_new/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; diff --git a/riscv_new/compiler/entfile.pas b/riscv_new/compiler/entfile.pas index 34b3bc3325..7bbbbca9b1 100644 --- a/riscv_new/compiler/entfile.pas +++ b/riscv_new/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} diff --git a/riscv_new/compiler/fpcdefs.inc b/riscv_new/compiler/fpcdefs.inc index ff3add6a38..59f48cd00a 100644 --- a/riscv_new/compiler/fpcdefs.inc +++ b/riscv_new/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} diff --git a/riscv_new/compiler/globals.pas b/riscv_new/compiler/globals.pas index 121845ae28..d5dddbbc4d 100644 --- a/riscv_new/compiler/globals.pas +++ b/riscv_new/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} diff --git a/riscv_new/compiler/options.pas b/riscv_new/compiler/options.pas index a5844254b5..c2c6c055a4 100644 --- a/riscv_new/compiler/options.pas +++ b/riscv_new/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 diff --git a/riscv_new/compiler/pp.pas b/riscv_new/compiler/pp.pas index aec3a42891..7dd479d360 100644 --- a/riscv_new/compiler/pp.pas +++ b/riscv_new/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} diff --git a/riscv_new/compiler/ppcriscv64.lpi b/riscv_new/compiler/ppcriscv64.lpi new file mode 100644 index 0000000000..479f39e551 --- /dev/null +++ b/riscv_new/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> diff --git a/riscv_new/compiler/psub.pas b/riscv_new/compiler/psub.pas index 5bad837ff9..39e9f2bdcf 100644 --- a/riscv_new/compiler/psub.pas +++ b/riscv_new/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; diff --git a/riscv_new/compiler/psystem.pas b/riscv_new/compiler/psystem.pas index 36caae6c8f..ac1b9c86da 100644 --- a/riscv_new/compiler/psystem.pas +++ b/riscv_new/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); diff --git a/riscv_new/compiler/riscv/aasmcpu.pas b/riscv_new/compiler/riscv/aasmcpu.pas new file mode 100644 index 0000000000..30acbaa154 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv/agrvgas.pas b/riscv_new/compiler/riscv/agrvgas.pas new file mode 100644 index 0000000000..19b83e74fe --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/cgrv.pas b/riscv_new/compiler/riscv/cgrv.pas new file mode 100644 index 0000000000..5fb781150b --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/hlcgrv.pas b/riscv_new/compiler/riscv/hlcgrv.pas new file mode 100644 index 0000000000..ece3fdd238 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv/nrvadd.pas b/riscv_new/compiler/riscv/nrvadd.pas new file mode 100644 index 0000000000..672e9ee6f4 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/nrvcnv.pas b/riscv_new/compiler/riscv/nrvcnv.pas new file mode 100644 index 0000000000..54f3e91f29 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/nrvcon.pas b/riscv_new/compiler/riscv/nrvcon.pas new file mode 100644 index 0000000000..66698527b7 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/nrvinl.pas b/riscv_new/compiler/riscv/nrvinl.pas new file mode 100644 index 0000000000..cc6eaa211a --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/nrvset.pas b/riscv_new/compiler/riscv/nrvset.pas new file mode 100644 index 0000000000..e0a51771b6 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv/rgcpu.pas b/riscv_new/compiler/riscv/rgcpu.pas new file mode 100644 index 0000000000..3c7047e4db --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/aoptcpu.pas b/riscv_new/compiler/riscv32/aoptcpu.pas new file mode 100644 index 0000000000..eb45ee1b9d --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/aoptcpub.pas b/riscv_new/compiler/riscv32/aoptcpub.pas new file mode 100644 index 0000000000..eb60faa451 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/aoptcpuc.pas b/riscv_new/compiler/riscv32/aoptcpuc.pas new file mode 100644 index 0000000000..4b82e87f4a --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/aoptcpud.pas b/riscv_new/compiler/riscv32/aoptcpud.pas new file mode 100644 index 0000000000..2df7e2e49e --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/cgcpu.pas b/riscv_new/compiler/riscv32/cgcpu.pas new file mode 100644 index 0000000000..b1830b938b --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/cpubase.pas b/riscv_new/compiler/riscv32/cpubase.pas new file mode 100644 index 0000000000..feb63fc5b5 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/cpuinfo.pas b/riscv_new/compiler/riscv32/cpuinfo.pas new file mode 100644 index 0000000000..755da23976 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/cpunode.pas b/riscv_new/compiler/riscv32/cpunode.pas new file mode 100644 index 0000000000..08190a8a57 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/cpupara.pas b/riscv_new/compiler/riscv32/cpupara.pas new file mode 100644 index 0000000000..7c90ebd074 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/cpupi.pas b/riscv_new/compiler/riscv32/cpupi.pas new file mode 100644 index 0000000000..138d9ab915 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv32/cputarg.pas b/riscv_new/compiler/riscv32/cputarg.pas new file mode 100644 index 0000000000..0643083eee --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/hlcgcpu.pas b/riscv_new/compiler/riscv32/hlcgcpu.pas new file mode 100644 index 0000000000..e18851b3ae --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv32/itcpugas.pas b/riscv_new/compiler/riscv32/itcpugas.pas new file mode 100644 index 0000000000..190b7bfbb2 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/nrv32add.pas b/riscv_new/compiler/riscv32/nrv32add.pas new file mode 100644 index 0000000000..836663390d --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/nrv32cal.pas b/riscv_new/compiler/riscv32/nrv32cal.pas new file mode 100644 index 0000000000..4896c362c3 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/nrv32cnv.pas b/riscv_new/compiler/riscv32/nrv32cnv.pas new file mode 100644 index 0000000000..dd56a22d49 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv32/nrv32mat.pas b/riscv_new/compiler/riscv32/nrv32mat.pas new file mode 100644 index 0000000000..ee25d85273 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/rarv32.pas b/riscv_new/compiler/riscv32/rarv32.pas new file mode 100644 index 0000000000..8d7d3effad --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/rarv32gas.pas b/riscv_new/compiler/riscv32/rarv32gas.pas new file mode 100644 index 0000000000..b4ca7843c6 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv32/rrv32con.inc b/riscv_new/compiler/riscv32/rrv32con.inc new file mode 100644 index 0000000000..94c5f42533 --- /dev/null +++ b/riscv_new/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); diff --git a/riscv_new/compiler/riscv32/rrv32dwa.inc b/riscv_new/compiler/riscv32/rrv32dwa.inc new file mode 100644 index 0000000000..6755ebb4c5 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv32/rrv32nor.inc b/riscv_new/compiler/riscv32/rrv32nor.inc new file mode 100644 index 0000000000..a3c3b517a4 --- /dev/null +++ b/riscv_new/compiler/riscv32/rrv32nor.inc @@ -0,0 +1,2 @@ +{ don't edit, this file is generated from rv32reg.dat } +66 diff --git a/riscv_new/compiler/riscv32/rrv32num.inc b/riscv_new/compiler/riscv32/rrv32num.inc new file mode 100644 index 0000000000..f9553bf4fb --- /dev/null +++ b/riscv_new/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) diff --git a/riscv_new/compiler/riscv32/rrv32rni.inc b/riscv_new/compiler/riscv32/rrv32rni.inc new file mode 100644 index 0000000000..de9f6b796b --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv32/rrv32sri.inc b/riscv_new/compiler/riscv32/rrv32sri.inc new file mode 100644 index 0000000000..a39dc1faa3 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv32/rrv32sta.inc b/riscv_new/compiler/riscv32/rrv32sta.inc new file mode 100644 index 0000000000..6755ebb4c5 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv32/rrv32std.inc b/riscv_new/compiler/riscv32/rrv32std.inc new file mode 100644 index 0000000000..468a711616 --- /dev/null +++ b/riscv_new/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' diff --git a/riscv_new/compiler/riscv32/rrv32sup.inc b/riscv_new/compiler/riscv32/rrv32sup.inc new file mode 100644 index 0000000000..cb12862e9d --- /dev/null +++ b/riscv_new/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; diff --git a/riscv_new/compiler/riscv32/rv32reg.dat b/riscv_new/compiler/riscv32/rv32reg.dat new file mode 100644 index 0000000000..0be9f17f99 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv32/symcpu.pas b/riscv_new/compiler/riscv32/symcpu.pas new file mode 100644 index 0000000000..43005180e9 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/aoptcpu.pas b/riscv_new/compiler/riscv64/aoptcpu.pas new file mode 100644 index 0000000000..cebdc53420 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv64/aoptcpub.pas b/riscv_new/compiler/riscv64/aoptcpub.pas new file mode 100644 index 0000000000..da6587c061 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/aoptcpuc.pas b/riscv_new/compiler/riscv64/aoptcpuc.pas new file mode 100644 index 0000000000..e002fedb21 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/aoptcpud.pas b/riscv_new/compiler/riscv64/aoptcpud.pas new file mode 100644 index 0000000000..5e6e7fc308 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/cgcpu.pas b/riscv_new/compiler/riscv64/cgcpu.pas new file mode 100644 index 0000000000..88b4dd10ee --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv64/cpubase.pas b/riscv_new/compiler/riscv64/cpubase.pas new file mode 100644 index 0000000000..6bc19044de --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/cpuinfo.pas b/riscv_new/compiler/riscv64/cpuinfo.pas new file mode 100644 index 0000000000..0c3f2b1124 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/cpunode.pas b/riscv_new/compiler/riscv64/cpunode.pas new file mode 100644 index 0000000000..f9f680bf91 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/cpupara.pas b/riscv_new/compiler/riscv64/cpupara.pas new file mode 100644 index 0000000000..4c85ae9861 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/cpupi.pas b/riscv_new/compiler/riscv64/cpupi.pas new file mode 100644 index 0000000000..a0b3c129fb --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/cputarg.pas b/riscv_new/compiler/riscv64/cputarg.pas new file mode 100644 index 0000000000..6986b1f2b6 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv64/hlcgcpu.pas b/riscv_new/compiler/riscv64/hlcgcpu.pas new file mode 100644 index 0000000000..3c0f4968f7 --- /dev/null +++ b/riscv_new/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. diff --git a/riscv_new/compiler/riscv64/itcpugas.pas b/riscv_new/compiler/riscv64/itcpugas.pas new file mode 100644 index 0000000000..4fabace6e8 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/nrv64add.pas b/riscv_new/compiler/riscv64/nrv64add.pas new file mode 100644 index 0000000000..37356772ff --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/nrv64cal.pas b/riscv_new/compiler/riscv64/nrv64cal.pas new file mode 100644 index 0000000000..7781434673 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/nrv64cnv.pas b/riscv_new/compiler/riscv64/nrv64cnv.pas new file mode 100644 index 0000000000..531b6d49f1 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/nrv64ld.pas b/riscv_new/compiler/riscv64/nrv64ld.pas new file mode 100644 index 0000000000..c2a6963a5b --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/nrv64mat.pas b/riscv_new/compiler/riscv64/nrv64mat.pas new file mode 100644 index 0000000000..abcdfdb124 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/rarv.pas b/riscv_new/compiler/riscv64/rarv.pas new file mode 100644 index 0000000000..a735913b92 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/rarv64gas.pas b/riscv_new/compiler/riscv64/rarv64gas.pas new file mode 100644 index 0000000000..9cf15fe457 --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/riscv64/rrv32con.inc b/riscv_new/compiler/riscv64/rrv32con.inc new file mode 100644 index 0000000000..94c5f42533 --- /dev/null +++ b/riscv_new/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); diff --git a/riscv_new/compiler/riscv64/rrv32dwa.inc b/riscv_new/compiler/riscv64/rrv32dwa.inc new file mode 100644 index 0000000000..6755ebb4c5 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv64/rrv32nor.inc b/riscv_new/compiler/riscv64/rrv32nor.inc new file mode 100644 index 0000000000..a3c3b517a4 --- /dev/null +++ b/riscv_new/compiler/riscv64/rrv32nor.inc @@ -0,0 +1,2 @@ +{ don't edit, this file is generated from rv32reg.dat } +66 diff --git a/riscv_new/compiler/riscv64/rrv32num.inc b/riscv_new/compiler/riscv64/rrv32num.inc new file mode 100644 index 0000000000..f9553bf4fb --- /dev/null +++ b/riscv_new/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) diff --git a/riscv_new/compiler/riscv64/rrv32rni.inc b/riscv_new/compiler/riscv64/rrv32rni.inc new file mode 100644 index 0000000000..de9f6b796b --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv64/rrv32sri.inc b/riscv_new/compiler/riscv64/rrv32sri.inc new file mode 100644 index 0000000000..a39dc1faa3 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv64/rrv32sta.inc b/riscv_new/compiler/riscv64/rrv32sta.inc new file mode 100644 index 0000000000..6755ebb4c5 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv64/rrv32std.inc b/riscv_new/compiler/riscv64/rrv32std.inc new file mode 100644 index 0000000000..468a711616 --- /dev/null +++ b/riscv_new/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' diff --git a/riscv_new/compiler/riscv64/rrv32sup.inc b/riscv_new/compiler/riscv64/rrv32sup.inc new file mode 100644 index 0000000000..cb12862e9d --- /dev/null +++ b/riscv_new/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; diff --git a/riscv_new/compiler/riscv64/rv32reg.dat b/riscv_new/compiler/riscv64/rv32reg.dat new file mode 100644 index 0000000000..0be9f17f99 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/compiler/riscv64/symcpu.pas b/riscv_new/compiler/riscv64/symcpu.pas new file mode 100644 index 0000000000..e1b5f3b08e --- /dev/null +++ b/riscv_new/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. + diff --git a/riscv_new/compiler/systems.inc b/riscv_new/compiler/systems.inc index 9da234156e..997fb22199 100644 --- a/riscv_new/compiler/systems.inc +++ b/riscv_new/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 diff --git a/riscv_new/compiler/systems.pas b/riscv_new/compiler/systems.pas index b0201c7576..7366b8de1b 100644 --- a/riscv_new/compiler/systems.pas +++ b/riscv_new/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; diff --git a/riscv_new/compiler/systems/i_linux.pas b/riscv_new/compiler/systems/i_linux.pas index 701dca158f..5ccdb25e90 100644 --- a/riscv_new/compiler/systems/i_linux.pas +++ b/riscv_new/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. diff --git a/riscv_new/compiler/systems/t_linux.pas b/riscv_new/compiler/systems/t_linux.pas index 0a4af94074..013667b8a8 100644 --- a/riscv_new/compiler/systems/t_linux.pas +++ b/riscv_new/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. diff --git a/riscv_new/compiler/utils/fpc.pp b/riscv_new/compiler/utils/fpc.pp index e2152aaf69..b531da3f9a 100644 --- a/riscv_new/compiler/utils/fpc.pp +++ b/riscv_new/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 diff --git a/riscv_new/compiler/utils/ppuutils/ppudump.pp b/riscv_new/compiler/utils/ppuutils/ppudump.pp index 74fde5c6c2..e94c4df219 100644 --- a/riscv_new/compiler/utils/ppuutils/ppudump.pp +++ b/riscv_new/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 diff --git a/riscv_new/compiler/version.pas b/riscv_new/compiler/version.pas index f217547df9..d5ad996f9b 100644 --- a/riscv_new/compiler/version.pas +++ b/riscv_new/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; diff --git a/riscv_new/rtl/inc/system.inc b/riscv_new/rtl/inc/system.inc index 3aa5f656f0..3dea5fa444 100644 --- a/riscv_new/rtl/inc/system.inc +++ b/riscv_new/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} diff --git a/riscv_new/rtl/inc/systemh.inc b/riscv_new/rtl/inc/systemh.inc index 08df955d8b..4d9f991023 100644 --- a/riscv_new/rtl/inc/systemh.inc +++ b/riscv_new/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; diff --git a/riscv_new/rtl/linux/osdefs.inc b/riscv_new/rtl/linux/osdefs.inc index 67f7324a36..7e7a91e227 100644 --- a/riscv_new/rtl/linux/osdefs.inc +++ b/riscv_new/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} diff --git a/riscv_new/rtl/linux/riscv32/bsyscall.inc b/riscv_new/rtl/linux/riscv32/bsyscall.inc new file mode 100644 index 0000000000..c690ebeb2c --- /dev/null +++ b/riscv_new/rtl/linux/riscv32/bsyscall.inc @@ -0,0 +1 @@ +{ nothing } diff --git a/riscv_new/rtl/linux/riscv32/cprt0.as b/riscv_new/rtl/linux/riscv32/cprt0.as new file mode 100644 index 0000000000..5b9474e9c3 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/rtl/linux/riscv32/dllprt0.as b/riscv_new/rtl/linux/riscv32/dllprt0.as new file mode 100644 index 0000000000..a7b7ee585d --- /dev/null +++ b/riscv_new/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 + diff --git a/riscv_new/rtl/linux/riscv32/gprt0.as b/riscv_new/rtl/linux/riscv32/gprt0.as new file mode 100644 index 0000000000..d7d6337e55 --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/rtl/linux/riscv32/prt0.as b/riscv_new/rtl/linux/riscv32/prt0.as new file mode 100644 index 0000000000..18f568521f --- /dev/null +++ b/riscv_new/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 diff --git a/riscv_new/rtl/linux/riscv32/sighnd.inc b/riscv_new/rtl/linux/riscv32/sighnd.inc new file mode 100644 index 0000000000..011b63a960 --- /dev/null +++ b/riscv_new/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; diff --git a/riscv_new/rtl/linux/riscv32/sighndh.inc b/riscv_new/rtl/linux/riscv32/sighndh.inc new file mode 100644 index 0000000000..8fa6a35ebd --- /dev/null +++ b/riscv_new/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; diff --git a/riscv_new/rtl/linux/riscv32/stat.inc b/riscv_new/rtl/linux/riscv32/stat.inc new file mode 100644 index 0000000000..6d69441361 --- /dev/null +++ b/riscv_new/rtl/linux/riscv32/stat.inc @@ -0,0 +1,72 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Jonas Maebe, (c) 2005 Thomas Schatzl, + members of the Free Pascal development team. + + Contains the definition of the stat type for the PowerPC64 platform. + + 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. + + **********************************************************************} + +{ This structure was adapted from + + include/uapi/asm-generic/stat.h + + in Linux 4.0. Note that the stat record is the same for direct + syscalls as for when linking to libc. +} + +{$PACKRECORDS C} + stat = record + case integer of + 0 : ( + st_dev : cULong; + st_ino : cULong; + st_mode : cUInt; + st_nlink : cUInt; + st_uid : cUInt; + st_gid : cUInt; + st_rdev : cULong; + __pad1a : cULong; + st_size : cLong; + st_blksize : cInt; + __pad2a : cInt; + st_blocks : cLong; + st_atime : cLong; + st_atime_nsec : cULong; + st_mtime : cLong; + st_mtime_nsec : cULong; + st_ctime : cLong; + st_ctime_nsec : cULong; + __unused4a : cUInt; + __unused5a : cUInt; + ); + 1 : ( + dev : cULong deprecated; + ino : cULong deprecated; + mode : cUInt deprecated; + nlink : cUInt deprecated; + uid : cUInt deprecated; + gid : cUInt deprecated; + rdev : cULong deprecated; + __pad1b : cULong deprecated; + size : cLong deprecated; + blksize : cInt deprecated; + __pad2b : cInt deprecated; + blocks : cLong deprecated; + atime : cLong deprecated; + atime_nsec : cULong deprecated; + mtime : cLong deprecated; + mtime_nsec : cULong deprecated; + ctime : cLong deprecated; + ctime_nsec : cULong deprecated; + __unused4b : cUInt deprecated; + __unused5b : cUInt deprecated; + ); + end; diff --git a/riscv_new/rtl/linux/riscv32/syscall.inc b/riscv_new/rtl/linux/riscv32/syscall.inc new file mode 100644 index 0000000000..a7ecca5d8c --- /dev/null +++ b/riscv_new/rtl/linux/riscv32/syscall.inc @@ -0,0 +1,141 @@ +{ + This file is part of the Free Pascal run time library. + + Perform syscall with 0..6 arguments. + If syscall return value is negative, negate it, set errno, and return -1. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +} + +function FpSysCall(sysnr:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL0']; +asm + addi x17, sysnr, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL1']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL2']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL3']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL4']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + addi x13, x14, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4,param5:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL5']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + addi x13, x14, 0 + addi x14, x15, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4,param5,param6:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL6']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + addi x13, x14, 0 + addi x14, x15, 0 + addi x15, x16, 0 + scall + bge x10,x0,.Ldone + sw x1, -4(x2) + addi x2, x2, -4 + sub x10, x0, x10 + jal x1, seterrno + addi x2, x2, 4 + lw x1, -4(x2) + addi x10,x0, -1 +.Ldone: +end; diff --git a/riscv_new/rtl/linux/riscv32/syscallh.inc b/riscv_new/rtl/linux/riscv32/syscallh.inc new file mode 100644 index 0000000000..ea0768dd7f --- /dev/null +++ b/riscv_new/rtl/linux/riscv32/syscallh.inc @@ -0,0 +1,35 @@ +{ + Copyright (c) 2002 by Marco van de Voort + + Header for syscalls in system unit. + + 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + **************************************************************************** + +} + +Type + TSysResult = longint; + TSysParam = longint; + +function Do_SysCall(sysnr:TSysParam):TSysResult; external name 'FPC_SYSCALL0'; +function Do_SysCall(sysnr,param1:TSysParam):TSysResult; external name 'FPC_SYSCALL1'; +function Do_SysCall(sysnr,param1,param2:TSysParam):TSysResult; external name 'FPC_SYSCALL2'; +function Do_SysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; external name 'FPC_SYSCALL3'; +function Do_SysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; external name 'FPC_SYSCALL4'; +function Do_SysCall(sysnr,param1,param2,param3,param4,param5:TSysParam):TSysResult; external name 'FPC_SYSCALL5'; +function Do_SysCall(sysnr,param1,param2,param3,param4,param5,param6:TSysParam):TSysResult; external name 'FPC_SYSCALL6'; diff --git a/riscv_new/rtl/linux/riscv32/sysnr.inc b/riscv_new/rtl/linux/riscv32/sysnr.inc new file mode 100644 index 0000000000..4d654232bf --- /dev/null +++ b/riscv_new/rtl/linux/riscv32/sysnr.inc @@ -0,0 +1,413 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2003-2004 by Florian Klaempfl, + member of the Free Pascal development team. + + Syscall nrs for arm-linux + + 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. + + **********************************************************************} + + +{ +* This file contains the system call numbers. + Last update from 2.4.22 kernel sources according to the sources it contains already the 2.5 extensions +} + +Const +{$ifdef FPC_ABI_EABI} + syscall_nr_base = $0; +{$else FPC_ABI_EABI} + syscall_nr_base = $900000; +{$endif FPC_ABI_EABI} + + syscall_nr_exit = syscall_nr_base+ 1; + syscall_nr_fork = syscall_nr_base+ 2; + syscall_nr_read = syscall_nr_base+ 3; + syscall_nr_write = syscall_nr_base+ 4; + syscall_nr_open = syscall_nr_base+ 5; + syscall_nr_close = syscall_nr_base+ 6; + // not supported: syscall_nr_waitpid = syscall_nr_base+ 7; + syscall_nr_creat = syscall_nr_base+ 8; + syscall_nr_link = syscall_nr_base+ 9; + syscall_nr_unlink = syscall_nr_base+10; + syscall_nr_execve = syscall_nr_base+11; + syscall_nr_chdir = syscall_nr_base+12; +{$ifndef FPC_ABI_EABI} + syscall_nr_time = syscall_nr_base+13; +{$endif} + syscall_nr_mknod = syscall_nr_base+14; + syscall_nr_chmod = syscall_nr_base+15; + syscall_nr_lchown = syscall_nr_base+16; + syscall_nr_break = syscall_nr_base+17; + + syscall_nr_lseek = syscall_nr_base+19; + syscall_nr_getpid = syscall_nr_base+20; + syscall_nr_mount = syscall_nr_base+21; +{$ifndef FPC_ABI_EABI} + syscall_nr_umount = syscall_nr_base+22; +{$endif} + syscall_nr_setuid = syscall_nr_base+23; + syscall_nr_getuid = syscall_nr_base+24; +{$ifndef FPC_ABI_EABI} + syscall_nr_stime = syscall_nr_base+25; +{$endif} + syscall_nr_ptrace = syscall_nr_base+26; +{$ifndef FPC_ABI_EABI} + syscall_nr_alarm = syscall_nr_base+27; +{$endif} + + syscall_nr_pause = syscall_nr_base+29; +{$ifndef FPC_ABI_EABI} + syscall_nr_utime = syscall_nr_base+30; +{$endif} + syscall_nr_stty = syscall_nr_base+31; + syscall_nr_gtty = syscall_nr_base+32; + syscall_nr_access = syscall_nr_base+33; + syscall_nr_nice = syscall_nr_base+34; + syscall_nr_ftime = syscall_nr_base+35; + syscall_nr_sync = syscall_nr_base+36; + syscall_nr_kill = syscall_nr_base+37; + syscall_nr_rename = syscall_nr_base+38; + syscall_nr_mkdir = syscall_nr_base+39; + syscall_nr_rmdir = syscall_nr_base+40; + syscall_nr_dup = syscall_nr_base+41; + syscall_nr_pipe = syscall_nr_base+42; + syscall_nr_times = syscall_nr_base+43; + syscall_nr_prof = syscall_nr_base+44; + syscall_nr_brk = syscall_nr_base+45; + syscall_nr_setgid = syscall_nr_base+46; + syscall_nr_getgid = syscall_nr_base+47; + syscall_nr_signal = syscall_nr_base+48; + syscall_nr_geteuid = syscall_nr_base+49; + syscall_nr_getegid = syscall_nr_base+50; + syscall_nr_acct = syscall_nr_base+51; + syscall_nr_umount2 = syscall_nr_base+52; + syscall_nr_lock = syscall_nr_base+53; + syscall_nr_ioctl = syscall_nr_base+54; + syscall_nr_fcntl = syscall_nr_base+55; + syscall_nr_mpx = syscall_nr_base+56; + syscall_nr_setpgid = syscall_nr_base+57; + syscall_nr_ulimit = syscall_nr_base+58; + + syscall_nr_umask = syscall_nr_base+60; + syscall_nr_chroot = syscall_nr_base+61; + syscall_nr_ustat = syscall_nr_base+62; + syscall_nr_dup2 = syscall_nr_base+63; + syscall_nr_getppid = syscall_nr_base+64; + syscall_nr_getpgrp = syscall_nr_base+65; + syscall_nr_setsid = syscall_nr_base+66; + syscall_nr_sigaction = syscall_nr_base+67; + syscall_nr_sgetmask = syscall_nr_base+68; + syscall_nr_ssetmask = syscall_nr_base+69; + syscall_nr_setreuid = syscall_nr_base+70; + syscall_nr_setregid = syscall_nr_base+71; + syscall_nr_sigsuspend = syscall_nr_base+72; + syscall_nr_sigpending = syscall_nr_base+73; + syscall_nr_sethostname = syscall_nr_base+74; + syscall_nr_setrlimit = syscall_nr_base+75; +{$ifndef FPC_ABI_EABI} + syscall_nr_getrlimit = syscall_nr_base+76; +{$endif} + syscall_nr_getrusage = syscall_nr_base+77; + syscall_nr_gettimeofday = syscall_nr_base+78; + syscall_nr_settimeofday = syscall_nr_base+79; + syscall_nr_getgroups = syscall_nr_base+80; + syscall_nr_setgroups = syscall_nr_base+81; +{$ifndef FPC_ABI_EABI} + syscall_nr_select = syscall_nr_base+82; +{$endif} + syscall_nr_symlink = syscall_nr_base+83; + + syscall_nr_readlink = syscall_nr_base+85; + syscall_nr_uselib = syscall_nr_base+86; + syscall_nr_swapon = syscall_nr_base+87; + syscall_nr_reboot = syscall_nr_base+88; +{$ifndef FPC_ABI_EABI} + syscall_nr_readdir = syscall_nr_base+89; + syscall_nr_mmap = syscall_nr_base+90; +{$endif} + syscall_nr_munmap = syscall_nr_base+91; + syscall_nr_truncate = syscall_nr_base+92; + syscall_nr_ftruncate = syscall_nr_base+93; + syscall_nr_fchmod = syscall_nr_base+94; + syscall_nr_fchown = syscall_nr_base+95; + syscall_nr_getpriority = syscall_nr_base+96; + syscall_nr_setpriority = syscall_nr_base+97; + syscall_nr_profil = syscall_nr_base+98; + syscall_nr_statfs = syscall_nr_base+99; + syscall_nr_fstatfs = syscall_nr_base+100; + syscall_nr_ioperm = syscall_nr_base+101; +{$ifndef FPC_ABI_EABI} + syscall_nr_socketcall = syscall_nr_base+102; +{$endif} + syscall_nr_syslog = syscall_nr_base+103; + syscall_nr_setitimer = syscall_nr_base+104; + syscall_nr_getitimer = syscall_nr_base+105; + syscall_nr_stat = syscall_nr_base+106; + syscall_nr_lstat = syscall_nr_base+107; + syscall_nr_fstat = syscall_nr_base+108; + syscall_nr_vhangup = syscall_nr_base+111; + syscall_nr_idle = syscall_nr_base+112; +{$ifndef FPC_ABI_EABI} + syscall_nr_syscall = syscall_nr_base+113; +{$endif} + syscall_nr_wait4 = syscall_nr_base+114; + syscall_nr_swapoff = syscall_nr_base+115; + syscall_nr_sysinfo = syscall_nr_base+116; +{$ifndef FPC_ABI_EABI} + syscall_nr_ipc = syscall_nr_base+117; +{$endif} + syscall_nr_fsync = syscall_nr_base+118; + syscall_nr_sigreturn = syscall_nr_base+119; + syscall_nr_clone = syscall_nr_base+120; + syscall_nr_setdomainname = syscall_nr_base+121; + syscall_nr_uname = syscall_nr_base+122; + syscall_nr_modify_ldt = syscall_nr_base+123; + syscall_nr_adjtimex = syscall_nr_base+124; + syscall_nr_mprotect = syscall_nr_base+125; + syscall_nr_sigprocmask = syscall_nr_base+126; + syscall_nr_create_module = syscall_nr_base+127; + syscall_nr_init_module = syscall_nr_base+128; + syscall_nr_delete_module = syscall_nr_base+129; + syscall_nr_get_kernel_syms = syscall_nr_base+130; + syscall_nr_quotactl = syscall_nr_base+131; + syscall_nr_getpgid = syscall_nr_base+132; + syscall_nr_fchdir = syscall_nr_base+133; + syscall_nr_bdflush = syscall_nr_base+134; + syscall_nr_sysfs = syscall_nr_base+135; + syscall_nr_personality = syscall_nr_base+136; + syscall_nr_afs_syscall = syscall_nr_base+137; + syscall_nr_setfsuid = syscall_nr_base+138; + syscall_nr_setfsgid = syscall_nr_base+139; + syscall_nr__llseek = syscall_nr_base+140; + syscall_nr_getdents = syscall_nr_base+141; + syscall_nr__newselect = syscall_nr_base+142; + syscall_nr_flock = syscall_nr_base+143; + syscall_nr_msync = syscall_nr_base+144; + syscall_nr_readv = syscall_nr_base+145; + syscall_nr_writev = syscall_nr_base+146; + syscall_nr_getsid = syscall_nr_base+147; + syscall_nr_fdatasync = syscall_nr_base+148; + syscall_nr__sysctl = syscall_nr_base+149; + syscall_nr_mlock = syscall_nr_base+150; + syscall_nr_munlock = syscall_nr_base+151; + syscall_nr_mlockall = syscall_nr_base+152; + syscall_nr_munlockall = syscall_nr_base+153; + syscall_nr_sched_setparam = syscall_nr_base+154; + syscall_nr_sched_getparam = syscall_nr_base+155; + syscall_nr_sched_setscheduler = syscall_nr_base+156; + syscall_nr_sched_getscheduler = syscall_nr_base+157; + syscall_nr_sched_yield = syscall_nr_base+158; + syscall_nr_sched_get_priority_max = syscall_nr_base+159; + syscall_nr_sched_get_priority_min = syscall_nr_base+160; + syscall_nr_sched_rr_get_interval = syscall_nr_base+161; + syscall_nr_nanosleep = syscall_nr_base+162; + syscall_nr_mremap = syscall_nr_base+163; + syscall_nr_setresuid = syscall_nr_base+164; + syscall_nr_getresuid = syscall_nr_base+165; + syscall_nr_vm86 = syscall_nr_base+166; + syscall_nr_query_module = syscall_nr_base+167; + syscall_nr_poll = syscall_nr_base+168; + syscall_nr_nfsservctl = syscall_nr_base+169; + syscall_nr_setresgid = syscall_nr_base+170; + syscall_nr_getresgid = syscall_nr_base+171; + syscall_nr_prctl = syscall_nr_base+172; + syscall_nr_rt_sigreturn = syscall_nr_base+173; + syscall_nr_rt_sigaction = syscall_nr_base+174; + syscall_nr_rt_sigprocmask = syscall_nr_base+175; + syscall_nr_rt_sigpending = syscall_nr_base+176; + syscall_nr_rt_sigtimedwait = syscall_nr_base+177; + syscall_nr_rt_sigqueueinfo = syscall_nr_base+178; + syscall_nr_rt_sigsuspend = syscall_nr_base+179; + syscall_nr_pread = syscall_nr_base+180; + syscall_nr_pwrite = syscall_nr_base+181; + syscall_nr_chown = syscall_nr_base+182; + syscall_nr_getcwd = syscall_nr_base+183; + syscall_nr_capget = syscall_nr_base+184; + syscall_nr_capset = syscall_nr_base+185; + syscall_nr_sigaltstack = syscall_nr_base+186; + syscall_nr_sendfile = syscall_nr_base+187; + syscall_nr_vfork = syscall_nr_base+190; + syscall_nr_ugetrlimit = syscall_nr_base+191; + syscall_nr_mmap2 = syscall_nr_base+192; + syscall_nr_truncate64 = syscall_nr_base+193; + syscall_nr_ftruncate64 = syscall_nr_base+194; + syscall_nr_stat64 = syscall_nr_base+195; + syscall_nr_lstat64 = syscall_nr_base+196; + syscall_nr_fstat64 = syscall_nr_base+197; + syscall_nr_lchown32 = syscall_nr_base+198; + syscall_nr_getuid32 = syscall_nr_base+199; + syscall_nr_getgid32 = syscall_nr_base+200; + syscall_nr_geteuid32 = syscall_nr_base+201; + syscall_nr_getegid32 = syscall_nr_base+202; + syscall_nr_setreuid32 = syscall_nr_base+203; + syscall_nr_setregid32 = syscall_nr_base+204; + syscall_nr_getgroups32 = syscall_nr_base+205; + syscall_nr_setgroups32 = syscall_nr_base+206; + syscall_nr_fchown32 = syscall_nr_base+207; + syscall_nr_setresuid32 = syscall_nr_base+208; + syscall_nr_getresuid32 = syscall_nr_base+209; + syscall_nr_setresgid32 = syscall_nr_base+210; + syscall_nr_getresgid32 = syscall_nr_base+211; + syscall_nr_chown32 = syscall_nr_base+212; + syscall_nr_setuid32 = syscall_nr_base+213; + syscall_nr_setgid32 = syscall_nr_base+214; + syscall_nr_setfsuid32 = syscall_nr_base+215; + syscall_nr_setfsgid32 = syscall_nr_base+216; + syscall_nr_getdents64 = syscall_nr_base+217; + syscall_nr_pivot_root = syscall_nr_base+218; + syscall_nr_mincore = syscall_nr_base+219; + syscall_nr_madvise = syscall_nr_base+220; + syscall_nr_fcntl64 = syscall_nr_base+221; + syscall_nr_security = syscall_nr_base+223; + syscall_nr_gettid = syscall_nr_base+224; + syscall_nr_readahead = syscall_nr_base+225; + syscall_nr_setxattr = syscall_nr_base+226; + syscall_nr_lsetxattr = syscall_nr_base+227; + syscall_nr_fsetxattr = syscall_nr_base+228; + syscall_nr_getxattr = syscall_nr_base+229; + syscall_nr_lgetxattr = syscall_nr_base+230; + syscall_nr_fgetxattr = syscall_nr_base+231; + syscall_nr_listxattr = syscall_nr_base+232; + syscall_nr_llistxattr = syscall_nr_base+233; + syscall_nr_flistxattr = syscall_nr_base+234; + syscall_nr_removexattr = syscall_nr_base+235; + syscall_nr_lremovexattr = syscall_nr_base+236; + syscall_nr_fremovexattr = syscall_nr_base+237; + syscall_nr_tkill = syscall_nr_base+238; + syscall_nr_sendfile64 = syscall_nr_base+239; + syscall_nr_futex = syscall_nr_base+240; + syscall_nr_sched_setaffinity = syscall_nr_base+241; + syscall_nr_sched_getaffinity = syscall_nr_base+242; + syscall_nr_io_setup = syscall_nr_base+243; + syscall_nr_io_destroy = syscall_nr_base+244; + syscall_nr_io_getevents = syscall_nr_base+245; + syscall_nr_io_submit = syscall_nr_base+246; + syscall_nr_io_cancel = syscall_nr_base+247; + syscall_nr_exit_group = syscall_nr_base+248; + syscall_nr_lookup_dcookie = syscall_nr_base+249; + syscall_nr_epoll_create = syscall_nr_base+250; + syscall_nr_epoll_ctl = syscall_nr_base+251; + syscall_nr_epoll_wait = syscall_nr_base+252; + syscall_nr_remap_file_pages = syscall_nr_base+253; + syscall_nr_set_tid_address = syscall_nr_base+256; + { 254 for set_thread_area } + { 255 for get_thread_area } + syscall_nr_timer_create = syscall_nr_base+257; + syscall_nr_timer_settime = syscall_nr_base+258; + syscall_nr_timer_gettime = syscall_nr_base+259; + syscall_nr_timer_getoverrun = syscall_nr_base+260; + syscall_nr_timer_delete = syscall_nr_base+261; + syscall_nr_clock_settime = syscall_nr_base+262; + syscall_nr_clock_gettime = syscall_nr_base+263; + syscall_nr_clock_getres = syscall_nr_base+264; + syscall_nr_clock_nanosleep = syscall_nr_base+265; + syscall_nr_statfs64 = syscall_nr_base+266; + syscall_nr_fstatfs64 = syscall_nr_base+267; + syscall_nr_tgkill = syscall_nr_base+268; + syscall_nr_utimes = syscall_nr_base+269; + syscall_nr_fadvise64_64 = syscall_nr_base+270; + syscall_nr_pciconfig_iobase = syscall_nr_base+271; + syscall_nr_pciconfig_read = syscall_nr_base+272; + syscall_nr_pciconfig_write = syscall_nr_base+273; + syscall_nr_mq_open = syscall_nr_base+274; + syscall_nr_mq_unlink = syscall_nr_base+275; + syscall_nr_mq_timedsend = syscall_nr_base+276; + syscall_nr_mq_timedreceive = syscall_nr_base+277; + syscall_nr_mq_notify = syscall_nr_base+278; + syscall_nr_mq_getsetattr = syscall_nr_base+279; + syscall_nr_waitid = syscall_nr_base+280; + syscall_nr_socket = syscall_nr_base+281; + syscall_nr_bind = syscall_nr_base+282; + syscall_nr_connect = syscall_nr_base+283; + syscall_nr_listen = syscall_nr_base+284; + syscall_nr_accept = syscall_nr_base+285; + syscall_nr_getsockname = syscall_nr_base+286; + syscall_nr_getpeername = syscall_nr_base+287; + syscall_nr_socketpair = syscall_nr_base+288; + syscall_nr_send = syscall_nr_base+289; + syscall_nr_sendto = syscall_nr_base+290; + syscall_nr_recv = syscall_nr_base+291; + syscall_nr_recvfrom = syscall_nr_base+292; + syscall_nr_shutdown = syscall_nr_base+293; + syscall_nr_setsockopt = syscall_nr_base+294; + syscall_nr_getsockopt = syscall_nr_base+295; + syscall_nr_sendmsg = syscall_nr_base+296; + syscall_nr_recvmsg = syscall_nr_base+297; + syscall_nr_semop = syscall_nr_base+298; + syscall_nr_semget = syscall_nr_base+299; + syscall_nr_semctl = syscall_nr_base+300; + syscall_nr_msgsnd = syscall_nr_base+301; + syscall_nr_msgrcv = syscall_nr_base+302; + syscall_nr_msgget = syscall_nr_base+303; + syscall_nr_msgctl = syscall_nr_base+304; + syscall_nr_shmat = syscall_nr_base+305; + syscall_nr_shmdt = syscall_nr_base+306; + syscall_nr_shmget = syscall_nr_base+307; + syscall_nr_shmctl = syscall_nr_base+308; + syscall_nr_add_key = syscall_nr_base+309; + syscall_nr_request_key = syscall_nr_base+310; + syscall_nr_keyctl = syscall_nr_base+311; + syscall_nr_semtimedop = syscall_nr_base+312; + syscall_nr_vserver = syscall_nr_base+313; + syscall_nr_ioprio_set = syscall_nr_base+314; + syscall_nr_ioprio_get = syscall_nr_base+315; + syscall_nr_inotify_init = syscall_nr_base+316; + syscall_nr_inotify_add_watch = syscall_nr_base+317; + syscall_nr_inotify_rm_watch = syscall_nr_base+318; + syscall_nr_mbind = syscall_nr_base+319; + syscall_nr_get_mempolicy = syscall_nr_base+320; + syscall_nr_set_mempolicy = syscall_nr_base+321; + syscall_nr_openat = syscall_nr_base+322; + syscall_nr_mkdirat = syscall_nr_base+323; + syscall_nr_mknodat = syscall_nr_base+324; + syscall_nr_fchownat = syscall_nr_base+325; + syscall_nr_futimesat = syscall_nr_base+326; + syscall_nr_fstatat64 = syscall_nr_base+327; + syscall_nr_unlinkat = syscall_nr_base+328; + syscall_nr_renameat = syscall_nr_base+329; + syscall_nr_linkat = syscall_nr_base+330; + syscall_nr_symlinkat = syscall_nr_base+331; + syscall_nr_readlinkat = syscall_nr_base+332; + syscall_nr_fchmodat = syscall_nr_base+333; + syscall_nr_faccessat = syscall_nr_base+334; + {* 335 for pselect6 *} + {* 336 for ppoll *} + syscall_nr_unshare = syscall_nr_base+337; + syscall_nr_set_robust_list = syscall_nr_base+338; + syscall_nr_get_robust_list = syscall_nr_base+339; + syscall_nr_splice = syscall_nr_base+340; + syscall_nr_arm_sync_file_range = syscall_nr_base+341; + syscall_nr_sync_file_range2 = syscall_nr_arm_sync_file_range; + syscall_nr_tee = syscall_nr_base+342; + syscall_nr_vmsplice = syscall_nr_base+343; + syscall_nr_move_pages = syscall_nr_base+344; + syscall_nr_getcpu = syscall_nr_base+345; + {* 346 for epoll_pwait *} + syscall_nr_kexec_load = syscall_nr_base+347; + syscall_nr_utimensat = syscall_nr_base+348; + syscall_nr_signalfd = syscall_nr_base+349; + syscall_nr_timerfd_create = syscall_nr_base+350; + syscall_nr_eventfd = syscall_nr_base+351; + syscall_nr_fallocate = syscall_nr_base+352; + syscall_nr_timerfd_settime = syscall_nr_base+353; + syscall_nr_timerfd_gettime = syscall_nr_base+354; + syscall_nr_signalfd4 = syscall_nr_base+355; + syscall_nr_eventfd2 = syscall_nr_base+356; + syscall_nr_epoll_create1 = syscall_nr_base+357; + syscall_nr_dup3 = syscall_nr_base+358; + syscall_nr_pipe2 = syscall_nr_base+359; + syscall_nr_inotify_init1 = syscall_nr_base+360; + syscall_nr_preadv = syscall_nr_base+361; + syscall_nr_pwritev = syscall_nr_base+362; + syscall_nr_rt_tgsigqueueinfo = syscall_nr_base+363; + syscall_nr_perf_event_open = syscall_nr_base+364; + syscall_nr_recvmmsg = syscall_nr_base+365; + diff --git a/riscv_new/rtl/linux/riscv64/bsyscall.inc b/riscv_new/rtl/linux/riscv64/bsyscall.inc new file mode 100644 index 0000000000..c690ebeb2c --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/bsyscall.inc @@ -0,0 +1 @@ +{ nothing } diff --git a/riscv_new/rtl/linux/riscv64/cprt0.as b/riscv_new/rtl/linux/riscv64/cprt0.as new file mode 100644 index 0000000000..5b9474e9c3 --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/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 diff --git a/riscv_new/rtl/linux/riscv64/dllprt0.as b/riscv_new/rtl/linux/riscv64/dllprt0.as new file mode 100644 index 0000000000..a7b7ee585d --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/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 + diff --git a/riscv_new/rtl/linux/riscv64/gprt0.as b/riscv_new/rtl/linux/riscv64/gprt0.as new file mode 100644 index 0000000000..592c9c9b96 --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/gprt0.as @@ -0,0 +1,162 @@ +/* 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. */ + addi x8, x0, 0 + ld a2, (sp) + addi sp, sp, 4 + + /* Pop argc off the stack and save a pointer to argv */ + la x5, operatingsystem_parameter_argc + la x6,operatingsystem_parameter_argv + sd a2, (x5) + + /* calc envp */ + addi a4,a2,1 + slli a4,a4,3 + add a4,sp,a4 + la x5, operatingsystem_parameter_envp + + sd sp,(a3) + sd a4,(x5) + + /* Save initial stackpointer */ + la x5,__stkptr + sd sp, (x5) + + /* Initialize gmon */ + mov r2,#1 + ldr r1,=_etext + ldr r0,=_start + bl __monstartup + ldr r0,=_mcleanup + bl atexit + + /* argc already loaded to a2*/ + ldr ip, =operatingsystem_parameter_argc + ldr a2,[ip] + + /* Fetch address of fini */ + ldr ip, =_fini + + /* 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 + + .globl _haltproc_eabi + .type _haltproc_eabi,#function +_haltproc_eabi: + bl exit /* libc exit */ + + ldr r0,=operatingsystem_result + ldrb r0,[r0] + mov r7,#248 + swi 0x0 + b _haltproc_eabi + + /* 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 diff --git a/riscv_new/rtl/linux/riscv64/prt0.as b/riscv_new/rtl/linux/riscv64/prt0.as new file mode 100644 index 0000000000..d489b5dcad --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/prt0.as @@ -0,0 +1,83 @@ +/* + 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: +1: + auipc x5,%pcrel_hi(__dl_fini) + sd x10, %pcrel_lo(1b)(x5) + jal x0, _start + + .globl _start + .type _start, function +_start: +1: + auipc gp, %pcrel_hi(__bss_start+0x800) + addi gp, gp, %pcrel_lo(1b) + + /* Get argc, argv, envp */ + ld 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 */ +1:auipc x8,%pcrel_hi(operatingsystem_parameter_argc) + sd x5,%pcrel_lo(1b)(x8) +1:auipc x8,%pcrel_hi(operatingsystem_parameter_argv) + sd x6,%pcrel_lo(1b)(x8) +1:auipc x8,%pcrel_hi(operatingsystem_parameter_envp) + sd x7,%pcrel_lo(1b)(x8) +1:auipc x5,%pcrel_hi(__stkptr) + addi x6, x2, 0 + sd x6,%pcrel_lo(1b)(x5) + + /* Initialise FP to zero */ + addi x8,x0,0 + + /* Call main */ + jal x1, PASCALMAIN + + .globl _haltproc + .type _haltproc,function +_haltproc: +1:auipc x10,%pcrel_hi(__dl_fini) + ld x10,%pcrel_lo(1b)(x10) + beq x10,x0,.Lexit + jalr x1,x10 +.Lexit: +1:auipc x10,%pcrel_hi(operatingsystem_result) + ld x10,%pcrel_lo(1b)(x10) + addi x17, x0, 94 + ecall + jal x0, _haltproc + + /* Define a symbol for the first piece of initialized data. */ + .data + .align 4 + .globl __data_start +__data_start: + .quad 0 + .weak data_start + data_start = __data_start + + .bss + .align 4 + + .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 diff --git a/riscv_new/rtl/linux/riscv64/sighnd.inc b/riscv_new/rtl/linux/riscv64/sighnd.inc new file mode 100644 index 0000000000..011b63a960 --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/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; diff --git a/riscv_new/rtl/linux/riscv64/sighndh.inc b/riscv_new/rtl/linux/riscv64/sighndh.inc new file mode 100644 index 0000000000..8fa6a35ebd --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/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; diff --git a/riscv_new/rtl/linux/riscv64/stat.inc b/riscv_new/rtl/linux/riscv64/stat.inc new file mode 100644 index 0000000000..6d69441361 --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/stat.inc @@ -0,0 +1,72 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Jonas Maebe, (c) 2005 Thomas Schatzl, + members of the Free Pascal development team. + + Contains the definition of the stat type for the PowerPC64 platform. + + 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. + + **********************************************************************} + +{ This structure was adapted from + + include/uapi/asm-generic/stat.h + + in Linux 4.0. Note that the stat record is the same for direct + syscalls as for when linking to libc. +} + +{$PACKRECORDS C} + stat = record + case integer of + 0 : ( + st_dev : cULong; + st_ino : cULong; + st_mode : cUInt; + st_nlink : cUInt; + st_uid : cUInt; + st_gid : cUInt; + st_rdev : cULong; + __pad1a : cULong; + st_size : cLong; + st_blksize : cInt; + __pad2a : cInt; + st_blocks : cLong; + st_atime : cLong; + st_atime_nsec : cULong; + st_mtime : cLong; + st_mtime_nsec : cULong; + st_ctime : cLong; + st_ctime_nsec : cULong; + __unused4a : cUInt; + __unused5a : cUInt; + ); + 1 : ( + dev : cULong deprecated; + ino : cULong deprecated; + mode : cUInt deprecated; + nlink : cUInt deprecated; + uid : cUInt deprecated; + gid : cUInt deprecated; + rdev : cULong deprecated; + __pad1b : cULong deprecated; + size : cLong deprecated; + blksize : cInt deprecated; + __pad2b : cInt deprecated; + blocks : cLong deprecated; + atime : cLong deprecated; + atime_nsec : cULong deprecated; + mtime : cLong deprecated; + mtime_nsec : cULong deprecated; + ctime : cLong deprecated; + ctime_nsec : cULong deprecated; + __unused4b : cUInt deprecated; + __unused5b : cUInt deprecated; + ); + end; diff --git a/riscv_new/rtl/linux/riscv64/syscall.inc b/riscv_new/rtl/linux/riscv64/syscall.inc new file mode 100644 index 0000000000..6abf3ac807 --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/syscall.inc @@ -0,0 +1,155 @@ +{ + This file is part of the Free Pascal run time library. + + Perform syscall with 0..6 arguments. + If syscall return value is negative, negate it, set errno, and return -1. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +} + +function FpSysCall(sysnr:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL0']; +asm + addi x17, sysnr, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL1']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL2']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL3']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL4']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + addi x13, x14, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4,param5:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL5']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + addi x13, x14, 0 + addi x14, x15, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4,param5,param6:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL6']; +asm + addi x17, sysnr, 0 + addi x10, x11, 0 + addi x11, x12, 0 + addi x12, x13, 0 + addi x13, x14, 0 + addi x14, x15, 0 + addi x15, x16, 0 + ecall + bge x10,x0,.Ldone + sd x1, -8(x2) + addi x2, x2, -8 + sub x10, x0, x10 +.Ll1: + auipc x1, %pcrel_hi(seterrno) + jalr x1, x1, %pcrel_lo(.Ll1) + addi x2, x2, 8 + ld x1, -8(x2) + addi x10,x0, -1 +.Ldone: +end; diff --git a/riscv_new/rtl/linux/riscv64/syscallh.inc b/riscv_new/rtl/linux/riscv64/syscallh.inc new file mode 100644 index 0000000000..6961a190ca --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/syscallh.inc @@ -0,0 +1,35 @@ +{ + Copyright (c) 2002 by Marco van de Voort + + Header for syscalls in system unit. + + 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + **************************************************************************** + +} + +Type + TSysResult = Int64; + TSysParam = Int64; + +function Do_SysCall(sysnr:TSysParam):TSysResult; external name 'FPC_SYSCALL0'; +function Do_SysCall(sysnr,param1:TSysParam):TSysResult; external name 'FPC_SYSCALL1'; +function Do_SysCall(sysnr,param1,param2:TSysParam):TSysResult; external name 'FPC_SYSCALL2'; +function Do_SysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; external name 'FPC_SYSCALL3'; +function Do_SysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; external name 'FPC_SYSCALL4'; +function Do_SysCall(sysnr,param1,param2,param3,param4,param5:TSysParam):TSysResult; external name 'FPC_SYSCALL5'; +function Do_SysCall(sysnr,param1,param2,param3,param4,param5,param6:TSysParam):TSysResult; external name 'FPC_SYSCALL6'; diff --git a/riscv_new/rtl/linux/riscv64/sysnr.inc b/riscv_new/rtl/linux/riscv64/sysnr.inc new file mode 100644 index 0000000000..3763caa818 --- /dev/null +++ b/riscv_new/rtl/linux/riscv64/sysnr.inc @@ -0,0 +1 @@ +{$i ../sysnr-gen.inc} diff --git a/riscv_new/rtl/linux/system.pp b/riscv_new/rtl/linux/system.pp index 332a7fb54b..398bf6471d 100644 --- a/riscv_new/rtl/linux/system.pp +++ b/riscv_new/rtl/linux/system.pp @@ -45,13 +45,13 @@ const function get_cmdline:Pchar; deprecated 'use paramstr' ; property cmdline:Pchar read get_cmdline; -{$if defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} +{$if defined(CPURISCV32) or defined(CPURISCV64) or defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} {$define fpc_softfpu_interface} {$i softfpu.pp} {$undef fpc_softfpu_interface} -{$endif defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} +{$endif defined(CPURISCV32) or defined(CPURISCV64) or defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} {$ifdef android} {$I sysandroidh.inc} @@ -73,7 +73,7 @@ const procedure OsSetupEntryInformation(constref info: TEntryInformation); forward; {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION} -{$if defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} +{$if defined(CPURISCV32) or defined(CPURISCV64) or defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} {$define fpc_softfpu_implementation} {$if defined(CPUM68K)} @@ -95,7 +95,7 @@ procedure OsSetupEntryInformation(constref info: TEntryInformation); forward; {$define FPC_SYSTEM_HAS_extractFloat32Exp} {$define FPC_SYSTEM_HAS_extractFloat32Sign} -{$endif defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} +{$endif defined(CPURISCV32) or defined(CPURISCV64) or defined(CPUARM) or defined(CPUM68K) or (defined(CPUSPARC) and defined(VER2_6))} {$I system.inc} diff --git a/riscv_new/rtl/linux/termios.inc b/riscv_new/rtl/linux/termios.inc index 8bc408362e..0e0d5abbc4 100644 --- a/riscv_new/rtl/linux/termios.inc +++ b/riscv_new/rtl/linux/termios.inc @@ -556,6 +556,536 @@ Const {$endif cpupowerpc} +{$ifdef cpuriscv32} + +{ from Linux 4.0, include/uapi/asm-generic/ioctls.h } + + { For Terminal handling } + TCGETS = $5401; + TCSETS = $5402; + TCSETSW = $5403; + TCSETSF = $5404; + TCGETA = $5405; + TCSETA = $5406; + TCSETAW = $5407; + TCSETAF = $5408; + TCSBRK = $5409; + TCXONC = $540A; + TCFLSH = $540B; + TIOCEXCL = $540C; + TIOCNXCL = $540D; + TIOCSCTTY = $540E; + TIOCGPGRP = $540F; + TIOCSPGRP = $5410; + TIOCOUTQ = $5411; + TIOCSTI = $5412; + TIOCGWINSZ = $5413; + TIOCSWINSZ = $5414; + TIOCMGET = $5415; + TIOCMBIS = $5416; + TIOCMBIC = $5417; + TIOCMSET = $5418; + TIOCGSOFTCAR = $5419; + TIOCSSOFTCAR = $541A; + FIONREAD = $541B; + TIOCINQ = FIONREAD; + TIOCLINUX = $541C; + TIOCCONS = $541D; + TIOCGSERIAL = $541E; + TIOCSSERIAL = $541F; + TIOCPKT = $5420; + FIONBIO = $5421; + TIOCNOTTY = $5422; + TIOCSETD = $5423; + TIOCGETD = $5424; + TCSBRKP = $5425; + + TIOCSBRK = $5427; + TIOCCBRK = $5428; + TIOCGSID = $5429; + + TIOCGRS485 = $542E; + TIOCSRS485 = $542F; + + TCGETX = $5432; + TCSETX = $5433; + TCSETXF = $5434; + TCSETXW = $5435; + TIOCVHANGUP = $5437; + + FIONCLEX = $5450; + FIOCLEX = $5451; + FIOASYNC = $5452; + TIOCSERCONFIG = $5453; + TIOCSERGWILD = $5454; + TIOCSERSWILD = $5455; + TIOCGLCKTRMIOS = $5456; + TIOCSLCKTRMIOS = $5457; + TIOCSERGSTRUCT = $5458; + TIOCSERGETLSR = $5459; + TIOCSERGETMULTI = $545A; + TIOCSERSETMULTI = $545B; + TIOCMIWAIT = $545C; + TIOCGICOUNT = $545D; + + FIOQSIZE = $5460; + + TIOCPKT_DATA = 0; + TIOCPKT_FLUSHREAD = 1; + TIOCPKT_FLUSHWRITE = 2; + TIOCPKT_STOP = 4; + TIOCPKT_START = 8; + TIOCPKT_NOSTOP = 16; + TIOCPKT_DOSTOP = 32; + TIOCPKT_IOCTL = 64; + + TIOCSER_TEMT = $01; + +{ from Linux 4.0, include/uapi/asm-generic/termbits.h } + + { c_cc characters } + VINTR = 0; + VQUIT = 1; + VERASE = 2; + VKILL = 3; + VEOF = 4; + VTIME = 5; + VMIN = 6; + VSWTC = 7; + VSTART = 8; + VSTOP = 9; + VSUSP = 10; + VEOL = 11; + VREPRINT = 12; + VDISCARD = 13; + VWERASE = 14; + VLNEXT = 15; + VEOL2 = 16; + + { c_iflag bits } + IGNBRK = &0000001; + BRKINT = &0000002; + IGNPAR = &0000004; + PARMRK = &0000010; + INPCK = &0000020; + ISTRIP = &0000040; + INLCR = &0000100; + IGNCR = &0000200; + ICRNL = &0000400; + IUCLC = &0001000; + IXON = &0002000; + IXANY = &0004000; + IXOFF = &0010000; + IMAXBEL = &0020000; + IUTF8 = &0040000; + + { c_oflag bits } + OPOST = &0000001; + OLCUC = &0000002; + ONLCR = &0000004; + OCRNL = &0000010; + ONOCR = &0000020; + ONLRET = &0000040; + OFILL = &0000100; + OFDEL = &0000200; + NLDLY = &0000400; + NL0 = &0000000; + NL1 = &0000400; + CRDLY = &0003000; + CR0 = &0000000; + CR1 = &0001000; + CR2 = &0002000; + CR3 = &0003000; + TABDLY = &0014000; + TAB0 = &0000000; + TAB1 = &0004000; + TAB2 = &0010000; + TAB3 = &0014000; + XTABS = &0014000; + BSDLY = &0020000; + BS0 = &0000000; + BS1 = &0020000; + VTDLY = &0040000; + VT0 = &0000000; + VT1 = &0040000; + FFDLY = &0100000; + FF0 = &0000000; + FF1 = &0100000; + + { c_cflag bits } + CBAUD = &0010017; + B0 = &0000000; + B50 = &0000001; + B75 = &0000002; + B110 = &0000003; + B134 = &0000004; + B150 = &0000005; + B200 = &0000006; + B300 = &0000007; + B600 = &0000010; + B1200 = &0000011; + B1800 = &0000012; + B2400 = &0000013; + B4800 = &0000014; + B9600 = &0000015; + B19200 = &0000016; + B38400 = &0000017; + EXTA = B19200; + EXTB = B38400; + CSIZE = &0000060; + CS5 = &0000000; + CS6 = &0000020; + CS7 = &0000040; + CS8 = &0000060; + CSTOPB = &0000100; + CREAD = &0000200; + PARENB = &0000400; + PARODD = &0001000; + HUPCL = &0002000; + CLOCAL = &0004000; + CBAUDEX = &0010000; + BOTHER = &0010000; + B57600 = &0010001; + B115200 = &0010002; + B230400 = &0010003; + B460800 = &0010004; + B500000 = &0010005; + B576000 = &0010006; + B921600 = &0010007; + B1000000 = &0010010; + B1152000 = &0010011; + B1500000 = &0010012; + B2000000 = &0010013; + B2500000 = &0010014; + B3000000 = &0010015; + B3500000 = &0010016; + B4000000 = &0010017; + + CIBAUD = &002003600000; + CMSPAR = &010000000000; + CRTSCTS = &020000000000; + + IBSHIFT = 16; + + { c_lflag bits } + ISIG = &0000001; + ICANON = &0000002; + XCASE = &0000004; + ECHO = &0000010; + ECHOE = &0000020; + ECHOK = &0000040; + ECHONL = &0000100; + NOFLSH = &0000200; + TOSTOP = &0000400; + ECHOCTL = &0001000; + ECHOPRT = &0002000; + ECHOKE = &0004000; + FLUSHO = &0010000; + PENDIN = &0040000; + IEXTEN = &0100000; + EXTPROC = &0200000; + + { TCFlow } + TCOOFF = 0; + TCOON = 1; + TCIOFF = 2; + TCION = 3; + + { TCFlush } + TCIFLUSH = 0; + TCOFLUSH = 1; + TCIOFLUSH = 2; + + { TCSetAttr } + TCSANOW = 0; + TCSADRAIN = 1; + TCSAFLUSH = 2; + +{ from Linux 4.0, include/uapi/asm-generic/termios.h } + + { c_line bits } + TIOCM_LE = $001; + TIOCM_DTR = $002; + TIOCM_RTS = $004; + TIOCM_ST = $008; + TIOCM_SR = $010; + TIOCM_CTS = $020; + TIOCM_CAR = $040; + TIOCM_RNG = $080; + TIOCM_DSR = $100; + TIOCM_CD = TIOCM_CAR; + TIOCM_RI = TIOCM_RNG; + TIOCM_OUT1 = $2000; + TIOCM_OUT2 = $4000; + TIOCM_LOOP = $8000; + +{$endif cpuriscv32} + +{$ifdef cpuriscv64} + +{ from Linux 4.0, include/uapi/asm-generic/ioctls.h } + + { For Terminal handling } + TCGETS = $5401; + TCSETS = $5402; + TCSETSW = $5403; + TCSETSF = $5404; + TCGETA = $5405; + TCSETA = $5406; + TCSETAW = $5407; + TCSETAF = $5408; + TCSBRK = $5409; + TCXONC = $540A; + TCFLSH = $540B; + TIOCEXCL = $540C; + TIOCNXCL = $540D; + TIOCSCTTY = $540E; + TIOCGPGRP = $540F; + TIOCSPGRP = $5410; + TIOCOUTQ = $5411; + TIOCSTI = $5412; + TIOCGWINSZ = $5413; + TIOCSWINSZ = $5414; + TIOCMGET = $5415; + TIOCMBIS = $5416; + TIOCMBIC = $5417; + TIOCMSET = $5418; + TIOCGSOFTCAR = $5419; + TIOCSSOFTCAR = $541A; + FIONREAD = $541B; + TIOCINQ = FIONREAD; + TIOCLINUX = $541C; + TIOCCONS = $541D; + TIOCGSERIAL = $541E; + TIOCSSERIAL = $541F; + TIOCPKT = $5420; + FIONBIO = $5421; + TIOCNOTTY = $5422; + TIOCSETD = $5423; + TIOCGETD = $5424; + TCSBRKP = $5425; + + TIOCSBRK = $5427; + TIOCCBRK = $5428; + TIOCGSID = $5429; + + TIOCGRS485 = $542E; + TIOCSRS485 = $542F; + + TCGETX = $5432; + TCSETX = $5433; + TCSETXF = $5434; + TCSETXW = $5435; + TIOCVHANGUP = $5437; + + FIONCLEX = $5450; + FIOCLEX = $5451; + FIOASYNC = $5452; + TIOCSERCONFIG = $5453; + TIOCSERGWILD = $5454; + TIOCSERSWILD = $5455; + TIOCGLCKTRMIOS = $5456; + TIOCSLCKTRMIOS = $5457; + TIOCSERGSTRUCT = $5458; + TIOCSERGETLSR = $5459; + TIOCSERGETMULTI = $545A; + TIOCSERSETMULTI = $545B; + TIOCMIWAIT = $545C; + TIOCGICOUNT = $545D; + + FIOQSIZE = $5460; + + TIOCPKT_DATA = 0; + TIOCPKT_FLUSHREAD = 1; + TIOCPKT_FLUSHWRITE = 2; + TIOCPKT_STOP = 4; + TIOCPKT_START = 8; + TIOCPKT_NOSTOP = 16; + TIOCPKT_DOSTOP = 32; + TIOCPKT_IOCTL = 64; + + TIOCSER_TEMT = $01; + +{ from Linux 4.0, include/uapi/asm-generic/termbits.h } + + { c_cc characters } + VINTR = 0; + VQUIT = 1; + VERASE = 2; + VKILL = 3; + VEOF = 4; + VTIME = 5; + VMIN = 6; + VSWTC = 7; + VSTART = 8; + VSTOP = 9; + VSUSP = 10; + VEOL = 11; + VREPRINT = 12; + VDISCARD = 13; + VWERASE = 14; + VLNEXT = 15; + VEOL2 = 16; + + { c_iflag bits } + IGNBRK = &0000001; + BRKINT = &0000002; + IGNPAR = &0000004; + PARMRK = &0000010; + INPCK = &0000020; + ISTRIP = &0000040; + INLCR = &0000100; + IGNCR = &0000200; + ICRNL = &0000400; + IUCLC = &0001000; + IXON = &0002000; + IXANY = &0004000; + IXOFF = &0010000; + IMAXBEL = &0020000; + IUTF8 = &0040000; + + { c_oflag bits } + OPOST = &0000001; + OLCUC = &0000002; + ONLCR = &0000004; + OCRNL = &0000010; + ONOCR = &0000020; + ONLRET = &0000040; + OFILL = &0000100; + OFDEL = &0000200; + NLDLY = &0000400; + NL0 = &0000000; + NL1 = &0000400; + CRDLY = &0003000; + CR0 = &0000000; + CR1 = &0001000; + CR2 = &0002000; + CR3 = &0003000; + TABDLY = &0014000; + TAB0 = &0000000; + TAB1 = &0004000; + TAB2 = &0010000; + TAB3 = &0014000; + XTABS = &0014000; + BSDLY = &0020000; + BS0 = &0000000; + BS1 = &0020000; + VTDLY = &0040000; + VT0 = &0000000; + VT1 = &0040000; + FFDLY = &0100000; + FF0 = &0000000; + FF1 = &0100000; + + { c_cflag bits } + CBAUD = &0010017; + B0 = &0000000; + B50 = &0000001; + B75 = &0000002; + B110 = &0000003; + B134 = &0000004; + B150 = &0000005; + B200 = &0000006; + B300 = &0000007; + B600 = &0000010; + B1200 = &0000011; + B1800 = &0000012; + B2400 = &0000013; + B4800 = &0000014; + B9600 = &0000015; + B19200 = &0000016; + B38400 = &0000017; + EXTA = B19200; + EXTB = B38400; + CSIZE = &0000060; + CS5 = &0000000; + CS6 = &0000020; + CS7 = &0000040; + CS8 = &0000060; + CSTOPB = &0000100; + CREAD = &0000200; + PARENB = &0000400; + PARODD = &0001000; + HUPCL = &0002000; + CLOCAL = &0004000; + CBAUDEX = &0010000; + BOTHER = &0010000; + B57600 = &0010001; + B115200 = &0010002; + B230400 = &0010003; + B460800 = &0010004; + B500000 = &0010005; + B576000 = &0010006; + B921600 = &0010007; + B1000000 = &0010010; + B1152000 = &0010011; + B1500000 = &0010012; + B2000000 = &0010013; + B2500000 = &0010014; + B3000000 = &0010015; + B3500000 = &0010016; + B4000000 = &0010017; + + CIBAUD = &002003600000; + CMSPAR = &010000000000; + CRTSCTS = &020000000000; + + IBSHIFT = 16; + + { c_lflag bits } + ISIG = &0000001; + ICANON = &0000002; + XCASE = &0000004; + ECHO = &0000010; + ECHOE = &0000020; + ECHOK = &0000040; + ECHONL = &0000100; + NOFLSH = &0000200; + TOSTOP = &0000400; + ECHOCTL = &0001000; + ECHOPRT = &0002000; + ECHOKE = &0004000; + FLUSHO = &0010000; + PENDIN = &0040000; + IEXTEN = &0100000; + EXTPROC = &0200000; + + { TCFlow } + TCOOFF = 0; + TCOON = 1; + TCIOFF = 2; + TCION = 3; + + { TCFlush } + TCIFLUSH = 0; + TCOFLUSH = 1; + TCIOFLUSH = 2; + + { TCSetAttr } + TCSANOW = 0; + TCSADRAIN = 1; + TCSAFLUSH = 2; + +{ from Linux 4.0, include/uapi/asm-generic/termios.h } + + { c_line bits } + TIOCM_LE = $001; + TIOCM_DTR = $002; + TIOCM_RTS = $004; + TIOCM_ST = $008; + TIOCM_SR = $010; + TIOCM_CTS = $020; + TIOCM_CAR = $040; + TIOCM_RNG = $080; + TIOCM_DSR = $100; + TIOCM_CD = TIOCM_CAR; + TIOCM_RI = TIOCM_RNG; + TIOCM_OUT1 = $2000; + TIOCM_OUT2 = $4000; + TIOCM_LOOP = $8000; + +{$endif cpuriscv64} + {$ifdef cpui386} { For Terminal handling } TCGETS = $5401; diff --git a/riscv_new/rtl/riscv32/int64p.inc b/riscv_new/rtl/riscv32/int64p.inc new file mode 100644 index 0000000000..1cb045808f --- /dev/null +++ b/riscv_new/rtl/riscv32/int64p.inc @@ -0,0 +1,14 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team + + This file contains some helper routines for int64 and qword + + 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. + + **********************************************************************} diff --git a/riscv_new/rtl/riscv32/makefile.cpu b/riscv_new/rtl/riscv32/makefile.cpu new file mode 100644 index 0000000000..48d8c2101f --- /dev/null +++ b/riscv_new/rtl/riscv32/makefile.cpu @@ -0,0 +1,6 @@ +# +# Here we set processor dependent include file names. +# + +CPUNAMES=riscv32 int64p math set setjump setjumph strings stringss +CPUINCNAMES=$(addsuffix .inc,$(CPUNAMES)) diff --git a/riscv_new/rtl/riscv32/math.inc b/riscv_new/rtl/riscv32/math.inc new file mode 100644 index 0000000000..472337688e --- /dev/null +++ b/riscv_new/rtl/riscv32/math.inc @@ -0,0 +1,15 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + Implementation of mathematical Routines (only for real) + + 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. + + **********************************************************************} diff --git a/riscv_new/rtl/riscv32/riscv32.inc b/riscv_new/rtl/riscv32/riscv32.inc new file mode 100644 index 0000000000..597e395c75 --- /dev/null +++ b/riscv_new/rtl/riscv32/riscv32.inc @@ -0,0 +1,83 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + Processor dependent implementation for the system unit for + AVR + + 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 fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + end; + + +{$IFNDEF INTERNAL_BACKTRACE} +{$define FPC_SYSTEM_HAS_GET_FRAME} +function get_frame:pointer;assembler;nostackframe; + asm + end; +{$ENDIF not INTERNAL_BACKTRACE} + + +{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR} +function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;assembler; + asm + end; + + +{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME} +function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler; + asm + end; + + +{$define FPC_SYSTEM_HAS_SPTR} +Function Sptr : pointer;assembler; + asm + end; + + +function InterLockedDecrement (var Target: longint) : longint; + begin + dec(Target); + Result:=Target; + end; + + +function InterLockedIncrement (var Target: longint) : longint; + begin + inc(Target); + Result:=Target; + end; + + +function InterLockedExchange (var Target: longint;Source : longint) : longint; + begin + Result:=Target; + Target:=Source; + end; + + +function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; + begin + Result:=Target; + if Target=Comperand then + Target:=NewValue; + end; + + +function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; + begin + Result:=Target; + inc(Target,Source); + end; + diff --git a/riscv_new/rtl/riscv32/set.inc b/riscv_new/rtl/riscv32/set.inc new file mode 100644 index 0000000000..681a4b7cbb --- /dev/null +++ b/riscv_new/rtl/riscv32/set.inc @@ -0,0 +1,15 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + Include file with set operations called by the compiler + + 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. + + **********************************************************************} diff --git a/riscv_new/rtl/riscv32/setjump.inc b/riscv_new/rtl/riscv32/setjump.inc new file mode 100644 index 0000000000..be2a0c181c --- /dev/null +++ b/riscv_new/rtl/riscv32/setjump.inc @@ -0,0 +1,26 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + SetJmp and LongJmp implementation for exception handling + + 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. + + **********************************************************************} + +function fpc_setjmp(var S : jmp_buf) : longint;assembler;[Public, alias : 'FPC_SETJMP'];nostackframe;compilerproc; + asm + end; + + +procedure fpc_longjmp(var S : jmp_buf;value : longint);assembler;[Public, alias : 'FPC_LONGJMP'];compilerproc; + asm + end; + + diff --git a/riscv_new/rtl/riscv32/setjumph.inc b/riscv_new/rtl/riscv32/setjumph.inc new file mode 100644 index 0000000000..f27b3c9cbc --- /dev/null +++ b/riscv_new/rtl/riscv32/setjumph.inc @@ -0,0 +1,25 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + SetJmp/Longjmp declarations + + 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. + + **********************************************************************} + +type + jmp_buf = packed record + end; + pjmp_buf = ^jmp_buf; + +function setjmp(var S : jmp_buf) : longint;[external name 'FPC_SETJMP']; +procedure longjmp(var S : jmp_buf;value : longint);[external name 'FPC_LONGJMP']; + + diff --git a/riscv_new/rtl/riscv32/strings.inc b/riscv_new/rtl/riscv32/strings.inc new file mode 100644 index 0000000000..0d10cd5002 --- /dev/null +++ b/riscv_new/rtl/riscv32/strings.inc @@ -0,0 +1,18 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2000 by Jonas Maebe, member of the + Free Pascal development team + + Processor dependent part of strings.pp, that can be shared with + sysutils unit. + + 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. + + **********************************************************************} + + diff --git a/riscv_new/rtl/riscv32/stringss.inc b/riscv_new/rtl/riscv32/stringss.inc new file mode 100644 index 0000000000..b30572827e --- /dev/null +++ b/riscv_new/rtl/riscv32/stringss.inc @@ -0,0 +1,18 @@ +{ + 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 + + Processor dependent part of strings.pp, not shared with + sysutils unit. + + 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. + + **********************************************************************} + + diff --git a/riscv_new/rtl/riscv64/int64p.inc b/riscv_new/rtl/riscv64/int64p.inc new file mode 100644 index 0000000000..1cb045808f --- /dev/null +++ b/riscv_new/rtl/riscv64/int64p.inc @@ -0,0 +1,14 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team + + This file contains some helper routines for int64 and qword + + 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. + + **********************************************************************} diff --git a/riscv_new/rtl/riscv64/makefile.cpu b/riscv_new/rtl/riscv64/makefile.cpu new file mode 100644 index 0000000000..03bae91aca --- /dev/null +++ b/riscv_new/rtl/riscv64/makefile.cpu @@ -0,0 +1,6 @@ +# +# Here we set processor dependent include file names. +# + +CPUNAMES=riscv64 int64p math set setjump setjumph strings stringss +CPUINCNAMES=$(addsuffix .inc,$(CPUNAMES)) diff --git a/riscv_new/rtl/riscv64/math.inc b/riscv_new/rtl/riscv64/math.inc new file mode 100644 index 0000000000..472337688e --- /dev/null +++ b/riscv_new/rtl/riscv64/math.inc @@ -0,0 +1,15 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + Implementation of mathematical Routines (only for real) + + 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. + + **********************************************************************} diff --git a/riscv_new/rtl/riscv64/mathu.inc b/riscv_new/rtl/riscv64/mathu.inc new file mode 100644 index 0000000000..74743e0a6e --- /dev/null +++ b/riscv_new/rtl/riscv64/mathu.inc @@ -0,0 +1,151 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2014 by Jonas Maebe + member of the Free Pascal development team + + 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. + +**********************************************************************} + +function getfpcr: dword; nostackframe; assembler; + asm + end; + + +procedure setfpcr(val: dword); nostackframe; assembler; + asm + end; + + +function getfpsr: dword; nostackframe; assembler; + asm + end; + + +procedure setfpsr(val: dword); nostackframe; assembler; + asm + end; + + +function GetRoundMode: TFPURoundingMode; + const + bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmUp,rmDown,rmTruncate); + begin + result:=TFPURoundingMode(bits2rm[(getfpcr shr 22) and 3]) + end; + + +function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode; + const + rm2bits: array[TFPURoundingMode] of byte = (0,2,1,3); + begin + softfloat_rounding_mode:=RoundMode; + SetRoundMode:=RoundMode; + setfpcr((getfpcr and $ff3fffff) or (rm2bits[RoundMode] shl 22)); + end; + + +function GetPrecisionMode: TFPUPrecisionMode; + begin + result:=pmDouble; + end; + + +function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode; + begin + result:=pmDouble; + end; + + +const + fpu_ioe = 1 shl 8; + fpu_dze = 1 shl 9; + fpu_ofe = 1 shl 10; + fpu_ufe = 1 shl 11; + fpu_ixe = 1 shl 12; + fpu_ide = 1 shl 15; + fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide; + fpu_exception_mask_to_status_mask_shift = 8; + + +function GetExceptionMask: TFPUExceptionMask; + var + fpcr: dword; + begin + fpcr:=getfpcr; + result:=[]; + if ((fpcr and fpu_ioe)=0) then + result := result+[exInvalidOp]; + if ((fpcr and fpu_ofe)=0) then + result := result+[exOverflow]; + if ((fpcr and fpu_ufe)=0) then + result := result+[exUnderflow]; + if ((fpcr and fpu_dze)=0) then + result := result+[exZeroDivide]; + if ((fpcr and fpu_ixe)=0) then + result := result+[exPrecision]; + if ((fpcr and fpu_ide)=0) then + result := result+[exDenormalized]; + end; + + +function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask; + var + newfpcr: dword; + begin + softfloat_exception_mask:=mask; + newfpcr:=fpu_exception_mask; + if exInvalidOp in Mask then + newfpcr:=newfpcr and not(fpu_ioe); + if exOverflow in Mask then + newfpcr:=newfpcr and not(fpu_ofe); + if exUnderflow in Mask then + newfpcr:=newfpcr and not(fpu_ufe); + if exZeroDivide in Mask then + newfpcr:=newfpcr and not(fpu_dze); + if exPrecision in Mask then + newfpcr:=newfpcr and not(fpu_ixe); + if exDenormalized in Mask then + newfpcr:=newfpcr and not(fpu_ide); + { clear "exception happened" flags } + ClearExceptions(false); + { set new exception mask } + setfpcr((getfpcr and not(fpu_exception_mask)) or newfpcr); + { unsupported mask bits will remain 0 -> read exception mask again } + result:=GetExceptionMask; + softfloat_exception_mask:=result; + end; + + +procedure ClearExceptions(RaisePending: Boolean); + var + fpsr: dword; + f: TFPUException; + begin + fpsr:=getfpsr; + if raisepending then + begin + if (fpsr and (fpu_dze shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exZeroDivide); + if (fpsr and (fpu_ofe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exOverflow); + if (fpsr and (fpu_ufe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exUnderflow); + if (fpsr and (fpu_ioe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exInvalidOp); + if (fpsr and (fpu_ixe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exPrecision); + if (fpsr and (fpu_ide shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exDenormalized); + { now the soft float exceptions } + for f in softfloat_exception_flags do + float_raise(f); + end; + softfloat_exception_flags:=[]; + setfpsr(fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift)); + end; diff --git a/riscv_new/rtl/riscv64/riscv64.inc b/riscv_new/rtl/riscv64/riscv64.inc new file mode 100644 index 0000000000..3b71640ca5 --- /dev/null +++ b/riscv_new/rtl/riscv64/riscv64.inc @@ -0,0 +1,124 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + Processor dependent implementation for the system unit for + AVR + + 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 fpc_cpuinit;{$ifdef SYSTEMINLINE}inline;{$endif} + begin + end; + + +{$IFNDEF INTERNAL_BACKTRACE} +{$define FPC_SYSTEM_HAS_GET_FRAME} +function get_frame:pointer;assembler;nostackframe; + asm + addi a0, fp, 0 + end; +{$ENDIF not INTERNAL_BACKTRACE} + + +{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR} +function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;assembler; + asm + ld a0, -8*2(a0) + end; + + +{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME} +function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler; + asm + ld a0, -8*1(a0) + end; + + +{$define FPC_SYSTEM_HAS_SPTR} +Function Sptr : pointer;assembler; + asm + addi a0, sp, 0 + end; + + +function InterLockedDecrement (var Target: longint) : longint; + begin + dec(Target); + Result:=Target; + end; + + +function InterLockedIncrement (var Target: longint) : longint; + begin + inc(Target); + Result:=Target; + end; + + +function InterLockedExchange (var Target: longint;Source : longint) : longint; + begin + Result:=Target; + Target:=Source; + end; + + +function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; + begin + Result:=Target; + if Target=Comperand then + Target:=NewValue; + end; + + +function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; + begin + Result:=Target; + inc(Target,Source); + end; + + + +function InterLockedDecrement64 (var Target: int64) : int64; + begin + dec(Target); + Result:=Target; + end; + + +function InterLockedIncrement64 (var Target: int64) : int64; + begin + inc(Target); + Result:=Target; + end; + + +function InterLockedExchange64 (var Target: int64;Source : int64) : int64; + begin + Result:=Target; + Target:=Source; + end; + + +function InterlockedCompareExchange64(var Target: int64; NewValue: int64; Comperand: int64): int64; + begin + Result:=Target; + if Target=Comperand then + Target:=NewValue; + end; + + +function InterLockedExchangeAdd64 (var Target: int64;Source : int64) : int64; + begin + Result:=Target; + inc(Target,Source); + end; + diff --git a/riscv_new/rtl/riscv64/set.inc b/riscv_new/rtl/riscv64/set.inc new file mode 100644 index 0000000000..681a4b7cbb --- /dev/null +++ b/riscv_new/rtl/riscv64/set.inc @@ -0,0 +1,15 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + Include file with set operations called by the compiler + + 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. + + **********************************************************************} diff --git a/riscv_new/rtl/riscv64/setjump.inc b/riscv_new/rtl/riscv64/setjump.inc new file mode 100644 index 0000000000..bb238b7aba --- /dev/null +++ b/riscv_new/rtl/riscv64/setjump.inc @@ -0,0 +1,132 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + SetJmp and LongJmp implementation for exception handling + + 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. + + **********************************************************************} + +function fpc_setjmp(var S : jmp_buf) : longint;assembler;nostackframe;[Public, alias : 'FPC_SETJMP'];nostackframe;compilerproc; + asm + sd ra, 0*8(a0) + sd s0, 1*8(a0) + sd s1, 2*8(a0) + sd s2, 3*8(a0) + sd s3, 4*8(a0) + sd s4, 5*8(a0) + sd s5, 6*8(a0) + sd s6, 7*8(a0) + sd s7, 8*8(a0) + sd s8, 9*8(a0) + sd s9, 10*8(a0) + sd s10, 11*8(a0) + sd s11, 12*8(a0) + sd sp, 13*8(a0) + +{$if defined(FPUFD) or defined(FPUD)} + frcsr s0 + + sd s0, 14*8(a0) + + fsd f8, 15*8(a0) + fsd f9, 16*8(a0) + fsd f18, 17*8(a0) + fsd f19, 18*8(a0) + fsd f20, 19*8(a0) + fsd f21, 20*8(a0) + fsd f22, 21*8(a0) + fsd f23, 22*8(a0) + fsd f24, 23*8(a0) + fsd f25, 24*8(a0) + fsd f26, 25*8(a0) + fsd f27, 26*8(a0) +{$endif FPUFD or FPUD} +{$if defined(FPUF)} + frcsr s0 + + sd s0, 14*8(a0) + + fsw f8, 30*4(a0) + fsw f9, 31*4(a0) + fsw f18, 32*4(a0) + fsw f19, 33*4(a0) + fsw f20, 34*4(a0) + fsw f21, 35*4(a0) + fsw f22, 36*4(a0) + fsw f23, 37*4(a0) + fsw f24, 38*4(a0) + fsw f25, 39*4(a0) + fsw f26, 40*4(a0) + fsw f27, 41*4(a0) +{$endif FPUF} + + addi x10, x0, 0 + end; + + +procedure fpc_longjmp(var S : jmp_buf;value : longint);assembler;nostackframe;[Public, alias : 'FPC_LONGJMP'];compilerproc; + asm + ld ra, 0*8(a0) + ld s0, 1*8(a0) + ld s1, 2*8(a0) + ld s2, 3*8(a0) + ld s3, 4*8(a0) + ld s4, 5*8(a0) + ld s5, 6*8(a0) + ld s6, 7*8(a0) + ld s7, 8*8(a0) + ld s8, 9*8(a0) + ld s9, 10*8(a0) + ld s10,11*8(a0) + ld s11,12*8(a0) + +{$if defined(FPUFD) or defined(FPUD)} + ld sp, 14*8(a0) + + fld f8, 15*8(a0) + fld f9, 16*8(a0) + fld f18, 17*8(a0) + fld f19, 18*8(a0) + fld f20, 19*8(a0) + fld f21, 20*8(a0) + fld f22, 21*8(a0) + fld f23, 22*8(a0) + fld f24, 23*8(a0) + fld f25, 24*8(a0) + fld f26, 25*8(a0) + fld f27, 26*8(a0) + + fscsr sp +{$endif FPUFD or FPUD} +{$if defined(FPUF)} + ld sp, 14*8(a0) + + flw f8, 30*4(a0) + flw f9, 31*4(a0) + flw f18, 32*4(a0) + flw f19, 33*4(a0) + flw f20, 34*4(a0) + flw f21, 35*4(a0) + flw f22, 36*4(a0) + flw f23, 37*4(a0) + flw f24, 38*4(a0) + flw f25, 39*4(a0) + flw f26, 40*4(a0) + flw f27, 41*4(a0) + + fscsr sp +{$endif FPUF} + ld sp, 13*8(a0) + + sltiu a0, a1, 1 + add a0, a0, a1 + end; + diff --git a/riscv_new/rtl/riscv64/setjumph.inc b/riscv_new/rtl/riscv64/setjumph.inc new file mode 100644 index 0000000000..fa0c4a14c6 --- /dev/null +++ b/riscv_new/rtl/riscv64/setjumph.inc @@ -0,0 +1,39 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2008 by the Free Pascal development team. + + SetJmp/Longjmp declarations + + 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. + + **********************************************************************} + +type + jmp_buf = packed record + ra, + x8,x9,x18,x19,x20,x21, + x22,x23,x24,x25,x26, + x27,x2: qword; +{$if defined(FPUFD) or defined(FPUD)} + fcsr, + f8,f9,f18,f19,f20,f21, + f22,f23,f24,f25,f26,f27: qword; +{$endif FPUFD or FPUD} +{$if defined(FPUF)} + fcsr: qword; + f8,f9,f18,f19,f20,f21, + f22,f23,f24,f25,f26,f27: longword; +{$endif FPUF} + end; + pjmp_buf = ^jmp_buf; + +function setjmp(var S : jmp_buf) : longint;[external name 'FPC_SETJMP']; +procedure longjmp(var S : jmp_buf;value : longint);[external name 'FPC_LONGJMP']; + + diff --git a/riscv_new/rtl/riscv64/strings.inc b/riscv_new/rtl/riscv64/strings.inc new file mode 100644 index 0000000000..0d10cd5002 --- /dev/null +++ b/riscv_new/rtl/riscv64/strings.inc @@ -0,0 +1,18 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2000 by Jonas Maebe, member of the + Free Pascal development team + + Processor dependent part of strings.pp, that can be shared with + sysutils unit. + + 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. + + **********************************************************************} + + diff --git a/riscv_new/rtl/riscv64/stringss.inc b/riscv_new/rtl/riscv64/stringss.inc new file mode 100644 index 0000000000..b30572827e --- /dev/null +++ b/riscv_new/rtl/riscv64/stringss.inc @@ -0,0 +1,18 @@ +{ + 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 + + Processor dependent part of strings.pp, not shared with + sysutils unit. + + 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. + + **********************************************************************} + + diff --git a/riscv_new/utils/fpcm/fpcmmain.pp b/riscv_new/utils/fpcm/fpcmmain.pp index 925f3eb92d..174fc8ec3b 100644 --- a/riscv_new/utils/fpcm/fpcmmain.pp +++ b/riscv_new/utils/fpcm/fpcmmain.pp @@ -67,7 +67,7 @@ interface type TCpu=( - c_i386,c_m68k,c_powerpc,c_sparc,c_x86_64,c_arm,c_powerpc64,c_avr,c_armeb,c_armel,c_mips,c_mipsel,c_mips64,c_mips64el,c_jvm,c_i8086,c_aarch64,c_wasm,c_sparc64 + c_i386,c_m68k,c_powerpc,c_sparc,c_x86_64,c_arm,c_powerpc64,c_avr,c_armeb,c_armel,c_mips,c_mipsel,c_mips64,c_mips64el,c_jvm,c_i8086,c_aarch64,c_wasm,c_sparc64,c_riscv32,c_riscv64 ); TOS=( @@ -82,15 +82,15 @@ interface const CpuStr : array[TCpu] of string=( - 'i386','m68k','powerpc','sparc','x86_64','arm','powerpc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','i8086','aarch64','wasm','sparc64' + 'i386','m68k','powerpc','sparc','x86_64','arm','powerpc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','i8086','aarch64','wasm','sparc64','riscv32','riscv64' ); CpuSuffix : array[TCpu] of string=( - '_i386','_m68k','_powerpc','_sparc','_x86_64','_arm','_powerpc64','_avr','_armeb', '_armel', '_mips', '_mipsel', '_mips64', '_mips64el', '_jvm','_i8086','_aarch64','_wasm','_sparc64' + '_i386','_m68k','_powerpc','_sparc','_x86_64','_arm','_powerpc64','_avr','_armeb', '_armel', '_mips', '_mipsel', '_mips64', '_mips64el', '_jvm','_i8086','_aarch64','_wasm','_sparc64','_riscv32','_riscv64' ); ppcSuffix : array[TCpu] of string=( - '386','68k','ppc','sparc','x64','arm','ppc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','8086','a64','wasm','sparc64' + '386','68k','ppc','sparc','x64','arm','ppc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','8086','a64','wasm','sparc64','rv32','rv64' ); OSStr : array[TOS] of string=( @@ -113,46 +113,46 @@ interface { This table is kept OS,Cpu because it is easier to maintain (PFV) } OSCpuPossible : array[TOS,TCpu] of boolean = ( - { os i386 m68k ppc sparc x86_64 arm ppc64 avr armeb armel mips mipsel mips64 misp64el jvm i8086 aarch64 wasm sparc64} - { linux } ( true, true, true, true, true, true, true, false, true, false, true, true, false, false, false, false, true, false, true), - { go32v2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { win32 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { os2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { freebsd } ( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { beos } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { haiku } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { netbsd } ( true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { amiga } ( false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { atari } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { solaris } ( true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { qnx } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { netware } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { openbsd } ( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { wdosx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { palmos } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { macos } ( false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { darwin } ( true, false, true, false, true, true, true, false, false, false, false, false, false, false, false, false, true, false, false), - { emx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { watcom } ( true, false, false, false ,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { morphos } ( false, false, true, false ,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { netwlibc }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { win64 } ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { wince }( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { gba } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { nds } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { embedded }( true, true, true, true, true, true, true, true, true , false, false, true , false, false, false, true , false, false, false), - { symbian } ( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { nativent }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { iphonesim }( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { wii } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { aix } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { java } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false), - { android } ( true, false, false, false, false, true, false, false, false, false, false, true, false, false, true, false, false, false, false), - { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false), - { aros } ( true, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - {dragonfly} ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { win16 } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false), - { wasm } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false) + { os i386 m68k ppc sparc x86_64 arm ppc64 avr armeb armel mips mipsel mips64 misp64el jvm i8086 aarch64 wasm sparc64 riscv32 riscv64} + { linux } ( true, true, true, true, true, true, true, false, true, false, true, true, false, false, false, false, true, false, true, true, true), + { go32v2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win32 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { os2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { freebsd } ( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { beos } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { haiku } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netbsd } ( true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { amiga } ( false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { atari } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { solaris } ( true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { qnx } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netware } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { openbsd } ( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { wdosx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { palmos } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { macos } ( false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { darwin } ( true, false, true, false, true, true, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false), + { emx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { watcom } ( true, false, false, false ,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { morphos } ( false, false, true, false ,false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netwlibc }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win64 } ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { wince }( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { gba } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { nds } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { embedded }( true, true, true, true, true, true, true, true, true , false, false, true , false, false, false, true , false, false, false, true, true ), + { symbian } ( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { nativent }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { iphonesim }( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { wii } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { aix } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { java } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false), + { android } ( true, false, false, false, false, true, false, false, false, false, false, true, false, false, true, false, false, false, false, false, false), + { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false, false, false), + { aros } ( true, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + {dragonfly} ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win16 } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false, false, false, false, false), + { wasm } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false) ); type |