cgcpu.pas 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088
  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; out allocatedregs:tregisterlist) : 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;
  1100. const refopertypes: trefoperandtypes; out allocatedregs: tregisterlist
  1101. ): treference;
  1102. var
  1103. tmpref : treference;
  1104. l : tasmlabel;
  1105. begin
  1106. SetLength(allocatedregs,0);
  1107. if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then
  1108. begin
  1109. ref.base:=ref.index;
  1110. ref.index:=NR_NO;
  1111. end;
  1112. if is_ref_in_opertypes(ref,refopertypes) then
  1113. begin
  1114. Result:=ref;
  1115. exit;
  1116. end;
  1117. { can we use the HL register? }
  1118. if OT_REF_HL in refopertypes then
  1119. begin
  1120. SetLength(allocatedregs,2);
  1121. allocatedregs[0]:=NR_H;
  1122. allocatedregs[1]:=NR_L;
  1123. getcpuregisters(list,allocatedregs);
  1124. if assigned(ref.symbol) then
  1125. begin
  1126. reference_reset(tmpref,0,[]);
  1127. tmpref.symbol:=ref.symbol;
  1128. tmpref.offset:=ref.offset;
  1129. tmpref.refaddr:=addr_full;
  1130. list.concat(taicpu.op_reg_ref(A_LD,NR_HL,tmpref));
  1131. end
  1132. else
  1133. list.concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
  1134. if ref.base<>NR_NO then
  1135. begin
  1136. getcpuregister(list,NR_A);
  1137. emit_mov(list,NR_A,NR_L);
  1138. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.base));
  1139. emit_mov(list,NR_L,NR_A);
  1140. emit_mov(list,NR_A,NR_H);
  1141. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.base)));
  1142. emit_mov(list,NR_H,NR_A);
  1143. ungetcpuregister(list,NR_A);
  1144. end;
  1145. if ref.index<>NR_NO then
  1146. begin
  1147. if ref.scalefactor>1 then
  1148. internalerror(2020042002);
  1149. getcpuregister(list,NR_A);
  1150. emit_mov(list,NR_A,NR_L);
  1151. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index));
  1152. emit_mov(list,NR_L,NR_A);
  1153. emit_mov(list,NR_A,NR_H);
  1154. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index)));
  1155. emit_mov(list,NR_H,NR_A);
  1156. ungetcpuregister(list,NR_A);
  1157. end;
  1158. end
  1159. else
  1160. internalerror(2020042001);
  1161. end;
  1162. procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  1163. var
  1164. href : treference;
  1165. i : integer;
  1166. begin
  1167. href:=Ref;
  1168. { ensure, href.base contains a valid register if there is any register used }
  1169. if href.base=NR_NO then
  1170. begin
  1171. href.base:=href.index;
  1172. href.index:=NR_NO;
  1173. end;
  1174. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1175. internalerror(2011021307);
  1176. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1177. internalerror(2020040802);
  1178. if (fromsize=tosize) or (fromsize in [OS_8,OS_16,OS_32]) then
  1179. begin
  1180. getcpuregister(list,NR_A);
  1181. for i:=1 to tcgsize2size[fromsize] do
  1182. begin
  1183. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1184. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1185. if i<>tcgsize2size[fromsize] then
  1186. reg:=GetNextReg(reg);
  1187. if i<>tcgsize2size[tosize] then
  1188. inc(href.offset);
  1189. end;
  1190. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1191. begin
  1192. if i=(tcgsize2size[fromsize]+1) then
  1193. list.concat(taicpu.op_reg_const(A_LD,NR_A,0));
  1194. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1195. if i<>tcgsize2size[tosize] then
  1196. begin
  1197. inc(href.offset);
  1198. reg:=GetNextReg(reg);
  1199. end;
  1200. end;
  1201. ungetcpuregister(list,NR_A);
  1202. end
  1203. else
  1204. begin
  1205. getcpuregister(list,NR_A);
  1206. for i:=1 to tcgsize2size[fromsize] do
  1207. begin
  1208. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1209. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1210. if i<>tcgsize2size[fromsize] then
  1211. reg:=GetNextReg(reg);
  1212. if i<>tcgsize2size[tosize] then
  1213. inc(href.offset);
  1214. end;
  1215. list.concat(taicpu.op_none(A_RLA));
  1216. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1217. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1218. begin
  1219. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1220. if i<>tcgsize2size[tosize] then
  1221. begin
  1222. inc(href.offset);
  1223. reg:=GetNextReg(reg);
  1224. end;
  1225. end;
  1226. ungetcpuregister(list,NR_A);
  1227. end;
  1228. end;
  1229. procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1230. const Ref : treference;reg : tregister);
  1231. var
  1232. href : treference;
  1233. i : integer;
  1234. begin
  1235. href:=Ref;
  1236. { ensure, href.base contains a valid register if there is any register used }
  1237. if href.base=NR_NO then
  1238. begin
  1239. href.base:=href.index;
  1240. href.index:=NR_NO;
  1241. end;
  1242. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1243. internalerror(2011021307);
  1244. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1245. internalerror(2020040804);
  1246. if (tosize=fromsize) or (fromsize in [OS_8,OS_16,OS_32]) then
  1247. begin
  1248. getcpuregister(list,NR_A);
  1249. for i:=1 to tcgsize2size[fromsize] do
  1250. begin
  1251. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1252. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1253. if i<>tcgsize2size[fromsize] then
  1254. inc(href.offset);
  1255. if i<>tcgsize2size[tosize] then
  1256. reg:=GetNextReg(reg);
  1257. end;
  1258. ungetcpuregister(list,NR_A);
  1259. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1260. begin
  1261. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  1262. if i<>tcgsize2size[tosize] then
  1263. reg:=GetNextReg(reg);
  1264. end;
  1265. end
  1266. else
  1267. begin
  1268. getcpuregister(list,NR_A);
  1269. for i:=1 to tcgsize2size[fromsize] do
  1270. begin
  1271. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1272. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1273. if i<>tcgsize2size[fromsize] then
  1274. inc(href.offset);
  1275. if i<>tcgsize2size[tosize] then
  1276. reg:=GetNextReg(reg);
  1277. end;
  1278. list.concat(taicpu.op_none(A_RLA));
  1279. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1280. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1281. begin
  1282. emit_mov(list,reg,NR_A);
  1283. if i<>tcgsize2size[tosize] then
  1284. reg:=GetNextReg(reg);
  1285. end;
  1286. ungetcpuregister(list,NR_A);
  1287. end;
  1288. end;
  1289. procedure tcgz80.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1290. var
  1291. conv_done: boolean;
  1292. tmpreg : tregister;
  1293. i : integer;
  1294. begin
  1295. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1296. internalerror(2011021310);
  1297. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1298. fromsize:=tosize;
  1299. if (tosize=fromsize) or (fromsize in [OS_8,OS_16,OS_32]) then
  1300. begin
  1301. if reg1<>reg2 then
  1302. for i:=1 to tcgsize2size[fromsize] do
  1303. begin
  1304. emit_mov(list,reg2,reg1);
  1305. if i<>tcgsize2size[fromsize] then
  1306. reg1:=GetNextReg(reg1);
  1307. if i<>tcgsize2size[tosize] then
  1308. reg2:=GetNextReg(reg2);
  1309. end
  1310. else
  1311. for i:=1 to tcgsize2size[fromsize] do
  1312. if i<>tcgsize2size[tosize] then
  1313. reg2:=GetNextReg(reg2);
  1314. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1315. begin
  1316. list.Concat(taicpu.op_reg_const(A_LD,reg2,0));
  1317. if i<>tcgsize2size[tosize] then
  1318. reg2:=GetNextReg(reg2);
  1319. end
  1320. end
  1321. else
  1322. begin
  1323. if reg1<>reg2 then
  1324. for i:=1 to tcgsize2size[fromsize]-1 do
  1325. begin
  1326. emit_mov(list,reg2,reg1);
  1327. reg1:=GetNextReg(reg1);
  1328. reg2:=GetNextReg(reg2);
  1329. end
  1330. else
  1331. for i:=1 to tcgsize2size[fromsize]-1 do
  1332. reg2:=GetNextReg(reg2);
  1333. emit_mov(list,reg2,reg1);
  1334. getcpuregister(list,NR_A);
  1335. emit_mov(list,NR_A,reg2);
  1336. reg2:=GetNextReg(reg2);
  1337. list.concat(taicpu.op_none(A_RLA));
  1338. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1339. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1340. begin
  1341. emit_mov(list,reg2,NR_A);
  1342. if i<>tcgsize2size[tosize] then
  1343. reg2:=GetNextReg(reg2);
  1344. end;
  1345. ungetcpuregister(list,NR_A);
  1346. end;
  1347. end;
  1348. procedure tcgz80.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1349. begin
  1350. internalerror(2012010702);
  1351. end;
  1352. procedure tcgz80.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1353. begin
  1354. internalerror(2012010703);
  1355. end;
  1356. procedure tcgz80.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1357. begin
  1358. internalerror(2012010704);
  1359. end;
  1360. { comparison operations }
  1361. procedure tcgz80.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1362. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1363. var
  1364. swapped : boolean;
  1365. tmpreg : tregister;
  1366. i : byte;
  1367. begin
  1368. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_cmp_const_reg_label')));
  1369. //if a=0 then
  1370. // begin
  1371. // swapped:=false;
  1372. // { swap parameters? }
  1373. // case cmp_op of
  1374. // OC_GT:
  1375. // begin
  1376. // swapped:=true;
  1377. // cmp_op:=OC_LT;
  1378. // end;
  1379. // OC_LTE:
  1380. // begin
  1381. // swapped:=true;
  1382. // cmp_op:=OC_GTE;
  1383. // end;
  1384. // OC_BE:
  1385. // begin
  1386. // swapped:=true;
  1387. // cmp_op:=OC_AE;
  1388. // end;
  1389. // OC_A:
  1390. // begin
  1391. // swapped:=true;
  1392. // cmp_op:=OC_B;
  1393. // end;
  1394. // end;
  1395. //
  1396. // if swapped then
  1397. // list.concat(taicpu.op_reg_reg(A_CP,NR_R1,reg))
  1398. // else
  1399. // list.concat(taicpu.op_reg_reg(A_CP,reg,NR_R1));
  1400. //
  1401. // for i:=2 to tcgsize2size[size] do
  1402. // begin
  1403. // reg:=GetNextReg(reg);
  1404. // if swapped then
  1405. // list.concat(taicpu.op_reg_reg(A_CPC,NR_R1,reg))
  1406. // else
  1407. // list.concat(taicpu.op_reg_reg(A_CPC,reg,NR_R1));
  1408. // end;
  1409. //
  1410. // a_jmp_cond(list,cmp_op,l);
  1411. // end
  1412. //else
  1413. // inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
  1414. end;
  1415. procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1416. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1417. var
  1418. swapped : boolean;
  1419. tmpreg : tregister;
  1420. i : byte;
  1421. begin
  1422. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_cmp_reg_reg_label')));
  1423. //swapped:=false;
  1424. //{ swap parameters? }
  1425. //case cmp_op of
  1426. // OC_GT:
  1427. // begin
  1428. // swapped:=true;
  1429. // cmp_op:=OC_LT;
  1430. // end;
  1431. // OC_LTE:
  1432. // begin
  1433. // swapped:=true;
  1434. // cmp_op:=OC_GTE;
  1435. // end;
  1436. // OC_BE:
  1437. // begin
  1438. // swapped:=true;
  1439. // cmp_op:=OC_AE;
  1440. // end;
  1441. // OC_A:
  1442. // begin
  1443. // swapped:=true;
  1444. // cmp_op:=OC_B;
  1445. // end;
  1446. //end;
  1447. //if swapped then
  1448. // begin
  1449. // tmpreg:=reg1;
  1450. // reg1:=reg2;
  1451. // reg2:=tmpreg;
  1452. // end;
  1453. //list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1454. //
  1455. //for i:=2 to tcgsize2size[size] do
  1456. // begin
  1457. // reg1:=GetNextReg(reg1);
  1458. // reg2:=GetNextReg(reg2);
  1459. // list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1460. // end;
  1461. //
  1462. //a_jmp_cond(list,cmp_op,l);
  1463. end;
  1464. procedure tcgz80.a_jmp_name(list : TAsmList;const s : string);
  1465. var
  1466. ai : taicpu;
  1467. begin
  1468. ai:=taicpu.op_sym(A_JP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1469. ai.is_jmp:=true;
  1470. list.concat(ai);
  1471. end;
  1472. procedure tcgz80.a_jmp_always(list : TAsmList;l: tasmlabel);
  1473. var
  1474. ai : taicpu;
  1475. begin
  1476. ai:=taicpu.op_sym(A_JP,l);
  1477. ai.is_jmp:=true;
  1478. list.concat(ai);
  1479. end;
  1480. procedure tcgz80.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1481. var
  1482. ai : taicpu;
  1483. begin
  1484. ai:=taicpu.op_cond_sym(A_JP,flags_to_cond(f),l);
  1485. ai.is_jmp:=true;
  1486. list.concat(ai);
  1487. end;
  1488. procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1489. var
  1490. l : TAsmLabel;
  1491. tmpflags : TResFlags;
  1492. begin
  1493. if f in [F_C,F_NC] then
  1494. begin
  1495. a_load_const_reg(list,size,0,reg);
  1496. if f=F_NC then
  1497. list.concat(taicpu.op_none(A_CCF));
  1498. list.concat(taicpu.op_reg(A_RL,reg));
  1499. end
  1500. else
  1501. begin
  1502. current_asmdata.getjumplabel(l);
  1503. a_load_const_reg(list,size,0,reg);
  1504. tmpflags:=f;
  1505. inverse_flags(tmpflags);
  1506. a_jmp_flags(list,tmpflags,l);
  1507. list.concat(taicpu.op_reg(A_INC,reg));
  1508. cg.a_label(list,l);
  1509. end;
  1510. end;
  1511. procedure tcgz80.g_stackpointer_alloc(list: TAsmList; localsize: longint);
  1512. begin
  1513. if localsize>0 then
  1514. begin
  1515. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize));
  1516. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
  1517. list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
  1518. end;
  1519. end;
  1520. procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
  1521. var
  1522. i : integer;
  1523. begin
  1524. //case value of
  1525. // 0:
  1526. // ;
  1527. // {-14..-1:
  1528. // begin
  1529. // if ((-value) mod 2)<>0 then
  1530. // list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1531. // for i:=1 to (-value) div 2 do
  1532. // list.concat(taicpu.op_const(A_RCALL,0));
  1533. // end;
  1534. // 1..7:
  1535. // begin
  1536. // for i:=1 to value do
  1537. // list.concat(taicpu.op_reg(A_POP,NR_R0));
  1538. // end;}
  1539. // else
  1540. // begin
  1541. // list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1542. // list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1543. // // get SREG
  1544. // list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1545. //
  1546. // // block interrupts
  1547. // list.concat(taicpu.op_none(A_CLI));
  1548. //
  1549. // // write high SP
  1550. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1551. //
  1552. // // release interrupts
  1553. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1554. //
  1555. // // write low SP
  1556. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1557. // end;
  1558. //end;
  1559. end;
  1560. procedure tcgz80.make_simple_ref(list: TAsmList; var ref: treference);
  1561. begin
  1562. end;
  1563. procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1564. var
  1565. regsize,stackmisalignment: longint;
  1566. begin
  1567. regsize:=0;
  1568. stackmisalignment:=0;
  1569. { save old framepointer }
  1570. if not nostackframe then
  1571. begin
  1572. { return address }
  1573. inc(stackmisalignment,2);
  1574. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  1575. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1576. begin
  1577. { push <frame_pointer> }
  1578. inc(stackmisalignment,2);
  1579. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  1580. list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG));
  1581. { Return address and FP are both on stack }
  1582. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2);
  1583. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2));
  1584. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  1585. begin
  1586. list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0));
  1587. list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG))
  1588. end
  1589. else
  1590. begin
  1591. internalerror(2020040301);
  1592. (*push_regs;
  1593. gen_load_frame_for_exceptfilter(list);
  1594. { Need only as much stack space as necessary to do the calls.
  1595. Exception filters don't have own local vars, and temps are 'mapped'
  1596. to the parent procedure.
  1597. maxpushedparasize is already aligned at least on x86_64. }
  1598. localsize:=current_procinfo.maxpushedparasize;*)
  1599. end;
  1600. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  1601. end
  1602. else
  1603. begin
  1604. CGmessage(cg_d_stackframe_omited);
  1605. end;
  1606. { allocate stackframe space }
  1607. if (localsize<>0) or
  1608. ((target_info.stackalign>sizeof(pint)) and
  1609. (stackmisalignment <> 0) and
  1610. ((pi_do_call in current_procinfo.flags) or
  1611. (po_assembler in current_procinfo.procdef.procoptions))) then
  1612. begin
  1613. if target_info.stackalign>sizeof(pint) then
  1614. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  1615. g_stackpointer_alloc(list,localsize);
  1616. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1617. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
  1618. current_procinfo.final_localsize:=localsize;
  1619. end
  1620. end;
  1621. end;
  1622. procedure tcgz80.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1623. var
  1624. regs : tcpuregisterset;
  1625. reg : TSuperRegister;
  1626. LocalSize : longint;
  1627. begin
  1628. { every byte counts for Z80, so if a subroutine is marked as non-returning, we do
  1629. not generate any exit code, so we really trust the noreturn directive
  1630. }
  1631. if po_noreturn in current_procinfo.procdef.procoptions then
  1632. exit;
  1633. { remove stackframe }
  1634. if not nostackframe then
  1635. begin
  1636. stacksize:=current_procinfo.calc_stackframe_size;
  1637. if (target_info.stackalign>4) and
  1638. ((stacksize <> 0) or
  1639. (pi_do_call in current_procinfo.flags) or
  1640. { can't detect if a call in this case -> use nostackframe }
  1641. { if you (think you) know what you are doing }
  1642. (po_assembler in current_procinfo.procdef.procoptions)) then
  1643. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  1644. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1645. begin
  1646. internalerror(2020040302);
  1647. {if (stacksize<>0) then
  1648. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);}
  1649. end
  1650. else
  1651. begin
  1652. list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  1653. list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG));
  1654. end;
  1655. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  1656. end;
  1657. list.concat(taicpu.op_none(A_RET));
  1658. end;
  1659. procedure tcgz80.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1660. var
  1661. tmpref : treference;
  1662. begin
  1663. if assigned(ref.symbol) then
  1664. begin
  1665. reference_reset(tmpref,0,[]);
  1666. tmpref.symbol:=ref.symbol;
  1667. tmpref.offset:=ref.offset;
  1668. tmpref.refaddr:=addr_lo8;
  1669. list.concat(taicpu.op_reg_ref(A_LD,r,tmpref));
  1670. tmpref.refaddr:=addr_hi8;
  1671. list.concat(taicpu.op_reg_ref(A_LD,GetNextReg(r),tmpref));
  1672. if (ref.base<>NR_NO) then
  1673. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  1674. if (ref.index<>NR_NO) then
  1675. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  1676. end
  1677. else if ref.base=NR_IX then
  1678. begin
  1679. list.concat(taicpu.op_reg(A_PUSH,NR_IX));
  1680. getcpuregister(list,NR_H);
  1681. getcpuregister(list,NR_L);
  1682. list.concat(taicpu.op_reg(A_POP,NR_HL));
  1683. emit_mov(list,r,NR_L);
  1684. ungetcpuregister(list,NR_L);
  1685. emit_mov(list,GetNextReg(r),NR_H);
  1686. ungetcpuregister(list,NR_H);
  1687. if (ref.index<>NR_NO) then
  1688. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  1689. if ref.offset<>0 then
  1690. a_op_const_reg(list,OP_ADD,OS_16,ref.offset,r);
  1691. end
  1692. else
  1693. begin
  1694. a_load_const_reg(list,OS_16,ref.offset,r);
  1695. if (ref.base<>NR_NO) then
  1696. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  1697. if (ref.index<>NR_NO) then
  1698. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  1699. end;
  1700. end;
  1701. procedure tcgz80.fixref(list : TAsmList;var ref : treference);
  1702. begin
  1703. internalerror(2011021320);
  1704. end;
  1705. procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  1706. var
  1707. tmpreg,srcreg,dstreg: tregister;
  1708. srcref,dstref : treference;
  1709. begin
  1710. if (len=1) and
  1711. is_ref_in_opertypes(source,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) and
  1712. is_ref_in_opertypes(dest,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
  1713. begin
  1714. tmpreg:=getintregister(list,OS_8);
  1715. list.concat(taicpu.op_reg_ref(A_LD,tmpreg,source));
  1716. list.concat(taicpu.op_ref_reg(A_LD,dest,tmpreg));
  1717. end
  1718. else
  1719. begin
  1720. srcreg:=getintregister(list,OS_16);
  1721. a_loadaddr_ref_reg(list,source,srcreg);
  1722. dstreg:=getintregister(list,OS_16);
  1723. a_loadaddr_ref_reg(list,dest,dstreg);
  1724. getcpuregister(list,NR_L);
  1725. a_load_reg_reg(list,OS_8,OS_8,srcreg,NR_L);
  1726. getcpuregister(list,NR_H);
  1727. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(srcreg),NR_H);
  1728. getcpuregister(list,NR_E);
  1729. a_load_reg_reg(list,OS_8,OS_8,dstreg,NR_E);
  1730. getcpuregister(list,NR_D);
  1731. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(dstreg),NR_D);
  1732. getcpuregister(list,NR_B);
  1733. getcpuregister(list,NR_C);
  1734. list.concat(taicpu.op_reg_const(A_LD,NR_BC,len));
  1735. list.concat(taicpu.op_none(A_LDIR));
  1736. ungetcpuregister(list,NR_B);
  1737. ungetcpuregister(list,NR_C);
  1738. ungetcpuregister(list,NR_D);
  1739. ungetcpuregister(list,NR_E);
  1740. ungetcpuregister(list,NR_H);
  1741. ungetcpuregister(list,NR_L);
  1742. end;
  1743. end;
  1744. procedure tcgz80.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  1745. var
  1746. hl : tasmlabel;
  1747. ai : taicpu;
  1748. cond : TAsmCond;
  1749. begin
  1750. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck')));
  1751. //if not(cs_check_overflow in current_settings.localswitches) then
  1752. // exit;
  1753. //current_asmdata.getjumplabel(hl);
  1754. //if not ((def.typ=pointerdef) or
  1755. // ((def.typ=orddef) and
  1756. // (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1757. // pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1758. // cond:=C_VC
  1759. //else
  1760. // cond:=C_CC;
  1761. //ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1762. //ai.SetCondition(cond);
  1763. //ai.is_jmp:=true;
  1764. //list.concat(ai);
  1765. //
  1766. //a_call_name(list,'FPC_OVERFLOW',false);
  1767. //a_label(list,hl);
  1768. end;
  1769. procedure tcgz80.g_save_registers(list: TAsmList);
  1770. begin
  1771. { this is done by the entry code }
  1772. end;
  1773. procedure tcgz80.g_restore_registers(list: TAsmList);
  1774. begin
  1775. { this is done by the exit code }
  1776. end;
  1777. procedure tcgz80.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1778. var
  1779. ai1,ai2 : taicpu;
  1780. hl : TAsmLabel;
  1781. begin
  1782. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: a_jmp_cond')));
  1783. //ai1:=Taicpu.Op_sym(A_BRxx,l);
  1784. //ai1.is_jmp:=true;
  1785. //hl:=nil;
  1786. //case cond of
  1787. // OC_EQ:
  1788. // ai1.SetCondition(C_EQ);
  1789. // OC_GT:
  1790. // begin
  1791. // { emulate GT }
  1792. // current_asmdata.getjumplabel(hl);
  1793. // ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1794. // ai2.SetCondition(C_EQ);
  1795. // ai2.is_jmp:=true;
  1796. // list.concat(ai2);
  1797. //
  1798. // ai1.SetCondition(C_GE);
  1799. // end;
  1800. // OC_LT:
  1801. // ai1.SetCondition(C_LT);
  1802. // OC_GTE:
  1803. // ai1.SetCondition(C_GE);
  1804. // OC_LTE:
  1805. // begin
  1806. // { emulate LTE }
  1807. // ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1808. // ai2.SetCondition(C_EQ);
  1809. // ai2.is_jmp:=true;
  1810. // list.concat(ai2);
  1811. //
  1812. // ai1.SetCondition(C_LT);
  1813. // end;
  1814. // OC_NE:
  1815. // ai1.SetCondition(C_NE);
  1816. // OC_BE:
  1817. // begin
  1818. // { emulate BE }
  1819. // ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1820. // ai2.SetCondition(C_EQ);
  1821. // ai2.is_jmp:=true;
  1822. // list.concat(ai2);
  1823. //
  1824. // ai1.SetCondition(C_LO);
  1825. // end;
  1826. // OC_B:
  1827. // ai1.SetCondition(C_LO);
  1828. // OC_AE:
  1829. // ai1.SetCondition(C_SH);
  1830. // OC_A:
  1831. // begin
  1832. // { emulate A (unsigned GT) }
  1833. // current_asmdata.getjumplabel(hl);
  1834. // ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1835. // ai2.SetCondition(C_EQ);
  1836. // ai2.is_jmp:=true;
  1837. // list.concat(ai2);
  1838. //
  1839. // ai1.SetCondition(C_SH);
  1840. // end;
  1841. // else
  1842. // internalerror(2011082501);
  1843. //end;
  1844. //list.concat(ai1);
  1845. //if assigned(hl) then
  1846. // a_label(list,hl);
  1847. end;
  1848. procedure tcgz80.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  1849. var
  1850. instr: taicpu;
  1851. begin
  1852. instr:=taicpu.op_reg_reg(A_LD,reg2,reg1);
  1853. list.Concat(instr);
  1854. { Notify the register allocator that we have written a move instruction so
  1855. it can try to eliminate it. }
  1856. add_move_instruction(instr);
  1857. end;
  1858. procedure tcg64fz80.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1859. begin
  1860. if not(size in [OS_S64,OS_64]) then
  1861. internalerror(2012102402);
  1862. tcgz80(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  1863. end;
  1864. procedure tcg64fz80.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1865. begin
  1866. tcgz80(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  1867. end;
  1868. function GetByteLoc(const loc : tlocation; nr : byte) : tlocation;
  1869. var
  1870. i : Integer;
  1871. begin
  1872. Result:=loc;
  1873. Result.size:=OS_8;
  1874. case loc.loc of
  1875. LOC_REFERENCE,LOC_CREFERENCE:
  1876. inc(Result.reference.offset,nr);
  1877. LOC_REGISTER,LOC_CREGISTER:
  1878. begin
  1879. if nr>=4 then
  1880. Result.register:=Result.register64.reghi;
  1881. nr:=nr mod 4;
  1882. for i:=1 to nr do
  1883. Result.register:=GetNextReg(Result.register);
  1884. end;
  1885. LOC_CONSTANT:
  1886. if loc.size in [OS_64,OS_S64] then
  1887. Result.value:=(Result.value64 shr (nr*8)) and $ff
  1888. else
  1889. Result.value:=(Result.value shr (nr*8)) and $ff;
  1890. else
  1891. Internalerror(2019020902);
  1892. end;
  1893. end;
  1894. procedure create_codegen;
  1895. begin
  1896. cg:=tcgz80.create;
  1897. cg64:=tcg64fz80.create;
  1898. end;
  1899. end.