implement routing + storei instruction
authorMarius Gavrilescu <marius@ieval.ro>
Mon, 15 Apr 2019 19:45:53 +0000 (22:45 +0300)
committerMarius Gavrilescu <marius@ieval.ro>
Mon, 15 Apr 2019 19:45:53 +0000 (22:45 +0300)
12 files changed:
asm.pm
blink.pl [new file with mode: 0644]
cells.pl
chip.v
master.v
master_rom.v
news.v
newsled.pl [new file with mode: 0644]
newstable.pl
ram.v
sim.c [new file with mode: 0644]
worker.v

diff --git a/asm.pm b/asm.pm
index 492bfccc1e2764dce4e1a4c0f20a3f615a17e854..269b8d1d49d62963131325ce32f42e95e1e0f3ca 100644 (file)
--- a/asm.pm
+++ b/asm.pm
@@ -7,10 +7,10 @@ use constant +{
        OP_LOADA => 1,
        OP_LOADB => 2,
        OP_STORE => 3,
-       OP_READ => 4,
+       OP_STOREI => 4,
        OP_LOADI => 5,
        OP_ROUTE => 6,
-       OP_RUG => 7,
+       OP_LED => 7,
 };
 
 q,
@@ -28,19 +28,22 @@ $port->read_const_time(2000);
 $port->write_settings or die "$!";
 ,;
 
-use Fcntl;
+#use Fcntl;
 use Time::HiRes qw/sleep/;
 
-sysopen my $port, '/dev/ttyUSB1', O_SYNC | O_RDWR or die "$!";
+my $port;
+#sysopen $port, '/dev/ttyUSB1', O_SYNC | O_RDWR or die "$!";
 
 
 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/;
-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/;
+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/;
 
 use File::Slurp::Tiny 'write_file';
 
