cgcpu.pas 75 KB

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