BizHawk/yabause/src/psp/rtl.h

315 lines
12 KiB
C

/* src/psp/rtl.h: Declarations for register transfer language used in
dynamic translation
Copyright 2009 Andrew Church
This file is part of Yabause.
Yabause is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Yabause is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yabause; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RTL_H
#define RTL_H
/*************************************************************************/
/**
* RTLBlock: State information used in translating a block of code.
* Opaque to callers.
*/
typedef struct RTLBlock_ RTLBlock;
/*-----------------------------------------------------------------------*/
/**
* RTLOpcode: Enumeration of operations, used as the value of the
* RTLInsn.op field.
*/
typedef enum RTLOpcode_ {
/* Zero is invalid */
/* No operation */
RTLOP_NOP = 1, // [No operation -- note that a value can be given
// in src1 for debugging purposes]
/* Register-register operations */
RTLOP_MOVE, // dest = src1
RTLOP_SELECT, // dest = other ? src1 : src2
RTLOP_ADD, // dest = src1 + src2
RTLOP_SUB, // dest = src1 - src2
RTLOP_MULU, // (uint64_t){other,dest} =
// (unsigned)src1 * (unsigned)src2
// [upper 32 bits of result stored in "other",
// lower 32 bits of result stored in "dest";
// either dest or other may be zero = omitted]
RTLOP_MULS, // (int64_t){other,dest} = (signed)src1 * (signed)src2
// [either dest or other may be zero = omitted]
RTLOP_MADDU, // (uint64_t){other,dest} +=
// (unsigned)src1 * (unsigned)src2
// [other/dest are both inputs and outputs; for
// optimal performance, they should be the same
// registers used as outputs of a MULU/MULS or
// previous MADDU/MADDS insn]
RTLOP_MADDS, // (int64_t){other,dest} += (signed)src1 * (signed)src2
RTLOP_DIVMODU, // dest = (unsigned)src1 / (unsigned)src2;
// other = (unsigned)src1 % (unsigned)src2
// [both undefined if src2 == 0]
// [either dest or other may be zero = omitted]
RTLOP_DIVMODS, // dest = (signed)src1 / (signed)src2;
// other = (signed)src1 % (signed)src2
// [both undefined if src2 == 0]
// [either dest or other may be zero = omitted]
RTLOP_AND, // dest = src1 & src2
RTLOP_OR, // dest = src1 | src2
RTLOP_XOR, // dest = src1 ^ src2
RTLOP_NOT, // dest = ~src1
RTLOP_SLL, // dest = src1 << src2 [undefined when src2 >= 32]
RTLOP_SRL, // dest = (unsigned)src1 >> src2
// [undefined when src2 >= 32]
RTLOP_SRA, // dest = (signed)src1 >> src2
// [undefined when src2 >= 32]
RTLOP_ROR, // dest = src1 ROR (src2 % 32) [in 32 bits]
RTLOP_CLZ, // dest = [number of leading zeros in src1]
RTLOP_CLO, // dest = [number of leading ones in src1]
RTLOP_SLTU, // dest = (unsigned)src1 < (unsigned)src2 ? 1 : 0
RTLOP_SLTS, // dest = (signed)src1 < (signed)src2 ? 1 : 0
RTLOP_BSWAPH, // dest = [swap adjacent pairs of bytes in src1]
RTLOP_BSWAPW, // dest = [reverse order of sets of 4 bytes in src1]
RTLOP_HSWAPW, // dest = [swap adjacent pairs of halfword in src1]
/* Register-immediate operations */
RTLOP_ADDI, // dest = src1 + IMMEDIATE(src2)
RTLOP_ANDI, // dest = src1 & IMMEDIATE(src2)
RTLOP_ORI, // dest = src1 | IMMEDIATE(src2)
RTLOP_XORI, // dest = src1 ^ IMMEDIATE(src2)
RTLOP_SLLI, // dest = src1 << IMMEDIATE(src2)
RTLOP_SRLI, // dest = (unsigned)src1 >> IMMEDIATE(src2)
RTLOP_SRAI, // dest = (signed)src1 << IMMEDIATE(src2)
RTLOP_RORI, // dest = src1 ROR IMMEDIATE(src2) [in 32 bits]
RTLOP_SLTUI, // dest = (unsigned)src1 < (unsigned)IMMEDIATE(src2)
// ? 1 : 0
RTLOP_SLTSI, // dest = (signed)src1 < (signed)IMMEDIATE(src2)
// ? 1 : 0
/* Bitfield operations ("start" and "count" are encoded in the "other"
* parameter as: other = start | count<<8) */
RTLOP_BFEXT, // dest = (src1 >> start) & ((1<<count) - 1)
RTLOP_BFINS, // dest = (src1 & ~(((1<<count) - 1) << start))
// | ((src2 & ((1<<count) - 1)) << start)
// [conceptually, "insert src2 into src1"]
RTLOP_LOAD_IMM, // dest = IMMEDIATE(src1) [src1 is a 32-bit immediate]
RTLOP_LOAD_ADDR, // dest = IMMEDIATE(src1) [src1 is a native pointer]
RTLOP_LOAD_PARAM, // dest = PARAM(src1) [src1 is a function param index]
/* Note: the load/store byte offset ("other") must be in [-32768,+32767] */
RTLOP_LOAD_BU, // dest = *(uint8_t *)(src1 + other)
RTLOP_LOAD_BS, // dest = *(int8_t *)(src1 + other)
RTLOP_LOAD_HU, // dest = *(uint16_t *)(src1 + other)
RTLOP_LOAD_HS, // dest = *(int16_t *)(src1 + other)
RTLOP_LOAD_W, // dest = *(uint32_t *)(src1 + other)
RTLOP_LOAD_PTR, // dest = *(uintptr_t *)(src1 + other)
RTLOP_STORE_B, // *(uint8_t *)(dest + other) = src1
RTLOP_STORE_H, // *(uint16_t *)(dest + other) = src1
RTLOP_STORE_W, // *(uint32_t *)(dest + other) = src1
RTLOP_STORE_PTR, // *(uintptr_t *)(dest + other) = src1
RTLOP_LABEL, // LABEL(other): [src1 is a label number]
RTLOP_GOTO, // goto LABEL(other)
RTLOP_GOTO_IF_Z, // if (src1 == 0) goto LABEL(other)
RTLOP_GOTO_IF_NZ, // if (src1 != 0) goto LABEL(other)
RTLOP_GOTO_IF_E, // if (src1 == src2) goto LABEL(other)
RTLOP_GOTO_IF_NE, // if (src1 != src2) goto LABEL(other)
RTLOP_CALL, // result = (*other)(src1, src2)
// [any of the registers result, src1, src2 may
// be zero = omitted, except that src1 must be
// nonzero if src2 is nonzero]
RTLOP_RETURN, // return
RTLOP_RETURN_TO, // goto other [execute function epilogue and jump
// to given address instead of returning; other
// is a native address, or RTL block when
// interpreting with rtl_execute_block()]
} RTLOpcode;
#define RTLOP__FIRST RTLOP_NOP
#define RTLOP__LAST RTLOP_RETURN_TO
/*-----------------------------------------------------------------------*/
/**
* RTLOPT_*: Flags indicating which optimizations should be performed on
* an RTL block. Bitwise or'd together and passed as the second parameter
* to rtl_optimize_block().
*/
/* Perform constant folding, precomputing the results of operations on
* constant operands and changing the corresponding RTL instructions to
* LOAD_IMM instructions */
#define RTLOPT_FOLD_CONSTANTS (1<<0)
/* Convert conditional branches with constant conditions to unconditional
* branches or NOPs */
#define RTLOPT_DECONDITION (1<<1)
/* Eliminate unreachable basic units from the code stream */
#define RTLOPT_DROP_DEAD_UNITS (1<<2)
/* Eliminate branches to the following instruction */
#define RTLOPT_DROP_DEAD_BRANCHES (1<<3)
/*************************************************************************/
/**
* rtl_create_block: Create a new RTLBlock structure for translation.
*
* [Parameters]
* None
* [Return value]
* New block, or NULL on error
*/
extern RTLBlock *rtl_create_block(void);
/**
* rtl_add_insn: Append an instruction to the given block. The meaning of
* each operand depends on the instruction.
*
* [Parameters]
* block: RTLBlock to append to
* opcode: Instruction opcode (RTLOP_*)
* dest: Destination register for instruction
* src1: First source register or immediate value for instruction
* src2: Second source register or immediate value for instruction
* other: Extra register for instruction
* [Return value]
* Nonzero on success, zero on error
*/
extern int rtl_add_insn(RTLBlock *block, RTLOpcode opcode, uint32_t dest,
uintptr_t src1, uint32_t src2, uint32_t other);
/**
* rtl_alloc_register: Allocate a new register for use in the given block.
* The register's value is undefined until it has been used as the
* destination of an instruction.
*
* [Parameters]
* block: RTLBlock to allocate a register for
* [Return value]
* Register number (nonzero) on success, zero on error
*/
extern uint32_t rtl_alloc_register(RTLBlock *block);
/**
* rtl_register_set_unique_pointer: Mark the given register as being a
* "unique pointer", which points to a region of memory which will never
* be accessed except through this register (or another register copied
* from it). This function must be called after adding the instruction
* which sets the register, and if the register's value is subsequently
* modified, its "unique pointer" status will be cancelled.
*
* [Parameters]
* block: RTLBlock containing register to mark
* regnum: Register number to mark
* [Return value]
* Nonzero on success, zero on error
*/
extern int rtl_register_set_unique_pointer(RTLBlock *block, uint32_t regnum);
/**
* rtl_alloc_label: Allocate a new label for use in the given block.
*
* [Parameters]
* block: RTLBlock to allocate a label for
* [Return value]
* Label number (nonzero) on success, zero on error
*/
extern uint32_t rtl_alloc_label(RTLBlock *block);
/**
* rtl_finalize_block: Perform housekeeping at the end of the given
* block's translation. rtl_add_insn(), rtl_alloc_register(), and
* rtl_alloc_label() may not be called for a block after calling this
* function on the block.
*
* [Parameters]
* block: RTLBlock to finalize
* [Return value]
* Nonzero on success, zero on error
*/
extern int rtl_finalize_block(RTLBlock *block);
/**
* rtl_optimize_block: Perform target-independent optimization on the
* given block. Before calling this function, rtl_finalize_block() must be
* called for the block.
*
* [Parameters]
* block: RTLBlock to optimize
* flags: RTLOPT_* flags indicating which optimizations to perform
* [Return value]
* Nonzero on success, zero on error
*/
extern int rtl_optimize_block(RTLBlock *block, uint32_t flags);
/**
* rtl_translate_block: Translate the given block into native machine code.
*
* [Parameters]
* block: RTLBlock to translate
* code_ret: Pointer to variable to receive code buffer pointer
* size_ret: Pointer to variable to receive code buffer size (in bytes)
* [Return value]
* Nonzero on success, zero on error
* [Notes]
* On error, *code_ret and *size_ret are not modified.
*/
extern int rtl_translate_block(RTLBlock *block, void **code_ret, uint32_t *size_ret);
/**
* rtl_execute_block: Execute the given block by interpreting RTL
* instructions one at a time.
*
* [Parameters]
* block: RTLBlock to execute
* state: SH-2 processor state block
* [Return value]
* Number of RTL instructions executed
*/
extern uint32_t rtl_execute_block(RTLBlock *block, void *state);
/**
* rtl_destroy_block: Destroy the given block, freeing any resources it
* used.
*
* [Parameters]
* block: RTLBlock to destroy (if NULL, this function does nothing)
* [Return value]
* None
*/
extern void rtl_destroy_block(RTLBlock *block);
/*************************************************************************/
#endif // RTL_H
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/