]>
iEval git - app-scheme79asm.git/blob - lib/App/Scheme79asm.pm
1 package App
:: Scheme79asm
;
9 use Data
:: Dumper qw
/Dumper/ ;
10 use Data
:: SExpression qw
/consp scalarp/ ;
11 use Scalar
:: Util qw
/looks_like_number/ ;
13 our $VERSION = '0.005001' ;
41 * consp
= * Data
:: SExpression
:: consp
;
42 * scalarp
= * Data
:: SExpression
:: scalarp
;
45 my ( $self , $sexp , $location ) = @_ ;
46 die 'Toplevel is not a list: ' , Dumper
( $sexp ), " \n " unless ref $sexp eq 'ARRAY' ;
47 my ( $type , @addrs ) = @
$sexp ;
50 die 'Type of toplevel is not atom: ' . Dumper
( $type ), " \n " unless scalarp
( $type );
53 $addr = $self ->{ freeptr
} + 1 ;
54 $self ->{ freeptr
} += @addrs ;
55 $self -> process ( $addrs [ $_ ], $addr + $_ ) for 0 .. $#addrs ;
60 $addr = $self -> process ( $addr ) if ref $addr eq 'ARRAY' ;
61 die 'Addr of toplevel is not atom: ' , Dumper
( $addr ), " \n " unless scalarp
( $addr );
62 my ( $comment_type , $comment_addr ) = ( $type , $addr );
63 die 'Computed addr is not a number: ' , Dumper
( $addr ), " \n " unless looks_like_number
$addr ;
65 if (! looks_like_number
$type ) {
66 die "No such type: $type \n " unless exists $TYPES { $type };
67 $type = $TYPES { $type };
70 $addr += ( 1 << $self ->{ addr_bits
}) if $addr < 0 ;
71 die "Type too large: $type \n " if $type >= ( 1 << $self ->{ type_bits
});
72 die "Addr too large: $addr \n " if $addr >= ( 1 << $self ->{ addr_bits
});
73 my $result = ( $type << $self ->{ addr_bits
}) + $addr ;
77 $location = $self ->{ freeptr
}
79 $self ->{ memory
}[ $location ] = $result ;
80 $self ->{ comment
}[ $location ] = " $comment_type $comment_addr " ;
85 my ( $self , $string ) = @_ ;
86 my $ds = Data
:: SExpression
-> new ({ symbol_case
=> 'up' , use_symbol_class
=> 1 , fold_lists
=> 1 });
90 last if $string =~ /^\s*$/ ;
91 ( $sexp , $string ) = $ds -> read ( $string );
98 $self ->{ memory
}[ 5 ] = $self ->{ memory
}[ $self ->{ freeptr
}];
99 $self ->{ comment
}[ 5 ] = $self ->{ comment
}[ $self ->{ freeptr
}];
100 $self ->{ memory
}[ 4 ] = $self ->{ freeptr
};
101 delete $self ->{ memory
}[ $self ->{ freeptr
}]
105 my ( $class , %args ) = @_ ;
106 $args { type_bits
} // = 3 ;
107 $args { addr_bits
} // = 8 ;
108 $args { freeptr
} // = 6 ;
109 $args { memory
} // = [ 0 , 0 , ( 1 << $args { addr_bits
}), ( 1 << $args { addr_bits
}), 0 , 0 , 0 ];
110 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)' );
111 for ( 0 .. $#default_comments ) {
112 $args { comment
}[ $_ ] = $default_comments [ $_ ]
118 my ( $self , $fh ) = @_ ;
119 $fh // = \
* STDOUT
; # uncoverable condition right
121 die "addr_bits + type_bits >= 16 \n " if $self ->{ addr_bits
} + $self ->{ type_bits
} > 16 ;
123 my $length = @
{ $self ->{ memory
}};
124 print $fh pack 'n' , $length or croak
"Failed to print memory size: $!" ;
125 for ( @
{ $self ->{ memory
}}) {
126 print $fh pack 'n' , $_ or croak
"Failed to print memory: $!"
131 my ( $self , $fh ) = @_ ;
132 $fh // = \
* STDOUT
; # uncoverable condition right
134 my $bits = $self ->{ type_bits
} + $self ->{ addr_bits
};
135 my $index_length = length $ #{$self->{memory}};
136 my $index_format = '%' . $index_length . 'd' ;
137 for my $index ( 0 .. $ #{$self->{memory}}) {
138 my $val = $self ->{ memory
}[ $index ];
139 my $comment = $self ->{ comment
}[ $index ];
141 $val = "${bits}'d $val "
143 $val = $val ?
sprintf " %d 'b %0 ${bits}b" , $bits , $val : '0' ;
145 my $spaces = ' ' x
( $bits + 5 - ( length $val ));
146 $index = sprintf $index_format , $index ;
148 my $string = "mem[ $index ] <= $val ;" ;
149 $string .= " $spaces // $comment " if defined $comment ;
150 say $fh $string or croak
"Failed to print verilog: $!" ;
154 sub parse_and_print_binary16
{
155 my ( $self , $string , $fh ) = @_ ;
156 $self -> parse ( $string );
158 $self -> print_binary16 ( $fh );
161 sub parse_and_print_verilog
{
162 my ( $self , $string , $fh ) = @_ ;
163 $self -> parse ( $string );
165 $self -> print_verilog ( $fh );
175 App::Scheme79asm - assemble sexp to Verilog ROM for SIMPLE processor
179 use App::Scheme79asm;
180 my $asm = App::Scheme79asm->new(type_bits => 3, addr_bits => 5);
181 $asm->parse_and_print_verilog('(number 70)');
185 SIMPLE is a LISP processor defined in the 1979
186 B<Design of LISP-Based Processors> paper by Steele and Sussman.
188 The SIMPLE processor expects input in a particular tagged-pointer
189 format. This module takes a string containing a sequence of
190 S-expressions. Each S-expression is a list of one of three types:
192 C<(tag value)>, for example C<(symbol 2)>, represents a value to be
193 put in memory (for example a number, or a symbol, or a variable
194 reference). The value must be a number.
196 C<(tag list)>, where C<list> is of one of these three types,
197 represents a tagged pointer. In this case, C<list> is (recursively)
198 laid out in memory as per these rules, and a pointer to that location
199 (and tagged C<tag>) is put somewhere in memory.
201 C<(tag list1 list2)>, where C<list1> and C<list2> are of one of these
202 three types (not necessarily the same type). In this case, C<list1>
203 and C<list2> are (recursively) laid out in memory such that C<list1>
204 is at position X and C<list2> is at position X+1, and a pointer of
205 type tag and value X is put somewhere in memory.
207 After this process the very last pointer placed in memory is moved to
208 the special location 5 (which is where SIMPLE expects to find the
209 expression to be evaluated).
211 In normal use a single S-expression will be supplied, representing an
214 The C<tag> is either a number, a type, or a primitive.
215 The available types are:
221 =item SYMBOL (syn. NUMBER)
223 =item VAR (syn. VARIABLE)
227 =item PROC (syn. PROCEDURE)
229 =item IF (syn. COND, CONDITIONAL)
233 =item QUOTE (syn. QUOTED)
237 The available primitives are:
259 The following methods are available:
263 =item App::Scheme79asm->B<new>([key => value, key => value, ...])
265 Create a new assembler object. Takes a list of keys and values, here
266 are the possible keys:
274 A word is made of a type and an address, with the type occupying the
275 most significant C<type_bits> (default 3) bits, and the address
276 occupying the least significant C<address_bits> (default 8) bits.
277 Therefore the word size is C<type_bits + address_bits> (default 11).
281 A pointer to the last used byte in memory (default 6). The program
282 will be laid out starting with location C<freeptr + 1>.
286 The initial contents of the memory. Note that locations 4, 5, 6 will
287 be overwritten, as will every location larger than the value of
292 The initial comments for memory entries. C<< $comment->[$i] >> is the
293 comment for C<< $memory->[$i] >>. Note that the first 7 entries of
294 this array will be overwritten with the default comments. This is
295 useful when using custom initial memory contents and freeptr, because
296 this key can be used to provide comments for the extra reserved
301 =item $asm->B<parse>(I<$string>)
303 Parse a sequence of S-expressions and lay it out in memory.
304 Can be called multiple times to lay out multiple sequences of
305 S-expressions one after another.
307 =item $asm->B<process>(I<$sexp>)
309 Given an already-parsed sexp (meaning a
310 L<Data::SExpression> object), lay it out in memory.
311 Can be called multiple times to lay out multiple sequences of
312 S-expressions one after another.
314 =item $asm->B<finish>
316 Move the last pointer to position 5, and put the free pointer at
317 position 4. After all sequences of S-expressions have been given to
318 B<parse>, this method should be called.
320 =item $asm->B<print_binary16>([I<$fh>])
322 Print the length of the memory (as a big-endian 16-bit value),
323 followed by the memory contents as a sequence of big-endian 16-bit
324 values to the given filehandle (default STDOUT). Dies if
325 C<addr_bits + type_bits> is more than 16.
327 Big-endian 16-bit values can be decoded with C<unpack 'n', $value>.
329 =item $asm->B<print_verilog>([I<$fh>])
331 Print a block of Verilog code assigning the memory contents to an
332 array named C<mem> to the given filehandle (default STDOUT).
334 =item $asm->B<parse_and_print_binary16>(I<$string>[, I<$fh>])
336 Convenience method that calls B<parse>($string), B<finish>, and then
337 B<print_binary16>($fh).
339 =item $asm->B<parse_and_print_verilog>(I<$string>[, I<$fh>])
341 Convenience method that calls B<parse>($string), B<finish>, and then
342 B<print_verilog>($fh).
348 L<http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-514.pdf>
352 Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
354 =head1 COPYRIGHT AND LICENSE
356 Copyright (C) 2018 by Marius Gavrilescu
358 This library is free software; you can redistribute it and/or modify
359 it under the same terms as Perl itself, either Perl version 5.24.3 or,
360 at your option, any later version of Perl 5 you may have available.
This page took 0.088856 seconds and 4 git commands to generate.