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/ppcx64.lpi svneol=native#text/plain
 compiler/ppcx64llvm.lpi svneol=native#text/plain
 compiler/ppcx64llvm.lpi svneol=native#text/plain
 compiler/ppcxtensa.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/ppheap.pas svneol=native#text/plain
 compiler/ppu.pas svneol=native#text/plain
 compiler/ppu.pas svneol=native#text/plain
 compiler/procdefutil.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_wii.pas svneol=native#text/plain
 compiler/systems/i_win.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_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/mac_crea.txt svneol=native#text/plain
 compiler/systems/t_aix.pas svneol=native#text/plain
 compiler/systems/t_aix.pas svneol=native#text/plain
 compiler/systems/t_amiga.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_wii.pas svneol=native#text/plain
 compiler/systems/t_win.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_win16.pas svneol=native#text/plain
+compiler/systems/t_zxspectrum.pas svneol=native#text/plain
 compiler/tgobj.pas svneol=native#text/plain
 compiler/tgobj.pas svneol=native#text/plain
 compiler/tokens.pas svneol=native#text/plain
 compiler/tokens.pas svneol=native#text/plain
 compiler/utils/Makefile 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/mkx86ins.pp svneol=native#text/plain
 compiler/utils/mkx86reg.pp svneol=native#text/plain
 compiler/utils/mkx86reg.pp svneol=native#text/plain
 compiler/utils/mkxtensareg.pp svneol=native#text/pascal
 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/msg2inc.pp svneol=native#text/plain
 compiler/utils/msgdif.pp svneol=native#text/plain
 compiler/utils/msgdif.pp svneol=native#text/plain
 compiler/utils/msgused.pl svneol=native#text/plain
 compiler/utils/msgused.pl svneol=native#text/plain
@@ -1052,6 +1057,44 @@ compiler/xtensa/symcpu.pas svneol=native#text/pascal
 compiler/xtensa/xtensaatt.inc svneol=native#text/plain
 compiler/xtensa/xtensaatt.inc svneol=native#text/plain
 compiler/xtensa/xtensaop.inc svneol=native#text/plain
 compiler/xtensa/xtensaop.inc svneol=native#text/plain
 compiler/xtensa/xtensareg.dat 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.pp svneol=native#text/plain
 /fpmake_add1.inc svneol=native#text/plain
 /fpmake_add1.inc svneol=native#text/plain
 /fpmake_proc1.inc svneol=native#text/plain
 /fpmake_proc1.inc svneol=native#text/plain
@@ -12142,6 +12185,24 @@ rtl/xtensa/setjumph.inc svneol=native#text/plain
 rtl/xtensa/strings.inc svneol=native#text/plain
 rtl/xtensa/strings.inc svneol=native#text/plain
 rtl/xtensa/stringss.inc svneol=native#text/plain
 rtl/xtensa/stringss.inc svneol=native#text/plain
 rtl/xtensa/xtensa.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/MPWMake -text
 tests/Makefile svneol=native#text/plain
 tests/Makefile svneol=native#text/plain
 tests/Makefile.fpc 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/testit.h -text
 utils/h2pas/yylex.cod svneol=native#text/plain
 utils/h2pas/yylex.cod svneol=native#text/plain
 utils/h2pas/yyparse.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 svneol=native#text/plain
 utils/importtl/Makefile.fpc svneol=native#text/plain
 utils/importtl/Makefile.fpc svneol=native#text/plain
 utils/importtl/Makefile.fpc.fpcmake 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
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 #
 default: help
 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
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -416,6 +416,9 @@ endif
 ifeq ($(CPU_TARGET),xtensa)
 ifeq ($(CPU_TARGET),xtensa)
 PPSUF=xtensa
 PPSUF=xtensa
 endif
 endif
+ifeq ($(CPU_TARGET),z80)
+PPSUF=z80
+endif
 ifdef CROSSCOMPILE
 ifdef CROSSCOMPILE
 ifneq ($(CPU_TARGET),jvm)
 ifneq ($(CPU_TARGET),jvm)
 PPPRE=ppcross
 PPPRE=ppcross
@@ -799,6 +802,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_DIRS+=compiler rtl utils packages installer
 override TARGET_DIRS+=compiler rtl utils packages installer
 endif
 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
 override INSTALL_FPCPACKAGE=y
 ifdef REQUIRE_UNITSDIR
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
@@ -1245,6 +1254,9 @@ STATICLIBEXT=.a
 else
 else
 EXEEXT=.bin
 EXEEXT=.bin
 endif
 endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
 SHORTSUFFIX=emb
 SHORTSUFFIX=emb
 endif
 endif
 ifeq ($(OS_TARGET),win16)
 ifeq ($(OS_TARGET),win16)
@@ -1253,6 +1265,9 @@ STATICLIBEXT=.a
 SHAREDLIBEXT=.dll
 SHAREDLIBEXT=.dll
 SHORTSUFFIX=w16
 SHORTSUFFIX=w16
 endif
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
@@ -2705,6 +2720,20 @@ TARGET_DIRS_UTILS=1
 TARGET_DIRS_PACKAGES=1
 TARGET_DIRS_PACKAGES=1
 TARGET_DIRS_INSTALLER=1
 TARGET_DIRS_INSTALLER=1
 endif
 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
 ifdef TARGET_DIRS_COMPILER
 compiler_all:
 compiler_all:
 	$(MAKE) -C compiler all
 	$(MAKE) -C compiler all

+ 3 - 0
Makefile.fpc

@@ -94,6 +94,9 @@ endif
 ifeq ($(CPU_TARGET),xtensa)
 ifeq ($(CPU_TARGET),xtensa)
 PPSUF=xtensa
 PPSUF=xtensa
 endif
 endif
+ifeq ($(CPU_TARGET),z80)
+PPSUF=z80
+endif
 
 
 # cross compilers uses full cpu_target, not just ppc-suffix
 # cross compilers uses full cpu_target, not just ppc-suffix
 # (except if the target cannot run a native compiler)
 # (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
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 #
 default: all
 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
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -350,7 +350,7 @@ endif
 override PACKAGE_NAME=compiler
 override PACKAGE_NAME=compiler
 override PACKAGE_VERSION=3.3.1
 override PACKAGE_VERSION=3.3.1
 unexport FPC_VERSION FPC_COMPILERINFO
 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)
 ALLTARGETS=$(CYCLETARGETS)
 ifdef POWERPC
 ifdef POWERPC
 PPC_TARGET=powerpc
 PPC_TARGET=powerpc
@@ -406,6 +406,9 @@ endif
 ifdef XTENSA
 ifdef XTENSA
 PPC_TARGET=xtensa
 PPC_TARGET=xtensa
 endif
 endif
+ifdef Z80
+PPC_TARGET=z80
+endif
 ifndef PPC_TARGET
 ifndef PPC_TARGET
 PPC_TARGET=$(CPU_TARGET)
 PPC_TARGET=$(CPU_TARGET)
 endif
 endif
@@ -516,6 +519,9 @@ endif
 ifeq ($(CPC_TARGET),xtensa)
 ifeq ($(CPC_TARGET),xtensa)
 CPUSUF=xtensa
 CPUSUF=xtensa
 endif
 endif
+ifeq ($(CPC_TARGET),z80)
+CPUSUF=z80
+endif
 NOCPUDEF=1
 NOCPUDEF=1
 MSGFILE=msg/error$(FPCLANG).msg
 MSGFILE=msg/error$(FPCLANG).msg
 SVNVERSION:=$(firstword $(wildcard $(addsuffix /svnversion$(SRCEXEEXT),$(SEARCHPATH))))
 SVNVERSION:=$(firstword $(wildcard $(addsuffix /svnversion$(SRCEXEEXT),$(SEARCHPATH))))
@@ -631,6 +637,9 @@ endif
 ifeq ($(OS_TARGET),freertos)
 ifeq ($(OS_TARGET),freertos)
 NoNativeBinaries=1
 NoNativeBinaries=1
 endif
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+NoNativeBinaries=1
+endif
 ifeq ($(NoNativeBinaries),1)
 ifeq ($(NoNativeBinaries),1)
 override EXEEXT=$(SRCEXEEXT)
 override EXEEXT=$(SRCEXEEXT)
 CROSSINSTALL=1
 CROSSINSTALL=1
@@ -926,6 +935,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_DIRS+=utils
 override TARGET_DIRS+=utils
 endif
 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)
 ifeq ($(FULL_TARGET),i386-linux)
 override TARGET_PROGRAMS+=pp
 override TARGET_PROGRAMS+=pp
 endif
 endif
@@ -1217,6 +1232,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_PROGRAMS+=pp
 override TARGET_PROGRAMS+=pp
 endif
 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
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
@@ -1509,6 +1530,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
 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)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
 endif
@@ -1800,6 +1827,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
 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)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 endif
 endif
@@ -2091,6 +2124,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 endif
 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)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
 endif
@@ -2382,6 +2421,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
 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
 ifdef REQUIRE_UNITSDIR
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 override UNITSDIR+=$(REQUIRE_UNITSDIR)
 endif
 endif
@@ -2827,6 +2872,9 @@ STATICLIBEXT=.a
 else
 else
 EXEEXT=.bin
 EXEEXT=.bin
 endif
 endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
 SHORTSUFFIX=emb
 SHORTSUFFIX=emb
 endif
 endif
 ifeq ($(OS_TARGET),win16)
 ifeq ($(OS_TARGET),win16)
@@ -2835,6 +2883,9 @@ STATICLIBEXT=.a
 SHAREDLIBEXT=.dll
 SHAREDLIBEXT=.dll
 SHORTSUFFIX=w16
 SHORTSUFFIX=w16
 endif
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
@@ -3381,6 +3432,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_RTL=1
 endif
 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
 ifdef REQUIRE_PACKAGES_RTL
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 ifneq ($(PACKAGEDIR_RTL),)
 ifneq ($(PACKAGEDIR_RTL),)
