Make it work
authorMarius Gavrilescu <marius@ieval.ro>
Tue, 23 Apr 2019 18:00:04 +0000 (21:00 +0300)
committerMarius Gavrilescu <marius@ieval.ro>
Tue, 23 Apr 2019 18:00:04 +0000 (21:00 +0300)
18 files changed:
Makefile
addtest.pl [new file with mode: 0644]
asm.pm
bigone.pl [new file with mode: 0644]
chip.v
i2c.v
id.pl [new file with mode: 0644]
ledmatrix.pl [new file with mode: 0644]
master.pcf
master.v
master_rom.v
news.v
newstable.pl
progall.sh [new file with mode: 0644]
tinyledmatrix.pl [new file with mode: 0644]
uart.v
worker.pcf [new file with mode: 0644]
worker.v

index e2c55e51e8aeba470fb0bc42aa38029f57958b53..1b88b5cc067ba581b9a065663003807172feb444 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,17 @@
-PROJ = master
-PIN_DEF = master.pcf
 DEVICE = hx1k
 
-all: $(PROJ).rpt $(PROJ).bin
+all: toplevel.bin
 
-%.blif: %.v
+toplevel.bin: master.rpt master.bin worker.rpt worker.bin
+       tools/icestorm/icemulti/icemulti -o toplevel.bin -v -p0 worker.bin master.bin
+
+master.blif: master.v
        tools/yosys/yosys -p 'synth_ice40 -top master -blif $@' $<
 
-%.asc: $(PIN_DEF) %.blif
+worker.blif: worker.v
+       tools/yosys/yosys -p 'synth_ice40 -top worker -blif $@' $<
+
+%.asc: %.pcf %.blif
        tools/arachne-pnr/bin/arachne-pnr -d $(subst hx,,$(subst lp,,$(DEVICE))) -o $@ -p $^ -P tq144
 
 %.bin: %.asc
@@ -16,14 +20,20 @@ all: $(PROJ).rpt $(PROJ).bin
 %.rpt: %.asc
        tools/icestorm/icetime/icetime -C tools/icestorm/icebox/chipdb-$(subst hx,,$(subst lp,,$(DEVICE))).txt -d $(DEVICE) -mtr $@ $<
 
-prog: $(PROJ).bin
+prog: toplevel.bin
+       tools/icestorm/iceprog/iceprog $<
+
+progall: toplevel.bin
+       bash progall.sh
+
+progmaster: master.bin
        tools/icestorm/iceprog/iceprog $<
 
 clean:
-       rm -f $(PROJ).blif $(PROJ).asc $(PROJ).bin
+       rm -f master.blif master.asc worker.blif worker.asc master.bin worker.bin toplevel.bin
 
 
 sim:
-       tools/yosys/yosys -p 'read_verilog -sv -DSIM master.v; prep -top master -nordff; sim -clock CLKin -vcd test.vcd -n 3000'
+       tools/yosys/yosys -p 'read_verilog -sv -DSIM worker.v; prep -top worker -nordff; sim -clock CLKin -vcd test.vcd -n 3000'
 
 .PHONY: all prog clean sim
diff --git a/addtest.pl b/addtest.pl
new file mode 100644 (file)
index 0000000..a43a4e1
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+sub flag_to_memory {
+       my ($address, $flag) = @_;
+       alu3 alu_zero, alu_select_f, 0, 0, $address, $flag, flag_zero;
+}
+
+storei 0, 5;
+storei 1, 7;
+
+add 0, 1, 0, 4;
+flag_to_memory 1, 4;
diff --git a/asm.pm b/asm.pm
index 269b8d1d49d62963131325ce32f42e95e1e0f3ca..1b6dc8ad82e0d98ad48dd0583098eb8279979a7b 100644 (file)
--- a/asm.pm
+++ b/asm.pm
@@ -36,8 +36,8 @@ my $port;
 
 
 use parent qw/Exporter/;
-our @EXPORT = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route/;
-our @EXPORT_OK = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news  alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route/;
+our @EXPORT = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route chip_select/;
+our @EXPORT_OK = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news  alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route chip_select/;
 
 use File::Slurp::Tiny 'write_file';
 
