spot/iface/nips/nips_vm/nips_asm.pl
Guillaume Sadegh bc5f13bb4e NIPS VM added to the SPOT distribution.
2008-05-29  Guillaume SADEGH  <sadegh@lrde.epita.fr>

	* iface/nips/nips.cc, iface/nips/nips.hh, iface/nips/common.cc,
	iface/nips/common.hh, iface/nips/Makefile.am: TGBA implementation
	with the NIPS library.
	* iface/nips/emptiness_check.cc: Emptiness check on a Promela
	interface.
	* iface/nips/dottynips.cc: Dot printer on the NIPS interface.
	* iface/nips/compile.sh: Add. Wrapper around nips compiler to
	compile Promela to NIPS bytecode.
	* iface/nips/nips_vm,iface/nips/nips_vm/bytecode.h,
	iface/nips/nips_vm/ChangeLog, iface/nips/nips_vm/COPYING,
	iface/nips/nips_vm/hashtab.c, iface/nips/nips_vm/hashtab.h,
	iface/nips/nips_vm/INSTALL, iface/nips/nips_vm/instr.c,
	iface/nips/nips_vm/instr.h, iface/nips/nips_vm/instr_step.c,
	iface/nips/nips_vm/instr_step.h,
	iface/nips/nips_vm/instr_tools.c,
	iface/nips/nips_vm/instr_tools.h,
	iface/nips/nips_vm/instr_wrap.c,
	iface/nips/nips_vm/instr_wrap.h,
	iface/nips/nips_vm/interactive.c,
	iface/nips/nips_vm/interactive.h, iface/nips/nips_vm/main.c,
	iface/nips/nips_vm/Makefile, iface/nips/nips_vm/Makefile.am,
	iface/nips/nips_vm/nips_asm_help.pl,
	iface/nips/nips_vm/nips_asm_instr.pl,
	iface/nips/nips_vm/nips_asm.pl,
	iface/nips/nips_vm/nips_disasm.pl, iface/nips/nips_vm/nipsvm.c,
	iface/nips/nips_vm/nipsvm.h, iface/nips/nips_vm/README,
	iface/nips/nips_vm/rt_err.c, iface/nips/nips_vm/rt_err.h,
	iface/nips/nips_vm/search.c, iface/nips/nips_vm/search.h,
	iface/nips/nips_vm/split.c, iface/nips/nips_vm/split.h,
	iface/nips/nips_vm/state.c, iface/nips/nips_vm/state.h,
	iface/nips/nips_vm/state_inline.h,
	iface/nips/nips_vm/state_parts.c,
	iface/nips/nips_vm/state_parts.h, iface/nips/nips_vm/timeval.h,
	iface/nips/nips_vm/tools.h: NIPS VM added to the SPOT
	distribution.
	* configure.ac, iface/Makefile.am: Build system updated for the
	NIPS front-end.
2008-05-30 13:22:00 +02:00

588 lines
14 KiB
Perl
Executable file

