123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955 |
- MODULE ZynqTools; (** AUTHOR "Timothée Martiel"; PURPOSE "Utility commands for Zynq platforms"; *)
- IMPORT SYSTEM, Commands, Streams, Files, Options, Strings;
- CONST
- HeaderSize = 8C0H;
- (* Defaults Settings for bootloader *)
- BoardAddress = "10.3.34.8";
- HostAddress = "10.3.34.145";
- Protocol = "TFTP";
- CommandPort = 59999;
- CommandTimeout = 10000;
- DefaultLoadAddress = 100000H;
- CR = 0DX;
- LF = 0AX;
- TCLModuleHeadComment0 = "(** TCL initialization module automatically generated by ZynqTools.ImportTCL for ";
- TCLModuleHeadComment1 = " *)";
- TCLModuleName = "TclInit";
- TCLMaskWrite = 0;
- TCLMaskPoll = 1;
- TCLMaskDelay = 3;
- TCLMwrForce = 4;
- TraceDeployCommands = TRUE;
- TYPE
- TclRewriter = OBJECT
- VAR
- token: ARRAY 128 OF CHAR;
- reader: Streams.Reader;
- writer: Streams.Writer;
- PROCEDURE & Init (reader: Streams.Reader; writer: Streams.Writer);
- BEGIN
- SELF.reader := reader;
- SELF.writer := writer
- END Init;
- PROCEDURE Section;
- BEGIN
- ASSERT(token = 'proc');
- ASSERT(reader.GetString(token));
- writer.String(" ");
- writer.String(token);
- writer.String(" * = [");
- REPEAT
- ASSERT(reader.GetString(token))
- UNTIL (token # '{') & (token # '}') & (token # '{}');
- LOOP
- IF (token = 'mask_write') OR (token = 'mask_poll') OR (token = 'mask_delay') OR (token = 'mwr') THEN
- IF token = 'mwr' THEN
- ASSERT(reader.GetString(token));
- ASSERT(token = '-force');
- token := "mwr_force";
- END;
- writer.Ln;
- writer.String(" ")
- ELSIF (token[0] = '0') & (token[1] = 'X') THEN
- token[1] := 'x'
- END;
- writer.String(token);
- ASSERT(reader.GetString(token));
- IF token = '}' THEN EXIT END;
- writer.String(", ");
- END;
- (*ASSERT(reader.GetString(token));*)
- writer.Ln;
- writer.String(" ];");
- writer.Ln
- END Section;
- PROCEDURE Rewrite;
- BEGIN
- WHILE reader.GetString(token) & (token = 'proc') DO Section END
- END Rewrite;
- END TclRewriter;
- (**
- Deploy a software/hardware system on a board using the ZynqBootloader.
- ZynqTools.Deploy [--protocol=<protocol> | -p=<protocol>] [--host=<ipaddress>] [--board=<ipaddress>|-b=<ipaddress>]
- [--software | -s] [--softwareLoadAddress=<address>]
- [--hardware | -h]
- [--bootloader]
- [<software code file>] [<hardware bitstream file>]
- ~
- Constraints:
- o if --bootloader is present, --software and --hardware are prohibited
- o protocols: TFTP, UART (for manual control)
- o host: TFTP server computer
- o board: board ip address
- PROCEDURE Deploy * (context: Commands.Context);
- VAR
- command: ARRAY 256 OF CHAR;
- softwareFile, hardwareFile, boardAddress, hostAddress, protocol: ARRAY 128 OF CHAR;
- boardIpAdr: IP.Adr;
- options: Options.Options;
- socket: UDP.Socket;
- loadAddress: LONGINT;
- res: LONGINT;
- loadBootloader, loadSoftware, loadHardware: BOOLEAN;
- BEGIN
- NEW(options);
- options.Add('b', 'board', Options.String);
- options.Add('h', 'hardware', Options.Flag);
- options.Add('p', 'protocol', Options.String);
- options.Add('s', 'software', Options.Flag);
- options.Add(0X, 'bootloader', Options.Flag);
- options.Add(0X, 'host', Options.String);
- options.Add(0X, 'softwareLoadAddress', Options.Integer);
- IF ~options.Parse(context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN END;
- loadBootloader := options.GetFlag('bootloader');
- loadSoftware := options.GetFlag('software');
- loadHardware := options.GetFlag('hardware');
- IF loadSoftware THEN
- IF ~options.GetInteger('softwareLoadAddress', loadAddress) THEN
- loadAddress := DefaultLoadAddress
- END;
- END;
- IF loadBootloader & (loadSoftware OR loadHardware) THEN
- context.error.String("Cannot program hardware or software when rewriting bootloader");
- context.error.Ln; context.result := Commands.CommandError;
- RETURN
- END;
- IF loadBootloader OR loadSoftware THEN
- IF ~context.arg.GetString(softwareFile) THEN
- context.error.String("Expected software file image");
- context.error.Ln; context.result := Commands.CommandParseError;
- RETURN
- END
- END;
- IF loadHardware THEN
- IF ~context.arg.GetString(hardwareFile) THEN
- context.error.String("Expected hardware file image");
- context.error.Ln; context.result := Commands.CommandParseError;
- RETURN
- END
- END;
- IF ~options.GetString('board', boardAddress) THEN
- boardAddress := BoardAddress
- END;
- IF ~options.GetString('host', hostAddress) THEN
- hostAddress := HostAddress
- END;
- IF ~options.GetString('protocol', protocol) THEN
- protocol := Protocol
- END;
- ASSERT(protocol = "TFTP"); (*! For now only TFTP is supported *)
- (* Print Deployment report *)
- context.out.String('Deploying:'); context.out.Ln;
- IF loadSoftware THEN
- context.out.String(" -> ");
- context.out.String(softwareFile);
- context.out.String(" as software at ");
- context.out.Hex(loadAddress, -8);
- context.out.String("H");
- context.out.Ln
- END;
- IF loadHardware THEN
- context.out.String(" -> ");
- context.out.String(hardwareFile);
- context.out.String(" on FPGA");
- context.out.Ln
- END;
- IF loadBootloader THEN
- context.out.String(" -> ");
- context.out.String(softwareFile);
- context.out.String(" as bootloader");
- context.out.Ln
- END;
- context.out.String("File Transfer Protocol: "); context.out.String(protocol); context.out.Ln;
- IF protocol = 'TFTP' THEN context.out.String(" TFTP server at: "); context.out.String(hostAddress); context.out.Ln END;
- context.out.String("Board network address: "); context.out.String(boardAddress); context.out.Ln;
- context.out.Update;
- TFTPServer.Start;
- (* Send commands *)
- context.out.String("Deploying application...");
- context.out.Update;
- NEW(socket, CommandPort, res);
- IF res # UDP.Ok THEN
- context.error.String("Error opening UDP command socket: ");
- context.error.Int(res, 0);
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- boardIpAdr := IP.StrToAdr(boardAddress);
- ASSERT(~IP.IsNilAdr(boardIpAdr));
- (* Source command *)
- command := "setsource ";
- Strings.Append(command, protocol);
- Strings.Append(command, " ");
- Strings.Append(command, hostAddress);
- Strings.AppendChar(command, CR);
- Strings.AppendChar(command, LF);
- SendCommand(context.out, socket, boardIpAdr, CommandPort, command, res);
- IF res # UDP.Ok THEN
- context.error.String("Error sending command: ");
- context.error.Int(res, 0);
- context.error.Ln;
- context.error.Update;
- socket.Close;
- context.result := Commands.CommandError;
- RETURN
- END;
- (* Load bitstream & program fpga *)
- IF loadHardware THEN
- command := 'load ';
- Strings.Append(command, hardwareFile);
- Strings.Append(command, ' fpga');
- Strings.AppendChar(command, CR);
- Strings.AppendChar(command, LF);
- SendCommand(context.out, socket, boardIpAdr, CommandPort, command, res);
- IF res # UDP.Ok THEN
- context.error.String("Error sending command: ");
- context.error.Int(res, 0);
- context.error.Ln;
- context.error.Update;
- socket.Close;
- context.result := Commands.CommandError;
- RETURN
- END;
- END;
- (* Load ARM image to memory and start command *)
- IF loadSoftware THEN
- command := "load ";
- Strings.Append(command, softwareFile);
- Strings.Append(command, " memory ");
- Strings.AppendInt(command, loadAddress);
- Strings.AppendChar(command, CR);
- Strings.AppendChar(command, LF);
- SendCommand(context.out, socket, boardIpAdr, CommandPort, command ,res);
- IF res # UDP.Ok THEN
- context.error.String("Error sending command: ");
- context.error.Int(res, 0);
- context.error.Ln;
- context.error.Update;
- socket.Close;
- context.result := Commands.CommandError;
- RETURN
- END;
- command := "start ";
- Strings.AppendInt(command, loadAddress);
- Strings.AppendChar(command, CR);
- Strings.AppendChar(command, LF);
- SendCommand(context.out, socket, boardIpAdr, CommandPort, command ,res);
- IF res # UDP.Ok THEN
- context.error.String("Error sending command: ");
- context.error.Int(res, 0);
- context.error.Ln;
- context.error.Update;
- socket.Close;
- context.result := Commands.CommandError;
- RETURN
- END;
- END;
- context.out.String('done'); context.out.Ln;
- socket.Close;
- TFTPServer.Stop
- END Deploy;
- PROCEDURE SendCommand (out: Streams.Writer; socket: UDP.Socket; CONST adr: IP.Adr; port: LONGINT; CONST str: ARRAY OF CHAR; VAR res: LONGINT);
- VAR
- ack: ARRAY 64 OF CHAR;
- hostAdr: IP.Adr;
- len, hostPort: LONGINT;
- BEGIN
- IF TraceDeployCommands THEN
- out.String("Deploy Command: ");
- out.String(str);
- out.Update
- END;
- socket.Send(adr, port, str, 0, Strings.Length(str), res);
- socket.Receive(ack, 0, LEN(ack), CommandTimeout, hostAdr, hostPort, len, res);
- IF res # UDP.Ok THEN
- IF TraceDeployCommands THEN
- out.String(" -> unable to send command");
- out.Ln
- END;
- RETURN
- ELSIF ~IP.AdrsEqual(hostAdr, adr) THEN
- res := - 1
- ELSIF (ack[0] # 'O') OR (ack[1] # 'K') OR (ack[2] # ':') THEN
- out.String(ack);
- out.Ln;
- out.Update;
- IF TraceDeployCommands THEN
- out.String(" -> error in command execution");
- out.Ln
- END;
- res := -3
- ELSIF TraceDeployCommands THEN
- out.String(" -> OK");
- out.Ln
- END
- END SendCommand;*)
- (**
- Import a Xilinx TCL board initialization file as an Oberon module suitable for use in the Zynq Bootloader.
- This command simply rewrites first sections of a TCL file, which are expected to be:
- - ps7_pll_init_data_*
- - ps7_clock_init_data_*
- - ps7_ddr_init_data_*
- - ps7_mio_init_data_*
- - ps7_peripherals_init_data_*
- where the * is 1_0, 2_0 or 3_0.
- These sections are placed in a module named FsblInit as matharray constants. These constants are then used
- by the Initializer of the bootloader.
- Syntax:
- ZynqTools.ImportTCL [-d=dir|--directory=dir] [-m=moduleName|--module=moduleName] boardName file ~
- board: name of the board
- file: TCL file name
- -d|--directory gives the output directory.
- -m|--module gives the module name (default TclInit).
- The output file is named Board.Module.Mos
- *)
- PROCEDURE ImportTCL * (context: Commands.Context);
- VAR
- board, outputFile, inputFile, moduleName: ARRAY 128 OF CHAR;
- options: Options.Options;
- inFile, outFile: Files.File;
- input: Files.Reader;
- output: Files.Writer;
- rewriter: TclRewriter;
- BEGIN
- NEW(options);
- options.Add('d', 'directory', Options.String);
- options.Add('m', 'module', Options.String);
- IF ~options.Parse(context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN END;
- IF ~context.arg.GetString(board) THEN
- context.error.String("Expected board name");
- context.error.Ln;
- context.result := Commands.CommandParseError;
- RETURN
- END;
- IF ~context.arg.GetString(inputFile) THEN
- context.error.String("Expected input TCL file");
- context.error.Ln;
- context.result := Commands.CommandParseError;
- RETURN
- END;
- IF ~options.GetString('module', moduleName) THEN
- COPY(TCLModuleName, moduleName)
- END;
- IF options.GetString('directory', outputFile) THEN
- IF outputFile[Strings.Length(outputFile) - 1] # '/' THEN
- Strings.AppendChar(outputFile, '/')
- END
- ELSE
- outputFile[0] := 0X
- END;
- Strings.Append(outputFile, board);
- Strings.Append(outputFile, '.');
- Strings.Append(outputFile, moduleName);
- Strings.Append(outputFile, '.Mos');
- inFile := Files.Old(inputFile);
- IF inFile = NIL THEN
- context.error.String("Could not open file '");
- context.error.String(inputFile);
- context.error.String("'.");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.OpenReader(input, inFile, 0);
- IF input = NIL THEN
- context.error.String("Cannot read file '");
- context.error.String(inputFile);
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- outFile := Files.New(outputFile);
- IF outFile = NIL THEN
- context.error.String("Could not open file '");
- context.error.String(outputFile);
- context.error.String("'.");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.OpenWriter(output, outFile, 0);
- IF output = NIL THEN
- context.error.String("Cannot write to file '");
- context.error.String(outputFile);
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.Register(outFile);
- NEW(rewriter, input, output);
- context.out.String("Importing TCL file '");
- context.out.String(inputFile);
- context.out.String("' (");
- context.out.String(board);
- context.out.String(") to '");
- context.out.String(outputFile);
- context.out.String("'.");
- context.out.Ln;
- context.out.Update;
- (* Generate module header *)
- output.String(TCLModuleHeadComment0);
- output.String(board);
- output.String(TCLModuleHeadComment1);
- output.Ln;
- output.String("MODULE ");
- output.String(moduleName);
- output.String(';');
- output.Ln;
- output.String('CONST');
- output.Ln;
- output.String(" mask_write * = ");
- output.Int(TCLMaskWrite, 0);
- output.String(";");
- output.Ln;
- output.String(" mask_poll * = ");
- output.Int(TCLMaskPoll, 0);
- output.String(';');
- output.Ln;
- output.String(" mask_delay * = ");
- output.Int(TCLMaskDelay, 0);
- output.String(';');
- output.Ln;
- output.String(" mwr_force * = ");
- output.Int(TCLMwrForce, 0);
- output.String(';');
- output.Ln;
- rewriter.Rewrite;
- (* Module Footer *)
- output.String("END ");
- output.String(TCLModuleName);
- output.String('.');
- output.Update;
- outFile.Close;
- inFile.Close
- END ImportTCL;
- (**
- * Generate a Zynq boot ROM.
- *
- * Creates a boot header with the specified options and add a binary image after it.
- *
- * ZynqTools.GenerateBootROM {-o outfile | -b boardName | -e encryption | --key AESkey | --keyFromEfuse | --keyFromRam | --inPlace | --userWord} input ~
- *)
- PROCEDURE GenerateBootROM * (context : Commands.Context);
- VAR
- header: ARRAY HeaderSize OF CHAR;
- buffer: ARRAY 1024 OF CHAR;
- input, output, board, key: ARRAY 128 OF CHAR;
- interrupts, registers: ARRAY 32 OF CHAR;
- opt: Options.Options;
- inFile, outFile: Files.File;
- in: Files.Reader;
- out: Files.Writer;
- userWord, read, size, wrote: LONGINT;
- encrypt, keyFromEFuse, keyFromRam, inPlace: BOOLEAN;
- BEGIN
- NEW(opt);
- opt.Add('o', 'outFile', Options.String);
- opt.Add('b', 'board', Options.String);
- opt.Add('e', 'encrypt', Options.Flag);
- opt.Add(0X, 'key', Options.String);
- opt.Add(0X, 'keyFromEfuse', Options.Flag);
- opt.Add(0X, 'keyFromRam', Options.Flag);
- opt.Add(0X, 'inPlace', Options.Flag);
- opt.Add(0X, 'userWord', Options.Integer);
- IF ~opt.Parse(context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN END;
- context.arg.String(input);
- IF ~opt.GetString("outFile", output) THEN
- output := "BOOT.BIN"
- END;
- IF opt.GetString('board', board) THEN
- board := "None"
- END;
- encrypt := opt.GetFlag('encrypt');
- IF opt.GetString('key', key) THEN
- IF encrypt THEN
- context.error.String("Cannot encrypt image without key");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END
- END;
- keyFromEFuse := opt.GetFlag('keyFromEfuse');
- keyFromRam := opt.GetFlag('keyFromRam');
- inPlace := opt.GetFlag('inPlace');
- IF ~opt.GetInteger('userWord', userWord) THEN
- userWord := 0
- END;
- IF encrypt & ~keyFromEFuse & ~keyFromRam THEN
- context.error.String("Cannot encrypt image without key source");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- inFile := Files.Old(input);
- IF inFile = NIL THEN
- context.error.String("Cannot open input file '");
- context.error.String(input);
- context.error.String("'");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.OpenReader(in, inFile, 0);
- outFile := Files.New(output);
- IF outFile = NIL THEN
- context.error.String("Cannot open output file '");
- context.error.String(output);
- context.error.String("'");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.OpenWriter(out, outFile, 0);
- context.out.String("Creating Zynq BootROM image...");
- size := inFile.Length();
- IF size > 30000H THEN
- context.error.String("Image size is too big."); context.error.Ln;
- context.error.String(" Maximum size: 30000H"); context.error.Ln;
- context.error.String(" Actual size: "); context.error.Hex(size, -5); context.error.String('H'); context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- FOR read := 0 TO 31 BY 4 DO
- interrupts[read] := 0FEX;
- interrupts[read + 1] := 0FFX;
- interrupts[read + 2] := 0FFX;
- interrupts[read + 3] := 0EAX;
- END;
- FOR read := 0 TO 31 BY 8 DO
- registers[read] := 0FFX;
- registers[read + 1] := 0FFX;
- registers[read + 2] := 0FFX;
- registers[read + 3] := 0FFX;
- registers[read + 4] := 0X;
- registers[read + 5] := 0X;
- registers[read + 6] := 0X;
- registers[read + 7] := 0X
- END;
- CreateBootHeader(userWord, size, 8C0H, 0, interrupts, registers, encrypt, keyFromEFuse, inPlace, header);
- out.Bytes(header, 0, HeaderSize);
- WHILE in.res = Streams.Ok DO
- in.Bytes(buffer, 0, 1024, read);
- out.Bytes(buffer, 0, read);
- INC(wrote, read)
- END;
- out.Update;
- IF wrote # size THEN
- context.error.String("Error: copied ");
- context.error.Int(wrote, 0);
- context.error.String("B from input file, but length is supposed to be ");
- context.error.Int(size, 0);
- context.error.String("B.");
- context.error.Ln;
- context.error.Update;
- context.result := Commands.CommandError;
- RETURN
- ELSE
- context.out.String("Copied ");
- context.out.Int(wrote, 0);
- context.out.String("/");
- context.out.Int(size, 0);
- context.out.String("B.");
- context.out.Ln
- END;
- context.out.String(" done");
- context.out.Ln;
- inFile.Close;
- Files.Register(outFile);
- outFile.Close;
- END GenerateBootROM;
- PROCEDURE ReplaceImageInBootROM * (context: Commands.Context);
- VAR
- block: ARRAY 1024 OF CHAR;
- imName, romName: ARRAY 128 OF CHAR;
- fIm, fRom, fOut: Files.File;
- im, rom: Files.Reader;
- out: Files.Writer;
- ofs, pos, read: LONGINT;
- BEGIN
- romName := "cfsbl/BOOT.BIN";
- imName := "Fsbl.Bin";
- context.out.String("Replacing image in '");
- context.out.String(romName);
- context.out.String("' by '");
- context.out.String(imName);
- context.out.String("'...");
- context.out.Ln;
- context.out.Update;
- fRom := Files.Old(romName);
- fIm := Files.Old(imName);
- fOut := Files.New("BOOT.BIN");
- IF fRom = NIL THEN
- context.error.String("Could not open ROM file");
- context.error.Ln;
- context.error.Update;
- context.result := Commands.CommandError;
- RETURN
- ELSIF fIm = NIL THEN
- context.error.String("Could not open image file");
- context.error.Ln;
- context.error.Update;
- context.result := Commands.CommandError;
- RETURN
- ELSIF fOut = NIL THEN
- context.error.String("Could not open output file");
- context.error.Ln;
- context.error.Update;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.OpenReader(rom, fRom, 0);
- Files.OpenReader(im, fIm, 0);
- Files.OpenWriter(out, fOut, 0);
- context.out.String(" Writing in 'BOOT.BIN'");
- context.out.Ln;
- context.out.Update;
- (*
- Read BootROM header:
- 1. Copy pre source-offset fields
- 2. Copy and remember source offset
- 3. Copy until source offset
- *)
- rom.Bytes(block, 0, 30H, read);
- ASSERT(read = 30H);
- out.Bytes(block, 0, read);
- rom.RawLInt(ofs);
- out.RawLInt(ofs);
- context.out.String(" Found image at location ");
- context.out.Hex(ofs, -8);
- context.out.Ln;
- context.out.Update;
- pos := 34H;
- WHILE pos < ofs DO
- rom.Bytes(block, 0, MIN(LEN(block), LONGINT(ofs) - pos), read);
- out.Bytes(block, 0, read);
- INC(pos, read);
- END;
- (* Copy image *)
- WHILE im.res = Streams.Ok DO
- im.Bytes(block, 0, LEN(block), read);
- out.Bytes(block, 0, read);
- END;
- Files.Register(fOut);
- fIm.Close;
- fRom.Close;
- fOut.Close;
- context.out.String(" done");
- context.out.Ln;
- END ReplaceImageInBootROM;
- (** Extract binary executable from BootROM image. Arguments: input output ~ *)
- PROCEDURE StripHeader*(context : Commands.Context);
- VAR
- block: ARRAY 1024 OF CHAR;
- romName, outName: ARRAY 128 OF CHAR;
- fRom, fOut: Files.File;
- rom: Files.Reader;
- out: Files.Writer;
- ofs, pos, read: LONGINT;
- BEGIN
- IF ~context.arg.GetString(romName) THEN
- context.error.String("Error: expected input and output files as parameters");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- IF ~context.arg.GetString(outName) THEN
- context.error.String("Error: expected output file name as parameter");
- context.error.Ln;
- context.result := Commands.CommandError;
- RETURN
- END;
- context.out.String("Removing BootROM header from '");
- context.out.String(romName);
- context.out.String("'...");
- context.out.Ln;
- context.out.Update;
- fRom := Files.Old(romName);
- fOut := Files.New(outName);
- IF fRom = NIL THEN
- context.error.String("Could not open ROM file");
- context.error.Ln;
- context.error.Update;
- context.result := Commands.CommandError;
- RETURN
- ELSIF fOut = NIL THEN
- context.error.String("Could not open output file");
- context.error.Ln;
- context.error.Update;
- context.result := Commands.CommandError;
- RETURN
- END;
- Files.OpenReader(rom, fRom, 0);
- Files.OpenWriter(out, fOut, 0);
- context.out.String(" Writing in 'out.bin'");
- context.out.Ln;
- context.out.Update;
- (*
- Read BootROM header:
- 1. Copy pre source-offset fields
- 2. Copy and remember source offset
- 3. Copy until source offset
- *)
- rom.Bytes(block, 0, 30H, read);
- ASSERT(read = 30H);
- rom.RawLInt(ofs);
- context.out.String(" Found image at location ");
- context.out.Hex(ofs, -8);
- context.out.Ln;
- context.out.Update;
- pos := 34H;
- WHILE pos < ofs DO
- rom.Bytes(block, 0, MIN(LEN(block), LONGINT(ofs) - pos), read);
- INC(pos, read)
- END;
- (* Copy image *)
- WHILE rom.res = Streams.Ok DO
- rom.Bytes(block, 0, LEN(block), read);
- out.Bytes(block, 0, read);
- END;
- Files.Register(fOut);
- fRom.Close;
- fOut.Close;
- context.out.String(" done");
- context.out.Ln;
- END StripHeader;
- (** Create a bootROM header from the given parameters. *)
- PROCEDURE CreateBootHeader (userWord, imageSize, imageStartAdr, imageLoadAdr: LONGINT; CONST interrupts, registers: ARRAY OF CHAR;
- encrypt, keyFromEFuse, inPlace: BOOLEAN; VAR header: ARRAY OF CHAR);
- CONST
- InterruptSize = 32;
- WidthDetection = LONGINT(0AA995566H);
- ImageId = LONGINT(0584C4E58H);
- KeyFromEFuse = LONGINT(0A5C3C5A3H);
- KeyFromRam = LONGINT(03A5C3C5AH);
- NoEncryption = 0H;
- ChecksumStart = 20H;
- ChecksumStop = 44H;
- MaxRegisterLength = 800H;
- RegisterEnd = 8A0H;
- VAR
- chk: LONGINT;
- i, pos: LONGINT;
- BEGIN
- ASSERT(LEN(header) >= 8C0H);
- (* Interrupt Vector *)
- Strings.Move(interrupts, 0, InterruptSize, header, pos);
- INC(pos, InterruptSize);
- (* Width Detection *)
- MoveRawInt(WidthDetection, header, pos);
- INC(pos, 4);
- (* Image Identification *)
- MoveRawInt(ImageId, header, pos);
- INC(pos, 4);
- (* Encryption *)
- IF encrypt & keyFromEFuse THEN
- MoveRawInt(KeyFromEFuse, header, pos)
- ELSIF encrypt THEN
- MoveRawInt(KeyFromRam, header, pos)
- ELSE
- MoveRawInt(NoEncryption, header, pos)
- END;
- INC(pos, 4);
- (* User Defined word *)
- MoveRawInt(userWord, header, pos);
- INC(pos, 4);
- (* Source Offset *)
- ASSERT(imageStartAdr >= 8C0H);
- ASSERT(imageStartAdr MOD 64 = 0);
- MoveRawInt(imageStartAdr, header, pos);
- INC(pos, 4);
- (* Length of image *)
- ASSERT(imageSize <= 30000H);
- IF ~inPlace THEN
- MoveRawInt(imageSize, header, pos);
- ELSE
- MoveRawInt(0, header, pos);
- END;
- INC(pos, 4);
- (* FSBL Load Address *)
- MoveRawInt(0, header, pos);
- INC(pos, 4);
- (* Start of Execution *)
- IF inPlace THEN
- ASSERT(imageLoadAdr < 32 * 1024 * 1024);
- ELSIF encrypt THEN
- ASSERT(imageLoadAdr = 0);
- ELSE
- ASSERT(imageLoadAdr >= 0);
- ASSERT(imageLoadAdr < 30000H);
- END;
- MoveRawInt(imageLoadAdr, header, pos);
- INC(pos, 4);
- (* Total Image Length *)
- IF ~inPlace THEN
- MoveRawInt(imageSize, header, pos);
- ELSE
- MoveRawInt(0, header, pos);
- END;
- INC(pos, 4);
- (* QSPI Config Word *)
- MoveRawInt(0, header, pos);
- INC(pos, 4);
- (* Header Checksum *)
- FOR i := ChecksumStart TO ChecksumStop BY 4 DO
- chk := chk + ReadRawInt(header, i)
- END;
- MoveRawInt(Invert(chk), header, pos);
- INC(pos, 4);
- (* Unused *)
- ASSERT(pos = 4CH);
- WHILE pos < 0A0H DO
- MoveRawInt(0, header, pos);
- INC(pos, 4)
- END;
- (* Registers *)
- ASSERT(pos = 0A0H);
- ASSERT(LEN(registers) <= MaxRegisterLength);
- Strings.Move(registers, 0, LEN(registers), header, pos);
- INC(pos, LEN(registers));
- WHILE pos < RegisterEnd DO
- MoveRawInt(LONGINT(0FFFFFFFFH), header, pos);
- INC(pos, 4);
- MoveRawInt(LONGINT(0), header, pos);
- INC(pos, 4);
- END;
- (* Unused *)
- WHILE pos < HeaderSize DO
- MoveRawInt(LONGINT(0FFFFFFFFH), header, pos);
- INC(pos, 4)
- END
- END CreateBootHeader;
- (** Insert a raw integer in the array at location [ofs .. ofs + 4). *)
- PROCEDURE MoveRawInt (int: LONGINT; VAR dest: ARRAY OF CHAR; ofs: LONGINT);
- BEGIN
- dest[ofs] := CHR(int MOD 100H);
- dest[ofs + 1] := CHR(int DIV 100H MOD 100H);
- dest[ofs + 2] := CHR(int DIV 10000H MOD 100H);
- dest[ofs + 3] := CHR(int DIV 1000000H MOD 100H)
- END MoveRawInt;
- (** Get an integer from the array at positions [ofs .. ofs + 4). *)
- PROCEDURE ReadRawInt (CONST src: ARRAY OF CHAR; ofs: LONGINT): LONGINT;
- VAR
- adr: LONGINT;
- BEGIN
- adr := LONGINT(ORD(src[ofs])) + LONGINT(ORD(src[ofs + 1])) * 100H + LONGINT(ORD(src[ofs + 2])) * 10000H + LONGINT(ORD(src[ofs + 3])) * 1000000H;
- RETURN adr
- END ReadRawInt;
- (** Invert bits of a LONGINT *)
- PROCEDURE Invert (val: LONGINT): LONGINT;
- BEGIN
- RETURN SYSTEM.VAL(LONGINT, -SYSTEM.VAL(SET, ADDRESS(val)))
- END Invert;
- END ZynqTools.
- ZynqTools.GenerateBootROM Fsbl.Bin ~
- ZynqTools.GenerateBootROM out.bin ~
- FoxARMInstructionSet.Disassemble BOOT.BIN ~
- FoxARMInstructionSet.Disassemble cfsbl/BOOT.BIN ~
- FoxARMInstructionSet.Disassemble Fsbl.Bin -a=2ffc0H~
- FoxARMInstructionSet.Disassemble C:/Users/tim/SDbackup/BOOT.BIN ~
- ZynqTools.ReplaceImageInBootROM cfsbl/BOOT.BIN Fsbl.Bin ~
- ZynqTools.StripHeader cfsbl/BOOT.BIN out.bin ~
- ZynqTools.Deploy -s A2.Bin ~
- ZynqTools.ImportTCL -d=ZBL:/ Zedboard boot/ps7_init.tcl ~
- ZynqTools.ImportTCL -d=ZBL:/ Zybo Zybo-boot/ps7_init.tcl ~
- ZynqTools.ImportTCL -d=basel/bootloader KRM KRM-boot/ps7_init.tcl ~
|