summaryrefslogtreecommitdiffstats
path: root/hdl/rom.py
diff options
context:
space:
mode:
Diffstat (limited to 'hdl/rom.py')
-rw-r--r--hdl/rom.py81
1 files changed, 81 insertions, 0 deletions
diff --git a/hdl/rom.py b/hdl/rom.py
new file mode 100644
index 0000000..d370e7d
--- /dev/null
+++ b/hdl/rom.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+"""
+Convert an Intel HEX file to a Verilog ROM module using Amaranth.
+Usage:
+ python3 hex2rom_amaranth.py program.hex > prog_rom.v
+Produces a module 'prog_rom' with:
+ input clk, input [12:0] addr, output [13:0] data
+Depth defaults to 4096 (8192/2).
+"""
+import sys
+import argparse
+from amaranth import *
+from amaranth.back import verilog
+
+DEPTH = 8192 // 2
+DATA_WIDTH = 14
+ADDR_WIDTH = 13 # external addr width
+
+def parse_ihex(path):
+ words = [0] * DEPTH
+ with open(path) as f:
+ for line in f:
+ line = line.strip()
+ if not line.startswith(':'):
+ continue
+ byte_count = int(line[1:3], 16)
+ address = int(line[3:7], 16)
+ record_type = int(line[7:9], 16)
+ if record_type != 0:
+ continue
+ data = bytes.fromhex(line[9:9 + byte_count * 2])
+ for i in range(0, len(data) - 1, 2):
+ word_addr = (address + i) // 2
+ if 0 <= word_addr < DEPTH:
+ words[word_addr] = (data[i] | (data[i+1] << 8)) & ((1 << DATA_WIDTH) - 1)
+ return words
+
+def make_rom_module(words):
+ m = Module()
+
+ clk = Signal()
+ addr = Signal(ADDR_WIDTH)
+ data = Signal(DATA_WIDTH)
+
+ mem = Memory(width=DATA_WIDTH, depth=DEPTH, init=words)
+ rd = mem.read_port(transparent=False)
+ m.submodules += rd
+
+ m.d.comb += [
+ rd.addr.eq(addr),
+ data.eq(rd.data)
+ ]
+
+ return m, clk, addr, data
+
+def render_verilog(words, module_name="prog_rom"):
+ m, clk, addr, data = make_rom_module(words)
+ v = verilog.convert(m, ports=[clk, addr, data], name=module_name)
+ return v.replace("(* top = 1 *)\n", "(* top = 0 *)\n")
+
+class ComponentWrapper(Elaboratable):
+ def __init__(self, module_obj, ports, name="prog_rom"):
+ self._module = module_obj
+ self._ports = ports
+ self._name = name
+
+ def elaborate(self, platform=None):
+ return self._module
+
+ def name(self):
+ return self._name
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('hexfile')
+ parser.add_argument('--module-name', default='prog_rom')
+ args = parser.parse_args()
+
+ words = parse_ihex(args.hexfile)
+ v = render_verilog(words, module_name=args.module_name)
+ sys.stdout.write(v)