#!/usr/bin/env python3

from string import Template
import argparse
import os.path
import sys
import binascii


parser = argparse.ArgumentParser(description='Convert binary file to verilog rom')
parser.add_argument('filename', metavar='filename', nargs=1,
                   help='filename of input binary')

args = parser.parse_args()
file = args.filename[0];

# check that file exists
if not os.path.isfile(file):
    print("File {} does not exist.".format(filename))
    sys.exit(1)

filename = os.path.splitext(file)[0]

license = """\
/* Copyright 2018 ETH Zurich and University of Bologna.
 * Copyright and related rights are licensed under the Solderpad Hardware
 * License, Version 0.51 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
 * or agreed to in writing, software, hardware and materials distributed under
 * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * File: $filename.v
 *
 * Description: Auto-generated bootrom
 */

// Auto-generated code
"""

module = """\
module $filename (
   input  logic         clk_i,
   input  logic         req_i,
   input  logic [63:0]  addr_i,
   output logic [63:0]  rdata_o
);
    localparam int RomSize = $size;

    const logic [RomSize-1:0][63:0] mem = {
$content
    };

    logic [$$clog2(RomSize)-1:0] addr_q;

    always_ff @(posedge clk_i) begin
        if (req_i) begin
            addr_q <= addr_i[$$clog2(RomSize)-1+3:3];
        end
    end

    // this prevents spurious Xes from propagating into
    // the speculative fetch stage of the core
    assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0;
endmodule
"""

c_var = """\
// Auto-generated code

const int reset_vec_size = $size;

uint32_t reset_vec[reset_vec_size] = {
$content
};
"""

def read_bin():

    numlines=0
    with open(filename + ".img", 'rb') as f:
        rom = binascii.hexlify(f.read())
        #rom = map(''.join, zip(rom[::2], rom[1::2]))
        zipped = zip(rom[::2], rom[1::2])
        #print(zipped)
        numlines = numlines+1


    #print (numlines)
    print (rom)
    print (len(rom))
    # align to 64 bit
    #mylist = list(rom)
    #align = (int((len(rom) + 7) / 8 )) * 8

    for i in range(len(list(rom)), align):
        rom.append("00")

    return rom

rom = read_bin()

""" Generate C header file for simulator
"""
with open(filename + ".h", "w") as f:
    rom_str = ""
    # process in junks of 32 bit (4 byte)
    for i in range(0, int(len(rom)/4)):
        rom_str += "    0x" + "".join(rom[i*4:i*4+4][::-1]) + ",\n"

    # remove the trailing comma
    rom_str = rom_str[:-2]

    s = Template(c_var)
    f.write(s.substitute(filename=filename, size=int(len(rom)/4), content=rom_str))

    f.close()

""" Generate SystemVerilog bootcode for FPGA and ASIC
"""
with open(filename + ".sv", "w") as f:
    rom_str = ""
    # process in junks of 64 bit (8 byte)
    for i in reversed(range(int(len(rom)/8))):
        rom_str += "        64'h" + "".join(rom[i*8+4:i*8+8][::-1]) + "_" + "".join(rom[i*8:i*8+4][::-1]) + ",\n"

    # remove the trailing comma
    rom_str = rom_str[:-2]

    f.write(license)
    s = Template(module)
    f.write(s.substitute(filename=filename, size=int(len(rom)/8), content=rom_str))

