#! /bin/sh

# Equivalent script to what preprocessor.xls might do.
#
# Run e.g. like
#  sh preprocessor.sh ATmega128 4096 PORTD PD4 3686400 9600 > defines.h
#
# Written by Joerg Wunsch, 2005-07-29

PARTFILE=parts.txt

usage()
{
    echo "usage: preprocessor.sh device bootsize progport prog_no cpu_freq baud_rate" >& 2
    exit 1
}

if [ $# -ne 6 ]
then
    usage
fi

if [ ! -f ${PARTFILE} ]
then
    echo "part definition file ${PARTFILE} not found" >& 2
    exit 1
fi

device="$1"
bootsize="$2"
progport="$3"
prog_no="$4"
cpu_freq="$5"
baud_rate="$6"

# is there a device at all?
if grep -i "^${device}	" ${PARTFILE} >/dev/null
then
    :
else
    echo "device ${device} not found in ${PARTFILE}" >& 2
    exit 1
fi
devupper=`echo $device | tr '[a-z]' '[A-Z]'`

# find an awk to use, out of nawk, gawk, or awk
AWK=none
for name in nawk gawk awk
do
  set -- `type $name 2>/dev/null`
  if [ "x$2" = 'xis' ]
  then
      AWK=$name
      break
  fi
done
if [ $AWK = 'none' ]
then
    echo "Sorry, no useable awk found" >& 2
    exit 1
fi

# OK, now get the individual fields.  Unfortunately, the AVR910 device ID
# is optional, and the shell cannot parse that natively.  Use awk to
# re-order the fields, and sort the avr910 column last (so we'll get an
# empty variable in read if it is not present).
set -- `grep -i "^${device}	" ${PARTFILE} |\
${AWK} -F '	' \
'{print $1 " " $2 " " $3 " " $4 " " $5 " " $7 " " $8 " " $9 " " $10 " " $11 " " $12 " " $13 " " $14 " " $15 " " $16 " " $17 " " $18 " " $6; exit}'`
dev=$1
include=$2
pagesz=$3
nrwwpag=$4
totpag=$5
sig1=$6
sig2=$7
sig3=$8
baudlo=$9
shift 9
uartc=$1
uarts=$2
txen=$3
rxen=$4
txc=$5
rxc=$6
udr=$7
spmcr=$8
avr910=$9

# Verify boot size
pagebytes=`expr $pagesz \* 2`
maxboot=`expr $nrwwpag \* $pagebytes`
bootbytes=`expr 2 \* $bootsize` || exit 1
if [ \( $bootbytes -ne $maxboot \) -a \
    \( $bootbytes -ne `expr $maxboot / 4` \) -a \
    \( $bootbytes -ne `expr $maxboot / 2` \) -a \
    \( $bootbytes -ne `expr $maxboot \* 3 / 4` \) ]
then
    echo "Invalid boot size ${bootsize}, valid: `expr $maxboot / 8`, `expr $maxboot / 4`, `expr $maxboot \* 3 / 8`, `expr $maxboot / 2` words" >& 2
    exit 1
fi

if p=`expr $progport : 'PORT\(.\)'`
then
    : # ok
else
    echo "Invalid port name ${progport}, must be PORTx" >& 2
    exit 1
fi
progpin="PIN$p"

brreg=`expr $cpu_freq / \( 16 \* $baud_rate \) - 1` || exit 1
memsize=`expr $totpag \* $pagebytes`
append=`expr $memsize - $bootbytes`

echo "/* definitions generated by preprocessor, copy into defines.h */
#ifndef	PPINC
#define	_${devupper}	// device select: _ATMEGAxxxx
#define	_B${bootsize}	// boot size select: _Bxxxx (words), powers of two only
#ifdef	__ICCAVR__
#include	\"${include}\"
#endif
#if	__GNUC__
#include	<avr/io.h>
#endif

/* define pin for enter-self-prog-mode */
#define	PROGPORT	${progport}
#define	PROGPIN	${progpin}
#define	PROG_NO	${prog_no}

/* baud rate register value calculation */
#define	CPU_FREQ	${cpu_freq}
#define	BAUD_RATE	${baud_rate}
#define	BRREG_VALUE	${brreg}

/* definitions for UART control */
#define	BAUD_RATE_LOW_REG	${baudlo}
#define	UART_CONTROL_REG	${uartc}
#define	ENABLE_TRANSMITTER_BIT	${txen}
#define	ENABLE_RECEIVER_BIT	${rxen}
#define	UART_STATUS_REG	${uarts}
#define	TRANSMIT_COMPLETE_BIT	${txc}
#define	RECEIVE_COMPLETE_BIT	${rxc}
#define	UART_DATA_REG	${udr}

/* definitions for SPM control */
#define	SPMCR_REG	${spmcr}
#define	PAGESIZE	${pagebytes}
#define	APP_END	${append}"

if [ $memsize -gt 65536 ]
then
    echo "#define	LARGE_MEMORY"
else
    echo "//#define	LARGE_MEMORY"
fi

echo "
/* definitions for device recognition */
#define	PARTCODE	${avr910}
#define	SIGNATURE_BYTE_1	${sig1}
#define	SIGNATURE_BYTE_2	${sig2}
#define	SIGNATURE_BYTE_3	${sig3}

/* indicate that preprocessor result is included */
#define	PPINC
#endif"

echo "(IAR) Replace all code segment definitions in the linker file with the following line:" >& 2
${AWK} 'BEGIN {printf "-Z(CODE)INTVEC,FAR_F,SWITCH,CODE=%X-%X\n", '$append', '$memsize' - 1; exit}' >& 2
