ZynqTools.Mod 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  1. MODULE ZynqTools; (** AUTHOR "Timothée Martiel"; PURPOSE "Utility commands for Zynq platforms"; *)
  2. IMPORT SYSTEM, Commands, Streams, Files, Options, Strings;
  3. CONST
  4. HeaderSize = 8C0H;
  5. (* Defaults Settings for bootloader *)
  6. BoardAddress = "10.3.34.8";
  7. HostAddress = "10.3.34.145";
  8. Protocol = "TFTP";
  9. CommandPort = 59999;
  10. CommandTimeout = 10000;
  11. DefaultLoadAddress = 100000H;
  12. CR = 0DX;
  13. LF = 0AX;
  14. TCLModuleHeadComment0 = "(** TCL initialization module automatically generated by ZynqTools.ImportTCL for ";
  15. TCLModuleHeadComment1 = " *)";
  16. TCLModuleName = "TclInit";
  17. TCLMaskWrite = 0;
  18. TCLMaskPoll = 1;
  19. TCLMaskDelay = 3;
  20. TCLMwrForce = 4;
  21. TraceDeployCommands = TRUE;
  22. TYPE
  23. TclRewriter = OBJECT
  24. VAR
  25. token: ARRAY 128 OF CHAR;
  26. reader: Streams.Reader;
  27. writer: Streams.Writer;
  28. PROCEDURE & Init (reader: Streams.Reader; writer: Streams.Writer);
  29. BEGIN
  30. SELF.reader := reader;
  31. SELF.writer := writer
  32. END Init;
  33. PROCEDURE Section;
  34. BEGIN
  35. ASSERT(token = 'proc');
  36. ASSERT(reader.GetString(token));
  37. writer.String(" ");
  38. writer.String(token);
  39. writer.String(" * = [");
  40. REPEAT
  41. ASSERT(reader.GetString(token))
  42. UNTIL (token # '{') & (token # '}') & (token # '{}');
  43. LOOP
  44. IF (token = 'mask_write') OR (token = 'mask_poll') OR (token = 'mask_delay') OR (token = 'mwr') THEN
  45. IF token = 'mwr' THEN
  46. ASSERT(reader.GetString(token));
  47. ASSERT(token = '-force');
  48. token := "mwr_force";
  49. END;
  50. writer.Ln;
  51. writer.String(" ")
  52. ELSIF (token[0] = '0') & (token[1] = 'X') THEN
  53. token[1] := 'x'
  54. END;
  55. writer.String(token);
  56. ASSERT(reader.GetString(token));
  57. IF token = '}' THEN EXIT END;
  58. writer.String(", ");
  59. END;
  60. (*ASSERT(reader.GetString(token));*)
  61. writer.Ln;
  62. writer.String(" ];");
  63. writer.Ln
  64. END Section;
  65. PROCEDURE Rewrite;
  66. BEGIN
  67. WHILE reader.GetString(token) & (token = 'proc') DO Section END
  68. END Rewrite;
  69. END TclRewriter;
  70. (**
  71. Deploy a software/hardware system on a board using the ZynqBootloader.
  72. ZynqTools.Deploy [--protocol=<protocol> | -p=<protocol>] [--host=<ipaddress>] [--board=<ipaddress>|-b=<ipaddress>]
  73. [--software | -s] [--softwareLoadAddress=<address>]
  74. [--hardware | -h]
  75. [--bootloader]
  76. [<software code file>] [<hardware bitstream file>]
  77. ~
  78. Constraints:
  79. o if --bootloader is present, --software and --hardware are prohibited
  80. o protocols: TFTP, UART (for manual control)
  81. o host: TFTP server computer
  82. o board: board ip address
  83. PROCEDURE Deploy * (context: Commands.Context);
  84. VAR
  85. command: ARRAY 256 OF CHAR;
  86. softwareFile, hardwareFile, boardAddress, hostAddress, protocol: ARRAY 128 OF CHAR;
  87. boardIpAdr: IP.Adr;
  88. options: Options.Options;
  89. socket: UDP.Socket;
  90. loadAddress: LONGINT;
  91. res: LONGINT;
  92. loadBootloader, loadSoftware, loadHardware: BOOLEAN;
  93. BEGIN
  94. NEW(options);
  95. options.Add('b', 'board', Options.String);
  96. options.Add('h', 'hardware', Options.Flag);
  97. options.Add('p', 'protocol', Options.String);
  98. options.Add('s', 'software', Options.Flag);
  99. options.Add(0X, 'bootloader', Options.Flag);
  100. options.Add(0X, 'host', Options.String);
  101. options.Add(0X, 'softwareLoadAddress', Options.Integer);
  102. IF ~options.Parse(context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN END;
  103. loadBootloader := options.GetFlag('bootloader');
  104. loadSoftware := options.GetFlag('software');
  105. loadHardware := options.GetFlag('hardware');
  106. IF loadSoftware THEN
  107. IF ~options.GetInteger('softwareLoadAddress', loadAddress) THEN
  108. loadAddress := DefaultLoadAddress
  109. END;
  110. END;
  111. IF loadBootloader & (loadSoftware OR loadHardware) THEN
  112. context.error.String("Cannot program hardware or software when rewriting bootloader");
  113. context.error.Ln; context.result := Commands.CommandError;
  114. RETURN
  115. END;
  116. IF loadBootloader OR loadSoftware THEN
  117. IF ~context.arg.GetString(softwareFile) THEN
  118. context.error.String("Expected software file image");
  119. context.error.Ln; context.result := Commands.CommandParseError;
  120. RETURN
  121. END
  122. END;
  123. IF loadHardware THEN
  124. IF ~context.arg.GetString(hardwareFile) THEN
  125. context.error.String("Expected hardware file image");
  126. context.error.Ln; context.result := Commands.CommandParseError;
  127. RETURN
  128. END
  129. END;
  130. IF ~options.GetString('board', boardAddress) THEN
  131. boardAddress := BoardAddress
  132. END;
  133. IF ~options.GetString('host', hostAddress) THEN
  134. hostAddress := HostAddress
  135. END;
  136. IF ~options.GetString('protocol', protocol) THEN
  137. protocol := Protocol
  138. END;
  139. ASSERT(protocol = "TFTP"); (*! For now only TFTP is supported *)
  140. (* Print Deployment report *)
  141. context.out.String('Deploying:'); context.out.Ln;
  142. IF loadSoftware THEN
  143. context.out.String(" -> ");
  144. context.out.String(softwareFile);
  145. context.out.String(" as software at ");
  146. context.out.Hex(loadAddress, -8);
  147. context.out.String("H");
  148. context.out.Ln
  149. END;
  150. IF loadHardware THEN
  151. context.out.String(" -> ");
  152. context.out.String(hardwareFile);
  153. context.out.String(" on FPGA");
  154. context.out.Ln
  155. END;
  156. IF loadBootloader THEN
  157. context.out.String(" -> ");
  158. context.out.String(softwareFile);
  159. context.out.String(" as bootloader");
  160. context.out.Ln
  161. END;
  162. context.out.String("File Transfer Protocol: "); context.out.String(protocol); context.out.Ln;
  163. IF protocol = 'TFTP' THEN context.out.String(" TFTP server at: "); context.out.String(hostAddress); context.out.Ln END;
  164. context.out.String("Board network address: "); context.out.String(boardAddress); context.out.Ln;
  165. context.out.Update;
  166. TFTPServer.Start;
  167. (* Send commands *)
  168. context.out.String("Deploying application...");
  169. context.out.Update;
  170. NEW(socket, CommandPort, res);
  171. IF res # UDP.Ok THEN
  172. context.error.String("Error opening UDP command socket: ");
  173. context.error.Int(res, 0);
  174. context.error.Ln;
  175. context.result := Commands.CommandError;
  176. RETURN
  177. END;
  178. boardIpAdr := IP.StrToAdr(boardAddress);
  179. ASSERT(~IP.IsNilAdr(boardIpAdr));
  180. (* Source command *)
  181. command := "setsource ";
  182. Strings.Append(command, protocol);
  183. Strings.Append(command, " ");
  184. Strings.Append(command, hostAddress);
  185. Strings.AppendChar(command, CR);
  186. Strings.AppendChar(command, LF);
  187. SendCommand(context.out, socket, boardIpAdr, CommandPort, command, res);
  188. IF res # UDP.Ok THEN
  189. context.error.String("Error sending command: ");
  190. context.error.Int(res, 0);
  191. context.error.Ln;
  192. context.error.Update;
  193. socket.Close;
  194. context.result := Commands.CommandError;
  195. RETURN
  196. END;
  197. (* Load bitstream & program fpga *)
  198. IF loadHardware THEN
  199. command := 'load ';
  200. Strings.Append(command, hardwareFile);
  201. Strings.Append(command, ' fpga');
  202. Strings.AppendChar(command, CR);
  203. Strings.AppendChar(command, LF);
  204. SendCommand(context.out, socket, boardIpAdr, CommandPort, command, res);
  205. IF res # UDP.Ok THEN
  206. context.error.String("Error sending command: ");
  207. context.error.Int(res, 0);
  208. context.error.Ln;
  209. context.error.Update;
  210. socket.Close;
  211. context.result := Commands.CommandError;
  212. RETURN
  213. END;
  214. END;
  215. (* Load ARM image to memory and start command *)
  216. IF loadSoftware THEN
  217. command := "load ";
  218. Strings.Append(command, softwareFile);
  219. Strings.Append(command, " memory ");
  220. Strings.AppendInt(command, loadAddress);
  221. Strings.AppendChar(command, CR);
  222. Strings.AppendChar(command, LF);
  223. SendCommand(context.out, socket, boardIpAdr, CommandPort, command ,res);
  224. IF res # UDP.Ok THEN
  225. context.error.String("Error sending command: ");
  226. context.error.Int(res, 0);
  227. context.error.Ln;
  228. context.error.Update;
  229. socket.Close;
  230. context.result := Commands.CommandError;
  231. RETURN
  232. END;
  233. command := "start ";
  234. Strings.AppendInt(command, loadAddress);
  235. Strings.AppendChar(command, CR);
  236. Strings.AppendChar(command, LF);
  237. SendCommand(context.out, socket, boardIpAdr, CommandPort, command ,res);
  238. IF res # UDP.Ok THEN
  239. context.error.String("Error sending command: ");
  240. context.error.Int(res, 0);
  241. context.error.Ln;
  242. context.error.Update;
  243. socket.Close;
  244. context.result := Commands.CommandError;
  245. RETURN
  246. END;
  247. END;
  248. context.out.String('done'); context.out.Ln;
  249. socket.Close;
  250. TFTPServer.Stop
  251. END Deploy;
  252. PROCEDURE SendCommand (out: Streams.Writer; socket: UDP.Socket; CONST adr: IP.Adr; port: LONGINT; CONST str: ARRAY OF CHAR; VAR res: LONGINT);
  253. VAR
  254. ack: ARRAY 64 OF CHAR;
  255. hostAdr: IP.Adr;
  256. len, hostPort: LONGINT;
  257. BEGIN
  258. IF TraceDeployCommands THEN
  259. out.String("Deploy Command: ");
  260. out.String(str);
  261. out.Update
  262. END;
  263. socket.Send(adr, port, str, 0, Strings.Length(str), res);
  264. socket.Receive(ack, 0, LEN(ack), CommandTimeout, hostAdr, hostPort, len, res);
  265. IF res # UDP.Ok THEN
  266. IF TraceDeployCommands THEN
  267. out.String(" -> unable to send command");
  268. out.Ln
  269. END;
  270. RETURN
  271. ELSIF ~IP.AdrsEqual(hostAdr, adr) THEN
  272. res := - 1
  273. ELSIF (ack[0] # 'O') OR (ack[1] # 'K') OR (ack[2] # ':') THEN
  274. out.String(ack);
  275. out.Ln;
  276. out.Update;
  277. IF TraceDeployCommands THEN
  278. out.String(" -> error in command execution");
  279. out.Ln
  280. END;
  281. res := -3
  282. ELSIF TraceDeployCommands THEN
  283. out.String(" -> OK");
  284. out.Ln
  285. END
  286. END SendCommand;*)
  287. (**
  288. Import a Xilinx TCL board initialization file as an Oberon module suitable for use in the Zynq Bootloader.
  289. This command simply rewrites first sections of a TCL file, which are expected to be:
  290. - ps7_pll_init_data_*
  291. - ps7_clock_init_data_*
  292. - ps7_ddr_init_data_*
  293. - ps7_mio_init_data_*
  294. - ps7_peripherals_init_data_*
  295. where the * is 1_0, 2_0 or 3_0.
  296. These sections are placed in a module named FsblInit as matharray constants. These constants are then used
  297. by the Initializer of the bootloader.
  298. Syntax:
  299. ZynqTools.ImportTCL [-d=dir|--directory=dir] [-m=moduleName|--module=moduleName] boardName file ~
  300. board: name of the board
  301. file: TCL file name
  302. -d|--directory gives the output directory.
  303. -m|--module gives the module name (default TclInit).
  304. The output file is named Board.Module.Mos
  305. *)
  306. PROCEDURE ImportTCL * (context: Commands.Context);
  307. VAR
  308. board, outputFile, inputFile, moduleName: ARRAY 128 OF CHAR;
  309. options: Options.Options;
  310. inFile, outFile: Files.File;
  311. input: Files.Reader;
  312. output: Files.Writer;
  313. rewriter: TclRewriter;
  314. BEGIN
  315. NEW(options);
  316. options.Add('d', 'directory', Options.String);
  317. options.Add('m', 'module', Options.String);
  318. IF ~options.Parse(context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN END;
  319. IF ~context.arg.GetString(board) THEN
  320. context.error.String("Expected board name");
  321. context.error.Ln;
  322. context.result := Commands.CommandParseError;
  323. RETURN
  324. END;
  325. IF ~context.arg.GetString(inputFile) THEN
  326. context.error.String("Expected input TCL file");
  327. context.error.Ln;
  328. context.result := Commands.CommandParseError;
  329. RETURN
  330. END;
  331. IF ~options.GetString('module', moduleName) THEN
  332. COPY(TCLModuleName, moduleName)
  333. END;
  334. IF options.GetString('directory', outputFile) THEN
  335. IF outputFile[Strings.Length(outputFile) - 1] # '/' THEN
  336. Strings.AppendChar(outputFile, '/')
  337. END
  338. ELSE
  339. outputFile[0] := 0X
  340. END;
  341. Strings.Append(outputFile, board);
  342. Strings.Append(outputFile, '.');
  343. Strings.Append(outputFile, moduleName);
  344. Strings.Append(outputFile, '.Mos');
  345. inFile := Files.Old(inputFile);
  346. IF inFile = NIL THEN
  347. context.error.String("Could not open file '");
  348. context.error.String(inputFile);
  349. context.error.String("'.");
  350. context.error.Ln;
  351. context.result := Commands.CommandError;
  352. RETURN
  353. END;
  354. Files.OpenReader(input, inFile, 0);
  355. IF input = NIL THEN
  356. context.error.String("Cannot read file '");
  357. context.error.String(inputFile);
  358. context.error.Ln;
  359. context.result := Commands.CommandError;
  360. RETURN
  361. END;
  362. outFile := Files.New(outputFile);
  363. IF outFile = NIL THEN
  364. context.error.String("Could not open file '");
  365. context.error.String(outputFile);
  366. context.error.String("'.");
  367. context.error.Ln;
  368. context.result := Commands.CommandError;
  369. RETURN
  370. END;
  371. Files.OpenWriter(output, outFile, 0);
  372. IF output = NIL THEN
  373. context.error.String("Cannot write to file '");
  374. context.error.String(outputFile);
  375. context.error.Ln;
  376. context.result := Commands.CommandError;
  377. RETURN
  378. END;
  379. Files.Register(outFile);
  380. NEW(rewriter, input, output);
  381. context.out.String("Importing TCL file '");
  382. context.out.String(inputFile);
  383. context.out.String("' (");
  384. context.out.String(board);
  385. context.out.String(") to '");
  386. context.out.String(outputFile);
  387. context.out.String("'.");
  388. context.out.Ln;
  389. context.out.Update;
  390. (* Generate module header *)
  391. output.String(TCLModuleHeadComment0);
  392. output.String(board);
  393. output.String(TCLModuleHeadComment1);
  394. output.Ln;
  395. output.String("MODULE ");
  396. output.String(moduleName);
  397. output.String(';');
  398. output.Ln;
  399. output.String('CONST');
  400. output.Ln;
  401. output.String(" mask_write * = ");
  402. output.Int(TCLMaskWrite, 0);
  403. output.String(";");
  404. output.Ln;
  405. output.String(" mask_poll * = ");
  406. output.Int(TCLMaskPoll, 0);
  407. output.String(';');
  408. output.Ln;
  409. output.String(" mask_delay * = ");
  410. output.Int(TCLMaskDelay, 0);
  411. output.String(';');
  412. output.Ln;
  413. output.String(" mwr_force * = ");
  414. output.Int(TCLMwrForce, 0);
  415. output.String(';');
  416. output.Ln;
  417. rewriter.Rewrite;
  418. (* Module Footer *)
  419. output.String("END ");
  420. output.String(TCLModuleName);
  421. output.String('.');
  422. output.Update;
  423. outFile.Close;
  424. inFile.Close
  425. END ImportTCL;
  426. (**
  427. * Generate a Zynq boot ROM.
  428. *
  429. * Creates a boot header with the specified options and add a binary image after it.
  430. *
  431. * ZynqTools.GenerateBootROM {-o outfile | -b boardName | -e encryption | --key AESkey | --keyFromEfuse | --keyFromRam | --inPlace | --userWord} input ~
  432. *)
  433. PROCEDURE GenerateBootROM * (context : Commands.Context);
  434. VAR
  435. header: ARRAY HeaderSize OF CHAR;
  436. buffer: ARRAY 1024 OF CHAR;
  437. input, output, board, key: ARRAY 128 OF CHAR;
  438. interrupts, registers: ARRAY 32 OF CHAR;
  439. opt: Options.Options;
  440. inFile, outFile: Files.File;
  441. in: Files.Reader;
  442. out: Files.Writer;
  443. userWord, read, size, wrote: LONGINT;
  444. encrypt, keyFromEFuse, keyFromRam, inPlace: BOOLEAN;
  445. BEGIN
  446. NEW(opt);
  447. opt.Add('o', 'outFile', Options.String);
  448. opt.Add('b', 'board', Options.String);
  449. opt.Add('e', 'encrypt', Options.Flag);
  450. opt.Add(0X, 'key', Options.String);
  451. opt.Add(0X, 'keyFromEfuse', Options.Flag);
  452. opt.Add(0X, 'keyFromRam', Options.Flag);
  453. opt.Add(0X, 'inPlace', Options.Flag);
  454. opt.Add(0X, 'userWord', Options.Integer);
  455. IF ~opt.Parse(context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN END;
  456. context.arg.String(input);
  457. IF ~opt.GetString("outFile", output) THEN
  458. output := "BOOT.BIN"
  459. END;
  460. IF opt.GetString('board', board) THEN
  461. board := "None"
  462. END;
  463. encrypt := opt.GetFlag('encrypt');
  464. IF opt.GetString('key', key) THEN
  465. IF encrypt THEN
  466. context.error.String("Cannot encrypt image without key");
  467. context.error.Ln;
  468. context.result := Commands.CommandError;
  469. RETURN
  470. END
  471. END;
  472. keyFromEFuse := opt.GetFlag('keyFromEfuse');
  473. keyFromRam := opt.GetFlag('keyFromRam');
  474. inPlace := opt.GetFlag('inPlace');
  475. IF ~opt.GetInteger('userWord', userWord) THEN
  476. userWord := 0
  477. END;
  478. IF encrypt & ~keyFromEFuse & ~keyFromRam THEN
  479. context.error.String("Cannot encrypt image without key source");
  480. context.error.Ln;
  481. context.result := Commands.CommandError;
  482. RETURN
  483. END;
  484. inFile := Files.Old(input);
  485. IF inFile = NIL THEN
  486. context.error.String("Cannot open input file '");
  487. context.error.String(input);
  488. context.error.String("'");
  489. context.error.Ln;
  490. context.result := Commands.CommandError;
  491. RETURN
  492. END;
  493. Files.OpenReader(in, inFile, 0);
  494. outFile := Files.New(output);
  495. IF outFile = NIL THEN
  496. context.error.String("Cannot open output file '");
  497. context.error.String(output);
  498. context.error.String("'");
  499. context.error.Ln;
  500. context.result := Commands.CommandError;
  501. RETURN
  502. END;
  503. Files.OpenWriter(out, outFile, 0);
  504. context.out.String("Creating Zynq BootROM image...");
  505. size := inFile.Length();
  506. IF size > 30000H THEN
  507. context.error.String("Image size is too big."); context.error.Ln;
  508. context.error.String(" Maximum size: 30000H"); context.error.Ln;
  509. context.error.String(" Actual size: "); context.error.Hex(size, -5); context.error.String('H'); context.error.Ln;
  510. context.result := Commands.CommandError;
  511. RETURN
  512. END;
  513. FOR read := 0 TO 31 BY 4 DO
  514. interrupts[read] := 0FEX;
  515. interrupts[read + 1] := 0FFX;
  516. interrupts[read + 2] := 0FFX;
  517. interrupts[read + 3] := 0EAX;
  518. END;
  519. FOR read := 0 TO 31 BY 8 DO
  520. registers[read] := 0FFX;
  521. registers[read + 1] := 0FFX;
  522. registers[read + 2] := 0FFX;
  523. registers[read + 3] := 0FFX;
  524. registers[read + 4] := 0X;
  525. registers[read + 5] := 0X;
  526. registers[read + 6] := 0X;
  527. registers[read + 7] := 0X
  528. END;
  529. CreateBootHeader(userWord, size, 8C0H, 0, interrupts, registers, encrypt, keyFromEFuse, inPlace, header);
  530. out.Bytes(header, 0, HeaderSize);
  531. WHILE in.res = Streams.Ok DO
  532. in.Bytes(buffer, 0, 1024, read);
  533. out.Bytes(buffer, 0, read);
  534. INC(wrote, read)
  535. END;
  536. out.Update;
  537. IF wrote # size THEN
  538. context.error.String("Error: copied ");
  539. context.error.Int(wrote, 0);
  540. context.error.String("B from input file, but length is supposed to be ");
  541. context.error.Int(size, 0);
  542. context.error.String("B.");
  543. context.error.Ln;
  544. context.error.Update;
  545. context.result := Commands.CommandError;
  546. RETURN
  547. ELSE
  548. context.out.String("Copied ");
  549. context.out.Int(wrote, 0);
  550. context.out.String("/");
  551. context.out.Int(size, 0);
  552. context.out.String("B.");
  553. context.out.Ln
  554. END;
  555. context.out.String(" done");
  556. context.out.Ln;
  557. inFile.Close;
  558. Files.Register(outFile);
  559. outFile.Close;
  560. END GenerateBootROM;
  561. PROCEDURE ReplaceImageInBootROM * (context: Commands.Context);
  562. VAR
  563. block: ARRAY 1024 OF CHAR;
  564. imName, romName: ARRAY 128 OF CHAR;
  565. fIm, fRom, fOut: Files.File;
  566. im, rom: Files.Reader;
  567. out: Files.Writer;
  568. ofs, pos, read: LONGINT;
  569. BEGIN
  570. romName := "cfsbl/BOOT.BIN";
  571. imName := "Fsbl.Bin";
  572. context.out.String("Replacing image in '");
  573. context.out.String(romName);
  574. context.out.String("' by '");
  575. context.out.String(imName);
  576. context.out.String("'...");
  577. context.out.Ln;
  578. context.out.Update;
  579. fRom := Files.Old(romName);
  580. fIm := Files.Old(imName);
  581. fOut := Files.New("BOOT.BIN");
  582. IF fRom = NIL THEN
  583. context.error.String("Could not open ROM file");
  584. context.error.Ln;
  585. context.error.Update;
  586. context.result := Commands.CommandError;
  587. RETURN
  588. ELSIF fIm = NIL THEN
  589. context.error.String("Could not open image file");
  590. context.error.Ln;
  591. context.error.Update;
  592. context.result := Commands.CommandError;
  593. RETURN
  594. ELSIF fOut = NIL THEN
  595. context.error.String("Could not open output file");
  596. context.error.Ln;
  597. context.error.Update;
  598. context.result := Commands.CommandError;
  599. RETURN
  600. END;
  601. Files.OpenReader(rom, fRom, 0);
  602. Files.OpenReader(im, fIm, 0);
  603. Files.OpenWriter(out, fOut, 0);
  604. context.out.String(" Writing in 'BOOT.BIN'");
  605. context.out.Ln;
  606. context.out.Update;
  607. (*
  608. Read BootROM header:
  609. 1. Copy pre source-offset fields
  610. 2. Copy and remember source offset
  611. 3. Copy until source offset
  612. *)
  613. rom.Bytes(block, 0, 30H, read);
  614. ASSERT(read = 30H);
  615. out.Bytes(block, 0, read);
  616. rom.RawLInt(ofs);
  617. out.RawLInt(ofs);
  618. context.out.String(" Found image at location ");
  619. context.out.Hex(ofs, -8);
  620. context.out.Ln;
  621. context.out.Update;
  622. pos := 34H;
  623. WHILE pos < ofs DO
  624. rom.Bytes(block, 0, MIN(LEN(block), LONGINT(ofs) - pos), read);
  625. out.Bytes(block, 0, read);
  626. INC(pos, read);
  627. END;
  628. (* Copy image *)
  629. WHILE im.res = Streams.Ok DO
  630. im.Bytes(block, 0, LEN(block), read);
  631. out.Bytes(block, 0, read);
  632. END;
  633. Files.Register(fOut);
  634. fIm.Close;
  635. fRom.Close;
  636. fOut.Close;
  637. context.out.String(" done");
  638. context.out.Ln;
  639. END ReplaceImageInBootROM;
  640. (** Extract binary executable from BootROM image. Arguments: input output ~ *)
  641. PROCEDURE StripHeader*(context : Commands.Context);
  642. VAR
  643. block: ARRAY 1024 OF CHAR;
  644. romName, outName: ARRAY 128 OF CHAR;
  645. fRom, fOut: Files.File;
  646. rom: Files.Reader;
  647. out: Files.Writer;
  648. ofs, pos, read: LONGINT;
  649. BEGIN
  650. IF ~context.arg.GetString(romName) THEN
  651. context.error.String("Error: expected input and output files as parameters");
  652. context.error.Ln;
  653. context.result := Commands.CommandError;
  654. RETURN
  655. END;
  656. IF ~context.arg.GetString(outName) THEN
  657. context.error.String("Error: expected output file name as parameter");
  658. context.error.Ln;
  659. context.result := Commands.CommandError;
  660. RETURN
  661. END;
  662. context.out.String("Removing BootROM header from '");
  663. context.out.String(romName);
  664. context.out.String("'...");
  665. context.out.Ln;
  666. context.out.Update;
  667. fRom := Files.Old(romName);
  668. fOut := Files.New(outName);
  669. IF fRom = NIL THEN
  670. context.error.String("Could not open ROM file");
  671. context.error.Ln;
  672. context.error.Update;
  673. context.result := Commands.CommandError;
  674. RETURN
  675. ELSIF fOut = NIL THEN
  676. context.error.String("Could not open output file");
  677. context.error.Ln;
  678. context.error.Update;
  679. context.result := Commands.CommandError;
  680. RETURN
  681. END;
  682. Files.OpenReader(rom, fRom, 0);
  683. Files.OpenWriter(out, fOut, 0);
  684. context.out.String(" Writing in 'out.bin'");
  685. context.out.Ln;
  686. context.out.Update;
  687. (*
  688. Read BootROM header:
  689. 1. Copy pre source-offset fields
  690. 2. Copy and remember source offset
  691. 3. Copy until source offset
  692. *)
  693. rom.Bytes(block, 0, 30H, read);
  694. ASSERT(read = 30H);
  695. rom.RawLInt(ofs);
  696. context.out.String(" Found image at location ");
  697. context.out.Hex(ofs, -8);
  698. context.out.Ln;
  699. context.out.Update;
  700. pos := 34H;
  701. WHILE pos < ofs DO
  702. rom.Bytes(block, 0, MIN(LEN(block), LONGINT(ofs) - pos), read);
  703. INC(pos, read)
  704. END;
  705. (* Copy image *)
  706. WHILE rom.res = Streams.Ok DO
  707. rom.Bytes(block, 0, LEN(block), read);
  708. out.Bytes(block, 0, read);
  709. END;
  710. Files.Register(fOut);
  711. fRom.Close;
  712. fOut.Close;
  713. context.out.String(" done");
  714. context.out.Ln;
  715. END StripHeader;
  716. (** Create a bootROM header from the given parameters. *)
  717. PROCEDURE CreateBootHeader (userWord, imageSize, imageStartAdr, imageLoadAdr: LONGINT; CONST interrupts, registers: ARRAY OF CHAR;
  718. encrypt, keyFromEFuse, inPlace: BOOLEAN; VAR header: ARRAY OF CHAR);
  719. CONST
  720. InterruptSize = 32;
  721. WidthDetection = LONGINT(0AA995566H);
  722. ImageId = LONGINT(0584C4E58H);
  723. KeyFromEFuse = LONGINT(0A5C3C5A3H);
  724. KeyFromRam = LONGINT(03A5C3C5AH);
  725. NoEncryption = 0H;
  726. ChecksumStart = 20H;
  727. ChecksumStop = 44H;
  728. MaxRegisterLength = 800H;
  729. RegisterEnd = 8A0H;
  730. VAR
  731. chk: LONGINT;
  732. i, pos: LONGINT;
  733. BEGIN
  734. ASSERT(LEN(header) >= 8C0H);
  735. (* Interrupt Vector *)
  736. Strings.Move(interrupts, 0, InterruptSize, header, pos);
  737. INC(pos, InterruptSize);
  738. (* Width Detection *)
  739. MoveRawInt(WidthDetection, header, pos);
  740. INC(pos, 4);
  741. (* Image Identification *)
  742. MoveRawInt(ImageId, header, pos);
  743. INC(pos, 4);
  744. (* Encryption *)
  745. IF encrypt & keyFromEFuse THEN
  746. MoveRawInt(KeyFromEFuse, header, pos)
  747. ELSIF encrypt THEN
  748. MoveRawInt(KeyFromRam, header, pos)
  749. ELSE
  750. MoveRawInt(NoEncryption, header, pos)
  751. END;
  752. INC(pos, 4);
  753. (* User Defined word *)
  754. MoveRawInt(userWord, header, pos);
  755. INC(pos, 4);
  756. (* Source Offset *)
  757. ASSERT(imageStartAdr >= 8C0H);
  758. ASSERT(imageStartAdr MOD 64 = 0);
  759. MoveRawInt(imageStartAdr, header, pos);
  760. INC(pos, 4);
  761. (* Length of image *)
  762. ASSERT(imageSize <= 30000H);
  763. IF ~inPlace THEN
  764. MoveRawInt(imageSize, header, pos);
  765. ELSE
  766. MoveRawInt(0, header, pos);
  767. END;
  768. INC(pos, 4);
  769. (* FSBL Load Address *)
  770. MoveRawInt(0, header, pos);
  771. INC(pos, 4);
  772. (* Start of Execution *)
  773. IF inPlace THEN
  774. ASSERT(imageLoadAdr < 32 * 1024 * 1024);
  775. ELSIF encrypt THEN
  776. ASSERT(imageLoadAdr = 0);
  777. ELSE
  778. ASSERT(imageLoadAdr >= 0);
  779. ASSERT(imageLoadAdr < 30000H);
  780. END;
  781. MoveRawInt(imageLoadAdr, header, pos);
  782. INC(pos, 4);
  783. (* Total Image Length *)
  784. IF ~inPlace THEN
  785. MoveRawInt(imageSize, header, pos);
  786. ELSE
  787. MoveRawInt(0, header, pos);
  788. END;
  789. INC(pos, 4);
  790. (* QSPI Config Word *)
  791. MoveRawInt(0, header, pos);
  792. INC(pos, 4);
  793. (* Header Checksum *)
  794. FOR i := ChecksumStart TO ChecksumStop BY 4 DO
  795. chk := chk + ReadRawInt(header, i)
  796. END;
  797. MoveRawInt(Invert(chk), header, pos);
  798. INC(pos, 4);
  799. (* Unused *)
  800. ASSERT(pos = 4CH);
  801. WHILE pos < 0A0H DO
  802. MoveRawInt(0, header, pos);
  803. INC(pos, 4)
  804. END;
  805. (* Registers *)
  806. ASSERT(pos = 0A0H);
  807. ASSERT(LEN(registers) <= MaxRegisterLength);
  808. Strings.Move(registers, 0, LEN(registers), header, pos);
  809. INC(pos, LEN(registers));
  810. WHILE pos < RegisterEnd DO
  811. MoveRawInt(LONGINT(0FFFFFFFFH), header, pos);
  812. INC(pos, 4);
  813. MoveRawInt(LONGINT(0), header, pos);
  814. INC(pos, 4);
  815. END;
  816. (* Unused *)
  817. WHILE pos < HeaderSize DO
  818. MoveRawInt(LONGINT(0FFFFFFFFH), header, pos);
  819. INC(pos, 4)
  820. END
  821. END CreateBootHeader;
  822. (** Insert a raw integer in the array at location [ofs .. ofs + 4). *)
  823. PROCEDURE MoveRawInt (int: LONGINT; VAR dest: ARRAY OF CHAR; ofs: LONGINT);
  824. BEGIN
  825. dest[ofs] := CHR(int MOD 100H);
  826. dest[ofs + 1] := CHR(int DIV 100H MOD 100H);
  827. dest[ofs + 2] := CHR(int DIV 10000H MOD 100H);
  828. dest[ofs + 3] := CHR(int DIV 1000000H MOD 100H)
  829. END MoveRawInt;
  830. (** Get an integer from the array at positions [ofs .. ofs + 4). *)
  831. PROCEDURE ReadRawInt (CONST src: ARRAY OF CHAR; ofs: LONGINT): LONGINT;
  832. VAR
  833. adr: LONGINT;
  834. BEGIN
  835. adr := LONGINT(ORD(src[ofs])) + LONGINT(ORD(src[ofs + 1])) * 100H + LONGINT(ORD(src[ofs + 2])) * 10000H + LONGINT(ORD(src[ofs + 3])) * 1000000H;
  836. RETURN adr
  837. END ReadRawInt;
  838. (** Invert bits of a LONGINT *)
  839. PROCEDURE Invert (val: LONGINT): LONGINT;
  840. BEGIN
  841. RETURN SYSTEM.VAL(LONGINT, -SYSTEM.VAL(SET, ADDRESS(val)))
  842. END Invert;
  843. END ZynqTools.
  844. ZynqTools.GenerateBootROM Fsbl.Bin ~
  845. ZynqTools.GenerateBootROM out.bin ~
  846. FoxARMInstructionSet.Disassemble BOOT.BIN ~
  847. FoxARMInstructionSet.Disassemble cfsbl/BOOT.BIN ~
  848. FoxARMInstructionSet.Disassemble Fsbl.Bin -a=2ffc0H~
  849. FoxARMInstructionSet.Disassemble C:/Users/tim/SDbackup/BOOT.BIN ~
  850. ZynqTools.ReplaceImageInBootROM cfsbl/BOOT.BIN Fsbl.Bin ~
  851. ZynqTools.StripHeader cfsbl/BOOT.BIN out.bin ~
  852. ZynqTools.Deploy -s A2.Bin ~
  853. ZynqTools.ImportTCL -d=ZBL:/ Zedboard boot/ps7_init.tcl ~
  854. ZynqTools.ImportTCL -d=ZBL:/ Zybo Zybo-boot/ps7_init.tcl ~
  855. ZynqTools.ImportTCL -d=basel/bootloader KRM KRM-boot/ps7_init.tcl ~