cgcpu.pas 79 KB

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