Browse Source

+ skeleton for Z80 support

git-svn-id: branches/z80@35665 -
florian 8 years ago
parent
commit
ea52a23179

+ 29 - 0
.gitattributes

@@ -637,6 +637,7 @@ compiler/ppcmipsel.lpi svneol=native#text/plain
 compiler/ppcppc.lpi svneol=native#text/plain
 compiler/ppcppc.lpi svneol=native#text/plain
 compiler/ppcppc64.lpi svneol=native#text/plain
 compiler/ppcppc64.lpi svneol=native#text/plain
 compiler/ppcsparc.lpi svneol=native#text/plain
 compiler/ppcsparc.lpi svneol=native#text/plain
+compiler/ppcz80.lpi svneol=native#text/plain
 compiler/ppheap.pas svneol=native#text/plain
 compiler/ppheap.pas svneol=native#text/plain
 compiler/ppu.pas svneol=native#text/plain
 compiler/ppu.pas svneol=native#text/plain
 compiler/ppx86_64.lpi svneol=native#text/plain
 compiler/ppx86_64.lpi svneol=native#text/plain
@@ -794,6 +795,7 @@ compiler/utils/mkppcreg.pp svneol=native#text/plain
 compiler/utils/mkspreg.pp svneol=native#text/plain
 compiler/utils/mkspreg.pp svneol=native#text/plain
 compiler/utils/mkx86ins.pp svneol=native#text/plain
 compiler/utils/mkx86ins.pp svneol=native#text/plain
 compiler/utils/mkx86reg.pp svneol=native#text/plain
 compiler/utils/mkx86reg.pp svneol=native#text/plain
+compiler/utils/mkz80reg.pp svneol=native#text/plain
 compiler/utils/msg2inc.pp svneol=native#text/plain
 compiler/utils/msg2inc.pp svneol=native#text/plain
 compiler/utils/msgdif.pp svneol=native#text/plain
 compiler/utils/msgdif.pp svneol=native#text/plain
 compiler/utils/msgused.pl svneol=native#text/plain
 compiler/utils/msgused.pl svneol=native#text/plain
@@ -884,6 +886,33 @@ compiler/x86_64/x8664nop.inc svneol=native#text/plain
 compiler/x86_64/x8664op.inc svneol=native#text/plain
 compiler/x86_64/x8664op.inc svneol=native#text/plain
 compiler/x86_64/x8664pro.inc svneol=native#text/plain
 compiler/x86_64/x8664pro.inc svneol=native#text/plain
 compiler/x86_64/x8664tab.inc svneol=native#text/plain
 compiler/x86_64/x8664tab.inc svneol=native#text/plain
+compiler/z80/aasmcpu.pas svneol=native#text/plain
+compiler/z80/agz80asm.pas svneol=native#text/plain
+compiler/z80/aoptcpu.pas svneol=native#text/plain
+compiler/z80/aoptcpub.pas svneol=native#text/plain
+compiler/z80/aoptcpud.pas svneol=native#text/plain
+compiler/z80/cgcpu.pas svneol=native#text/plain
+compiler/z80/cpubase.pas svneol=native#text/plain
+compiler/z80/cpuinfo.pas svneol=native#text/plain
+compiler/z80/cpunode.pas svneol=native#text/plain
+compiler/z80/cpupara.pas svneol=native#text/plain
+compiler/z80/cpupi.pas svneol=native#text/plain
+compiler/z80/cputarg.pas svneol=native#text/plain
+compiler/z80/hlcgcpu.pas svneol=native#text/plain
+compiler/z80/raz80.pas svneol=native#text/plain
+compiler/z80/raz80asm.pas svneol=native#text/plain
+compiler/z80/rgcpu.pas svneol=native#text/plain
+compiler/z80/rz80con.inc svneol=native#text/plain
+compiler/z80/rz80dwa.inc svneol=native#text/plain
+compiler/z80/rz80nor.inc svneol=native#text/plain
+compiler/z80/rz80num.inc svneol=native#text/plain
+compiler/z80/rz80rni.inc svneol=native#text/plain
+compiler/z80/rz80sri.inc svneol=native#text/plain
+compiler/z80/rz80sta.inc svneol=native#text/plain
+compiler/z80/rz80std.inc svneol=native#text/plain
+compiler/z80/rz80sup.inc svneol=native#text/plain
+compiler/z80/symcpu.pas svneol=native#text/plain
+compiler/z80/z80reg.dat svneol=native#text/plain
 /fpmake.pp svneol=native#text/plain
 /fpmake.pp svneol=native#text/plain
 /fpmake_add1.inc svneol=native#text/plain
 /fpmake_add1.inc svneol=native#text/plain
 /fpmake_proc1.inc svneol=native#text/plain
 /fpmake_proc1.inc svneol=native#text/plain

+ 31 - 4
compiler/Makefile

@@ -1,8 +1,8 @@
 #
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0 [2016-11-06 rev 34805]
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2017-03-15 rev 35592]
 #
 #
 default: all
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin wasm-wasm
 BSDs = freebsd netbsd openbsd darwin dragonfly
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16
 LIMIT83fs = go32v2 os2 emx watcom msdos win16
@@ -306,7 +306,7 @@ UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
 ifeq ($(UNITSDIR),)
 ifeq ($(UNITSDIR),)
 UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
 UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
 endif
 endif
-PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages)
 ifndef FPCFPMAKE
 ifndef FPCFPMAKE
 ifdef CROSSCOMPILE
 ifdef CROSSCOMPILE
 ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),)
 ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),)
@@ -815,6 +815,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override TARGET_DIRS+=utils
 override TARGET_DIRS+=utils
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override TARGET_DIRS+=utils
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override TARGET_PROGRAMS+=pp
 override TARGET_PROGRAMS+=pp
 endif
 endif
@@ -1067,6 +1070,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override TARGET_PROGRAMS+=pp
 override TARGET_PROGRAMS+=pp
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override TARGET_PROGRAMS+=pp
+endif
 override INSTALL_FPCPACKAGE=y
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
@@ -1320,6 +1326,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
 endif
@@ -1572,6 +1581,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_TARGETDIR+=.
 override COMPILER_TARGETDIR+=.
 endif
 endif
@@ -1824,6 +1836,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_TARGETDIR+=.
 override COMPILER_TARGETDIR+=.
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_TARGETDIR+=.
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
 endif
@@ -2076,6 +2091,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
 ifdef REQUIRE_UNITSDIR
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 endif
 endif
@@ -2993,6 +3011,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_RTL=1
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+REQUIRE_PACKAGES_RTL=1
+endif
 ifdef REQUIRE_PACKAGES_RTL
 ifdef REQUIRE_PACKAGES_RTL
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 ifneq ($(PACKAGEDIR_RTL),)
 ifneq ($(PACKAGEDIR_RTL),)
@@ -3886,6 +3907,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 ifeq ($(FULL_TARGET),aarch64-darwin)
 TARGET_DIRS_UTILS=1
 TARGET_DIRS_UTILS=1
 endif
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+TARGET_DIRS_UTILS=1
+endif
 ifdef TARGET_DIRS_UTILS
 ifdef TARGET_DIRS_UTILS
 utils_all:
 utils_all:
 	$(MAKE) -C utils all
 	$(MAKE) -C utils all
@@ -4105,7 +4129,10 @@ regdataarch64 : aarch64/a64reg.dat
 regdatmips : mips/mipsreg.dat
 regdatmips : mips/mipsreg.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
 	cd mips && ..$(PATHSEP)utils$(PATHSEP)mkmpsreg$(SRCEXEEXT)
 	cd mips && ..$(PATHSEP)utils$(PATHSEP)mkmpsreg$(SRCEXEEXT)
-regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips
+regdatz80 : z80/z80reg.dat
+	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80reg.pp
+	cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80reg$(SRCEXEEXT)
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatz80
 revision.inc :
 revision.inc :
 ifneq ($(REVSTR),)
 ifneq ($(REVSTR),)
 ifdef USEZIPWRAPPER
 ifdef USEZIPWRAPPER

+ 5 - 1
compiler/Makefile.fpc

@@ -548,7 +548,11 @@ regdatmips : mips/mipsreg.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
         cd mips && ..$(PATHSEP)utils$(PATHSEP)mkmpsreg$(SRCEXEEXT)
         cd mips && ..$(PATHSEP)utils$(PATHSEP)mkmpsreg$(SRCEXEEXT)
 
 
-regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips
+regdatz80 : z80/z80reg.dat
+            $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80reg.pp
+        cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80reg$(SRCEXEEXT)
+
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatz80
 
 
 # revision.inc rule
 # revision.inc rule
 revision.inc :
 revision.inc :

+ 1 - 1
compiler/aggas.pas

@@ -109,7 +109,7 @@ implementation
       cutils,cfileutl,systems,
       cutils,cfileutl,systems,
       fmodule,verbose,
       fmodule,verbose,
 {$ifndef DISABLE_WIN64_SEH}
 {$ifndef DISABLE_WIN64_SEH}
-      itcpugas,
+      itcpuasm,
 {$endif DISABLE_WIN64_SEH}
 {$endif DISABLE_WIN64_SEH}
 {$ifdef m68k}
 {$ifdef m68k}
       cpuinfo,aasmcpu,
       cpuinfo,aasmcpu,

+ 12 - 0
compiler/fpcdefs.inc

@@ -232,6 +232,18 @@
   {$define SUPPORT_GET_FRAME}
   {$define SUPPORT_GET_FRAME}
 {$endif aarch64}
 {$endif aarch64}
 
 
+{$ifdef z80}
+  {$define cpu8bit}
+  {$define cpu16bitaddr}
+  {$define cpu8bitalu}
+  {$define cpuflags}
+  {$define cpunofpu}
+  {$define cpunodefaultint}
+  {$define cpuneedsdivhelper}
+  {$define cpuneedsmulhelper}
+  {$define cpucapabilities}
+{$endif z80}
+
 {$IFDEF MACOS}
 {$IFDEF MACOS}
 {$DEFINE USE_FAKE_SYSUTILS}
 {$DEFINE USE_FAKE_SYSUTILS}
 {$ENDIF MACOS}
 {$ENDIF MACOS}

+ 10 - 0
compiler/globals.pas

@@ -495,6 +495,16 @@ interface
         asmcputype : cpu_none;
         asmcputype : cpu_none;
         fputype : fpu_x87;
         fputype : fpu_x87;
   {$endif i8086}
   {$endif i8086}
+  {$ifdef z80}
+        cputype : cpu_z80;
+        optimizecputype : cpu_z80;
+        { Use cpu_none by default,
+        because using cpu_8086 by default means
+        that we reject any instruction above bare 8086 instruction set
+        for all assembler code PM }
+        asmcputype : cpu_none;
+        fputype : fpu_soft;
+  {$endif z80}
 {$endif not GENERIC_CPU}
 {$endif not GENERIC_CPU}
         asmmode : asmmode_standard;
         asmmode : asmmode_standard;
 {$ifndef jvm}
 {$ifndef jvm}

+ 7 - 0
compiler/pp.pas

@@ -32,6 +32,7 @@ program pp;
   SPARC               generate a compiler for SPARC
   SPARC               generate a compiler for SPARC
   POWERPC             generate a compiler for the PowerPC
   POWERPC             generate a compiler for the PowerPC
   POWERPC64           generate a compiler for the PowerPC64 architecture
   POWERPC64           generate a compiler for the PowerPC64 architecture
+  Z80                 generate a compiler for Z80
   DEBUG               version with debug code is generated
   DEBUG               version with debug code is generated
   EXTDEBUG            some extra debug code is executed
   EXTDEBUG            some extra debug code is executed
   SUPPORT_MMX         only i386: releases the compiler switch
   SUPPORT_MMX         only i386: releases the compiler switch
@@ -134,6 +135,12 @@ program pp;
   {$endif CPUDEFINED}
   {$endif CPUDEFINED}
   {$define CPUDEFINED}
   {$define CPUDEFINED}
 {$endif AARCH64}
 {$endif AARCH64}
+{$ifdef Z80}
+  {$ifdef CPUDEFINED}
+    {$fatal ONLY one of the switches for the CPU type must be defined}
+  {$endif CPUDEFINED}
+  {$define CPUDEFINED}
+{$endif Z80}
 {$ifndef CPUDEFINED}
 {$ifndef CPUDEFINED}
   {$fatal A CPU type switch must be defined}
   {$fatal A CPU type switch must be defined}
 {$endif CPUDEFINED}
 {$endif CPUDEFINED}

+ 73 - 0
compiler/ppcz80.lpi

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="10"/>
+    <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="ppcz80"/>
+    </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>
+        <FormatVersion Value="1"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="pp.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="z80\aasmcpu.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit1>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="z80\pp"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="z80"/>
+      <OtherUnitFiles Value="z80;systems"/>
+      <UnitOutputDirectory Value="z80\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="-dz80"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 3 - 1
compiler/systems.inc

@@ -175,7 +175,8 @@
              system_i8086_win16,        { 89 }
              system_i8086_win16,        { 89 }
              system_i8086_embedded,     { 90 }
              system_i8086_embedded,     { 90 }
              system_arm_aros,           { 91 }
              system_arm_aros,           { 91 }
-             system_wasm_wasm32         { 92 }
+             system_wasm_wasm32,        { 92 }
+             system_z80_embedded        { 93 }
        );
        );
 
 
      type
      type
@@ -229,6 +230,7 @@
              ,as_m68k_vasm
              ,as_m68k_vasm
              ,as_m68k_as_aout
              ,as_m68k_as_aout
              ,as_wasm_binaryen
              ,as_wasm_binaryen
