#!/bin/sh

MACHINE=`uname -m`
if [ $MACHINE = i686 -o $MACHINE = i586 ]; then
  OS=`uname -o 2>/dev/null`
  if [ $? != 0 ]; then # -o option unrecognized
    OS=unknown
  fi
  if [ ! $OS = Cygwin ]; then
    OS=`uname -s`
  fi 
else
  OS=`uname -s`
fi

# TODO checks to allow valid machine / os combinations
# TODO check for existence of required linux commands

echo $MACHINE $OS

if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 -o $MACHINE = x86_64 -o $MACHINE = amd64 ]; then
  if [ $OS = Cygwin ]; then # windows
    if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 ]; then # 32 bit
      RT_OS=rt/rt-x86-src/rt-win.asm
      RT_ASM=rt32.asm
      CORE=src/asm/simpvir-x86-32-core.asm
    else
      echo "unsupported 64 bit"
      exit 0
    fi
  elif [ $OS = FreeBSD ]; then
    if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 ]; then # 32 bit
      echo "unsupported 32 bit"
      exit 0
    else # 64 bit
      RT_OS=rt/rt-x86-src/rt-freebsd64.asm
      RT_ASM=rt-null.asm
      CORE=src/asm/simpvir-x86-64-core.asm
    fi
  elif [ $OS = OpenBSD ]; then
    if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 ]; then # 32 bit
      RT_OS=rt/rt-x86-src/rt-openbsd32.asm
      RT_ASM=rt32.asm
      CORE=src/asm/simpvir-x86-32-core.asm
    else # 64 bit
      RT_OS=rt/rt-x86-src/rt-openbsd64.asm
      RT_ASM=rt64.asm
      CORE=src/asm/simpvir-x86-64-core.asm
    fi
  elif [ $OS = Darwin ]; then # Mac OS X
    if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 ]; then # 32 bit
      echo "unsupported 32 bit"
      exit 0
    else # 64 bit
      RT_OS=rt/rt-x86-src/rt-osx64.asm
      RT_ASM=rt-null.asm
      CORE=src/asm/simpvir-x86-64-core.asm
    fi
  else # GNU/Linux
    if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 ]; then # 32 bit
      RT_OS=rt/rt-x86-src/rt-linux32.asm
      RT_ASM=rt32.asm
      CORE=src/asm/simpvir-x86-32-core.asm
    else # 64 bit
      RT_OS=rt/rt-x86-src/rt-linux64.asm
      RT_ASM=rt64.asm
      CORE=src/asm/simpvir-x86-64-core.asm
    fi
  fi

  # increase stack size

  # TODO handle 64 bit case
  sed -e 's/STACK_SIZE = 21000000/STACK_SIZE = 22000000/g' \
    rt/rt-x86-src/$RT_ASM >rt.asm

  cat rt/rt-x86-src/rt-comment.asm \
      $RT_OS \
      rt.asm \
      $CORE \
      >x.asm

  if [ $MACHINE = i686 -o $MACHINE = i586 -o $MACHINE = i386 ]; then # 32 bit
    if [ $OS = Cygwin ]; then # windows
      ENTRY_NAME=_main
    else
      ENTRY_NAME=_start
    fi
    sed -e "s/@SUBSTITUTE_ENTRY_NAME/$ENTRY_NAME/g" \
      <x.asm >xx.asm
    mv xx.asm x.asm
    sed -e 's/rax/eax/g' \
        -e 's/rbx/ebx/g' \
        -e 's/rcx/ecx/g' \
        -e 's/rdx/edx/g' \
        -e 's/rbp/ebp/g' \
        -e 's/rdi/edi/g' \
        -e 's/rsi/esi/g' \
        -e 's/rsp/esp/g' \
      <x.asm >xx.asm
    mv xx.asm x.asm
    as -o zzz.o x.asm
    if [ $OS = Cygwin ]; then # windows
      gcc -o bin/simpvir zzz.o
    elif [ $OS = OpenBSD ]; then
      ld.bfd -nopie -static -o bin/simpvir zzz.o
    else # GNU/Linux or FreeBSD
      ld -s -o bin/simpvir zzz.o
    fi
  else # x86_64 or amd64
    ENTRY_NAME=main
    sed -e "s/@SUBSTITUTE_ENTRY_NAME/$ENTRY_NAME/g" \
      <x.asm >xx.asm
    mv xx.asm x.asm
    if [ $OS = Darwin ]; then
      # in darwin 16 byte alignment is a power of 2
      # and the effective address formed by adding a
      # label offset has to be indirect thru a 32 bit register
      sed -e 's/align 16/align 4/g' \
	  -e 's/(%rax), %rax/(%eax), %rax/g' \
        <x.asm >xx.asm
      mv xx.asm x.asm
    fi
    as -o zzz.o x.asm
    if [ $OS = FreeBSD ]; then
      ld zzz.o -e _main -o bin/simpvir
    elif [ $OS = OpenBSD ]; then
      cc -nopie -o bin/simpvir zzz.o # resolve calls to libc
    elif [ $OS = Darwin ]; then
      ld zzz.o -e _main -o bin/simpvir
    else
      gcc -no-pie -o bin/simpvir zzz.o # resolve calls to libc
    fi
  fi

  rm rt.asm x.asm zzz.o
