cgcpu.pas 76 KB

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