2014/07/19

Hex-FileをVHDL-Fileへ変換


概要

VHDLにてSoftCPUの設計をした際に、Hex-FileのProgramをROM(FPGA-Block-RAM利用)に変換するツールです。


プログラム

またRubyで作りました。
file : hex2vhdl.rb
#!/usr/bin/ruby
# Create: 2014/04/10 16:30 kawasan
# UpDate: 2014/04/10 16:30 kawasan
# 
# Hex-fileをVHDL-fileに変換 (XilinxのBlockRAM割り当てされる形式)

require 'date'

# 取り合えず64KWord迄で設計してみる
DATA_SIZE =  ( 1024 * 64 * 2 )

# データ値をBIN-code文字列に変換
def i2strbin( dat, dsize )
  if dsize > 16
    puts( "Error : i2strbin : Non support dsize!" )
  end

  hoge = sprintf( "000000000000000%s", dat.to_s(2) )

  return hoge[hoge.size - dsize, dsize]
end

if ARGV.size < 4
  puts( "Usage : hex2vhdl.rb filename modulename asize dsize" )
  puts( "Hex-file to VHDL-file converter (ver 0.1)" )
  puts( "ex.")
  puts( "    Hex-file = test.hex" )
  puts( "    Module-name = PROM" )
  puts( "    Address-Bus Width = 13bit" )
  puts( "    Data-Bus Width = 16bit" )
  puts( "    hex2vhdl.rb test.hex PROM 13 16" )
  exit
end

fname_source = ARGV[0]
fname_dest = ARGV[1]
asize = ARGV[2].to_i
dsize = ARGV[3].to_i

# Clear buffer
bin = [0]
for cnt in 0..DATA_SIZE-1
  bin[cnt] = 0xff
end

source = open( fname_source )
segment = 0
add_end = 0
lcnt = 0
while line = source.gets
  cnt = 0;

  # 検査 レコード・マーク
  if line[cnt] != ':'
    printf( "%d:Code error!\n", lcnt )
    exit
  end

  # Get レコード長
  cnt += 1
  ln = line[cnt,2].hex

  # Get ロード・アドレス
  cnt += 2
  add = line[cnt,4].hex

  # Get レコード・タイプ
  cnt += 4
  type = line[cnt,2].hex

  # Get データ列
  dat = [0]
  cnt2 = 0;
  while ln > cnt2
    cnt += 2;
    dat[ cnt2 ] = line[cnt,2].hex
    cnt2 += 1
  end

  case type
  when 0x00
    cnt2 = 0
    while ln > cnt2
       add_tmp = ( segment << 16 ) + add
       bin[ add_tmp ] = dat[ cnt2 ]
       cnt2 += 1
       add += 1

       if add_end < add_tmp
         add_end = add_tmp
       end
    end
  when 0x01
    break
  when 0x02
    # Get 拡張アドレス
    segment = dat[0,2].hex
  when 0x03
    # Get スタート・アドレス
    segment = dat[0,2].hex
    # 今のところはスタート処理はしません
  else
    printf( "Type error!\n" )
  end

  lcnt += 1
end
source.close

# --- Write -------------------------
dest = open( fname_dest + ".vhd", "wb" )

day = Time.now
dest.printf( "-- hex2vhdl (kawasan) %s --\n\n", day.strftime("%Y/%m/%d") )
dest.puts( "library IEEE;" )
dest.puts( "use IEEE.std_logic_1164.all;" )
dest.puts( "use IEEE.std_logic_unsigned.all;" )
dest.puts( "use IEEE.std_logic_arith.all;\n\n" )
dest.puts( "entity PROM is" )
dest.puts( "\tport(" )
dest.puts( "\t\tCLK\t: in std_logic;" )
dest.printf( "\t\tADD\t: in std_logic_vector(%d downto 0);\n", asize - 1 )
dest.printf( "\t\tDO\t: out std_logic_vector(%d downto 0)\n", dsize - 1 )
dest.puts( "\t);" )
dest.puts( "end PROM;\n\n" )
dest.puts( "architecture rtl of PROM is" )
dest.puts( "\tsignal WR\t: std_logic := '0';" )
dest.printf( "\tsignal DI\t: std_logic_vector(%d downto 0) := \"%s\";\n", dsize - 1, i2strbin( 0, dsize ) )
dest.printf( "\tsignal ADDR_REG : std_logic_vector(%d downto 0);\n", asize - 1 )
dest.printf( "\ttype rom_type is array (0 to %d) of std_logic_vector (%d downto 0);\n", add_end >> 1, dsize - 1 )
dest.puts( "\tsignal ROM : rom_type := (" );


