1 package App
::Scheme79asm
;
7 use Data
::Dumper qw
/Dumper/;
8 use Data
::SExpression qw
/consp scalarp/;
9 use Scalar
::Util qw
/looks_like_number/;
11 our $VERSION = '0.004';
39 *consp
= *Data
::SExpression
::consp
;
40 *scalarp
= *Data
::SExpression
::scalarp
;
43 my ($self, $sexp, $location) = @_;
44 die 'Toplevel is not a list: ', Dumper
($sexp), "\n" unless ref $sexp eq 'ARRAY';
45 my ($type, @addrs) = @
$sexp;
48 die 'Type of toplevel is not atom: '. Dumper
($type), "\n" unless scalarp
($type);
51 $addr = $self->{freeptr
} + 1;
52 $self->{freeptr
} += @addrs;
53 $self->process($addrs[$_], $addr + $_) for 0 .. $#addrs;
58 $addr = $self->process($addr) if ref $addr eq 'ARRAY';
59 die 'Addr of toplevel is not atom: ', Dumper
($addr), "\n" unless scalarp
($addr);
60 my ($comment_type, $comment_addr) = ($type, $addr);
61 die 'Computed addr is not a number: ', Dumper
($addr), "\n" unless looks_like_number
$addr;
63 if (!looks_like_number
$type) {
64 die "No such type: $type\n" unless exists $TYPES{$type};
65 $type = $TYPES{$type};
68 $addr += (1 << $self->{addr_bits
}) if $addr < 0;
69 die "Type too large: $type\n" unless $type < (1 << $self->{type_bits
});
70 die "Addr too large: $addr\n" unless $addr < (1 << $self->{addr_bits
});
71 my $result = ($type << $self->{addr_bits
}) + $addr;
74 $location = $self->{freeptr
}
76 $self->{memory
}[$location] = $result;
77 $self->{comment
}[$location] = "$comment_type $comment_addr";
82 my ($self, $string) = @_;
83 my $ds = Data
::SExpression
->new({symbol_case
=> 'up', use_symbol_class
=> 1, fold_lists
=> 1});
87 last if $string =~ /^\s*$/;
88 ($sexp, $string) = $ds->read($string);
95 $self->{memory
}[5] = $self->{memory
}[$self->{freeptr
}];
96 $self->{comment
}[5] = $self->{comment
}[$self->{freeptr
}];
97 $self->{memory
}[4] = $self->{freeptr
};
98 delete $self->{memory
}[$self->{freeptr
}]
102 my ($class, %args) = @_;
103 $args{type_bits
} //= 3;
104 $args{addr_bits
} //= 8;
105 $args{freeptr
} //= 6;
106 $args{memory
} //= [0, 0, (1<<$args{addr_bits
}), (1<<$args{addr_bits
}), 0, 0, 0];
107 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)');
108 for (0 .. $#default_comments) {
109 $args{comment
}[$_] = $default_comments[$_]
115 my ($self, $fh) = @_;
116 $fh //= \
*STDOUT
; # uncoverable condition right
118 die "addr_bits + type_bits >= 16\n"if $self->{addr_bits
} + $self->{type_bits
} > 16;
120 my $length = @
{$self->{memory
}};
121 print $fh pack('n', $length);
122 for (@
{$self->{memory
}}) {
123 print $fh pack('n', $_)
128 my ($self, $fh) = @_;
129 $fh //= \
*STDOUT
; # uncoverable condition right
131 my $bits = $self->{type_bits
} + $self->{addr_bits
};
132 my $index_length = length $#{$self->{memory}};
133 my $index_format = '%' . $index_length . 'd';
134 for my $index (0 .. $#{$self->{memory}}) {
135 my $val = $self->{memory
}[$index];
136 my $comment = $self->{comment
}[$index];
138 $val = "${bits}'d$val"
140 $val = $val ?
sprintf "%d'b%0${bits}b", $bits, $val : '0';
142 my $spaces = ' ' x
($bits + 5 - (length $val));
143 $index = sprintf $index_format, $index;
145 print $fh "mem[$index] <= $val;";
146 print $fh "$spaces // $comment" if defined $comment;
151 sub parse_and_print_binary16
{
152 my ($self, $string, $fh) = @_;
153 $self->parse($string);
155 $self->print_binary16($fh);
158 sub parse_and_print_verilog
{
159 my ($self, $string, $fh) = @_;
160 $self->parse($string);
162 $self->print_verilog($fh);
172 App::Scheme79asm - assemble sexp to Verilog ROM for SIMPLE processor
176 use App::Scheme79asm;
177 my $asm = App::Scheme79asm->new(type_bits => 3, addr_bits => 5);
178 $asm->parse_and_print_verilog('(number 70)');
182 SIMPLE is a LISP processor defined in the 1979
183 B<Design of LISP-Based Processors> paper by Steele and Sussman.
185 The SIMPLE processor expects input in a particular tagged-pointer
186 format. This module takes a string containing a sequence of
187 S-expressions. Each S-expression is a list of one of three types:
189 C<(tag value)>, for example C<(symbol 2)>, represents a value to be
190 put in memory (for example a number, or a symbol, or a variable
191 reference). The value must be a number.
193 C<(tag list)>, where C<list> is of one of these three types,
194 represents a tagged pointer. In this case, C<list> is (recursively)
195 laid out in memory as per these rules, and a pointer to that location
196 (and tagged C<tag>) is put somewhere in memory.
198 C<(tag list1 list2)>, where C<list1> and C<list2> are of one of these
199 three types (not necessarily the same type). In this case, C<list1>
200 and C<list2> are (recursively) laid out in memory such that C<list1>
201 is at position X and C<list2> is at position X+1, and a pointer of
202 type tag and value X is put somewhere in memory.
204 After this process the very last pointer placed in memory is moved to
205 the special location 5 (which is where SIMPLE expects to find the
206 expression to be evaluated).
208 In normal use a single S-expression will be supplied, representing an
211 The C<tag> is either a number, a type, or a primitive.
212 The available types are:
218 =item SYMBOL (syn. NUMBER)
220 =item VAR (syn. VARIABLE)
224 =item PROC (syn. PROCEDURE)
226 =item IF (syn. COND, CONDITIONAL)
230 =item QUOTE (syn. QUOTED)
234 The available primitives are:
256 The following methods are available:
260 =item App::Scheme79asm->B<new>([key => value, key => value, ...])
262 Create a new assembler object. Takes a list of keys and values, here
263 are the possible keys:
271 A word is made of a type and an address, with the type occupying the
272 most significant C<type_bits> (default 3) bits, and the address
273 occupying the least significant C<address_bits> (default 8) bits.
274 Therefore the word size is C<type_bits + address_bits> (default 11).
278 A pointer to the last used byte in memory (default 6). The program
279 will be laid out starting with location C<freeptr + 1>.
283 The initial contents of the memory. Note that locations 4, 5, 6 will
284 be overwritten, as will every location larger than the value of
289 The initial comments for memory entries. C<< $comment->[$i] >> is the
290 comment for C<< $memory->[$i] >>. Note that the first 7 entries of
291 this array will be overwritten with the default comments. This is
292 useful when using custom initial memory contents and freeptr, because
293 this key can be used to provide comments for the extra reserved
298 =item $asm->B<parse>(I<$string>)
300 Parse a sequence of S-expressions and lay it out in memory.
301 Can be called multiple times to lay out multiple sequences of
302 S-expressions one after another.
304 =item $asm->B<process>(I<$sexp>)
306 Given an already-parsed sexp (meaning a
307 L<Data::SExpression> object), lay it out in memory.
308 Can be called multiple times to lay out multiple sequences of
309 S-expressions one after another.
311 =item $asm->B<finish>
313 Move the last pointer to position 5, and put the free pointer at
314 position 4. After all sequences of S-expressions have been given to
315 B<parse>, this method should be called.
317 =item $asm->B<print_binary16>([I<$fh>])
319 Print the length of the memory (as a big-endian 16-bit value),
320 followed by the memory contents as a sequence of big-endian 16-bit
321 values to the given filehandle (default STDOUT). Dies if
322 C<addr_bits + type_bits> is more than 16.
324 Big-endian 16-bit values can be decoded with C<unpack 'n', $value>.
326 =item $asm->B<print_verilog>([I<$fh>])
328 Print a block of Verilog code assigning the memory contents to an
329 array named C<mem> to the given filehandle (default STDOUT).
331 =item $asm->B<parse_and_print_binary16>(I<$string>[, I<$fh>])
333 Convenience method that calls B<parse>($string), B<finish>, and then
334 B<print_binary16>($fh).
336 =item $asm->B<parse_and_print_verilog>(I<$string>[, I<$fh>])
338 Convenience method that calls B<parse>($string), B<finish>, and then
339 B<print_verilog>($fh).
345 L<http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-514.pdf>
349 Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
351 =head1 COPYRIGHT AND LICENSE
353 Copyright (C) 2018 by Marius Gavrilescu
355 This library is free software; you can redistribute it and/or modify
356 it under the same terms as Perl itself, either Perl version 5.24.3 or,
357 at your option, any later version of Perl 5 you may have available.
This page took 0.041995 seconds and 4 git commands to generate.