cgcpu.pas 82 KB

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