#!/usr/bin/env python3 """Convert a SDCC/gputils Intel HEX file to a prog_rom.vhd constant. Usage: python3 hex2rom.py program.hex > PIC/prog_rom.vhd python3 hex2rom.py blink.hex > PIC/prog_rom.vhd """ import sys import argparse DEPTH = 1024 INST_BITS = 14 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]) # PIC16: two bytes per 14-bit word, little-endian, address in bytes for i in range(0, len(data) - 1, 2): word_addr = (address + i) // 2 if word_addr < DEPTH: words[word_addr] = (data[i] | (data[i+1] << 8)) & 0x3FFF return words def render(words): lines = [] lines.append('library ieee;') lines.append('use ieee.std_logic_1164.all;') lines.append('use ieee.numeric_std.all;') lines.append('') lines.append('entity prog_rom is') lines.append(' generic (') lines.append(f' DEPTH : positive := {DEPTH}') lines.append(' );') lines.append(' port (') lines.append(' addr : in std_logic_vector(12 downto 0);') lines.append(' data : out std_logic_vector(13 downto 0)') lines.append(' );') lines.append('end entity prog_rom;') lines.append('') lines.append('architecture rtl of prog_rom is') lines.append(f' type rom_t is array (0 to {DEPTH} - 1) of std_logic_vector(13 downto 0);') lines.append(' constant rom : rom_t := (') for i, w in enumerate(words): bits = format(w, f'014b') sep = ',' if i < DEPTH - 1 else ' ' lines.append(f' {i:4d} => "{bits}"{sep}') lines.append(' );') lines.append('begin') lines.append(' data <= rom(to_integer(unsigned(addr(9 downto 0))));') lines.append('end architecture rtl;') return '\n'.join(lines) + '\n' if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('hexfile') args = parser.parse_args() words = parse_ihex(args.hexfile) print(render(words), end='')