/*******************************************************************************
 * Copyright (C) 2017, 2018 MINRES Technologies GmbH
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************/
 <% 
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getOriginalName(reg){
    if( reg.original instanceof RegisterFile) {
    	if( reg.index != null ) {
        	return reg.original.name+generator.generateHostCode(reg.index)
        } else {
        	return reg.original.name
        }
    } else if(reg.original instanceof Register){
        return reg.original.name
    }
}
def getRegisterNames(){
	def regNames = []
 	allRegs.each { reg -> 
		if( reg instanceof RegisterFile) {
			(reg.range.right..reg.range.left).each{
    			regNames+=reg.name.toLowerCase()+it
            }
        } else if(reg instanceof Register){
    		regNames+=reg.name.toLowerCase()
        }
    }
    return regNames
}
def getRegisterAliasNames(){
	def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
 	return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
		if( reg instanceof RegisterFile) {
			return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
        } else if(reg instanceof Register){
    		regMap[reg.name]?:reg.name.toLowerCase()
        }
 	}.flatten()
}
%>
#include "util/ities.h"
#include <util/logging.h>

#include <elfio/elfio.hpp>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <ihex.h>
#ifdef __cplusplus
}
#endif
#include <cstdio>
#include <cstring>
#include <fstream>

using namespace iss::arch;

constexpr std::array<const char*, ${getRegisterNames().size}>    iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${getRegisterAliasNames().size}>    iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;

${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
    reg.icount = 0;
}

${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;

void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
    for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
    reg.PC=address;
    reg.NEXT_PC=reg.PC;
    reg.trap_state=0;
    reg.machine_state=0x0;
    reg.icount=0;
}

uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
	return reinterpret_cast<uint8_t*>(&reg);
}

${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
    return phys_addr_t(pc); // change logical address to physical address
}

