Browse Source

* merged the z80 branch

git-svn-id: trunk@45143 -
nickysn 5 years ago
parent
commit
29d681168a
100 changed files with 13028 additions and 327 deletions
  1. 69 0
      .gitattributes
  2. 30 1
      Makefile
  3. 3 0
      Makefile.fpc
  4. 73 4
      compiler/Makefile
  5. 20 3
      compiler/Makefile.fpc
  6. 3 0
      compiler/aarch64/agcpugas.pas
  7. 15 3
      compiler/aasmbase.pas
  8. 29 29
      compiler/aggas.pas
  9. 3 0
      compiler/arm/agarmgas.pas
  10. 1 0
      compiler/arm/cpuelf.pas
  11. 3 2
      compiler/avr/agavrgas.pas
  12. 4 0
      compiler/cgbase.pas
  13. 8 4
      compiler/cgobj.pas
  14. 6 6
      compiler/dbgstabs.pas
  15. 4 4
      compiler/dbgstabx.pas
  16. 4 2
      compiler/entfile.pas
  17. 17 0
      compiler/fpcdefs.inc
  18. 10 0
      compiler/globals.pas
  19. 1 0
      compiler/i386/cpuelf.pas
  20. 1 0
      compiler/jvm/agjasmin.pas
  21. 24 4
      compiler/link.pas
  22. 3 1
      compiler/llvm/agllvm.pas
  23. 2 0
      compiler/m68k/ag68kgas.pas
  24. 1 0
      compiler/m68k/ag68kvasm.pas
  25. 2 0
      compiler/mips/cpugas.pas
  26. 6 0
      compiler/msg/errore.msg
  27. 1 1
      compiler/msgidx.inc
  28. 198 191
      compiler/msgtxt.inc
  29. 25 5
      compiler/nadd.pas
  30. 2 2
      compiler/ncal.pas
  31. 13 1
      compiler/ngenutil.pas
  32. 113 30
      compiler/ninl.pas
  33. 6 0
      compiler/ogcoff.pas
  34. 1 0
      compiler/ogmacho.pas
  35. 1 0
      compiler/ognlm.pas
  36. 1 0
      compiler/ogomf.pas
  37. 16 3
      compiler/options.pas
  38. 8 8
      compiler/pass_1.pas
  39. 1 0
      compiler/powerpc/agppcmpw.pas
  40. 1 0
      compiler/powerpc/agppcvasm.pas
  41. 8 1
      compiler/pp.pas
  42. 11 5
      compiler/ppcgen/agppcgas.pas
  43. 2 2
      compiler/ppcgen/cgppc.pas
  44. 81 0
      compiler/ppcz80.lpi
  45. 7 0
      compiler/psystem.pas
  46. 2 0
      compiler/rautils.pas
  47. 4 3
      compiler/riscv/agrvgas.pas
  48. 1 0
      compiler/sparc/cpuelf.pas
  49. 2 0
      compiler/sparc64/cpugas.pas
  50. 4 0
      compiler/sparcgen/cpugas.pas
  51. 11 3
      compiler/systems.inc
  52. 11 5
      compiler/systems.pas
  53. 73 0
      compiler/systems/i_embed.pas
  54. 108 0
      compiler/systems/i_zxspectrum.pas
  55. 267 0
      compiler/systems/t_embed.pas
  56. 305 0
      compiler/systems/t_zxspectrum.pas
  57. 37 1
      compiler/utils/Makefile
  58. 232 0
      compiler/utils/mkz80ins.pp
  59. 270 0
      compiler/utils/mkz80reg.pp
  60. 7 3
      compiler/utils/ppuutils/ppudump.pp
  61. 13 0
      compiler/x86/agx86att.pas
  62. 4 0
      compiler/x86/agx86int.pas
  63. 15 0
      compiler/x86/agx86nsm.pas
  64. 1 0
      compiler/x86_64/cpuelf.pas
  65. 1 0
      compiler/xtensa/agcpugas.pas
  66. 490 0
      compiler/z80/aasmcpu.pas
  67. 902 0
      compiler/z80/agsdasz80.pas
  68. 447 0
      compiler/z80/agz80asm.pas
  69. 242 0
      compiler/z80/aoptcpu.pas
  70. 132 0
      compiler/z80/aoptcpub.pas
  71. 40 0
      compiler/z80/aoptcpud.pas
  72. 2486 0
      compiler/z80/cgcpu.pas
  73. 506 0
      compiler/z80/cpubase.pas
  74. 130 0
      compiler/z80/cpuinfo.pas
  75. 51 0
      compiler/z80/cpunode.pas
  76. 533 0
      compiler/z80/cpupara.pas
  77. 70 0
      compiler/z80/cpupi.pas
  78. 76 0
      compiler/z80/cputarg.pas
  79. 88 0
      compiler/z80/hlcgcpu.pas
  80. 667 0
      compiler/z80/nz80add.pas
  81. 71 0
      compiler/z80/nz80cal.pas
  82. 156 0
      compiler/z80/nz80mat.pas
  83. 71 0
      compiler/z80/nz80mem.pas
  84. 52 0
      compiler/z80/raz80.pas
  85. 2390 0
      compiler/z80/raz80asm.pas
  86. 260 0
      compiler/z80/rgcpu.pas
  87. 28 0
      compiler/z80/rz80con.inc
  88. 28 0
      compiler/z80/rz80dwa.inc
  89. 2 0
      compiler/z80/rz80nor.inc
  90. 28 0
      compiler/z80/rz80num.inc
  91. 28 0
      compiler/z80/rz80rni.inc
  92. 28 0
      compiler/z80/rz80sri.inc
  93. 28 0
      compiler/z80/rz80sta.inc
  94. 28 0
      compiler/z80/rz80std.inc
  95. 28 0
      compiler/z80/rz80sup.inc
  96. 216 0
      compiler/z80/symcpu.pas
  97. 67 0
      compiler/z80/tgcpu.pas
  98. 381 0
      compiler/z80/z80ins.dat
  99. 2 0
      compiler/z80/z80nop.inc
  100. 70 0
      compiler/z80/z80op.inc

+ 69 - 0
.gitattributes

@@ -666,6 +666,7 @@ compiler/ppcsparc64.lpi svneol=native#text/plain
 compiler/ppcx64.lpi svneol=native#text/plain
 compiler/ppcx64llvm.lpi svneol=native#text/plain
 compiler/ppcxtensa.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/procdefutil.pas svneol=native#text/plain
@@ -857,6 +858,7 @@ compiler/systems/i_wdosx.pas svneol=native#text/plain
 compiler/systems/i_wii.pas svneol=native#text/plain
 compiler/systems/i_win.pas svneol=native#text/plain
 compiler/systems/i_win16.pas svneol=native#text/plain
+compiler/systems/i_zxspectrum.pas svneol=native#text/plain
 compiler/systems/mac_crea.txt svneol=native#text/plain
 compiler/systems/t_aix.pas svneol=native#text/plain
 compiler/systems/t_amiga.pas svneol=native#text/plain
@@ -890,6 +892,7 @@ compiler/systems/t_wdosx.pas svneol=native#text/plain
 compiler/systems/t_wii.pas svneol=native#text/plain
 compiler/systems/t_win.pas svneol=native#text/plain
 compiler/systems/t_win16.pas svneol=native#text/plain
+compiler/systems/t_zxspectrum.pas svneol=native#text/plain
 compiler/tgobj.pas svneol=native#text/plain
 compiler/tokens.pas svneol=native#text/plain
 compiler/utils/Makefile svneol=native#text/plain
@@ -921,6 +924,8 @@ compiler/utils/mkx86inl.pp svneol=native#text/plain
 compiler/utils/mkx86ins.pp svneol=native#text/plain
 compiler/utils/mkx86reg.pp svneol=native#text/plain
 compiler/utils/mkxtensareg.pp svneol=native#text/pascal
+compiler/utils/mkz80ins.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
@@ -1052,6 +1057,44 @@ compiler/xtensa/symcpu.pas svneol=native#text/pascal
 compiler/xtensa/xtensaatt.inc svneol=native#text/plain
 compiler/xtensa/xtensaop.inc svneol=native#text/plain
 compiler/xtensa/xtensareg.dat svneol=native#text/plain
+compiler/z80/aasmcpu.pas svneol=native#text/plain
+compiler/z80/agsdasz80.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/nz80add.pas svneol=native#text/plain
+compiler/z80/nz80cal.pas svneol=native#text/plain
+compiler/z80/nz80mat.pas svneol=native#text/plain
+compiler/z80/nz80mem.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/tgcpu.pas svneol=native#text/plain
+compiler/z80/z80ins.dat svneol=native#text/plain
+compiler/z80/z80nop.inc svneol=native#text/plain
+compiler/z80/z80op.inc svneol=native#text/plain
+compiler/z80/z80reg.dat svneol=native#text/plain
+compiler/z80/z80stdopnames.inc svneol=native#text/plain
+compiler/z80/z80tab.inc svneol=native#text/plain
 /fpmake.pp svneol=native#text/plain
 /fpmake_add1.inc svneol=native#text/plain
 /fpmake_proc1.inc svneol=native#text/plain
@@ -12142,6 +12185,24 @@ rtl/xtensa/setjumph.inc svneol=native#text/plain
 rtl/xtensa/strings.inc svneol=native#text/plain
 rtl/xtensa/stringss.inc svneol=native#text/plain
 rtl/xtensa/xtensa.inc svneol=native#text/plain
+rtl/z80/cpuh.inc svneol=native#text/plain
+rtl/z80/int64p.inc svneol=native#text/plain
+rtl/z80/makefile.cpu svneol=native#text/plain
+rtl/z80/math.inc svneol=native#text/plain
+rtl/z80/set.inc svneol=native#text/plain
+rtl/z80/setjump.inc svneol=native#text/plain
+rtl/z80/setjumph.inc svneol=native#text/plain
+rtl/z80/z80.inc svneol=native#text/plain
+rtl/zxspectrum/Makefile svneol=native#text/plain
+rtl/zxspectrum/Makefile.fpc svneol=native#text/plain
+rtl/zxspectrum/prt0.asm svneol=native#text/plain
+rtl/zxspectrum/rtldefs.inc svneol=native#text/plain
+rtl/zxspectrum/sysdir.inc svneol=native#text/plain
+rtl/zxspectrum/sysfile.inc svneol=native#text/plain
+rtl/zxspectrum/sysheap.inc svneol=native#text/plain
+rtl/zxspectrum/sysos.inc svneol=native#text/plain
+rtl/zxspectrum/sysosh.inc svneol=native#text/plain
+rtl/zxspectrum/system.pp svneol=native#text/plain
 tests/MPWMake -text
 tests/Makefile svneol=native#text/plain
 tests/Makefile.fpc svneol=native#text/plain
@@ -19074,6 +19135,14 @@ utils/h2pas/scan.pas svneol=native#text/plain
 utils/h2pas/testit.h -text
 utils/h2pas/yylex.cod svneol=native#text/plain
 utils/h2pas/yyparse.cod svneol=native#text/plain
+utils/ihx2tzx/Makefile svneol=native#text/plain
+utils/ihx2tzx/Makefile.fpc svneol=native#text/plain
+utils/ihx2tzx/fpmake.pp svneol=native#text/plain
+utils/ihx2tzx/ihx2tzx.lpi svneol=native#text/plain
+utils/ihx2tzx/ihx2tzx.lpr svneol=native#text/plain
+utils/ihx2tzx/ihxreader.pas svneol=native#text/plain
+utils/ihx2tzx/tzxwriter.pas svneol=native#text/plain
+utils/ihx2tzx/zxbasic.pas svneol=native#text/plain
 utils/importtl/Makefile svneol=native#text/plain
 utils/importtl/Makefile.fpc svneol=native#text/plain
 utils/importtl/Makefile.fpc.fpcmake svneol=native#text/plain

+ 30 - 1
Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: help
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos 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 aarch64-win64 aarch64-android wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos 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 aarch64-win64 aarch64-android wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -416,6 +416,9 @@ endif
 ifeq ($(CPU_TARGET),xtensa)
 PPSUF=xtensa
 endif
+ifeq ($(CPU_TARGET),z80)
+PPSUF=z80
+endif
 ifdef CROSSCOMPILE
 ifneq ($(CPU_TARGET),jvm)
 PPPRE=ppcross
@@ -799,6 +802,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_DIRS+=compiler rtl utils packages installer
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
 override INSTALL_FPCPACKAGE=y
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
@@ -1245,6 +1254,9 @@ STATICLIBEXT=.a
 else
 EXEEXT=.bin
 endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
 SHORTSUFFIX=emb
 endif
 ifeq ($(OS_TARGET),win16)
@@ -1253,6 +1265,9 @@ STATICLIBEXT=.a
 SHAREDLIBEXT=.dll
 SHORTSUFFIX=w16
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
@@ -2705,6 +2720,20 @@ TARGET_DIRS_UTILS=1
 TARGET_DIRS_PACKAGES=1
 TARGET_DIRS_INSTALLER=1
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
 ifdef TARGET_DIRS_COMPILER
 compiler_all:
 	$(MAKE) -C compiler all

+ 3 - 0
Makefile.fpc

@@ -94,6 +94,9 @@ endif
 ifeq ($(CPU_TARGET),xtensa)
 PPSUF=xtensa
 endif
+ifeq ($(CPU_TARGET),z80)
+PPSUF=z80
+endif
 
 # cross compilers uses full cpu_target, not just ppc-suffix
 # (except if the target cannot run a native compiler)

+ 73 - 4
compiler/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos 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 aarch64-win64 aarch64-android wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos 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 aarch64-win64 aarch64-android wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -350,7 +350,7 @@ endif
 override PACKAGE_NAME=compiler
 override PACKAGE_VERSION=3.3.1
 unexport FPC_VERSION FPC_COMPILERINFO
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80
 ALLTARGETS=$(CYCLETARGETS)
 ifdef POWERPC
 PPC_TARGET=powerpc
@@ -406,6 +406,9 @@ endif
 ifdef XTENSA
 PPC_TARGET=xtensa
 endif
+ifdef Z80
+PPC_TARGET=z80
+endif
 ifndef PPC_TARGET
 PPC_TARGET=$(CPU_TARGET)
 endif
@@ -516,6 +519,9 @@ endif
 ifeq ($(CPC_TARGET),xtensa)
 CPUSUF=xtensa
 endif
+ifeq ($(CPC_TARGET),z80)
+CPUSUF=z80
+endif
 NOCPUDEF=1
 MSGFILE=msg/error$(FPCLANG).msg
 SVNVERSION:=$(firstword $(wildcard $(addsuffix /svnversion$(SRCEXEEXT),$(SEARCHPATH))))
@@ -631,6 +637,9 @@ endif
 ifeq ($(OS_TARGET),freertos)
 NoNativeBinaries=1
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+NoNativeBinaries=1
+endif
 ifeq ($(NoNativeBinaries),1)
 override EXEEXT=$(SRCEXEEXT)
 CROSSINSTALL=1
@@ -926,6 +935,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_DIRS+=utils
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override TARGET_DIRS+=utils
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override TARGET_PROGRAMS+=pp
 endif
@@ -1217,6 +1232,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_PROGRAMS+=pp
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override TARGET_PROGRAMS+=pp
+endif
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
@@ -1509,6 +1530,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
@@ -1800,6 +1827,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 endif
@@ -2091,6 +2124,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
@@ -2382,6 +2421,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 endif
@@ -2827,6 +2872,9 @@ STATICLIBEXT=.a
 else
 EXEEXT=.bin
 endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
 SHORTSUFFIX=emb
 endif
 ifeq ($(OS_TARGET),win16)
@@ -2835,6 +2883,9 @@ STATICLIBEXT=.a
 SHAREDLIBEXT=.dll
 SHORTSUFFIX=w16
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
@@ -3381,6 +3432,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 REQUIRE_PACKAGES_RTL=1
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+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),)
@@ -4323,6 +4380,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 TARGET_DIRS_UTILS=1
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+TARGET_DIRS_UTILS=1
+endif
 ifdef TARGET_DIRS_UTILS
 utils_all:
 	$(MAKE) -C utils all
@@ -4603,7 +4666,10 @@ insdatarm : arm/armins.dat
 insdataarch64 : aarch64/a64ins.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mka64ins.pp
 	cd aarch64 && ..$(PATHSEP)utils$(PATHSEP)mka64ins$(SRCEXEEXT)
-insdat: insdatx86 insdatarm insdataarch64
+insdatz80 : z80/z80ins.dat
+	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80ins.pp
+	cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80ins$(SRCEXEEXT)
+insdat: insdatx86 insdatarm insdataarch64 insdatz80
 regdatx86 : x86/x86reg.dat
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86reg.pp
 	cd x86 && ..$(PATHSEP)utils$(PATHSEP)mkx86reg$(SRCEXEEXT) i8086
@@ -4632,7 +4698,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 regdatsp64
+regdatz80 : z80/z80reg.dat
+	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80reg.pp
+	cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80reg$(SRCEXEEXT)
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80
 revision.inc :
 ifneq ($(REVSTR),)
 ifdef USEZIPWRAPPER

+ 20 - 3
compiler/Makefile.fpc

@@ -32,7 +32,7 @@ fpcdir=..
 unexport FPC_VERSION FPC_COMPILERINFO
 
 # Which platforms are ready for inclusion in the cycle
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80
 
 # All supported targets used for clean
 ALLTARGETS=$(CYCLETARGETS)
@@ -92,6 +92,9 @@ endif
 ifdef XTENSA
 PPC_TARGET=xtensa
 endif
+ifdef Z80
+PPC_TARGET=z80
+endif
 
 # Default is to generate a compiler for the same
 # platform as CPU_TARGET (a native compiler)
@@ -230,6 +233,9 @@ endif
 ifeq ($(CPC_TARGET),xtensa)
 CPUSUF=xtensa
 endif
+ifeq ($(CPC_TARGET),z80)
+CPUSUF=z80
+endif
 
 # Do not define the default -d$(CPU_TARGET) because that
 # will conflict with our -d$(CPC_TARGET)
@@ -400,6 +406,9 @@ endif
 ifeq ($(OS_TARGET),freertos)
 NoNativeBinaries=1
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+NoNativeBinaries=1
+endif
 
 # Allow install for jvm
 ifeq ($(NoNativeBinaries),1)
@@ -702,7 +711,11 @@ insdataarch64 : aarch64/a64ins.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mka64ins.pp
         cd aarch64 && ..$(PATHSEP)utils$(PATHSEP)mka64ins$(SRCEXEEXT)
 
-insdat: insdatx86 insdatarm insdataarch64
+insdatz80 : z80/z80ins.dat
+	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80ins.pp
+        cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80ins$(SRCEXEEXT)
+
+insdat: insdatx86 insdatarm insdataarch64 insdatz80
 
 regdatx86 : x86/x86reg.dat
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86reg.pp
@@ -739,7 +752,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 regdatsp64
+regdatz80 : z80/z80reg.dat
+            $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80reg.pp
+        cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80reg$(SRCEXEEXT)
+
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80
 
 # revision.inc rule
 revision.inc :

+ 3 - 0
compiler/aarch64/agcpugas.pas

@@ -789,6 +789,7 @@ unit agcpugas;
             supported_targets : [system_aarch64_linux,system_aarch64_android];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '// ';
             dollarsign: '$';
           );
@@ -802,6 +803,7 @@ unit agcpugas;
             supported_targets : [system_aarch64_darwin];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -815,6 +817,7 @@ unit agcpugas;
             supported_targets : [system_aarch64_win64];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '// ';
             dollarsign: '$';
           );

+ 15 - 3
compiler/aasmbase.pas

@@ -240,7 +240,7 @@ interface
     function create_smartlink_library:boolean;inline;
     function create_smartlink:boolean;inline;
 
-    function ReplaceForbiddenAsmSymbolChars(const s: ansistring): ansistring;
+    function ApplyAsmSymbolRestrictions(const s: ansistring): ansistring;
 
     { dummy default noop callback }
     procedure default_global_used;
@@ -257,7 +257,7 @@ interface
 implementation
 
     uses
-      verbose;
+      verbose,fpccrc;
 
 
     function create_smartlink_sections:boolean;inline;
@@ -288,16 +288,28 @@ implementation
       end;
 
 
-    function ReplaceForbiddenAsmSymbolChars(const s: ansistring): ansistring;
+    function ApplyAsmSymbolRestrictions(const s: ansistring): ansistring;
       var
         i : longint;
         rchar: char;
+        crc: Cardinal;
+        charstoremove: integer;
       begin
         Result:=s;
         rchar:=target_asm.dollarsign;
         for i:=1 to Length(Result) do
           if Result[i]='$' then
             Result[i]:=rchar;
+        if (target_asm.labelmaxlen<>-1) and (Length(Result)>target_asm.labelmaxlen) then
+          begin
+            crc:=0;
+            crc:=UpdateCrc32(crc,Result[1],Length(Result));
+            charstoremove:=Length(Result)-target_asm.labelmaxlen+13;
+            Delete(Result,(Length(Result)-charstoremove) div 2,charstoremove);
+            Result:='_'+target_asm.dollarsign+'CRC'+hexstr(crc,8)+Result;
+            if Length(Result)>target_asm.labelmaxlen then
+              Internalerror(2020042501);
+          end;
       end;
 
 

+ 29 - 29
compiler/aggas.pas

@@ -873,7 +873,7 @@ implementation
              begin
                if tai_section(hp).sectype<>sec_none then
                  if replaceforbidden then
-                   WriteSection(tai_section(hp).sectype,ReplaceForbiddenAsmSymbolChars(tai_section(hp).name^),tai_section(hp).secorder,
+                   WriteSection(tai_section(hp).sectype,ApplyAsmSymbolRestrictions(tai_section(hp).name^),tai_section(hp).secorder,
                      tai_section(hp).secalign,tai_section(hp).secflags,tai_section(hp).secprogbits)
                  else
                    WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder,
@@ -925,8 +925,8 @@ implementation
                    if tai_datablock(hp).is_global then
                      begin
                        writer.AsmWrite(#9'.globl ');
-                       writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
-                       writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
+                       writer.AsmWriteln(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
+                       writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
                        writer.AsmWriteln(':');
                        writer.AsmWrite(#9'.space ');
                        writer.AsmWriteln(tostr(tai_datablock(hp).size));
@@ -936,7 +936,7 @@ implementation
                    else
                      begin
                        writer.AsmWrite(#9'.lcomm ');
-                       writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
+                       writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
                        writer.AsmWrite(',');
                        writer.AsmWrite(tostr(tai_datablock(hp).size)+',');
                        writer.AsmWrite('_data.bss_,');
@@ -956,7 +956,7 @@ implementation
                          begin
                            writer.AsmWrite(#9'.comm'#9);
                            if replaceforbidden then
-                             writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name))
+                             writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name))
                            else
                              writer.AsmWrite(tai_datablock(hp).sym.name);
                            writer.AsmWrite(','+tostr(tai_datablock(hp).size));
@@ -967,7 +967,7 @@ implementation
                          begin
                            writer.AsmWrite(#9'.lcomm'#9);
                            if replaceforbidden then
-                             writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
+                             writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
                            else
                              writer.AsmWrite(tai_datablock(hp).sym.name);
                            writer.AsmWrite(','+tostr(tai_datablock(hp).size));
@@ -984,7 +984,7 @@ implementation
                              WriteHiddenSymbol(tai_datablock(hp).sym);
                            writer.AsmWrite(#9'.globl ');
                            if replaceforbidden then
-                             writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name))
+                             writer.AsmWriteln(ApplyAsmSymbolRestrictions(Tai_datablock(hp).sym.name))
                            else
                              writer.AsmWriteln(Tai_datablock(hp).sym.name);
                          end;
@@ -995,10 +995,10 @@ implementation
                        if replaceforbidden then
                          begin
                            if (tf_needs_symbol_type in target_info.flags) then
-                             writer.AsmWriteln(#9'.type '+ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)+','+sepChar+'object');
+                             writer.AsmWriteln(#9'.type '+ApplyAsmSymbolRestrictions(Tai_datablock(hp).sym.name)+','+sepChar+'object');
                            if (tf_needs_symbol_size in target_info.flags) and (tai_datablock(hp).size > 0) then
-                              writer.AsmWriteln(#9'.size '+ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)+','+tostr(Tai_datablock(hp).size));
-                           writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name))
+                              writer.AsmWriteln(#9'.size '+ApplyAsmSymbolRestrictions(Tai_datablock(hp).sym.name)+','+tostr(Tai_datablock(hp).size));
+                           writer.AsmWrite(ApplyAsmSymbolRestrictions(Tai_datablock(hp).sym.name))
                          end
                        else
                          begin
@@ -1198,7 +1198,7 @@ implementation
                                else
                                  s:=tai_const(hp).sym.name;
                                if replaceforbidden then
-                                 s:=ReplaceForbiddenAsmSymbolChars(s);
+                                 s:=ApplyAsmSymbolRestrictions(s);
                                if tai_const(hp).value<>0 then
                                  s:=s+tostr_with_plus(tai_const(hp).value);
                              end
@@ -1300,12 +1300,12 @@ implementation
 {$endif arm}
                      writer.AsmWrite('.globl'#9);
                      if replaceforbidden then
-                       writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
+                       writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
                      else
                        writer.AsmWriteLn(tai_label(hp).labsym.name);
                    end;
                   if replaceforbidden then
-                    writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
+                    writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
                   else
                     writer.AsmWrite(tai_label(hp).labsym.name);
                   writer.AsmWriteLn(':');
@@ -1323,7 +1323,7 @@ implementation
                 begin
                   writer.AsmWrite('.globl'#9);
                   if replaceforbidden then
-                    writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name))
+                    writer.AsmWriteln(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name))
                   else
                     writer.AsmWriteln(tai_symbol(hp).sym.name);
                   if (tai_symbol(hp).sym.bind=AB_PRIVATE_EXTERN) then
@@ -1358,14 +1358,14 @@ implementation
                        s:=#9'.llong .';
                        ch:='3';
                      end;
-                   writer.AsmWriteLn(#9'.csect '+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+'[DS],'+ch);
-                   writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+':');
-                   writer.AsmWriteln(s+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+', TOC[tc0], 0');
+                   writer.AsmWriteLn(#9'.csect '+ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name)+'[DS],'+ch);
+                   writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name)+':');
+                   writer.AsmWriteln(s+ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name)+', TOC[tc0], 0');
                    writer.AsmWriteln(#9'.csect .text[PR]');
                    if (tai_symbol(hp).is_global) then
-                     writer.AsmWriteLn('.globl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name))
+                     writer.AsmWriteLn('.globl .'+ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name))
                    else
-                     writer.AsmWriteLn('.lglobl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name));
+                     writer.AsmWriteLn('.lglobl .'+ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name));
                    { the dotted name is the name of the actual function entry }
                    writer.AsmWrite('.');
                  end
@@ -1386,9 +1386,9 @@ implementation
                  end;
                if replaceforbidden then
                  if not(tai_symbol(hp).has_value) then
-                   writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name + ':'))
+                   writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name + ':'))
                  else
-                   writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value)))
+                   writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value)))
                else if not(tai_symbol(hp).has_value) then
                  writer.AsmWriteLn(tai_symbol(hp).sym.name + ':')
                else
@@ -1408,13 +1408,13 @@ implementation
                if replaceforbidden then
                  begin
                    { avoid string truncation }
-                   writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^));
+                   writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_symbolpair(hp).sym^));
                    writer.AsmWrite(s);
-                   writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).value^));
+                   writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbolpair(hp).value^));
                    if tai_symbolpair(hp).kind=spk_set_global then
                      begin
                        writer.AsmWrite(#9'.globl ');
-                       writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^));
+                       writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbolpair(hp).sym^));
                      end;
                  end
                else
@@ -1443,7 +1443,7 @@ implementation
                      (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
                     writer.AsmWrite('.');
                   if replaceforbidden then
-                    writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name))
+                    writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_symbol_end(hp).sym.name))
                   else
                     writer.AsmWrite(tai_symbol_end(hp).sym.name);
                   writer.AsmWrite(', '+s+' - ');
@@ -1452,7 +1452,7 @@ implementation
                      (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
                     writer.AsmWrite('.');
                   if replaceforbidden then
-                    writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name))
+                    writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol_end(hp).sym.name))
                   else
                     writer.AsmWriteLn(tai_symbol_end(hp).sym.name);
                 end;
@@ -1527,7 +1527,7 @@ implementation
                if tai_directive(hp).name <>'' then
                  begin
                    if replaceforbidden then
-                     writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_directive(hp).name))
+                     writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_directive(hp).name))
                    else
                      writer.AsmWrite(tai_directive(hp).name);
                  end;
@@ -1617,7 +1617,7 @@ implementation
         if asminfo^.dollarsign='$' then
           writer.AsmWriteLn(s.name)
         else
-          writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(s.name))
+          writer.AsmWriteLn(ApplyAsmSymbolRestrictions(s.name))
       end;
 
 
@@ -1635,7 +1635,7 @@ implementation
         if asminfo^.dollarsign='$' then
           writer.AsmWriteLn(sym.name)
         else
-          writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(sym.name))
+          writer.AsmWriteLn(ApplyAsmSymbolRestrictions(sym.name))
       end;
 
 

+ 3 - 0
compiler/arm/agarmgas.pas

@@ -445,6 +445,7 @@ unit agarmgas;
                                  system_arm_embedded,system_arm_symbian,system_arm_android,system_arm_aros,system_arm_freertos];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -458,6 +459,7 @@ unit agarmgas;
             supported_targets : [system_arm_darwin];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -472,6 +474,7 @@ unit agarmgas;
             supported_targets : [system_arm_darwin];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );

+ 1 - 0
compiler/arm/cpuelf.pas

@@ -977,6 +977,7 @@ implementation
                               system_arm_aros,system_arm_freertos];
          flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '';
          dollarsign: '$';
        );

+ 3 - 2
compiler/avr/agavrgas.pas

@@ -122,7 +122,7 @@ unit agavrgas;
               else if assigned(symbol) or (offset<>0) then
                 begin
                   if assigned(symbol) then
-                    s:=ReplaceForbiddenAsmSymbolChars(symbol.name);
+                    s:=ApplyAsmSymbolRestrictions(symbol.name);
 
                   if s='' then
                     s:=tostr(offset)
@@ -165,7 +165,7 @@ unit agavrgas;
             top_ref:
               if o.ref^.refaddr=addr_full then
                 begin
-                  hs:=ReplaceForbiddenAsmSymbolChars(o.ref^.symbol.name);
+                  hs:=ApplyAsmSymbolRestrictions(o.ref^.symbol.name);
                   if o.ref^.offset>0 then
                     hs:=hs+'+'+tostr(o.ref^.offset)
                   else if o.ref^.offset<0 then
@@ -216,6 +216,7 @@ unit agavrgas;
             supported_targets : [system_avr_embedded];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: 's';
           );

+ 4 - 0
compiler/cgbase.pas

@@ -107,6 +107,10 @@ interface
          ,addr_hi8
          ,addr_hi8_gs
          {$ENDIF}
+         {$IFDEF Z80}
+         ,addr_lo8
+         ,addr_hi8
+         {$ENDIF}
          {$IFDEF i8086}
          ,addr_dgroup      // the data segment group
          ,addr_fardataseg  // the far data segment of the current pascal module (unit or program)

+ 8 - 4
compiler/cgobj.pas

@@ -742,15 +742,15 @@ implementation
 {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
     function tcg.GetNextReg(const r: TRegister): TRegister;
       begin
-{$ifndef AVR}
+{$ifdef AVR}
         { the AVR code generator depends on the fact that it can do GetNextReg also on physical registers }
+        if (getsupreg(r)>=first_int_imreg) and not(has_next_reg[getsupreg(r)]) then
+          internalerror(2017091103);
+{$else AVR}
         if getsupreg(r)<first_int_imreg then
           internalerror(2013051401);
         if not has_next_reg[getsupreg(r)] then
           internalerror(2017091103);
-{$else AVR}
-        if (getsupreg(r)>=first_int_imreg) and not(has_next_reg[getsupreg(r)]) then
-          internalerror(2017091103);
 {$endif AVR}
         if getregtype(r)<>R_INTREGISTER then
           internalerror(2017091101);
@@ -2103,6 +2103,8 @@ implementation
                     a_load_const_reg(list,OS_8,0,dst);
                     exit;
                   end;
+                else
+                  ;
               end;
           end;
         OP_SHR:
@@ -2115,6 +2117,8 @@ implementation
                     a_load_const_reg(list,OS_8,0,GetNextReg(dst));
                     exit;
                   end;
+                else
+                  ;
               end;
           end;
 {$endif cpu8bitalu}

+ 6 - 6
compiler/dbgstabs.pas

@@ -197,7 +197,7 @@ implementation
       if (Sym.typ=typesym) and (ttypesym(Sym).Fprettyname<>'') then
         result:=ttypesym(Sym).FPrettyName;
       if target_asm.dollarsign<>'$' then
-        result:=ReplaceForbiddenAsmSymbolChars(result);
+        result:=ApplyAsmSymbolRestrictions(result);
     end;
 
     function GetSymTableName(SymTable : TSymTable) : string;
@@ -207,7 +207,7 @@ implementation
       else
         result := SymTable.RealName^;
       if target_asm.dollarsign<>'$' then
-        result:=ReplaceForbiddenAsmSymbolChars(result);
+        result:=ApplyAsmSymbolRestrictions(result);
     end;
 
     const
@@ -1190,7 +1190,7 @@ implementation
         if s='name' then
           result:=GetSymName(sym)
         else if s='mangledname' then
-          result:=ReplaceForbiddenAsmSymbolChars(sym.mangledname)
+          result:=ApplyAsmSymbolRestrictions(sym.mangledname)
         else if s='ownername' then
           result:=GetSymTableName(sym.owner)
         else if s='line' then
@@ -1217,7 +1217,7 @@ implementation
 
     function TDebugInfoStabs.staticvarsym_mangled_name(sym: tstaticvarsym): string;
       begin
-        result:=ReplaceForbiddenAsmSymbolChars(sym.mangledname);
+        result:=ApplyAsmSymbolRestrictions(sym.mangledname);
       end;
 
 
@@ -1228,7 +1228,7 @@ implementation
            assigned(def.owner.name) then
           list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
                  def_stab_number(vmttype)+'",'+
-                 base_stabs_str(globalvarsym_inited_stab,'0','0',ReplaceForbiddenAsmSymbolChars(tobjectdef(def).vmt_mangledname))));
+                 base_stabs_str(globalvarsym_inited_stab,'0','0',ApplyAsmSymbolRestrictions(tobjectdef(def).vmt_mangledname))));
       end;
 
 
@@ -1401,7 +1401,7 @@ implementation
                assigned(tprocdef(def.owner.defowner).procsym) then
               info := ','+GetSymName(def.procsym)+','+GetSymName(tprocdef(def.owner.defowner).procsym);
           end;
-        mangledname:=ReplaceForbiddenAsmSymbolChars(def.mangledname);
+        mangledname:=ApplyAsmSymbolRestrictions(def.mangledname);
         if target_info.system in systems_dotted_function_names then
           mangledname:='.'+mangledname;
         result.concat(Tai_stab.Create_ansistr(stabsdir,'"'+obj+':'+RType+def_stab_number(def.returndef)+info+'",'+

+ 4 - 4
compiler/dbgstabx.pas

@@ -95,7 +95,7 @@ implementation
     begin
       { create reference to the local symbol at the same address as the global
         symbol (with same name as unmangled symbol, so GDB can find it) }
-      Result:=ReplaceForbiddenAsmSymbolChars(sym.name);
+      Result:=ApplyAsmSymbolRestrictions(sym.name);
     end;
 
 
@@ -109,7 +109,7 @@ implementation
              assigned(def.owner.name) then
             list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
                    def_stab_number(vmttype)+'",'+
-                   base_stabs_str(globalvarsym_inited_stab,'0','0',ReplaceForbiddenAsmSymbolChars(tobjectdef(def).vmt_mangledname)+'.')));
+                   base_stabs_str(globalvarsym_inited_stab,'0','0',ApplyAsmSymbolRestrictions(tobjectdef(def).vmt_mangledname)+'.')));
         end;
 *)
       { do nothing, because creating debug information for a global symbol
@@ -193,7 +193,7 @@ implementation
         the place where it is defined }
       if not assigned(def.procstarttai) then
         exit;
-      mangledname:=ReplaceForbiddenAsmSymbolChars(def.mangledname);
+      mangledname:=ApplyAsmSymbolRestrictions(def.mangledname);
       if target_info.system in systems_dotted_function_names then
         mangledname:='.'+mangledname;
       result.concat(tai_stab.create(stabx_function,
@@ -254,7 +254,7 @@ implementation
       result:=inherited gen_procdef_endsym_stabs(def);
       if not assigned(def.procstarttai) then
         exit;
-      procendsymbol:=current_asmdata.DefineAsmSymbol('LT..'+ReplaceForbiddenAsmSymbolChars(def.mangledname),AB_LOCAL,AT_ADDR,voidpointertype);
+      procendsymbol:=current_asmdata.DefineAsmSymbol('LT..'+ApplyAsmSymbolRestrictions(def.mangledname),AB_LOCAL,AT_ADDR,voidpointertype);
       current_asmdata.asmlists[al_procedures].insertbefore(tai_symbol.create(procendsymbol,0),def.procendtai);
     end;
 

+ 4 - 2
compiler/entfile.pas

@@ -160,7 +160,8 @@ const
     { 18 } 64 {'sparc64'},
     { 19 } 32 {'riscv32'},
     { 20 } 64 {'riscv64'},
-    { 21 } 32 {'xtensa'}
+    { 21 } 32 {'xtensa'},
+    { 22 } 16 {'z80'}
     );
   CpuAluBitSize : array[tsystemcpu] of longint =
     (
@@ -185,7 +186,8 @@ const
     { 18 } 64 {'sparc64'},
     { 19 } 32 {'riscv32'},
     { 20 } 64 {'riscv64'},
-    { 21 } 32 {'xtensa'}
+    { 21 } 32 {'xtensa'},
+    { 22 }  8 {'z80'}
     );
 {$endif generic_cpu}
 

+ 17 - 0
compiler/fpcdefs.inc

@@ -295,6 +295,23 @@
   {$define cpurequiresproperalignment}
 {$endif riscv32}
 
+{$ifdef z80}
+  {$define cpu8bit}
+  {$define cpu16bitaddr}
+  {$define cpu8bitalu}
+  {$define cpufpemu}
+  {$define cpuflags}
+  {$define cpunofpu}
+  {$define cpunodefaultint}
+  {$define cpuneedsdivhelper}
+  {$define cpuneedsmulhelper}
+  {$define cpucapabilities}
+{$endif z80}
+
+{$IFDEF MACOS}
+{$DEFINE USE_FAKE_SYSUTILS}
+{$ENDIF MACOS}
+
 {$ifdef riscv64}
   {$define riscv}
   {$define cpu64bit}

+ 10 - 0
compiler/globals.pas

@@ -561,6 +561,16 @@ interface
         asmcputype : cpu_none;
         fputype : fpu_none;
   {$endif xtensa}
+  {$ifdef z80}
+        cputype : cpu_zilog_z80;
+        optimizecputype : cpu_zilog_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}

+ 1 - 0
compiler/i386/cpuelf.pas

@@ -524,6 +524,7 @@ implementation
                               system_i386_android,system_i386_aros];
          flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '';
          dollarsign: '$';
        );

+ 1 - 0
compiler/jvm/agjasmin.pas

@@ -1237,6 +1237,7 @@ implementation
          supported_targets : [system_jvm_java32,system_jvm_android32];
          flags : [];
          labelprefix : 'L';
+         labelmaxlen : -1;
          comment : ' ; ';
          dollarsign : '$';
        );

+ 24 - 4
compiler/link.pas

@@ -867,7 +867,8 @@ Implementation
 
 
         scripted_ar:=(target_ar.id=ar_gnu_ar_scripted) or
-                     (target_ar.id=ar_watcom_wlib_omf_scripted);
+                     (target_ar.id=ar_watcom_wlib_omf_scripted) or
+                     (target_ar.id=ar_sdcc_sdar_scripted);
 
         if scripted_ar then
           begin
@@ -876,7 +877,7 @@ Implementation
             Assign(script, scriptfile);
             Rewrite(script);
             try
-              if (target_ar.id=ar_gnu_ar_scripted) then
+              if (target_ar.id in [ar_gnu_ar_scripted,ar_sdcc_sdar_scripted]) then
                 writeln(script, 'CREATE ' + current_module.staticlibfilename)
               else { wlib case }
                 writeln(script,'-q -fo -c -b '+
@@ -884,13 +885,13 @@ Implementation
               current := TCmdStrListItem(SmartLinkOFiles.First);
               while current <> nil do
                 begin
-                  if (target_ar.id=ar_gnu_ar_scripted) then
+                  if (target_ar.id in [ar_gnu_ar_scripted,ar_sdcc_sdar_scripted]) then
                   writeln(script, 'ADDMOD ' + current.str)
                   else
                     writeln(script,'+' + current.str);
                   current := TCmdStrListItem(current.next);
                 end;
-              if (target_ar.id=ar_gnu_ar_scripted) then
+              if (target_ar.id in [ar_gnu_ar_scripted,ar_sdcc_sdar_scripted]) then
                 begin
                   writeln(script, 'SAVE');
                   writeln(script, 'END');
@@ -1742,6 +1743,23 @@ Implementation
             arfinishcmd : ''
           );
 
+      ar_sdcc_sdar_info : tarinfo =
+          ( id          : ar_sdcc_sdar;
+          addfilecmd  : '';
+          arfirstcmd  : '';
+          arcmd       : 'sdar qS $LIB $FILES';
+          arfinishcmd : 'sdar s $LIB'
+          );
+
+      ar_sdcc_sdar_scripted_info : tarinfo =
+          (
+            id    : ar_sdcc_sdar_scripted;
+            addfilecmd  : '';
+            arfirstcmd  : '';
+            arcmd : 'sdar -M < $SCRIPT';
+            arfinishcmd : ''
+          );
+
 
 initialization
   RegisterAr(ar_gnu_ar_info);
@@ -1749,4 +1767,6 @@ initialization
   RegisterAr(ar_gnu_gar_info);
   RegisterAr(ar_watcom_wlib_omf_info);
   RegisterAr(ar_watcom_wlib_omf_scripted_info);
+  RegisterAr(ar_sdcc_sdar_info);
+  RegisterAr(ar_sdcc_sdar_scripted_info);
 end.

+ 3 - 1
compiler/llvm/agllvm.pas

@@ -1271,7 +1271,7 @@ implementation
                      writer.AsmWriteln(asminfo^.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
                    end;
                  if replaceforbidden then
-                   writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
+                   writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
                  else
                    writer.AsmWrite(tai_label(hp).labsym.name);
                  writer.AsmWriteLn(':');
@@ -1737,6 +1737,7 @@ implementation
           supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_aarch64_linux,system_arm_linux];
           flags : [af_smartlink_sections,af_llvm];
           labelprefix : 'L';
+          labelmaxlen : -1;
           comment : '; ';
           dollarsign: '$';
         );
@@ -1751,6 +1752,7 @@ implementation
           supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_aarch64_linux,system_arm_linux];
           flags : [af_smartlink_sections,af_llvm];
           labelprefix : 'L';
+          labelmaxlen : -1;
           comment : '; ';
           dollarsign: '$';
         );

+ 2 - 0
compiler/m68k/ag68kgas.pas

@@ -355,6 +355,7 @@ interface
             supported_targets : [system_m68k_macos,system_m68k_linux,system_m68k_PalmOS,system_m68k_netbsd,system_m68k_embedded];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -368,6 +369,7 @@ interface
             supported_targets : [system_m68k_Amiga,system_m68k_Atari];
             flags : [af_needar];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );

+ 1 - 0
compiler/m68k/ag68kvasm.pas

@@ -136,6 +136,7 @@ unit ag68kvasm;
          supported_targets : [system_m68k_amiga,system_m68k_atari];
          flags : [af_needar,af_smartlink_sections];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign: '$';
        );

+ 2 - 0
compiler/mips/cpugas.pas

@@ -263,6 +263,7 @@ unit cpugas;
         supported_targets: [system_mipsel_linux,system_mipsel_android,system_mipsel_embedded];
         flags: [ af_needar, af_smartlink_sections];
         labelprefix: '.L';
+        labelmaxlen : -1;
         comment: '# ';
         dollarsign: '$';
         );
@@ -276,6 +277,7 @@ unit cpugas;
         supported_targets: [system_mipseb_linux];
         flags: [ af_needar, af_smartlink_sections];
         labelprefix: '.L';
+        labelmaxlen : -1;
         comment: '# ';
         dollarsign: '$';
         );

+ 6 - 0
compiler/msg/errore.msg

@@ -3818,6 +3818,7 @@ new features, etc.):
 #    s = Sparc64 targets
 #    V = AVR
 #    x = xtensa targets
+#    Z = Z80
 # The second character also indicates who will display this line,
 # (if the above character was TRUE) the current possibilities are :
 #    * = everyone
@@ -3880,6 +3881,8 @@ F*0*_Only options valid for the default or selected platform are listed.
 A*2Aas_Assemble using GNU AS
 P*2Aas_Assemble using GNU AS
 S*2Aas_Assemble using GNU AS
+Z*2Asdcc-sdasz80_Assemble using SDCC-SDASZ80
+Z*2Az80asm_Assemble using z80asm
 # Used only internally by IDE
 **1b_Generate browser info
 **2bl_Generate local symbol info
@@ -4191,6 +4194,9 @@ V*2Tembedded_Embedded
 x*2Tembedded_Embedded
 x*2Tfreertos_FreeRTOS
 x*2Tlinux_Linux
+# z80 targets
+Z*2Tembedded_Embedded
+Z*2Tzxspectrum_ZX Spectrum
 # end of targets section
 **1u<x>_Undefines the symbol <x>
 **1U_Unit options:

+ 1 - 1
compiler/msgidx.inc

@@ -1126,7 +1126,7 @@ const
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 85203;
+  MsgTxtSize = 85330;
 
   MsgIdxMax : array[1..20] of longint=(
     28,106,356,129,99,63,143,36,223,68,

+ 198 - 191
compiler/msgtxt.inc

@@ -1492,276 +1492,280 @@ const msgtxt : array[0..000355,1..240] of char=(
   'A*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'S*2Aas_Assemble u','sing GNU AS'#010+
+  'Z*2Asdcc-sdasz80_Assemble using SDCC-SDASZ80'#010+
+  'Z*2Az80asm_Assemble using z80asm'#010+
   '**1b_Generate browser info'#010+
   '**2bl_Generate local symbol info'#010+
   '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#010+
-  '**2C3_Turn on ieee error checking for constants'#010+
+  '**2C3_Turn on ieee error checking ','for constants'#010+
   '**2Ca<x>_Select ABI; see fpc -i or fpc -ia for possible values'#010+
-  '*','*2Cb_Generate code for a big-endian variant of the target architect'+
-  'ure'#010+
+  '**2Cb_Generate code for a big-endian variant of the target architectur'+
+  'e'#010+
   '**2Cc<x>_Set default calling convention to <x>'#010+
-  '**2CD_Create also dynamic library (not supported)'#010+
+  '**2CD_Create also dynamic library (not suppo','rted)'#010+
   '**2Ce_Compilation with emulated floating point opcodes'#010+
-  '**2CE_Generate FP','U code which can raise exceptions'#010+
+  '**2CE_Generate FPU code which can raise exceptions'#010+
   '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
   'possible values'#010+
-  '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
+  '**2CF<x>_Minimal floating point constant p','recision (default, 32, 64)'+
+  #010+
   '**2Cg_Generate PIC code'#010+
-  '**2Ch<n>[,m]_<n> bytes min ','heap size (between 1023 and 67107840) and'+
-  ' optionally [m] max heap size'#010+
+  '**2Ch<n>[,m]_<n> bytes min heap size (between 1023 and 67107840) and o'+
+  'ptionally [m] max heap size'#010+
   '**2Ci_IO-checking'#010+
   'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#010+
-  'l*2CL<x>_LLVM code generation options'#010+
-  'l*3CLflto_Enable Link-time optimisation (needed both when co','mpiling '+
-  'units and programs/libraries)'#010+
+  'l*2CL<x>_LLVM code g','eneration options'#010+
+  'l*3CLflto_Enable Link-time optimisation (needed both when compiling un'+
+  'its and programs/libraries)'#010+
   'l*3CLfltonosystem_Disable LTO for the system unit (needed with at leas'+
   't Xcode 10.2 and earlier due to linker bugs)'#010+
-  'l*3CLv<x>_LLVM target version: Xcode-10.1, 7.0, 8.0, .., 10.0'#010+
-  '**2Cn_Omit linking stage'#010,
+  'l*3CLv<x>','_LLVM target version: Xcode-10.1, 7.0, 8.0, .., 10.0'#010+
+  '**2Cn_Omit linking stage'#010+
   'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
-  '**2Cp<x>_Select instruction set; see fpc -i or fpc -ic for possible va'+
-  'lues'#010+
-  '**2CP<x>=<y>_ packing',' settings'#010+
+  '**2Cp<x>_Select in','struction set; see fpc -i or fpc -ic for possible '+
+  'values'#010+
+  '**2CP<x>=<y>_ packing settings'#010+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
   '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
   'L'#010+
-  '**3CPPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, 2,'+
-  ' 4, 8, 16 an','d 32'#010+
+  '**3C','PPACKRECORD=<y>_ <y> record packing: 0 or DEFAULT or NORMAL, 1, '+
+  '2, 4, 8, 16 and 32'#010+
   '**2Cr_Range checking'#010+
   '**2CR_Verify object method call validity'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
   '**2Ct_Stack checking (for testing only, see manual)'#010+
-  '8*2CT<x>_Target-specific code generation options'#010+
-  '3*2CT<x>_Target-specific code ge','neration options'#010+
+  '8*2','CT<x>_Target-specific code generation options'#010+
+  '3*2CT<x>_Target-specific code generation options'#010+
   '4*2CT<x>_Target-specific code generation options'#010+
   'p*2CT<x>_Target-specific code generation options'#010+
-  'P*2CT<x>_Target-specific code generation options'#010+
+  'P*2CT<x>_Target-specific code generation option','s'#010+
   'J*2CT<x>_Target-specific code generation options'#010+
-  'A*2CT<x>_Target-specific co','de generation options'#010+
+  'A*2CT<x>_Target-specific code generation options'#010+
   'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
   ' (AIX)'#010+
-  'P*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
-  ' (AIX)'#010+
-  'J*3CTautogetterprefix=X_  Automatically create getters for prope','rtie'+
-  's with prefix X (empty string disables)'#010+
+  'P*3CTsmalltoc_ Generate smaller TOCs at the expense of executio','n spe'+
+  'ed (AIX)'#010+
+  'J*3CTautogetterprefix=X_  Automatically create getters for properties '+
+  'with prefix X (empty string disables)'#010+
   'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
   'with prefix X (empty string disables)'#010+
-  '8*3CTcld_                 Emit a CLD instruction before using the x86 '+
-  'string instruction','s'#010+
+  '8*3CTcld_ ','                Emit a CLD instruction before using the x8'+
+  '6 string instructions'#010+
   '3*3CTcld_                 Emit a CLD instruction before using the x86 '+
   'string instructions'#010+
-  '4*3CTcld_                 Emit a CLD instruction before using the x86 '+
+  '4*3CTcld_                 Emit a CLD instruction before using the x86 ',
   'string instructions'#010+
-  '8*3CTfarprocspushoddbp_       Increment BP before pushing ','it in the '+
-  'prologue of far functions'#010+
+  '8*3CTfarprocspushoddbp_       Increment BP before pushing it in the pr'+
+  'ologue of far functions'#010+
   'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
   'de for initializing integer array constants'#010+
-  'J*3CTenumfieldinit_       Initialize enumeration fields in constructor'+
-  's to enumtype(0), af','ter calling inherited constructors'#010+
+  'J*3CTenumfie','ldinit_       Initialize enumeration fields in construct'+
+  'ors to enumtype(0), after calling inherited constructors'#010+
   'J*3CTinitlocals_          Initialize local variables that trigger a JV'+
-  'M bytecode verification error if used uninitialized (slows down code)'#010+
-  'J*3CTlowercaseprocstart_  Lowercase the first character of proced','ure'+
-  '/function/method names'#010+
+  'M bytecode verification error if used uninitialized (slow','s down code'+
+  ')'#010+
+  'J*3CTlowercaseprocstart_  Lowercase the first character of procedure/f'+
+  'unction/method names'#010+
   'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
   'ble'#010+
   'J*2Cv_Var/out parameter copy-out checking'#010+
-  'A*2CV<x>_Set section threadvar model to <x>'#010+
+  'A*2CV<x>_Set section',' threadvar model to <x>'#010+
   '**2CX_Create also smartlinked library'#010+
-  '**1d<x>_Defines ','the symbol <x>'#010+
+  '**1d<x>_Defines the symbol <x>'#010+
   '**1D_Generate a DEF file'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
   '**1e<x>_Set path to executable'#010+
-  '**1E_Same as -Cn'#010+
+  '**1E_S','ame as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1F<x>_Set file names and paths:'#010+
-  '**2Fa<x>[,y]_','(for a program) load units <x> and [y] before uses is p'+
-  'arsed'#010+
+  '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
+  'sed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
   '**2FC<x>_Set RC compiler binary name to <x>'#010+
-  '**2Fd_Disable the compiler'#039's internal directory cache'#010+
-  '**2FD<x>_Set the directory where to search for',' compiler utilities'#010+
+  '**2Fd_Disable the comp','iler'#039's internal directory cache'#010+
+  '**2FD<x>_Set the directory where to search for compiler utilities'#010+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
-  '**2Fi<x>_Add <x> to include path'#010+
+  '**2Fi<x>_Add <','x> to include path'#010+
   '**2Fl<x>_Add <x> to library path'#010+
-  '**2FL<x>_Use <x> as dynami','c linker'#010+
+  '**2FL<x>_Use <x> as dynamic linker'#010+
   '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
   'r'#010+
   '**2FM<x>_Set the directory where to search for unicode binary files'#010+
-  '**2FN<x>_Add <x> to list of default unit scopes (namespaces)'#010+
-  '**2Fo<x>_Add <x> to object pat','h'#010+
+  '**2FN<x>_Add ','<x> to list of default unit scopes (namespaces)'#010+
+  '**2Fo<x>_Add <x> to object path'#010+
   '**2Fr<x>_Load error message file <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2Fu<x>_Add <x> to unit path'#010+
-  '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
+  '**2FU<x>_Set unit output path to <x>, overrides -F','E'#010+
   '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
-  '**2Fw<x>','_Load previously stored whole-program optimization feedback '+
-  'from <x>'#010+
+  '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
+  'om <x>'#010+
   '*g1g_Generate debug information (default format for target)'#010+
-  '*g2gc_Generate checks for pointers (experimental, only available on so'+
-  'me targets, might generate false positive',')'#010+
+  '*g2gc_Generate checks for pointer','s (experimental, only available on '+
+  'some targets, might generate false positive)'#010+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
   '*g2gl_Use line info unit (show more info with backtraces)'#010+
-  '*g2gm_Generate Microsoft CodeView debug information (experimental)'#010+
+  '*g2gm_Generate Microsoft CodeView debu','g information (experimental)'#010+
   '*g2go<x>_Set debug information options'#010+
-  '*g3godwarf','sets_ Enable DWARF '#039'set'#039' type debug information (b'+
-  'reaks gdb < 6.5)'#010+
+  '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
+  'aks gdb < 6.5)'#010+
   '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
   #010+
-  '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
-  'ame'#010+
-  '*g3godwarfcpp_ Simulate C++ ','debug information in DWARF'#010+
+  '*g3godwarfmethodclasspre','fix_ Prefix method names in DWARF with class'+
+  ' name'#010+
+  '*g3godwarfcpp_ Simulate C++ debug information in DWARF'#010+
   '*g3godwarfomflinnum_ Generate line number information in OMF LINNUM re'+
-  'cords in MS LINK format in addition to the DWARF debug information (Op'+
-  'en Watcom Debugger/Linker compatibility)'#010+
-  '*g2gp_Preserve case in stabs sym','bol names'#010+
+  'cords in MS LINK format in addition to the DWARF debug informatio','n ('+
+  'Open Watcom Debugger/Linker compatibility)'#010+
+  '*g2gp_Preserve case in stabs symbol names'#010+
   '*g2gs_Generate Stabs debug information'#010+
   '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
   't'#039' changes the trashing value)'#010+
-  '*g2gv_Generates programs traceable with Valgrind'#010+
-  '*g2gw_Generate DWARFv2 debug information (','same as -gw2)'#010+
+  '*g2gv_Generat','es programs traceable with Valgrind'#010+
+  '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
   '*g2gw2_Generate DWARFv2 debug information'#010+
   '*g2gw3_Generate DWARFv3 debug information'#010+
   '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
-  '**1i_Information'#010+
+  '**1i_In','formation'#010+
   '**2iD_Return compiler date'#010+
   '**2iSO_Return compiler OS'#010+
-  '**2iSP_Return c','ompiler host processor'#010+
+  '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
   '**2iTP_Return target processor'#010+
   '**2iV_Return short compiler version'#010+
   '**2iW_Return full compiler version'#010+
-  '**2ia_Return list of supported ABI targets'#010+
-  '**2ib_Return the used code generation backend ty','pe'#010+
+  '**2ia_Return ','list of supported ABI targets'#010+
+  '**2ib_Return the used code generation backend type'#010+
   '**2ic_Return list of supported CPU instruction sets'#010+
   '**2if_Return list of supported FPU instruction sets'#010+
   '**2ii_Return list of supported inline assembler modes'#010+
-  '**2im_Return list of supported modeswitches'#010+
-  '**2io_Return list of supported opti','mizations'#010+
+  '*','*2im_Return list of supported modeswitches'#010+
+  '**2io_Return list of supported optimizations'#010+
   '**2ir_Return list of recognized compiler and RTL features'#010+
   '**2it_Return list of supported targets'#010+
   '**2iu_Return list of supported microcontroller types'#010+
-  '**2iw_Return list of supported whole program optimizations'#010+
-  '**1I<x>_Add <x> to in','clude path'#010+
+  '**','2iw_Return list of supported whole program optimizations'#010+
+  '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
   '**1M<x>_Set language mode to <x> / enable modeswitch <x> (see option -'+
   'im)'#010+
-  '**2Mfpc_Free Pascal dialect (default)'#010+
+  '**2Mfpc_Free Pascal dialect (d','efault)'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
-  '**2Mdelphi_Delphi 7 com','patibility mode'#010+
+  '**2Mdelphi_Delphi 7 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**2Miso_ISO 7185 mode'#010+
-  '**2Mextendedpascal_ISO 10206 mode'#010+
+  '**2Mextendedpascal_ISO 10206 mod','e'#010+
   '**2Mdelphiunicode_Delphi 2009 and later compatibility mode'#010+
-  '**2*_Each mode (a','s listed above) enables its default set of modeswit'+
-  'ches.'#010+
+  '**2*_Each mode (as listed above) enables its default set of modeswitch'+
+  'es.'#010+
   '**2*_Other modeswitches are disabled and need to be enabled one by ano'+
   'ther.'#010+
-  '**1M<x>-_Disable modeswitch <x> (see option -im)'#010+
+  '**1M<x>-_Disable modeswitch <','x> (see option -im)'#010+
   '**1n_Do not read the default config files'#010+
-  '**1o<x>_Change t','he name of the executable produced to <x>'#010+
+  '**1o<x>_Change the name of the executable produced to <x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
   '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
-  '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
-  '**2O3_Level 3 optimizations (-O2 ','+ slow optimizations)'#010+
+  '**2O2_Level',' 2 optimizations (-O1 + quick optimizations)'#010+
+  '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
   '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
   'pected side effects)'#010+
   '**2Oa<x>=<y>_Set alignment'#010+
-  '**2Oo[NO]<x>_Enable or disable optimizations; see fpc -i or fpc -io fo'+
-  'r possible values'#010+
-  '**2Op<x>_Set',' target cpu for optimizing; see fpc -i or fpc -ic for po'+
-  'ssible values'#010+
+  '**2Oo[NO]<x>_Enable or',' disable optimizations; see fpc -i or fpc -io '+
+  'for possible values'#010+
+  '**2Op<x>_Set target cpu for optimizing; see fpc -i or fpc -ic for poss'+
+  'ible values'#010+
   '**2OW<x>_Generate whole-program optimization feedback for optimization'+
-  ' <x>; see fpc -i or fpc -iw for possible values'#010+
-  '**2Ow<x>_Perform whole-program optimization <x>; see',' fpc -i or fpc -'+
-  'iw for possible values'#010+
+  ' <x>; see fpc -i or fp','c -iw for possible values'#010+
+  '**2Ow<x>_Perform whole-program optimization <x>; see fpc -i or fpc -iw'+
+  ' for possible values'#010+
   '**2Os_Optimize for size rather than speed'#010+
   '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
-  'F*1P<x>_Target CPU / compiler related options:'#010+
+  'F*1P<x>_Target CPU / ','compiler related options:'#010+
   'F*2PB_Show default compiler binary'#010+
-  'F*2PP_Show defaul','t target cpu'#010+
+  'F*2PP_Show default target cpu'#010+
   'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
   'l,powerpc,powerpc64,sparc,x86_64)'#010+
   '**1R<x>_Assembler reading style:'#010+
-  '**2Rdefault_Use default assembler for target'#010+
+  '**2Rdefault_','Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
-  '3*2Rintel_R','ead Intel style assembler'#010+
+  '3*2Rintel_Read Intel style assembler'#010+
   '4*2Ratt_Read AT&T style assembler'#010+
   '4*2Rintel_Read Intel style assembler'#010+
   '8*2Ratt_Read AT&T style assembler'#010+
-  '8*2Rintel_Read Intel style assembler'#010+
+  '8*2Rintel_Read Intel style asse','mbler'#010+
   '6*2RMOT_Read Motorola style assembler'#010+
   '**1S<x>_Syntax options:'#010+
-  '**2S2_Same',' as -Mobjfpc'#010+
+  '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#010+
-  '**2Se<x>_Error options. <x> is a combination of the following:'#010+
+  '**2Se<x>_Error options. <x> is a combination of the ','following:'#010+
   '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
-  '**3*_','w : Compiler also halts after warnings'#010+
+  '**3*_w : Compiler also halts after warnings'#010+
   '**3*_n : Compiler also halts after notes'#010+
   '**3*_h : Compiler also halts after hints'#010+
-  '**2Sf_Enable certain features in compiler and RTL; see fpc -i or fpc -'+
-  'ir for possible values)'#010+
-  '**2Sg_Enable LABEL and GO','TO (default in -Mtp and -Mdelphi)'#010+
+  '**2Sf_Enable certain features in compiler',' and RTL; see fpc -i or fpc'+
+  ' -ir for possible values)'#010+
+  '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
   '**2Sh_Use reference counted strings (ansistring by default) instead of'+
   ' shortstrings'#010+
-  '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
-  '**2Sj_Allows typed constants to be writeable (default ','in all modes)'#010+
+  '**2Si_Turn on inlining of procedures/functio','ns declared as "inline"'#010+
+  '**2Sj_Allows typed constants to be writeable (default in all modes)'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**3SIcom_COM compatible interface (default)'#010+
   '**3SIcorba_CORBA compatible interface'#010+
-  '**2Sm_Support macros like C (global)'#010+
+  '**2Sm_','Support macros like C (global)'#010+
   '**2So_Same as -Mtp'#010+
-  '**2Sr_Transparent file names',' in ISO mode'#010+
+  '**2Sr_Transparent file names in ISO mode'#010+
   '**2Ss_Constructor name must be init (destructor must be done)'#010+
   '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
   'e)'#010+
-  '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
-  '**2Sy_@<pointer> returns a ','typed pointer, same as $T+'#010+
+  '**2Sx_Enable e','xception keywords (default in Delphi/ObjFPC modes)'#010+
+  '**2Sy_@<pointer> returns a typed pointer, same as $T+'#010+
   '**1s_Do not call assembler and linker'#010+
   '**2sh_Generate script to link on host'#010+
   '**2st_Generate script to link on target'#010+
-  '**2sr_Skip register allocation phase (use with -alr)'#010+
+  '**2sr_Skip register',' allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
-  '3*2Tandroid','_Android'#010+
+  '3*2Tandroid_Android'#010+
   '3*2Taros_AROS'#010+
   '3*2Tbeos_BeOS'#010+
   '3*2Tdarwin_Darwin/Mac OS X'#010+
   '3*2Tembedded_Embedded'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Tfreebsd_FreeBSD'#010+
-  '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
+  '3*2Tgo','32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Thaiku_Haiku'#010+
-  '3*2Tiphonesim_iPhone','Simulator from iOS SDK 3.2+ (older versions: -Td'+
-  'arwin)'#010+
+  '3*2Tiphonesim_iPhoneSimulator from iOS SDK 3.2+ (older versions: -Tdar'+
+  'win)'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
   '3*2Tnetbsd_NetBSD'#010+
-  '3*2Tnetware_Novell Netware Module (clib)'#010+
+  '3*2Tnetware_Novell Netware Modu','le (clib)'#010+
   '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
-  '3*2Tos','2_OS/2 / eComStation'#010+
+  '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tsymbian_Symbian OS'#010+
   '3*2Tsolaris_Solaris'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twin32_Windows 32 Bit'#010+
-  '3*2Twince_Windows CE'#010+
+  '3*','2Twince_Windows CE'#010+
   '4*2Tandroid_Android'#010+
   '4*2Taros_AROS'#010+
-  '4*2Tdarwin_Darwin/Mac OS ','X'#010+
+  '4*2Tdarwin_Darwin/Mac OS X'#010+
   '4*2Tdragonfly_DragonFly BSD'#010+
   '4*2Tembedded_Embedded'#010+
   '4*2Tfreebsd_FreeBSD'#010+
@@ -1769,10 +1773,10 @@ const msgtxt : array[0..000355,1..240] of char=(
   '4*2Tiphonesim_iPhoneSimulator'#010+
   '4*2Tlinux_Linux'#010+
   '4*2Tnetbsd_NetBSD'#010+
-  '4*2Topenbsd_OpenBSD'#010+
+  '4*2Topenbs','d_OpenBSD'#010+
   '4*2Tsolaris_Solaris'#010+
   '4*2Twin64_Win64 (64 bit Windows systems)'#010+
-  '6*2Tami','ga_Commodore Amiga'#010+
+  '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tembedded_Embedded'#010+
   '6*2Tlinux_Linux'#010+
@@ -1780,21 +1784,21 @@ const msgtxt : array[0..000355,1..240] of char=(
   '6*2Tmacos_Mac OS'#010+
   '6*2Tpalmos_PalmOS'#010+
   '8*2Tembedded_Embedded'#010+
-  '8*2Tmsdos_MS-DOS (and compatible)'#010+
+  '8*2T','msdos_MS-DOS (and compatible)'#010+
   '8*2Twin16_Windows 16 Bit'#010+
   'A*2Tandroid_Android'#010+
-  'A*2','Taros_AROS'#010+
+  'A*2Taros_AROS'#010+
   'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
   'A*2Tembedded_Embedded'#010+
   'A*2Tfreertos_FreeRTOS'#010+
   'A*2Tgba_Game Boy Advance'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Tnds_Nintendo DS'#010+
-  'A*2Tnetbsd_NetBSD'#010+
+  'A*2Tnetbsd_NetB','SD'#010+
   'A*2Tpalmos_PalmOS'#010+
   'A*2Tsymbian_Symbian'#010+
   'A*2Twince_Windows CE'#010+
-  'a*2Tandroid_Andr','oid'#010+
+  'a*2Tandroid_Android'#010+
   'a*2Tdarwin_Darwin/iOS'#010+
   'a*2Tlinux_Linux'#010+
   'a*2Twin64_Windows 64'#010+
@@ -1803,11 +1807,11 @@ const msgtxt : array[0..000355,1..240] of char=(
   'm*2Tandroid_Android'#010+
   'm*2Tembedded_Embedded'#010+
   'm*2Tlinux_Linux'#010+
-  'M*2Tembedded_Embedded'#010+
+  'M*2Temb','edded_Embedded'#010+
   'M*2Tlinux_Linux'#010+
   'P*2Taix_AIX'#010+
   'P*2Tamiga_AmigaOS'#010+
-  'P*2Tdarwin_Darwin','/Mac OS X'#010+
+  'P*2Tdarwin_Darwin/Mac OS X'#010+
   'P*2Tembedded_Embedded'#010+
   'P*2Tlinux_Linux'#010+
   'P*2Tmacos_Mac OS (classic)'#010+
@@ -1815,11 +1819,11 @@ const msgtxt : array[0..000355,1..240] of char=(
   'P*2Tnetbsd_NetBSD'#010+
   'P*2Twii_Wii'#010+
   'p*2Taix_AIX'#010+
-  'p*2Tdarwin_Darwin/Mac OS X'#010+
+  'p*2Tdarwin_Darwin/Mac OS ','X'#010+
   'p*2Tembedded_Embedded'#010+
   'p*2Tlinux_Linux'#010+
   'R*2Tlinux_Linux'#010+
-  'R*2Tembedded_Embedded'#010,
+  'R*2Tembedded_Embedded'#010+
   'r*2Tlinux_Linux'#010+
   'r*2Tembedded_Embedded'#010+
   'S*2Tlinux_Linux'#010+
@@ -1828,148 +1832,151 @@ const msgtxt : array[0..000355,1..240] of char=(
   'V*2Tembedded_Embedded'#010+
   'x*2Tembedded_Embedded'#010+
   'x*2Tfreertos_FreeRTOS'#010+
-  'x*2Tlinux_Linux'#010+
+  'x*2Tli','nux_Linux'#010+
+  'Z*2Tembedded_Embedded'#010+
+  'Z*2Tzxspectrum_ZX Spectrum'#010+
   '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
-  '**2Un_Do not che','ck where the unit name matches the file name'#010+
+  '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
-  '**2Us_Compile a system unit'#010+
+  '*','*2Us_Compile a system unit'#010+
   '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
-  '**2*_e : Show errors (default)   ','    0 : Show nothing (except errors'+
-  ')'#010+
+  '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
-  '**2*_n : Show notes                  t : Show tried/used files'#010+
+  '**2*_n : Show notes ','                 t : Show tried/used files'#010+
   '**2*_h : Show hints                  c : Show conditionals'#010+
-  '**2*_i : Show general inf','o           d : Show debug info'#010+
+  '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_s : Show time stamps            q : Show message numbers'#010+
+  '**2*_s : Sh','ow time stamps            q : Show message numbers'#010+
   '**2*_a : Show everything             x : Show info about invoked tools'+
   #010+
-  '**2*_','b : Write file names messages   p : Write tree.log with parse t'+
-  'ree'#010+
-  '**2*_    with full path              v : Write fpcdebug.txt with'#010+
+  '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
+  'e'#010+
+  '**2*_    with full path              v : Write',' fpcdebug.txt with'#010+
   '**2*_z : Write output to stderr          lots of debugging info'#010+
-  '**2*_m<x>,<y> : Do not show messages numbere','d <x> and <y>'#010+
+  '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
   'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
   'or version)'#010+
-  '**1W<x>_Target-specific options (targets)'#010+
+  '**1W<x>_Target-specific o','ptions (targets)'#010+
   '3*2WA_Specify native type application (Windows)'#010+
   '4*2WA_Specify native type application (Windows)'#010+
-  'A*2WA_Specify ','native type application (Windows)'#010+
+  'A*2WA_Specify native type application (Windows)'#010+
   '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
+  'P*2Wb_Create a bundle inste','ad of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'a*2Wb_Create a bundle instead of a library (Darwin',')'#010+
+  'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '4*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
+  '3*2WB_C','reate a relocatable image (Windows, Symbian)'#010+
   '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
-  '4*2WB_Create a relocatable image',' (Windows)'#010+
+  '4*2WB_Create a relocatable image (Windows)'#010+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
   'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
+  'A*2WB<x>_','Set image base to <x> (Windows, Symbian)'#010+
   '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
-  '4*2WC_Specify console type',' application (Windows)'#010+
+  '4*2WC_Specify console type application (Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
-  'P*2WC_Specify console type application (Classic Mac OS)'#010+
+  'P*2WC_Specify console type application (C','lassic Mac OS)'#010+
   '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
-  '4*2WD_Use DEFFILE to export functions of DLL or EX','E (Windows)'#010+
+  '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
-  '4*2We_Use external resources (Darwin)'#010+
+  '4','*2We_Use external resources (Darwin)'#010+
   'a*2We_Use external resources (Darwin)'#010+
   'A*2We_Use external resources (Darwin)'#010+
-  'P*2We_Use exte','rnal resources (Darwin)'#010+
+  'P*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
-  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
+  '3*2WF_Specify full-screen type application (EMX, OS','/2)'#010+
   '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   '4*2WG_Specify graphic type application (Windows)'#010+
-  'A*2WG_Specify ','graphic type application (Windows)'#010+
+  'A*2WG_Specify graphic type application (Windows)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
-  '3*2Wi_Use internal resources (Darwin)'#010+
+  '3*2Wi_Use internal res','ources (Darwin)'#010+
   '4*2Wi_Use internal resources (Darwin)'#010+
   'a*2Wi_Use internal resources (Darwin)'#010+
-  'A*2Wi_Use internal resources (Darwi','n)'#010+
+  'A*2Wi_Use internal resources (Darwin)'#010+
   'P*2Wi_Use internal resources (Darwin)'#010+
   'p*2Wi_Use internal resources (Darwin)'#010+
-  '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
+  '3*2WI_Turn on/off the usage of imp','ort sections (Windows)'#010+
   '4*2WI_Turn on/off the usage of import sections (Windows)'#010+
-  'A*2WI_Turn on/off the usage of import sections ','(Windows)'#010+
+  'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
   'e segment)'#010+
-  '8*2Wm<x>_Set memory model'#010+
+  '8*2Wm<x>_Set memory mo','del'#010+
   '8*3WmTiny_Tiny memory model'#010+
   '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmMedium_Medium memory model'#010+
-  '8*3WmCompact_Compact me','mory model'#010+
+  '8*3WmCompact_Compact memory model'#010+
   '8*3WmLarge_Large memory model'#010+
   '8*3WmHuge_Huge memory model'#010+
-  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
-  'n)'#010+
+  '3*2WM<x>_Minimum Mac OS X deployment version',': 10.4, 10.5.1, ... (Dar'+
+  'win)'#010+
   '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
-  'p*2WM<x>_Minimum Mac OS X',' deployment version: 10.4, 10.5.1, ... (Dar'+
-  'win)'#010+
-  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
+  'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
+  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (','Dar'+
+  'win)'#010+
   '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  '4*2WN_Do not generate relocation code, needed for',' debugging (Windows'+
-  ')'#010+
+  '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+  'A*2Wp<x>_Specify the c','ontroller type; see fpc -i or fpc -iu for poss'+
+  'ible values'#010+
+  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possi',
-  'ble values'#010+
   'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+
+  '3*2WP<x>_Minimum iOS d','eployment version: 3.0, 5.0.1, ... (iphonesim)'+
+  #010+
   '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
-  'a*2WP<x>_Mi','nimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
-  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
+  'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
+  'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (','Darwin)'#010+
   '3*2WR_Generate relocation code (Windows)'#010+
   '4*2WR_Generate relocation code (Windows)'#010+
-  'A*2WR_Generate relocation code (Windo','ws)'#010+
+  'A*2WR_Generate relocation code (Windows)'#010+
   '8*2Wt<x>_Set the target executable format'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#010+
-  '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+
+  '8*3Wtcom_Create a DOS .CO','M file (requires tiny memory model)'#010+
   'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
-  '**2WX_Enable executable stack (Lin','ux)'#010+
+  '**2WX_Enable executable stack (Linux)'#010+
   '**1X_Executable options:'#010+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '9.1 (Linux)'#010+
-  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
-  'ux)'#010+
-  '**2Xd_Do not search default library path (sometimes req','uired for cro'+
-  'ss-compiling when not using -XR)'#010+
+  '**','2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, L'+
+  'inux)'#010+
+  '**2Xd_Do not search default library path (sometimes required for cross'+
+  '-compiling when not using -XR)'#010+
   '**2Xe_Use external linker'#010+
-  '**2Xf_Substitute pthread library name for linking (BSD)'#010+
+  '**2Xf_Substitute pthread library name for',' linking (BSD)'#010+
   '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
   'to executable'#010+
-  '**2XD_Try to link units dyna','mically      (defines FPC_LINK_DYNAMIC)'#010+
+  '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
-  'L*2XlS<x>_LLVM utilties suffix (e.g. -7 in case clang is called clang-'+
-  '7)'#010+
+  'L*2XlS<x>_LLVM utilties suffix (e.g. -7 in case',' clang is called clan'+
+  'g-7)'#010+
   '**2XLA_Define library substitutions for linking'#010+
   '**2XLO_Define order of library linking'#010+
-  '**2XLD_Exclude',' default order of standard libraries'#010+
+  '**2XLD_Exclude default order of standard libraries'#010+
   '**2Xm_Generate link map'#010+
-  '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
-  's '#039'main'#039')'#010+
+  '**2XM<x>_Set the name of the '#039'main'#039' program routine ','(default'+
+  ' is '#039'main'#039')'#010+
   '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
   #010+
-  'F*2Xp<x>_First search for the compil','er binary in the directory <x>'#010+
+  'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
-  '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
-  'ile, see the ld manual for more information) (BeOS, Linux)'#010+
-  '**2XR<x>_Prepend <x> to all ','linker search paths (BeOS, Darwin, FreeB'+
-  'SD, Linux, Mac OS, Solaris)'#010+
+  '**2Xr<x>_Set the linker'#039's ','rlink-path to <x> (needed for cross co'+
+  'mpile, see the ld manual for more information) (BeOS, Linux)'#010+
+  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
+  ', Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
-  '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
-  '**2Xt_Link with static libraries (-static is passed to linker)',#010+
+  '**2XS','_Try to link units statically (default, defines FPC_LINK_STATIC'+
+  ')'#010+
+  '**2Xt_Link with static libraries (-static is passed to linker)'#010+
   '**2Xv_Generate table for Virtual Entry calls'#010+
-  '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#010+
+  '**2XV_Use VLink as external linker       (default on Amiga, MorphOS',')'+
+  #010+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+
-  '**1h_Shows this help without wait','ing'
+  '**1h_Shows this help without waiting'
 );

+ 25 - 5
compiler/nadd.pas

@@ -4003,6 +4003,10 @@ implementation
                      result := nil;
 
                      case torddef(resultdef).ordtype of
+                       s8bit:
+                         procname := 'fpc_mul_shortint';
+                       u8bit:
+                         procname := 'fpc_mul_byte';
                        s16bit:
                          procname := 'fpc_mul_integer';
                        u16bit:
@@ -4158,19 +4162,29 @@ implementation
 
          else if is_implicit_pointer_object_type(ld) then
             begin
-              expectloc:=LOC_FLAGS;
+              if ld.size>sizeof(aint) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
             end
 
          else if (ld.typ=classrefdef) then
             begin
-              expectloc:=LOC_FLAGS;
+              if ld.size>sizeof(aint) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
             end
 
          { support procvar=nil,procvar<>nil }
          else if ((ld.typ=procvardef) and (rt=niln)) or
                  ((rd.typ=procvardef) and (lt=niln)) then
             begin
-              expectloc:=LOC_FLAGS;
+              if (ld.typ=procvardef) and (tprocvardef(ld).size>sizeof(aint)) or
+                 (rd.typ=procvardef) and (tprocvardef(rd).size>sizeof(aint)) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
             end
 
 {$ifdef SUPPORT_MMX}
@@ -4192,12 +4206,18 @@ implementation
                   (ld.typ=procvardef) and
                   equal_defs(rd,ld) then
            begin
-             expectloc:=LOC_FLAGS;
+             if tprocvardef(ld).size>sizeof(aint) then
+               expectloc:=LOC_JUMP
+             else
+               expectloc:=LOC_FLAGS;
            end
 
          else if (ld.typ=enumdef) then
            begin
-              expectloc:=LOC_FLAGS;
+              if tenumdef(ld).size>sizeof(aint) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
            end
 
 {$ifdef SUPPORT_MMX}

+ 2 - 2
compiler/ncal.pas

@@ -4144,8 +4144,8 @@ implementation
                               That means the for pushes the para with the
                               highest offset (see para3) needs to be pushed first
                             }
-{$if defined(i386) or defined(i8086) or defined(m68k)}
-                            { the i386, i8086, m68k and jvm code generators expect all reference }
+{$if defined(i386) or defined(i8086) or defined(m68k) or defined(z80)}
+                            { the i386, i8086, m68k, z80 and jvm code generators expect all reference }
                             { parameters to be in this order so they can use   }
                             { pushes in case of no fixed stack                 }
                             if (not paramanager.use_fixed_stack and

+ 13 - 1
compiler/ngenutil.pas

@@ -1516,6 +1516,18 @@ implementation
           );
           tcb.free;
         end;
+
+      { allocate the stack on the ZX Spectrum system }
+      if target_info.system in [system_z80_zxspectrum] then
+        begin
+          { tai_datablock cannot yet be handled via the high level typed const
+            builder, because it implies the generation of a symbol, while this
+            is separate in the builder }
+          maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+          new_section(current_asmdata.asmlists[al_globals],sec_stack,'__fpc_stackarea_start',current_settings.alignment.varalignmax);
+          current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_stackarea_start',stacksize-1,carraydef.getreusable(u8inttype,stacksize-1),AT_DATA));
+          current_asmdata.asmlists[al_globals].concat(tai_datablock.Create_global('__fpc_stackarea_end',1,carraydef.getreusable(u8inttype,1),AT_DATA));
+        end;
 {$IFDEF POWERPC}
       { AmigaOS4 "stack cookie" support }
       if ( target_info.system = system_powerpc_amiga ) then
@@ -1547,7 +1559,7 @@ implementation
       tcb.free;
 
       { allocate an initial heap on embedded systems }
-      if target_info.system in (systems_embedded+systems_freertos) then
+      if target_info.system in (systems_embedded+systems_freertos+[system_z80_zxspectrum]) then
         begin
           { tai_datablock cannot yet be handled via the high level typed const
             builder, because it implies the generation of a symbol, while this

+ 113 - 30
compiler/ninl.pas

@@ -3528,11 +3528,18 @@ implementation
               in_arctan_real,
               in_ln_real :
                 begin
-                  set_varstate(left,vs_read,[vsf_must_be_valid]);
+                  { on the Z80, the double result is returned in a var param, because
+                    it's too big to fit in registers. In that case we have 2 parameters
+                    and left.nodetype is a callparan. }
+                  if left.nodetype = callparan then
+                    temp_pnode := @tcallparanode(left).left
+                  else
+                    temp_pnode := @left;
+                  set_varstate(temp_pnode^,vs_read,[vsf_must_be_valid]);
                   { converting an int64 to double on platforms without }
                   { extended can cause precision loss                  }
-                  if not(left.nodetype in [ordconstn,realconstn]) then
-                    inserttypeconv(left,pbestrealtype^);
+                  if not(temp_pnode^.nodetype in [ordconstn,realconstn]) then
+                    inserttypeconv(temp_pnode^,pbestrealtype^);
                   resultdef:=pbestrealtype^;
                 end;
 
@@ -3572,7 +3579,14 @@ implementation
               in_sqr_real,
               in_sqrt_real :
                 begin
-                  set_varstate(left,vs_read,[vsf_must_be_valid]);
+                  { on the Z80, the double result is returned in a var param, because
+                    it's too big to fit in registers. In that case we have 2 parameters
+                    and left.nodetype is a callparan. }
+                  if left.nodetype = callparan then
+                    temp_pnode := @tcallparanode(left).left
+                  else
+                    temp_pnode := @left;
+                  set_varstate(temp_pnode^,vs_read,[vsf_must_be_valid]);
                   setfloatresultdef;
                 end;
 
@@ -4154,30 +4168,42 @@ implementation
 
 
      function tinlinenode.first_arctan_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         result := ccallnode.createintern('fpc_arctan_real',
-                ccallparanode.create(left,nil));
-        left := nil;
+                ccallparanode.create(temp_pnode^,nil));
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_abs_real : tnode;
       var
          callnode : tcallnode;
+         temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         callnode:=ccallnode.createintern('fpc_abs_real',
-                    ccallparanode.create(left,nil));
+                    ccallparanode.create(temp_pnode^,nil));
         result := ctypeconvnode.create(callnode,resultdef);
         include(callnode.callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_sqr_real : tnode;
       var
          callnode : tcallnode;
+         temp_pnode: pnode;
       begin
 {$ifndef cpufpemu}
         { this procedure might be only used for cpus definining cpufpemu else
@@ -4186,11 +4212,15 @@ implementation
 {$endif cpufpemu}
         { create the call to the helper }
         { on entry left node contains the parameter }
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         callnode:=ccallnode.createintern('fpc_sqr_real',
-                    ccallparanode.create(left,nil));
+                    ccallparanode.create(temp_pnode^,nil));
         result := ctypeconvnode.create(callnode,resultdef);
         include(callnode.callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_sqrt_real : tnode;
@@ -4198,14 +4228,19 @@ implementation
         fdef: tdef;
         procname: string[31];
         callnode: tcallnode;
+        temp_pnode: pnode;
       begin
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         if ((cs_fp_emulation in current_settings.moduleswitches)
 {$ifdef cpufpemu}
             or (current_settings.fputype=fpu_soft)
 {$endif cpufpemu}
             ) and not (target_info.system in systems_wince) then
           begin
-            case tfloatdef(left.resultdef).floattype of
+            case tfloatdef(temp_pnode^.resultdef).floattype of
               s32real:
                 begin
                   fdef:=search_system_type('FLOAT32REC').typedef;
@@ -4223,93 +4258,141 @@ implementation
               internalerror(2014052101);
             end;
             result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
-               ctypeconvnode.create_internal(left,fdef),nil)),resultdef);
+               ctypeconvnode.create_internal(temp_pnode^,fdef),nil)),resultdef);
           end
         else
           begin
             { create the call to the helper }
             { on entry left node contains the parameter }
             callnode := ccallnode.createintern('fpc_sqrt_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
             result := ctypeconvnode.create(callnode,resultdef);
             include(callnode.callnodeflags,cnf_check_fpu_exceptions);
           end;
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_ln_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         result := ccallnode.createintern('fpc_ln_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_cos_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         result := ccallnode.createintern('fpc_cos_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_sin_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         result := ccallnode.createintern('fpc_sin_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_exp_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        result := ccallnode.createintern('fpc_exp_real',ccallparanode.create(left,nil));
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
+        result := ccallnode.createintern('fpc_exp_real',ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_int_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        result := ccallnode.createintern('fpc_int_real',ccallparanode.create(left,nil));
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
+        result := ccallnode.createintern('fpc_int_real',ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_frac_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        result := ccallnode.createintern('fpc_frac_real',ccallparanode.create(left,nil));
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
+        result := ccallnode.createintern('fpc_frac_real',ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_round_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        result := ccallnode.createintern('fpc_round_real',ccallparanode.create(left,nil));
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
+        result := ccallnode.createintern('fpc_round_real',ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_trunc_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
         { create the call to the helper }
         { on entry left node contains the parameter }
-        result := ccallnode.createintern('fpc_trunc_real',ccallparanode.create(left,nil));
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
+        result := ccallnode.createintern('fpc_trunc_real',ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
 
      function tinlinenode.first_abs_long : tnode;

+ 6 - 0
compiler/ogcoff.pas

@@ -3472,6 +3472,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_go32v2];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );
@@ -3485,6 +3486,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_win32,system_i386_nativent];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );
@@ -3498,6 +3500,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_wdosx];
             flags : [af_outputbinary];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );
@@ -3511,6 +3514,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_wince];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );
@@ -3526,6 +3530,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_x86_64_win64];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );
@@ -3541,6 +3546,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_arm_wince];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );

+ 1 - 0
compiler/ogmacho.pas

@@ -1229,6 +1229,7 @@ uses
         supported_targets : [system_i386_darwin,system_i386_iphonesim];
         flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf{, af_stabs_use_function_absolute_addresses}];
         labelprefix : '.L';
+        labelmaxlen : -1;
         comment : '#';
         dollarsign: '$';
       );

+ 1 - 0
compiler/ognlm.pas

@@ -1497,6 +1497,7 @@ const
             supported_targets : [system_i386_Netware,system_i386_netwlibc];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             dollarsign: '$';
           );

+ 1 - 0
compiler/ogomf.pas

@@ -4920,6 +4920,7 @@ cleanup:
             supported_targets : [system_i8086_msdos,system_i8086_embedded,system_i8086_win16];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );

+ 16 - 3
compiler/options.pas

@@ -757,6 +757,9 @@ begin
 {$endif}
 {$ifdef llvm}
       'L',
+{$endif}
+{$ifdef z80}
+      'Z',
 {$endif}
       '*' : show:=true;
      end;
@@ -3360,6 +3363,8 @@ begin
       lets disable the feature. }
     system_m68k_amiga:
       target_unsup_features:=[f_dynlibs];
+    system_z80_zxspectrum:
+      target_unsup_features:=[f_threading,f_dynlibs{,f_fileio,f_textio},f_commandargs,f_exitcode];
     else
       target_unsup_features:=[];
   end;
@@ -3783,6 +3788,13 @@ procedure read_arguments(cmd:TCmdStr);
         def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
       {$endif xtensa}
 
+      {$ifdef z80}
+        def_system_macro('CPUZ80');
+        def_system_macro('CPU16');
+        def_system_macro('FPC_CURRENCY_IS_INT64');
+        def_system_macro('FPC_COMP_IS_INT64');
+      {$endif z80}
+
       {$if defined(cpu8bitalu)}
         def_system_macro('CPUINT8');
       {$elseif defined(cpu16bitalu)}
@@ -3940,7 +3952,7 @@ begin
     end;
 
   { Set up default value for the heap }
-  if target_info.system in (systems_embedded+systems_freertos) then
+  if target_info.system in (systems_embedded+systems_freertos+[system_z80_zxspectrum]) then
     begin
       case target_info.system of
 {$ifdef AVR}
@@ -4241,7 +4253,8 @@ begin
      ((target_info.system in [system_arm_wince,system_arm_gba,
          system_m68k_amiga,system_m68k_atari,
          system_arm_nds,system_arm_embedded,
-         system_riscv32_embedded,system_riscv64_embedded,system_xtensa_embedded])
+         system_riscv32_embedded,system_riscv64_embedded,system_xtensa_embedded,
+         system_z80_embedded,system_z80_zxspectrum])
 {$ifdef arm}
       or (target_info.abi=abi_eabi)
 {$endif arm}
@@ -4680,7 +4693,7 @@ begin
   option.free;
   Option:=nil;
 
-  clearstack_pocalls := [pocall_cdecl,pocall_cppdecl,pocall_syscall,pocall_mwpascal,pocall_sysv_abi_cdecl,pocall_ms_abi_cdecl];
+  clearstack_pocalls := [pocall_cdecl,pocall_cppdecl,pocall_syscall,pocall_mwpascal,pocall_sysv_abi_cdecl,pocall_ms_abi_cdecl{$ifdef z80},pocall_stdcall{$endif}];
   cdecl_pocalls := [pocall_cdecl, pocall_cppdecl, pocall_mwpascal, pocall_sysv_abi_cdecl, pocall_ms_abi_cdecl];
   if (tf_safecall_clearstack in target_info.flags) then
     begin

+ 8 - 8
compiler/pass_1.pas

@@ -194,18 +194,18 @@ implementation
                        p:=hp;
                      end;
                    if codegenerror then
-                     include(p.flags,nf_error)
-                   else
-                     begin
-{$ifdef EXTDEBUG}
-                       if (p.expectloc=LOC_INVALID) then
-                         Comment(V_Warning,'Expectloc is not set in firstpass: '+nodetype2str[p.nodetype]);
-{$endif EXTDEBUG}
-                     end;
+                     include(p.flags,nf_error);
                  end;
              until not assigned(hp) or
                    (nf_pass1_done in hp.flags);
              include(p.flags,nf_pass1_done);
+{$ifdef EXTDEBUG}
+             if not(nf_error in p.flags) then
+               begin
+                 if (p.expectloc=LOC_INVALID) then
+                   Comment(V_Warning,'Expectloc is not set in firstpass: '+nodetype2str[p.nodetype]);
+               end;
+{$endif EXTDEBUG}
              codegenerror:=codegenerror or oldcodegenerror;
              current_settings.localswitches:=oldlocalswitches;
              current_filepos:=oldpos;

+ 1 - 0
compiler/powerpc/agppcmpw.pas

@@ -1243,6 +1243,7 @@ interface
             supported_targets : [system_powerpc_macos];
             flags : [af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure];
             labelprefix : '@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: 's';
           );

+ 1 - 0
compiler/powerpc/agppcvasm.pas

@@ -125,6 +125,7 @@ unit agppcvasm;
          supported_targets : [system_powerpc_amiga,system_powerpc_morphos,system_powerpc_linux];
          flags : [af_needar,af_smartlink_sections];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign: '$';
        );

+ 8 - 1
compiler/pp.pas

@@ -37,6 +37,7 @@ program pp;
   MIPSEL              generate a compiler for the MIPSEL (Littel Endian)
   POWERPC             generate a compiler for the PowerPC
   POWERPC64           generate a compiler for the PowerPC64 architecture
+  Z80                 generate a compiler for Z80
   RISCV64             generate a compiler for the RiscV64 architecture
   SPARC               generate a compiler for SPARC
   SPARC64             generate a compiler for SPARC64
@@ -46,6 +47,7 @@ program pp;
   Other compiler switches
   -----------------------------------------------------------------
   CMEM                use cmem unit for better memory debugging
+=======
   DEBUG               version with debug code is generated
   EXTDEBUG            some extra debug code is executed
   EXTERN_MSG          Don't compile the msgfiles in the compiler, always
@@ -184,7 +186,12 @@ program pp;
   {$endif CPUDEFINED}
   {$define CPUDEFINED}
 {$endif XTENSA}
-
+{$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}

+ 11 - 5
compiler/ppcgen/agppcgas.pas

@@ -112,7 +112,7 @@ unit agppcgas;
                    not assigned(symbol) then
                   internalerror(2011122701);
                 if asminfo^.dollarsign<>'$' then
-                  getreferencestring:=ReplaceForbiddenAsmSymbolChars(symbol.name)+'('+gas_regname(NR_RTOC)+')'
+                  getreferencestring:=ApplyAsmSymbolRestrictions(symbol.name)+'('+gas_regname(NR_RTOC)+')'
                 else
                   getreferencestring:=symbol.name+'('+gas_regname(NR_RTOC)+')';
                 exit;
@@ -128,9 +128,9 @@ unit agppcgas;
                   begin
                     if asminfo^.dollarsign<>'$' then
                       begin
-                        s:=s+ReplaceForbiddenAsmSymbolChars(symbol.name);
+                        s:=s+ApplyAsmSymbolRestrictions(symbol.name);
                         if assigned(relsymbol) then
-                          s:=s+'-'+ReplaceForbiddenAsmSymbolChars(relsymbol.name)
+                          s:=s+'-'+ApplyAsmSymbolRestrictions(relsymbol.name)
                       end
                     else
                       begin
@@ -206,7 +206,7 @@ unit agppcgas;
               internalerror(200402267);
             hs:=o.ref^.symbol.name;
             if asminfo^.dollarsign<>'$' then
-              hs:=ReplaceForbiddenAsmSymbolChars(hs);
+              hs:=ApplyAsmSymbolRestrictions(hs);
             if o.ref^.offset>0 then
               hs:=hs+'+'+tostr(o.ref^.offset)
             else
@@ -236,7 +236,7 @@ unit agppcgas;
             begin
               hs:=o.ref^.symbol.name;
               if asminfo^.dollarsign<>'$' then
-                hs:=ReplaceForbiddenAsmSymbolChars(hs);
+                hs:=ApplyAsmSymbolRestrictions(hs);
               if o.ref^.offset>0 then
                hs:=hs+'+'+tostr(o.ref^.offset)
               else
@@ -646,6 +646,7 @@ unit agppcgas;
          supported_targets : [system_powerpc_linux,system_powerpc_netbsd,system_powerpc_openbsd,system_powerpc_MorphOS,system_powerpc_Amiga,system_powerpc64_linux,system_powerpc_embedded,system_powerpc64_embedded];
          flags : [af_needar,af_smartlink_sections];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign: '$';
        );
@@ -664,6 +665,7 @@ unit agppcgas;
          supported_targets : [system_powerpc_morphos];
          flags : [af_needar];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign: '$';
        );
@@ -678,6 +680,7 @@ unit agppcgas;
          supported_targets : [system_powerpc_darwin,system_powerpc64_darwin];
          flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
          labelprefix : 'L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign : '$';
        );
@@ -701,6 +704,7 @@ unit agppcgas;
          supported_targets : [system_powerpc_aix,system_powerpc64_aix];
          flags : [af_needar,af_smartlink_sections,af_stabs_use_function_absolute_addresses];
          labelprefix : 'L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign : '.'
        );
@@ -723,6 +727,7 @@ unit agppcgas;
          supported_targets : [system_powerpc_aix,system_powerpc64_aix];
          flags : [af_needar,af_smartlink_sections,af_stabs_use_function_absolute_addresses];
          labelprefix : 'L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign : '.'
        );
@@ -736,6 +741,7 @@ unit agppcgas;
          supported_targets : [system_powerpc_macos, system_powerpc_darwin, system_powerpc64_darwin];
          flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
          labelprefix : 'L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign: '$';
        );

+ 2 - 2
compiler/ppcgen/cgppc.pas

@@ -846,7 +846,7 @@ unit cgppc;
                 current_asmdata.WeakRefAsmSymbol(symname,AT_DATA)
               else
                 current_asmdata.WeakRefAsmSymbol('.'+symname,AT_DATA);
-              newsymname:=ReplaceForbiddenAsmSymbolChars(symname);
+              newsymname:=ApplyAsmSymbolRestrictions(symname);
               current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_toc_entry,newsymname+'[TC],'+newsymname));
             end;
         end
@@ -879,7 +879,7 @@ unit cgppc;
               ref.symbol:=tocsym;
               tocsym.ftocsecnr:=tocnr;
               current_asmdata.asmlists[al_indirectpicdata].concat(tai_symbol.create(tocsym,0));
-              newsymname:=ReplaceForbiddenAsmSymbolChars(symname);
+              newsymname:=ApplyAsmSymbolRestrictions(symname);
               sym:=current_asmdata.RefAsmSymbol(newsymname,AT_DATA);
               current_asmdata.asmlists[al_indirectpicdata].concat(tai_const.Create_sym(sym));
             end;

+ 81 - 0
compiler/ppcz80.lpi

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <LRSInOutputDirectory Value="False"/>
+        <CompatibilityMode Value="True"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="ppcz80"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default">
+          <local>
+            <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T &apos;Lazarus Run Output&apos; -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
+          </local>
+        </Mode0>
+      </Modes>
+    </RunParams>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="pp.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="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
+-dEXTDEBUG"/>
+      <OtherDefines Count="3">
+        <Define0 Value="z80"/>
+        <Define1 Value="DEBUG_REGALLOC"/>
+        <Define2 Value="EXTDEBUG"/>
+      </OtherDefines>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 7 - 0
compiler/psystem.pas

@@ -356,6 +356,13 @@ implementation
         sc80floattype:=cfloatdef.create(sc80real,true);
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
 {$endif avr}
+{$ifdef z80}
+        s32floattype:=cfloatdef.create(s32real,true);
+        s64floattype:=cfloatdef.create(s64real,true);
+        s80floattype:=cfloatdef.create(s80real,true);
+        sc80floattype:=cfloatdef.create(sc80real,true);
+        s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif z80}
 {$ifdef mips}
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);

+ 2 - 0
compiler/rautils.pas

@@ -54,6 +54,8 @@ type
       OPR_CONSTANT  : (val:longint);
 {$elseif defined(i8086)}
       OPR_CONSTANT  : (val:longint);
+{$elseif defined(Z80)}
+      OPR_CONSTANT  : (val:longint);
 {$else}
       OPR_CONSTANT  : (val:aint);
 {$endif}

+ 4 - 3
compiler/riscv/agrvgas.pas

@@ -79,9 +79,9 @@ unit agrvgas;
                   begin
                     if asminfo^.dollarsign<>'$' then
                       begin
-                        s:=s+ReplaceForbiddenAsmSymbolChars(symbol.name);
+                        s:=s+ApplyAsmSymbolRestrictions(symbol.name);
                         if assigned(relsymbol) then
-                          s:=s+'-'+ReplaceForbiddenAsmSymbolChars(relsymbol.name)
+                          s:=s+'-'+ApplyAsmSymbolRestrictions(relsymbol.name)
                       end
                     else
                       begin
@@ -159,7 +159,7 @@ unit agrvgas;
             begin
               hs:=o.ref^.symbol.name;
               if asminfo^.dollarsign<>'$' then
-                hs:=ReplaceForbiddenAsmSymbolChars(hs);
+                hs:=ApplyAsmSymbolRestrictions(hs);
               if o.ref^.offset>0 then
                hs:=hs+'+'+tostr(o.ref^.offset)
               else
@@ -263,6 +263,7 @@ unit agrvgas;
          supported_targets : [system_riscv32_linux,system_riscv64_linux];
          flags : [af_needar,af_smartlink_sections];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '# ';
          dollarsign: '$';
        );

+ 1 - 0
compiler/sparc/cpuelf.pas

@@ -128,6 +128,7 @@ implementation
 //            flags : [af_outputbinary,af_smartlink_sections];
          flags : [af_outputbinary,af_supports_dwarf];
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '';
          dollarsign: '$';
        );

+ 2 - 0
compiler/sparc64/cpugas.pas

@@ -240,6 +240,7 @@ implementation
            supported_targets : [system_sparc64_linux];
            flags : [af_needar,af_smartlink_sections];
            labelprefix : '.L';
+           labelmaxlen : -1;
            comment : '# ';
            dollarsign: '$';
          );
@@ -253,6 +254,7 @@ implementation
            supported_targets : [system_sparc64_linux];
            flags : [af_needar,af_smartlink_sections];
            labelprefix : '.L';
+           labelmaxlen : -1;
            comment : '# ';
            dollarsign: '$';
          );

+ 4 - 0
compiler/sparcgen/cpugas.pas

@@ -236,6 +236,7 @@ implementation
            supported_targets : [system_sparc_solaris,system_sparc_linux,system_sparc_embedded];
            flags : [af_needar,af_smartlink_sections];
            labelprefix : '.L';
+           labelmaxlen : -1;
            comment : '# ';
            dollarsign: '$';
          );
@@ -249,6 +250,7 @@ implementation
            supported_targets : [system_sparc_solaris,system_sparc_linux,system_sparc_embedded];
            flags : [af_needar,af_smartlink_sections];
            labelprefix : '.L';
+           labelmaxlen : -1;
            comment : '# ';
            dollarsign: '$';
          );
@@ -266,6 +268,7 @@ implementation
            supported_targets : [system_sparc64_linux];
            flags : [af_needar,af_smartlink_sections];
            labelprefix : '.L';
+           labelmaxlen : -1;
            comment : '# ';
            dollarsign: '$';
          );
@@ -279,6 +282,7 @@ implementation
            supported_targets : [system_sparc64_linux];
            flags : [af_needar,af_smartlink_sections];
            labelprefix : '.L';
+           labelmaxlen : -1;
            comment : '# ';
            dollarsign: '$';
          );

+ 11 - 3
compiler/systems.inc

@@ -55,7 +55,8 @@
              cpu_sparc64,                  { 18 }
              cpu_riscv32,                  { 19 }
              cpu_riscv64,                  { 20 }
-             cpu_xtensa                    { 21 }
+             cpu_xtensa,                   { 21 }
+             cpu_z80                       { 22 }
        );
 
        tasmmode= (asmmode_none
@@ -195,7 +196,9 @@
              system_xtensa_freertos,    { 104 }
              system_xtensa_linux,       { 105 }
              system_arm_freertos,       { 106 }
-             system_aarch64_win64       { 107 }
+             system_aarch64_win64,      { 107 }
+             system_z80_embedded,       { 108 }
+             system_z80_zxspectrum      { 109 }
        );
 
      type
@@ -252,6 +255,8 @@
              ,as_powerpc_gas_legacy    { for systems with very old GAS versions only, which don't support eg. named sections }
              ,as_llvm_clang
              ,as_clang_gas
+             ,as_z80asm
+             ,as_sdcc_sdasz80
        );
 
        tlink = (ld_none,
@@ -291,7 +296,8 @@
              ld_int_windows,
              ld_int_msdos,
              ld_int_win16,
-             ld_freertos
+             ld_freertos,
+             ld_zxspectrum
        );
 
        tar = (ar_none
@@ -301,6 +307,8 @@
             ,ar_gnu_gar
             ,ar_watcom_wlib_omf
             ,ar_watcom_wlib_omf_scripted
+            ,ar_sdcc_sdar
+            ,ar_sdcc_sdar_scripted
        );
 
        tres = (res_none

+ 11 - 5
compiler/systems.pas

@@ -88,6 +88,7 @@ interface
           supported_targets : set of tsystem;
           flags        : set of tasmflags;
           labelprefix : string[3];
+          labelmaxlen : integer;
           comment     : string[3];
           { set to '$' if that character is allowed in symbol names, otherwise
             to alternate character by which '$' should be replaced }
@@ -100,7 +101,7 @@ interface
           addfilecmd  : string[10];
           arfirstcmd  : string[50];
           arcmd       : string[50];
-          arfinishcmd : string[10];
+          arfinishcmd : string[11];
        end;
 
        presinfo = ^tresinfo;
@@ -186,7 +187,7 @@ interface
        tsysteminfo = record
           system       : tsystem;
           name         : string[34];
-          shortname    : string[9];
+          shortname    : string[10];
           flags        : set of tsystemflags;
           cpu          : tsystemcpu;
           unit_env     : string[16];
@@ -302,7 +303,7 @@ interface
                            system_powerpc64_embedded,system_avr_embedded,
                            system_jvm_java32,system_mipseb_embedded,system_mipsel_embedded,
                            system_i8086_embedded,system_riscv32_embedded,system_riscv64_embedded,
-                           system_xtensa_embedded];
+                           system_xtensa_embedded,system_z80_embedded];
 
        { all FreeRTOS systems }
        systems_freertos = [system_xtensa_freertos,system_arm_freertos];
@@ -441,7 +442,8 @@ interface
        cpu2str : array[TSystemCpu] of string[10] =
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
              'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
-             'aarch64', 'wasm', 'sparc64', 'riscv32', 'riscv64', 'xtensa');
+             'aarch64', 'wasm', 'sparc64', 'riscv32', 'riscv64', 'xtensa',
+             'z80');
 
        abiinfo : array[tabi] of tabiinfo = (
          (name: 'DEFAULT'; supported: true),
@@ -1130,7 +1132,11 @@ begin
 
 {$ifdef wasm}
   default_target(system_wasm_wasm32);
-{$endif}
+{$endif wasm}
+
+{$ifdef z80}
+  default_target(system_z80_embedded);
+{$endif z80}
 
 {$ifdef riscv32}
   default_target(system_riscv32_linux);

+ 73 - 0
compiler/systems/i_embed.pas

@@ -716,6 +716,74 @@ unit i_embed;
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S32';
           );
 
+       system_z80_embedded_info : tsysteminfo =
+          (
+            system       : system_z80_embedded;
+            name         : 'Embedded';
+            shortname    : 'embedded';
+            flags        : [tf_needs_symbol_size,tf_files_case_sensitive,
+                            tf_smartlink_library,
+                            tf_no_objectfiles_when_smartlinking];
+            cpu          : cpu_z80;
+            unit_env     : '';
+            extradefines : '';
+            exeext       : '';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.s';
+            objext       : '.rel';
+            resext       : '.res';
+            resobjext    : '.or';
+            sharedlibext : '.so';
+            staticlibext : '.a';
+            staticlibprefix : 'libp';
+            sharedlibprefix : 'lib';
+            sharedClibext : '.so';
+            staticClibext : '.a';
+            staticClibprefix : 'lib';
+            sharedClibprefix : 'lib';
+            importlibprefix : 'libimp';
+            importlibext : '.a';
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_sdcc_sdasz80;
+            assemextern  : as_sdcc_sdasz80;
+            link         : ld_none;
+            linkextern   : ld_embedded;
+            ar           : ar_sdcc_sdar;
+            res          : res_none;
+            dbg          : dbg_dwarf2;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign            : 1;
+                loopalign            : 1;
+                jumpalign            : 0;
+                jumpalignskipmax     : 0;
+                coalescealign        : 0;
+                coalescealignskipmax : 0;
+                constalignmin        : 0;
+                constalignmax        : 1;
+                varalignmin          : 0;
+                varalignmax          : 1;
+                localalignmin        : 0;
+                localalignmax        : 1;
+                recordalignmin       : 0;
+                recordalignmax       : 1;
+                maxCrecordalign      : 1
+              );
+            first_parm_offset : 4;
+            stacksize    : 1024;
+            stackalign   : 1;
+            abi : abi_default;
+            llvmdatalayout : 'todo';
+          );
+
  implementation
 
 initialization
@@ -769,5 +837,10 @@ initialization
     set_source_info(system_xtensa_embedded_info);
   {$endif embedded}
 {$endif cpuxtensa}
+{$ifdef CPUZ80}
+  {$ifdef embedded}
+    set_source_info(system_z80_embedded_info);
+  {$endif embedded}
+{$endif CPUZ80}
 end.
 

+ 108 - 0
compiler/systems/i_zxspectrum.pas

@@ -0,0 +1,108 @@
+{
+    This unit implements support information structures for the FPC ZX Spectrum target
+
+    Copyright (c) 1998-2006 by Peter Vreman
+
+    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 i_zxspectrum;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       systems;
+
+    const
+       system_z80_zxspectrum_info : tsysteminfo =
+          (
+            system       : system_z80_zxspectrum;
+            name         : 'ZX Spectrum';
+            shortname    : 'zxspectrum';
+            flags        : [tf_needs_symbol_size,tf_files_case_sensitive,
+                            tf_smartlink_library,
+                            tf_no_objectfiles_when_smartlinking];
+            cpu          : cpu_z80;
+            unit_env     : '';
+            extradefines : '';
+            exeext       : '';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.s';
+            objext       : '.rel';
+            resext       : '.res';
+            resobjext    : '.or';
+            sharedlibext : '.so';
+            staticlibext : '.a';
+            staticlibprefix : 'libp';
+            sharedlibprefix : 'lib';
+            sharedClibext : '.so';
+            staticClibext : '.a';
+            staticClibprefix : 'lib';
+            sharedClibprefix : 'lib';
+            importlibprefix : 'libimp';
+            importlibext : '.a';
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_sdcc_sdasz80;
+            assemextern  : as_sdcc_sdasz80;
+            link         : ld_none;
+            linkextern   : ld_zxspectrum;
+            ar           : ar_sdcc_sdar;
+            res          : res_none;
+            dbg          : dbg_dwarf2;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign            : 1;
+                loopalign            : 1;
+                jumpalign            : 0;
+                jumpalignskipmax     : 0;
+                coalescealign        : 0;
+                coalescealignskipmax : 0;
+                constalignmin        : 0;
+                constalignmax        : 1;
+                varalignmin          : 0;
+                varalignmax          : 1;
+                localalignmin        : 0;
+                localalignmax        : 1;
+                recordalignmin       : 0;
+                recordalignmax       : 1;
+                maxCrecordalign      : 1
+              );
+            first_parm_offset : 4;
+            stacksize    : 1024;
+            stackalign   : 1;
+            abi : abi_default;
+            llvmdatalayout : 'todo';
+          );
+
+ implementation
+
+initialization
+{$ifdef CPUZ80}
+  {$ifdef zxspectrum}
+    set_source_info(system_z80_zxspectrum_info);
+  {$endif zxspectrum}
+{$endif CPUZ80}
+end.
+

+ 267 - 0
compiler/systems/t_embed.pas

@@ -46,6 +46,18 @@ implementation
           function postprocessexecutable(const fn : string;isdll:boolean):boolean;
        end;
 
+       { TlinkerEmbedded_SdccSdld - the sdld linker from the SDCC project ( http://sdcc.sourceforge.net/ ) }
+
+       TlinkerEmbedded_SdccSdld=class(texternallinker)
+       private
+          Function  WriteResponseFile: Boolean;
+       public
+{          constructor Create; override;}
+          procedure SetDefaultInfo; override;
+          function  MakeExecutable:boolean; override;
+{          function postprocessexecutable(const fn : string;isdll:boolean):boolean;}
+       end;
+
 
 
 {*****************************************************************************
@@ -1804,6 +1816,256 @@ function TLinkerEmbedded.postprocessexecutable(const fn : string;isdll:boolean):
   end;
 
 
+{*****************************************************************************
+                              TlinkerEmbedded_SdccSdld
+*****************************************************************************}
+
+function TlinkerEmbedded_SdccSdld.WriteResponseFile: Boolean;
+  Var
+    linkres  : TLinkRes;
+    i        : longint;
+    HPath    : TCmdStrListItem;
+    s,s1,s2  : TCmdStr;
+    prtobj,
+    cprtobj  : string[80];
+    linklibc : boolean;
+    found1,
+    found2   : boolean;
+  {$if defined(ARM)}
+    LinkStr  : string;
+  {$endif}
+  begin
+    WriteResponseFile:=False;
+    linklibc:=(SharedLibFiles.Find('c')<>nil);
+    prtobj:='prt0';
+    cprtobj:='cprt0';
+    if linklibc then
+      prtobj:=cprtobj;
+
+    { Open link.res file }
+    LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
+
+    { Write path to search libraries }
+(*    HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
+    while assigned(HPath) do
+     begin
+      s:=HPath.Str;
+      if (cs_link_on_target in current_settings.globalswitches) then
+       s:=ScriptFixFileName(s);
+      LinkRes.Add('-L'+s);
+      HPath:=TCmdStrListItem(HPath.Next);
+     end;
+    HPath:=TCmdStrListItem(LibrarySearchPath.First);
+    while assigned(HPath) do
+     begin
+      s:=HPath.Str;
+      if s<>'' then
+       LinkRes.Add('SEARCH_DIR("'+s+'")');
+      HPath:=TCmdStrListItem(HPath.Next);
+     end;
+
+    LinkRes.Add('INPUT (');
+    { add objectfiles, start with prt0 always }*)
+    //s:=FindObjectFile('prt0','',false);
+    if prtobj<>'' then
+      begin
+        s:=FindObjectFile(prtobj,'',false);
+        LinkRes.AddFileName(s);
+      end;
+
+    { try to add crti and crtbegin if linking to C }
+    if linklibc then
+     begin
+       if librarysearchpath.FindFile('crtbegin.o',false,s) then
+        LinkRes.AddFileName(s);
+       if librarysearchpath.FindFile('crti.o',false,s) then
+        LinkRes.AddFileName(s);
+     end;
+
+    while not ObjectFiles.Empty do
+     begin
+      s:=ObjectFiles.GetFirst;
+      if s<>'' then
+       begin
+        { vlink doesn't use SEARCH_DIR for object files }
+        if not(cs_link_on_target in current_settings.globalswitches) then
+         s:=FindObjectFile(s,'',false);
+        LinkRes.AddFileName((maybequoted(s)));
+       end;
+     end;
+
+    { Write staticlibraries }
+    if not StaticLibFiles.Empty then
+     begin
+      { vlink doesn't need, and doesn't support GROUP }
+{      if (cs_link_on_target in current_settings.globalswitches) then
+       begin
+        LinkRes.Add(')');
+        LinkRes.Add('GROUP(');
+       end;}
+      while not StaticLibFiles.Empty do
+       begin
+        S:=StaticLibFiles.GetFirst;
+        LinkRes.Add('-l'+maybequoted(s));
+       end;
+     end;
+
+(*    if (cs_link_on_target in current_settings.globalswitches) then
+     begin
+      LinkRes.Add(')');
+
+      { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
+        here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
+      linklibc:=false;
+      while not SharedLibFiles.Empty do
+       begin
+        S:=SharedLibFiles.GetFirst;
+        if s<>'c' then
+         begin
+          i:=Pos(target_info.sharedlibext,S);
+          if i>0 then
+           Delete(S,i,255);
+          LinkRes.Add('-l'+s);
+         end
+        else
+         begin
+          LinkRes.Add('-l'+s);
+          linklibc:=true;
+         end;
+       end;
+      { be sure that libc&libgcc is the last lib }
+      if linklibc then
+       begin
+        LinkRes.Add('-lc');
+        LinkRes.Add('-lgcc');
+       end;
+     end
+    else
+     begin
+      while not SharedLibFiles.Empty do
+       begin
+        S:=SharedLibFiles.GetFirst;
+        LinkRes.Add('lib'+s+target_info.staticlibext);
+       end;
+      LinkRes.Add(')');
+     end;*)
+
+    { objects which must be at the end }
+    (*if linklibc then
+     begin
+       found1:=librarysearchpath.FindFile('crtend.o',false,s1);
+       found2:=librarysearchpath.FindFile('crtn.o',false,s2);
+       if found1 or found2 then
+        begin
+          LinkRes.Add('INPUT(');
+          if found1 then
+           LinkRes.AddFileName(s1);
+          if found2 then
+           LinkRes.AddFileName(s2);
+          LinkRes.Add(')');
+        end;
+     end;*)
+
+    { Write and Close response }
+    linkres.writetodisk;
+    linkres.free;
+
+    WriteResponseFile:=True;
+  end;
+
+procedure TlinkerEmbedded_SdccSdld.SetDefaultInfo;
+  const
+{$if defined(Z80)}
+    ExeName='sdldz80';
+{$else}
+    ExeName='sdld';
+{$endif}
+  begin
+    with Info do
+     begin
+       ExeCmd[1]:=ExeName+' -n $OPT -i $MAP $EXE -f $RES'
+       //-g '+platform_select+' $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP -L. -o $EXE -T $RES';
+     end;
+  end;
+
+function TlinkerEmbedded_SdccSdld.MakeExecutable: boolean;
+  var
+    binstr,
+    cmdstr,
+    mapstr: TCmdStr;
+    success : boolean;
+    StaticStr,
+//    GCSectionsStr,
+    DynLinkStr,
+    StripStr,
+    FixedExeFileName: string;
+  begin
+    { for future use }
+    StaticStr:='';
+    StripStr:='';
+    mapstr:='';
+    DynLinkStr:='';
+    FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
+
+(*    GCSectionsStr:='--gc-sections';
+    //if not(cs_link_extern in current_settings.globalswitches) then
+    if not(cs_link_nolink in current_settings.globalswitches) then
+     Message1(exec_i_linking,current_module.exefilename);*)
+
+    if (cs_link_map in current_settings.globalswitches) then
+     mapstr:='-mw';
+
+  { Write used files and libraries }
+    WriteResponseFile();
+
+  { Call linker }
+    SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
+    Replace(cmdstr,'$OPT',Info.ExtraOptions);
+    if not(cs_link_on_target in current_settings.globalswitches) then
+     begin
+      Replace(cmdstr,'$EXE',FixedExeFileName);
+      Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
+      Replace(cmdstr,'$STATIC',StaticStr);
+      Replace(cmdstr,'$STRIP',StripStr);
+      Replace(cmdstr,'$MAP',mapstr);
+//      Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+      Replace(cmdstr,'$DYNLINK',DynLinkStr);
+     end
+    else
+     begin
+      Replace(cmdstr,'$EXE',FixedExeFileName);
+      Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
+      Replace(cmdstr,'$STATIC',StaticStr);
+      Replace(cmdstr,'$STRIP',StripStr);
+      Replace(cmdstr,'$MAP',mapstr);
+//      Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+      Replace(cmdstr,'$DYNLINK',DynLinkStr);
+     end;
+    success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
+
+  { Remove ReponseFile }
+    if success and not(cs_link_nolink in current_settings.globalswitches) then
+     DeleteFile(outputexedir+Info.ResName);
+
+(*  { Post process }
+    if success and not(cs_link_nolink in current_settings.globalswitches) then
+      success:=PostProcessExecutable(FixedExeFileName,false);
+
+    if success and (target_info.system in [system_arm_embedded,system_avr_embedded,system_mipsel_embedded,system_xtensa_embedded]) then
+      begin
+        success:=DoExec(FindUtil(utilsprefix+'objcopy'),'-O ihex '+
+          FixedExeFileName+' '+
+          maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.hex'))),true,false);
+        if success then
+          success:=DoExec(FindUtil(utilsprefix+'objcopy'),'-O binary '+
+            FixedExeFileName+' '+
+            maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.bin'))),true,false);
+      end;*)
+
+    MakeExecutable:=success;   { otherwise a recursive call to link method }
+  end;
+
+
 {*****************************************************************************
                                      Initialize
 *****************************************************************************}
@@ -1861,4 +2123,9 @@ initialization
   RegisterLinker(ld_embedded,TLinkerEmbedded);
   RegisterTarget(system_xtensa_embedded_info);
 {$endif xtensa}
+
+{$ifdef z80}
+  RegisterLinker(ld_embedded,TlinkerEmbedded_SdccSdld);
+  RegisterTarget(system_z80_embedded_info);
+{$endif z80}
 end.

+ 305 - 0
compiler/systems/t_zxspectrum.pas

@@ -0,0 +1,305 @@
+{
+    Copyright (c) 2005-2020 by Free Pascal Compiler team
+
+    This unit implements support import, export, link routines
+    for the ZX Spectrum Target
+
+    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 t_zxspectrum;
+
+{$i fpcdefs.inc}
+
+interface
+
+
+implementation
+
+    uses
+       SysUtils,
+       cutils,cfileutl,cclasses,
+       globtype,globals,systems,verbose,comphook,cscript,fmodule,i_zxspectrum,link,
+       cpuinfo;
+
+    type
+
+       { TLinkerZXSpectrum_SdccSdld - the sdld linker from the SDCC project ( http://sdcc.sourceforge.net/ ) }
+
+       TLinkerZXSpectrum_SdccSdld=class(texternallinker)
+       private
+          FOrigin: Word;
+          Function  WriteResponseFile: Boolean;
+       public
+          procedure SetDefaultInfo; override;
+          function  MakeExecutable:boolean; override;
+          function postprocessexecutable(const fn : string;isdll:boolean):boolean;
+       end;
+
+
+{*****************************************************************************
+                          TLinkerZXSpectrum_SdccSdld
+*****************************************************************************}
+
+function TLinkerZXSpectrum_SdccSdld.WriteResponseFile: Boolean;
+  Var
+    linkres  : TLinkRes;
+    i        : longint;
+    HPath    : TCmdStrListItem;
+    s,s1,s2  : TCmdStr;
+    prtobj,
+    cprtobj  : string[80];
+    linklibc : boolean;
+    found1,
+    found2   : boolean;
+  {$if defined(ARM)}
+    LinkStr  : string;
+  {$endif}
+  begin
+    WriteResponseFile:=False;
+    linklibc:=(SharedLibFiles.Find('c')<>nil);
+    prtobj:='prt0';
+    cprtobj:='cprt0';
+    if linklibc then
+      prtobj:=cprtobj;
+
+    { Open link.res file }
+    LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
+
+    { Write the origin (i.e. the program load address) }
+    LinkRes.Add('-b _CODE='+tostr(FOrigin));
+
+    { Write path to search libraries }
+(*    HPath:=TCmdStrListItem(current_module.locallibrarysearchpath.First);
+    while assigned(HPath) do
+     begin
+      s:=HPath.Str;
+      if (cs_link_on_target in current_settings.globalswitches) then
+       s:=ScriptFixFileName(s);
+      LinkRes.Add('-L'+s);
+      HPath:=TCmdStrListItem(HPath.Next);
+     end;
+    HPath:=TCmdStrListItem(LibrarySearchPath.First);
+    while assigned(HPath) do
+     begin
+      s:=HPath.Str;
+      if s<>'' then
+       LinkRes.Add('SEARCH_DIR("'+s+'")');
+      HPath:=TCmdStrListItem(HPath.Next);
+     end;
+
+    LinkRes.Add('INPUT (');
+    { add objectfiles, start with prt0 always }*)
+    //s:=FindObjectFile('prt0','',false);
+    if prtobj<>'' then
+      begin
+        s:=FindObjectFile(prtobj,'',false);
+        LinkRes.AddFileName(s);
+      end;
+
+    { try to add crti and crtbegin if linking to C }
+    if linklibc then
+     begin
+       if librarysearchpath.FindFile('crtbegin.o',false,s) then
+        LinkRes.AddFileName(s);
+       if librarysearchpath.FindFile('crti.o',false,s) then
+        LinkRes.AddFileName(s);
+     end;
+
+    while not ObjectFiles.Empty do
+     begin
+      s:=ObjectFiles.GetFirst;
+      if s<>'' then
+       begin
+        { vlink doesn't use SEARCH_DIR for object files }
+        if not(cs_link_on_target in current_settings.globalswitches) then
+         s:=FindObjectFile(s,'',false);
+        LinkRes.AddFileName((maybequoted(s)));
+       end;
+     end;
+
+    { Write staticlibraries }
+    if not StaticLibFiles.Empty then
+     begin
+      { vlink doesn't need, and doesn't support GROUP }
+{      if (cs_link_on_target in current_settings.globalswitches) then
+       begin
+        LinkRes.Add(')');
+        LinkRes.Add('GROUP(');
+       end;}
+      while not StaticLibFiles.Empty do
+       begin
+        S:=StaticLibFiles.GetFirst;
+        LinkRes.Add('-l'+maybequoted(s));
+       end;
+     end;
+
+(*    if (cs_link_on_target in current_settings.globalswitches) then
+     begin
+      LinkRes.Add(')');
+
+      { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
+        here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
+      linklibc:=false;
+      while not SharedLibFiles.Empty do
+       begin
+        S:=SharedLibFiles.GetFirst;
+        if s<>'c' then
+         begin
+          i:=Pos(target_info.sharedlibext,S);
+          if i>0 then
+           Delete(S,i,255);
+          LinkRes.Add('-l'+s);
+         end
+        else
+         begin
+          LinkRes.Add('-l'+s);
+          linklibc:=true;
+         end;
+       end;
+      { be sure that libc&libgcc is the last lib }
+      if linklibc then
+       begin
+        LinkRes.Add('-lc');
+        LinkRes.Add('-lgcc');
+       end;
+     end
+    else
+     begin
+      while not SharedLibFiles.Empty do
+       begin
+        S:=SharedLibFiles.GetFirst;
+        LinkRes.Add('lib'+s+target_info.staticlibext);
+       end;
+      LinkRes.Add(')');
+     end;*)
+
+    { objects which must be at the end }
+    (*if linklibc then
+     begin
+       found1:=librarysearchpath.FindFile('crtend.o',false,s1);
+       found2:=librarysearchpath.FindFile('crtn.o',false,s2);
+       if found1 or found2 then
+        begin
+          LinkRes.Add('INPUT(');
+          if found1 then
+           LinkRes.AddFileName(s1);
+          if found2 then
+           LinkRes.AddFileName(s2);
+          LinkRes.Add(')');
+        end;
+     end;*)
+
+    { Write and Close response }
+    linkres.writetodisk;
+    linkres.free;
+
+    WriteResponseFile:=True;
+  end;
+
+procedure TLinkerZXSpectrum_SdccSdld.SetDefaultInfo;
+  const
+    ExeName='sdldz80';
+  begin
+    FOrigin:={32768}23800;
+    with Info do
+     begin
+       ExeCmd[1]:=ExeName+' -n $OPT -i $MAP $EXE -f $RES'
+     end;
+  end;
+
+function TLinkerZXSpectrum_SdccSdld.MakeExecutable: boolean;
+  var
+    binstr,
+    cmdstr,
+    mapstr: TCmdStr;
+    success : boolean;
+    StaticStr,
+    //GCSectionsStr,
+    DynLinkStr,
+    StripStr,
+    FixedExeFileName: string;
+  begin
+    { for future use }
+    StaticStr:='';
+    StripStr:='';
+    mapstr:='';
+    DynLinkStr:='';
+    FixedExeFileName:=maybequoted(ScriptFixFileName(ChangeFileExt(current_module.exefilename,'.ihx')));
+
+(*    GCSectionsStr:='--gc-sections';
+    //if not(cs_link_extern in current_settings.globalswitches) then
+    if not(cs_link_nolink in current_settings.globalswitches) then
+     Message1(exec_i_linking,current_module.exefilename);*)
+
+    if (cs_link_map in current_settings.globalswitches) then
+     mapstr:='-mw';
+
+  { Write used files and libraries }
+    WriteResponseFile();
+
+  { Call linker }
+    SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
+    Replace(cmdstr,'$OPT',Info.ExtraOptions);
+    if not(cs_link_on_target in current_settings.globalswitches) then
+     begin
+      Replace(cmdstr,'$EXE',FixedExeFileName);
+      Replace(cmdstr,'$RES',(maybequoted(ScriptFixFileName(outputexedir+Info.ResName))));
+      Replace(cmdstr,'$STATIC',StaticStr);
+      Replace(cmdstr,'$STRIP',StripStr);
+      Replace(cmdstr,'$MAP',mapstr);
+      //Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+      Replace(cmdstr,'$DYNLINK',DynLinkStr);
+     end
+    else
+     begin
+      Replace(cmdstr,'$EXE',FixedExeFileName);
+      Replace(cmdstr,'$RES',maybequoted(ScriptFixFileName(outputexedir+Info.ResName)));
+      Replace(cmdstr,'$STATIC',StaticStr);
+      Replace(cmdstr,'$STRIP',StripStr);
+      Replace(cmdstr,'$MAP',mapstr);
+      //Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+      Replace(cmdstr,'$DYNLINK',DynLinkStr);
+     end;
+    success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
+
+  { Remove ReponseFile }
+    if success and not(cs_link_nolink in current_settings.globalswitches) then
+     DeleteFile(outputexedir+Info.ResName);
+
+  { Post process }
+    if success and not(cs_link_nolink in current_settings.globalswitches) then
+      success:=PostProcessExecutable(FixedExeFileName,false);
+
+    MakeExecutable:=success;   { otherwise a recursive call to link method }
+  end;
+
+function TLinkerZXSpectrum_SdccSdld.postprocessexecutable(const fn: string; isdll: boolean): boolean;
+  begin
+    result:=DoExec(FindUtil(utilsprefix+'ihx2tzx'),' '+fn,true,false);
+  end;
+
+
+{*****************************************************************************
+                                     Initialize
+*****************************************************************************}
+
+initialization
+{$ifdef z80}
+  RegisterLinker(ld_zxspectrum,TLinkerZXSpectrum_SdccSdld);
+  RegisterTarget(system_z80_zxspectrum_info);
+{$endif z80}
+end.

+ 37 - 1
compiler/utils/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos 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 aarch64-win64 aarch64-android wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos 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 aarch64-win64 aarch64-android wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -641,6 +641,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override CLEAN_UNITS+=ppu crc
 endif
@@ -932,6 +938,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override CLEAN_UNITS+=ppu crc
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override CLEAN_UNITS+=ppu crc
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override CLEAN_UNITS+=ppu crc
+endif
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=..
@@ -1224,6 +1236,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_UNITDIR+=..
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_UNITDIR+=..
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_UNITDIR+=..
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_SOURCEDIR+=..
 endif
@@ -1515,6 +1533,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_SOURCEDIR+=..
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_SOURCEDIR+=..
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_SOURCEDIR+=..
+endif
 override SHARED_BUILD=n
 override SHARED_BUILD=n
 ifdef REQUIRE_UNITSDIR
@@ -1962,6 +1986,9 @@ STATICLIBEXT=.a
 else
 EXEEXT=.bin
 endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
 SHORTSUFFIX=emb
 endif
 ifeq ($(OS_TARGET),win16)
@@ -1970,6 +1997,9 @@ STATICLIBEXT=.a
 SHAREDLIBEXT=.dll
 SHORTSUFFIX=w16
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
@@ -2516,6 +2546,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 REQUIRE_PACKAGES_RTL=1
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+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),)

+ 232 - 0
compiler/utils/mkz80ins.pp

@@ -0,0 +1,232 @@
+{
+    Copyright (c) 2020 by Nikolay Nikolov
+
+    Convert z80ins.dat to a set of .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.
+
+ **********************************************************************}
+
+program mkz80ins;
+
+{$mode objfpc}{$H+}
+
+uses
+  SysUtils,StrUtils;
+
+const
+  Version = '1.0.0';
+  HeaderStr = '{ don''t edit, this file is generated from z80ins.dat; to regenerate, run ''make insdat'' in the compiler directory }';
+  max_operands = 2;
+
+  ParamTypes: array [0..40,0..1] of string = (
+    ('void',  'OT_NONE'),
+    ('r',     'OT_REG8'),
+    ('r''',   'OT_REG8'),
+    ('b',     'OT_IMM3'),
+    ('n',     'OT_IMM8'),
+    ('p',     'OT_IMM_RST'),
+    ('e',     'OT_RELJMP8'),
+    ('nn',    'OT_IMM16'),
+    ('0',     'OT_IMM_VAL0'),
+    ('1',     'OT_IMM_VAL1'),
+    ('2',     'OT_IMM_VAL2'),
+    ('cc',    'OT_COND'),
+    ('C',     'OT_COND_C'),
+    ('NC',    'OT_COND_NC'),
+    ('Z',     'OT_COND_Z'),
+    ('NZ',    'OT_COND_NZ'),
+    ('dd',    'OT_REG16_BC_DE_HL_SP'),
+    ('qq',    'OT_REG16_BC_DE_HL_AF'),
+    ('pp',    'OT_REG16_BC_DE_IX_SP'),
+    ('rr',    'OT_REG16_BC_DE_IY_SP'),
+    ('A',     'OT_REG8_A'),
+    ('I',     'OT_REG8_I'),
+    ('R',     'OT_REG8_R'),
+    ('IX',    'OT_REG16_IX'),
+    ('IY',    'OT_REG16_IY'),
+    ('SP',    'OT_REG16_SP'),
+    ('DE',    'OT_REG16_DE'),
+    ('HL',    'OT_REG16_HL'),
+    ('AF',    'OT_REG16_AF'),
+    ('AF''',  'OT_REG16_AF_'),
+    ('(C)',   'OT_REG8_C_PORT'),
+    ('(n)',   'OT_IMM_PORT'),
+    ('(nn)',  'OT_REF_ADDR16'),
+    ('(BC)',  'OT_REF_BC'),
+    ('(DE)',  'OT_REF_DE'),
+    ('(HL)',  'OT_REF_HL'),
+    ('(SP)',  'OT_REF_SP'),
+    ('(IX)',  'OT_REF_IX'),
+    ('(IY)',  'OT_REF_IY'),
+    ('(IX+d)','OT_REF_IX_d'),
+    ('(IY+d)','OT_REF_IY_d')
+  );
+
+type
+
+  { TZ80InsDatOutputFiles }
+
+  TZ80InsDatOutputFiles = class
+  public
+    OpFile: TextFile;
+    NOpFile: TextFile;
+    StdOpNames: TextFile;
+    InsTabFile: TextFile;
+
+    constructor Create;
+    destructor Destroy;override;
+  end;
+
+function PasEncode(const S: string): string;
+  var
+    Ch: Char;
+    InQuotes: Boolean;
+  begin
+    Result:='';
+    InQuotes:=False;
+    for Ch in S do
+      if (Ch>=#32) and (Ch<=#126) then
+        begin
+          if not InQuotes then
+            begin
+              Result:=Result+'''';
+              InQuotes:=True;
+            end;
+          if Ch='''' then
+            Result:=Result+''''''
+          else
+            Result:=Result+Ch;
+        end
+      else
+        begin
+          if InQuotes then
+            begin
+              Result:=Result+'''';
+              InQuotes:=False;
+            end;
+          Result:=Result+'#'+IntToStr(Ord(Ch));
+        end;
+    if InQuotes then
+      Result:=Result+'''';
+    if Result='' then
+      Result:='''''';
+  end;
+
+constructor TZ80InsDatOutputFiles.Create;
+  begin
+    AssignFile(OpFile,'z80op.inc');
+    Rewrite(OpFile);
+    Writeln(OpFile,HeaderStr);
+    Writeln(OpFile,'(');
+    AssignFile(NOpFile,'z80nop.inc');
+    Rewrite(NOpFile);
+    Writeln(NOpFile,HeaderStr);
+    AssignFile(StdOpNames,'z80stdopnames.inc');
+    Rewrite(StdOpNames);
+    Writeln(StdOpNames,HeaderStr);
+    Writeln(StdOpNames,'(');
+    AssignFile(InsTabFile,'z80tab.inc');
+    Rewrite(InsTabFile);
+    Writeln(InsTabFile,HeaderStr);
+    Writeln(InsTabFile,'(');
+  end;
+
+destructor TZ80InsDatOutputFiles.Destroy;
+  begin
+    CloseFile(OpFile);
+    CloseFile(NOpFile);
+    CloseFile(StdOpNames);
+    CloseFile(InsTabFile);
+    inherited Destroy;
+  end;
+
+function FindParamType(const ParamTypeStr: string): Integer;
+var
+  I: Integer;
+begin
+  for I:=Low(ParamTypes) to High(ParamTypes) do
+    if ParamTypes[I,0]=ParamTypeStr then
+      exit(I);
+  raise Exception.Create('Invalid param type: '''+ParamTypeStr+'''');
+end;
+
+var
+  InsDatFile: TextFile;
+  OutputFiles: TZ80InsDatOutputFiles=nil;
+  S, op, ParamsStr: string;
+  FirstIns: Boolean=true;
+  OpCount: Integer=0;
+  S_Split, S_Params: TStringArray;
+  ParamIdx: Integer;
+begin
+  writeln('FPC Z80 Instruction Table Converter Version ',Version);
+  AssignFile(InsDatFile,'../z80/z80ins.dat');
+  Reset(InsDatFile);
+  try
+    OutputFiles:=TZ80InsDatOutputFiles.Create;
+    while not EoF(InsDatFile) do
+      begin
+        Readln(InsDatFile,S);
+        S:=Trim(S);
+        if AnsiStartsStr(';',S) then
+          continue
+        else if AnsiStartsStr('[',S) then
+          begin
+            op:=Copy(S,2,Length(S)-2);
+            if not FirstIns then
+              begin
+                Writeln(OutputFiles.OpFile,',');
+                Writeln(OutputFiles.StdOpNames,',');
+              end;
+            FirstIns:=False;
+            Write(OutputFiles.OpFile,'A_'+op);
+            Write(OutputFiles.StdOpNames,''''+LowerCase(op)+'''');
+          end
+        else if S<>'' then
+          begin
+            Inc(OpCount);
+            if OpCount<>1 then
+              Writeln(OutputFiles.InsTabFile,',');
+            S_Split:=S.Split(' ',TStringSplitOptions.ExcludeEmpty);
+            S_Params:=S_Split[0].Split(',',TStringSplitOptions.ExcludeEmpty);
+            if (Length(S_Params)=1) and (S_Params[0]='void') then
+              SetLength(S_Params,0);
+            Writeln(OutputFiles.InsTabFile,'  (');
+            Writeln(OutputFiles.InsTabFile,'    opcode  : A_',op,';');
+            Writeln(OutputFiles.InsTabFile,'    ops     : ',Length(S_Params),';');
+            Write(OutputFiles.InsTabFile,  '    optypes : (');
+            if Length(S_Params)>max_operands then
+              raise Exception.Create('Too many operands');
+            for ParamIdx:=0 to max_operands-1 do
+              begin
+                if ParamIdx<>0 then
+                  Write(OutputFiles.InsTabFile,',');
+                if ParamIdx<=High(S_Params) then
+                  Write(OutputFiles.InsTabFile,ParamTypes[FindParamType(S_Params[ParamIdx]),1])
+                else
+                  Write(OutputFiles.InsTabFile,'OT_NONE');
+              end;
+            Writeln(OutputFiles.InsTabFile, ');');
+            Writeln(OutputFiles.InsTabFile,  '    code    : ',PasEncode(S_Split[1]),';');
+            Writeln(OutputFiles.InsTabFile,  '    flags   : 0');
+            Write(OutputFiles.InsTabFile,  '  )');
+          end;
+      end;
+    Writeln(OutputFiles.OpFile,');');
+    Writeln(OutputFiles.StdOpNames,');');
+    Writeln(OutputFiles.NOpFile,OpCount,';');
+    Writeln(OutputFiles.InsTabFile);
+    Writeln(OutputFiles.InsTabFile,');');
+  finally
+    FreeAndNil(OutputFiles);
+    CloseFile(InsDatFile);
+  end;
+end.
+

+ 270 - 0
compiler/utils/mkz80reg.pp

@@ -0,0 +1,270 @@
+{
+    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;
+
+uses
+  sysutils;
+
+const Version = '1.00';
+      max_regcount = 200;
+
+var s : string;
+    i : longint;
+    line : longint;
+    regcount:byte;
+    regcount_bsstart:byte;
+    names,
+    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;
+        numbers[regcount]:=readstr;
+        readcomma;
+        stdnames[regcount]:=readstr;
+        readcomma;
+        stabs[regcount]:=readstr;
+        readcomma;
+        dwarf[regcount]:=readstr;
+        { Create register number }
+        if numbers[regcount][1]<>'$' then
+          begin
+            writeln('Missing $ before number, at line ',line);
+            writeln('Line: "',s,'"');
+            halt(1);
+          end;
+        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],' = ',StrToInt(numbers[i]) and $ff,';');
+      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.

+ 7 - 3
compiler/utils/ppuutils/ppudump.pp

@@ -86,7 +86,8 @@ const
     { 18 } 'sparc64',
     { 19 } 'riscv32',
     { 20 } 'riscv64',
-    { 21 } 'xtensa'
+    { 21 } 'xtensa',
+    { 22 } 'z80'
     );
 
   CpuHasController : array[tsystemcpu] of boolean =
@@ -112,7 +113,8 @@ const
     { 18 } false {'sparc64'},
     { 19 } false {'riscv32'},
     { 20 } false {'riscv64'},
-    { 21 } true  {'xtensa'}
+    { 21 } true  {'xtensa'},
+    { 22 } true  {'z80'}
     );
 
 { List of all supported system-cpu couples }
@@ -225,7 +227,9 @@ const
   { 104 } 'FreeRTos-Xtensa',
   { 105 } 'Linux-Xtensa',
   { 106 } 'FreeRTos-arm',
-  { 107 } 'Win64-AArch64'
+  { 107 } 'Win64-AArch64',
+  { 108 } 'Embedded-Z80',
+  { 109 } 'ZXSpectrum-Z80'
   );
 
 const

+ 13 - 0
compiler/x86/agx86att.pas

@@ -441,6 +441,7 @@ interface
                                  system_x86_64_android,system_x86_64_haiku];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -454,6 +455,7 @@ interface
             supported_targets : [system_x86_64_linux,system_x86_64_freebsd,system_x86_64_win64,system_x86_64_embedded];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -467,6 +469,7 @@ interface
             supported_targets : [system_x86_64_solaris];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -481,6 +484,7 @@ interface
             supported_targets : [system_x86_64_solaris];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -496,6 +500,7 @@ interface
             supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -509,6 +514,7 @@ interface
             supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -526,6 +532,7 @@ interface
                                 system_i386_nativent,system_i386_android,system_i386_aros];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -542,6 +549,7 @@ interface
                                 system_i386_nativent];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -556,6 +564,7 @@ interface
             supported_targets : [system_i386_linux,system_i386_OS2,system_i386_freebsd,system_i386_netbsd,system_i386_openbsd,system_i386_EMX,system_i386_embedded];
             flags : [af_needar,af_stabs_use_function_absolute_addresses];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -570,6 +579,7 @@ interface
             supported_targets : [system_i386_darwin,system_i386_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -583,6 +593,7 @@ interface
             supported_targets : [system_i386_darwin,system_i386_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs];
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -599,6 +610,7 @@ interface
                                 system_x86_6432_linux,system_i386_android];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );
@@ -612,6 +624,7 @@ interface
             supported_targets : [system_i386_solaris];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );

+ 4 - 0
compiler/x86/agx86int.pas

@@ -1159,6 +1159,7 @@ implementation
             supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
             flags : [af_needar,af_labelprefix_only_inside_procedure];
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1172,6 +1173,7 @@ implementation
             supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
             flags : [af_needar];
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1185,6 +1187,7 @@ implementation
             supported_targets : [system_i386_watcom];
             flags : [af_needar];
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1199,6 +1202,7 @@ implementation
             supported_targets : [system_x86_64_win64];
             flags : [af_needar];
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );

+ 15 - 0
compiler/x86/agx86nsm.pas

@@ -1483,6 +1483,7 @@ interface
             supported_targets : [system_i8086_msdos,system_i8086_win16,system_i8086_embedded];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1495,6 +1496,7 @@ interface
             supported_targets : [system_i8086_msdos,system_i8086_win16,system_i8086_embedded];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1510,6 +1512,7 @@ interface
             supported_targets : [system_i386_go32v2];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1523,6 +1526,7 @@ interface
             supported_targets : [system_i386_win32];
             flags : [af_needar,af_no_debug,af_smartlink_sections];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1536,6 +1540,7 @@ interface
             supported_targets : [system_i386_embedded, system_i8086_msdos];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1549,6 +1554,7 @@ interface
             supported_targets : [system_i386_wdosx];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1563,6 +1569,7 @@ interface
             supported_targets : [system_i386_linux];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1576,6 +1583,7 @@ interface
             supported_targets : [system_i386_darwin];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1589,6 +1597,7 @@ interface
             supported_targets : [system_i386_beos];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1602,6 +1611,7 @@ interface
             supported_targets : [system_i386_haiku];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1614,6 +1624,7 @@ interface
             supported_targets : [system_any];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1630,6 +1641,7 @@ interface
             supported_targets : [system_any];
             flags : [af_needar{,af_no_debug}];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1643,6 +1655,7 @@ interface
             supported_targets : [system_x86_64_win64];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1656,6 +1669,7 @@ interface
             supported_targets : [system_x86_64_linux];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );
@@ -1670,6 +1684,7 @@ interface
             supported_targets : [system_x86_64_darwin];
             flags : [af_needar,af_no_debug];
             labelprefix : '..@';
+            labelmaxlen : -1;
             comment : '; ';
             dollarsign: '$';
           );

+ 1 - 0
compiler/x86_64/cpuelf.pas

@@ -699,6 +699,7 @@ implementation
                              system_x86_64_haiku];
         flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
         labelprefix : '.L';
+        labelmaxlen : -1;
         comment : '';
         dollarsign: '$';
       );

+ 1 - 0
compiler/xtensa/agcpugas.pas

@@ -176,6 +176,7 @@ unit agcpugas;
             supported_targets : [system_xtensa_embedded,system_xtensa_linux,system_xtensa_freertos];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             dollarsign: '$';
           );

+ 490 - 0
compiler/z80/aasmcpu.pas

@@ -0,0 +1,490 @@
+{
+    Copyright (c) 1999-2008 by Mazen Neifer and Florian Klaempfl
+
+    Contains the assembler object 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 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;
+
+      instabentries = {$i z80nop.inc}
+      maxinfolen = 18;
+
+    type
+      { Operand types }
+      toperandtype=(
+        OT_NONE,
+        OT_IMM3,               { 3-bit immediate value (bit number: [0..7])                       }
+        OT_IMM8,               { 8-bit immediate value                                            }
+        OT_IMM16,              { 16-bit immediate value                                           }
+        OT_IMM_VAL0,           { the immediate value 0                                            }
+        OT_IMM_VAL1,           { the immediate value 1                                            }
+        OT_IMM_VAL2,           { the immediate value 2                                            }
+        OT_IMM_RST,            { immediate value in [$00,$08,$10,$18,$20,$28,$30,$38]             }
+        OT_IMM_PORT,           { 8-bit immediate port number for the IN and OUT instructions      }
+        OT_REG8,               { 8-bit register: A/B/C/D/E/H/L                                    }
+        OT_REG8_A,             { register A                                                       }
+        OT_REG8_I,             { register I                                                       }
+        OT_REG8_R,             { register R                                                       }
+        OT_REG8_C_PORT,        { implied parameter of the IN and OUT instructions                 }
+        OT_REG16_IX,           { register IX                                                      }
+        OT_REG16_IY,           { register IY                                                      }
+        OT_REG16_SP,           { register SP                                                      }
+        OT_REG16_BC_DE_HL_SP,  { 16-bit register pair: BC/DE/HL/SP                                }
+        OT_REG16_BC_DE_HL_AF,  { 16-bit register pair: BC/DE/HL/AF                                }
+        OT_REG16_BC_DE_IX_SP,  { 16-bit register pair: BC/DE/IX/SP                                }
+        OT_REG16_BC_DE_IY_SP,  { 16-bit register pair: BC/DE/IY/SP                                }
+        OT_REG16_DE,           { 16-bit register pair DE                                          }
+        OT_REG16_HL,           { 16-bit register pair HL                                          }
+        OT_REG16_AF,           { 16-bit register pair AF                                          }
+        OT_REG16_AF_,          { alternate register set, 16-bit register pair AF'                 }
+        OT_RELJMP8,            { 8-bit relative jump offset                                       }
+        OT_COND,               { condition: NZ/Z/NC/C/PO/PE/P/M                                   }
+        OT_COND_C,             { condition C                                                      }
+        OT_COND_NC,            { condition NC                                                     }
+        OT_COND_Z,             { condition Z                                                      }
+        OT_COND_NZ,            { condition NZ                                                     }
+        OT_REF_ADDR16,         { memory contents at address (nn = 16-bit immediate address)       }
+        OT_REF_BC,             { memory contents at address in register BC                        }
+        OT_REF_DE,             { memory contents at address in register DE                        }
+        OT_REF_HL,             { memory contents at address in register HL                        }
+        OT_REF_SP,             { memory contents at address in register SP                        }
+        OT_REF_IX,             { memory contents at address in register IX                        }
+        OT_REF_IY,             { memory contents at address in register IY                        }
+        OT_REF_IX_d,           { memory contents at address in register IX+d, d is in [-128..127] }
+        OT_REF_IY_d);          { memory contents at address in register IY+d, d is in [-128..127] }
+      timmoperandtype = OT_IMM3..OT_IMM_PORT;
+      tregoperandtype = OT_REG8..OT_REG16_AF_;
+      treg8operandtype = OT_REG8..OT_REG8_C_PORT;
+      treg16operandtype = OT_REG16_IX..OT_REG16_AF_;
+      tcondoperandtype = OT_COND..OT_COND_NZ;
+      trefoperandtype = OT_REF_ADDR16..OT_REF_IY_d;
+      trefoperandtypes = set of trefoperandtype;
+
+      tinsentry = record
+        opcode  : tasmop;
+        ops     : byte;
+        optypes : array[0..max_operands-1] of toperandtype;
+        code    : array[0..maxinfolen] of char;
+        flags   : longint;
+      end;
+
+      pinsentry=^tinsentry;
+
+      { taicpu }
+
+      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);
+         constructor op_ref_const(op:tasmop; _op1: treference; _op2: LongInt);
+
+         { 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;
+
+    function is_ref_addr16(const ref:treference): Boolean;
+    function is_ref_bc(const ref:treference): Boolean;
+    function is_ref_de(const ref:treference): Boolean;
+    function is_ref_hl(const ref:treference): Boolean;
+    function is_ref_sp(const ref:treference): Boolean;
+    function is_ref_ix(const ref:treference): Boolean;
+    function is_ref_iy(const ref:treference): Boolean;
+    function is_ref_ix_d(const ref:treference): Boolean;
+    function is_ref_iy_d(const ref:treference): Boolean;
+    function is_ref_opertype(const ref:treference;opertype:toperandtype): Boolean;
+    function is_ref_in_opertypes(const ref:treference;const refopertypes:trefoperandtypes): Boolean;
+
+implementation
+
+{****************************************************************************
+                                Instruction table
+*****************************************************************************}
+
+    const
+      InsTab:array[0..instabentries-1] of TInsEntry={$i z80tab.inc}
+
+{*****************************************************************************
+                                 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,_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_ref_const(op: tasmop; _op1: treference; _op2: LongInt);
+      begin
+        inherited create(op);
+        ops:=2;
+        loadref(0,_op1);
+        loadconst(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_CP,
+          A_DJNZ,
+          A_JR,
+          A_JP,
+          A_CALL,
+          A_RET,
+          A_RETI,
+          A_RETN,
+          A_RST,
+          A_IM:
+            ;
+          A_SET,
+          A_RES:
+            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
+        case getregtype(r) of
+          R_INTREGISTER :
+            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
+        case getregtype(r) of
+          R_INTREGISTER :
+            result:=taicpu.op_ref_reg(A_LD,ref,r);
+          else
+            internalerror(200401041);
+        end;
+      end;
+
+
+    function is_ref_addr16(const ref: treference): Boolean;
+      begin
+        result:=(ref.base=NR_NO) and (ref.index=NR_NO);
+      end;
+
+
+    function is_ref_bc(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_BC) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_BC))) and
+                (ref.offset=0) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_de(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_DE) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_DE))) and
+                (ref.offset=0) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_hl(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_HL) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_HL))) and
+                (ref.offset=0) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_sp(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_SP) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_SP))) and
+                (ref.offset=0) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_ix(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_IX) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_IX))) and
+                (ref.offset=0) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_iy(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_IY) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_IY))) and
+                (ref.offset=0) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_ix_d(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_IX) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_IX))) and
+                (ref.offset>=-128) and (ref.offset<=127) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_iy_d(const ref: treference): Boolean;
+      begin
+        result:=(((ref.base=NR_IY) and (ref.index=NR_NO)) or
+                 ((ref.base=NR_NO) and (ref.index=NR_IY))) and
+                (ref.offset>=-128) and (ref.offset<=127) and (ref.scalefactor<=1) and
+                (ref.symbol=nil) and (ref.relsymbol=nil);
+      end;
+
+
+    function is_ref_opertype(const ref: treference; opertype: toperandtype): Boolean;
+      begin
+        case opertype of
+          OT_REF_ADDR16:
+            result:=is_ref_addr16(ref);
+          OT_REF_BC:
+            result:=is_ref_bc(ref);
+          OT_REF_DE:
+            result:=is_ref_de(ref);
+          OT_REF_HL:
+            result:=is_ref_hl(ref);
+          OT_REF_SP:
+            result:=is_ref_sp(ref);
+          OT_REF_IX:
+            result:=is_ref_ix(ref);
+          OT_REF_IY:
+            result:=is_ref_iy(ref);
+          OT_REF_IX_d:
+            result:=is_ref_ix_d(ref);
+          OT_REF_IY_d:
+            result:=is_ref_iy_d(ref);
+          else
+            internalerror(2020041801);
+        end;
+      end;
+
+
+    function is_ref_in_opertypes(const ref: treference; const refopertypes: trefoperandtypes): Boolean;
+      var
+        ot: trefoperandtype;
+      begin
+        result:=true;
+        for ot:=low(trefoperandtypes) to high(trefoperandtypes) do
+          if (ot in refopertypes) and is_ref_opertype(ref,ot) then
+            exit;
+        result:=false;
+      end;
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+begin
+  cai_cpu:=taicpu;
+  cai_align:=tai_align;
+end.

+ 902 - 0
compiler/z80/agsdasz80.pas

@@ -0,0 +1,902 @@
+{
+    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 assembler writer for the sdcc-sdasz80 assembler:
+  http://sdcc.sourceforge.net/
+}
+
+unit agsdasz80;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,systems,
+       aasmbase,aasmtai,aasmdata,aasmcpu,
+       assemble,
+       cpubase;
+
+    type
+
+      { TSdccSdasZ80Assembler }
+
+      TSdccSdasZ80Assembler=class(TExternalAssembler)
+      private
+        procedure WriteDecodedSleb128(a: int64);
+        procedure WriteDecodedUleb128(a: qword);
+        procedure WriteRealConstAsBytes(hp: tai_realconst; const dbdir: string; do_line: boolean);
+        function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
+        procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder;secalign:longint;
+          secflags:TSectionFlags=[];secprogbits:TSectionProgbits=SPB_None);
+        procedure WriteInstruction(hp: taicpu);
+        procedure WriteOper(const o:toper; opcode: tasmop;ops:longint;dest : boolean);
+        procedure WriteOper_jmp(const o:toper; ai : taicpu);
+        procedure WriteExternals;
+      public
+        procedure WriteTree(p : TAsmList); override;
+        procedure WriteAsmList;override;
+        function MakeCmdLine: TCmdStr; override;
+      end;
+
+  implementation
+
+    uses
+       cutils,globals,verbose,
+       cpuinfo,
+       cgbase,cgutils,
+       finput;
+
+    const
+      line_length = 70;
+      max_tokens : longint = 25;
+      ait_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[20]=(
+        #9''#9,#9'FIXMEDQ'#9,#9'FIXMEDD'#9,#9'.dw'#9,#9'.db'#9,
+        #9'FIXMESLEB',#9'FIXEMEULEB',
+        #9'FIXMEDD RVA'#9,#9'FIXMEDD SECREL32'#9,
+        #9'FIXME',#9'FIXME',#9'FIXME',#9'FIXME',
+        #9'.dw'#9,#9'FIXMEDD'#9,#9'FIXMEDQ'#9
+      );
+
+    procedure TSdccSdasZ80Assembler.WriteDecodedSleb128(a: int64);
+      var
+        i,len : longint;
+        buf   : array[0..255] of byte;
+      begin
+        writer.AsmWrite(#9'.db'#9);
+        len:=EncodeSleb128(a,buf,0);
+        for i:=0 to len-1 do
+          begin
+            if (i > 0) then
+              writer.AsmWrite(',');
+            writer.AsmWrite(tostr(buf[i]));
+          end;
+        writer.AsmWriteLn(#9'; sleb '+tostr(a));
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteDecodedUleb128(a: qword);
+      var
+        i,len : longint;
+        buf   : array[0..63] of byte;
+      begin
+        writer.AsmWrite(#9'.db'#9);
+        len:=EncodeUleb128(a,buf,0);
+        for i:=0 to len-1 do
+          begin
+            if (i > 0) then
+              writer.AsmWrite(',');
+            writer.AsmWrite(tostr(buf[i]));
+          end;
+        writer.AsmWriteLn(#9'; uleb '+tostr(a));
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteRealConstAsBytes(hp: tai_realconst; const dbdir: string; do_line: boolean);
+      var
+        pdata: pbyte;
+        index, step, swapmask, count: longint;
+        ssingle: single;
+        ddouble: double;
+        ccomp: comp;
+{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+        eextended: extended;
+{$else}
+{$ifdef FPC_SOFT_FPUX80}
+	eextended: floatx80;
+{$endif}
+{$endif cpuextended}
+      begin
+        if do_line then
+          begin
+            case tai_realconst(hp).realtyp of
+              aitrealconst_s32bit:
+                writer.AsmWriteLn(asminfo^.comment+'value: '+single2str(tai_realconst(hp).value.s32val));
+              aitrealconst_s64bit:
+                writer.AsmWriteLn(asminfo^.comment+'value: '+double2str(tai_realconst(hp).value.s64val));
+{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+              { can't write full 80 bit floating point constants yet on non-x86 }
+              aitrealconst_s80bit:
+                writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s80val));
+{$else}
+{$ifdef FPC_SOFT_FPUX80}
+{$push}{$warn 6018 off} { Unreachable code due to compile time evaluation }
+             aitrealconst_s80bit:
+               begin
+     	         if sizeof(tai_realconst(hp).value.s80val) = sizeof(double) then
+                   writer.AsmWriteLn(asminfo^.comment+'value: '+double2str(tai_realconst(hp).value.s80val))
+     	         else if sizeof(tai_realconst(hp).value.s80val) = sizeof(single) then
+                   writer.AsmWriteLn(asminfo^.comment+'value: '+single2str(tai_realconst(hp).value.s80val))
+                else
+     	         internalerror(2017091901);
+       	      end;
+{$pop}
+{$endif}
+{$endif cpuextended}
+              aitrealconst_s64comp:
+                writer.AsmWriteLn(asminfo^.comment+'value: '+extended2str(tai_realconst(hp).value.s64compval));
+              else
+                internalerror(2014050604);
+            end;
+          end;
+        writer.AsmWrite(dbdir);
+        { generic float writing code: get start address of value, then write
+          byte by byte. Can't use fields directly, because e.g ts64comp is
+          defined as extended on x86 }
+        case tai_realconst(hp).realtyp of
+          aitrealconst_s32bit:
+            begin
+              ssingle:=single(tai_realconst(hp).value.s32val);
+              pdata:=@ssingle;
+            end;
+          aitrealconst_s64bit:
+            begin
+              ddouble:=double(tai_realconst(hp).value.s64val);
+              pdata:=@ddouble;
+            end;
+{$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
+          { can't write full 80 bit floating point constants yet on non-x86 }
+          aitrealconst_s80bit:
+            begin
+              eextended:=extended(tai_realconst(hp).value.s80val);
+              pdata:=@eextended;
+            end;
+{$else}
+{$ifdef FPC_SOFT_FPUX80}
+{$push}{$warn 6018 off} { Unreachable code due to compile time evaluation }
+          aitrealconst_s80bit:
+            begin
+	      if sizeof(tai_realconst(hp).value.s80val) = sizeof(double) then
+                eextended:=float64_to_floatx80(float64(double(tai_realconst(hp).value.s80val)))
+	      else if sizeof(tai_realconst(hp).value.s80val) = sizeof(single) then
+	        eextended:=float32_to_floatx80(float32(single(tai_realconst(hp).value.s80val)))
+	      else
+	        internalerror(2017091901);
+              pdata:=@eextended;
+            end;
+{$pop}
+{$endif}
+{$endif cpuextended}
+          aitrealconst_s64comp:
+            begin
+              ccomp:=comp(tai_realconst(hp).value.s64compval);
+              pdata:=@ccomp;
+            end;
+          else
+            internalerror(2014051001);
+        end;
+        count:=tai_realconst(hp).datasize;
+        { write bytes in inverse order if source and target endianess don't
+          match }
+        if source_info.endian<>target_info.endian then
+          begin
+            { go from back to front }
+            index:=count-1;
+            step:=-1;
+          end
+        else
+          begin
+            index:=0;
+            step:=1;
+          end;
+{$ifdef ARM}
+        { ARM-specific: low and high dwords of a double may be swapped }
+        if tai_realconst(hp).formatoptions=fo_hiloswapped then
+          begin
+            { only supported for double }
+            if tai_realconst(hp).datasize<>8 then
+              internalerror(2014050605);
+            { switch bit of the index so that the words are written in
+              the opposite order }
+            swapmask:=4;
+          end
+        else
+{$endif ARM}
+          swapmask:=0;
+        repeat
+          writer.AsmWrite(tostr(pdata[index xor swapmask]));
+          inc(index,step);
+          dec(count);
+          if count<>0 then
+            writer.AsmWrite(',');
+        until count=0;
+        { padding }
+        for count:=tai_realconst(hp).datasize+1 to tai_realconst(hp).savesize do
+          writer.AsmWrite(',0');
+        writer.AsmLn;
+      end;
+
+    function TSdccSdasZ80Assembler.sectionname(atype: TAsmSectiontype;
+        const aname: string; aorder: TAsmSectionOrder): string;
+      const
+        secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
+          '_CODE',
+          '_DATA',
+          '_DATA',
+          '.rodata',
+          '.bss',
+          '.threadvar',
+          '.pdata',
+          '', { stubs }
+          '__DATA,__nl_symbol_ptr',
+          '__DATA,__la_symbol_ptr',
+          '__DATA,__mod_init_func',
+          '__DATA,__mod_term_func',
+          '.stab',
+          '.stabstr',
+          '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
+          '.eh_frame',
+          '.debug_frame','.debug_info','.debug_line','.debug_abbrev','.debug_aranges','.debug_ranges',
+          '.fpc',
+          '.toc',
+          '.init',
+          '.fini',
+          '.objc_class',
+          '.objc_meta_class',
+          '.objc_cat_cls_meth',
+          '.objc_cat_inst_meth',
+          '.objc_protocol',
+          '.objc_string_object',
+          '.objc_cls_meth',
+          '.objc_inst_meth',
+          '.objc_cls_refs',
+          '.objc_message_refs',
+          '.objc_symbols',
+          '.objc_category',
+          '.objc_class_vars',
+          '.objc_instance_vars',
+          '.objc_module_info',
+          '.objc_class_names',
+          '.objc_meth_var_types',
+          '.objc_meth_var_names',
+          '.objc_selector_strs',
+          '.objc_protocol_ext',
+          '.objc_class_ext',
+          '.objc_property',
+          '.objc_image_info',
+          '.objc_cstring_object',
+          '.objc_sel_fixup',
+          '__DATA,__objc_data',
+          '__DATA,__objc_const',
+          '.objc_superrefs',
+          '__DATA, __datacoal_nt,coalesced',
+          '.objc_classlist',
+          '.objc_nlclasslist',
+          '.objc_catlist',
+          '.obcj_nlcatlist',
+          '.objc_protolist',
+          '.stack',
+          '.heap',
+          '.gcc_except_table',
+          '.ARM.attributes'
+        );
+      begin
+        result:=secnames[atype];
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteSection(atype: TAsmSectiontype;
+        const aname: string; aorder: TAsmSectionOrder; secalign: longint;
+        secflags: TSectionFlags; secprogbits: TSectionProgbits);
+      var
+        s : string;
+        secflag: TSectionFlag;
+        sectionprogbits,
+        sectionflags: boolean;
+      begin
+        writer.AsmLn;
+        sectionflags:=false;
+        sectionprogbits:=false;
+        writer.AsmWrite(#9'.area ');
+        { sectionname may rename those sections, so we do not write flags/progbits for them,
+          the assembler will ignore them/spite out a warning anyways }
+        if not(atype in [sec_data,sec_rodata,sec_rodata_norel]) then
+          begin
+            sectionflags:=true;
+            sectionprogbits:=true;
+          end;
+        s:=sectionname(atype,aname,aorder);
+        writer.AsmWrite(s);
+        writer.AsmLn;
+        LastSecType:=atype;
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteInstruction(hp: taicpu);
+      var
+        i: Integer;
+      begin
+        writer.AsmWrite(#9#9+std_op2str[hp.opcode]);
+        if (taicpu(hp).ops<>0) or (hp.condition<>C_None) then
+          begin
+            writer.AsmWrite(#9);
+            if hp.condition<>C_None then
+              begin
+                writer.AsmWrite(uppercond2str[hp.condition]);
+                if taicpu(hp).ops<>0 then
+                  writer.AsmWrite(',');
+              end;
+            for i:=0 to taicpu(hp).ops-1 do
+              begin
+                if i<>0 then
+                  writer.AsmWrite(',');
+                if is_calljmp(hp.opcode) then
+                  WriteOper_jmp(taicpu(hp).oper[i]^,hp)
+                else
+                  WriteOper(taicpu(hp).oper[i]^,hp.opcode,taicpu(hp).ops,(i=2));
+              end;
+          end;
+        writer.AsmLn;
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteOper(const o: toper; opcode: tasmop; ops: longint; dest: boolean);
+      var
+        need_plus: Boolean;
+      begin
+        case o.typ of
+          top_reg :
+            writer.AsmWrite(std_regname(o.reg));
+          top_const :
+            begin
+              writer.AsmWrite('#'+tostr(longint(o.val)));
+            end;
+          top_ref:
+            begin
+              if assigned(o.ref^.symbol) and (o.ref^.refaddr in [addr_lo8,addr_hi8,addr_full]) then
+                begin
+                  {if SmartAsm then
+                    AddSymbol(o.ref^.symbol.name,false);}
+                  if (o.ref^.base<>NR_NO) or (o.ref^.index<>NR_NO) then
+                    internalerror(2020041101);
+                  writer.AsmWrite('#');
+                  case o.ref^.refaddr of
+                    addr_lo8:
+                      writer.AsmWrite('<');
+                    addr_hi8:
+                      writer.AsmWrite('>');
+                    addr_full:
+                      {nothing};
+                    else
+                      ;
+                  end;
+                  if o.ref^.offset<>0 then
+                    writer.AsmWrite('('+ApplyAsmSymbolRestrictions(o.ref^.symbol.name)+'+'+tostr(o.ref^.offset)+')')
+                  else
+                    writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name));
+                end
+              else if not assigned(o.ref^.symbol) and
+                 ((o.ref^.base<>NR_NO) or (o.ref^.index<>NR_NO)) and
+                 (o.ref^.offset<>0) then
+                begin
+                  writer.AsmWrite(tostr(o.ref^.offset));
+                  writer.AsmWrite(' (');
+                  if o.ref^.base<>NR_NO then
+                    begin
+                      if o.ref^.index<>NR_NO then
+                        internalerror(2020040201);
+                      writer.AsmWrite(std_regname(o.ref^.base));
+                    end
+                  else if o.ref^.index<>NR_NO then
+                    begin
+                      if o.ref^.scalefactor>1 then
+                        internalerror(2020040202);
+                      writer.AsmWrite(std_regname(o.ref^.index));
+                    end;
+                  writer.AsmWrite(')');
+                end
+              else
+                begin
+                  writer.AsmWrite('(');
+                  need_plus:=false;
+                  if o.ref^.base<>NR_NO then
+                    begin
+                      if o.ref^.index<>NR_NO then
+                        internalerror(2020040201);
+                      writer.AsmWrite(std_regname(o.ref^.base));
+                      need_plus:=true;
+                    end
+                  else if o.ref^.index<>NR_NO then
+                    begin
+                      if o.ref^.scalefactor>1 then
+                        internalerror(2020040202);
+                      writer.AsmWrite(std_regname(o.ref^.index));
+                      need_plus:=true;
+                    end;
+                  if assigned(o.ref^.symbol) then
+                    begin
+                      {if SmartAsm then
+                        AddSymbol(o.ref^.symbol.name,false);}
+                      if need_plus then
+                        writer.AsmWrite('+');
+                      writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name));
+                      need_plus:=true;
+                    end;
+                  if o.ref^.offset<>0 then
+                    begin
+                      if need_plus and (o.ref^.offset>0) then
+                        writer.AsmWrite('+');
+                      writer.AsmWrite(tostr(o.ref^.offset));
+                      need_plus:=true;
+                    end;
+                  if not need_plus then
+                    writer.AsmWrite('0');
+                  writer.AsmWrite(')');
+                end;
+            end;
+          else
+            internalerror(10001);
+        end;
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteOper_jmp(const o: toper; ai: taicpu);
+      begin
+        case o.typ of
+          top_reg :
+            writer.AsmWrite(std_regname(o.reg));
+          top_const :
+            begin
+              writer.AsmWrite('#'+tostr(longint(o.val)));
+            end;
+          top_ref:
+            begin
+              if o.ref^.refaddr=addr_no then
+                begin
+                  writer.AsmWrite('TODO:indirect jump ref');
+                  //WriteReference(o.ref^);
+                end
+              else
+                begin
+                  writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name));
+                  //if SmartAsm then
+                  //  AddSymbol(o.ref^.symbol.name,false);
+                  if o.ref^.offset>0 then
+                   writer.AsmWrite('+'+tostr(o.ref^.offset))
+                  else
+                   if o.ref^.offset<0 then
+                    writer.AsmWrite(tostr(o.ref^.offset));
+                end;
+            end;
+          else
+            internalerror(10001);
+        end;
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteExternals;
+      var
+        sym : TAsmSymbol;
+        i   : longint;
+      begin
+        writer.AsmWriteln('; Begin externals');
+        for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do
+          begin
+            sym:=TAsmSymbol(current_asmdata.AsmSymbolDict[i]);
+            if sym.bind in [AB_EXTERNAL,AB_EXTERNAL_INDIRECT] then
+              writer.AsmWriteln(#9'.globl'#9+ApplyAsmSymbolRestrictions(sym.name));
+          end;
+        writer.AsmWriteln('; End externals');
+      end;
+
+    procedure TSdccSdasZ80Assembler.WriteTree(p: TAsmList);
+
+      procedure doalign(alignment: byte; use_op: boolean; fillop: byte; maxbytes: byte; out last_align: longint;lasthp:tai);
+        var
+          i: longint;
+          alignment64 : int64;
+        begin
+          last_align:=alignment;
+          if alignment>1 then
+            writer.AsmWriteLn(#9'.bndry '+tostr(alignment));
+        end;
+
+    var
+      lasthp,
+      hp: tai;
+      s, LastSecName: string;
+      counter,lines,i,j,l,tokens,pos,last_align: longint;
+      quoted, do_line: Boolean;
+      consttype: taiconst_type;
+      ch: Char;
+      InlineLevel : longint;
+      prevfileinfo : tfileposinfo;
+      previnfile : tinputfile;
+      LastAlign: Integer;
+      LastSecOrder: TAsmSectionOrder;
+    begin
+      if not assigned(p) then
+       exit;
+      InlineLevel:=0;
+      last_align:=1;
+      lasthp:=nil;
+      { lineinfo is only needed for al_procedures (PFV) }
+      do_line:=(cs_asm_source in current_settings.globalswitches) or
+               ((cs_lineinfo in current_settings.moduleswitches)
+                 and (p=current_asmdata.asmlists[al_procedures]));
+      hp:=tai(p.first);
+      while assigned(hp) do
+        begin
+          prefetch(pointer(hp.next)^);
+          if not(hp.typ in SkipLineInfo) then
+            begin
+              previnfile:=lastinfile;
+              prevfileinfo:=lastfileinfo;
+              current_filepos:=tailineinfo(hp).fileinfo;
+
+              { no line info for inlined code }
+              if do_line and (inlinelevel=0) then
+                WriteSourceLine(hp as tailineinfo);
+              (*if (lastfileinfo.line<>prevfileinfo.line) or
+                 (previnfile<>lastinfile) then
+                begin
+                  { +0 postfix means no line increment per assembler instruction }
+                  writer.AsmWrite('%LINE '+tostr(current_filepos.line)+'+0');
+                  if assigned(lastinfile) and ((previnfile<>lastinfile) or NewObject) then
+                    writer.AsmWriteLn(' '+lastinfile.name)
+                  else
+                    writer.AsmLn;
+                  NewObject:=false;
+                end;*)
+            end;
+          case hp.typ of
+            ait_comment :
+              begin
+                writer.AsmWrite(asminfo^.comment);
+                writer.AsmWritePChar(tai_comment(hp).str);
+                writer.AsmLn;
+              end;
+            ait_regalloc :
+              begin
+                if (cs_asm_regalloc in current_settings.globalswitches) then
+                  writer.AsmWriteLn(#9#9+asminfo^.comment+'Register '+std_regname(tai_regalloc(hp).reg)+' '+
+                    regallocstr[tai_regalloc(hp).ratype]);
+              end;
+            ait_tempalloc :
+              begin
+                if (cs_asm_tempalloc in current_settings.globalswitches) then
+                  WriteTempalloc(tai_tempalloc(hp));
+              end;
+            ait_section :
+              begin
+                if tai_section(hp).sectype<>sec_none then
+                  WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder,
+                    tai_section(hp).secalign,tai_section(hp).secflags,tai_section(hp).secprogbits)
+                else
+                  begin
+{$ifdef EXTDEBUG}
+                    writer.AsmWrite(asminfo^.comment);
+                    writer.AsmWriteln(' sec_none');
+{$endif EXTDEBUG}
+                 end;
+              end;
+            ait_align :
+              begin
+                doalign(tai_align_abstract(hp).aligntype,tai_align_abstract(hp).use_op,tai_align_abstract(hp).fillop,tai_align_abstract(hp).maxbytes,last_align,lasthp);
+              end;
+            ait_label :
+              begin
+                if tai_label(hp).labsym.is_used then
+                  begin
+                    writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name));
+                    if tai_label(hp).labsym.bind in [AB_GLOBAL,AB_PRIVATE_EXTERN] then
+                      writer.AsmWriteLn('::')
+                    else
+                      writer.AsmWriteLn(':');
+                  end;
+              end;
+            ait_symbol :
+              begin
+                if not(tai_symbol(hp).has_value) then
+                  begin
+                    if tai_symbol(hp).is_global then
+                      writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name) + '::')
+                    else
+                      writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name) + ':');
+                  end
+                else
+                  begin
+                    if tai_symbol(hp).is_global then
+                      writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name) + '==' + tostr(tai_symbol(hp).value))
+                    else
+                      writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name) + '=' + tostr(tai_symbol(hp).value));
+                  end;
+              end;
+            ait_symbol_end :
+              begin
+              end;
+            ait_datablock :
+              begin
+                if tai_datablock(hp).is_global or SmartAsm then
+                  writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name) + '::')
+                else
+                  writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name) + ':');
+                {if SmartAsm then
+                  AddSymbol(tai_datablock(hp).sym.name,true);}
+                writer.AsmWriteLn(#9'.rs'#9+tostr(tai_datablock(hp).size));
+              end;
+            ait_realconst:
+              WriteRealConstAsBytes(tai_realconst(hp),#9'.db'#9,do_line);
+            ait_const:
+              begin
+                consttype:=tai_const(hp).consttype;
+                case consttype of
+                  aitconst_uleb128bit:
+                    WriteDecodedUleb128(qword(tai_const(hp).value));
+                  aitconst_sleb128bit:
+                    WriteDecodedSleb128(int64(tai_const(hp).value));
+                  aitconst_64bit,
+                  aitconst_64bit_unaligned,
+                  aitconst_32bit,
+                  aitconst_32bit_unaligned:
+                    begin
+                      writer.AsmWrite(#9'.dw'#9);
+                      l:=0;
+ 		      tokens:=1;
+                      repeat
+                        if assigned(tai_const(hp).sym) then
+                          begin
+                            if assigned(tai_const(hp).endsym) then
+                              s:=ApplyAsmSymbolRestrictions(tai_const(hp).endsym.name)+'-'+ApplyAsmSymbolRestrictions(tai_const(hp).sym.name)
+                            else
+                              s:=ApplyAsmSymbolRestrictions(tai_const(hp).sym.name);
+                            if tai_const(hp).value<>0 then
+                              s:=s+tostr_with_plus(tai_const(hp).value);
+                            if consttype in [aitconst_64bit,aitconst_64bit_unaligned] then
+                              s:=s+',0,0,0'
+                            else
+                              s:=s+',0';
+                          end
+                        else
+                          if consttype in [aitconst_64bit,aitconst_64bit_unaligned] then
+                            s:=tostr(Word(tai_const(hp).value))       +','+tostr(Word(tai_const(hp).value shr 16))+','+
+                               tostr(Word(tai_const(hp).value shr 32))+','+tostr(Word(tai_const(hp).value shr 48))
+                          else
+                            s:=tostr(Word(tai_const(hp).value))+','+tostr(Word(tai_const(hp).value shr 16));
+                        writer.AsmWrite(s);
+                        inc(l,length(s));
+ 		        inc(tokens);
+                        if (l>line_length) or
+                           (tokens>max_tokens) or
+                           (hp.next=nil) or
+                           (tai(hp.next).typ<>ait_const) or
+                           (tai_const(hp.next).consttype<>consttype) then
+                          break;
+                        hp:=tai(hp.next);
+                        writer.AsmWrite(',');
+                      until false;
+                      { Substract section start for secrel32 type }
+                      {if consttype=aitconst_secrel32_symbol then
+                        writer.AsmWrite(' - $$');}
+                      writer.AsmLn;
+                    end;
+                  {aitconst_128bit,}
+                  aitconst_16bit,
+                  aitconst_8bit,
+                  aitconst_16bit_unaligned{,
+                  aitconst_rva_symbol,
+                  aitconst_secrel32_symbol} :
+                    begin
+                      writer.AsmWrite(ait_const2str[consttype]);
+                      l:=0;
+ 		      tokens:=1;
+                      repeat
+                        if assigned(tai_const(hp).sym) then
+                          begin
+                            if assigned(tai_const(hp).endsym) then
+                              s:=ApplyAsmSymbolRestrictions(tai_const(hp).endsym.name)+'-'+ApplyAsmSymbolRestrictions(tai_const(hp).sym.name)
+                            else
+                              s:=ApplyAsmSymbolRestrictions(tai_const(hp).sym.name);
+                            if tai_const(hp).value<>0 then
+                              s:=s+tostr_with_plus(tai_const(hp).value);
+                          end
+                        else
+                          s:=tostr(tai_const(hp).value);
+                        writer.AsmWrite(s);
+                        inc(l,length(s));
+ 		        inc(tokens);
+                        if (l>line_length) or
+                           (tokens>max_tokens) or
+                           (hp.next=nil) or
+                           (tai(hp.next).typ<>ait_const) or
+                           (tai_const(hp.next).consttype<>consttype) then
+                          break;
+                        hp:=tai(hp.next);
+                        writer.AsmWrite(',');
+                      until false;
+                      { Substract section start for secrel32 type }
+                      if consttype=aitconst_secrel32_symbol then
+                        writer.AsmWrite(' - $$');
+                      writer.AsmLn;
+                    end;
+                  else
+                    begin
+                      writer.AsmWrite(asminfo^.comment);
+                      writer.AsmWrite('WARNING: not yet implemented in assembler output: ');
+                      Str(consttype,s);
+                      writer.AsmWriteLn(s);
+                    end;
+                end;
+              end;
+            ait_string :
+              begin
+                pos:=0;
+                for i:=1 to tai_string(hp).len do
+                  begin
+                    if pos=0 then
+                      begin
+                        writer.AsmWrite(#9'.ascii'#9'"');
+                        pos:=20;
+                      end;
+                    ch:=tai_string(hp).str[i-1];
+                    case ch of
+                              #0, {This can't be done by range, because a bug in FPC}
+                         #1..#31,
+                      #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
+                             '"' : s:='\"';
+                             '\' : s:='\\';
+                    else
+                      s:=ch;
+                    end;
+                    writer.AsmWrite(s);
+                    inc(pos,length(s));
+                    if (pos>line_length) or (i=tai_string(hp).len) then
+                      begin
+                        writer.AsmWriteLn('"');
+                        pos:=0;
+                      end;
+                  end;
+              end;
+            ait_instruction :
+              begin
+                WriteInstruction(taicpu(hp));
+              end;
+            ait_directive :
+              begin
+                case tai_directive(hp).directive of
+                  asd_cpu :
+                    writer.AsmWriteLn('; CPU '+tai_directive(hp).name);
+                  else
+                    begin
+                      writer.AsmWrite(asminfo^.comment);
+                      writer.AsmWrite('WARNING: not yet implemented in assembler output: ait_directive.');
+                      Str(tai_directive(hp).directive,s);
+                      writer.AsmWriteLn(s);
+                    end;
+                end;
+              end;
+            ait_cutobject :
+              begin
+                if SmartAsm then
+                 begin
+                  { only reset buffer if nothing has changed }
+                  if not writer.ClearIfEmpty then
+                   begin
+                     {if SmartAsm then
+                       begin
+                         WriteSmartExternals;
+                         FreeExternChainList;
+                       end;
+                     WriteGroups;}
+                     writer.AsmClose;
+                     DoAssemble;
+                     writer.AsmCreate(tai_cutobject(hp).place);
+                     {ResetSectionsList;
+                     WriteHeader;}
+                   end;
+                { avoid empty files }
+                  LastSecType:=sec_none;
+                  LastSecName:='';
+                  LastSecOrder:=secorder_default;
+                  LastAlign:=1;
+                  while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
+                   begin
+                     if tai(hp.next).typ=ait_section then
+                       begin
+                         LastSecType:=tai_section(hp.next).sectype;
+                         LastSecName:=tai_section(hp.next).name^;
+                         LastSecOrder:=tai_section(hp.next).secorder;
+                         LastAlign:=tai_section(hp.next).secalign;
+                       end;
+                     hp:=tai(hp.next);
+                   end;
+                  if LastSecType<>sec_none then
+                    WriteSection(LastSecType,LastSecName,LastSecOrder,LastAlign);
+                  writer.MarkEmpty;
+                  //NewObject:=true;
+                end;
+              end;
+            ait_marker :
+              if tai_marker(hp).kind=mark_NoLineInfoStart then
+                inc(InlineLevel)
+              else if tai_marker(hp).kind=mark_NoLineInfoEnd then
+                dec(InlineLevel);
+            ait_stab,
+            ait_force_line,
+            ait_function_name : ;
+            else
+              begin
+                writer.AsmWrite(asminfo^.comment);
+                writer.AsmWrite('WARNING: not yet implemented in assembler output: ');
+                Str(hp.typ,s);
+                writer.AsmWriteLn(s);
+              end;
+          end;
+          lasthp:=hp;
+          hp:=tai(hp.next);
+        end;
+    end;
+
+
+    procedure TSdccSdasZ80Assembler.WriteAsmList;
+      var
+        hal: TAsmListType;
+      begin
+        WriteExternals;
+
+        for hal:=low(TasmlistType) to high(TasmlistType) do
+          begin
+            writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]);
+            writetree(current_asmdata.asmlists[hal]);
+            writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]);
+          end;
+      end;
+
+
+    function TSdccSdasZ80Assembler.MakeCmdLine: TCmdStr;
+      begin
+        result := {'-mmcu='+lower(cputypestr[current_settings.cputype])+' '+}inherited MakeCmdLine;
+      end;
+
+
+    const
+       as_sdcc_sdasZ80_asm_info : tasminfo =
+          (
+            id     : as_sdcc_sdasz80;
+
+            idtxt  : 'SDCC-SDASZ80';
+            asmbin : 'sdasz80';
+            asmcmd : '-g -o $EXTRAOPT $OBJ $ASM';
+            supported_targets : [system_Z80_embedded];
+            flags : [af_needar,af_smartlink_sections];
+            labelprefix : '.L';
+            labelmaxlen : 79;
+            comment : '; ';
+            dollarsign: '$';
+          );
+
+
+begin
+  RegisterAssembler(as_sdcc_sdasZ80_asm_info,TSdccSdasZ80Assembler);
+end.

+ 447 - 0
compiler/z80/agz80asm.pas

@@ -0,0 +1,447 @@
+{
+    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 assembler writer for the z80asm assembler:
+  http://savannah.nongnu.org/projects/z80asm
+}
+
+unit agz80asm;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,systems,
+       aasmtai,aasmdata,
+       assemble,
+       cpubase;
+
+    type
+
+      { TZ80AsmAssembler }
+
+      TZ80AsmAssembler=class(TExternalAssembler)
+      private
+        function EscapeLabel(s: ansistring): ansistring;
+      public
+        procedure WriteTree(p : TAsmList); override;
+        procedure WriteAsmList;override;
+        function MakeCmdLine: TCmdStr; override;
+      end;
+
+  implementation
+
+    uses
+       cutils,globals,verbose,
+       aasmbase,aasmcpu,
+       cpuinfo,
+       cgbase,cgutils;
+
+    const
+      line_length = 70;
+      max_tokens : longint = 25;
+      ait_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[20]=(
+        #9''#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9,
+        #9'FIXMESLEB',#9'FIXEMEULEB',
+        #9'DD RVA'#9,#9'DD SECREL32'#9,
+        #9'FIXME',#9'FIXME',#9'FIXME',#9'FIXME',
+        #9'DW'#9,#9'DD'#9,#9'DQ'#9
+      );
+
+    function TZ80AsmAssembler.EscapeLabel(s: ansistring): ansistring;
+      var
+        i: Integer;
+      begin
+        result:='';
+        for i:=1 to length(s) do
+          if ((s[i]>='a') and (s[i]<='z')) or
+             ((s[i]>='A') and (s[i]<='Z')) or
+             ((s[i]>='0') and (s[i]<='9')) or
+             (s[i]='.') then
+            result:=result+s[i]
+          else if s[i]='_' then
+            result:=result+'__'
+          else
+            result:=result+('_'+HexStr(Ord(s[i]),2));
+      end;
+
+    procedure TZ80AsmAssembler.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:=ApplyAsmSymbolRestrictions(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
+          result:='';
+          //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:=ApplyAsmSymbolRestrictions(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];
+    var
+      hp: tai;
+      s: string;
+      counter,lines,i,j,l,tokens: longint;
+      quoted: Boolean;
+      consttype: taiconst_type;
+    begin
+      if not assigned(p) then
+       exit;
+      hp:=tai(p.first);
+      while assigned(hp) do
+        begin
+          prefetch(pointer(hp.next)^);
+          case hp.typ of
+            ait_comment :
+              begin
+                writer.AsmWrite(asminfo^.comment);
+                writer.AsmWritePChar(tai_comment(hp).str);
+                writer.AsmLn;
+              end;
+            ait_align :
+              begin
+                if tai_align_abstract(hp).aligntype>1 then
+                  writer.AsmWriteLn(asminfo^.comment+'Unsupported ALIGN '+tostr(tai_align_abstract(hp).aligntype));
+              end;
+            ait_label :
+              begin
+                if tai_label(hp).labsym.is_used then
+                 begin
+                   writer.AsmWrite(EscapeLabel(tai_label(hp).labsym.name));
+                   writer.AsmWriteLn(':');
+                 end;
+              end;
+            ait_symbol :
+              begin
+                if tai_symbol(hp).has_value then
+                  internalerror(2009090802);
+                { wasm is case insensitive, we nned to use only uppercase version
+                  if both a lowercase and an uppercase version are provided }
+                {if (asminfo^.id = as_i386_wasm) then
+                  begin
+                    nhp:=tai(hp.next);
+                    while assigned(nhp) and (nhp.typ in [ait_function_name,ait_force_line]) do
+                      nhp:=tai(nhp.next);
+                    if assigned(nhp) and (tai(nhp).typ=ait_symbol) and
+                       (lower(tai_symbol(nhp).sym.name)=tai_symbol(hp).sym.name) then
+                      begin
+                        writer.AsmWriteln(asminfo^.comment+' '+tai_symbol(hp).sym.name+' removed');
+                        hp:=tai(nhp);
+                      end;
+                  end;}
+                {if tai_symbol(hp).is_global then
+                  writer.AsmWriteLn(#9'PUBLIC'#9+tai_symbol(hp).sym.name);}
+                writer.AsmWrite(EscapeLabel(tai_symbol(hp).sym.name));
+                {if assigned(hp.next) and not(tai(hp.next).typ in
+                   [ait_const,ait_realconst,ait_string]) then}
+                  writer.AsmWriteLn(':');
+              end;
+            ait_symbol_end :
+              begin
+              end;
+            ait_const:
+              begin
+                consttype:=tai_const(hp).consttype;
+                case consttype of
+                  {aitconst_uleb128bit,
+                  aitconst_sleb128bit,
+                  aitconst_128bit,
+                  aitconst_64bit,
+                  aitconst_32bit,}
+                  aitconst_16bit,
+                  aitconst_8bit,
+                  aitconst_16bit_unaligned{,
+                  aitconst_32bit_unaligned,
+                  aitconst_64bit_unaligned,
+                  aitconst_rva_symbol,
+                  aitconst_secrel32_symbol} :
+                    begin
+                      writer.AsmWrite(ait_const2str[consttype]);
+                      l:=0;
+ 		      tokens:=1;
+                      repeat
+                        if assigned(tai_const(hp).sym) then
+                          begin
+                            if assigned(tai_const(hp).endsym) then
+                              s:=EscapeLabel(tai_const(hp).endsym.name)+'-'+EscapeLabel(tai_const(hp).sym.name)
+                            else
+                              s:=EscapeLabel(tai_const(hp).sym.name);
+                            if tai_const(hp).value<>0 then
+                              s:=s+tostr_with_plus(tai_const(hp).value);
+                          end
+                        else
+                          s:=tostr(tai_const(hp).value);
+                        writer.AsmWrite(s);
+                        inc(l,length(s));
+ 		        inc(tokens);
+                        if (l>line_length) or
+                           (tokens>max_tokens) or
+                           (hp.next=nil) or
+                           (tai(hp.next).typ<>ait_const) or
+                           (tai_const(hp.next).consttype<>consttype) then
+                          break;
+                        hp:=tai(hp.next);
+                        writer.AsmWrite(',');
+                      until false;
+                      { Substract section start for secrel32 type }
+                      if consttype=aitconst_secrel32_symbol then
+                        writer.AsmWrite(' - $$');
+                      writer.AsmLn;
+                    end;
+                  else
+                    begin
+                      writer.AsmWrite(asminfo^.comment);
+                      writer.AsmWrite('WARNING: not yet implemented in assembler output: ');
+                      Str(consttype,s);
+                      writer.AsmWriteLn(s);
+                    end;
+                end;
+              end;
+            ait_string :
+              begin
+                counter := 0;
+                lines := tai_string(hp).len div line_length;
+                { separate lines in different parts }
+                if tai_string(hp).len > 0 then
+                 Begin
+                   for j := 0 to lines-1 do
+                    begin
+                      writer.AsmWrite(#9#9'DB'#9);
+                      quoted:=false;
+                      for i:=counter to counter+line_length-1 do
+                         begin
+                           { it is an ascii character. }
+                           if (ord(tai_string(hp).str[i])>31) and
+                              (ord(tai_string(hp).str[i])<127) and
+                              (tai_string(hp).str[i]<>'"') then
+                               begin
+                                 if not(quoted) then
+                                     begin
+                                       if i>counter then
+                                         writer.AsmWrite(',');
+                                       writer.AsmWrite('"');
+                                     end;
+                                 writer.AsmWrite(tai_string(hp).str[i]);
+                                 quoted:=true;
+                               end { if > 31 and < 127 and ord('"') }
+                           else
+                               begin
+                                   if quoted then
+                                       writer.AsmWrite('"');
+                                   if i>counter then
+                                       writer.AsmWrite(',');
+                                   quoted:=false;
+                                   writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
+                               end;
+                        end; { end for i:=0 to... }
+                      if quoted then writer.AsmWrite('"');
+                        writer.AsmWrite(target_info.newline);
+                      counter := counter+line_length;
+                   end; { end for j:=0 ... }
+                 { do last line of lines }
+                 if counter<tai_string(hp).len then
+                   writer.AsmWrite(#9#9'DB'#9);
+                 quoted:=false;
+                 for i:=counter to tai_string(hp).len-1 do
+                   begin
+                     { it is an ascii character. }
+                     if (ord(tai_string(hp).str[i])>31) and
+                        (ord(tai_string(hp).str[i])<128) and
+                        (tai_string(hp).str[i]<>'"') then
+                         begin
+                           if not(quoted) then
+                               begin
+                                 if i>counter then
+                                   writer.AsmWrite(',');
+                                 writer.AsmWrite('"');
+                               end;
+                           writer.AsmWrite(tai_string(hp).str[i]);
+                           quoted:=true;
+                         end { if > 31 and < 128 and " }
+                     else
+                         begin
+                           if quoted then
+                             writer.AsmWrite('"');
+                           if i>counter then
+                               writer.AsmWrite(',');
+                           quoted:=false;
+                           writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
+                         end;
+                   end; { end for i:=0 to... }
+                 if quoted then
+                   writer.AsmWrite('"');
+                 end;
+                writer.AsmLn;
+              end;
+            else
+              begin
+                writer.AsmWrite(asminfo^.comment);
+                writer.AsmWrite('WARNING: not yet implemented in assembler output: ');
+                Str(hp.typ,s);
+                writer.AsmWriteLn(s);
+              end;
+          end;
+          hp:=tai(hp.next);
+        end;
+      //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;
+
+
+    procedure TZ80AsmAssembler.WriteAsmList;
+      var
+        hal: TAsmListType;
+      begin
+        for hal:=low(TasmlistType) to high(TasmlistType) do
+          begin
+            writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]);
+            writetree(current_asmdata.asmlists[hal]);
+            writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]);
+          end;
+      end;
+
+
+    function TZ80AsmAssembler.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';
+            labelmaxlen : -1;
+            comment : '; ';
+            dollarsign: 's';
+          );
+
+
+begin
+  RegisterAssembler(as_Z80_asm_info,TZ80AsmAssembler);
+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.

+ 2486 - 0
compiler/z80/cgcpu.pas

@@ -0,0 +1,2486 @@
+{
+
+    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
+      tregisterlist = array of tregister;
+
+      { tcgz80 }
+
+      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;
+
+        procedure getcpuregisters(list:TAsmList;regs:tregisterlist);
+        procedure ungetcpuregisters(list:TAsmList;regs:tregisterlist);
+
+        function getaddressregister(list:TAsmList):TRegister;override;
+
+        function GetOffsetReg(const r: TRegister;ofs : shortint): TRegister;override;
+        function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): 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 cgpara : 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_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;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_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);override;
+        procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
+        procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
+        procedure a_load_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;
+
+        { Z80-specific unsigned comparison code generation jmp helper }
+        procedure a_jmp_unsigned_cmp_3way(list : TAsmList;onbelow,onequal,onabove: tasmlabel);
+        { Z80-specific signed comparison code generation jmp helper. Should follow a SUB instruction,
+          and the A register must still contain the result. }
+        procedure a_jmp_signed_cmp_3way(list : TAsmList;onless,onequal,ongreater: tasmlabel);
+
+        procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
+
+        procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);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_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);
+        function normalize_ref(list : TAsmList;ref : treference; const refopertypes:trefoperandtypes; out allocatedregs:tregisterlist) : treference;
+        procedure adjust_normalized_ref(list: TAsmList;var ref: treference; value: longint);
+
+        procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
+
+        procedure a_adjust_sp(list: TAsmList; value: longint);
+
+      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 gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean);
+      end;
+
+      tcg64fz80 = 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;
+
+
+    function use_push(const cgpara:tcgpara):boolean;
+      begin
+        result:=(not paramanager.use_fixed_stack) and
+                assigned(cgpara.location) and
+                (cgpara.location^.loc=LOC_REFERENCE) and
+                (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
+      end;
+
+
+    procedure tcgz80.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+        rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
+            [RS_A,RS_B,RS_C,RS_D,RS_E,RS_H,RS_L],first_int_imreg,[]);
+      end;
+
+
+    procedure tcgz80.done_register_allocators;
+      begin
+        rg[R_INTREGISTER].free;
+        inherited done_register_allocators;
+      end;
+
+
+    procedure tcgz80.getcpuregisters(list: TAsmList; regs: tregisterlist);
+      var
+        r: tregister;
+      begin
+        for r in regs do
+          getcpuregister(list,r);
+      end;
+
+    procedure tcgz80.ungetcpuregisters(list: TAsmList; regs: tregisterlist);
+      var
+        r: tregister;
+      begin
+        for r in regs do
+          ungetcpuregister(list,r);
+      end;
+
+
+    function tcgz80.getaddressregister(list: TAsmList): TRegister;
+      begin
+       Result:=getintregister(list,OS_ADDR);
+      end;
+
+
+    function tcgz80.GetOffsetReg(const r: TRegister; ofs: shortint): TRegister;
+      var
+        i: Integer;
+      begin
+        result:=r;
+        for i:=1 to ofs do
+          result:=GetNextReg(result);
+      end;
+
+
+    function tcgz80.GetOffsetReg64(const r, rhi: TRegister; ofs: shortint): TRegister;
+      var
+        i: Integer;
+      begin
+        if ofs>=4 then
+          begin
+            result:=rhi;
+            dec(ofs,4);
+          end
+        else
+          result:=r;
+        for i:=1 to ofs do
+          result:=GetNextReg(result);
+      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,ctempposinvalid,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
+            case tcgsize2size[cgpara.Size] of
+              1:
+                begin
+                  cgpara.check_simple_location;
+                  getcpuregister(list,NR_A);
+                  a_load_reg_reg(list,OS_8,OS_8,r,NR_A);
+                  list.concat(taicpu.op_reg(A_PUSH,NR_AF));
+                  list.concat(taicpu.op_reg(A_INC,NR_SP));
+                  ungetcpuregister(list,NR_A);
+                end;
+              2:
+                begin
+                  cgpara.check_simple_location;
+                  getcpuregister(list,NR_L);
+                  a_load_reg_reg(list,OS_8,OS_8,r,NR_L);
+                  getcpuregister(list,NR_H);
+                  a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H);
+                  list.concat(taicpu.op_reg(A_PUSH,NR_HL));
+                  getcpuregister(list,NR_H);
+                  getcpuregister(list,NR_L);
+                end;
+              4:
+                begin
+                  cgpara.check_simple_location;
+
+                  getcpuregister(list,NR_L);
+                  a_load_reg_reg(list,OS_8,OS_8,GetNextReg(GetNextReg(r)),NR_L);
+                  getcpuregister(list,NR_H);
+                  a_load_reg_reg(list,OS_8,OS_8,GetNextReg(GetNextReg(GetNextReg(r))),NR_H);
+                  list.concat(taicpu.op_reg(A_PUSH,NR_HL));
+                  getcpuregister(list,NR_H);
+                  getcpuregister(list,NR_L);
+
+                  getcpuregister(list,NR_L);
+                  a_load_reg_reg(list,OS_8,OS_8,r,NR_L);
+                  getcpuregister(list,NR_H);
+                  a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H);
+                  list.concat(taicpu.op_reg(A_PUSH,NR_HL));
+                  getcpuregister(list,NR_H);
+                  getcpuregister(list,NR_L);
+                end;
+              else
+                internalerror(2020040801);
+            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_loadfpu_ref_cgpara(list: TAsmList; size: tcgsize; const ref: treference; const cgpara: TCGPara);
+      var
+        href: treference;
+        curloc: PCGParaLocation;
+        i: Integer;
+      begin
+        case cgpara.location^.loc of
+          LOC_REGISTER,LOC_CREGISTER:
+            begin
+              case size of
+                OS_F32:
+                  begin
+                    curloc:=cgpara.location;
+                    href:=ref;
+                    for i:=1 to 4 do
+                      begin
+                        if not assigned(curloc) then
+                          internalerror(2020042303);
+                        if not (curloc^.Loc in [LOC_REGISTER,LOC_CREGISTER]) then
+                          internalerror(2020042304);
+                        a_load_ref_reg(list,OS_8,OS_8,href,curloc^.register);
+                        curloc:=curloc^.Next;
+                      end;
+                    if assigned(curloc) then
+                      internalerror(2020042305);
+                  end;
+                else
+                  internalerror(2020042302);
+              end;
+            end;
+          else
+            inherited;
+        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);
+
+        if use_push(paraloc) then
+          begin
+            case tcgsize2size[paraloc.Size] of
+               1:
+                 begin
+                   getcpuregister(list,NR_A);
+                   a_load_const_reg(list,OS_8,a,NR_A);
+                   list.Concat(taicpu.op_reg(A_PUSH,NR_AF));
+                   list.Concat(taicpu.op_reg(A_INC,NR_SP));
+                   ungetcpuregister(list,NR_A);
+                 end;
+               2:
+                 begin
+                   getcpuregister(list,NR_IY);
+                   list.Concat(taicpu.op_reg_const(A_LD,NR_IY,a));
+                   list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
+                   ungetcpuregister(list,NR_IY);
+                 end;
+               4:
+                 begin
+                   getcpuregister(list,NR_IY);
+                   list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a shr 16)));
+                   list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
+                   if Word(a)<>Word(a shr 16) then
+                     list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a)));
+                   list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
+                   ungetcpuregister(list,NR_IY);
+                 end;
+               else
+                 internalerror(2020040701);
+            end;
+          end
+        else
+          begin
+            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;
+      end;
+
+
+    procedure tcgz80.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);
+
+        procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
+        var
+          pushsize : tcgsize;
+          opsize : topsize;
+          tmpreg   : tregister;
+          href,tmpref: treference;
+        begin
+          if not assigned(paraloc) then
+            exit;
+          if (paraloc^.loc<>LOC_REFERENCE) or
+             (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
+             (tcgsize2size[paraloc^.size]>4) then
+            internalerror(200501162);
+          { Pushes are needed in reverse order, add the size of the
+            current location to the offset where to load from. This
+            prevents wrong calculations for the last location when
+            the size is not a power of 2 }
+          if assigned(paraloc^.next) then
+            pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
+          { Push the data starting at ofs }
+          href:=r;
+          inc(href.offset,ofs);
+          {if tcgsize2size[paraloc^.size]>cgpara.alignment then}
+            pushsize:=paraloc^.size
+          {else
+            pushsize:=int_cgsize(cgpara.alignment)};
+          {Writeln(pushsize);}
+          case tcgsize2size[pushsize] of
+            1:
+              begin
+                tmpreg:=getintregister(list,OS_8);
+                a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
+                getcpuregister(list,NR_A);
+                a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
+                list.concat(taicpu.op_reg(A_PUSH,NR_AF));
+                list.concat(taicpu.op_reg(A_INC,NR_SP));
+                ungetcpuregister(list,NR_A);
+              end;
+            2:
+              begin
+                tmpreg:=getintregister(list,OS_16);
+                a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
+                getcpuregister(list,NR_L);
+                a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
+                getcpuregister(list,NR_H);
+                a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
+                list.concat(taicpu.op_reg(A_PUSH,NR_HL));
+                ungetcpuregister(list,NR_H);
+                ungetcpuregister(list,NR_L);
+              end;
+            4:
+              begin
+                tmpreg:=getintregister(list,OS_16);
+                inc(href.offset,2);
+                a_load_ref_reg(list,OS_16,OS_16,href,tmpreg);
+                getcpuregister(list,NR_L);
+                a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
+                getcpuregister(list,NR_H);
+                a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
+                list.concat(taicpu.op_reg(A_PUSH,NR_HL));
+                ungetcpuregister(list,NR_H);
+                ungetcpuregister(list,NR_L);
+                dec(href.offset,2);
+                a_load_ref_reg(list,OS_16,OS_16,href,tmpreg);
+                getcpuregister(list,NR_L);
+                a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
+                getcpuregister(list,NR_H);
+                a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
+                list.concat(taicpu.op_reg(A_PUSH,NR_HL));
+                ungetcpuregister(list,NR_H);
+                ungetcpuregister(list,NR_L);
+              end;
+            else
+              internalerror(2020040803);
+          end;
+        end;
+
+      var
+        tmpref, ref, href: treference;
+        location: pcgparalocation;
+        sizeleft: tcgint;
+        len: tcgint;
+      begin
+        { cgpara.size=OS_NO requires a copy on the stack }
+        if use_push(cgpara) then
+          begin
+            { Record copy? }
+            if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
+              begin
+                cgpara.check_simple_location;
+                len:=align(cgpara.intsize,cgpara.alignment);
+                g_stackpointer_alloc(list,len);
+                reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]);
+                g_concatcopy(list,r,href,len);
+              end
+            else
+              begin
+                if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
+                  internalerror(200501161);
+                { We need to push the data in reverse order,
+                  therefor we use a recursive algorithm }
+                pushdata(cgpara.location,0);
+              end
+          end
+        else
+          begin
+            location := cgpara.location;
+            tmpref := r;
+            sizeleft := cgpara.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,ctempposinvalid,cgpara.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;
+      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
+        { HACK: at this point all registers are allocated, due to the way the
+          calling convention works, but we need to free some registers, in order
+          for the following code to work, so we do it here }
+        dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+
+        getcpuregister(list,NR_L);
+        a_load_reg_reg(list,OS_8,OS_8,reg,NR_L);
+        getcpuregister(list,NR_H);
+        a_load_reg_reg(list,OS_8,OS_8,GetNextReg(reg),NR_H);
+        current_asmdata.getjumplabel(l);
+        reference_reset(ref,0,[]);
+        ref.symbol:=l;
+        list.concat(taicpu.op_ref_reg(A_LD,ref,NR_HL));
+        ungetcpuregister(list,NR_H);
+        ungetcpuregister(list,NR_L);
+
+        { allocate them again, right before the actual call instruction }
+        alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+
+        list.concat(tai_const.Create_8bit($CD));  { $CD is the opcode of the call instruction }
+        list.concat(tai_label.Create(l));
+        list.concat(tai_const.Create_16bit(0));
+        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
+         i : integer;
+
+       procedure NextSrcDst;
+         begin
+           if i=5 then
+             begin
+               dst:=dsthi;
+               src:=srchi;
+             end
+           else
+             begin
+               dst:=GetNextReg(dst);
+               src:=GetNextReg(src);
+             end;
+         end;
+
+       var
+         tmpreg,tmpreg2: tregister;
+         instr : taicpu;
+         l1,l2 : tasmlabel;
+
+      begin
+         case op of
+           OP_ADD:
+             begin
+               getcpuregister(list,NR_A);
+               a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
+               list.concat(taicpu.op_reg_reg(A_ADD,NR_A,src));
+               a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+               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;
+                       a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
+                       list.concat(taicpu.op_reg_reg(A_ADC,NR_A,src));
+                       a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+                     end;
+                 end;
+               ungetcpuregister(list,NR_A);
+             end;
+
+           OP_SUB:
+             begin
+               getcpuregister(list,NR_A);
+               a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
+               list.concat(taicpu.op_reg_reg(A_SUB,NR_A,src));
+               a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+               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;
+                       a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
+                       list.concat(taicpu.op_reg_reg(A_SBC,NR_A,src));
+                       a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+                     end;
+                 end;
+               ungetcpuregister(list,NR_A);
+             end;
+
+           OP_NEG:
+             begin
+               getcpuregister(list,NR_A);
+               if tcgsize2size[size]>=2 then
+                 begin
+                   tmpreg:=GetNextReg(src);
+                   tmpreg2:=GetNextReg(dst);
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
+                       list.concat(taicpu.op_none(A_CPL));
+                       a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
+                       if i<>tcgsize2size[size] then
+                         begin
+                           if i=4 then
+                             begin
+                               tmpreg:=srchi;
+                               tmpreg2:=dsthi;
+                             end
+                           else
+                             begin
+                               tmpreg:=GetNextReg(tmpreg);
+                               tmpreg2:=GetNextReg(tmpreg2);
+                             end;
+                         end;
+                     end;
+                 end;
+               a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
+               list.concat(taicpu.op_none(A_NEG));
+               a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+               if tcgsize2size[size]>=2 then
+                 begin
+                   tmpreg2:=GetNextReg(dst);
+                   for i:=2 to tcgsize2size[size] do
+                     begin
+                       a_load_reg_reg(list,OS_8,OS_8,tmpreg2,NR_A);
+                       list.concat(taicpu.op_reg_const(A_SBC,NR_A,-1));
+                       a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
+                       if i<>tcgsize2size[size] then
+                         begin
+                           if i=4 then
+                             begin
+                               tmpreg2:=dsthi;
+                             end
+                           else
+                             begin
+                               tmpreg2:=GetNextReg(tmpreg2);
+                             end;
+                         end;
+                     end;
+                 end;
+               ungetcpuregister(list,NR_A);
+             end;
+
+           OP_NOT:
+             begin
+               getcpuregister(list,NR_A);
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   if i<>1 then
+                     NextSrcDst;
+                   a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
+                   list.concat(taicpu.op_none(A_CPL));
+                   a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+                 end;
+               ungetcpuregister(list,NR_A);
+             end;
+
+           OP_MUL,OP_IMUL:
+             begin
+               tmpreg:=dst;
+               if size in [OS_16,OS_S16] then
+                 begin
+                   tmpreg:=getintregister(list,size);
+                   a_load_reg_reg(list,size,size,dst,tmpreg);
+                 end;
+               gen_multiply(list,op,size,src,tmpreg,dst,false);
+             end;
+
+           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);
+               getcpuregister(list,NR_B);
+               emit_mov(list,NR_B,src);
+               list.concat(taicpu.op_reg(A_INC,NR_B));
+               list.concat(taicpu.op_reg(A_DEC,NR_B));
+               a_jmp_flags(list,F_E,l2);
+               if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                 case op of
+                   OP_ROL:
+                     begin
+                       list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+                       list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+                     end;
+                   OP_ROR:
+                     begin
+                       list.concat(taicpu.op_reg(A_RLC,dst));
+                       list.concat(taicpu.op_reg(A_RRC,dst));
+                     end;
+                   else
+                     ;
+                 end;
+               cg.a_label(list,l1);
+               case op of
+                 OP_SHL:
+                   list.concat(taicpu.op_reg(A_SLA,dst));
+                 OP_SHR:
+                   list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+                 OP_SAR:
+                   list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+                 OP_ROL:
+                   if size in [OS_8,OS_S8] then
+                     list.concat(taicpu.op_reg(A_RLC,dst))
+                   else
+                     list.concat(taicpu.op_reg(A_RL,dst));
+                 OP_ROR:
+                   if size in [OS_8,OS_S8] then
+                     list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)))
+                   else
+                     list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
+                 else
+                   internalerror(2020040903);
+               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,
+                         OP_SAR:
+                           list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
+                         OP_ROL,
+                         OP_SHL:
+                           list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(dst,dsthi,i-1)));
+                         else
+                           internalerror(2020040904);
+                       end;
+                   end;
+                 end;
+               instr:=taicpu.op_sym(A_DJNZ,l1);
+               instr.is_jmp:=true;
+               list.concat(instr);
+               ungetcpuregister(list,NR_B);
+               cg.a_label(list,l2);
+             end;
+
+           OP_AND,OP_OR,OP_XOR:
+             begin
+               getcpuregister(list,NR_A);
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   if i<>1 then
+                     NextSrcDst;
+                   a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
+                   list.concat(taicpu.op_reg_reg(topcg2asmop[op],NR_A,src));
+                   a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
+                 end;
+               ungetcpuregister(list,NR_A);
+             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
+         i : byte;
+
+      procedure NextReg;
+        begin
+          if i=4 then
+            reg:=reghi
+          else
+            reg:=GetNextReg(reg);
+        end;
+
+      var
+        mask : qword;
+        shift : byte;
+        curvalue : byte;
+        tmpop: TAsmOp;
+        l1: TAsmLabel;
+        instr: taicpu;
+        tmpreg : tregister;
+        tmpreg64 : tregister64;
+
+       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_AND:
+             begin
+               curvalue:=a and mask;
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   case curvalue of
+                     0:
+                       list.concat(taicpu.op_reg_const(A_LD,reg,0));
+                     $ff:
+                       {nothing};
+                     else
+                       begin
+                         getcpuregister(list,NR_A);
+                         emit_mov(list,NR_A,reg);
+                         list.concat(taicpu.op_reg_const(A_AND,NR_A,curvalue));
+                         emit_mov(list,reg,NR_A);
+                         ungetcpuregister(list,NR_A);
+                       end;
+                   end;
+                   if i<>tcgsize2size[size] then
+                     begin
+                       NextReg;
+                       mask:=mask shl 8;
+                       inc(shift,8);
+                       curvalue:=(qword(a) and mask) shr shift;
+                     end;
+                 end;
+             end;
+           OP_OR:
+             begin
+               curvalue:=a and mask;
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   case curvalue of
+                     0:
+                       {nothing};
+                     $ff:
+                       list.concat(taicpu.op_reg_const(A_LD,reg,$ff));
+                     else
+                       begin
+                         getcpuregister(list,NR_A);
+                         emit_mov(list,NR_A,reg);
+                         list.concat(taicpu.op_reg_const(A_OR,NR_A,curvalue));
+                         emit_mov(list,reg,NR_A);
+                         ungetcpuregister(list,NR_A);
+                       end;
+                   end;
+                   if i<>tcgsize2size[size] then
+                     begin
+                       NextReg;
+                       mask:=mask shl 8;
+                       inc(shift,8);
+                       curvalue:=(qword(a) and mask) shr shift;
+                     end;
+                 end;
+             end;
+           OP_XOR:
+             begin
+               curvalue:=a and mask;
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   case curvalue of
+                     0:
+                       {nothing};
+                     $ff:
+                       begin
+                         getcpuregister(list,NR_A);
+                         emit_mov(list,NR_A,reg);
+                         list.concat(taicpu.op_none(A_CPL));
+                         emit_mov(list,reg,NR_A);
+                         ungetcpuregister(list,NR_A);
+                       end;
+                     else
+                       begin
+                         getcpuregister(list,NR_A);
+                         emit_mov(list,NR_A,reg);
+                         list.concat(taicpu.op_reg_const(A_XOR,NR_A,curvalue));
+                         emit_mov(list,reg,NR_A);
+                         ungetcpuregister(list,NR_A);
+                       end;
+                   end;
+                   if i<>tcgsize2size[size] then
+                     begin
+                       NextReg;
+                       mask:=mask shl 8;
+                       inc(shift,8);
+                       curvalue:=(qword(a) and mask) shr shift;
+                     end;
+                 end;
+             end;
+           OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
+             begin
+               if size in [OS_64,OS_S64] then
+                 a:=a and 63
+               else
+                 a:=a and 31;
+               if a<>0 then
+                 begin
+                   if a>1 then
+                     begin
+                       current_asmdata.getjumplabel(l1);
+                       getcpuregister(list,NR_B);
+                       list.concat(taicpu.op_reg_const(A_LD,NR_B,a));
+                     end;
+                   if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
+                     case op of
+                       OP_ROL:
+                         begin
+                           list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+                           list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+                         end;
+                       OP_ROR:
+                         begin
+                           list.concat(taicpu.op_reg(A_RLC,reg));
+                           list.concat(taicpu.op_reg(A_RRC,reg));
+                         end;
+                       else
+                         ;
+                     end;
+                   if a>1 then
+                     cg.a_label(list,l1);
+                   case op of
+                     OP_SHL:
+                       list.concat(taicpu.op_reg(A_SLA,reg));
+                     OP_SHR:
+                       list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+                     OP_SAR:
+                       list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+                     OP_ROL:
+                       if size in [OS_8,OS_S8] then
+                         list.concat(taicpu.op_reg(A_RLC,reg))
+                       else
+                         list.concat(taicpu.op_reg(A_RL,reg));
+                     OP_ROR:
+                       if size in [OS_8,OS_S8] then
+                         list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)))
+                       else
+                         list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
+                     else
+                       internalerror(2020040903);
+                   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,
+                             OP_SAR:
+                               list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
+                             OP_ROL,
+                             OP_SHL:
+                               list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(reg,reghi,i-1)));
+                             else
+                               internalerror(2020040904);
+                           end;
+                       end;
+                     end;
+                   if a>1 then
+                     begin
+                       instr:=taicpu.op_sym(A_DJNZ,l1);
+                       instr.is_jmp:=true;
+                       list.concat(instr);
+                       ungetcpuregister(list,NR_B);
+                     end;
+                 end;
+             end;
+           OP_ADD:
+             begin
+               curvalue:=a and mask;
+               tmpop:=A_NONE;
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
+                     tmpop:=A_INC
+                   else if (tmpop=A_NONE) and (curvalue=255) and (i=tcgsize2size[size]) then
+                     tmpop:=A_DEC
+                   else if (tmpop=A_NONE) and (curvalue<>0) then
+                     tmpop:=A_ADD
+                   else if tmpop=A_ADD then
+                     tmpop:=A_ADC;
+                   case tmpop of
+                     A_NONE:
+                       {nothing};
+                     A_INC,A_DEC:
+                       list.concat(taicpu.op_reg(tmpop,reg));
+                     A_ADD,A_ADC:
+                       begin
+                         getcpuregister(list,NR_A);
+                         emit_mov(list,NR_A,reg);
+                         list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
+                         emit_mov(list,reg,NR_A);
+                         ungetcpuregister(list,NR_A);
+                       end;
+                     else
+                       internalerror(2020040901);
+                   end;
+                   if i<>tcgsize2size[size] then
+                     begin
+                       NextReg;
+                       mask:=mask shl 8;
+                       inc(shift,8);
+                       curvalue:=(qword(a) and mask) shr shift;
+                     end;
+                 end;
+             end;
+           OP_SUB:
+             begin
+               curvalue:=a and mask;
+               tmpop:=A_NONE;
+               for i:=1 to tcgsize2size[size] do
+                 begin
+                   if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
+                     tmpop:=A_DEC
+                   else if (tmpop=A_NONE) and (curvalue=255) and (i=tcgsize2size[size]) then
+                     tmpop:=A_INC
+                   else if (tmpop=A_NONE) and (curvalue<>0) then
+                     tmpop:=A_SUB
+                   else if tmpop=A_SUB then
+                     tmpop:=A_SBC;
+                   case tmpop of
+                     A_NONE:
+                       {nothing};
+                     A_DEC,A_INC:
+                       list.concat(taicpu.op_reg(tmpop,reg));
+                     A_SUB,A_SBC:
+                       begin
+                         getcpuregister(list,NR_A);
+                         emit_mov(list,NR_A,reg);
+                         list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
+                         emit_mov(list,reg,NR_A);
+                         ungetcpuregister(list,NR_A);
+                       end;
+                     else
+                       internalerror(2020040902);
+                   end;
+                   if i<>tcgsize2size[size] then
+                     begin
+                       NextReg;
+                       mask:=mask shl 8;
+                       inc(shift,8);
+                       curvalue:=(qword(a) and mask) shr shift;
+                     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.gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean);
+       var
+         pd: tprocdef;
+         paraloc1, paraloc2: tcgpara;
+         ai: taicpu;
+         hl, no_overflow: TAsmLabel;
+         name: String;
+       begin
+         if size in [OS_8,OS_S8] then
+           begin
+             if size=OS_8 then
+               name:='fpc_mul_byte'
+             else
+               name:='fpc_mul_shortint';
+
+             if check_overflow then
+               name:=name+'_checkoverflow';
+
+             pd:=search_system_proc(name);
+             paraloc1.init;
+             paraloc2.init;
+             paramanager.getcgtempparaloc(list,pd,1,paraloc1);
+             paramanager.getcgtempparaloc(list,pd,2,paraloc2);
+             a_load_reg_cgpara(list,OS_8,src1,paraloc2);
+             a_load_reg_cgpara(list,OS_8,src2,paraloc1);
+             paramanager.freecgpara(list,paraloc2);
+             paramanager.freecgpara(list,paraloc1);
+             alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+             a_call_name(list,upper(name),false);
+             dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+             cg.a_reg_alloc(list,NR_L);
+             cg.a_load_reg_reg(list,OS_8,OS_8,NR_L,dst);
+             cg.a_reg_dealloc(list,NR_L);
+             paraloc2.done;
+             paraloc1.done;
+           end
+         else if size in [OS_16,OS_S16] then
+           begin
+             if size=OS_16 then
+               name:='fpc_mul_word'
+             else
+               name:='fpc_mul_integer';
+
+             if check_overflow then
+               name:=name+'_checkoverflow';
+
+             pd:=search_system_proc(name);
+             paraloc1.init;
+             paraloc2.init;
+             paramanager.getcgtempparaloc(list,pd,1,paraloc1);
+             paramanager.getcgtempparaloc(list,pd,2,paraloc2);
+             a_load_reg_cgpara(list,OS_16,src1,paraloc2);
+             a_load_reg_cgpara(list,OS_16,src2,paraloc1);
+             paramanager.freecgpara(list,paraloc2);
+             paramanager.freecgpara(list,paraloc1);
+             alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+             a_call_name(list,upper(name),false);
+             dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
+             cg.a_reg_alloc(list,NR_L);
+             cg.a_reg_alloc(list,NR_H);
+             cg.a_load_reg_reg(list,OS_8,OS_8,NR_L,dst);
+             cg.a_reg_dealloc(list,NR_L);
+             cg.a_load_reg_reg(list,OS_8,OS_8,NR_H,GetNextReg(dst));
+             cg.a_reg_dealloc(list,NR_H);
+             paraloc2.done;
+             paraloc1.done;
+           end
+         else
+           internalerror(2011022002);
+       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:=tcgsize2size[size] downto 1 do
+           begin
+             list.Concat(taicpu.op_reg_const(A_LD,reg,(qword(a) and mask) shr shift));
+             if i<>1 then
+               begin
+                 mask:=mask shl 8;
+                 inc(shift,8);
+                 reg:=GetNextReg(reg);
+               end;
+           end;
+       end;
+
+
+     procedure tcgz80.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
+       var
+         mask : qword;
+         shift : byte;
+         href: treference;
+         i: Integer;
+       begin
+         mask:=$ff;
+         shift:=0;
+         href:=ref;
+         if (href.base=NR_NO) and (href.index<>NR_NO) then
+           begin
+             href.base:=href.index;
+             href.index:=NR_NO;
+           end;
+         if is_ref_in_opertypes(href,[OT_REF_IX_d,OT_REF_IY_d]) or
+            (is_ref_hl(href) and (size in [OS_8,OS_S8])) then
+           begin
+             for i:=tcgsize2size[size] downto 1 do
+               begin
+                 list.Concat(taicpu.op_ref_const(A_LD,href,(qword(a) and mask) shr shift));
+                 if i<>1 then
+                   begin
+                     mask:=mask shl 8;
+                     inc(shift,8);
+                     inc(href.offset);
+                   end;
+               end;
+           end
+         else
+           inherited;
+       end;
+
+
+    function tcgz80.normalize_ref(list: TAsmList; ref: treference;
+        const refopertypes: trefoperandtypes; out allocatedregs: tregisterlist): treference;
+      var
+        tmpref : treference;
+        l : tasmlabel;
+      begin
+        SetLength(allocatedregs,0);
+
+        if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then
+          begin
+            ref.base:=ref.index;
+            ref.index:=NR_NO;
+          end;
+
+        if is_ref_in_opertypes(ref,refopertypes) then
+          begin
+            Result:=ref;
+            exit;
+          end;
+
+        { can we use the HL register? }
+        if OT_REF_HL in refopertypes then
+          begin
+            SetLength(allocatedregs,2);
+            allocatedregs[0]:=NR_H;
+            allocatedregs[1]:=NR_L;
+            getcpuregisters(list,allocatedregs);
+            if assigned(ref.symbol) or (ref.offset<>0) then
+              begin
+                if assigned(ref.symbol) then
+                  begin
+                    reference_reset(tmpref,0,[]);
+                    tmpref.symbol:=ref.symbol;
+                    tmpref.offset:=ref.offset;
+
+                    tmpref.refaddr:=addr_full;
+                    list.concat(taicpu.op_reg_ref(A_LD,NR_HL,tmpref));
+                  end
+                else
+                  list.concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
+                if (ref.base=NR_IX) or (ref.base=NR_IY) then
+                  begin
+                    getcpuregister(list,NR_D);
+                    getcpuregister(list,NR_E);
+                    list.concat(taicpu.op_reg(A_PUSH,ref.base));
+                    list.concat(taicpu.op_reg(A_POP,NR_DE));
+                    list.concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_DE));
+                    ungetcpuregister(list,NR_E);
+                    ungetcpuregister(list,NR_D);
+                  end
+                else if ref.base<>NR_NO then
+                  begin
+                    getcpuregister(list,NR_A);
+                    emit_mov(list,NR_A,NR_L);
+                    list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.base));
+                    emit_mov(list,NR_L,NR_A);
+                    emit_mov(list,NR_A,NR_H);
+                    list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.base)));
+                    emit_mov(list,NR_H,NR_A);
+                    ungetcpuregister(list,NR_A);
+                  end;
+                if ref.index<>NR_NO then
+                  begin
+                    if ref.scalefactor>1 then
+                      internalerror(2020042002);
+                    getcpuregister(list,NR_A);
+                    emit_mov(list,NR_A,NR_L);
+                    list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index));
+                    emit_mov(list,NR_L,NR_A);
+                    emit_mov(list,NR_A,NR_H);
+                    list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index)));
+                    emit_mov(list,NR_H,NR_A);
+                    ungetcpuregister(list,NR_A);
+                  end;
+              end
+            else
+              begin
+                { not assigned(ref.symbol) and (ref.offset=0) }
+                if (ref.base=NR_IX) or (ref.base=NR_IY) then
+                  begin
+                    list.concat(taicpu.op_reg(A_PUSH,ref.base));
+                    list.concat(taicpu.op_reg(A_POP,NR_HL));
+                  end
+                else if ref.base<>NR_NO then
+                  begin
+                    emit_mov(list,NR_L,ref.base);
+                    emit_mov(list,NR_H,GetNextReg(ref.base));
+                  end;
+                if ref.index<>NR_NO then
+                  begin
+                    if ref.scalefactor>1 then
+                      internalerror(2020042002);
+                    getcpuregister(list,NR_A);
+                    emit_mov(list,NR_A,NR_L);
+                    list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index));
+                    emit_mov(list,NR_L,NR_A);
+                    emit_mov(list,NR_A,NR_H);
+                    list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index)));
+                    emit_mov(list,NR_H,NR_A);
+                    ungetcpuregister(list,NR_A);
+                  end;
+              end;
+            reference_reset_base(result,NR_HL,0,ctempposinvalid,0,[]);
+          end
+        else
+          internalerror(2020042001);
+      end;
+
+
+    procedure tcgz80.adjust_normalized_ref(list: TAsmList; var ref: treference; value: longint);
+      var
+        i: Integer;
+      begin
+        if is_ref_addr16(ref) then
+          Inc(ref.offset,value)
+        else if is_ref_hl(ref) then
+          begin
+            if value>0 then
+              for i:=1 to value do
+                list.concat(taicpu.op_reg(A_INC,NR_HL))
+            else
+              for i:=-1 downto value do
+                list.concat(taicpu.op_reg(A_DEC,NR_HL));
+          end
+        else if is_ref_ix_d(ref) then
+          begin
+            if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
+              inc(ref.offset,value)
+            else
+              begin
+                { todo: IX is the frame pointer, we cannot change it, so we }
+                {       think of another mechanism to deal with this situation }
+                internalerror(2020042101);
+                //if value>0 then
+                //  for i:=1 to value do
+                //    list.concat(taicpu.op_reg(A_INC,NR_IX))
+                //else
+                //  for i:=-1 downto value do
+                //    list.concat(taicpu.op_reg(A_DEC,NR_IX));
+              end;
+          end
+        else if is_ref_iy_d(ref) then
+          begin
+            if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
+              inc(ref.offset,value)
+            else
+              if value>0 then
+                for i:=1 to value do
+                  list.concat(taicpu.op_reg(A_INC,NR_IY))
+              else
+                for i:=-1 downto value do
+                  list.concat(taicpu.op_reg(A_DEC,NR_IY));
+          end;
+      end;
+
+
+     procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
+       var
+         href : treference;
+         i : integer;
+         regsused: tregisterlist;
+       begin
+         if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
+           internalerror(2011021307);
+         if tcgsize2size[fromsize]>tcgsize2size[tosize] then
+           internalerror(2020040802);
+
+         href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
+         if (tcgsize2size[fromsize]=tcgsize2size[tosize]) or (fromsize in [OS_8,OS_16,OS_32]) then
+           begin
+             getcpuregister(list,NR_A);
+             for i:=1 to tcgsize2size[fromsize] do
+               begin
+                 a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
+                 list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
+                 if i<>tcgsize2size[fromsize] then
+                   reg:=GetNextReg(reg);
+                 if i<>tcgsize2size[tosize] then
+                   adjust_normalized_ref(list,href,1);
+               end;
+             for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
+               begin
+                 if i=(tcgsize2size[fromsize]+1) then
+                   list.concat(taicpu.op_reg_const(A_LD,NR_A,0));
+                 list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
+                 if i<>tcgsize2size[tosize] then
+                   begin
+                     adjust_normalized_ref(list,href,1);
+                     reg:=GetNextReg(reg);
+                   end;
+               end;
+             ungetcpuregister(list,NR_A);
+           end
+         else
+           begin
+             getcpuregister(list,NR_A);
+             for i:=1 to tcgsize2size[fromsize] do
+               begin
+                 a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
+                 list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
+                 if i<>tcgsize2size[fromsize] then
+                   reg:=GetNextReg(reg);
+                 if i<>tcgsize2size[tosize] then
+                   adjust_normalized_ref(list,href,1);
+               end;
+             list.concat(taicpu.op_none(A_RLA));
+             list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
+             for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
+               begin
+                 list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
+                 if i<>tcgsize2size[tosize] then
+                   begin
+                     adjust_normalized_ref(list,href,1);
+                     reg:=GetNextReg(reg);
+                   end;
+               end;
+             ungetcpuregister(list,NR_A);
+           end;
+         ungetcpuregisters(list,regsused);
+       end;
+
+
+     procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
+       const Ref : treference;reg : tregister);
+       var
+         href : treference;
+         i : integer;
+         regsused: tregisterlist;
+       begin
+         if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
+           internalerror(2011021307);
+         if tcgsize2size[fromsize]>=tcgsize2size[tosize] then
+           fromsize:=tosize;
+
+         href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
+         if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then
+           begin
+             getcpuregister(list,NR_A);
+             for i:=1 to tcgsize2size[fromsize] do
+               begin
+                 list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
+                 a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
+
+                 if i<>tcgsize2size[fromsize] then
+                   adjust_normalized_ref(list,href,1);
+                 if i<>tcgsize2size[tosize] then
+                   reg:=GetNextReg(reg);
+               end;
+             ungetcpuregisters(list,regsused);
+             ungetcpuregister(list,NR_A);
+             for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
+               begin
+                 list.concat(taicpu.op_reg_const(A_LD,reg,0));
+                 if i<>tcgsize2size[tosize] then
+                   reg:=GetNextReg(reg);
+               end;
+           end
+         else
+           begin
+             getcpuregister(list,NR_A);
+             for i:=1 to tcgsize2size[fromsize] do
+               begin
+                 list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
+                 a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
+
+                 if i<>tcgsize2size[fromsize] then
+                   adjust_normalized_ref(list,href,1);
+                 if i<>tcgsize2size[tosize] then
+                   reg:=GetNextReg(reg);
+               end;
+             ungetcpuregisters(list,regsused);
+             list.concat(taicpu.op_none(A_RLA));
+             list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
+             for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
+               begin
+                 emit_mov(list,reg,NR_A);
+                 if i<>tcgsize2size[tosize] then
+                   reg:=GetNextReg(reg);
+               end;
+             ungetcpuregister(list,NR_A);
+           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);
+         if tcgsize2size[fromsize]>tcgsize2size[tosize] then
+           fromsize:=tosize;
+
+         if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then
+           begin
+             if reg1<>reg2 then
+               for i:=1 to tcgsize2size[fromsize] do
+                 begin
+                   emit_mov(list,reg2,reg1);
+                   if i<>tcgsize2size[fromsize] then
+                     reg1:=GetNextReg(reg1);
+                   if i<>tcgsize2size[tosize] then
+                     reg2:=GetNextReg(reg2);
+                 end
+             else
+               for i:=1 to tcgsize2size[fromsize] do
+                 if i<>tcgsize2size[tosize] then
+                   reg2:=GetNextReg(reg2);
+             for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
+               begin
+                 list.Concat(taicpu.op_reg_const(A_LD,reg2,0));
+                 if i<>tcgsize2size[tosize] then
+                   reg2:=GetNextReg(reg2);
+               end
+           end
+         else
+           begin
+             if reg1<>reg2 then
+               for i:=1 to tcgsize2size[fromsize]-1 do
+                 begin
+                   emit_mov(list,reg2,reg1);
+                   reg1:=GetNextReg(reg1);
+                   reg2:=GetNextReg(reg2);
+                 end
+             else
+               for i:=1 to tcgsize2size[fromsize]-1 do
+                 reg2:=GetNextReg(reg2);
+             emit_mov(list,reg2,reg1);
+             getcpuregister(list,NR_A);
+             emit_mov(list,NR_A,reg2);
+             reg2:=GetNextReg(reg2);
+             list.concat(taicpu.op_none(A_RLA));
+             list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
+             for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
+               begin
+                 emit_mov(list,reg2,NR_A);
+                 if i<>tcgsize2size[tosize] then
+                   reg2:=GetNextReg(reg2);
+               end;
+             ungetcpuregister(list,NR_A);
+           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;
+        tmpl: TAsmLabel;
+      begin
+        if size in [OS_8,OS_S8]then
+          begin
+            if cmp_op in [OC_EQ,OC_NE,OC_B,OC_AE] then
+              begin
+                getcpuregister(list,NR_A);
+                a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
+                list.concat(taicpu.op_reg_const(A_CP,NR_A,a));
+                case cmp_op of
+                  OC_EQ:
+                    a_jmp_flags(list,F_E,l);
+                  OC_NE:
+                    a_jmp_flags(list,F_NE,l);
+                  OC_B:
+                    a_jmp_flags(list,F_C,l);
+                  OC_AE:
+                    a_jmp_flags(list,F_NC,l);
+                  else
+                    internalerror(2020042206);
+                end;
+                ungetcpuregister(list,NR_A);
+              end
+            else if cmp_op in [OC_A,OC_BE] then
+              begin
+                getcpuregister(list,NR_A);
+                a_load_const_reg(list,OS_8,a,NR_A);
+                list.concat(taicpu.op_reg_reg(A_CP,NR_A,reg));
+                case cmp_op of
+                  OC_A:
+                    a_jmp_flags(list,F_C,l);
+                  OC_BE:
+                    a_jmp_flags(list,F_NC,l);
+                  else
+                    internalerror(2020042206);
+                end;
+                ungetcpuregister(list,NR_A);
+              end
+            else if cmp_op in [OC_LT,OC_GTE] then
+              begin
+                getcpuregister(list,NR_A);
+                a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
+                list.concat(taicpu.op_reg_const(A_SUB,NR_A,a));
+                current_asmdata.getjumplabel(tmpl);
+                a_jmp_flags(list,F_PO,tmpl);
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+                cg.a_label(current_asmdata.CurrAsmList,tmpl);
+                case cmp_op of
+                  OC_LT:
+                    a_jmp_flags(list,F_M,l);
+                  OC_GTE:
+                    a_jmp_flags(list,F_P,l);
+                  else
+                    internalerror(2020042206);
+                end;
+                ungetcpuregister(list,NR_A);
+              end
+            else if cmp_op in [OC_GT,OC_LTE] then
+              begin
+                getcpuregister(list,NR_A);
+                a_load_const_reg(list,OS_8,a,NR_A);
+                list.concat(taicpu.op_reg_reg(A_SUB,NR_A,reg));
+                current_asmdata.getjumplabel(tmpl);
+                a_jmp_flags(list,F_PO,tmpl);
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+                cg.a_label(current_asmdata.CurrAsmList,tmpl);
+                case cmp_op of
+                  OC_GT:
+                    a_jmp_flags(list,F_M,l);
+                  OC_LTE:
+                    a_jmp_flags(list,F_P,l);
+                  else
+                    internalerror(2020042206);
+                end;
+                ungetcpuregister(list,NR_A);
+              end;
+          end
+        else if cmp_op in [OC_EQ,OC_NE] then
+          begin
+            if cmp_op=OC_EQ then
+              current_asmdata.getjumplabel(tmpl);
+            for i:=0 to tcgsize2size[size]-1 do
+              begin
+                a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A);
+                list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i))));
+                case cmp_op of
+                  OC_EQ:
+                    if i<>(tcgsize2size[size]-1) then
+                      a_jmp_flags(list,F_NE,tmpl)
+                    else
+                      a_jmp_flags(list,F_E,l);
+                  OC_NE:
+                    a_jmp_flags(list,F_NE,l);
+                  else
+                    internalerror(2020042206);
+                end;
+              end;
+            if cmp_op=OC_EQ then
+              cg.a_label(current_asmdata.CurrAsmList,tmpl);
+          end
+        else if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE,OC_BE,OC_B,OC_AE,OC_A] then
+          begin
+            getcpuregister(list,NR_A);
+            current_asmdata.getjumplabel(tmpl);
+            for i:=tcgsize2size[size]-1 downto 0 do
+              begin
+                a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A);
+                list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i))));
+                if (i=(tcgsize2size[size]-1)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then
+                  case cmp_op of
+                    OC_GTE,
+                    OC_GT:
+                      a_jmp_signed_cmp_3way(list,tmpl,nil,l);
+                    OC_LT,
+                    OC_LTE:
+                      a_jmp_signed_cmp_3way(list,l,nil,tmpl);
+                    else
+                      internalerror(2020042206);
+                  end
+                else if i<>0 then
+                  case cmp_op of
+                    OC_AE,
+                    OC_A,
+                    OC_GTE,
+                    OC_GT:
+                      a_jmp_unsigned_cmp_3way(list,tmpl,nil,l);
+                    OC_BE,
+                    OC_B,
+                    OC_LT,
+                    OC_LTE:
+                      a_jmp_unsigned_cmp_3way(list,l,nil,tmpl);
+                    else
+                      internalerror(2020042206);
+                  end
+                else
+                case cmp_op of
+                  OC_A,
+                  OC_GT:
+                    a_jmp_unsigned_cmp_3way(list,nil,nil,l);
+                  OC_B,
+                  OC_LT:
+                    a_jmp_unsigned_cmp_3way(list,l,nil,nil);
+                  OC_AE,
+                  OC_GTE:
+                    a_jmp_unsigned_cmp_3way(list,nil,l,l);
+                  OC_BE,
+                  OC_LTE:
+                    a_jmp_unsigned_cmp_3way(list,l,l,nil);
+                  else
+                    internalerror(2020042206);
+                end;
+              end;
+            cg.a_label(current_asmdata.CurrAsmList,tmpl);
+            ungetcpuregister(list,NR_A);
+          end
+        else
+          internalerror(2020042205);
+      end;
+
+
+    procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
+      begin
+        internalerror(2020042301);
+      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:=taicpu.op_cond_sym(A_JP,flags_to_cond(f),l);
+        ai.is_jmp:=true;
+        list.concat(ai);
+      end;
+
+
+    procedure tcgz80.a_jmp_unsigned_cmp_3way(list: TAsmList; onbelow, onequal, onabove: tasmlabel);
+      var
+        skiplabel: TAsmLabel;
+      begin
+        if      (onbelow= nil) and (onequal= nil) and (onabove= nil) then
+          {nothing}
+        else if (onbelow= nil) and (onequal= nil) and (onabove<>nil) then
+          begin
+            current_asmdata.getjumplabel(skiplabel);
+            a_jmp_flags(list,F_E,skiplabel);
+            a_jmp_flags(list,F_NC,onabove);
+            cg.a_label(list,skiplabel);
+          end
+        else if (onbelow= nil) and (onequal<>nil) and (onabove= nil) then
+          a_jmp_flags(list,F_E,onequal)
+        else if (onbelow= nil) and (onequal<>nil) and (onabove<>nil) then
+          begin
+            if onequal<>onabove then
+              a_jmp_flags(list,F_E,onequal);
+            a_jmp_flags(list,F_NC,onabove);
+          end
+        else if (onbelow<>nil) and (onequal= nil) and (onabove= nil) then
+          a_jmp_flags(list,F_C,onbelow)
+        else if (onbelow<>nil) and (onequal= nil) and (onabove<>nil) then
+          begin
+            if onbelow<>onabove then
+              a_jmp_flags(list,F_C,onbelow);
+            a_jmp_flags(list,F_NE,onabove);
+          end
+        else if (onbelow<>nil) and (onequal<>nil) and (onabove= nil) then
+          begin
+            a_jmp_flags(list,F_C,onbelow);
+            a_jmp_flags(list,F_E,onequal);
+          end
+        else if (onbelow<>nil) and (onequal<>nil) and (onabove<>nil) then
+          begin
+            if (onbelow=onequal) and (onequal=onabove) then
+              a_jmp_always(list,onbelow)
+            else if onequal=onabove then
+              begin
+                a_jmp_flags(list,F_C,onbelow);
+                a_jmp_always(list,onabove);
+              end
+            else if onbelow=onequal then
+              begin
+                a_jmp_flags(list,F_C,onbelow);
+                a_jmp_flags(list,F_E,onequal);
+                a_jmp_always(list,onabove);
+              end
+            else if onbelow=onabove then
+              begin
+                a_jmp_flags(list,F_E,onequal);
+                a_jmp_always(list,onabove);
+              end
+            else
+              begin
+                { the generic case - all 3 are different labels }
+                a_jmp_flags(list,F_C,onbelow);
+                a_jmp_flags(list,F_E,onequal);
+                a_jmp_always(list,onabove);
+              end;
+          end
+        else
+          begin
+            { Shouldn't happen! All possible combinations are handled by the above code. }
+            internalerror(2020042201);
+          end;
+      end;
+
+    procedure tcgz80.a_jmp_signed_cmp_3way(list: TAsmList; onless, onequal, ongreater: tasmlabel);
+      var
+        l, skiplabel: TAsmLabel;
+      begin
+        if      (onless= nil) and (onequal= nil) and (ongreater= nil) then
+          {nothing}
+        else if (onless= nil) and (onequal= nil) and (ongreater<>nil) then
+          begin
+            current_asmdata.getjumplabel(skiplabel);
+            a_jmp_flags(list,F_E,skiplabel);
+            current_asmdata.getjumplabel(l);
+            a_jmp_flags(list,F_PO,l);
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+            cg.a_label(current_asmdata.CurrAsmList,l);
+            a_jmp_flags(list,F_P,ongreater);
+            cg.a_label(list,skiplabel);
+          end
+        else if (onless= nil) and (onequal<>nil) and (ongreater= nil) then
+          a_jmp_flags(list,F_E,onequal)
+        else if (onless= nil) and (onequal<>nil) and (ongreater<>nil) then
+          begin
+            if onequal<>ongreater then
+              a_jmp_flags(list,F_E,onequal);
+            current_asmdata.getjumplabel(l);
+            a_jmp_flags(list,F_PO,l);
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+            cg.a_label(current_asmdata.CurrAsmList,l);
+            a_jmp_flags(list,F_P,ongreater);
+          end
+        else if (onless<>nil) and (onequal= nil) and (ongreater= nil) then
+          begin
+            current_asmdata.getjumplabel(l);
+            a_jmp_flags(list,F_PO,l);
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+            cg.a_label(current_asmdata.CurrAsmList,l);
+            a_jmp_flags(list,F_M,onless);
+          end
+        else if (onless<>nil) and (onequal= nil) and (ongreater<>nil) then
+          begin
+            if onless=ongreater then
+              a_jmp_flags(list,F_NE,onless)
+            else
+              begin
+                current_asmdata.getjumplabel(skiplabel);
+                a_jmp_flags(list,F_E,skiplabel);
+                current_asmdata.getjumplabel(l);
+                a_jmp_flags(list,F_PO,l);
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+                cg.a_label(current_asmdata.CurrAsmList,l);
+                a_jmp_flags(list,F_M,onless);
+                a_jmp_always(list,ongreater);
+                cg.a_label(list,skiplabel);
+              end;
+          end
+        else if (onless<>nil) and (onequal<>nil) and (ongreater= nil) then
+          begin
+            a_jmp_flags(list,F_E,onequal);
+            current_asmdata.getjumplabel(l);
+            a_jmp_flags(list,F_PO,l);
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+            cg.a_label(current_asmdata.CurrAsmList,l);
+            a_jmp_flags(list,F_M,onless);
+          end
+        else if (onless<>nil) and (onequal<>nil) and (ongreater<>nil) then
+          begin
+            if (onless=onequal) and (onequal=ongreater) then
+              a_jmp_always(list,onless)
+            else if onequal=ongreater then
+              begin
+                current_asmdata.getjumplabel(l);
+                a_jmp_flags(list,F_PO,l);
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+                cg.a_label(current_asmdata.CurrAsmList,l);
+                a_jmp_flags(list,F_M,onless);
+                a_jmp_always(list,ongreater);
+              end
+            else if onless=onequal then
+              begin
+                a_jmp_flags(list,F_E,onequal);
+                current_asmdata.getjumplabel(l);
+                a_jmp_flags(list,F_PO,l);
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+                cg.a_label(current_asmdata.CurrAsmList,l);
+                a_jmp_flags(list,F_M,onless);
+                a_jmp_always(list,ongreater);
+              end
+            else if onless=ongreater then
+              begin
+                a_jmp_flags(list,F_E,onequal);
+                a_jmp_always(list,ongreater);
+              end
+            else
+              begin
+                { the generic case - all 3 are different labels }
+                a_jmp_flags(list,F_E,onequal);
+                current_asmdata.getjumplabel(l);
+                a_jmp_flags(list,F_PO,l);
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+                cg.a_label(current_asmdata.CurrAsmList,l);
+                a_jmp_flags(list,F_M,onless);
+                a_jmp_always(list,ongreater);
+              end;
+          end
+        else
+          begin
+            { Shouldn't happen! All possible combinations are handled by the above code. }
+            internalerror(2020042204);
+          end;
+      end;
+
+
+    procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
+      var
+        l : TAsmLabel;
+        tmpflags : TResFlags;
+      begin
+        if f in [F_C,F_NC] then
+          begin
+            a_load_const_reg(list,size,0,reg);
+            if f=F_NC then
+              list.concat(taicpu.op_none(A_CCF));
+            list.concat(taicpu.op_reg(A_RL,reg));
+          end
+        else
+          begin
+            current_asmdata.getjumplabel(l);
+            a_load_const_reg(list,size,0,reg);
+            tmpflags:=f;
+            inverse_flags(tmpflags);
+            a_jmp_flags(list,tmpflags,l);
+            list.concat(taicpu.op_reg(A_INC,reg));
+            cg.a_label(list,l);
+          end;
+      end;
+
+
+    procedure tcgz80.g_stackpointer_alloc(list: TAsmList; localsize: longint);
+      begin
+        if localsize>0 then
+          begin
+            list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize));
+            list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
+            list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
+          end;
+      end;
+
+
+    procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
+      var
+        i : integer;
+        sym: TAsmSymbol;
+        ref: treference;
+      begin
+        case value of
+          0:
+            ;
+          -7..-1:
+            begin
+              for i:=value to -1 do
+                list.concat(taicpu.op_reg(A_DEC,NR_SP));
+            end;
+          1..7:
+            begin
+              for i:=1 to value do
+                list.concat(taicpu.op_reg(A_INC,NR_SP));
+            end;
+          else
+            begin
+              sym:=current_asmdata.RefAsmSymbol('FPC_Z80_SAVE_HL',AT_DATA);
+              reference_reset_symbol(ref,sym,0,1,[]);
+
+              // block interrupts
+              list.concat(taicpu.op_none(A_DI));
+
+              // save HL
+              list.concat(taicpu.op_ref_reg(A_LD,ref,NR_HL));
+
+              // adjust SP
+              list.concat(taicpu.op_reg_const(A_LD,NR_HL,value));
+              list.concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
+              list.concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
+
+              // restore HL
+              list.concat(taicpu.op_reg_ref(A_LD,NR_HL,ref));
+
+              // release interrupts
+              list.concat(taicpu.op_none(A_EI));
+            end;
+        end;
+      end;
+
+
+    procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
+      var
+        regsize,stackmisalignment: longint;
+      begin
+        regsize:=0;
+        stackmisalignment:=0;
+        { save old framepointer }
+        if not nostackframe then
+          begin
+            { return address }
+            inc(stackmisalignment,2);
+            list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
+            if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
+              begin
+                { push <frame_pointer> }
+                inc(stackmisalignment,2);
+                include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
+                list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG));
+                { Return address and FP are both on stack }
+                current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2);
+                current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2));
+                if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
+                  begin
+                    list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0));
+                    list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG))
+                  end
+                else
+                  begin
+                    internalerror(2020040301);
+                    (*push_regs;
+                    gen_load_frame_for_exceptfilter(list);
+                    { Need only as much stack space as necessary to do the calls.
+                      Exception filters don't have own local vars, and temps are 'mapped'
+                      to the parent procedure.
+                      maxpushedparasize is already aligned at least on x86_64. }
+                    localsize:=current_procinfo.maxpushedparasize;*)
+                  end;
+                current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
+              end
+            else
+              begin
+                CGmessage(cg_d_stackframe_omited);
+              end;
+
+            { allocate stackframe space }
+            if (localsize<>0) or
+               ((target_info.stackalign>sizeof(pint)) and
+                (stackmisalignment <> 0) and
+                ((pi_do_call in current_procinfo.flags) or
+                 (po_assembler in current_procinfo.procdef.procoptions))) then
+              begin
+                if target_info.stackalign>sizeof(pint) then
+                  localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
+                g_stackpointer_alloc(list,localsize);
+                if current_procinfo.framepointer=NR_STACK_POINTER_REG then
+                  current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
+                current_procinfo.final_localsize:=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 Z80, 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;
+
+        { remove stackframe }
+        if not nostackframe then
+          begin
+            stacksize:=current_procinfo.calc_stackframe_size;
+            if (target_info.stackalign>4) and
+               ((stacksize <> 0) or
+                (pi_do_call in current_procinfo.flags) or
+                { can't detect if a call in this case -> use nostackframe }
+                { if you (think you) know what you are doing              }
+                (po_assembler in current_procinfo.procdef.procoptions)) then
+              stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
+            if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
+              begin
+                internalerror(2020040302);
+                {if (stacksize<>0) then
+                  cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);}
+              end
+            else
+              begin
+                list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
+                list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG));
+              end;
+            list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
+          end;
+
+        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 assigned(ref.symbol) then
+          begin
+            reference_reset(tmpref,0,[]);
+            tmpref.symbol:=ref.symbol;
+            tmpref.offset:=ref.offset;
+
+            tmpref.refaddr:=addr_lo8;
+            list.concat(taicpu.op_reg_ref(A_LD,r,tmpref));
+
+            tmpref.refaddr:=addr_hi8;
+            list.concat(taicpu.op_reg_ref(A_LD,GetNextReg(r),tmpref));
+
+            if (ref.base<>NR_NO) then
+              a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
+            if (ref.index<>NR_NO) then
+              a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
+          end
+        else if ref.base=NR_IX then
+          begin
+            list.concat(taicpu.op_reg(A_PUSH,NR_IX));
+            getcpuregister(list,NR_H);
+            getcpuregister(list,NR_L);
+            list.concat(taicpu.op_reg(A_POP,NR_HL));
+            emit_mov(list,r,NR_L);
+            ungetcpuregister(list,NR_L);
+            emit_mov(list,GetNextReg(r),NR_H);
+            ungetcpuregister(list,NR_H);
+            if (ref.index<>NR_NO) then
+              a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
+            if ref.offset<>0 then
+              a_op_const_reg(list,OP_ADD,OS_16,ref.offset,r);
+          end
+        else if (ref.base=NR_SP) or (ref.base=NR_BC) or (ref.base=NR_DE) then
+          begin
+            getcpuregister(list,NR_H);
+            getcpuregister(list,NR_L);
+            list.Concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
+            list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,ref.base));
+            emit_mov(list,r,NR_L);
+            ungetcpuregister(list,NR_L);
+            emit_mov(list,GetNextReg(r),NR_H);
+            ungetcpuregister(list,NR_H);
+            if (ref.index<>NR_NO) then
+              a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
+          end
+        else if ref.base<>NR_NO then
+          begin
+            a_op_const_reg_reg(list,OP_ADD,OS_16,ref.offset,ref.base,r);
+            if (ref.index<>NR_NO) then
+              a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
+          end
+        else if ref.index<>NR_NO then
+          a_op_const_reg_reg(list,OP_ADD,OS_16,ref.offset,ref.index,r)
+        else
+          a_load_const_reg(list,OS_16,ref.offset,r);
+      end;
+
+
+    procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
+      var
+        tmpreg,srcreg,dstreg: tregister;
+        srcref,dstref : treference;
+        i: Integer;
+      begin
+        if (len<=2) and
+           is_ref_in_opertypes(source,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) and
+           is_ref_in_opertypes(dest,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
+          begin
+            srcref:=source;
+            dstref:=dest;
+            tmpreg:=getintregister(list,OS_8);
+            for i:=1 to len do
+              begin
+                list.concat(taicpu.op_reg_ref(A_LD,tmpreg,srcref));
+                list.concat(taicpu.op_ref_reg(A_LD,dstref,tmpreg));
+                if i<>len then
+                  begin
+                    adjust_normalized_ref(list,srcref,1);
+                    adjust_normalized_ref(list,dstref,1);
+                  end;
+              end;
+          end
+        else
+          begin
+            srcreg:=getintregister(list,OS_16);
+            a_loadaddr_ref_reg(list,source,srcreg);
+            dstreg:=getintregister(list,OS_16);
+            a_loadaddr_ref_reg(list,dest,dstreg);
+            getcpuregister(list,NR_L);
+            a_load_reg_reg(list,OS_8,OS_8,srcreg,NR_L);
+            getcpuregister(list,NR_H);
+            a_load_reg_reg(list,OS_8,OS_8,GetNextReg(srcreg),NR_H);
+            getcpuregister(list,NR_E);
+            a_load_reg_reg(list,OS_8,OS_8,dstreg,NR_E);
+            getcpuregister(list,NR_D);
+            a_load_reg_reg(list,OS_8,OS_8,GetNextReg(dstreg),NR_D);
+            getcpuregister(list,NR_B);
+            getcpuregister(list,NR_C);
+            list.concat(taicpu.op_reg_const(A_LD,NR_BC,len));
+            list.concat(taicpu.op_none(A_LDIR));
+            ungetcpuregister(list,NR_B);
+            ungetcpuregister(list,NR_C);
+            ungetcpuregister(list,NR_D);
+            ungetcpuregister(list,NR_E);
+            ungetcpuregister(list,NR_H);
+            ungetcpuregister(list,NR_L);
+          end;
+      end;
+
+
+    procedure tcgz80.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
+      var
+        hl : tasmlabel;
+        ai : taicpu;
+        cond : TAsmCond;
+      begin
+        list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck')));
+        //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);
+      begin
+        case cond of
+          OC_EQ:
+            a_jmp_unsigned_cmp_3way(list,nil,l,nil);
+          OC_NE:
+            a_jmp_unsigned_cmp_3way(list,l,nil,l);
+          OC_A:
+            a_jmp_unsigned_cmp_3way(list,nil,nil,l);
+          OC_B:
+            a_jmp_unsigned_cmp_3way(list,l,nil,nil);
+          OC_AE:
+            a_jmp_unsigned_cmp_3way(list,nil,l,l);
+          OC_BE:
+            a_jmp_unsigned_cmp_3way(list,l,l,nil);
+          OC_GT:
+            a_jmp_signed_cmp_3way(list,nil,nil,l);
+          OC_LT:
+            a_jmp_signed_cmp_3way(list,l,nil,nil);
+          OC_GTE:
+            a_jmp_signed_cmp_3way(list,nil,l,l);
+          OC_LTE:
+            a_jmp_signed_cmp_3way(list,l,l,nil);
+          else
+            internalerror(2011082501);
+        end;
+      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 tcg64fz80.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 tcg64fz80.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:=tcg64fz80.create;
+      end;
+
+end.

+ 506 - 0
compiler/z80/cpubase.pas

@@ -0,0 +1,506 @@
+{
+    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={$i z80op.inc}
+
+
+      { This should define the array of instructions as string }
+      op2strtable=array[tasmop] of string[4];
+
+    const
+      { First value of opcode enumeration }
+      firstop = low(tasmop);
+      { Last value of opcode enumeration  }
+      lastop  = high(tasmop);
+
+      std_op2str:op2strtable={$i z80stdopnames.inc}
+
+      { call/reg instructions are not considered as jmp instructions for the usage cases of
+        this set }
+      jmp_instructions = [A_JP,A_JR,A_DJNZ];
+      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_SUBL;
+
+      { Available Registers }
+      {$i rz80con.inc}
+
+      { Integer Super registers first and last }
+      first_int_supreg = RS_A;
+      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_A,RS_B,RS_C,RS_D,RS_E,RS_H,RS_L];
+      VOLATILE_FPUREGISTERS = [];
+
+    type
+      totherregisterset = set of tregisterindex;
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+    type
+      TAsmCond=(C_None,
+        C_NZ,C_Z,C_NC,C_C,C_PO,C_PE,C_P,C_M
+      );
+
+    const
+      cond2str : array[TAsmCond] of string[2]=('',
+        'nz','z','nc','c','po','pe','p','m'
+      );
+
+      uppercond2str : array[TAsmCond] of string[2]=('',
+        'NZ','Z','NC','C','PO','PE','P','M'
+      );
+
+{*****************************************************************************
+                                   Flags
+*****************************************************************************}
+
+    type
+      TResFlags = (F_NotPossible,F_NE,F_E,F_NC,F_C,F_PO,F_PE,F_P,F_M);
+
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      max_operands = 2;
+
+      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_INVALID;
+      lastsaveintreg  = RS_INVALID;
+      firstsavefpureg = RS_INVALID;
+      lastsavefpureg  = RS_INVALID;
+      firstsavemmreg  = RS_INVALID;
+      lastsavemmreg   = 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_SP;
+      RS_STACK_POINTER_REG = RS_SP;
+      { Frame pointer register }
+      RS_FRAME_POINTER_REG = RS_IX;
+      NR_FRAME_POINTER_REG = NR_IX;
+      { 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_INVALID;
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_L;
+      RS_FUNCTION_RETURN_REG = RS_L;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_L;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_L;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_C;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_C;
+      { 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_F;
+      RS_DEFAULTFLAGS = RS_F;
+
+{*****************************************************************************
+                       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}
+
+    { Checks if Subset is a subset of c (e.g. "less than" is a subset of "less than or equal" }
+    function condition_in(const Subset, c: TAsmCond): Boolean;
+
+    function dwarf_reg(r:tregister):byte;
+    function dwarf_reg_no_error(r:tregister):shortint;
+    function eh_return_data_regno(nr: longint): longint;
+
+    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
+        case s of
+          OS_8,OS_S8:
+            cgsize2subreg:=R_SUBL;
+          OS_16,OS_S16:
+            cgsize2subreg:=R_SUBW;
+          OS_32,OS_S32:
+            cgsize2subreg:=R_SUBD;
+          OS_64,OS_S64:
+            cgsize2subreg:=R_SUBQ;
+          OS_NO:
+            { error message should have been thrown already before, so avoid only
+              an internal error }
+            cgsize2subreg:=R_SUBNONE;
+          else
+            internalerror(200301231);
+        end;
+      end;
+
+
+    function reg_cgsize(const reg: tregister): tcgsize;
+      begin
+        case getregtype(reg) of
+          R_INTREGISTER,
+          R_SPECIALREGISTER:
+            case getsubreg(reg) of
+              R_SUBL,
+              R_SUBH:
+                reg_cgsize:=OS_8;
+              R_SUBW:
+                reg_cgsize:=OS_16;
+              else
+                internalerror(2020041901);
+            end;
+          else
+            internalerror(2011021905);
+          end;
+        end;
+
+
+    procedure inverse_flags(var f: TResFlags);
+      const
+        inv_flags: array[TResFlags] of TResFlags =
+          (F_NotPossible,F_E,F_NE,F_C,F_NC,F_PE,F_PO,F_M,F_P);
+      begin
+        f:=inv_flags[f];
+      end;
+
+
+    function flags_to_cond(const f: TResFlags) : TAsmCond;
+      const
+        flag_2_cond: array[F_NE..F_M] of TAsmCond =
+          (C_NZ,C_Z,C_NC,C_C,C_PO,C_PE,C_P,C_M);
+      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_Z,C_NZ,C_C,C_NC,C_PE,C_PO,C_M,C_P);
+      begin
+        result := inverse[c];
+      end;
+
+
+    function conditions_equal(const c1, c2: TAsmCond): boolean; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      begin
+        result := c1 = c2;
+      end;
+
+
+    { Checks if Subset is a subset of c (e.g. "less than" is a subset of "less than or equal" }
+    function condition_in(const Subset, c: TAsmCond): Boolean;
+      begin
+        Result := {(c.cond = C_None) or} conditions_equal(Subset, c);
+
+        { TODO: Can a PowerPC programmer please update this procedure to
+          actually detect subsets? Thanks. [Kit] }
+      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 dwarf_reg_no_error(r:tregister):shortint;
+      begin
+        result:=regdwarf_table[findreg_by_number(r)];
+      end;
+
+
+    function eh_return_data_regno(nr: longint): longint;
+      begin
+        result:=-1;
+      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_zilog_z80,
+       cpu_zilog_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_zilog_z80  } [],
+       { cpu_zilog_ez80 } [CPUZ80_HAS_CALLCC]
+     );
+
+Implementation
+
+end.

+ 51 - 0
compiler/z80/cpunode.pas

@@ -0,0 +1,51 @@
+{
+    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
+       ,nz80cal
+       ,nz80mat
+       ,nz80mem
+//       ,nz80cnv
+//       ,nz80util,
+       { these are not really nodes }
+       ,tgcpu
+       { symtable }
+       ,symcpu,
+       aasmdef
+       ;
+
+
+end.

+ 533 - 0
compiler/z80/cpupara.pas

@@ -0,0 +1,533 @@
+{
+    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; side: tcallercallee; 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: longint);
+          function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
+            var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: longint):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>4 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: longint);
+      begin
+        curintreg:=RS_HL;
+        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: longint):longint;
+
+      var
+        nextintreg,nextfloatreg,nextmmreg : tsuperregister;
+        paradef : tdef;
+        paraloc : pcgparalocation;
+        stack_offset : longint;
+        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 false and { no fastcall yet }
+           //   (nextintreg=RS_HL) 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;
+               inc(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_HL;
+                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_HL then
+                   curintreg:=nextintreg-1
+                 else
+                   begin
+                     curintreg:=RS_HL;
+                     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_HL 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 Z80 }
+                          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:=paradef;
+                             paraloc^.loc:=LOC_REFERENCE;
+                             paraloc^.reference.index:=NR_STACK_POINTER_REG;
+                             paraloc^.reference.offset:=stack_offset;
+                             inc(stack_offset,paradef.size);
+                          end;
+                        paralen:=0;
+                      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,target_info.first_parm_offset);
+                       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: longint;
+        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;
+
+
+    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_32,
+                  OS_F32:
+                    begin
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_L;
+                      paraloc^.size:=OS_8;
+                      paraloc^.def:=u8inttype;
+
+                      paraloc:=result.add_location;
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_H;
+                      paraloc^.size:=OS_8;
+                      paraloc^.def:=u8inttype;
+
+                      paraloc:=result.add_location;
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_E;
+                      paraloc^.size:=OS_8;
+                      paraloc^.def:=u8inttype;
+
+                      paraloc:=result.add_location;
+                      paraloc^.loc:=LOC_REGISTER;
+                      paraloc^.register:=NR_D;
+                      paraloc^.size:=OS_8;
+                      paraloc^.def:=u8inttype;
+                    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_32,OS_S32:
+                begin
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_L;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+
+                  paraloc:=result.add_location;
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_H;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+
+                  paraloc:=result.add_location;
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_E;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+
+                  paraloc:=result.add_location;
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_D;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+                end;
+              OS_16,OS_S16:
+                begin
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_L;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+
+                  paraloc:=result.add_location;
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_H;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+                end;
+              OS_8,OS_S8:
+                begin
+                  paraloc^.loc:=LOC_REGISTER;
+                  paraloc^.register:=NR_L;
+                  paraloc^.size:=OS_8;
+                  paraloc^.def:=u8inttype;
+                end;
+              else
+                internalerror(2014030101);
+            end;
+          end;
+      end;
+
+
+    function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
+      var
+        cur_stack_offset: longint;
+        curintreg, curfloatreg, curmmreg: tsuperregister;
+      begin
+        init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
+
+        result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset);
+        if (p.proccalloption in cstylearrayofconst) then
+          { just continue loading the parameters in the registers }
+          result:=create_paraloc_info_intern(p,side,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset)
+        else
+          internalerror(200410231);
+      end;
+
+begin
+   paramanager:=tcpuparamanager.create;
+end.

+ 70 - 0
compiler/z80/cpupi.pas

@@ -0,0 +1,70 @@
+{
+    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
+        tg.setfirsttemp(0);
+      end;
+
+
+    function tcpuprocinfo.calc_stackframe_size:longint;
+      begin
+        result:=-tg.lasttemp+maxpushedparasize;
+      end;
+
+
+begin
+   cprocinfo:=tcpuprocinfo;
+end.
+

+ 76 - 0
compiler/z80/cputarg.pas

@@ -0,0 +1,76 @@
+{
+    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}
+    {$ifndef NOTARGETZXSPECTRUM}
+      ,t_zxspectrum
+    {$endif}
+
+{**************************************
+             Assemblers
+**************************************}
+
+    {$ifndef NOAGZ80ASM}
+      ,agz80asm
+    {$endif}
+    {$ifndef NOAGSDASZ80}
+      ,agsdasz80
+    {$endif}
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+  {$ifndef NoRaZ80asm}
+      ,raz80asm
+  {$endif NoRaZ80asm}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoDbgStabs}
+      ,dbgstabs
+  {$endif NoDbgStabs}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+      ;
+
+end.

+ 88 - 0
compiler/z80/hlcgcpu.pas

@@ -0,0 +1,88 @@
+{
+    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,
+    aasmbase,aasmtai,
+    cgcpu,
+    symconst,
+    verbose,fmodule,cutils;
+
+  procedure thlcgcpu.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+    var
+      make_global: Boolean;
+    begin
+      if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
+        Internalerror(200006137);
+      if not assigned(procdef.struct) or
+         (procdef.procoptions*[po_classmethod, po_staticmethod,
+           po_methodpointer, po_interrupt, po_iocheck]<>[]) then
+        Internalerror(200006138);
+      if procdef.owner.symtabletype<>ObjectSymtable then
+        Internalerror(200109191);
+
+      make_global:=false;
+      if (not current_module.is_unit) or
+         create_smartlink or
+         (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
+        make_global:=true;
+
+      if make_global then
+        List.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0,procdef))
+      else
+        List.concat(Tai_symbol.Createname_hidden(labelname,AT_FUNCTION,0,procdef));
+
+      list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_intf_wrapper')));
+    end;
+
+
+  procedure create_hlcodegen;
+    begin
+      hlcg:=thlcgcpu.create;
+      create_codegen;
+    end;
+
+begin
+  chlcgobj:=thlcgcpu;
+end.

+ 667 - 0
compiler/z80/nz80add.pas

@@ -0,0 +1,667 @@
+{
+    Copyright (c) 2008 by Florian Klaempfl
+
+    Code generation for add nodes on 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 nz80add;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       node,ncgadd, symtype,cpubase;
+
+    type
+
+       { TZ80AddNode }
+
+       TZ80AddNode = class(tcgaddnode)
+       private
+         function GetResFlags(unsigned:Boolean;anodetype:tnodetype):TResFlags;
+       protected
+         function use_mul_helper: boolean;override;
+         function first_cmppointer: tnode;override;
+         function pass_1 : tnode;override;
+         procedure second_cmpordinal;override;
+         procedure second_cmpsmallset;override;
+         procedure second_cmp64bit;override;
+         procedure second_cmp16_32_64bit;
+         procedure second_cmp;
+       end;
+
+  implementation
+
+    uses
+      globtype,systems,
+      cutils,verbose,globals,
+      symconst,symdef,paramgr,
+      aasmbase,aasmtai,aasmdata,aasmcpu,defutil,htypechk,
+      cgbase,cgutils,cgcpu,
+      cpuinfo,pass_1,pass_2,procinfo,
+      cpupara,
+      ncon,nset,nadd,
+      ncgutil,tgobj,rgobj,rgcpu,cgobj,cg64f32,
+      hlcgobj;
+
+{*****************************************************************************
+                               TZ80AddNode
+*****************************************************************************}
+
+
+    function TZ80AddNode.GetResFlags(unsigned: Boolean; anodetype: tnodetype): TResFlags;
+      begin
+        case anodetype of
+          equaln:
+            GetResFlags:=F_E;
+          unequaln:
+            GetResFlags:=F_NE;
+          else
+            if not(unsigned) then
+              begin
+                { signed }
+                if nf_swapped in flags then
+                  case anodetype of
+                    ltn:
+                      GetResFlags:=F_NotPossible;
+                    lten:
+                      GetResFlags:=F_P;
+                    gtn:
+                      GetResFlags:=F_M;
+                    gten:
+                      GetResFlags:=F_NotPossible;
+                    else
+                      internalerror(2014082020);
+                  end
+                else
+                  case anodetype of
+                    ltn:
+                      GetResFlags:=F_M;
+                    lten:
+                      GetResFlags:=F_NotPossible;
+                    gtn:
+                      GetResFlags:=F_NotPossible;
+                    gten:
+                      GetResFlags:=F_P;
+                    else
+                      internalerror(2014082021);
+                  end;
+              end
+            else
+              begin
+                { unsigned }
+                if nf_swapped in Flags then
+                  case anodetype of
+                    ltn:
+                      GetResFlags:=F_NotPossible;
+                    lten:
+                      GetResFlags:=F_NC;
+                    gtn:
+                      GetResFlags:=F_C;
+                    gten:
+                      GetResFlags:=F_NotPossible;
+                    else
+                      internalerror(2014082022);
+                  end
+                else
+                  case anodetype of
+                    ltn:
+                      GetResFlags:=F_C;
+                    lten:
+                      GetResFlags:=F_NotPossible;
+                    gtn:
+                      GetResFlags:=F_NotPossible;
+                    gten:
+                      GetResFlags:=F_NC;
+                    else
+                      internalerror(2014082023);
+                  end;
+              end;
+        end;
+      end;
+
+
+    function TZ80AddNode.use_mul_helper: boolean;
+      begin
+        result:=(nodetype=muln);
+      end;
+
+
+    function TZ80AddNode.first_cmppointer: tnode;
+      begin
+        result:=nil;
+        expectloc:=LOC_JUMP;
+      end;
+
+
+    procedure TZ80AddNode.second_cmpsmallset;
+
+      procedure gencmp(tmpreg1,tmpreg2 : tregister);
+        var
+          i : byte;
+        begin
+          //current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CP,tmpreg1,tmpreg2));
+          //for i:=2 to tcgsize2size[left.location.size] do
+          //  begin
+          //    tmpreg1:=GetNextReg(tmpreg1);
+          //    tmpreg2:=GetNextReg(tmpreg2);
+          //    current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CPC,tmpreg1,tmpreg2));
+          //  end;
+        end;
+
+      var
+        tmpreg : tregister;
+      begin
+        //pass_left_right;
+        //location_reset(location,LOC_FLAGS,OS_NO);
+        //force_reg_left_right(false,false);
+        //
+        //case nodetype of
+        //  equaln:
+        //    begin
+        //      gencmp(left.location.register,right.location.register);
+        //      location.resflags:=F_EQ;
+        //    end;
+        //  unequaln:
+        //    begin
+        //      gencmp(left.location.register,right.location.register);
+        //      location.resflags:=F_NE;
+        //    end;
+        //  lten,
+        //  gten:
+        //    begin
+        //      if (not(nf_swapped in flags) and
+        //          (nodetype = lten)) or
+        //         ((nf_swapped in flags) and
+        //          (nodetype = gten)) then
+        //        swapleftright;
+        //      tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+        //      cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,location.size,
+        //        left.location.register,right.location.register,tmpreg);
+        //      gencmp(tmpreg,right.location.register);
+        //      location.resflags:=F_EQ;
+        //    end;
+        //  else
+        //    internalerror(2004012401);
+        //end;
+      end;
+
+
+    procedure TZ80AddNode.second_cmp;
+      var
+        unsigned : boolean;
+        tmpreg1,tmpreg2 : tregister;
+        i : longint;
+        opdef: tdef;
+        opsize: TCgSize;
+        l: TAsmLabel;
+      begin
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+        opdef:=left.resultdef;
+        opsize:=def_cgsize(opdef);
+
+        pass_left_right;
+
+        if (opsize=OS_8) or ((opsize=OS_S8) and (NodeType in [equaln,unequaln])) then
+          begin
+            if getresflags(unsigned,NodeType)=F_NotPossible then
+              swapleftright;
+
+            if left.location.loc<>LOC_REGISTER then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+            if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
+              begin
+                if is_ref_in_opertypes(right.location.reference,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
+                  begin
+                    cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    cg.a_load_loc_reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),left.location,NR_A);
+                    current_asmdata.CurrAsmList.Concat(taicpu.op_reg_ref(A_CP,NR_A,right.location.reference));
+                    cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  end
+                else
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+              end;
+            case right.location.loc of
+              LOC_CONSTANT:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  cg.a_load_loc_reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),left.location,NR_A);
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_CP,NR_A,right.location.value));
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                end;
+              LOC_REGISTER,LOC_CREGISTER:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  cg.a_load_loc_reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),left.location,NR_A);
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_CP,NR_A,right.location.register));
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                end;
+              LOC_REFERENCE,LOC_CREFERENCE:
+                begin
+                  { Already handled before the case statement. Nothing to do here. }
+                end;
+              else
+                internalerror(2020040402);
+            end;
+
+            location_reset(location,LOC_FLAGS,OS_NO);
+            location.resflags:=getresflags(unsigned,NodeType);
+          end
+        else if opsize=OS_S8 then
+          begin
+            if getresflags(unsigned,NodeType)=F_NotPossible then
+              swapleftright;
+
+            if left.location.loc<>LOC_REGISTER then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+            if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
+              begin
+                if is_ref_in_opertypes(right.location.reference,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
+                  begin
+                    cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    cg.a_load_loc_reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),left.location,NR_A);
+                    current_asmdata.CurrAsmList.Concat(taicpu.op_reg_ref(A_SUB,NR_A,right.location.reference));
+                  end
+                else
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+              end;
+            case right.location.loc of
+              LOC_CONSTANT:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  cg.a_load_loc_reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),left.location,NR_A);
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_SUB,NR_A,right.location.value));
+                end;
+              LOC_REGISTER,LOC_CREGISTER:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  cg.a_load_loc_reg(current_asmdata.CurrAsmList,def_cgsize(left.resultdef),left.location,NR_A);
+                  current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_SUB,NR_A,right.location.register));
+                end;
+              LOC_REFERENCE,LOC_CREFERENCE:
+                begin
+                  { Already handled before the case statement. Nothing to do here. }
+                end;
+              else
+                internalerror(2020040402);
+            end;
+            current_asmdata.getjumplabel(l);
+            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_PO,l);
+            current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
+            cg.a_label(current_asmdata.CurrAsmList,l);
+            cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+
+            location_reset(location,LOC_FLAGS,OS_NO);
+            location.resflags:=getresflags(unsigned,NodeType);
+          end
+        else
+          internalerror(2020040401);
+      end;
+
+
+    procedure TZ80AddNode.second_cmp64bit;
+      begin
+        second_cmp16_32_64bit;
+      end;
+
+
+    procedure TZ80AddNode.second_cmp16_32_64bit;
+      var
+        truelabel,
+        falselabel: tasmlabel;
+        unsigned  : boolean;
+        i, size: Integer;
+        tmpref: treference;
+        op: TAsmOp;
+        actualnodetype: tnodetype;
+      begin
+        truelabel:=nil;
+        falselabel:=nil;
+        pass_left_right;
+
+        unsigned:=not(is_signed(left.resultdef)) or
+                  not(is_signed(right.resultdef));
+
+        { we have LOC_JUMP as result }
+        current_asmdata.getjumplabel(truelabel);
+        current_asmdata.getjumplabel(falselabel);
+        location_reset_jump(location,truelabel,falselabel);
+
+        size:=tcgsize2size[def_cgsize(left.resultdef)];
+
+        if NodeType in [equaln,unequaln] then
+          begin
+            if left.location.loc<>LOC_REGISTER then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+            if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
+              begin
+                if is_ref_in_opertypes(right.location.reference,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
+                  begin
+                    cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    tmpref:=right.location.reference;
+                    for i:=0 to size-1 do
+                      begin
+                        cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,tcgz80(cg).GetOffsetReg64(left.location.register,left.location.registerhi,i),NR_A);
+                        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_ref(A_CP,NR_A,tmpref));
+                        case NodeType of
+                          equaln:
+                            if i<>(size-1) then
+                              cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,falselabel)
+                            else
+                              cg.a_jmp_flags(current_asmdata.CurrAsmList,F_E,truelabel);
+                          unequaln:
+                            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,truelabel);
+                          else
+                            internalerror(2020042102);
+                        end;
+                        if i<>(size-1) then
+                          tcgz80(cg).adjust_normalized_ref(current_asmdata.CurrAsmList,tmpref,1);
+                      end;
+                    cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    cg.a_jmp_always(current_asmdata.CurrAsmList,falselabel);
+                  end
+                else
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+              end;
+            case right.location.loc of
+              LOC_CONSTANT:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  for i:=0 to size-1 do
+                    begin
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,tcgz80(cg).GetOffsetReg64(left.location.register,left.location.registerhi,i),NR_A);
+                      current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_CP,NR_A,byte(right.location.value shr (i*8))));
+                      case NodeType of
+                        equaln:
+                          if i<>(size-1) then
+                            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,falselabel)
+                          else
+                            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_E,truelabel);
+                        unequaln:
+                          cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,truelabel);
+                        else
+                          internalerror(2020042102);
+                      end;
+                    end;
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  cg.a_jmp_always(current_asmdata.CurrAsmList,falselabel);
+                end;
+              LOC_REGISTER,LOC_CREGISTER:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  for i:=0 to size-1 do
+                    begin
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,tcgz80(cg).GetOffsetReg64(left.location.register,left.location.registerhi,i),NR_A);
+                      current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_CP,NR_A,tcgz80(cg).GetOffsetReg64(right.location.register,right.location.registerhi,i)));
+                      case NodeType of
+                        equaln:
+                          if i<>(size-1) then
+                            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,falselabel)
+                          else
+                            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_E,truelabel);
+                        unequaln:
+                          cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,truelabel);
+                        else
+                          internalerror(2020042102);
+                      end;
+                    end;
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  cg.a_jmp_always(current_asmdata.CurrAsmList,falselabel);
+                end;
+              LOC_REFERENCE,LOC_CREFERENCE:
+                begin
+                  { Already handled before the case statement. Nothing to do here. }
+                end;
+              else
+                internalerror(2020042103);
+            end;
+          end
+        else
+          begin
+            if nf_swapped in Flags then
+              begin
+                case NodeType of
+                  ltn:
+                    actualnodetype:=gtn;
+                  lten:
+                    actualnodetype:=gten;
+                  gtn:
+                    actualnodetype:=ltn;
+                  gten:
+                    actualnodetype:=lten;
+                  else
+                    internalerror(2020042701);
+                end;
+              end
+            else
+              actualnodetype:=NodeType;
+
+            if left.location.loc<>LOC_REGISTER then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+            if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
+              begin
+                if is_ref_in_opertypes(right.location.reference,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
+                  begin
+                    cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    tmpref:=right.location.reference;
+                    tcgz80(cg).adjust_normalized_ref(current_asmdata.CurrAsmList,tmpref,size-1);
+                    for i:=size-1 downto 0 do
+                      begin
+                        cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,tcgz80(cg).GetOffsetReg64(left.location.register,left.location.registerhi,i),NR_A);
+                        if (i=(size-1)) and (not unsigned) then
+                          op:=A_SUB
+                        else
+                          op:=A_CP;
+                        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_ref(op,NR_A,tmpref));
+                        if (i=(size-1)) and (not unsigned) then
+                          case actualnodetype of
+                            ltn,
+                            lten:
+                              tcgz80(cg).a_jmp_signed_cmp_3way(current_asmdata.CurrAsmList,truelabel,nil,falselabel);
+                            gtn,
+                            gten:
+                              tcgz80(cg).a_jmp_signed_cmp_3way(current_asmdata.CurrAsmList,falselabel,nil,truelabel);
+                            else
+                              internalerror(2020042202);
+                          end
+                        else if i<>0 then
+                          case actualnodetype of
+                            ltn,
+                            lten:
+                              tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,nil,falselabel);
+                            gtn,
+                            gten:
+                              tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,nil,truelabel);
+                            else
+                              internalerror(2020042202);
+                          end
+                        else
+                          case actualnodetype of
+                            ltn:
+                              tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,falselabel,falselabel);
+                            lten:
+                              tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,truelabel,falselabel);
+                            gtn:
+                              tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,falselabel,truelabel);
+                            gten:
+                              tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,truelabel,truelabel);
+                            else
+                              internalerror(2020042203);
+                          end;
+                        if i<>0 then
+                          tcgz80(cg).adjust_normalized_ref(current_asmdata.CurrAsmList,tmpref,-1);
+                      end;
+                    cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  end
+                else
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
+              end;
+            case right.location.loc of
+              LOC_CONSTANT:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  for i:=size-1 downto 0 do
+                    begin
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,tcgz80(cg).GetOffsetReg64(left.location.register,left.location.registerhi,i),NR_A);
+                      if (i=(size-1)) and (not unsigned) then
+                        op:=A_SUB
+                      else
+                        op:=A_CP;
+                      current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(op,NR_A,byte(right.location.value shr (i*8))));
+                      if (i=(size-1)) and (not unsigned) then
+                        case actualnodetype of
+                          ltn,
+                          lten:
+                            tcgz80(cg).a_jmp_signed_cmp_3way(current_asmdata.CurrAsmList,truelabel,nil,falselabel);
+                          gtn,
+                          gten:
+                            tcgz80(cg).a_jmp_signed_cmp_3way(current_asmdata.CurrAsmList,falselabel,nil,truelabel);
+                          else
+                            internalerror(2020042202);
+                        end
+                      else if i<>0 then
+                        case actualnodetype of
+                          ltn,
+                          lten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,nil,falselabel);
+                          gtn,
+                          gten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,nil,truelabel);
+                          else
+                            internalerror(2020042202);
+                        end
+                      else
+                        case actualnodetype of
+                          ltn:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,falselabel,falselabel);
+                          lten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,truelabel,falselabel);
+                          gtn:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,falselabel,truelabel);
+                          gten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,truelabel,truelabel);
+                          else
+                            internalerror(2020042203);
+                        end;
+                    end;
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                end;
+              LOC_REGISTER,LOC_CREGISTER:
+                begin
+                  cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                  for i:=size-1 downto 0 do
+                    begin
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,tcgz80(cg).GetOffsetReg64(left.location.register,left.location.registerhi,i),NR_A);
+                      if (i=(size-1)) and (not unsigned) then
+                        op:=A_SUB
+                      else
+                        op:=A_CP;
+                      current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(op,NR_A,tcgz80(cg).GetOffsetReg64(right.location.register,right.location.registerhi,i)));
+                      if (i=(size-1)) and (not unsigned) then
+                        case actualnodetype of
+                          ltn,
+                          lten:
+                            tcgz80(cg).a_jmp_signed_cmp_3way(current_asmdata.CurrAsmList,truelabel,nil,falselabel);
+                          gtn,
+                          gten:
+                            tcgz80(cg).a_jmp_signed_cmp_3way(current_asmdata.CurrAsmList,falselabel,nil,truelabel);
+                          else
+                            internalerror(2020042202);
+                        end
+                      else if i<>0 then
+                        case actualnodetype of
+                          ltn,
+                          lten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,nil,falselabel);
+                          gtn,
+                          gten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,nil,truelabel);
+                          else
+                            internalerror(2020042202);
+                        end
+                      else
+                        case actualnodetype of
+                          ltn:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,falselabel,falselabel);
+                          lten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,truelabel,truelabel,falselabel);
+                          gtn:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,falselabel,truelabel);
+                          gten:
+                            tcgz80(cg).a_jmp_unsigned_cmp_3way(current_asmdata.CurrAsmList,falselabel,truelabel,truelabel);
+                          else
+                            internalerror(2020042203);
+                        end;
+                    end;
+                  cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                end;
+              LOC_REFERENCE,LOC_CREFERENCE:
+                begin
+                  { Already handled before the case statement. Nothing to do here. }
+                end;
+              else
+                internalerror(2020042103);
+            end;
+          end;
+      end;
+
+
+    function TZ80AddNode.pass_1 : tnode;
+      begin
+        result:=inherited pass_1;
+{$ifdef dummy}
+        if not(assigned(result)) then
+          begin
+            unsigned:=not(is_signed(left.resultdef)) or
+              not(is_signed(right.resultdef));
+
+            if is_64bit(left.resultdef) and
+              ((nodetype in [equaln,unequaln]) or
+               (unsigned and (nodetype in [ltn,lten,gtn,gten]))
+              ) then
+              expectloc:=LOC_FLAGS;
+          end;
+        { handling boolean expressions }
+        if not(assigned(result)) and
+           (
+             not(is_boolean(left.resultdef)) or
+             not(is_boolean(right.resultdef)) or
+             is_dynamic_array(left.resultdef)
+           ) then
+          expectloc:=LOC_FLAGS;
+{$endif dummy}
+      end;
+
+
+    procedure TZ80AddNode.second_cmpordinal;
+      begin
+        if left.resultdef.size>=2 then
+          second_cmp16_32_64bit
+        else
+          second_cmp;
+      end;
+
+begin
+  caddnode:=TZ80AddNode;
+end.

+ 71 - 0
compiler/z80/nz80cal.pas

@@ -0,0 +1,71 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Z80 assembler for in call nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nz80cal;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      ncgcal;
+
+    type
+       tz80callnode = class(tcgcallnode)
+       protected
+          procedure pop_parasize(pop_size:longint);override;
+       end;
+
+
+implementation
+
+    uses
+      cpubase,
+      aasmdata,aasmcpu,
+      ncal,
+      cgobj;
+
+
+{*****************************************************************************
+                             TZ80CALLNODE
+*****************************************************************************}
+
+
+    procedure tz80callnode.pop_parasize(pop_size:longint);
+      begin
+        if pop_size>=2 then
+          begin
+            cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+            while pop_size>=2 do
+              begin
+                current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_POP,NR_AF));
+                dec(pop_size,2);
+              end;
+            cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+          end;
+        if pop_size=1 then
+          current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_INC,NR_SP));
+      end;
+
+
+begin
+   ccallnode:=tz80callnode;
+end.

+ 156 - 0
compiler/z80/nz80mat.pas

@@ -0,0 +1,156 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Z80 assembler for math nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nz80mat;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,nmat,ncgmat;
+
+    type
+
+      { tz80notnode }
+
+      tz80notnode = class(tcgnotnode)
+      protected
+        procedure second_boolean;override;
+      end;
+
+
+implementation
+
+    uses
+      globtype,systems,constexp,
+      cutils,verbose,globals,
+      symconst,symdef,aasmbase,aasmtai,aasmdata,aasmcpu,defutil,
+      cgbase,pass_2,
+      ncon,
+      cpubase,cpuinfo,
+      ncgutil,cgobj,cgutils,
+      hlcgobj;
+
+{*****************************************************************************
+                                tz80notnode
+*****************************************************************************}
+
+
+    procedure tz80notnode.second_boolean;
+      var
+        i: Integer;
+      begin
+        if not handle_locjump then
+          begin
+            { the second pass could change the location of left }
+            { if it is a register variable, so we've to do      }
+            { this before the case statement                    }
+            secondpass(left);
+
+            if left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
+              hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,false);
+            case left.location.loc of
+              LOC_FLAGS :
+                begin
+                  location_reset(location,LOC_FLAGS,OS_NO);
+                  location.resflags:=left.location.resflags;
+                  inverse_flags(location.resflags);
+                end;
+(*              LOC_CREFERENCE,
+              LOC_REFERENCE:
+                begin
+ {$if defined(cpu32bitalu)}
+                  if is_64bit(resultdef) then
+                    begin
+                      hreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_32);
+                      tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,left.location.reference);
+                      cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.reference,hreg);
+                      inc(left.location.reference.offset,4);
+                      cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.reference,hreg);
+                    end
+                  else
+ {$elseif defined(cpu16bitalu)}
+                  if is_64bit(resultdef) then
+                    begin
+                      hreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_16);
+                      tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,left.location.reference);
+                      cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,left.location.reference,hreg);
+                      inc(left.location.reference.offset,2);
+                      cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_16,left.location.reference,hreg);
+                      inc(left.location.reference.offset,2);
+                      cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_16,left.location.reference,hreg);
+                      inc(left.location.reference.offset,2);
+                      cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_16,left.location.reference,hreg);
+                    end
+                  else if is_32bit(resultdef) then
+                    begin
+                      hreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_16);
+                      tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,left.location.reference);
+                      cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_16,OS_16,left.location.reference,hreg);
+                      inc(left.location.reference.offset,2);
+                      cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_16,left.location.reference,hreg);
+                    end
+                  else
+ {$endif}
+                    emit_const_ref(A_CMP, TCGSize2Opsize[opsize], 0, left.location.reference);
+                  location_reset(location,LOC_FLAGS,OS_NO);
+                  location.resflags:=F_E;
+                end;*)
+              LOC_CONSTANT,
+              LOC_REGISTER,
+              LOC_CREGISTER,
+              LOC_SUBSETREG,
+              LOC_CSUBSETREG,
+              LOC_SUBSETREF,
+              LOC_CSUBSETREF :
+                begin
+                  if tcgsize2size[def_cgsize(left.resultdef)]<>tcgsize2size[def_cgsize(resultdef)] then
+                    internalerror(2020042209);
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,false);
+                  if tcgsize2size[def_cgsize(left.resultdef)]=1 then
+                    begin
+                      cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,left.location.register,NR_A);
+                      current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_OR,NR_A,NR_A));
+                      cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    end
+                  else
+                    begin
+                      cg.getcpuregister(current_asmdata.CurrAsmList,NR_A);
+                      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,left.location.register,NR_A);
+                      for i:=1 to tcgsize2size[def_cgsize(left.resultdef)]-1 do
+                        current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(A_OR,NR_A,cg.GetOffsetReg64(left.location.register,left.location.registerhi,i)));
+                      cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_A);
+                    end;
+                  location_reset(location,LOC_FLAGS,OS_NO);
+                  location.resflags:=F_E;
+                end;
+              else
+                internalerror(2020042208);
+            end;
+          end;
+      end;
+
+
+begin
+   cnotnode:=tz80notnode;
+end.

+ 71 - 0
compiler/z80/nz80mem.pas

@@ -0,0 +1,71 @@
+{
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    Generate Z80 assembler for in memory related nodes
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nz80mem;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cgbase,cpubase,
+      nmem,ncgmem;
+
+    type
+
+       { tz80loadparentfpnode }
+
+       tz80loadparentfpnode = class(tcgloadparentfpnode)
+         procedure pass_generate_code;override;
+       end;
+
+implementation
+
+    uses
+      aasmdata,aasmcpu,
+      cgobj;
+
+
+{*****************************************************************************
+                            TZ80LOADPARENTFPNODE
+*****************************************************************************}
+
+      procedure tz80loadparentfpnode.pass_generate_code;
+        begin
+          inherited pass_generate_code;
+          if (location.loc=LOC_REGISTER) and ((location.register=NR_IX) or (location.register=NR_IY)) then
+            begin
+              cg.getcpuregister(current_asmdata.CurrAsmList,NR_H);
+              cg.getcpuregister(current_asmdata.CurrAsmList,NR_L);
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_PUSH,location.register));
+              current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_POP,NR_HL));
+              location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_16);
+              cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,NR_L,location.register);
+              cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_L);
+              cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_8,OS_8,NR_H,GetNextReg(location.register));
+              cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_H);
+            end;
+        end;
+
+
+begin
+  cloadparentfpnode:=tz80loadparentfpnode;
+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.

+ 2390 - 0
compiler/z80/raz80asm.pas

@@ -0,0 +1,2390 @@
+{
+    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
+      cclasses,
+      globtype,
+      rasm,raz80,
+      aasmbase,cpubase;
+
+    type
+      tasmtoken = (
+        AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_INTNUM,
+        AS_REALNUM,AS_COMMA,AS_LPAREN,
+        AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,
+        AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_CONDITION,AS_SLASH,AS_DOLLAR,
+        AS_HASH,AS_LSBRACKET,AS_RSBRACKET,AS_LBRACKET,AS_RBRACKET,
+        AS_EQUAL,
+        {------------------ Assembler directives --------------------}
+        AS_DEFB,AS_DEFW,AS_END,
+        {------------------ Assembler Operators  --------------------}
+        AS_TYPE,AS_SIZEOF,AS_VMTOFFSET,AS_MOD,AS_SHL,AS_SHR,AS_NOT,AS_AND,AS_OR,AS_XOR,AS_NOR,AS_AT,
+        AS_RELTYPE, // common token for relocation types
+        {------------------ Target-specific directive ---------------}
+        AS_TARGET_DIRECTIVE
+        );
+      tasmkeyword = string[10];
+
+    const
+      { These tokens should be modified accordingly to the modifications }
+      { in the different enumerations.                                   }
+      firstdirective = AS_DEFB;
+      lastdirective  = AS_END;
+      token2str : array[tasmtoken] of tasmkeyword=(
+        '','Label','LLabel','string','integer',
+        'float',',','(',
+        ')',':','.','+','-','*',
+        ';','identifier','register','opcode','condition','/','$',
+        '#','{','}','[',']',
+        '=',
+        'defb','defw','END',
+        'TYPE','SIZEOF','VMTOFFSET','%','<<','>>','!','&','|','^','~','@','reltype',
+        'directive');
+
+    type
+      { input flags for BuildConstSymbolExpression }
+      tconstsymbolexpressioninputflag = (
+        cseif_needofs,
+        cseif_isref,
+        cseif_startingminus,
+        { allows using full reference-like syntax for constsymbol expressions,
+          for example:
+          Rec.Str[5]  ->  Rec.Str+5 }
+        cseif_referencelike
+      );
+      tconstsymbolexpressioninputflags = set of tconstsymbolexpressioninputflag;
+      { output flags for BuildConstSymbolExpression }
+      tconstsymbolexpressionoutputflag = (
+        cseof_isseg,
+        cseof_is_farproc_entry,
+        cseof_hasofs
+      );
+      tconstsymbolexpressionoutputflags = set of tconstsymbolexpressionoutputflag;
+
+      { tz80reader }
+
+      tz80reader = class(tasmreader)
+        actasmcond : TAsmCond;
+        actasmpattern_origcase : string;
+        actasmtoken   : tasmtoken;
+        prevasmtoken  : tasmtoken;
+        inexpression : boolean;
+        procedure SetupTables;
+        procedure GetToken;
+        function consume(t : tasmtoken):boolean;
+        procedure RecoverConsume(allowcomma:boolean);
+        procedure AddReferences(dest,src : tz80operand);
+        function is_locallabel(const s:string):boolean;
+        function is_asmopcode(const s: string):boolean;
+        Function is_asmdirective(const s: string):boolean;
+        function is_register(const s:string):boolean;
+        function is_condition(const s:string):boolean;
+        function is_targetdirective(const s: string):boolean;
+        procedure BuildRecordOffsetSize(const expr: string;out offset:tcgint;out size:tcgint; out mangledname: string; needvmtofs: boolean; out hastypecast: boolean);
+        procedure BuildConstSymbolExpression(in_flags: tconstsymbolexpressioninputflags;out value:tcgint;out asmsym:string;out asmsymtyp:TAsmsymtype;out size:tcgint;out out_flags:tconstsymbolexpressionoutputflags);
+        function BuildConstExpression:longint;
+        function BuildRefConstExpression(out size:tcgint;startingminus:boolean=false):longint;
+        procedure BuildConstantOperand(oper: tz80operand);
+        procedure BuildReference(oper : tz80operand);
+        procedure BuildOperand(oper: tz80operand;istypecast:boolean);
+        procedure BuildOpCode(instr:TZ80Instruction);
+        procedure handleopcode;
+        procedure ConvertCalljmp(instr : tz80instruction);
+        function Assemble: tlinkedlist;override;
+      end;
+
+
+  Implementation
+
+    uses
+      { helpers }
+      cutils,
+      { global }
+      globals,verbose,
+      systems,
+      { aasm }
+      cpuinfo,aasmtai,aasmdata,aasmcpu,
+      { symtable }
+      symconst,symbase,symtype,symsym,symtable,symdef,symutil,
+      { parser }
+      scanner,pbase,
+      procinfo,
+      rabase,rautils,
+      cgbase,cgutils,cgobj
+      ;
+
+
+{*****************************************************************************
+                                tz80reader
+*****************************************************************************}
+
+
+    procedure tz80reader.SetupTables;
+      var
+        i: TAsmOp;
+      begin
+        iasmops:=TFPHashList.create;
+        for i:=firstop to lastop do
+          iasmops.Add(upper(std_op2str[i]),Pointer(PtrInt(i)));
+      end;
+
+
+    procedure tz80reader.GetToken;
+      var
+        len: Integer;
+        srsym : tsym;
+        srsymtable : TSymtable;
+        can_be_condition : Boolean;
+      begin
+        c:=scanner.c;
+        { certain instructions can have a condition, as an operand. We need to set this flag,
+          because 'C' can be either a register, or a condition, depending on the context }
+        can_be_condition:=(actasmtoken=AS_OPCODE) and (actopcode in [A_JP,A_JR,A_CALL,A_RET]);
+        { save old token and reset new token }
+        prevasmtoken:=actasmtoken;
+        actasmtoken:=AS_NONE;
+        { reset }
+        actasmpattern:='';
+        { while space and tab , continue scan... }
+        while c in [' ',#9] do
+          c:=current_scanner.asmgetchar;
+        { get token pos }
+        if not (c in [#10,#13,'{',';','/','(']) then
+          current_scanner.gettokenpos;
+        { Local Label, Label, Directive, Prefix or Opcode }
+        if firsttoken and not(c in [#10,#13,'{',';','/','(']) then
+          begin
+            firsttoken:=FALSE;
+            len:=0;
+            { directive }
+            if c = '.' then
+              begin
+                inc(len);
+                actasmpattern[len]:=c;
+                { Let us point to the next character }
+                c:=current_scanner.asmgetchar;
+                while c in ['A'..'Z','a'..'z','0'..'9','_','$'] do
+                  begin
+                    inc(len);
+                    actasmpattern[len]:=c;
+                    c:=current_scanner.asmgetchar;
+                  end;
+                actasmpattern[0]:=chr(len);
+                { must be a directive }
+                if is_asmdirective(actasmpattern) then
+                 exit;
+                if is_targetdirective(actasmpattern) then
+                  begin
+                    actasmtoken:=AS_TARGET_DIRECTIVE;
+                    exit;
+                  end;
+                Message1(asmr_e_not_directive_or_local_symbol,actasmpattern);
+              end;
+            { only opcodes, global and local labels are allowed now. }
+            while c in ['A'..'Z','a'..'z','0'..'9','_','@'] do
+              begin
+                inc(len);
+                actasmpattern[len]:=c;
+                c:=current_scanner.asmgetchar;
+              end;
+            actasmpattern[0]:=chr(len);
+            actasmpattern_origcase:=actasmpattern;
+            { Label ? }
+            if c = ':' then
+              begin
+                { Local label ? }
+                if is_locallabel(actasmpattern) then
+                  actasmtoken:=AS_LLABEL
+                else
+                  actasmtoken:=AS_LABEL;
+                { let us point to the next character }
+                c:=current_scanner.asmgetchar;
+                firsttoken:=true;
+                exit;
+              end;
+            { Opcode ? }
+            if is_asmopcode(upper(actasmpattern)) then
+              begin
+                uppervar(actasmpattern);
+                exit;
+              end;
+            { End of assemblerblock ? }
+            if upper(actasmpattern) = 'END' then
+              begin
+                actasmtoken:=AS_END;
+                exit;
+              end;
+            message1(asmr_e_unknown_opcode,actasmpattern);
+            actasmtoken:=AS_NONE;
+          end
+        else { else firsttoken }
+          { Here we must handle all possible cases }
+          begin
+            case c of
+              '.' :  { possiblities : - local label reference , such as in jmp @local1 }
+                     {               - field of object/record                         }
+                     {               - directive.                                     }
+                begin
+                  if (prevasmtoken in [AS_ID,AS_RPAREN]) then
+                   begin
+                     c:=current_scanner.asmgetchar;
+                     actasmtoken:=AS_DOT;
+                     exit;
+                   end;
+                  actasmpattern:=c;
+                  c:=current_scanner.asmgetchar;
+                  while c in  ['A'..'Z','a'..'z','0'..'9','_','$'] do
+                   begin
+                     actasmpattern:=actasmpattern + c;
+                     c:=current_scanner.asmgetchar;
+                   end;
+                  if is_asmdirective(actasmpattern) then
+                   exit;
+                  if is_targetdirective(actasmpattern) then
+                    begin
+                      actasmtoken:=AS_TARGET_DIRECTIVE;
+                      exit;
+                    end;
+                  { local label references and directives }
+                  { are case sensitive                    }
+                  actasmtoken:=AS_ID;
+                  exit;
+                end;
+
+           { identifier, register, prefix or directive }
+              '_','A'..'Z','a'..'z':
+                begin
+                  len:=0;
+                  while c in ['A'..'Z','a'..'z','0'..'9','_','$'] do
+                   begin
+                     inc(len);
+                     actasmpattern[len]:=c;
+                     c:=current_scanner.asmgetchar;
+                   end;
+                  actasmpattern[0]:=chr(len);
+                  actasmpattern_origcase:=actasmpattern;
+                  uppervar(actasmpattern);
+ {$ifdef x86}
+                  { only x86 architectures have instruction prefixes }
+
+                  { Opcode, can only be when the previous was a prefix }
+                  If is_prefix(actopcode) and is_asmopcode(actasmpattern) then
+                   Begin
+                     uppervar(actasmpattern);
+                     exit;
+                   end;
+ {$endif x86}
+                  { check for end which is a reserved word unlike the opcodes }
+                  if actasmpattern = 'END' then
+                    begin
+                      actasmtoken:=AS_END;
+                      exit;
+                    end;
+                  if actasmpattern = 'TYPE' then
+                    begin
+                      actasmtoken:=AS_TYPE;
+                      exit;
+                    end;
+                  if actasmpattern = 'SIZEOF' then
+                    begin
+                      actasmtoken:=AS_SIZEOF;
+                      exit;
+                    end;
+                  if actasmpattern = 'VMTOFFSET' then
+                    begin
+                      actasmtoken:=AS_VMTOFFSET;
+                      exit;
+                    end;
+                  if can_be_condition and is_condition(actasmpattern) then
+                    begin
+                      actasmtoken:=AS_CONDITION;
+                      exit;
+                    end;
+                  if is_register(actasmpattern) then
+                    begin
+                      actasmtoken:=AS_REGISTER;
+                      exit;
+                    end;
+                  { if next is a '.' and this is a unitsym then we also need to
+                    parse the identifier }
+                  if (c='.') then
+                   begin
+                     searchsym(actasmpattern,srsym,srsymtable);
+                     if assigned(srsym) and
+                        (srsym.typ=unitsym) and
+                        (srsym.owner.symtabletype in [staticsymtable,globalsymtable]) and
+                        srsym.owner.iscurrentunit then
+                      begin
+                        actasmpattern:=actasmpattern+c;
+                        c:=current_scanner.asmgetchar;
+                        while c in  ['A'..'Z','a'..'z','0'..'9','_','$'] do
+                         begin
+                           actasmpattern:=actasmpattern + upcase(c);
+                           c:=current_scanner.asmgetchar;
+                         end;
+                      end;
+                   end;
+                  actasmtoken:=AS_ID;
+                  exit;
+                end;
+
+              //'%' : { register or modulo }
+              //  handlepercent;
+
+              '1'..'9': { integer number }
+                begin
+                  len:=0;
+                  while c in ['0'..'9'] do
+                   Begin
+                     inc(len);
+                     actasmpattern[len]:=c;
+                     c:=current_scanner.asmgetchar;
+                   end;
+                  actasmpattern[0]:=chr(len);
+                  actasmpattern:=tostr(ParseVal(actasmpattern,10));
+                  actasmtoken:=AS_INTNUM;
+                  exit;
+                end;
+              '0' : { octal,hexa,real or binary number. }
+                begin
+                  actasmpattern:=c;
+                  c:=current_scanner.asmgetchar;
+                  case upcase(c) of
+                    'B': { binary }
+                      Begin
+                        c:=current_scanner.asmgetchar;
+                        while c in ['0','1'] do
+                         Begin
+                           actasmpattern:=actasmpattern + c;
+                           c:=current_scanner.asmgetchar;
+                         end;
+                        actasmpattern:=tostr(ParseVal(actasmpattern,2));
+                        actasmtoken:=AS_INTNUM;
+                        exit;
+                      end;
+                    'D': { real }
+                      Begin
+                        c:=current_scanner.asmgetchar;
+                        { get ridd of the 0d }
+                        if (c in ['+','-']) then
+                         begin
+                           actasmpattern:=c;
+                           c:=current_scanner.asmgetchar;
+                         end
+                        else
+                         actasmpattern:='';
+                        while c in ['0'..'9'] do
+                         Begin
+                           actasmpattern:=actasmpattern + c;
+                           c:=current_scanner.asmgetchar;
+                         end;
+                        if c='.' then
+                         begin
+                           actasmpattern:=actasmpattern + c;
+                           c:=current_scanner.asmgetchar;
+                           while c in ['0'..'9'] do
+                            Begin
+                              actasmpattern:=actasmpattern + c;
+                              c:=current_scanner.asmgetchar;
+                            end;
+                           if upcase(c) = 'E' then
+                            begin
+                              actasmpattern:=actasmpattern + c;
+                              c:=current_scanner.asmgetchar;
+                              if (c in ['+','-']) then
+                               begin
+                                 actasmpattern:=actasmpattern + c;
+                                 c:=current_scanner.asmgetchar;
+                               end;
+                              while c in ['0'..'9'] do
+                               Begin
+                                 actasmpattern:=actasmpattern + c;
+                                 c:=current_scanner.asmgetchar;
+                               end;
+                            end;
+                           actasmtoken:=AS_REALNUM;
+                           exit;
+                         end
+                        else
+                         begin
+                           Message1(asmr_e_invalid_float_const,actasmpattern+c);
+                           actasmtoken:=AS_NONE;
+                         end;
+                      end;
+                    'X': { hexadecimal }
+                      Begin
+                        c:=current_scanner.asmgetchar;
+                        while c in ['0'..'9','a'..'f','A'..'F'] do
+                         Begin
+                           actasmpattern:=actasmpattern + c;
+                           c:=current_scanner.asmgetchar;
+                         end;
+                        actasmpattern:=tostr(ParseVal(actasmpattern,16));
+                        actasmtoken:=AS_INTNUM;
+                        exit;
+                      end;
+                    '1'..'7': { octal }
+                      begin
+                        actasmpattern:=actasmpattern + c;
+                        while c in ['0'..'7'] do
+                         Begin
+                           actasmpattern:=actasmpattern + c;
+                           c:=current_scanner.asmgetchar;
+                         end;
+                        actasmpattern:=tostr(ParseVal(actasmpattern,8));
+                        actasmtoken:=AS_INTNUM;
+                        exit;
+                      end;
+                    else { octal number zero value...}
+                      Begin
+                        actasmpattern:=tostr(ParseVal(actasmpattern,8));
+                        actasmtoken:=AS_INTNUM;
+                        exit;
+                      end;
+                  end; { end case }
+                end;
+
+              '&' :
+                begin
+                  c:=current_scanner.asmgetchar;
+                  actasmtoken:=AS_AND;
+                end;
+
+              '''' : { char }
+                begin
+                  actasmpattern:='';
+                  repeat
+                    c:=current_scanner.asmgetchar;
+                    case c of
+                      '\' :
+                        begin
+                          { copy also the next char so \" is parsed correctly }
+                          actasmpattern:=actasmpattern+c;
+                          c:=current_scanner.asmgetchar;
+                          actasmpattern:=actasmpattern+c;
+                        end;
+                      '''' :
+                        begin
+                          c:=current_scanner.asmgetchar;
+                          break;
+                        end;
+                      #10,#13:
+                        Message(scan_f_string_exceeds_line);
+                      else
+                        actasmpattern:=actasmpattern+c;
+                    end;
+                  until false;
+                  actasmpattern:=EscapeToPascal(actasmpattern);
+                  actasmtoken:=AS_STRING;
+                  exit;
+                end;
+
+              '"' : { string }
+                begin
+                  actasmpattern:='';
+                  repeat
+                    c:=current_scanner.asmgetchar;
+                    case c of
+                      '\' :
+                        begin
+                          { copy also the next char so \" is parsed correctly }
+                          actasmpattern:=actasmpattern+c;
+                          c:=current_scanner.asmgetchar;
+                          actasmpattern:=actasmpattern+c;
+                        end;
+                      '"' :
+                        begin
+                          c:=current_scanner.asmgetchar;
+                          break;
+                        end;
+                      #10,#13:
+                        Message(scan_f_string_exceeds_line);
+                      else
+                        actasmpattern:=actasmpattern+c;
+                    end;
+                  until false;
+                  actasmpattern:=EscapeToPascal(actasmpattern);
+                  actasmtoken:=AS_STRING;
+                  exit;
+                end;
+
+              //'$' :
+              //  begin
+              //    handledollar;
+              //    exit;
+              //  end;
+
+              '#' :
+                begin
+                  actasmtoken:=AS_HASH;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '[' :
+                begin
+                  actasmtoken:=AS_LBRACKET;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              ']' :
+                begin
+                  actasmtoken:=AS_RBRACKET;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '{' :
+                begin
+ {$ifdef arm}
+                  // the arm assembler uses { ... } for register sets
+                  // but compiler directives {$... } are still allowed
+                  c:=current_scanner.asmgetchar;
+                  if c<>'$' then
+                    actasmtoken:=AS_LSBRACKET
+                  else
+                    begin
+                      current_scanner.skipcomment(false);
+                      GetToken;
+                    end;
+ {$else arm}
+                  current_scanner.skipcomment(true);
+                  GetToken;
+ {$endif arm}
+                  exit;
+                end;
+
+ {$ifdef arm}
+              '}' :
+                begin
+                  actasmtoken:=AS_RSBRACKET;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '=' :
+                begin
+                  actasmtoken:=AS_EQUAL;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+ {$endif arm}
+
+              ',' :
+                begin
+                  actasmtoken:=AS_COMMA;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '<' :
+                begin
+                  actasmtoken:=AS_SHL;
+                  c:=current_scanner.asmgetchar;
+                  if c = '<' then
+                   c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '>' :
+                begin
+                  actasmtoken:=AS_SHL;
+                  c:=current_scanner.asmgetchar;
+                  if c = '>' then
+                   c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '|' :
+                begin
+                  actasmtoken:=AS_OR;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '^' :
+                begin
+                  actasmtoken:=AS_XOR;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+
+              '(' :
+                begin
+                  c:=current_scanner.asmgetchar;
+                  if c='*' then
+                    begin
+                      current_scanner.skipoldtpcomment(true);
+                      GetToken;
+                    end
+                  else
+                    actasmtoken:=AS_LPAREN;
+                  exit;
+                end;
+
+              ')' :
+                begin
+                  actasmtoken:=AS_RPAREN;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              ':' :
+                begin
+                  actasmtoken:=AS_COLON;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '+' :
+                begin
+                  actasmtoken:=AS_PLUS;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '-' :
+                begin
+                  actasmtoken:=AS_MINUS;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '*' :
+                begin
+                  actasmtoken:=AS_STAR;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '/' :
+                begin
+                  c:=current_scanner.asmgetchar;
+                  if c='/' then
+                    begin
+                      current_scanner.skipdelphicomment;
+                      GetToken;
+                    end
+                  else
+                    actasmtoken:=AS_SLASH;
+                  exit;
+                end;
+
+              '!', '~' :
+                begin
+                  actasmtoken:=AS_NOT;
+                  c:=current_scanner.asmgetchar;
+                  exit;
+                end;
+
+              '@' : { possiblities : - local label reference , such as in jmp @local1 }
+                    {                - @Result, @Code or @Data special variables.     }
+                begin
+                  actasmpattern:=c;
+                  c:=current_scanner.asmgetchar;
+                  while c in  ['A'..'Z','a'..'z','0'..'9','_','@','$','&','?'] do
+                   begin
+                     actasmpattern:=actasmpattern + c;
+                     c:=current_scanner.asmgetchar;
+                   end;
+                  actasmpattern_origcase:=actasmpattern;
+                  uppervar(actasmpattern);
+                  actasmtoken:=AS_ID;
+                  exit;
+                end;
+
+              #13,#10:
+                begin
+                  current_scanner.linebreak;
+                  c:=current_scanner.asmgetchar;
+                  firsttoken:=TRUE;
+                  actasmtoken:=AS_SEPARATOR;
+                  exit;
+                end;
+
+              ';' :
+                begin
+                  c:=current_scanner.asmgetchar;
+                  firsttoken:=TRUE;
+                  actasmtoken:=AS_SEPARATOR;
+                  exit;
+                end;
+
+              else
+                current_scanner.illegal_char(c);
+            end;
+          end;
+      end;
+
+
+    function tz80reader.consume(t: tasmtoken): boolean;
+      begin
+        Consume:=true;
+        if t<>actasmtoken then
+         begin
+           Message2(scan_f_syn_expected,token2str[t],token2str[actasmtoken]);
+           Consume:=false;
+         end;
+        repeat
+          gettoken;
+        until actasmtoken<>AS_NONE;
+      end;
+
+
+    procedure tz80reader.RecoverConsume(allowcomma: boolean);
+      begin
+        while not (actasmtoken in [AS_SEPARATOR,AS_END]) do
+          begin
+            if allowcomma and (actasmtoken=AS_COMMA) then
+             break;
+            Consume(actasmtoken);
+          end;
+      end;
+
+
+    procedure tz80reader.AddReferences(dest, src: tz80operand);
+
+      procedure AddRegister(reg:tregister;scalefactor:byte);
+        begin
+          if reg=NR_NO then
+            exit;
+          if (dest.opr.ref.base=NR_NO) and (scalefactor=1) then
+            begin
+              dest.opr.ref.base:=reg;
+              exit;
+            end;
+          if dest.opr.ref.index=NR_NO then
+            begin
+              dest.opr.ref.index:=reg;
+              dest.opr.ref.scalefactor:=scalefactor;
+              exit;
+            end;
+          if dest.opr.ref.index=reg then
+            begin
+              Inc(dest.opr.ref.scalefactor,scalefactor);
+              exit;
+            end;
+          Message(asmr_e_multiple_index);
+        end;
+
+      var
+        tmplocal: TOprRec;
+        segreg: TRegister;
+      begin
+        case dest.opr.typ of
+          OPR_REFERENCE:
+            begin
+              case src.opr.typ of
+                OPR_REFERENCE:
+                  begin
+                    AddRegister(src.opr.ref.base,1);
+                    AddRegister(src.opr.ref.index,src.opr.ref.scalefactor);
+                    Inc(dest.opr.ref.offset,src.opr.ref.offset);
+                    Inc(dest.opr.constoffset,src.opr.constoffset);
+                    dest.haslabelref:=dest.haslabelref or src.haslabelref;
+                    dest.hasproc:=dest.hasproc or src.hasproc;
+                    dest.hasvar:=dest.hasvar or src.hasvar;
+                    if assigned(src.opr.ref.symbol) then
+                      begin
+                        if assigned(dest.opr.ref.symbol) then
+                          Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                        dest.opr.ref.symbol:=src.opr.ref.symbol;
+                      end;
+                    if assigned(src.opr.ref.relsymbol) then
+                      begin
+                        if assigned(dest.opr.ref.relsymbol) then
+                          Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                        dest.opr.ref.relsymbol:=src.opr.ref.relsymbol;
+                      end;
+                    if dest.opr.ref.refaddr=addr_no then
+                      dest.opr.ref.refaddr:=src.opr.ref.refaddr;
+                  end;
+                OPR_LOCAL:
+                  begin
+                    tmplocal:=src.opr;
+                    if dest.opr.ref.base<>NR_NO then
+                      begin
+                        if tmplocal.localindexreg=NR_NO then
+                          begin
+                            tmplocal.localindexreg:=dest.opr.ref.base;
+                            tmplocal.localscale:=0;
+                          end
+                        else if tmplocal.localindexreg=dest.opr.ref.base then
+                          tmplocal.localscale:=Min(tmplocal.localscale,1)+1
+                        else
+                          Message(asmr_e_multiple_index);
+                      end;
+                    if dest.opr.ref.index<>NR_NO then
+                      begin
+                        if tmplocal.localindexreg=NR_NO then
+                          begin
+                            tmplocal.localindexreg:=dest.opr.ref.index;
+                            tmplocal.localscale:=dest.opr.ref.scalefactor;
+                          end
+                        else if tmplocal.localindexreg=dest.opr.ref.index then
+                          tmplocal.localscale:=Min(tmplocal.localscale,1)+Min(dest.opr.ref.scalefactor,1)
+                        else
+                          Message(asmr_e_multiple_index);
+                      end;
+                    Inc(tmplocal.localconstoffset,dest.opr.constoffset);
+                    Inc(tmplocal.localsymofs,dest.opr.ref.offset);
+                    dest.opr:=tmplocal;
+                  end;
+                else
+                  internalerror(2018030701);
+              end;
+            end;
+          OPR_LOCAL:
+            begin
+              case src.opr.typ of
+                OPR_REFERENCE:
+                  begin
+                    if src.opr.ref.base<>NR_NO then
+                      begin
+                        if dest.opr.localindexreg=NR_NO then
+                          begin
+                            dest.opr.localindexreg:=src.opr.ref.base;
+                            dest.opr.localscale:=0;
+                          end
+                        else if dest.opr.localindexreg=src.opr.ref.base then
+                          dest.opr.localscale:=Min(dest.opr.localscale,1)+1
+                        else
+                          Message(asmr_e_multiple_index);
+                      end;
+                    if src.opr.ref.index<>NR_NO then
+                      begin
+                        if dest.opr.localindexreg=NR_NO then
+                          begin
+                            dest.opr.localindexreg:=src.opr.ref.index;
+                            dest.opr.localscale:=src.opr.ref.scalefactor;
+                          end
+                        else if dest.opr.localindexreg=src.opr.ref.index then
+                          dest.opr.localscale:=Min(dest.opr.localscale,1)+Min(src.opr.ref.scalefactor,1)
+                        else
+                          Message(asmr_e_multiple_index);
+                      end;
+                    Inc(dest.opr.localconstoffset,src.opr.constoffset);
+                    Inc(dest.opr.localsymofs,src.opr.ref.offset);
+                  end;
+                OPR_LOCAL:
+                  Message(asmr_e_no_local_or_para_allowed);
+                else
+                  internalerror(2018030703);
+              end;
+            end;
+          else
+            internalerror(2018030702);
+        end;
+      end;
+
+
+    function tz80reader.is_locallabel(const s: string): boolean;
+      begin
+        is_locallabel:=(length(s)>1) and (s[1]='@');
+      end;
+
+
+    function tz80reader.is_asmopcode(const s: string):boolean;
+      begin
+        actcondition:=C_None;
+        actopcode:=tasmop(PtrUInt(iasmops.Find(s)));
+        if actopcode<>A_NONE then
+          begin
+            actasmtoken:=AS_OPCODE;
+            is_asmopcode:=true;
+          end
+        else
+          is_asmopcode:=false;
+      end;
+
+
+    function tz80reader.is_asmdirective(const s: string): boolean;
+      var
+        i : tasmtoken;
+        hs : string;
+      begin
+        hs:=lower(s);
+        for i:=firstdirective to lastdirective do
+         if hs=token2str[i] then
+          begin
+            actasmtoken:=i;
+            is_asmdirective:=true;
+            exit;
+          end;
+        is_asmdirective:=false;
+      end;
+
+
+    function tz80reader.is_register(const s:string):boolean;
+      begin
+        is_register:=false;
+        actasmregister:=std_regnum_search(lower(s));
+        if actasmregister<>NR_NO then
+          begin
+            is_register:=true;
+            actasmtoken:=AS_REGISTER;
+          end;
+      end;
+
+
+    function tz80reader.is_condition(const s: string): boolean;
+      var
+        condstr: string;
+        cond: TAsmCond;
+      begin
+        is_condition:=false;
+        actasmcond:=C_None;
+        condstr:=lower(s);
+        for cond in TAsmCond do
+          if (cond<>C_None) and (cond2str[cond]=condstr) then
+            begin
+              is_condition:=true;
+              actasmtoken:=AS_CONDITION;
+              actasmcond:=cond;
+              exit;
+            end;
+      end;
+
+
+    function tz80reader.is_targetdirective(const s: string): boolean;
+      begin
+        result:=false;
+      end;
+
+    procedure tz80reader.BuildRecordOffsetSize(const expr: string; out
+        offset: tcgint; out size: tcgint; out mangledname: string;
+        needvmtofs: boolean; out hastypecast: boolean);
+      var
+        s: string;
+      Begin
+        offset:=0;
+        size:=0;
+        mangledname:='';
+        hastypecast:=false;
+        s:=expr;
+        while (actasmtoken=AS_DOT) do
+         begin
+           Consume(AS_DOT);
+           if actasmtoken in [AS_ID,AS_REGISTER] then
+             begin
+               s:=s+'.'+actasmpattern;
+               consume(actasmtoken);
+             end
+           else
+            begin
+              Consume(AS_ID);
+              RecoverConsume(true);
+              break;
+            end;
+         end;
+        if not GetRecordOffsetSize(s,offset,size,mangledname,needvmtofs,hastypecast) then
+          Message(asmr_e_building_record_offset);
+      end;
+
+    procedure tz80reader.BuildConstSymbolExpression(
+        in_flags: tconstsymbolexpressioninputflags; out value: tcgint; out
+        asmsym: string; out asmsymtyp: TAsmsymtype; out size: tcgint; out
+        out_flags: tconstsymbolexpressionoutputflags);
+      var
+        tempstr,expr,hs,mangledname : string;
+        parenlevel : longint;
+        l,k : tcgint;
+        hasparen,
+        errorflag,
+        needvmtofs : boolean;
+        prevtok : tasmtoken;
+        hl : tasmlabel;
+        hssymtyp : Tasmsymtype;
+        def : tdef;
+        sym : tsym;
+        srsymtable : TSymtable;
+        hastypecast : boolean;
+      Begin
+        { reset }
+        value:=0;
+        asmsym:='';
+        asmsymtyp:=AT_DATA;
+        size:=0;
+        out_flags:=[];
+        errorflag:=FALSE;
+        tempstr:='';
+        expr:='';
+        if cseif_startingminus in in_flags then
+          expr:='-';
+        inexpression:=TRUE;
+        parenlevel:=0;
+        sym:=nil;
+        needvmtofs:=FALSE;
+        Repeat
+          { Support ugly delphi constructs like: [ECX].1+2[EDX] }
+          if (cseif_isref in in_flags) and (actasmtoken=AS_LBRACKET) then
+            break;
+          if (cseif_referencelike in in_flags) and
+             (actasmtoken in [AS_LBRACKET,AS_RBRACKET]) then
+            case actasmtoken of
+              AS_LBRACKET:
+                begin
+                  Consume(AS_LBRACKET);
+                  if (length(expr)>0) and
+                     not (expr[length(expr)] in ['+','-']) then
+                    expr:=expr+'+';
+                  expr:=expr+'[';
+                end;
+              AS_RBRACKET:
+                begin
+                  Consume(AS_RBRACKET);
+                  expr:=expr+']';
+                end;
+              else
+                ;
+            end;
+          Case actasmtoken of
+            AS_LPAREN:
+              Begin
+                Consume(AS_LPAREN);
+                expr:=expr + '(';
+                inc(parenlevel);
+              end;
+            AS_RPAREN:
+              Begin
+                { Keep the AS_PAREN in actasmtoken, it is maybe a typecast }
+                if parenlevel=0 then
+                  break;
+                Consume(AS_RPAREN);
+                expr:=expr + ')';
+                dec(parenlevel);
+              end;
+            AS_SHL:
+              Begin
+                Consume(AS_SHL);
+                expr:=expr + '<';
+              end;
+            AS_SHR:
+              Begin
+                Consume(AS_SHR);
+                expr:=expr + '>';
+              end;
+            AS_SLASH:
+              Begin
+                Consume(AS_SLASH);
+                expr:=expr + '/';
+              end;
+            AS_MOD:
+              Begin
+                Consume(AS_MOD);
+                expr:=expr + '%';
+              end;
+            AS_STAR:
+              Begin
+                Consume(AS_STAR);
+                if (cseif_isref in in_flags) and (actasmtoken=AS_REGISTER) then
+                 break;
+                expr:=expr + '*';
+              end;
+            AS_PLUS:
+              Begin
+                Consume(AS_PLUS);
+                if (cseif_isref in in_flags) and ((actasmtoken=AS_REGISTER) or (actasmtoken=AS_LBRACKET)) then
+                 break;
+                expr:=expr + '+';
+              end;
+            AS_MINUS:
+              Begin
+                Consume(AS_MINUS);
+                expr:=expr + '-';
+              end;
+            AS_AND:
+              Begin
+                Consume(AS_AND);
+                expr:=expr + '&';
+              end;
+            AS_NOT:
+              Begin
+                Consume(AS_NOT);
+                expr:=expr + '~';
+              end;
+            AS_XOR:
+              Begin
+                Consume(AS_XOR);
+                expr:=expr + '^';
+              end;
+            AS_OR:
+              Begin
+                Consume(AS_OR);
+                expr:=expr + '|';
+              end;
+            AS_INTNUM:
+              Begin
+                expr:=expr + actasmpattern;
+                Consume(AS_INTNUM);
+              end;
+{$ifdef i8086}
+            AS_SEG:
+              begin
+                include(out_flags,cseof_isseg);
+                Consume(actasmtoken);
+                if actasmtoken<>AS_ID then
+                 Message(asmr_e_seg_without_identifier);
+              end;
+{$endif i8086}
+            AS_VMTOFFSET{,
+            AS_OFFSET}:
+              begin
+                {if (actasmtoken = AS_OFFSET) then
+                  begin
+                    include(in_flags,cseif_needofs);
+                    include(out_flags,cseof_hasofs);
+                  end
+                else}
+                  needvmtofs:=true;
+                Consume(actasmtoken);
+                if actasmtoken<>AS_ID then
+                 Message(asmr_e_offset_without_identifier);
+              end;
+            AS_SIZEOF,
+            AS_TYPE:
+              begin
+                l:=0;
+                hasparen:=false;
+                Consume(actasmtoken);
+                if actasmtoken=AS_LPAREN then
+                  begin
+                    hasparen:=true;
+                    Consume(AS_LPAREN);
+                  end;
+                if actasmtoken<>AS_ID then
+                 Message(asmr_e_type_without_identifier)
+                else
+                 begin
+                   tempstr:=actasmpattern;
+                   Consume(AS_ID);
+                   if actasmtoken=AS_DOT then
+                     begin
+                       BuildRecordOffsetSize(tempstr,k,l,mangledname,false,hastypecast);
+                       if mangledname<>'' then
+                         { procsym }
+                         Message(asmr_e_wrong_sym_type);
+                       if hastypecast then
+
+                     end
+                   else
+                    begin
+                      asmsearchsym(tempstr,sym,srsymtable);
+                      if assigned(sym) then
+                       begin
+                         case sym.typ of
+                           staticvarsym,
+                           localvarsym,
+                           paravarsym :
+                             l:=tabstractvarsym(sym).getsize;
+                           typesym :
+                             l:=ttypesym(sym).typedef.size;
+                           else
+                             Message(asmr_e_wrong_sym_type);
+                         end;
+                       end
+                      else
+                       Message1(sym_e_unknown_id,tempstr);
+                    end;
+                 end;
+                str(l, tempstr);
+                expr:=expr + tempstr;
+                if hasparen then
+                  Consume(AS_RPAREN);
+              end;
+            //AS_PTR :
+            //  begin
+            //    { Support ugly delphi constructs like <constant> PTR [ref] }
+            //    break;
+            //  end;
+            AS_STRING:
+              begin
+                l:=0;
+                case Length(actasmpattern) of
+                 1 :
+                  l:=ord(actasmpattern[1]);
+                 2 :
+                  l:=ord(actasmpattern[2]) + ord(actasmpattern[1]) shl 8;
+                 3 :
+                  l:=ord(actasmpattern[3]) +
+                     Ord(actasmpattern[2]) shl 8 + ord(actasmpattern[1]) shl 16;
+                 4 :
+                  l:=ord(actasmpattern[4]) + ord(actasmpattern[3]) shl 8 +
+                     Ord(actasmpattern[2]) shl 16 + ord(actasmpattern[1]) shl 24;
+                else
+                  Message1(asmr_e_invalid_string_as_opcode_operand,actasmpattern);
+                end;
+                str(l, tempstr);
+                expr:=expr + tempstr;
+                Consume(AS_STRING);
+              end;
+            AS_ID:
+              begin
+                hs:='';
+                hssymtyp:=AT_DATA;
+                def:=nil;
+                tempstr:=actasmpattern;
+                prevtok:=prevasmtoken;
+                { stop parsing a constant expression if we find an opcode after a
+                  non-operator like "db $66 mov eax,ebx" }
+                if (prevtok in [AS_ID,AS_INTNUM,AS_RPAREN]) and
+                   is_asmopcode(actasmpattern) then
+                  break;
+                consume(AS_ID);
+                if (tempstr='@CODE') or (tempstr='@DATA') then
+                 begin
+                   if asmsym='' then
+                     begin
+                       asmsym:=tempstr;
+                       asmsymtyp:=AT_SECTION;
+                     end
+                   else
+                    Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                 end
+                else if SearchIConstant(tempstr,l) then
+                 begin
+                   str(l, tempstr);
+                   expr:=expr + tempstr;
+                 end
+                else
+                 begin
+                   if is_locallabel(tempstr) then
+                    begin
+                      CreateLocalLabel(tempstr,hl,false);
+                      hs:=hl.name;
+                      hssymtyp:=AT_FUNCTION;
+                    end
+                   else
+                    if SearchLabel(tempstr,hl,false) then
+                      begin
+                        hs:=hl.name;
+                        hssymtyp:=AT_FUNCTION;
+                      end
+                   else
+                    begin
+                      asmsearchsym(tempstr,sym,srsymtable);
+                      if assigned(sym) then
+                       begin
+                         case sym.typ of
+                           staticvarsym :
+                             begin
+                               hs:=tstaticvarsym(sym).mangledname;
+                               def:=tstaticvarsym(sym).vardef;
+                             end;
+                           localvarsym,
+                           paravarsym :
+                             begin
+                               Message(asmr_e_no_local_or_para_allowed);
+                             end;
+                           procsym :
+                             begin
+                               if Tprocsym(sym).ProcdefList.Count>1 then
+                                Message(asmr_w_calling_overload_func);
+                               hs:=tprocdef(tprocsym(sym).ProcdefList[0]).mangledname;
+{$ifdef i8086}
+                               if is_proc_far(tprocdef(tprocsym(sym).ProcdefList[0]))
+                                  and not (po_interrupt in tprocdef(tprocsym(sym).ProcdefList[0]).procoptions) then
+                                 include(out_flags,cseof_is_farproc_entry)
+                               else
+                                 exclude(out_flags,cseof_is_farproc_entry);
+{$endif i8086}
+                               hssymtyp:=AT_FUNCTION;
+                             end;
+                           typesym :
+                             begin
+                               if not(ttypesym(sym).typedef.typ in [recorddef,objectdef]) then
+                                Message(asmr_e_wrong_sym_type);
+                               size:=ttypesym(sym).typedef.size;
+                             end;
+                           fieldvarsym :
+                             begin
+                               tempstr:=upper(tdef(sym.owner.defowner).GetTypeName)+'.'+tempstr;
+                             end;
+                           else
+                             Message(asmr_e_wrong_sym_type);
+                         end;
+                       end
+                      else
+                       Message1(sym_e_unknown_id,tempstr);
+                    end;
+                   { symbol found? }
+                   if hs<>'' then
+                    begin
+                      if asmsym='' then
+                        begin
+                          asmsym:=hs;
+                          asmsymtyp:=hssymtyp;
+                        end
+                      else
+                       Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                      if (expr='') or (expr[length(expr)]='+') then
+                       begin
+                         { don't remove the + if there could be a record field }
+                         if actasmtoken<>AS_DOT then
+                          delete(expr,length(expr),1);
+                       end
+                      else
+                       //if (cseif_needofs in in_flags) then
+                       //  begin
+                       //    if (prevtok<>AS_OFFSET) then
+                       //      Message(asmr_e_need_offset);
+                       //  end
+                       //else
+                         Message(asmr_e_only_add_relocatable_symbol);
+                    end;
+                   if (actasmtoken=AS_DOT) or
+                      (assigned(sym) and
+                       is_normal_fieldvarsym(sym)) then
+                     begin
+                      BuildRecordOffsetSize(tempstr,l,size,hs,needvmtofs,hastypecast);
+                      if hs <> '' then
+                        hssymtyp:=AT_FUNCTION
+                      else
+                        begin
+                          str(l, tempstr);
+                          expr:=expr + tempstr;
+                        end
+                    end
+                   else if (actasmtoken<>AS_DOT) and
+                           assigned(sym) and
+                           (sym.typ=typesym) and
+                           (ttypesym(sym).typedef.typ in [recorddef,objectdef]) then
+                     begin
+                       { just a record type (without being followed by dot)
+                         evaluates to 0. Ugly, but TP7 compatible. }
+                       expr:=expr+'0';
+                     end
+                   else
+                    begin
+                      if (expr='') or (expr[length(expr)] in ['+','-','/','*']) then
+                       delete(expr,length(expr),1);
+                    end;
+                   if (actasmtoken=AS_LBRACKET) and
+                      assigned(def) and
+                      (def.typ=arraydef) then
+                     begin
+                       consume(AS_LBRACKET);
+                       l:=BuildConstExpression;
+                       if l<tarraydef(def).lowrange then
+                         begin
+                           Message(asmr_e_constant_out_of_bounds);
+                           l:=0;
+                         end
+                       else
+                         l:=(l-tarraydef(def).lowrange)*tarraydef(def).elesize;
+                       str(l, tempstr);
+                       expr:=expr + '+' + tempstr;
+                       consume(AS_RBRACKET);
+                     end;
+                 end;
+                { check if there are wrong operator used like / or mod etc. }
+                if (hs<>'') and not(actasmtoken in [AS_MINUS,AS_PLUS,AS_COMMA,AS_SEPARATOR,AS_END,AS_RBRACKET]) then
+                 Message(asmr_e_only_add_relocatable_symbol);
+              end;
+            //AS_ALIGN,
+            //AS_DB,
+            //AS_DW,
+            //AS_DD,
+            //AS_DQ,
+            AS_END,
+            AS_RBRACKET,
+            AS_SEPARATOR,
+            AS_COMMA,
+            AS_COLON:
+              break;
+          else
+            begin
+              { write error only once. }
+              if not errorflag then
+                Message(asmr_e_invalid_constant_expression);
+              { consume tokens until we find COMMA or SEPARATOR }
+              Consume(actasmtoken);
+              errorflag:=TRUE;
+            end;
+          end;
+        Until false;
+        { calculate expression }
+        if not ErrorFlag then
+          value:=CalculateExpression(expr)
+        else
+          value:=0;
+        { no longer in an expression }
+        inexpression:=FALSE;
+      end;
+
+
+    function tz80reader.BuildConstExpression: longint;
+      var
+        l,size : tcgint;
+        hs : string;
+        hssymtyp : TAsmsymtype;
+        out_flags : tconstsymbolexpressionoutputflags;
+      begin
+        BuildConstSymbolExpression([],l,hs,hssymtyp,size,out_flags);
+        if hs<>'' then
+         Message(asmr_e_relocatable_symbol_not_allowed);
+        BuildConstExpression:=l;
+      end;
+
+
+    function tz80reader.BuildRefConstExpression(out size: tcgint;
+        startingminus: boolean): longint;
+      var
+        l : tcgint;
+        hs : string;
+        hssymtyp : TAsmsymtype;
+        in_flags : tconstsymbolexpressioninputflags;
+        out_flags : tconstsymbolexpressionoutputflags;
+      begin
+        in_flags:=[cseif_isref];
+        if startingminus then
+          include(in_flags,cseif_startingminus);
+        BuildConstSymbolExpression(in_flags,l,hs,hssymtyp,size,out_flags);
+        if hs<>'' then
+         Message(asmr_e_relocatable_symbol_not_allowed);
+        BuildRefConstExpression:=l;
+      end;
+
+
+    procedure tz80reader.BuildConstantOperand(oper: tz80operand);
+      var
+        l,size : tcgint;
+        tempstr : string;
+        tempsymtyp : tasmsymtype;
+        cse_out_flags : tconstsymbolexpressionoutputflags;
+      begin
+        if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
+          Message(asmr_e_invalid_operand_type);
+        BuildConstSymbolExpression([cseif_needofs],l,tempstr,tempsymtyp,size,cse_out_flags);
+        if tempstr<>'' then
+          begin
+            oper.opr.typ:=OPR_SYMBOL;
+            oper.opr.symofs:=l;
+            oper.opr.symbol:=current_asmdata.RefAsmSymbol(tempstr,tempsymtyp);
+            oper.opr.symseg:=cseof_isseg in cse_out_flags;
+            oper.opr.sym_farproc_entry:=cseof_is_farproc_entry in cse_out_flags;
+          end
+        else
+          if oper.opr.typ=OPR_NONE then
+            begin
+              oper.opr.typ:=OPR_CONSTANT;
+              oper.opr.val:=l;
+            end
+          else
+            inc(oper.opr.val,l);
+      end;
+
+
+    procedure tz80reader.BuildReference(oper: tz80operand);
+      var
+        scale : byte;
+        k,l,size : tcgint;
+        tempstr,hs : string;
+        tempsymtyp : tasmsymtype;
+        code : integer;
+        hreg : tregister;
+        GotStar,GotOffset,HadVar,
+        GotPlus,Negative,BracketlessReference : boolean;
+        hl : tasmlabel;
+        hastypecast: boolean;
+        tmpoper: tz80operand;
+        cse_in_flags: tconstsymbolexpressioninputflags;
+        cse_out_flags: tconstsymbolexpressionoutputflags;
+      begin
+        if actasmtoken=AS_LPAREN then
+          begin
+            Consume(AS_LPAREN);
+            BracketlessReference:=false;
+          end
+        else
+          BracketlessReference:=true;
+        if not(oper.opr.typ in [OPR_LOCAL,OPR_REFERENCE]) then
+          oper.InitRef;
+        GotStar:=false;
+        GotPlus:=true;
+        GotOffset:=false;
+        Negative:=false;
+        Scale:=0;
+        repeat
+          if GotOffset and (actasmtoken<>AS_ID) then
+            Message(asmr_e_invalid_reference_syntax);
+
+          Case actasmtoken of
+            AS_ID, { Constant reference expression OR variable reference expression }
+            AS_VMTOFFSET:
+              Begin
+                if not GotPlus then
+                  Message(asmr_e_invalid_reference_syntax);
+                GotStar:=false;
+                GotPlus:=false;
+                if (actasmtoken = AS_VMTOFFSET) or
+                   (SearchIConstant(actasmpattern,l) or
+                    SearchRecordType(actasmpattern)) then
+                 begin
+                   l:=BuildRefConstExpression(size,negative);
+                   if size<>0 then
+                     oper.SetSize(size,false);
+                   negative:=false;   { "l" was negated if necessary }
+                   GotPlus:=(prevasmtoken=AS_PLUS);
+                   GotStar:=(prevasmtoken=AS_STAR);
+                   case oper.opr.typ of
+                     OPR_LOCAL :
+                       begin
+                         if GotStar then
+                           Message(asmr_e_invalid_reference_syntax);
+                         Inc(oper.opr.localsymofs,l);
+                       end;
+                     OPR_REFERENCE :
+                       begin
+                         if GotStar then
+                          oper.opr.ref.scalefactor:=l
+                         else
+                           Inc(oper.opr.ref.offset,l);
+                       end;
+                     else
+                       internalerror(2019050715);
+                   end;
+                 end
+                else
+                 Begin
+                   if negative and not oper.hasvar then
+                     Message(asmr_e_only_add_relocatable_symbol)
+                   else if oper.hasvar and not GotOffset and
+                           (not negative or assigned(oper.opr.ref.relsymbol)) then
+                     Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                   HadVar:=oper.hasvar and GotOffset;
+                   tempstr:=actasmpattern;
+                   Consume(AS_ID);
+                   { typecasting? }
+                   if (actasmtoken=AS_LPAREN) and
+                      SearchType(tempstr,l) then
+                    begin
+                      oper.hastype:=true;
+                      oper.typesize:=l;
+                      Consume(AS_LPAREN);
+                      BuildOperand(oper,true);
+                      Consume(AS_RPAREN);
+                    end
+                   else
+                    if is_locallabel(tempstr) then
+                      begin
+                        CreateLocalLabel(tempstr,hl,false);
+                        oper.InitRef;
+                        oper.haslabelref:=true;
+                        if not negative then
+                          begin
+                            oper.opr.ref.symbol:=hl;
+                            oper.hasvar:=true;
+                          end
+                        else
+                          oper.opr.ref.relsymbol:=hl;
+{$ifdef i8086}
+                        if oper.opr.ref.segment=NR_NO then
+                          oper.opr.ref.segment:=NR_CS;
+{$endif i8086}
+                      end
+                   else
+                    if oper.SetupVar(tempstr,GotOffset) then
+                     begin
+                       { convert OPR_LOCAL register para into a reference base }
+                       if (oper.opr.typ=OPR_LOCAL) and
+                          AsmRegisterPara(oper.opr.localsym) then
+                         oper.InitRefConvertLocal
+                       else
+                         begin
+{$ifdef x86_64}
+                           if actasmtoken=AS_WRT then
+                             begin
+                               if (oper.opr.typ=OPR_REFERENCE) then
+                                 begin
+                                   Consume(AS_WRT);
+                                   Consume(AS___GOTPCREL);
+                                   if (oper.opr.ref.base<>NR_NO) or
+                                      (oper.opr.ref.index<>NR_NO) or
+                                      (oper.opr.ref.offset<>0) then
+                                     Message(asmr_e_wrong_gotpcrel_intel_syntax);
+                                   if tf_no_pic_supported in target_info.flags then
+                                     Message(asmr_e_no_gotpcrel_support);
+                                   oper.opr.ref.refaddr:=addr_pic;
+                                   oper.opr.ref.base:=NR_RIP;
+                                 end
+                               else
+                                 message(asmr_e_invalid_reference_syntax);
+                             end;
+{$endif x86_64}
+                         end;
+                     end
+                   else
+                     Message1(sym_e_unknown_id,tempstr);
+                   { record.field ? }
+                   if actasmtoken=AS_DOT then
+                    begin
+                      BuildRecordOffsetSize(tempstr,l,k,hs,false,hastypecast);
+                      if (hs<>'') then
+                        Message(asmr_e_invalid_symbol_ref);
+                      case oper.opr.typ of
+                        OPR_LOCAL :
+                          inc(oper.opr.localsymofs,l);
+                        OPR_REFERENCE :
+                          inc(oper.opr.ref.offset,l);
+                        else
+                          internalerror(2019050716);
+                      end;
+                      if hastypecast then
+                       oper.hastype:=true;
+                      oper.SetSize(k,false);
+                    end;
+                   if GotOffset then
+                    begin
+                      if oper.hasvar and (oper.opr.ref.base=current_procinfo.framepointer) then
+                       begin
+                         if (oper.opr.typ=OPR_REFERENCE) then
+                           oper.opr.ref.base:=NR_NO;
+                         oper.hasvar:=hadvar;
+                       end
+                      else
+                       begin
+                         if oper.hasvar and hadvar then
+                          Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                         { should we allow ?? }
+                       end;
+                    end;
+                 end;
+                GotOffset:=false;
+              end;
+
+            AS_PLUS :
+              Begin
+                Consume(AS_PLUS);
+                Negative:=false;
+                GotPlus:=true;
+                GotStar:=false;
+                Scale:=0;
+              end;
+
+            AS_DOT :
+              Begin
+                { Handle like a + }
+                Consume(AS_DOT);
+                Negative:=false;
+                GotPlus:=true;
+                GotStar:=false;
+                Scale:=0;
+              end;
+
+            AS_MINUS :
+              begin
+                Consume(AS_MINUS);
+                Negative:=true;
+                GotPlus:=true;
+                GotStar:=false;
+                Scale:=0;
+              end;
+
+            AS_STAR : { Scaling, with eax*4 order }
+              begin
+                Consume(AS_STAR);
+                hs:='';
+                l:=0;
+                case actasmtoken of
+                  AS_ID,
+                  AS_LPAREN :
+                    l:=BuildConstExpression;
+                  AS_INTNUM:
+                    Begin
+                      hs:=actasmpattern;
+                      Consume(AS_INTNUM);
+                    end;
+                  AS_REGISTER :
+                    begin
+                      case oper.opr.typ of
+                        OPR_REFERENCE :
+                          begin
+                            if oper.opr.ref.scalefactor=0 then
+                              begin
+                                if scale<>0 then
+                                  begin
+                                    oper.opr.ref.scalefactor:=scale;
+                                    scale:=0;
+                                  end
+                                else
+                                 Message(asmr_e_wrong_scale_factor);
+                              end
+                            else
+                              Message(asmr_e_invalid_reference_syntax);
+                          end;
+                        OPR_LOCAL :
+                          begin
+                            if oper.opr.localscale=0 then
+                              begin
+                                if scale<>0 then
+                                  begin
+                                    oper.opr.localscale:=scale;
+                                    scale:=0;
+                                  end
+                                else
+                                 Message(asmr_e_wrong_scale_factor);
+                              end
+                            else
+                              Message(asmr_e_invalid_reference_syntax);
+                          end;
+                        else
+                          internalerror(2019050719);
+                      end;
+                    end;
+                  else
+                    Message(asmr_e_invalid_reference_syntax);
+                end;
+                if actasmtoken<>AS_REGISTER then
+                  begin
+                    if hs<>'' then
+                      val(hs,l,code);
+                    case oper.opr.typ of
+                      OPR_REFERENCE :
+                        oper.opr.ref.scalefactor:=l;
+                      OPR_LOCAL :
+                        oper.opr.localscale:=l;
+                      else
+                        internalerror(2019050717);
+                    end;
+                    if l>9 then
+                      Message(asmr_e_wrong_scale_factor);
+                  end;
+                GotPlus:=false;
+                GotStar:=false;
+              end;
+
+            AS_REGISTER :
+              begin
+                hreg:=actasmregister;
+
+                Consume(AS_REGISTER);
+
+                if not((GotPlus and (not Negative)) or
+                       GotStar) then
+                  Message(asmr_e_invalid_reference_syntax);
+                { this register will be the index:
+                   1. just read a *
+                   2. next token is a *
+                   3. base register is already used }
+                case oper.opr.typ of
+                  OPR_LOCAL :
+                    begin
+                      if (oper.opr.localindexreg<>NR_NO) then
+                        Message(asmr_e_multiple_index);
+                      oper.opr.localindexreg:=hreg;
+                      if scale<>0 then
+                        begin
+                          oper.opr.localscale:=scale;
+                          scale:=0;
+                        end;
+                    end;
+                  OPR_REFERENCE :
+                    begin
+                      if (GotStar) or
+                         (actasmtoken=AS_STAR) or
+                         (oper.opr.ref.base<>NR_NO) then
+                       begin
+                         if (oper.opr.ref.index<>NR_NO) then
+                          Message(asmr_e_multiple_index);
+                         oper.opr.ref.index:=hreg;
+                         if scale<>0 then
+                           begin
+                             oper.opr.ref.scalefactor:=scale;
+                             scale:=0;
+                           end;
+                       end
+                      else
+                        begin
+                          oper.opr.ref.base:=hreg;
+{$ifdef x86_64}
+                          { non-GOT based RIP-relative accesses are also position-independent }
+                          if (oper.opr.ref.base=NR_RIP) and
+                             (oper.opr.ref.refaddr<>addr_pic) then
+                            oper.opr.ref.refaddr:=addr_pic_no_got;
+{$endif x86_64}
+                        end;
+                    end;
+                  else
+                    internalerror(2019050718);
+                end;
+                GotPlus:=false;
+                GotStar:=false;
+              end;
+
+            //AS_OFFSET :
+            //  begin
+            //    Consume(AS_OFFSET);
+            //    GotOffset:=true;
+            //  end;
+
+            AS_TYPE,
+            AS_NOT,
+            AS_STRING,
+            AS_INTNUM,
+            AS_LPAREN : { Constant reference expression }
+              begin
+                if not GotPlus and not GotStar then
+                  Message(asmr_e_invalid_reference_syntax);
+                cse_in_flags:=[cseif_needofs,cseif_isref];
+                if GotPlus and negative then
+                  include(cse_in_flags,cseif_startingminus);
+                BuildConstSymbolExpression(cse_in_flags,l,tempstr,tempsymtyp,size,cse_out_flags);
+                { already handled by BuildConstSymbolExpression(); must be
+                  handled there to avoid [reg-1+1] being interpreted as
+                  [reg-(1+1)] }
+                negative:=false;
+
+                if tempstr<>'' then
+                 begin
+                   if GotStar then
+                    Message(asmr_e_only_add_relocatable_symbol);
+                   if not assigned(oper.opr.ref.symbol) then
+                     begin
+                       oper.opr.ref.symbol:=current_asmdata.RefAsmSymbol(tempstr,tempsymtyp);
+{$ifdef i8086}
+                       if cseof_isseg in cse_out_flags then
+                         begin
+                           if not (oper.opr.ref.refaddr in [addr_fardataseg,addr_dgroup]) then
+                             oper.opr.ref.refaddr:=addr_seg;
+                         end
+                       else if (tempsymtyp=AT_FUNCTION) and (oper.opr.ref.segment=NR_NO) then
+                         oper.opr.ref.segment:=NR_CS;
+{$endif i8086}
+                     end
+                   else
+                    Message(asmr_e_cant_have_multiple_relocatable_symbols);
+                 end;
+                case oper.opr.typ of
+                  OPR_REFERENCE :
+                    begin
+                      if GotStar then
+                       oper.opr.ref.scalefactor:=l
+                      else if (prevasmtoken = AS_STAR) then
+                       begin
+                         if scale<>0 then
+                           scale:=l*scale
+                         else
+                           scale:=l;
+                       end
+                      else
+                      begin
+                        Inc(oper.opr.ref.offset,l);
+                        Inc(oper.opr.constoffset,l);
+                      end;
+                    end;
+                  OPR_LOCAL :
+                    begin
+                      if GotStar then
+                       oper.opr.localscale:=l
+                      else if (prevasmtoken = AS_STAR) then
+                       begin
+                         if scale<>0 then
+                           scale:=l*scale
+                         else
+                           scale:=l;
+                       end
+                      else
+                        Inc(oper.opr.localsymofs,l);
+                    end;
+                  else
+                    internalerror(2019050714);
+                end;
+                GotPlus:=(prevasmtoken=AS_PLUS) or
+                         (prevasmtoken=AS_MINUS);
+                if GotPlus then
+                  negative := prevasmtoken = AS_MINUS;
+                GotStar:=(prevasmtoken=AS_STAR);
+              end;
+
+            //AS_LBRACKET :
+            //  begin
+            //    if (GotPlus and Negative) or GotStar then
+            //      Message(asmr_e_invalid_reference_syntax);
+            //    tmpoper:=Tz80Operand.create;
+            //    BuildReference(tmpoper);
+            //    AddReferences(oper,tmpoper);
+            //    tmpoper.Free;
+            //    GotPlus:=false;
+            //    GotStar:=false;
+            //  end;
+
+            AS_RPAREN :
+              begin
+                if GotPlus or GotStar or BracketlessReference then
+                  Message(asmr_e_invalid_reference_syntax);
+
+                Consume(AS_RPAREN);
+
+
+
+                if actasmtoken=AS_LPAREN then
+                  begin
+                    tmpoper:=Tz80Operand.create;
+                    BuildReference(tmpoper);
+                    AddReferences(oper,tmpoper);
+                    tmpoper.Free;
+                  end;
+                break;
+              end;
+
+            AS_SEPARATOR,
+            AS_END,
+            AS_COMMA:
+              begin
+                if not BracketlessReference then
+                  begin
+                    Message(asmr_e_invalid_reference_syntax);
+                    RecoverConsume(true);
+                  end;
+                break;
+              end;
+
+            else
+              Begin
+                Message(asmr_e_invalid_reference_syntax);
+                RecoverConsume(true);
+                break;
+              end;
+          end;
+        until false;
+      end;
+
+
+    procedure tz80reader.BuildOperand(oper: tz80operand; istypecast: boolean);
+
+      procedure AddLabelOperand(hl:tasmlabel);
+      begin
+        if (oper.opr.typ=OPR_NONE) 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;
+           oper.haslabelref:=true;
+         end;
+      end;
+
+      var
+        l: tcgint;
+        tsize: tcgint;
+        expr: string;
+        hl: tasmlabel;
+      begin
+        repeat
+          case actasmtoken of
+            //AS_OFFSET,
+            AS_SIZEOF,
+            AS_VMTOFFSET,
+            AS_TYPE,
+            AS_NOT,
+            AS_STRING,
+            AS_PLUS,
+            AS_MINUS,
+//            AS_LPAREN,
+            AS_INTNUM :
+              begin
+                case oper.opr.typ of
+                  OPR_REFERENCE :
+                    begin
+                      l := BuildRefConstExpression(tsize);
+                      if tsize<>0 then
+                        oper.SetSize(tsize,false);
+                      inc(oper.opr.ref.offset,l);
+                      inc(oper.opr.constoffset,l);
+                    end;
+                  OPR_LOCAL :
+                    begin
+                      l := BuildConstExpression;
+                      inc(oper.opr.localsymofs,l);
+                      inc(oper.opr.localconstoffset,l);
+                    end;
+
+                  OPR_NONE,
+                  OPR_CONSTANT :
+                    BuildConstantOperand(oper);
+                  else
+                    Message(asmr_e_invalid_operand_type);
+                end;
+              end;
+
+            AS_LPAREN:
+              begin
+                BuildReference(oper);
+              end;
+
+            AS_ID : { A constant expression, or a Variable ref. }
+              Begin
+                { Label or Special symbol reference? }
+                if actasmpattern[1] = '@' then
+                 Begin
+                   if actasmpattern = '@RESULT' then
+                    Begin
+                      oper.SetupResult;
+                      Consume(AS_ID);
+                      expr:='result';
+                    end
+                   else
+                    if (actasmpattern = '@CODE') or (actasmpattern = '@DATA') then
+                     begin
+                       Message(asmr_w_CODE_and_DATA_not_supported);
+                       Consume(AS_ID);
+                     end
+                   else
+                    { Local Label }
+                    begin
+                      CreateLocalLabel(actasmpattern,hl,false);
+                      Consume(AS_ID);
+                      AddLabelOperand(hl);
+                    end;
+                 end
+                else
+                { support result for delphi modes }
+                 if (m_objpas in current_settings.modeswitches) and (actasmpattern='RESULT') then
+                  begin
+                    oper.SetUpResult;
+                    Consume(AS_ID);
+                    expr:='result';
+                  end
+                { probably a variable or normal expression }
+                { or a procedure (such as in CALL ID)      }
+                else
+                 Begin
+                   { is it a constant ? }
+                   if SearchIConstant(actasmpattern,l) then
+                    Begin
+                      case oper.opr.typ of
+                        OPR_REFERENCE :
+                          begin
+                            l := BuildRefConstExpression(tsize);
+                            if tsize<>0 then
+                              oper.SetSize(tsize,false);
+                            inc(oper.opr.ref.offset,l);
+                            inc(oper.opr.constoffset,l);
+                          end;
+
+                        OPR_LOCAL :
+                          begin
+                            l := BuildRefConstExpression(tsize);
+                            if tsize<>0 then
+                              oper.SetSize(tsize,false);
+                            inc(oper.opr.localsymofs,l);
+                            inc(oper.opr.localconstoffset,l);
+                          end;
+                        OPR_NONE,
+                        OPR_CONSTANT :
+                          BuildConstantOperand(oper);
+                        else
+                          Message(asmr_e_invalid_operand_type);
+                      end;
+                    end
+                   else
+                    { Check for pascal label }
+                    if SearchLabel(actasmpattern,hl,false) then
+                     begin
+                       Consume(AS_ID);
+                       AddLabelOperand(hl);
+                     end
+                    else
+                    { is it a normal variable ? }
+                     Begin
+                       expr:=actasmpattern;
+                       Consume(AS_ID);
+
+
+                       { typecasting? }
+                       if SearchType(expr,l) then
+                        begin
+                          oper.hastype:=true;
+                          oper.typesize:=l;
+                          case actasmtoken of
+                            AS_LPAREN :
+                              begin
+                                { Support Type([Reference]) }
+                                Consume(AS_LPAREN);
+                                BuildOperand(oper,true);
+                                { Delphi also supports Type(Register) and
+                                  interprets it the same as Type([Register]).  }
+                                if (oper.opr.typ = OPR_REGISTER) then
+                                  { This also sets base to the register.  }
+                                  oper.InitRef;
+                                Consume(AS_RPAREN);
+                              end;
+                            //AS_LBRACKET :
+                            //  begin
+                            //    { Support Var.Type[Index] }
+                            //    { Convert @label.Byte[1] to reference }
+                            //    if oper.opr.typ=OPR_SYMBOL then
+                            //      oper.initref;
+                            //  end;
+                            else
+                              ;
+                          end;
+                        end
+                       else
+                        begin
+                          if not oper.SetupVar(expr,false) then
+                            Begin
+                              { not a variable, check special variables.. }
+                              if expr = 'SELF' then
+                                begin
+                                  oper.SetupSelf;
+                                  expr:='self';
+                                end
+                              else
+                                begin
+                                  Message1(sym_e_unknown_id,expr);
+                                  expr:='';
+                                end;
+                            end;
+                          { indexed access to variable? }
+                          //if actasmtoken=AS_LBRACKET then
+                          //  begin
+                          //    { ... then the operand size is not known anymore }
+                          //    oper.size:=OS_NO;
+                          //    BuildReference(oper);
+                          //  end;
+                        end;
+                     end;
+                 end;
+              end;
+
+            AS_REGISTER : { Register, a variable reference or a constant reference }
+              begin
+                Consume(AS_REGISTER);
+
+                { Simple register }
+                if (oper.opr.typ <> OPR_NONE) then
+                  Message(asmr_e_syn_operand);
+                oper.opr.typ:=OPR_REGISTER;
+                oper.opr.reg:=actasmregister;
+                oper.SetSize(tcgsize2size[reg_cgsize(oper.opr.reg)],true);
+              end;
+
+            AS_SEPARATOR,
+            AS_END,
+            AS_COMMA:
+              begin
+                break;
+              end;
+
+            else
+              begin
+                Message(asmr_e_syn_operand);
+                RecoverConsume(true);
+                break;
+              end;
+          end;
+        until false;
+      end;
+
+
+    procedure tz80reader.BuildOpCode(instr: TZ80Instruction);
+      var
+        operandnum: Integer;
+      begin
+        instr.opcode:=actopcode;
+        operandnum:=1;
+        Consume(AS_OPCODE);
+        { Zero operand opcode ?  }
+        if actasmtoken in [AS_SEPARATOR,AS_END] then
+          exit;
+        { Condition (e.g. 'NC' in 'JP NC, label') }
+        if actasmtoken=AS_CONDITION then
+          begin
+            instr.condition:=actasmcond;
+            Consume(AS_CONDITION);
+            if actasmtoken in [AS_SEPARATOR,AS_END] then
+              exit;
+            if actasmtoken=AS_COMMA then
+              Consume(AS_COMMA);
+          end;
+        { Read Operands }
+        repeat
+          case actasmtoken of
+            { End of asm operands for this opcode }
+            AS_END,
+            AS_SEPARATOR :
+              break;
+
+            { Operand delimiter }
+            AS_COMMA :
+              begin
+                { should have something before the comma }
+                if instr.operands[operandnum].opr.typ=OPR_NONE then
+                  Message(asmr_e_syntax_error);
+                if operandnum >= max_operands then
+                  Message(asmr_e_too_many_operands)
+                else
+                  Inc(operandnum);
+                Consume(AS_COMMA);
+              end;
+            else
+              BuildOperand(instr.Operands[operandnum] as tz80operand,false);
+          end;
+        until false;
+        instr.ops:=operandnum;
+      end;
+
+
+    procedure tz80reader.handleopcode;
+      var
+        instr: TZ80Instruction;
+      begin
+        instr:=TZ80Instruction.create(TZ80Operand);
+        BuildOpcode(instr);
+        with instr do
+          begin
+            //CheckNonCommutativeOpcodes;
+            //AddReferenceSizes;
+            //SetInstructionOpsize;
+            //CheckOperandSizes;
+            ConcatInstruction(curlist);
+          end;
+        instr.Free;
+      end;
+
+
+    procedure tz80reader.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;
+
+
+    function tz80reader.Assemble: tlinkedlist;
+      var
+        hl: tasmlabel;
+      begin
+        Message1(asmr_d_start_reading,'Z80');
+        firsttoken:=TRUE;
+        { sets up all opcode and register tables in uppercase }
+        if not _asmsorted then
+          begin
+            SetupTables;
+            _asmsorted:=TRUE;
+          end;
+        curlist:=TAsmList.Create;
+
+        { we might need to know which parameters are passed in registers }
+        if not parse_generic then
+          current_procinfo.generate_parameter_info;
+
+        { start tokenizer }
+        gettoken;
+        { main loop }
+        repeat
+          case actasmtoken of
+            AS_LLABEL:
+              Begin
+                if CreateLocalLabel(actasmpattern,hl,true) then
+                  ConcatLabel(curlist,hl);
+                Consume(AS_LLABEL);
+              end;
+
+            AS_LABEL:
+              Begin
+                if SearchLabel(upper(actasmpattern),hl,true) then
+                  begin
+                    if hl.is_public then
+                      ConcatPublic(curlist,actasmpattern_origcase);
+                    ConcatLabel(curlist,hl);
+                  end
+                else
+                 Message1(asmr_e_unknown_label_identifier,actasmpattern);
+                Consume(AS_LABEL);
+              end;
+
+            AS_END:
+              begin
+                break; { end assembly block }
+              end;
+
+            AS_SEPARATOR:
+              begin
+                Consume(AS_SEPARATOR);
+              end;
+
+            AS_OPCODE:
+              begin
+                HandleOpCode;
+              end;
+
+            else
+              begin
+                Message(asmr_e_syntax_error);
+                RecoverConsume(false);
+              end;
+          end;
+        until false;
+        { check that all referenced local labels are defined }
+        checklocallabels;
+        { Return the list in an asmnode }
+        assemble:=curlist;
+        Message1(asmr_d_finish_reading,'Z80');
+      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 : tz80reader;
+          );
+
+initialization
+//  RegisterAsmMode(asmmode_z80_att_info);
+  RegisterAsmMode(asmmode_z80_standard_info);
+end.

+ 260 - 0
compiler/z80/rgcpu.pas

@@ -0,0 +1,260 @@
+{
+    Copyright (c) 1998-2008 by Florian Klaempfl
+
+    This unit implements the Z80 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
+          R_SUBL,R_SUBH:
+            begin
+              { Some registers have no 8-bit subregister }
+              supreg:=getsupreg(reg);
+              add_edge(supreg,RS_IX);
+              add_edge(supreg,RS_IY);
+              add_edge(supreg,RS_SP);
+            end;
+          else
+            ;
+        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)>127 then
+  //        begin
+  //          Internalerror(2017032701);
+//
+//            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)>127 then
+  //        begin
+  //          Internalerror(2017032702);
+//
+//            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 (spilltemp.offset<-128) or (spilltemp.offset>127) then
+          exit;
+
+        { Replace 'ld  orgreg,src' with 'ld  spilltemp,src'
+          and     'ld  dst,orgreg' with 'ld  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.loadref(0,spilltemp);
+                    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(1,spilltemp);
+                    result:=true;
+                  end;
+              end
+            { Replace 'ld  orgreg,const' with 'ld  spilltemp,const' }
+            else if (opcode=A_LD) and (ops=2) and (oper[1]^.typ=top_const) and (oper[0]^.typ=top_reg) then
+              begin
+                if (getregtype(oper[0]^.reg)=regtype) and
+                   (get_alias(getsupreg(oper[0]^.reg))=orgreg) then
+                  begin
+                    instr.loadref(0,spilltemp);
+                    result:=true;
+                  end;
+              end
+            { Replace 'add A,orgreg' with 'add A,spilltemp'
+              and     'adc A,orgreg' with 'adc A,spilltemp'
+              and     'sub A,orgreg' with 'sub A,spilltemp'
+              and     'sbc A,orgreg' with 'sbc A,spilltemp'
+              and     'and A,orgreg' with 'and A,spilltemp'
+              and     'or  A,orgreg' with 'or  A,spilltemp'
+              and     'xor A,orgreg' with 'xor A,spilltemp'
+              and     'cp  A,orgreg' with 'cp  A,spilltemp' }
+            else if (opcode in [A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_XOR,A_CP]) and (ops=2) and (oper[1]^.typ=top_reg) and (oper[0]^.typ=top_reg) then
+              begin
+                { we don't really need to check whether the first register is 'A',
+                  because that's the only register allowed as a destination for
+                  these instructions }
+                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(1,spilltemp);
+                    result:=true;
+                  end;
+              end
+            { Replace 'bit const,orgreg' with 'bit const,spilltemp'
+              and     'set const,orgreg' with 'set const,spilltemp'
+              and     'res const,orgreg' with 'res const,spilltemp' }
+            else if (opcode in [A_BIT,A_SET,A_RES]) and (ops=2) and (oper[1]^.typ=top_reg) and (oper[0]^.typ=top_const) then
+              begin
+                if (getregtype(oper[1]^.reg)=regtype) and
+                   (get_alias(getsupreg(oper[1]^.reg))=orgreg) then
+                  begin
+                    instr.loadref(1,spilltemp);
+                    result:=true;
+                  end;
+              end
+            { Replace 'inc orgreg' with 'inc spilltemp'
+              and     'dec orgreg' with 'dec spilltemp'
+              and     'add orgreg' with 'add spilltemp'
+              and     'adc orgreg' with 'adc spilltemp'
+              and     'sub orgreg' with 'sub spilltemp'
+              and     'sbc orgreg' with 'sbc spilltemp'
+              and     'and orgreg' with 'and spilltemp'
+              and     'or  orgreg' with 'or  spilltemp'
+              and     'xor orgreg' with 'xor spilltemp'
+              and     'cp  orgreg' with 'cp  spilltemp'
+              and     'rlc orgreg' with 'rlc spilltemp'
+              and     'rl  orgreg' with 'rl  spilltemp'
+              and     'rrc orgreg' with 'rrc spilltemp'
+              and     'rr  orgreg' with 'rr  spilltemp'
+              and     'sla orgreg' with 'sla spilltemp'
+              and     'sra orgreg' with 'sra spilltemp'
+              and     'srl orgreg' with 'srl spilltemp' }
+            else if (opcode in [A_INC,A_DEC,A_ADD,A_ADC,A_SUB,A_SBC,A_AND,A_OR,A_XOR,A_CP,
+                     A_RLC,A_RL,A_RRC,A_RR,A_SLA,A_SRA,A_SRL]) and (ops=1) and (oper[0]^.typ=top_reg) then
+              begin
+                if (getregtype(oper[0]^.reg)=regtype) and
+                   (get_alias(getsupreg(oper[0]^.reg))=orgreg) then
+                  begin
+                    instr.loadref(0,spilltemp);
+                    result:=true;
+                  end;
+              end;
+          end;
+      end;
+
+end.

+ 28 - 0
compiler/z80/rz80con.inc

@@ -0,0 +1,28 @@
+{ don't edit, this file is generated from z80reg.dat }
+NR_NO = tregister($00000000);
+NR_B = tregister($01010000);
+NR_C = tregister($01010001);
+NR_D = tregister($01010002);
+NR_E = tregister($01010003);
+NR_H = tregister($01010004);
+NR_L = tregister($01010005);
+NR_A = tregister($01010007);
+NR_BC = tregister($01030001);
+NR_DE = tregister($01030003);
+NR_HL = tregister($01030005);
+NR_AF = tregister($01030007);
+NR_IX = tregister($01030008);
+NR_IY = tregister($01030009);
+NR_B_ = tregister($05010000);
+NR_C_ = tregister($05010001);
+NR_D_ = tregister($05010002);
+NR_E_ = tregister($05010003);
+NR_H_ = tregister($05010004);
+NR_L_ = tregister($05010005);
+NR_A_ = tregister($05010007);
+NR_SP = tregister($05030008);
+NR_F = tregister($05010009);
+NR_F_ = tregister($0501000a);
+NR_PC = tregister($0503000b);
+NR_I = tregister($0501000c);
+NR_R = tregister($0501000d);

+ 28 - 0
compiler/z80/rz80dwa.inc

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

+ 2 - 0
compiler/z80/rz80nor.inc

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

+ 28 - 0
compiler/z80/rz80num.inc

@@ -0,0 +1,28 @@
+{ don't edit, this file is generated from z80reg.dat }
+tregister($00000000),
+tregister($01010000),
+tregister($01010001),
+tregister($01010002),
+tregister($01010003),
+tregister($01010004),
+tregister($01010005),
+tregister($01010007),
+tregister($01030001),
+tregister($01030003),
+tregister($01030005),
+tregister($01030007),
+tregister($01030008),
+tregister($01030009),
+tregister($05010000),
+tregister($05010001),
+tregister($05010002),
+tregister($05010003),
+tregister($05010004),
+tregister($05010005),
+tregister($05010007),
+tregister($05030008),
+tregister($05010009),
+tregister($0501000a),
+tregister($0503000b),
+tregister($0501000c),
+tregister($0501000d)

+ 28 - 0
compiler/z80/rz80rni.inc

@@ -0,0 +1,28 @@
+{ 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,
+22,
+23,
+25,
+26,
+21,
+24

+ 28 - 0
compiler/z80/rz80sri.inc

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

+ 28 - 0
compiler/z80/rz80sta.inc

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

+ 28 - 0
compiler/z80/rz80std.inc

@@ -0,0 +1,28 @@
+{ don't edit, this file is generated from z80reg.dat }
+'INVALID',
+'b',
+'c',
+'d',
+'e',
+'h',
+'l',
+'a',
+'bc',
+'de',
+'hl',
+'af',
+'ix',
+'iy',
+'b''',
+'c''',
+'d''',
+'e''',
+'h''',
+'l''',
+'a''',
+'sp',
+'f',
+'f''',
+'pc',
+'i',
+'r'

+ 28 - 0
compiler/z80/rz80sup.inc

@@ -0,0 +1,28 @@
+{ don't edit, this file is generated from z80reg.dat }
+RS_NO = 0;
+RS_B = 0;
+RS_C = 1;
+RS_D = 2;
+RS_E = 3;
+RS_H = 4;
+RS_L = 5;
+RS_A = 7;
+RS_BC = 1;
+RS_DE = 3;
+RS_HL = 5;
+RS_AF = 7;
+RS_IX = 8;
+RS_IY = 9;
+RS_B_ = 0;
+RS_C_ = 1;
+RS_D_ = 2;
+RS_E_ = 3;
+RS_H_ = 4;
+RS_L_ = 5;
+RS_A_ = 7;
+RS_SP = 8;
+RS_F = 9;
+RS_F_ = 10;
+RS_PC = 11;
+RS_I = 12;
+RS_R = 13;

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

+ 67 - 0
compiler/z80/tgcpu.pas

@@ -0,0 +1,67 @@
+{
+    Copyright (C) 1998-2000 by Florian Klaempfl
+
+    This unit handles the temporary variables stuff 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.
+
+ ****************************************************************************
+}
+{
+  This unit handles the temporary variables stuff for Z80.
+}
+unit tgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      tgobj,globtype,aasmdata,cgutils,symtype;
+
+    type
+
+      { ttgz80 }
+
+      ttgz80 = class(ttgobj)
+      public
+        procedure setfirsttemp(l: asizeint); override;
+      end;
+
+implementation
+
+uses
+  globals,
+  verbose,
+  cpubase,
+  cutils;
+
+{ ttgz80 }
+
+procedure ttgz80.setfirsttemp(l: asizeint);
+  begin
+    { this is a negative value normally }
+    if l>0 then
+      internalerror(200204221);
+    firsttemp:=l;
+    lasttemp:=l;
+{$ifdef EXTDEBUG}
+    Comment(V_Note,'tgobj: (SetFirstTemp) set to '+tostr(l));
+{$endif}
+  end;
+
+begin
+  tgobjclass:=ttgz80;
+end.

+ 381 - 0
compiler/z80/z80ins.dat

@@ -0,0 +1,381 @@
+; legend:
+; r      - 8-bit register: A/B/C/D/E/H/L
+; r'     - 8-bit register: A/B/C/D/E/H/L
+; b      - 3-bit immediate value (bit number: [0..7])
+; n      - 8-bit immediate value
+; p      - immediate value in [$00,$08,$10,$18,$20,$28,$30,$38]
+; e      - 8-bit relative jump offset
+; nn     - 16-bit immediate value
+; 0      - the immediate value 0
+; 1      - the immediate value 1
+; 2      - the immediate value 2
+; cc     - condition: NZ/Z/NC/C/PO/PE/P/M
+; C      - condition C
+; NC     - condition NC
+; Z      - condition Z
+; NZ     - condition NZ
+; dd     - 16-bit register pair: BC/DE/HL/SP
+; qq     - 16-bit register pair: BC/DE/HL/AF
+; pp     - 16-bit register pair: BC/DE/IX/SP
+; rr     - 16-bit register pair: BC/DE/IY/SP
+; A      - register A
+; I      - register I
+; R      - register R
+; IX     - register IX
+; IY     - register IY
+; SP     - register SP
+; DE     - 16-bit register pair DE
+; HL     - 16-bit register pair HL
+; AF     - 16-bit register pair AF
+; AF'    - alternate register set, 16-bit register pair AF'
+; (C)    - implied parameter of the IN and OUT instructions
+; (n)    - 8-bit immediate port number for the IN and OUT instructions
+; (nn)   - memory contents at address (nn = 16-bit immediate address)
+; (BC)   - memory contents at address in register BC
+; (DE)   - memory contents at address in register DE
+; (HL)   - memory contents at address in register HL
+; (SP)   - memory contents at address in register SP
+; (IX)   - memory contents at address in register IX
+; (IY)   - memory contents at address in register IY
+; (IX+d) - memory contents at address in register IX+d, d is in [-128..127]
+; (IY+d) - memory contents at address in register IY+d, d is in [-128..127]
+
+[None]
+void                  void
+
+[ADC]
+A,r                   %10001rrr
+A,n                   $CE,n
+A,(HL)                $8E
+A,(IX+d)              $DD,$8E,d
+A,(IY+d)              $FD,$8E,d
+HL,dd                 $ED,%01dd1010
+
+[ADD]
+A,r                   %10000rrr
+A,n                   $C6,n
+A,(HL)                $86
+A,(IX+d)              $DD,$86,d
+A,(IY+d)              $FD,$86,d
+HL,dd                 %00dd1001
+IX,pp                 $DD,%00pp1001
+IY,rr                 $FD,%00rr1001
+
+[AND]
+A,r                   %10100rrr
+A,n                   $E6,n
+A,(HL)                $A6
+A,(IX+d)              $DD,$A6,d
+A,(IY+d)              $FD,$A6,d
+
+[BIT]
+b,r                   $CB,%01bbbrrr
+b,(HL)                $CB,%01bbb110
+b,(IX+d)              $DD,$CB,d,%01bbb110
+b,(IY+d)              $FD,$CB,d,%01bbb110
+
+[CALL]
+nn                    $CD,nn
+cc,nn                 %11ccc100,nn
+
+[CCF]
+void                  $3F
+
+[CP]
+A,r                   %10111rrr
+A,n                   $FE,n
+A,(HL)                $BE
+A,(IX+d)              $DD,$BE,d
+A,(IY+d)              $FD,$BE,d
+
+[CPD]
+void                  $ED,$A9
+
+[CPDR]
+void                  $ED,$B9
+
+[CPI]
+void                  $ED,$A1
+
+[CPIR]
+void                  $ED,$B1
+
+[CPL]
+void                  $2F
+
+[DAA]
+void                  $27
+
+[DEC]
+r                     %00rrr101
+(HL)                  $35
+(IX+d)                $DD,$35,d
+(IY+d)                $FD,$35,d
+dd                    %00dd1011
+IX                    $DD,$2B
+IY                    $FD,$2B
+
+[DI]
+void                  $F3
+
+[DJNZ]
+e                     $10,e
+
+[EI]
+void                  $FB
+
+[EX]
+DE,HL                 $EB
+AF,AF'                $08
+(SP),HL               $E3
+(SP),IX               $DD,$E3
+(SP),IY               $FD,$E3
+
+[EXX]
+void                  $D9
+
+[HALT]
+void                  $76
+
+[IM]
+0                     $ED,$46
+1                     $ED,$56
+2                     $ED,$5E
+
+[IN]
+A,(n)                 $DB,n
+r,(C)                 $ED,%01rrr000
+
+[INC]
+r                     %00rrr100
+(HL)                  $34
+(IX+d)                $DD,$34,d
+(IY+d)                $FD,$34,d
+dd                    %00dd0011
+IX                    $DD,$23
+IY                    $FD,$23
+
+[IND]
+void                  $ED,$AA
+
+[INDR]
+void                  $ED,$BA
+
+[INI]
+void                  $ED,$A2
+
+[INIR]
+void                  $ED,$B2
+
+[JP]
+nn                    $C3,nn
+cc,nn                 %11ccc010,nn
+(HL)                  $E9
+(IX)                  $DD,$E9
+(IY)                  $FD,$E9
+
+[JR]
+e                     $18,e
+C,e                   $38,e
+NC,e                  $30,e
+Z,e                   $28,e
+NZ,e                  $20,e
+
+[LD]
+r,r'                  %01rrrr'r'r'
+r,n                   %00rrr110,n
+r,(HL)                %01rrr110
+r,(IX+d)              $DD,%01rrr110,d
+r,(IY+d)              $FD,%01rrr110,d
+(HL),r                %01110rrr
+(IX+d),r              $DD,%01110rrr,d
+(IY+d),r              $FD,%01110rrr,d
+(HL),n                $36,n
+(IX+d),n              $DD,$36,d,n
+(IY+d),n              $FD,$36,d,n
+A,(BC)                $0A
+A,(DE)                $1A
+A,(nn)                $3A,nn
+(BC),A                $02
+(DE),A                $12
+(nn),A                $32,nn
+A,I                   $ED,$57
+A,R                   $ED,$5F
+I,A                   $ED,$47
+R,A                   $ED,$4F
+dd,nn                 %00dd0001,nn
+IX,nn                 $DD,$21,nn
+IY,nn                 $FD,$21,nn
+HL,(nn)               $2A,nn
+dd,(nn)               $ED,%01dd1011,nn
+IX,(nn)               $DD,$2A,nn
+IY,(nn)               $FD,$2A,nn
+(nn),HL               $22,nn
+(nn),dd               $ED,%01dd0011,nn
+(nn),IX               $DD,$22,nn
+(nn),IY               $FD,$22,nn
+SP,HL                 $F9
+SP,IX                 $DD,$F9
+SP,IY                 $FD,$F9
+
+[LDD]
+void                  $ED,$A8
+
+[LDDR]
+void                  $ED,$B8
+
+[LDI]
+void                  $ED,$A0
+
+[LDIR]
+void                  $ED,$B0
+
+[NEG]
+void                  $ED,$44
+
+[NOP]
+void                  $00
+
+[OR]
+A,r                   %10110rrr
+A,n                   $F6,n
+A,(HL)                $B6
+A,(IX+d)              $DD,$B6,d
+A,(IY+d)              $FD,$B6,d
+
+[OTDR]
+void                  $ED,$BB
+
+[OTIR]
+void                  $ED,$B3
+
+[OUT]
+(n),A                 $D3,n
+(C),r                 $ED,%01rrr001
+
+[OUTD]
+void                  $ED,$AB
+
+[OUTI]
+void                  $ED,$A3
+
+[POP]
+qq                    %11qq0001
+IX                    $DD,$E1
+IY                    $FD,$E1
+
+[PUSH]
+qq                    %11qq0101
+IX                    $DD,$E5
+IY                    $FD,$E5
+
+[RES]
+b,r                   $CB,%10bbbrrr
+b,(HL)                $CB,%10bbb110
+b,(IX+d)              $DD,$CB,d,%10bbb110
+b,(IY+d)              $FD,$CB,d,%10bbb110
+
+[RET]
+void                  $C9
+cc                    %11ccc000
+
+[RETI]
+void                  $ED,$4D
+
+[RETN]
+void                  $ED,$45
+
+[RL]
+r                     $CB,%00010rrr
+(HL)                  $CB,$16
+(IX+d)                $DD,$CB,d,$16
+(IY+d)                $FD,$CB,d,$16
+
+[RLA]
+void                  $17
+
+[RLC]
+r                     $CB,%00000rrr
+(HL)                  $CB,$06
+(IX+d)                $DD,$CB,d,$06
+(IY+d)                $FD,$CB,d,$06
+
+[RLCA]
+void                  $07
+
+[RLD]
+void                  $ED,$6F
+
+[RR]
+r                     $CB,%00001rrr
+(HL)                  $CB,$1E
+(IX+d)                $DD,$CB,d,$1E
+(IY+d)                $FD,$CB,d,$1E
+
+[RRA]
+void                  $1F
+
+[RRC]
+r                     $CB,%00001rrr
+(HL)                  $CB,$0E
+(IX+d)                $DD,$CB,d,$0E
+(IY+d)                $FD,$CB,d,$0E
+
+[RRCA]
+void                  $0F
+
+[RRD]
+void                  $ED,$67
+
+[RST]
+p                     %11ppp111
+
+[SBC]
+A,r                   %10011rrr
+A,n                   $DE,n
+A,(HL)                $9E
+A,(IX+d)              $DD,$9E,d
+A,(IY+d)              $FD,$9E,d
+HL,dd                 $ED,%01dd0010
+
+[SCF]
+void                  $37
+
+[SET]
+b,r                   $CB,%11bbbrrr
+b,(HL)                $CB,%11bbb110
+b,(IX+d)              $DD,$CB,d,%11bbb110
+b,(IY+d)              $FD,$CB,d,%11bbb110
+
+[SLA]
+r                     $CB,%00100rrr
+(HL)                  $CB,$26
+(IX+d)                $DD,$CB,d,$26
+(IY+d)                $FD,$CB,d,$26
+
+[SRA]
+r                     $CB,%00101rrr
+(HL)                  $CB,$2E
+(IX+d)                $DD,$CB,d,$2E
+(IY+d)                $FD,$CB,d,$2E
+
+[SRL]
+r                     $CB,%00111rrr
+(HL)                  $CB,$3E
+(IX+d)                $DD,$CB,d,$3E
+(IY+d)                $FD,$CB,d,$3E
+
+[SUB]
+A,r                   %10010rrr
+A,n                   $D6,n
+A,(HL)                $96
+A,(IX+d)              $DD,$96,d
+A,(IY+d)              $FD,$96,d
+
+[XOR]
+A,r                   %10101rrr
+A,n                   $EE,n
+A,(HL)                $AE
+A,(IX+d)              $DD,$AE,d
+A,(IY+d)              $FD,$AE,d
+

+ 2 - 0
compiler/z80/z80nop.inc

@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from z80ins.dat; to regenerate, run 'make insdat' in the compiler directory }
+203;

+ 70 - 0
compiler/z80/z80op.inc

@@ -0,0 +1,70 @@
+{ don't edit, this file is generated from z80ins.dat; to regenerate, run 'make insdat' in the compiler directory }
+(
+A_None,
+A_ADC,
+A_ADD,
+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_OUTI,
+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);

Some files were not shown because too many files changed in this diff