diff --git a/firmware/Makefile b/firmware/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fc269b78f888a42c1e3a31597e9253f25e9bf88d
--- /dev/null
+++ b/firmware/Makefile
@@ -0,0 +1,54 @@
+RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX ?= /opt/riscv
+PYTHON = python3
+GCC_WARNS  = -Werror -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings
+GCC_WARNS += -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic # -Wconversion
+TOOLCHAIN_PREFIX = $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)/bin/riscv32-unknown-elf-
+COMPRESSED_ISA = C
+
+FIRMWARE_OBJS= \
+start.o \
+main.o \
+print.o
+
+FIRMWARE_FILES= \
+start.s \
+atoi.c \
+itoa.c \
+firmware.c \
+io.c \
+rnn.c \
+strchr.c \
+strcmp.c \
+strcpy.c \
+strlen.c \
+strncmp.c \
+strncpy.c \
+strnlen.c \
+strrchr.c \
+strstr.c \
+memchr.c \
+memcmp.c \
+memcpy.c \
+memmove.c \
+memset.c \
+isdigit.c
+
+FIRMWARE_CFLAGS=
+FIRMWARE_CFLAGS+=-mabi=ilp32 -march=rv32imc
+FIRMWARE_CFLAGS+=-Wl,--build-id=none,-Bstatic,-T,sections.lds,--strip-debug
+FIRMWARE_CFLAGS+=-ffreestanding -nostdlib
+FIRMWARE_CFLAGS+=-Iinclude
+
+all: firmware.hex
+
+firmware.hex: firmware.bin
+	$(TOOLCHAIN_PREFIX)objcopy -O verilog firmware.elf firmware.hex
+
+firmware.bin: firmware.elf
+	$(TOOLCHAIN_PREFIX)objcopy -O binary $< $@
+
+firmware.elf: sections.lds $(FIRMWARE_FILES)
+	$(TOOLCHAIN_PREFIX)gcc $(CFLAGS) $(FIRMWARE_CFLAGS) -o $@ $(FIRMWARE_FILES)
+
+clean:
+	rm -f *.elf *.hex *.bin *.o *.map