use parent qw/Exporter/;
-our @EXPORT = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route/;
-our @EXPORT_OK = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route/;
+our @EXPORT = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route chip_select/;
+our @EXPORT_OK = qw/loada loadb store write_verilog alu_select_a alu_select_b alu_select_f alu_zero flag_zero flag_news alu_xor alu_xnor alu_or alu_of_function aluc_add alus_add aluc_addAF alus_addAF alu2 alu3 add addC loadi storei ledm ledi route chip_select/;
use File::Slurp::Tiny 'write_file';
my $rom_cnt = 0;
+# by default instructions are for all 4 chips to execute
+our $CS = 0xF;
+
sub send_ {
my ($cmd) = @_;
my %cmd = %$cmd;
+ my $op_cs = $cmd{op} + ($CS << 4);
- my $binary = pack 'vCC', @cmd{qw/I mem_addr op/}; # we ignore CS for now
+ my $binary = pack 'vCC', $cmd{I}, $cmd{mem_addr}, $op_cs;
my $hex = reverse unpack 'h*', $binary;
- say "$rom_cnt: data <= 32'h$hex;";
+ # say "$rom_cnt: data <= 32'h$hex;";
+ say $hex;
$rom_cnt++;
}
+sub chip_select {
+ my ($new_cs, $sub) = @_;
+ local $CS = $new_cs;
+ $sub->();
+}
sub nop {
send_
- { I => 0, mem_addr => 0, op => OP_NOP, CS => 0 }
+ { I => 0, mem_addr => 0, op => OP_NOP }
}
sub loada {
$I |= $bsel << 4;
$I |= $aluc << 5;
send_
- { I => $I, mem_addr => $addr, op => OP_LOADA, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_LOADA }
}
sub loadb {
$I |= $inv << 4;
$I |= $alus << 5;
send_
- { I => $I, mem_addr => $addr, op => OP_LOADB, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_LOADB }
}
#sub read_ {
$I |= $edge_ << 7;
$I |= $cube << 8;
send_
- { I => $I, mem_addr => $addr, op => OP_STORE, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_STORE }
}
sub loadi {
my ($addr, $I) = @_;
send_
- { I => $I, mem_addr => $addr, op => OP_LOADI, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_LOADI }
}
sub route {
- my ($addr, $dest_addr) = @_;
+ my ($addr, $dest_addr, $led) = @_;
+ $led //= 0;
my $I = $dest_addr;
+ $I |= $led << 12;
send_
- { I => $I, mem_addr => $addr, op => OP_ROUTE, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_ROUTE }
}
sub storei {
my ($addr, $I) = @_;
send_
- { I => $I, mem_addr => $addr, op => OP_STOREI, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_STOREI }
}
sub led {
my $I = $offset_leds;
$I |= $mode << 4;
send_
- { I => $I, mem_addr => $addr, op => OP_LED, CS => 0 }
+ { I => $I, mem_addr => $addr, op => OP_LED }
}
sub ledm {
my ($addr, $offset) = @_;
+ $offset //= 0;
led $addr, 1, $offset;
}
sub alu_or { alu_of_function { $a | $b | $_ } }
+sub alu_and { alu_of_function { $a & $b & $_ } }
+
+BEGIN {
+ die "alus_add != alu_xor" unless alus_add == alu_xor;
+ die "bad alu_select_f" unless alu_select_f == alu_of_function { $_ };
+}
+
sub alu2 {
my ($aluc, $alus, $addrA, $addrB, $flagr, $flagw, $cond, $inv) = @_;
loada $addrA, $flagr, 0, $aluc;
store $addrC, $flagw, 0, 0;
}
+sub mov {
+ my ($addrA, $addrC) = @_;
+ alu3 alu_zero, alu_select_a, $addrA, $addrA, $addrC, flag_zero, flag_zero
+}
+
sub add {
my ($addrA, $addrB, $addrC, $flag_carry) = @_;
alu3 aluc_add, alus_add, $addrA, $addrB, $addrC, flag_zero, $flag_carry;
alu3 aluc_add, alus_add, $addrA, $addrB, $addrC, $flag_carry, $flag_carry;
}
+sub xor_ {
+ my ($addrA, $addrB, $addrC) = @_;
+ alu3 alu_zero, alu_xor, $addrA, $addrB, $addrC, flag_zero, flag_zero;
+}
+
+sub and_ {
+ my ($addrA, $addrB, $addrC) = @_;
+ alu3 alu_zero, alu_and, $addrA, $addrB, $addrC, flag_zero, flag_zero;
+}
+
# news_gen face partea de mijloc
# news_[mf][mf] face primul alu3, apeleaza news_gen, apoi face ultimul alu3
sub news_generic {
my %dest = %$dest;
while ($nX || $nY) {
my $direction;
- if ($nX && $nY) {
- $nX--;
- $nY--;
- $direction = 7;
- } elsif ($nX) {
+ if ($nX > 0) {
$nX--;
+ $direction = 2;
+ } elsif ($nX < 0) {
+ $nX++;
$direction = 0;
- } else {
+ } elsif ($nY > 0) {
$nY--;
- $direction = 6;
+ $direction = 1;
+ } elsif ($nY < 0) {
+ $nY++;
+ $direction = 3;
}
if ($nX || $nY) { # not the last go
alu3 alu_select_f, alu_select_a, 0, 0, 0, flag_news($direction), flag_zero