cgcpu.pas 75 KB

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