-sub send_ {
+=begin comment
+
+sub send__ {
        my ($cmd) = @_;
        my %cmd = %$cmd;
 
@@ -60,6 +63,29 @@ sub send_ {
        }
 }
 
+=end
+
+
+=cut
+
+my $rom_cnt = 0;
+
+sub send_ {
+       my ($cmd) = @_;
+       my %cmd = %$cmd;
+
+       my $binary = pack 'vCC', @cmd{qw/I mem_addr op/}; # we ignore CS for now
+       my $hex = reverse unpack 'h*', $binary;
+       say "$rom_cnt: data <= 32'h$hex;";
+       $rom_cnt++;
+}
+
+
+sub nop {
+       send_
+         { I => 0, mem_addr => 0, op => OP_NOP, CS => 0 }
+  }
+
 sub loada {
        my ($addr, $flagr, $bsel, $aluc) = @_;
        my $I = 0;
@@ -80,10 +106,10 @@ sub loadb {
          { I => $I, mem_addr => $addr, op => OP_LOADB, CS => 0 }
   }
 
-sub read_ {
-       my ($addr) = @_;
-       send_ { I => 0, mem_addr => $addr, op => OP_READ, CS => 1 }
-}
+#sub read_ {
+#      my ($addr) = @_;
+#      send_ { I => 0, mem_addr => $addr, op => OP_READ, CS => 1 }
+#}
 
 sub store {
        my ($addr, $flagw, $edge_, $cube) = @_;
@@ -101,6 +127,37 @@ sub loadi {
          { I => $I, mem_addr => $addr, op => OP_LOADI, CS => 0 }
 }
 
+sub route {
+       my ($addr, $dest_addr) = @_;
+       my $I = $dest_addr;
+       send_
+         { I => $I, mem_addr => $addr, op => OP_ROUTE, CS => 0 }
+}
+
+sub storei {
+       my ($addr, $I) = @_;
+       send_
+         { I => $I, mem_addr => $addr, op => OP_STOREI, CS => 0 }
+}
+
+sub led {
+       my ($addr, $mode, $offset_leds) = @_;
+       my $I = $offset_leds;
+       $I |= $mode << 4;
+       send_
+         { I => $I, mem_addr => $addr, op => OP_LED, CS => 0 }
+}
+
+sub ledm {
+       my ($addr, $offset) = @_;
+       led $addr, 1, $offset;
+}
+
+sub ledi {
+       my ($leds) = @_;
+       led 0, 0, $leds;
+}
+
 sub flag_zero { 0 }
 sub flag_temp { 7 }
 
@@ -227,3 +284,5 @@ sub news_ff {
        alu3 alu_select_f, alu_select_a, 0, 0, 0, $flagIN, flag_zero;
        news_generic $nX, $nY, {flag => $flagOUT};
 }
+
+1;
diff --git a/blink.pl b/blink.pl
new file mode 100644 (file)
index 0000000..9aac0fe
--- /dev/null
+++ b/blink.pl
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+for (1 .. 3) {
+       ledi 1;
+       ledi 2;
+       ledi 4;
+       ledi 8;
+}
+nop;
+nop;
+nop;
+nop;
index c8a936a8c3e09670f5f23457434772bf8ecaa070..68c0f9e81b7e0e143724589373d9fd5b4744d8f8 100644 (file)
--- a/cells.pl
+++ b/cells.pl
@@ -28,7 +28,7 @@ sub read_write_two_ways {
 }
 
 sub conway_step {
-       say "CONWAY STEP";
+       #say "CONWAY STEP";
        # write memory 0 to news
        # read from news direction 0 into memory 1
        # write memory 0 to news
@@ -106,7 +106,7 @@ sub conway_step {
 #      read_ 5;
 #      read_ 6;
 
-       sleep 10;
+       #sleep 10;
 }
 
 $| = 1;
@@ -119,7 +119,7 @@ loadi 0, 0x2022;
 store 0, flag_zero, 0, 0;
 read_ 0;
 read_ 0;
-sleep 10;
+#sleep 10;
 
 conway_step;
 conway_step;
diff --git a/chip.v b/chip.v
index b29fde674e49645d41ad06993427028e448a4612..1ff0d50022a41d9918f528bffdb736e5379e5a9f 100644 (file)
--- a/chip.v
+++ b/chip.v
@@ -1,13 +1,13 @@
 `include "news.v"
 
-`define OP_NOP   3'd0
-`define OP_LOADA 3'd1
-`define OP_LOADB 3'd2
-`define OP_STORE 3'd3
-`define OP_READ  3'd4
-`define OP_LOADI 3'd5
-`define OP_ROUTE 3'd6
-`define OP_RUG   3'd7
+`define OP_NOP    3'd0
+`define OP_LOADA  3'd1
+`define OP_LOADB  3'd2
+`define OP_STORE  3'd3
+`define OP_STOREI 3'd4
+`define OP_LOADI  3'd5
+`define OP_ROUTE  3'd6
+`define OP_LED    3'd7
 
 `define DIRECTION_N  3'd0
 `define DIRECTION_NE 3'd1
@@ -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 [63:0] mem_in, input [63:0] mem_out, output reg mem_write);
+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);
 
    // parity is unimplemented
 
@@ -50,29 +50,34 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
    wire          news = I[2];
    wire [4:0] reg_ = I[8:4];
 
+   // OP_LED
+   wire          mode   = I[4];
+   wire [1:0] offset = I[1:0];
+   wire [3:0] leds   = I[3:0];
 
-   reg [63:0] A = 0;
-   reg [63:0] B = 0;
-   reg [63:0] C = 0;
-   reg [63:0] F = 0;
-   reg [63:0] Cond = 0;
-   reg [63:0] R = 0;
+
+   reg [15:0] A = 0;
+   reg [15:0] B = 0;
+   reg [15:0] C = 0;
+   reg [15:0] F = 0;
+   reg [15:0] Cond = 0;
+   reg [15:0] R = 0;
    reg [7:0]  alu_sum = 0;
    reg [7:0]  alu_carry = 0;
-   reg [63:0] cube_in;
+   reg [15:0] cube_in;
    reg                   io;
 
    // these are not really regs
 
-   reg [63:0]  alu_sum_out;
-   reg [63:0]  alu_carry_out;
+   reg [15:0]  alu_sum_out;
+   reg [15:0]  alu_carry_out;
 
-   reg [2:0]  alu_index [63:0];
+   reg [2:0]  alu_index [15:0];
 
    reg [15:0]  idx;
 
    always @* begin
-         for(idx = 0; idx < 64; idx=idx+1) begin
+         for(idx = 0; idx < 16; idx=idx+1) begin
                 alu_index[idx] = (A[idx] << 2) + (B[idx] << 1) + F[idx];
                 alu_sum_out[idx] <= alu_sum[alu_index[idx]];
                 alu_carry_out[idx] <= alu_carry[alu_index[idx]];
@@ -98,16 +103,16 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
                endcase
    end // always @ *
 
-   reg  [63:0] flags_in;
-   wire [63:0] flags_out;
+   reg  [15:0] flags_in;
+   wire [15:0] flags_out;
    reg                    flags_write;
 
-   reg [63:0]  latest_news;
+   reg [15:0]  latest_news;
 
    RAM #(.ADDRESS_BITS(3)) flags (.clk(clk), .write(flags_write), .addr(flags_addr[2:0]), .in(flags_in), .out(flags_out));
 
-   reg [63:0]  flag_or_news;
-   reg [63:0]  news_out;
+   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));
 
@@ -145,7 +150,7 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
 
                `OP_STORE:
                  begin
-                        for(idx = 0; idx < 64; idx++) begin
+                        for(idx = 0; idx < 16; idx++) begin
                                flags_in[idx] = Cond[idx] ? alu_carry_out[idx] : flags_out[idx];
                                latest_news[idx] <= flags_in[idx];
                         end
@@ -157,18 +162,33 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o
                         mem_write <= 1;
                  end
 
-               `OP_READ:
+               `OP_STOREI:
                  begin
-                        if (CS)
-                          mem_in <= mem_out;
+                        mem_in <= I;
+                        mem_write <= 1;
                  end
-
+/*
                `OP_LOADI:
                  begin
                         C <= mem_out;
                         A <= I;
                         alu_sum <= 8'b11110000; // out of A, B, F, select exactly A
                  end
+*/
+
+               `OP_LED:
+                 begin
+                        if(!mode)
+                          led_out <= leds;
+                        else if(offset == 0)
+                          led_out <= mem_out[3:0];
+                        else if(offset == 1)
+                          led_out <= mem_out[7:4];
+                        else if(offset == 2)
+                          led_out <= mem_out[11:8];
+                        else if(offset == 3)
+                          led_out <= mem_out[15:12];
+                 end
 
 /*             `OP_RUG:
                  begin
index 00573888f3fef398e3c8372ac72ae8315d0fd7d2..b54abe9ad0e9ef94025b22001e66658e9082ff39 100644 (file)
--- a/master.v
+++ b/master.v
@@ -26,8 +26,8 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
                counter <= counter + 1;
    end
 
-   reg [4:0] program_counter = 0;
-   wire [63:0] rom_output;
+   reg [3:0] program_counter = 0;
+   wire [31:0] rom_output;
 
    master_rom master_rom (.clk(clk), .addr(program_counter), .data(rom_output));
 
@@ -35,6 +35,8 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
 `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;
@@ -49,6 +51,13 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
    // 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;
+
+   reg [7:0]   saved_news [3:0];
+
+   assign led[4] = state != `STATE_WASTE_TIME;
+   assign led[3:0] = 0;
+
    always @(posedge clk) begin
          case(state)
                `STATE_SEND: begin
@@ -57,7 +66,10 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
                   end else if(uart_ptr == 4) begin
                          program_counter <= program_counter + 1;
                          uart_ptr <= 0;
-                         state <= `STATE_WAIT_PROPAGATE;
+                         if(rom_output[26:24] == 6) // `OP_ROUTE
+                               state <= `STATE_WAIT_NEWS;
+                         else
+                               state <= `STATE_WAIT_PROPAGATE;
                   end else if(!is_transmitting && ready_in) begin
                          tx_byte <= rom_output[uart_ptr * 8 +: 8];
                          transmit <= 1;
@@ -67,12 +79,44 @@ module master(input CLKin, output [4:0] led, output uart_tx, input uart_rx, outp
 
                `STATE_WAIT_PROPAGATE: begin
                   if(received) begin
-                         state <= `STATE_SEND;
+                         state <= `STATE_WASTE_TIME;
                   end
                end
 
+               `STATE_WASTE_TIME: begin
+                  if(waste_counter == 100) begin
+                         waste_counter <= 0;
+                         state <= `STATE_SEND;
+                  end else
+                        waste_counter <= waste_counter + 1;
+               end
+
                `STATE_WAIT_NEWS: begin
+                  /** On a route instruction, we:
+                          - receive the instruction back
+                          - receive the news
+                          - propagate the news
+                          - go back to `STATE_SEND
+                       */
+                  if(uart_ptr == 8) begin
+                         state <= `STATE_PROPAGATE_NEWS;
+                         uart_ptr <= 0;
+                  end else if(received) begin
+                         if(uart_ptr[2]) /* uart_ptr >= 4 */
+                               saved_news[uart_ptr[1:0]] <= rx_byte;
+                         uart_ptr <= uart_ptr + 1;
+                  end
+               end // case: `STATE_WAIT_NEWS
 
+               `STATE_PROPAGATE_NEWS: begin
+                  if(uart_ptr == 4) begin
+                         state <= `STATE_WASTE_TIME;
+                         uart_ptr <= 0;
+                  end else if(!is_transmitting && ready_in) begin
+                         tx_byte <= saved_news[uart_ptr];
+                         transmit <= 1;
+                         uart_ptr <= uart_ptr + 1;
+                  end
                end
          endcase
    end
index f95062820b7db40cc6d1b720103618eefc92e5dd..0fc52ddd16f4cf194f7b79304d239d65fac2683a 100644 (file)
@@ -1,26 +1,25 @@
 // 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 [63:0] data);
+module master_rom (input clk, input [3:0] addr, output reg [31:0] data);
    always @ (posedge clk) begin
       case(addr)
-               4'd0:    data <= 8'b0001_0110; // LDI 6
-               4'd1:    data <= 8'b0110_0010; // JP 9
-               4'd2:    data <= 8'b0010_0001; // ADD 1
-               4'd3:    data <= 8'b1001_0000; // WRITE
-               4'd4:    data <= 8'b0110_0010; // JP 2
-               4'd5:    data <= 8'b0000_0000;
-               4'd6:    data <= 8'b0001_0001; // LDI 1
-               4'd7:    data <= 8'b1000_0000; // READ
-               4'd8:    data <= 8'b0110_0111; // JP 7
-               4'd9:    data <= 8'b1110_0000; // LDQ
-               4'd10:   data <= 8'b0001_1100; // LDI 12
-               4'd11:   data <= 8'b1010_0000; // CONS
-               4'd12:   data <= 8'b1100_0000; // RDQ
-               4'd13:   data <= 8'b1101_0000; // CDR
-               4'd14:   data <= 8'b1100_0000; // RDQ
-               4'd15:   data <= 8'b0000_0000;
-               default: data <= 8'bxxxx_xxxx;
+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
    end
 endmodule
diff --git a/news.v b/news.v
index d2e1def6cd8371724fe49c8632c867a24263545e..b0d34a78bbfc328e37f5120a84ea048909597fc0 100644 (file)
--- a/news.v
+++ b/news.v
@@ -1,10 +1,10 @@
-module news(input clk, input [63:0] news_in, input [1:0] direction, output [63:0] news_out);
+module news(input clk, input [15:0] news_in, input [1:0] direction, output [15:0] news_out);
    always @(posedge clk) begin
                 case (direction)
-                  0: news_out = {news_in[56:63], news_in[0:55]};
-                  1: news_out = {news_in[ 1], news_in[ 2], news_in[ 3], news_in[ 4], news_in[ 5], news_in[ 6], news_in[ 7], news_in[ 0], news_in[ 9], news_in[10], news_in[11], news_in[12], news_in[13], news_in[14], news_in[15], news_in[ 8], news_in[17], news_in[18], news_in[19], news_in[20], news_in[21], news_in[22], news_in[23], news_in[16], news_in[25], news_in[26], news_in[27], news_in[28], news_in[29], news_in[30], news_in[31], news_in[24], news_in[33], news_in[34], news_in[35], news_in[36], news_in[37], news_in[38], news_in[39], news_in[32], news_in[41], news_in[42], news_in[43], news_in[44], news_in[45], news_in[46], news_in[47], news_in[40], news_in[49], news_in[50], news_in[51], news_in[52], news_in[53], news_in[54], news_in[55], news_in[48], news_in[57], news_in[58], news_in[59], news_in[60], news_in[61], news_in[62], news_in[63], news_in[56]};
-                  2: news_out = {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[16], news_in[17], news_in[18], news_in[19], news_in[20], news_in[21], news_in[22], news_in[23], news_in[24], news_in[25], news_in[26], news_in[27], news_in[28], news_in[29], news_in[30], news_in[31], news_in[32], news_in[33], news_in[34], news_in[35], news_in[36], news_in[37], news_in[38], news_in[39], news_in[40], news_in[41], news_in[42], news_in[43], news_in[44], news_in[45], news_in[46], news_in[47], news_in[48], news_in[49], news_in[50], news_in[51], news_in[52], news_in[53], news_in[54], news_in[55], news_in[56], news_in[57], news_in[58], news_in[59], news_in[60], news_in[61], news_in[62], news_in[63], news_in[ 0], news_in[ 1], news_in[ 2], news_in[ 3], news_in[ 4], news_in[ 5], news_in[ 6], news_in[ 7]};
-                  3: news_out = {news_in[ 7], news_in[ 0], news_in[ 1], news_in[ 2], news_in[ 3], news_in[ 4], news_in[ 5], news_in[ 6], news_in[15], news_in[ 8], news_in[ 9], news_in[10], news_in[11], news_in[12], news_in[13], news_in[14], news_in[23], news_in[16], news_in[17], news_in[18], news_in[19], news_in[20], news_in[21], news_in[22], news_in[31], news_in[24], news_in[25], news_in[26], news_in[27], news_in[28], news_in[29], news_in[30], news_in[39], news_in[32], news_in[33], news_in[34], news_in[35], news_in[36], news_in[37], news_in[38], news_in[47], news_in[40], news_in[41], news_in[42], news_in[43], news_in[44], news_in[45], news_in[46], news_in[55], news_in[48], news_in[49], news_in[50], news_in[51], news_in[52], news_in[53], news_in[54], news_in[63], news_in[56], news_in[57], news_in[58], news_in[59], news_in[60], news_in[61], news_in[62]};
+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]};
                 endcase
 
    end
diff --git a/newsled.pl b/newsled.pl
new file mode 100644 (file)
index 0000000..55eea89
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+use lib '.';
+
+use asm;
+
+storei 0, 4;
+storei 1, 2;
+ledm   1, 0;
+nop;
+nop;
+route  0, 1;
+ledm   1, 0;
+nop;
+nop;
+storei 1, 3;
+ledm   1, 0;
+nop;
+nop;
+route  0, 1;
+ledm   1, 0;
+nop;
index 233d317e1f660fcc3b97a432dd4204ec8594fb89..cbfbbd7da0594d2ab3b80800f418729e5a84e888 100644 (file)
@@ -17,7 +17,7 @@ my @cpus;
 
 my @newstable;
 
-my $side = 8; # there are $side * $side CPUs
+my $side = 4; # there are $side * $side CPUs
 
 for my $line (0 .. ($side - 1)) {
        $cpus[$line] = [ ($line * $side) .. (($line + 1) * $side - 1) ]
@@ -34,10 +34,10 @@ for my $cpu (0 .. ($side * $side - 1)) {
 }
 
 for my $direction (0 .. $#diffs) {
-       print "$direction: flag_or_news = {";
-       printf 'latest_news[%2d]', $newstable[0][$direction];
+       print "$direction: news_out = {";
+       printf 'news_in[%2d]', $newstable[0][$direction];
        for my $cpu (1 .. ($side * $side - 1)) {
-               printf ', latest_news[%2d]', $newstable[$cpu][$direction];
+               printf ', news_in[%2d]', $newstable[$cpu][$direction];
        }
        say '};'
 }
diff --git a/ram.v b/ram.v
index 28e0f06e255e12f126c4c0656f3d270b387076aa..acd11eeb1613e592e4058f5366cc09d25ccece71 100644 (file)
--- a/ram.v
+++ b/ram.v
@@ -1,7 +1,7 @@
 module RAM #(parameter ADDRESS_BITS = 4)
-(input clk, input write, input[ADDRESS_BITS-1:0] addr, input [63:0] in, output reg [63:0] out);
+(input clk, input write, input[ADDRESS_BITS-1:0] addr, input [15:0] in, output reg [15:0] out);
 
-    reg [63:0] memory [0:2**ADDRESS_BITS-1];
+    reg [15:0] memory [0:2**ADDRESS_BITS-1];
 
    reg [ADDRESS_BITS:0] idx;
    initial begin
diff --git a/sim.c b/sim.c
new file mode 100644 (file)
index 0000000..1d01e20
--- /dev/null
+++ b/sim.c
@@ -0,0 +1,419 @@
+#define _GNU_SOURCE
+#include<assert.h>
+#include<sched.h>
+#include<signal.h>
+#include<stdio.h>
+#include<stdlib.h>
+#include<time.h>
+#include<unistd.h>
+#include<sys/wait.h>
+
+#include<pthread.h>
+
+/* magic value to indicate upstream is dead */
+#define UART_DEAD 2
+
+/* only relevant instructions */
+#define INSTR_NOP 0
+#define INSTR_ROUTE 4
+
+/* Doing nothing, waiting for an instruction */
+#define STATE_IDLE 0
+#define STATE_READ_INSTRUCTION 10
+#define STATE_READ_NEWS_ADDRESS 20
+#define STATE_READ_NEWS_DATA 30
+/* Propagating the last received instruction
+  (or waiting for neighbour to be ready so I can propagate) */
+#define STATE_PROPAGATE 1
+#define STATE_PROPAGATE2 11
+/* Executing some instruction */
+#define STATE_EXECUTE 2
+/* Sending NEWS to neighbour
+   (or waiting for neighbour to be ready so I can send) */
+#define STATE_NEWS 3
+#define STATE_NEWS2 13
+#define STATE_NEWS3 23
+
+// UART encoding is: to send the byte [b] we write [b * 2 + 1] in the
+// given location, then on the next cycle we write 0.
+
+static void wait_cycles(int cycles) {
+       struct timespec ts;
+       long millis = 200;
+       millis += (long)(rand() % 100 - 50);
+       millis *= cycles;
+       ts.tv_sec = millis / 1000;
+       ts.tv_nsec = (millis % 1000) * 100000;
+       nanosleep(&ts, NULL);
+}
+
+/* sleep for 150-250ms */
+static void wait_one_cycle(void) {
+       wait_cycles(1);
+}
+
+#define BLOG_THREAD_STARTED    0
+#define BLOG_UART_BAD_KIND     1
+#define BLOG_READ_INSTRUCTION  2
+#define BLOG_READ_NEWS_ADDRESS 3
+#define BLOG_READ_NEWS_DATA    4
+#define BLOG_BECAME_NOT_READY  5
+#define BLOG_INVALID_STATE     6
+#define BLOG_EXECUTED_INSTR    7
+#define BLOG_MANUFACTURED_INSTRUCTION 8
+#define BLOG_READ_KIND 9
+#define BLOG_TRY_SENDING_NEWS 10
+#define BLOG_DONE_SENDING_NEWS 11
+
+const char *blog_what[] = {
+       "thread started",
+       "uart bad kind",
+       "read instruction",
+       "read news address",
+       "read news data",
+       "ERROR: downstream became not ready!",
+       "ERROR: invalid state",
+       "executed instruction",
+       "manufactured instruction",
+       "read kind from uart",
+       "trying to send news",
+       "finished sending news",
+};
+
+struct blog {
+       int who;
+       int what;
+       int data;
+};
+
+static volatile struct blog blog[1000];
+static volatile int blog_n = 0;
+
+void display_post(int i) {
+       printf("\033[3%dm%d: %s (%d)\033[0m\n", blog[i].who + 1, blog[i].who, blog_what[blog[i].what], blog[i].data);
+}
+
+void post(int who, int what, int data) {
+       int idx = blog_n++;
+       blog[idx].who = who;
+       blog[idx].what = what;
+       blog[idx].data = data;
+       display_post(idx);
+}
+
+#define POST(what, data) post(id, what, data)
+
+int uart_data(int x) {
+       return 2 * x + 1;
+}
+
+static void tx(volatile int *uart_tx, int data) {
+       *uart_tx = data;
+       wait_cycles(5);
+//     assert(*uart_tx == 0);
+}
+
+#define TX(data) tx(uart_tx, uart_data(data))
+#define KILL_UART() tx(uart_tx, 2)
+
+static int rx(volatile int *uart_rx) {
+       int read = *uart_rx;
+       *uart_rx = 0;
+       return read;
+}
+
+#define RX() rx(uart_rx)
+
+void worker(int id, volatile int *uart_tx, volatile int *uart_rx, volatile int *ready_out, volatile const int *ready_in){
+       int current_instr = 0;
+
+       int state = STATE_IDLE;
+       *ready_out = 1;
+       *uart_tx = 0;
+       POST(BLOG_THREAD_STARTED, 0);
+
+       int read, kind, instruction, address, data;
+
+       while(1) {
+               switch(state) {
+               case STATE_IDLE:
+                       read = RX();
+                       wait_one_cycle();
+                       if(read == 2) { // upstream dead!
+                               KILL_UART();
+                               return;
+                       }
+                       if(!read) /* nothing on uart */
+                               break;
+                       kind = read >> 1;
+                       POST(BLOG_READ_KIND, kind);
+                       if(kind == 1)
+                               state = STATE_READ_INSTRUCTION;
+                       else if(kind == 2)
+                               state = STATE_READ_NEWS_ADDRESS;
+                       else
+                               POST(BLOG_UART_BAD_KIND, kind);
+                       break;
+
+               case STATE_READ_INSTRUCTION:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       instruction = read >> 1;
+                       current_instr = instruction;
+                       *ready_out = 0;
+                       POST(BLOG_READ_INSTRUCTION, instruction);
+                       state = STATE_PROPAGATE;
+                       break;
+
+               case STATE_READ_NEWS_ADDRESS:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       address = read >> 1;
+                       current_instr = address;
+                       POST(BLOG_READ_NEWS_ADDRESS, address);
+                       state = STATE_READ_NEWS_DATA;
+                       break;
+
+               case STATE_READ_NEWS_DATA:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       data = read >> 1;
+                       /* we now have the address in [current_instr] and data in [data].
+                          We write a NOP instruction because we have no memory. */
+                       current_instr = INSTR_NOP;
+                       *ready_out = 0;
+                       POST(BLOG_READ_NEWS_DATA, data);
+                       state = STATE_EXECUTE;
+                       break;
+
+               case STATE_PROPAGATE:
+                       if(!*ready_in)
+                               break;
+                       TX(1); /* we're writing an instruction */
+                       state = STATE_PROPAGATE2;
+                       break;
+
+               case STATE_PROPAGATE2:
+                       if(!*ready_in) {
+                               POST(BLOG_BECAME_NOT_READY, state);
+                               state = STATE_PROPAGATE;
+                               break;
+                       }
+                       TX(current_instr);
+                       state = STATE_EXECUTE;
+                       break;
+
+               case STATE_EXECUTE:
+                       wait_one_cycle(); // execution takes time! (not really)
+                       if(current_instr == INSTR_ROUTE) {
+                               state = STATE_NEWS;
+                               POST(BLOG_EXECUTED_INSTR, current_instr);
+//                             POST(BLOG_TRY_SENDING_NEWS, 0);
+                       } else {
+                               state = STATE_IDLE;
+                               *ready_out = 1;
+                               POST(BLOG_EXECUTED_INSTR, current_instr);
+                       }
+                       break;
+
+               case STATE_NEWS:
+                       if(!*ready_in)
+                               break;
+                       TX(2);
+                       state = STATE_NEWS2;
+                       break;
+
+               case STATE_NEWS2:
+                       if(!*ready_in) {
+                               POST(BLOG_BECAME_NOT_READY, state);
+                               state = STATE_NEWS;
+                               break;
+                       }
+                       TX(rand() & 0xFF);
+                       state = STATE_NEWS3;
+                       break;
+
+               case STATE_NEWS3:
+                       if(!*ready_in) {
+                               POST(BLOG_BECAME_NOT_READY, state);
+                               state = STATE_NEWS;
+                               break;
+                       }
+                       TX(rand() & 0xFF);
+                       state = STATE_IDLE;
+                       *ready_out = 1;
+//                     POST(BLOG_DONE_SENDING_NEWS, 0);
+                       break;
+
+               default:
+                       POST(BLOG_INVALID_STATE, state);
+                       break;
+               }
+               wait_one_cycle();
+       }
+}
+
+#define MASTER_SEND_INSTRUCTION 0
+#define MASTER_SEND_INSTRUCTION2 10
+#define MASTER_WAIT_FOR_NEWS 1
+#define MASTER_READ_NEWS_ADDRESS 11
+#define MASTER_READ_NEWS_DATA 21
+#define MASTER_WAIT_FOR_PROPAGATE 2
+#define MASTER_WAIT_FOR_PROPAGATE2 12
+
+void master(volatile int *uart_tx, volatile int *uart_rx, volatile int *ready_out, volatile const int *ready_in){
+       int instructions_left = 10;
+       int state = MASTER_SEND_INSTRUCTION;
+       int ignore_next_rx = 0;
+       const int id = 0;
+       int read, kind, instruction, data, rnd;
+
+       *uart_tx = 0;
+       *ready_out = 1;
+       POST(BLOG_THREAD_STARTED, 0);
+
+       while(1) {
+               switch(state) {
+               case MASTER_SEND_INSTRUCTION:
+                       if(!instructions_left) { /* done! */
+                               KILL_UART();
+                               return;
+                       }
+                       if(!*ready_in)
+                               break;
+                       TX(1);
+                       state = MASTER_SEND_INSTRUCTION2;
+                       break;
+
+               case MASTER_SEND_INSTRUCTION2:
+                       if(!*ready_in) {
+                               POST(BLOG_BECAME_NOT_READY, state);
+                               state = MASTER_SEND_INSTRUCTION;
+                               break;
+                       }
+                       /* manufacture an instruction */
+                       rnd = rand() & 7;
+                       if(rnd <= 4)
+                               instruction = INSTR_NOP;
+                       else if(rnd <= 6)
+                               instruction = INSTR_ROUTE;
+                       else
+                               instruction = INSTR_ROUTE; /* actually READ */
+
+                       POST(BLOG_MANUFACTURED_INSTRUCTION, rnd);
+                       TX(instruction);
+                       instructions_left--;
+
+                       if(instruction == INSTR_ROUTE)
+                               state = MASTER_WAIT_FOR_NEWS;
+                       else
+                               state = MASTER_WAIT_FOR_PROPAGATE;
+                       break;
+
+               case MASTER_WAIT_FOR_PROPAGATE:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       kind = read >> 1;
+                       if(kind == 1)
+                               state = MASTER_WAIT_FOR_PROPAGATE2;
+                       else /* kind == 2 is also bad here */
+                               POST(BLOG_UART_BAD_KIND, kind);
+                       break;
+
+               case MASTER_WAIT_FOR_PROPAGATE2:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       instruction = read >> 1; /* we don't care about this */
+                       state = MASTER_SEND_INSTRUCTION;
+                       break;
+
+               case MASTER_WAIT_FOR_NEWS:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       kind = read >> 1;
+                       if(ignore_next_rx)
+                               ignore_next_rx = 0;
+                       else if(kind == 1) /* propagation, ignore next byte */
+                               ignore_next_rx = 1;
+                       else if(kind == 2) { /* ka-ching! */
+                               state = MASTER_READ_NEWS_ADDRESS;
+                       } else
+                               POST(BLOG_UART_BAD_KIND, kind);
+                       break;
+
+               case MASTER_READ_NEWS_ADDRESS:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       /* we do not care about the address, we go read the data */
+                       state = MASTER_READ_NEWS_DATA;
+                       break;
+
+               case MASTER_READ_NEWS_DATA:
+                       read = RX();
+                       wait_one_cycle();
+                       if(!read) /* nothing on uart */
+                               break;
+                       data = read >> 1;
+                       POST(BLOG_READ_NEWS_DATA, data);
+                       state = MASTER_SEND_INSTRUCTION;
+                       break;
+
+               default:
+                       POST(BLOG_INVALID_STATE, state);
+                       break;
+               }
+               wait_one_cycle();
+       }
+       KILL_UART();
+}
+
+static int uarts[5];
+static int ready[5];
+static pthread_t threads[5];
+
+void* spawn_thread(void* index) {
+       switch((long)index) {
+       case 0:
+               master(uarts + 0, uarts + 4, ready + 4, ready + 0);
+               break;
+       case 1:
+               worker(1, uarts + 1, uarts + 0, ready + 0, ready + 1);
+               break;
+       case 2:
+               worker(2, uarts + 2, uarts + 1, ready + 1, ready + 2);
+               break;
+       case 3:
+               worker(3, uarts + 3, uarts + 2, ready + 2, ready + 3);
+               break;
+       case 4:
+               worker(4, uarts + 4, uarts + 3, ready + 3, ready + 4);
+               break;
+       default:
+               printf("Spawned bad thread %ld\n", (long)index);
+       }
+       return NULL;
+}
+
+int main(void){
+       for(long i = 0 ; i < 5 ; i++)
+               pthread_create(threads + i, NULL, spawn_thread, (void*)i);
+       for(int i = 0 ; i < 5 ; i++)
+               pthread_join(threads[i], NULL);
+//     for(int i = 0; i < blog_n; i++)
+//             display_post(i);
+       return 0;
+}
index 7a5a909effeaf81f3396aa140c26f0271b3d466a..e8552d0b43b87f2629d7837bc7681d54c754701f 100644 (file)
--- a/worker.v
+++ b/worker.v
@@ -30,8 +30,8 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    end
 
    wire [11:0] mem_addr;
-   wire [63:0] mem_in;
-   wire [63:0] mem_out;
+   wire [15:0] mem_in;
+   wire [15:0] mem_out;
    wire           mem_write;
 
    RAM #(.ADDRESS_BITS(8)) ram (.clk(clk), .write(mem_write), .addr(mem_addr), .in(mem_in), .out(mem_out));
@@ -44,6 +44,15 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    wire [2:0]  op_from_uart = from_uart[3][2:0];
    wire           CS = from_uart[3][3];
 
+   /* to execute a ROUTE instruction, we send our neighbour a STOREI
+   /* instruction with the correct address and value. This is the
+   /* STOREI instruction. */
+   wire [7:0]  route_storei [3:0];
+   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
+
    reg [2:0]   op = 0;
 
    reg [2:0]   last_op = 0;
@@ -51,7 +60,9 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    reg [15:0]  I;
    reg                    CS;
 
-   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));
+   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));
 
    wire           received;
    wire [7:0]  rx_byte;
