cgcpu.pas 74 KB

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