X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=asm.pm;h=1b6dc8ad82e0d98ad48dd0583098eb8279979a7b;hb=46a95fd39e0ef114dd837bed285f8ca6acf6bb32;hp=269b8d1d49d62963131325ce32f42e95e1e0f3ca;hpb=ffba35f814eda0a4c47af601206cf2d3ab6eab03;p=clump.git diff --git a/asm.pm b/asm.pm index 269b8d1..1b6dc8a 100644 --- a/asm.pm +++ b/asm.pm @@ -36,8 +36,8 @@ my $port; 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'; @@ -70,20 +70,30 @@ sub send__ { 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 { @@ -93,7 +103,7 @@ 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 { @@ -103,7 +113,7 @@ 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_ { @@ -118,26 +128,28 @@ sub store { $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 { @@ -145,11 +157,12 @@ 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; } @@ -207,6 +220,13 @@ sub alus_addAF { alu_of_function { ($a + $_) & 1 } } 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; @@ -221,6 +241,11 @@ sub alu3 { 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; @@ -231,6 +256,16 @@ sub addC { 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 { @@ -238,16 +273,18 @@ 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