[sw] Add Meson as software build system

Overview:

This commit adds the following changes:

* Meson build files for sw/ targets. There are two supported build
  configurations:
  * build-fpga: Nexys FPGA
  * build-sim: Verilator
* RISCV crosstool support via toolchain.txt
* Add util/embedded_target.py to generate additional objects per
  embedded_target.
* Breakdown sw/lib/ot_lib.a intp per IP libraries. Each target now
  includes the dependencies it needs, e.g. sw_lib_uart_ot can be used to
  include the UART device library.

New build system requirements:

```console
$ pip3 install --user meson
$ apt-get install ninja-build
```

Steps for using Meson:

```console
$ cd ${REPO_TOP}
$ ./meson_init.sh
$ ninja -C build-fpga
$ ninja -C build-verilator
```

To build an individual target:

In the following example, just build the flash_test.bin
target:

```console
$ ninja -C build-fpga sw/tests/flash_ctrl/flash_test.bin
```

meson_init.sh configuration options:

* `-f`: Delete build directories before calling meson.
* `-r`: Call Meson with `--reconfigure` flag. Requires valid build
  directories.
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..acc8422
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,62 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+project('opentitan', 'c', 'cpp', version: '0.1',)
+
+target = get_option('target')
+if target == 'undef'
+  error('target option not set. Please run meson with a valid build target option.')
+endif
+
+if target == 'verilator'
+  # TODO: Consider using extra args array if using this flag globally is no
+  # longer OK.
+  add_project_arguments('-DSIMULATION', language: 'c')
+endif
+
+# The following flags are applied to all native builds.
+add_project_arguments('-Wall', '-Werror', 'cpp_std=c++14', language: 'cpp')
+add_project_arguments('-std=gnu99', '-Wall', '-Werror', language: 'c')
+
+# Common program references.
+prog_python = import('python').find_installation('python3')
+prog_objcopy = find_program('objcopy')
+prog_srec_cat = find_program('srec_cat')
+prog_git = find_program('git')
+
+# RISCV linker parameters.
+riscv_linkfile = files(['sw/exts/common/link.ld'])
+riscv_link_args = ['-Wl,-T,@0@/@1@'.format('..', riscv_linkfile[0])]
+riscv_link_deps = [riscv_linkfile]
+
+# RISCV CRT parameters
+startup_files = files(['sw/exts/common/_crt.c'])
+
+# Additional arguments for utility in charge of generating bin and vmem outputs
+# These variables are expected to be used in custom_target rules.
+embedded_target_output = ['@BASENAME@.bin', '@BASENAME@.vmem']
+embedded_target_args = [prog_python, '../util/embedded_target.py',
+  '--objcopy', prog_objcopy, '--srec_cat', prog_srec_cat,
+  '--input', '@INPUT@', '--basename', '@BASENAME@', '--outdir', '@OUTDIR@']
+
+# HW headers. Placed here to avoid adding meson build files in the hw directory.
+gen_hw_hdr = generator(
+  prog_python,
+  output: '@BASENAME@_regs.h',
+  arguments: [
+    '@SOURCE_DIR@/util/regtool.py', '-D', '-o', '@BUILD_DIR@/@BASENAME@_regs.h',
+    '@INPUT@',
+  ],
+)
+
+# TODO: Considering moving these into hw/ip directories.
+hw_ip_flash_ctrl_regs_h = gen_hw_hdr.process('hw/ip/flash_ctrl/doc/flash_ctrl.hjson')
+hw_ip_gpio_reg_h = gen_hw_hdr.process('hw/ip/gpio/doc/gpio.hjson')
+hw_ip_hmac_reg_h = gen_hw_hdr.process('hw/ip/hmac/doc/hmac.hjson')
+hw_ip_spi_device_reg_h = gen_hw_hdr.process('hw/ip/spi_device/doc/spi_device.hjson')
+hw_ip_rv_timer_reg_h = gen_hw_hdr.process('hw/ip/rv_timer/doc/rv_timer.hjson')
+hw_ip_uart_reg_h = gen_hw_hdr.process('hw/ip/uart/doc/uart.hjson')
+hw_ip_usbdev_reg_h = gen_hw_hdr.process('hw/ip/usbdev/doc/usbdev.hjson')
+
+subdir('sw')
diff --git a/meson_init.sh b/meson_init.sh
new file mode 100755
index 0000000..6f06bc9
--- /dev/null
+++ b/meson_init.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+set -o errexit
+set -o pipefail
+set -o nounset
+
+readonly BUILD_DIR_PREFIX="build"
+readonly TARGET_VERILATOR="verilator"
+readonly TARGET_FPGA="fpga"
+
+function usage() {
+  cat << USAGE
+Configure Meson build targets.
+
+Usage: $0 [-r|-f]
+
+  -f: Remove build directories before running Meson.
+  -r: Force reconfiguration of build directories.
+
+USAGE
+}
+
+FLAGS_force=false
+FLAGS_reconfigure=""
+while getopts 'r?:f?' flag; do
+  case "${flag}" in
+    f) FLAGS_force=true;;
+    r) FLAGS_reconfigure="--reconfigure";;
+    ?) usage && exit 1;;
+    *) usage
+       error "Unexpected option ${flag}"
+       ;;
+  esac
+done
+
+if [[ "${FLAGS_force}" == true && -n "${FLAGS_reconfigure}" ]]; then
+  usage >&2
+  echo "Error: -r and -f cannont be used at the same time." >&2
+  exit 1
+fi
+
+if [[ ! -n "$(command -v meson)" ]]; then
+  echo "Unable to find meson. Please install meson before running this command." >&2
+  exit 1
+fi
+
+if [[ ! -n "$(command -v ninja)" ]]; then
+  echo "Unable to find ninja. Please install ninja before running this command." >&2
+  exit 1
+fi
+
+if [[ "${FLAGS_force}" == true ]]; then
+  for target_suffix in "${TARGET_VERILATOR}" "${TARGET_FPGA}"; do
+    rm -rf "${BUILD_DIR_PREFIX}-${target_suffix}"
+  done
+fi
+
+if [[ ! -n "${FLAGS_reconfigure}" ]] ; then
+  for target_suffix in "${TARGET_VERILATOR}" "${TARGET_FPGA}"; do
+    if [[ -d "${BUILD_DIR_PREFIX}-${target_suffix}" ]]; then
+      usage >&2
+      echo "Error: ${BUILD_DIR_PREFIX}-${target_suffix} already exists. " \
+           "Remove directory, or rerun $0 with the -r option" >&2
+      exit 1
+    fi
+  done
+fi
+
+meson ${FLAGS_reconfigure} "-Dtarget=${TARGET_VERILATOR}" --cross-file=toolchain.txt \
+    --buildtype=plain "${BUILD_DIR_PREFIX}-${TARGET_VERILATOR}"
+
+meson ${FLAGS_reconfigure} "-Dtarget=${TARGET_FPGA}" --cross-file=toolchain.txt \
+    --buildtype=plain "${BUILD_DIR_PREFIX}-${TARGET_FPGA}"
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..e78fb4c
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1 @@
+option('target', type : 'combo', choices: ['verilator', 'fpga', 'undef'], value : 'undef')
diff --git a/sw/boot_rom/meson.build b/sw/boot_rom/meson.build
new file mode 100644
index 0000000..9bdf160
--- /dev/null
+++ b/sw/boot_rom/meson.build
@@ -0,0 +1,42 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Generate header file with chip_info information.
+chip_info_h = custom_target(
+  'chip_info_h',
+  output: 'chip_info.h',
+  command: [
+    prog_python, '@SOURCE_DIR@/util/rom_chip_info.py', '--outdir', '@OUTDIR@']
+)
+
+# ROM linker parameters.
+rom_linkfile = files(['rom_link.ld'])
+rom_link_args = ['-Wl,-T,@0@/@1@'.format('..', rom_linkfile[0])]
+rom_link_deps = [rom_linkfile]
+
+custom_target(
+  'boot_rom',
+  output: embedded_target_output,
+  input: executable(
+    'boot_rom',
+    [
+      chip_info_h,
+      'boot_rom.c',
+      'bootstrap.c',
+      'crt0.S'
+    ],
+    name_suffix: 'elf',
+    link_args: rom_link_args,
+    link_depends: rom_link_deps,
+    dependencies: [
+      sw_lib_flash_ctrl,
+      sw_lib_gpio,
+      sw_lib_hmac,
+      sw_lib_spi_device,
+      sw_lib_uart,
+    ],
+  ),
+  command: embedded_target_args,
+  build_by_default: true,
+)
diff --git a/sw/examples/hello_usbdev/meson.build b/sw/examples/hello_usbdev/meson.build
new file mode 100644
index 0000000..7482181
--- /dev/null
+++ b/sw/examples/hello_usbdev/meson.build
@@ -0,0 +1,23 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+custom_target(
+  'hello_usbdev',
+  output: embedded_target_output,
+  input: executable(
+    'hello_usbdev',
+    ['hello_usbdev.c', startup_files],
+    name_suffix: 'elf',
+    link_args: riscv_link_args,
+    link_depends: riscv_link_deps,
+    dependencies: [
+      sw_lib_gpio,
+      sw_lib_irq,
+      sw_lib_uart,
+      sw_lib_usb,
+    ],
+  ),
+  command: embedded_target_args,
+  build_by_default: true,
+)
diff --git a/sw/examples/hello_world/meson.build b/sw/examples/hello_world/meson.build
new file mode 100644
index 0000000..646b1d4
--- /dev/null
+++ b/sw/examples/hello_world/meson.build
@@ -0,0 +1,23 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+custom_target(
+  'hello_world',
+  output: embedded_target_output,
+  input: executable(
+    'hello_world',
+    ['hello_world.c', startup_files],
+    name_suffix: 'elf',
+    link_args: riscv_link_args,
+    link_depends: riscv_link_deps,
+    dependencies: [
+      sw_lib_gpio,
+      sw_lib_irq,
+      sw_lib_spi_device,
+      sw_lib_uart,
+    ],
+  ),
+  command: embedded_target_args,
+  build_by_default: true,
+)
diff --git a/sw/examples/meson.build b/sw/examples/meson.build
new file mode 100644
index 0000000..fe95ea4
--- /dev/null
+++ b/sw/examples/meson.build
@@ -0,0 +1,6 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+subdir('hello_usbdev')
+subdir('hello_world')
diff --git a/sw/host/meson.build b/sw/host/meson.build
new file mode 100644
index 0000000..10356b0
--- /dev/null
+++ b/sw/host/meson.build
@@ -0,0 +1,6 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+subdir('vendor')
+subdir('spiflash')
diff --git a/sw/host/spiflash/meson.build b/sw/host/spiflash/meson.build
new file mode 100644
index 0000000..e41921a
--- /dev/null
+++ b/sw/host/spiflash/meson.build
@@ -0,0 +1,18 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+executable(
+  'spiflash',
+  [
+    'ftdi_spi_interface.cc',
+    'spiflash.cc',
+    'updater.cc',
+    'verilator_spi_interface.cc',
+  ],
+  dependencies: [
+    dependency('libcrypto', native: true),
+    libmpsse
+  ],
+  native: true,
+)
diff --git a/sw/host/vendor/meson.build b/sw/host/vendor/meson.build
new file mode 100644
index 0000000..be5c0b1
--- /dev/null
+++ b/sw/host/vendor/meson.build
@@ -0,0 +1,5 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+subdir('mpsse')
diff --git a/sw/host/vendor/mpsse/meson.build b/sw/host/vendor/mpsse/meson.build
new file mode 100644
index 0000000..119aa90
--- /dev/null
+++ b/sw/host/vendor/mpsse/meson.build
@@ -0,0 +1,19 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+libmpsse = declare_dependency(
+  include_directories : include_directories('.'),
+  link_with: static_library(
+    'mpsse',
+    sources: [
+      'mpsse.c',
+      'support.c'
+    ],
+    dependencies: [
+      dependency('libftdi1', native: true),
+      dependency('libusb-1.0', native: true),
+    ],
+    native: true,
+  ),
+)
diff --git a/sw/lib/meson.build b/sw/lib/meson.build
new file mode 100644
index 0000000..2c0655e
--- /dev/null
+++ b/sw/lib/meson.build
@@ -0,0 +1,120 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# UART library (sw_lib_uart)
+sw_lib_uart = declare_dependency(
+  include_directories: ['.'],
+  sources: [hw_ip_uart_reg_h],
+  link_with: static_library(
+    'uart_ot',
+    sources: [
+      hw_ip_uart_reg_h,
+      'uart.c',
+    ]
+  )
+)
+
+
+# Flash controller library (sw_lib_flash_ctrl)
+sw_lib_flash_ctrl = declare_dependency(
+  include_directories: ['.'],
+  sources: [hw_ip_flash_ctrl_regs_h],
+  link_with: static_library(
+    'flash_ctrl_ot',
+    sources: [
+      hw_ip_flash_ctrl_regs_h,
+      'flash_ctrl.c',
+    ]
+  )
+)
+
+# GPIO library (sw_lib_gpio)
+sw_lib_gpio = declare_dependency(
+  include_directories: ['.'],
+  sources: [hw_ip_gpio_reg_h],
+  link_with: static_library(
+    'gpio_ot',
+    sources: [
+      hw_ip_gpio_reg_h,
+      'gpio.c',
+    ]
+  )
+)
+
+# HMAC library (sw_lib_hmac)
+sw_lib_hmac = declare_dependency(
+  include_directories: [
+    '.',
+    '../vendor',
+  ],
+  sources: [hw_ip_hmac_reg_h],
+  link_with: static_library(
+    'hmac_ot',
+    include_directories: ['.', '../vendor'],
+    sources: [
+      hw_ip_hmac_reg_h,
+      'hw_sha256.c',
+      'hmac.c',
+    ]
+  )
+)
+
+# IRQ library (sw_lib_irq)
+sw_lib_irq = declare_dependency(
+  include_directories: ['.'],
+  link_with: static_library(
+    'irq_ot',
+    sources: [
+      'handler.c',
+      'irq_vectors.S',
+      'irq.c'
+    ],
+    dependencies: [
+      sw_lib_uart,
+    ]
+  )
+)
+
+# RV_TIMER library (sw_lib_rv_timer)
+sw_lib_rv_timer = declare_dependency(
+  include_directories: ['.'],
+  sources: [hw_ip_rv_timer_reg_h],
+  link_with: static_library(
+    'rv_timer_ot',
+    sources: [
+      hw_ip_rv_timer_reg_h,
+      'rv_timer.c',
+    ]
+  )
+)
+
+# SPI device library (sw_lib_spi_device)
+sw_lib_spi_device = declare_dependency(
+  include_directories: ['.'],
+  link_with: static_library(
+    'spid_ot',
+    sources: [
+      hw_ip_spi_device_reg_h,
+      'spi_device.c',
+    ]
+  )
+)
+
+# USB DEV library (sw_lib_usb)
+sw_lib_usb = declare_dependency(
+  include_directories: ['.'],
+  sources: [hw_ip_usbdev_reg_h],
+  link_with: static_library(
+    'usb_ot',
+    sources: [
+      hw_ip_usbdev_reg_h,
+      'usb_controlep.c',
+      'usb_simpleserial.c',
+      'usbdev.c',
+    ],
+    dependencies: [
+      sw_lib_uart,
+    ]
+  )
+)
diff --git a/sw/meson.build b/sw/meson.build
new file mode 100644
index 0000000..9d70a8e
--- /dev/null
+++ b/sw/meson.build
@@ -0,0 +1,11 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+subdir('lib')
+
+subdir('boot_rom')
+subdir('examples')
+subdir('tests')
+
+subdir('host')
diff --git a/sw/tests/flash_ctrl/meson.build b/sw/tests/flash_ctrl/meson.build
new file mode 100644
index 0000000..01191bc
--- /dev/null
+++ b/sw/tests/flash_ctrl/meson.build
@@ -0,0 +1,23 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+custom_target(
+  'flash_test',
+  output: embedded_target_output,
+  input: executable(
+    'flash_test',
+    ['flash_test.c', startup_files],
+    name_suffix: 'elf',
+    link_args: riscv_link_args,
+    link_depends: riscv_link_deps,
+    dependencies: [
+      sw_lib_flash_ctrl,
+      sw_lib_gpio,
+      sw_lib_irq,
+      sw_lib_uart,
+    ],
+  ),
+  command: embedded_target_args,
+  build_by_default: true,
+)
diff --git a/sw/tests/hmac/meson.build b/sw/tests/hmac/meson.build
new file mode 100644
index 0000000..81f009b
--- /dev/null
+++ b/sw/tests/hmac/meson.build
@@ -0,0 +1,23 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+custom_target(
+  'sha256_test',
+  output: embedded_target_output,
+  input: executable(
+    'sha256_test',
+    ['sha256_test.c', startup_files],
+    name_suffix: 'elf',
+    link_args: riscv_link_args,
+    link_depends: riscv_link_deps,
+    dependencies: [
+      sw_lib_flash_ctrl,
+      sw_lib_hmac,
+      sw_lib_irq,
+      sw_lib_uart,
+    ],
+  ),
+  command: embedded_target_args,
+  build_by_default: true,
+)
diff --git a/sw/tests/meson.build b/sw/tests/meson.build
new file mode 100644
index 0000000..298c2cf
--- /dev/null
+++ b/sw/tests/meson.build
@@ -0,0 +1,7 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+subdir('flash_ctrl')
+subdir('hmac')
+subdir('rv_timer')
diff --git a/sw/tests/rv_timer/meson.build b/sw/tests/rv_timer/meson.build
new file mode 100644
index 0000000..74a85ed
--- /dev/null
+++ b/sw/tests/rv_timer/meson.build
@@ -0,0 +1,22 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+custom_target(
+  'rv_timer_test',
+  output: embedded_target_output,
+  input: executable(
+    'rv_timer_test',
+    ['rv_timer_test.c', startup_files],
+    name_suffix: 'elf',
+    link_args: riscv_link_args,
+    link_depends: riscv_link_deps,
+    dependencies: [
+      sw_lib_irq,
+      sw_lib_rv_timer,
+      sw_lib_uart,
+    ],
+  ),
+  command: embedded_target_args,
+  build_by_default: true,
+)
diff --git a/toolchain.txt b/toolchain.txt
new file mode 100644
index 0000000..c77f563
--- /dev/null
+++ b/toolchain.txt
@@ -0,0 +1,41 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Meson RISCV toolchain configuration.
+
+[binaries]
+c = '/tools/riscv/bin/riscv32-unknown-elf-gcc'
+cpp = '/tools/riscv/bin/riscv32-unknown-elf-g++'
+ar = '/tools/riscv/bin/riscv32-unknown-elf-ar'
+ld = '/tools/riscv/bin/riscv32-unknown-elf-ld'
+objdump = '/tools/riscv/bin/riscv32-unknown-elf-objdump'
+objcopy = '/tools/riscv/bin/riscv32-unknown-elf-objcopy'
+strip = '/tools/riscv/bin/riscv32-unknown-elf-strip'
+
+[properties]
+has_function_printf = false
+c_args = [
+  '-fvisibility=hidden',
+  '-g',
+  '-mabi=ilp32',
+  '-march=rv32imc',
+  '-mcmodel=medany',
+  '-nostartfiles',
+  '-nostdlib',
+  '-Os',
+  '-static',
+  '-Wall',
+  '-Werror']
+c_link_args = ['-nostdlib']
+
+[build_machine]
+system = 'linux'
+cpu_family = 'x86'
+endian = 'little'
+
+[host_machine]
+system = 'bare metal'
+cpu_family = 'riscv32'
+cpu = 'ibex'
+endian = 'little'
diff --git a/util/embedded_target.py b/util/embedded_target.py
new file mode 100644
index 0000000..f1c653e
--- /dev/null
+++ b/util/embedded_target.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+"""Script used to generate additional output files for Meson embedded targets.
+
+This script takes the input ELF file generated by the build system, and
+generates BIN and VMEM files. The BIN file is generated using objcopy, whereas
+the VMEM file is generated using srec_cat.
+"""
+import argparse
+import os
+from pathlib import Path
+import subprocess
+import sys
+
+
+def run_objcopy(objcopy, input, basename, outdir):
+    filename = basename + '.bin'
+    output = outdir / filename
+    cmd = [
+        objcopy, '-O', 'binary', input, output
+    ]
+    subprocess.run(cmd, check=True)
+    return output
+
+
+def run_srec_cat(srec_cat, input, basename, outdir):
+    # TODO: Replace command for objcopy once this bug is fixed and released.
+    # https://sourceware.org/bugzilla/show_bug.cgi?id=19921
+    filename = basename + '.vmem'
+    output = outdir / filename
+    cmd = [
+        srec_cat, input, '-binary', '-offset', '0x0', '-byte-swap', '4', '-o',
+        output, '-vmem'
+    ]
+    subprocess.run(cmd, check=True)
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--basename',
+        '-b',
+        required=True,
+        help='File basename used as preffix in output filenames.')
+    parser.add_argument(
+        '--input',
+        '-i',
+        required=True,
+        help="Input file")
+    parser.add_argument(
+        '--objcopy',
+        '-c',
+        required=True,
+        help='Absolute path to objcopy tool.')
+    parser.add_argument(
+        '--outdir',
+        '-d',
+        required=True,
+        help="Output directory.")
+    parser.add_argument(
+        '--srec_cat',
+        '-s',
+        required=True,
+        help='Absolute path to srec_cat tool.')
+    args = parser.parse_args()
+
+    if not os.path.exists(args.outdir):
+        os.makedirs(args.outdir)
+
+    outdir = Path(args.outdir)
+    bin_file = run_objcopy(args.objcopy, args.input, args.basename, outdir)
+    run_srec_cat(args.srec_cat, bin_file, args.basename, outdir)
+
+
+if __name__ == "__main__":
+    main()