elif [ $MACHINE = armv6l -o $MACHINE = armv7l -o $MACHINE = evbarm -o $MACHINE = aarch64 ]; then

  # increase stack size

  if [ $MACHINE = armv6l -o $MACHINE = evbarm ]; then
    ARM_MODE=arm6
    RT_SRC=rt-arm-src
  elif [ $MACHINE = armv7l ]; then
    ARM_MODE=arm7
    RT_SRC=rt-arm-src
  else
    ARM_MODE=aarch64
    RT_SRC=rt-aarch64-src
  fi

  sed -e 's/84000000/88000000/g' \
      -e 's/21000000/22000000/g' \
    rt/$RT_SRC/data.s >data.s

  cp src/asm/simpvir-$ARM_MODE-core.s xxx.s

  cat xxx.s | sed -e 's/_-/_/g' >yyy.s # absolute value of -maxint is somehow neg
  rm xxx.s
  grep "@X@" yyy.s | sed -e 's/@X@//g' >global-defines.s

  if [ $OS = NetBSD ]; then
    RT_OS=rt/$RT_SRC/rt-netbsd.s
    TEXT=rt/$RT_SRC/text-netbsd.s
    RT=rt/$RT_SRC/rt-netbsd1.s
    START=rt/$RT_SRC/start-netbsd.s
  else
    RT_OS=rt/$RT_SRC/rt-linux.s
    TEXT=rt/$RT_SRC/text.s
    RT=rt/$RT_SRC/rt.s
    START=rt/$RT_SRC/start.s
  fi

  cat data.s \
    global-defines.s \
    $TEXT \
    $RT_OS \
    $RT \
    $START \
    rt/$RT_SRC/init.s \
    yyy.s \
    rt/$RT_SRC/cleanup.s >zzz.s

  if [ $MACHINE = arm6l ]; then
    as -march=armv6j -mfpu=vfp -mfloat-abi=hard --fatal-warnings \
      -o zzz.o zzz.s
  else
    as --fatal-warnings \
      -o zzz.o zzz.s
  fi

  if [ $OS = NetBSD ]; then
    cc zzz.o -o bin/simpvir -lc
  else
    ld zzz.o -o bin/simpvir
  fi

  rm -f rt.s yyy.s global-defines.s zzz.o
elif [ $MACHINE = riscv64 ]; then

  cp src/asm/simpvir-riscv-core.s xxx.s

  # TODO do we need rt/rt-arm-src/init.s
  cat rt/rt-riscv-src/data.s \
    rt/rt-riscv-src/text.s \
    rt/rt-riscv-src/rt-linux.s \
    rt/rt-riscv-src/rt.s \
    rt/rt-riscv-src/start.s \
    xxx.s \
    rt/rt-riscv-src/cleanup.s >zzz.s

    as -o zzz.o zzz.s
    ld zzz.o -o bin/simpvir

    rm -f xxx.s zzz.o
else
  echo "unsupported machine type:" $MACHINE
fi
