cgcpu.pas 76 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135
  1. {
  2. Copyright (c) 2008 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the Z80
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tregisterlist = array of tregister;
  29. { tcgz80 }
  30. tcgz80 = class(tcg)
  31. { true, if the next arithmetic operation should modify the flags }
  32. cgsetflags : boolean;
  33. procedure init_register_allocators;override;
  34. procedure done_register_allocators;override;
  35. procedure getcpuregisters(list:TAsmList;regs:tregisterlist);
  36. procedure ungetcpuregisters(list:TAsmList;regs:tregisterlist);
  37. function getaddressregister(list:TAsmList):TRegister;override;
  38. function GetOffsetReg(const r: TRegister;ofs : shortint): TRegister;override;
  39. function GetOffsetReg64(const r,rhi: TRegister;ofs : shortint): TRegister;override;
  40. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
  41. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);override;
  42. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  43. procedure a_load_reg_cgpara(list : TAsmList; size : tcgsize;r : tregister; const cgpara : tcgpara);override;
  44. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  45. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  46. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  47. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override;
  48. { move instructions }
  49. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  50. procedure a_load_const_ref(list : TAsmList;size : tcgsize;a : tcgint;const ref : treference);override;
  51. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  52. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  53. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  54. { fpu move instructions }
  55. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  56. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  57. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  58. { comparison operations }
  59. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  60. l : tasmlabel);override;
  61. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  62. procedure a_jmp_name(list : TAsmList;const s : string); override;
  63. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  64. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  65. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  66. procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
  67. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  68. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  69. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  70. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  71. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  72. procedure g_save_registers(list : TAsmList);override;
  73. procedure g_restore_registers(list : TAsmList);override;
  74. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  75. function normalize_ref(list : TAsmList;ref : treference; const refopertypes:trefoperandtypes; out allocatedregs:tregisterlist) : treference;
  76. procedure adjust_normalized_ref(list: TAsmList;var ref: treference; value: longint);
  77. procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  78. procedure a_adjust_sp(list: TAsmList; value: longint);
  79. protected
  80. procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  81. procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister);
  82. procedure maybegetcpuregister(list : tasmlist; reg : tregister);
  83. end;
  84. tcg64fz80 = class(tcg64f32)
  85. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  86. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  87. end;
  88. function GetByteLoc(const loc : tlocation;nr : byte) : tlocation;
  89. procedure create_codegen;
  90. const
  91. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_LD,A_ADD,A_AND,A_NONE,
  92. A_NONE,A_NONE,A_NONE,A_NEG,A_CPL,A_OR,
  93. A_SRA,A_SLA,A_SRL,A_SUB,A_XOR,A_RLCA,A_RRCA);
  94. implementation
  95. uses
  96. globals,verbose,systems,cutils,
  97. fmodule,
  98. symconst,symsym,symtable,
  99. tgobj,rgobj,
  100. procinfo,cpupi,
  101. paramgr;
  102. function use_push(const cgpara:tcgpara):boolean;
  103. begin
  104. result:=(not paramanager.use_fixed_stack) and
  105. assigned(cgpara.location) and
  106. (cgpara.location^.loc=LOC_REFERENCE) and
  107. (cgpara.location^.reference.index=NR_STACK_POINTER_REG);
  108. end;
  109. procedure tcgz80.init_register_allocators;
  110. begin
  111. inherited init_register_allocators;
  112. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  113. [RS_A,RS_B,RS_C,RS_D,RS_E,RS_H,RS_L],first_int_imreg,[]);
  114. end;
  115. procedure tcgz80.done_register_allocators;
  116. begin
  117. rg[R_INTREGISTER].free;
  118. // rg[R_ADDRESSREGISTER].free;
  119. inherited done_register_allocators;
  120. end;
  121. procedure tcgz80.getcpuregisters(list: TAsmList; regs: tregisterlist);
  122. var
  123. r: tregister;
  124. begin
  125. for r in regs do
  126. getcpuregister(list,r);
  127. end;
  128. procedure tcgz80.ungetcpuregisters(list: TAsmList; regs: tregisterlist);
  129. var
  130. r: tregister;
  131. begin
  132. for r in regs do
  133. ungetcpuregister(list,r);
  134. end;
  135. function tcgz80.getaddressregister(list: TAsmList): TRegister;
  136. begin
  137. Result:=getintregister(list,OS_ADDR);
  138. end;
  139. function tcgz80.GetOffsetReg(const r: TRegister; ofs: shortint): TRegister;
  140. var
  141. i: Integer;
  142. begin
  143. result:=r;
  144. for i:=1 to ofs do
  145. result:=GetNextReg(result);
  146. end;
  147. function tcgz80.GetOffsetReg64(const r, rhi: TRegister; ofs: shortint): TRegister;
  148. var
  149. i: Integer;
  150. begin
  151. if ofs>=4 then
  152. begin
  153. result:=rhi;
  154. dec(ofs,4);
  155. end
  156. else
  157. result:=r;
  158. for i:=1 to ofs do
  159. result:=GetNextReg(result);
  160. end;
  161. procedure tcgz80.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  162. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  163. var
  164. ref : treference;
  165. begin
  166. paramanager.allocparaloc(list,paraloc);
  167. case paraloc^.loc of
  168. LOC_REGISTER,LOC_CREGISTER:
  169. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  170. LOC_REFERENCE,LOC_CREFERENCE:
  171. begin
  172. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,ctempposinvalid,2,[]);
  173. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  174. end;
  175. else
  176. internalerror(2002071004);
  177. end;
  178. end;
  179. var
  180. i, i2 : longint;
  181. hp : PCGParaLocation;
  182. begin
  183. if use_push(cgpara) then
  184. begin
  185. case tcgsize2size[cgpara.Size] of
  186. 1:
  187. begin
  188. cgpara.check_simple_location;
  189. getcpuregister(list,NR_A);
  190. a_load_reg_reg(list,OS_8,OS_8,r,NR_A);
  191. list.concat(taicpu.op_reg(A_PUSH,NR_AF));
  192. list.concat(taicpu.op_reg(A_INC,NR_SP));
  193. ungetcpuregister(list,NR_A);
  194. end;
  195. 2:
  196. begin
  197. cgpara.check_simple_location;
  198. getcpuregister(list,NR_L);
  199. a_load_reg_reg(list,OS_8,OS_8,r,NR_L);
  200. getcpuregister(list,NR_H);
  201. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(r),NR_H);
  202. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  203. getcpuregister(list,NR_H);
  204. getcpuregister(list,NR_L);
  205. end;
  206. else
  207. internalerror(2020040801);
  208. end;
  209. { if tcgsize2size[cgpara.Size] > 2 then
  210. begin
  211. if tcgsize2size[cgpara.Size] <> 4 then
  212. internalerror(2013031101);
  213. if cgpara.location^.Next = nil then
  214. begin
  215. if tcgsize2size[cgpara.location^.size] <> 4 then
  216. internalerror(2013031101);
  217. end
  218. else
  219. begin
  220. if tcgsize2size[cgpara.location^.size] <> 2 then
  221. internalerror(2013031101);
  222. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  223. internalerror(2013031101);
  224. if cgpara.location^.Next^.Next <> nil then
  225. internalerror(2013031101);
  226. end;
  227. if tcgsize2size[cgpara.size]>cgpara.alignment then
  228. pushsize:=cgpara.size
  229. else
  230. pushsize:=int_cgsize(cgpara.alignment);
  231. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  232. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  233. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  234. end
  235. else
  236. begin
  237. cgpara.check_simple_location;
  238. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  239. pushsize:=cgpara.location^.size
  240. else
  241. pushsize:=int_cgsize(cgpara.alignment);
  242. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  243. end;}
  244. end
  245. else
  246. begin
  247. if not(tcgsize2size[cgpara.Size] in [1..4]) then
  248. internalerror(2014011101);
  249. hp:=cgpara.location;
  250. i:=0;
  251. while i<tcgsize2size[cgpara.Size] do
  252. begin
  253. if not(assigned(hp)) then
  254. internalerror(2014011102);
  255. inc(i, tcgsize2size[hp^.Size]);
  256. if hp^.Loc=LOC_REGISTER then
  257. begin
  258. load_para_loc(r,hp);
  259. hp:=hp^.Next;
  260. r:=GetNextReg(r);
  261. end
  262. else
  263. begin
  264. load_para_loc(r,hp);
  265. for i2:=1 to tcgsize2size[hp^.Size] do
  266. r:=GetNextReg(r);
  267. hp:=hp^.Next;
  268. end;
  269. end;
  270. if assigned(hp) then
  271. internalerror(2014011103);
  272. end;
  273. end;
  274. procedure tcgz80.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
  275. var
  276. i : longint;
  277. hp : PCGParaLocation;
  278. ref: treference;
  279. begin
  280. if not(tcgsize2size[paraloc.Size] in [1..4]) then
  281. internalerror(2014011101);
  282. if use_push(paraloc) then
  283. begin
  284. case tcgsize2size[paraloc.Size] of
  285. 1:
  286. begin
  287. getcpuregister(list,NR_A);
  288. a_load_const_reg(list,OS_8,a,NR_A);
  289. list.Concat(taicpu.op_reg(A_PUSH,NR_AF));
  290. list.Concat(taicpu.op_reg(A_INC,NR_SP));
  291. ungetcpuregister(list,NR_A);
  292. end;
  293. 2:
  294. begin
  295. getcpuregister(list,NR_IY);
  296. list.Concat(taicpu.op_reg_const(A_LD,NR_IY,a));
  297. list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
  298. ungetcpuregister(list,NR_IY);
  299. end;
  300. 4:
  301. begin
  302. getcpuregister(list,NR_IY);
  303. list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a shr 16)));
  304. list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
  305. list.Concat(taicpu.op_reg_const(A_LD,NR_IY,Word(a)));
  306. list.Concat(taicpu.op_reg(A_PUSH,NR_IY));
  307. ungetcpuregister(list,NR_IY);
  308. end;
  309. else
  310. internalerror(2020040701);
  311. end;
  312. end
  313. else
  314. begin
  315. hp:=paraloc.location;
  316. i:=1;
  317. while i<=tcgsize2size[paraloc.Size] do
  318. begin
  319. if not(assigned(hp)) then
  320. internalerror(2014011105);
  321. //paramanager.allocparaloc(list,hp);
  322. case hp^.loc of
  323. LOC_REGISTER,LOC_CREGISTER:
  324. begin
  325. if (tcgsize2size[hp^.size]<>1) or
  326. (hp^.shiftval<>0) then
  327. internalerror(2015041101);
  328. a_load_const_reg(list,hp^.size,(a shr (8*(i-1))) and $ff,hp^.register);
  329. inc(i,tcgsize2size[hp^.size]);
  330. hp:=hp^.Next;
  331. end;
  332. LOC_REFERENCE,LOC_CREFERENCE:
  333. begin
  334. reference_reset(ref,paraloc.alignment,[]);
  335. ref.base:=hp^.reference.index;
  336. ref.offset:=hp^.reference.offset;
  337. a_load_const_ref(list,hp^.size,a shr (8*(i-1)),ref);
  338. inc(i,tcgsize2size[hp^.size]);
  339. hp:=hp^.Next;
  340. end;
  341. else
  342. internalerror(2002071004);
  343. end;
  344. end;
  345. end;
  346. end;
  347. procedure tcgz80.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const cgpara : TCGPara);
  348. procedure pushdata(paraloc:pcgparalocation;ofs:tcgint);
  349. var
  350. pushsize : tcgsize;
  351. opsize : topsize;
  352. tmpreg : tregister;
  353. href,tmpref: treference;
  354. begin
  355. if not assigned(paraloc) then
  356. exit;
  357. if (paraloc^.loc<>LOC_REFERENCE) or
  358. (paraloc^.reference.index<>NR_STACK_POINTER_REG) or
  359. (tcgsize2size[paraloc^.size]>4) then
  360. internalerror(200501162);
  361. { Pushes are needed in reverse order, add the size of the
  362. current location to the offset where to load from. This
  363. prevents wrong calculations for the last location when
  364. the size is not a power of 2 }
  365. if assigned(paraloc^.next) then
  366. pushdata(paraloc^.next,ofs+tcgsize2size[paraloc^.size]);
  367. { Push the data starting at ofs }
  368. href:=r;
  369. inc(href.offset,ofs);
  370. {if tcgsize2size[paraloc^.size]>cgpara.alignment then}
  371. pushsize:=paraloc^.size
  372. {else
  373. pushsize:=int_cgsize(cgpara.alignment)};
  374. {Writeln(pushsize);}
  375. case tcgsize2size[pushsize] of
  376. 1:
  377. begin
  378. tmpreg:=getintregister(list,OS_8);
  379. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  380. getcpuregister(list,NR_A);
  381. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
  382. list.concat(taicpu.op_reg(A_PUSH,NR_AF));
  383. list.concat(taicpu.op_reg(A_INC,NR_SP));
  384. ungetcpuregister(list,NR_A);
  385. end;
  386. 2:
  387. begin
  388. tmpreg:=getintregister(list,OS_16);
  389. a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  390. getcpuregister(list,NR_L);
  391. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_L);
  392. getcpuregister(list,NR_H);
  393. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(tmpreg),NR_H);
  394. list.concat(taicpu.op_reg(A_PUSH,NR_HL));
  395. ungetcpuregister(list,NR_H);
  396. ungetcpuregister(list,NR_L);
  397. end
  398. else
  399. internalerror(2020040803);
  400. end;
  401. //if tcgsize2size[paraloc^.size]<cgpara.alignment then
  402. // begin
  403. // tmpreg:=getintregister(list,pushsize);
  404. // a_load_ref_reg(list,paraloc^.size,pushsize,href,tmpreg);
  405. // list.concat(taicpu.op_reg(A_PUSH,opsize,tmpreg));
  406. // end
  407. //else
  408. // begin
  409. // make_simple_ref(list,href);
  410. // if tcgsize2size[pushsize] > 2 then
  411. // begin
  412. // tmpref := href;
  413. // Inc(tmpref.offset, 2);
  414. // list.concat(taicpu.op_ref(A_PUSH,TCgsize2opsize[int_cgsize(tcgsize2size[pushsize]-2)],tmpref));
  415. // end;
  416. // list.concat(taicpu.op_ref(A_PUSH,opsize,href));
  417. // end;
  418. end;
  419. var
  420. tmpref, ref: treference;
  421. location: pcgparalocation;
  422. sizeleft: tcgint;
  423. begin
  424. { cgpara.size=OS_NO requires a copy on the stack }
  425. if use_push(cgpara) then
  426. begin
  427. { Record copy? }
  428. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  429. begin
  430. internalerror(2020040802);
  431. //cgpara.check_simple_location;
  432. //len:=align(cgpara.intsize,cgpara.alignment);
  433. //g_stackpointer_alloc(list,len);
  434. //reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]);
  435. //g_concatcopy(list,r,href,len);
  436. end
  437. else
  438. begin
  439. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  440. internalerror(200501161);
  441. { We need to push the data in reverse order,
  442. therefor we use a recursive algorithm }
  443. pushdata(cgpara.location,0);
  444. end
  445. end
  446. else
  447. begin
  448. location := cgpara.location;
  449. tmpref := r;
  450. sizeleft := cgpara.intsize;
  451. while assigned(location) do
  452. begin
  453. paramanager.allocparaloc(list,location);
  454. case location^.loc of
  455. LOC_REGISTER,LOC_CREGISTER:
  456. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  457. LOC_REFERENCE:
  458. begin
  459. reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  460. { doubles in softemu mode have a strange order of registers and references }
  461. if location^.size=OS_32 then
  462. g_concatcopy(list,tmpref,ref,4)
  463. else
  464. begin
  465. g_concatcopy(list,tmpref,ref,sizeleft);
  466. if assigned(location^.next) then
  467. internalerror(2005010710);
  468. end;
  469. end;
  470. LOC_VOID:
  471. begin
  472. // nothing to do
  473. end;
  474. else
  475. internalerror(2002081103);
  476. end;
  477. inc(tmpref.offset,tcgsize2size[location^.size]);
  478. dec(sizeleft,tcgsize2size[location^.size]);
  479. location := location^.next;
  480. end;
  481. end;
  482. end;
  483. procedure tcgz80.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  484. var
  485. tmpreg: tregister;
  486. begin
  487. tmpreg:=getaddressregister(list);
  488. a_loadaddr_ref_reg(list,r,tmpreg);
  489. a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc);
  490. end;
  491. procedure tcgz80.a_call_name(list : TAsmList;const s : string; weak: boolean);
  492. var
  493. sym: TAsmSymbol;
  494. begin
  495. if weak then
  496. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)
  497. else
  498. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  499. list.concat(taicpu.op_sym(A_CALL,sym));
  500. include(current_procinfo.flags,pi_do_call);
  501. end;
  502. procedure tcgz80.a_call_reg(list : TAsmList;reg: tregister);
  503. var
  504. l : TAsmLabel;
  505. ref : treference;
  506. begin
  507. current_asmdata.getjumplabel(l);
  508. reference_reset(ref,0,[]);
  509. ref.symbol:=l;
  510. list.concat(taicpu.op_ref_reg(A_LD,ref,reg));
  511. list.concat(tai_const.Create_8bit($CD));
  512. list.concat(tai_label.Create(l));
  513. include(current_procinfo.flags,pi_do_call);
  514. end;
  515. procedure tcgz80.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  516. begin
  517. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  518. internalerror(2012102403);
  519. a_op_const_reg_internal(list,Op,size,a,reg,NR_NO);
  520. end;
  521. procedure tcgz80.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister);
  522. begin
  523. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  524. internalerror(2012102401);
  525. a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO);
  526. end;
  527. procedure tcgz80.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  528. var
  529. i : integer;
  530. procedure NextSrcDst;
  531. begin
  532. if i=5 then
  533. begin
  534. dst:=dsthi;
  535. src:=srchi;
  536. end
  537. else
  538. begin
  539. dst:=GetNextReg(dst);
  540. src:=GetNextReg(src);
  541. end;
  542. end;
  543. var
  544. tmpreg,tmpreg2: tregister;
  545. instr : taicpu;
  546. l1,l2 : tasmlabel;
  547. begin
  548. case op of
  549. OP_ADD:
  550. begin
  551. getcpuregister(list,NR_A);
  552. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  553. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,src));
  554. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  555. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  556. begin
  557. for i:=2 to tcgsize2size[size] do
  558. begin
  559. NextSrcDst;
  560. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  561. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,src));
  562. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  563. end;
  564. end;
  565. ungetcpuregister(list,NR_A);
  566. end;
  567. OP_SUB:
  568. begin
  569. getcpuregister(list,NR_A);
  570. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  571. list.concat(taicpu.op_reg_reg(A_SUB,NR_A,src));
  572. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  573. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  574. begin
  575. for i:=2 to tcgsize2size[size] do
  576. begin
  577. NextSrcDst;
  578. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  579. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,src));
  580. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  581. end;
  582. end;
  583. ungetcpuregister(list,NR_A);
  584. end;
  585. OP_NEG:
  586. begin
  587. getcpuregister(list,NR_A);
  588. if tcgsize2size[size]>=2 then
  589. begin
  590. tmpreg:=GetNextReg(src);
  591. tmpreg2:=GetNextReg(dst);
  592. for i:=2 to tcgsize2size[size] do
  593. begin
  594. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
  595. list.concat(taicpu.op_none(A_CPL));
  596. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  597. if i<>tcgsize2size[size] then
  598. begin
  599. if i=5 then
  600. begin
  601. tmpreg:=srchi;
  602. tmpreg2:=dsthi;
  603. end
  604. else
  605. begin
  606. tmpreg:=GetNextReg(tmpreg);
  607. tmpreg2:=GetNextReg(tmpreg2);
  608. end;
  609. end;
  610. end;
  611. end;
  612. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  613. list.concat(taicpu.op_none(A_NEG));
  614. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  615. if tcgsize2size[size]>=2 then
  616. begin
  617. tmpreg2:=GetNextReg(dst);
  618. for i:=2 to tcgsize2size[size] do
  619. begin
  620. a_load_reg_reg(list,OS_8,OS_8,tmpreg2,NR_A);
  621. list.concat(taicpu.op_reg_const(A_SBC,NR_A,-1));
  622. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  623. if i<>tcgsize2size[size] then
  624. begin
  625. if i=5 then
  626. begin
  627. tmpreg2:=dsthi;
  628. end
  629. else
  630. begin
  631. tmpreg2:=GetNextReg(tmpreg2);
  632. end;
  633. end;
  634. end;
  635. end;
  636. ungetcpuregister(list,NR_A);
  637. end;
  638. OP_NOT:
  639. begin
  640. getcpuregister(list,NR_A);
  641. for i:=1 to tcgsize2size[size] do
  642. begin
  643. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  644. list.concat(taicpu.op_none(A_CPL));
  645. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  646. if i<>tcgsize2size[size] then
  647. NextSrcDst;
  648. end;
  649. ungetcpuregister(list,NR_A);
  650. end;
  651. OP_MUL,OP_IMUL:
  652. { special stuff, needs separate handling inside code
  653. generator }
  654. internalerror(2017032604);
  655. OP_DIV,OP_IDIV:
  656. { special stuff, needs separate handling inside code
  657. generator }
  658. internalerror(2017032604);
  659. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  660. begin
  661. current_asmdata.getjumplabel(l1);
  662. current_asmdata.getjumplabel(l2);
  663. getcpuregister(list,NR_B);
  664. emit_mov(list,NR_B,src);
  665. list.concat(taicpu.op_reg(A_INC,NR_B));
  666. list.concat(taicpu.op_reg(A_DEC,NR_B));
  667. a_jmp_flags(list,F_E,l2);
  668. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  669. case op of
  670. OP_ROL:
  671. begin
  672. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  673. list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  674. end;
  675. OP_ROR:
  676. begin
  677. list.concat(taicpu.op_reg(A_RLC,dst));
  678. list.concat(taicpu.op_reg(A_RRC,dst));
  679. end;
  680. else
  681. ;
  682. end;
  683. cg.a_label(list,l1);
  684. case op of
  685. OP_SHL:
  686. list.concat(taicpu.op_reg(A_SLA,dst));
  687. OP_SHR:
  688. list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  689. OP_SAR:
  690. list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  691. OP_ROL:
  692. if size in [OS_8,OS_S8] then
  693. list.concat(taicpu.op_reg(A_RLC,dst))
  694. else
  695. list.concat(taicpu.op_reg(A_RL,dst));
  696. OP_ROR:
  697. if size in [OS_8,OS_S8] then
  698. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)))
  699. else
  700. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  701. else
  702. internalerror(2020040903);
  703. end;
  704. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  705. begin
  706. for i:=2 to tcgsize2size[size] do
  707. begin
  708. case op of
  709. OP_ROR,
  710. OP_SHR,
  711. OP_SAR:
  712. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  713. OP_ROL,
  714. OP_SHL:
  715. list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(dst,dsthi,i-1)));
  716. else
  717. internalerror(2020040904);
  718. end;
  719. end;
  720. end;
  721. instr:=taicpu.op_sym(A_DJNZ,l1);
  722. instr.is_jmp:=true;
  723. list.concat(instr);
  724. ungetcpuregister(list,NR_B);
  725. cg.a_label(list,l2);
  726. end;
  727. OP_AND,OP_OR,OP_XOR:
  728. begin
  729. getcpuregister(list,NR_A);
  730. for i:=1 to tcgsize2size[size] do
  731. begin
  732. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  733. list.concat(taicpu.op_reg_reg(topcg2asmop[op],NR_A,src));
  734. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  735. if i<>tcgsize2size[size] then
  736. NextSrcDst;
  737. end;
  738. ungetcpuregister(list,NR_A);
  739. end;
  740. else
  741. internalerror(2011022004);
  742. end;
  743. end;
  744. procedure tcgz80.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
  745. size: TCGSize; a: tcgint; reg, reghi: TRegister);
  746. var
  747. i : byte;
  748. procedure NextReg;
  749. begin
  750. if i=4 then
  751. reg:=reghi
  752. else
  753. reg:=GetNextReg(reg);
  754. end;
  755. var
  756. mask : qword;
  757. shift : byte;
  758. curvalue : byte;
  759. tmpop: TAsmOp;
  760. l1: TAsmLabel;
  761. instr: taicpu;
  762. tmpreg : tregister;
  763. tmpreg64 : tregister64;
  764. begin
  765. optimize_op_const(size,op,a);
  766. mask:=$ff;
  767. shift:=0;
  768. case op of
  769. OP_NONE:
  770. begin
  771. { Opcode is optimized away }
  772. end;
  773. OP_MOVE:
  774. begin
  775. { Optimized, replaced with a simple load }
  776. a_load_const_reg(list,size,a,reg);
  777. end;
  778. OP_AND:
  779. begin
  780. curvalue:=a and mask;
  781. for i:=1 to tcgsize2size[size] do
  782. begin
  783. case curvalue of
  784. 0:
  785. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  786. $ff:
  787. {nothing};
  788. else
  789. begin
  790. getcpuregister(list,NR_A);
  791. emit_mov(list,NR_A,reg);
  792. list.concat(taicpu.op_reg_const(A_AND,NR_A,curvalue));
  793. emit_mov(list,reg,NR_A);
  794. ungetcpuregister(list,NR_A);
  795. end;
  796. end;
  797. if i<>tcgsize2size[size] then
  798. begin
  799. NextReg;
  800. mask:=mask shl 8;
  801. inc(shift,8);
  802. curvalue:=(qword(a) and mask) shr shift;
  803. end;
  804. end;
  805. end;
  806. OP_OR:
  807. begin
  808. curvalue:=a and mask;
  809. for i:=1 to tcgsize2size[size] do
  810. begin
  811. case curvalue of
  812. 0:
  813. {nothing};
  814. $ff:
  815. list.concat(taicpu.op_reg_const(A_LD,reg,$ff));
  816. else
  817. begin
  818. getcpuregister(list,NR_A);
  819. emit_mov(list,NR_A,reg);
  820. list.concat(taicpu.op_reg_const(A_OR,NR_A,curvalue));
  821. emit_mov(list,reg,NR_A);
  822. ungetcpuregister(list,NR_A);
  823. end;
  824. end;
  825. if i<>tcgsize2size[size] then
  826. begin
  827. NextReg;
  828. mask:=mask shl 8;
  829. inc(shift,8);
  830. curvalue:=(qword(a) and mask) shr shift;
  831. end;
  832. end;
  833. end;
  834. OP_XOR:
  835. begin
  836. curvalue:=a and mask;
  837. for i:=1 to tcgsize2size[size] do
  838. begin
  839. case curvalue of
  840. 0:
  841. {nothing};
  842. $ff:
  843. begin
  844. getcpuregister(list,NR_A);
  845. emit_mov(list,NR_A,reg);
  846. list.concat(taicpu.op_none(A_CPL));
  847. emit_mov(list,reg,NR_A);
  848. ungetcpuregister(list,NR_A);
  849. end;
  850. else
  851. begin
  852. getcpuregister(list,NR_A);
  853. emit_mov(list,NR_A,reg);
  854. list.concat(taicpu.op_reg_const(A_XOR,NR_A,curvalue));
  855. emit_mov(list,reg,NR_A);
  856. ungetcpuregister(list,NR_A);
  857. end;
  858. end;
  859. if i<>tcgsize2size[size] then
  860. begin
  861. NextReg;
  862. mask:=mask shl 8;
  863. inc(shift,8);
  864. curvalue:=(qword(a) and mask) shr shift;
  865. end;
  866. end;
  867. end;
  868. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  869. begin
  870. if size in [OS_64,OS_S64] then
  871. a:=a and 63
  872. else
  873. a:=a and 31;
  874. if a<>0 then
  875. begin
  876. if a>1 then
  877. begin
  878. current_asmdata.getjumplabel(l1);
  879. getcpuregister(list,NR_B);
  880. list.concat(taicpu.op_reg_const(A_LD,NR_B,a));
  881. end;
  882. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  883. case op of
  884. OP_ROL:
  885. begin
  886. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  887. list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  888. end;
  889. OP_ROR:
  890. begin
  891. list.concat(taicpu.op_reg(A_RLC,reg));
  892. list.concat(taicpu.op_reg(A_RRC,reg));
  893. end;
  894. else
  895. ;
  896. end;
  897. if a>1 then
  898. cg.a_label(list,l1);
  899. case op of
  900. OP_SHL:
  901. list.concat(taicpu.op_reg(A_SLA,reg));
  902. OP_SHR:
  903. list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  904. OP_SAR:
  905. list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  906. OP_ROL:
  907. if size in [OS_8,OS_S8] then
  908. list.concat(taicpu.op_reg(A_RLC,reg))
  909. else
  910. list.concat(taicpu.op_reg(A_RL,reg));
  911. OP_ROR:
  912. if size in [OS_8,OS_S8] then
  913. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)))
  914. else
  915. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  916. else
  917. internalerror(2020040903);
  918. end;
  919. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  920. begin
  921. for i:=2 to tcgsize2size[size] do
  922. begin
  923. case op of
  924. OP_ROR,
  925. OP_SHR,
  926. OP_SAR:
  927. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  928. OP_ROL,
  929. OP_SHL:
  930. list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(reg,reghi,i-1)));
  931. else
  932. internalerror(2020040904);
  933. end;
  934. end;
  935. end;
  936. if a>1 then
  937. begin
  938. instr:=taicpu.op_sym(A_DJNZ,l1);
  939. instr.is_jmp:=true;
  940. list.concat(instr);
  941. ungetcpuregister(list,NR_B);
  942. end;
  943. end;
  944. end;
  945. OP_ADD:
  946. begin
  947. curvalue:=a and mask;
  948. tmpop:=A_NONE;
  949. for i:=1 to tcgsize2size[size] do
  950. begin
  951. if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
  952. tmpop:=A_INC
  953. else if (tmpop=A_NONE) and (curvalue<>0) then
  954. tmpop:=A_ADD
  955. else if tmpop=A_ADD then
  956. tmpop:=A_ADC;
  957. case tmpop of
  958. A_NONE:
  959. {nothing};
  960. A_INC:
  961. list.concat(taicpu.op_reg(tmpop,reg));
  962. A_ADD,A_ADC:
  963. begin
  964. getcpuregister(list,NR_A);
  965. emit_mov(list,NR_A,reg);
  966. list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
  967. emit_mov(list,reg,NR_A);
  968. ungetcpuregister(list,NR_A);
  969. end;
  970. else
  971. internalerror(2020040901);
  972. end;
  973. if i<>tcgsize2size[size] then
  974. begin
  975. NextReg;
  976. mask:=mask shl 8;
  977. inc(shift,8);
  978. curvalue:=(qword(a) and mask) shr shift;
  979. end;
  980. end;
  981. end;
  982. OP_SUB:
  983. begin
  984. curvalue:=a and mask;
  985. tmpop:=A_NONE;
  986. for i:=1 to tcgsize2size[size] do
  987. begin
  988. if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
  989. tmpop:=A_DEC
  990. else if (tmpop=A_NONE) and (curvalue<>0) then
  991. tmpop:=A_SUB
  992. else if tmpop=A_ADD then
  993. tmpop:=A_SBC;
  994. case tmpop of
  995. A_NONE:
  996. {nothing};
  997. A_DEC:
  998. list.concat(taicpu.op_reg(tmpop,reg));
  999. A_SUB,A_SBC:
  1000. begin
  1001. getcpuregister(list,NR_A);
  1002. emit_mov(list,NR_A,reg);
  1003. list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
  1004. emit_mov(list,reg,NR_A);
  1005. ungetcpuregister(list,NR_A);
  1006. end;
  1007. else
  1008. internalerror(2020040902);
  1009. end;
  1010. if i<>tcgsize2size[size] then
  1011. begin
  1012. NextReg;
  1013. mask:=mask shl 8;
  1014. inc(shift,8);
  1015. curvalue:=(qword(a) and mask) shr shift;
  1016. end;
  1017. end;
  1018. end;
  1019. else
  1020. begin
  1021. if size in [OS_64,OS_S64] then
  1022. begin
  1023. tmpreg64.reglo:=getintregister(list,OS_32);
  1024. tmpreg64.reghi:=getintregister(list,OS_32);
  1025. cg64.a_load64_const_reg(list,a,tmpreg64);
  1026. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  1027. end
  1028. else
  1029. begin
  1030. {$if 0}
  1031. { code not working yet }
  1032. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  1033. begin
  1034. tmpreg:=reg;
  1035. for i:=1 to 4 do
  1036. begin
  1037. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
  1038. tmpreg:=GetNextReg(tmpreg);
  1039. end;
  1040. end
  1041. else
  1042. {$endif}
  1043. begin
  1044. tmpreg:=getintregister(list,size);
  1045. a_load_const_reg(list,size,a,tmpreg);
  1046. a_op_reg_reg(list,op,size,tmpreg,reg);
  1047. end;
  1048. end;
  1049. end;
  1050. end;
  1051. end;
  1052. procedure tcgz80.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  1053. var
  1054. mask : qword;
  1055. shift : byte;
  1056. i : byte;
  1057. begin
  1058. mask:=$ff;
  1059. shift:=0;
  1060. for i:=tcgsize2size[size] downto 1 do
  1061. begin
  1062. list.Concat(taicpu.op_reg_const(A_LD,reg,(qword(a) and mask) shr shift));
  1063. if i<>1 then
  1064. begin
  1065. mask:=mask shl 8;
  1066. inc(shift,8);
  1067. reg:=GetNextReg(reg);
  1068. end;
  1069. end;
  1070. end;
  1071. procedure tcgz80.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
  1072. var
  1073. mask : qword;
  1074. shift : byte;
  1075. href: treference;
  1076. i: Integer;
  1077. begin
  1078. mask:=$ff;
  1079. shift:=0;
  1080. href:=ref;
  1081. if (href.base=NR_NO) and (href.index<>NR_NO) then
  1082. begin
  1083. href.base:=href.index;
  1084. href.index:=NR_NO;
  1085. end;
  1086. if is_ref_in_opertypes(href,[OT_REF_IX_d,OT_REF_IY_d]) or
  1087. (is_ref_hl(href) and (size in [OS_8,OS_S8])) then
  1088. begin
  1089. for i:=tcgsize2size[size] downto 1 do
  1090. begin
  1091. list.Concat(taicpu.op_ref_const(A_LD,href,(qword(a) and mask) shr shift));
  1092. if i<>1 then
  1093. begin
  1094. mask:=mask shl 8;
  1095. inc(shift,8);
  1096. inc(href.offset);
  1097. end;
  1098. end;
  1099. end
  1100. else
  1101. inherited;
  1102. end;
  1103. procedure tcgz80.maybegetcpuregister(list:tasmlist;reg : tregister);
  1104. begin
  1105. { allocate the register only, if a cpu register is passed }
  1106. if getsupreg(reg)<first_int_imreg then
  1107. getcpuregister(list,reg);
  1108. end;
  1109. function tcgz80.normalize_ref(list: TAsmList; ref: treference;
  1110. const refopertypes: trefoperandtypes; out allocatedregs: tregisterlist): treference;
  1111. var
  1112. tmpref : treference;
  1113. l : tasmlabel;
  1114. begin
  1115. SetLength(allocatedregs,0);
  1116. if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then
  1117. begin
  1118. ref.base:=ref.index;
  1119. ref.index:=NR_NO;
  1120. end;
  1121. if is_ref_in_opertypes(ref,refopertypes) then
  1122. begin
  1123. Result:=ref;
  1124. exit;
  1125. end;
  1126. { can we use the HL register? }
  1127. if OT_REF_HL in refopertypes then
  1128. begin
  1129. SetLength(allocatedregs,2);
  1130. allocatedregs[0]:=NR_H;
  1131. allocatedregs[1]:=NR_L;
  1132. getcpuregisters(list,allocatedregs);
  1133. if assigned(ref.symbol) then
  1134. begin
  1135. reference_reset(tmpref,0,[]);
  1136. tmpref.symbol:=ref.symbol;
  1137. tmpref.offset:=ref.offset;
  1138. tmpref.refaddr:=addr_full;
  1139. list.concat(taicpu.op_reg_ref(A_LD,NR_HL,tmpref));
  1140. end
  1141. else
  1142. list.concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
  1143. if ref.base<>NR_NO then
  1144. begin
  1145. getcpuregister(list,NR_A);
  1146. emit_mov(list,NR_A,NR_L);
  1147. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.base));
  1148. emit_mov(list,NR_L,NR_A);
  1149. emit_mov(list,NR_A,NR_H);
  1150. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.base)));
  1151. emit_mov(list,NR_H,NR_A);
  1152. ungetcpuregister(list,NR_A);
  1153. end;
  1154. if ref.index<>NR_NO then
  1155. begin
  1156. if ref.scalefactor>1 then
  1157. internalerror(2020042002);
  1158. getcpuregister(list,NR_A);
  1159. emit_mov(list,NR_A,NR_L);
  1160. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index));
  1161. emit_mov(list,NR_L,NR_A);
  1162. emit_mov(list,NR_A,NR_H);
  1163. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index)));
  1164. emit_mov(list,NR_H,NR_A);
  1165. ungetcpuregister(list,NR_A);
  1166. end;
  1167. reference_reset_base(result,NR_HL,0,ctempposinvalid,0,[]);
  1168. end
  1169. else
  1170. internalerror(2020042001);
  1171. end;
  1172. procedure tcgz80.adjust_normalized_ref(list: TAsmList; var ref: treference; value: longint);
  1173. var
  1174. i: Integer;
  1175. begin
  1176. if is_ref_addr16(ref) then
  1177. Inc(ref.offset,value)
  1178. else if is_ref_hl(ref) then
  1179. begin
  1180. if value>0 then
  1181. for i:=1 to value do
  1182. list.concat(taicpu.op_reg(A_INC,NR_HL))
  1183. else
  1184. for i:=-1 downto value do
  1185. list.concat(taicpu.op_reg(A_DEC,NR_HL));
  1186. end
  1187. else if is_ref_ix_d(ref) then
  1188. begin
  1189. if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
  1190. inc(ref.offset,value)
  1191. else
  1192. begin
  1193. { todo: IX is the frame pointer, we cannot change it, so we }
  1194. { think of another mechanism to deal with this situation }
  1195. internalerror(2020042101);
  1196. //if value>0 then
  1197. // for i:=1 to value do
  1198. // list.concat(taicpu.op_reg(A_INC,NR_IX))
  1199. //else
  1200. // for i:=-1 downto value do
  1201. // list.concat(taicpu.op_reg(A_DEC,NR_IX));
  1202. end;
  1203. end
  1204. else if is_ref_iy_d(ref) then
  1205. begin
  1206. if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
  1207. inc(ref.offset,value)
  1208. else
  1209. if value>0 then
  1210. for i:=1 to value do
  1211. list.concat(taicpu.op_reg(A_INC,NR_IY))
  1212. else
  1213. for i:=-1 downto value do
  1214. list.concat(taicpu.op_reg(A_DEC,NR_IY));
  1215. end;
  1216. end;
  1217. procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  1218. var
  1219. href : treference;
  1220. i : integer;
  1221. regsused: tregisterlist;
  1222. begin
  1223. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1224. internalerror(2011021307);
  1225. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1226. internalerror(2020040802);
  1227. href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
  1228. if (fromsize=tosize) or (fromsize in [OS_8,OS_16,OS_32]) then
  1229. begin
  1230. getcpuregister(list,NR_A);
  1231. for i:=1 to tcgsize2size[fromsize] do
  1232. begin
  1233. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1234. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1235. if i<>tcgsize2size[fromsize] then
  1236. reg:=GetNextReg(reg);
  1237. if i<>tcgsize2size[tosize] then
  1238. adjust_normalized_ref(list,href,1);
  1239. end;
  1240. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1241. begin
  1242. if i=(tcgsize2size[fromsize]+1) then
  1243. list.concat(taicpu.op_reg_const(A_LD,NR_A,0));
  1244. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1245. if i<>tcgsize2size[tosize] then
  1246. begin
  1247. adjust_normalized_ref(list,href,1);
  1248. reg:=GetNextReg(reg);
  1249. end;
  1250. end;
  1251. ungetcpuregister(list,NR_A);
  1252. end
  1253. else
  1254. begin
  1255. getcpuregister(list,NR_A);
  1256. for i:=1 to tcgsize2size[fromsize] do
  1257. begin
  1258. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1259. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1260. if i<>tcgsize2size[fromsize] then
  1261. reg:=GetNextReg(reg);
  1262. if i<>tcgsize2size[tosize] then
  1263. adjust_normalized_ref(list,href,1);
  1264. end;
  1265. list.concat(taicpu.op_none(A_RLA));
  1266. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1267. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1268. begin
  1269. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1270. if i<>tcgsize2size[tosize] then
  1271. begin
  1272. adjust_normalized_ref(list,href,1);
  1273. reg:=GetNextReg(reg);
  1274. end;
  1275. end;
  1276. ungetcpuregister(list,NR_A);
  1277. end;
  1278. ungetcpuregisters(list,regsused);
  1279. end;
  1280. procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1281. const Ref : treference;reg : tregister);
  1282. var
  1283. href : treference;
  1284. i : integer;
  1285. regsused: tregisterlist;
  1286. begin
  1287. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1288. internalerror(2011021307);
  1289. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1290. internalerror(2020040804);
  1291. href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
  1292. if (tosize=fromsize) or (fromsize in [OS_8,OS_16,OS_32]) then
  1293. begin
  1294. getcpuregister(list,NR_A);
  1295. for i:=1 to tcgsize2size[fromsize] do
  1296. begin
  1297. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1298. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1299. if i<>tcgsize2size[fromsize] then
  1300. adjust_normalized_ref(list,href,1);
  1301. if i<>tcgsize2size[tosize] then
  1302. reg:=GetNextReg(reg);
  1303. end;
  1304. ungetcpuregisters(list,regsused);
  1305. ungetcpuregister(list,NR_A);
  1306. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1307. begin
  1308. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  1309. if i<>tcgsize2size[tosize] then
  1310. reg:=GetNextReg(reg);
  1311. end;
  1312. end
  1313. else
  1314. begin
  1315. getcpuregister(list,NR_A);
  1316. for i:=1 to tcgsize2size[fromsize] do
  1317. begin
  1318. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1319. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1320. if i<>tcgsize2size[fromsize] then
  1321. adjust_normalized_ref(list,href,1);
  1322. if i<>tcgsize2size[tosize] then
  1323. reg:=GetNextReg(reg);
  1324. end;
  1325. ungetcpuregisters(list,regsused);
  1326. list.concat(taicpu.op_none(A_RLA));
  1327. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1328. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1329. begin
  1330. emit_mov(list,reg,NR_A);
  1331. if i<>tcgsize2size[tosize] then
  1332. reg:=GetNextReg(reg);
  1333. end;
  1334. ungetcpuregister(list,NR_A);
  1335. end;
  1336. end;
  1337. procedure tcgz80.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1338. var
  1339. conv_done: boolean;
  1340. tmpreg : tregister;
  1341. i : integer;
  1342. begin
  1343. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1344. internalerror(2011021310);
  1345. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1346. fromsize:=tosize;
  1347. if (tosize=fromsize) or (fromsize in [OS_8,OS_16,OS_32]) then
  1348. begin
  1349. if reg1<>reg2 then
  1350. for i:=1 to tcgsize2size[fromsize] do
  1351. begin
  1352. emit_mov(list,reg2,reg1);
  1353. if i<>tcgsize2size[fromsize] then
  1354. reg1:=GetNextReg(reg1);
  1355. if i<>tcgsize2size[tosize] then
  1356. reg2:=GetNextReg(reg2);
  1357. end
  1358. else
  1359. for i:=1 to tcgsize2size[fromsize] do
  1360. if i<>tcgsize2size[tosize] then
  1361. reg2:=GetNextReg(reg2);
  1362. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1363. begin
  1364. list.Concat(taicpu.op_reg_const(A_LD,reg2,0));
  1365. if i<>tcgsize2size[tosize] then
  1366. reg2:=GetNextReg(reg2);
  1367. end
  1368. end
  1369. else
  1370. begin
  1371. if reg1<>reg2 then
  1372. for i:=1 to tcgsize2size[fromsize]-1 do
  1373. begin
  1374. emit_mov(list,reg2,reg1);
  1375. reg1:=GetNextReg(reg1);
  1376. reg2:=GetNextReg(reg2);
  1377. end
  1378. else
  1379. for i:=1 to tcgsize2size[fromsize]-1 do
  1380. reg2:=GetNextReg(reg2);
  1381. emit_mov(list,reg2,reg1);
  1382. getcpuregister(list,NR_A);
  1383. emit_mov(list,NR_A,reg2);
  1384. reg2:=GetNextReg(reg2);
  1385. list.concat(taicpu.op_none(A_RLA));
  1386. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1387. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1388. begin
  1389. emit_mov(list,reg2,NR_A);
  1390. if i<>tcgsize2size[tosize] then
  1391. reg2:=GetNextReg(reg2);
  1392. end;
  1393. ungetcpuregister(list,NR_A);
  1394. end;
  1395. end;
  1396. procedure tcgz80.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1397. begin
  1398. internalerror(2012010702);
  1399. end;
  1400. procedure tcgz80.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1401. begin
  1402. internalerror(2012010703);
  1403. end;
  1404. procedure tcgz80.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1405. begin
  1406. internalerror(2012010704);
  1407. end;
  1408. { comparison operations }
  1409. procedure tcgz80.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1410. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1411. var
  1412. swapped : boolean;
  1413. tmpreg : tregister;
  1414. i : byte;
  1415. begin
  1416. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_cmp_const_reg_label')));
  1417. //if a=0 then
  1418. // begin
  1419. // swapped:=false;
  1420. // { swap parameters? }
  1421. // case cmp_op of
  1422. // OC_GT:
  1423. // begin
  1424. // swapped:=true;
  1425. // cmp_op:=OC_LT;
  1426. // end;
  1427. // OC_LTE:
  1428. // begin
  1429. // swapped:=true;
  1430. // cmp_op:=OC_GTE;
  1431. // end;
  1432. // OC_BE:
  1433. // begin
  1434. // swapped:=true;
  1435. // cmp_op:=OC_AE;
  1436. // end;
  1437. // OC_A:
  1438. // begin
  1439. // swapped:=true;
  1440. // cmp_op:=OC_B;
  1441. // end;
  1442. // end;
  1443. //
  1444. // if swapped then
  1445. // list.concat(taicpu.op_reg_reg(A_CP,NR_R1,reg))
  1446. // else
  1447. // list.concat(taicpu.op_reg_reg(A_CP,reg,NR_R1));
  1448. //
  1449. // for i:=2 to tcgsize2size[size] do
  1450. // begin
  1451. // reg:=GetNextReg(reg);
  1452. // if swapped then
  1453. // list.concat(taicpu.op_reg_reg(A_CPC,NR_R1,reg))
  1454. // else
  1455. // list.concat(taicpu.op_reg_reg(A_CPC,reg,NR_R1));
  1456. // end;
  1457. //
  1458. // a_jmp_cond(list,cmp_op,l);
  1459. // end
  1460. //else
  1461. // inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
  1462. end;
  1463. procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1464. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1465. var
  1466. swapped : boolean;
  1467. tmpreg : tregister;
  1468. i : byte;
  1469. begin
  1470. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_cmp_reg_reg_label')));
  1471. //swapped:=false;
  1472. //{ swap parameters? }
  1473. //case cmp_op of
  1474. // OC_GT:
  1475. // begin
  1476. // swapped:=true;
  1477. // cmp_op:=OC_LT;
  1478. // end;
  1479. // OC_LTE:
  1480. // begin
  1481. // swapped:=true;
  1482. // cmp_op:=OC_GTE;
  1483. // end;
  1484. // OC_BE:
  1485. // begin
  1486. // swapped:=true;
  1487. // cmp_op:=OC_AE;
  1488. // end;
  1489. // OC_A:
  1490. // begin
  1491. // swapped:=true;
  1492. // cmp_op:=OC_B;
  1493. // end;
  1494. //end;
  1495. //if swapped then
  1496. // begin
  1497. // tmpreg:=reg1;
  1498. // reg1:=reg2;
  1499. // reg2:=tmpreg;
  1500. // end;
  1501. //list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1502. //
  1503. //for i:=2 to tcgsize2size[size] do
  1504. // begin
  1505. // reg1:=GetNextReg(reg1);
  1506. // reg2:=GetNextReg(reg2);
  1507. // list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1508. // end;
  1509. //
  1510. //a_jmp_cond(list,cmp_op,l);
  1511. end;
  1512. procedure tcgz80.a_jmp_name(list : TAsmList;const s : string);
  1513. var
  1514. ai : taicpu;
  1515. begin
  1516. ai:=taicpu.op_sym(A_JP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1517. ai.is_jmp:=true;
  1518. list.concat(ai);
  1519. end;
  1520. procedure tcgz80.a_jmp_always(list : TAsmList;l: tasmlabel);
  1521. var
  1522. ai : taicpu;
  1523. begin
  1524. ai:=taicpu.op_sym(A_JP,l);
  1525. ai.is_jmp:=true;
  1526. list.concat(ai);
  1527. end;
  1528. procedure tcgz80.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1529. var
  1530. ai : taicpu;
  1531. begin
  1532. ai:=taicpu.op_cond_sym(A_JP,flags_to_cond(f),l);
  1533. ai.is_jmp:=true;
  1534. list.concat(ai);
  1535. end;
  1536. procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1537. var
  1538. l : TAsmLabel;
  1539. tmpflags : TResFlags;
  1540. begin
  1541. if f in [F_C,F_NC] then
  1542. begin
  1543. a_load_const_reg(list,size,0,reg);
  1544. if f=F_NC then
  1545. list.concat(taicpu.op_none(A_CCF));
  1546. list.concat(taicpu.op_reg(A_RL,reg));
  1547. end
  1548. else
  1549. begin
  1550. current_asmdata.getjumplabel(l);
  1551. a_load_const_reg(list,size,0,reg);
  1552. tmpflags:=f;
  1553. inverse_flags(tmpflags);
  1554. a_jmp_flags(list,tmpflags,l);
  1555. list.concat(taicpu.op_reg(A_INC,reg));
  1556. cg.a_label(list,l);
  1557. end;
  1558. end;
  1559. procedure tcgz80.g_stackpointer_alloc(list: TAsmList; localsize: longint);
  1560. begin
  1561. if localsize>0 then
  1562. begin
  1563. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize));
  1564. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
  1565. list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
  1566. end;
  1567. end;
  1568. procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
  1569. var
  1570. i : integer;
  1571. begin
  1572. //case value of
  1573. // 0:
  1574. // ;
  1575. // {-14..-1:
  1576. // begin
  1577. // if ((-value) mod 2)<>0 then
  1578. // list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1579. // for i:=1 to (-value) div 2 do
  1580. // list.concat(taicpu.op_const(A_RCALL,0));
  1581. // end;
  1582. // 1..7:
  1583. // begin
  1584. // for i:=1 to value do
  1585. // list.concat(taicpu.op_reg(A_POP,NR_R0));
  1586. // end;}
  1587. // else
  1588. // begin
  1589. // list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1590. // list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1591. // // get SREG
  1592. // list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1593. //
  1594. // // block interrupts
  1595. // list.concat(taicpu.op_none(A_CLI));
  1596. //
  1597. // // write high SP
  1598. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1599. //
  1600. // // release interrupts
  1601. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1602. //
  1603. // // write low SP
  1604. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1605. // end;
  1606. //end;
  1607. end;
  1608. procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1609. var
  1610. regsize,stackmisalignment: longint;
  1611. begin
  1612. regsize:=0;
  1613. stackmisalignment:=0;
  1614. { save old framepointer }
  1615. if not nostackframe then
  1616. begin
  1617. { return address }
  1618. inc(stackmisalignment,2);
  1619. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  1620. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1621. begin
  1622. { push <frame_pointer> }
  1623. inc(stackmisalignment,2);
  1624. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  1625. list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG));
  1626. { Return address and FP are both on stack }
  1627. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2);
  1628. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2));
  1629. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  1630. begin
  1631. list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0));
  1632. list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG))
  1633. end
  1634. else
  1635. begin
  1636. internalerror(2020040301);
  1637. (*push_regs;
  1638. gen_load_frame_for_exceptfilter(list);
  1639. { Need only as much stack space as necessary to do the calls.
  1640. Exception filters don't have own local vars, and temps are 'mapped'
  1641. to the parent procedure.
  1642. maxpushedparasize is already aligned at least on x86_64. }
  1643. localsize:=current_procinfo.maxpushedparasize;*)
  1644. end;
  1645. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  1646. end
  1647. else
  1648. begin
  1649. CGmessage(cg_d_stackframe_omited);
  1650. end;
  1651. { allocate stackframe space }
  1652. if (localsize<>0) or
  1653. ((target_info.stackalign>sizeof(pint)) and
  1654. (stackmisalignment <> 0) and
  1655. ((pi_do_call in current_procinfo.flags) or
  1656. (po_assembler in current_procinfo.procdef.procoptions))) then
  1657. begin
  1658. if target_info.stackalign>sizeof(pint) then
  1659. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  1660. g_stackpointer_alloc(list,localsize);
  1661. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1662. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
  1663. current_procinfo.final_localsize:=localsize;
  1664. end
  1665. end;
  1666. end;
  1667. procedure tcgz80.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1668. var
  1669. regs : tcpuregisterset;
  1670. reg : TSuperRegister;
  1671. LocalSize : longint;
  1672. begin
  1673. { every byte counts for Z80, so if a subroutine is marked as non-returning, we do
  1674. not generate any exit code, so we really trust the noreturn directive
  1675. }
  1676. if po_noreturn in current_procinfo.procdef.procoptions then
  1677. exit;
  1678. { remove stackframe }
  1679. if not nostackframe then
  1680. begin
  1681. stacksize:=current_procinfo.calc_stackframe_size;
  1682. if (target_info.stackalign>4) and
  1683. ((stacksize <> 0) or
  1684. (pi_do_call in current_procinfo.flags) or
  1685. { can't detect if a call in this case -> use nostackframe }
  1686. { if you (think you) know what you are doing }
  1687. (po_assembler in current_procinfo.procdef.procoptions)) then
  1688. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1689. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1690. begin
  1691. internalerror(2020040302);
  1692. {if (stacksize<>0) then
  1693. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);}
  1694. end
  1695. else
  1696. begin
  1697. list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  1698. list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG));
  1699. end;
  1700. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1701. end;
  1702. list.concat(taicpu.op_none(A_RET));
  1703. end;
  1704. procedure tcgz80.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1705. var
  1706. tmpref : treference;
  1707. begin
  1708. if assigned(ref.symbol) then
  1709. begin
  1710. reference_reset(tmpref,0,[]);
  1711. tmpref.symbol:=ref.symbol;
  1712. tmpref.offset:=ref.offset;
  1713. tmpref.refaddr:=addr_lo8;
  1714. list.concat(taicpu.op_reg_ref(A_LD,r,tmpref));
  1715. tmpref.refaddr:=addr_hi8;
  1716. list.concat(taicpu.op_reg_ref(A_LD,GetNextReg(r),tmpref));
  1717. if (ref.base<>NR_NO) then
  1718. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  1719. if (ref.index<>NR_NO) then
  1720. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  1721. end
  1722. else if ref.base=NR_IX then
  1723. begin
  1724. list.concat(taicpu.op_reg(A_PUSH,NR_IX));
  1725. getcpuregister(list,NR_H);
  1726. getcpuregister(list,NR_L);
  1727. list.concat(taicpu.op_reg(A_POP,NR_HL));
  1728. emit_mov(list,r,NR_L);
  1729. ungetcpuregister(list,NR_L);
  1730. emit_mov(list,GetNextReg(r),NR_H);
  1731. ungetcpuregister(list,NR_H);
  1732. if (ref.index<>NR_NO) then
  1733. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  1734. if ref.offset<>0 then
  1735. a_op_const_reg(list,OP_ADD,OS_16,ref.offset,r);
  1736. end
  1737. else
  1738. begin
  1739. a_load_const_reg(list,OS_16,ref.offset,r);
  1740. if (ref.base<>NR_NO) then
  1741. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  1742. if (ref.index<>NR_NO) then
  1743. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  1744. end;
  1745. end;
  1746. procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  1747. var
  1748. tmpreg,srcreg,dstreg: tregister;
  1749. srcref,dstref : treference;
  1750. i: Integer;
  1751. begin
  1752. if (len<=2) and
  1753. is_ref_in_opertypes(source,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) and
  1754. is_ref_in_opertypes(dest,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
  1755. begin
  1756. srcref:=source;
  1757. dstref:=dest;
  1758. tmpreg:=getintregister(list,OS_8);
  1759. for i:=1 to len do
  1760. begin
  1761. list.concat(taicpu.op_reg_ref(A_LD,tmpreg,srcref));
  1762. list.concat(taicpu.op_ref_reg(A_LD,dstref,tmpreg));
  1763. if i<>len then
  1764. begin
  1765. adjust_normalized_ref(list,srcref,1);
  1766. adjust_normalized_ref(list,dstref,1);
  1767. end;
  1768. end;
  1769. end
  1770. else
  1771. begin
  1772. srcreg:=getintregister(list,OS_16);
  1773. a_loadaddr_ref_reg(list,source,srcreg);
  1774. dstreg:=getintregister(list,OS_16);
  1775. a_loadaddr_ref_reg(list,dest,dstreg);
  1776. getcpuregister(list,NR_L);
  1777. a_load_reg_reg(list,OS_8,OS_8,srcreg,NR_L);
  1778. getcpuregister(list,NR_H);
  1779. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(srcreg),NR_H);
  1780. getcpuregister(list,NR_E);
  1781. a_load_reg_reg(list,OS_8,OS_8,dstreg,NR_E);
  1782. getcpuregister(list,NR_D);
  1783. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(dstreg),NR_D);
  1784. getcpuregister(list,NR_B);
  1785. getcpuregister(list,NR_C);
  1786. list.concat(taicpu.op_reg_const(A_LD,NR_BC,len));
  1787. list.concat(taicpu.op_none(A_LDIR));
  1788. ungetcpuregister(list,NR_B);
  1789. ungetcpuregister(list,NR_C);
  1790. ungetcpuregister(list,NR_D);
  1791. ungetcpuregister(list,NR_E);
  1792. ungetcpuregister(list,NR_H);
  1793. ungetcpuregister(list,NR_L);
  1794. end;
  1795. end;
  1796. procedure tcgz80.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  1797. var
  1798. hl : tasmlabel;
  1799. ai : taicpu;
  1800. cond : TAsmCond;
  1801. begin
  1802. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck')));
  1803. //if not(cs_check_overflow in current_settings.localswitches) then
  1804. // exit;
  1805. //current_asmdata.getjumplabel(hl);
  1806. //if not ((def.typ=pointerdef) or
  1807. // ((def.typ=orddef) and
  1808. // (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1809. // pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1810. // cond:=C_VC
  1811. //else
  1812. // cond:=C_CC;
  1813. //ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1814. //ai.SetCondition(cond);
  1815. //ai.is_jmp:=true;
  1816. //list.concat(ai);
  1817. //
  1818. //a_call_name(list,'FPC_OVERFLOW',false);
  1819. //a_label(list,hl);
  1820. end;
  1821. procedure tcgz80.g_save_registers(list: TAsmList);
  1822. begin
  1823. { this is done by the entry code }
  1824. end;
  1825. procedure tcgz80.g_restore_registers(list: TAsmList);
  1826. begin
  1827. { this is done by the exit code }
  1828. end;
  1829. procedure tcgz80.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1830. var
  1831. ai1,ai2 : taicpu;
  1832. hl : TAsmLabel;
  1833. begin
  1834. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_jmp_cond')));
  1835. //ai1:=Taicpu.Op_sym(A_BRxx,l);
  1836. //ai1.is_jmp:=true;
  1837. //hl:=nil;
  1838. //case cond of
  1839. // OC_EQ:
  1840. // ai1.SetCondition(C_EQ);
  1841. // OC_GT:
  1842. // begin
  1843. // { emulate GT }
  1844. // current_asmdata.getjumplabel(hl);
  1845. // ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1846. // ai2.SetCondition(C_EQ);
  1847. // ai2.is_jmp:=true;
  1848. // list.concat(ai2);
  1849. //
  1850. // ai1.SetCondition(C_GE);
  1851. // end;
  1852. // OC_LT:
  1853. // ai1.SetCondition(C_LT);
  1854. // OC_GTE:
  1855. // ai1.SetCondition(C_GE);
  1856. // OC_LTE:
  1857. // begin
  1858. // { emulate LTE }
  1859. // ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1860. // ai2.SetCondition(C_EQ);
  1861. // ai2.is_jmp:=true;
  1862. // list.concat(ai2);
  1863. //
  1864. // ai1.SetCondition(C_LT);
  1865. // end;
  1866. // OC_NE:
  1867. // ai1.SetCondition(C_NE);
  1868. // OC_BE:
  1869. // begin
  1870. // { emulate BE }
  1871. // ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1872. // ai2.SetCondition(C_EQ);
  1873. // ai2.is_jmp:=true;
  1874. // list.concat(ai2);
  1875. //
  1876. // ai1.SetCondition(C_LO);
  1877. // end;
  1878. // OC_B:
  1879. // ai1.SetCondition(C_LO);
  1880. // OC_AE:
  1881. // ai1.SetCondition(C_SH);
  1882. // OC_A:
  1883. // begin
  1884. // { emulate A (unsigned GT) }
  1885. // current_asmdata.getjumplabel(hl);
  1886. // ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1887. // ai2.SetCondition(C_EQ);
  1888. // ai2.is_jmp:=true;
  1889. // list.concat(ai2);
  1890. //
  1891. // ai1.SetCondition(C_SH);
  1892. // end;
  1893. // else
  1894. // internalerror(2011082501);
  1895. //end;
  1896. //list.concat(ai1);
  1897. //if assigned(hl) then
  1898. // a_label(list,hl);
  1899. end;
  1900. procedure tcgz80.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  1901. var
  1902. instr: taicpu;
  1903. begin
  1904. instr:=taicpu.op_reg_reg(A_LD,reg2,reg1);
  1905. list.Concat(instr);
  1906. { Notify the register allocator that we have written a move instruction so
  1907. it can try to eliminate it. }
  1908. add_move_instruction(instr);
  1909. end;
  1910. procedure tcg64fz80.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1911. begin
  1912. if not(size in [OS_S64,OS_64]) then
  1913. internalerror(2012102402);
  1914. tcgz80(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  1915. end;
  1916. procedure tcg64fz80.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1917. begin
  1918. tcgz80(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  1919. end;
  1920. function GetByteLoc(const loc : tlocation; nr : byte) : tlocation;
  1921. var
  1922. i : Integer;
  1923. begin
  1924. Result:=loc;
  1925. Result.size:=OS_8;
  1926. case loc.loc of
  1927. LOC_REFERENCE,LOC_CREFERENCE:
  1928. inc(Result.reference.offset,nr);
  1929. LOC_REGISTER,LOC_CREGISTER:
  1930. begin
  1931. if nr>=4 then
  1932. Result.register:=Result.register64.reghi;
  1933. nr:=nr mod 4;
  1934. for i:=1 to nr do
  1935. Result.register:=GetNextReg(Result.register);
  1936. end;
  1937. LOC_CONSTANT:
  1938. if loc.size in [OS_64,OS_S64] then
  1939. Result.value:=(Result.value64 shr (nr*8)) and $ff
  1940. else
  1941. Result.value:=(Result.value shr (nr*8)) and $ff;
  1942. else
  1943. Internalerror(2019020902);
  1944. end;
  1945. end;
  1946. procedure create_codegen;
  1947. begin
  1948. cg:=tcgz80.create;
  1949. cg64:=tcg64fz80.create;
  1950. end;
  1951. end.