summaryrefslogtreecommitdiffstats
path: root/hex2rom.py
blob: 291a702f8f0a024c8a02150a20e5681a14402089 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/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('    clk  : in  std_logic;')
    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('  signal 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('  attribute ram_style : string;')
    lines.append('  attribute ram_style of rom : signal is "block";')
    lines.append('begin')
    lines.append('  process(clk)')
    lines.append('  begin')
    lines.append('    if rising_edge(clk) then')
    lines.append('      data <= rom(to_integer(unsigned(addr(9 downto 0))));')
    lines.append('    end if;')
    lines.append('  end process;')
    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='')