cgcpu.pas 76 KB

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