ソースを参照

+ skeleton for Z80 support

git-svn-id: branches/z80@35665 -
florian 8 年 前
コミット
ea52a23179

+ 29 - 0
.gitattributes

@@ -637,6 +637,7 @@ compiler/ppcmipsel.lpi svneol=native#text/plain
 compiler/ppcppc.lpi svneol=native#text/plain
 compiler/ppcppc64.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/ppu.pas 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/mkx86ins.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/msgdif.pp 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/x8664pro.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_add1.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
-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
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16
@@ -306,7 +306,7 @@ UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
 ifeq ($(UNITSDIR),)
 UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
 endif
-PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages)
 ifndef FPCFPMAKE
 ifdef CROSSCOMPILE
 ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),)
@@ -815,6 +815,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override TARGET_DIRS+=utils
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override TARGET_DIRS+=utils
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override TARGET_PROGRAMS+=pp
 endif
@@ -1067,6 +1070,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override TARGET_PROGRAMS+=pp
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override TARGET_PROGRAMS+=pp
+endif
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
@@ -1320,6 +1326,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
@@ -1572,6 +1581,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_TARGETDIR+=.
 endif
@@ -1824,6 +1836,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_TARGETDIR+=.
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_TARGETDIR+=.
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
@@ -2076,6 +2091,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 endif
@@ -2993,6 +3011,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 REQUIRE_PACKAGES_RTL=1
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+REQUIRE_PACKAGES_RTL=1
+endif
 ifdef REQUIRE_PACKAGES_RTL
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 ifneq ($(PACKAGEDIR_RTL),)
@@ -3886,6 +3907,9 @@ endif
 ifeq ($(FULL_TARGET),aarch64-darwin)
 TARGET_DIRS_UTILS=1
 endif
+ifeq ($(FULL_TARGET),wasm-wasm)
+TARGET_DIRS_UTILS=1
+endif
 ifdef TARGET_DIRS_UTILS
 utils_all:
 	$(MAKE) -C utils all
@@ -4105,7 +4129,10 @@ regdataarch64 : aarch64/a64reg.dat
 regdatmips : mips/mipsreg.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
 	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 :
 ifneq ($(REVSTR),)
 ifdef USEZIPWRAPPER

+ 5 - 1
compiler/Makefile.fpc

@@ -548,7 +548,11 @@ regdatmips : mips/mipsreg.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
         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 :

+ 1 - 1
compiler/aggas.pas

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

+ 12 - 0
compiler/fpcdefs.inc

@@ -232,6 +232,18 @@
   {$define SUPPORT_GET_FRAME}
 {$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}
 {$DEFINE USE_FAKE_SYSUTILS}
 {$ENDIF MACOS}

+ 10 - 0
compiler/globals.pas

@@ -495,6 +495,16 @@ interface
         asmcputype : cpu_none;
         fputype : fpu_x87;
   {$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}
         asmmode : asmmode_standard;
 {$ifndef jvm}

+ 7 - 0
compiler/pp.pas

@@ -32,6 +32,7 @@ program pp;
   SPARC               generate a compiler for SPARC
   POWERPC             generate a compiler for the PowerPC
   POWERPC64           generate a compiler for the PowerPC64 architecture
+  Z80                 generate a compiler for Z80
   DEBUG               version with debug code is generated
   EXTDEBUG            some extra debug code is executed
   SUPPORT_MMX         only i386: releases the compiler switch
@@ -134,6 +135,12 @@ program pp;
   {$endif CPUDEFINED}
   {$define CPUDEFINED}
 {$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}
   {$fatal A CPU type switch must be defined}
 {$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_embedded,     { 90 }
              system_arm_aros,           { 91 }
-             system_wasm_wasm32         { 92 }
+             system_wasm_wasm32,        { 92 }
+             system_z80_embedded        { 93 }
        );
 
      type
@@ -229,6 +230,7 @@
              ,as_m68k_vasm
              ,as_m68k_as_aout
              ,as_wasm_binaryen
+             ,as_z80asm
        );
 
        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
+
+