@@ -4323,6 +4380,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 TARGET_DIRS_UTILS=1
 TARGET_DIRS_UTILS=1
 endif
 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
 ifdef TARGET_DIRS_UTILS
 utils_all:
 utils_all:
 	$(MAKE) -C utils all
 	$(MAKE) -C utils all
@@ -4603,7 +4666,10 @@ insdatarm : arm/armins.dat
 insdataarch64 : aarch64/a64ins.dat
 insdataarch64 : aarch64/a64ins.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mka64ins.pp
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mka64ins.pp
 	cd aarch64 && ..$(PATHSEP)utils$(PATHSEP)mka64ins$(SRCEXEEXT)
 	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
 regdatx86 : x86/x86reg.dat
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86reg.pp
 	$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86reg.pp
 	cd x86 && ..$(PATHSEP)utils$(PATHSEP)mkx86reg$(SRCEXEEXT) i8086
 	cd x86 && ..$(PATHSEP)utils$(PATHSEP)mkx86reg$(SRCEXEEXT) i8086
@@ -4632,7 +4698,10 @@ regdataarch64 : aarch64/a64reg.dat
 regdatmips : mips/mipsreg.dat
 regdatmips : mips/mipsreg.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkmpsreg.pp
 	cd mips && ..$(PATHSEP)utils$(PATHSEP)mkmpsreg$(SRCEXEEXT)
 	cd mips && ..$(PATHSEP)utils$(PATHSEP)mkmpsreg$(SRCEXEEXT)
-regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips 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 :
 revision.inc :
 ifneq ($(REVSTR),)
 ifneq ($(REVSTR),)
 ifdef USEZIPWRAPPER
 ifdef USEZIPWRAPPER

+ 20 - 3
compiler/Makefile.fpc

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

+ 3 - 0
compiler/aarch64/agcpugas.pas

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

+ 15 - 3
compiler/aasmbase.pas

@@ -240,7 +240,7 @@ interface
     function create_smartlink_library:boolean;inline;
     function create_smartlink_library:boolean;inline;
     function create_smartlink:boolean;inline;
     function create_smartlink:boolean;inline;
 
 
-    function ReplaceForbiddenAsmSymbolChars(const s: ansistring): ansistring;
+    function ApplyAsmSymbolRestrictions(const s: ansistring): ansistring;
 
 
     { dummy default noop callback }
     { dummy default noop callback }
     procedure default_global_used;
     procedure default_global_used;
@@ -257,7 +257,7 @@ interface
 implementation
 implementation
 
 
     uses
     uses
-      verbose;
+      verbose,fpccrc;
 
 
 
 
     function create_smartlink_sections:boolean;inline;
     function create_smartlink_sections:boolean;inline;
@@ -288,16 +288,28 @@ implementation
       end;
       end;
 
 
 
 
-    function ReplaceForbiddenAsmSymbolChars(const s: ansistring): ansistring;
+    function ApplyAsmSymbolRestrictions(const s: ansistring): ansistring;
       var
       var
         i : longint;
         i : longint;
         rchar: char;
         rchar: char;
+        crc: Cardinal;
+        charstoremove: integer;
       begin
       begin
         Result:=s;
         Result:=s;
         rchar:=target_asm.dollarsign;
         rchar:=target_asm.dollarsign;
         for i:=1 to Length(Result) do
         for i:=1 to Length(Result) do
           if Result[i]='$' then
           if Result[i]='$' then
             Result[i]:=rchar;
             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;
       end;
 
 
 
 

+ 29 - 29
compiler/aggas.pas

@@ -873,7 +873,7 @@ implementation
              begin
              begin
                if tai_section(hp).sectype<>sec_none then
                if tai_section(hp).sectype<>sec_none then
                  if replaceforbidden 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)
                      tai_section(hp).secalign,tai_section(hp).secflags,tai_section(hp).secprogbits)
                  else
                  else
                    WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder,
                    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
                    if tai_datablock(hp).is_global then
                      begin
                      begin
                        writer.AsmWrite(#9'.globl ');
                        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.AsmWriteln(':');
                        writer.AsmWrite(#9'.space ');
                        writer.AsmWrite(#9'.space ');
                        writer.AsmWriteln(tostr(tai_datablock(hp).size));
                        writer.AsmWriteln(tostr(tai_datablock(hp).size));
@@ -936,7 +936,7 @@ implementation
                    else
                    else
                      begin
                      begin
                        writer.AsmWrite(#9'.lcomm ');
                        writer.AsmWrite(#9'.lcomm ');
-                       writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
+                       writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
                        writer.AsmWrite(',');
                        writer.AsmWrite(',');
                        writer.AsmWrite(tostr(tai_datablock(hp).size)+',');
                        writer.AsmWrite(tostr(tai_datablock(hp).size)+',');
                        writer.AsmWrite('_data.bss_,');
                        writer.AsmWrite('_data.bss_,');
@@ -956,7 +956,7 @@ implementation
                          begin
                          begin
                            writer.AsmWrite(#9'.comm'#9);
                            writer.AsmWrite(#9'.comm'#9);
                            if replaceforbidden then
                            if replaceforbidden then
-                             writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name))
+                             writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name))
                            else
                            else
                              writer.AsmWrite(tai_datablock(hp).sym.name);
                              writer.AsmWrite(tai_datablock(hp).sym.name);
                            writer.AsmWrite(','+tostr(tai_datablock(hp).size));
                            writer.AsmWrite(','+tostr(tai_datablock(hp).size));
@@ -967,7 +967,7 @@ implementation
                          begin
                          begin
                            writer.AsmWrite(#9'.lcomm'#9);
                            writer.AsmWrite(#9'.lcomm'#9);
                            if replaceforbidden then
                            if replaceforbidden then
-                             writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
+                             writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
                            else
                            else
                              writer.AsmWrite(tai_datablock(hp).sym.name);
                              writer.AsmWrite(tai_datablock(hp).sym.name);
                            writer.AsmWrite(','+tostr(tai_datablock(hp).size));
                            writer.AsmWrite(','+tostr(tai_datablock(hp).size));
@@ -984,7 +984,7 @@ implementation
                              WriteHiddenSymbol(tai_datablock(hp).sym);
                              WriteHiddenSymbol(tai_datablock(hp).sym);
                            writer.AsmWrite(#9'.globl ');
                            writer.AsmWrite(#9'.globl ');
                            if replaceforbidden then
                            if replaceforbidden then
-                             writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name))
+                             writer.AsmWriteln(ApplyAsmSymbolRestrictions(Tai_datablock(hp).sym.name))
                            else
                            else
                              writer.AsmWriteln(Tai_datablock(hp).sym.name);
                              writer.AsmWriteln(Tai_datablock(hp).sym.name);
                          end;
                          end;
@@ -995,10 +995,10 @@ implementation
                        if replaceforbidden then
                        if replaceforbidden then
                          begin
                          begin
                            if (tf_needs_symbol_type in target_info.flags) then
                            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
                            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
                          end
                        else
                        else
                          begin
                          begin
@@ -1198,7 +1198,7 @@ implementation
                                else
                                else
                                  s:=tai_const(hp).sym.name;
                                  s:=tai_const(hp).sym.name;
                                if replaceforbidden then
                                if replaceforbidden then
-                                 s:=ReplaceForbiddenAsmSymbolChars(s);
+                                 s:=ApplyAsmSymbolRestrictions(s);
                                if tai_const(hp).value<>0 then
                                if tai_const(hp).value<>0 then
                                  s:=s+tostr_with_plus(tai_const(hp).value);
                                  s:=s+tostr_with_plus(tai_const(hp).value);
                              end
                              end
@@ -1300,12 +1300,12 @@ implementation
 {$endif arm}
 {$endif arm}
                      writer.AsmWrite('.globl'#9);
                      writer.AsmWrite('.globl'#9);
                      if replaceforbidden then
                      if replaceforbidden then
-                       writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
+                       writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
                      else
                      else
                        writer.AsmWriteLn(tai_label(hp).labsym.name);
                        writer.AsmWriteLn(tai_label(hp).labsym.name);
                    end;
                    end;
                   if replaceforbidden then
                   if replaceforbidden then
-                    writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
+                    writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
                   else
                   else
                     writer.AsmWrite(tai_label(hp).labsym.name);
                     writer.AsmWrite(tai_label(hp).labsym.name);
                   writer.AsmWriteLn(':');
                   writer.AsmWriteLn(':');
@@ -1323,7 +1323,7 @@ implementation
                 begin
                 begin
                   writer.AsmWrite('.globl'#9);
                   writer.AsmWrite('.globl'#9);
                   if replaceforbidden then
                   if replaceforbidden then
-                    writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name))
+                    writer.AsmWriteln(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name))
                   else
                   else
                     writer.AsmWriteln(tai_symbol(hp).sym.name);
                     writer.AsmWriteln(tai_symbol(hp).sym.name);
                   if (tai_symbol(hp).sym.bind=AB_PRIVATE_EXTERN) then
                   if (tai_symbol(hp).sym.bind=AB_PRIVATE_EXTERN) then
@@ -1358,14 +1358,14 @@ implementation
                        s:=#9'.llong .';
                        s:=#9'.llong .';
                        ch:='3';
                        ch:='3';
                      end;
                      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]');
                    writer.AsmWriteln(#9'.csect .text[PR]');
                    if (tai_symbol(hp).is_global) then
                    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
                    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 }
                    { the dotted name is the name of the actual function entry }
                    writer.AsmWrite('.');
                    writer.AsmWrite('.');
                  end
                  end
@@ -1386,9 +1386,9 @@ implementation
                  end;
                  end;
                if replaceforbidden then
                if replaceforbidden then
                  if not(tai_symbol(hp).has_value) 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
                  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
                else if not(tai_symbol(hp).has_value) then
                  writer.AsmWriteLn(tai_symbol(hp).sym.name + ':')
                  writer.AsmWriteLn(tai_symbol(hp).sym.name + ':')
                else
                else
@@ -1408,13 +1408,13 @@ implementation
                if replaceforbidden then
                if replaceforbidden then
                  begin
                  begin
                    { avoid string truncation }
                    { avoid string truncation }
-                   writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^));
+                   writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_symbolpair(hp).sym^));
                    writer.AsmWrite(s);
                    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
                    if tai_symbolpair(hp).kind=spk_set_global then
                      begin
                      begin
                        writer.AsmWrite(#9'.globl ');
                        writer.AsmWrite(#9'.globl ');
-                       writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^));
+                       writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbolpair(hp).sym^));
                      end;
                      end;
                  end
                  end
                else
                else
