From 7f1b6bd9e0070ddc074215defc46d64abef645ac Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu Date: Mon, 15 Apr 2019 22:45:53 +0300 Subject: [PATCH] implement routing + storei instruction --- asm.pm | 81 ++++++++-- blink.pl | 17 +++ cells.pl | 6 +- chip.v | 80 ++++++---- master.v | 52 ++++++- master_rom.v | 35 +++-- news.v | 10 +- newsled.pl | 23 +++ newstable.pl | 8 +- ram.v | 4 +- sim.c | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++ worker.v | 77 ++++------ 12 files changed, 688 insertions(+), 124 deletions(-) create mode 100644 blink.pl create mode 100644 newsled.pl create mode 100644 sim.c diff --git a/asm.pm b/asm.pm index 492bfcc..269b8d1 100644 --- 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 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; diff --git a/cells.pl b/cells.pl index c8a936a..68c0f9e 100644 --- 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 b29fde6..1ff0d50 100644 --- 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 diff --git a/master.v b/master.v index 0057388..b54abe9 100644 --- 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 diff --git a/master_rom.v b/master_rom.v index f950628..0fc52dd 100644 --- a/master_rom.v +++ b/master_rom.v @@ -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 d2e1def..b0d34a7 100644 --- 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 index 0000000..55eea89 --- /dev/null +++ b/newsled.pl @@ -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; diff --git a/newstable.pl b/newstable.pl index 233d317..cbfbbd7 100644 --- a/newstable.pl +++ b/newstable.pl @@ -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 28e0f06..acd11ee 100644 --- 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 index 0000000..1d01e20 --- /dev/null +++ b/sim.c @@ -0,0 +1,419 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* 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; +} diff --git a/worker.v b/worker.v index 7a5a909..e8552d0 100644 --- 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 -- 2.39.2