From: Marius Gavrilescu Date: Wed, 31 Jan 2018 16:31:12 +0000 (+0000) Subject: Initial commit X-Git-Tag: 0.001^0 X-Git-Url: http://git.ieval.ro/?a=commitdiff_plain;h=509643aa72045d0554141ef9f133788a6eee61e4;p=app-scheme79asm.git Initial commit --- 509643aa72045d0554141ef9f133788a6eee61e4 diff --git a/Changes b/Changes new file mode 100644 index 0000000..dfa8266 --- /dev/null +++ b/Changes @@ -0,0 +1,5 @@ +Revision history for Perl extension App::Scheme79asm. + +0.001 2018-01-31T16:31+00:00 + - Initial release + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..6f8aef8 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,7 @@ +Changes +Makefile.PL +MANIFEST +README +scheme79asm +t/App-Scheme79asm.t +lib/App/Scheme79asm.pm diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..01a6524 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,20 @@ +use 5.014000; +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'App::Scheme79asm', + VERSION_FROM => 'lib/App/Scheme79asm.pm', + ABSTRACT_FROM => 'lib/App/Scheme79asm.pm', + MIN_PERL_VERSION => '5.14.0', + LICENSE => 'perl', + SIGN => 1, + PREREQ_PM => { + qw/Data::SExpression 0.41/, + }, + META_ADD => { + dynamic_config => 0, + resources => { + repository => 'https://git.ieval.ro/?p=app-scheme79asm.git', + }, + } +); diff --git a/README b/README new file mode 100644 index 0000000..85e76bc --- /dev/null +++ b/README @@ -0,0 +1,39 @@ +App-Scheme79asm version 0.001 +============================= + +SIMPLE is a LISP processor defined in the 1979 +B paper by Steele and Sussman. + +The SIMPLE processor expects input in a particular tagged-pointer +format. This module takes a string containing a sequence of +S-expressions of the form C<(tag . value)> representing a tagged +pointer. Here the tag is either a number or one of several predefined +values (see the source for a full list), and the value is either a +number or another tagged pointer. These values are laid out in memory +and a block of verilog code assigning the memory contents to an array +named C is printed. + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires these other modules and libraries: + +* Data::SExpression + +COPYRIGHT AND LICENCE + +Copyright (C) 2018 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.24.3 or, +at your option, any later version of Perl 5 you may have available. + + diff --git a/lib/App/Scheme79asm.pm b/lib/App/Scheme79asm.pm new file mode 100644 index 0000000..ec0ada3 --- /dev/null +++ b/lib/App/Scheme79asm.pm @@ -0,0 +1,159 @@ +package App::Scheme79asm; + +use 5.014000; +use strict; +use warnings; + +use Data::SExpression qw/consp scalarp/; +use Scalar::Util qw/looks_like_number/; + +our $VERSION = '0.001'; + +our %TYPES = ( + LIST => 0, + SYMBOL => 1, + VAR => 2, + VARIABLE => 2, + CLOSURE => 3, + PROC => 4, + PROCEDURE => 4, + COND => 5, + CONDITIONAL => 5, + CALL => 6, + FUNCALL => 6, + QUOTE => 7, + QUOTED => 7, +); + +*consp = *Data::SExpression::consp; +*scalarp = *Data::SExpression::scalarp; + +sub process { + my ($self, $sexp) = @_; + die "Toplevel is not a cons: $sexp\n " unless consp($sexp); + my $type = $sexp->car; + my $addr = $sexp->cdr; + + die "Type of toplevel is not atom: $type\n" unless scalarp($type); + $addr = $self->process($addr) if consp($addr); + die "Addr of toplevel is not atom: $addr\n" unless scalarp($addr); + + die "Computed addr is not a number: $addr\n" unless looks_like_number $addr; + + if (ref $type eq 'Data::SExpression::Symbol') { + 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}); + my $result = ($type << $self->{addr_bits}) + $addr; + $self->{freeptr}++; + $self->{memory}[$self->{freeptr}] = $result; + $self->{freeptr} +} + +sub parse { + my ($self, $string) = @_; + my $ds = Data::SExpression->new({symbol_case => 'up', use_symbol_class => 1, fold_lists => 0}); + + my $sexp; + while () { + last if $string =~ /^\s*$/; + ($sexp, $string) = $ds->read($string); + $self->process($sexp) + } +} + +sub finish { + my ($self) = @_; + $self->{memory}[5] = $self->{memory}[$self->{freeptr}]; + $self->{memory}[4] = $self->{freeptr}; + delete $self->{memory}[$self->{freeptr}] +} + +sub new { + my ($class, %args) = @_; + $args{type_bits} //= 3; + $args{addr_bits} //= 8; + $args{freeptr} //= 6; + $args{memory} //= [0, 0, (1<<$args{addr_bits}), (1<<$args{addr_bits}), 0, 0, 0]; + bless \%args, $class +} + +sub print { + my ($self, $fh) = @_; + $fh //= \*STDOUT; + + my $bits = $self->{type_bits} + $self->{addr_bits}; + for my $index (0 .. $#{$self->{memory}}) { + my $val = $self->{memory}[$index]; + if ($index == 4) { + $val = "${bits}'d$val" + } else { + $val = $val ? sprintf "%d'b%0${bits}b", $bits, $val : '0'; + } + say $fh "mem[$index] <= $val;" + } +} + +sub parse_and_print { + my ($self, $string, $fh) = @_; + $self->parse($string); + $self->finish; + $self->print($fh); +} + +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +App::Scheme79asm - assemble sexp to Verilog ROM for SIMPLE processor + +=head1 SYNOPSIS + + use App::Scheme79asm; + my $asm = App::Scheme79asm->new(type_bits => 3, addr_bits => 5); + $asm->parse_and_print('(number . 70)'); + +=head1 DESCRIPTION + +B this module does not do much at the moment. + +SIMPLE is a LISP processor defined in the 1979 +B paper by Steele and Sussman. + +The SIMPLE processor expects input in a particular tagged-pointer +format. This module takes a string containing a sequence of +S-expressions of the form C<(tag . value)> representing a tagged +pointer. Here the tag is either a number or one of several predefined +values (see the source for a full list), and the value is either a +number or another tagged pointer. These values are laid out in memory +and a block of verilog code assigning the memory contents to an array +named C is printed. + +More documentation and features to follow. + +=head1 SEE ALSO + +L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2018 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.24.3 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/scheme79asm b/scheme79asm new file mode 100755 index 0000000..9b2724a --- /dev/null +++ b/scheme79asm @@ -0,0 +1,16 @@ +#!/usr/bin/perl +use 5.014000; + +use App::Scheme79asm; +use Getopt::Long; + +my $type_bits; +my $addr_bits; + +GetOptions ('addr-bits=i' => \$addr_bits, 'type-bits=i' => \$type_bits); + +my $asm = App::Scheme79asm->new(addr_bits => $addr_bits, type_bits => $type_bits); +my $str = join '', <>; +$asm->parse_and_print($str); + +__END__ diff --git a/t/App-Scheme79asm.t b/t/App-Scheme79asm.t new file mode 100644 index 0000000..d95980b --- /dev/null +++ b/t/App-Scheme79asm.t @@ -0,0 +1,26 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Test::More tests => 2; +BEGIN { use_ok('App::Scheme79asm') }; + +sub run_test { + my ($args, $input, $expected, $name) = @_; + my $actual = ''; + open my $fh, '>', \$actual; + my $asm = App::Scheme79asm->new(%$args); + $asm->parse_and_print($input, $fh); + close $fh; + is $actual, $expected, $name +} + +run_test {addr_bits => 5}, '(quoted . (symbol . 5))', <<'', '(QUOTE 5)'; +mem[0] <= 0; +mem[1] <= 0; +mem[2] <= 8'b00100000; +mem[3] <= 8'b00100000; +mem[4] <= 8'd8; +mem[5] <= 8'b11100111; +mem[6] <= 0; +mem[7] <= 8'b00100101;