@@ -1443,7 +1443,7 @@ implementation
                      (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
                      (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
                     writer.AsmWrite('.');
                     writer.AsmWrite('.');
                   if replaceforbidden then
                   if replaceforbidden then
-                    writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name))
+                    writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_symbol_end(hp).sym.name))
                   else
                   else
                     writer.AsmWrite(tai_symbol_end(hp).sym.name);
                     writer.AsmWrite(tai_symbol_end(hp).sym.name);
                   writer.AsmWrite(', '+s+' - ');
                   writer.AsmWrite(', '+s+' - ');
@@ -1452,7 +1452,7 @@ implementation
                      (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
                      (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
                     writer.AsmWrite('.');
                     writer.AsmWrite('.');
                   if replaceforbidden then
                   if replaceforbidden then
-                    writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name))
+                    writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbol_end(hp).sym.name))
                   else
                   else
                     writer.AsmWriteLn(tai_symbol_end(hp).sym.name);
                     writer.AsmWriteLn(tai_symbol_end(hp).sym.name);
                 end;
                 end;
@@ -1527,7 +1527,7 @@ implementation
                if tai_directive(hp).name <>'' then
                if tai_directive(hp).name <>'' then
                  begin
                  begin
                    if replaceforbidden then
                    if replaceforbidden then
-                     writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_directive(hp).name))
+                     writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_directive(hp).name))
                    else
                    else
                      writer.AsmWrite(tai_directive(hp).name);
                      writer.AsmWrite(tai_directive(hp).name);
                  end;
                  end;
@@ -1617,7 +1617,7 @@ implementation
         if asminfo^.dollarsign='$' then
         if asminfo^.dollarsign='$' then
           writer.AsmWriteLn(s.name)
           writer.AsmWriteLn(s.name)
         else
         else
-          writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(s.name))
+          writer.AsmWriteLn(ApplyAsmSymbolRestrictions(s.name))
       end;
       end;
 
 
 
 
@@ -1635,7 +1635,7 @@ implementation
         if asminfo^.dollarsign='$' then
         if asminfo^.dollarsign='$' then
           writer.AsmWriteLn(sym.name)
           writer.AsmWriteLn(sym.name)
         else
         else
-          writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(sym.name))
+          writer.AsmWriteLn(ApplyAsmSymbolRestrictions(sym.name))
       end;
       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];
                                  system_arm_embedded,system_arm_symbian,system_arm_android,system_arm_aros,system_arm_freertos];
             flags : [af_needar,af_smartlink_sections];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -458,6 +459,7 @@ unit agarmgas;
             supported_targets : [system_arm_darwin];
             supported_targets : [system_arm_darwin];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -472,6 +474,7 @@ unit agarmgas;
             supported_targets : [system_arm_darwin];
             supported_targets : [system_arm_darwin];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );

+ 1 - 0
compiler/arm/cpuelf.pas

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

+ 3 - 2
compiler/avr/agavrgas.pas

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

+ 4 - 0
compiler/cgbase.pas

@@ -107,6 +107,10 @@ interface
          ,addr_hi8
          ,addr_hi8
          ,addr_hi8_gs
          ,addr_hi8_gs
          {$ENDIF}
          {$ENDIF}
+         {$IFDEF Z80}
+         ,addr_lo8
+         ,addr_hi8
+         {$ENDIF}
          {$IFDEF i8086}
          {$IFDEF i8086}
          ,addr_dgroup      // the data segment group
          ,addr_dgroup      // the data segment group
          ,addr_fardataseg  // the far data segment of the current pascal module (unit or program)
          ,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)}
 {$if defined(cpu8bitalu) or defined(cpu16bitalu)}
     function tcg.GetNextReg(const r: TRegister): TRegister;
     function tcg.GetNextReg(const r: TRegister): TRegister;
       begin
       begin
