Selaa lähdekoodia

moved TRM tools from OC to trunk

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@6337 8c9fc860-2736-0410-a75d-ab315db34111
felixf 10 vuotta sitten
vanhempi
commit
ede77e921b
2 muutettua tiedostoa jossa 1068 lisäystä ja 0 poistoa
  1. BIN
      source/Fox.Tool
  2. 1068 0
      source/FoxTRMTools.Mod

BIN
source/Fox.Tool


+ 1068 - 0
source/FoxTRMTools.Mod

@@ -0,0 +1,1068 @@
+MODULE FoxTRMTools; (** AUTHOR ""; PURPOSE ""; *)
+
+IMPORT Files,Commands,Options,Strings,Basic := FoxBasic, Diagnostics, Random, Machine, ActiveCells := FoxActiveCells, Streams, WinApplications, Hardware := FoxHardware,
+		BitSets,ObjectFile;
+
+VAR
+	random: Random.Generator;
+
+	PROCEDURE PatchSpartan6(this: ARRAY OF CHAR; VAR result: ARRAY OF CHAR; line: LONGINT);
+
+		(*
+			decode 36 bits 2 instruction big endian format
+				35 ... 18				17 .. 0
+				ins2_bit17 ... ins2_bit0 ins1_bit17 .. ins1_bit0
+
+			to 2 x 18 bits instructions in the following form
+				35			34			33..16					15..0
+				ins2_bit17, ins2_bit16 ins1_bit17 ... inst1_bit0 ins2_bit15.. ins2_bit_0
+
+		*)
+
+	VAR inpos, outpos, i, bits, i1, i2, val: LONGINT;
+
+		PROCEDURE ReadInt(): LONGINT;
+		VAR c: CHAR;
+		BEGIN
+			c := this[inpos]; INC(inpos);
+			CASE c OF
+				'0' .. '9': RETURN ORD(c)- ORD('0')
+				|'A'..'F': RETURN ORD(c) - ORD('A') + 10
+				|'a'..'f': RETURN ORD(c) - ORD('a') + 10
+			ELSE HALT(100) (* to be on the safe side *)
+			END;
+		END ReadInt;
+
+		PROCEDURE WriteInt(i: LONGINT);
+		VAR c: CHAR;
+		BEGIN
+			IF i < 0AH THEN c := CHR(i + ORD('0'))
+			ELSIF i < 10H THEN c := CHR(i-10 + ORD('A'))
+			ELSE HALT(100)
+			END;
+			result[outpos] := c; INC(outpos);
+		END WriteInt;
+
+	BEGIN
+		(* decode *)
+		inpos := 0; outpos := 0;
+		WHILE (this[inpos] # 0X) & (this[inpos] <=" ") DO INC(inpos) END; (* skip spaces, if any *)
+		i1 := 0; i2 := 0;
+
+		IF this[inpos] # 0X THEN
+			i2 := 0;
+			(* upper most 16 bits of i2 *)
+			FOR i := 0 TO 3 DO
+				i2 := i2 * 10H + ReadInt();
+			END;
+			(* lower most 2 bits of i2 *)
+			val := ReadInt();
+			i2 := i2 * 4 + val DIV 4;
+			(* upper most 2 bits of i1 *)
+			i1 := val MOD 4;
+			(* lower most 16 bits of i2 *)
+			FOR i := 0 TO 3 DO
+				i1 := i1 * 10H + ReadInt();
+			END;
+
+			(* make sure that no meaningful code is written to the "forbidden" islands *)
+			ASSERT((line MOD 512 < 480) OR (line MOD 512 > 487) OR (i1 = 0) & (i2=0) OR (this = "fffffffff"));
+
+			i := 0;
+			(* upper most 2 bits of i1 and i2 *)
+			WriteInt( (i2 DIV  10000H) * 4 + (i1 DIV 10000H) );
+			i2 := i2 MOD 10000H; i1 := i1 MOD 10000H;
+			(* remaining 16 bits of i1 *)
+			bits := 10000H;
+			FOR i := 0 TO 3 DO
+				i1 := i1 MOD bits; bits := bits DIV 10H;
+				WriteInt(i1 DIV bits);
+			END;
+			(* remaining 16 bits of i2 *)
+			bits := 10000H;
+			FOR i := 0 TO 3 DO
+				i2 := i2 MOD bits; bits := bits DIV 10H;
+				WriteInt(i2 DIV bits);
+			END;
+		END;
+		result[outpos] := 0X;
+
+	END PatchSpartan6;
+
+	(*trm code file is split into columns. baseDiv words per line, line distributed onto numBase words.*)
+	PROCEDURE SplitColumns* (CONST source,target: ARRAY OF CHAR; instructionWidth, numBase, baseDiv: LONGINT;diagnostics: Diagnostics.Diagnostics): BOOLEAN;
+	VAR
+		i,j,k,numReadNibbles,nibble,payloadInLeadingNibble,unCutWordLength:LONGINT;
+		files: ARRAY 5 OF Files.File;
+		writers: ARRAY 5 OF Files.Writer;
+		currFileName: Files.FileName;
+		base:  BitSets.BitSet;
+		word: BitSets.BitSet;
+		reader: Files.Reader;
+		inputFileName: ARRAY 50 OF CHAR;
+		inputFile: Files.File;
+		line: ARRAY 128 OF CHAR;
+
+	BEGIN
+		(*generate multiple outupt files. horizontal split into blocks later using splitfiles*)
+		FOR i:=0 TO numBase-1 DO(*create filenames*)
+			(*copy name. add '.base i' to distinguish*)
+			COPY(target,currFileName);
+			Strings.Append(currFileName,"base");
+			Basic.AppendNumber(currFileName, i);
+			files[i]:= Files.New(currFileName);
+			Files.OpenWriter(writers[i],files[i],0);
+		END;
+
+		unCutWordLength:= (numBase*36) DIV (baseDiv); (*a division of the base row may be longer than the actual word length*)
+		payloadInLeadingNibble:=instructionWidth MOD 4;
+		IF payloadInLeadingNibble=0 THEN payloadInLeadingNibble:=payloadInLeadingNibble+4; END;
+		numReadNibbles:=instructionWidth DIV 4;
+		IF payloadInLeadingNibble<4 THEN
+			INC(numReadNibbles);
+		END;
+		COPY(source, inputFileName);
+		inputFile := Files.Old(inputFileName);
+		IF inputFile= NIL THEN
+			diagnostics.Error(inputFileName,Diagnostics.Invalid,Diagnostics.Invalid,"could not open file");
+			RETURN FALSE
+		END;
+		Files.OpenReader( reader,inputFile,0);
+		NEW(base,numBase*36);
+		NEW(word,instructionWidth);
+		WHILE reader.Available()>0 DO (*assumes number of words is a multiple of baseDiv. make sure in static linker*)
+			
+			base.Zero;
+			(*read a BASE line*)
+			FOR k:=0 TO baseDiv-1 DO 
+				(*read a word into the base*)
+				word.Zero;
+				j:=0;
+				(*read 1 word from row into BASE bitset*)
+				reader.LnEOT(line);
+				(*TRACE(line);
+				TRACE(payloadInLeadingNibble);
+				TRACE(line[0]);*)
+				(*read first nibble, removes padding*)
+				nibble:=ObjectFile.CharacterToNibble(line[0]);
+				j:=j+payloadInLeadingNibble;
+				word.SetBits(instructionWidth-j,payloadInLeadingNibble, nibble);
+				
+				(*read rest*)
+				FOR i:=1 TO numReadNibbles-1 DO
+					(*TRACE(line[i]);*)
+					nibble:=ObjectFile.CharacterToNibble(line[i]);
+					j:=j+4;
+					word.SetBits(instructionWidth-j,4,nibble);
+				END;
+				(*note there may be gaps because unCut is larger than insW*)
+				BitSets.CopyBits(word,0,base,k*unCutWordLength,instructionWidth);
+			END;
+			FOR j:= 0 TO numBase-1 DO (*divide base into the columns*)
+				(*write 36 bits to appropriate file*)	(*writing msb first*)	
+				FOR k:=8 TO 0 BY -1 DO
+					writers[j].Char(ObjectFile.NibbleToCharacter(base.GetBits((j)*36+k*4,4) ) );
+				END;
+				writers[j].Ln;
+			END;
+		END;
+		FOR i:=0 TO numBase-1 DO
+			writers[i].Update;
+			Files.Register(files[i]);
+		END;
+		RETURN TRUE
+	END SplitColumns;
+
+
+
+
+
+	PROCEDURE DoSplitFiles*(CONST source, dest, extension: ARRAY OF CHAR; blocks, blockSize: LONGINT; verbose,strided,patchSpartan6: BOOLEAN; diagnostics: Diagnostics.Diagnostics): BOOLEAN;
+	VAR line: LONGINT; fileName: Files.FileName; oldFile: Files.File;
+		newFiles: POINTER TO ARRAY OF Files.File;
+		reader: Files.Reader;
+		writers: POINTER TO ARRAY OF Files.Writer;
+		x: ARRAY 128 OF CHAR;
+		i,fileNumber: LONGINT;
+		linewidth: LONGINT;
+
+		PROCEDURE GetFileName(index: LONGINT; VAR fileName: ARRAY OF CHAR);
+		BEGIN
+			COPY(dest,fileName);
+			Basic.AppendNumber(fileName, index);
+			Files.JoinExtension(fileName,extension,fileName);
+		END GetFileName;
+
+
+
+	BEGIN
+	
+		TRACE(source);
+	
+		COPY(source, fileName);
+		oldFile := Files.Old(fileName);
+		IF oldFile = NIL THEN
+			diagnostics.Error(fileName,Diagnostics.Invalid,Diagnostics.Invalid,"could not open file");
+			RETURN FALSE
+		END;
+		Files.OpenReader( reader,oldFile,0);
+
+		NEW(newFiles, blocks);
+		NEW(writers, blocks);
+
+		FOR i := 0 TO blocks-1 DO
+			GetFileName(i,fileName);
+			newFiles[i] := Files.New(fileName);
+			IF newFiles[i]= NIL THEN
+				diagnostics.Error(fileName,Diagnostics.Invalid,Diagnostics.Invalid,"could not open file");
+				RETURN FALSE
+			ELSE
+				Files.OpenWriter(writers[i],newFiles[i],0);
+			END;
+			IF verbose THEN
+				diagnostics.Information(fileName,Diagnostics.Invalid,Diagnostics.Invalid,"file generated");
+			END;
+		END;
+		(*If strided: read line by line, fill round robin into the output files*)
+		line := 0;
+		WHILE (line < blocks*blockSize) & (reader.Available()>0) DO
+			IF strided THEN fileNumber := line MOD blocks ELSE fileNumber := line DIV blockSize END;
+			reader.LnEOT(x);
+			IF linewidth = 0 THEN linewidth := Strings.Length(x) END;
+			IF patchSpartan6 THEN PatchSpartan6(x,x, line) END;
+			writers[fileNumber].String(x); writers[fileNumber].Ln;
+			INC(line);
+		END;
+		ASSERT((linewidth = 8) OR (linewidth =9) OR (linewidth = 0));
+		WHILE line < blocks*blockSize DO
+			IF strided THEN fileNumber := line MOD blocks ELSE fileNumber := line DIV blockSize END;
+			FOR i := 0 TO linewidth-1 DO
+				writers[fileNumber].Char("0");
+			END;
+			writers[fileNumber].Ln;
+			INC(line);
+		END;
+		IF reader.Available()>0 THEN
+			diagnostics.Warning(source,Diagnostics.Invalid,Diagnostics.Invalid,"source file truncated");
+		END;
+		FOR i := 0 TO blocks-1 DO
+			writers[i].Update; Files.Register(newFiles[i])
+		END;
+		RETURN TRUE
+	END DoSplitFiles;
+
+
+	PROCEDURE SplitFiles* (context: Commands.Context);
+	VAR options: Options.Options;
+		sourceName, name, extension: Files.FileName;
+		blocks: LONGINT;
+		blockSize: LONGINT;
+		strided: BOOLEAN;
+		diagnostics: Diagnostics.StreamDiagnostics;
+		done: BOOLEAN;
+	BEGIN
+		NEW (options);
+		options.Add('b',"blocks",Options.Integer);
+		options.Add('s',"blockSize",Options.Integer);
+		options.Add('S',"strided",Options.Flag);
+		options.Add(0X,"patchSpartan6", Options.Flag);
+
+		IF ~options.Parse (context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN; END;
+		IF ~options.GetInteger("blocks",blocks) THEN blocks := 1 END;
+		IF ~options.GetInteger("blockSize",blockSize) THEN blockSize := 1024 END;
+		strided := options.GetFlag("strided");
+		NEW(diagnostics,context.out);
+
+		done := TRUE;
+		WHILE done & context.arg.GetString (name) DO
+			Files.SplitExtension(name,sourceName,extension);
+			done := DoSplitFiles(name, sourceName, extension, blocks, blockSize, TRUE, strided, options.GetFlag("patchSpartan6"), diagnostics);
+		END;
+	END SplitFiles;
+
+	PROCEDURE GenerateTestFile*(context: Commands.Context);
+	VAR fileName, sourceFileName: Files.FileName; size, value: LONGINT; options: Options.Options; file: Files.File; writer: Files.Writer; i: LONGINT; i1, i2: LONGINT;
+		 source: Files.File; reader: Files.Reader;
+
+		PROCEDURE WriteInt(i: LONGINT);
+		VAR c: CHAR;
+		BEGIN
+			IF i < 0AH THEN c := CHR(i + ORD('0'))
+			ELSIF i < 10H THEN c := CHR(i-10 + ORD('A'))
+			ELSE HALT(100)
+			END;
+			writer.Char(c);
+		END WriteInt;
+
+		PROCEDURE WriteHex36(i1, i2: LONGINT);
+		VAR i,j: LONGINT; c: ARRAY 9 OF LONGINT;
+		BEGIN
+			FOR i := 0 TO 3 DO
+				c[j] := i1 MOD 10H; i1 := i1 DIV 10H; INC(j);
+			END;
+			c[j] := i1 + (i2 MOD 4H) * 4H; i2 := i2 DIV 4H;
+			INC(j);
+			FOR i := 0 TO 3 DO
+				c[j] := i2 MOD 10H; i2 := i2 DIV 10H; INC(j);
+			END;
+
+			FOR j := 8 TO 0 BY -1 DO WriteInt(c[j]) END; writer.Ln;
+		END WriteHex36;
+
+	BEGIN
+		NEW(options);
+		options.Add("s","size",Options.Integer);
+		options.Add("v","value",Options.Integer);
+		options.Add("r","random",Options.Flag);
+		options.Add("f","sourceFile",Options.String);
+
+		IF ~options.Parse (context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN; END;
+		IF ~options.GetInteger("size",size) THEN size := 4096 END;
+		IF ~options.GetInteger("value",value) THEN value := 0 END;
+		IF options.GetString("sourceFile", sourceFileName) THEN
+			source := Files.Old(sourceFileName);
+			NEW(reader, source, 0);
+			ASSERT(source # NIL);
+		END;
+
+		IF context.arg.GetString(fileName) THEN
+			file := Files.New(fileName);
+			ASSERT(file # NIL);
+			NEW(writer, file, 0);
+			IF source = NIL THEN
+				FOR i := 0 TO size -1 DO
+					IF options.GetFlag("random") THEN
+						i1 := random.Dice(40000H);
+						i2 := random.Dice(40000H);
+					ELSE
+					i1 := value; i2 := value;
+					END;
+					WriteHex36(i1, i2);
+				END;
+			ELSE
+				WHILE reader.Available()>0 DO
+					reader.RawLInt(i1); reader.RawLInt(i2);
+					WriteHex36(i1,i2);
+				END;
+			END;
+			writer.Update;
+			Files.Register(file);
+			context.out.String("written file "); context.out.String(fileName); context.out.Ln;
+		END;
+
+	END GenerateTestFile;
+
+	PROCEDURE CompareFiles*(context: Commands.Context);
+	VAR f1,f2,f3: Files.File; name1, name2, matrixname: Files.FileName; r1, r2: Files.Reader;  x,y: ARRAY 32 OF CHAR; i: LONGINT; line1, line2: LONGINT;
+		matrix: ARRAY 16 OF ARRAY 16 OF LONGINT; j: LONGINT; p1, p2: LONGINT; writer: Files.Writer;
+
+		PROCEDURE WriteBit(x: LONGINT);
+		BEGIN
+			IF ODD(x) THEN context.out.Char("1") ELSE context.out.Char("0") END;
+		END WriteBit;
+
+		PROCEDURE WriteBits(c: CHAR);
+		VAR v: LONGINT;
+		BEGIN
+			CASE c OF
+				'0' .. '9': v :=  ORD(c)- ORD('0')
+				|'A'..'F': v :=  ORD(c) - ORD('A') + 10
+				|'a'..'f': v :=  ORD(c) - ORD('a') + 10
+			ELSE HALT(100) (* to be on the safe side *)
+			END;
+			WriteBit(ORD(c) DIV 8);
+			WriteBit(ORD(c) DIV 4);
+			WriteBit(ORD(c) DIV 2);
+			WriteBit(ORD(c));
+
+		END WriteBits;
+
+		PROCEDURE Value(c: CHAR): LONGINT;
+		BEGIN
+			CASE c OF
+				'0' .. '9': RETURN  ORD(c)- ORD('0')
+				|'A'..'F': RETURN  ORD(c) - ORD('A') + 10
+				|'a'..'f': RETURN  ORD(c) - ORD('a') + 10
+			ELSE HALT(100) (* to be on the safe side *)
+			END;
+
+		END Value;
+
+
+		PROCEDURE WriteLn;
+		BEGIN
+			context.out.Ln;
+		END WriteLn;
+
+	BEGIN
+		IF context.arg.GetString(name1) & context.arg.GetString(name2) &  context.arg.GetString(matrixname) THEN
+			f1 := Files.Old(name1); f2 := Files.Old(name2); f3 := Files.New(matrixname);
+			NEW(r1,f1,0); NEW(r2,f2,0); NEW(writer, f3,0);
+			WHILE (r1.Available() > 0) & (r2.Available() > 0) DO
+				r1.LnEOT(x);r2.LnEOT(y);
+
+				IF (line1 MOD 512 >= 480) & (line1 MOD 512 <= 487) THEN
+					p1 := (Value(x[0]) DIV 4H)*4H+Value(x[4]) MOD 4H;
+					p2 := (Value(y[0]) DIV 4H)*4H+Value(y[4]) MOD 4H;
+					context.out.Int(line1,1); context.out.Ln; context.out.Update;
+					ASSERT(Value(x[0]) MOD 4 = Value(y[0]) MOD 4);
+					ASSERT(Value(x[4]) DIV 4 = Value(y[4]) DIV 4);
+					INC(matrix[p1, p2]);
+				ELSE
+					ASSERT(x = y);
+				END;
+				INC(line1);
+
+
+				(*
+				IF (line1 MOD 512 = 480)  THEN
+					context.out.Int(line1,1); context.out.String(":");
+					WHILE line1 MOD 512 < 487 DO
+					r1.LnEOT(x);
+					i := 0;
+					WHILE (x[i] # 0X) DO
+						IF i IN {0,4} THEN
+						WriteBits(x[i]);
+						ELSE
+						context.out.Char(x[i]);
+						END;
+						context.out.String("|");
+						INC(i);
+					END;
+					context.out.String(" ");
+					INC(line1);
+					END;
+
+					WriteLn;
+					context.out.Int(line2,1); context.out.String(":");
+					WHILE line2 MOD 512 < 487 DO
+					r2.LnEOT(y);
+					i := 0;
+					WHILE (y[i] # 0X) DO
+						IF i IN {0,4} THEN
+						WriteBits(y[i]);
+						ELSE context.out.Char(y[i]);
+						END;
+						context.out.String("|");
+						INC(i)
+					END;
+					context.out.String(" ");
+					INC(line2);
+					END;
+
+					WriteLn;
+					WriteLn;
+				ELSE INC(line1); INC(line2);r1.LnEOT(x);r2.LnEOT(y);
+
+				END;
+				*)
+			END;
+
+
+			FOR i := 0 TO 15 DO
+			FOR j := 0 TO 15 DO
+				writer.Int(matrix[i,j],1); writer.String(" ");
+				context.out.Int(matrix[i,j],1); context.out.String(" ");
+			END;
+				context.out.Ln;
+				writer.Ln;
+			END;
+			writer.Update;
+			Files.Register(f3);
+		END;
+	END CompareFiles;
+
+	PROCEDURE SameFiles(CONST filename1, filename2: ARRAY OF CHAR): BOOLEAN;
+	VAR
+		file1, file2 : Files.File; reader1, reader2 : Files.Reader; ch1, ch2 : CHAR;
+	BEGIN
+		file1 := Files.Old(filename1);
+		IF (file1# NIL) THEN
+			file2 := Files.Old(filename2);
+			IF (file2 # NIL) THEN
+				IF (file1.Length() = file2.Length()) THEN
+					NEW(reader1, file1, 0);
+					NEW(reader2, file2, 0);
+					REPEAT
+						reader1.Char(ch1);
+						reader2.Char(ch2);
+					UNTIL (ch1 # ch2) OR (reader1.res # Files.Ok) OR (reader2.res # Files.Ok);
+
+					IF (ch1 = ch2) & (reader1.res = reader2.res) & (reader1.res = Streams.EOF) THEN
+						RETURN TRUE;
+					ELSE
+						RETURN FALSE;
+					END;
+				ELSE
+					RETURN FALSE;
+				END;
+			ELSE
+				RETURN FALSE;
+			END;
+		ELSE
+			RETURN FALSE;
+		END;
+	END SameFiles;
+
+	PROCEDURE IsEngine(instance: ActiveCells.Instance): BOOLEAN;
+	VAR type: ActiveCells.Type;
+	BEGIN
+		type := instance.instanceType;
+		IF type.scope.name = "Engines" THEN
+			IF type.name = "Adder" THEN RETURN TRUE
+			ELSE RETURN FALSE (* unknown engine in Engines module *)
+			END;
+		ELSE (* not in Engines module *)
+			RETURN FALSE
+		END;
+	END IsEngine;
+
+	PROCEDURE DeleteFiles(CONST fileSelectionMask: ARRAY OF CHAR; context: Commands.Context; VAR res: LONGINT);
+	VAR
+		enum: Files.Enumerator;
+		flags: SET;
+		time, date, size: LONGINT;
+		name: Files.FileName;
+	BEGIN
+		NEW(enum);
+		enum.Open(fileSelectionMask,{});
+
+		res := 0;
+		WHILE (res = 0) & enum.GetEntry(name,flags,time,date,size) DO
+			IF ~(Files.Directory IN flags) THEN
+				context.out.String("deleting file "); context.out.String(name); context.out.String(" ...");
+				Files.Delete(name,res);
+				IF res = 0 THEN context.out.String(" Ok"); context.out.Ln; context.out.Update;
+				ELSE
+					context.error.String("failed to delete file "); context.error.String(name); context.error.String(", res="); context.error.Int(res,0); context.error.Ln; context.error.Update;
+				END;
+			END;
+		END;
+	END DeleteFiles;
+
+	(* Execute a command line command given a path *)
+	PROCEDURE ExecuteInPath(CONST cmd: ARRAY OF CHAR; CONST path: ARRAY OF CHAR; VAR res: LONGINT);
+	VAR
+		file: Files.File;
+		w: Files.Writer;
+	BEGIN
+		file := Files.New("temp.bat"); ASSERT(file # NIL);
+		Files.Register(file);
+		NEW(w,file,0);
+		w.String("cd \"); w.Ln;
+		w.String("cd ");
+		w.String(path); w.Ln;
+		w.String(cmd); w.Ln;
+		w.Update;
+		file.Close;
+
+		res := WinApplications.Call("temp.bat","");
+	END ExecuteInPath;
+
+	PROCEDURE SizeInBlocks(sizeInUnits, blockSize: LONGINT): LONGINT;
+	BEGIN
+		RETURN (sizeInUnits-1) DIV blockSize +1
+	END SizeInBlocks;
+
+	(* Get the execution status of an impact batch command
+
+		cmdPath - the path where impact command was issued
+		success - TRUE for success
+		res - result code (0 in case if status was determined successfully)
+	*)
+	PROCEDURE GetImpactCmdStatus(CONST cmdPath: ARRAY OF CHAR; VAR success: BOOLEAN; VAR res: LONGINT);
+	VAR
+		file: Files.File;
+		fileName: Files.FileName;
+		r: Files.Reader;
+		str: ARRAY 128 OF CHAR;
+		overwrite: BOOLEAN;
+		k: LONGINT;
+	BEGIN
+		res := 0;
+
+		Files.JoinPath(cmdPath,"_impactbatch.log",fileName);
+
+
+		file := Files.Old(fileName);
+		IF file = NIL THEN res := -1; RETURN; END;
+		NEW(r,file,0);
+
+		REPEAT
+			r.Ln(str);
+			(*success := str = "'1': Programmed successfully.";*)
+			k := Strings.Find(str,0,':');
+			IF k > 0 THEN
+				Strings.Delete(str,0,k+1);
+				Strings.TrimWS(str);
+				success := str = "Programmed successfully.";
+			END;
+		UNTIL success OR (r.res = Streams.EOF);
+
+	FINALLY
+		file.Close();
+	END GetImpactCmdStatus;
+
+	(**
+		Command for building ActiveCells hardware
+
+		syntax:
+
+		BuildHardware -p=platformId -f=specificationName ~
+
+		where
+
+		platformId - a string with an ActiveCells platform ID
+		specificationName - a string with the name of hardware specification (file name without ".spec" extension)
+	*)
+	PROCEDURE BuildHardware*(context: Commands.Context);
+	CONST BuiltPrefix = "built-";
+	VAR
+		options: Options.Options;
+		specName, builtSpecName, specPath, hwPath, str: Files.FileName;
+		platformId: Files.FileName;
+		spec, builtSpec: ActiveCells.Specification;
+		instance: ActiveCells.Instance;
+		description: Hardware.Description;
+		changes: BOOLEAN;
+
+		res: LONGINT;
+		diagnostics: Diagnostics.StreamDiagnostics;
+
+		PROCEDURE Exists(CONST path, name, ext: ARRAY OF CHAR): BOOLEAN;
+		VAR fileName: Files.FileName;
+		BEGIN
+			Files.JoinPath(path,name,fileName);
+			Files.JoinExtension(fileName,ext,fileName);
+			RETURN Files.Old(fileName) # NIL;
+		END Exists;
+
+		PROCEDURE CopyAsBuilt(CONST path, name, ext: ARRAY OF CHAR; CONST dstPath: ARRAY OF CHAR; VAR res: LONGINT);
+		VAR
+			overwrite: BOOLEAN;
+			fileName, builtFileName: Files.FileName;
+		BEGIN
+			Files.JoinExtension(name,ext,fileName);
+			Files.JoinPath(path,fileName,fileName);
+
+			Strings.Concat(BuiltPrefix,name,builtFileName);
+			Files.JoinExtension(builtFileName,ext,builtFileName);
+			Files.JoinPath(dstPath,builtFileName,builtFileName);
+
+			overwrite := TRUE;
+			Files.CopyFile(fileName,builtFileName,overwrite,res);
+			IF res # 0 THEN context.error.String("failed to copy file "); context.error.String(fileName); context.error.String(" to "); context.error.String(builtFileName); context.error.Ln; context.error.Update; RETURN; END;
+		END CopyAsBuilt;
+
+		PROCEDURE SameAsBuilt(CONST path, name, ext: ARRAY OF CHAR): BOOLEAN;
+		VAR fileName, builtFileName: Files.FileName;
+		BEGIN
+			Files.JoinExtension(name,ext,fileName);
+			Files.JoinPath(path,fileName,fileName);
+
+			Strings.Concat(BuiltPrefix,name,builtFileName);
+			Files.JoinExtension(builtFileName,ext,builtFileName);
+			Files.JoinPath(path,builtFileName,builtFileName);
+
+			RETURN SameFiles(fileName,builtFileName);
+		END SameAsBuilt;
+
+		PROCEDURE PatchAndConfigure(VAR res: LONGINT);
+		VAR
+			insBlockSize, dataBlockSize: LONGINT;
+			file: Files.File;
+			w: Files.Writer;
+			iBlock, numBlocks: LONGINT;
+			k: LONGINT;
+			blockName, instanceName: Files.FileName;
+			tempOut, success: BOOLEAN;
+			numPatched: LONGINT;
+		BEGIN
+			(* instruction and data memory block sizes *)
+			(*! query these parameters from FoxActiveCells!!! *)
+			IF platformId = "ML505" THEN insBlockSize := 2048; dataBlockSize := 1024;
+			ELSIF platformId = "AVSP6LX75T" THEN insBlockSize := 1024; dataBlockSize := 512;
+			ELSIF platformId = "TL400" THEN insBlockSize := 1024; dataBlockSize := 512;
+			ELSIF platformId = "Spartan_XC3S200" THEN insBlockSize := 1024; dataBlockSize := 512;
+			ELSIF platformId = "Spartan_XC3S500e" THEN insBlockSize := 1024; dataBlockSize := 512;
+			ELSE HALT(100);
+			END;
+
+			file := Files.New("temp.bat"); ASSERT(file # NIL);
+			NEW(w,file,0);
+			w.String("cd \"); w.Ln;
+			w.String("cd "); w.String(hwPath); w.Ln;
+
+			tempOut := TRUE;
+			numPatched := 0;
+
+			FOR k := 0 TO spec.instances.Length()-1 DO
+
+				instance := spec.instances.GetInstance(k);
+				IF ~IsEngine(instance) THEN
+
+					(** process instruction memory files *)
+					instance.GetFullName(instanceName,NIL);
+					Files.JoinExtension(instanceName,ActiveCells.CodeFileExtension,instanceName);
+					iBlock := 0; numBlocks := SizeInBlocks(instance.instructionMemorySize,insBlockSize);
+					WHILE iBlock < numBlocks DO
+
+						ActiveCells.NormalizeName(instanceName,blockName);
+						Basic.AppendNumber(blockName,iBlock);
+						Files.JoinExtension(blockName,"mem",blockName);
+
+						IF ~SameAsBuilt(hwPath,blockName,"") THEN
+
+							IF ~Exists(hwPath,blockName,"") THEN res := -1; diagnostics.Error(blockName,Diagnostics.Invalid,Diagnostics.Invalid," file does not exist"); RETURN; END;
+
+							w.String("data2mem -bm "); ActiveCells.WriteName(w,spec,"","bd"); w.String(".bmm  -bt  .\");
+							IF tempOut THEN w.String(builtSpecName); ELSE w.String("temp"); END;
+							w.String(".bit  -bd "); w.String(blockName);
+							w.String(" tag "); ActiveCells.WriteName(w,instance.scope,instance.name,"ins"); w.Int(iBlock,1);
+							w.String(" -o b .\");
+							IF tempOut THEN w.String("temp"); ELSE w.String(builtSpecName); END; tempOut := ~tempOut;
+							w.String(".bit");
+							w.Ln;
+
+							CopyAsBuilt(hwPath,blockName,"",hwPath,res);
+							IF res # 0 THEN RETURN; END;
+
+							INC(numPatched);
+						END;
+
+						INC(iBlock);
+					END;
+
+					(** process data memory files *)
+					instance.GetFullName(instanceName,NIL);
+					Files.JoinExtension(instanceName,ActiveCells.DataFileExtension,instanceName);
+					iBlock := 0; numBlocks := SizeInBlocks(instance.dataMemorySize,dataBlockSize);
+					WHILE iBlock < numBlocks DO
+						ActiveCells.NormalizeName(instanceName,blockName);
+						Basic.AppendNumber(blockName,iBlock);
+						Files.JoinExtension(blockName,"mem",blockName);
+
+						IF ~SameAsBuilt(hwPath,blockName,"") THEN
+
+							IF ~Exists(hwPath,blockName,"") THEN res := -1; diagnostics.Error(blockName,Diagnostics.Invalid,Diagnostics.Invalid," file does not exist"); END;
+
+							w.String("data2mem -bm "); ActiveCells.WriteName(w,spec,"","bd"); w.String(".bmm  -bt  .\");
+							IF tempOut THEN w.String(builtSpecName); ELSE w.String("temp"); END;
+							w.String(".bit  -bd "); w.String(blockName);
+							w.String(" tag "); ActiveCells.WriteName(w,instance.scope,instance.name,"dat"); w.Int(iBlock,1);
+							w.String(" -o b .\");
+							IF tempOut THEN w.String("temp"); ELSE w.String(builtSpecName); END; tempOut := ~tempOut;
+							w.String(".bit");
+							w.Ln;
+
+							CopyAsBuilt(hwPath,blockName,"",hwPath,res);
+							IF res # 0 THEN RETURN; END;
+
+							INC(numPatched);
+						END;
+
+						INC(iBlock);
+					END;
+
+				END;
+			END;
+
+			IF numPatched > 0 THEN
+				IF ~tempOut THEN (* copy final bitstream stored in temp.bit to builtSpecName.bit *)
+					w.String("copy /B /Y /V temp.bit "); w.String(builtSpecName); w.String(".bit"); w.Ln;
+				END;
+				w.String("del temp.bit"); w.Ln;
+			END;
+
+			w.String("copy /B /Y /V "); w.String(builtSpecName); w.String(".bit"); w.String(" df.bit"); w.Ln;
+			w.String("copy /B /Y /V ..\download.cmd  download.cmd"); w.Ln;
+			w.String("impact -batch download.cmd"); w.Ln;
+			w.String("del df.bit"); w.Ln;
+
+			w.Update;
+			Files.Register(file);
+			file.Close;
+
+			(* execute the script *)
+			context.out.String("configuring the FPGA ... "); context.out.Update;
+			res := WinApplications.Call("temp.bat","");
+			IF res # 0 THEN context.error.String("failed to configure the FPGA, cmd batch res="); context.error.Int(res,0); context.error.Ln; context.error.Update; RETURN; END;
+
+			GetImpactCmdStatus(hwPath,success,res);
+			IF res # 0 THEN context.error.String("failed to determine status of Xilinx Impact command execution!"); RETURN; END;
+
+			IF success THEN
+				context.out.String("Ok"); context.out.Ln; context.out.Update;
+			ELSE
+				res := -1;
+				Files.JoinPath(hwPath,"_impactbatch.log",str);
+				context.error.String("failed to configure the FPGA: see "); context.error.String(str); context.error.String(" for details about the error!"); context.error.Ln; context.error.Update;
+			END;
+		END PatchAndConfigure;
+
+	BEGIN
+		NEW(options);
+		options.Add("p","platform",Options.String);
+		options.Add("f","specName",Options.String);
+		options.Add("n","forceNew",Options.Flag);
+		IF ~options.Parse(context.arg,context.error) THEN RETURN; END;
+
+		IF ~options.GetString("platform",platformId) THEN
+			context.error.String("platform string ID is expected!"); context.error.Ln; RETURN;
+		END;
+
+		IF ~options.GetString("specName",specName) THEN
+			context.error.String("specification file name is expected!"); context.error.Ln; RETURN;
+		END;
+
+		NEW(diagnostics,context.error);
+
+		spec := ActiveCells.LoadSpecification(specName,diagnostics,context.out);
+		IF spec = NIL THEN
+			context.error.String("failed to load specification from file "); context.error.String(specName); context.error.String(".spec"); context.error.Ln; RETURN;
+		END;
+
+		description := Hardware.GetDescription(platformId);
+		IF description = NIL THEN
+			context.error.String("failed to instantiate hardware description "); context.error.String(platformId); context.error.Ln; RETURN;
+		END;
+
+
+		(* get the hardware path *)
+		description.GetHardwarePath(hwPath);
+
+		(* remove the path from the specification name *)
+		Files.SplitPath(specName,specPath,specName); IF specPath = "" THEN specPath := "WORK:"; END;
+
+		Strings.Concat(BuiltPrefix,specName,builtSpecName);
+		Files.JoinPath(hwPath,builtSpecName,str);
+		builtSpec := ActiveCells.LoadSpecification(str,diagnostics,context.out);
+
+		changes := (builtSpec = NIL) OR ~spec.Same(builtSpec,{});
+
+		IF changes OR options.GetFlag("forceNew") THEN (* have to compile the hardware *)
+
+			IF changes THEN
+				context.out.String("detected changes in hardware specification, ");
+			END;
+			context.out.String("compiling FPGA hardware design ... "); context.out.Update;
+
+			(* remove old bit file *)
+			Files.JoinExtension(specName,"bit",str);
+			Files.JoinPath(hwPath,str,str);
+			DeleteFiles(str,context,res);
+
+			(* execute TCL script *)
+			Strings.Concat("xtclsh ",specName,str);
+			Strings.Concat(str,".tcl",str);
+			ExecuteInPath(str,hwPath,res);
+
+			(* get the result of compilation *)
+			IF res # 0 THEN context.error.String("failed to compile FPGA hardware design, cmd batch res="); context.error.Int(res,0); context.error.Ln; RETURN; END;
+
+			context.out.String("Ok"); context.out.Ln; context.out.Update;
+
+			(* remove old built bitstream *)
+			Files.JoinExtension(builtSpecName,"bit",str);
+			Files.JoinPath(hwPath,str,str);
+			DeleteFiles(str,context,res);
+			IF res # 0 THEN RETURN; END;
+
+			(* remove old built mem-files *)
+			Strings.Concat(builtSpecName,"*.mem",str);
+			Files.JoinPath(hwPath,str,str);
+			DeleteFiles(str,context,res);
+			IF res # 0 THEN RETURN; END;
+
+			(*
+				make a copy of the bitstream and use it as a built version
+			*)
+			CopyAsBuilt(hwPath,specName,"bit",hwPath,res);
+			IF res # 0 THEN RETURN; END;
+
+			(*
+				remember the current specification as already built
+			*)
+			CopyAsBuilt(specPath,specName,"spec",hwPath,res);
+			IF res # 0 THEN RETURN; END;
+		END;
+
+		PatchAndConfigure(res);
+
+		IF res = 0 THEN
+			context.out.String("successfully built ActiveCells hardware!"); context.out.Ln;
+		ELSE context.result := Commands.CommandError
+		END;
+	END BuildHardware;
+
+BEGIN
+	NEW(random);
+	random.InitSeed(SHORT(Machine.GetTimer()));
+END FoxTRMTools.
+
+FoxTRMTools.Test ~
+
+Compiler.Compile -b=TRM --objectFile=Intermediate --activeCells --noRuntimeChecks --activeCellsSpecification=FoxAVSP6LX75T --patchSpartan6
+oc/TRM.RS232.Mod
+oc/TRM.Testing.Mod
+oc/TRM.TRMRuntime.Mod
+oc/TRM.TestNet.Mdf
+~
+
+Compiler.Compile -b=TRM --objectFile=Intermediate --activeCells --noRuntimeChecks --activeCellsSpecification=ML505
+oc/TRM.RS232.Mod
+oc/TRM.Testing.Mod
+oc/TRM.TRMRuntime.Mod
+oc/TRM.TestNet.Mdf
+~
+
+
+FoxAVSP6LX75T.ReadSpecification TestNet ~
+
+FoxTRMTools.BuildHardware -p="AVSP6LX75T" -f="TestNet" ~
+
+FoxTRMTools.BuildHardware -p="ML505" -f="TestNet" ~
+
+SystemTools.Free FoxTRMTools ~
+
+FoxTRMTools.SplitFiles  code.mem data.mem ~
+FoxTRMTools.SplitFiles  --blocks=8 --strided data.mem ~
+PET.Open data.mem ~
+PET.Open data0.mem ~
+PET.Open data1.mem ~
+
+
+FoxTRMTools.GenerateTestFile test.code ~
+FoxTRMTools.GenerateTestFile --value=010H test.code ~
+FoxTRMTools.GenerateTestFile --random test.code ~
+FoxTRMTools.GenerateTestFile --sourceFile=binary.code test2.code ~
+
+FoxTRMTools.SplitFiles  --blockSize=1024 --blocks=5 test.code ~
+
+PET.Open -e test.code test2.code ~
+
+FoxTRMTools.CompareFiles test.code test2.code matrix.txt ~
+
+
+
+UARTPC.Open 6 ~
+
+SystemTools.DoCommands
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+FoxTRMTools.GenerateTestFile --random --size=4096 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=8 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 8192 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+
+SystemTools.Show "DONE!" ~
+~
+
+
+
+
+SystemTools.DoCommands
+
+FoxTRMTools.GenerateTestFile --random --size=512 TestBRAM0con0code.mem ~
+FoxTRMTools.SplitFiles  --blockSize=512 --blocks=1 --patchSpartan6 TestBRAM0con0code.mem ~
+WinApplications.Run "testbram.bat" ~
+UARTPC.DumpBRAM 6 0 1024 "bram.dat" ~
+FoxTRMTools.GenerateTestFile --sourceFile=bram.dat test.code ~
+PET.Open -e TestBRAM0con0code.mem test.code ~
+FoxTRMTools.CompareFiles TestBRAM0con0code.mem test.code bram.mtx~
+
+~
+
+
+M = {};
+
+file =fopen('bram.mtx')
+A = fscanf(file,'%d');
+fclose(file)
+A = reshape(A,16,16);
+
+M{numel(M)+1}=A;