cgcpu.pas 92 KB

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