cgcpu.pas 91 KB

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