cgcpu.pas 73 KB

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