-{$ifndef AVR}
+{$ifdef AVR}
         { the AVR code generator depends on the fact that it can do GetNextReg also on physical registers }
         { 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
         if getsupreg(r)<first_int_imreg then
           internalerror(2013051401);
           internalerror(2013051401);
         if not has_next_reg[getsupreg(r)] then
         if not has_next_reg[getsupreg(r)] then
           internalerror(2017091103);
           internalerror(2017091103);
-{$else AVR}
-        if (getsupreg(r)>=first_int_imreg) and not(has_next_reg[getsupreg(r)]) then
-          internalerror(2017091103);
 {$endif AVR}
 {$endif AVR}
         if getregtype(r)<>R_INTREGISTER then
         if getregtype(r)<>R_INTREGISTER then
           internalerror(2017091101);
           internalerror(2017091101);
@@ -2103,6 +2103,8 @@ implementation
                     a_load_const_reg(list,OS_8,0,dst);
                     a_load_const_reg(list,OS_8,0,dst);
                     exit;
                     exit;
                   end;
                   end;
+                else
+                  ;
               end;
               end;
           end;
           end;
         OP_SHR:
         OP_SHR:
@@ -2115,6 +2117,8 @@ implementation
                     a_load_const_reg(list,OS_8,0,GetNextReg(dst));
                     a_load_const_reg(list,OS_8,0,GetNextReg(dst));
                     exit;
                     exit;
                   end;
                   end;
+                else
+                  ;
               end;
               end;
           end;
           end;
 {$endif cpu8bitalu}
 {$endif cpu8bitalu}

+ 6 - 6
compiler/dbgstabs.pas

@@ -197,7 +197,7 @@ implementation
       if (Sym.typ=typesym) and (ttypesym(Sym).Fprettyname<>'') then
       if (Sym.typ=typesym) and (ttypesym(Sym).Fprettyname<>'') then
         result:=ttypesym(Sym).FPrettyName;
         result:=ttypesym(Sym).FPrettyName;
       if target_asm.dollarsign<>'$' then
       if target_asm.dollarsign<>'$' then
-        result:=ReplaceForbiddenAsmSymbolChars(result);
+        result:=ApplyAsmSymbolRestrictions(result);
     end;
     end;
 
 
     function GetSymTableName(SymTable : TSymTable) : string;
     function GetSymTableName(SymTable : TSymTable) : string;
@@ -207,7 +207,7 @@ implementation
       else
       else
         result := SymTable.RealName^;
         result := SymTable.RealName^;
       if target_asm.dollarsign<>'$' then
       if target_asm.dollarsign<>'$' then
-        result:=ReplaceForbiddenAsmSymbolChars(result);
+        result:=ApplyAsmSymbolRestrictions(result);
     end;
     end;
 
 
     const
     const
@@ -1190,7 +1190,7 @@ implementation
         if s='name' then
         if s='name' then
           result:=GetSymName(sym)
           result:=GetSymName(sym)
         else if s='mangledname' then
         else if s='mangledname' then
-          result:=ReplaceForbiddenAsmSymbolChars(sym.mangledname)
+          result:=ApplyAsmSymbolRestrictions(sym.mangledname)
         else if s='ownername' then
         else if s='ownername' then
           result:=GetSymTableName(sym.owner)
           result:=GetSymTableName(sym.owner)
         else if s='line' then
         else if s='line' then
@@ -1217,7 +1217,7 @@ implementation
 
 
     function TDebugInfoStabs.staticvarsym_mangled_name(sym: tstaticvarsym): string;
     function TDebugInfoStabs.staticvarsym_mangled_name(sym: tstaticvarsym): string;
       begin
       begin
-        result:=ReplaceForbiddenAsmSymbolChars(sym.mangledname);
+        result:=ApplyAsmSymbolRestrictions(sym.mangledname);
       end;
       end;
 
 
 
 
@@ -1228,7 +1228,7 @@ implementation
            assigned(def.owner.name) then
            assigned(def.owner.name) then
           list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
           list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
                  def_stab_number(vmttype)+'",'+
                  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;
       end;
 
 
 
 
@@ -1401,7 +1401,7 @@ implementation
                assigned(tprocdef(def.owner.defowner).procsym) then
                assigned(tprocdef(def.owner.defowner).procsym) then
               info := ','+GetSymName(def.procsym)+','+GetSymName(tprocdef(def.owner.defowner).procsym);
               info := ','+GetSymName(def.procsym)+','+GetSymName(tprocdef(def.owner.defowner).procsym);
           end;
           end;
-        mangledname:=ReplaceForbiddenAsmSymbolChars(def.mangledname);
+        mangledname:=ApplyAsmSymbolRestrictions(def.mangledname);
         if target_info.system in systems_dotted_function_names then
         if target_info.system in systems_dotted_function_names then
           mangledname:='.'+mangledname;
           mangledname:='.'+mangledname;
         result.concat(Tai_stab.Create_ansistr(stabsdir,'"'+obj+':'+RType+def_stab_number(def.returndef)+info+'",'+
         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
     begin
       { create reference to the local symbol at the same address as the global
       { 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) }
         symbol (with same name as unmangled symbol, so GDB can find it) }
-      Result:=ReplaceForbiddenAsmSymbolChars(sym.name);
+      Result:=ApplyAsmSymbolRestrictions(sym.name);
     end;
     end;
 
 
 
 
@@ -109,7 +109,7 @@ implementation
              assigned(def.owner.name) then
              assigned(def.owner.name) then
             list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
             list.concat(Tai_stab.create_ansistr(stabsdir,ansistring('"vmt_')+GetSymTableName(def.owner)+tobjectdef(def).objname^+':S'+
                    def_stab_number(vmttype)+'",'+
                    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;
         end;
 *)
 *)
       { do nothing, because creating debug information for a global symbol
       { do nothing, because creating debug information for a global symbol
@@ -193,7 +193,7 @@ implementation
         the place where it is defined }
         the place where it is defined }
       if not assigned(def.procstarttai) then
       if not assigned(def.procstarttai) then
         exit;
         exit;
-      mangledname:=ReplaceForbiddenAsmSymbolChars(def.mangledname);
+      mangledname:=ApplyAsmSymbolRestrictions(def.mangledname);
       if target_info.system in systems_dotted_function_names then
       if target_info.system in systems_dotted_function_names then
         mangledname:='.'+mangledname;
         mangledname:='.'+mangledname;
       result.concat(tai_stab.create(stabx_function,
       result.concat(tai_stab.create(stabx_function,
@@ -254,7 +254,7 @@ implementation
       result:=inherited gen_procdef_endsym_stabs(def);
       result:=inherited gen_procdef_endsym_stabs(def);
       if not assigned(def.procstarttai) then
       if not assigned(def.procstarttai) then
         exit;
         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);
       current_asmdata.asmlists[al_procedures].insertbefore(tai_symbol.create(procendsymbol,0),def.procendtai);
     end;
     end;
 
 

+ 4 - 2
compiler/entfile.pas

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

+ 17 - 0
compiler/fpcdefs.inc

@@ -295,6 +295,23 @@
   {$define cpurequiresproperalignment}
   {$define cpurequiresproperalignment}
 {$endif riscv32}
 {$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}
 {$ifdef riscv64}
   {$define riscv}
   {$define riscv}
   {$define cpu64bit}
   {$define cpu64bit}

+ 10 - 0
compiler/globals.pas

@@ -561,6 +561,16 @@ interface
         asmcputype : cpu_none;
         asmcputype : cpu_none;
         fputype : fpu_none;
         fputype : fpu_none;
   {$endif xtensa}
   {$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}
 {$endif not GENERIC_CPU}
         asmmode : asmmode_standard;
         asmmode : asmmode_standard;
 {$ifndef jvm}
 {$ifndef jvm}

+ 1 - 0
compiler/i386/cpuelf.pas

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

+ 1 - 0
compiler/jvm/agjasmin.pas

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

+ 24 - 4
compiler/link.pas

@@ -867,7 +867,8 @@ Implementation
 
 
 
 
         scripted_ar:=(target_ar.id=ar_gnu_ar_scripted) or
         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
         if scripted_ar then
           begin
           begin
@@ -876,7 +877,7 @@ Implementation
             Assign(script, scriptfile);
             Assign(script, scriptfile);
             Rewrite(script);
             Rewrite(script);
             try
             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)
                 writeln(script, 'CREATE ' + current_module.staticlibfilename)
               else { wlib case }
               else { wlib case }
                 writeln(script,'-q -fo -c -b '+
                 writeln(script,'-q -fo -c -b '+
@@ -884,13 +885,13 @@ Implementation
               current := TCmdStrListItem(SmartLinkOFiles.First);
               current := TCmdStrListItem(SmartLinkOFiles.First);
               while current <> nil do
               while current <> nil do
                 begin
                 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)
                   writeln(script, 'ADDMOD ' + current.str)
                   else
                   else
                     writeln(script,'+' + current.str);
                     writeln(script,'+' + current.str);
                   current := TCmdStrListItem(current.next);
                   current := TCmdStrListItem(current.next);
                 end;
                 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
                 begin
                   writeln(script, 'SAVE');
                   writeln(script, 'SAVE');
                   writeln(script, 'END');
                   writeln(script, 'END');
@@ -1742,6 +1743,23 @@ Implementation
             arfinishcmd : ''
             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
 initialization
   RegisterAr(ar_gnu_ar_info);
   RegisterAr(ar_gnu_ar_info);
@@ -1749,4 +1767,6 @@ initialization
   RegisterAr(ar_gnu_gar_info);
   RegisterAr(ar_gnu_gar_info);
   RegisterAr(ar_watcom_wlib_omf_info);
   RegisterAr(ar_watcom_wlib_omf_info);
   RegisterAr(ar_watcom_wlib_omf_scripted_info);
   RegisterAr(ar_watcom_wlib_omf_scripted_info);
+  RegisterAr(ar_sdcc_sdar_info);
+  RegisterAr(ar_sdcc_sdar_scripted_info);
 end.
 end.

+ 3 - 1
compiler/llvm/agllvm.pas

@@ -1271,7 +1271,7 @@ implementation
                      writer.AsmWriteln(asminfo^.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
                      writer.AsmWriteln(asminfo^.comment+'global/privateextern label: '+tai_label(hp).labsym.name);
                    end;
                    end;
                  if replaceforbidden then
                  if replaceforbidden then
-                   writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
+                   writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name))
                  else
                  else
                    writer.AsmWrite(tai_label(hp).labsym.name);
                    writer.AsmWrite(tai_label(hp).labsym.name);
                  writer.AsmWriteLn(':');
                  writer.AsmWriteLn(':');
@@ -1737,6 +1737,7 @@ implementation
           supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_aarch64_linux,system_arm_linux];
           supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_aarch64_linux,system_arm_linux];
           flags : [af_smartlink_sections,af_llvm];
           flags : [af_smartlink_sections,af_llvm];
           labelprefix : 'L';
           labelprefix : 'L';
+          labelmaxlen : -1;
           comment : '; ';
           comment : '; ';
           dollarsign: '$';
           dollarsign: '$';
         );
         );
@@ -1751,6 +1752,7 @@ implementation
           supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_aarch64_linux,system_arm_linux];
           supported_targets : [system_x86_64_linux,system_x86_64_darwin,system_aarch64_linux,system_arm_linux];
           flags : [af_smartlink_sections,af_llvm];
           flags : [af_smartlink_sections,af_llvm];
           labelprefix : 'L';
           labelprefix : 'L';
+          labelmaxlen : -1;
           comment : '; ';
           comment : '; ';
           dollarsign: '$';
           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];
             supported_targets : [system_m68k_macos,system_m68k_linux,system_m68k_PalmOS,system_m68k_netbsd,system_m68k_embedded];
             flags : [af_needar,af_smartlink_sections];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -368,6 +369,7 @@ interface
             supported_targets : [system_m68k_Amiga,system_m68k_Atari];
             supported_targets : [system_m68k_Amiga,system_m68k_Atari];
             flags : [af_needar];
             flags : [af_needar];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );

+ 1 - 0
compiler/m68k/ag68kvasm.pas

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

+ 2 - 0
compiler/mips/cpugas.pas

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

+ 6 - 0
compiler/msg/errore.msg

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

+ 1 - 1
compiler/msgidx.inc

@@ -1126,7 +1126,7 @@ const
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 85203;
+  MsgTxtSize = 85330;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
     28,106,356,129,99,63,143,36,223,68,
     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+
   'A*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'S*2Aas_Assemble u','sing 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+
   '**1b_Generate browser info'#010+
   '**2bl_Generate local symbol info'#010+
   '**2bl_Generate local symbol info'#010+
   '**1B_Build all modules'#010+
   '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#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+
   '**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+
   '**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_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 '+
   '**2Cf<x>_Select fpu instruction set to use; see fpc -i or fpc -if for '+
   'possible values'#010+
   '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+
   '**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+
   '**2Ci_IO-checking'#010+
   'A*2CI<x>_Select instruction set on ARM: ARM or THUMB'#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'+
   'l*3CLfltonosystem_Disable LTO for the system unit (needed with at leas'+
   't Xcode 10.2 and earlier due to linker bugs)'#010+
   '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+
   'P*2CN_Generate nil-pointer checks (AIX-only)'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible 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 '+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
   'and 8'#010+
   '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
   '**3CPPACKENUM=<y>_ <y> enum packing: 0, 1, 2 and 4 or DEFAULT or NORMA'+
   'L'#010+
   '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_Range checking'#010+
   '**2CR_Verify object method call validity'#010+
   '**2CR_Verify object method call validity'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
   '**2Cs<n>_Set stack checking size to <n>'#010+
   '**2Ct_Stack checking (for testing only, see manual)'#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+
   '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 options'#010+
+  'P*2CT<x>_Target-specific code generation option','s'#010+
   'J*2CT<x>_Target-specific code generation options'#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'+
   'p*3CTsmalltoc_ Generate smaller TOCs at the expense of execution speed'+
   ' (AIX)'#010+
   ' (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 '+
   'J*3CTautosetterprefix=X_  Automatically create setters for properties '+
   'with prefix X (empty string disables)'#010+
   '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 '+
   '3*3CTcld_                 Emit a CLD instruction before using the x86 '+
   'string instructions'#010+
   '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+
   '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'+
   'J*3CTcompactintarrayinit_ Generate smaller (but potentially slower) co'+
   'de for initializing integer array constants'#010+
   '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'+
   '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'+
   'A*3CTthumbinterworking_ Generate Thumb interworking-safe code if possi'+
   'ble'#010+
   'ble'#010+
   'J*2Cv_Var/out parameter copy-out checking'#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+
   '**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+
   '**1D_Generate a DEF file'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
   '*O2Dw_PM application'#010+
   '**1e<x>_Set path to executable'#010+
   '**1e<x>_Set path to executable'#010+
