From 23c26e0422eda4cb868569e6c3cc4f41fe6e2864 Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu Date: Wed, 9 Jan 2019 12:29:59 +0000 Subject: [PATCH] Conway works (with sleeps) --- Makefile | 6 +- asm.pm | 174 ++++++++++++++++++++++++++ cells.pl | 129 ++++++++++++++++++++ chip.v | 312 +++++++++++++++++++++++++++++++++-------------- intermediare.pl | 62 ++++++++++ newstable.pl | 32 +++++ ram.v | 6 + toplevel.v | 84 ++++++++++--- yosys-sim-script | 2 +- 9 files changed, 695 insertions(+), 112 deletions(-) create mode 100644 asm.pm create mode 100644 cells.pl create mode 100644 intermediare.pl create mode 100644 newstable.pl diff --git a/Makefile b/Makefile index 6460637..0fb0a57 100644 --- a/Makefile +++ b/Makefile @@ -22,4 +22,8 @@ prog: $(PROJ).bin clean: rm -f $(PROJ).blif $(PROJ).asc $(PROJ).bin -.PHONY: all prog clean + +sim: + tools/yosys/yosys -p 'read_verilog -sv -DSIM toplevel.v; prep -top toplevel -nordff; sim -clock CLKin -vcd test.vcd -n 3000' + +.PHONY: all prog clean sim diff --git a/asm.pm b/asm.pm new file mode 100644 index 0000000..d07004e --- /dev/null +++ b/asm.pm @@ -0,0 +1,174 @@ +#!/usr/bin/perl +use v5.14; +use warnings; + +use constant +{ + OP_NOP => 0, + OP_LOADA => 1, + OP_LOADB => 2, + OP_STORE => 3, + OP_READ => 4, + OP_LOADI => 5, + OP_ROUTE => 6, + OP_RUG => 7, +}; + +q, +use Device::SerialPort; + +my $port = Device::SerialPort->new($ARGV[0] // '/dev/ttyUSB1') or die "$!"; +$port->baudrate(300); +#$port->baudrate(4000000); +$port->parity('none'); +$port->databits(8); +$port->stopbits(2); +$port->handshake('none'); +$port->read_const_time(2000); + +$port->write_settings or die "$!"; +,; + +use Fcntl; +use Time::HiRes qw/sleep/; + +sysopen my $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/; + +use File::Slurp::Tiny 'write_file'; + +sub send_ { + my ($cmd) = @_; + my %cmd = %$cmd; + + my $binary = pack 'vCC', @cmd{qw/I mem_addr op/}; # we ignore CS for now + my $length = length $binary; + my $wrote = syswrite $port, $binary, $length; + sleep 0.2; +# say "Wrote $wrote of $length bytes"; + if ($cmd{op} == OP_READ) { + my $string_in; + my $count_in = sysread $port, $string_in, 2; + my @memory = unpack 'v*', $string_in; + for (@memory) { + printf "%X", $_ + } + print " " + } +} + +sub loada { + my ($addr, $flagr, $bsel, $aluc) = @_; + my $I = 0; + $I |= $flagr; + $I |= $bsel << 4; + $I |= $aluc << 5; + send_ + { I => $I, mem_addr => $addr, op => OP_LOADA, CS => 0 } + } + +sub loadb { + my ($addr, $cond, $inv, $alus) = @_; + my $I = 0; + $I |= $cond; + $I |= $inv << 4; + $I |= $alus << 5; + send_ + { 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 store { + my ($addr, $flagw, $edge_, $cube) = @_; + my $I = 0; + $I |= $flagw; + $I |= $edge_ << 7; + $I |= $cube << 8; + send_ + { I => $I, mem_addr => $addr, op => OP_STORE, CS => 0 } + } + +sub loadi { + my ($addr, $I) = @_; + send_ + { I => $I, mem_addr => $addr, op => OP_LOADI, CS => 0 } +} + +sub flag_zero { 0 } + +sub flag_news { 8 + $_[0] } + +sub alu_select_a { + 0b11110000 +} + +sub alu_select_b { + 0b11001100 +} + +sub alu_select_f { + 0b10101010 +} + +sub alu_zero { + 0 +} + +sub alu_xor { + 0b10010110 +} + +sub alu_xnor { + 0b01101001 +} + +sub alu_of_function (&) { + my ($fun) = @_; + my $alu = 0; + for my $i (0 .. 7) { + local $a = ($i & 4) >> 2; + local $b = ($i & 2) >> 1; + local $_ = $i & 1; + $alu += ($fun->() ? 1 : 0) << $i; + } + $alu +} + +sub aluc_add { alu_of_function { ($a + $b + $_) & 2 } } +sub alus_add { alu_of_function { ($a + $b + $_) & 1 } } + +sub aluc_addAF { alu_of_function { ($a + $_) & 2 } } +sub alus_addAF { alu_of_function { ($a + $_) & 1 } } + +sub alu_or { alu_of_function { $a | $b | $_ } } + +sub alu2 { + my ($aluc, $alus, $addrA, $addrB, $flagr, $flagw, $cond, $inv) = @_; + loada $addrA, $flagr, 0, $aluc; + loadb $addrB, $cond, $inv, $alus; + store $addrA, $flagw, 0, 0; +} + +sub alu3 { + my ($aluc, $alus, $addrA, $addrB, $addrC, $flagr, $flagw) = @_; + loada $addrA, $flagr, 0, $aluc; + loadb $addrB, 0, 1, $alus; + store $addrC, $flagw, 0, 0; +} + +sub add { + my ($addrA, $addrB, $addrC, $flag_carry) = @_; + alu3 aluc_add, alus_add, $addrA, $addrB, $addrC, flag_zero, $flag_carry; +} + +sub addC { + my ($addrA, $addrB, $addrC, $flag_carry) = @_; + alu3 aluc_add, alus_add, $addrA, $addrB, $addrC, $flag_carry, $flag_carry; +} diff --git a/cells.pl b/cells.pl new file mode 100644 index 0000000..c8a936a --- /dev/null +++ b/cells.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl +use v5.14; +use warnings; +use lib '.'; + +use asm; + +sub send_memory_to_news { + my ($address) = @_; + alu3 alu_select_a, alu_select_a, $address, $address, $address, flag_zero, flag_zero; +} + +sub flag_to_memory { + my ($address, $flag) = @_; + alu3 alu_zero, alu_select_f, 0, 0, $address, $flag, flag_zero; +} + +my $flag_F = 1; + +sub read_write_two_ways { + my ($news) = @_; + my $memory = $news + 1; + send_memory_to_news 0; + alu3 alu_zero, alu_select_f, 0, 0, $memory, flag_news($news), flag_zero; + send_memory_to_news 0; + alu3 aluc_addAF, alus_addAF, $memory, 0, $memory, flag_news($news + 1), $flag_F; + flag_to_memory $memory + 1, $flag_F; +} + +sub conway_step { + say "CONWAY STEP"; + # write memory 0 to news + # read from news direction 0 into memory 1 + # write memory 0 to news + # read from news direction 1, add to memory 1, write into memory 1 and flag F + # write flag F to memory 2 + read_write_two_ways(0); + + # write memory 0 to news + # read from news direction 2 into memory 3 + # write memory 0 to news + # read from news direction 3, add to memory 3, write into memory 3 and flag F + # write flag F to memory 4 + read_write_two_ways(2); + + # write memory 0 to news + # read from news direction 4 into memory 5 + # write memory 0 to news + # read from news direction 5, add to memory 5, write into memory 5 and flag F + # write flag F to memory 6 + read_write_two_ways(4); + + # write memory 0 to news + # read from news direction 6 into memory 7 + # write memory 0 to news + # read from news direction 7, add to memory 7, write into memory 7 and flag F + # write flag F to memory 8 + read_write_two_ways(6); + + # read from memory 1, add to memory 3, write into memory 1 and flag F + add 1, 3, 1, $flag_F; + # read from memory 2, add to memory 4 and flag F, write into memory 2 and flag F + addC 2, 4, 2, $flag_F; + # write flag F to memory 3 + flag_to_memory 3, $flag_F; + + # read from memory 5, add to memory 7, write into memory 5 and flag F + add 5, 7, 5, $flag_F; + # read from memory 6, add to memory 8 and flag F, write into memory 6 and flag F + addC 6, 8, 6, $flag_F; + # write flag F to memory 7 + flag_to_memory 7, $flag_F; + + # read from memory 1, add to memory 5, write into memory 1 and flag F + add 1, 5, 1, $flag_F; + # read from memory 2, add to memory 6 and flag F, write into memory 2 and flag F + addC 2, 6, 2, $flag_F; + # read from memory 3, or with memory 7 and flag F, write into flag F + alu3 alu_or, alu_select_a, 3, 7, 3, $flag_F, $flag_F; + + # should a new cell be born here? (do we have 3 neighbours?) + sub alu_birth { alu_of_function {; $a && $b && !$_ } } + + # should a living cell survive here? (do we have 2 or 3 neighbours?) + sub alu_survival { alu_of_function {; $a && !$_ } } + + # compute the state of this cell at the next tick + sub alu_step { alu_of_function {; $_ & ($a | $b) } } + + # read from memory 1, and with memory 2 and not F, write into memory 1 (= birth-p) + alu3 alu_zero, alu_birth, 1, 2, 1, $flag_F, flag_zero; + # read from memory 2, and with flag not F, write into flag F (= survive-p) + alu3 alu_survival, alu_select_a, 2, 0, 2, $flag_F, $flag_F; + # read from memory 0, memory 1, and flag F, write F and (mem0 or mem1) into memory 0 + alu3 alu_zero, alu_step, 0, 1, 0, $flag_F, $flag_F; # also zeroes out flag F + + read_ 0; +# say 'Press enter to continue:'; +# my $nope = <>; +# say 'Pressed, continuing'; + read_ 0; +# read_ 1; +# read_ 2; +# read_ 3; +# read_ 4; +# read_ 5; +# read_ 6; + + sleep 10; +} + +$| = 1; + +# start with a blinker +read_ 0; +loadi 0, 0x2022; +#sleep 100; + +store 0, flag_zero, 0, 0; +read_ 0; +read_ 0; +sleep 10; + +conway_step; +conway_step; +conway_step; +conway_step; +conway_step; +conway_step; diff --git a/chip.v b/chip.v index 610ad6f..ff16ced 100644 --- a/chip.v +++ b/chip.v @@ -7,22 +7,31 @@ `define OP_ROUTE 3'd6 `define OP_RUG 3'd7 +`define DIRECTION_N 3'd0 +`define DIRECTION_NE 3'd1 +`define DIRECTION_E 3'd2 +`define DIRECTION_SE 3'd3 +`define DIRECTION_S 3'd4 +`define DIRECTION_SW 3'd5 +`define DIRECTION_W 3'd6 +`define DIRECTION_NW 3'd7 + module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, output reg [15:0] mem_in, input [15:0] mem_out, output reg mem_write); // parity is unimplemented // OP_LOADA - wire [2:0] flagr = I[2:0]; - wire bsel = I[3]; - wire [7:0] aluc = I[11:4]; + wire [3:0] flagr = I[3:0]; + wire bsel = I[4]; + wire [0:7] aluc = I[12:5]; // OP_LOADB - wire [2:0] cond = I[2:0]; - wire inv = I[3]; - wire [7:0] alus = I[11:4]; + wire [3:0] cond = I[3:0]; + wire inv = I[4]; + wire [0:7] alus = I[12:5]; // OP_STORE - wire [2:0] flagw = I[2:0]; + wire [3:0] flagw = I[3:0]; wire edge_ = I[7]; wire [3:0] cube = I[11:8]; @@ -40,101 +49,216 @@ module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, o wire [4:0] reg_ = I[8:4]; - reg [15:0] A; - reg [15:0] B; - reg [15:0] C; - reg [15:0] F; - reg [15:0] Cond; - reg [15:0] R; - reg [7:0] alu_sum; - reg [7:0] alu_carry; + 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 [15:0] cube_in; reg io; // these are not really regs - wire [15:0] alu_sum_out; - wire [15:0] alu_carry_out; - - wire [2:0] alu_index [15:0]; - -assign alu_index[0] = (A[0] << 2) + (B[0] << 1) + F[0]; -assign alu_sum_out[0] = alu_sum[alu_index[0]]; -assign alu_carry_out[0] = alu_carry[alu_index[0]]; -assign alu_index[1] = (A[1] << 2) + (B[1] << 1) + F[1]; -assign alu_sum_out[1] = alu_sum[alu_index[1]]; -assign alu_carry_out[1] = alu_carry[alu_index[1]]; -assign alu_index[2] = (A[2] << 2) + (B[2] << 1) + F[2]; -assign alu_sum_out[2] = alu_sum[alu_index[2]]; -assign alu_carry_out[2] = alu_carry[alu_index[2]]; -assign alu_index[3] = (A[3] << 2) + (B[3] << 1) + F[3]; -assign alu_sum_out[3] = alu_sum[alu_index[3]]; -assign alu_carry_out[3] = alu_carry[alu_index[3]]; -assign alu_index[4] = (A[4] << 2) + (B[4] << 1) + F[4]; -assign alu_sum_out[4] = alu_sum[alu_index[4]]; -assign alu_carry_out[4] = alu_carry[alu_index[4]]; -assign alu_index[5] = (A[5] << 2) + (B[5] << 1) + F[5]; -assign alu_sum_out[5] = alu_sum[alu_index[5]]; -assign alu_carry_out[5] = alu_carry[alu_index[5]]; -assign alu_index[6] = (A[6] << 2) + (B[6] << 1) + F[6]; -assign alu_sum_out[6] = alu_sum[alu_index[6]]; -assign alu_carry_out[6] = alu_carry[alu_index[6]]; -assign alu_index[7] = (A[7] << 2) + (B[7] << 1) + F[7]; -assign alu_sum_out[7] = alu_sum[alu_index[7]]; -assign alu_carry_out[7] = alu_carry[alu_index[7]]; -assign alu_index[8] = (A[8] << 2) + (B[8] << 1) + F[8]; -assign alu_sum_out[8] = alu_sum[alu_index[8]]; -assign alu_carry_out[8] = alu_carry[alu_index[8]]; -assign alu_index[9] = (A[9] << 2) + (B[9] << 1) + F[9]; -assign alu_sum_out[9] = alu_sum[alu_index[9]]; -assign alu_carry_out[9] = alu_carry[alu_index[9]]; -assign alu_index[10] = (A[10] << 2) + (B[10] << 1) + F[10]; -assign alu_sum_out[10] = alu_sum[alu_index[10]]; -assign alu_carry_out[10] = alu_carry[alu_index[10]]; -assign alu_index[11] = (A[11] << 2) + (B[11] << 1) + F[11]; -assign alu_sum_out[11] = alu_sum[alu_index[11]]; -assign alu_carry_out[11] = alu_carry[alu_index[11]]; -assign alu_index[12] = (A[12] << 2) + (B[12] << 1) + F[12]; -assign alu_sum_out[12] = alu_sum[alu_index[12]]; -assign alu_carry_out[12] = alu_carry[alu_index[12]]; -assign alu_index[13] = (A[13] << 2) + (B[13] << 1) + F[13]; -assign alu_sum_out[13] = alu_sum[alu_index[13]]; -assign alu_carry_out[13] = alu_carry[alu_index[13]]; -assign alu_index[14] = (A[14] << 2) + (B[14] << 1) + F[14]; -assign alu_sum_out[14] = alu_sum[alu_index[14]]; -assign alu_carry_out[14] = alu_carry[alu_index[14]]; -assign alu_index[15] = (A[15] << 2) + (B[15] << 1) + F[15]; -assign alu_sum_out[15] = alu_sum[alu_index[15]]; -assign alu_carry_out[15] = alu_carry[alu_index[15]]; - - reg [2:0] flags_addr; + reg [15:0] alu_sum_out; + reg [15:0] alu_carry_out; + + reg [2:0] alu_index [15:0]; + + reg [15:0] idx; always @* begin - case(op) - `OP_LOADA: - flags_addr <= flagr; - `OP_LOADB: - flags_addr <= cond; - `OP_STORE: - flags_addr <= flagw; - default: - flags_addr <= 0; - endcase + 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]]; + end end - wire [15:0] flags_in; - reg [15:0] flags_out; + reg [3:0] newstable[0:15][0:7]; + + initial begin + newstable[0][0] = 12; + newstable[0][1] = 13; + newstable[0][2] = 1; + newstable[0][3] = 5; + newstable[0][4] = 4; + newstable[0][5] = 7; + newstable[0][6] = 3; + newstable[0][7] = 15; + newstable[1][0] = 13; + newstable[1][1] = 14; + newstable[1][2] = 2; + newstable[1][3] = 6; + newstable[1][4] = 5; + newstable[1][5] = 4; + newstable[1][6] = 0; + newstable[1][7] = 12; + newstable[2][0] = 14; + newstable[2][1] = 15; + newstable[2][2] = 3; + newstable[2][3] = 7; + newstable[2][4] = 6; + newstable[2][5] = 5; + newstable[2][6] = 1; + newstable[2][7] = 13; + newstable[3][0] = 15; + newstable[3][1] = 12; + newstable[3][2] = 0; + newstable[3][3] = 4; + newstable[3][4] = 7; + newstable[3][5] = 6; + newstable[3][6] = 2; + newstable[3][7] = 14; + newstable[4][0] = 0; + newstable[4][1] = 1; + newstable[4][2] = 5; + newstable[4][3] = 9; + newstable[4][4] = 8; + newstable[4][5] = 11; + newstable[4][6] = 7; + newstable[4][7] = 3; + newstable[5][0] = 1; + newstable[5][1] = 2; + newstable[5][2] = 6; + newstable[5][3] = 10; + newstable[5][4] = 9; + newstable[5][5] = 8; + newstable[5][6] = 4; + newstable[5][7] = 0; + newstable[6][0] = 2; + newstable[6][1] = 3; + newstable[6][2] = 7; + newstable[6][3] = 11; + newstable[6][4] = 10; + newstable[6][5] = 9; + newstable[6][6] = 5; + newstable[6][7] = 1; + newstable[7][0] = 3; + newstable[7][1] = 0; + newstable[7][2] = 4; + newstable[7][3] = 8; + newstable[7][4] = 11; + newstable[7][5] = 10; + newstable[7][6] = 6; + newstable[7][7] = 2; + newstable[8][0] = 4; + newstable[8][1] = 5; + newstable[8][2] = 9; + newstable[8][3] = 13; + newstable[8][4] = 12; + newstable[8][5] = 15; + newstable[8][6] = 11; + newstable[8][7] = 7; + newstable[9][0] = 5; + newstable[9][1] = 6; + newstable[9][2] = 10; + newstable[9][3] = 14; + newstable[9][4] = 13; + newstable[9][5] = 12; + newstable[9][6] = 8; + newstable[9][7] = 4; + newstable[10][0] = 6; + newstable[10][1] = 7; + newstable[10][2] = 11; + newstable[10][3] = 15; + newstable[10][4] = 14; + newstable[10][5] = 13; + newstable[10][6] = 9; + newstable[10][7] = 5; + newstable[11][0] = 7; + newstable[11][1] = 4; + newstable[11][2] = 8; + newstable[11][3] = 12; + newstable[11][4] = 15; + newstable[11][5] = 14; + newstable[11][6] = 10; + newstable[11][7] = 6; + newstable[12][0] = 8; + newstable[12][1] = 9; + newstable[12][2] = 13; + newstable[12][3] = 1; + newstable[12][4] = 0; + newstable[12][5] = 3; + newstable[12][6] = 15; + newstable[12][7] = 11; + newstable[13][0] = 9; + newstable[13][1] = 10; + newstable[13][2] = 14; + newstable[13][3] = 2; + newstable[13][4] = 1; + newstable[13][5] = 0; + newstable[13][6] = 12; + newstable[13][7] = 8; + newstable[14][0] = 10; + newstable[14][1] = 11; + newstable[14][2] = 15; + newstable[14][3] = 3; + newstable[14][4] = 2; + newstable[14][5] = 1; + newstable[14][6] = 13; + newstable[14][7] = 9; + newstable[15][0] = 11; + newstable[15][1] = 8; + newstable[15][2] = 12; + newstable[15][3] = 0; + newstable[15][4] = 3; + newstable[15][5] = 2; + newstable[15][6] = 14; + newstable[15][7] = 10; + end // initial begin + + reg [3:0] flags_addr_latch; + reg [3:0] flags_addr; + + always @* begin + if(flags_addr_latch) + flags_addr <= flags_addr_latch; + else + case(op) + `OP_LOADA: + flags_addr <= flagr; + `OP_LOADB: + flags_addr <= cond; + `OP_STORE: + flags_addr <= flagw; + default: + flags_addr <= 0; + endcase + end // always @ * + + reg [15:0] flags_in; + wire [15:0] flags_out; reg flags_write; - RAM #(.ADDRESS_BITS(3)) flags (.clk(clk), .write(flags_write), .addr(flags_addr), .in(flags_in), .out(flags_out)); + reg [15:0] latest_news; - reg [15:0] idx; + RAM #(.ADDRESS_BITS(3)) flags (.clk(clk), .write(flags_write), .addr(flags_addr[2:0]), .in(flags_in), .out(flags_out)); + + reg [15:0] flag_or_news; + + reg [15:0] newsidx; + + always @* begin + if(flags_addr[3]) begin // read from news + for(idx = 0; idx < 16; idx++) begin + newsidx = newstable[idx][flags_addr[2:0]]; + flag_or_news[idx] = latest_news[newsidx]; + end + end else begin + flag_or_news = flags_out; + end + end always @ (posedge clk) begin if(mem_write) mem_write <= 0; - if(flags_write) - flags_write <= 0; + if(flags_write) begin + flags_write <= 0; + flags_addr_latch <= 0; + end case (op) `OP_NOP: begin end @@ -142,7 +266,7 @@ assign alu_carry_out[15] = alu_carry[alu_index[15]]; `OP_LOADA: begin alu_carry <= aluc; - F <= flags_out; + F <= flag_or_news; A <= mem_out; C <= mem_out; io <= io_pin; @@ -153,19 +277,23 @@ assign alu_carry_out[15] = alu_carry[alu_index[15]]; `OP_LOADB: begin alu_sum <= alus; - Cond <= inv ? ~flags_out : flags_out; + Cond <= inv ? ~flag_or_news : flag_or_news; B <= mem_out; R <= mem_out; end `OP_STORE: begin - for(idx=0; idx < 16; idx++) - flags_in[idx] <= Cond[idx] ? alu_carry_out[idx] : flags_out[idx]; - flags_write <= 1; + 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 + if(flags_addr) begin // we do not write to flag 0 + flags_write <= 1; + flags_addr_latch <= flags_addr; + end mem_in <= alu_sum_out; mem_write <= 1; - // lots other stuff end `OP_READ: diff --git a/intermediare.pl b/intermediare.pl new file mode 100644 index 0000000..91df8ae --- /dev/null +++ b/intermediare.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +use v5.14; +use warnings; + +my @initial = ( + [qw/1 1 1 0/], + [qw/0 0 0 0/], + [qw/0 0 0 0/], + [qw/0 0 0 0/], + ); + +my @diffs = ( + [-1, 0], + [-1, 1], + [0 , 1], + [1 , 1], + [1 , 0], + [1 , -1], + [0 , -1], + [-1, -1] +); + +sub sum_for_diff { + my ($diff) = @_; + my @result; + my ($dx, $dy) = @{$diffs[$diff]}; + for my $i (0 .. 3) { + for my $j (0 .. 3) { + my $ni = ($i + 4 + $dx) % 4; + my $nj = ($j + 4 + $dy) % 4; + $result[$i][$j] = $initial[$ni][$nj]; + } + } +# say 'For diff ', $diff, ': '; +# say join ' ', @$_ for @result; + @result +} + +use Data::Dumper; + +my @sum1; +my @sum2; + +for my $x (qw/0 2 4 6/) { + @sum1 = sum_for_diff $x; + @sum2 = sum_for_diff ($x+1); + + my ($sum1, $sum2, $sumA, $sumB) = (0, 0, 0, 0); + my $cnt = 0; + for my $i (0 .. 3) { + for my $j (0 .. 3) { + my $sum = $sum1[$i][$j] + $sum2[$i][$j]; + $sum1 += $sum1[$i][$j] << $cnt; + $sum2 += $sum2[$i][$j] << $cnt; + $sumA += ($sum&1) << $cnt; + $sumB += ($sum&2) << ($cnt - 1); + $cnt++; + } + } + + printf "%04X + %04X = %016b %016b\n", $sum1, $sum2, $sumA, $sumB; +} diff --git a/newstable.pl b/newstable.pl new file mode 100644 index 0000000..402de4f --- /dev/null +++ b/newstable.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl +use v5.14; +use warnings; + +my @diffs = ( + [-1, 0], + [-1, 1], + [0 , 1], + [1 , 1], + [1 , 0], + [1 , -1], + [0 , -1], + [-1, -1] +); + +my @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 $cpu (0 .. ($side * $side - 1)) { + my $x = $cpu / $side; + my $y = $cpu % $side; + for my $direction (0 .. 7) { + my $nx = ($x + $diffs[$direction][0] + $side) % $side; + my $ny = ($y + $diffs[$direction][1] + $side) % $side; + say "newstable[$cpu][$direction] = ", $cpus[$nx][$ny], ';'; + } +} diff --git a/ram.v b/ram.v index 3720675..acd11ee 100644 --- a/ram.v +++ b/ram.v @@ -3,6 +3,12 @@ module RAM #(parameter ADDRESS_BITS = 4) reg [15:0] memory [0:2**ADDRESS_BITS-1]; + reg [ADDRESS_BITS:0] idx; + initial begin + for(idx = 0; idx < 2**ADDRESS_BITS; idx=idx+1) + memory[idx] <= 0; + end + always @ (negedge clk) begin if (write) memory[addr] <= in; diff --git a/toplevel.v b/toplevel.v index 728fee4..f908234 100644 --- a/toplevel.v +++ b/toplevel.v @@ -1,16 +1,40 @@ +`include "pll.v" `include "ram.v" `include "chip.v" `include "uart.v" +`ifdef SIM + `define UART_DIVIDE 1 +`else + `define UART_DIVIDE 1 + // s/192/3/ for 19200 baud uart +`endif + module toplevel (input CLKin, output [4:0] led, output uart_tx, input uart_rx); - wire clk = CLKin; + wire clk; + wire clk_tmp; + + //pll pll (.clock_in(CLKin), .clock_out(clk)); + + reg [20:0] counter = 0; + + reg clk = 0; + + always @ (posedge CLKin) begin + if(counter == 5000) begin + counter <= 0; + clk <= 1 - clk; + end + else + counter <= counter + 1; + end wire [11:0] mem_addr; wire [15:0] mem_in; wire [15:0] mem_out; wire mem_write; - RAM #(.ADDRESS_BITS(12)) ram (.clk(clk), .write(mem_write), .addr(mem_addr), .in(mem_in), .out(mem_out)); + RAM #(.ADDRESS_BITS(8)) ram (.clk(clk), .write(mem_write), .addr(mem_addr), .in(mem_in), .out(mem_out)); reg [7:0] from_uart [3:0]; reg [2:0] uart_ptr = 0; @@ -22,49 +46,73 @@ module toplevel (input CLKin, output [4:0] led, output uart_tx, input uart_rx); reg [2:0] op = 0; - assign led = uart_ptr; + 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)); wire received; wire [7:0] rx_byte; reg transmit = 0; - reg [7:0] tx_byte; + reg [7:0] tx_byte = 0; + wire is_receiving; + wire is_transmitting; + + // 19200 (actually 300) baud uart + uart #(.CLOCK_DIVIDE(`UART_DIVIDE)) uart (.clk(clk), .rx(uart_rx), .tx(uart_tx), .received(received), .transmit(transmit), .tx_byte(tx_byte), .rx_byte(rx_byte), .is_receiving(is_receiving), .is_transmitting(is_transmitting)); - uart uart (.clk(clk), .rx(uart_rx), .tx(uart_tx), .received(received), .transmit(transmit), .tx_byte(tx_byte), .rx_byte(rx_byte)); + assign led[0] = is_transmitting; + assign led[4] = received; +// assign led[3:1] = last_op; - reg [15:0] rom_I [0:5]; - reg [7:0] rom_mem_addr [0:5]; - reg [2:0] rom_op [0:5]; - reg rom_CS [0:5]; + reg did_it = 0; + assign led[2] = did_it; reg [2:0] state = 0; +// assign led[4:2] = state; + always @ (posedge clk) begin - if (received) begin + if (state == 0 && received) begin from_uart[uart_ptr] <= rx_byte; uart_ptr <= uart_ptr + 1; end - if (uart_ptr == 4) begin + if (state == 0 && uart_ptr == 4) begin op <= op_from_uart; + last_op <= op_from_uart; uart_ptr <= 0; + did_it <= 1; state <= 1; end - if (state == 1) begin - transmit <= 1; - tx_byte <= mem_in; + 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) begin + if (state == 2 && transmit) begin transmit <= 0; - state <= 0; end - if (op != 0) begin - op <= 0; + 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 endmodule diff --git a/yosys-sim-script b/yosys-sim-script index 10f21ec..f82bfb4 100755 --- a/yosys-sim-script +++ b/yosys-sim-script @@ -1,3 +1,3 @@ -read_verilog -sv -DSIM lisp_processor.v +read_verilog -sv -DSIM toplevel.v prep -top cpu -nordff sim -clock clk -vcd test.vcd -n 3000 -- 2.39.2