cgcpu.pas 80 KB

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