+             ,as_z80asm
        );
        );
 
 
        tlink = (ld_none,
        tlink = (ld_none,

+ 272 - 0
compiler/utils/mkz80reg.pp

@@ -0,0 +1,272 @@
+{
+    Copyright (c) 1998-2002 by Peter Vreman and Florian Klaempfl
+
+    Convert z80reg.dat to several .inc files for usage with
+    the Free pascal 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.
+
+ **********************************************************************}
+{$mode objfpc}
+program mkz80reg;
+
+const Version = '1.00';
+      max_regcount = 200;
+
+var s : string;
+    i : longint;
+    line : longint;
+    regcount:byte;
+    regcount_bsstart:byte;
+    names,
+    regtypes,
+    supregs,
+    numbers,
+    stdnames,
+    stabs,dwarf : array[0..max_regcount-1] of string[63];
+    regnumber_index,
+    std_regname_index : array[0..max_regcount-1] of byte;
+
+function tostr(l : longint) : string;
+
+begin
+  str(l,tostr);
+end;
+
+function readstr : string;
+
+  begin
+     result:='';
+     while (s[i]<>',') and (i<=length(s)) do
+       begin
+          result:=result+s[i];
+          inc(i);
+       end;
+  end;
+
+
+procedure readcomma;
+  begin
+     if s[i]<>',' then
+       begin
+         writeln('Missing "," at line ',line);
+         writeln('Line: "',s,'"');
+         halt(1);
+       end;
+     inc(i);
+  end;
+
+
+procedure skipspace;
+
+  begin
+     while (s[i] in [' ',#9]) do
+       inc(i);
+  end;
+
+procedure openinc(out f:text;const fn:string);
+begin
+  writeln('creating ',fn);
+  assign(f,fn);
+  rewrite(f);
+  writeln(f,'{ don''t edit, this file is generated from z80reg.dat }');
+end;
+
+
+procedure closeinc(var f:text);
+begin
+  writeln(f);
+  close(f);
+end;
+
+procedure build_regnum_index;
+
+var h,i,j,p,t:byte;
+
+begin
+  {Build the registernumber2regindex index.
+   Step 1: Fill.}
+  for i:=0 to regcount-1 do
+    regnumber_index[i]:=i;
+  {Step 2: Sort. We use a Shell-Metzner sort.}
+  p:=regcount_bsstart;
+  repeat
+    for h:=0 to regcount-p-1 do
+      begin
+        i:=h;
+        repeat
+          j:=i+p;
+          if numbers[regnumber_index[j]]>=numbers[regnumber_index[i]] then
+            break;
+          t:=regnumber_index[i];
+          regnumber_index[i]:=regnumber_index[j];
+          regnumber_index[j]:=t;
+          if i<p then
+            break;
+          dec(i,p);
+        until false;
+      end;
+    p:=p shr 1;
+  until p=0;
+end;
+
+procedure build_std_regname_index;
+
+var h,i,j,p,t:byte;
+
+begin
+  {Build the registernumber2regindex index.
+   Step 1: Fill.}
+  for i:=0 to regcount-1 do
+    std_regname_index[i]:=i;
+  {Step 2: Sort. We use a Shell-Metzner sort.}
+  p:=regcount_bsstart;
+  repeat
+    for h:=0 to regcount-p-1 do
+      begin
+        i:=h;
+        repeat
+          j:=i+p;
+          if stdnames[std_regname_index[j]]>=stdnames[std_regname_index[i]] then
+            break;
+          t:=std_regname_index[i];
+          std_regname_index[i]:=std_regname_index[j];
+          std_regname_index[j]:=t;
+          if i<p then
+            break;
+          dec(i,p);
+        until false;
+      end;
+    p:=p shr 1;
+  until p=0;
+end;
+
+
+procedure read_spreg_file;
+
+var infile:text;
+
+begin
+   { open dat file }
+   assign(infile,'z80reg.dat');
+   reset(infile);
+   while not(eof(infile)) do
+     begin
+        { handle comment }
+        readln(infile,s);
+        inc(line);
+        while (s[1]=' ') do
+         delete(s,1,1);
+        if (s='') or (s[1]=';') then
+          continue;
+
+        i:=1;
+        names[regcount]:=readstr;
+        readcomma;
+        regtypes[regcount]:=readstr;
+        readcomma;
+        supregs[regcount]:=readstr;
+        readcomma;
+        stdnames[regcount]:=readstr;
+        readcomma;
+        stabs[regcount]:=readstr;
+        readcomma;
+        dwarf[regcount]:=readstr;
+        { Create register number }
+        if supregs[regcount][1]<>'$' then
+          begin
+            writeln('Missing $ before number, at line ',line);
+            writeln('Line: "',s,'"');
+            halt(1);
+          end;
+        numbers[regcount]:=regtypes[regcount]+'0000'+copy(supregs[regcount],2,255);
+        if i<length(s) then
+          begin
+            writeln('Extra chars at end of line, at line ',line);
+            writeln('Line: "',s,'"');
+            halt(1);
+          end;
+        inc(regcount);
+        if regcount>max_regcount then
+          begin
+            writeln('Error: Too much registers, please increase maxregcount in source');
+            halt(2);
+          end;
+     end;
+   close(infile);
+end;
+
+procedure write_inc_files;
+
+var
+    norfile,stdfile,supfile,
+    numfile,stabfile,dwarffile,confile,
+    rnifile,srifile:text;
+    first:boolean;
+
+begin
+  { create inc files }
+  openinc(confile,'rz80con.inc');
+  openinc(supfile,'rz80sup.inc');
+  openinc(numfile,'rz80num.inc');
+  openinc(stdfile,'rz80std.inc');
+  openinc(stabfile,'rz80sta.inc');
+  openinc(dwarffile,'rz80dwa.inc');
+  openinc(norfile,'rz80nor.inc');
+  openinc(rnifile,'rz80rni.inc');
+  openinc(srifile,'rz80sri.inc');
+  first:=true;
+  for i:=0 to regcount-1 do
+    begin
+      if not first then
+        begin
+          writeln(numfile,',');
+          writeln(stdfile,',');
+          writeln(stabfile,',');
+          writeln(dwarffile,',');
+          writeln(rnifile,',');
+          writeln(srifile,',');
+        end
+      else
+        first:=false;
+      writeln(supfile,'RS_',names[i],' = ',supregs[i],';');
+      writeln(confile,'NR_'+names[i],' = ','tregister(',numbers[i],')',';');
+      write(numfile,'tregister(',numbers[i],')');
+      write(stdfile,'''',stdnames[i],'''');
+      write(stabfile,stabs[i]);
+      write(dwarffile,dwarf[i]);
+      write(rnifile,regnumber_index[i]);
+      write(srifile,std_regname_index[i]);
+    end;
+  write(norfile,regcount);
+  close(confile);
+  close(supfile);
+  closeinc(numfile);
+  closeinc(stdfile);
+  closeinc(stabfile);
+  closeinc(dwarffile);
+  closeinc(norfile);
+  closeinc(rnifile);
+  closeinc(srifile);
+  writeln('Done!');
+  writeln(regcount,' registers processed');
+end;
+
+
+begin
+   writeln('Register Table Converter Version ',Version);
+   line:=0;
+   regcount:=0;
+   read_spreg_file;
+   regcount_bsstart:=1;
+   while 2*regcount_bsstart<regcount do
+     regcount_bsstart:=regcount_bsstart*2;
+   build_regnum_index;
+   build_std_regname_index;
+   write_inc_files;
+end.

+ 305 - 0
compiler/z80/aasmcpu.pas

@@ -0,0 +1,305 @@
+{
+    Copyright (c) 1999-2008 by Mazen Neifer and Florian Klaempfl
+
+    Contains the assembler object for the AVR
+
+    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
+  cclasses,
+  globtype,globals,verbose,
+  aasmbase,aasmtai,aasmdata,aasmsym,
+  cgbase,cgutils,cpubase,cpuinfo,
+  ogbase;
+
+    const
+      { "mov reg,reg" source operand number }
+      O_MOV_SOURCE = 1;
+      { "mov reg,reg" source operand number }
+      O_MOV_DEST = 0;
+
+      maxinfolen = 5;
+
+    type
+      tinsentry = record
+        opcode  : tasmop;
+        ops     : byte;
+        optypes : array[0..3] of longint;
+        code    : array[0..maxinfolen] of char;
+        flags   : longint;
+      end;
+
+      pinsentry=^tinsentry;
+
+      taicpu = class(tai_cpu_abstract_sym)
+         constructor op_none(op : tasmop);
+
+         constructor op_reg(op : tasmop;_op1 : tregister);
+         constructor op_const(op : tasmop;_op1 : LongInt);
+         constructor op_ref(op : tasmop;const _op1 : treference);
+
+         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: LongInt);
+         constructor op_const_reg(op:tasmop; _op1: LongInt; _op2: tregister);
+         constructor op_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister);
+
+         { this is for Jmp instructions }
+         constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+         constructor op_sym(op : tasmop;_op1 : tasmsymbol);
+         constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
+         procedure loadbool(opidx:longint;_b:boolean);
+         { register allocation }
+         function is_same_reg_move(regtype: Tregistertype):boolean; override;
+
+         { register spilling code }
+         function spilling_get_operation_type(opnr: longint): 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
+
+{*****************************************************************************
+                                 taicpu Constructors
+*****************************************************************************}
+
+    procedure taicpu.loadbool(opidx:longint;_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_ref(op : tasmop;const _op1 : treference);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadref(0,_op1);
+      end;
+
+
+    constructor taicpu.op_const(op : tasmop;_op1 : LongInt);
+      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: LongInt);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadconst(1,aint(_op2));
+      end;
+
+     constructor taicpu.op_const_reg(op:tasmop; _op1: LongInt; _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_ref_reg(op : tasmop;const _op1 : treference;_op2 : tregister);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadref(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         is_jmp:=op in jmp_instructions;
+         condition:=cond;
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         is_jmp:=op in jmp_instructions;
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,_op1ofs);
+      end;
+
+
+    function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
+      begin
+        result:=(
+                 ((opcode in [A_LD]) and (regtype = R_INTREGISTER))
+                ) and
+                (ops=2) and
+                (oper[0]^.typ=top_reg) and
+                (oper[1]^.typ=top_reg) and
+                (oper[0]^.reg=oper[1]^.reg);
+      end;
+
+
+    function taicpu.spilling_get_operation_type(opnr: longint): topertype;
+      begin
+        result:=operand_read;
+        case opcode of
+          A_LD,
+          A_POP:
+            if opnr=0 then
+              result:=operand_write;
+          A_PUSH,
+          A_BIT,
+          A_DJNZ,
+          A_JR,
+          A_JP:
+            ;
+          A_SET:
+            if opnr=1 then
+              result:=operand_readwrite;
+          A_EX:
+            result:=operand_readwrite;
+          else
+            begin
+              if opnr=0 then
+                result:=operand_readwrite;
+            end;
+        end;
+      end;
+
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+      begin
+        internalerror(2017032602);
+        {
+        case getregtype(r) of
+          R_INTREGISTER :
+            if ref.offset<>0 then
+              result:=taicpu.op_reg_ref(A_LDD,r,ref)
+            else
+              result:=taicpu.op_reg_ref(A_LD,r,ref);
+          R_ADDRESSREGISTER :
+            if ref.offset<>0 then
+              result:=taicpu.op_reg_ref(A_LDD,r,ref)
+            else
+              result:=taicpu.op_reg_ref(A_LD,r,ref);
+          else
+            internalerror(200401041);
+        end;
+        }
+      end;
+
+
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+      begin
+        internalerror(2017032601);
+        {
+        case getregtype(r) of
+          R_INTREGISTER :
+            if ref.offset<>0 then
+              result:=taicpu.op_ref_reg(A_STD,ref,r)
+            else
+              result:=taicpu.op_ref_reg(A_ST,ref,r);
+          R_ADDRESSREGISTER :
+            if ref.offset<>0 then
+              result:=taicpu.op_ref_reg(A_STD,ref,r)
+            else
+              result:=taicpu.op_ref_reg(A_ST,ref,r);
+          else
+            internalerror(200401041);
+        end;
+        }
+      end;
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+begin
+  cai_cpu:=taicpu;
+  cai_align:=tai_align;
+end.

+ 192 - 0
compiler/z80/agz80asm.pas

@@ -0,0 +1,192 @@
+{
+    Copyright (c) 2003 by Florian Klaempfl
+
+    This unit implements an asm for the Z80
+
+    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 implements the GNU Assembler writer for the ARM
+}
+
+unit agz80asm;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,systems,
+       aasmtai,aasmdata,
+       assemble,
+       cpubase;
+
+    type
+      TZ80GNUAssembler=class(TExternalAssembler)
+        procedure WriteTree(p : TAsmList); override;
+        function MakeCmdLine: TCmdStr; override;
+      end;
+
+  implementation
+
+    uses
+       cutils,globals,verbose,
+       aasmbase,aasmcpu,
+       cpuinfo,
+       cgbase,cgutils;
+
+    Procedure TZ80GNUAssembler.WriteTree(p:TAsmList);
+
+      function getreferencestring(var ref : treference) : string;
+        var
+          s : string;
+        begin
+           s:='';
+           with ref do
+            begin
+  {$ifdef extdebug}
+              // if base=NR_NO then
+              //   internalerror(200308292);
+
+              // if ((index<>NR_NO) or (shiftmode<>SM_None)) and ((offset<>0) or (symbol<>nil)) then
+              //   internalerror(200308293);
+  {$endif extdebug}
+              if index<>NR_NO then
+                internalerror(2011021701)
+              else if base<>NR_NO then
+                begin
+//                  if addressmode=AM_PREDRECEMENT then
+//                    s:='-';
+
+                  //case base of
+                  //  NR_R26:
+                  //    s:=s+'X';
+                  //  NR_R28:
+                  //    s:=s+'Y';
+                  //  NR_R30:
+                  //    s:=s+'Z';
+                  //  else
+                  //    s:=gas_regname(base);
+                  //end;
+                  //if addressmode=AM_POSTINCREMENT then
+                  //  s:=s+'+';
+                  //
+                  //if offset>0 then
+                  //  s:=s+'+'+tostr(offset)
+                  //else if offset<0 then
+                  //  s:=s+tostr(offset)
+                end
+              else if assigned(symbol) or (offset<>0) then
+                begin
+                  //if assigned(symbol) then
+                  //  s:=ReplaceForbiddenAsmSymbolChars(symbol.name);
+                  //
+                  //if offset<0 then
+                  //  s:=s+tostr(offset)
+                  //else if offset>0 then
+                  //  s:=s+'+'+tostr(offset);
+                  //case refaddr of
+                  //  addr_hi8:
+                  //    s:='hi8('+s+')';
+                  //  addr_hi8_gs:
+                  //    s:='hi8(gs('+s+'))';
+                  //  addr_lo8:
+                  //    s:='lo8('+s+')';
+                  //  addr_lo8_gs:
+                  //    s:='lo8(gs('+s+'))';
+                  //  else
+                  //    s:='('+s+')';
+                  //end;
+                end;
+            end;
+          getreferencestring:=s;
+        end;
+
+
+      function getopstr(const o:toper) : string;
+        var
+          hs : string;
+          first : boolean;
+          r : tsuperregister;
+        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:=ReplaceForbiddenAsmSymbolChars(o.ref^.symbol.name);
+          //        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(o.ref^);
+          //  else
+          //    internalerror(2002070604);
+          //end;
+        end;
+
+    var op: TAsmOp;
+        s: string;
+        i: byte;
+        sep: string[3];
+    begin
+      //op:=taicpu(hp).opcode;
+      //s:=#9+gas_op2str[op]+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(taicpu(hp).oper[i]^);
+      //        sep:=',';
+      //      end;
+      //  end;
+      //owner.writer.AsmWriteLn(s);
+    end;
+
+
+    function TZ80GNUAssembler.MakeCmdLine: TCmdStr;
+      begin
+        result := '-mmcu='+lower(cputypestr[current_settings.cputype])+' '+inherited MakeCmdLine;
+      end;
+
+
+    const
+       as_Z80_asm_info : tasminfo =
+          (
+            id     : as_z80asm;
+
+            idtxt  : 'Z80Asm';
+            asmbin : 'z80asm';
+            asmcmd : '-o $OBJ $EXTRAOPT $ASM';
+            supported_targets : [system_Z80_embedded];
+            flags : [af_needar,af_smartlink_sections];
+            labelprefix : '.L';
+            comment : '# ';
+            dollarsign: 's';
+          );
+
+
+begin
+  RegisterAssembler(as_Z80_asm_info,TZ80GNUAssembler);
+end.

+ 242 - 0
compiler/z80/aoptcpu.pas

@@ -0,0 +1,242 @@
+{
+    Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
+    Development Team
+
+    This unit implements the Z80 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;
+
+{$i fpcdefs.inc}
+
+{$define DEBUG_AOPTCPU}
+
+Interface
+
+uses cpubase, cgbase, aasmtai, aopt,AoptObj, aoptcpub;
+
+Type
+  TCpuAsmOptimizer = class(TAsmOptimizer)
+    { outputs a debug message into the assembler file }
+    procedure DebugMsg(const s: string; p: tai);
+
+    Function GetNextInstructionUsingReg(Current: tai; Var Next: tai;reg : TRegister): Boolean;
+    function RegLoadedWithNewValue(reg : tregister; hp : tai) : boolean; override;
+    function InstructionLoadsFromReg(const reg : TRegister; const hp : tai) : boolean; override;
+
+    { uses the same constructor as TAopObj }
+    function PeepHoleOptPass1Cpu(var p: tai): boolean; override;
+    procedure PeepHoleOptPass2;override;
+  End;
+
+Implementation
+
+  uses
+    cutils,
+    verbose,
+    cpuinfo,
+    aasmbase,aasmcpu,aasmdata,
+    globals,globtype,
+    cgutils;
+
+  type
+    TAsmOpSet = set of TAsmOp;
+
+  function CanBeCond(p : tai) : boolean;
+    begin
+      result:=(p.typ=ait_instruction) and (taicpu(p).condition=C_None);
+    end;
+
+
+  function RefsEqual(const r1, r2: treference): boolean;
+    begin
+      refsequal :=
+        (r1.offset = r2.offset) and
+        (r1.base = r2.base) and
+        (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
+        (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
+        (r1.relsymbol = r2.relsymbol);
+    end;
+
+
+  function MatchOperand(const oper1: TOper; const oper2: TOper): boolean; inline;
+    begin
+      result:=oper1.typ=oper2.typ;
+
+      if result then
+        case oper1.typ of
+          top_const:
+            Result:=oper1.val = oper2.val;
+          top_reg:
+            Result:=oper1.reg = oper2.reg;
+          top_ref:
+            Result:=RefsEqual(oper1.ref^, oper2.ref^);
+          else Result:=false;
+        end
+    end;
+
+
+  function MatchOperand(const oper: TOper; const reg: TRegister): boolean; inline;
+    begin
+      result := (oper.typ = top_reg) and (oper.reg = reg);
+    end;
+
+
+  function MatchInstruction(const instr: tai; const op: TAsmOp): boolean;
+    begin
+      result :=
+        (instr.typ = ait_instruction) and
+        (taicpu(instr).opcode = op);
+    end;
+
+
+  function MatchInstruction(const instr: tai; const ops: TAsmOpSet): boolean;
+    begin
+      result :=
+        (instr.typ = ait_instruction) and
+        (taicpu(instr).opcode in ops);
+    end;
+
+
+  function MatchInstruction(const instr: tai; const ops: TAsmOpSet;opcount : byte): boolean;
+    begin
+      result :=
+        (instr.typ = ait_instruction) and
+        (taicpu(instr).opcode in ops) and
+        (taicpu(instr).ops=opcount);
+    end;
+
+
+  function MatchOpType(const instr : tai;ot0,ot1 : toptype) : Boolean;
+    begin
+      Result:=(taicpu(instr).ops=2) and
+        (taicpu(instr).oper[0]^.typ=ot0) and
+        (taicpu(instr).oper[1]^.typ=ot1);
+    end;
+
+{$ifdef DEBUG_AOPTCPU}
+  procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);
+    begin
+      asml.insertbefore(tai_comment.Create(strpnew(s)), p);
+    end;
+{$else DEBUG_AOPTCPU}
+  procedure TCpuAsmOptimizer.DebugMsg(const s: string;p : tai);inline;
+    begin
+    end;
+{$endif DEBUG_AOPTCPU}
+
+
+  function TCpuAsmOptimizer.GetNextInstructionUsingReg(Current: tai;
+    var Next: tai; reg: TRegister): Boolean;
+    begin
+      Next:=Current;
+      repeat
+        Result:=GetNextInstruction(Next,Next);
+      until not(cs_opt_level3 in current_settings.optimizerswitches) or not(Result) or (Next.typ<>ait_instruction) or (RegInInstruction(reg,Next)) or
+        (is_calljmp(taicpu(Next).opcode));
+    end;
+
+
+  function TCpuAsmOptimizer.RegLoadedWithNewValue(reg: tregister; hp: tai): boolean;
+    var
+      p: taicpu;
+    begin
+      if not assigned(hp) or
+         (hp.typ <> ait_instruction) then
+       begin
+         Result := false;
+         exit;
+       end;
+      internalerror(2017032606);
+      //p := taicpu(hp);
+      //Result := ((p.opcode in [A_LDI,A_MOV,A_LDS]) and (reg=p.oper[0]^.reg) and ((p.oper[1]^.typ<>top_reg) or (reg<>p.oper[0]^.reg))) or
+      //  ((p.opcode in [A_LD,A_LDD,A_LPM]) and (reg=p.oper[0]^.reg) and not(RegInRef(reg,p.oper[1]^.ref^))) or
+      //  ((p.opcode in [A_MOVW]) and ((reg=p.oper[0]^.reg) or (TRegister(ord(reg)+1)=p.oper[0]^.reg)) and not(reg=p.oper[1]^.reg) and not(TRegister(ord(reg)+1)=p.oper[1]^.reg)) or
+      //  ((p.opcode in [A_POP]) and (reg=p.oper[0]^.reg));
+    end;
+
+
+  function TCpuAsmOptimizer.InstructionLoadsFromReg(const reg: TRegister; const hp: tai): boolean;
+    var
+      p: taicpu;
+      i: longint;
+    begin
+      Result := false;
+
+      internalerror(2017032607);
+
+      //if not (assigned(hp) and (hp.typ = ait_instruction)) then
+      //  exit;
+      //p:=taicpu(hp);
+      //
+      //i:=0;
+      //
+      //{ we do not care about the stack pointer }
+      //if p.opcode in [A_POP] then
+      //  exit;
+      //
+      //{ first operand only written?
+      //  then skip it }
+      //if p.opcode in [A_MOV,A_LD,A_LDD,A_LDS,A_LPM,A_LDI,A_MOVW] then
+      //  i:=1;
+      //
+      //while(i<p.ops) do
+      //  begin
+      //    case p.oper[I]^.typ of
+      //      top_reg:
+      //        Result := (p.oper[I]^.reg = reg) or
+      //          { MOVW }
+      //          ((i=1) and (p.opcode=A_MOVW) and (getsupreg(p.oper[0]^.reg)+1=getsupreg(reg)));
+      //      top_ref:
+      //        Result :=
+      //          (p.oper[I]^.ref^.base = reg) or
+      //          (p.oper[I]^.ref^.index = reg);
+      //    end;
+      //    { Bailout if we found something }
+      //    if Result then
+      //      exit;
+      //    Inc(I);
+      //  end;
+    end;
+
+  function TCpuAsmOptimizer.PeepHoleOptPass1Cpu(var p: tai): boolean;
+    var
+      hp1,hp2,hp3,hp4,hp5: tai;
+      alloc, dealloc: tai_regalloc;
+      i: integer;
+      l: TAsmLabel;
+      TmpUsedRegs : TAllUsedRegs;
+    begin
+      result := false;
+      case p.typ of
+        ait_instruction:
+          begin
+          end;
+      end;
+    end;
+
+
+  procedure TCpuAsmOptimizer.PeepHoleOptPass2;
+    begin
+    end;
+
+begin
+  casmoptimizer:=TCpuAsmOptimizer;
+End.

+ 132 - 0
compiler/z80/aoptcpub.pas

@@ -0,0 +1,132 @@
+ {
+    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 Z80 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
+  cpubase,
+  cgbase,
+  aasmcpu,aasmtai,
+  AOptBase;
+
+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)
+    function RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; override;
+  End;
+
+
+{ ************************************************************************* }
+{ ******************************* Constants ******************************* }
+{ ************************************************************************* }
+Const
+
+{ the maximum number of things (registers, memory, ...) a single instruction }
+{ changes                                                                    }
+
+  MaxCh = 2;
+
+{ the maximum number of operands an instruction has }
+
+  MaxOps = 2;
+
+{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 = 1;
+
+{Oper index of operand that contains the destination (reference) with a load }
+{instruction                                                                 }
+
+  StoreDst = 0;
+
+  aopt_uncondjmp = A_JP;
+  aopt_condjmp = A_JP;
+
+Implementation
+
+{ ************************************************************************* }
+{ **************************** TCondRegs ********************************** }
+{ ************************************************************************* }
+  Constructor TCondRegs.init;
+    Begin
+    End;
+
+  Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
+    Begin
+    End;
+
+
+  function TAoptBaseCpu.RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean;
+    var
+      i : Longint;
+    begin
+      result:=false;
+      for i:=0 to taicpu(p1).ops-1 do
+        if (taicpu(p1).oper[i]^.typ=top_reg) and (taicpu(p1).oper[i]^.reg=Reg) and (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then
+          begin
+            result:=true;
+            exit;
+          end;
+    end;
+
+End.

+ 40 - 0
compiler/z80/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.

+ 2198 - 0
compiler/z80/cgcpu.pas

@@ -0,0 +1,2198 @@
+{
+
+    Copyright (c) 2008 by Florian Klaempfl
+    Member of the Free Pascal development team
+
+    This unit implements the code generator for the Z80
+
+    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,cgutils,cgobj,
+       aasmbase,aasmcpu,aasmtai,aasmdata,
+       parabase,
+       cpubase,cpuinfo,node,cg64f32,rgcpu;
+
+    type
+      tcgz80 = class(tcg)
+        { true, if the next arithmetic operation should modify the flags }
+        cgsetflags : boolean;
+        procedure init_register_allocators;override;
+        procedure done_register_allocators;override;
+
+        function getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
+        function getaddressregister(list:TAsmList):TRegister;override;
+
+        procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
+        procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
+        procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
+        procedure a_load_reg_cgpara(list : TAsmList; size : tcgsize;r : tregister; const cgpara : tcgpara);override;
+
+        procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
+        procedure a_call_reg(list : TAsmList;reg: 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;
+
+        { move instructions }
+        procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);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_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);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;
+
+        {  comparison operations }
+        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 a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
+
+        procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: 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 a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
+
+        procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
+        procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
+
+        procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
+
+        procedure g_save_registers(list : TAsmList);override;
+        procedure g_restore_registers(list : TAsmList);override;
+
+        procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
+        procedure fixref(list : TAsmList;var ref : treference);
+        function normalize_ref(list : TAsmList;ref : treference;
+          tmpreg : tregister) : treference;
+
+        procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
+
+        procedure a_adjust_sp(list: TAsmList; value: longint);
+        function GetLoad(const ref : treference) : tasmop;
+        function GetStore(const ref: treference): tasmop;
+
+      protected
+        procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
+        procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister);
+        procedure maybegetcpuregister(list : tasmlist; reg : tregister);
+      end;
+
+      tcg64favr = 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;
+      end;
+
+    procedure create_codegen;
+
+    const
+      TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_LD,A_ADD,A_AND,A_NONE,
+                            A_NONE,A_NONE,A_NONE,A_NEG,A_CPL,A_OR,
+                            A_SRA,A_SLA,A_SRL,A_SUB,A_XOR,A_RLCA,A_RRCA);
+  implementation
+
+    uses
+       globals,verbose,systems,cutils,
+       fmodule,
+       symconst,symsym,symtable,
+       tgobj,rgobj,
+       procinfo,cpupi,
+       paramgr;
+
+
+    procedure tcgz80.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+        rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+            [RS_R18,RS_R19,RS_R20,RS_R21,RS_R22,RS_R23,RS_R24,RS_R25,
+             RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
+             RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17],first_int_imreg,[]);
+      end;
+
+
+    procedure tcgz80.done_register_allocators;
+      begin
+        rg[R_INTREGISTER].free;
+        // rg[R_ADDRESSREGISTER].free;
+        inherited done_register_allocators;
+      end;
+
+
+    function tcgz80.getintregister(list: TAsmList; size: Tcgsize): Tregister;
+      var
+        tmp1,tmp2,tmp3 : TRegister;
+      begin
+        case size of
+          OS_8,OS_S8:
+            Result:=inherited getintregister(list, size);
+          OS_16,OS_S16:
+            begin
+              Result:=inherited getintregister(list, OS_8);
+              { ensure that the high register can be retrieved by
+                GetNextReg
+              }
+              if inherited getintregister(list, OS_8)<>GetNextReg(Result) then
+                internalerror(2011021331);
+            end;
+          OS_32,OS_S32:
+            begin
+              Result:=inherited getintregister(list, OS_8);
+              tmp1:=inherited getintregister(list, OS_8);
+              { ensure that the high register can be retrieved by
+                GetNextReg
+              }
+              if tmp1<>GetNextReg(Result) then
+                internalerror(2011021332);
+              tmp2:=inherited getintregister(list, OS_8);
+              { ensure that the upper register can be retrieved by
+                GetNextReg
+              }
+              if tmp2<>GetNextReg(tmp1) then
+                internalerror(2011021333);
+              tmp3:=inherited getintregister(list, OS_8);
+              { ensure that the upper register can be retrieved by
+                GetNextReg
+              }
+              if tmp3<>GetNextReg(tmp2) then
+                internalerror(2011021334);
+            end;
+          else
+            internalerror(2011021330);
+        end;
+      end;
+
+
+    function tcgz80.getaddressregister(list: TAsmList): TRegister;
+      begin
+       Result:=getintregister(list,OS_ADDR);
+      end;
+
+
+    procedure tcgz80.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
+
+      procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
+        var
+          ref : treference;
+        begin
+          paramanager.allocparaloc(list,paraloc);
+          case paraloc^.loc of
+             LOC_REGISTER,LOC_CREGISTER:
+               a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
+             LOC_REFERENCE,LOC_CREFERENCE:
+               begin
+                  reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,2,[]);
+                  a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
+               end;
+             else
+               internalerror(2002071004);
+          end;
+        end;
+
+      var
+        i, i2 : longint;
+        hp : PCGParaLocation;
+
+      begin
+{        if use_push(cgpara) then
+          begin
+            if tcgsize2size[cgpara.Size] > 2 then
+              begin
+                if tcgsize2size[cgpara.Size] <> 4 then
+                  internalerror(2013031101);
+                if cgpara.location^.Next = nil then
+                  begin
+                    if tcgsize2size[cgpara.location^.size] <> 4 then
+                      internalerror(2013031101);
+                  end
+                else
+                  begin
+                    if tcgsize2size[cgpara.location^.size] <> 2 then
+                      internalerror(2013031101);
+                    if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
+                      internalerror(2013031101);
+                    if cgpara.location^.Next^.Next <> nil then
+                      internalerror(2013031101);
+                  end;
+
+                if tcgsize2size[cgpara.size]>cgpara.alignment then
+                  pushsize:=cgpara.size
+                else
+                  pushsize:=int_cgsize(cgpara.alignment);
+                pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
+                list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
+                list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
+              end
+            else
+              begin
+                cgpara.check_simple_location;
+                if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
+                  pushsize:=cgpara.location^.size
+                else
+                  pushsize:=int_cgsize(cgpara.alignment);
+                list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
+              end;
+
+          end
+        else }
+          begin
+            if not(tcgsize2size[cgpara.Size] in [1..4]) then
+              internalerror(2014011101);
+
+            hp:=cgpara.location;
+
+            i:=0;
+            while i<tcgsize2size[cgpara.Size] do
+              begin
+                if not(assigned(hp)) then
+                  internalerror(2014011102);
+
+                inc(i, tcgsize2size[hp^.Size]);
+
+                if hp^.Loc=LOC_REGISTER then
+                  begin
+                    load_para_loc(r,hp);
+                    hp:=hp^.Next;
+                    r:=GetNextReg(r);
+                  end
+                else
+                  begin
+                    load_para_loc(r,hp);
+
+                    for i2:=1 to tcgsize2size[hp^.Size] do
+                      r:=GetNextReg(r);
+
+                    hp:=hp^.Next;
+                  end;
+              end;
+            if assigned(hp) then
+              internalerror(2014011103);
+          end;
+      end;
+
+
+    procedure tcgz80.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
+      var
+        i : longint;
+        hp : PCGParaLocation;
+        ref: treference;
+      begin
+        if not(tcgsize2size[paraloc.Size] in [1..4]) then
+          internalerror(2014011101);
+
+        hp:=paraloc.location;
+
+        i:=1;
+        while i<=tcgsize2size[paraloc.Size] do
+          begin
+            if not(assigned(hp)) then
+              internalerror(2014011105);
+             //paramanager.allocparaloc(list,hp);
+             case hp^.loc of
+               LOC_REGISTER,LOC_CREGISTER:
+                 begin
+                   if (tcgsize2size[hp^.size]<>1) or
+                     (hp^.shiftval<>0) then
+                     internalerror(2015041101);
+                   a_load_const_reg(list,hp^.size,(a shr (8*(i-1))) and $ff,hp^.register);
+
+                   inc(i,tcgsize2size[hp^.size]);
+                   hp:=hp^.Next;
+                 end;
+               LOC_REFERENCE,LOC_CREFERENCE:
+                 begin
+                   reference_reset(ref,paraloc.alignment,[]);
+                   ref.base:=hp^.reference.index;
+                   ref.offset:=hp^.reference.offset;
+                   a_load_const_ref(list,hp^.size,a shr (8*(i-1)),ref);
+
+                   inc(i,tcgsize2size[hp^.size]);
+                   hp:=hp^.Next;
+                 end;
+               else
+                 internalerror(2002071004);
+            end;
+          end;
+      end;
+
+
+    procedure tcgz80.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
+      var
+        tmpref, ref: treference;
+        location: pcgparalocation;
+        sizeleft: tcgint;
+      begin
+        location := paraloc.location;
+        tmpref := r;
+        sizeleft := paraloc.intsize;
+        while assigned(location) do
+          begin
+            paramanager.allocparaloc(list,location);
+            case location^.loc of
+              LOC_REGISTER,LOC_CREGISTER:
+                a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
+              LOC_REFERENCE:
+                begin
+                  reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment,[]);
+                  { doubles in softemu mode have a strange order of registers and references }
+                  if location^.size=OS_32 then
+                    g_concatcopy(list,tmpref,ref,4)
+                  else
+                    begin
+                      g_concatcopy(list,tmpref,ref,sizeleft);
+                      if assigned(location^.next) then
+                        internalerror(2005010710);
+                    end;
+                end;
+              LOC_VOID:
+                begin
+                  // nothing to do
+                end;
+              else
+                internalerror(2002081103);
+            end;
+            inc(tmpref.offset,tcgsize2size[location^.size]);
+            dec(sizeleft,tcgsize2size[location^.size]);
+            location := location^.next;
+          end;
+      end;
+
+
+    procedure tcgz80.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
+      var
+        tmpreg: tregister;
+      begin
+        tmpreg:=getaddressregister(list);
+        a_loadaddr_ref_reg(list,r,tmpreg);
+        a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc);
+      end;
+
+
+    procedure tcgz80.a_call_name(list : TAsmList;const s : string; weak: boolean);
+      var
+        sym: TAsmSymbol;
+      begin
+        if weak then
+          sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)
+        else
+          sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
+
+        list.concat(taicpu.op_sym(A_CALL,sym));
+
+        include(current_procinfo.flags,pi_do_call);
+      end;
+
+
+    procedure tcgz80.a_call_reg(list : TAsmList;reg: tregister);
+      var
+        l : TAsmLabel;
+        ref : treference;
+      begin
+        current_asmdata.getjumplabel(l);
+        reference_reset(ref,0,[]);
+        ref.symbol:=l;
+        list.concat(taicpu.op_ref_reg(A_LD,ref,reg));
+        list.concat(tai_const.Create_8bit($CD));
+        list.concat(tai_label.Create(l));
+        include(current_procinfo.flags,pi_do_call);
+      end;
+
+
+     procedure tcgz80.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
+       begin
+         if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
+           internalerror(2012102403);
+         a_op_const_reg_internal(list,Op,size,a,reg,NR_NO);
+       end;
+
+
+     procedure tcgz80.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister);
+       begin
+         if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
+           internalerror(2012102401);
+         a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO);
+       end;
+
+
+     procedure tcgz80.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
+       var
+         countreg,
+         tmpreg: tregister;
+         i : integer;
+         instr : taicpu;
+         paraloc1,paraloc2,paraloc3 : TCGPara;
+         l1,l2 : tasmlabel;
+         pd : tprocdef;
+
+       procedure NextSrcDst;
+         begin
+           if i=5 then
+             begin
+               dst:=dsthi;
+               src:=srchi;
+             end
+           else
+             begin
+               dst:=GetNextReg(dst);
+               src:=GetNextReg(src);
+             end;
+         end;
+
+       { iterates TmpReg through all registers of dst }
+       procedure NextTmp;
+         begin
+           if i=5 then
+             tmpreg:=dsthi
+           else
+             tmpreg:=GetNextReg(tmpreg);
+         end;
+
+      begin
+         case op of
+           OP_ADD:
+             begin
+               list.concat(taicpu.op_reg_reg(A_ADD,dst,src));
+               if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                 begin
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       NextSrcDst;
+                       list.concat(taicpu.op_reg_reg(A_ADC,dst,src));
+                     end;
+                 end;
+             end;
+
+           OP_SUB:
+             begin
+               list.concat(taicpu.op_reg_reg(A_SUB,dst,src));
+               if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                 begin
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       NextSrcDst;
+                       list.concat(taicpu.op_reg_reg(A_SBC,dst,src));
+                     end;
+                 end;
+             end;
+
+           OP_NEG:
+             begin
+               if src<>dst then
+                 begin
+                   if size in [OS_S64,OS_64] then
+                     begin
+                       a_load_reg_reg(list,OS_32,OS_32,src,dst);
+                       a_load_reg_reg(list,OS_32,OS_32,srchi,dsthi);
+                     end
+                   else
+                     a_load_reg_reg(list,size,size,src,dst);
+                 end;
+
+               if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                 begin
+                   tmpreg:=GetNextReg(dst);
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       list.concat(taicpu.op_reg(A_CPL,tmpreg));
+                       NextTmp;
+                     end;
+                   list.concat(taicpu.op_reg(A_NEG,dst));
+                   tmpreg:=GetNextReg(dst);
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       list.concat(taicpu.op_reg_const(A_SBC,tmpreg,-1));
+                       NextTmp;
+                   end;
+                 end;
+             end;
+
+           OP_NOT:
+             begin
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   if src<>dst then
+                     a_load_reg_reg(list,OS_8,OS_8,src,dst);
+                   list.concat(taicpu.op_reg(A_CPL,dst));
+                   NextSrcDst;
+                 end;
+             end;
+
+           OP_MUL,OP_IMUL:
+             { special stuff, needs separate handling inside code
+               generator                                          }
+             internalerror(2017032604);
+
+           OP_DIV,OP_IDIV:
+             { special stuff, needs separate handling inside code
+               generator                                          }
+             internalerror(2017032604);
+
+           OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
+             begin
+               //current_asmdata.getjumplabel(l1);
+               //current_asmdata.getjumplabel(l2);
+               //countreg:=getintregister(list,OS_8);
+               //a_load_reg_reg(list,size,OS_8,src,countreg);
+               //list.concat(taicpu.op_reg(A_TST,countreg));
+               //a_jmp_flags(list,F_EQ,l2);
+               //cg.a_label(list,l1);
+               //case op of
+               //  OP_SHR:
+               //    list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+               //  OP_SHL:
+               //    list.concat(taicpu.op_reg(A_LSL,dst));
+               //  OP_SAR:
+               //    list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+               //  OP_ROR:
+               //    begin
+               //      { load carry? }
+               //      if not(size in [OS_8,OS_S8]) then
+               //        begin
+               //          list.concat(taicpu.op_none(A_CLC));
+               //          list.concat(taicpu.op_reg_const(A_SBRC,src,0));
+               //          list.concat(taicpu.op_none(A_SEC));
+               //        end;
+               //      list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+               //    end;
+               //  OP_ROL:
+               //    begin
+               //      { load carry? }
+               //      if not(size in [OS_8,OS_S8]) then
+               //        begin
+               //          list.concat(taicpu.op_none(A_CLC));
+               //          list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1),7));
+               //          list.concat(taicpu.op_none(A_SEC));
+               //        end;
+               //      list.concat(taicpu.op_reg(A_ROL,dst))
+               //    end;
+               //  else
+               //    internalerror(2011030901);
+               //end;
+               //if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+               //  begin
+               //    for i:=2 to tcgsize2size[size] do
+               //      begin
+               //        case op of
+               //          OP_ROR,
+               //          OP_SHR:
+               //            list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
+               //          OP_ROL,
+               //          OP_SHL:
+               //            list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(dst,dsthi,i-1)));
+               //          OP_SAR:
+               //            list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
+               //          else
+               //            internalerror(2011030902);
+               //        end;
+               //    end;
+               //  end;
+               //
+               //list.concat(taicpu.op_reg(A_DEC,countreg));
+               //a_jmp_flags(list,F_NE,l1);
+               //// keep registers alive
+               //list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
+               //cg.a_label(list,l2);
+             end;
+
+           OP_AND,OP_OR,OP_XOR:
+             begin
+                for i:=1 to tcgsize2size[size] do
+                  begin
+                    list.concat(taicpu.op_reg_reg(topcg2asmop[op],dst,src));
+                    NextSrcDst;
+                  end;
+             end;
+           else
+             internalerror(2011022004);
+         end;
+       end;
+
+     procedure tcgz80.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
+      size: TCGSize; a: tcgint; reg, reghi: TRegister);
+
+       var
+         mask : qword;
+         shift : byte;
+         i,j : byte;
+         tmpreg : tregister;
+         tmpreg64 : tregister64;
+
+      procedure NextReg;
+        begin
+          if i=5 then
+            reg:=reghi
+          else
+            reg:=GetNextReg(reg);
+        end;
+
+      var
+        curvalue : byte;
+
+       begin
+         optimize_op_const(size,op,a);
+         mask:=$ff;
+         shift:=0;
+         case op of
+           OP_NONE:
+             begin
+               { Opcode is optimized away }
+             end;
+           OP_MOVE:
+             begin
+               { Optimized, replaced with a simple load }
+               a_load_const_reg(list,size,a,reg);
+             end;
+           OP_OR:
+             begin
+               //for i:=1 to tcgsize2size[size] do
+               //  begin
+               //    if ((qword(a) and mask) shr shift)<>0 then
+               //      list.concat(taicpu.op_reg_const(A_ORI,reg,(qword(a) and mask) shr shift));
+               //    NextReg;
+               //    mask:=mask shl 8;
+               //    inc(shift,8);
+               //  end;
+             end;
+           OP_AND:
+             begin
+               //for i:=1 to tcgsize2size[size] do
+               //  begin
+               //    if ((qword(a) and mask) shr shift)=0 then
+               //      list.concat(taicpu.op_reg_reg(A_MOV,reg,NR_R1))
+               //    else
+               //      list.concat(taicpu.op_reg_const(A_ANDI,reg,(qword(a) and mask) shr shift));
+               //    NextReg;
+               //    mask:=mask shl 8;
+               //    inc(shift,8);
+               //  end;
+             end;
+           OP_SUB:
+             begin
+               //if ((a and mask)=1) and (tcgsize2size[size]=1) then
+               //  list.concat(taicpu.op_reg(A_DEC,reg))
+               //else
+               //  list.concat(taicpu.op_reg_const(A_SUBI,reg,a and mask));
+               //if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+               //  begin
+               //    for i:=2 to tcgsize2size[size] do
+               //      begin
+               //        NextReg;
+               //        mask:=mask shl 8;
+               //        inc(shift,8);
+               //        curvalue:=(qword(a) and mask) shr shift;
+               //        { decrease pressure on upper half of registers by using SBC ...,R1 instead
+               //          of SBCI ...,0 }
+               //        if curvalue=0 then
+               //          list.concat(taicpu.op_reg_reg(A_SBC,reg,NR_R1))
+               //        else
+               //          list.concat(taicpu.op_reg_const(A_SBCI,reg,curvalue));
+               //      end;
+               //  end;
+             end;
+           OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
+             begin
+               //if a*tcgsize2size[size]<=8 then
+               //  begin
+               //    for j:=1 to a do
+               //      begin
+               //        case op of
+               //          OP_SHR:
+               //            list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+               //          OP_SHL:
+               //            list.concat(taicpu.op_reg(A_LSL,reg));
+               //          OP_SAR:
+               //            list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+               //          OP_ROR:
+               //            begin
+               //              { load carry? }
+               //              if not(size in [OS_8,OS_S8]) then
+               //                begin
+               //                  list.concat(taicpu.op_none(A_CLC));
+               //                  list.concat(taicpu.op_reg_const(A_SBRC,reg,0));
+               //                  list.concat(taicpu.op_none(A_SEC));
+               //                end;
+               //              list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+               //            end;
+               //          OP_ROL:
+               //            begin
+               //              { load carry? }
+               //              if not(size in [OS_8,OS_S8]) then
+               //                begin
+               //                  list.concat(taicpu.op_none(A_CLC));
+               //                  list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1),7));
+               //                  list.concat(taicpu.op_none(A_SEC));
+               //                end;
+               //              list.concat(taicpu.op_reg(A_ROL,reg))
+               //            end;
+               //          else
+               //            internalerror(2011030901);
+               //        end;
+               //        if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+               //          begin
+               //            for i:=2 to tcgsize2size[size] do
+               //              begin
+               //                case op of
+               //                  OP_ROR,
+               //                  OP_SHR:
+               //                    list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
+               //                  OP_ROL,
+               //                  OP_SHL:
+               //                    list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(reg,reghi,i-1)));
+               //                  OP_SAR:
+               //                    list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
+               //                  else
+               //                    internalerror(2011030902);
+               //                end;
+               //            end;
+               //          end;
+               //    end;
+               //  end
+               //else
+               //  begin
+               //    tmpreg:=getintregister(list,size);
+               //    a_load_const_reg(list,size,a,tmpreg);
+               //    a_op_reg_reg(list,op,size,tmpreg,reg);
+               //  end;
+             end;
+           OP_ADD:
+             begin
+               curvalue:=a and mask;
+               if curvalue=0 then
+                 list.concat(taicpu.op_reg_reg(A_ADD,reg,NR_R1))
+               else if (curvalue=1) and (tcgsize2size[size]=1) then
+                 list.concat(taicpu.op_reg(A_INC,reg))
+               else
+                 begin
+                   tmpreg:=getintregister(list,OS_8);
+                   a_load_const_reg(list,OS_8,curvalue,tmpreg);
+                   list.concat(taicpu.op_reg_reg(A_ADD,reg,tmpreg));
+                 end;
+               if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                 begin
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       NextReg;
+                       mask:=mask shl 8;
+                       inc(shift,8);
+                       curvalue:=(qword(a) and mask) shr shift;
+                       { decrease pressure on upper half of registers by using ADC ...,R1 instead
+                         of ADD ...,0 }
+                       if curvalue=0 then
+                         list.concat(taicpu.op_reg_reg(A_ADC,reg,NR_R1))
+                       else
+                         begin
+                           tmpreg:=getintregister(list,OS_8);
+                           a_load_const_reg(list,OS_8,curvalue,tmpreg);
+                           list.concat(taicpu.op_reg_reg(A_ADC,reg,tmpreg));
+                         end;
+                     end;
+                 end;
+             end;
+         else
+           begin
+             if size in [OS_64,OS_S64] then
+               begin
+                 tmpreg64.reglo:=getintregister(list,OS_32);
+                 tmpreg64.reghi:=getintregister(list,OS_32);
+                 cg64.a_load64_const_reg(list,a,tmpreg64);
+                 cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
+               end
+             else
+               begin
+{$if 0}
+                 { code not working yet }
+                 if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
+                   begin
+                     tmpreg:=reg;
+                     for i:=1 to 4 do
+                       begin
+                         list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
+                         tmpreg:=GetNextReg(tmpreg);
+                       end;
+                   end
+                 else
+{$endif}
+                   begin
+                     tmpreg:=getintregister(list,size);
+                     a_load_const_reg(list,size,a,tmpreg);
+                     a_op_reg_reg(list,op,size,tmpreg,reg);
+                   end;
+               end;
+           end;
+       end;
+     end;
+
+
+     procedure tcgz80.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
+       var
+         mask : qword;
+         shift : byte;
+         i : byte;
+       begin
+         mask:=$ff;
+         shift:=0;
+         for i:=1 to tcgsize2size[size] do
+           begin
+             if ((qword(a) and mask) shr shift)=0 then
+               emit_mov(list,reg,NR_R1)
+             else
+               begin
+                 getcpuregister(list,NR_R26);
+                 list.concat(taicpu.op_reg_const(A_LDI,NR_R26,(qword(a) and mask) shr shift));
+                 a_load_reg_reg(list,OS_8,OS_8,NR_R26,reg);
+                 ungetcpuregister(list,NR_R26);
+               end;
+
+             mask:=mask shl 8;
+             inc(shift,8);
+             reg:=GetNextReg(reg);
+           end;
+       end;
+
+
+    procedure tcgz80.maybegetcpuregister(list:tasmlist;reg : tregister);
+      begin
+        { allocate the register only, if a cpu register is passed }
+        if getsupreg(reg)<first_int_imreg then
+          getcpuregister(list,reg);
+      end;
+
+
+    function tcgz80.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
+
+      var
+        tmpref : treference;
+        l : tasmlabel;
+      begin
+        Result:=ref;
+//
+//         if ref.addressmode<>AM_UNCHANGED then
+//           internalerror(2011021701);
+//
+//        { Be sure to have a base register }
+//        if (ref.base=NR_NO) then
+//          begin
+//            { only symbol+offset? }
+//            if ref.index=NR_NO then
+//              exit;
+//            ref.base:=ref.index;
+//            ref.index:=NR_NO;
+//          end;
+//
+//        { can we take advantage of adiw/sbiw? }
+//        if (current_settings.cputype>=cpu_avr2) and not(assigned(ref.symbol)) and (ref.offset<>0) and (ref.offset>=-63) and (ref.offset<=63) and
+//          ((tmpreg=NR_R24) or (tmpreg=NR_R26) or (tmpreg=NR_R28) or (tmpreg=NR_R30)) and (ref.base<>NR_NO) then
+//          begin
+//            maybegetcpuregister(list,tmpreg);
+//            emit_mov(list,tmpreg,ref.base);
+//            maybegetcpuregister(list,GetNextReg(tmpreg));
+//            emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
+//            if ref.index<>NR_NO then
+//              begin
+//                list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
+//                list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
+//              end;
+//            if ref.offset>0 then
+//              list.concat(taicpu.op_reg_const(A_ADIW,tmpreg,ref.offset))
+//            else
+//              list.concat(taicpu.op_reg_const(A_SBIW,tmpreg,-ref.offset));
+//            ref.offset:=0;
+//            ref.base:=tmpreg;
+//            ref.index:=NR_NO;
+//          end
+//        else if assigned(ref.symbol) or (ref.offset<>0) then
+//          begin
+//            reference_reset(tmpref,0,[]);
+//            tmpref.symbol:=ref.symbol;
+//            tmpref.offset:=ref.offset;
+//            if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
+//              tmpref.refaddr:=addr_lo8_gs
+//            else
+//              tmpref.refaddr:=addr_lo8;
+//            maybegetcpuregister(list,tmpreg);
+//            list.concat(taicpu.op_reg_ref(A_LDI,tmpreg,tmpref));
+//
+//            if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
+//              tmpref.refaddr:=addr_hi8_gs
+//            else
+//              tmpref.refaddr:=addr_hi8;
+//            maybegetcpuregister(list,GetNextReg(tmpreg));
+//            list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(tmpreg),tmpref));
+//
+//            if (ref.base<>NR_NO) then
+//              begin
+//                list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.base));
+//                list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.base)));
+//              end;
+//            if (ref.index<>NR_NO) then
+//              begin
+//                list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
+//                list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
+//              end;
+//            ref.symbol:=nil;
+//            ref.offset:=0;
+//            ref.base:=tmpreg;
+//            ref.index:=NR_NO;
+//          end
+//        else if (ref.base<>NR_NO) and (ref.index<>NR_NO) then
+//          begin
+//            maybegetcpuregister(list,tmpreg);
+//            emit_mov(list,tmpreg,ref.base);
+//            maybegetcpuregister(list,GetNextReg(tmpreg));
+//            emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
+//            list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
+//            list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
+//            ref.base:=tmpreg;
+//            ref.index:=NR_NO;
+//          end
+//        else if (ref.base<>NR_NO) then
+//          begin
+//            maybegetcpuregister(list,tmpreg);
+//            emit_mov(list,tmpreg,ref.base);
+//            maybegetcpuregister(list,GetNextReg(tmpreg));
+//            emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
+//            ref.base:=tmpreg;
+//            ref.index:=NR_NO;
+//          end
+//        else if (ref.index<>NR_NO) then
+//          begin
+//            maybegetcpuregister(list,tmpreg);
+//            emit_mov(list,tmpreg,ref.index);
+//            maybegetcpuregister(list,GetNextReg(tmpreg));
+//            emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.index));
+//            ref.base:=tmpreg;
+//            ref.index:=NR_NO;
+//          end;
+        Result:=ref;
+      end;
+
+
+     procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
+       var
+         href : treference;
+         conv_done: boolean;
+         tmpreg : tregister;
+         i : integer;
+         QuickRef : Boolean;
+       begin
+         QuickRef:=false;
+
+         //href:=Ref;
+         //{ ensure, href.base contains a valid register if there is any register used }
+         //if href.base=NR_NO then
+         //  begin
+         //    href.base:=href.index;
+         //    href.index:=NR_NO;
+         //  end;
+         //
+         //{ try to use std/sts }
+         //if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
+         //  begin
+         //    if not((href.addressmode=AM_UNCHANGED) and
+         //           (href.symbol=nil) and
+         //            (href.Index=NR_NO) and
+         //            (href.Offset in [0..64-tcgsize2size[fromsize]])) then
+         //      href:=normalize_ref(list,href,NR_R30)
+         //    else
+         //      begin
+         //        if (href.base<>NR_R28) and (href.base<>NR_R30) then
+         //          begin
+         //            maybegetcpuregister(list,NR_R30);
+         //            emit_mov(list,NR_R30,href.base);
+         //            maybegetcpuregister(list,NR_R31);
+         //            emit_mov(list,NR_R31,GetNextReg(href.base));
+         //            href.base:=NR_R30;
+         //          end;
+         //        QuickRef:=true;
+         //      end;
+         //  end
+         //else
+         //  QuickRef:=true;
+         //
+         //if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
+         //  internalerror(2011021307);
+         //
+         //conv_done:=false;
+         //if tosize<>fromsize then
+         //  begin
+         //    conv_done:=true;
+         //    if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
+         //      fromsize:=tosize;
+         //    case fromsize of
+         //      OS_8:
+         //        begin
+         //          if not(QuickRef) and (tcgsize2size[tosize]>1) then
+         //            href.addressmode:=AM_POSTINCREMENT;
+         //
+         //          list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //          for i:=2 to tcgsize2size[tosize] do
+         //            begin
+         //              if QuickRef then
+         //                inc(href.offset);
+         //
+         //              if not(QuickRef) and (i<tcgsize2size[fromsize]) then
+         //                href.addressmode:=AM_POSTINCREMENT
+         //              else
+         //                href.addressmode:=AM_UNCHANGED;
+         //
+         //              list.concat(taicpu.op_ref_reg(GetStore(href),href,NR_R1));
+         //            end;
+         //        end;
+         //      OS_S8:
+         //        begin
+         //          if not(QuickRef) and (tcgsize2size[tosize]>1) then
+         //            href.addressmode:=AM_POSTINCREMENT;
+         //          list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //
+         //          if tcgsize2size[tosize]>1 then
+         //            begin
+         //              tmpreg:=getintregister(list,OS_8);
+         //              emit_mov(list,tmpreg,NR_R1);
+         //              list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
+         //              list.concat(taicpu.op_reg(A_COM,tmpreg));
+         //              for i:=2 to tcgsize2size[tosize] do
+         //                begin
+         //                  if QuickRef then
+         //                    inc(href.offset);
+         //
+         //                  if not(QuickRef) and (i<tcgsize2size[fromsize]) then
+         //                    href.addressmode:=AM_POSTINCREMENT
+         //                  else
+         //                    href.addressmode:=AM_UNCHANGED;
+         //                  list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
+         //                end;
+         //            end;
+         //        end;
+         //      OS_16:
+         //        begin
+         //          if not(QuickRef) and (tcgsize2size[tosize]>1) then
+         //            href.addressmode:=AM_POSTINCREMENT;
+         //
+         //          list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //          if QuickRef then
+         //            inc(href.offset)
+         //          else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
+         //            href.addressmode:=AM_POSTINCREMENT
+         //          else
+         //            href.addressmode:=AM_UNCHANGED;
+         //
+         //          reg:=GetNextReg(reg);
+         //          list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //
+         //          for i:=3 to tcgsize2size[tosize] do
+         //            begin
+         //              if QuickRef then
+         //                inc(href.offset);
+         //
+         //              if not(QuickRef) and (i<tcgsize2size[fromsize]) then
+         //                href.addressmode:=AM_POSTINCREMENT
+         //              else
+         //                href.addressmode:=AM_UNCHANGED;
+         //
+         //              list.concat(taicpu.op_ref_reg(GetStore(href),href,NR_R1));
+         //            end;
+         //        end;
+         //      OS_S16:
+         //        begin
+         //          if not(QuickRef) and (tcgsize2size[tosize]>1) then
+         //            href.addressmode:=AM_POSTINCREMENT;
+         //
+         //          list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //          if QuickRef then
+         //            inc(href.offset)
+         //          else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
+         //            href.addressmode:=AM_POSTINCREMENT
+         //          else
+         //            href.addressmode:=AM_UNCHANGED;
+         //
+         //          reg:=GetNextReg(reg);
+         //          list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //
+         //          if tcgsize2size[tosize]>2 then
+         //            begin
+         //              tmpreg:=getintregister(list,OS_8);
+         //              emit_mov(list,tmpreg,NR_R1);
+         //              list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
+         //              list.concat(taicpu.op_reg(A_COM,tmpreg));
+         //              for i:=3 to tcgsize2size[tosize] do
+         //                begin
+         //                  if QuickRef then
+         //                    inc(href.offset);
+         //
+         //                  if not(QuickRef) and (i<tcgsize2size[fromsize]) then
+         //                    href.addressmode:=AM_POSTINCREMENT
+         //                  else
+         //                    href.addressmode:=AM_UNCHANGED;
+         //                  list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
+         //                end;
+         //            end;
+         //        end;
+         //      else
+         //        conv_done:=false;
+         //    end;
+         //  end;
+         //if not conv_done then
+         //  begin
+         //    for i:=1 to tcgsize2size[fromsize] do
+         //      begin
+         //          if not(QuickRef) and (i<tcgsize2size[fromsize]) then
+         //            href.addressmode:=AM_POSTINCREMENT
+         //          else
+         //            href.addressmode:=AM_UNCHANGED;
+         //
+         //        list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
+         //
+         //        if QuickRef then
+         //          inc(href.offset);
+         //
+         //        reg:=GetNextReg(reg);
+         //      end;
+         //  end;
+         //
+         //if not(QuickRef) then
+         //  begin
+         //    ungetcpuregister(list,href.base);
+         //    ungetcpuregister(list,GetNextReg(href.base));
+         //  end;
+       end;
+
+
+     procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
+       const Ref : treference;reg : tregister);
+       var
+         href : treference;
+         conv_done: boolean;
+         tmpreg : tregister;
+         i : integer;
+         QuickRef : boolean;
+       begin
+         QuickRef:=false;
+
+         //href:=Ref;
+         //{ ensure, href.base contains a valid register if there is any register used }
+         //if href.base=NR_NO then
+         //  begin
+         //    href.base:=href.index;
+         //    href.index:=NR_NO;
+         //  end;
+         //
+         //{ try to use ldd/lds }
+         //if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
+         //  begin
+         //    if not((href.addressmode=AM_UNCHANGED) and
+         //           (href.symbol=nil) and
+         //            (href.Index=NR_NO) and
+         //            (href.Offset in [0..64-tcgsize2size[fromsize]])) then
+         //      href:=normalize_ref(list,href,NR_R30)
+         //    else
+         //      begin
+         //        if (href.base<>NR_R28) and (href.base<>NR_R30) then
+         //          begin
+         //            maybegetcpuregister(list,NR_R30);
+         //            emit_mov(list,NR_R30,href.base);
+         //            maybegetcpuregister(list,NR_R31);
+         //            emit_mov(list,NR_R31,GetNextReg(href.base));
+         //            href.base:=NR_R30;
+         //          end;
+         //        QuickRef:=true;
+         //      end;
+         //  end
+         //else
+         //  QuickRef:=true;
+         //
+         //if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
+         //  internalerror(2011021307);
+         //
+         //conv_done:=false;
+         //if tosize<>fromsize then
+         //  begin
+         //    conv_done:=true;
+         //    if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
+         //      fromsize:=tosize;
+         //    case fromsize of
+         //      OS_8:
+         //        begin
+         //          list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //          for i:=2 to tcgsize2size[tosize] do
+         //            begin
+         //              reg:=GetNextReg(reg);
+         //              emit_mov(list,reg,NR_R1);
+         //            end;
+         //        end;
+         //      OS_S8:
+         //        begin
+         //          list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //          tmpreg:=reg;
+         //
+         //          if tcgsize2size[tosize]>1 then
+         //            begin
+         //              reg:=GetNextReg(reg);
+         //              emit_mov(list,reg,NR_R1);
+         //              list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
+         //              list.concat(taicpu.op_reg(A_COM,reg));
+         //              tmpreg:=reg;
+         //              for i:=3 to tcgsize2size[tosize] do
+         //                begin
+         //                  reg:=GetNextReg(reg);
+         //                  emit_mov(list,reg,tmpreg);
+         //                end;
+         //            end;
+         //        end;
+         //      OS_16:
+         //        begin
+         //          if not(QuickRef) then
+         //            href.addressmode:=AM_POSTINCREMENT;
+         //          list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //
+         //          if QuickRef then
+         //            inc(href.offset);
+         //          href.addressmode:=AM_UNCHANGED;
+         //
+         //          reg:=GetNextReg(reg);
+         //          list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //
+         //          for i:=3 to tcgsize2size[tosize] do
+         //            begin
+         //              reg:=GetNextReg(reg);
+         //              emit_mov(list,reg,NR_R1);
+         //            end;
+         //        end;
+         //      OS_S16:
+         //        begin
+         //          if not(QuickRef) then
+         //            href.addressmode:=AM_POSTINCREMENT;
+         //          list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //          if QuickRef then
+         //            inc(href.offset);
+         //          href.addressmode:=AM_UNCHANGED;
+         //
+         //          reg:=GetNextReg(reg);
+         //          list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //          tmpreg:=reg;
+         //
+         //          reg:=GetNextReg(reg);
+         //          emit_mov(list,reg,NR_R1);
+         //          list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
+         //          list.concat(taicpu.op_reg(A_COM,reg));
+         //          tmpreg:=reg;
+         //          for i:=4 to tcgsize2size[tosize] do
+         //            begin
+         //              reg:=GetNextReg(reg);
+         //              emit_mov(list,reg,tmpreg);
+         //            end;
+         //        end;
+         //      else
+         //        conv_done:=false;
+         //    end;
+         //  end;
+         //if not conv_done then
+         //  begin
+         //    for i:=1 to tcgsize2size[fromsize] do
+         //      begin
+         //        if not(QuickRef) and (i<tcgsize2size[fromsize]) then
+         //          href.addressmode:=AM_POSTINCREMENT
+         //        else
+         //          href.addressmode:=AM_UNCHANGED;
+         //
+         //        list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
+         //
+         //        if QuickRef then
+         //          inc(href.offset);
+         //
+         //        reg:=GetNextReg(reg);
+         //      end;
+         //  end;
+         //
+         //if not(QuickRef) then
+         //  begin
+         //    ungetcpuregister(list,href.base);
+         //    ungetcpuregister(list,GetNextReg(href.base));
+         //  end;
+       end;
+
+
+     procedure tcgz80.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
+       var
+         conv_done: boolean;
+         tmpreg : tregister;
+         i : integer;
+       begin
+         //if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
+         //  internalerror(2011021310);
+         //
+         //conv_done:=false;
+         //if tosize<>fromsize then
+         //  begin
+         //    conv_done:=true;
+         //    if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
+         //      fromsize:=tosize;
+         //    case fromsize of
+         //      OS_8:
+         //        begin
+         //          emit_mov(list,reg2,reg1);
+         //          for i:=2 to tcgsize2size[tosize] do
+         //            begin
+         //              reg2:=GetNextReg(reg2);
+         //              emit_mov(list,reg2,NR_R1);
+         //            end;
+         //        end;
+         //      OS_S8:
+         //        begin
+         //          emit_mov(list,reg2,reg1);
+         //
+         //          if tcgsize2size[tosize]>1 then
+         //            begin
+         //              reg2:=GetNextReg(reg2);
+         //              emit_mov(list,reg2,NR_R1);
+         //              list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
+         //              list.concat(taicpu.op_reg(A_COM,reg2));
+         //              tmpreg:=reg2;
+         //              for i:=3 to tcgsize2size[tosize] do
+         //                begin
+         //                  reg2:=GetNextReg(reg2);
+         //                  emit_mov(list,reg2,tmpreg);
+         //                end;
+         //            end;
+         //        end;
+         //      OS_16:
+         //        begin
+         //          emit_mov(list,reg2,reg1);
+         //
+         //          reg1:=GetNextReg(reg1);
+         //          reg2:=GetNextReg(reg2);
+         //          emit_mov(list,reg2,reg1);
+         //
+         //          for i:=3 to tcgsize2size[tosize] do
+         //            begin
+         //              reg2:=GetNextReg(reg2);
+         //              emit_mov(list,reg2,NR_R1);
+         //            end;
+         //        end;
+         //      OS_S16:
+         //        begin
+         //          emit_mov(list,reg2,reg1);
+         //
+         //          reg1:=GetNextReg(reg1);
+         //          reg2:=GetNextReg(reg2);
+         //          emit_mov(list,reg2,reg1);
+         //
+         //          if tcgsize2size[tosize]>2 then
+         //            begin
+         //              reg2:=GetNextReg(reg2);
+         //              emit_mov(list,reg2,NR_R1);
+         //              list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
+         //              list.concat(taicpu.op_reg(A_COM,reg2));
+         //              tmpreg:=reg2;
+         //              for i:=4 to tcgsize2size[tosize] do
+         //                begin
+         //                  reg2:=GetNextReg(reg2);
+         //                  emit_mov(list,reg2,tmpreg);
+         //                end;
+         //            end;
+         //        end;
+         //      else
+         //        conv_done:=false;
+         //    end;
+         //  end;
+         //if not conv_done and (reg1<>reg2) then
+         //  begin
+         //    for i:=1 to tcgsize2size[fromsize] do
+         //      begin
+         //        emit_mov(list,reg2,reg1);
+         //        reg1:=GetNextReg(reg1);
+         //        reg2:=GetNextReg(reg2);
+         //      end;
+         //  end;
+       end;
+
+
+     procedure tcgz80.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
+       begin
+         internalerror(2012010702);
+       end;
+
+
+     procedure tcgz80.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
+       begin
+         internalerror(2012010703);
+       end;
+
+
+     procedure tcgz80.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
+       begin
+         internalerror(2012010704);
+       end;
+
+
+    {  comparison operations }
+    procedure tcgz80.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
+      cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
+      var
+        swapped : boolean;
+        tmpreg : tregister;
+        i : byte;
+      begin
+        //if a=0 then
+        //  begin
+        //    swapped:=false;
+        //    { swap parameters? }
+        //    case cmp_op of
+        //      OC_GT:
+        //        begin
+        //          swapped:=true;
+        //          cmp_op:=OC_LT;
+        //        end;
+        //      OC_LTE:
+        //        begin
+        //          swapped:=true;
+        //          cmp_op:=OC_GTE;
+        //        end;
+        //      OC_BE:
+        //        begin
+        //          swapped:=true;
+        //          cmp_op:=OC_AE;
+        //        end;
+        //      OC_A:
+        //        begin
+        //          swapped:=true;
+        //          cmp_op:=OC_B;
+        //        end;
+        //    end;
+        //
+        //    if swapped then
+        //      list.concat(taicpu.op_reg_reg(A_CP,NR_R1,reg))
+        //    else
+        //      list.concat(taicpu.op_reg_reg(A_CP,reg,NR_R1));
+        //
+        //    for i:=2 to tcgsize2size[size] do
+        //      begin
+        //        reg:=GetNextReg(reg);
+        //        if swapped then
+        //          list.concat(taicpu.op_reg_reg(A_CPC,NR_R1,reg))
+        //        else
+        //          list.concat(taicpu.op_reg_reg(A_CPC,reg,NR_R1));
+        //      end;
+        //
+        //    a_jmp_cond(list,cmp_op,l);
+        //  end
+        //else
+        //  inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
+      end;
+
+
+    procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
+      cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
+      var
+        swapped : boolean;
+        tmpreg : tregister;
+        i : byte;
+      begin
+        //swapped:=false;
+        //{ swap parameters? }
+        //case cmp_op of
+        //  OC_GT:
+        //    begin
+        //      swapped:=true;
+        //      cmp_op:=OC_LT;
+        //    end;
+        //  OC_LTE:
+        //    begin
+        //      swapped:=true;
+        //      cmp_op:=OC_GTE;
+        //    end;
+        //  OC_BE:
+        //    begin
+        //      swapped:=true;
+        //      cmp_op:=OC_AE;
+        //    end;
+        //  OC_A:
+        //    begin
+        //      swapped:=true;
+        //      cmp_op:=OC_B;
+        //    end;
+        //end;
+        //if swapped then
+        //  begin
+        //    tmpreg:=reg1;
+        //    reg1:=reg2;
+        //    reg2:=tmpreg;
+        //  end;
+        //list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
+        //
+        //for i:=2 to tcgsize2size[size] do
+        //  begin
+        //    reg1:=GetNextReg(reg1);
+        //    reg2:=GetNextReg(reg2);
+        //    list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
+        //  end;
+        //
+        //a_jmp_cond(list,cmp_op,l);
+      end;
+
+
+    procedure tcgz80.a_jmp_name(list : TAsmList;const s : string);
+      var
+        ai : taicpu;
+      begin
+        ai:=taicpu.op_sym(A_JP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
+        ai.is_jmp:=true;
+        list.concat(ai);
+      end;
+
+
+    procedure tcgz80.a_jmp_always(list : TAsmList;l: tasmlabel);
+      var
+        ai : taicpu;
+      begin
+        ai:=taicpu.op_sym(A_JP,l);
+        ai.is_jmp:=true;
+        list.concat(ai);
+      end;
+
+
+    procedure tcgz80.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
+      var
+        ai : taicpu;
+      begin
+//        ai:=setcondition(taicpu.op_sym(A_BRxx,l),flags_to_cond(f));
+        ai.is_jmp:=true;
+        list.concat(ai);
+      end;
+
+
+    procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
+      var
+        l : TAsmLabel;
+        tmpflags : TResFlags;
+      begin
+        current_asmdata.getjumplabel(l);
+        {
+        if flags_to_cond(f) then
+          begin
+            tmpflags:=f;
+            inverse_flags(tmpflags);
+            emit_mov(reg,NR_R1);
+            a_jmp_flags(list,tmpflags,l);
+            list.concat(taicpu.op_reg_const(A_LDI,reg,1));
+          end
+        else
+        }
+          begin
+            list.concat(taicpu.op_reg_const(A_LDI,reg,1));
+            a_jmp_flags(list,f,l);
+            emit_mov(list,reg,NR_R1);
+          end;
+        cg.a_label(list,l);
+      end;
+
+
+    procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
+      var
+        i : integer;
+      begin
+        //case value of
+        //  0:
+        //    ;
+        //  {-14..-1:
+        //    begin
+        //      if ((-value) mod 2)<>0 then
+        //        list.concat(taicpu.op_reg(A_PUSH,NR_R0));
+        //      for i:=1 to (-value) div 2 do
+        //        list.concat(taicpu.op_const(A_RCALL,0));
+        //    end;
+        //  1..7:
+        //    begin
+        //      for i:=1 to value do
+        //        list.concat(taicpu.op_reg(A_POP,NR_R0));
+        //    end;}
+        //  else
+        //    begin
+        //      list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
+        //      list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
+        //      // get SREG
+        //      list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
+        //
+        //      // block interrupts
+        //      list.concat(taicpu.op_none(A_CLI));
+        //
+        //      // write high SP
+        //      list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
+        //
+        //      // release interrupts
+        //      list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
+        //
+        //      // write low SP
+        //      list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
+        //    end;
+        //end;
+      end;
+
+
+    function tcgz80.GetLoad(const ref: treference) : tasmop;
+      begin
+        //if (ref.base=NR_NO) and (ref.index=NR_NO) then
+        //  result:=A_LDS
+        //else if (ref.base<>NR_NO) and (ref.offset<>0) then
+        //  result:=A_LDD
+        //else
+        //  result:=A_LD;
+      end;
+
+
+    function tcgz80.GetStore(const ref: treference) : tasmop;
+      begin
+        //if (ref.base=NR_NO) and (ref.index=NR_NO) then
+        //  result:=A_STS
+        //else if (ref.base<>NR_NO) and (ref.offset<>0) then
+        //  result:=A_STD
+        //else
+        //  result:=A_ST;
+      end;
+
+
+    procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
+      var
+         regs : tcpuregisterset;
+         reg : tsuperregister;
+      begin
+        //if po_interrupt in current_procinfo.procdef.procoptions then
+        //  begin
+        //    { check if the framepointer is actually used, this is done here because
+        //      we have to know the size of the locals (must be 0), avr does not know
+        //      an sp based stack }
+        //
+        //    if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
+        //      (localsize=0) then
+        //      current_procinfo.framepointer:=NR_NO;
+        //
+        //    { save int registers,
+        //      but only if the procedure returns }
+        //    if not(po_noreturn in current_procinfo.procdef.procoptions) then
+        //      regs:=rg[R_INTREGISTER].used_in_proc
+        //    else
+        //      regs:=[];
+        //    { if the framepointer is potentially used, save it always because we need a proper stack frame,
+        //      even if the procedure never returns, the procedure could be e.g. a nested one accessing
+        //      an outer stackframe }
+        //    if current_procinfo.framepointer<>NR_NO then
+        //      regs:=regs+[RS_R28,RS_R29];
+        //
+        //    regs:=regs+[RS_R0];
+        //
+        //    for reg:=RS_R31 downto RS_R0 do
+        //      if reg in regs then
+        //        list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
+        //
+        //    { Save SREG }
+        //    list.concat(taicpu.op_reg_const(A_IN, NR_R0, $3F));
+        //    list.concat(taicpu.op_reg(A_PUSH, NR_R0));
+        //
+        //    if current_procinfo.framepointer<>NR_NO then
+        //      begin
+        //        list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
+        //        list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
+        //        a_adjust_sp(list,-localsize);
+        //      end;
+        //  end
+        //else if not(nostackframe) then
+        //  begin
+        //    { check if the framepointer is actually used, this is done here because
+        //      we have to know the size of the locals (must be 0), avr does not know
+        //      an sp based stack }
+        //
+        //    if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
+        //      (localsize=0) then
+        //      current_procinfo.framepointer:=NR_NO;
+        //
+        //    { save int registers,
+        //      but only if the procedure returns }
+        //    if not(po_noreturn in current_procinfo.procdef.procoptions) then
+        //      regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)
+        //    else
+        //      regs:=[];
+        //    { if the framepointer is potentially used, save it always because we need a proper stack frame,
+        //      even if the procedure never returns, the procedure could be e.g. a nested one accessing
+        //      an outer stackframe }
+        //    if current_procinfo.framepointer<>NR_NO then
+        //      regs:=regs+[RS_R28,RS_R29];
+        //
+        //    for reg:=RS_R31 downto RS_R0 do
+        //      if reg in regs then
+        //        list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
+        //
+        //    if current_procinfo.framepointer<>NR_NO then
+        //      begin
+        //        list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
+        //        list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
+        //        a_adjust_sp(list,-localsize);
+        //      end;
+        //  end;
+      end;
+
+
+    procedure tcgz80.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
+      var
+        regs : tcpuregisterset;
+        reg : TSuperRegister;
+        LocalSize : longint;
+      begin
+        { every byte counts for avr, so if a subroutine is marked as non-returning, we do
+          not generate any exit code, so we really trust the noreturn directive
+        }
+        if po_noreturn in current_procinfo.procdef.procoptions then
+          exit;
+        if po_interrupt in current_procinfo.procdef.procoptions then
+          begin
+            regs:=rg[R_INTREGISTER].used_in_proc;
+            if current_procinfo.framepointer<>NR_NO then
+              begin
+                regs:=regs+[RS_R28,RS_R29];
+                LocalSize:=current_procinfo.calc_stackframe_size;
+                a_adjust_sp(list,LocalSize);
+              end;
+
+            { Reload SREG }
+            regs:=regs+[RS_R0];
+
+            list.concat(taicpu.op_reg(A_POP, NR_R0));
+            list.concat(taicpu.op_const_reg(A_OUT, $3F, NR_R0));
+
+            for reg:=RS_R0 to RS_R31 do
+              if reg in regs then
+                list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
+
+            list.concat(taicpu.op_none(A_RETI));
+          end
+        else if not(nostackframe) then
+          begin
+            regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
+            if current_procinfo.framepointer<>NR_NO then
+              begin
+                regs:=regs+[RS_R28,RS_R29];
+                LocalSize:=current_procinfo.calc_stackframe_size;
+                a_adjust_sp(list,LocalSize);
+              end;
+            for reg:=RS_R0 to RS_R31 do
+              if reg in regs then
+                list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
+            list.concat(taicpu.op_none(A_RET));
+          end
+        else
+          list.concat(taicpu.op_none(A_RET));
+      end;
+
+
+    procedure tcgz80.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
+      var
+        tmpref : treference;
+      begin
+        // if ref.addressmode<>AM_UNCHANGED then
+        //   internalerror(2011021701);
+        //
+        //if assigned(ref.symbol) or (ref.offset<>0) then
+        //  begin
+        //    reference_reset(tmpref,0,[]);
+        //    tmpref.symbol:=ref.symbol;
+        //    tmpref.offset:=ref.offset;
+        //
+        //    if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
+        //      tmpref.refaddr:=addr_lo8_gs
+        //    else
+        //      tmpref.refaddr:=addr_lo8;
+        //    list.concat(taicpu.op_reg_ref(A_LDI,r,tmpref));
+        //
+        //    if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
+        //      tmpref.refaddr:=addr_hi8_gs
+        //    else
+        //      tmpref.refaddr:=addr_hi8;
+        //    list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(r),tmpref));
+        //
+        //    if (ref.base<>NR_NO) then
+        //      begin
+        //        list.concat(taicpu.op_reg_reg(A_ADD,r,ref.base));
+        //        list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.base)));
+        //      end;
+        //    if (ref.index<>NR_NO) then
+        //      begin
+        //        list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
+        //        list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
+        //      end;
+        //  end
+        //else if (ref.base<>NR_NO)then
+        //  begin
+        //    emit_mov(list,r,ref.base);
+        //    emit_mov(list,GetNextReg(r),GetNextReg(ref.base));
+        //    if (ref.index<>NR_NO) then
+        //      begin
+        //        list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
+        //        list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
+        //      end;
+        //  end
+        //else if (ref.index<>NR_NO) then
+        //  begin
+        //    emit_mov(list,r,ref.index);
+        //    emit_mov(list,GetNextReg(r),GetNextReg(ref.index));
+        //  end;
+      end;
+
+
+    procedure tcgz80.fixref(list : TAsmList;var ref : treference);
+      begin
+        internalerror(2011021320);
+      end;
+
+
+    procedure tcgz80.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));
+        a_call_name_static(list,'FPC_MOVE');
+        dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+        paraloc3.done;
+        paraloc2.done;
+        paraloc1.done;
+      end;
+
+
+    procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
+      var
+        countreg,tmpreg : tregister;
+        srcref,dstref : treference;
+        copysize,countregsize : tcgsize;
+        l : TAsmLabel;
+        i : longint;
+        SrcQuickRef, DestQuickRef : Boolean;
+      begin
+        //if len>16 then
+        //  begin
+        //    current_asmdata.getjumplabel(l);
+        //
+        //    reference_reset(srcref,source.alignment,source.volatility);
+        //    reference_reset(dstref,dest.alignment,source.volatility);
+        //    srcref.base:=NR_R30;
+        //    srcref.addressmode:=AM_POSTINCREMENT;
+        //    dstref.base:=NR_R26;
+        //    dstref.addressmode:=AM_POSTINCREMENT;
+        //
+        //    copysize:=OS_8;
+        //    if len<256 then
+        //      countregsize:=OS_8
+        //    else if len<65536 then
+        //      countregsize:=OS_16
+        //    else
+        //      internalerror(2011022007);
+        //    countreg:=getintregister(list,countregsize);
+        //    a_load_const_reg(list,countregsize,len,countreg);
+        //    a_loadaddr_ref_reg(list,source,NR_R30);
+        //
+        //    { only base or index register in dest? }
+        //    if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
+        //      ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
+        //      begin
+        //        if dest.base<>NR_NO then
+        //          tmpreg:=dest.base
+        //        else if dest.index<>NR_NO then
+        //          tmpreg:=dest.index
+        //        else
+        //          internalerror(2016112001);
+        //      end
+        //    else
+        //      begin
+        //        tmpreg:=getaddressregister(list);
+        //        a_loadaddr_ref_reg(list,dest,tmpreg);
+        //      end;
+        //
+        //    { X is used for spilling code so we can load it
+        //      only by a push/pop sequence, this can be
+        //      optimized later on by the peephole optimizer
+        //    }
+        //    list.concat(taicpu.op_reg(A_PUSH,tmpreg));
+        //    list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
+        //    list.concat(taicpu.op_reg(A_POP,NR_R27));
+        //    list.concat(taicpu.op_reg(A_POP,NR_R26));
+        //    cg.a_label(list,l);
+        //    list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
+        //    list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
+        //    list.concat(taicpu.op_reg(A_DEC,countreg));
+        //    a_jmp_flags(list,F_NE,l);
+        //    // keep registers alive
+        //    list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
+        //  end
+        //else
+        //  begin
+        //    SrcQuickRef:=false;
+        //    DestQuickRef:=false;
+        //    if not((source.addressmode=AM_UNCHANGED) and
+        //           (source.symbol=nil) and
+        //           ((source.base=NR_R28) or
+        //            (source.base=NR_R30)) and
+        //            (source.Index=NR_NO) and
+        //            (source.Offset in [0..64-len])) and
+        //      not((source.Base=NR_NO) and (source.Index=NR_NO)) then
+        //      srcref:=normalize_ref(list,source,NR_R30)
+        //    else
+        //      begin
+        //        SrcQuickRef:=true;
+        //        srcref:=source;
+        //      end;
+        //
+        //    if not((dest.addressmode=AM_UNCHANGED) and
+        //           (dest.symbol=nil) and
+        //           ((dest.base=NR_R28) or
+        //            (dest.base=NR_R30)) and
+        //            (dest.Index=NR_No) and
+        //            (dest.Offset in [0..64-len])) and
+        //      not((dest.Base=NR_NO) and (dest.Index=NR_NO)) then
+        //      begin
+        //        if not(SrcQuickRef) then
+        //          begin
+        //            { only base or index register in dest? }
+        //            if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
+        //              ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
+        //              begin
+        //                if dest.base<>NR_NO then
+        //                  tmpreg:=dest.base
+        //                else if dest.index<>NR_NO then
+        //                  tmpreg:=dest.index
+        //                else
+        //                  internalerror(2016112002);
+        //              end
+        //            else
+        //              tmpreg:=getaddressregister(list);
+        //
+        //            dstref:=normalize_ref(list,dest,tmpreg);
+        //
+        //            { X is used for spilling code so we can load it
+        //              only by a push/pop sequence, this can be
+        //              optimized later on by the peephole optimizer
+        //            }
+        //            list.concat(taicpu.op_reg(A_PUSH,tmpreg));
+        //            list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
+        //            list.concat(taicpu.op_reg(A_POP,NR_R27));
+        //            list.concat(taicpu.op_reg(A_POP,NR_R26));
+        //            dstref.base:=NR_R26;
+        //          end
+        //        else
+        //          dstref:=normalize_ref(list,dest,NR_R30);
+        //      end
+        //    else
+        //      begin
+        //        DestQuickRef:=true;
+        //        dstref:=dest;
+        //      end;
+        //
+        //    for i:=1 to len do
+        //      begin
+        //        if not(SrcQuickRef) and (i<len) then
+        //          srcref.addressmode:=AM_POSTINCREMENT
+        //        else
+        //          srcref.addressmode:=AM_UNCHANGED;
+        //
+        //        if not(DestQuickRef) and (i<len) then
+        //          dstref.addressmode:=AM_POSTINCREMENT
+        //        else
+        //          dstref.addressmode:=AM_UNCHANGED;
+        //
+        //        list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
+        //        list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
+        //
+        //        if SrcQuickRef then
+        //          inc(srcref.offset);
+        //        if DestQuickRef then
+        //          inc(dstref.offset);
+        //      end;
+        //    if not(SrcQuickRef) then
+        //      begin
+        //        ungetcpuregister(list,srcref.base);
+        //        ungetcpuregister(list,GetNextReg(srcref.base));
+        //      end;
+        //  end;
+      end;
+
+
+    procedure tcgz80.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
+      var
+        hl : tasmlabel;
+        ai : taicpu;
+        cond : TAsmCond;
+      begin
+        //if not(cs_check_overflow in current_settings.localswitches) then
+        // exit;
+        //current_asmdata.getjumplabel(hl);
+        //if not ((def.typ=pointerdef) or
+        //       ((def.typ=orddef) and
+        //        (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
+        //                                  pasbool8,pasbool16,pasbool32,pasbool64]))) then
+        //  cond:=C_VC
+        //else
+        //  cond:=C_CC;
+        //ai:=Taicpu.Op_Sym(A_BRxx,hl);
+        //ai.SetCondition(cond);
+        //ai.is_jmp:=true;
+        //list.concat(ai);
+        //
+        //a_call_name(list,'FPC_OVERFLOW',false);
+        //a_label(list,hl);
+      end;
+
+
+    procedure tcgz80.g_save_registers(list: TAsmList);
+      begin
+        { this is done by the entry code }
+      end;
+
+
+    procedure tcgz80.g_restore_registers(list: TAsmList);
+      begin
+        { this is done by the exit code }
+      end;
+
+
+    procedure tcgz80.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
+      var
+        ai1,ai2 : taicpu;
+        hl : TAsmLabel;
+      begin
+        //ai1:=Taicpu.Op_sym(A_BRxx,l);
+        //ai1.is_jmp:=true;
+        //hl:=nil;
+        //case cond of
+        //  OC_EQ:
+        //    ai1.SetCondition(C_EQ);
+        //  OC_GT:
+        //    begin
+        //      { emulate GT }
+        //      current_asmdata.getjumplabel(hl);
+        //      ai2:=Taicpu.Op_Sym(A_BRxx,hl);
+        //      ai2.SetCondition(C_EQ);
+        //      ai2.is_jmp:=true;
+        //      list.concat(ai2);
+        //
+        //      ai1.SetCondition(C_GE);
+        //    end;
+        //  OC_LT:
+        //    ai1.SetCondition(C_LT);
+        //  OC_GTE:
+        //    ai1.SetCondition(C_GE);
+        //  OC_LTE:
+        //    begin
+        //      { emulate LTE }
+        //      ai2:=Taicpu.Op_Sym(A_BRxx,l);
+        //      ai2.SetCondition(C_EQ);
+        //      ai2.is_jmp:=true;
+        //      list.concat(ai2);
+        //
+        //      ai1.SetCondition(C_LT);
+        //    end;
+        //  OC_NE:
+        //    ai1.SetCondition(C_NE);
+        //  OC_BE:
+        //    begin
+        //      { emulate BE }
+        //      ai2:=Taicpu.Op_Sym(A_BRxx,l);
+        //      ai2.SetCondition(C_EQ);
+        //      ai2.is_jmp:=true;
+        //      list.concat(ai2);
+        //
+        //      ai1.SetCondition(C_LO);
+        //    end;
+        //  OC_B:
+        //    ai1.SetCondition(C_LO);
+        //  OC_AE:
+        //    ai1.SetCondition(C_SH);
+        //  OC_A:
+        //    begin
+        //      { emulate A (unsigned GT) }
+        //      current_asmdata.getjumplabel(hl);
+        //      ai2:=Taicpu.Op_Sym(A_BRxx,hl);
+        //      ai2.SetCondition(C_EQ);
+        //      ai2.is_jmp:=true;
+        //      list.concat(ai2);
+        //
+        //      ai1.SetCondition(C_SH);
+        //    end;
+        //  else
+        //    internalerror(2011082501);
+        //end;
+        //list.concat(ai1);
+        //if assigned(hl) then
+        //  a_label(list,hl);
+      end;
+
+
+    procedure tcgz80.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
+      var
+         instr: taicpu;
+      begin
+       instr:=taicpu.op_reg_reg(A_LD,reg2,reg1);
+       list.Concat(instr);
+       { Notify the register allocator that we have written a move instruction so
+         it can try to eliminate it. }
+       add_move_instruction(instr);
+      end;
+
+
+    procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
+      begin
+         if not(size in [OS_S64,OS_64]) then
+           internalerror(2012102402);
+         tcgz80(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
+      end;
+
+
+    procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
+      begin
+        tcgz80(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
+      end;
+
+
+    procedure create_codegen;
+      begin
+        cg:=tcgz80.create;
+        cg64:=tcg64favr.create;
+      end;
+
+end.

+ 492 - 0
compiler/z80/cpubase.pas

@@ -0,0 +1,492 @@
+{
+    Copyright (c) 2006 by Florian Klaempfl
+
+    Contains the base types for the AVR
+
+    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.
+
+ ****************************************************************************
+}
+{# Base unit for processor information. This unit contains
+   enumerations of registers, opcodes, sizes, and other
+   such things which are processor specific.
+}
+unit cpubase;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      cutils,cclasses,
+      globtype,globals,
+      cpuinfo,
+      aasmbase,
+      cgbase
+      ;
+
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+    type
+      TAsmOp=(A_None,
+        A_ADD,A_ADC,A_AND,A_BIT,A_CALL,A_CCF,A_CP,A_CPD,A_CPDR,
+        A_CPI,A_CPIR,A_CPL,A_DAA,A_DEC,A_DI,A_DJNZ,A_EI,A_EX,
+        A_EXX,A_HALT,A_IM,A_IN,A_INC,A_IND,A_INDR,A_INI,A_INIR,
+        A_JP,A_JR,A_LD,A_LDD,A_LDDR,A_LDI,A_LDIR,A_NEG,A_NOP,A_OR,
+        A_OTDR,A_OTIR,A_OUT,A_OUTD,A_POP,A_PUSH,A_RES,A_RET,A_RETI,
+        A_RETN,A_RL,A_RLA,A_RLC,A_RLCA,A_RLD,A_RR,A_RRA,A_RRC,
+        A_RRCA,A_RRD,A_RST,A_SBC,A_SCF,A_SET,A_SLA,A_SRA,A_SRL,A_SUB,A_XOR);
+
+
+      { This should define the array of instructions as string }
+      op2strtable=array[tasmop] of string[11];
+
+    const
+      { First value of opcode enumeration }
+      firstop = low(tasmop);
+      { Last value of opcode enumeration  }
+      lastop  = high(tasmop);
+
+      { call/reg instructions are not considered as jmp instructions for the usage cases of
+        this set }
+      jmp_instructions = [A_JP,A_JR];
+      call_jmp_instructions = [A_CALL]+jmp_instructions;
+
+{*****************************************************************************
+                                  Registers
+*****************************************************************************}
+
+    type
+      { Number of registers used for indexing in tables }
+      tregisterindex=0..{$i rz80nor.inc}-1;
+
+    const
+      { Available Superregisters }
+      {$i rz80sup.inc}
+
+      { No Subregisters }
+      R_SUBWHOLE = R_SUBNONE;
+
+      { Available Registers }
+      {$i rz80con.inc}
+
+      NR_XLO = NR_R26;
+      NR_XHI = NR_R27;
+      NR_YLO = NR_R28;
+      NR_YHI = NR_R29;
+      NR_ZLO = NR_R30;
+      NR_ZHI = NR_R31;
+
+      NIO_SREG = $3f;
+      NIO_SP_LO = $3d;
+      NIO_SP_HI = $3e;
+
+      { Integer Super registers first and last }
+      first_int_supreg = RS_R0;
+      first_int_imreg = $20;
+
+      { Float Super register first and last }
+      first_fpu_supreg    = RS_INVALID;
+      first_fpu_imreg     = 0;
+
+      { MM Super register first and last }
+      first_mm_supreg    = RS_INVALID;
+      first_mm_imreg     = 0;
+
+      regnumber_count_bsstart = 32;
+
+      regnumber_table : array[tregisterindex] of tregister = (
+        {$i rz80num.inc}
+      );
+
+      regstabs_table : array[tregisterindex] of shortint = (
+        {$i rz80sta.inc}
+      );
+
+      regdwarf_table : array[tregisterindex] of shortint = (
+        {$i rz80dwa.inc}
+      );
+      { registers which may be destroyed by calls }
+      VOLATILE_INTREGISTERS = [RS_R0,RS_R1,RS_R18..RS_R27,RS_R30,RS_R31];
+      VOLATILE_FPUREGISTERS = [];
+
+    type
+      totherregisterset = set of tregisterindex;
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+    type
+      TAsmCond=(C_None,
+        C_CC,C_CS,C_EQ,C_GE,C_HC,C_HS,C_ID,C_IE,C_LO,C_LT,
+        C_MI,C_NE,C_PL,C_SH,C_TC,C_TS,C_VC,C_VS
+      );
+
+    const
+      cond2str : array[TAsmCond] of string[2]=('',
+        'cc','cs','eq','ge','hc','hs','id','ie','lo','lt',
+        'mi','ne','pl','sh','tc','ts','vc','vs'
+      );
+
+      uppercond2str : array[TAsmCond] of string[2]=('',
+        'CC','CS','EQ','GE','HC','HS','ID','IE','LO','LT',
+        'MI','NE','PL','SH','TC','TS','VC','VS'
+      );
+
+{*****************************************************************************
+                                   Flags
+*****************************************************************************}
+
+    type
+      TResFlags = (F_NotPossible,F_CC,F_CS,F_EQ,F_GE,F_LO,F_LT,
+        F_NE,F_SH,F_VC,F_VS);
+
+{*****************************************************************************
+                                Operands
+*****************************************************************************}
+
+      taddressmode = (AM_UNCHANGED,AM_POSTINCREMENT,AM_PREDRECEMENT);
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      max_operands = 4;
+
+      maxintregs = 15;
+      maxfpuregs = 0;
+      maxaddrregs = 0;
+
+{*****************************************************************************
+                                Operand Sizes
+*****************************************************************************}
+
+    type
+      topsize = (S_NO,
+        S_B,S_W,S_L,S_BW,S_BL,S_WL,
+        S_IS,S_IL,S_IQ,
+        S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
+      );
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      firstsaveintreg = RS_R4;
+      lastsaveintreg  = RS_R10;
+      firstsavefpureg = RS_INVALID;
+      lastsavefpureg  = RS_INVALID;
+      firstsavemmreg  = RS_INVALID;
+      lastsavemmreg   = RS_INVALID;
+
+      maxvarregs = 7;
+      varregs : Array [1..maxvarregs] of tsuperregister =
+                (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
+
+      maxfpuvarregs = 1;
+      fpuvarregs : Array [1..maxfpuvarregs] of tsuperregister =
+                (RS_INVALID);
+
+{*****************************************************************************
+                          Default generic sizes
+*****************************************************************************}
+
+      { Defines the default address size for a processor, }
+      OS_ADDR = OS_16;
+      { the natural int size for a processor,
+        has to match osuinttype/ossinttype as initialized in psystem,
+        initially, this was OS_16/OS_S16 on avr, but experience has
+        proven that it is better to make it 8 Bit thus having the same
+        size as a register.
+      }
+      OS_INT = OS_8;
+      OS_SINT = OS_S8;
+      { the maximum float size for a processor,           }
+      OS_FLOAT = OS_F64;
+      { the size of a vector register for a processor     }
+      OS_VECTOR = OS_M32;
+
+{*****************************************************************************
+                          Generic Register names
+*****************************************************************************}
+
+      { Stack pointer register }
+      NR_STACK_POINTER_REG = NR_R13;
+      RS_STACK_POINTER_REG = RS_R13;
+      { Frame pointer register }
+      RS_FRAME_POINTER_REG = RS_R28;
+      NR_FRAME_POINTER_REG = NR_R28;
+      { Register for addressing absolute data in a position independant way,
+        such as in PIC code. The exact meaning is ABI specific. For
+        further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
+      }
+      NR_PIC_OFFSET_REG = NR_R9;
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_R24;
+      RS_FUNCTION_RETURN_REG = RS_R24;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_R22;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_R22;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_R1;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_R1;
+      { 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_NO;
+
+      NR_MM_RESULT_REG  = NR_NO;
+
+      NR_RETURN_ADDRESS_REG = NR_FUNCTION_RETURN_REG;
+
+      { Offset where the parent framepointer is pushed }
+      PARENT_FRAMEPOINTER_OFFSET = 0;
+
+      NR_DEFAULTFLAGS = NR_SREG;
+      RS_DEFAULTFLAGS = RS_SREG;
+
+{*****************************************************************************
+                       GCC /ABI linking information
+*****************************************************************************}
+
+    const
+      { 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 the CALLED_USED_REGISTERS array in the
+        GCC source.
+      }
+      { on avr, gen_entry/gen_exit code saves/restores registers, so
+        we don't need this array }
+      saved_standard_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;
+
+      saved_address_registers : array[0..0] of tsuperregister = (RS_INVALID);
+      saved_mm_registers : array[0..0] of tsuperregister = (RS_INVALID);
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    { Returns the tcgsize corresponding with the size of reg.}
+    function reg_cgsize(const reg: tregister) : tcgsize;
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+    procedure inverse_flags(var f: TResFlags);
+    function flags_to_cond(const f: TResFlags) : TAsmCond;
+    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 conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+
+    function dwarf_reg(r:tregister):byte;
+    function GetHigh(const r : TRegister) : TRegister;
+
+    { returns the next virtual register }
+    function GetNextReg(const r : TRegister) : TRegister;
+
+    { returns the last virtual register }
+    function GetLastReg(const r : TRegister) : TRegister;
+
+    { returns the register with the offset of ofs of a continuous set of register starting with r }
+    function GetOffsetReg(const r : TRegister;ofs : shortint) : TRegister;
+    { returns the register with the offset of ofs of a continuous set of register starting with r and being continued with rhi }
+    function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): TRegister;
+
+    function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
+
+  implementation
+
+    uses
+      rgBase,verbose;
+
+
+    const
+      std_regname_table : TRegNameTable = (
+        {$i rz80std.inc}
+      );
+
+      regnumber_index : array[tregisterindex] of tregisterindex = (
+        {$i rz80rni.inc}
+      );
+
+      std_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rz80sri.inc}
+      );
+
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+      begin
+        cgsize2subreg:=R_SUBWHOLE;
+      end;
+
+
+    function reg_cgsize(const reg: tregister): tcgsize;
+      begin
+        case getregtype(reg) of
+          R_INTREGISTER :
+            reg_cgsize:=OS_8;
+          R_ADDRESSREGISTER :
+            reg_cgsize:=OS_16;
+          else
+            internalerror(2011021905);
+          end;
+        end;
+
+
+    procedure inverse_flags(var f: TResFlags);
+      const
+        inv_flags: array[TResFlags] of TResFlags =
+          (F_NotPossible,F_CS,F_CC,F_NE,F_LT,F_SH,F_GE,
+           F_NE,F_LO,F_VS,F_VC);
+      begin
+        f:=inv_flags[f];
+      end;
+
+
+    function flags_to_cond(const f: TResFlags) : TAsmCond;
+      const
+        flag_2_cond: array[F_CC..F_VS] of TAsmCond =
+          (C_CC,C_CS,C_EQ,C_GE,C_LO,C_LT,
+           C_NE,C_SH,C_VC,C_VS);
+      begin
+        if f=F_NotPossible then
+          internalerror(2011022101);
+        if f>high(flag_2_cond) then
+          internalerror(200112301);
+        result:=flag_2_cond[f];
+      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 inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      const
+        inverse: array[TAsmCond] of TAsmCond=(C_None,
+          C_CS,C_CC,C_NE,C_LT,C_HS,C_HC,C_IE,C_ID,C_SH,C_GE,
+          C_PL,C_EQ,C_MI,C_LO,C_TS,C_TC,C_VS,C_VC);
+      begin
+        result := inverse[c];
+      end;
+
+
+    function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      begin
+        result := c1 = c2;
+      end;
+
+
+    function rotl(d : dword;b : byte) : dword;
+      begin
+         result:=(d shr (32-b)) or (d shl b);
+      end;
+
+
+    function dwarf_reg(r:tregister):byte;
+      var
+        reg : shortint;
+      begin
+        reg:=regdwarf_table[findreg_by_number(r)];
+        if reg=-1 then
+          internalerror(200603251);
+        result:=reg;
+      end;
+
+
+    function GetHigh(const r : TRegister) : TRegister;
+      begin
+        result:=TRegister(longint(r)+1)
+      end;
+
+
+    function GetNextReg(const r: TRegister): TRegister;
+      begin
+        result:=TRegister(longint(r)+1);
+      end;
+
+
+    function GetLastReg(const r: TRegister): TRegister;
+      begin
+        result:=TRegister(longint(r)-1);
+      end;
+
+
+    function GetOffsetReg(const r: TRegister;ofs : shortint): TRegister;
+      begin
+        result:=TRegister(longint(r)+ofs);
+      end;
+
+
+    function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): TRegister;
+      begin
+        if ofs>3 then
+          result:=TRegister(longint(rhi)+ofs-4)
+        else
+          result:=TRegister(longint(r)+ofs);
+      end;
+
+
+    function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE}
+      begin
+        is_calljmp:= o in call_jmp_instructions;
+      end;
+
+
+end.

