diff -uNr a/fg.ucf b/fg.ucf --- a/fg.ucf false +++ b/fg.ucf 2e1120e28077b4fc31bc2de704cba9591daad2e4193737cf911a0dd49d4731843cc9fb9c3595f65c9e1bdf6a13d2d41011552de688cff10a7074ace6827cc37f @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////// +// 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/fg.v b/fg.v --- a/fg.v false +++ b/fg.v 0000b0abcb2fe3f54b635a846a7e3a8734ed944a54b9cd6bbd9f8696e97734f4fd0d7d82e964f47034f2b3468654027ca488b78ee3914a89f88c59596e0df133 @@ -0,0 +1,437 @@ +/////////////////////////////////////////////////////////////////////////// +// 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 + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// diff -uNr a/Makefile b/Makefile --- a/Makefile false +++ b/Makefile f6312358148d7ebedddce03178db0943d7a753219ecbe0b803407f99a02173e629ef6e8aa9c0f936ba05322461dae2003e81beb9a37a3e74f8253c883acef43c @@ -0,0 +1,94 @@ +########################################################################### +## 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 diff -uNr a/README b/README --- a/README false +++ b/README ad61b6fadcbfc33accc92d5c9367a032396bfbde81505e9c9085d4148684bea7d711983e1a49af8d3b89784e4fb875471c2a2fa3d148d8de9a09066595cf65b2 @@ -0,0 +1,16 @@ +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.