Skip navigation.

Pal2abl

One of the creators of Abel is Walter Bright, who also designed the D-language.

Pal2abl is a PALASM to Abel translator. I used it for the transition from PALASM to Abel. At that time we used several types PALs and GALs.

The PALASM to Abel transator consists of an Awk script and a KornShell script. The KornShell script is used to drive the Awk script. The KornShell script in turn can be used from a batch script when working with DOS or Windows.

I used the triple Batch script -- KornShell script -- Awk script quite often. Under MS-DOS, I used the MKS-KornShell (You guessed, I'm not very fond of Perl as a language, even though it is a powerfull programming tool).

Batch driver script

@echo off
Rem
Rem pal2abl.bat
Rem

sh ./pal2abl.ksh %1 %2 %3 %4 %5 %6 %7 %8 %9

Rem
Rem
Rem

KornShell driver script

#
# pal2abl.ksh - convert Palasm source to Abel source
#
# Version: 0.01
# Date   : 15 Jan 1997
# Disk   : rulhe1:~moene/msdos/adm/ea/pal2abl/
# Author : M.J. Moene
#
# Usage: sh ./pal2abl.ksh [file ...]
#

# trap '' INT EXIT

typeset bnm=${0%.*}                             # basename
typeset prg=${bnm##*/}  awk=${bnm}.awk  ver="0.00" dat="1 Oct 1992"

if [ $# -eq 0 ]
then
   print - "$prg  $ver  Program to convert PALASM source to ABEL source file."
   print - "Usage: $prg [file ...]"
   exit 1
fi

for src in $@                                   # for all specified files
do                                              # e.g. ./HL9102A.PAL
   typeset -l tmp=${src%%.*}                    # -->  ./hl9102a
   typeset -l tmp=${tmp%%a}                     # -->  ./hl9102
   typeset -l dst=${tmp}b.abl                   # -->  ./hl9102b.abl ( dest. filename )
   typeset -u mod=${tmp##*/}B                   # -->  HL9102B       ( module name )

   if [ -f $src ]                               # if file exists:
   then                                         #    then process it
      print - "$dst:"
      awkl -f $awk module=$mod $src >$dst  ||  rm $dst
   else                                         # else warn user
      print - "$prg: cannot find file $src."
   fi
done

#
# End of file
#

Awk translator script

#
# pal2abl.awk - convert Palasm source to Abel source file.
#
# Version: 2.1
# Date   : 15 Jan 1997
# Disk   : rulhe1:~moene/msdos/adm/ea/pal2abl/
# Author : M.J. Moene
#
# Usage: awkl -f pal2abl.awk [debug=1] module=HL9209B hl9209.pal >hl9209b.abl
#                                 
# Gal used:
#   P16V8C P16V8S P16V8R  (20-pin)
#   P20V8C P20V8S P20V8R  (24-pin)
#
# Supported Pals:
#   10L8 10H8 12L6  12H6 14L4 14H4 16L2  16H2 16L8 16C1 16R4 16R6 16R8  (20-pin)
#   20L8 12L10 14L8 16L6 18L4 20L2 20L10 20C1 20R4 20R6 20R8            (24-pin)
#

BEGIN {
   #
   # global names used:
   #

   # debug              # debug                     (command line)
   # module             # module name like HL9201B  (command line)
   # paltype            # pal type: 10L8, 16L8 etc. (Palasm source line 1)
   # title              # title line                (Palasm source line 2)
   # application        # application line          (Palasm source line 3)
   # company            # company line              (Palasm source line 4)
   # galtype            # gal type to use

   #
   # equation analyzer:
   #

   # line               # line used for equation scanning
   # tok                # current token
   # cur_out            # current output name (without complement prefix)
   # pinoe              # current output enable expression
   # pinmax             # highest pin number encountered
   # pinlst             # array[ 1..pinmax ] of pin names (without complement prefix)
   # pininv             # array[ pin names ] with pin polarity (1: complemented)
   # pintyp             # array[ pin names ] with type of pin ("reg", "com")
   # pinequ             # array[ pin names ] with output expression

   # out_lnr            # array [ pin names ] with output equation line number
   # out_inv            # array [ pin names ] with output equation polarity
   # cmt_str            # array [     NR    ] with comment strings
   # cmt_max            # highest line number of comment
   # cmt_ndx            # line number last printed comment

   #
   # other:
   #

   # des_num            # number of description lines
   # des_str            # array [1..des_num] with description strings
   # fxn_num            # number of function table lines
   # fxn_str            # array [1..fxn_num] with function table strings

   #
   # configuration:
   #

   PRDTRMBRK = 1                                # product term break length

   #
   # constants:
   #
                      
   GAL16C  = "p16v8c"                           # 20-pin combinatorial
   GAL16S  = "p16v8s"                           # 20-pin registered
   GAL16R  = "p16v8r"                           # 20-pin registered
   GAL20C  = "p20v8c"                           # 24-pin combinatorial
   GAL20S  = "p20v8s"                           # 24-pin combinatorial
   GAL20R  = "p20v8r"                           # 24-pin registered
   PAL20C  = "16L8"                                             # 20-pin combinatorial
   PAL20S  = "10L8 10H8 12L6 12H6 14L4 14H4 16L2 16H2 16C1"     # 20-pin combinatorial
   PAL20R  = "16R4 16R6 16R8"                                   # 20-pin registered
   PAL24C  = "20L8"                                             # 24-pin combinatorial
   PAL24S  = "12L10 14L8 16L6 18L4 20L2 20L10 20C1"             # 24-pin combinatorial
   PAL24R  = "20R4  20R6 20R8"                                  # 24-pin registered
   PALFIT  = "12L10 16C1 20C1 20L10"            # pals that may not fit into gal

   IF      = "^[Ii][Ff]$"                       # if reserved word (opt_if)
   IF_     = "^[Ii][Ff][ \\\t]*\\("             # if reserved word (advance)
   VCC     = "^[Vv][Cc][Cc]"                    # vcc (oe-expression)
   WS      = "^[ \\\t]+"                        # white space
   IDENT   = "^[A-Za-z_][A-Za-z_\\.'0-9]*"      # Palasm identifier
   OPER    = "^(/|\\+|\\*|:\\+:|:\\*:)"         # Palasm operator
   ASSIGN  = "^(:?\\=)"                         # Palasm assignment
   REGASGN = "^(:\\=)"                          # Palasm register assignment
   OROPS   = "^(\\+|:\\+:|:\\*:)"               # Palasm or operators
   ANDOP   = "^\\*"                             # Palasm and operator
   PARENT  = "^(\\(|\\))"                       # left and right parent
   PALTYP  = "[0-9]+[CHLRX][0-9]+"              # pal basic type
   PALTYPL = "[0-9]+[L][0-9]+"                  # pal type active low
   DESCR   = "^(descr|Descr|DESCR)"             # description
   FUNCT   = "^(funct|Funct|FUNCT)"             # function table
}

/;/             { chg_comment()         }       # change ; to "
NR == 1         { get_paltype()         }       # pal type
NR == 2         { get_title()           }       # user part number etc.
NR == 3         { get_application()     }       # application name
NR == 4         { get_company()         }       # company name
NR == 5         { get_pinlist()         }       # PAL pin list

/=/             { get_equations()       }       # output equations:
$0 ~ FUNCT      { get_functionTable()   }       #   expect function table after
$0 ~ DESCR      { get_description()     }       #     equations, descr. after function table

END {                                           # generate Abel code
   gen_header()                                 # header with module name
   gen_title()                                  # title definition
   gen_description()                            # description section
   gen_declarations()                           # declaration section
   gen_equations()                              # equatiion section
   gen_testvectors()                            # function table as comments
   gen_trailer()                                # end of module
}


#------------------------------------------------------------------------------
# analyzer
#------------------------------------------------------------------------------

function chg_comment()                          # change Palasm comment to Abel comment
{
   gsub(/"/, "\'");                             # change all " to '
   sub(/;/, "\"");                              # only change first ; to "
}

function get_paltype(   i, pal)                 # get Palasm pal type number
{                                               # (line 1)
   paltype = $1                                 # first word
                                                # save basic type only
   pal = substr(paltype, match(paltype, PALTYP), RLENGTH)

   if ( length(pal) == 0)
      error("line " NR ": '" paltype "' is not a valid Pal type.")

   if ( PALFIT ~ pal )
      warning("line " NR ": Pal type " paltype " may not fit into gal (try anyway).")

   if ( PAL20C ~ pal ) {                        # check if Pal is in Pal list
      galtype = GAL16C
      return
   }

   if ( PAL20S ~ pal ) {                        # check if Pal is in Pal list
      galtype = GAL16S
      return
   }

   if ( PAL20R ~ pal ) {                        # check if Pal is in Pal list
      galtype = GAL16R
      return
   }

   if ( PAL24C ~ pal ) {                        # check if Pal is in Pal list
      galtype = GAL20C
      return
   }

   if ( PAL24S ~ pal ) {                        # check if Pal is in Pal list
      galtype = GAL20S
      return
   }

   if ( PAL24R ~ pal ) {                        # check if Pal is in Pal list
      galtype = GAL20R
      return
   }

   error("line " NR ": cannot convert for Pal type '" paltype "'.")
}

function get_title()                            # get Palasm user part nr
{                                               #   name and date (line 2)
   gsub(/\'/, "\"")                             # change all ' to "
   title = $0
}

function get_application()                      # get Palasm application name
{                                               # (line 3)
   application = $0
}

function get_company()                          # get Palasm company line
{                                               # (line 4)
   company = $0
}

function get_pinlist(   i, inv, line)           # read the Palasm pin list
{
   line = $0

   while ( 20 > split(line, pinlst) && getline > 0 ) {
                                                # only >= 20 pins pals
      line = line " " $0
   }

   line = edit_identifier(line)                 # handle X.Y and X'

   pinmax = split(line, pinlst)                 # save number of pins

   for ( i = 1; i <= pinmax; i++ ) {            # save pin polarity 
                                                #   and remove it from namelist
      if ( pinlst[i] ~ /\// ) inv = "!"
      else                    inv = ""

      sub(/\//, "", pinlst[i])

      if ( pinlst[i] ~ /[nN][cC]/ )
         pinlst[i] = sprintf( "%s%d", pinlst[i], i )

      pininv[pinlst[i]] = inv
   }
}

function get_equations()
{
   #
   # The following grammar is regocnized for equations:
   #
   # comments, introduced by ; or " are saved and
   # printed with generation of output equations
   #

   # equations -> equation equations
   #            | ""

   # equation  -> opt_IF stat

   # opt_IF    -> IF (if_expr)                  ( output enable expression )
   #            | ""

   # stat      -> lhs  = expr                   ( combinatorial output  )
   #            | lhs := expr                   ( registered output     )

   # if_expr   -> expr
   #            | VCC

   # expr      -> term
   #            | term  +  term                 ( or   )
   #            | term :+: term                 ( xor  )
   #            | term :*: term                 ( xnor )

   # term      -> fact
   #            | fact * fact                   ( and  )

   # fact      -> /ident                        ( negation )
   #            | ident

   # lhs       -> /ident                        ( handles output inversion )
   #            | ident

   # ident     -> [A-Za-z_][A-Za-z_\.'0-9]*     ( . and ' used in some Palasm src )
   # comment   -> ;.* | ".*

   equations()
}

function get_functionTable()            # get Palasm function table section
{
   do
   {
      gsub(/\"/, "\'")                  # no \"-s within comment
      fxn_str[++fxn_num] = $0
   }
   while ( getline > 0 && $0 !~ DESCR )
}

function get_description()              # get Palasm description section
{
   do
   {
      gsub(/\"/, "\'")                  # no \"-s within comment
      des_str[++des_num] = $0
   }
   while ( getline > 0 )
}


#------------------------------------------------------------------------------
# equation analyzer
#------------------------------------------------------------------------------

function equations()                    # equitions -> equation equations | ""
{
   if (debug)
      print "equations"

   line = $0                            # use line for equations in stead of $0
   advance()                            # read first token

   while ( line ~ /:?\=/ ) {            # while assignment on line
      equation()                        #   scan equation
   }
}

function equation(   oe, e)             # equation -> opt_if statement
{
   if (debug)
      print "equation"

   oe = opt_if()                        # get output enable expression
   e  = statement()                     # get expression for current output
                                        #   (sets cur_out to pin name)
   pinoe [cur_out] = oe                 # save output enable expression
   pinequ[cur_out] = e                  # save output expression
}

function opt_if(   e)                   # opt_if -> expr | VCC
{
   if (debug)
      print "opt_if"

   if ( tok ~ IF ) {
      advance()                         # read next token 
      eat("(")                          #   ( don't know exact form of if )
      e = expression()
      eat(")")
      return e ~ VCC ? "1" : e
   }

   return "1"
}

function statement()                    # statement -> ident := expr | ident = expr
{
   if (debug)
      print "statement"

   cur_out = lhs()                      # get left hand side identifier
   out_lnr[cur_out] = NR                # save line number for this output

   if ( tok ~ ASSIGN ) {                # save type of output
      pintyp[cur_out] = (tok ~ REGASGN ) ? "reg" : "com"
      eat(tok);
      return expression()               # return expression for this output
   }
   else error("line " NR ": assignment expected.")
}

function expression(   op, e)           # expression -> term | term op term
{                                       #  op: + :+: :*:  (OR, XOR, XNOR)
   if (debug)
      print "expression"

   e = term()
   while ( tok ~ OROPS ) {
      op = edit_operator(tok)
      advance()
      e = sprintf("%s %s %s", e, op, term() )
   }
   return e
}

function term(   op, e)                 # term -> fact | fact * fact
{
   if (debug)
      print "term"

   e = fact()
   while ( tok ~ ANDOP ) {
      op = edit_operator(tok)
      advance()
      e = sprintf("%s %s %s", e, op, fact() )
   }
   return e
}

function fact()                         # fact -> /ident | ident
{
   if (debug)
      print "fact"

   if ( tok ~ /\// ) {
      eat("\/")
      return "!" ident()
   }
   else return ident()
}

function lhs(  id)                      # lhs -> /ident | ident
{
   if (debug)
      print "lhs"

   id = fact()                          # use fact to handle negation

   if ( id ~ /^\!/ ) {                  # check for negation
      sub(/\!/, "", id)                 # remove polarity from output identifier
      out_inv[id] = "!"                 # save
   }                                    #   output
   else out_inv[id] = ""                #     polarity

   return id                            # return identifier
}

function ident(   id)                   # ident -> [A-Za-z_][A-Za-z_\.'0-9]
{
   if (debug)
      print "ident"

   tok = edit_identifier(tok)           # handle X.Y. and X'

   if ( tok !~ IDENT )                  # check if identifier
      error("unexpected " tok " at line " NR ".")

   id = tok                             # save identifier
   advance()                            # scan next token

   return id                            # return identifier
}

function advance()                      # scan next token
{
   if ( tok == "(eof)" )
      return "(eof)"

   while (1) {                          # leave loop with return or error

      sub(WS, "", line)                 # remove leading white space

      if ( length(line) == 0 )          # line exhausted?
         if ( (getline line) < 0 )      # yes: read new line
            return tok = "(eof)"        #      end of file reached
         else {                         # save line in $0 to continue with
            $0 = line                   #  function table or description
            continue                    #   breaks out in function equations
         }

      if ( line ~ /^("|;)/ ) {          # comment: save & skip rest of line
         sub(/^;/, "\"", line)          # ; -> "
         cmt_max     = NR               # save highest comment line number
         cmt_str[NR] = line             # save comment
         line        = "";              # clear current line
         continue                       # read next line
      }

      if ( line ~ IF_ ) {               # special case: IF iff /[Ii][Ff][ \t]*\(/
         tok  = substr(line, 1, 2)      # isolate token
         line = substr(line, 3   )      # strip token from line

          if (debug)
             print "advance ", tok

         return "IF"                    # return token
      }

      if ( match(line, IDENT  )  ||                     # Palasm identifier
           match(line, OPER   )  ||                     # Palasm operator
           match(line, ASSIGN )  ||                     # Palasm assignment operator
           match(line, PARENT )   )  {                  # ( )

          tok  = substr(line, 1, RLENGTH )              # isolate token
          line = substr(line, RLENGTH + 1)              # remove token from line

          if (debug)
             print "advance ", tok

          return tok                                    # return new token
       }

       error("line " NR " incomprehensible at '" line "'.")       # not recognized syntax
    }
}

function eat(s)                         # advance over specified token
{
   if (debug)
      print "eat(" s ")"

  if ( tok != s )
     error ("line " NR ": saw " tok ", expected " s ".")

   advance()
}

function error(s)                       # print specified error message & exit
{
   print "Error: " s >"con"; exit 1
}

function warning(s)                     # print specified warning message
{
   print "Warning: " s >"con"
}


#------------------------------------------------------------------------------
# edit
#------------------------------------------------------------------------------

function edit_operator(op)              # translate Palasm operator to Abel
{
   gsub(/\//  , "!" , op)               # negate
   gsub(/\*/  , "\&", op)               # and
   gsub(/\+/  , "#" , op)               # or
   gsub(/\:*:/, "!$", op)               # xnor
   gsub(/\:+:/, "$" , op)               # xor

   return op
}

function edit_identifier(id)            # translate Palasm identifier to Abel
{
   gsub(/(\.|\')/, "_" , id)            # X.Y. -> X_Y_  and  X' -> X_
   gsub(/(ENABLE|[Ee]nable)/, "&_", id) # append _ to keyword(s)

   return id
}


#------------------------------------------------------------------------------
# Abel source code generator
#------------------------------------------------------------------------------

function gen_header()                   # generate Abel header
{
   print "module", module
}

function gen_trailer()                  # generate Abel trailer
{
   print "\nend", module
}

function gen_title()                    # generate Abel title line
{
   print "\ntitle '" title "'"
}

function gen_description(   i)          # generate Abel description section
{
   print ""

   print "\"" paltype
   print "\"" application
   print "\"" company

   print ""

   for ( i = 1; i <= des_num; i++ )
      print "\"" des_str[i]
}

function gen_declarations()             # generate Abel declaration section
{
   print "\ndeclarations"

   gen_device()                         # device declarations
   gen_pinlist()                        # pin list declareations
}

function gen_equations()                # generate Abel equation section
{
   print "\nequations"

   gen_oe()                             # output enable equations
   gen_out()                            # output equations
}

function gen_testvectors(   i)          # generate Abel test vector section
{
   print "\n\"Test_vectors 'function table'"

   for ( i = 1; i <= fxn_num; i++ )     # just print Palasm function table
      printf("\n\t\"%s", fxn_str[i])    #   as Abel comments
}

function gen_device()                   # generate Abel device declaration
{
   print "\n\t" module " device '" galtype "';\n"
}

function gen_pinlist(   pinpol)         # generate Abel pin list declarations
{
   #
   # for active low output PALs, define output pins active low,
   # don't use inversion on ouput in equation
   #

   for ( i = 1; i <= pinmax; i++ ) {
      pinpol = ( isLpal() && pinlst[i] in pintyp ) ? "!" : pininv[ pinlst[i] ]

      printf("\t%s%s\tpin %2d", pinpol, pinlst[i], i)

      if ( (pinlst[i]) in pintyp )
         printf("\tistype '%s'", pintyp[ pinlst[i] ] )

      printf(";\n")
   }
}

function gen_oe(   out, tmpoe)          # generate Abel output enable equations
{
   for ( out in pinoe )                 # reverse pinoe list (implementation dep.)
      tmpoe[out] = pinoe[out]

   for ( out in tmpoe )
      if ( pintyp[out] == "com" )
         printf("\n\t%s.oe\t= %s;", out, pinoe[out] )
}

function gen_out(   out, pol, tmpequ)   # generate Abel output equations
{
   for ( out in pinequ )                # reverse pinequ array (implementation dep.)
      tmpequ[out] = pinequ[out]

   for ( out in tmpequ ) {

      print ""

      for ( ; cmt_ndx <= out_lnr[out]; cmt_ndx++ ) {    # print comment lines

         if ( cmt_ndx in cmt_str )
            printf("\n\t%s", cmt_str[cmt_ndx])
      }

      if ( length( pinequ[out] ) >= PRDTRMBRK )         # product term break length
         gsub(/\#/, "\n\t\t #", pinequ[out])            # align product terms

      pol = isLpal() ? "" : out_inv[out]

      printf("\n\t%s%s\t%s= %s;", pol, out, pintyp[out] == "reg" ? ":":" ", pinequ[out]);
   }

   print ""

   for ( ; cmt_ndx <= cmt_max; cmt_ndx++ ) {            # print other comment lines

      if ( cmt_ndx in cmt_str )
         printf("\n\t%s", cmt_str[cmt_ndx])
   }

   print ""
}


#------------------------------------------------------------------------------
# other functions
#------------------------------------------------------------------------------

function isLpal()
{
   return match(paltype, PALTYPL)
}


#
# End of file
#