#! /usr/bin/perl
# NIPS Asm - New Implementation of Promela Semantics Assembler
# Copyright (C) 2005: Stefan Schuermans <stefan@schuermans.info>
# Michael Weber <michaelw@i2.informatik.rwth-aachen.de>
# Lehrstuhl fuer Informatik II, RWTH Aachen
# Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
use strict;
# add directory of script to include directory
my $incdir=$0;
$incdir =~ s/[^\/]*$//;
$incdir = "./" if( $incdir eq "" );
push @INC, $incdir;
my $libprefix = $ENV{'NIPS_HOME'} || ".";
require $libprefix."/nips_asm_help.pl";
require $libprefix."/nips_asm_instr.pl";
my @instructions = get_instructions( );
print <<EOF;
NIPS Asm - New Implementation of Promela Semantics Assembler
Copyright (C) 2005: Stefan Schuermans <stefan\@schuermans.info>
Michael Weber <michaelw\@i2.informatik.rwth-aachen.de>
Lehrstuhl fuer Informatik II, RWTH Aachen
Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
EOF
# parse parameters
die "usage: perl nips_asm.pl <input.s> [<output.b> [<output.l>]]" if( @ARGV < 1 || @ARGV > 3 );
my ( $file_asm, $file_byte, $file_list ) = ( @ARGV[0], @ARGV[0], @ARGV[0] );
$file_byte =~ s/(\.s)?$/.b/;
$file_byte = @ARGV[1] if( @ARGV >= 2 );
$file_list =~ s/(\.s)?$/.l/;
$file_list = @ARGV[2] if( @ARGV >= 3 );
# parse input
print "parsing input file \"$file_asm\"...\n";
open ASM, "<".$file_asm or die "could not open input file \"$file_asm\"";
my ( $line_no, $line, $module );
my $modflags = 0;
my $addr = 0;
my @bytecodes = ( );
my @flags = ( );
my @strings = ( );
my @srclocs = ( );
my @strinfs = ( );
$module = "";
my @modules = ( );
for( $line_no = 1; $line = <ASM>; $line_no++ )
{
# remove newline, whitespace, comment
chomp $line;
chomp $line;
$line =~ s/\t/ /g;
$line =~ s/^ *([^;]*)(;.*)?$/\1/;
# get label and split words
$line =~ /^(([A-Za-z][A-Za-z0-9_]*): *)?(.*)$/;
my $label = $2;
my @words = split /[ ,]+/, $3;
# get string possibly contained in line
my $str = undef;
$str = eval( $1 ) if( $line =~ /^[^"]*("([^"]|\\.)*").*$/ );
# empty line
if( @words <= 0 || (@words == 1 && @words[0] eq "") )
{
# save empty bytecode for this line if there is a label
push @bytecodes, [ $addr, $label, [ ], [ ] ] if( $label ne "" );
next;
}
# start of new module
if( @words[0] eq "!module" )
{
die "\"!module\" needs a string in line $line_no" if( $str eq undef );
push @modules, [ $module, $modflags, [ @bytecodes ], [ @strings ] ] if( @bytecodes > 0 or @strings > 0 );
$module = $str;
$modflags = 0;
$addr = 0;
@bytecodes = ( );
@flags = ( );
@strings = ( );
@srclocs = ( );
@strinfs = ( );
next;
}
# module flags
if( @words[0] eq "!modflags" )
{
my $flag;
foreach $flag (@words)
{
if( $flag eq "monitor" ) { $modflags |= 0x00000001; }
}
next;
}
# flags for address
if( @words[0] eq "!flags" || @words[0] eq "!flags_addr" )
{
my $ad = $addr;
my $i = 1;
if( @words[0] eq "!flags_addr" )
{
if( @words[1] =~ /^0*[xX]/ )
{ $ad = hex( @words[1] ); }
else
{ $ad = int( @words[1] ); }
$i = 2;
}
my $fl = 0;
for( ; $i < @words; $i++ )
{
if( @words[$i] eq "progress" )
{ $fl |= 0x00000001; }
elsif( @words[$i] eq "accept" )
{ $fl |= 0x00000002; }
else
{ die "unknown flag \"@words[$i]\" in line $line_no"; }
}
if( @flags > 0 && @{@flags[@flags-1]}[0] > $ad ) {
die "flags out of order in line $line_no"
} elsif (@flags > 0 && @{@flags[@flags-1]}[0] == $ad) {
# add more flags
@{@flags[@flags-1]}[1] |= $fl;
} else {
push @flags, [ $ad, $fl ] if( $fl != 0 );
}
next;
}
# string to put into string table
if( @words[0] eq "!string" )
{
die "\"!string\" needs a number in line $line_no" if( @words[1] !~ /^[0-9]+$/ );
die "\"!string\" needs a string in line $line_no" if( $str eq undef );
my $i = int( @words[1] );
die "duplicate definition of string $i in line $line_no" if( $i < @strings and @strings[$i] ne undef );
my $j;
for( $j = @strings; $j < $i; $j++ )
{ @strings[$j] = undef; }
@strings[$i] = $str;
next;
}
# source location
if( @words[0] eq "!srcloc" || @words[0] eq "!srcloc_addr" )
{
my $ad = $addr;
my $i = 1;
if( @words[0] eq "!srcloc_addr" )
{
if( @words[1] =~ /^0*[xX]/ )
{ $ad = hex( @words[1] ); }
else
{ $ad = int( @words[1] ); }
$i = 2;
}
my $line = int( @words[$i] );
my $col = int( @words[$i+1] );
die "source location out of order in line $line_no" if( @srclocs > 0 && @{@srclocs[@srclocs-1]}[0] > $ad );
push @srclocs, [ $ad, $line, $col ];
next;
}
# structure information
if( @words[0] eq "!strinf" || @words[0] eq "!strinf_addr" )
{
my $ad = $addr;
my $i = 1;
if( @words[0] eq "!strinf_addr" )
{
if( @words[1] =~ /^0*[xX]/ )
{ $ad = hex( @words[1] ); }
else
{ $ad = int( @words[1] ); }
$i = 2;
}
my $code = 0xFF;
$code = 0x00 if( @words[$i] eq "begin" );
$code = 0x01 if( @words[$i] eq "end" );
$code = 0x02 if( @words[$i] eq "middle" );
my $type = @words[$i+1] . "";
die "invalid type \"$type\" in structure information in line $line_no" if( $type !~ /^[A-Za-z0-9_]+$/ );
my $name = @words[$i+2] . "";
die "invalid name \"$name\" in structure information in line $line_no" if( $name !~ /^[A-Za-z0-9_.]*$/ );
die "structure information out of order in line $line_no" if( @strinfs > 0 && @{@strinfs[@strinfs-1]}[0] > $ad );
push @strinfs, [ $ad, $code, $type, $name ];
next;
}
# find instruction in table
my $ok = 0;
my ( $opcode, $params );
for (@instructions)
{
( $opcode, $params ) = @{$_};
if( @words == @{$params} )
{
my $i;
for( $i = 0; $i < @{$params}; $i++ )
{
my $param = @{$params}[$i];
my $word = @words[$i];
last if( $param !~ /^\!/ and $param ne $word );
}
if( $i >= @{$params} )
{
$ok = 1;
last;
}
}
}
die "invalid instruction \"@words\" in line $line_no" if( ! $ok );
# process parameters and generate bytecode
my @bytecode = ( $opcode );
my $i;
for( $i = 0; $i < @{$params}; $i++ )
{
# byte constant
if( @{$params}[$i] eq "!const1" )
{
die "invalid constant \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^-?[0-9]+$/ );
my $val = int( @words[$i] );
die "1-byte constant \"".@words[$i]."\" in line $line_no is out of range" if( $val > 0xFF or $val < -0x80 );
push @bytecode, $val & 0xFF;
}
# word constant
elsif( @{$params}[$i] eq "!const2" )
{
die "invalid constant \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^-?[0-9]+$/ );
my $val = int( @words[$i] );
die "2-byte constant \"".@words[$i]."\" in line $line_no is out of range" if( $val > 0xFFFF or $val < -0x8000 );
push @bytecode, ($val >> 8) & 0xFF;
push @bytecode, $val & 0xFF;
}
# double-word constant
elsif( @{$params}[$i] eq "!const4" )
{
die "invalid constant \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^-?[0-9]+$/ );
my $val = int( @words[$i] );
push @bytecode, ($val >> 24) & 0xFF;
push @bytecode, ($val >> 16) & 0xFF;
push @bytecode, ($val >> 8) & 0xFF;
push @bytecode, $val & 0xFF;
}
# register
elsif( @{$params}[$i] eq "!reg" )
{
die "invalid register \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^r([0-7])$/ );
push @bytecode, int( $1 );
}
# relative address given by label
elsif( @{$params}[$i] eq "!addr" )
{
die "invalid label \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^[A-Za-z][A-Za-z0-9_]*$/ );
push @bytecode, "addr1:".@words[$i]; # relative address of label takes 2 bytes
push @bytecode, "addr0:".@words[$i];
}
# absolute address given by label
elsif( @{$params}[$i] eq "!address" )
{
die "invalid label \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^[A-Za-z][A-Za-z0-9_]*$/ );
push @bytecode, "address3:".@words[$i]; # absolute address of label takes 4 bytes
push @bytecode, "address2:".@words[$i];
push @bytecode, "address1:".@words[$i];
push @bytecode, "address0:".@words[$i];
}
# other parmeter type
elsif( @{$params}[$i] =~ /^\!/ )
{
die "internal error: unknown parmeter type \"".@{$params}[$i]."\"\n";
}
}
# save bytecode of this line
push @bytecodes, [ $addr, $label, [ @bytecode ], [ @words ] ];
$addr += @bytecode
}
push @modules, [ $module, $modflags, [ @bytecodes ], [ @flags ], [ @strings ], [ @srclocs], [ @strinfs ] ] if( @bytecodes > 0 or @strings > 0 );
die "no code found" if( @modules <= 0 );
# convert labels into addresses
print "converting labels to addresses...\n";
for (@modules)
{
my ($module, $modflags, $bytecodes, $flags, $strings, $srclocs, $strinfs) = @{$_};
for (@{$bytecodes})
{
my ( $addr, $label, $bc, $w ) = @{$_};
for (@{$bc})
{
# byte in bytecode is a label
if( $_ =~ /^addr(ess)?([0123]):([A-Za-z][A-Za-z0-9_]*)$/ )
{
my $rel = $1 eq "";
my $byte = $2;
my $lab = $3;
# find declaration of this label
my $ok = 0;
my $ad = "";
for (@{$bytecodes})
{
my ( $addr, $label, $bc, $w ) = @{$_};
if( $label eq $lab )
{
$ad = $addr;
$ok = 1;
last;
}
}
die "label \"$lab\" is not declared in module \"$module\"" if( ! $ok );
# convert address into relative one
if( $rel )
{
$ad -= $addr + @{$bc};
die "destination label \"".$lab."\" in module \"$module\" is out of range" if( $ad > 0x7FFF or $ad < -0x8000 );
}
# put right byte address into bytecode
$_ = ($ad >> ($byte * 8)) & 0xFF;
}
}
# update this line
$_ = [ $addr, $label, $bc, $w ];
}
}
# output bytecode and listing
print "writing output files \"$file_byte\" and \"$file_list\"...\n";
open BYTE, ">".$file_byte or die "could not open bytecode output file \"$file_byte\"";
binmode BYTE;
open LIST, ">".$file_list or die "could not open list output file \"$file_list\"";
# file header
print BYTE "NIPS v2 ";
wr_word( \*BYTE, @modules + 0 );
print LIST "# this code was assembled according to \"NIPS v2 \"\n\n";
# modules
for (@modules)
{
my ($module, $modflags, $bytecodes, $flags, $strings, $srclocs, $strinfs) = @{$_};
# module header
# sec_type
print BYTE "mod ";
# sec_sz (0 for now)
my $sec_sz_pos = wr_size_tmp( \*BYTE );
print LIST "!module \"" . escape_str( $module ) . "\"\n\n";
# module_name
wr_string( \*BYTE, $module );
# part_cnt
wr_word( \*BYTE, 6 );
# module flags
print BYTE "modf";
wr_dword( \*BYTE, 4 );
wr_dword( \*BYTE, $modflags );
print LIST "!modflags";
print LIST " monitor" if( $modflags & 0x00000001 );
print LIST "\n\n";
# code
# part_type
print BYTE "bc ";
# part_sz (0 for now)
my $part_sz_pos = wr_size_tmp( \*BYTE );
for (@{$bytecodes})
{
my ( $addr, $label, $bc, $w ) = @{$_};
# byte code
wr_byte( \*BYTE, $_ ) for (@{$bc});
# hex dump of bytecode
printf LIST "0x%08X:", $addr;
printf LIST " 0x%02X", $_ for (@{$bc});
# indentation
my $i;
for( $i = 0; $i < 48 - 7 - 5 * @{$bc}; $i++ ) { print LIST " "; }
# source code
print LIST " #";
print LIST " $label:" if( $label ne "" );
print LIST " $_" for (@{$w});
print LIST "\n";
}
print LIST "\n";
# part_sz
wr_size_fillin( \*BYTE, $part_sz_pos );
# flag table
# part_type
print BYTE "flag";
# part_sz
$part_sz_pos = wr_size_tmp( \*BYTE );
# flag_cnt
wr_word( \*BYTE, @{$flags} + 0 );
my $i;
for( $i = 0; $i < @{$flags}; $i++ )
{
my ($addr, $fl) = @{@{$flags}[$i]};
# flag
wr_dword( \*BYTE, $addr );
wr_dword( \*BYTE, $fl );
printf LIST "!flags_addr 0x%08X", $addr;
print LIST " progress" if( $fl & 0x00000001 );
print LIST " accept" if( $fl & 0x00000002 );
print LIST "\n";
}
print LIST "\n";
# part_sz
wr_size_fillin( \*BYTE, $part_sz_pos );
# string table
# part_type
print BYTE "str ";
# part_sz
$part_sz_pos = wr_size_tmp( \*BYTE );
# str_cnt
wr_word( \*BYTE, @{$strings} + 0 );
for( $i = 0; $i < @{$strings}; $i++ )
{
my $str = @{$strings}[$i];
if( $str ne undef )
{
wr_string( \*BYTE, $str );
print LIST "!string $i \"" . escape_str( $str ) . "\"\n";
}
else
{
# empty string
wr_string( \*BYTE, "" );
}
}
print LIST "\n";
# part_sz
wr_size_fillin( \*BYTE, $part_sz_pos );
# source location table
# part_type
print BYTE "sloc";
# part_sz
$part_sz_pos = wr_size_tmp( \*BYTE );
# sloc_cnt
wr_word( \*BYTE, @{$srclocs} + 0 );
for( $i = 0; $i < @{$srclocs}; $i++ )
{
my ($addr, $line, $col) = @{@{$srclocs}[$i]};
# srcloc
wr_dword( \*BYTE, $addr );
wr_dword( \*BYTE, $line );
wr_dword( \*BYTE, $col );
printf LIST "!srcloc_addr 0x%08X %d %d\n", $addr, $line, $col;
}
print LIST "\n";
# part_sz
wr_size_fillin( \*BYTE, $part_sz_pos );
# structure information table
# part_type
print BYTE "stin";
# part_sz
$part_sz_pos = wr_size_tmp( \*BYTE );
# stin_cnt
wr_word( \*BYTE, @{$strinfs} + 0 );
for( $i = 0; $i < @{$strinfs}; $i++ )
{
my ($addr, $code, $type, $name) = @{@{$strinfs}[$i]};
# strinf
wr_dword( \*BYTE, $addr );
wr_byte( \*BYTE, $code );
wr_string( \*BYTE, $type );
wr_string( \*BYTE, $name );
printf LIST "!strinf_addr 0x%08X", $addr;
if( $code == 0x00 )
{ print LIST " begin "; }
elsif( $code == 0x01 )
{ print LIST " end "; }
elsif( $code == 0x02 )
{ print LIST " middle "; }
else
{ print LIST " unknown "; }
print LIST $type;
print LIST " $name" if( $name ne "" );
print LIST "\n";
}
print LIST "\n";
# part_sz
wr_size_fillin( \*BYTE, $part_sz_pos );
# end of section
# sec_sz
wr_size_fillin( \*BYTE, $sec_sz_pos );
}
print "done...\n\n";