+ 130 - 0
compiler/z80/cpuinfo.pas

@@ -0,0 +1,130 @@
+{
+    Copyright (c) 2008 by the Free Pascal development team
+
+    Basic Processor information for the Z80
+
+    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 = type extended;
+   ts128real = type extended;
+   ts64comp = comp;
+
+   pbestreal=^bestreal;
+
+   { possible supported processors for this target }
+   tcputype =
+      (cpu_none,
+       cpu_z80,
+       cpu_ez80
+      );
+
+   tfputype =
+     (fpu_none,
+      fpu_soft,
+      fpu_libgcc
+     );
+
+   tcontrollertype =
+     (ct_none
+     );
+
+   tcontrollerdatatype = record
+      controllertypestr, controllerunitstr: string[20];
+      cputype: tcputype; fputype: tfputype;
+      flashbase, flashsize, srambase, sramsize, eeprombase, eepromsize, bootbase, bootsize: dword;
+   end;
+
+Const
+   {# Size of native extended floating point type }
+   extended_size = 12;
+   { target cpu string (used by compiler options) }
+   target_cpu_string = 'z80';
+
+   { 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_safecall,
+     pocall_stdcall,
+     { same as stdcall only different name mangling }
+     pocall_cdecl,
+     { same as stdcall only different name mangling }
+     pocall_cppdecl,
+     { same as stdcall but floating point numbers are handled like equal sized integers }
+     pocall_softfloat
+   ];
+
+   cputypestr : array[tcputype] of string[5] = ('',
+     'Z80',
+     'EZ80'
+   );
+
+   fputypestr : array[tfputype] of string[6] = (
+     'NONE',
+     'SOFT',
+     'LIBGCC'
+   );
+
+   { 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_tailrecursion,
+                                  cs_opt_stackframe,cs_opt_nodecse,cs_opt_reorder_fields,cs_opt_fastmath];
+
+   level1optimizerswitches = genericlevel1optimizerswitches;
+   level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
+     [cs_opt_regvar,cs_opt_stackframe,cs_opt_tailrecursion];
+   level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+   level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [];
+
+ type
+   tcpuflags =
+      (CPUZ80_HAS_CALLCC
+      );
+
+ const
+   cpu_capabilities : array[tcputype] of set of tcpuflags =
+     ( { cpu_none  } [],
+       { cpu_z80  } [],
+       { cpu_ez80 } [CPUZ80_HAS_CALLCC]
+     );
+
+Implementation
+
+end.

+ 48 - 0
compiler/z80/cpunode.pas

@@ -0,0 +1,48 @@
+{
+    Copyright (c) 2000-2017 by Florian Klaempfl
+
+    This unit includes the Z80 code generator into the compiler
+
+    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,ncgmat,ncgadd
+       { to be able to only parts of the generic code,
+         the processor specific nodes must be included
+         after the generic one (FK)
+       }
+//       ,nz80add
+//       ,nz80mat
+//       ,nz80cnv
+//       ,nz80mem
+//       ,nz80util,
+       { symtable }
+       ,symcpu,
+       aasmdef
+       ;
+
+
+end.

+ 547 - 0
compiler/z80/cpupara.pas

@@ -0,0 +1,547 @@
+{
+    Copyright (c) 2008 by Florian Klaempfl
+
+    Z80 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.
+ ****************************************************************************
+}
+{ ARM specific calling conventions are handled by this unit
+}
+unit cpupara;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,globals,
+       aasmtai,aasmdata,
+       cpuinfo,cpubase,cgbase,cgutils,
+       symconst,symbase,symtype,symdef,parabase,paramgr;
+
+    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;
+          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):longint;
+       end;
+
+  implementation
+
+    uses
+       verbose,systems,
+       rgobj,
+       defutil,symsym;
+
+
+    function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
+      begin
+        result:=VOLATILE_INTREGISTERS;
+      end;
+
+
+    function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
+      begin
+        result:=VOLATILE_FPUREGISTERS;
+      end;
+
+
+    function getparaloc_fastcall(calloption : tproccalloption; 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:
+              result:=LOC_REGISTER;
+            enumdef:
+              result:=LOC_REGISTER;
+            pointerdef:
+              result:=LOC_REGISTER;
+            formaldef:
+              result:=LOC_REGISTER;
+            classrefdef:
+              result:=LOC_REGISTER;
+            recorddef:
+              result:=LOC_REGISTER;
+            objectdef:
+              result:=LOC_REGISTER;
+            stringdef:
+              if is_shortstring(p) or is_longstring(p) then
+                result:=LOC_REFERENCE
+              else
+                result:=LOC_REGISTER;
+            procvardef:
+              result:=LOC_REGISTER;
+            filedef:
+              result:=LOC_REGISTER;
+            arraydef:
+              if is_dynamic_array(p) then
+                result:=LOC_REGISTER
+              else
+                result:=LOC_REFERENCE;
+            setdef:
+              if is_smallset(p) then
+                result:=LOC_REGISTER
+              else
+                result:=LOC_REFERENCE;
+            variantdef:
+              result:=LOC_REGISTER;
+            { avoid problems with errornous definitions }
+            errordef:
+              result:=LOC_REGISTER;
+            else
+              internalerror(2017032603);
+         end;
+      end;
+
+
+    function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
+      begin
+        result:=false;
+        if varspez in [vs_var,vs_out,vs_constref] then
+          begin
+            result:=true;
+            exit;
+          end;
+        case def.typ of
+          objectdef:
+            result:=is_object(def) and ((varspez=vs_const) or (def.size=0));
+          recorddef:
+            result:=(varspez=vs_const) or (def.size=0);
+          variantdef,
+          formaldef:
+            result:=true;
+          arraydef:
+            result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
+                             is_open_array(def) or
+                             is_array_of_const(def) or
+                             is_array_constructor(def);
+          setdef :
+            result:=not is_smallset(def);
+          stringdef :
+            result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
+        else
+          result:=def.size>8;
+        end;
+      end;
+
+
+    function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
+      begin
+        if handle_common_ret_in_param(def,pd,result) then
+          exit;
+        case def.typ of
+          recorddef:
+            { this is how gcc 4.0.4 on linux seems to do it, it doesn't look like being
+              ARM ABI standard compliant
+            }
+            result:=not((trecorddef(def).symtable.SymList.count=1) and
+              not(ret_in_param(tabstractvarsym(trecorddef(def).symtable.SymList[0]).vardef,pd)));
+          {
+          objectdef
+          arraydef:
+            result:=not(def.size in [1,2,4]);
+          }
+          else
+            if (def.size > 8) then
+              result:=true
+            else
+              result:=inherited ret_in_param(def,pd);
+        end;
+      end;
+
+
+    procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
+      begin
+        curintreg:=RS_R25;
+        curfloatreg:=RS_INVALID;
+        curmmreg:=RS_INVALID;
+        cur_stack_offset:=0;
+      end;
+
+
+    { TODO : fix tcpuparamanager.create_paraloc_info_intern }
+    function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
+        var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
+
+      var
+        nextintreg,nextfloatreg,nextmmreg : tsuperregister;
+        paradef : tdef;
+        paraloc : pcgparalocation;
+        stack_offset : aword;
+        hp : tparavarsym;
+        loc : tcgloc;
+        paracgsize   : tcgsize;
+        paralen : longint;
+        i : integer;
+        firstparaloc: boolean;
+
+      procedure assignintreg;
+        begin
+          { In case of po_delphi_nested_cc, the parent frame pointer
+            is always passed on the stack. }
+           if (nextintreg>RS_R9) and
+              (not(vo_is_parentfp in hp.varoptions) or
+               not(po_delphi_nested_cc in p.procoptions)) then
+             begin
+               paraloc^.loc:=LOC_REGISTER;
+               paraloc^.register:=newreg(R_INTREGISTER,nextintreg-1,R_SUBWHOLE);
+               paraloc:=hp.paraloc[side].add_location;
+               paraloc^.loc:=LOC_REGISTER;
+               paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
+               dec(nextintreg,2);
+             end
+           else
+             begin
+               paraloc^.loc:=LOC_REFERENCE;
+               paraloc^.reference.index:=NR_STACK_POINTER_REG;
+               paraloc^.reference.offset:=stack_offset;
+               dec(stack_offset,2);
+            end;
+        end;
+
+
+      begin
+        result:=0;
+        nextintreg:=curintreg;
+        nextfloatreg:=curfloatreg;
+        nextmmreg:=curmmreg;
+        stack_offset:=cur_stack_offset;
+
+        for i:=0 to paras.count-1 do
+          begin
+            hp:=tparavarsym(paras[i]);
+            paradef:=hp.vardef;
+
+            hp.paraloc[side].reset;
+
+            { currently only support C-style array of const,
+              there should be no location assigned to the vararg array itself }
+            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_R25;
+                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)];
+                // loc := getparaloc(p.proccalloption,paradef);
+                loc:=LOC_REFERENCE;
+                if (paradef.typ in [objectdef,arraydef,recorddef]) and
+                  not is_special_array(paradef) and
+                  (hp.varspez in [vs_value,vs_const]) then
+                  paracgsize := int_cgsize(paralen)
+                else
+                  begin
+                    paracgsize:=def_cgsize(paradef);
+                    { for things like formaldef }
+                    if (paracgsize=OS_NO) then
+                      begin
+                        paracgsize:=OS_ADDR;
+                        paralen:=tcgsize2size[OS_ADDR];
+                        paradef:=voidpointertype;
+                      end;
+                  end
+              end;
+
+             hp.paraloc[side].size:=paracgsize;
+             hp.paraloc[side].Alignment:=std_param_align;
+             hp.paraloc[side].intsize:=paralen;
+             hp.paraloc[side].def:=paradef;
+
+{$ifdef EXTDEBUG}
+             if paralen=0 then
+               internalerror(200410311);
+{$endif EXTDEBUG}
+             firstparaloc:=true;
+             if loc=LOC_REGISTER then
+               begin
+                 { the lsb is located in the register with the lowest number,
+                   by adding paralen mod 2, make the size even
+                 }
+                 nextintreg:=curintreg-(paralen+(paralen mod 2))+1;
+                 if nextintreg>=RS_R8 then
+                   curintreg:=nextintreg-1
+                 else
+                   begin
+                     curintreg:=RS_R7;
+                     loc:=LOC_REFERENCE;
+                   end;
+               end;
+             while paralen>0 do
+               begin
+                 paraloc:=hp.paraloc[side].add_location;
+
+                 if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
+                   case paracgsize of
+                     OS_F32:
+                       begin
+                         paraloc^.size:=OS_32;
+                         paraloc^.def:=u32inttype;
+                       end;
+                     OS_F64:
+                       begin
+                         paraloc^.size:=OS_32;
+                         paraloc^.def:=u32inttype;
+                       end;
+                     else
+                       internalerror(2005082901);
+                   end
+                 else
+                   begin
+                     paraloc^.size:=paracgsize;
+                     paraloc^.def:=paradef;
+                   end;
+                 case loc of
+                    LOC_REGISTER:
+                      begin
+                        if nextintreg>=RS_R8 then
+                          begin
+                            paraloc^.loc:=LOC_REGISTER;
+                            paraloc^.size:=OS_8;
+                            paraloc^.def:=u8inttype;
+                            paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
+                            inc(nextintreg);
+                          end
+                        else
+                          { parameters are always passed completely in registers or in memory on avr }
+                          internalerror(2015041002);
+                        dec(paralen,tcgsize2size[paraloc^.size]);
+                      end;
+                    LOC_REFERENCE:
+                      begin
+                        if push_addr_param(hp.varspez,paradef,p.proccalloption) then
+                          begin
+                            paraloc^.size:=OS_ADDR;
+                            paraloc^.def:=cpointerdef.getreusable_no_free(paradef);
+                            assignintreg
+                          end
+                        else
+                          begin
+                             paraloc^.def:=hp.vardef;
+                             paraloc^.loc:=LOC_REFERENCE;
+                             paraloc^.reference.index:=NR_STACK_POINTER_REG;
+                             paraloc^.reference.offset:=stack_offset;
+                             inc(stack_offset,hp.vardef.size);
+                          end;
+                        dec(paralen,hp.vardef.size);
+                      end;
+                    else
+                      internalerror(2002071002);
+                 end;
+                 if side=calleeside then
+                   begin
+                     if paraloc^.loc=LOC_REFERENCE then
+                       begin
+                         paraloc^.reference.index:=NR_FRAME_POINTER_REG;
+                         inc(paraloc^.reference.offset,2);
+                       end;
+                   end;
+                 firstparaloc:=false;
+               end;
+          end;
+        curfloatreg:=nextfloatreg;
+        curmmreg:=nextmmreg;
+        cur_stack_offset:=stack_offset;
+        result:=cur_stack_offset;
+      end;
+
+
+    function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
+      var
+        cur_stack_offset: aword;
+        curintreg, curfloatreg, curmmreg: tsuperregister;
+        retcgsize  : tcgsize;
+      begin
+        init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
+
+        result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
+
+        create_funcretloc_info(p,side);
+     end;
+
+
+    { TODO : fix tavrparamanager.get_funcretloc }
+    function  tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+      var
+        retcgsize : tcgsize;
+        paraloc : pcgparalocation;
+        reg : TRegister;
+      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) then
+              begin
+                case retcgsize of
+                  OS_64,
+                  OS_F64:
+                    begin
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
+                      paraloc^.size:=OS_32;
+                      paraloc^.def:=u32inttype;
+                      paraloc:=result.add_location;
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
+                      paraloc^.size:=OS_32;
+                      paraloc^.def:=u32inttype;
+                    end;
+                  OS_32,
+                  OS_F32:
+                    begin
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_FUNCTION_RETURN_REG;
+                      paraloc^.size:=OS_32;
+                      paraloc^.def:=u32inttype;
+                    end;
+                  else
+                    internalerror(2005082603);
+                end;
+              end
+            else
+              begin
+                paraloc^.loc:=LOC_FPUREGISTER;
+                paraloc^.register:=NR_FPU_RESULT_REG;
+                paraloc^.size:=retcgsize;
+                paraloc^.def:=result.def;
+              end;
+          end
+          { Return in register }
+        else
+          begin
+            case retcgsize of
+              OS_64,OS_S64:
+                begin
+                  for reg:=NR_R18 to NR_R25 do
+                    begin
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=reg;
+                      paraloc^.size:=OS_8;
+                      paraloc^.def:=u8inttype;
+                      if reg<>NR_R25 then
+                        paraloc:=result.add_location;
+                    end;
+                end;
+              OS_32,OS_S32:
+                begin
+                  for reg:=NR_R22 to NR_R25 do
+                    begin
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=reg;
+                      paraloc^.size:=OS_8;
+                      paraloc^.def:=u8inttype;
+                      if reg<>NR_R25 then
+                        paraloc:=result.add_location;
+                    end;
+                end;
+              OS_16,OS_S16:
+                begin
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_R24;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+
+                  paraloc:=result.add_location;
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_R25;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+                end;
+              OS_8,OS_S8:
+                begin
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_R24;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+                end;
+              else
+                internalerror(2014030101);
+            end;
+
+            {if retcgsize in [OS_64,OS_S64] then
+              begin
+                paraloc^.loc:=LOC_REGISTER;
+                paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
+                paraloc^.size:=OS_32;
+                paraloc^.def:=u32inttype;
+                paraloc:=result.add_location;
+                paraloc^.loc:=LOC_REGISTER;
+                paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
+                paraloc^.size:=OS_32;
+                paraloc^.def:=u32inttype;
+              end
+            else
+              begin
+                paraloc^.loc:=LOC_REGISTER;
+                paraloc^.register:=NR_FUNCTION_RETURN_REG;
+                paraloc^.size:=OS_INT;
+                paraloc^.def:=u16inttype;
+              end;}
+          end;
+      end;
+
+
+    function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):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,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
+        if (p.proccalloption in cstylearrayofconst) then
+          { just continue loading the parameters in the registers }
+          result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset)
+        else
+          internalerror(200410231);
+      end;
+
+begin
+   paramanager:=tcpuparamanager.create;
+end.

