X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=lib%2FApp%2FScheme79asm.pm;h=fb99ee33ef5a51fc4bd05ddbaf25896fdde4a929;hb=1756f22980afffd139ded7742af489196f928c1a;hp=5aebe08689da7b303fc85016d414f0a16d8ae910;hpb=0edb4b34e85aceb436bfc91748338a4155c881e5;p=app-scheme79asm.git diff --git a/lib/App/Scheme79asm.pm b/lib/App/Scheme79asm.pm index 5aebe08..fb99ee3 100644 --- a/lib/App/Scheme79asm.pm +++ b/lib/App/Scheme79asm.pm @@ -3,12 +3,14 @@ package App::Scheme79asm; use 5.014000; use strict; use warnings; +use re '/s'; +use Carp qw/croak/; use Data::Dumper qw/Dumper/; use Data::SExpression qw/consp scalarp/; use Scalar::Util qw/looks_like_number/; -our $VERSION = '0.002'; +our $VERSION = '0.004'; our %TYPES = ( LIST => 0, @@ -32,7 +34,7 @@ our %TYPES = ( CONS => 3, ATOM => 4, PROGN => 5, - MAKELIST => 6, + 'REVERSE-LIST' => 6, FUNCALL => 7, ); @@ -57,28 +59,17 @@ sub process { $addr = $self->process($addr) if ref $addr eq 'ARRAY'; die 'Addr of toplevel is not atom: ', Dumper($addr), "\n" unless scalarp($addr); - my ($comment_type, $comment_addr) = ($type, $addr); - - unless (looks_like_number $addr) { # is symbol - unless (exists $self->{symbols}{$addr}) { - $self->{symbols}{$addr} = $self->{nsymbols}; - $self->{nsymbols}++; - } - $addr = $self->{symbols}{$addr} - } - die 'Computed addr is not a number: ', Dumper($addr), "\n" unless looks_like_number $addr; - if (ref $type eq 'Data::SExpression::Symbol') { + if (!looks_like_number $type) { die "No such type: $type\n" unless exists $TYPES{$type}; $type = $TYPES{$type}; - } elsif (!looks_like_number $type) { - die "Type is not a number or symbol: $type\n" } - die "Type too large: $type\n" unless $type < (1 << $self->{type_bits}); - die "Addr too large: $addr\n" unless $addr < (1 << $self->{addr_bits}); + $addr += (1 << $self->{addr_bits}) if $addr < 0; + die "Type too large: $type\n" if $type >= (1 << $self->{type_bits}); + die "Addr too large: $addr\n" if $addr >= (1 << $self->{addr_bits}); my $result = ($type << $self->{addr_bits}) + $addr; unless ($location) { $self->{freeptr}++; @@ -115,16 +106,29 @@ sub new { $args{addr_bits} //= 8; $args{freeptr} //= 6; $args{memory} //= [0, 0, (1<<$args{addr_bits}), (1<<$args{addr_bits}), 0, 0, 0]; - $args{symbols}{NIL} = 0; - $args{symbols}{T} = 1; - $args{nsymbols} = 2; - $args{comment} = ['(cdr part of NIL)', '(car part of NIL)', '(cdr part of T)', '(car part of T)', '(free storage pointer)', '', '(result of computation)']; + my @default_comments = ('(cdr part of NIL)', '(car part of NIL)', '(cdr part of T)', '(car part of T)', '(free storage pointer)', '', '(result of computation)'); + for (0 .. $#default_comments) { + $args{comment}[$_] = $default_comments[$_] + } bless \%args, $class } -sub print { +sub print_binary16 { + my ($self, $fh) = @_; + $fh //= \*STDOUT; # uncoverable condition right + + die "addr_bits + type_bits >= 16\n"if $self->{addr_bits} + $self->{type_bits} > 16; + + my $length = @{$self->{memory}}; + print $fh pack 'n', $length or croak "Failed to print memory size: $!"; + for (@{$self->{memory}}) { + print $fh pack 'n', $_ or croak "Failed to print memory: $!" + } +} + +sub print_verilog { my ($self, $fh) = @_; - $fh //= \*STDOUT; + $fh //= \*STDOUT; # uncoverable condition right my $bits = $self->{type_bits} + $self->{addr_bits}; my $index_length = length $#{$self->{memory}}; @@ -139,15 +143,25 @@ sub print { } my $spaces = ' ' x ($bits + 5 - (length $val)); $index = sprintf $index_format, $index; - say $fh "mem[$index] <= $val;$spaces // $comment" + + my $string = "mem[$index] <= $val;"; + $string .= "$spaces // $comment" if defined $comment; + say $fh $string or croak "Failed to print verilog: $!"; } + +} +sub parse_and_print_binary16 { + my ($self, $string, $fh) = @_; + $self->parse($string); + $self->finish; + $self->print_binary16($fh); } -sub parse_and_print { +sub parse_and_print_verilog { my ($self, $string, $fh) = @_; $self->parse($string); $self->finish; - $self->print($fh); + $self->print_verilog($fh); } 1; @@ -163,7 +177,7 @@ App::Scheme79asm - assemble sexp to Verilog ROM for SIMPLE processor use App::Scheme79asm; my $asm = App::Scheme79asm->new(type_bits => 3, addr_bits => 5); - $asm->parse_and_print('(number 70)'); + $asm->parse_and_print_verilog('(number 70)'); =head1 DESCRIPTION @@ -174,9 +188,9 @@ The SIMPLE processor expects input in a particular tagged-pointer format. This module takes a string containing a sequence of S-expressions. Each S-expression is a list of one of three types: -C<(tag value)>, for example C<(symbol nil)>, represents a value to be +C<(tag value)>, for example C<(symbol 2)>, represents a value to be put in memory (for example a number, or a symbol, or a variable -reference). +reference). The value must be a number. C<(tag list)>, where C is of one of these three types, represents a tagged pointer. In this case, C is (recursively) @@ -235,7 +249,7 @@ The available primitives are: =item PROGN -=item MAKELIST +=item REVERSE-LIST =item FUNCALL @@ -259,7 +273,7 @@ are the possible keys: A word is made of a type and an address, with the type occupying the most significant C (default 3) bits, and the address occupying the least significant C (default 8) bits. -Therefore the word size is C (default 13). +Therefore the word size is C (default 11). =item freeptr @@ -275,16 +289,11 @@ C. =item comment The initial comments for memory entries. C<< $comment->[$i] >> is the -comment for C<< $memory->[$i] >>. - -=item symbols - -The initial symbol map, as a hashref from symbol name to the index of -that symbol. Defaults to C<< {NIL => 0, T => 1} >>. - -=item nsymbols - -The number of distinct symbols in the initial symbols map (default 2). +comment for C<< $memory->[$i] >>. Note that the first 7 entries of +this array will be overwritten with the default comments. This is +useful when using custom initial memory contents and freeptr, because +this key can be used to provide comments for the extra reserved +locations in memory. =back @@ -294,21 +303,42 @@ Parse a sequence of S-expressions and lay it out in memory. Can be called multiple times to lay out multiple sequences of S-expressions one after another. +=item $asm->B(I<$sexp>) + +Given an already-parsed sexp (meaning a +L object), lay it out in memory. +Can be called multiple times to lay out multiple sequences of +S-expressions one after another. + =item $asm->B Move the last pointer to position 5, and put the free pointer at position 4. After all sequences of S-expressions have been given to B, this method should be called. -=item $asm->B([I<$fh>]) +=item $asm->B([I<$fh>]) + +Print the length of the memory (as a big-endian 16-bit value), +followed by the memory contents as a sequence of big-endian 16-bit +values to the given filehandle (default STDOUT). Dies if +C is more than 16. + +Big-endian 16-bit values can be decoded with C. + +=item $asm->B([I<$fh>]) Print a block of Verilog code assigning the memory contents to an array named C to the given filehandle (default STDOUT). -=item $asm->B(I<$string>[, I<$fh>]) +=item $asm->B(I<$string>[, I<$fh>]) + +Convenience method that calls B($string), B, and then +B($fh). + +=item $asm->B(I<$string>[, I<$fh>]) Convenience method that calls B($string), B, and then -B($fh). +B($fh). =back