/*	Copyright  (c)	Günter Woigk 2018 - 2020
					mailto:kio@little-bat.de

	This file is free software.

	Permission to use, copy, modify, distribute, and sell this software
	and its documentation for any purpose is hereby granted without fee,
	provided that the above copyright notice appears in all copies and
	that both that copyright notice, this permission notice and the
	following disclaimer appear in supporting documentation.

	THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY,
	NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
	A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE COPYRIGHT HOLDER
	BE LIABLE FOR ANY DAMAGES ARISING FROM THE USE OF THIS SOFTWARE,
	TO THE EXTENT PERMITTED BY APPLICABLE LAW.
*/

#include "kio/kio.h"
#include "Templates/Array.h"
#include "vcc/Type.h"
#include "utilities.h"
#include "TargetDescr.h"
#include <cmath>
#include "vcx/Assembler.h"
#include "vcx/Linker.h"
#include "vcx/TargetVcx.h"
#include "z80/TargetZ80.h"
#include "z80/TargetVss.h"
#include "i386/TargetI386.h"
#include "k1/TargetK1.h"
#include "ppc/TargetPPC.h"
#include "m68k/TargetM68k.h"


// planned / supported backends:
#define VCX   TargetVcx::IDF
#define Z80   TargetZ80::IDF
#define I386  TargetI386::IDF
#define AMD64 TargetAMD64::IDF
#define PPC   TargetPPC::IDF
#define M68K  TargetM68k::IDF
#define VSS   TargetVss::IDF
#define K1    TargetK1::IDF
#define K1EE  TargetK1EE::IDF
#define K1MC  TargetK1MC::IDF


namespace vcc
{

const cstr backends = usingstr("%s, %s", VCX, Z80);

TargetDescr target {TargetVcx{}};


// dummy handler for not implemented backends:
__attribute__((noreturn))
void throw_todo (cstr, cstr) throws { TODO(); }


// Proprietary floats:
class FloatSoft32Type : public BasicType
{	public:
	FloatSoft32Type() :
		BasicType(Type::FLOAT, "float32", 32,	// TODO: preliminary filled with IEEE float values!
		float128(3.402823466e+38),
		float128(1.175494351e-38),
		24,			// 24	 num digits for mantissa
		-125,		// -125	 min. exponent for mantissa in range 0.5 ≤ mant < 1.0
		+128,		// +128	 max. exponent for mantissa in range 0.5 ≤ mant < 1.0
		yes){}		// yes	 denormalizes before tiny values are rounded to zero?
};
class FloatK1Type : public BasicType
{	public:
	FloatK1Type() :
		BasicType(Type::FLOAT, "float48", 48,	// TODO: preliminary values!
		float128(ldexpl(0xFFFFFFFE,0x3FFF)),
		float128(ldexp(-0xFFFFFFFE,0x4000)),
		32,			// num digits for mantissa
		-0x4000-32,	// min. exponent for mantissa in range 0.5 ≤ mant < 1.0
		+0x3FFF+32,	// max. exponent for mantissa in range 0.5 ≤ mant < 1.0
		no){}		// denormalizes before tiny values are rounded to zero?
};

static const FloatK1Type float_K1;
const BasicType*const tfloat_K1 = &float_K1;

const FloatSoft32Type float_soft32;
const BasicType*const tfloat_soft32 = &float_soft32;


// helper:
static constexpr uint16 ss (uint n) { return n==4 ? 2 : n==8 ? 3 : n==16 ? 4 : 0; }
static inline cBasicType* intForBits  (uint b) { return b==8?tint8 : b==16?tint16 : b==32?tint32 : tint64; }
static inline cBasicType* uintForBits (uint b) { return b==8?tuint8 : b==16?tuint16 : b==32?tuint32 : tuint64; }


TargetDescr::TargetDescr (
		cstr name, cstr descr,
		void(*assemble)(cstr,cstr),
		void (*link)(cstr,cstr),
		ByteOrder byteorder,
		uint bpp, uint bpc,
		uint bpb, uint bps, uint bpi, uint bpl,
		cBasicType* tsfloat, cBasicType* tfloat, cBasicType* tlfloat )
:
	name(name),
	descr(descr),

	byteorder(byteorder),
	b2b(ss(bpb)),	// num_bits <-> num_bytes shift
	bpb(bpb),
	bpc(bpc),
	bps(bps),
	bpi(bpi),
	bpl(bpl),
	bpf(tfloat?tfloat->bits:0),
	bpsf(tsfloat?tsfloat->bits:0),
	bplf(tlfloat?tlfloat->bits:0),
	bpp(bpp),

	_tfloat  (tfloat),
	_tsfloat (tsfloat),
	_tlfloat (tlfloat),

	assemble(assemble),
	link(link)
{}


TargetDescr* setTarget (cstr name)
{
	// setup cpu:

	if (!name || !*name) name = TargetVcx::IDF; // == this computer

	if      (eq(name,target.name))      {}
	else if (eq(name,TargetVcx::IDF))   new(&target) TargetVcx ;
	else if (eq(name,TargetZ80::IDF))   new(&target) TargetZ80 ;
	else if (eq(name,TargetVss::IDF))   new(&target) TargetVss ;
	else if (eq(name,TargetI386::IDF))  new(&target) TargetI386;
	else if (eq(name,TargetAMD64::IDF)) new(&target) TargetAMD64;
	else if (eq(name,TargetK1::IDF))    new(&target) TargetK1  ;
	else if (eq(name,TargetK1EE::IDF))  new(&target) TargetK1EE;
	else if (eq(name,TargetK1MC::IDF))  new(&target) TargetK1MC;
	else if (eq(name,TargetPPC::IDF))   new(&target) TargetPPC ;
	else if (eq(name,TargetM68k::IDF))  new(&target) TargetM68k;
	else throw AnyError("unknown target: %s", name);

	tfloat  = target._tfloat;
	tsfloat = target._tsfloat;
	tlfloat = target._tlfloat;

	tbyte  = intForBits(target.bpb);
	tshort = intForBits(target.bps);
	tint   = intForBits(target.bpi);
	tlong  = intForBits(target.bpl);

	tubyte  = uintForBits(target.bpb);
	tushort = uintForBits(target.bps);
	tuint   = uintForBits(target.bpi);
	tulong  = uintForBits(target.bpl);

	delete tbool;
	delete tchar;
	delete tcstr;
	tbool = new EnumType(tubyte,"bool");
	tchar = new EnumType(target.bpc==8?tuint8:target.bpc==16?tuint16:tuint32,"char");
	tcstr = new ArrayType(tchar);

	return &target;
}


} // namespace
