+ 81 - 0
compiler/z80/cpupi.pas

@@ -0,0 +1,81 @@
+{
+    Copyright (c) 2008 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
+       globtype,cutils,
+       procinfo,cpuinfo,psub;
+
+    type
+       tcpuprocinfo = class(tcgprocinfo)
+          // procedure handle_body_start;override;
+          // procedure after_pass1;override;
+          procedure set_first_temp_offset;override;
+          function calc_stackframe_size:longint;override;
+       end;
+
+
+  implementation
+
+    uses
+       globals,systems,
+       cpubase,
+       aasmtai,aasmdata,
+       tgobj,
+       symconst,symsym,paramgr,
+       cgbase,
+       cgobj,
+       aasmcpu;
+
+    procedure tcpuprocinfo.set_first_temp_offset;
+      begin
+        if tg.direction = -1 then
+          tg.setfirsttemp(-1)
+        else if not (po_nostackframe in procdef.procoptions) then
+          tg.setfirsttemp(maxpushedparasize+1)
+        else
+          tg.setfirsttemp(maxpushedparasize);
+      end;
+
+
+    function tcpuprocinfo.calc_stackframe_size:longint;
+      begin
+        if tg.lasttemp=2 then
+          { correct that lasttemp is 2 in case of an empty stack due to the post-decrement pushing and an additional correction
+            in tgobj.setfirsttemp.
+          }
+          result:=maxpushedparasize
+        else
+          result:=tg.direction*tg.lasttemp+maxpushedparasize;
+      end;
+
+
+begin
+   cprocinfo:=tcpuprocinfo;
+end.
+

+ 70 - 0
compiler/z80/cputarg.pas

@@ -0,0 +1,70 @@
+{
+    Copyright (c) 2001-2008 by Peter Vreman
+
+    Includes the Z80 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 NOTARGETEMBEDDED}
+      ,t_embed
+    {$endif}
+
+{**************************************
+             Assemblers
+**************************************}
+
+    {$ifndef NOAGZ80ASM}
+      ,agz80asm
+    {$endif}
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+  {$ifndef NoRaarmgas}
+//       ,raz80asm
+  {$endif NoRaarmgas}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoDbgStabs}
+      ,dbgstabs
+  {$endif NoDbgStabs}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+      ;
+
+end.