-  '**1E_Same as -Cn'#010+
+  '**1E_S','ame as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1F<x>_Set file names and paths:'#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 input codepage to <x>'#010+
   '**2FC<x>_Set RC compiler binary name 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+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#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>_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'+
   '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
   'r'#010+
   'r'#010+
   '**2FM<x>_Set the directory where to search for unicode binary files'#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>_Load error message file <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2Fu<x>_Add <x> to unit path'#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>_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+
   '*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+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
   '*g2gl_Use line info unit (show more info with backtraces)'#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+
   '*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'+
   '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
   #010+
   #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'+
   '*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+
   '*g2gs_Generate Stabs debug information'#010+
   '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
   '*g2gt_Trash local variables (to detect uninitialized uses; multiple '#039+
   't'#039' changes the trashing value)'#010+
   '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+
   '*g2gw2_Generate DWARFv2 debug information'#010+
   '*g2gw3_Generate DWARFv3 debug information'#010+
   '*g2gw3_Generate DWARFv3 debug information'#010+
   '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
   '*g2gw4_Generate DWARFv4 debug information (experimental)'#010+
-  '**1i_Information'#010+
+  '**1i_In','formation'#010+
   '**2iD_Return compiler date'#010+
   '**2iD_Return compiler date'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSO_Return compiler OS'#010+
-  '**2iSP_Return c','ompiler host processor'#010+
+  '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
   '**2iTO_Return target OS'#010+
   '**2iTP_Return target processor'#010+
   '**2iTP_Return target processor'#010+
   '**2iV_Return short compiler version'#010+
   '**2iV_Return short compiler version'#010+
   '**2iW_Return full 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+
   '**2ic_Return list of supported CPU instruction sets'#010+
   '**2if_Return list of supported FPU instruction sets'#010+
   '**2if_Return list of supported FPU instruction sets'#010+
   '**2ii_Return list of supported inline assembler modes'#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+
   '**2ir_Return list of recognized compiler and RTL features'#010+
   '**2it_Return list of supported targets'#010+
   '**2it_Return list of supported targets'#010+
   '**2iu_Return list of supported microcontroller types'#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+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
   '**1l_Write logo'#010+
   '**1M<x>_Set language mode to <x> / enable modeswitch <x> (see option -'+
   '**1M<x>_Set language mode to <x> / enable modeswitch <x> (see option -'+
   'im)'#010+
   'im)'#010+
-  '**2Mfpc_Free Pascal dialect (default)'#010+
+  '**2Mfpc_Free Pascal dialect (d','efault)'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#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+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**2Miso_ISO 7185 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+
   '**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'+
   '**2*_Other modeswitches are disabled and need to be enabled one by ano'+
   'ther.'#010+
   '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+
   '**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+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
   '**2O-_Disable optimizations'#010+
   '**2O1_Level 1 optimizations (quick and debugger friendly)'#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'+
   '**2O4_Level 4 optimizations (-O3 + optimizations which might have unex'+
   'pected side effects)'#010+
   'pected side effects)'#010+
   '**2Oa<x>=<y>_Set alignment'#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'+
   '**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+
   '**2Os_Optimize for size rather than speed'#010+
   '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#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*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'+
   'F*2P<x>_Set target CPU (aarch64,arm,avr,i386,i8086,jvm,m68k,mips,mipse'+
   'l,powerpc,powerpc64,sparc,x86_64)'#010+
   'l,powerpc,powerpc64,sparc,x86_64)'#010+
   '**1R<x>_Assembler reading style:'#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*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*2Ratt_Read AT&T style assembler'#010+
   '4*2Rintel_Read Intel style assembler'#010+
   '4*2Rintel_Read Intel style assembler'#010+
   '8*2Ratt_Read AT&T 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+
   '6*2RMOT_Read Motorola style assembler'#010+
   '**1S<x>_Syntax options:'#010+
   '**1S<x>_Syntax options:'#010+
-  '**2S2_Same',' as -Mobjfpc'#010+
+  '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#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*_<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*_n : Compiler also halts after notes'#010+
   '**3*_h : Compiler also halts after hints'#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'+
   '**2Sh_Use reference counted strings (ansistring by default) instead of'+
   ' shortstrings'#010+
   ' 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+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**3SIcom_COM compatible interface (default)'#010+
   '**3SIcom_COM compatible interface (default)'#010+
   '**3SIcorba_CORBA compatible interface'#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+
   '**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+
   '**2Ss_Constructor name must be init (destructor must be done)'#010+
   '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
   '**2Sv_Support vector processing (use CPU vector extensions if availabl'+
   'e)'#010+
   '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+
   '**1s_Do not call assembler and linker'#010+
   '**2sh_Generate script to link on host'#010+
   '**2sh_Generate script to link on host'#010+
   '**2st_Generate script to link on target'#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+
   '**1T<x>_Target operating system:'#010+
-  '3*2Tandroid','_Android'#010+
+  '3*2Tandroid_Android'#010+
   '3*2Taros_AROS'#010+
   '3*2Taros_AROS'#010+
   '3*2Tbeos_BeOS'#010+
   '3*2Tbeos_BeOS'#010+
   '3*2Tdarwin_Darwin/Mac OS X'#010+
   '3*2Tdarwin_Darwin/Mac OS X'#010+
   '3*2Tembedded_Embedded'#010+
   '3*2Tembedded_Embedded'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Tfreebsd_FreeBSD'#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*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*2Tlinux_Linux'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
   '3*2Tnativent_Native NT API (experimental)'#010+
   '3*2Tnetbsd_NetBSD'#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*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Topenbsd_OpenBSD'#010+
-  '3*2Tos','2_OS/2 / eComStation'#010+
+  '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tsymbian_Symbian OS'#010+
   '3*2Tsymbian_Symbian OS'#010+
   '3*2Tsolaris_Solaris'#010+
   '3*2Tsolaris_Solaris'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twin32_Windows 32 Bit'#010+
   '3*2Twin32_Windows 32 Bit'#010+
-  '3*2Twince_Windows CE'#010+
+  '3*','2Twince_Windows CE'#010+
   '4*2Tandroid_Android'#010+
   '4*2Tandroid_Android'#010+
   '4*2Taros_AROS'#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*2Tdragonfly_DragonFly BSD'#010+
   '4*2Tembedded_Embedded'#010+
   '4*2Tembedded_Embedded'#010+
   '4*2Tfreebsd_FreeBSD'#010+
   '4*2Tfreebsd_FreeBSD'#010+
