cgcpu.pas 95 KB

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