@@ -63,21 +74,15 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
    // 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));
 
-   assign led[0] = is_transmitting;
-   assign led[4] = received;
-//   assign led[3:1] = last_op;
-
-   assign led[2] = |mem_out; // so that mem_out is used
-
-   // 0 is idle
 `define STATE_IDLE 0
 `define STATE_PROPAGATE 1
 `define STATE_EXECUTE 2
 `define STATE_ROUTE 3
 
-   reg [5:0]   state = 0;
+   reg [5:0]   state = `STATE_IDLE;
 
-//   assign led[4:2] = state;
+   assign led[3:0] = led_out;
+   assign led[4] = 0;
 
    always @ (posedge clk) begin
          case(state)
@@ -100,7 +105,8 @@ 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;
-                         if(op == `OP_ROUTE) begin
+                         the_leds <= last_op;
+                         if(last_op == `OP_ROUTE) begin
                                 state <= `STATE_ROUTE;
                          end else begin
                                 op <= last_op;
@@ -119,42 +125,19 @@ module worker (input CLKin, output [4:0] led, output uart_tx, input uart_rx, out
                end
 
                `STATE_ROUTE: begin
-                  state <= `STATE_IDLE; // for now
+                  if(transmit)
+                         transmit <= 0;
+                  else if(uart_ptr == 4) begin
+                         uart_ptr <= 0;
+                         state <= `STATE_IDLE;
+                  end else if(!is_transmitting && ready_in) begin
+                         tx_byte <= route_storei[uart_ptr];
+                         transmit <= 1;
+                         uart_ptr <= uart_ptr + 1;
+                  end
                end
          endcase
-
-         /*
-
-         if (state == 1 && op != `OP_READ) begin
-                op <= 0;
-                state <= 0;
-         end
-
-         if (state == 1 && op == `OP_READ) begin
-                op <= 0;
-                state <= 2;
-                transmit <= 1;
-                tx_byte <= mem_out[7:0];
-         end
-
-         if (state == 2 && transmit) begin
-                transmit <= 0;
-         end
-
-         if (state == 2 && !transmit && !is_transmitting) begin
-                state <= 3;
-                transmit <= 1;
-                tx_byte <= mem_out[15:8];
-         end
-
-         if (state == 3) begin
-                transmit <= 0;
-                state <= 0;
-         end */
    end
 
-   wire ready = (state == 0 && !is_receiving);
-
-   assign ready_out = ready_in & ready;
-
+//   wire ready = (state == 0 && !is_receiving);
 endmodule
This page took 0.033371 seconds and 4 git commands to generate.