// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    drccache.h

    Universal dynamic recompiler cache management.

***************************************************************************/

#pragma once

#ifndef __DRCCACHE_H__
#define __DRCCACHE_H__



//**************************************************************************
//  MACROS
//**************************************************************************

// ensure that a given pointer is within the cache boundaries
#define assert_in_cache(c,p)        assert((c).contains_pointer(p))
#define assert_in_near_cache(c,p)   assert((c).contains_near_pointer(p))



//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// generic code pointer
typedef uint8_t *drccodeptr;


// helper template for oob codegen
typedef delegate<void (drccodeptr *, void *, void *)> drc_oob_delegate;


// drc_cache
class drc_cache
{
public:
	// construction/destruction
	drc_cache(size_t bytes);
	~drc_cache();

	// getters
	drccodeptr near() const { return m_near; }
	drccodeptr base() const { return m_base; }
	drccodeptr top() const { return m_top; }

	// pointer checking
	bool contains_pointer(const void *ptr) const { return ((const drccodeptr)ptr >= m_near && (const drccodeptr)ptr < m_near + m_size); }
	bool contains_near_pointer(const void *ptr) const { return ((const drccodeptr)ptr >= m_near && (const drccodeptr)ptr < m_neartop); }
	bool generating_code() const { return (m_codegen != nullptr); }

	// memory management
	void flush();
	void *alloc(size_t bytes);
	void *alloc_near(size_t bytes);
	void *alloc_temporary(size_t bytes);
	void dealloc(void *memory, size_t bytes);

	// codegen helpers
	drccodeptr *begin_codegen(uint32_t reserve_bytes);
	drccodeptr end_codegen();
	void request_oob_codegen(drc_oob_delegate callback, void *param1 = nullptr, void *param2 = nullptr);

private:
	// largest block of code that can be generated at once
	static const size_t CODEGEN_MAX_BYTES = 131072;

	// minimum alignment, in bytes (must be power of 2)
	static const size_t CACHE_ALIGNMENT = alignof(std::max_align_t);

	// largest permanent allocation we allow
	static const size_t MAX_PERMANENT_ALLOC = 1024;

	// size of "near" area at the base of the cache
	static const size_t NEAR_CACHE_SIZE = 131072;

	// core parameters
	drccodeptr          m_near;             // pointer to the near part of the cache
	drccodeptr          m_neartop;          // top of the near part of the cache
	drccodeptr          m_base;             // base pointer to the compiler cache
	drccodeptr          m_top;              // current top of cache
	drccodeptr          m_end;              // end of cache memory
	drccodeptr          m_codegen;          // start of generated code
	size_t              m_size;             // size of the cache in bytes

	// oob management
	struct oob_handler
	{
		oob_handler *next() const { return m_next; }

		oob_handler *   m_next;             // next handler
		drc_oob_delegate m_callback;        // callback function
		void *          m_param1;           // 1st pointer parameter
		void *          m_param2;           // 2nd pointer parameter
	};
	simple_list<oob_handler> m_ooblist;     // list of oob handlers

	// free lists
	struct free_link
	{
		free_link *         m_next;         // pointer to the next guy
	};
	free_link *         m_free[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
	free_link *         m_nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
};


#endif /* __DRCCACHE_H__ */
