2
0

systems.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. {
  2. $Id$
  3. Copyright (C) 1998-2000 by Florian Klaempfl
  4. This unit contains information about the target systems supported
  5. (these are not processor specific)
  6. This progsam is free software; you can redistribute it and/or modify
  7. iu under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge- MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit systems;
  20. {$i defines.inc}
  21. interface
  22. type
  23. tendian = (endian_little,endian_big);
  24. ttargetcpu=(no_cpu
  25. ,i386,m68k,alpha,powerpc
  26. );
  27. tprocessors = (no_processor
  28. ,Class386,ClassP5,ClassP6
  29. ,MC68000,MC68100,MC68020
  30. );
  31. tsection=(sec_none,
  32. sec_code,sec_data,sec_bss,
  33. sec_idata2,sec_idata4,sec_idata5,sec_idata6,sec_idata7,sec_edata,
  34. sec_stab,sec_stabstr
  35. );
  36. tasmmode= (asmmode_none
  37. ,asmmode_i386_direct,asmmode_i386_att,asmmode_i386_intel
  38. ,asmmode_m68k_mot
  39. ,asmmode_alpha_direct
  40. ,asmmode_powerpc_direct
  41. );
  42. ttarget = (target_none,
  43. target_i386_GO32V1,target_i386_GO32V2,target_i386_linux,
  44. target_i386_OS2,target_i386_Win32,target_i386_freebsd,
  45. target_i386_Netware,target_i386_sunos,target_i386_beos,
  46. target_m68k_Amiga,target_m68k_Atari,target_m68k_Mac,
  47. target_m68k_linux,target_m68k_PalmOS,
  48. target_alpha_linux,
  49. target_powerpc_linux,target_powerpc_macos
  50. );
  51. tasm = (as_none
  52. ,as_i386_as,as_i386_as_aout,as_i386_asw,
  53. as_i386_nasmcoff,as_i386_nasmwin32,
  54. as_i386_nasmelf,as_i386_nasmobj,
  55. as_i386_tasm,as_i386_masm,
  56. as_i386_dbg,as_i386_coff,as_i386_pecoff,as_i386_elf32
  57. ,as_m68k_as,as_m68k_gas,as_m68k_mit,as_m68k_mot,as_m68k_mpw
  58. ,as_alpha_as
  59. ,as_powerpc_as,as_powerpc_mpw
  60. );
  61. tld = (ld_none,
  62. ld_i386_GO32V1,ld_i386_GO32V2,ld_i386_linux,
  63. ld_i386_OS2,ld_i386_Win32,ld_i386_freebsd,
  64. ld_i386_Netware,ld_i386_sunos,ld_i386_beos,
  65. ld_m68k_Amiga,ld_m68k_Atari,ld_m68k_Mac,
  66. ld_m68k_linux,ld_m68k_PalmOS,
  67. ld_alpha_linux,
  68. ld_powerpc_linux,ld_powerpc_macos
  69. );
  70. tar = (ar_none
  71. ,ar_gnu_ar,ar_gnu_arw
  72. );
  73. tres = (res_none
  74. ,res_gnu_windres,res_emxbind
  75. );
  76. {*****************************************************************************
  77. Structures
  78. *****************************************************************************}
  79. type
  80. palignmentinfo = ^talignmentinfo;
  81. talignmentinfo = packed record
  82. procalign,
  83. loopalign,
  84. jumpalign,
  85. constalignmin,
  86. constalignmax,
  87. varalignmin,
  88. varalignmax,
  89. localalignmin,
  90. localalignmax,
  91. paraalign,
  92. recordalignmin,
  93. recordalignmax,
  94. maxCrecordalign : longint;
  95. end;
  96. pasminfo = ^tasminfo;
  97. tasminfo = packed record
  98. id : tasm;
  99. idtxt : string[9];
  100. asmbin : string[8];
  101. asmcmd : string[50];
  102. supported_target : ttarget;
  103. outputbinary,
  104. allowdirect,
  105. externals,
  106. needar,
  107. labelprefix_only_inside_procedure : boolean;
  108. labelprefix : string[3];
  109. comment : string[2];
  110. secnames : array[tsection] of string[20];
  111. end;
  112. parinfo = ^tarinfo;
  113. tarinfo = packed record
  114. id : tar;
  115. arcmd : string[50];
  116. end;
  117. presinfo = ^tresinfo;
  118. tresinfo = packed record
  119. id : tres;
  120. resbin : string[8];
  121. rescmd : string[50];
  122. end;
  123. ttargetflags = (tf_none,
  124. tf_supports_stack_checking,tf_need_export,tf_needs_isconsole
  125. );
  126. ptargetinfo = ^ttargetinfo;
  127. ttargetinfo = packed record
  128. target : ttarget;
  129. name : string[30];
  130. shortname : string[9];
  131. flags : set of ttargetflags;
  132. cpu : ttargetcpu;
  133. unit_env : string[12];
  134. extradefines : string[40];
  135. sharedlibext : string[10];
  136. staticlibext,
  137. sourceext,
  138. pasext,
  139. exeext,
  140. defext,
  141. scriptext,
  142. smartext,
  143. unitext,
  144. unitlibext,
  145. asmext,
  146. objext,
  147. resext,
  148. resobjext : string[4];
  149. staticlibprefix : string[4];
  150. sharedlibprefix : string[4];
  151. Cprefix : string[2];
  152. newline : string[2];
  153. assem : tasm;
  154. assemextern : tasm; { external assembler, used by -a }
  155. link : tld;
  156. linkextern : tld; { external linker, used by -s }
  157. ar : tar;
  158. res : tres;
  159. endian : tendian;
  160. alignment : talignmentinfo;
  161. size_of_pointer : byte;
  162. size_of_longint : byte;
  163. heapsize,
  164. maxheapsize,
  165. stacksize : longint;
  166. DllScanSupported : boolean;
  167. use_bound_instruction : boolean;
  168. use_function_relative_addresses : boolean;
  169. end;
  170. pasmmodeinfo = ^tasmmodeinfo;
  171. tasmmodeinfo = packed record
  172. id : tasmmode;
  173. idtxt : string[8];
  174. end;
  175. const
  176. { alias for supported_target field in tasminfo }
  177. target_any = target_none;
  178. var
  179. targetinfos : array[ttarget] of ptargetinfo;
  180. asminfos : array[tasm] of pasminfo;
  181. arinfos : array[tar] of parinfo;
  182. resinfos : array[tres] of presinfo;
  183. asmmodeinfos : array[tasmmode] of pasmmodeinfo;
  184. source_info : ttargetinfo;
  185. target_cpu : ttargetcpu;
  186. target_info : ttargetinfo;
  187. target_asm : tasminfo;
  188. target_ar : tarinfo;
  189. target_res : tresinfo;
  190. target_path : string[12]; { for rtl/<X>/,fcl/<X>/, etc. }
  191. function set_target(t:ttarget):boolean;
  192. function set_target_asm(t:tasm):boolean;
  193. function set_target_ar(t:tar):boolean;
  194. function set_target_res(t:tres):boolean;
  195. function set_target_by_string(const s : string) : boolean;
  196. function set_target_asm_by_string(const s : string) : boolean;
  197. function set_asmmode_by_string(const s:string;var t:tasmmode):boolean;
  198. procedure UpdateAlignment(var d:talignmentinfo;const s:talignmentinfo);
  199. procedure RegisterTarget(const r:ttargetinfo);
  200. procedure RegisterAsmMode(const r:tasmmodeinfo);
  201. procedure RegisterRes(const r:tresinfo);
  202. procedure RegisterAr(const r:tarinfo);
  203. procedure InitSystems;
  204. implementation
  205. uses
  206. cutils;
  207. {****************************************************************************
  208. Target setting
  209. ****************************************************************************}
  210. function set_target(t:ttarget):boolean;
  211. begin
  212. set_target:=false;
  213. if assigned(targetinfos[t]) then
  214. begin
  215. target_info:=targetinfos[t]^;
  216. set_target_asm(target_info.assem);
  217. set_target_ar(target_info.ar);
  218. set_target_res(target_info.res);
  219. target_path:=lower(target_info.shortname);
  220. target_cpu:=target_info.cpu;
  221. set_target:=true;
  222. exit;
  223. end;
  224. end;
  225. function set_target_asm(t:tasm):boolean;
  226. begin
  227. set_target_asm:=false;
  228. if assigned(asminfos[t]) then
  229. begin
  230. target_asm:=asminfos[t]^;
  231. set_target_asm:=true;
  232. exit;
  233. end;
  234. end;
  235. function set_target_ar(t:tar):boolean;
  236. begin
  237. set_target_ar:=false;
  238. if assigned(arinfos[t]) then
  239. begin
  240. target_ar:=arinfos[t]^;
  241. set_target_ar:=true;
  242. exit;
  243. end;
  244. end;
  245. function set_target_res(t:tres):boolean;
  246. begin
  247. set_target_res:=false;
  248. if assigned(resinfos[t]) then
  249. begin
  250. target_res:=resinfos[t]^;
  251. set_target_res:=true;
  252. exit;
  253. end;
  254. end;
  255. function set_target_by_string(const s : string) : boolean;
  256. var
  257. hs : string;
  258. t : ttarget;
  259. begin
  260. set_target_by_string:=false;
  261. { this should be case insensitive !! PM }
  262. hs:=upper(s);
  263. for t:=low(ttarget) to high(ttarget) do
  264. if assigned(targetinfos[t]) and
  265. (upper(targetinfos[t]^.shortname)=hs) then
  266. begin
  267. set_target_by_string:=set_target(t);
  268. exit;
  269. end;
  270. end;
  271. function set_target_asm_by_string(const s : string) : boolean;
  272. var
  273. hs : string;
  274. t : tasm;
  275. begin
  276. set_target_asm_by_string:=false;
  277. { this should be case insensitive !! PM }
  278. hs:=upper(s);
  279. for t:=low(tasm) to high(tasm) do
  280. if assigned(asminfos[t]) and
  281. (asminfos[t]^.idtxt=hs) then
  282. begin
  283. set_target_asm_by_string:=set_target_asm(t);
  284. exit;
  285. end;
  286. end;
  287. function set_asmmode_by_string(const s:string;var t:tasmmode):boolean;
  288. var
  289. hs : string;
  290. ht : tasmmode;
  291. begin
  292. set_asmmode_by_string:=false;
  293. { this should be case insensitive !! PM }
  294. hs:=upper(s);
  295. for ht:=low(tasmmode) to high(tasmmode) do
  296. if assigned(asmmodeinfos[ht]) and
  297. (asmmodeinfos[ht]^.idtxt=hs) then
  298. begin
  299. t:=asmmodeinfos[ht]^.id;
  300. set_asmmode_by_string:=true;
  301. end;
  302. end;
  303. procedure UpdateAlignment(var d:talignmentinfo;const s:talignmentinfo);
  304. begin
  305. with d do
  306. begin
  307. { general update rules:
  308. minimum: if higher then update
  309. maximum: if lower then update or if undefined then update }
  310. if s.procalign>procalign then
  311. procalign:=s.procalign;
  312. if s.loopalign>loopalign then
  313. loopalign:=s.loopalign;
  314. if s.jumpalign>jumpalign then
  315. jumpalign:=s.jumpalign;
  316. if s.constalignmin>constalignmin then
  317. constalignmin:=s.constalignmin;
  318. if (constalignmax=0) or (s.constalignmax<constalignmax) then
  319. constalignmax:=s.constalignmax;
  320. if s.varalignmin>varalignmin then
  321. varalignmin:=s.varalignmin;
  322. if (varalignmax=0) or (s.varalignmax<varalignmax) then
  323. varalignmax:=s.varalignmax;
  324. if s.localalignmin>localalignmin then
  325. localalignmin:=s.localalignmin;
  326. if (localalignmax=0) or (s.localalignmax<localalignmax) then
  327. localalignmax:=s.localalignmax;
  328. if s.paraalign>paraalign then
  329. paraalign:=s.paraalign;
  330. if s.recordalignmin>recordalignmin then
  331. recordalignmin:=s.recordalignmin;
  332. if (recordalignmax=0) or (s.recordalignmax<recordalignmax) then
  333. recordalignmax:=s.recordalignmax;
  334. if (maxCrecordalign=0) or (s.maxCrecordalign<maxCrecordalign) then
  335. maxCrecordalign:=s.maxCrecordalign;
  336. end;
  337. end;
  338. {****************************************************************************
  339. Target registration
  340. ****************************************************************************}
  341. procedure RegisterTarget(const r:ttargetinfo);
  342. var
  343. t : ttarget;
  344. begin
  345. t:=r.target;
  346. if assigned(targetinfos[t]) then
  347. writeln('Warning: Target is already registered!')
  348. else
  349. Getmem(targetinfos[t],sizeof(ttargetinfo));
  350. targetinfos[t]^:=r;
  351. end;
  352. procedure RegisterAsmmode(const r:tasmmodeinfo);
  353. var
  354. t : tasmmode;
  355. begin
  356. t:=r.id;
  357. if assigned(asmmodeinfos[t]) then
  358. writeln('Warning: Asmmode is already registered!')
  359. else
  360. Getmem(asmmodeinfos[t],sizeof(tasmmodeinfo));
  361. asmmodeinfos[t]^:=r;
  362. end;
  363. procedure RegisterRes(const r:tresinfo);
  364. var
  365. t : tres;
  366. begin
  367. t:=r.id;
  368. if assigned(resinfos[t]) then
  369. writeln('Warning: resourcecompiler is already registered!')
  370. else
  371. Getmem(resinfos[t],sizeof(tresinfo));
  372. resinfos[t]^:=r;
  373. end;
  374. procedure RegisterAr(const r:tarinfo);
  375. var
  376. t : tar;
  377. begin
  378. t:=r.id;
  379. if assigned(arinfos[t]) then
  380. writeln('Warning: ar is already registered!')
  381. else
  382. Getmem(arinfos[t],sizeof(tarinfo));
  383. arinfos[t]^:=r;
  384. end;
  385. procedure DeregisterInfos;
  386. var
  387. assem : tasm;
  388. target : ttarget;
  389. ar : tar;
  390. asmmode : tasmmode;
  391. res : tres;
  392. begin
  393. for target:=low(ttarget) to high(ttarget) do
  394. if assigned(targetinfos[target]) then
  395. begin
  396. freemem(targetinfos[target],sizeof(ttargetinfo));
  397. targetinfos[target]:=nil;
  398. end;
  399. for assem:=low(tasm) to high(tasm) do
  400. if assigned(asminfos[assem]) then
  401. begin
  402. freemem(asminfos[assem],sizeof(tasminfo));
  403. asminfos[assem]:=nil;
  404. end;
  405. for ar:=low(tar) to high(tar) do
  406. if assigned(arinfos[ar]) then
  407. begin
  408. freemem(arinfos[ar],sizeof(tarinfo));
  409. arinfos[ar]:=nil;
  410. end;
  411. for res:=low(tres) to high(tres) do
  412. if assigned(resinfos[res]) then
  413. begin
  414. freemem(resinfos[res],sizeof(tresinfo));
  415. resinfos[res]:=nil;
  416. end;
  417. for asmmode:=low(tasmmode) to high(tasmmode) do
  418. if assigned(asmmodeinfos[asmmode]) then
  419. begin
  420. freemem(asmmodeinfos[asmmode],sizeof(tasmmodeinfo));
  421. asmmodeinfos[asmmode]:=nil;
  422. end;
  423. end;
  424. {****************************************************************************
  425. Initialization of default target
  426. ****************************************************************************}
  427. procedure default_target(t:ttarget);
  428. begin
  429. set_target(t);
  430. if source_info.name='' then
  431. source_info:=target_info;
  432. end;
  433. procedure set_source(t:ttarget);
  434. begin
  435. { can't use message() here (PFV) }
  436. if source_info.name<>'' then
  437. Writeln('Warning: Source OS Redefined!');
  438. if assigned(targetinfos[t]) then
  439. source_info:=targetinfos[t]^
  440. else
  441. Writeln('Warning: Source OS Not Supported!');
  442. end;
  443. procedure InitSystems;
  444. begin
  445. { first get source OS }
  446. source_info.name:='';
  447. { please note then we use cpu86 and cpu68 here on purpose !! }
  448. {$ifdef cpu86}
  449. {$ifdef GO32V1}
  450. set_source(target_i386_GO32V1);
  451. {$else}
  452. {$ifdef GO32V2}
  453. set_source(target_i386_GO32V2);
  454. {$else}
  455. {$ifdef OS2}
  456. set_source(target_i386_OS2);
  457. if (target_Mode = osDOS) or (target_Mode = osDPMI) then
  458. source_info.scriptext := '.bat';
  459. { OS/2 via EMX can be run under DOS as well }
  460. {$else}
  461. {$ifdef WIN32}
  462. set_source(target_i386_WIN32);
  463. {$else}
  464. {$Ifdef BSD}
  465. set_source(target_i386_FreeBSD);
  466. {$else}
  467. {$ifdef sunos}
  468. set_source(target_i386_sunos);
  469. {$else}
  470. { Must be the last as some freebsd also
  471. defined linux }
  472. {$ifdef Linux}
  473. set_source(target_i386_LINUX);
  474. {$endif linux}
  475. {$endif sunos}
  476. {$endif bsd}
  477. {$endif win32}
  478. {$endif os2}
  479. {$endif go32v2}
  480. {$endif go32v1}
  481. {$endif cpu86}
  482. {$ifdef cpu68}
  483. {$ifdef AMIGA}
  484. set_source(target_m68k_Amiga);
  485. {$else}
  486. {$ifdef ATARI}
  487. set_source(target_m68k_Atari);
  488. {$else}
  489. {$ifdef MACOS}
  490. set_source(target_m68k_MAC);
  491. {$else}
  492. {$ifdef LINUX}
  493. set_source(target_m68k_linux);
  494. {$endif linux}
  495. {$endif macos}
  496. {$endif atari}
  497. {$endif amiga}
  498. {$endif cpu68}
  499. { Now default target !! }
  500. {$ifdef i386}
  501. {$ifdef GO32V1}
  502. default_target(target_i386_GO32V1);
  503. {$else}
  504. {$ifdef GO32V2}
  505. default_target(target_i386_GO32V2);
  506. {$else}
  507. {$ifdef OS2}
  508. default_target(target_i386_OS2);
  509. {$else}
  510. {$ifdef unix}
  511. {$ifdef BSD}
  512. default_target(target_i386_FreeBSD);
  513. {$else}
  514. default_target(target_i386_LINUX);
  515. {$endif}
  516. {$else}
  517. {$ifdef WIN32}
  518. default_target(target_i386_WIN32);
  519. {$else}
  520. default_target(target_i386_GO32V2);
  521. {$endif win32}
  522. {$endif linux}
  523. {$endif os2}
  524. {$endif go32v2}
  525. {$endif go32v1}
  526. {$endif i386}
  527. {$ifdef m68k}
  528. {$ifdef AMIGA}
  529. default_target(target_m68k_Amiga);
  530. {$else}
  531. {$ifdef ATARI}
  532. default_target(target_m68k_Atari);
  533. {$else}
  534. {$ifdef MACOS}
  535. default_target(target_m68k_Mac);
  536. {$else}
  537. {$ifdef LINUX}
  538. default_target(target_m68k_linux);
  539. {$else}
  540. default_target(target_m68k_Amiga);
  541. {$endif linux}
  542. {$endif macos}
  543. {$endif atari}
  544. {$endif amiga}
  545. {$endif m68k}
  546. {$ifdef alpha}
  547. default_target(target_alpha_linux);
  548. {$endif alpha}
  549. {$ifdef powerpc}
  550. default_target(target_powerpc_linux);
  551. {$endif powerpc}
  552. end;
  553. initialization
  554. finalization
  555. DeregisterInfos;
  556. end.
  557. {
  558. $Log$
  559. Revision 1.21 2001-07-01 20:16:18 peter
  560. * alignmentinfo record added
  561. * -Oa argument supports more alignment settings that can be specified
  562. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  563. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  564. required alignment and the maximum usefull alignment. The final
  565. alignment will be choosen per variable size dependent on these
  566. settings
  567. Revision 1.20 2001/06/19 14:43:31 marco
  568. * Fixed ifdef linux bug
  569. Revision 1.19 2001/06/03 20:21:08 peter
  570. * Kylix fixes, mostly case names of units
  571. Revision 1.18 2001/06/03 15:15:31 peter
  572. * dllprt0 stub for linux shared libs
  573. * pass -init and -fini for linux shared libs
  574. * libprefix splitted into staticlibprefix and sharedlibprefix
  575. Revision 1.17 2001/06/02 19:21:45 peter
  576. * extradefines field added to target_info, so that targets don't
  577. need to put code in options.pas for it
  578. Revision 1.16 2001/04/18 22:02:00 peter
  579. * registration of targets and assemblers
  580. Revision 1.15 2001/03/06 18:28:02 peter
  581. * patch from Pavel with a new and much faster DLL Scanner for
  582. automatic importing so $linklib works for DLLs. Thanks Pavel!
  583. Revision 1.14 2001/02/26 19:44:55 peter
  584. * merged generic m68k updates from fixes branch
  585. Revision 1.13 2001/02/20 21:36:40 peter
  586. * tasm/masm fixes merged
  587. Revision 1.12 2001/01/06 20:15:43 peter
  588. * merged libp library prefix
  589. Revision 1.11 2000/10/15 09:08:58 peter
  590. * use System for the systemunit instead of target dependent
  591. Revision 1.10 2000/09/24 21:12:41 hajny
  592. * OS/2 stack alignment corrected + default stack increased
  593. Revision 1.9 2000/09/24 15:06:30 peter
  594. * use defines.inc
  595. Revision 1.8 2000/09/20 10:49:39 marco
  596. * Set writer to elf. (Only a prob for smart with -OG3p3r)
  597. Revision 1.7 2000/09/16 12:22:52 peter
  598. * freebsd support merged
  599. Revision 1.6 2000/09/11 17:00:23 florian
  600. + first implementation of Netware Module support, thanks to
  601. Armin Diehl ([email protected]) for providing the patches
  602. Revision 1.5 2000/08/12 19:14:59 peter
  603. * ELF writer works now also with -g
  604. * ELF writer is default again for linux
  605. Revision 1.4 2000/07/14 21:29:38 michael
  606. * Back to external assembler till peter fixes gdb
  607. Revision 1.3 2000/07/13 12:08:28 michael
  608. + patched to 1.1.0 with former 1.09patch from peter
  609. Revision 1.2 2000/07/13 11:32:50 michael
  610. + removed logs
  611. }