@@ -70,20 +70,30 @@ sub send__ {
 
 my $rom_cnt = 0;
 
+# by default instructions are for all 4 chips to execute
+our $CS = 0xF;
+
 sub send_ {
        my ($cmd) = @_;
        my %cmd = %$cmd;
+       my $op_cs = $cmd{op} + ($CS << 4);
 
-       my $binary = pack 'vCC', @cmd{qw/I mem_addr op/}; # we ignore CS for now
+       my $binary = pack 'vCC', $cmd{I}, $cmd{mem_addr}, $op_cs;
        my $hex = reverse unpack 'h*', $binary;
-       say "$rom_cnt: data <= 32'h$hex;";
+       #       say "$rom_cnt: data <= 32'h$hex;";
+       say $hex;
        $rom_cnt++;
 }
 
+sub chip_select {
+       my ($new_cs, $sub) = @_;
+       local $CS = $new_cs;
+       $sub->();
+}
 
 sub nop {
        send_
-         { I => 0, mem_addr => 0, op => OP_NOP, CS => 0 }
+         { I => 0, mem_addr => 0, op => OP_NOP }
   }
 
 sub loada {
@@ -93,7 +103,7 @@ sub loada {
        $I |= $bsel << 4;
        $I |= $aluc << 5;
        send_
-         { I => $I, mem_addr => $addr, op => OP_LOADA, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_LOADA }
   }
 
 sub loadb {
@@ -103,7 +113,7 @@ sub loadb {
        $I |= $inv << 4;
        $I |= $alus << 5;
        send_
-         { I => $I, mem_addr => $addr, op => OP_LOADB, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_LOADB }
   }
 
 #sub read_ {
@@ -118,26 +128,28 @@ sub store {
        $I |= $edge_ << 7;
        $I |= $cube << 8;
        send_
-         { I => $I, mem_addr => $addr, op => OP_STORE, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_STORE }
   }
 
 sub loadi {
        my ($addr, $I) = @_;
        send_
-         { I => $I, mem_addr => $addr, op => OP_LOADI, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_LOADI }
 }
 
 sub route {
-       my ($addr, $dest_addr) = @_;
+       my ($addr, $dest_addr, $led) = @_;
+       $led //= 0;
        my $I = $dest_addr;
+       $I |= $led << 12;
        send_
-         { I => $I, mem_addr => $addr, op => OP_ROUTE, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_ROUTE }
 }
 
 sub storei {
        my ($addr, $I) = @_;
        send_
-         { I => $I, mem_addr => $addr, op => OP_STOREI, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_STOREI }
 }
 
 sub led {
@@ -145,11 +157,12 @@ sub led {
        my $I = $offset_leds;
        $I |= $mode << 4;
        send_
-         { I => $I, mem_addr => $addr, op => OP_LED, CS => 0 }
+         { I => $I, mem_addr => $addr, op => OP_LED }
 }
 
 sub ledm {
        my ($addr, $offset) = @_;
+       $offset //= 0;
        led $addr, 1, $offset;
 }
 
@@ -207,6 +220,13 @@ sub alus_addAF { alu_of_function { ($a + $_) & 1 } }
 
 sub alu_or { alu_of_function { $a | $b | $_ } }
 
+sub alu_and { alu_of_function { $a & $b & $_ } }
+
+BEGIN {
+       die "alus_add != alu_xor" unless alus_add == alu_xor;
+       die "bad alu_select_f" unless alu_select_f == alu_of_function { $_ };
+}
+
 sub alu2 {
        my ($aluc, $alus, $addrA, $addrB, $flagr, $flagw, $cond, $inv) = @_;
        loada $addrA, $flagr, 0, $aluc;
@@ -221,6 +241,11 @@ sub alu3 {
        store $addrC, $flagw, 0, 0;
 }
 
+sub mov {
+       my ($addrA, $addrC) = @_;
+       alu3 alu_zero, alu_select_a, $addrA, $addrA, $addrC, flag_zero, flag_zero
+}
+
 sub add {
        my ($addrA, $addrB, $addrC, $flag_carry) = @_;
        alu3 aluc_add, alus_add, $addrA, $addrB, $addrC, flag_zero, $flag_carry;
@@ -231,6 +256,16 @@ sub addC {
        alu3 aluc_add, alus_add, $addrA, $addrB, $addrC, $flag_carry, $flag_carry;
 }
 
+sub xor_ {
+       my ($addrA, $addrB, $addrC) = @_;
+       alu3 alu_zero, alu_xor, $addrA, $addrB, $addrC, flag_zero, flag_zero;
+}
+
+sub and_ {
+       my ($addrA, $addrB, $addrC) = @_;
+       alu3 alu_zero, alu_and, $addrA, $addrB, $addrC, flag_zero, flag_zero;
+}
+
 # news_gen face partea de mijloc
 # news_[mf][mf] face primul alu3, apeleaza news_gen, apoi face ultimul alu3
 sub news_generic {
@@ -238,16 +273,18 @@ sub news_generic {
        my %dest = %$dest;
        while ($nX || $nY) {
                my $direction;
-               if ($nX && $nY) {
-                       $nX--;
-                       $nY--;
-                       $direction = 7;
-               } elsif ($nX) {
+               if ($nX > 0) {
                        $nX--;
+                       $direction = 2;
+               } elsif ($nX < 0) {
+                       $nX++;
                        $direction = 0;
-               } else {
+               } elsif ($nY > 0) {
                        $nY--;
-                       $direction = 6;
+                       $direction = 1;
+               } elsif ($nY < 0) {
+                       $nY++;
+                       $direction = 3;
                }
                if ($nX || $nY) { # not the last go
                        alu3 alu_select_f, alu_select_a, 0, 0, 0, flag_news($direction), flag_zero
diff --git a/bigone.pl b/bigone.pl
new file mode 100644 (file)
index 0000000..e4c3008
--- /dev/null
+++ b/bigone.pl
@@ -0,0 +1,160 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+sub update_leds {
+       my ($x) = @_;
+       route $x + 0, $x + 1, 4;
+       route $x + 1, $x + 2, 3;
+       route $x + 2, $x + 3, 2;
+       route $x + 3, $x + 4, 1;
+}
+
+sub xori {
+       my ($addrA, $imm, $addrC) = @_;
+       storei 42, $imm;
+       xor_ $addrA, 42, $addrC;
+}
+
+sub andi {
+       my ($addrA, $imm, $addrC) = @_;
+       storei 42, $imm;
+       and_ $addrA, 42, $addrC;
+}
+
+# we want everyone to have
+#
+# own   quadrant at mem[0]
+# east  quadrant at mem[11]
+# south quadrant at mem[12]
+# SE    quadrant at mem[13]
+
+my $q_east = 11;
+my $q_south = 12;
+my $q_SE = 13;
+
+chip_select 4, sub { storei 0, 0x247 }; # glider
+chip_select $_, sub { ledi $_ } for 1, 2, 4, 8;
+
+
+update_leds 0;
+
+chip_select 1, sub { route 0,  11 };
+chip_select 2, sub { route 11, 12 };
+chip_select 4, sub { route 12, 13 };
+
+chip_select 2, sub { route 0,  13 };
+chip_select 4, sub { route 13, 12 };
+chip_select 8, sub { route 12, 11 };
+
+chip_select 4, sub { route 0,  11 };
+chip_select 8, sub { route 11, 12 };
+chip_select 1, sub { route 12, 13 };
+
+chip_select 8, sub { route 0,  13 };
+chip_select 1, sub { route 13, 12 };
+chip_select 2, sub { route 12, 11 };
+
+
+sub news_to_mem {
+       my ($dir, $mem) = @_;
+       alu3 alu_zero, alu_select_f, 0, 0, $mem, flag_news($dir), flag_zero
+}
+
+my $and_AB = alu_of_function { $a & $b };
+
+sub compute_neighbour {
+       my ($dest, $dir, $mask, $other) = @_;
+       storei $dest, $mask;
+       alu3 $and_AB, $and_AB, 0, $dest, $dest, flag_zero, flag_zero;
+       news_to_mem $dir, $dest;
+
+       storei $dest + 1, 0xFFFF - $mask;
+       alu3 $and_AB, $and_AB, $other, $dest + 1, $dest + 1, flag_zero, flag_zero;
+       alu3 alu_zero, alus_addAF, $dest, 0, $dest, flag_news($dir), flag_zero
+}
+
+# N neighbour
+compute_neighbour 1, 0, 0x0FFF, $q_south;
+# E neighbour
+compute_neighbour 2, 1, 0xEEEE, $q_east;
+# S neighbour
+compute_neighbour 3, 2, 0xFFF0, $q_south;
+# W neighbour
+compute_neighbour 4, 3, 0x7777, $q_east;
+
+sub compute_diagonal_neighbour {
+       my ($dest, $dir, @masks) = @_;
+       die 'expected exactly 4 @masks' unless @masks == 4;
+       storei $dest, $masks[0];
+       alu3 $and_AB, alu_select_a, 0, $dest, 0, flag_zero, flag_zero;
+       news_to_mem $dir, $dest;
+
+       for my $quad (1 .. 3) {
+               storei $dest + 1, $masks[$quad];
+               alu3 $and_AB, alu_select_a, 10 + $quad, $dest + 1, 10 + $quad, flag_zero, flag_zero;
+               alu3 alu_zero, alus_addAF, $dest, 0, $dest, flag_news($dir), flag_zero;
+       }
+}
+
+#update_leds $q_SE;
+
+# NW neighbour
+compute_diagonal_neighbour 5, 4, 0x0777, 0x0888, 0x7000, 0x8000;
+#update_leds 5;
+# NE neighbour
+compute_diagonal_neighbour 6, 5, 0x0EEE, 0x0111, 0xE000, 0x1000;
+#update_leds 6;
+# SE neighbour
+compute_diagonal_neighbour 7, 6, 0xEEE0, 0x1110, 0x000E, 0x0001;
+#update_leds 7;
+# SW neighbour (DODGY)
+compute_diagonal_neighbour 8, 7, 0x7770, 0x8880, 0x0007, 0x0008;
+#update_leds 8;
+
+sub flag_to_memory {
+       my ($address, $flag) = @_;
+       alu3 alu_zero, alu_select_f, 0, 0, $address, $flag, flag_zero;
+}
+
+# now we add bits mem[1] .. mem[8]
+# result should be mem[1] .. mem[3] (we don't distinguish 8 from 0)
+my $F = 1;
+
+# add 1 and 2, 3 and 4, 5 and 6, 7 and 8
+for my $x (1, 3, 5, 7) {
+       add $x, $x + 1, $x, $F;
+       flag_to_memory $x + 1, $F;
+}
+
+# add 12 and 34, 56 and 78
+for my $x (1, 5) {
+       add $x, $x + 2, $x, $F;
+       addC $x + 1, $x + 3, $x + 1, $F;
+       flag_to_memory $x + 2, $F;
+}
+
+# add 12 and 56
+add 1, 5, 1, $F;
+addC 2, 6, 2, $F;
+# F = F | 3 | 7
+alu3 alu_or, alu_select_a, 3, 7, 3, $F, $F;
+
+# should a new cell be born here? (do we have 3 neighbours?)
+sub alu_birth { alu_of_function {; $a && $b && !$_ } }
+
+# should a living cell survive here? (do we have 2 or 3 neighbours?)
+sub alu_survival { alu_of_function {; $a && !$_  } }
+
+# compute the state of this cell at the next tick
+sub alu_step { alu_of_function {; $_ & ($a | $b) } }
+
+# read from memory 1, and with memory 2 and not F, write into memory 1 (= birth-p)
+alu3 alu_zero, alu_birth, 1, 2, 1, $F, flag_zero;
+# read from memory 2, and with flag not F, write into flag F (= survive-p)
+alu3 alu_survival, alu_select_a, 2, 0, 2, $F, $F;
+# read from memory 0, memory 1, and flag F, write F and (mem0 or mem1) into memory 0
+alu3 alu_zero, alu_step, 0, 1, 0, $F, $F; # also zeroes out flag F
diff --git a/chip.v b/chip.v
index 1ff0d50022a41d9918f528bffdb736e5379e5a9f..12006404f1da684b5c77e5632555219c29bffb89 100644 (file)
--- a/chip.v
+++ b/chip.v
@@ -18,7 +18,7 @@
 `define DIRECTION_W  3'd6
 `define DIRECTION_NW 3'd7
 
-module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, output reg [15:0] mem_in, input [15:0] mem_out, output reg mem_write, output reg [3:0] led_out = 0);
+module chip(input clk, input [2:0] op, input [15:0] I, output reg [15:0] mem_in, input [15:0] mem_out, output reg mem_write, output reg [3:0] led_out = 0);
 
    // parity is unimplemented
 
@@ -37,19 +37,6 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
    wire          edge_ = I[7];
    wire [3:0] cube = I[11:8];
 
-   // OP_ROUTE
-   wire [5:0] cycle = I[5:0];
-   wire [1:0] check = I[7:6];
-   wire [3:0] xor_  = I[11:8];
-   wire [2:0] snarf = I[14:12];
-   wire          odd   = I[15];
-
-   // OP_RUG
-   wire          rw = I[0];
-   wire          ac = I[1];
-   wire          news = I[2];
-   wire [4:0] reg_ = I[8:4];
-
    // OP_LED
    wire          mode   = I[4];
    wire [1:0] offset = I[1:0];
@@ -65,14 +52,13 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
    reg [7:0]  alu_sum = 0;
    reg [7:0]  alu_carry = 0;
    reg [15:0] cube_in;
-   reg                   io;
 
    // these are not really regs
 
    reg [15:0]  alu_sum_out;
    reg [15:0]  alu_carry_out;
 
-   reg [2:0]  alu_index [15:0];
+   reg [2:0]   alu_index [15:0];
 
    reg [15:0]  idx;
 
@@ -114,7 +100,7 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
    reg [15:0]  flag_or_news;
    reg [15:0]  news_out;
 
-   news newspaper (.news_in(latest_news), .direction(flags_addr[1:0]), .news_out(news_out));
+   news newspaper (.news_in(latest_news), .direction(flags_addr[2:0]), .news_out(news_out));
 
    assign flag_or_news = flags_addr[3] ? news_out : flags_out;
 
@@ -135,7 +121,6 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
                         F <= flag_or_news;
                         A <= mem_out;
                         C <= mem_out;
-                        io <= io_pin;
                         if (bsel)
                           B <= cube_in;
                  end
diff --git a/i2c.v b/i2c.v
index 68156179eda6376324d90c5c941cc91e1db36dbb..9620ba05df43f6f6749e937555e2d01c0f8e9140 100644 (file)
--- a/i2c.v
+++ b/i2c.v
@@ -15,12 +15,13 @@ parameter CLOCK_DIVIDE = 1;
 // We transmit a START, then the address (constant 0xE1), then
 // [tx_byte], then [more_bytes] bytes from [mb_in]
 parameter TX_IDLE = 0;
-parameter TX_ADDRESS = 1;
-parameter TX_FIRST_BYTE = 2;
-parameter TX_MORE_BYTES = 3;
-parameter TX_STOP = 4;
+parameter TX_START = 1;
+parameter TX_ADDRESS = 2;
+parameter TX_FIRST_BYTE = 3;
+parameter TX_MORE_BYTES = 4;
+parameter TX_STOP = 5;
 
-reg [10:0] tx_clk_divider = CLOCK_DIVIDE;
+reg [30:0] tx_clk_divider = CLOCK_DIVIDE;
 
 reg data_out = 1'b1;
 reg clk_out = 1'b1;
@@ -31,6 +32,7 @@ reg [3:0] tx_bits_remaining;
 reg [7:0] tx_data;
 
 reg [3:0] step = 0;
+reg [5:0] more_bytes_idx = 0;
 
 wire [7:0]  address = {7'h70, 1'b0}; // address 0x70, write
 wire [15:0] address_data = {address, tx_data};
@@ -38,37 +40,37 @@ wire [15:0] address_data = {address, tx_data};
 assign sda = data_out;
 assign scl = clk_out;
 assign is_transmitting = tx_state != TX_IDLE;
+assign mb_addr = more_bytes_idx;
 
 always @(posedge clk) begin
-       // The clk_divider counter counts down from
-       // the CLOCK_DIVIDE constant. Whenever it
-       // reaches 0, 1/16 of the bit period has elapsed.
-   // Countdown timers for the receiving and transmitting
-       // state machines are decremented.
-       tx_clk_divider = tx_clk_divider - 1;
-       if (!tx_clk_divider) begin
-               tx_clk_divider = CLOCK_DIVIDE;
-               tx_countdown = tx_countdown - 1;
-       end
-
-   // Transmit state machine
-   case (tx_state)
+   if(tx_clk_divider) begin
+         tx_clk_divider <= tx_clk_divider - 1;
+   end else begin
+         tx_clk_divider <= CLOCK_DIVIDE - 1;
+   end
+
+       case (tx_state)
         TX_IDLE: begin
                if (transmit) begin
-                  // If the transmit flag is raised in the idle
-                  // state, save tx_byte for transmission
                   tx_data = tx_byte;
-                  // Send the initial, low pulse of 1 bit period
-                  // to signal the start, followed by the data
-                  data_out = 0;
-                  tx_state = TX_ADDRESS;
                   tx_bits_remaining = 8;
                   step = 0;
+                  tx_state = TX_START;
+                  tx_clk_divider <= CLOCK_DIVIDE - 1;
                end
         end // case: TX_IDLE
 
+        TX_START: begin
+               if(tx_clk_divider) begin end
+               else begin
+                  data_out = 0;
+                  tx_state = TX_ADDRESS;
+               end
+        end
+
         TX_ADDRESS: begin
-               if(step == 0) begin
+               if(tx_clk_divider) begin end
+               else if(step == 0) begin
                   clk_out <= 0;
                   step <= 1;
                end else if (tx_bits_remaining == 0) begin
@@ -97,7 +99,8 @@ always @(posedge clk) begin
         end // case: TX_ADDRESS
 
         TX_FIRST_BYTE: begin
-               if(step == 0) begin
+               if(tx_clk_divider) begin end
+               else if(step == 0) begin
                   clk_out <= 0;
                   step <= 1;
                end else if (tx_bits_remaining == 0) begin
@@ -110,7 +113,12 @@ always @(posedge clk) begin
                   end else begin
                          step <= 0;
 
-                         tx_state <= TX_STOP;
+                         if(more_bytes)
+                               tx_state <= TX_MORE_BYTES;
+                         else
+                               tx_state <= TX_STOP;
+                         tx_bits_remaining <= 8;
+                         more_bytes_idx <= 0;
                   end
                end else if(step == 1) begin
                   data_out <= tx_data[tx_bits_remaining - 1];
@@ -124,8 +132,41 @@ always @(posedge clk) begin
                end
         end // case: TX_FIRST_BYTE
 
+        TX_MORE_BYTES: begin
+               if(tx_clk_divider) begin end
+               else if(step == 0) begin
+                  clk_out <= 0;
+                  step <= 1;
+               end else if (tx_bits_remaining == 0) begin
+                  if(step == 1) begin
+                         data_out <= 0; // really should be z, not 0
+                         step <= 2;
+                  end else if(step == 2)begin
+                         clk_out <= 1;
+                         step <= 3;
+                  end else begin
+                         step <= 0;
+                         tx_bits_remaining <= 8;
+
+                         if(more_bytes_idx == more_bytes)
+                               tx_state <= TX_STOP;
+                         more_bytes_idx <= more_bytes_idx + 1;
+                  end
+               end else if(step == 1) begin
+                  data_out <= mb_in[tx_bits_remaining - 1];
+                  step <= 2;
+               end else if(step == 2) begin
+                  clk_out <= 1;
+                  step <= 3;
+               end else begin // step == 3
+                  tx_bits_remaining = tx_bits_remaining - 1;
+                  step <= 0;
+               end
+        end // case: TX_MORE_BYTES
+
         TX_STOP: begin
-               if(step == 0) begin
+               if(tx_clk_divider) begin end
+               else if(step == 0) begin
                   clk_out <= 0;
                   step <= 1;
                end else if(step == 1) begin
diff --git a/id.pl b/id.pl
new file mode 100644 (file)
index 0000000..3f03d73
--- /dev/null
+++ b/id.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+chip_select 1, sub {
+       storei 0, 0x3;
+};
+
+chip_select 2, sub {
+       storei 0, 0x2;
+};
+
+chip_select 4, sub {
+       storei 0, 0x4;
+};
+
+chip_select 8, sub {
+       storei 0, 0x8;
+};
+
+ledm 0;
diff --git a/ledmatrix.pl b/ledmatrix.pl
new file mode 100644 (file)
index 0000000..576fe92
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+storei 0, 0xF;
+route 0, 9, 1;
+ledi 1;
+news_mm 0, 1, -1, 0;
+route 1, 9, 1;
+ledi 2;
+news_mm 1, 2, -1, 0;
+route 2, 9, 1;
+ledi 4;
+news_mm 2, 3, -1, 0;
+route 3, 9, 1;
+ledi 8;
index 037381f98b46e27d5e1c22987e52904fdb50845f..b2de457f660f483e5f53e73277a8694c30003225 100644 (file)
@@ -10,6 +10,12 @@ set_io led[4] 95
 # 12 MHz clock
 set_io CLKin 21
 
+set_io uart_tx 79
+set_io -pullup yes uart_rx 88
+
+set_io busy_out 87
+set_io -pullup yes busy_in 78
+
 # i2c to led matrix
 set_io scl 80 # PIO1_04
 set_io sda 81 # PIO1_05
index f76bfb1a9fcd11920b74597c1a02190d8c588ed7..a009ce2c74099540bddc75c6f422705042b99134 100644 (file)
--- a/master.v
+++ b/master.v
+`include "pll.v"
 `include "master_rom.v"
 `include "i2c.v"
 `include "uart.v"
 
 `ifdef SIM
  `define UART_DIVIDE 1
+ `define I2C_DIVIDE 4
 `else
- `define UART_DIVIDE 1
- // s/192/3/ for 19200 baud uart
+ `define UART_DIVIDE 2048
+ `define I2C_DIVIDE 256
 `endif
 
-module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, output reg ready_out = 1, input ready_in, output scl, output sda);
-//   wire clk;
-//   wire clk_tmp;
+module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, output reg busy_out = 0, input busy_in, output scl, output sda);
+   wire clk;
 
-   //pll pll (.clock_in(CLKin), .clock_out(clk));
+   assign clk = CLKin;
 
-   reg [20:0] counter = 0;
+   // ROM
 
-`ifdef SIM
-   wire clk = CLKin;
-`else
-   reg                   clk = 0;
+   reg [7:0] program_counter = 0;
+   // go here at end of program
+   reg [7:0] main = 1;
+   wire [31:0] rom_output;
 
-   always @ (posedge CLKin) begin
-         if(counter == 5000) begin
-                counter <= 0;
-                clk <= 1 - clk;
-         end
-         else
-               counter <= counter + 1;
+   master_rom master_rom (.clk(clk), .addr(program_counter), .data(rom_output));
+
+   wire [2:0]  rom_op = rom_output[26:24];
+   wire [2:0]  rom_led = rom_output[14:12];
+   wire [3:0]  rom_chip_select = rom_output[31:28];
+
+   // if the 4th board won't execute this instruction,
+   // then we won't receive propagation or news
+   wire           dont_wait = !rom_chip_select[3];
+   reg [25:0]  dont_send = 23'b11111111111111111111111;
+
+   always @(posedge clk) begin
+         if(busy_in)
+               dont_send <= 23'b11111111111111111111111;
+         else if(dont_send)
+               dont_send <= dont_send - 1;
    end
-`endif
 
-   reg [3:0] program_counter = 0;
-   wire [31:0] rom_output;
+   // state
 
-   master_rom master_rom (.clk(clk), .addr(program_counter), .data(rom_output));
+`define STATE_SEND 0
+`define STATE_WAIT_PROPAGATE 1
+`define STATE_WAIT_NEWS 2
+`define STATE_PROPAGATE_NEWS 3
+`define STATE_SET_LEDS 4
+`define STATE_WASTE_TIME 5
+
+   reg [5:0] state = `STATE_SEND;
+   reg [5:0] uart_ptr = 0;
+
+   reg [30:0]  waste_counter = 0;
+   reg [7:0]   saved_news [3:0];
+   reg [7:0]   sent_byte [3:0];
+
+   reg [7:0]   bytes_sent = 0;
+
+   // i2c
+   reg [15:0]  leds [3:0];
+
+   initial begin
+         leds[0] <= 16'hF00F;
+         leds[1] <= 16'h0000;
+         leds[2] <= 16'h0000;
+         leds[3] <= 16'hFFFF;
+   end
+
+   /* even rows are green, odd rows are red:
+    * mb_leds[2 * k] is the kth row of green leds
+       * mb_leds[2 * k + 1] is the kth row of red leds
+       */
+   wire [7:0] mb_leds [15:0];
+
+   // all red leds are off
+   assign mb_leds[1] = program_counter;
+   assign mb_leds[3] = 0;
+   assign mb_leds[5] = state;
+   assign mb_leds[7] = uart_ptr;
+   assign mb_leds[9] = 0;
+   assign mb_leds[11] = 0;
+   assign mb_leds[13] = 0;
+   assign mb_leds[15] = 0;
+
+   // green leds, first half
+   assign mb_leds[0] = {leds[1][3:0],   leds[0][3:0]};
+   assign mb_leds[2] = {leds[1][7:4],   leds[0][7:4]};
+   assign mb_leds[4] = {leds[1][11:8],  leds[0][11:8]};
+   assign mb_leds[6] = {leds[1][15:12], leds[0][15:12]};
+
+   // green leds, second half
+   assign mb_leds[8]  = {leds[3][3:0],   leds[2][3:0]};
+   assign mb_leds[10] = {leds[3][7:4],   leds[2][7:4]};
+   assign mb_leds[12] = {leds[3][11:8],  leds[2][11:8]};
+   assign mb_leds[14] = {leds[3][15:12], leds[2][15:12]};
+
+   wire [7:0]  mb_in;
+   wire [5:0]  mb_addr;
+   assign mb_in = mb_leds[mb_addr];
 
    reg [7:0]   i2c_tx_byte;
+   reg [5:0]   more_bytes = 0;
    reg                    i2c_transmit = 0;
    wire           i2c_is_transmitting;
 
-   i2c_write i2c (.clk(clk), .scl(scl), .sda(sda), .tx_byte(i2c_tx_byte), .transmit(i2c_transmit), .is_transmitting(i2c_is_transmitting));
+   i2c_write #(.CLOCK_DIVIDE(`I2C_DIVIDE)) i2c (.clk(clk), .scl(scl), .sda(sda), .tx_byte(i2c_tx_byte), .transmit(i2c_transmit), .is_transmitting(i2c_is_transmitting), .more_bytes(more_bytes), .mb_in(mb_in), .mb_addr(mb_addr));
 
    reg [3:0]   i2c_init_step = 0;
 
@@ -54,27 +119,25 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
                        i2c_transmit <= 1;
                        i2c_init_step <= 1;
                 end else if(i2c_init_step == 1) begin
-                       i2c_tx_byte <= 8'h87; // display on, blink 0.5Hz
+                       i2c_tx_byte <= 8'h81; // display on, blink off
                        i2c_transmit <= 1;
                        i2c_init_step <= 2;
                 end else if(i2c_init_step == 2) begin
                        i2c_tx_byte <= 8'hEF; // max brightness
                        i2c_transmit <= 1;
                        i2c_init_step <= 3;
+                end else if(i2c_init_step == 3) begin
+                       i2c_tx_byte <= 0;
+                       more_bytes <= 16;
+                       i2c_transmit <= 1;
+                       i2c_init_step <= 4;
+                end else begin
+                       i2c_transmit <= 1;
                 end
          end
    end
 
 
-`define STATE_SEND 0
-`define STATE_WAIT_PROPAGATE 1
-`define STATE_WAIT_NEWS 2
-`define STATE_PROPAGATE_NEWS 3
-`define STATE_WASTE_TIME 4
-
-   reg [5:0] state = `STATE_SEND;
-   reg [5:0] uart_ptr = 0;
-
    wire           received;
    wire [7:0]  rx_byte;
    reg                    transmit = 0;
@@ -82,15 +145,22 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
    wire           is_receiving;
    wire           is_transmitting;
 
-   // 19200 (actually 300) baud uart
    uart #(.CLOCK_DIVIDE(`UART_DIVIDE)) uart (.clk(clk), .rx(uart_rx), .tx(uart_tx), .received(received), .transmit(transmit), .tx_byte(tx_byte), .rx_byte(rx_byte), .is_receiving(is_receiving), .is_transmitting(is_transmitting));
 
-   reg [15:0]  waste_counter = 0;
+   assign led[4] = state != `STATE_WASTE_TIME;
+//   assign led[2:0] = rom_op == 6 ? rom_led : 0;
+//   assign led[3] = refresh_leds || i2c_is_transmitting;
+//   assign led[0] = (leds[0] == 16'h000f);
+//   assign led[1] = (leds[0] == 16'h00f0);
+//   assign led[2] = (leds[0] == 16'h0111);
+//   assign led[3] = (leds[0] == 16'hf00f);
 
-   reg [7:0]   saved_news [3:0];
 
-   assign led[4] = state != `STATE_WASTE_TIME;
-   assign led[3:0] = i2c_init_step;
+   //assign led[3:0] = saved_news[0][3:0];
+   //assign led[3:0] = program_counter[3:0];
+   assign led[0] = dont_send;
+   assign led[1] = dont_wait;
+   assign led[2] = is_transmitting;
 
    always @(posedge clk) begin
          case(state)
@@ -98,15 +168,18 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
                   if(transmit) begin
                          transmit <= 0;
                   end else if(uart_ptr == 4) begin
-                         program_counter <= program_counter + 1;
                          uart_ptr <= 0;
-                         if(rom_output[26:24] == 6) // `OP_ROUTE
+                         if(dont_wait)
+                               state <= `STATE_WASTE_TIME;
+                         else if(rom_op == 6) // `OP_ROUTE
                                state <= `STATE_WAIT_NEWS;
                          else
                                state <= `STATE_WAIT_PROPAGATE;
-                  end else if(!is_transmitting && ready_in) begin
+                  end else if(!is_transmitting && !dont_send) begin
                          tx_byte <= rom_output[uart_ptr * 8 +: 8];
+                         sent_byte[uart_ptr] <= rom_output[uart_ptr * 8 +: 8];
                          transmit <= 1;
+                         bytes_sent <= bytes_sent + 1;
                          uart_ptr <= uart_ptr + 1;
                   end
                end
@@ -118,8 +191,12 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
                end
 
                `STATE_WASTE_TIME: begin
-                  if(waste_counter == 100) begin
+                  if(waste_counter == 50000) begin
                          waste_counter <= 0;
+                         if(program_counter == 255)
+                               program_counter <= main;
+                         else
+                               program_counter <= program_counter + 1;
                          state <= `STATE_SEND;
                   end else
                         waste_counter <= waste_counter + 1;
@@ -143,15 +220,22 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
                end // case: `STATE_WAIT_NEWS
 
                `STATE_PROPAGATE_NEWS: begin
-                  if(uart_ptr == 4) begin
+                  if(transmit) begin
+                         transmit <= 0;
+                  end else if(uart_ptr == 4) begin
+                         if(rom_led) begin
+                                leds[rom_led - 1] <= (saved_news[1] << 8) + saved_news[0];
+                         end
                          state <= `STATE_WASTE_TIME;
                          uart_ptr <= 0;
-                  end else if(!is_transmitting && ready_in) begin
+                  end else if(!is_transmitting && !dont_send) begin
                          tx_byte <= saved_news[uart_ptr];
+                         sent_byte[uart_ptr] <= saved_news[uart_ptr];
                          transmit <= 1;
+                         bytes_sent <= bytes_sent + 1;
                          uart_ptr <= uart_ptr + 1;
                   end
-               end
+               end // case: `STATE_PROPAGATE_NEWS
          endcase
    end
 
index 0fc52ddd16f4cf194f7b79304d239d65fac2683a..a088c87dc5d204e2206369f5d9ddb601716b2ee1 100644 (file)
@@ -1,25 +1,11 @@
 // ROM module with single input addr, output port, and clock input.
 // Data is clocked out of the ROM on positive clock edges.
 
-module master_rom (input clk, input [3:0] addr, output reg [31:0] data);
+module master_rom (input clk, input [7:0] addr, output reg [31:0] data);
+   reg [31:0] rom [0:255];
+   initial $readmemh("code.hex", rom);
+
    always @ (posedge clk) begin
-      case(addr)
-0: data <= 32'h04000004;
-1: data <= 32'h04010002;
-2: data <= 32'h07010010;
-3: data <= 32'h00000000;
-4: data <= 32'h00000000;
-5: data <= 32'h06000001;
-6: data <= 32'h07010010;
-7: data <= 32'h00000000;
-8: data <= 32'h00000000;
-9: data <= 32'h04010003;
-10: data <= 32'h07010010;
-11: data <= 32'h00000000;
-12: data <= 32'h00000000;
-13: data <= 32'h06000001;
-14: data <= 32'h07010010;
-15: data <= 32'h00000000;
-         endcase
+         data <= rom[addr];
    end
 endmodule
diff --git a/news.v b/news.v
index b0d34a78bbfc328e37f5120a84ea048909597fc0..73c750718631e08ed220a4fbd7072471bcdcba03 100644 (file)
--- a/news.v
+++ b/news.v
@@ -1,10 +1,14 @@
-module news(input clk, input [15:0] news_in, input [1:0] direction, output [15:0] news_out);
-   always @(posedge clk) begin
+module news(input clk, input [15:0] news_in, input [2:0] direction, output [0:15] news_out);
+   always @* begin
                 case (direction)
-0: news_out = {news_in[12], news_in[13], news_in[14], news_in[15], news_in[ 0], news_in[ 1], news_in[ 2], news_in[ 3], news_in[ 4], news_in[ 5], news_in[ 6], news_in[ 7], news_in[ 8], news_in[ 9], news_in[10], news_in[11]};
-1: news_out = {news_in[ 1], news_in[ 2], news_in[ 3], news_in[ 0], news_in[ 5], news_in[ 6], news_in[ 7], news_in[ 4], news_in[ 9], news_in[10], news_in[11], news_in[ 8], news_in[13], news_in[14], news_in[15], news_in[12]};
-2: news_out = {news_in[ 4], news_in[ 5], news_in[ 6], news_in[ 7], news_in[ 8], news_in[ 9], news_in[10], news_in[11], news_in[12], news_in[13], news_in[14], news_in[15], news_in[ 0], news_in[ 1], news_in[ 2], news_in[ 3]};
-3: news_out = {news_in[ 3], news_in[ 0], news_in[ 1], news_in[ 2], news_in[ 7], news_in[ 4], news_in[ 5], news_in[ 6], news_in[11], news_in[ 8], news_in[ 9], news_in[10], news_in[15], news_in[12], news_in[13], news_in[14]};
+0: news_out = {news_in[11], news_in[10], news_in[ 9], news_in[ 8], news_in[ 7], news_in[ 6], news_in[ 5], news_in[ 4], news_in[ 3], news_in[ 2], news_in[ 1], news_in[ 0], news_in[15], news_in[14], news_in[13], news_in[12]};
+1: news_out = {news_in[12], news_in[15], news_in[14], news_in[13], news_in[ 8], news_in[11], news_in[10], news_in[ 9], news_in[ 4], news_in[ 7], news_in[ 6], news_in[ 5], news_in[ 0], news_in[ 3], news_in[ 2], news_in[ 1]};
+2: news_out = {news_in[ 3], news_in[ 2], news_in[ 1], news_in[ 0], news_in[15], news_in[14], news_in[13], news_in[12], news_in[11], news_in[10], news_in[ 9], news_in[ 8], news_in[ 7], news_in[ 6], news_in[ 5], news_in[ 4]};
+3: news_out = {news_in[14], news_in[13], news_in[12], news_in[15], news_in[10], news_in[ 9], news_in[ 8], news_in[11], news_in[ 6], news_in[ 5], news_in[ 4], news_in[ 7], news_in[ 2], news_in[ 1], news_in[ 0], news_in[ 3]};
+4: news_out = {news_in[10], news_in[ 9], news_in[ 8], news_in[11], news_in[ 6], news_in[ 5], news_in[ 4], news_in[ 7], news_in[ 2], news_in[ 1], news_in[ 0], news_in[ 3], news_in[14], news_in[13], news_in[12], news_in[15]};
+5: news_out = {news_in[ 8], news_in[11], news_in[10], news_in[ 9], news_in[ 4], news_in[ 7], news_in[ 6], news_in[ 5], news_in[ 0], news_in[ 3], news_in[ 2], news_in[ 1], news_in[12], news_in[15], news_in[14], news_in[13]};
+6: news_out = {news_in[ 0], news_in[ 3], news_in[ 2], news_in[ 1], news_in[12], news_in[15], news_in[14], news_in[13], news_in[ 8], news_in[11], news_in[10], news_in[ 9], news_in[ 4], news_in[ 7], news_in[ 6], news_in[ 5]};
+7: news_out = {news_in[ 2], news_in[ 1], news_in[ 0], news_in[ 3], news_in[14], news_in[13], news_in[12], news_in[15], news_in[10], news_in[ 9], news_in[ 8], news_in[11], news_in[ 6], news_in[ 5], news_in[ 4], news_in[ 7]};
                 endcase
 
    end
index cbfbbd7da0594d2ab3b80800f418729e5a84e888..67957b8d8da967c0e78d3dd9446823630b007219 100644 (file)
@@ -4,13 +4,13 @@ use warnings;
 
 my @diffs = (
        [-1,  0],
-#      [-1,  1],
        [0 ,  1],
-#      [1 ,  1],
        [1 ,  0],
-#      [1 , -1],
        [0 , -1],
-#      [-1, -1]
+       [-1, -1],
+       [-1,  1],
+       [1 ,  1],
+       [1 , -1],
 );
 
 my @cpus;
@@ -35,8 +35,9 @@ for my $cpu (0 .. ($side * $side - 1)) {
 
 for my $direction (0 .. $#diffs) {
        print "$direction: news_out = {";
-       printf 'news_in[%2d]', $newstable[0][$direction];
-       for my $cpu (1 .. ($side * $side - 1)) {
+       printf 'news_in[%2d]', $newstable[$side * $side - 1][$direction];
+       my @lst = 0 .. ($side * $side - 2);
+       for my $cpu (reverse @lst) {
                printf ', news_in[%2d]', $newstable[$cpu][$direction];
        }
        say '};'
diff --git a/progall.sh b/progall.sh
new file mode 100644 (file)
index 0000000..9be606f
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+for i in `seq 1 $(lsusb | grep -c 6010)`
+do tools/icestorm/iceprog/iceprog -d i:0x0403:0x6010:$(($i - 1)) toplevel.bin
+done
diff --git a/tinyledmatrix.pl b/tinyledmatrix.pl
new file mode 100644 (file)
index 0000000..b1899ce
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+storei 0, 0xF;
+route 0, 1, 1;
+nop;
+nop;
+nop;
+nop;
+nop;
+storei 0, 0xF0;
+route 0, 1, 1;
+nop;
+nop;
+nop;
+nop;
+nop;
+storei 0, 0x111;
+route 0, 1, 1;
+nop;
+nop;
+nop;
+nop;
+nop;
diff --git a/uart.v b/uart.v
index 6db365089599f3b0eeaa0982b3648ddf4fe967d7..4db8881b3f256a921cf626d5c7debd012a028716 100644 (file)
--- a/uart.v
+++ b/uart.v
@@ -53,8 +53,8 @@ parameter TX_IDLE = 0;
 parameter TX_SENDING = 1;
 parameter TX_DELAY_RESTART = 2;
 
-reg [10:0] rx_clk_divider = CLOCK_DIVIDE;
-reg [10:0] tx_clk_divider = CLOCK_DIVIDE;
+reg [21:0] rx_clk_divider = CLOCK_DIVIDE;
+reg [21:0] tx_clk_divider = CLOCK_DIVIDE;
 
 reg [2:0] recv_state = RX_IDLE;
 reg [5:0] rx_countdown;
diff --git a/worker.pcf b/worker.pcf
new file mode 100644 (file)
index 0000000..574efb6
--- /dev/null
@@ -0,0 +1,19 @@
+# Red LEDs
+set_io led[0] 99
+set_io led[1] 98
+set_io led[2] 97
+set_io led[3] 96
+
+# Green LED
+set_io led[4] 95
+
+# 12 MHz clock
+set_io CLKin 21
+
+set_io uart_tx 79
+set_io -pullup yes uart_rx 88
+
+set_io busy_out 87
+set_io -pullup yes busy_in 78
+
+set_io -pullup yes is_worker 91
\ No newline at end of file
index e8552d0b43b87f2629d7837bc7681d54c754701f..9a7760e5d07f2f19eddfd00b4abfd25b869581c6 100644 (file)
--- a/worker.v
+++ b/worker.v
@@ -6,34 +6,49 @@
 `ifdef SIM
  `define UART_DIVIDE 1
 `else
- `define UART_DIVIDE 1
- // s/192/3/ for 19200 baud uart
+ `define UART_DIVIDE 2048
 `endif
 
-module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, output reg ready_out = 1, input ready_in);
-   wire clk;
-   wire clk_tmp;
-
-   //pll pll (.clock_in(CLKin), .clock_out(clk));
+module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, output reg busy_out = 1, input busy_in, input is_worker);
+   wire clk = CLKin;
 
-   reg [20:0] counter = 0;
+`ifndef SIM
+   // if [is_worker == 0], boot into master image
+   SB_WARMBOOT wb (.BOOT (!is_worker), .S0(1'b1), .S1(1'b0));
+`endif
 
-   reg                   clk = 0;
+`ifdef SIM
+   wire dont_send = 0;
+`else
+   reg [25:0]  dont_send = 23'b11111111111111111111111;
 
-   always @ (posedge CLKin) begin
-         if(counter == 5000) begin
-                counter <= 0;
-                clk <= 1 - clk;
-         end
-         else
-               counter <= counter + 1;
+   always @(posedge clk) begin
+         if(busy_in)
+               dont_send <= 23'b11111111111111111111111;
+         else if(dont_send)
+               dont_send <= dont_send - 1;
    end
+`endif
 
    wire [11:0] mem_addr;
    wire [15:0] mem_in;
    wire [15:0] mem_out;
    wire           mem_write;
 
+   reg [31:0]  the_rom [0:100];
+   reg [10:0]  rom_pc = 0;
+
+   initial begin
+         the_rom[0] <= 32'hfC000005;
+         the_rom[1] <= 32'hfC010007;
+         the_rom[2] <= 32'hf9001d00;
+         the_rom[3] <= 32'hfA0112d0;
+         the_rom[4] <= 32'hfB000004;
+         the_rom[5] <= 32'hf9000004;
+         the_rom[6] <= 32'hfA001550;
+         the_rom[7] <= 32'hfB010000;
+   end
+
    RAM #(.ADDRESS_BITS(8)) ram (.clk(clk), .write(mem_write), .addr(mem_addr), .in(mem_in), .out(mem_out));
 
    reg [7:0]   from_uart [3:0];
@@ -42,7 +57,18 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    wire [15:0] I  = {from_uart[1], from_uart[0]};
    assign mem_addr = from_uart[2];
    wire [2:0]  op_from_uart = from_uart[3][2:0];
-   wire           CS = from_uart[3][3];
+
+   wire [3:0]  chip_select = from_uart[3][7:4];
+   wire           is_virtual = from_uart[3][3];
+   wire           dont_propagate = is_virtual || ~| chip_select;
+   wire           not_for_us = !chip_select[0];
+
+   wire [7:0]   to_uart [3:0];
+   wire [3:0]   next_chip_select = {0, chip_select[3:1]};
+   assign to_uart[0] = from_uart[0];
+   assign to_uart[1] = from_uart[1];
+   assign to_uart[2] = from_uart[2];
+   assign to_uart[3] = {next_chip_select, from_uart[3][3:0]};
 
    /* to execute a ROUTE instruction, we send our neighbour a STOREI
    /* instruction with the correct address and value. This is the
@@ -51,18 +77,17 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    assign route_storei[0] = mem_out[7:0];
    assign route_storei[1] = mem_out[15:8];
    assign route_storei[2] = from_uart[0];
-   assign route_storei[3] = 3'd4; // OP_STOREI
+   assign route_storei[3] = 8'h1C; // chip_select = 1, is_virtual = 1, op = OP_STOREI
 
    reg [2:0]   op = 0;
 
    reg [2:0]   last_op = 0;
 
    reg [15:0]  I;
-   reg                    CS;
 
    reg [3:0]   led_out;
 
-   chip chip (.clk(clk), .op(op), .I(I), .io_pin(0), .CS(CS), .mem_in(mem_in), .mem_out(mem_out), .mem_write(mem_write), .led_out(led_out));
+   chip chip (.clk(clk), .op(op), .I(I), .mem_in(mem_in), .mem_out(mem_out), .mem_write(mem_write), .led_out(led_out));
 
    wire           received;
    wire [7:0]  rx_byte;
@@ -70,19 +95,20 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    reg  [7:0]  tx_byte = 0;
    wire           is_receiving;
    wire           is_transmitting;
+   wire           recv_error;
 
-   // 19200 (actually 300) baud uart
-   uart #(.CLOCK_DIVIDE(`UART_DIVIDE)) uart (.clk(clk), .rx(uart_rx), .tx(uart_tx), .received(received), .transmit(transmit), .tx_byte(tx_byte), .rx_byte(rx_byte), .is_receiving(is_receiving), .is_transmitting(is_transmitting));
+   uart #(.CLOCK_DIVIDE(`UART_DIVIDE)) uart (.clk(clk), .rx(uart_rx), .tx(uart_tx), .received(received), .transmit(transmit), .tx_byte(tx_byte), .rx_byte(rx_byte), .is_receiving(is_receiving), .is_transmitting(is_transmitting), .recv_error(recv_error));
 
 `define STATE_IDLE 0
 `define STATE_PROPAGATE 1
-`define STATE_EXECUTE 2
-`define STATE_ROUTE 3
+`define STATE_PREEXEC 2
+`define STATE_EXECUTE 3
+`define STATE_ROUTE 4
 
-   reg [5:0]   state = `STATE_IDLE;
+   reg [3:0]   state = `STATE_IDLE;
 
-   assign led[3:0] = led_out;
-   assign led[4] = 0;
+   assign led[3:0] = uart_ptr;
+   assign led[4] = is_receiving;
 
    always @ (posedge clk) begin
          case(state)
@@ -90,14 +116,27 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
                   if(uart_ptr == 4) begin
                          last_op <= op_from_uart;
                          uart_ptr <= 0;
-                         state <= `STATE_PROPAGATE;
-                         ready_out <= 0;
+                         if(dont_propagate)
+                               state <= `STATE_PREEXEC;
+                         else
+                               state <= `STATE_PROPAGATE;
+                         busy_out <= 1;
                   end
                   else if (received) begin
                          from_uart[uart_ptr] <= rx_byte;
                          uart_ptr <= uart_ptr + 1;
-                  end else
-                        ready_out <= 1;
+                  end else begin
+`ifdef SIM
+                         from_uart[0] <= the_rom[rom_pc][7:0];
+                         from_uart[1] <= the_rom[rom_pc][15:8];
+                         from_uart[2] <= the_rom[rom_pc][23:16];
+                         from_uart[3] <= the_rom[rom_pc][31:24];
+                         uart_ptr <= 4;
+                         rom_pc <= rom_pc + 1;
+`else
+                         busy_out <= 0;
+`endif
+                  end
                end
 
                `STATE_PROPAGATE: begin
@@ -105,18 +144,23 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
                          transmit <= 0;
                   else if(uart_ptr == 4) begin
                          uart_ptr <= 0;
-                         the_leds <= last_op;
-                         if(last_op == `OP_ROUTE) begin
-                                state <= `STATE_ROUTE;
-                         end else begin
-                                op <= last_op;
-                                state <= `STATE_EXECUTE;
-                         end
-                  end else if(!is_transmitting && ready_in) begin
-                         tx_byte <= from_uart[uart_ptr];
+                         state <= `STATE_PREEXEC;
+                  end else if(!is_transmitting && !dont_send) begin
+                         tx_byte <= to_uart[uart_ptr];
                          transmit <= 1;
                          uart_ptr <= uart_ptr + 1;
                   end
+               end // case: `STATE_PROPAGATE
+
+               `STATE_PREEXEC: begin
+                  if(not_for_us) begin
+                         state <= `STATE_IDLE;
+                  end else if(last_op == `OP_ROUTE) begin
+                         state <= `STATE_ROUTE;
+                  end else begin
+                         op <= last_op;
+                         state <= `STATE_EXECUTE;
+                  end
                end
 
                `STATE_EXECUTE: begin
@@ -130,7 +174,7 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
                   else if(uart_ptr == 4) begin
                          uart_ptr <= 0;
                          state <= `STATE_IDLE;
-                  end else if(!is_transmitting && ready_in) begin
+                  end else if(!is_transmitting && !dont_send) begin
                          tx_byte <= route_storei[uart_ptr];
                          transmit <= 1;
                          uart_ptr <= uart_ptr + 1;
@@ -138,6 +182,4 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
                end
          endcase
    end
-
-//   wire ready = (state == 0 && !is_receiving);
 endmodule
This page took 0.038771 seconds and 4 git commands to generate.