[dv,sw] sw Makefile refactor
[sw] Makefile refactor
- added centrallized Makefile infra for maximizing reuse across SW
test, lib and boot_rom targets
- existing Make flows still remain (for the timebeing; will remove it
once all approve of this)
- all make commands are to be run from sw/ area
- updated with chip_info generation
- TODOs
- add some documentation
- need to fix support for external apps, eg coremark
[dv,sw] coremark port now works
- updates to get external app (coremark) compiling with the refactored
flow
- added ability to compile targets with external Makefiles with
STANDALONE_SW var
- added sw/benchmarks/srcs.mk to supply STANDALONE_CMD to build custom
app
[dv,sw] removed existing Makefiles (deprecated)
diff --git a/hw/dv/tools/Makefile b/hw/dv/tools/Makefile
index 7f7fab6..1f7ab76 100644
--- a/hw/dv/tools/Makefile
+++ b/hw/dv/tools/Makefile
@@ -29,8 +29,8 @@
BUILD_DIR := ${SCRATCH_PATH}/${BUILD_LOC}
RUN_PATH ?= ${SCRATCH_PATH}/${TEST_NAME}
RUN_DIR := ${RUN_PATH}/${RUN_LOC}
-
-SW_DIR := ${PRJ_DIR}/sw
+SW_BUILD_DIR ?= ${RUN_DIR}/sw_build
+SW_ROOT_DIR := ${PRJ_DIR}/sw
JOB_OPTS ?=
BUILD_JOB_OPTS ?= $(JOB_OPTS)
@@ -44,13 +44,27 @@
BUILD_LOG ?= ${BUILD_DIR}/build.log
RUN_LOG ?= ${RUN_DIR}/run.log
UVM_VERBOSITY ?= UVM_LOW
-BUILD_OPTS +=
-# command line version of BUILD_OPTS - CL_BUILD_OPTS - it should be empty here
+
+####################################################################################################
+## Options for SV build / C build / simulation run ##
+## CL_ prefix represents command line versions of these options - they should be empty and only ##
+## be set on the command line ##
+####################################################################################################
+# BUILD_OPTS are passed to the simulator during the SV testbench compile step
CL_BUILD_OPTS +=
-RUN_OPTS += +UVM_NO_RELNOTES
-# command line version of RUN_OPTS - CL_RUN_OPTS - it should be empty here
+BUILD_OPTS +=
+
+# RUN_OPTS are passed to the simulation executable that is invoked to run the simulation
CL_RUN_OPTS +=
-CAPP_BUILD_OPTS ?=
+RUN_OPTS += +UVM_NO_RELNOTES
+
+# SW_OPTS are options for SW apps that come with their own Makefile (example coremark)
+CL_SW_OPTS +=
+SW_OPTS += ${CL_SW_OPTS}
+
+# SW_FLAGS are compiler flags / directives that we can pass for each test using our own Makefiles
+CL_SW_FLAGS +=
+SW_FLAGS += ${CL_SW_FLAGS}
# default project-wide bus widths
TL_AW ?= 32
diff --git a/hw/dv/tools/rules.mk b/hw/dv/tools/rules.mk
index bb2eaea..864727c 100644
--- a/hw/dv/tools/rules.mk
+++ b/hw/dv/tools/rules.mk
@@ -42,24 +42,21 @@
/bin/bash ${MAKE_ROOT}/run_dir_limiter ${RUN_PATH} ${RUN_DIR_LIMIT}
env > ${RUN_DIR}/env_vars
-# TODO: clean this (capp tooling infrastructure)
-capp: pre_run
-ifneq (${CAPP_NAME},)
- # Recursive make calls
- make distclean -C ${SW_DIR}/boot_rom
- make -C ${SW_DIR}/boot_rom
- make distclean -C ${SW_DIR}/${CAPP_DIR} MAKEFLAGS=$(CAPP_BUILD_OPTS)
- make -C ${SW_DIR}/${CAPP_DIR} MAKEFLAGS=$(CAPP_BUILD_OPTS) \
- PROGRAM_CFLAGS=$(PROGRAM_CFLAGS)
-
- # Copy outputs over to run area
- cp $(SW_DIR)/boot_rom/boot_rom.vmem ${RUN_DIR}/rom.vmem
- cp ${SW_DIR}/${CAPP_DIR}/${CAPP_NAME}.vmem ${RUN_DIR}/main.vmem
- cp ${SW_DIR}/${CAPP_DIR}/${CAPP_NAME}.dis ${RUN_DIR}/main.dis
- cp ${SW_DIR}/${CAPP_DIR}/${CAPP_NAME}.map ${RUN_DIR}/main.map
+sw_build: pre_run
+ifneq (${SW_NAME},)
+ mkdir -p ${SW_BUILD_DIR}
+ $(MAKE) -C $(SW_ROOT_DIR) \
+ SW_DIR=boot_rom \
+ SW_BUILD_DIR=$(SW_BUILD_DIR)/rom \
+ MAKEFLAGS="$(SW_OPTS)"
+ $(MAKE) -C $(SW_ROOT_DIR) \
+ SW_DIR=$(SW_DIR) \
+ SW_NAME=$(SW_NAME) \
+ SW_BUILD_DIR=$(SW_BUILD_DIR)/sw \
+ MAKEFLAGS="$(SW_OPTS)"
endif
-simulate: capp
+simulate: sw_build
$(RUN_JOB_OPTS) cd ${RUN_DIR} && ${SIMX} ${RUN_OPTS} ${CL_RUN_OPTS}
post_run: simulate
@@ -77,6 +74,7 @@
compile \
post_compile \
compile_result \
+ sw_build \
pre_run \
simulate \
post_run \
diff --git a/hw/top_earlgrey/dv/Makefile b/hw/top_earlgrey/dv/Makefile
index f7d1896..000b2e1 100644
--- a/hw/top_earlgrey/dv/Makefile
+++ b/hw/top_earlgrey/dv/Makefile
@@ -16,7 +16,6 @@
DV_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
export DUT_TOP := top_earlgrey_asic
export TB_TOP := tb
-export RV_TOOLS := /edascratch/ms_edatools/riscv-tools/rv32ic/bin
FUSESOC_CORE := lowrisc:dv:chip_sim:0.1
COMPILE_KEY ?= default
@@ -28,33 +27,33 @@
UVM_TEST_SEQ ?= chip_base_vseq
ifeq (${TEST_NAME},chip_sanity)
- CAPP_DIR = examples/hello_world
- CAPP_NAME = hello_world
+ SW_DIR = examples/hello_world
+ SW_NAME = hello_world
endif
ifeq (${TEST_NAME},chip_flash_test)
- CAPP_DIR = tests/flash_ctrl
- CAPP_NAME = flash_test
+ SW_DIR = tests/flash_ctrl
+ SW_NAME = flash_test
RUN_OPTS += +cpu_test_timeout_ns=15000000
endif
ifeq (${TEST_NAME},chip_sha256_test)
- CAPP_DIR = tests/hmac
- CAPP_NAME = sha256_test
+ SW_DIR = tests/hmac
+ SW_NAME = sha256_test
RUN_OPTS += +cpu_test_timeout_ns=4000000
endif
ifeq (${TEST_NAME},chip_rv_timer_test)
- CAPP_DIR = tests/rv_timer
- CAPP_NAME = rv_timer_test
+ SW_DIR = tests/rv_timer
+ SW_NAME = rv_timer_test
RUN_OPTS += +cpu_test_timeout_ns=4000000
endif
ifeq (${TEST_NAME},coremark)
- CAPP_DIR = coremark
- CAPP_NAME = coremark
+ SW_DIR = benchmarks/coremark
+ SW_NAME = coremark
RUN_OPTS += +cpu_test_timeout_ns=20000000
- CAPP_BUILD_OPTS += ITERATIONS=1
+ SW_OPTS += ITERATIONS=1
endif
ifeq (${TEST_NAME},chip_csr_hw_reset)
diff --git a/hw/top_earlgrey/dv/env/chip_env_pkg.sv b/hw/top_earlgrey/dv/env/chip_env_pkg.sv
index c3a1e8a..17b532c 100644
--- a/hw/top_earlgrey/dv/env/chip_env_pkg.sv
+++ b/hw/top_earlgrey/dv/env/chip_env_pkg.sv
@@ -26,7 +26,10 @@
`include "dv_macros.svh"
// local parameters and types
- parameter NUM_GPIOS = 16;
+ parameter NUM_GPIOS = 16;
+ parameter string ROM_MEM_IMG = "sw_build/rom/rom.vmem";
+ parameter string SW_MEM_IMG = "sw_build/sw/sw.vmem";
+
typedef virtual pins_if #(NUM_GPIOS) gpio_vif;
typedef virtual mem_bkdr_if mem_bkdr_vif;
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
index 833ba89..ab06770 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
@@ -46,12 +46,12 @@
// routine to backdoor load cpu test hex image and bring the cpu out of reset (if required)
// TODO(sriyerg): for future implementation
virtual task cpu_init();
- cfg.mem_bkdr_vifs[Rom].load_mem_from_file("rom.vmem");
+ cfg.mem_bkdr_vifs[Rom].load_mem_from_file(ROM_MEM_IMG);
cfg.mem_bkdr_vifs[FlashBank0].set_mem();
cfg.mem_bkdr_vifs[FlashBank1].set_mem();
// TODO: the location of the main execution image should be randomized for either bank in future
- cfg.mem_bkdr_vifs[FlashBank0].load_mem_from_file("main.vmem");
+ cfg.mem_bkdr_vifs[FlashBank0].load_mem_from_file(SW_MEM_IMG);
cpu_test_state = CpuTestRunning;
endtask
diff --git a/sw/Makefile b/sw/Makefile
new file mode 100644
index 0000000..056dd30
--- /dev/null
+++ b/sw/Makefile
@@ -0,0 +1,34 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+####################################################################################################
+## Generate a baremetal application for the microcontroller ##
+## Mandatory variables that need to be set over the command line: ##
+## SW_DIR: this is the partial directory path to the SW test being built starting from sw/ ##
+## ex: if running hello_world.c, then SW_DIR=examples/hello_world ##
+## At this location, there needs to be a 'srcs.mk' file that contains the list of ##
+## SW_SRCS to be built for that SW test. ##
+## SW_NAME: This is the name of the SW test begin run. Optional if SW_DIR name (last dir) is ##
+## the same as the SW test name. ##
+## ##
+## Optional variables: ##
+## SW_BUILD_DIR: This is the output location for generating all sources ##
+## SW_FLAGS Global args to pass on to the compiler ##
+## SW_OPTS Global args to pass on to the sub-make commands ##
+####################################################################################################
+
+
+# Generate a baremetal application for the microcontroller
+SW_ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+SW_DIR ?= examples/hello_world
+
+# sources
+STANDALONE_SW ?= 0
+include ${SW_DIR}/srcs.mk
+include exts/common/srcs.mk
+include lib/srcs.mk
+
+# common options and rules
+include opts.mk
+include rules.mk
diff --git a/sw/benchmarks/coremark/Makefile b/sw/benchmarks/coremark/Makefile
deleted file mode 100644
index 0fa4dfb..0000000
--- a/sw/benchmarks/coremark/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-NAME := coremark
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-COREMARK_DIR := $(PROGRAM_DIR)/../../vendor/$(NAME)
-COREMARK_PORT := $(PROGRAM_DIR)/top_earlgrey
-
-all:
-# $(MAKE) -C $(LIB_DIR) MAKEFLAGS=$(MAKEFLAGS)
- $(MAKE) -C $(LIB_DIR)
- $(MAKE) -C $(COREMARK_DIR) PORT_DIR=$(COREMARK_PORT)
- $(foreach out, $(OUTFILES), cp $(COREMARK_DIR)/$(out) .;)
-
-
-distclean:
- $(RM) $(OUTFILES)
- $(MAKE) -C $(LIB_DIR) distclean
- $(MAKE) -C $(COREMARK_DIR) clean PORT_DIR=$(COREMARK_PORT)
-
-include ${PROGRAM_DIR}/../../exts/common/options.mk
diff --git a/sw/benchmarks/coremark/srcs.mk b/sw/benchmarks/coremark/srcs.mk
new file mode 100644
index 0000000..369286c
--- /dev/null
+++ b/sw/benchmarks/coremark/srcs.mk
@@ -0,0 +1,13 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+COREMARK_DIR = $(SW_ROOT_DIR)/vendor/$(SW_NAME)
+COREMARK_PORT = $(SW_ROOT_DIR)/$(SW_DIR)/top_earlgrey
+STANDALONE_SW := 1
+STANDALONE_CMD = $(MAKE) $(IMG_OUTPUTS) -C $(COREMARK_DIR) \
+ PORT_DIR=$(COREMARK_PORT) \
+ SW_DIR=$(SW_DIR) \
+ SW_ROOT_DIR=$(SW_ROOT_DIR) \
+ SW_BUILD_DIR=$(SW_BUILD_DIR) \
+ MAKEFLAGS=$(MAKEFLAGS)
diff --git a/sw/benchmarks/coremark/top_earlgrey/core_portme.mak b/sw/benchmarks/coremark/top_earlgrey/core_portme.mak
index 739e251..cd45021 100755
--- a/sw/benchmarks/coremark/top_earlgrey/core_portme.mak
+++ b/sw/benchmarks/coremark/top_earlgrey/core_portme.mak
@@ -1,82 +1,90 @@
#File : core_portme.mak
-NAME = coremark
-PORTME_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-PROGRAM_DIR := $(PORTME_DIR)/../
+include ${SW_ROOT_DIR}/opts.mk
-include ${PROGRAM_DIR}/../../exts/common/options.mk
-PORT_CLEAN := $(OUTFILES)
+PORT_CLEAN := $(IMG_OUTPUTS)
+# FLAG : EXE, OEXT
+# Extensions of generated outputs
+OEXT = .o
+EXE = .elf
+
+# FLAG : OPATH
+# Path to the output folder. Default - current folder.
+OPATH = $(SW_BUILD_DIR)/
# Flag : OUTFLAG
-# Use this flag to define how to to get an executable (e.g -o)
-OUTFLAG= -T $(LINKER_SCRIPT) -L$(LIB_DIR) -l$(LIB_NAME) -Xlinker -Map=coremark.map -o
-# Flag : CC
-# Use this flag to define compiler to use
-CC = $(RV_TOOLS)/riscv32-unknown-elf-gcc
-# Flag : LD
-# Use this flag to define compiler to use
-LD = $(RV_TOOLS)/riscv32-unknown-elf-ld
-# Flag : AS
-# Use this flag to define compiler to use
-AS = $(RV_TOOLS)/riscv32-unknown-elf-as
-# Flag : CFLAGS
-# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags"
-PORT_CFLAGS = -DTOTAL_DATA_SIZE=6000 -DMAIN_HAS_NOARGC=1
-FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)"
-CFLAGS += $(PORT_CFLAGS) $(XCFLAGS) -I$(PORT_DIR) -I. -I$(LIB_DIR)
-#Flag : LFLAGS_END
-# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts).
-# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt.
-#SEPARATE_COMPILE=1
-# Flag : SEPARATE_COMPILE
-# You must also define below how to create an object file, and how to link.
-OBJOUT = -o
-LFLAGS =
-ASFLAGS =
-OFLAG = -o
-COUT = -c
+# Use this flag to define how to to get an executable (e.g -o)
+OUTFLAG = $(LINK_OPTS) -o
+# Flag : CFLAGS
+# Use this flag to define compiler options. Note, you can add compiler options
+# from the command line using XCFLAGS="other flags"
+PORT_CFLAGS = -DTOTAL_DATA_SIZE=6000 -DMAIN_HAS_NOARGC=1
+FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)"
+CFLAGS += $(PORT_CFLAGS) $(XCFLAGS) -I$(PORT_DIR) -I. $(INCS)
+
+# Flag : LFLAGS_END
+# Define any libraries needed for linking or other flags that should come
+# at the end of the link line (e.g. linker scripts).
+# Note : On certain platforms, the default clock_gettime implementation
+# is supported but requires linking of librt.
LFLAGS_END =
+
+# Flag : SEPARATE_COMPILE
+# Do compile and link steps separately. Not needed at this point.
+
+# You must also define below how to create an object file, and how to link.
+OBJOUT = -o
+LFLAGS =
+ASFLAGS =
+OFLAG = -o
+COUT = -c
+
# Flag : PORT_SRCS
-# Port specific source files can be added here
-# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler!
+# Port specific source files can be added here
+# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler!
PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c $(EXT_SRCS)
vpath %.c $(PORT_DIR)
vpath %.s $(PORT_DIR)
# Flag : LOAD
-# For a simple port, we assume self hosted compile and run, no load needed.
+# For a simple port, we assume self hosted compile and run, no load needed.
# Flag : RUN
-# For a simple port, we assume self hosted compile and run, simple invocation of the executable
+# For a simple port, we assume self hosted compile and run, simple invocation of the executable
+
+# Flag : MKDIR
+MKDIR = mkdir -p
LOAD = echo "Please set LOAD to the process of loading the executable to the flash"
RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)"
-OEXT = .o
-EXE = .elf
-
-$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c
- $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@
-
$(OPATH)%$(OEXT) : %.c
$(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@
-$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s
+$(OPATH)%$(OEXT) : %.s
$(AS) $(ASFLAGS) $< $(OBJOUT) $@
+$(OPATH)%$(OEXT) : $(PORT_DIR)/%.c
+ $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@
+
+$(OPATH)%$(OEXT) : $(PORT_DIR)/%.s
+ $(AS) $(ASFLAGS) $< $(OBJOUT) $@
+
+%.vmem: %.bin
+ srec_cat $^ -binary -offset 0x0 -byte-swap 4 -o $@ -vmem
+
+%.bin: %.elf
+ $(OBJCOPY) -O binary $^ $@
+
+%.dis: %.elf
+ $(OBJDUMP) -SD $^ > $@
+
+$(SW_BUILD_DIR)/$(IMG_NAME).elf: $(OUTFILE)
+ $(MAKE) $(OUTFILE)
+ mv $(OUTFILE) $@
+
# Target : port_pre% and port_post%
-# For the purpose of this simple port, no pre or post steps needed.
.PHONY : port_clean port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload
-
-port_postbuild:
- $(RV_TOOLS)/riscv32-unknown-elf-objcopy -O binary coremark.elf coremark.bin
- srec_cat coremark.bin -binary -offset 0x0 -byte-swap 4 -o coremark.vmem -vmem
- $(RV_TOOLS)/riscv32-unknown-elf-objdump -SD coremark.elf > coremark.dis
-
-# FLAG : OPATH
-# Path to the output folder. Default - current folder.
-OPATH = ./
-MKDIR = mkdir -p
diff --git a/sw/boot_rom/Makefile b/sw/boot_rom/Makefile
deleted file mode 100644
index c5dd590..0000000
--- a/sw/boot_rom/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-NAME = boot_rom
-SRCS = bootstrap.c boot_rom.c
-LINKER_SCRIPT = rom_link.ld
-CRT_SRCS =
-EXT_ASMS = crt0.S
-CHIP_INFO = chip_info.h
-
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-SW_DIR := $(PROGRAM_DIR)/..
-
-include ${PROGRAM_DIR}/../exts/common/options.mk
-include ${PROGRAM_DIR}/../exts/common/common.mk
diff --git a/sw/boot_rom/srcs.mk b/sw/boot_rom/srcs.mk
new file mode 100644
index 0000000..456df0c
--- /dev/null
+++ b/sw/boot_rom/srcs.mk
@@ -0,0 +1,10 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+SW_NAME ?= boot_rom
+SW_SRCS += $(SW_DIR)/bootstrap.c $(SW_DIR)/boot_rom.c
+
+# overrides
+CRT_SRCS := $(SW_DIR)/crt0.S
+LINKER_SCRIPT := $(SW_DIR)/rom_link.ld
diff --git a/sw/examples/hello_usbdev/Makefile b/sw/examples/hello_usbdev/Makefile
deleted file mode 100644
index 2814e8d..0000000
--- a/sw/examples/hello_usbdev/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the project
-
-NAME = hello_usbdev
-SRCS = $(NAME).c
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-
-include ${PROGRAM_DIR}/../../exts/common/options.mk
-include ${PROGRAM_DIR}/../../exts/common/common.mk
diff --git a/sw/examples/hello_usbdev/srcs.mk b/sw/examples/hello_usbdev/srcs.mk
new file mode 100644
index 0000000..26811ac
--- /dev/null
+++ b/sw/examples/hello_usbdev/srcs.mk
@@ -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
+
+SW_SRCS += $(SW_DIR)/hello_usbdev.c
diff --git a/sw/examples/hello_world/Makefile b/sw/examples/hello_world/Makefile
deleted file mode 100644
index f947497..0000000
--- a/sw/examples/hello_world/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-NAME = hello_world
-SRCS = hello_world.c
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-
-include ${PROGRAM_DIR}/../../exts/common/options.mk
-include ${PROGRAM_DIR}/../../exts/common/common.mk
diff --git a/sw/examples/hello_world/srcs.mk b/sw/examples/hello_world/srcs.mk
new file mode 100644
index 0000000..4cf4756
--- /dev/null
+++ b/sw/examples/hello_world/srcs.mk
@@ -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
+
+SW_SRCS += $(SW_DIR)/hello_world.c
diff --git a/sw/exts/common/srcs.mk b/sw/exts/common/srcs.mk
new file mode 100644
index 0000000..e50b681
--- /dev/null
+++ b/sw/exts/common/srcs.mk
@@ -0,0 +1,10 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+EXT_COMMON_DIR ?= $(SW_ROOT_DIR)/exts/common
+INCS += -I$(EXT_COMMON_DIR)
+
+EXT_COMMON_LOC_SRCS +=
+
+EXT_SRCS += $(addprefix $(EXT_COMMON_DIR)/, $(EXT_COMMON_LOC_SRCS))
diff --git a/sw/lib/Makefile b/sw/lib/Makefile
deleted file mode 100644
index 5220ca0..0000000
--- a/sw/lib/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-DIF_SRCS = uart.c gpio.c spi_device.c flash_ctrl.c hmac.c usbdev.c rv_timer.c
-EXT_SRCS = usb_controlep.c usb_simpleserial.c irq.c handler.c hw_sha256.c
-EXT_ASMS = irq_vectors.S
-GENHDRS := ${DIF_SRCS:.c=_regs.h}
-GENHDR_BASE := ${DIF_SRCS:.c=}
-ARCH = rv32imc
-# ARCH = rv32im # to disable compressed instructions
-
-RV_TOOLS ?= /tools/riscv/bin
-
-INCS += -I../vendor
-CC := ${RV_TOOLS}/riscv32-unknown-elf-gcc
-CFLAGS ?= -Wall -g -Os -march=$(ARCH) -mabi=ilp32 -static -mcmodel=medany \
- -fvisibility=hidden -nostdlib -nostartfiles $(INCS)
-
-
-ifeq ($(SIM),1)
- CFLAGS += -DSIMULATION
-endif
-
-AR := $(subst gcc,ar,$(wordlist 1,1,$(CC)))
-ARFLAGS := rc
-
-REGTOOL = ../../util/regtool.py
-
-OBJS := ${DIF_SRCS:.c=.o} ${EXT_SRCS:.c=.o} ${EXT_ASMS:.S=.o}
-DEPS = $(OBJS:%.o=%.d)
-
-OUTFILES = libot.a
-
-$(OUTFILES): $(OBJS)
- $(AR) $(ARFLAGS) $@ $(OBJS)
-
-all: $(OUTFILES)
-
-define header_gen
- $1.c: $1_regs.h
-
- $1_regs.h: ../../hw/ip/$1/doc/*.hjson
- if [ -f ../../hw/ip/$1/doc/$1.hjson ]; then \
- $(REGTOOL) -D -o $1_regs.h ../../hw/ip/$1/doc/$1.hjson ; \
- else \
- $(REGTOOL) -D -o $1_regs.h ../../hw/ip/$1/doc/$1_reg.hjson ; \
- fi
-endef
-$(foreach f,$(GENHDR_BASE),$(eval $(call header_gen,$f)))
-
--include $(DEPS)
-
-clean:
- $(RM) *.o *.d $(GENHDRS)
-
-distclean: clean
- $(RM) $(OUTFILES)
diff --git a/sw/lib/srcs.mk b/sw/lib/srcs.mk
new file mode 100644
index 0000000..609e7a8
--- /dev/null
+++ b/sw/lib/srcs.mk
@@ -0,0 +1,9 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+GEN_HEADERS += $(LIB_LOC_DIF_SRCS:.c=_regs.h) chip_info.h
+LIB_LOC_DIF_SRCS += uart.c gpio.c spi_device.c flash_ctrl.c hmac.c usbdev.c rv_timer.c
+LIB_LOC_EXT_SRCS += usb_controlep.c usb_simpleserial.c irq.c handler.c irq_vectors.S
+
+LIB_SRCS += $(addprefix $(LIB_DIR)/, $(LIB_LOC_DIF_SRCS) $(LIB_LOC_EXT_SRCS))
diff --git a/sw/opts.mk b/sw/opts.mk
new file mode 100644
index 0000000..c3eaf0c
--- /dev/null
+++ b/sw/opts.mk
@@ -0,0 +1,78 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+####################################################################################################
+## SW build infrastructure - common opts ##
+## Two types of embedded SW is built typically for a test - boot_rom and sw test application. ##
+## Each has two components - top level sources (indicated with SW_ prefix) and libraries ##
+## (indicated with LIB_ prefix. ##
+## If a new dir with SW or LIB sources are added, a 'srcs.mk' needs to be included and it should ##
+## specify the additional sources either via SW_SRCS or LIB_SRCS variable, See existing examples ##
+## for reference. ##
+####################################################################################################
+
+# sources and targets
+SW_NAME ?= $(notdir $(SW_DIR))
+SW_SRCS := $(CRT_SRCS) $(SW_SRCS)
+SW_OBJS += $(addprefix $(SW_BUILD_DIR)/, $(addsuffix .o, $(basename $(notdir $(SW_SRCS)))))
+SW_PPOS += $(SW_OBJS:.o=.ppo)
+SW_DEPS ?= lib
+SW_BUILD_DIR ?= $(SW_ROOT_DIR)/$(SW_DIR)
+
+LIB_NAME ?= ot
+LIB_DIR ?= $(SW_ROOT_DIR)/lib
+LIB_TARGET ?= $(LIB_BUILD_DIR)/lib${LIB_NAME}.a
+LIB_SRCS +=
+LIB_OBJS += $(addprefix $(LIB_BUILD_DIR)/, $(addsuffix .o, $(basename $(notdir $(LIB_SRCS)))))
+LIB_PPOS += $(LIB_OBJS:.o=.ppo)
+LIB_BUILD_DIR ?= $(SW_BUILD_DIR)/lib
+
+DEPS += $(SW_OBJS:%.o=%.d) $(LIB_OBJS:%.o=%.d)
+INCS += -I$(SW_DIR) -I$(LIB_DIR) -I$(SW_BUILD_DIR) -I$(LIB_BUILD_DIR)
+
+LINK_OPTS += -T $(LINKER_SCRIPT)
+LINK_OPTS += $(SW_OBJS) -L$(LIB_BUILD_DIR) -l$(LIB_NAME)
+LINK_OPTS += -Xlinker -Map=${SW_BUILD_DIR}/${IMG_NAME}.map
+
+# target (either 'boot_rom' or 'sw')
+ifeq ($(SW_NAME),boot_rom)
+ IMG_NAME ?= rom
+else
+ IMG_NAME ?= sw
+endif
+
+IMG_OUTPUTS += $(SW_BUILD_DIR)/$(IMG_NAME).elf \
+ $(SW_BUILD_DIR)/$(IMG_NAME).map \
+ $(SW_BUILD_DIR)/$(IMG_NAME).dis \
+ $(SW_BUILD_DIR)/$(IMG_NAME).bin \
+ $(SW_BUILD_DIR)/$(IMG_NAME).vmem
+GEN_HEADER_OUTPUTS = $(addprefix $(LIB_BUILD_DIR)/, $(GEN_HEADERS))
+
+# defaults
+CRT_SRCS ?= $(EXT_COMMON_DIR)/_crt.c
+LINKER_SCRIPT ?= $(SW_ROOT_DIR)/exts/common/link.ld
+
+# tools and opts
+REGTOOL ?= $(SW_ROOT_DIR)/../util/regtool.py
+INFOTOOL ?= $(SW_ROOT_DIR)/../util/rom_chip_info.py
+
+RV_TOOLS ?= /tools/riscv/bin
+# ARCH = rv32im # to disable compressed instructions
+ARCH = rv32imc
+CC = ${RV_TOOLS}/riscv32-unknown-elf-gcc
+AR = $(subst gcc,ar,$(wordlist 1,1,$(CC)))
+AS = $(subst gcc,as,$(wordlist 1,1,$(CC)))
+LD = $(subst gcc,ld,$(wordlist 1,1,$(CC)))
+OBJCOPY = $(subst gcc,objcopy,$(wordlist 1,1,$(CC)))
+OBJDUMP = $(subst gcc,objdump,$(wordlist 1,1,$(CC)))
+
+CFLAGS += -march=$(ARCH) -mabi=ilp32 -static -mcmodel=medany -Wall -g -Os \
+ -fvisibility=hidden -nostdlib -nostartfiles $(SW_FLAGS)
+ARFLAGS = rc
+
+# conditional flags
+SIM ?= 0
+ifeq ($(SIM),1)
+ CFLAGS += -DSIMULATION
+endif
diff --git a/sw/rules.mk b/sw/rules.mk
new file mode 100644
index 0000000..f1af2d7
--- /dev/null
+++ b/sw/rules.mk
@@ -0,0 +1,133 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+##############################################################
+## Generic rules set for compiling SW for different targets ##
+##############################################################
+
+# rules
+.SECONDEXPANSION:
+ifeq ($(STANDALONE_SW), 1)
+all: gen_dir standalone
+else
+all: gen_dir $(IMG_OUTPUTS)
+endif
+
+gen_dir:
+ mkdir -p ${SW_BUILD_DIR}
+ mkdir -p ${LIB_BUILD_DIR}
+ env > ${SW_BUILD_DIR}/env_vars
+
+standalone: $(SW_DEPS)
+ $(STANDALONE_CMD)
+
+$(LIB_TARGET): $(GEN_HEADER_OUTPUTS) $(LIB_PPOS) $(LIB_OBJS)
+ $(AR) $(ARFLAGS) $@ $(LIB_OBJS)
+
+lib: $(LIB_TARGET)
+
+# Note: this IMG_NAME requires the srecord package to be installed.
+# XXX: This could be replaced by objcopy onc is merged.
+# https://sourceware.org/bugzilla/show_bug.cgi?id=19921
+# XXX: Currently the start address 0x1000 is hardcoded. It could/should be
+# read from the elf file, but is lost in the bin file.
+# Switching to objcopy will resolve that as well.
+%.vmem: %.bin
+ srec_cat $^ -binary -offset 0x0 -byte-swap 4 -o $@ -vmem
+
+%.bin: %.elf
+ $(OBJCOPY) -O binary $^ $@
+
+%.dis: %.elf
+ $(OBJDUMP) -SD $^ > $@
+
+# link & generate elf
+%.elf %.map: $(SW_DEPS) $(SW_PPOS) $(SW_OBJS) $(LINKER_SCRIPT)
+ $(CC) $(CFLAGS) $(LINK_OPTS) -o $@
+
+# compile sw sources
+# TOOD: figure out a way to 'templatise' .o/.ppo ruleset for each dir containing srcs
+
+$(SW_BUILD_DIR)/%.o: $(SW_DIR)/$$*.c
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.o: $(SW_DIR)/$$*.S
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.ppo: $(SW_DIR)/$$*.c
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.ppo: $(SW_DIR)/$$*.S
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.o: $(LIB_DIR)/$$*.c
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.o: $(LIB_DIR)/$$*.S
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.ppo: $(LIB_DIR)/$$*.c
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.ppo: $(LIB_DIR)/$$*.S
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.o: $(EXT_COMMON_DIR)/$$*.c
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.o: $(EXT_COMMON_DIR)/$$*.S
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.ppo: $(EXT_COMMON_DIR)/$$*.c
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(SW_BUILD_DIR)/%.ppo: $(EXT_COMMON_DIR)/$$*.S
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+# compile lib sources
+$(LIB_BUILD_DIR)/%.o: $(LIB_DIR)/$$*.c
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.o: $(LIB_DIR)/$$*.S
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.ppo: $(LIB_DIR)/$$*.c
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.ppo: $(LIB_DIR)/$$*.S
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.o: $(EXT_COMMON_DIR)/$$*.c
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.o: $(EXT_COMMON_DIR)/$$*.S
+ $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.ppo: $(EXT_COMMON_DIR)/$$*.c
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+$(LIB_BUILD_DIR)/%.ppo: $(EXT_COMMON_DIR)/$$*.S
+ $(CC) $(CFLAGS) -E -MMD -c $(INCS) -o $@ $<
+
+# regtool
+$(LIB_BUILD_DIR)/%_regs.h: $(SW_ROOT_DIR)/../hw/ip/$$*/doc/$$*.hjson
+ $(REGTOOL) -D -o $@ $<
+
+$(LIB_BUILD_DIR)/%_regs.h: $(SW_ROOT_DIR)/../hw/ip/$$*/doc/$$*_regs.hjson
+ $(REGTOOL) -D -o $@ $<
+
+# chip_info
+$(LIB_BUILD_DIR)/chip_info.h: $(INFOTOOL)
+ $(INFOTOOL) -o $(LIB_BUILD_DIR)
+
+-include $(DEPS)
+
+# clean sources
+clean:
+ -$(RM) -r $(LIB_OBJS) $(LIB_PPOS) $(SW_OBJS) $(SW_PPOS) $(DEPS) \
+ $(GEN_HEADER_OUTPUTS) $(IMG_OUTPUTS) $(LIB_TARGET) ${SW_BUILD_DIR}/env_vars
+
+distclean: clean
+
+.PHONY: gen_dir lib clean distclean standalone
diff --git a/sw/tests/flash_ctrl/Makefile b/sw/tests/flash_ctrl/Makefile
deleted file mode 100644
index 6f595dd..0000000
--- a/sw/tests/flash_ctrl/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-NAME = flash_test
-SRCS = flash_test.c
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-
-include ${PROGRAM_DIR}/../../exts/common/options.mk
-include ${PROGRAM_DIR}/../../exts/common/common.mk
diff --git a/sw/tests/flash_ctrl/srcs.mk b/sw/tests/flash_ctrl/srcs.mk
new file mode 100644
index 0000000..c1be2b8
--- /dev/null
+++ b/sw/tests/flash_ctrl/srcs.mk
@@ -0,0 +1,10 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+SW_NAME ?= flash_test
+
+# list srcs for each test
+ifeq ($(SW_NAME), flash_test)
+ SW_SRCS += $(SW_DIR)/flash_test.c
+endif
diff --git a/sw/tests/hmac/Makefile b/sw/tests/hmac/Makefile
deleted file mode 100644
index 61f3e40..0000000
--- a/sw/tests/hmac/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-NAME = sha256_test
-SRCS = sha256_test.c
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-
-include ${PROGRAM_DIR}/../../exts/common/options.mk
-include ${PROGRAM_DIR}/../../exts/common/common.mk
diff --git a/sw/tests/hmac/srcs.mk b/sw/tests/hmac/srcs.mk
new file mode 100644
index 0000000..3e62103
--- /dev/null
+++ b/sw/tests/hmac/srcs.mk
@@ -0,0 +1,12 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+SW_NAME ?= sha256_test
+INCS += -I$(SW_ROOT_DIR)/vendor
+
+# list srcs for each test
+ifeq ($(SW_NAME), sha256_test)
+ SW_SRCS += $(SW_DIR)/sha256_test.c
+ SW_SRCS += $(LIB_DIR)/hw_sha256.c
+endif
diff --git a/sw/tests/rv_timer/Makefile b/sw/tests/rv_timer/Makefile
deleted file mode 100644
index 22e926c..0000000
--- a/sw/tests/rv_timer/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-#
-# Generate a baremetal application for the microcontroller
-
-NAME = rv_timer_test
-SRCS = rv_timer_test.c
-PROGRAM_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-
-include ${PROGRAM_DIR}/../../exts/common/options.mk
-include ${PROGRAM_DIR}/../../exts/common/common.mk
diff --git a/sw/tests/rv_timer/srcs.mk b/sw/tests/rv_timer/srcs.mk
new file mode 100644
index 0000000..fb7651c
--- /dev/null
+++ b/sw/tests/rv_timer/srcs.mk
@@ -0,0 +1,10 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+SW_NAME ?= rv_timer_test
+
+# list srcs for each test
+ifeq ($(SW_NAME), rv_timer_test)
+ SW_SRCS += $(SW_DIR)/rv_timer_test.c
+endif