@@ -1769,10 +1773,10 @@ const msgtxt : array[0..000355,1..240] of char=(
   '4*2Tiphonesim_iPhoneSimulator'#010+
   '4*2Tiphonesim_iPhoneSimulator'#010+
   '4*2Tlinux_Linux'#010+
   '4*2Tlinux_Linux'#010+
   '4*2Tnetbsd_NetBSD'#010+
   '4*2Tnetbsd_NetBSD'#010+
-  '4*2Topenbsd_OpenBSD'#010+
+  '4*2Topenbs','d_OpenBSD'#010+
   '4*2Tsolaris_Solaris'#010+
   '4*2Tsolaris_Solaris'#010+
   '4*2Twin64_Win64 (64 bit Windows systems)'#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*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tembedded_Embedded'#010+
   '6*2Tembedded_Embedded'#010+
   '6*2Tlinux_Linux'#010+
   '6*2Tlinux_Linux'#010+
@@ -1780,21 +1784,21 @@ const msgtxt : array[0..000355,1..240] of char=(
   '6*2Tmacos_Mac OS'#010+
   '6*2Tmacos_Mac OS'#010+
   '6*2Tpalmos_PalmOS'#010+
   '6*2Tpalmos_PalmOS'#010+
   '8*2Tembedded_Embedded'#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+
   '8*2Twin16_Windows 16 Bit'#010+
   'A*2Tandroid_Android'#010+
   'A*2Tandroid_Android'#010+
-  'A*2','Taros_AROS'#010+
+  'A*2Taros_AROS'#010+
   'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
   'A*2Tdarwin_Darwin/iPhoneOS/iOS'#010+
   'A*2Tembedded_Embedded'#010+
   'A*2Tembedded_Embedded'#010+
   'A*2Tfreertos_FreeRTOS'#010+
   'A*2Tfreertos_FreeRTOS'#010+
   'A*2Tgba_Game Boy Advance'#010+
   'A*2Tgba_Game Boy Advance'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Tnds_Nintendo DS'#010+
   'A*2Tnds_Nintendo DS'#010+
-  'A*2Tnetbsd_NetBSD'#010+
+  'A*2Tnetbsd_NetB','SD'#010+
   'A*2Tpalmos_PalmOS'#010+
   'A*2Tpalmos_PalmOS'#010+
   'A*2Tsymbian_Symbian'#010+
   'A*2Tsymbian_Symbian'#010+
   'A*2Twince_Windows CE'#010+
   'A*2Twince_Windows CE'#010+
-  'a*2Tandroid_Andr','oid'#010+
+  'a*2Tandroid_Android'#010+
   'a*2Tdarwin_Darwin/iOS'#010+
   'a*2Tdarwin_Darwin/iOS'#010+
   'a*2Tlinux_Linux'#010+
   'a*2Tlinux_Linux'#010+
   'a*2Twin64_Windows 64'#010+
   'a*2Twin64_Windows 64'#010+
@@ -1803,11 +1807,11 @@ const msgtxt : array[0..000355,1..240] of char=(
   'm*2Tandroid_Android'#010+
   'm*2Tandroid_Android'#010+
   'm*2Tembedded_Embedded'#010+
   'm*2Tembedded_Embedded'#010+
   'm*2Tlinux_Linux'#010+
   'm*2Tlinux_Linux'#010+
-  'M*2Tembedded_Embedded'#010+
+  'M*2Temb','edded_Embedded'#010+
   'M*2Tlinux_Linux'#010+
   'M*2Tlinux_Linux'#010+
   'P*2Taix_AIX'#010+
   'P*2Taix_AIX'#010+
   'P*2Tamiga_AmigaOS'#010+
   'P*2Tamiga_AmigaOS'#010+
-  'P*2Tdarwin_Darwin','/Mac OS X'#010+
+  'P*2Tdarwin_Darwin/Mac OS X'#010+
   'P*2Tembedded_Embedded'#010+
   'P*2Tembedded_Embedded'#010+
   'P*2Tlinux_Linux'#010+
   'P*2Tlinux_Linux'#010+
   'P*2Tmacos_Mac OS (classic)'#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*2Tnetbsd_NetBSD'#010+
   'P*2Twii_Wii'#010+
   'P*2Twii_Wii'#010+
   'p*2Taix_AIX'#010+
   'p*2Taix_AIX'#010+
-  'p*2Tdarwin_Darwin/Mac OS X'#010+
+  'p*2Tdarwin_Darwin/Mac OS ','X'#010+
   'p*2Tembedded_Embedded'#010+
   'p*2Tembedded_Embedded'#010+
   'p*2Tlinux_Linux'#010+
   'p*2Tlinux_Linux'#010+
   'R*2Tlinux_Linux'#010+
   'R*2Tlinux_Linux'#010+
-  'R*2Tembedded_Embedded'#010,
+  'R*2Tembedded_Embedded'#010+
   'r*2Tlinux_Linux'#010+
   'r*2Tlinux_Linux'#010+
   'r*2Tembedded_Embedded'#010+
   'r*2Tembedded_Embedded'#010+
   'S*2Tlinux_Linux'#010+
   'S*2Tlinux_Linux'#010+
@@ -1828,148 +1832,151 @@ const msgtxt : array[0..000355,1..240] of char=(
   'V*2Tembedded_Embedded'#010+
   'V*2Tembedded_Embedded'#010+
   'x*2Tembedded_Embedded'#010+
   'x*2Tembedded_Embedded'#010+
   'x*2Tfreertos_FreeRTOS'#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<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#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+
   '**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+
   '**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*_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*_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*_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'+
   '**2*_a : Show everything             x : Show info about invoked tools'+
   #010+
   #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*_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'+
   'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
   'or version)'#010+
   '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+
   '3*2WA_Specify native type application (Windows)'#010+
   '4*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+
   '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+
   '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+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '4*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+
   '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+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
   'A*2WB_Create a relocatable image (Windows, Symbian)'#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+
   '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+
   '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+
   '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+
   'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#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+
   '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+
   '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+
   '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   '4*2WG_Specify graphic type application (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+
   '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+
   '4*2Wi_Use internal resources (Darwin)'#010+
   'a*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+
   '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+
   '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'+
   '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
   'e segment)'#010+
   '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*3WmTiny_Tiny memory model'#010+
   '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmMedium_Medium memory model'#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*3WmLarge_Large memory model'#010+
   '8*3WmHuge_Huge 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'+
   '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
   '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+
   '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+
   '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*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+
   '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'+
   'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
   '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+
   '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+
   '3*2WR_Generate relocation code (Windows)'#010+
   '4*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*2Wt<x>_Set the target executable format'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#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+
   '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+
   '**1X_Executable options:'#010+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
   '9.1 (Linux)'#010+
   '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+
   '**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 '+
   '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
   'to executable'#010+
   '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+
   '**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+
   '**2XLA_Define library substitutions for linking'#010+
   '**2XLO_Define order of library 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_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)'+
   '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
   #010+
   #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+
   '**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_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_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+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1*_'#010+
   '**1?_Show this help'#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;
                      result := nil;
 
 
                      case torddef(resultdef).ordtype of
                      case torddef(resultdef).ordtype of
+                       s8bit:
+                         procname := 'fpc_mul_shortint';
+                       u8bit:
+                         procname := 'fpc_mul_byte';
                        s16bit:
                        s16bit:
                          procname := 'fpc_mul_integer';
                          procname := 'fpc_mul_integer';
                        u16bit:
                        u16bit:
@@ -4158,19 +4162,29 @@ implementation
 
 
          else if is_implicit_pointer_object_type(ld) then
          else if is_implicit_pointer_object_type(ld) then
             begin
             begin
-              expectloc:=LOC_FLAGS;
+              if ld.size>sizeof(aint) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
             end
             end
 
 
          else if (ld.typ=classrefdef) then
          else if (ld.typ=classrefdef) then
             begin
             begin
-              expectloc:=LOC_FLAGS;
+              if ld.size>sizeof(aint) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
             end
             end
 
 
          { support procvar=nil,procvar<>nil }
          { support procvar=nil,procvar<>nil }
          else if ((ld.typ=procvardef) and (rt=niln)) or
          else if ((ld.typ=procvardef) and (rt=niln)) or
                  ((rd.typ=procvardef) and (lt=niln)) then
                  ((rd.typ=procvardef) and (lt=niln)) then
             begin
             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
             end
 
 
 {$ifdef SUPPORT_MMX}
 {$ifdef SUPPORT_MMX}
@@ -4192,12 +4206,18 @@ implementation
                   (ld.typ=procvardef) and
                   (ld.typ=procvardef) and
                   equal_defs(rd,ld) then
                   equal_defs(rd,ld) then
            begin
            begin
-             expectloc:=LOC_FLAGS;
+             if tprocvardef(ld).size>sizeof(aint) then
+               expectloc:=LOC_JUMP
+             else
+               expectloc:=LOC_FLAGS;
            end
            end
 
 
          else if (ld.typ=enumdef) then
          else if (ld.typ=enumdef) then
            begin
            begin
-              expectloc:=LOC_FLAGS;
+              if tenumdef(ld).size>sizeof(aint) then
+                expectloc:=LOC_JUMP
+              else
+                expectloc:=LOC_FLAGS;
            end
            end
 
 
 {$ifdef SUPPORT_MMX}
 {$ifdef SUPPORT_MMX}

+ 2 - 2
compiler/ncal.pas

@@ -4144,8 +4144,8 @@ implementation
                               That means the for pushes the para with the
                               That means the for pushes the para with the
                               highest offset (see para3) needs to be pushed first
                               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   }
                             { parameters to be in this order so they can use   }
                             { pushes in case of no fixed stack                 }
                             { pushes in case of no fixed stack                 }
                             if (not paramanager.use_fixed_stack and
                             if (not paramanager.use_fixed_stack and

+ 13 - 1
compiler/ngenutil.pas

@@ -1516,6 +1516,18 @@ implementation
           );
           );
           tcb.free;
           tcb.free;
         end;
         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}
 {$IFDEF POWERPC}
       { AmigaOS4 "stack cookie" support }
       { AmigaOS4 "stack cookie" support }
       if ( target_info.system = system_powerpc_amiga ) then
       if ( target_info.system = system_powerpc_amiga ) then
@@ -1547,7 +1559,7 @@ implementation
       tcb.free;
       tcb.free;
 
 
       { allocate an initial heap on embedded systems }
       { 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
         begin
           { tai_datablock cannot yet be handled via the high level typed const
           { tai_datablock cannot yet be handled via the high level typed const
             builder, because it implies the generation of a symbol, while this
             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_arctan_real,
               in_ln_real :
               in_ln_real :
                 begin
                 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 }
                   { converting an int64 to double on platforms without }
                   { extended can cause precision loss                  }
                   { 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^;
                   resultdef:=pbestrealtype^;
                 end;
                 end;
 
 
@@ -3572,7 +3579,14 @@ implementation
               in_sqr_real,
               in_sqr_real,
               in_sqrt_real :
               in_sqrt_real :
                 begin
                 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;
                   setfloatresultdef;
                 end;
                 end;
 
 
@@ -4154,30 +4168,42 @@ implementation
 
 
 
 
      function tinlinenode.first_arctan_real : tnode;
      function tinlinenode.first_arctan_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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',
         result := ccallnode.createintern('fpc_arctan_real',
-                ccallparanode.create(left,nil));
-        left := nil;
+                ccallparanode.create(temp_pnode^,nil));
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_abs_real : tnode;
      function tinlinenode.first_abs_real : tnode;
       var
       var
          callnode : tcallnode;
          callnode : tcallnode;
+         temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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',
         callnode:=ccallnode.createintern('fpc_abs_real',
-                    ccallparanode.create(left,nil));
+                    ccallparanode.create(temp_pnode^,nil));
         result := ctypeconvnode.create(callnode,resultdef);
         result := ctypeconvnode.create(callnode,resultdef);
         include(callnode.callnodeflags,cnf_check_fpu_exceptions);
         include(callnode.callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_sqr_real : tnode;
      function tinlinenode.first_sqr_real : tnode;
       var
       var
          callnode : tcallnode;
          callnode : tcallnode;
+         temp_pnode: pnode;
       begin
       begin
 {$ifndef cpufpemu}
 {$ifndef cpufpemu}
         { this procedure might be only used for cpus definining cpufpemu else
         { this procedure might be only used for cpus definining cpufpemu else
@@ -4186,11 +4212,15 @@ implementation
 {$endif cpufpemu}
 {$endif cpufpemu}
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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',
         callnode:=ccallnode.createintern('fpc_sqr_real',
-                    ccallparanode.create(left,nil));
+                    ccallparanode.create(temp_pnode^,nil));
         result := ctypeconvnode.create(callnode,resultdef);
         result := ctypeconvnode.create(callnode,resultdef);
         include(callnode.callnodeflags,cnf_check_fpu_exceptions);
         include(callnode.callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_sqrt_real : tnode;
      function tinlinenode.first_sqrt_real : tnode;
@@ -4198,14 +4228,19 @@ implementation
         fdef: tdef;
         fdef: tdef;
         procname: string[31];
         procname: string[31];
         callnode: tcallnode;
         callnode: tcallnode;
+        temp_pnode: pnode;
       begin
       begin
+        if left.nodetype = callparan then
+          temp_pnode := @tcallparanode(left).left
+        else
+          temp_pnode := @left;
         if ((cs_fp_emulation in current_settings.moduleswitches)
         if ((cs_fp_emulation in current_settings.moduleswitches)
 {$ifdef cpufpemu}
 {$ifdef cpufpemu}
             or (current_settings.fputype=fpu_soft)
             or (current_settings.fputype=fpu_soft)
 {$endif cpufpemu}
 {$endif cpufpemu}
             ) and not (target_info.system in systems_wince) then
             ) and not (target_info.system in systems_wince) then
           begin
           begin
-            case tfloatdef(left.resultdef).floattype of
+            case tfloatdef(temp_pnode^.resultdef).floattype of
               s32real:
               s32real:
                 begin
                 begin
                   fdef:=search_system_type('FLOAT32REC').typedef;
                   fdef:=search_system_type('FLOAT32REC').typedef;
@@ -4223,93 +4258,141 @@ implementation
               internalerror(2014052101);
               internalerror(2014052101);
             end;
             end;
             result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
             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
           end
         else
         else
           begin
           begin
             { create the call to the helper }
             { create the call to the helper }
             { on entry left node contains the parameter }
             { on entry left node contains the parameter }
             callnode := ccallnode.createintern('fpc_sqrt_real',
             callnode := ccallnode.createintern('fpc_sqrt_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
             result := ctypeconvnode.create(callnode,resultdef);
             result := ctypeconvnode.create(callnode,resultdef);
             include(callnode.callnodeflags,cnf_check_fpu_exceptions);
             include(callnode.callnodeflags,cnf_check_fpu_exceptions);
           end;
           end;
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_ln_real : tnode;
      function tinlinenode.first_ln_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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',
         result := ccallnode.createintern('fpc_ln_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_cos_real : tnode;
      function tinlinenode.first_cos_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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',
         result := ccallnode.createintern('fpc_cos_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_sin_real : tnode;
      function tinlinenode.first_sin_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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',
         result := ccallnode.createintern('fpc_sin_real',
-                ccallparanode.create(left,nil));
+                ccallparanode.create(temp_pnode^,nil));
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_exp_real : tnode;
      function tinlinenode.first_exp_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_int_real : tnode;
      function tinlinenode.first_int_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_frac_real : tnode;
      function tinlinenode.first_frac_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_round_real : tnode;
      function tinlinenode.first_round_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_trunc_real : tnode;
      function tinlinenode.first_trunc_real : tnode;
+      var
+        temp_pnode: pnode;
       begin
       begin
         { create the call to the helper }
         { create the call to the helper }
         { on entry left node contains the parameter }
         { 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);
         include(tcallnode(result).callnodeflags,cnf_check_fpu_exceptions);
-        left := nil;
+        temp_pnode^ := nil;
       end;
       end;
 
 
      function tinlinenode.first_abs_long : tnode;
      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];
             supported_targets : [system_i386_go32v2];
             flags : [af_outputbinary,af_smartlink_sections];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             comment : '';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -3485,6 +3486,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_win32,system_i386_nativent];
             supported_targets : [system_i386_win32,system_i386_nativent];
             flags : [af_outputbinary,af_smartlink_sections];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             comment : '';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -3498,6 +3500,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_wdosx];
             supported_targets : [system_i386_wdosx];
             flags : [af_outputbinary];
             flags : [af_outputbinary];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             comment : '';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -3511,6 +3514,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_i386_wince];
             supported_targets : [system_i386_wince];
             flags : [af_outputbinary,af_smartlink_sections];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             comment : '';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -3526,6 +3530,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_x86_64_win64];
             supported_targets : [system_x86_64_win64];
             flags : [af_outputbinary,af_smartlink_sections];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             comment : '';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -3541,6 +3546,7 @@ const pemagic : array[0..3] of byte = (
             supported_targets : [system_arm_wince];
             supported_targets : [system_arm_wince];
             flags : [af_outputbinary,af_smartlink_sections];
             flags : [af_outputbinary,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '';
             comment : '';
             dollarsign: '$';
             dollarsign: '$';
           );
           );

+ 1 - 0
compiler/ogmacho.pas

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

+ 1 - 0
compiler/ognlm.pas

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

+ 1 - 0
compiler/ogomf.pas

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

+ 16 - 3
compiler/options.pas

@@ -757,6 +757,9 @@ begin
 {$endif}
 {$endif}
 {$ifdef llvm}
 {$ifdef llvm}
       'L',
       'L',
+{$endif}
+{$ifdef z80}
+      'Z',
 {$endif}
 {$endif}
       '*' : show:=true;
       '*' : show:=true;
      end;
      end;
@@ -3360,6 +3363,8 @@ begin
       lets disable the feature. }
       lets disable the feature. }
     system_m68k_amiga:
     system_m68k_amiga:
       target_unsup_features:=[f_dynlibs];
       target_unsup_features:=[f_dynlibs];
+    system_z80_zxspectrum:
+      target_unsup_features:=[f_threading,f_dynlibs{,f_fileio,f_textio},f_commandargs,f_exitcode];
     else
     else
       target_unsup_features:=[];
       target_unsup_features:=[];
   end;
   end;
@@ -3783,6 +3788,13 @@ procedure read_arguments(cmd:TCmdStr);
         def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
         def_system_macro('FPC_REQUIRES_PROPER_ALIGNMENT');
       {$endif xtensa}
       {$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)}
       {$if defined(cpu8bitalu)}
         def_system_macro('CPUINT8');
         def_system_macro('CPUINT8');
       {$elseif defined(cpu16bitalu)}
       {$elseif defined(cpu16bitalu)}
@@ -3940,7 +3952,7 @@ begin
     end;
     end;
 
 
   { Set up default value for the heap }
   { 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
     begin
       case target_info.system of
       case target_info.system of
 {$ifdef AVR}
 {$ifdef AVR}
@@ -4241,7 +4253,8 @@ begin
      ((target_info.system in [system_arm_wince,system_arm_gba,
      ((target_info.system in [system_arm_wince,system_arm_gba,
          system_m68k_amiga,system_m68k_atari,
          system_m68k_amiga,system_m68k_atari,
          system_arm_nds,system_arm_embedded,
          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}
 {$ifdef arm}
       or (target_info.abi=abi_eabi)
       or (target_info.abi=abi_eabi)
 {$endif arm}
 {$endif arm}
@@ -4680,7 +4693,7 @@ begin
   option.free;
   option.free;
   Option:=nil;
   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];
   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
   if (tf_safecall_clearstack in target_info.flags) then
     begin
     begin

+ 8 - 8
compiler/pass_1.pas

@@ -194,18 +194,18 @@ implementation
                        p:=hp;
                        p:=hp;
                      end;
                      end;
                    if codegenerror then
                    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;
                  end;
              until not assigned(hp) or
              until not assigned(hp) or
                    (nf_pass1_done in hp.flags);
                    (nf_pass1_done in hp.flags);
              include(p.flags,nf_pass1_done);
              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;
              codegenerror:=codegenerror or oldcodegenerror;
              current_settings.localswitches:=oldlocalswitches;
              current_settings.localswitches:=oldlocalswitches;
              current_filepos:=oldpos;
              current_filepos:=oldpos;

+ 1 - 0
compiler/powerpc/agppcmpw.pas

@@ -1243,6 +1243,7 @@ interface
             supported_targets : [system_powerpc_macos];
             supported_targets : [system_powerpc_macos];
             flags : [af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure];
             flags : [af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure];
             labelprefix : '@';
             labelprefix : '@';
+            labelmaxlen : -1;
             comment : '; ';
             comment : '; ';
             dollarsign: 's';
             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];
          supported_targets : [system_powerpc_amiga,system_powerpc_morphos,system_powerpc_linux];
          flags : [af_needar,af_smartlink_sections];
          flags : [af_needar,af_smartlink_sections];
          labelprefix : '.L';
          labelprefix : '.L';
+         labelmaxlen : -1;
          comment : '# ';
          comment : '# ';
          dollarsign: '$';
          dollarsign: '$';
        );
        );

+ 8 - 1
compiler/pp.pas

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

+ 11 - 5
compiler/ppcgen/agppcgas.pas

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

+ 2 - 2
compiler/ppcgen/cgppc.pas

@@ -846,7 +846,7 @@ unit cgppc;
                 current_asmdata.WeakRefAsmSymbol(symname,AT_DATA)
                 current_asmdata.WeakRefAsmSymbol(symname,AT_DATA)
               else
               else
                 current_asmdata.WeakRefAsmSymbol('.'+symname,AT_DATA);
                 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));
               current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_toc_entry,newsymname+'[TC],'+newsymname));
             end;
             end;
         end
         end
