diff -uNr a/dir2txt.py b/dir2txt.py --- a/dir2txt.py false +++ b/dir2txt.py 60a22e02dccf7857320339b34898544b1e4f27a69a8a227b26d5a93371cdac7a1c54cd5e3affcf0a8074e7c1d1cc6e689e38ed20d187b3ae9ade54505f5da71b @@ -0,0 +1,55 @@ +#!/usr/bin/python + +####################################### +#### THIS IS EXPERIMENTAL PROGRAM! #### +####################################### + +import os, sys +from stat import * + + +## The one and only formatting character +header_cutter = '@' + + +## These exist merely for the pleasure of the naked-eye reader. +decoration = '#' * 78 + + +## Process a Unix directory tree, to create a 'crystallized' output +def do_dir(top, callback): + for f in os.listdir(top): + pathname = os.path.join(top, f) + mode = os.stat(pathname).st_mode + if S_ISDIR(mode): + # Directory: recurse into it + do_dir(pathname, callback) + elif S_ISREG(mode): + # File: eat it + callback(pathname) + else: + # Neither a normal Unix file, nor directory: + print 'Skipping %s' % pathname + + +## Process a file, as part of directory 'crystallization' +def do_file(path): + ## Put a separator decoration into the 'crystal' + print decoration + ## Put the exact size, in bytes, followed by path + print os.stat(path).st_size, header_cutter, path + ## Put a separator decoration into the 'crystal' + print decoration + ## From this point, follows the entirety of this file: + print open(path, 'rb').read() + + +## Do the deed: +if __name__ == '__main__': + if (len(sys.argv) != 2): + print "Usage: ",sys.argv[0],"PATH" + print "" + print "\tEats a Unix dir and produces (to stdout) a text 'crystal'." + sys.exit(0) + else: + do_dir(sys.argv[1], do_file) diff -uNr a/fg.xtal b/fg.xtal --- a/fg.xtal false +++ b/fg.xtal ee25cd37ed316e8a6305f4a0651a43e40be3ef3ec5be85089ff1c821d4e4a16e6b89bdf2306d961f9969ec2bcde41c072873e54f8d49dae46f469e2113065e88 @@ -0,0 +1,610 @@ +############################################################################## +13865 @ ./fg.v +############################################################################## +/////////////////////////////////////////////////////////////////////////// +// FUCKGOATS CPLD circuit. V.3K (December 2016.) +// +// This was written for an XC9572XL. It SHOULD work on any gate array of +// equal or greater size, but no such assurance is given. +// It SHOULD also work quite well in the form of an ASIC, or in TTL, or +// using any other reasonably-fast logic element. +// +// (C) 2016 No Such lAbs. +// +// You do not have, nor can you ever acquire the right to use, copy or +// distribute this software ; Should you use this software for any purpose, +// or copy and distribute it to anyone or in any manner, you are breaking +// the laws of whatever soi-disant jurisdiction, and you promise to +// continue doing so for the indefinite future. In any case, please +// always : read and understand any software ; verify any PGP signatures +// that you use - for any purpose. +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// Knobs. +/////////////////////////////////////////////////////////////////////////// +// BITS of analogue input used to make each BYTE of accum output. +// You MAY want to change if you were to use another type of analogue RNG, +// particularly one having a different spectrum from the 'TW' board. +`define FOLD_RSIZE 4 // size of counter register +`define FOLD 4'd15 // bit count +/////////////////////////////////////////////////////////////////////////// + + +// div128, for UART's 115200b on 14.7456MHz crystal. +// We also use it as slow clock for the watchdog. +module baudgen(clk, clkout); + input clk; + output clkout; + + reg [6:0] counter = 0; + wire clkout; + + always @(posedge clk) + begin + counter <= counter + 1; + end + assign clkout = (counter == 7'b1111111); +endmodule + + +// A very simple TX-only UART. 'No user serviceable parts inside.' +// No async reset, because nothing good can come of aborting mid-byte. +module ser_tx(clk, baud_clk, fire, txbyte, tx, busy); + input clk, baud_clk, fire; + input [7:0] txbyte; + output tx, busy; + wire busy; + + // Transmitter state machine + reg [3:0] state = 0; + wire tx_ready = (state == 0); + assign busy = ~tx_ready; + + wire [7:0] txbyteD = txbyte; + + always @(posedge clk) + case(state) + 4'b0000: if(fire) state <= 4'b0001; + 4'b0001: if(baud_clk) state <= 4'b0100; + 4'b0100: if(baud_clk) state <= 4'b1000; // start + 4'b1000: if(baud_clk) state <= 4'b1001; // bit 0 + 4'b1001: if(baud_clk) state <= 4'b1010; // bit 1 + 4'b1010: if(baud_clk) state <= 4'b1011; // bit 2 + 4'b1011: if(baud_clk) state <= 4'b1100; // bit 3 + 4'b1100: if(baud_clk) state <= 4'b1101; // bit 4 + 4'b1101: if(baud_clk) state <= 4'b1110; // bit 5 + 4'b1110: if(baud_clk) state <= 4'b1111; // bit 6 + 4'b1111: if(baud_clk) state <= 4'b0010; // bit 7 + 4'b0010: if(baud_clk) state <= 4'b0000; // stop1 + 4'b0011: if(baud_clk) state <= 4'b0000; // stop2 (off) + default: if(baud_clk) state <= 4'b0000; + endcase + + reg muxbit; + always @(*) + case(state[2:0]) + 3'd0: muxbit <= txbyteD[0]; + 3'd1: muxbit <= txbyteD[1]; + 3'd2: muxbit <= txbyteD[2]; + 3'd3: muxbit <= txbyteD[3]; + 3'd4: muxbit <= txbyteD[4]; + 3'd5: muxbit <= txbyteD[5]; + 3'd6: muxbit <= txbyteD[6]; + 3'd7: muxbit <= txbyteD[7]; + endcase + + reg tx; + always @(posedge clk) + tx <= (state<4) | (state[3] & muxbit); +endmodule + + +// One way to gather entropy from absolute pulse widths. +// This was not feasible in v.10K (it could not rely on synced clk.) +module eater(clk, nres, in, valid, out); + input clk, nres, in; + output valid, out; + + reg [3:0] q; + reg out; + reg s; + + always @(posedge clk or negedge nres) + if (~nres) + begin + s <= 0; + end + else + begin + s <= in; + end + + wire pulse = s ^ in; // either rise or fall of input + + always @(posedge clk or negedge nres) + if (~nres) + begin + q <= 0; + out <= 0; + end + else + begin + out <= q[3] ^ q[2] ^ q[1] ^ q[0]; + q <= pulse ? 0 : q + 1; + end + + assign valid = pulse; +endmodule +// NOTE that if you are doing a yoke test with two units and one set +// of analogue RNGs, you must buffer the latter with a latch clocked +// from the common clock, so that they obey the hold time constraint +// of the CPLD's input buffer. Without this, operation will ~still~ +// be repeatable between the yoked units, but ~with errors~. + + +// Von Neumann's 'fair coin' algorithm. +module debias(clk, res, fire, in, valid, out); + input clk, res, fire, in; + output valid, out; + + reg p, q; + reg [1:0] state; + wire valid; + + always @(posedge clk or negedge res) + if (~res) + begin + state <= 0; + p <= 0; + q <= 0; + end + else + begin + case(state) + 2'd0: + begin + p <= in; + state <= fire ? 2'd1 : 2'd0; + end + 2'd1: + begin + q <= in; + state <= fire ? 2'd2 : 2'd1; + end + 2'd2: + begin + state <= 2'd0; + end + 2'd3: // unused + begin + state <= 2'd0; + end + endcase + end + + assign valid = (p ^ q) & (state == 2'd2); + assign out = p; +endmodule + + +// Byte Accumulator. +module accum(clk, nres, fire, in, roll, rdy); + parameter fold = 8; // bits per shot + parameter count_bits = 4; + + input clk, in, nres, fire; + output rdy; + output [7:0] roll; + + reg [7:0] roll; + reg [count_bits-1:0] bit_count; + reg rdy; + + always @(posedge clk or negedge nres) + begin + if (~nres) // async reset + begin + bit_count <= 0; + roll <= 0; + rdy <= 0; + end + else + if (fire) + begin + roll[bit_count[2:0]] <= roll[bit_count[2:0]] ^ in; + bit_count <= bit_count + 1; + if (bit_count == fold) rdy <= 1; // raise ready flag + end + end +endmodule + + +// Watchdog. Counter, stops advancing at max until reset. +module dog(clk, nres, run, alarm); + input clk, nres, run; + output alarm; + + reg [5:0] count; + + assign alarm = (count == 6'b111111); + + always @(posedge clk or negedge nres) + begin + if (~nres) // async reset + begin + count <= 0; + end + else + if (run & ~alarm) + begin + count <= count + 1; + end + end +endmodule + + +// Werker. +module fg(input wire xtal, // on-board clock, from 14.7456MHz resonator + inout wire clk, // clock output (master) or input (slave) + input wire IN_A, // 'bottom' analogue RNG input, pulled high + input wire IN_B, // 'top' analogue RNG input, pulled high + output wire ser_tx, // output of UART, to TTL converter + output wire SAD // red lamp + ); + + /////////////////////////////////////////////////////////////////////////// + // Serial UART + /////////////////////////////////////////////////////////////////////////// + + wire tx; + wire fire; + wire busy; + wire baud_clk; + reg [7:0] txbyte; + + // baud clock generator + baudgen bg(clk, baud_clk); + + // UART. + ser_tx sender(clk, baud_clk, fire, txbyte, tx, busy); + + /////////////////////////////////////////////////////////////////////////// + // Master/Slave toggle, for clock-synchronized slave yoke tests. + // Yoke two units by connecting the CLK ('RESET' on v1 pcb) pins together. + // The first board powered up will become the master. + // Slave's red lamp will stay lit, and his clock is inhibited, uses master + /////////////////////////////////////////////////////////////////////////// + reg [2:0] boot_state = 0; + + // If I master, I output ~my~ clock; otherwise - I slave, wait for a clock: + wire am_master = (boot_state == 3'd6); + assign clk = am_master ? xtal : 1'bz; // this pin is pulled high + + // Breath of Life + always @(posedge xtal) // must use on-board oscillator, for obvious reasons + begin + case(boot_state) + default: + begin + boot_state <= clk ? boot_state + 1 : 3'd7; + end + 3'd6: // I am a master, for life! (until powerdown) + begin + boot_state <= 3'd6; + end + 3'd7: // I am a slave, for life! (until powerdown) + begin + boot_state <= 3'd7; + end + endcase + end + + // we want to hold reset for a short while on bootup + reg nreset = 0; + + always @(posedge clk) // use the active clock, ~when we get one~ + begin + if ((~IN_A) & (~IN_B) & baud_clk) // stay in reset until both rng work + begin // and until first baud clock pulse + nreset <= 1'd1; + end + end + + // We hold ser_tx low on reset, this way it is easy to see when finished. + assign ser_tx = tx & nreset; + + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // If this device were to grind to a halt, wouldn't you like to know? + /////////////////////////////////////////////////////////////////////////// + wire dog_alarm; + wire dog_run; + wire dog_reset; + + dog sad_dog(clk, + dog_reset & nreset, // watchdog reset (if either dips low) + dog_run, // watchdog enable-advance + dog_alarm); // watchdog alarm, tied to 'SAD' lamp + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // RNG + /////////////////////////////////////////////////////////////////////////// + wire eater_a_valid; + wire eater_a_out; + eater e_a(clk, nreset, IN_A, eater_a_valid, eater_a_out); + + wire eater_b_valid; + wire eater_b_out; + eater e_b(clk, nreset, IN_B, eater_b_valid, eater_b_out); + + wire valid_a; + wire outbit_a; + + debias dbias_a(clk, + nreset, + eater_a_valid, + eater_a_out, + valid_a, + outbit_a); + + wire valid_b; + wire outbit_b; + + debias dbias_b(clk, + nreset, + eater_b_valid, + eater_b_out, + valid_b, + outbit_b); + + // per xor lemma: + wire valid = valid_a | valid_b; + wire outbit = outbit_a ^ outbit_b; + + wire acc_res; // reset accum (active low) + wire acc_rdy; // accum has byte + wire [7:0] acc_byte; // output of accumulator + + accum #(.fold(`FOLD), + .count_bits(`FOLD_RSIZE)) acc_a(clk, + acc_res & nreset, // if either low + valid, + outbit, + acc_byte, + acc_rdy); + + /////////////////////////////////////////////////////////////////////////// + + // device cycles forever through four phases + reg [1:0] state; + + always @(posedge clk or negedge nreset) + if (~nreset) + begin + state <= 0; + txbyte <= 0; + end + else + begin + case(state) + 2'd0: // ground state + begin + txbyte <= 0; // clear tx buffer + state <= 2'd1; // next + end + 2'd1: + begin // wait for 'a' accum + if (acc_rdy) + begin + txbyte <= acc_byte; + state <= 2'd2; // next + end + else + state <= 2'd1; // wait + end + 2'd2: + begin // clear 'a'; fire tx + state <= 2'd3; // next + end + 2'd3: + begin // wait to end of tx + state <= (~busy) ? 2'd0 : 2'd3; // wait for UART + end + endcase + end + + assign fire = (state == 2'd2); // txbyte is ready, so fire the UART + assign acc_res = ~(fire); // zap acc_byte (active low) + + // advance dogometer at the baud clock rate + assign dog_run = baud_clk & (state == 2'd1); + + assign dog_reset = acc_res; // reset dogometer we got a byte + + // Red 'Sadness' lamp. + // If STEADILY LIT, check ALL connections: the device is halted and is + // doing NO USEFUL WORK at all! + // Re-seat analogue RNG boards, check their power supplies (if you have, + // e.g., a custom isolation system.) Otherwise - one or both analogue + // RNG units may need replacement. + assign SAD = dog_alarm | ~am_master | (~nreset); + // Red lamp will also light if the board is placed into the slave + // state (for verification) using the external clock + // (marked RESET on early board revs) pin; and when in RESET state. +endmodule + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +############################################################################## +3182 @ ./Makefile +############################################################################## +########################################################################### +## FUCKGOATS CPLD Makefile. V.3K (December 2016.) +## +## This was written for an XC9572XL. It SHOULD work on any gate array of +## equal or greater size, but no such assurance is given. +## It SHOULD also work quite well in the form of an ASIC, or in TTL, or +## using any other reasonably-fast logic element. +## +## (C) 2016 No Such lAbs. +## +## You do not have, nor can you ever acquire the right to use, copy or +## distribute this software ; Should you use this software for any purpose, +## or copy and distribute it to anyone or in any manner, you are breaking +## the laws of whatever soi-disant jurisdiction, and you promise to +## continue doing so for the indefinite future. In any case, please +## always : read and understand any software ; verify any PGP signatures +## that you use - for any purpose. +########################################################################### + +########################################################################### +## make clean && make #<<<<<<<<<<<< build +## make burn #<<<<<<<<<<<< burn ROM with Xilinx's burner +########################################################################### + +## Project name +PROJECT=fg +## Part number +PART=XC9572XL-5-vq44 +## Output configuration file +OUTPUT=$(PROJECT).jed +## Verilog sources +SOURCES=fg.v +## Constraints file +UCF=$(PROJECT).ucf + +## Path to Xilinx tools, blank if in $PATH, must end in / +## YOU MUST CHANGE THIS TO YOURS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +XILINX=/opt/Xilinx/13.1/ISE_DS/ISE/bin/lin64/ +## If you have some OTHER version of the Xilinx turdware, this build MAY work. + +WD=work +PB=$(WD)/$(PROJECT) + +XSTFLAGS=-opt_mode Speed -opt_level 2 -verilog2001 YES +CPLDFITFLAGS=-slew fast -power std -terminate keeper -unused float -optimize speed -init low + +.PHONY: all clean + +all: $(PB).tim $(OUTPUT) + +$(WD): + mkdir $(WD)/ + +$(PB).ngc: $(SOURCES) + @[ ! -e $(WD) ] && mkdir $(WD) || true + @echo "Generating $(PB).prj..." + @rm -f $(PB).prj + @for i in $(SOURCES); do \ + echo "verilog $(PROJECT) $$i" >> $(PB).prj; \ + done + @echo "DEFAULT_SEARCH_ORDER" > $(PB).lso + @echo "set -tmpdir $(WD) -xsthdpdir $(WD)" > $(PB).xst + @echo "run -ifn $(PB).prj -ifmt mixed -top $(PROJECT) -ofn $@ -ofmt NGC -p $(PART) $(XSTFLAGS) -lso $(PB).lso" >> $(PB).xst + $(XILINX)xst -ifn $(PB).xst -ofn $(PB)_xst.log + +$(PB).ngd: $(PB).ngc $(UCF) + cd $(WD) ; $(XILINX)ngdbuild -p $(PART) -uc ../$(UCF) ../$< ../$@ + +$(PB).vm6: $(PB).ngd + cd $(WD) ; $(XILINX)cpldfit -exhaust -p $(PART) ../$< + +$(PB).tim: $(PB).vm6 + cd $(WD) ; $(XILINX)taengine -l ../$@ -detail -f $(PROJECT) ../$< + +$(PB).jed: $(PB).vm6 + cd $(WD) ; $(XILINX)hprep6 -i ../$< + @echo "Generating $(PB).cmd..." + @echo "setmode -bscan" > $(PB).cmd + @echo "setcable -p auto" >> $(PB).cmd + @echo "Identify -inferir" >> $(PB).cmd + @echo "ReadIdcode -p 1" >> $(PB).cmd + @echo "assignFile -p 1 -file $(PROJECT).jed" >> $(PB).cmd + @echo "erase -p 1 -o" >> $(PB).cmd + @echo "program -p 1" >> $(PB).cmd + @echo "quit" >> $(PB).cmd + +burn: + cd $(WD) ; $(XILINX)impact -batch $(PROJECT).cmd + +%: $(WD)/% + @echo "Output $@ is ready" + +clean: + rm -rf $(WD) $(OUTPUT) _xmsgs + +############################################################################## +654 @ ./README +############################################################################## +The current FUCKGOATS schematics (pcb v1): fg.png +sha512: +03d8a77e0d5d082f0f40c3bc73fa4f605326d224954b4c75a2bb8c653f260683d8031596f496e6c5aecca7e6380ca1821c3919816c726cefe571680f4eb973ae + + +The current ANALOGUE RNG schematics (pcb TW): trng_tw.png +sha512: +f6e19a7afa01f16ed2f40d9154fa10c37a3e188a584cbe892c91216d136958916c89dadabea8ba8fd59a7e536aa04b5f1893096c6f256d146db1c9a23a70aa00 + + +V.3K compiled CPLD turd: fg.jed +sha512: +af7ae91db33800352408ca66edc08228931bb14864610f8f2bd2c1a587c5e0370f1f5b26f4033be044969d5b225269ba309d3cb5e3f8b584e967002c34de5208 + + +Please read comments in fg.v and http://nosuchlabs.com/hardware.html for operating instructions. + +############################################################################## +2094 @ ./fg.ucf +############################################################################## +/////////////////////////////////////////////////////////////////////////// +// FUCKGOATS CPLD UCF constraint file. V.3K (December 2016.) +// +// This was written for an XC9572XL. It SHOULD work on any gate array of +// equal or greater size, but no such assurance is given. +// It SHOULD also work quite well in the form of an ASIC, or in TTL, or +// using any other reasonably-fast logic element. +// +// (C) 2016 No Such lAbs. +// +// You do not have, nor can you ever acquire the right to use, copy or +// distribute this software ; Should you use this software for any purpose, +// or copy and distribute it to anyone or in any manner, you are breaking +// the laws of whatever soi-disant jurisdiction, and you promise to +// continue doing so for the indefinite future. In any case, please +// always : read and understand any software ; verify any PGP signatures +// that you use - for any purpose. +/////////////////////////////////////////////////////////////////////////// + +// Device : XC9572XL-5-VQ44 +// +// -------------------------------- +// /44 43 42 41 40 39 38 37 36 35 34 \ +// | 1 33 | +// | 2 32 | +// | 3 31 | +// | 4 30 | +// | 5 XC9572XL-5-VQ44 29 | +// | 6 28 | +// | 7 27 | +// | 8 26 | +// | 9 25 | +// | 10 24 | +// | 11 23 | +// \ 12 13 14 15 16 17 18 19 20 21 22 / +// -------------------------------- + +NET "xtal" LOC = "P1"; // on-board 14.7456MHz resonator +NET "clk" LOC = "P33"; // master/slave clk ('RESET' on v1 pcb) + +NET "IN_A" LOC = "P37"; // bottom analogue RNG connector +NET "IN_B" LOC = "P18"; // top analogue RNG connector + +NET "ser_tx" LOC = "P28"; // serial out +NET "SAD" LOC = "P34"; // red lamp + +/////////////////////////////////////////////////////////////////////////// + diff -uNr a/README b/README --- a/README false +++ b/README 3618a87021625a5c7ef7d9f988ee6a9dcf322e78b05c0b13336400804b753a6a9e44b410cc7d39978db40b6b39c335c0a5434c188955dcbb2fe4bb27afed5be3 @@ -0,0 +1,56 @@ +This is an EXPERIMENTAL utility, to demonstrate a concept that could be used +in a hypothetical 'monocrystalline' Vtron. There are three included items: + +(1) + +dir2txt.py PATH + + ^ eats a Unix dir PATH, and produces a textual representation + of its total contents to stdout. + + Example usage: + + ./dir2txt.py fg > fg.xtal + + This example's output is INCLUDED with this genesis. + + +(2) + +txt2dir.py XTALFILE [OPTIONAL PATH PREFIX] + + ^ eats a 'crystal' text file produced by dir2txt.py, and an + OPTIONAL prefix path. Produces a binary-identical + representation of the directory that went into producing the + file; and optionally prefixes the given prefix (second arg.) + + +(3) + +The included example, fg.xtal, represents the contents of the +FUCKGOATS genesis. + + + +TESTING PROCESS: + +Test by creating arse-mouth system: + +E.g., + +$ ./txt2dir.py fg.xtal foo +Reconstituting crystal: fg.xtal ... +Creating 13865 byte file at path: foo/./fg.v +Creating directories of path: foo/. +Creating 3182 byte file at path: foo/./Makefile +Creating 654 byte file at path: foo/./README +Creating 2094 byte file at path: foo/./fg.ucf +Done! + +$ cd foo + +$ ../dir2txt.py . > ../test.xtal + +$ diff fg.xtal t.xtal + +[ null output ] diff -uNr a/txt2dir.py b/txt2dir.py --- a/txt2dir.py false +++ b/txt2dir.py b544fd75c003173dddaf1913ef3ea8c0d3759d3251f1b5ea172b5e7d6eacab239298954b7da7f77cb9c58cc2dccf0509dfadabce8a2808cd260abad65f445e4a @@ -0,0 +1,102 @@ +#!/usr/bin/python + +####################################### +#### THIS IS EXPERIMENTAL PROGRAM! #### +####################################### + +import os, sys +from stat import * + + +## The one and only formatting character +header_cutter = '@' + + +## Let's start with death: +def eggog(msg): + sys.stderr.write("EGGOG: " + msg + "\n") + sys.exit(1) + + +## Do or die (for our format): +def must_get(l): + if l is None: + eggog("Premature End of Crystal") + else: + return l + + +## Force the directory structure of the given path to exist: +def create_path(path): + file_dirpath = os.path.dirname(path) + if not os.path.exists(file_dirpath): + print "Creating directories of path: ", file_dirpath + try: + os.makedirs(file_dirpath) + except OSError as exc: + if exc.errno != errno.EEXIST: + raise + + +## Reconstitute a crystal: +def do_xtal(path, prefix): + print "Reconstituting crystal: ", path, "..." + with open(path, 'rb') as fp: + ## From each header block, we skip first line; + ## if we are at EOF here, we have reached the end of the crystal. + while fp.readline(): + + ## Now read the header meat, which takes the form BYTES : PATH + header = must_get(fp.readline()) + + ## The line which follows a header meat, is of no significance: + must_get(fp.readline()) + + ## Now analyze the header meat, to recreate the file path, + ## and to find the expected mass of the file: + cut_pos = header.find(header_cutter) + if cut_pos == -1: + eggog("Malformatted Crystal: bad header: \n\t" + header + "\n") + + ## The path is found on the right-hand side of the : + filepath = os.path.join(prefix, header[cut_pos + 1:].strip()) + + ## The size is found on the left-hand side of the : + try: + filesize = int(header[:cut_pos].strip()) + except Exception as ex: + eggog("Malformatted Crystal: bad header: \n\t" + header + "\n") + + print "Creating", filesize, "byte file at path: ", filepath + + create_path(filepath) + + file_meat = must_get(fp.read(filesize)) + + try: + with open(filepath, "wb") as fout: + fout.write(file_meat) + except Exception: + eggog("Error writing file at path: " + filepath) + + ## Eat the newline which follows the Meat. + must_get(fp.readline()) + + +## Do the deed: +if __name__ == '__main__': + if ((len(sys.argv) < 2) or (len(sys.argv) > 3)): + print "Usage: ",sys.argv[0],"XTAL [OPTIONAL PATH PREFIX]" + print "" + print "\tEats a text 'crystal' and reconstitutes contents of the Unix dir." + sys.exit(0) + else: + prefix = "./" + + ## Did user specify a nondefault prefix? + if len(sys.argv) == 3: + prefix = sys.argv[2] + + ## Reconstitute the crystal: + do_xtal(sys.argv[1], prefix) + print "Done!"