cgcpu.pas 81 KB

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