cgcpu.pas 74 KB

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