+ 63 - 0
compiler/z80/hlcgcpu.pas

@@ -0,0 +1,63 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit contains routines to create a pass-through high-level code
+    generator. This is used by most regular code generators.
+
+    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,
+    symdef,
+    hlcg2ll;
+
+  type
+    thlcgcpu = class(thlcg2ll)
+      procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
+    end;
+
+  procedure create_hlcodegen;
+
+implementation
+
+  uses
+    hlcgobj,
+    cgcpu;
+
+  procedure thlcgcpu.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+    begin
+      //internalerror(2011021324);
+    end;
+
+
+  procedure create_hlcodegen;
+    begin
+      hlcg:=thlcgcpu.create;
+      create_codegen;
+    end;
+
+begin
+  chlcgobj:=thlcgcpu;
+end.

+ 52 - 0
compiler/z80/raz80.pas

@@ -0,0 +1,52 @@
+{
+    Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
+
+    Handles the common arm 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 raz80;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      cpubase,
+      aasmtai,aasmdata,
+      rautils;
+
+    type
+      TZ80Operand=class(TOperand)
+      end;
+
+      TZ80Instruction=class(TInstruction)
+        function ConcatInstruction(p:TAsmList) : tai;override;
+      end;
+
+  implementation
+
+    uses
+      aasmcpu;
+
+    function TZ80Instruction.ConcatInstruction(p:TAsmList) : tai;
+      begin
+        result:=inherited ConcatInstruction(p);
+      end;
+
+
+end.

+ 732 - 0
compiler/z80/raz80asm.pas

@@ -0,0 +1,732 @@
+{
+    Copyright (c) 1998-2008 by Carl Eric Codere and Peter Vreman
+
+    Does the parsing for the Z80 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 raz80asm;
+
+{$i fpcdefs.inc}
+
+  Interface
+
+    uses
+      rasm,
+      raz80,
+      cpubase;
+
+    type
+      tz80reader = class(tasmreader)
+        function is_asmopcode(const s: string):boolean;override;
+        function is_register(const s:string):boolean;override;
+        procedure handleopcode;override;
+        procedure BuildReference(oper : tz80operand);
+        procedure BuildOperand(oper : tz80operand);
+        procedure BuildOpCode(instr : tz80instruction);
+        procedure ReadSym(oper : tz80operand);
+        procedure ConvertCalljmp(instr : tz80instruction);
+      end;
+
+
+  Implementation
+
+    uses
+      { helpers }
+      cutils,
+      { global }
+      globtype,globals,verbose,
+      systems,
+      { aasm }
+      cpuinfo,aasmbase,aasmtai,aasmdata,aasmcpu,
+      { symtable }
+      symconst,symbase,symtype,symsym,symtable,
+      { parser }
+      scanner,
+      procinfo,
+      itcpugas,
+      rabase,rautils,
+      cgbase,cgutils,cgobj
+      ;
+
+
+    function tz80attreader.is_register(const s:string):boolean;
+      type
+        treg2str = record
+          name : string[2];
+          reg : tregister;
+        end;
+
+      const
+        extraregs : array[0..8] of treg2str = (
+          (name: 'X'; reg : NR_R26),
+          (name: 'XL'; reg : NR_R26),
+          (name: 'XH'; reg : NR_R27),
+          (name: 'Y'; reg : NR_R28),
+          (name: 'YL'; reg : NR_R28),
+          (name: 'YH'; reg : NR_R29),
+          (name: 'Z'; reg : NR_R30),
+          (name: 'ZL'; reg : NR_R30),
+          (name: 'ZH'; reg : NR_R31)
+        );
+
+      var
+        i : longint;
+
+      begin
+        result:=inherited is_register(s);
+        { reg found?
+          possible aliases are always 2 char
+        }
+        if result or (not (length(s) in [1,2])) 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;
+
+
+    procedure tz80attreader.ReadSym(oper : tz80operand);
+      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 tz80attreader.BuildReference(oper : tz80operand);
+
+      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;
+
+
+      procedure read_index;
+        begin
+          Consume(AS_COMMA);
+          if actasmtoken=AS_REGISTER then
+            Begin
+              oper.opr.ref.index:=actasmregister;
+              Consume(AS_REGISTER);
+            end
+          else if actasmtoken=AS_HASH then
+            begin
+              Consume(AS_HASH);
+              inc(oper.opr.ref.offset,BuildConstExpression(false,true));
+            end;
+        end;
+
+
+      begin
+        Consume(AS_LPAREN);
+        if actasmtoken=AS_REGISTER then
+          begin
+            oper.opr.ref.base:=actasmregister;
+            Consume(AS_REGISTER);
+            { can either be a register or a right parenthesis }
+            { (reg)        }
+            if actasmtoken=AS_LPAREN then
+             Begin
+               Consume_RParen;
+               exit;
+             end;
+            if actasmtoken=AS_PLUS then
+              begin
+                consume(AS_PLUS);
+                oper.opr.ref.addressmode:=AM_POSTINCREMENT;
+              end;
+          end {end case }
+        else
+          Begin
+            Message(asmr_e_invalid_reference_syntax);
+            RecoverConsume(false);
+          end;
+      end;
+
+
+    Procedure tz80attreader.BuildOperand(oper : tz80operand);
+      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;
+            mangledname:='';
+            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
+                     (tabstractnormalvarsym(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 :
+                inc(oper.opr.val,l);
+              OPR_REFERENCE :
+                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.RefAsmSymbol(mangledname,AT_FUNCTION);
+                  end
+                else
+                  inc(oper.opr.val,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;
+        ireg : tsuperregister;
+        hl : tasmlabel;
+        ofs : longint;
+        registerset : tcpuregisterset;
+        tempstr : string;
+        tempsymtyp : tasmsymtype;
+      Begin
+        expr:='';
+        case actasmtoken of
+          AS_LBRACKET: { Memory reference or constant expression }
+            Begin
+              oper.InitRef;
+              BuildReference(oper);
+            end;
+
+          AS_INTNUM,
+          AS_MINUS,
+          AS_PLUS:
+            Begin
+              if (actasmtoken=AS_MINUS) and
+                 (actopcode in [A_LD,A_ST]) then
+                begin
+                  { Special handling of predecrement addressing }
+                  oper.InitRef;
+                  oper.opr.ref.addressmode:=AM_PREDRECEMENT;
+
+                  consume(AS_MINUS);
+
+                  if actasmtoken=AS_REGISTER then
+                    begin
+                      oper.opr.ref.base:=actasmregister;
+                      consume(AS_REGISTER);
+                    end
+                  else
+                    begin
+                      Message(asmr_e_invalid_reference_syntax);
+                      RecoverConsume(false);
+                    end;
+                end
+              else
+                begin
+                  { Constant memory offset }
+                  { This must absolutely be followed by (  }
+                  oper.InitRef;
+                  oper.opr.ref.offset:=BuildConstExpression(True,False);
+
+                  { absolute memory addresss? }
+                  if actopcode in [A_LDS,A_STS] then
+                    BuildReference(oper)
+                  else
+                    begin
+                      ofs:=oper.opr.ref.offset;
+                      BuildConstantOperand(oper);
+                      inc(oper.opr.val,ofs);
+                    end;
+                end;
+            end;
+
+          AS_ID: { A constant expression, or a Variable ref.  }
+            Begin
+              if (actasmpattern='LO8') or (actasmpattern='HI8') then
+                begin
+                  { Low or High part of a constant (or constant
+                    memory location) }
+                  oper.InitRef;
+                  if actasmpattern='LO8' then
+                    oper.opr.ref.refaddr:=addr_lo8
+                  else
+                    oper.opr.ref.refaddr:=addr_hi8;
+                  Consume(actasmtoken);
+                  Consume(AS_LPAREN);
+                  BuildConstSymbolExpression(false, true,false,l,tempstr,tempsymtyp);
+                  if not assigned(oper.opr.ref.symbol) then
+                    oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr,tempsymtyp)
+                  else
+                    Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                  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;
+                  Consume(AS_RPAREN);
+                end
+              { Local Label ? }
+              else if is_locallabel(actasmpattern) then
+               begin
+                 CreateLocalLabel(actasmpattern,hl,false);
+                 Consume(AS_ID);
+                 AddLabelOperand(hl);
+               end
+              { Check for label }
+              else 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 not(oper.SetupVar(expr,false)) then
+                        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;
+
+          { Register, a variable reference or a constant reference  }
+          AS_REGISTER:
+            Begin
+              { save the type of register used. }
+              tempreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (actasmtoken=AS_PLUS) then
+                begin
+                  oper.opr.typ:=OPR_REFERENCE;
+
+                  reference_reset_base(oper.opr.ref,tempreg,0,1,[]);
+                  oper.opr.ref.addressmode:=AM_POSTINCREMENT;
+
+                  consume(AS_PLUS);
+                end
+              else 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 }
+      end;
+
+
+{*****************************************************************************
+                                tz80attreader
+*****************************************************************************}
+
+    procedure tz80attreader.BuildOpCode(instr : tz80instruction);
+      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
+                  Inc(operandnum);
+                Consume(AS_COMMA);
+              end;
+            AS_SEPARATOR,
+            AS_END : { End of asm operands for this opcode  }
+              begin
+                break;
+              end;
+          else
+            BuildOperand(instr.Operands[operandnum] as tz80operand);
+          end; { end case }
+        until false;
+        instr.Ops:=operandnum;
+      end;
+
+
+    function tz80attreader.is_asmopcode(const s: string):boolean;
+
+      const
+        { sorted by length so longer postfixes will match first }
+        postfix2strsorted : array[1..19] of string[2] = (
+          'EP','SB','BT','SH',
+          'IA','IB','DA','DB','FD','FA','ED','EA',
+          'B','D','E','P','T','H','S');
+
+      var
+        len,
+        j,
+        sufidx : longint;
+        hs : string;
+        maxlen : longint;
+        icond : tasmcond;
+      Begin
+        { making s a value parameter would break other assembler readers }
+        hs:=s;
+        is_asmopcode:=false;
+
+        { clear op code }
+        actopcode:=A_None;
+
+        actcondition:=C_None;
+
+        { first, handle B else BLS is read wrong }
+        if ((copy(hs,1,2)='BR') and (length(hs)=4)) then
+          begin
+            for icond:=low(tasmcond) to high(tasmcond) do
+              begin
+                if copy(hs,2,3)=uppercond2str[icond] then
+                  begin
+                    actopcode:=A_BRxx;
+                    actasmtoken:=AS_OPCODE;
+                    actcondition:=icond;
+                    is_asmopcode:=true;
+                    exit;
+                  end;
+              end;
+          end;
+        maxlen:=max(length(hs),5);
+        actopcode:=A_NONE;
+        for j:=maxlen downto 1 do
+          begin
+            actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
+            if actopcode<>A_NONE then
+              begin
+                actasmtoken:=AS_OPCODE;
+                { strip op code }
+                delete(hs,1,j);
+                break;
+              end;
+          end;
+        if actopcode=A_NONE then
+          exit;
+        { search for condition, conditions are always 2 chars }
+        if length(hs)>1 then
+          begin
+            for icond:=low(tasmcond) to high(tasmcond) do
+              begin
+                if copy(hs,1,2)=uppercond2str[icond] then
+                  begin
+                    actcondition:=icond;
+                    { strip condition }
+                    delete(hs,1,2);
+                    break;
+                  end;
+              end;
+          end;
+        { if we stripped all postfixes, it's a valid opcode }
+        is_asmopcode:=length(hs)=0;
+      end;
+
+
+    procedure tz80attreader.ConvertCalljmp(instr : tz80instruction);
+      var
+        newopr : toprrec;
+      begin
+        if instr.Operands[1].opr.typ=OPR_REFERENCE then
+          begin
+            newopr.typ:=OPR_SYMBOL;
+            newopr.symbol:=instr.Operands[1].opr.ref.symbol;
+            newopr.symofs:=instr.Operands[1].opr.ref.offset;
+            if (instr.Operands[1].opr.ref.base<>NR_NO) or
+              (instr.Operands[1].opr.ref.index<>NR_NO) then
+              Message(asmr_e_syn_operand);
+            instr.Operands[1].opr:=newopr;
+          end;
+      end;
+
+
+    procedure tz80attreader.handleopcode;
+      var
+        instr : tz80instruction;
+      begin
+        instr:=tz80instruction.Create(tz80operand);
+        BuildOpcode(instr);
+{        if is_calljmp(instr.opcode) then
+          ConvertCalljmp(instr); }
+        {
+        instr.AddReferenceSizes;
+        instr.SetInstructionOpsize;
+        instr.CheckOperandSizes;
+        }
+        instr.ConcatInstruction(curlist);
+        instr.Free;
+      end;
+
+
+{*****************************************************************************
+                                     Initialize
+*****************************************************************************}
+
+const
+  asmmode_z80_att_info : tasmmodeinfo =
+          (
+            id    : asmmode_z80_gas;
+            idtxt : 'GAS';
+            casmreader : tz80attreader;
+          );
+
+  asmmode_z80_standard_info : tasmmodeinfo =
+          (
+            id    : asmmode_standard;
+            idtxt : 'STANDARD';
+            casmreader : tz80attreader;
+          );
+
+initialization
+  RegisterAsmMode(asmmode_z80_att_info);
+  RegisterAsmMode(asmmode_z80_standard_info);
+end.

+ 205 - 0
compiler/z80/rgcpu.pas

@@ -0,0 +1,205 @@
+{
+    Copyright (c) 1998-2008 by Florian Klaempfl
+
+    This unit implements the avr 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,aasmsym,
+       cgbase,cgutils,
+       cpubase,
+       rgobj;
+
+     type
+       trgcpu = class(trgobj)
+         procedure add_constraints(reg:tregister);override;
+         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;
+         function do_spill_replace(list : TAsmList;instr : tai_cpu_abstract_sym; orgreg : tsuperregister;const spilltemp : treference) : boolean; override;
+       end;
+
+       trgintcpu = class(trgcpu)
+         procedure add_cpu_interferences(p : tai);override;
+       end;
+
+  implementation
+
+    uses
+      verbose, cutils,
+      cgobj,
+      procinfo;
+
+
+    procedure trgcpu.add_constraints(reg:tregister);
+      var
+        supreg,i : Tsuperregister;
+      begin
+        case getsubreg(reg) of
+          { Let 64bit floats conflict with all odd float regs }
+          R_SUBFD:
+            begin
+            {
+              supreg:=getsupreg(reg);
+              i:=RS_F1;
+              while (i<=RS_F31) do
+                begin
+                  add_edge(supreg,i);
+                  inc(i,2);
+                end;
+            }
+            end;
+          { Let 64bit ints conflict with all odd int regs }
+          R_SUBQ:
+            begin
+              supreg:=getsupreg(reg);
+              {
+              i:=RS_G1;
+              while (i<=RS_I7) do
+                begin
+                  add_edge(supreg,i);
+                  inc(i,2);
+                end;
+              }
+            end;
+        end;
+      end;
+
+
+    procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
+      var
+        helpins  : tai;
+        tmpref   : treference;
+        helplist : TAsmList;
+        hreg     : tregister;
+      begin
+        if abs(spilltemp.offset)>63 then
+          begin
+            helplist:=TAsmList.create;
+
+            helplist.concat(taicpu.op_reg_const(A_LDI,NR_R26,lo(word(spilltemp.offset))));
+            helplist.concat(taicpu.op_reg_const(A_LDI,NR_R27,hi(word(spilltemp.offset))));
+            helplist.concat(taicpu.op_reg_reg(A_ADD,NR_R26,spilltemp.base));
+            helplist.concat(taicpu.op_reg_reg(A_ADC,NR_R27,GetNextReg(spilltemp.base)));
+
+            reference_reset_base(tmpref,NR_R26,0,1,[]);
+            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 abs(spilltemp.offset)>63 then
+          begin
+            helplist:=TAsmList.create;
+
+            helplist.concat(taicpu.op_reg_const(A_LDI,NR_R26,lo(word(spilltemp.offset))));
+            helplist.concat(taicpu.op_reg_const(A_LDI,NR_R27,hi(word(spilltemp.offset))));
+            helplist.concat(taicpu.op_reg_reg(A_ADD,NR_R26,spilltemp.base));
+            helplist.concat(taicpu.op_reg_reg(A_ADC,NR_R27,GetNextReg(spilltemp.base)));
+
+            reference_reset_base(tmpref,NR_R26,0,1,[]);
+            helplist.concat(spilling_create_store(tempreg,tmpref));
+            list.insertlistafter(pos,helplist);
+            helplist.free;
+          end
+        else
+          inherited;
+      end;
+
+
+    procedure trgintcpu.add_cpu_interferences(p : tai);
+      var
+        r : tsuperregister;
+      begin
+        //if p.typ=ait_instruction then
+        //  begin
+        //    case taicpu(p).opcode of
+        //      A_CPI,
+        //      A_ANDI,
+        //      A_ORI,
+        //      A_SUBI,
+        //      A_SBCI,
+        //      A_LDI:
+        //        for r:=RS_R0 to RS_R15 do
+        //          add_edge(r,GetSupReg(taicpu(p).oper[0]^.reg));
+        //      A_MULS:
+        //        begin
+        //          for r:=RS_R0 to RS_R15 do
+        //            add_edge(r,GetSupReg(taicpu(p).oper[0]^.reg));
+        //          for r:=RS_R0 to RS_R15 do
+        //            add_edge(r,GetSupReg(taicpu(p).oper[1]^.reg));
+        //        end;
+        //    end;
+        //  end;
+      end;
+
+
+    function trgcpu.do_spill_replace(list:TAsmList;instr:tai_cpu_abstract_sym;orgreg:tsuperregister;const spilltemp:treference):boolean;
+      var
+        b : byte;
+      begin
+        result:=false;
+        if not(spilltemp.offset in [0..63]) then
+          exit;
+
+        { Replace 'mov  dst,orgreg' with 'ld  dst,spilltemp'
+          and     'mov  orgreg,src' with 'st  dst,spilltemp' }
+        with instr do
+          begin
+            if (opcode=A_LD) and (ops=2) and (oper[1]^.typ=top_reg) and (oper[0]^.typ=top_reg) then
+              begin
+                if (getregtype(oper[0]^.reg)=regtype) and
+                   (get_alias(getsupreg(oper[0]^.reg))=orgreg) and
+                   (get_alias(getsupreg(oper[1]^.reg))<>orgreg) then
+                  begin
+                    instr.loadreg(0,oper[1]^.reg);
+                    instr.loadref(1,spilltemp);
+                    opcode:=A_LD;
+                    result:=true;
+                  end
+                else if (getregtype(oper[1]^.reg)=regtype) and
+                   (get_alias(getsupreg(oper[1]^.reg))=orgreg) and
+                   (get_alias(getsupreg(oper[0]^.reg))<>orgreg) then
+                  begin
+                    instr.loadref(0,spilltemp);
+                    opcode:=A_LD;
+                    result:=true;
+                  end;
+              end;
+          end;
+      end;
+
+end.

+ 35 - 0
compiler/z80/rz80con.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.dat }
+NR_NO = tregister($00000000);
+NR_R0 = tregister($01000000);
+NR_R1 = tregister($01000001);
+NR_R2 = tregister($01000002);
+NR_R3 = tregister($01000003);
+NR_R4 = tregister($01000004);
+NR_R5 = tregister($01000005);
+NR_R6 = tregister($01000006);
+NR_R7 = tregister($01000007);
+NR_R8 = tregister($01000008);
+NR_R9 = tregister($01000009);
+NR_R10 = tregister($0100000a);
+NR_R11 = tregister($0100000b);
+NR_R12 = tregister($0100000c);
+NR_R13 = tregister($0100000d);
+NR_R14 = tregister($0100000e);
+NR_R15 = tregister($0100000f);
+NR_R16 = tregister($01000010);
+NR_R17 = tregister($01000011);
+NR_R18 = tregister($01000012);
+NR_R19 = tregister($01000013);
+NR_R20 = tregister($01000014);
+NR_R21 = tregister($01000015);
+NR_R22 = tregister($01000016);
+NR_R23 = tregister($01000017);
+NR_R24 = tregister($01000018);
+NR_R25 = tregister($01000019);
+NR_R26 = tregister($0100001a);
+NR_R27 = tregister($0100001b);
+NR_R28 = tregister($0100001c);
+NR_R29 = tregister($0100001d);
+NR_R30 = tregister($0100001e);
+NR_R31 = tregister($0100001f);
+NR_SREG = tregister($05000000);

+ 35 - 0
compiler/z80/rz80dwa.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.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

+ 2 - 0
compiler/z80/rz80nor.inc

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

+ 35 - 0
compiler/z80/rz80num.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.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($05000000)

+ 35 - 0
compiler/z80/rz80rni.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.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

+ 35 - 0
compiler/z80/rz80sri.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.dat }
+0,
+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,
+33

+ 35 - 0
compiler/z80/rz80sta.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.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

+ 35 - 0
compiler/z80/rz80std.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.dat }
+'INVALID',
+'r0',
+'r1',
+'r2',
+'r3',
+'r4',
+'r5',
+'r6',
+'r7',
+'r8',
+'r9',
+'r10',
+'r11',
+'r12',
+'r13',
+'r14',
+'r15',
+'r16',
+'r17',
+'r18',
+'r19',
+'r20',
+'r21',
+'r22',
+'r23',
+'r24',
+'r25',
+'r26',
+'r27',
+'r28',
+'r29',
+'r30',
+'r31',
+'sreg'

+ 35 - 0
compiler/z80/rz80sup.inc

@@ -0,0 +1,35 @@
+{ don't edit, this file is generated from z80reg.dat }
+RS_NO = $00;
+RS_R0 = $00;
+RS_R1 = $01;
+RS_R2 = $02;
+RS_R3 = $03;
+RS_R4 = $04;
+RS_R5 = $05;
+RS_R6 = $06;
+RS_R7 = $07;
+RS_R8 = $08;
+RS_R9 = $09;
+RS_R10 = $0a;
+RS_R11 = $0b;
+RS_R12 = $0c;
+RS_R13 = $0d;
+RS_R14 = $0e;
+RS_R15 = $0f;
+RS_R16 = $10;
+RS_R17 = $11;
+RS_R18 = $12;
+RS_R19 = $13;
+RS_R20 = $14;
+RS_R21 = $15;
+RS_R22 = $16;
+RS_R23 = $17;
+RS_R24 = $18;
+RS_R25 = $19;
+RS_R26 = $1a;
+RS_R27 = $1b;
+RS_R28 = $1c;
+RS_R29 = $1d;
+RS_R30 = $1e;
+RS_R31 = $1f;
+RS_SREG = $00;

+ 216 - 0
compiler/z80/symcpu.pas

@@ -0,0 +1,216 @@
+{
+    Copyright (c) 2014 by Florian Klaempfl
+
+    Symbol table overrides for Z80
+
+    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
+
+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.
+

+ 44 - 0
compiler/z80/z80reg.dat

@@ -0,0 +1,44 @@
+;
+; AVR registers
+;
+; layout
+; <name>,<type>,<value>,<stdname>,<stab idx>,<dwarf idx>
+;
+NO,$00,$00,INVALID,-1,-1
+
+R0,$01,$00,r0,0,0
+R1,$01,$01,r1,1,1
+R2,$01,$02,r2,2,2
+R3,$01,$03,r3,3,3
+R4,$01,$04,r4,4,4
+R5,$01,$05,r5,5,5
+R6,$01,$06,r6,6,6
+R7,$01,$07,r7,7,7
+R8,$01,$08,r8,8,8
+R9,$01,$09,r9,9,9
+R10,$01,$0a,r10,10,10
+R11,$01,$0b,r11,11,11
+R12,$01,$0c,r12,12,12
+R13,$01,$0d,r13,13,13
+R14,$01,$0e,r14,14,14
+R15,$01,$0f,r15,15,15
+R16,$01,$10,r16,16,16
+R17,$01,$11,r17,17,17
+R18,$01,$12,r18,18,18
+R19,$01,$13,r19,19,19
+R20,$01,$14,r20,20,20
+R21,$01,$15,r21,21,21
+R22,$01,$16,r22,22,22
+R23,$01,$17,r23,23,23
+R24,$01,$18,r24,24,24
+R25,$01,$19,r25,25,25
+R26,$01,$1a,r26,26,26
+R27,$01,$1b,r27,27,27
+R28,$01,$1c,r28,28,28
+R29,$01,$1d,r29,29,29
+R30,$01,$1e,r30,30,30
+R31,$01,$1f,r31,31,31
+
+SREG,$05,$00,sreg,0,0
+
+