@@ -879,7 +879,7 @@ unit cgppc;
               ref.symbol:=tocsym;
               ref.symbol:=tocsym;
               tocsym.ftocsecnr:=tocnr;
               tocsym.ftocsecnr:=tocnr;
               current_asmdata.asmlists[al_indirectpicdata].concat(tai_symbol.create(tocsym,0));
               current_asmdata.asmlists[al_indirectpicdata].concat(tai_symbol.create(tocsym,0));
-              newsymname:=ReplaceForbiddenAsmSymbolChars(symname);
+              newsymname:=ApplyAsmSymbolRestrictions(symname);
               sym:=current_asmdata.RefAsmSymbol(newsymname,AT_DATA);
               sym:=current_asmdata.RefAsmSymbol(newsymname,AT_DATA);
               current_asmdata.asmlists[al_indirectpicdata].concat(tai_const.Create_sym(sym));
               current_asmdata.asmlists[al_indirectpicdata].concat(tai_const.Create_sym(sym));
             end;
             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);
         sc80floattype:=cfloatdef.create(sc80real,true);
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
 {$endif avr}
 {$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}
 {$ifdef mips}
         create_fpu_types;
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);

+ 2 - 0
compiler/rautils.pas

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

+ 4 - 3
compiler/riscv/agrvgas.pas

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

+ 1 - 0
compiler/sparc/cpuelf.pas

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

+ 2 - 0
compiler/sparc64/cpugas.pas

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

+ 4 - 0
compiler/sparcgen/cpugas.pas

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

+ 11 - 3
compiler/systems.inc

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

+ 11 - 5
compiler/systems.pas