if dsize <= 8
  add_end = add_end - 1
elsif dsize <= 16
  add_end = add_end >> 1
else
  puts( "Error : Non support dsize!" )
  exit
end

delm = ","
for add in 0..add_end
  if dsize <= 8
    dat = bin[add]
  else
    dat = bin[add * 2] + 0x100 * bin[add * 2 + 1]
  end

  if add >= add_end
    delm = "";
  end

  dest.printf( "\t\"%s\"%s\t-- %04x\n", i2strbin( dat, dsize ), delm, add )
end

dest.puts( "\t);" )
dest.puts( "begin" )
dest.puts( "\tprocess (CLK)" )
dest.puts( "\tbegin" )
dest.puts( "\t\tif (CLK'event and CLK = '1') then" )
dest.puts( "\t\t\tif (WR = '1') then" )
dest.puts( "\t\t\t\tROM(CONV_INTEGER(ADD)) <= DI;" )
dest.puts( "\t\t\tend if;" )
dest.puts( "\t\t\tADDR_REG <= ADD;" )
dest.puts( "\t\tend if;" )
dest.puts( "\tend process;" )
dest.puts( "\tDO <= ROM(CONV_INTEGER(ADDR_REG));" )
dest.puts( "end;" )
dest.close


実行結果

$ hex2vhdl.rb top.hex PROM 13 16
$ head top.hex 
:100000000C9481000C94A3000C94A3000C94A30006
:100010000C94A3000C94A3000C94A3000C94A300D4
:100020000C94A3000C94A3000C94A3000C94A300C4
:100030000C94A3000C94A3000C94A3000C94A300B4
:100040000C94A3000C94A3000C94A3000C94A300A4
:100050000C94A3000C94A3000C94A3000C94A30094
:100060002D465047412D00547565204A756C20205F
:10007000362030383A33303A3031203230313000A7
:10008000352E32366130322000456D63732D524D6E
:10009000495820202020202020002D4669726D77AD
$ head -40 PROM.vhd 
-- hex2vhdl (kawasan) 2014/07/19 --

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity PROM is
        port(
                CLK: in std_logic;
                ADD: in std_logic_vector(12 downto 0);
                DO: out std_logic_vector(15 downto 0)
        );
end PROM;

architecture rtl of PROM is
        signal WR: std_logic := '0';
        signal DI: std_logic_vector(15 downto 0) := "0000000000000000";
        signal ADDR_REG : std_logic_vector(12 downto 0);
        type rom_type is array (0 to 3959) of std_logic_vector (15 downto 0);
        signal ROM : rom_type := (
        "1001010000001100",-- 0000
        "0000000010000001",-- 0001
        "1001010000001100",-- 0002
        "0000000010100011",-- 0003
        "1001010000001100",-- 0004
        "0000000010100011",-- 0005
        "1001010000001100",-- 0006
        "0000000010100011",-- 0007
        "1001010000001100",-- 0008
        "0000000010100011",-- 0009
        "1001010000001100",-- 000a
        "0000000010100011",-- 000b
        "1001010000001100",-- 000c
        "0000000010100011",-- 000d
        "1001010000001100",-- 000e
        "0000000010100011",-- 000f
        "1001010000001100",-- 0010
        "0000000010100011",-- 0011
        "1001010000001100",-- 0012
$ tail top.hex 
:101E60000A0F163111F0812FF7CF87E06091EE0352
:101E700040E126E00E94D20E0E94AA0E90E01F913F
:101E80000F9108950F931F93882311F400E001C070
:101E900003E080E1182F1F5F602F0E940A0F1631A8
:101EA00011F0812FF7CF87E06091EF0340E126E04A
:101EB0000E94D20E0E94AA0E90E01F910F910895E9
:101EC000E62FF72FA82FB92F03C0C89531960D9292
:101ED00041505040D0F70895E62FF72FA82FB92F83
:101EE000C89531960D920020D9F70895F894FFCF48
:00000001FF
$ tail -20 PROM.vhd 
        "1001011000110001",-- 0f71
        "1001001000001101",-- 0f72
        "0010000000000000",-- 0f73
        "1111011111011001",-- 0f74
        "1001010100001000",-- 0f75
        "1001010011111000",-- 0f76
        "1100111111111111"-- 0f77
        );
begin
        process (CLK)
        begin
                if (CLK'event and CLK = '1') then
                        if (WR = '1') then
                                ROM(CONV_INTEGER(ADD)) <= DI;
                        end if;
                        ADDR_REG <= ADD;
                end if;
        end process;
        DO <= ROM(CONV_INTEGER(ADDR_REG));
end;