cgcpu.pas 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559
  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 gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean);
  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. end;
  482. var
  483. tmpref, ref, href: treference;
  484. location: pcgparalocation;
  485. sizeleft: tcgint;
  486. len: tcgint;
  487. begin
  488. { cgpara.size=OS_NO requires a copy on the stack }
  489. if use_push(cgpara) then
  490. begin
  491. { Record copy? }
  492. if (cgpara.size in [OS_NO,OS_F64]) or (size=OS_NO) then
  493. begin
  494. cgpara.check_simple_location;
  495. len:=align(cgpara.intsize,cgpara.alignment);
  496. g_stackpointer_alloc(list,len);
  497. reference_reset_base(href,NR_STACK_POINTER_REG,0,ctempposinvalid,4,[]);
  498. g_concatcopy(list,r,href,len);
  499. end
  500. else
  501. begin
  502. if tcgsize2size[cgpara.size]<>tcgsize2size[size] then
  503. internalerror(200501161);
  504. { We need to push the data in reverse order,
  505. therefor we use a recursive algorithm }
  506. pushdata(cgpara.location,0);
  507. end
  508. end
  509. else
  510. begin
  511. location := cgpara.location;
  512. tmpref := r;
  513. sizeleft := cgpara.intsize;
  514. while assigned(location) do
  515. begin
  516. paramanager.allocparaloc(list,location);
  517. case location^.loc of
  518. LOC_REGISTER,LOC_CREGISTER:
  519. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  520. LOC_REFERENCE:
  521. begin
  522. reference_reset_base(ref,location^.reference.index,location^.reference.offset,ctempposinvalid,cgpara.alignment,[]);
  523. { doubles in softemu mode have a strange order of registers and references }
  524. if location^.size=OS_32 then
  525. g_concatcopy(list,tmpref,ref,4)
  526. else
  527. begin
  528. g_concatcopy(list,tmpref,ref,sizeleft);
  529. if assigned(location^.next) then
  530. internalerror(2005010710);
  531. end;
  532. end;
  533. LOC_VOID:
  534. begin
  535. // nothing to do
  536. end;
  537. else
  538. internalerror(2002081103);
  539. end;
  540. inc(tmpref.offset,tcgsize2size[location^.size]);
  541. dec(sizeleft,tcgsize2size[location^.size]);
  542. location := location^.next;
  543. end;
  544. end;
  545. end;
  546. procedure tcgz80.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  547. var
  548. tmpreg: tregister;
  549. begin
  550. tmpreg:=getaddressregister(list);
  551. a_loadaddr_ref_reg(list,r,tmpreg);
  552. a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc);
  553. end;
  554. procedure tcgz80.a_call_name(list : TAsmList;const s : string; weak: boolean);
  555. var
  556. sym: TAsmSymbol;
  557. begin
  558. if weak then
  559. sym:=current_asmdata.WeakRefAsmSymbol(s,AT_FUNCTION)
  560. else
  561. sym:=current_asmdata.RefAsmSymbol(s,AT_FUNCTION);
  562. list.concat(taicpu.op_sym(A_CALL,sym));
  563. include(current_procinfo.flags,pi_do_call);
  564. end;
  565. procedure tcgz80.a_call_reg(list : TAsmList;reg: tregister);
  566. var
  567. l : TAsmLabel;
  568. ref : treference;
  569. begin
  570. { HACK: at this point all registers are allocated, due to the way the
  571. calling convention works, but we need to free some registers, in order
  572. for the following code to work, so we do it here }
  573. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  574. getcpuregister(list,NR_L);
  575. a_load_reg_reg(list,OS_8,OS_8,reg,NR_L);
  576. getcpuregister(list,NR_H);
  577. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(reg),NR_H);
  578. current_asmdata.getjumplabel(l);
  579. reference_reset(ref,0,[]);
  580. ref.symbol:=l;
  581. list.concat(taicpu.op_ref_reg(A_LD,ref,NR_HL));
  582. ungetcpuregister(list,NR_H);
  583. ungetcpuregister(list,NR_L);
  584. { allocate them again, right before the actual call instruction }
  585. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  586. list.concat(tai_const.Create_8bit($CD)); { $CD is the opcode of the call instruction }
  587. list.concat(tai_label.Create(l));
  588. list.concat(tai_const.Create_16bit(0));
  589. include(current_procinfo.flags,pi_do_call);
  590. end;
  591. procedure tcgz80.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  592. begin
  593. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  594. internalerror(2012102403);
  595. a_op_const_reg_internal(list,Op,size,a,reg,NR_NO);
  596. end;
  597. procedure tcgz80.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister);
  598. begin
  599. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  600. internalerror(2012102401);
  601. a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO);
  602. end;
  603. procedure tcgz80.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  604. var
  605. i : integer;
  606. procedure NextSrcDst;
  607. begin
  608. if i=5 then
  609. begin
  610. dst:=dsthi;
  611. src:=srchi;
  612. end
  613. else
  614. begin
  615. dst:=GetNextReg(dst);
  616. src:=GetNextReg(src);
  617. end;
  618. end;
  619. var
  620. tmpreg,tmpreg2: tregister;
  621. instr : taicpu;
  622. l1,l2 : tasmlabel;
  623. begin
  624. case op of
  625. OP_ADD:
  626. begin
  627. getcpuregister(list,NR_A);
  628. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  629. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,src));
  630. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  631. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  632. begin
  633. for i:=2 to tcgsize2size[size] do
  634. begin
  635. NextSrcDst;
  636. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  637. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,src));
  638. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  639. end;
  640. end;
  641. ungetcpuregister(list,NR_A);
  642. end;
  643. OP_SUB:
  644. begin
  645. getcpuregister(list,NR_A);
  646. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  647. list.concat(taicpu.op_reg_reg(A_SUB,NR_A,src));
  648. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  649. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  650. begin
  651. for i:=2 to tcgsize2size[size] do
  652. begin
  653. NextSrcDst;
  654. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  655. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,src));
  656. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  657. end;
  658. end;
  659. ungetcpuregister(list,NR_A);
  660. end;
  661. OP_NEG:
  662. begin
  663. getcpuregister(list,NR_A);
  664. if tcgsize2size[size]>=2 then
  665. begin
  666. tmpreg:=GetNextReg(src);
  667. tmpreg2:=GetNextReg(dst);
  668. for i:=2 to tcgsize2size[size] do
  669. begin
  670. a_load_reg_reg(list,OS_8,OS_8,tmpreg,NR_A);
  671. list.concat(taicpu.op_none(A_CPL));
  672. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  673. if i<>tcgsize2size[size] then
  674. begin
  675. if i=4 then
  676. begin
  677. tmpreg:=srchi;
  678. tmpreg2:=dsthi;
  679. end
  680. else
  681. begin
  682. tmpreg:=GetNextReg(tmpreg);
  683. tmpreg2:=GetNextReg(tmpreg2);
  684. end;
  685. end;
  686. end;
  687. end;
  688. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  689. list.concat(taicpu.op_none(A_NEG));
  690. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  691. if tcgsize2size[size]>=2 then
  692. begin
  693. tmpreg2:=GetNextReg(dst);
  694. for i:=2 to tcgsize2size[size] do
  695. begin
  696. a_load_reg_reg(list,OS_8,OS_8,tmpreg2,NR_A);
  697. list.concat(taicpu.op_reg_const(A_SBC,NR_A,-1));
  698. a_load_reg_reg(list,OS_8,OS_8,NR_A,tmpreg2);
  699. if i<>tcgsize2size[size] then
  700. begin
  701. if i=4 then
  702. begin
  703. tmpreg2:=dsthi;
  704. end
  705. else
  706. begin
  707. tmpreg2:=GetNextReg(tmpreg2);
  708. end;
  709. end;
  710. end;
  711. end;
  712. ungetcpuregister(list,NR_A);
  713. end;
  714. OP_NOT:
  715. begin
  716. getcpuregister(list,NR_A);
  717. for i:=1 to tcgsize2size[size] do
  718. begin
  719. if i<>1 then
  720. NextSrcDst;
  721. a_load_reg_reg(list,OS_8,OS_8,src,NR_A);
  722. list.concat(taicpu.op_none(A_CPL));
  723. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  724. end;
  725. ungetcpuregister(list,NR_A);
  726. end;
  727. OP_MUL,OP_IMUL:
  728. begin
  729. tmpreg:=dst;
  730. if size in [OS_16,OS_S16] then
  731. begin
  732. tmpreg:=getintregister(list,size);
  733. a_load_reg_reg(list,size,size,dst,tmpreg);
  734. end;
  735. gen_multiply(list,op,size,src,tmpreg,dst,false);
  736. end;
  737. OP_DIV,OP_IDIV:
  738. { special stuff, needs separate handling inside code
  739. generator }
  740. internalerror(2017032604);
  741. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  742. begin
  743. current_asmdata.getjumplabel(l1);
  744. current_asmdata.getjumplabel(l2);
  745. getcpuregister(list,NR_B);
  746. emit_mov(list,NR_B,src);
  747. list.concat(taicpu.op_reg(A_INC,NR_B));
  748. list.concat(taicpu.op_reg(A_DEC,NR_B));
  749. a_jmp_flags(list,F_E,l2);
  750. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  751. case op of
  752. OP_ROL:
  753. begin
  754. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  755. list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  756. end;
  757. OP_ROR:
  758. begin
  759. list.concat(taicpu.op_reg(A_RLC,dst));
  760. list.concat(taicpu.op_reg(A_RRC,dst));
  761. end;
  762. else
  763. ;
  764. end;
  765. cg.a_label(list,l1);
  766. case op of
  767. OP_SHL:
  768. list.concat(taicpu.op_reg(A_SLA,dst));
  769. OP_SHR:
  770. list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  771. OP_SAR:
  772. list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  773. OP_ROL:
  774. if size in [OS_8,OS_S8] then
  775. list.concat(taicpu.op_reg(A_RLC,dst))
  776. else
  777. list.concat(taicpu.op_reg(A_RL,dst));
  778. OP_ROR:
  779. if size in [OS_8,OS_S8] then
  780. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)))
  781. else
  782. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  783. else
  784. internalerror(2020040903);
  785. end;
  786. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  787. begin
  788. for i:=2 to tcgsize2size[size] do
  789. begin
  790. case op of
  791. OP_ROR,
  792. OP_SHR,
  793. OP_SAR:
  794. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  795. OP_ROL,
  796. OP_SHL:
  797. list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(dst,dsthi,i-1)));
  798. else
  799. internalerror(2020040904);
  800. end;
  801. end;
  802. end;
  803. instr:=taicpu.op_sym(A_DJNZ,l1);
  804. instr.is_jmp:=true;
  805. list.concat(instr);
  806. ungetcpuregister(list,NR_B);
  807. cg.a_label(list,l2);
  808. end;
  809. OP_AND,OP_OR,OP_XOR:
  810. begin
  811. getcpuregister(list,NR_A);
  812. for i:=1 to tcgsize2size[size] do
  813. begin
  814. if i<>1 then
  815. NextSrcDst;
  816. a_load_reg_reg(list,OS_8,OS_8,dst,NR_A);
  817. list.concat(taicpu.op_reg_reg(topcg2asmop[op],NR_A,src));
  818. a_load_reg_reg(list,OS_8,OS_8,NR_A,dst);
  819. end;
  820. ungetcpuregister(list,NR_A);
  821. end;
  822. else
  823. internalerror(2011022004);
  824. end;
  825. end;
  826. procedure tcgz80.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
  827. size: TCGSize; a: tcgint; reg, reghi: TRegister);
  828. var
  829. i : byte;
  830. procedure NextReg;
  831. begin
  832. if i=4 then
  833. reg:=reghi
  834. else
  835. reg:=GetNextReg(reg);
  836. end;
  837. var
  838. mask : qword;
  839. shift : byte;
  840. curvalue : byte;
  841. tmpop: TAsmOp;
  842. l1: TAsmLabel;
  843. instr: taicpu;
  844. tmpreg : tregister;
  845. tmpreg64 : tregister64;
  846. begin
  847. optimize_op_const(size,op,a);
  848. mask:=$ff;
  849. shift:=0;
  850. case op of
  851. OP_NONE:
  852. begin
  853. { Opcode is optimized away }
  854. end;
  855. OP_MOVE:
  856. begin
  857. { Optimized, replaced with a simple load }
  858. a_load_const_reg(list,size,a,reg);
  859. end;
  860. OP_AND:
  861. begin
  862. curvalue:=a and mask;
  863. for i:=1 to tcgsize2size[size] do
  864. begin
  865. case curvalue of
  866. 0:
  867. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  868. $ff:
  869. {nothing};
  870. else
  871. begin
  872. getcpuregister(list,NR_A);
  873. emit_mov(list,NR_A,reg);
  874. list.concat(taicpu.op_reg_const(A_AND,NR_A,curvalue));
  875. emit_mov(list,reg,NR_A);
  876. ungetcpuregister(list,NR_A);
  877. end;
  878. end;
  879. if i<>tcgsize2size[size] then
  880. begin
  881. NextReg;
  882. mask:=mask shl 8;
  883. inc(shift,8);
  884. curvalue:=(qword(a) and mask) shr shift;
  885. end;
  886. end;
  887. end;
  888. OP_OR:
  889. begin
  890. curvalue:=a and mask;
  891. for i:=1 to tcgsize2size[size] do
  892. begin
  893. case curvalue of
  894. 0:
  895. {nothing};
  896. $ff:
  897. list.concat(taicpu.op_reg_const(A_LD,reg,$ff));
  898. else
  899. begin
  900. getcpuregister(list,NR_A);
  901. emit_mov(list,NR_A,reg);
  902. list.concat(taicpu.op_reg_const(A_OR,NR_A,curvalue));
  903. emit_mov(list,reg,NR_A);
  904. ungetcpuregister(list,NR_A);
  905. end;
  906. end;
  907. if i<>tcgsize2size[size] then
  908. begin
  909. NextReg;
  910. mask:=mask shl 8;
  911. inc(shift,8);
  912. curvalue:=(qword(a) and mask) shr shift;
  913. end;
  914. end;
  915. end;
  916. OP_XOR:
  917. begin
  918. curvalue:=a and mask;
  919. for i:=1 to tcgsize2size[size] do
  920. begin
  921. case curvalue of
  922. 0:
  923. {nothing};
  924. $ff:
  925. begin
  926. getcpuregister(list,NR_A);
  927. emit_mov(list,NR_A,reg);
  928. list.concat(taicpu.op_none(A_CPL));
  929. emit_mov(list,reg,NR_A);
  930. ungetcpuregister(list,NR_A);
  931. end;
  932. else
  933. begin
  934. getcpuregister(list,NR_A);
  935. emit_mov(list,NR_A,reg);
  936. list.concat(taicpu.op_reg_const(A_XOR,NR_A,curvalue));
  937. emit_mov(list,reg,NR_A);
  938. ungetcpuregister(list,NR_A);
  939. end;
  940. end;
  941. if i<>tcgsize2size[size] then
  942. begin
  943. NextReg;
  944. mask:=mask shl 8;
  945. inc(shift,8);
  946. curvalue:=(qword(a) and mask) shr shift;
  947. end;
  948. end;
  949. end;
  950. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  951. begin
  952. if size in [OS_64,OS_S64] then
  953. a:=a and 63
  954. else
  955. a:=a and 31;
  956. if a<>0 then
  957. begin
  958. if a>1 then
  959. begin
  960. current_asmdata.getjumplabel(l1);
  961. getcpuregister(list,NR_B);
  962. list.concat(taicpu.op_reg_const(A_LD,NR_B,a));
  963. end;
  964. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  965. case op of
  966. OP_ROL:
  967. begin
  968. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  969. list.concat(taicpu.op_reg(A_RLC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  970. end;
  971. OP_ROR:
  972. begin
  973. list.concat(taicpu.op_reg(A_RLC,reg));
  974. list.concat(taicpu.op_reg(A_RRC,reg));
  975. end;
  976. else
  977. ;
  978. end;
  979. if a>1 then
  980. cg.a_label(list,l1);
  981. case op of
  982. OP_SHL:
  983. list.concat(taicpu.op_reg(A_SLA,reg));
  984. OP_SHR:
  985. list.concat(taicpu.op_reg(A_SRL,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  986. OP_SAR:
  987. list.concat(taicpu.op_reg(A_SRA,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  988. OP_ROL:
  989. if size in [OS_8,OS_S8] then
  990. list.concat(taicpu.op_reg(A_RLC,reg))
  991. else
  992. list.concat(taicpu.op_reg(A_RL,reg));
  993. OP_ROR:
  994. if size in [OS_8,OS_S8] then
  995. list.concat(taicpu.op_reg(A_RRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)))
  996. else
  997. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  998. else
  999. internalerror(2020040903);
  1000. end;
  1001. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  1002. begin
  1003. for i:=2 to tcgsize2size[size] do
  1004. begin
  1005. case op of
  1006. OP_ROR,
  1007. OP_SHR,
  1008. OP_SAR:
  1009. list.concat(taicpu.op_reg(A_RR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  1010. OP_ROL,
  1011. OP_SHL:
  1012. list.concat(taicpu.op_reg(A_RL,GetOffsetReg64(reg,reghi,i-1)));
  1013. else
  1014. internalerror(2020040904);
  1015. end;
  1016. end;
  1017. end;
  1018. if a>1 then
  1019. begin
  1020. instr:=taicpu.op_sym(A_DJNZ,l1);
  1021. instr.is_jmp:=true;
  1022. list.concat(instr);
  1023. ungetcpuregister(list,NR_B);
  1024. end;
  1025. end;
  1026. end;
  1027. OP_ADD:
  1028. begin
  1029. curvalue:=a and mask;
  1030. tmpop:=A_NONE;
  1031. for i:=1 to tcgsize2size[size] do
  1032. begin
  1033. if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
  1034. tmpop:=A_INC
  1035. else if (tmpop=A_NONE) and (curvalue<>0) then
  1036. tmpop:=A_ADD
  1037. else if tmpop=A_ADD then
  1038. tmpop:=A_ADC;
  1039. case tmpop of
  1040. A_NONE:
  1041. {nothing};
  1042. A_INC:
  1043. list.concat(taicpu.op_reg(tmpop,reg));
  1044. A_ADD,A_ADC:
  1045. begin
  1046. getcpuregister(list,NR_A);
  1047. emit_mov(list,NR_A,reg);
  1048. list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
  1049. emit_mov(list,reg,NR_A);
  1050. ungetcpuregister(list,NR_A);
  1051. end;
  1052. else
  1053. internalerror(2020040901);
  1054. end;
  1055. if i<>tcgsize2size[size] then
  1056. begin
  1057. NextReg;
  1058. mask:=mask shl 8;
  1059. inc(shift,8);
  1060. curvalue:=(qword(a) and mask) shr shift;
  1061. end;
  1062. end;
  1063. end;
  1064. OP_SUB:
  1065. begin
  1066. curvalue:=a and mask;
  1067. tmpop:=A_NONE;
  1068. for i:=1 to tcgsize2size[size] do
  1069. begin
  1070. if (tmpop=A_NONE) and (curvalue=1) and (i=tcgsize2size[size]) then
  1071. tmpop:=A_DEC
  1072. else if (tmpop=A_NONE) and (curvalue<>0) then
  1073. tmpop:=A_SUB
  1074. else if tmpop=A_SUB then
  1075. tmpop:=A_SBC;
  1076. case tmpop of
  1077. A_NONE:
  1078. {nothing};
  1079. A_DEC:
  1080. list.concat(taicpu.op_reg(tmpop,reg));
  1081. A_SUB,A_SBC:
  1082. begin
  1083. getcpuregister(list,NR_A);
  1084. emit_mov(list,NR_A,reg);
  1085. list.concat(taicpu.op_reg_const(tmpop,NR_A,curvalue));
  1086. emit_mov(list,reg,NR_A);
  1087. ungetcpuregister(list,NR_A);
  1088. end;
  1089. else
  1090. internalerror(2020040902);
  1091. end;
  1092. if i<>tcgsize2size[size] then
  1093. begin
  1094. NextReg;
  1095. mask:=mask shl 8;
  1096. inc(shift,8);
  1097. curvalue:=(qword(a) and mask) shr shift;
  1098. end;
  1099. end;
  1100. end;
  1101. else
  1102. begin
  1103. if size in [OS_64,OS_S64] then
  1104. begin
  1105. tmpreg64.reglo:=getintregister(list,OS_32);
  1106. tmpreg64.reghi:=getintregister(list,OS_32);
  1107. cg64.a_load64_const_reg(list,a,tmpreg64);
  1108. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  1109. end
  1110. else
  1111. begin
  1112. {$if 0}
  1113. { code not working yet }
  1114. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  1115. begin
  1116. tmpreg:=reg;
  1117. for i:=1 to 4 do
  1118. begin
  1119. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
  1120. tmpreg:=GetNextReg(tmpreg);
  1121. end;
  1122. end
  1123. else
  1124. {$endif}
  1125. begin
  1126. tmpreg:=getintregister(list,size);
  1127. a_load_const_reg(list,size,a,tmpreg);
  1128. a_op_reg_reg(list,op,size,tmpreg,reg);
  1129. end;
  1130. end;
  1131. end;
  1132. end;
  1133. end;
  1134. procedure tcgz80.gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean);
  1135. var
  1136. pd: tprocdef;
  1137. paraloc1, paraloc2: tcgpara;
  1138. ai: taicpu;
  1139. hl, no_overflow: TAsmLabel;
  1140. name: String;
  1141. begin
  1142. if size in [OS_8,OS_S8] then
  1143. begin
  1144. if size=OS_8 then
  1145. name:='fpc_mul_byte'
  1146. else
  1147. name:='fpc_mul_shortint';
  1148. if check_overflow then
  1149. name:=name+'_checkoverflow';
  1150. pd:=search_system_proc(name);
  1151. paraloc1.init;
  1152. paraloc2.init;
  1153. paramanager.getcgtempparaloc(list,pd,1,paraloc1);
  1154. paramanager.getcgtempparaloc(list,pd,2,paraloc2);
  1155. a_load_reg_cgpara(list,OS_8,src1,paraloc2);
  1156. a_load_reg_cgpara(list,OS_8,src2,paraloc1);
  1157. paramanager.freecgpara(list,paraloc2);
  1158. paramanager.freecgpara(list,paraloc1);
  1159. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1160. a_call_name(list,upper(name),false);
  1161. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1162. cg.a_reg_alloc(list,NR_L);
  1163. cg.a_load_reg_reg(list,OS_8,OS_8,NR_L,dst);
  1164. cg.a_reg_dealloc(list,NR_L);
  1165. paraloc2.done;
  1166. paraloc1.done;
  1167. end
  1168. else if size in [OS_16,OS_S16] then
  1169. begin
  1170. if size=OS_16 then
  1171. name:='fpc_mul_word'
  1172. else
  1173. name:='fpc_mul_integer';
  1174. if check_overflow then
  1175. name:=name+'_checkoverflow';
  1176. pd:=search_system_proc(name);
  1177. paraloc1.init;
  1178. paraloc2.init;
  1179. paramanager.getcgtempparaloc(list,pd,1,paraloc1);
  1180. paramanager.getcgtempparaloc(list,pd,2,paraloc2);
  1181. a_load_reg_cgpara(list,OS_16,src1,paraloc2);
  1182. a_load_reg_cgpara(list,OS_16,src2,paraloc1);
  1183. paramanager.freecgpara(list,paraloc2);
  1184. paramanager.freecgpara(list,paraloc1);
  1185. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1186. a_call_name(list,upper(name),false);
  1187. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1188. cg.a_reg_alloc(list,NR_L);
  1189. cg.a_reg_alloc(list,NR_H);
  1190. cg.a_load_reg_reg(list,OS_8,OS_8,NR_L,dst);
  1191. cg.a_reg_dealloc(list,NR_L);
  1192. cg.a_load_reg_reg(list,OS_8,OS_8,NR_H,GetNextReg(dst));
  1193. cg.a_reg_dealloc(list,NR_H);
  1194. paraloc2.done;
  1195. paraloc1.done;
  1196. end
  1197. else
  1198. internalerror(2011022002);
  1199. end;
  1200. procedure tcgz80.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  1201. var
  1202. mask : qword;
  1203. shift : byte;
  1204. i : byte;
  1205. begin
  1206. mask:=$ff;
  1207. shift:=0;
  1208. for i:=tcgsize2size[size] downto 1 do
  1209. begin
  1210. list.Concat(taicpu.op_reg_const(A_LD,reg,(qword(a) and mask) shr shift));
  1211. if i<>1 then
  1212. begin
  1213. mask:=mask shl 8;
  1214. inc(shift,8);
  1215. reg:=GetNextReg(reg);
  1216. end;
  1217. end;
  1218. end;
  1219. procedure tcgz80.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference);
  1220. var
  1221. mask : qword;
  1222. shift : byte;
  1223. href: treference;
  1224. i: Integer;
  1225. begin
  1226. mask:=$ff;
  1227. shift:=0;
  1228. href:=ref;
  1229. if (href.base=NR_NO) and (href.index<>NR_NO) then
  1230. begin
  1231. href.base:=href.index;
  1232. href.index:=NR_NO;
  1233. end;
  1234. if is_ref_in_opertypes(href,[OT_REF_IX_d,OT_REF_IY_d]) or
  1235. (is_ref_hl(href) and (size in [OS_8,OS_S8])) then
  1236. begin
  1237. for i:=tcgsize2size[size] downto 1 do
  1238. begin
  1239. list.Concat(taicpu.op_ref_const(A_LD,href,(qword(a) and mask) shr shift));
  1240. if i<>1 then
  1241. begin
  1242. mask:=mask shl 8;
  1243. inc(shift,8);
  1244. inc(href.offset);
  1245. end;
  1246. end;
  1247. end
  1248. else
  1249. inherited;
  1250. end;
  1251. function tcgz80.normalize_ref(list: TAsmList; ref: treference;
  1252. const refopertypes: trefoperandtypes; out allocatedregs: tregisterlist): treference;
  1253. var
  1254. tmpref : treference;
  1255. l : tasmlabel;
  1256. begin
  1257. SetLength(allocatedregs,0);
  1258. if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then
  1259. begin
  1260. ref.base:=ref.index;
  1261. ref.index:=NR_NO;
  1262. end;
  1263. if is_ref_in_opertypes(ref,refopertypes) then
  1264. begin
  1265. Result:=ref;
  1266. exit;
  1267. end;
  1268. { can we use the HL register? }
  1269. if OT_REF_HL in refopertypes then
  1270. begin
  1271. SetLength(allocatedregs,2);
  1272. allocatedregs[0]:=NR_H;
  1273. allocatedregs[1]:=NR_L;
  1274. getcpuregisters(list,allocatedregs);
  1275. if assigned(ref.symbol) then
  1276. begin
  1277. reference_reset(tmpref,0,[]);
  1278. tmpref.symbol:=ref.symbol;
  1279. tmpref.offset:=ref.offset;
  1280. tmpref.refaddr:=addr_full;
  1281. list.concat(taicpu.op_reg_ref(A_LD,NR_HL,tmpref));
  1282. end
  1283. else
  1284. list.concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
  1285. if (ref.base=NR_IX) or (ref.base=NR_IY) then
  1286. begin
  1287. getcpuregister(list,NR_D);
  1288. getcpuregister(list,NR_E);
  1289. list.concat(taicpu.op_reg(A_PUSH,ref.base));
  1290. list.concat(taicpu.op_reg(A_POP,NR_DE));
  1291. list.concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_DE));
  1292. ungetcpuregister(list,NR_E);
  1293. ungetcpuregister(list,NR_D);
  1294. end
  1295. else if ref.base<>NR_NO then
  1296. begin
  1297. getcpuregister(list,NR_A);
  1298. emit_mov(list,NR_A,NR_L);
  1299. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.base));
  1300. emit_mov(list,NR_L,NR_A);
  1301. emit_mov(list,NR_A,NR_H);
  1302. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.base)));
  1303. emit_mov(list,NR_H,NR_A);
  1304. ungetcpuregister(list,NR_A);
  1305. end;
  1306. if ref.index<>NR_NO then
  1307. begin
  1308. if ref.scalefactor>1 then
  1309. internalerror(2020042002);
  1310. getcpuregister(list,NR_A);
  1311. emit_mov(list,NR_A,NR_L);
  1312. list.concat(taicpu.op_reg_reg(A_ADD,NR_A,ref.index));
  1313. emit_mov(list,NR_L,NR_A);
  1314. emit_mov(list,NR_A,NR_H);
  1315. list.concat(taicpu.op_reg_reg(A_ADC,NR_A,GetNextReg(ref.index)));
  1316. emit_mov(list,NR_H,NR_A);
  1317. ungetcpuregister(list,NR_A);
  1318. end;
  1319. reference_reset_base(result,NR_HL,0,ctempposinvalid,0,[]);
  1320. end
  1321. else
  1322. internalerror(2020042001);
  1323. end;
  1324. procedure tcgz80.adjust_normalized_ref(list: TAsmList; var ref: treference; value: longint);
  1325. var
  1326. i: Integer;
  1327. begin
  1328. if is_ref_addr16(ref) then
  1329. Inc(ref.offset,value)
  1330. else if is_ref_hl(ref) then
  1331. begin
  1332. if value>0 then
  1333. for i:=1 to value do
  1334. list.concat(taicpu.op_reg(A_INC,NR_HL))
  1335. else
  1336. for i:=-1 downto value do
  1337. list.concat(taicpu.op_reg(A_DEC,NR_HL));
  1338. end
  1339. else if is_ref_ix_d(ref) then
  1340. begin
  1341. if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
  1342. inc(ref.offset,value)
  1343. else
  1344. begin
  1345. { todo: IX is the frame pointer, we cannot change it, so we }
  1346. { think of another mechanism to deal with this situation }
  1347. internalerror(2020042101);
  1348. //if value>0 then
  1349. // for i:=1 to value do
  1350. // list.concat(taicpu.op_reg(A_INC,NR_IX))
  1351. //else
  1352. // for i:=-1 downto value do
  1353. // list.concat(taicpu.op_reg(A_DEC,NR_IX));
  1354. end;
  1355. end
  1356. else if is_ref_iy_d(ref) then
  1357. begin
  1358. if ((ref.offset+value)<=127) and ((ref.offset+value)>=-128) then
  1359. inc(ref.offset,value)
  1360. else
  1361. if value>0 then
  1362. for i:=1 to value do
  1363. list.concat(taicpu.op_reg(A_INC,NR_IY))
  1364. else
  1365. for i:=-1 downto value do
  1366. list.concat(taicpu.op_reg(A_DEC,NR_IY));
  1367. end;
  1368. end;
  1369. procedure tcgz80.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  1370. var
  1371. href : treference;
  1372. i : integer;
  1373. regsused: tregisterlist;
  1374. begin
  1375. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1376. internalerror(2011021307);
  1377. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1378. internalerror(2020040802);
  1379. href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
  1380. if (tcgsize2size[fromsize]=tcgsize2size[tosize]) or (fromsize in [OS_8,OS_16,OS_32]) then
  1381. begin
  1382. getcpuregister(list,NR_A);
  1383. for i:=1 to tcgsize2size[fromsize] do
  1384. begin
  1385. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1386. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1387. if i<>tcgsize2size[fromsize] then
  1388. reg:=GetNextReg(reg);
  1389. if i<>tcgsize2size[tosize] then
  1390. adjust_normalized_ref(list,href,1);
  1391. end;
  1392. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1393. begin
  1394. if i=(tcgsize2size[fromsize]+1) then
  1395. list.concat(taicpu.op_reg_const(A_LD,NR_A,0));
  1396. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1397. if i<>tcgsize2size[tosize] then
  1398. begin
  1399. adjust_normalized_ref(list,href,1);
  1400. reg:=GetNextReg(reg);
  1401. end;
  1402. end;
  1403. ungetcpuregister(list,NR_A);
  1404. end
  1405. else
  1406. begin
  1407. getcpuregister(list,NR_A);
  1408. for i:=1 to tcgsize2size[fromsize] do
  1409. begin
  1410. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1411. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1412. if i<>tcgsize2size[fromsize] then
  1413. reg:=GetNextReg(reg);
  1414. if i<>tcgsize2size[tosize] then
  1415. adjust_normalized_ref(list,href,1);
  1416. end;
  1417. list.concat(taicpu.op_none(A_RLA));
  1418. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1419. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1420. begin
  1421. list.concat(taicpu.op_ref_reg(A_LD,href,NR_A));
  1422. if i<>tcgsize2size[tosize] then
  1423. begin
  1424. adjust_normalized_ref(list,href,1);
  1425. reg:=GetNextReg(reg);
  1426. end;
  1427. end;
  1428. ungetcpuregister(list,NR_A);
  1429. end;
  1430. ungetcpuregisters(list,regsused);
  1431. end;
  1432. procedure tcgz80.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1433. const Ref : treference;reg : tregister);
  1434. var
  1435. href : treference;
  1436. i : integer;
  1437. regsused: tregisterlist;
  1438. begin
  1439. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1440. internalerror(2011021307);
  1441. if tcgsize2size[fromsize]>=tcgsize2size[tosize] then
  1442. fromsize:=tosize;
  1443. href:=normalize_ref(list,Ref,[OT_REF_ADDR16,OT_REF_HL,OT_REF_IX_d,OT_REF_IY_d],regsused);
  1444. if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then
  1445. begin
  1446. getcpuregister(list,NR_A);
  1447. for i:=1 to tcgsize2size[fromsize] do
  1448. begin
  1449. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1450. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1451. if i<>tcgsize2size[fromsize] then
  1452. adjust_normalized_ref(list,href,1);
  1453. if i<>tcgsize2size[tosize] then
  1454. reg:=GetNextReg(reg);
  1455. end;
  1456. ungetcpuregisters(list,regsused);
  1457. ungetcpuregister(list,NR_A);
  1458. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1459. begin
  1460. list.concat(taicpu.op_reg_const(A_LD,reg,0));
  1461. if i<>tcgsize2size[tosize] then
  1462. reg:=GetNextReg(reg);
  1463. end;
  1464. end
  1465. else
  1466. begin
  1467. getcpuregister(list,NR_A);
  1468. for i:=1 to tcgsize2size[fromsize] do
  1469. begin
  1470. list.concat(taicpu.op_reg_ref(A_LD,NR_A,href));
  1471. a_load_reg_reg(list,OS_8,OS_8,NR_A,reg);
  1472. if i<>tcgsize2size[fromsize] then
  1473. adjust_normalized_ref(list,href,1);
  1474. if i<>tcgsize2size[tosize] then
  1475. reg:=GetNextReg(reg);
  1476. end;
  1477. ungetcpuregisters(list,regsused);
  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,reg,NR_A);
  1483. if i<>tcgsize2size[tosize] then
  1484. reg:=GetNextReg(reg);
  1485. end;
  1486. ungetcpuregister(list,NR_A);
  1487. end;
  1488. end;
  1489. procedure tcgz80.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1490. var
  1491. conv_done: boolean;
  1492. tmpreg : tregister;
  1493. i : integer;
  1494. begin
  1495. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1496. internalerror(2011021310);
  1497. if tcgsize2size[fromsize]>tcgsize2size[tosize] then
  1498. fromsize:=tosize;
  1499. if (tcgsize2size[tosize]=tcgsize2size[fromsize]) or (fromsize in [OS_8,OS_16,OS_32]) then
  1500. begin
  1501. if reg1<>reg2 then
  1502. for i:=1 to tcgsize2size[fromsize] do
  1503. begin
  1504. emit_mov(list,reg2,reg1);
  1505. if i<>tcgsize2size[fromsize] then
  1506. reg1:=GetNextReg(reg1);
  1507. if i<>tcgsize2size[tosize] then
  1508. reg2:=GetNextReg(reg2);
  1509. end
  1510. else
  1511. for i:=1 to tcgsize2size[fromsize] do
  1512. if i<>tcgsize2size[tosize] then
  1513. reg2:=GetNextReg(reg2);
  1514. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1515. begin
  1516. list.Concat(taicpu.op_reg_const(A_LD,reg2,0));
  1517. if i<>tcgsize2size[tosize] then
  1518. reg2:=GetNextReg(reg2);
  1519. end
  1520. end
  1521. else
  1522. begin
  1523. if reg1<>reg2 then
  1524. for i:=1 to tcgsize2size[fromsize]-1 do
  1525. begin
  1526. emit_mov(list,reg2,reg1);
  1527. reg1:=GetNextReg(reg1);
  1528. reg2:=GetNextReg(reg2);
  1529. end
  1530. else
  1531. for i:=1 to tcgsize2size[fromsize]-1 do
  1532. reg2:=GetNextReg(reg2);
  1533. emit_mov(list,reg2,reg1);
  1534. getcpuregister(list,NR_A);
  1535. emit_mov(list,NR_A,reg2);
  1536. reg2:=GetNextReg(reg2);
  1537. list.concat(taicpu.op_none(A_RLA));
  1538. list.concat(taicpu.op_reg_reg(A_SBC,NR_A,NR_A));
  1539. for i:=tcgsize2size[fromsize]+1 to tcgsize2size[tosize] do
  1540. begin
  1541. emit_mov(list,reg2,NR_A);
  1542. if i<>tcgsize2size[tosize] then
  1543. reg2:=GetNextReg(reg2);
  1544. end;
  1545. ungetcpuregister(list,NR_A);
  1546. end;
  1547. end;
  1548. procedure tcgz80.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1549. begin
  1550. internalerror(2012010702);
  1551. end;
  1552. procedure tcgz80.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1553. begin
  1554. internalerror(2012010703);
  1555. end;
  1556. procedure tcgz80.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1557. begin
  1558. internalerror(2012010704);
  1559. end;
  1560. { comparison operations }
  1561. procedure tcgz80.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1562. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1563. var
  1564. swapped : boolean;
  1565. tmpreg : tregister;
  1566. i : byte;
  1567. tmpl: TAsmLabel;
  1568. begin
  1569. if size in [OS_8,OS_S8]then
  1570. begin
  1571. if cmp_op in [OC_EQ,OC_NE,OC_B,OC_AE] then
  1572. begin
  1573. getcpuregister(list,NR_A);
  1574. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1575. list.concat(taicpu.op_reg_const(A_CP,NR_A,a));
  1576. case cmp_op of
  1577. OC_EQ:
  1578. a_jmp_flags(list,F_E,l);
  1579. OC_NE:
  1580. a_jmp_flags(list,F_NE,l);
  1581. OC_B:
  1582. a_jmp_flags(list,F_C,l);
  1583. OC_AE:
  1584. a_jmp_flags(list,F_NC,l);
  1585. else
  1586. internalerror(2020042206);
  1587. end;
  1588. ungetcpuregister(list,NR_A);
  1589. end
  1590. else if cmp_op in [OC_A,OC_BE] then
  1591. begin
  1592. getcpuregister(list,NR_A);
  1593. a_load_const_reg(list,OS_8,a,NR_A);
  1594. list.concat(taicpu.op_reg_reg(A_CP,NR_A,reg));
  1595. case cmp_op of
  1596. OC_A:
  1597. a_jmp_flags(list,F_C,l);
  1598. OC_BE:
  1599. a_jmp_flags(list,F_NC,l);
  1600. else
  1601. internalerror(2020042206);
  1602. end;
  1603. ungetcpuregister(list,NR_A);
  1604. end
  1605. else if cmp_op in [OC_LT,OC_GTE] then
  1606. begin
  1607. getcpuregister(list,NR_A);
  1608. a_load_reg_reg(list,OS_8,OS_8,reg,NR_A);
  1609. list.concat(taicpu.op_reg_const(A_SUB,NR_A,a));
  1610. current_asmdata.getjumplabel(tmpl);
  1611. a_jmp_flags(list,F_PO,tmpl);
  1612. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1613. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1614. case cmp_op of
  1615. OC_LT:
  1616. a_jmp_flags(list,F_M,l);
  1617. OC_GTE:
  1618. a_jmp_flags(list,F_P,l);
  1619. else
  1620. internalerror(2020042206);
  1621. end;
  1622. ungetcpuregister(list,NR_A);
  1623. end
  1624. else if cmp_op in [OC_GT,OC_LTE] then
  1625. begin
  1626. getcpuregister(list,NR_A);
  1627. a_load_const_reg(list,OS_8,a,NR_A);
  1628. list.concat(taicpu.op_reg_reg(A_SUB,NR_A,reg));
  1629. current_asmdata.getjumplabel(tmpl);
  1630. a_jmp_flags(list,F_PO,tmpl);
  1631. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1632. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1633. case cmp_op of
  1634. OC_GT:
  1635. a_jmp_flags(list,F_M,l);
  1636. OC_LTE:
  1637. a_jmp_flags(list,F_P,l);
  1638. else
  1639. internalerror(2020042206);
  1640. end;
  1641. ungetcpuregister(list,NR_A);
  1642. end;
  1643. end
  1644. else if cmp_op in [OC_EQ,OC_NE] then
  1645. begin
  1646. if cmp_op=OC_EQ then
  1647. current_asmdata.getjumplabel(tmpl);
  1648. for i:=0 to tcgsize2size[size]-1 do
  1649. begin
  1650. a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A);
  1651. list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i))));
  1652. case cmp_op of
  1653. OC_EQ:
  1654. if i<>(tcgsize2size[size]-1) then
  1655. a_jmp_flags(list,F_NE,tmpl)
  1656. else
  1657. a_jmp_flags(list,F_E,l);
  1658. OC_NE:
  1659. a_jmp_flags(list,F_NE,l);
  1660. else
  1661. internalerror(2020042206);
  1662. end;
  1663. end;
  1664. if cmp_op=OC_EQ then
  1665. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1666. end
  1667. else if cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE,OC_BE,OC_B,OC_AE,OC_A] then
  1668. begin
  1669. getcpuregister(list,NR_A);
  1670. current_asmdata.getjumplabel(tmpl);
  1671. for i:=tcgsize2size[size]-1 downto 0 do
  1672. begin
  1673. a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg(reg,i),NR_A);
  1674. list.concat(taicpu.op_reg_const(A_CP,NR_A,Byte(a shr (8*i))));
  1675. if (i=(tcgsize2size[size]-1)) and (cmp_op in [OC_GT,OC_LT,OC_GTE,OC_LTE]) then
  1676. case cmp_op of
  1677. OC_GTE,
  1678. OC_GT:
  1679. a_jmp_signed_cmp_3way(list,tmpl,nil,l);
  1680. OC_LT,
  1681. OC_LTE:
  1682. a_jmp_signed_cmp_3way(list,l,nil,tmpl);
  1683. else
  1684. internalerror(2020042206);
  1685. end
  1686. else if i<>0 then
  1687. case cmp_op of
  1688. OC_AE,
  1689. OC_A,
  1690. OC_GTE,
  1691. OC_GT:
  1692. a_jmp_unsigned_cmp_3way(list,tmpl,nil,l);
  1693. OC_BE,
  1694. OC_B,
  1695. OC_LT,
  1696. OC_LTE:
  1697. a_jmp_unsigned_cmp_3way(list,l,nil,tmpl);
  1698. else
  1699. internalerror(2020042206);
  1700. end
  1701. else
  1702. case cmp_op of
  1703. OC_A,
  1704. OC_GT:
  1705. a_jmp_unsigned_cmp_3way(list,nil,nil,l);
  1706. OC_B,
  1707. OC_LT:
  1708. a_jmp_unsigned_cmp_3way(list,l,nil,nil);
  1709. OC_AE,
  1710. OC_GTE:
  1711. a_jmp_unsigned_cmp_3way(list,nil,l,l);
  1712. OC_BE,
  1713. OC_LTE:
  1714. a_jmp_unsigned_cmp_3way(list,l,l,nil);
  1715. else
  1716. internalerror(2020042206);
  1717. end;
  1718. end;
  1719. cg.a_label(current_asmdata.CurrAsmList,tmpl);
  1720. ungetcpuregister(list,NR_A);
  1721. end
  1722. else
  1723. internalerror(2020042205);
  1724. end;
  1725. procedure tcgz80.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1726. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1727. var
  1728. swapped : boolean;
  1729. tmpreg : tregister;
  1730. i : byte;
  1731. begin
  1732. internalerror(2020042301);
  1733. //swapped:=false;
  1734. //{ swap parameters? }
  1735. //case cmp_op of
  1736. // OC_GT:
  1737. // begin
  1738. // swapped:=true;
  1739. // cmp_op:=OC_LT;
  1740. // end;
  1741. // OC_LTE:
  1742. // begin
  1743. // swapped:=true;
  1744. // cmp_op:=OC_GTE;
  1745. // end;
  1746. // OC_BE:
  1747. // begin
  1748. // swapped:=true;
  1749. // cmp_op:=OC_AE;
  1750. // end;
  1751. // OC_A:
  1752. // begin
  1753. // swapped:=true;
  1754. // cmp_op:=OC_B;
  1755. // end;
  1756. //end;
  1757. //if swapped then
  1758. // begin
  1759. // tmpreg:=reg1;
  1760. // reg1:=reg2;
  1761. // reg2:=tmpreg;
  1762. // end;
  1763. //list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1764. //
  1765. //for i:=2 to tcgsize2size[size] do
  1766. // begin
  1767. // reg1:=GetNextReg(reg1);
  1768. // reg2:=GetNextReg(reg2);
  1769. // list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1770. // end;
  1771. //
  1772. //a_jmp_cond(list,cmp_op,l);
  1773. end;
  1774. procedure tcgz80.a_jmp_name(list : TAsmList;const s : string);
  1775. var
  1776. ai : taicpu;
  1777. begin
  1778. ai:=taicpu.op_sym(A_JP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1779. ai.is_jmp:=true;
  1780. list.concat(ai);
  1781. end;
  1782. procedure tcgz80.a_jmp_always(list : TAsmList;l: tasmlabel);
  1783. var
  1784. ai : taicpu;
  1785. begin
  1786. ai:=taicpu.op_sym(A_JP,l);
  1787. ai.is_jmp:=true;
  1788. list.concat(ai);
  1789. end;
  1790. procedure tcgz80.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1791. var
  1792. ai : taicpu;
  1793. begin
  1794. ai:=taicpu.op_cond_sym(A_JP,flags_to_cond(f),l);
  1795. ai.is_jmp:=true;
  1796. list.concat(ai);
  1797. end;
  1798. procedure tcgz80.a_jmp_unsigned_cmp_3way(list: TAsmList; onbelow, onequal, onabove: tasmlabel);
  1799. var
  1800. skiplabel: TAsmLabel;
  1801. begin
  1802. if (onbelow= nil) and (onequal= nil) and (onabove= nil) then
  1803. {nothing}
  1804. else if (onbelow= nil) and (onequal= nil) and (onabove<>nil) then
  1805. begin
  1806. current_asmdata.getjumplabel(skiplabel);
  1807. a_jmp_flags(list,F_E,skiplabel);
  1808. a_jmp_flags(list,F_NC,onabove);
  1809. cg.a_label(list,skiplabel);
  1810. end
  1811. else if (onbelow= nil) and (onequal<>nil) and (onabove= nil) then
  1812. a_jmp_flags(list,F_E,onequal)
  1813. else if (onbelow= nil) and (onequal<>nil) and (onabove<>nil) then
  1814. begin
  1815. if onequal<>onabove then
  1816. a_jmp_flags(list,F_E,onequal);
  1817. a_jmp_flags(list,F_NC,onabove);
  1818. end
  1819. else if (onbelow<>nil) and (onequal= nil) and (onabove= nil) then
  1820. a_jmp_flags(list,F_C,onbelow)
  1821. else if (onbelow<>nil) and (onequal= nil) and (onabove<>nil) then
  1822. begin
  1823. if onbelow<>onabove then
  1824. a_jmp_flags(list,F_C,onbelow);
  1825. a_jmp_flags(list,F_NE,onabove);
  1826. end
  1827. else if (onbelow<>nil) and (onequal<>nil) and (onabove= nil) then
  1828. begin
  1829. a_jmp_flags(list,F_C,onbelow);
  1830. a_jmp_flags(list,F_E,onequal);
  1831. end
  1832. else if (onbelow<>nil) and (onequal<>nil) and (onabove<>nil) then
  1833. begin
  1834. if (onbelow=onequal) and (onequal=onabove) then
  1835. a_jmp_always(list,onbelow)
  1836. else if onequal=onabove then
  1837. begin
  1838. a_jmp_flags(list,F_C,onbelow);
  1839. a_jmp_always(list,onabove);
  1840. end
  1841. else if onbelow=onequal then
  1842. begin
  1843. a_jmp_flags(list,F_C,onbelow);
  1844. a_jmp_flags(list,F_E,onequal);
  1845. a_jmp_always(list,onabove);
  1846. end
  1847. else if onbelow=onabove then
  1848. begin
  1849. a_jmp_flags(list,F_E,onequal);
  1850. a_jmp_always(list,onabove);
  1851. end
  1852. else
  1853. begin
  1854. { the generic case - all 3 are different labels }
  1855. a_jmp_flags(list,F_C,onbelow);
  1856. a_jmp_flags(list,F_E,onequal);
  1857. a_jmp_always(list,onabove);
  1858. end;
  1859. end
  1860. else
  1861. begin
  1862. { Shouldn't happen! All possible combinations are handled by the above code. }
  1863. internalerror(2020042201);
  1864. end;
  1865. end;
  1866. procedure tcgz80.a_jmp_signed_cmp_3way(list: TAsmList; onless, onequal, ongreater: tasmlabel);
  1867. var
  1868. l, skiplabel: TAsmLabel;
  1869. begin
  1870. if (onless= nil) and (onequal= nil) and (ongreater= nil) then
  1871. {nothing}
  1872. else if (onless= nil) and (onequal= nil) and (ongreater<>nil) then
  1873. begin
  1874. current_asmdata.getjumplabel(skiplabel);
  1875. a_jmp_flags(list,F_E,skiplabel);
  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_P,ongreater);
  1881. cg.a_label(list,skiplabel);
  1882. end
  1883. else if (onless= nil) and (onequal<>nil) and (ongreater= nil) then
  1884. a_jmp_flags(list,F_E,onequal)
  1885. else if (onless= nil) and (onequal<>nil) and (ongreater<>nil) then
  1886. begin
  1887. if onequal<>ongreater then
  1888. a_jmp_flags(list,F_E,onequal);
  1889. current_asmdata.getjumplabel(l);
  1890. a_jmp_flags(list,F_PO,l);
  1891. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1892. cg.a_label(current_asmdata.CurrAsmList,l);
  1893. a_jmp_flags(list,F_P,ongreater);
  1894. end
  1895. else if (onless<>nil) and (onequal= nil) and (ongreater= nil) then
  1896. begin
  1897. current_asmdata.getjumplabel(l);
  1898. a_jmp_flags(list,F_PO,l);
  1899. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1900. cg.a_label(current_asmdata.CurrAsmList,l);
  1901. a_jmp_flags(list,F_M,onless);
  1902. end
  1903. else if (onless<>nil) and (onequal= nil) and (ongreater<>nil) then
  1904. begin
  1905. if onless=ongreater then
  1906. a_jmp_flags(list,F_NE,onless)
  1907. else
  1908. begin
  1909. current_asmdata.getjumplabel(skiplabel);
  1910. a_jmp_flags(list,F_E,skiplabel);
  1911. current_asmdata.getjumplabel(l);
  1912. a_jmp_flags(list,F_PO,l);
  1913. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1914. cg.a_label(current_asmdata.CurrAsmList,l);
  1915. a_jmp_flags(list,F_M,onless);
  1916. a_jmp_always(list,ongreater);
  1917. cg.a_label(list,skiplabel);
  1918. end;
  1919. end
  1920. else if (onless<>nil) and (onequal<>nil) and (ongreater= nil) then
  1921. begin
  1922. a_jmp_flags(list,F_E,onequal);
  1923. current_asmdata.getjumplabel(l);
  1924. a_jmp_flags(list,F_PO,l);
  1925. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1926. cg.a_label(current_asmdata.CurrAsmList,l);
  1927. a_jmp_flags(list,F_M,onless);
  1928. end
  1929. else if (onless<>nil) and (onequal<>nil) and (ongreater<>nil) then
  1930. begin
  1931. if (onless=onequal) and (onequal=ongreater) then
  1932. a_jmp_always(list,onless)
  1933. else if onequal=ongreater then
  1934. begin
  1935. current_asmdata.getjumplabel(l);
  1936. a_jmp_flags(list,F_PO,l);
  1937. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1938. cg.a_label(current_asmdata.CurrAsmList,l);
  1939. a_jmp_flags(list,F_M,onless);
  1940. a_jmp_always(list,ongreater);
  1941. end
  1942. else if onless=onequal then
  1943. begin
  1944. a_jmp_flags(list,F_E,onequal);
  1945. current_asmdata.getjumplabel(l);
  1946. a_jmp_flags(list,F_PO,l);
  1947. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1948. cg.a_label(current_asmdata.CurrAsmList,l);
  1949. a_jmp_flags(list,F_M,onless);
  1950. a_jmp_always(list,ongreater);
  1951. end
  1952. else if onless=ongreater then
  1953. begin
  1954. a_jmp_flags(list,F_E,onequal);
  1955. a_jmp_always(list,ongreater);
  1956. end
  1957. else
  1958. begin
  1959. { the generic case - all 3 are different labels }
  1960. a_jmp_flags(list,F_E,onequal);
  1961. current_asmdata.getjumplabel(l);
  1962. a_jmp_flags(list,F_PO,l);
  1963. current_asmdata.CurrAsmList.Concat(taicpu.op_reg_const(A_XOR,NR_A,$80));
  1964. cg.a_label(current_asmdata.CurrAsmList,l);
  1965. a_jmp_flags(list,F_M,onless);
  1966. a_jmp_always(list,ongreater);
  1967. end;
  1968. end
  1969. else
  1970. begin
  1971. { Shouldn't happen! All possible combinations are handled by the above code. }
  1972. internalerror(2020042204);
  1973. end;
  1974. end;
  1975. procedure tcgz80.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1976. var
  1977. l : TAsmLabel;
  1978. tmpflags : TResFlags;
  1979. begin
  1980. if f in [F_C,F_NC] then
  1981. begin
  1982. a_load_const_reg(list,size,0,reg);
  1983. if f=F_NC then
  1984. list.concat(taicpu.op_none(A_CCF));
  1985. list.concat(taicpu.op_reg(A_RL,reg));
  1986. end
  1987. else
  1988. begin
  1989. current_asmdata.getjumplabel(l);
  1990. a_load_const_reg(list,size,0,reg);
  1991. tmpflags:=f;
  1992. inverse_flags(tmpflags);
  1993. a_jmp_flags(list,tmpflags,l);
  1994. list.concat(taicpu.op_reg(A_INC,reg));
  1995. cg.a_label(list,l);
  1996. end;
  1997. end;
  1998. procedure tcgz80.g_stackpointer_alloc(list: TAsmList; localsize: longint);
  1999. begin
  2000. if localsize>0 then
  2001. begin
  2002. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,-localsize));
  2003. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,NR_SP));
  2004. list.Concat(taicpu.op_reg_reg(A_LD,NR_SP,NR_HL));
  2005. end;
  2006. end;
  2007. procedure tcgz80.a_adjust_sp(list : TAsmList; value : longint);
  2008. var
  2009. i : integer;
  2010. begin
  2011. //case value of
  2012. // 0:
  2013. // ;
  2014. // {-14..-1:
  2015. // begin
  2016. // if ((-value) mod 2)<>0 then
  2017. // list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  2018. // for i:=1 to (-value) div 2 do
  2019. // list.concat(taicpu.op_const(A_RCALL,0));
  2020. // end;
  2021. // 1..7:
  2022. // begin
  2023. // for i:=1 to value do
  2024. // list.concat(taicpu.op_reg(A_POP,NR_R0));
  2025. // end;}
  2026. // else
  2027. // begin
  2028. // list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  2029. // list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  2030. // // get SREG
  2031. // list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  2032. //
  2033. // // block interrupts
  2034. // list.concat(taicpu.op_none(A_CLI));
  2035. //
  2036. // // write high SP
  2037. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  2038. //
  2039. // // release interrupts
  2040. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  2041. //
  2042. // // write low SP
  2043. // list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  2044. // end;
  2045. //end;
  2046. end;
  2047. procedure tcgz80.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  2048. var
  2049. regsize,stackmisalignment: longint;
  2050. begin
  2051. regsize:=0;
  2052. stackmisalignment:=0;
  2053. { save old framepointer }
  2054. if not nostackframe then
  2055. begin
  2056. { return address }
  2057. inc(stackmisalignment,2);
  2058. list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
  2059. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  2060. begin
  2061. { push <frame_pointer> }
  2062. inc(stackmisalignment,2);
  2063. include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
  2064. list.concat(Taicpu.op_reg(A_PUSH,NR_FRAME_POINTER_REG));
  2065. { Return address and FP are both on stack }
  2066. current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*2);
  2067. current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*2));
  2068. if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
  2069. begin
  2070. list.concat(Taicpu.op_reg_const(A_LD,NR_FRAME_POINTER_REG,0));
  2071. list.concat(Taicpu.op_reg_reg(A_ADD,NR_FRAME_POINTER_REG,NR_STACK_POINTER_REG))
  2072. end
  2073. else
  2074. begin
  2075. internalerror(2020040301);
  2076. (*push_regs;
  2077. gen_load_frame_for_exceptfilter(list);
  2078. { Need only as much stack space as necessary to do the calls.
  2079. Exception filters don't have own local vars, and temps are 'mapped'
  2080. to the parent procedure.
  2081. maxpushedparasize is already aligned at least on x86_64. }
  2082. localsize:=current_procinfo.maxpushedparasize;*)
  2083. end;
  2084. current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
  2085. end
  2086. else
  2087. begin
  2088. CGmessage(cg_d_stackframe_omited);
  2089. end;
  2090. { allocate stackframe space }
  2091. if (localsize<>0) or
  2092. ((target_info.stackalign>sizeof(pint)) and
  2093. (stackmisalignment <> 0) and
  2094. ((pi_do_call in current_procinfo.flags) or
  2095. (po_assembler in current_procinfo.procdef.procoptions))) then
  2096. begin
  2097. if target_info.stackalign>sizeof(pint) then
  2098. localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
  2099. g_stackpointer_alloc(list,localsize);
  2100. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  2101. current_asmdata.asmcfi.cfa_def_cfa_offset(list,regsize+localsize+sizeof(pint));
  2102. current_procinfo.final_localsize:=localsize;
  2103. end
  2104. end;
  2105. end;
  2106. procedure tcgz80.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  2107. var
  2108. regs : tcpuregisterset;
  2109. reg : TSuperRegister;
  2110. LocalSize : longint;
  2111. begin
  2112. { every byte counts for Z80, so if a subroutine is marked as non-returning, we do
  2113. not generate any exit code, so we really trust the noreturn directive
  2114. }
  2115. if po_noreturn in current_procinfo.procdef.procoptions then
  2116. exit;
  2117. { remove stackframe }
  2118. if not nostackframe then
  2119. begin
  2120. stacksize:=current_procinfo.calc_stackframe_size;
  2121. if (target_info.stackalign>4) and
  2122. ((stacksize <> 0) or
  2123. (pi_do_call in current_procinfo.flags) or
  2124. { can't detect if a call in this case -> use nostackframe }
  2125. { if you (think you) know what you are doing }
  2126. (po_assembler in current_procinfo.procdef.procoptions)) then
  2127. stacksize := align(stacksize+sizeof(aint),target_info.stackalign) - sizeof(aint);
  2128. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  2129. begin
  2130. internalerror(2020040302);
  2131. {if (stacksize<>0) then
  2132. cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);}
  2133. end
  2134. else
  2135. begin
  2136. list.Concat(taicpu.op_reg_reg(A_LD,NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
  2137. list.Concat(taicpu.op_reg(A_POP,NR_FRAME_POINTER_REG));
  2138. end;
  2139. list.concat(tai_regalloc.dealloc(current_procinfo.framepointer,nil));
  2140. end;
  2141. list.concat(taicpu.op_none(A_RET));
  2142. end;
  2143. procedure tcgz80.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  2144. var
  2145. tmpref : treference;
  2146. begin
  2147. if assigned(ref.symbol) then
  2148. begin
  2149. reference_reset(tmpref,0,[]);
  2150. tmpref.symbol:=ref.symbol;
  2151. tmpref.offset:=ref.offset;
  2152. tmpref.refaddr:=addr_lo8;
  2153. list.concat(taicpu.op_reg_ref(A_LD,r,tmpref));
  2154. tmpref.refaddr:=addr_hi8;
  2155. list.concat(taicpu.op_reg_ref(A_LD,GetNextReg(r),tmpref));
  2156. if (ref.base<>NR_NO) then
  2157. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  2158. if (ref.index<>NR_NO) then
  2159. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2160. end
  2161. else if ref.base=NR_IX then
  2162. begin
  2163. list.concat(taicpu.op_reg(A_PUSH,NR_IX));
  2164. getcpuregister(list,NR_H);
  2165. getcpuregister(list,NR_L);
  2166. list.concat(taicpu.op_reg(A_POP,NR_HL));
  2167. emit_mov(list,r,NR_L);
  2168. ungetcpuregister(list,NR_L);
  2169. emit_mov(list,GetNextReg(r),NR_H);
  2170. ungetcpuregister(list,NR_H);
  2171. if (ref.index<>NR_NO) then
  2172. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2173. if ref.offset<>0 then
  2174. a_op_const_reg(list,OP_ADD,OS_16,ref.offset,r);
  2175. end
  2176. else if (ref.base=NR_SP) or (ref.base=NR_BC) or (ref.base=NR_DE) then
  2177. begin
  2178. getcpuregister(list,NR_H);
  2179. getcpuregister(list,NR_L);
  2180. list.Concat(taicpu.op_reg_const(A_LD,NR_HL,ref.offset));
  2181. list.Concat(taicpu.op_reg_reg(A_ADD,NR_HL,ref.base));
  2182. emit_mov(list,r,NR_L);
  2183. ungetcpuregister(list,NR_L);
  2184. emit_mov(list,GetNextReg(r),NR_H);
  2185. ungetcpuregister(list,NR_H);
  2186. if (ref.index<>NR_NO) then
  2187. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2188. end
  2189. else
  2190. begin
  2191. a_load_const_reg(list,OS_16,ref.offset,r);
  2192. if (ref.base<>NR_NO) then
  2193. a_op_reg_reg(list,OP_ADD,OS_16,ref.base,r);
  2194. if (ref.index<>NR_NO) then
  2195. a_op_reg_reg(list,OP_ADD,OS_16,ref.index,r);
  2196. end;
  2197. end;
  2198. procedure tcgz80.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  2199. var
  2200. tmpreg,srcreg,dstreg: tregister;
  2201. srcref,dstref : treference;
  2202. i: Integer;
  2203. begin
  2204. if (len<=2) and
  2205. is_ref_in_opertypes(source,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) and
  2206. is_ref_in_opertypes(dest,[OT_REF_IX_d,OT_REF_IY_d,OT_REF_HL]) then
  2207. begin
  2208. srcref:=source;
  2209. dstref:=dest;
  2210. tmpreg:=getintregister(list,OS_8);
  2211. for i:=1 to len do
  2212. begin
  2213. list.concat(taicpu.op_reg_ref(A_LD,tmpreg,srcref));
  2214. list.concat(taicpu.op_ref_reg(A_LD,dstref,tmpreg));
  2215. if i<>len then
  2216. begin
  2217. adjust_normalized_ref(list,srcref,1);
  2218. adjust_normalized_ref(list,dstref,1);
  2219. end;
  2220. end;
  2221. end
  2222. else
  2223. begin
  2224. srcreg:=getintregister(list,OS_16);
  2225. a_loadaddr_ref_reg(list,source,srcreg);
  2226. dstreg:=getintregister(list,OS_16);
  2227. a_loadaddr_ref_reg(list,dest,dstreg);
  2228. getcpuregister(list,NR_L);
  2229. a_load_reg_reg(list,OS_8,OS_8,srcreg,NR_L);
  2230. getcpuregister(list,NR_H);
  2231. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(srcreg),NR_H);
  2232. getcpuregister(list,NR_E);
  2233. a_load_reg_reg(list,OS_8,OS_8,dstreg,NR_E);
  2234. getcpuregister(list,NR_D);
  2235. a_load_reg_reg(list,OS_8,OS_8,GetNextReg(dstreg),NR_D);
  2236. getcpuregister(list,NR_B);
  2237. getcpuregister(list,NR_C);
  2238. list.concat(taicpu.op_reg_const(A_LD,NR_BC,len));
  2239. list.concat(taicpu.op_none(A_LDIR));
  2240. ungetcpuregister(list,NR_B);
  2241. ungetcpuregister(list,NR_C);
  2242. ungetcpuregister(list,NR_D);
  2243. ungetcpuregister(list,NR_E);
  2244. ungetcpuregister(list,NR_H);
  2245. ungetcpuregister(list,NR_L);
  2246. end;
  2247. end;
  2248. procedure tcgz80.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  2249. var
  2250. hl : tasmlabel;
  2251. ai : taicpu;
  2252. cond : TAsmCond;
  2253. begin
  2254. list.Concat(tai_comment.Create(strpnew('WARNING! not implemented: g_overflowCheck')));
  2255. //if not(cs_check_overflow in current_settings.localswitches) then
  2256. // exit;
  2257. //current_asmdata.getjumplabel(hl);
  2258. //if not ((def.typ=pointerdef) or
  2259. // ((def.typ=orddef) and
  2260. // (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2261. // pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2262. // cond:=C_VC
  2263. //else
  2264. // cond:=C_CC;
  2265. //ai:=Taicpu.Op_Sym(A_BRxx,hl);
  2266. //ai.SetCondition(cond);
  2267. //ai.is_jmp:=true;
  2268. //list.concat(ai);
  2269. //
  2270. //a_call_name(list,'FPC_OVERFLOW',false);
  2271. //a_label(list,hl);
  2272. end;
  2273. procedure tcgz80.g_save_registers(list: TAsmList);
  2274. begin
  2275. { this is done by the entry code }
  2276. end;
  2277. procedure tcgz80.g_restore_registers(list: TAsmList);
  2278. begin
  2279. { this is done by the exit code }
  2280. end;
  2281. procedure tcgz80.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2282. begin
  2283. case cond of
  2284. OC_EQ:
  2285. a_jmp_unsigned_cmp_3way(list,nil,l,nil);
  2286. OC_NE:
  2287. a_jmp_unsigned_cmp_3way(list,l,nil,l);
  2288. OC_A:
  2289. a_jmp_unsigned_cmp_3way(list,nil,nil,l);
  2290. OC_B:
  2291. a_jmp_unsigned_cmp_3way(list,l,nil,nil);
  2292. OC_AE:
  2293. a_jmp_unsigned_cmp_3way(list,nil,l,l);
  2294. OC_BE:
  2295. a_jmp_unsigned_cmp_3way(list,l,l,nil);
  2296. OC_GT:
  2297. a_jmp_signed_cmp_3way(list,nil,nil,l);
  2298. OC_LT:
  2299. a_jmp_signed_cmp_3way(list,l,nil,nil);
  2300. OC_GTE:
  2301. a_jmp_signed_cmp_3way(list,nil,l,l);
  2302. OC_LTE:
  2303. a_jmp_signed_cmp_3way(list,l,l,nil);
  2304. else
  2305. internalerror(2011082501);
  2306. end;
  2307. end;
  2308. procedure tcgz80.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  2309. var
  2310. instr: taicpu;
  2311. begin
  2312. instr:=taicpu.op_reg_reg(A_LD,reg2,reg1);
  2313. list.Concat(instr);
  2314. { Notify the register allocator that we have written a move instruction so
  2315. it can try to eliminate it. }
  2316. add_move_instruction(instr);
  2317. end;
  2318. procedure tcg64fz80.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2319. begin
  2320. if not(size in [OS_S64,OS_64]) then
  2321. internalerror(2012102402);
  2322. tcgz80(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  2323. end;
  2324. procedure tcg64fz80.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2325. begin
  2326. tcgz80(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  2327. end;
  2328. function GetByteLoc(const loc : tlocation; nr : byte) : tlocation;
  2329. var
  2330. i : Integer;
  2331. begin
  2332. Result:=loc;
  2333. Result.size:=OS_8;
  2334. case loc.loc of
  2335. LOC_REFERENCE,LOC_CREFERENCE:
  2336. inc(Result.reference.offset,nr);
  2337. LOC_REGISTER,LOC_CREGISTER:
  2338. begin
  2339. if nr>=4 then
  2340. Result.register:=Result.register64.reghi;
  2341. nr:=nr mod 4;
  2342. for i:=1 to nr do
  2343. Result.register:=GetNextReg(Result.register);
  2344. end;
  2345. LOC_CONSTANT:
  2346. if loc.size in [OS_64,OS_S64] then
  2347. Result.value:=(Result.value64 shr (nr*8)) and $ff
  2348. else
  2349. Result.value:=(Result.value shr (nr*8)) and $ff;
  2350. else
  2351. Internalerror(2019020902);
  2352. end;
  2353. end;
  2354. procedure create_codegen;
  2355. begin
  2356. cg:=tcgz80.create;
  2357. cg64:=tcg64fz80.create;
  2358. end;
  2359. end.