@@ -88,6 +88,7 @@ interface
           supported_targets : set of tsystem;
           supported_targets : set of tsystem;
           flags        : set of tasmflags;
           flags        : set of tasmflags;
           labelprefix : string[3];
           labelprefix : string[3];
+          labelmaxlen : integer;
           comment     : string[3];
           comment     : string[3];
           { set to '$' if that character is allowed in symbol names, otherwise
           { set to '$' if that character is allowed in symbol names, otherwise
             to alternate character by which '$' should be replaced }
             to alternate character by which '$' should be replaced }
@@ -100,7 +101,7 @@ interface
           addfilecmd  : string[10];
           addfilecmd  : string[10];
           arfirstcmd  : string[50];
           arfirstcmd  : string[50];
           arcmd       : string[50];
           arcmd       : string[50];
-          arfinishcmd : string[10];
+          arfinishcmd : string[11];
        end;
        end;
 
 
        presinfo = ^tresinfo;
        presinfo = ^tresinfo;
@@ -186,7 +187,7 @@ interface
        tsysteminfo = record
        tsysteminfo = record
           system       : tsystem;
           system       : tsystem;
           name         : string[34];
           name         : string[34];
-          shortname    : string[9];
+          shortname    : string[10];
           flags        : set of tsystemflags;
           flags        : set of tsystemflags;
           cpu          : tsystemcpu;
           cpu          : tsystemcpu;
           unit_env     : string[16];
           unit_env     : string[16];
@@ -302,7 +303,7 @@ interface
                            system_powerpc64_embedded,system_avr_embedded,
                            system_powerpc64_embedded,system_avr_embedded,
                            system_jvm_java32,system_mipseb_embedded,system_mipsel_embedded,
                            system_jvm_java32,system_mipseb_embedded,system_mipsel_embedded,
                            system_i8086_embedded,system_riscv32_embedded,system_riscv64_embedded,
                            system_i8086_embedded,system_riscv32_embedded,system_riscv64_embedded,
-                           system_xtensa_embedded];
+                           system_xtensa_embedded,system_z80_embedded];
 
 
        { all FreeRTOS systems }
        { all FreeRTOS systems }
        systems_freertos = [system_xtensa_freertos,system_arm_freertos];
        systems_freertos = [system_xtensa_freertos,system_arm_freertos];
@@ -441,7 +442,8 @@ interface
        cpu2str : array[TSystemCpu] of string[10] =
        cpu2str : array[TSystemCpu] of string[10] =
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
              'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
              '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 = (
        abiinfo : array[tabi] of tabiinfo = (
          (name: 'DEFAULT'; supported: true),
          (name: 'DEFAULT'; supported: true),
@@ -1130,7 +1132,11 @@ begin
 
 
 {$ifdef wasm}
 {$ifdef wasm}
   default_target(system_wasm_wasm32);
   default_target(system_wasm_wasm32);
-{$endif}
+{$endif wasm}
+
+{$ifdef z80}
+  default_target(system_z80_embedded);
+{$endif z80}
 
 
 {$ifdef riscv32}
 {$ifdef riscv32}
   default_target(system_riscv32_linux);
   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';
             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
  implementation
 
 
 initialization
 initialization
@@ -769,5 +837,10 @@ initialization
     set_source_info(system_xtensa_embedded_info);
     set_source_info(system_xtensa_embedded_info);
   {$endif embedded}
   {$endif embedded}
 {$endif cpuxtensa}
 {$endif cpuxtensa}
+{$ifdef CPUZ80}
+  {$ifdef embedded}
+    set_source_info(system_z80_embedded_info);
+  {$endif embedded}
+{$endif CPUZ80}
 end.
 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;
           function postprocessexecutable(const fn : string;isdll:boolean):boolean;
        end;
        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;
   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
                                      Initialize
 *****************************************************************************}
 *****************************************************************************}
@@ -1861,4 +2123,9 @@ initialization
   RegisterLinker(ld_embedded,TLinkerEmbedded);
   RegisterLinker(ld_embedded,TLinkerEmbedded);
   RegisterTarget(system_xtensa_embedded_info);
   RegisterTarget(system_xtensa_embedded_info);
 {$endif xtensa}
 {$endif xtensa}
+
+{$ifdef z80}
+  RegisterLinker(ld_embedded,TlinkerEmbedded_SdccSdld);
+  RegisterTarget(system_z80_embedded_info);
+{$endif z80}
 end.
 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
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 #
 default: all
 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
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -641,6 +641,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
 override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins
 endif
 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)
 ifeq ($(FULL_TARGET),i386-linux)
 override CLEAN_UNITS+=ppu crc
 override CLEAN_UNITS+=ppu crc
 endif
 endif
@@ -932,6 +938,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override CLEAN_UNITS+=ppu crc
 override CLEAN_UNITS+=ppu crc
 endif
 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
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_UNITDIR+=..
 override COMPILER_UNITDIR+=..
@@ -1224,6 +1236,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_UNITDIR+=..
 override COMPILER_UNITDIR+=..
 endif
 endif
+ifeq ($(FULL_TARGET),z80-embedded)
+override COMPILER_UNITDIR+=..
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+override COMPILER_UNITDIR+=..
+endif
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
 override COMPILER_SOURCEDIR+=..
 override COMPILER_SOURCEDIR+=..
 endif
 endif
@@ -1515,6 +1533,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 override COMPILER_SOURCEDIR+=..
 override COMPILER_SOURCEDIR+=..
 endif
 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
 override SHARED_BUILD=n
 override SHARED_BUILD=n
 ifdef REQUIRE_UNITSDIR
 ifdef REQUIRE_UNITSDIR
@@ -1962,6 +1986,9 @@ STATICLIBEXT=.a
 else
 else
 EXEEXT=.bin
 EXEEXT=.bin
 endif
 endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
 SHORTSUFFIX=emb
 SHORTSUFFIX=emb
 endif
 endif
 ifeq ($(OS_TARGET),win16)
 ifeq ($(OS_TARGET),win16)
@@ -1970,6 +1997,9 @@ STATICLIBEXT=.a
 SHAREDLIBEXT=.dll
 SHAREDLIBEXT=.dll
 SHORTSUFFIX=w16
 SHORTSUFFIX=w16
 endif
 endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 FPCMADE=fpcmade.$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
 ZIPSUFFIX=$(SHORTSUFFIX)
@@ -2516,6 +2546,12 @@ endif
 ifeq ($(FULL_TARGET),xtensa-freertos)
 ifeq ($(FULL_TARGET),xtensa-freertos)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_RTL=1
 endif
 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
 ifdef REQUIRE_PACKAGES_RTL
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
 ifneq ($(PACKAGEDIR_RTL),)
 ifneq ($(PACKAGEDIR_RTL),)

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

+ 13 - 0
compiler/x86/agx86att.pas

@@ -441,6 +441,7 @@ interface
                                  system_x86_64_android,system_x86_64_haiku];
                                  system_x86_64_android,system_x86_64_haiku];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -454,6 +455,7 @@ interface
             supported_targets : [system_x86_64_linux,system_x86_64_freebsd,system_x86_64_win64,system_x86_64_embedded];
             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];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -467,6 +469,7 @@ interface
             supported_targets : [system_x86_64_solaris];
             supported_targets : [system_x86_64_solaris];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -481,6 +484,7 @@ interface
             supported_targets : [system_x86_64_solaris];
             supported_targets : [system_x86_64_solaris];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -496,6 +500,7 @@ interface
             supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim];
             supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -509,6 +514,7 @@ interface
             supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim];
             supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -526,6 +532,7 @@ interface
                                 system_i386_nativent,system_i386_android,system_i386_aros];
                                 system_i386_nativent,system_i386_android,system_i386_aros];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -542,6 +549,7 @@ interface
                                 system_i386_nativent];
                                 system_i386_nativent];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             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];
             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];
             flags : [af_needar,af_stabs_use_function_absolute_addresses];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -570,6 +579,7 @@ interface
             supported_targets : [system_i386_darwin,system_i386_iphonesim];
             supported_targets : [system_i386_darwin,system_i386_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -583,6 +593,7 @@ interface
             supported_targets : [system_i386_darwin,system_i386_iphonesim];
             supported_targets : [system_i386_darwin,system_i386_iphonesim];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_no_stabs];
             labelprefix : 'L';
             labelprefix : 'L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -599,6 +610,7 @@ interface
                                 system_x86_6432_linux,system_i386_android];
                                 system_x86_6432_linux,system_i386_android];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -612,6 +624,7 @@ interface
             supported_targets : [system_i386_solaris];
             supported_targets : [system_i386_solaris];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf];
             labelprefix : '.L';
             labelprefix : '.L';
+            labelmaxlen : -1;
             comment : '# ';
             comment : '# ';
             dollarsign: '$';
             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];
             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];
             flags : [af_needar,af_labelprefix_only_inside_procedure];
             labelprefix : '@@';
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             comment : '; ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -1172,6 +1173,7 @@ implementation
             supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
             supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
             flags : [af_needar];
             flags : [af_needar];
             labelprefix : '@@';
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             comment : '; ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -1185,6 +1187,7 @@ implementation
             supported_targets : [system_i386_watcom];
             supported_targets : [system_i386_watcom];
             flags : [af_needar];
             flags : [af_needar];
             labelprefix : '@@';
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             comment : '; ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );
@@ -1199,6 +1202,7 @@ implementation
             supported_targets : [system_x86_64_win64];
             supported_targets : [system_x86_64_win64];
             flags : [af_needar];
             flags : [af_needar];
             labelprefix : '@@';
             labelprefix : '@@';
+            labelmaxlen : -1;
             comment : '; ';
             comment : '; ';
             dollarsign: '$';
             dollarsign: '$';
           );
           );

+ 15 - 0
compiler/x86/agx86nsm.pas

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

+ 1 - 0
compiler/x86_64/cpuelf.pas

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

+ 1 - 0
compiler/xtensa/agcpugas.pas

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