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,
$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;
}
}
+=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;
{ 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) = @_;
{ 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 }
alu3 alu_select_f, alu_select_a, 0, 0, 0, $flagIN, flag_zero;
news_generic $nX, $nY, {flag => $flagOUT};
}
+
+1;
--- /dev/null
+#!/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;
}
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
# read_ 5;
# read_ 6;
- sleep 10;
+ #sleep 10;
}
$| = 1;
store 0, flag_zero, 0, 0;
read_ 0;
read_ 0;
-sleep 10;
+#sleep 10;
conway_step;
conway_step;
`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
`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
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]];
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));
`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
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
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));
`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;
// 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
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;
`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
// 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
-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
--- /dev/null
+#!/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;
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) ]
}
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 '};'
}
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
--- /dev/null
+#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;
+}
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));
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;
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;
// 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)
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;
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