883 lines
27 KiB
C
883 lines
27 KiB
C
/* IBM_PROLOG_BEGIN_TAG */
|
|
/* This is an automatically generated prolog. */
|
|
/* */
|
|
/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/pore_inline.h $ */
|
|
/* */
|
|
/* OpenPOWER HostBoot Project */
|
|
/* */
|
|
/* Contributors Listed Below - COPYRIGHT 2012,2014 */
|
|
/* [+] International Business Machines Corp. */
|
|
/* */
|
|
/* */
|
|
/* Licensed under the Apache License, Version 2.0 (the "License"); */
|
|
/* you may not use this file except in compliance with the License. */
|
|
/* You may obtain a copy of the License at */
|
|
/* */
|
|
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
|
/* */
|
|
/* Unless required by applicable law or agreed to in writing, software */
|
|
/* distributed under the 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. */
|
|
/* */
|
|
/* IBM_PROLOG_END_TAG */
|
|
#ifndef __PORE_INLINE_H__
|
|
#define __PORE_INLINE_H__
|
|
|
|
// $Id: pore_inline.h,v 1.20 2013/12/11 00:11:13 bcbrock Exp $
|
|
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/pore_inline.h,v $
|
|
//-----------------------------------------------------------------------------
|
|
// *! (C) Copyright International Business Machines Corp. 2013
|
|
// *! All Rights Reserved -- Property of IBM
|
|
// *! *** ***
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// ** WARNING : This file is maintained as part of the OCC firmware. Do **
|
|
// ** not edit this file in the PMX area or the hardware procedure area **
|
|
// ** as any changes will be lost. **
|
|
|
|
/// \file pore_inline.h
|
|
/// \brief Inline assembler for PORE code
|
|
///
|
|
/// Note that this file defines several short macro symbols for register names
|
|
/// and other mnemonics used by inline assembly. For this reason it would
|
|
/// probably be best to only include this header when it was absolutely
|
|
/// necessary, i.e., only in C files that explicitly use inline assembly and
|
|
/// disassembly.
|
|
|
|
#ifndef PPC_HYP
|
|
#include <ctype.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#endif // PPC_HYP
|
|
#include "pgas.h"
|
|
|
|
#if( defined(__cplusplus) && !defined(PLIC_MODULE) )
|
|
extern "C" {
|
|
#endif
|
|
#if 0
|
|
} /* So __cplusplus doesn't mess w/auto-indent */
|
|
#endif
|
|
|
|
|
|
#ifndef __ASSEMBLER__
|
|
|
|
// PHYP tools do not support 'static' functions and variables as it interferes
|
|
// with their concurrent patch methodology. So when compiling for PHYP the
|
|
// PORE instruction "macros" are simply declared "inline". This also extends
|
|
// into the implementation C files - so under PHYP all previosuly local static
|
|
// functions will now be global functions. We retain 'static' to reduce code
|
|
// size and improve abstraction for OCC applications.
|
|
|
|
#ifdef PPC_HYP
|
|
#define PORE_STATIC
|
|
#include <p8_pore_api_custom.h>
|
|
#else
|
|
#define PORE_STATIC static
|
|
#endif
|
|
|
|
/// Error code strings from the PORE inline assembler/disassembler
|
|
///
|
|
/// The PoreInlineContext object stores error codes that occur during
|
|
/// assembly as small integers. The '0' code indicates success. This is a
|
|
/// table of strings that describe the codes. It will be instantiated in
|
|
/// pore_inline.c
|
|
|
|
extern const char *pore_inline_error_strings[];
|
|
|
|
#ifdef __PORE_INLINE_ASSEMBLER_C__
|
|
const char *pore_inline_error_strings[] = {
|
|
"No error",
|
|
"The inline assembler memory is full, or disassembly has reached the end of the memory area",
|
|
"The instruction requires an ImD24 operand",
|
|
"The LC is not aligned or the instruction requires an aligned operand",
|
|
"The branch target is unreachable (too distant)",
|
|
"A register operand is illegal for the given instruction",
|
|
"The instruction form requires a signed 16-bit immediate",
|
|
"Valid rotate lengths are 1, 4, 8, 16 and 32",
|
|
"The instruction requires a 20-bit signed immediate",
|
|
"The instruction requires a 24-bit unsigned immediate",
|
|
"A parameter to pore_inline_context_create() is invalid",
|
|
"The instruction form requires an unsigned 22-bit immediate",
|
|
"This error is due to a bug in the PORE inline assembler (Please report)",
|
|
"The 'source' label for pore_inline_branch_fixup() is illegal",
|
|
"The 'source' instruction for pore_inline_branch_fixup() is not a branch",
|
|
"The disassembler does not recognize the instruction as a PORE opcode",
|
|
"Instruction parity error during disassembly",
|
|
"The string form of the disassembly is too long to represent (Please report)`",
|
|
"Use HALT instead of WAIT 0 if the intention is to halt.",
|
|
"A putative SCOM address is illegal (has non-0 bits where 0s are expected)."
|
|
};
|
|
#endif /* __PORE_INLINE_ASSEMBLER_C__ */
|
|
|
|
#endif /* __ASSEMBLER__ */
|
|
|
|
#define PORE_INLINE_SUCCESS 0
|
|
#define PORE_INLINE_NO_MEMORY 1
|
|
#define PORE_INLINE_IMD24_ERROR 2
|
|
#define PORE_INLINE_ALIGNMENT_ERROR 3
|
|
#define PORE_INLINE_UNREACHABLE_TARGET 4
|
|
#define PORE_INLINE_ILLEGAL_REGISTER 5
|
|
#define PORE_INLINE_INT16_REQUIRED 6
|
|
#define PORE_INLINE_ILLEGAL_ROTATE 7
|
|
#define PORE_INLINE_INT20_REQUIRED 8
|
|
#define PORE_INLINE_UINT24_REQUIRED 9
|
|
#define PORE_INLINE_INVALID_PARAMETER 10
|
|
#define PORE_INLINE_UINT22_REQUIRED 11
|
|
#define PORE_INLINE_BUG 12
|
|
#define PORE_INLINE_ILLEGAL_SOURCE_LC 13
|
|
#define PORE_INLINE_NOT_A_BRANCH 14
|
|
#define PORE_INLINE_UNKNOWN_OPCODE 15
|
|
#define PORE_INLINE_PARITY_ERROR 16
|
|
#define PORE_INLINE_DISASSEMBLY_OVERFLOW 17
|
|
#define PORE_INLINE_USE_HALT 18
|
|
#define PORE_INLINE_ILLEGAL_SCOM_ADDRESS 19
|
|
|
|
|
|
/// Register name strings for the PORE inline assembler/disassembler
|
|
|
|
extern const char *pore_inline_register_strings[16];
|
|
|
|
// C++ requires that these arrays of strings be declared 'const' to avoid
|
|
// warnings. But then you get warnings when the strings get stored into
|
|
// non-const variables. The solution is to rename these arrays inside the
|
|
// disassembler. If anyone has a better solution please let me know - Bishop
|
|
|
|
#ifdef __PORE_INLINE_ASSEMBLER_C__
|
|
const char* pore_inline_register_strings[16] = {
|
|
"P0", "P1", "A0", "A1", "CTR", "D0", "D1", "EMR",
|
|
"?", "ETR", "SPRG0", "?", "?", "?", "PC", "IFR"
|
|
};
|
|
#endif /* __PORE_INLINE_ASSEMBLER_C__ */
|
|
|
|
|
|
// Shorthand forms of constants defined in pgas.h, defined for consistency
|
|
// using the assembler-supported names. These constants are defined as an
|
|
// enum to avoid name conflicts with some firmware symbols when the PORE
|
|
// inline facility is used to create Host Boot procedures.
|
|
|
|
enum {
|
|
|
|
// Shorthand register mnemonics, defined as an enum to avoid name clashes.
|
|
|
|
P0 = PORE_REGISTER_PRV_BASE_ADDR0,
|
|
P1 = PORE_REGISTER_PRV_BASE_ADDR1,
|
|
A0 = PORE_REGISTER_OCI_BASE_ADDR0,
|
|
A1 = PORE_REGISTER_OCI_BASE_ADDR1,
|
|
CTR = PORE_REGISTER_SCRATCH0,
|
|
D0 = PORE_REGISTER_SCRATCH1,
|
|
D1 = PORE_REGISTER_SCRATCH2,
|
|
EMR = PORE_REGISTER_ERROR_MASK,
|
|
ETR = PORE_REGISTER_EXE_TRIGGER,
|
|
SPRG0 = PORE_REGISTER_DATA0,
|
|
PC = PORE_REGISTER_PC,
|
|
IFR = PORE_REGISTER_IBUF_ID,
|
|
|
|
// PgP IBUF_ID values
|
|
|
|
PORE_GPE0 = PORE_ID_GPE0,
|
|
PORE_GPE1 = PORE_ID_GPE1,
|
|
PORE_SLW = PORE_ID_SLW,
|
|
PORE_SBE = PORE_ID_SBE,
|
|
|
|
// Condition Codes
|
|
|
|
CC_UGT = PORE_CC_UGT,
|
|
CC_ULT = PORE_CC_ULT,
|
|
CC_SGT = PORE_CC_SGT,
|
|
CC_SLT = PORE_CC_SLT,
|
|
CC_C = PORE_CC_C,
|
|
CC_V = PORE_CC_V,
|
|
CC_N = PORE_CC_N,
|
|
CC_Z = PORE_CC_Z,
|
|
};
|
|
|
|
// Pseudo-opcodes for LD/LDANDI/STD
|
|
|
|
#define PORE_INLINE_PSEUDO_LD 0
|
|
#define PORE_INLINE_PSEUDO_LDANDI 1
|
|
#define PORE_INLINE_PSEUDO_STD 2
|
|
|
|
|
|
// Private version of _BIG_ENDIAN
|
|
|
|
#ifndef _BIG_ENDIAN
|
|
#define PORE_BIG_ENDIAN 0
|
|
#else
|
|
#define PORE_BIG_ENDIAN _BIG_ENDIAN
|
|
#endif
|
|
|
|
|
|
/// Maximum size of disassembly strings
|
|
///
|
|
/// This is currently sufficient for PORE_INLINE_LISTING_MODE. We don't want
|
|
/// to make this too long since the PoreInlineDisassembly object may be on the
|
|
/// stack in embedded applications.
|
|
#define PORE_INLINE_DISASSEMBLER_STRING_SIZE 128
|
|
|
|
|
|
/// Generate PORE instruction parity
|
|
///
|
|
/// This flag is an option to pore_inline_context_create(). If set, PORE
|
|
/// inline assembly sets the instruction parity bit for each assembled
|
|
/// instruction; otherwise the instruction parity bit is always 0.
|
|
#define PORE_INLINE_GENERATE_PARITY 0x01
|
|
|
|
/// Check PORE instruction parity
|
|
///
|
|
/// This flag is an option to pore_inline_context_create(). If set, PORE
|
|
/// inline disassembly checks the instruction parity bit for each disassembled
|
|
/// instruction, failing with PORE_INLINE_PARITY_ERROR if the parify is not
|
|
/// correct. Otherwise the instruction parity bit is ignored during
|
|
/// disassembly.
|
|
#define PORE_INLINE_CHECK_PARITY 0x02
|
|
|
|
/// Disassemble in listing mode
|
|
///
|
|
/// This flag is an option to pore_inline_context_create(). If set, then
|
|
/// generate disassembly strings in the form of a listing that contains
|
|
/// location counters and encoded instructions as well as their diassembly.
|
|
/// By default the disassembly strings do not contain this information and can
|
|
/// be fed back in as source code to a PORE assembler.
|
|
#define PORE_INLINE_LISTING_MODE 0x04
|
|
|
|
/// Disassemble in data mode
|
|
///
|
|
/// This flag is an option to pore_inline_context_create(). If set, then
|
|
/// generate disassembly assuming that the context contains data rather than
|
|
/// text. Normally data is disassembled as .long directives, however if the
|
|
/// context is unaligned or of an odd length then .byte directives may be used
|
|
/// as well. This option can be used in conjunction with
|
|
/// PORE_INLINE_LISTING_MODE and PORE_INLINE_8_BYTE_DATA.
|
|
///
|
|
/// Note: An intelligent application can switch between the default text
|
|
/// disassembly and data disassembly by manipulating the \a options field of
|
|
/// the PoreInlineContext between calls of pore_inline_disassemble().
|
|
#define PORE_INLINE_DISASSEMBLE_DATA 0x08
|
|
|
|
/// Disassemble data in 8-byte format
|
|
///
|
|
/// This flag is an option to pore_inline_context_create(). If set, then if
|
|
/// PORE_INLINE_DISASSEMBLE_DATA is also set then generate data disassembly as
|
|
/// 8-byte values rather then the default 4-byte values. Normally data is
|
|
/// disassembled as .quad directives under this option, however if the context
|
|
/// is unaligned or of an odd length then .long and .byte directives may be
|
|
/// used as well. This option can be used in conjunction with
|
|
/// PORE_INLINE_LISTING_MODE.
|
|
///
|
|
/// Note: An intelligent application can switch between the default text
|
|
/// disassembly and data disassembly by manipulating the \a options field of
|
|
/// the PoreInlineContext between calls of pore_inline_disassemble().
|
|
#define PORE_INLINE_8_BYTE_DATA 0x10
|
|
|
|
/// Disassemble unrecognized opcodes as 4-byte data
|
|
///
|
|
/// This flag is an option to pore_inline_context_create(). If set, then
|
|
/// any putative instruction with an unrecognized opcode will be silently
|
|
/// diassembled as 4-byte data.
|
|
///
|
|
/// This option was added to allow error-free disassembly of
|
|
/// non-parity-protected PORE text sections that contain 0x00000000 alignment
|
|
/// padding, and is not guaranteed to produce correct or consistent results in
|
|
/// any other case.
|
|
#define PORE_INLINE_DISASSEMBLE_UNKNOWN 0x20
|
|
|
|
|
|
#ifndef __ASSEMBLER__
|
|
|
|
/// The type of location counters for the PORE inline assembler
|
|
|
|
typedef uint32_t PoreInlineLocation;
|
|
|
|
/// PORE inline assembler context
|
|
///
|
|
/// See the documentation page \ref pore_inline_assembler and the function
|
|
/// pore_inline_context_create() for futher details.
|
|
|
|
typedef struct {
|
|
|
|
/// The memory area to receive the inline assembly
|
|
///
|
|
/// This field is never modified, allowing the *reset* APIs to function.
|
|
///
|
|
/// Note: C++ does not allow arithmetic on void* objects, so we use the
|
|
/// Linux convention of storing memory addresses as type 'unsigned long'.
|
|
unsigned long memory;
|
|
|
|
/// The original size of the memory area to receive the inline assembly
|
|
///
|
|
/// This field is never modified, allowing the *reset* APIs to function.
|
|
size_t size;
|
|
|
|
/// The original Location Counter (associated with \a memory)
|
|
///
|
|
/// This field is never modified, allowing the *reset* APIs to function.
|
|
PoreInlineLocation original_lc;
|
|
|
|
/// The memory address associated with the current LC
|
|
///
|
|
/// Note: C++ does not allow arithmetic on void* objects, so we use the
|
|
/// Linux convention of storing memory addresses as type 'unsigned long'.
|
|
unsigned long lc_address;
|
|
|
|
/// The remaining size of the memory area to receive the inline assembly
|
|
size_t remaining;
|
|
|
|
/// The bytewise Location Counter of the assembled code
|
|
PoreInlineLocation lc;
|
|
|
|
/// Inline assembly options
|
|
///
|
|
/// This field is never modified, allowing the *reset* APIs to function.
|
|
int options;
|
|
|
|
/// The last error code generated by the inline assembler
|
|
int error;
|
|
|
|
} PoreInlineContext;
|
|
|
|
|
|
/// PORE inline disassembler result
|
|
///
|
|
/// This object holds the disassembly produced by pore_inline_disassemble().
|
|
/// See documentation for that function for complete details.
|
|
|
|
typedef struct {
|
|
|
|
/// The context as it existed when the instruction was assembled
|
|
///
|
|
/// Disassembling an instruction modifies the context provided to
|
|
/// pore_inline_disassemble() to point to the next instruction. This
|
|
/// structure stores a copy of the context at the initial call of
|
|
/// pore_inline_disassemble(), that is, the context in effect when the
|
|
/// dissassembled instruction was assembled.
|
|
PoreInlineContext ctx;
|
|
|
|
/// The first 32 bits of every instruction
|
|
uint32_t instruction;
|
|
|
|
/// The opcode; bits 0..6 of the instruction
|
|
int opcode;
|
|
|
|
/// A flag - If set the opcode is for a 12-byte instruction
|
|
int long_instruction;
|
|
|
|
/// The parity bit; bit 7 of the instruction
|
|
int parity;
|
|
|
|
/// The register specifier at bits 8..11 of the instruction
|
|
///
|
|
/// This register is sometimes called the source, sometimes the target,
|
|
/// depending on the opcode.
|
|
int r0;
|
|
|
|
/// The register specifier at bits 12..15 of the instruction
|
|
///
|
|
/// This register is always called the 'source' but is named generically
|
|
/// here since sometimes the specifier at bits 8..11 is also called a
|
|
/// 'source'.
|
|
int r1;
|
|
|
|
/// 'ImD16' is the signed 16-bit immediate for short immediate adds and
|
|
/// subtracts. For the rotate instruction this field also contains the
|
|
/// rotate count which is either 1, 4, 8, 16 or 32.
|
|
int16_t imd16;
|
|
|
|
/// 'ImD20' is the 20-bit signed immediate for the LOAD20 instruction
|
|
int32_t imd20;
|
|
|
|
/// 'ImD24' is the 24-bit unsigned immediate for the WAIT instruction
|
|
uint32_t imd24;
|
|
|
|
/// 'ImD64' is the 64-bit immediate for data immediates and BRAI. This
|
|
/// field is only set for 3-word instructions.
|
|
uint64_t imd64;
|
|
|
|
/// 'ImPCO20' is a signed, 20-bit word offset for branch instructions
|
|
int32_t impco20;
|
|
|
|
/// 'ImPCO24' is a signed, 24-bit word offset for branch instructions
|
|
int32_t impco24;
|
|
|
|
/// For imA24 opcodes, this indicates memory/pib (1/0) addressing..
|
|
int memory_space;
|
|
|
|
/// This is the base register specifier - either a memory (OCI) base
|
|
/// register or a pervasive base register - for Read/Write operations.
|
|
/// Note that this is a PORE register index, not simply 0/1.
|
|
int base_register;
|
|
|
|
/// This is the 22-bit signed offset for memory (OCI) addressing. This
|
|
/// unsigned offset is added to a memory base register (A0/A1) to form the
|
|
/// final 32-bit address.
|
|
uint32_t memory_offset;
|
|
|
|
/// This field contains the port number and local address portions of the
|
|
/// PIB/PCB address for load/store operations that target the PIB/PCB.
|
|
/// Note that bits 0..11 will always be 0 in this address. Bits 1..7 (the
|
|
/// multicast bit and chiplet id) are sourced from the associated
|
|
/// pervasive base register when the instruction executes.
|
|
uint32_t pib_offset;
|
|
|
|
/// The update bit of the SCAND instruction
|
|
int update;
|
|
|
|
/// The capture bit of the SCAND instruction
|
|
int capture;
|
|
|
|
/// The scan length from a SCAND instruction
|
|
int scan_length;
|
|
|
|
/// The scan select from a SCAND instruction
|
|
uint32_t scan_select;
|
|
|
|
/// The address offset from a SCAND instruction
|
|
uint32_t scan_offset;
|
|
|
|
/// The string form of the disassembly.
|
|
///
|
|
/// The disassembly string is \e not terminated by a newline. In listing
|
|
/// mode the disassembly string \e will contain embedded newlines for long
|
|
/// instructions.
|
|
char s[PORE_INLINE_DISASSEMBLER_STRING_SIZE];
|
|
|
|
/// The data (for data disassembly)
|
|
///
|
|
/// This is either 1, 4 or 8 bytes in host byte order.
|
|
uint64_t data;
|
|
|
|
/// The size of the disassembled \a data field (for data disassembly)
|
|
size_t data_size;
|
|
|
|
/// Was this location disassembled as an instruction (0) or as data (1)
|
|
int is_data;
|
|
|
|
} PoreInlineDisassembly;
|
|
|
|
|
|
// These are internal APIs - they are not needed by application code.
|
|
|
|
void
|
|
pore_inline_be32(unsigned long p, uint32_t x);
|
|
|
|
void
|
|
pore_inline_be64(unsigned long p, uint64_t x);
|
|
|
|
uint32_t
|
|
pore_inline_host32(unsigned long p);
|
|
|
|
uint64_t
|
|
pore_inline_host64(unsigned long p);
|
|
|
|
int
|
|
pore_inline_parity(uint32_t instruction, uint64_t imd64);
|
|
|
|
void
|
|
pore_inline_context_bump(PoreInlineContext *ctx, size_t bytes);
|
|
|
|
int
|
|
pore_inline_instruction1(PoreInlineContext *ctx, int opcode, uint32_t operand);
|
|
|
|
int
|
|
pore_inline_instruction3(PoreInlineContext *ctx, int opcode, uint32_t operand,
|
|
uint64_t imm);
|
|
|
|
int
|
|
pore_inline_bra(PoreInlineContext *ctx,
|
|
int opcode, PoreInlineLocation target);
|
|
|
|
int
|
|
pore_inline_brac(PoreInlineContext *ctx,
|
|
int opcode, int reg, PoreInlineLocation target);
|
|
|
|
int
|
|
pore_inline_cmpibra(PoreInlineContext *ctx,
|
|
int opcode, int reg,
|
|
PoreInlineLocation target, uint64_t imm);
|
|
|
|
int
|
|
pore_inline_brad(PoreInlineContext *ctx, int opcode, int reg);
|
|
|
|
int
|
|
pore_inline_ilogic(PoreInlineContext *ctx,
|
|
int opcode, int dest, int src, uint64_t imm);
|
|
int
|
|
pore_inline_alurr(PoreInlineContext *ctx,
|
|
int opcode, int dest, int src1, int src2);
|
|
|
|
int
|
|
pore_inline_adds(PoreInlineContext *ctx,
|
|
int opcode, int dest, int src, int imm);
|
|
|
|
int
|
|
pore_inline_load_store(PoreInlineContext *ctx,
|
|
int opcode, int src_dest, int32_t offset, int base,
|
|
uint64_t imm);
|
|
|
|
|
|
// These are utility APIs that may be required by special-purpose code that
|
|
// uses the pore_inline library.
|
|
|
|
void
|
|
pore_inline_decode_instruction(PoreInlineDisassembly* dis,
|
|
uint32_t instruction);
|
|
|
|
void
|
|
pore_inline_decode_imd64(PoreInlineDisassembly* dis, uint64_t imd64);
|
|
|
|
|
|
// These are the inline PORE instructions, extended mnemonics and pseudo-ops
|
|
// to be used by application code.
|
|
|
|
/// Set a location counter variable from a context
|
|
///
|
|
/// This is a macro that sets the \a var (of type PoreInlineLocation) to the
|
|
/// current location counter of the \a ctx. The macro produces an expression
|
|
/// that evaluates to 0 so that it can be used in the logical-OR expressions
|
|
/// used to define inline assembly sequences.
|
|
|
|
#define PORE_LOCATION(ctx, var) (((var) = (ctx)->lc), 0)
|
|
|
|
int
|
|
pore_inline_context_create(PoreInlineContext *context,
|
|
void *memory,
|
|
size_t size,
|
|
PoreInlineLocation lc,
|
|
int options);
|
|
|
|
void
|
|
pore_inline_context_reset(PoreInlineContext *context);
|
|
|
|
void
|
|
pore_inline_context_reset_excursion(PoreInlineContext *context);
|
|
|
|
void
|
|
pore_inline_context_copy(PoreInlineContext *dest, PoreInlineContext *src);
|
|
|
|
|
|
int
|
|
pore_inline_branch_fixup(PoreInlineContext *ctx,
|
|
PoreInlineLocation source,
|
|
PoreInlineLocation target);
|
|
|
|
|
|
int
|
|
pore_inline_disassemble(PoreInlineContext *ctx, PoreInlineDisassembly *dis);
|
|
|
|
|
|
// Native PORE instruction assembly, using PGAS opcode names and operand
|
|
// ordering rules.
|
|
|
|
// NOP, TRAP, RET
|
|
|
|
PORE_STATIC inline int
|
|
pore_NOP(PoreInlineContext *ctx)
|
|
{
|
|
return pore_inline_instruction1(ctx, PGAS_OPCODE_NOP, 0);
|
|
}
|
|
|
|
|
|
PORE_STATIC inline int
|
|
pore_TRAP(PoreInlineContext *ctx)
|
|
{
|
|
return pore_inline_instruction1(ctx, PGAS_OPCODE_TRAP, 0);
|
|
}
|
|
|
|
|
|
PORE_STATIC inline int
|
|
pore_RET(PoreInlineContext *ctx)
|
|
{
|
|
return pore_inline_instruction1(ctx, PGAS_OPCODE_RET, 0);
|
|
}
|
|
|
|
|
|
// WAITS, HALT, HOOKI
|
|
|
|
int
|
|
pore_WAITS(PoreInlineContext *ctx, uint32_t cycles);
|
|
|
|
PORE_STATIC inline int
|
|
pore_HALT(PoreInlineContext *ctx)
|
|
{
|
|
return pore_inline_instruction1(ctx, PGAS_OPCODE_WAITS, 0);
|
|
}
|
|
|
|
int
|
|
pore_HOOKI(PoreInlineContext *ctx, uint32_t index, uint64_t imm);
|
|
|
|
|
|
// BRA, BSR, LOOP
|
|
|
|
PORE_STATIC inline int
|
|
pore_BRA(PoreInlineContext *ctx, PoreInlineLocation target)
|
|
{
|
|
return pore_inline_bra(ctx, PGAS_OPCODE_BRA, target);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_BSR(PoreInlineContext *ctx, PoreInlineLocation target)
|
|
{
|
|
return pore_inline_bra(ctx, PGAS_OPCODE_BSR, target);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_LOOP(PoreInlineContext *ctx, PoreInlineLocation target)
|
|
{
|
|
return pore_inline_bra(ctx, PGAS_OPCODE_LOOP, target);
|
|
}
|
|
|
|
|
|
// BRAZ, BRANZ
|
|
|
|
PORE_STATIC inline int
|
|
pore_BRAZ(PoreInlineContext *ctx, int reg, PoreInlineLocation target)
|
|
{
|
|
return pore_inline_brac(ctx, PGAS_OPCODE_BRAZ, reg, target);
|
|
}
|
|
|
|
|
|
PORE_STATIC inline int
|
|
pore_BRANZ(PoreInlineContext *ctx, int reg, PoreInlineLocation target)
|
|
{
|
|
return pore_inline_brac(ctx, PGAS_OPCODE_BRANZ, reg, target);
|
|
}
|
|
|
|
|
|
// CMPIBRAEQ, CMPIBRANE, CMPIBSREQ
|
|
|
|
PORE_STATIC inline int
|
|
pore_CMPIBRAEQ(PoreInlineContext *ctx,
|
|
int reg, PoreInlineLocation target, uint64_t imm)
|
|
{
|
|
return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBRAEQ, reg, target, imm);
|
|
}
|
|
|
|
|
|
PORE_STATIC inline int
|
|
pore_CMPIBRANE(PoreInlineContext *ctx,
|
|
int reg, PoreInlineLocation target, uint64_t imm)
|
|
{
|
|
return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBRANE, reg, target, imm);
|
|
}
|
|
|
|
|
|
PORE_STATIC inline int
|
|
pore_CMPIBSREQ(PoreInlineContext *ctx,
|
|
int reg, PoreInlineLocation target, uint64_t imm)
|
|
{
|
|
return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBSREQ, reg, target, imm);
|
|
}
|
|
|
|
|
|
// BRAD, BSRD
|
|
|
|
PORE_STATIC inline int
|
|
pore_BRAD(PoreInlineContext *ctx, int reg) {
|
|
return pore_inline_brad(ctx, PGAS_OPCODE_BRAD, reg);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_BSRD(PoreInlineContext *ctx, int reg) {
|
|
return pore_inline_brad(ctx, PGAS_OPCODE_BSRD, reg);
|
|
}
|
|
|
|
|
|
// ANDI, ORI, XORI
|
|
|
|
PORE_STATIC inline int
|
|
pore_ANDI(PoreInlineContext *ctx, int dest, int src, uint64_t imm)
|
|
{
|
|
return pore_inline_ilogic(ctx, PGAS_OPCODE_ANDI, dest, src, imm);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_ORI(PoreInlineContext *ctx, int dest, int src, uint64_t imm)
|
|
{
|
|
return pore_inline_ilogic(ctx, PGAS_OPCODE_ORI, dest, src, imm);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_XORI(PoreInlineContext *ctx, int dest, int src, uint64_t imm)
|
|
{
|
|
return pore_inline_ilogic(ctx, PGAS_OPCODE_XORI, dest, src, imm);
|
|
}
|
|
|
|
|
|
// AND, OR, XOR, ADD, SUB
|
|
|
|
PORE_STATIC inline int
|
|
pore_AND(PoreInlineContext *ctx, int dest, int src1, int src2)
|
|
{
|
|
return pore_inline_alurr(ctx, PGAS_OPCODE_AND, dest, src1, src2);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_OR(PoreInlineContext *ctx, int dest, int src1, int src2)
|
|
{
|
|
return pore_inline_alurr(ctx, PGAS_OPCODE_OR, dest, src1, src2);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_XOR(PoreInlineContext *ctx, int dest, int src1, int src2)
|
|
{
|
|
return pore_inline_alurr(ctx, PGAS_OPCODE_XOR, dest, src1, src2);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_ADD(PoreInlineContext *ctx, int dest, int src1, int src2)
|
|
{
|
|
return pore_inline_alurr(ctx, PGAS_OPCODE_ADD, dest, src1, src2);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_SUB(PoreInlineContext *ctx, int dest, int src1, int src2)
|
|
{
|
|
return pore_inline_alurr(ctx, PGAS_OPCODE_SUB, dest, src1, src2);
|
|
}
|
|
|
|
|
|
// ADDS, SUBS
|
|
|
|
PORE_STATIC inline int
|
|
pore_ADDS(PoreInlineContext *ctx, int dest, int src, int imm)
|
|
{
|
|
return pore_inline_adds(ctx, PGAS_OPCODE_ADDS, dest, src, imm);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_SUBS(PoreInlineContext *ctx, int dest, int src, int imm)
|
|
{
|
|
return pore_inline_adds(ctx, PGAS_OPCODE_SUBS, dest, src, imm);
|
|
}
|
|
|
|
|
|
// NEG, MR, ROLS, LS, LI
|
|
|
|
int
|
|
pore_NEG(PoreInlineContext *ctx, int dest, int src);
|
|
|
|
int
|
|
pore_MR(PoreInlineContext *ctx, int dest, int src);
|
|
|
|
int
|
|
pore_ROLS(PoreInlineContext *ctx, int dest, int src, int imm);
|
|
|
|
int
|
|
pore_LS(PoreInlineContext *ctx, int dest, int imm);
|
|
|
|
int
|
|
pore_LI(PoreInlineContext *ctx, int dest, uint64_t imm);
|
|
|
|
|
|
// LD, LDANDI, STD, STI, BSI, BCI
|
|
|
|
PORE_STATIC inline int
|
|
pore_LD(PoreInlineContext *ctx, int dest, int32_t offset, int base)
|
|
{
|
|
return
|
|
pore_inline_load_store(ctx,
|
|
PORE_INLINE_PSEUDO_LD, dest, offset, base, 0);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_LDANDI(PoreInlineContext *ctx,
|
|
int dest, int32_t offset, int base, uint64_t imm)
|
|
{
|
|
return
|
|
pore_inline_load_store(ctx,
|
|
PORE_INLINE_PSEUDO_LDANDI,
|
|
dest, offset, base, imm);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_STD(PoreInlineContext *ctx, int src, int32_t offset, int base)
|
|
{
|
|
return
|
|
pore_inline_load_store(ctx,
|
|
PORE_INLINE_PSEUDO_STD, src, offset, base, 0);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_STI(PoreInlineContext *ctx, int32_t offset, int base, uint64_t imm)
|
|
{
|
|
return
|
|
pore_inline_load_store(ctx,
|
|
PGAS_OPCODE_STI, 0, offset, base, imm);
|
|
}
|
|
|
|
|
|
#ifdef IGNORE_HW274735
|
|
|
|
// BSI and BCI are redacted as instructions and reimplemented as "macros" due
|
|
// to HW274735, unless specifically overridden. Note that the inline assembler
|
|
// will allow D1 to be used as scratch here, unlike the underlying hardware
|
|
// instruction.
|
|
|
|
PORE_STATIC inline int
|
|
pore_BSI(PoreInlineContext *ctx,
|
|
int src, int32_t offset, int base, uint64_t imm)
|
|
{
|
|
return
|
|
pore_inline_load_store(ctx,
|
|
PGAS_OPCODE_BSI, src, offset, base, imm);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_BCI(PoreInlineContext *ctx,
|
|
int src, int32_t offset, int base, uint64_t imm)
|
|
{
|
|
return
|
|
pore_inline_load_store(ctx,
|
|
PGAS_OPCODE_BCI, src, offset, base, imm);
|
|
}
|
|
|
|
#else
|
|
|
|
PORE_STATIC inline int
|
|
pore_BSI(PoreInlineContext *ctx,
|
|
int src, int32_t offset, int base, uint64_t imm)
|
|
{
|
|
return
|
|
((pore_LD(ctx, src, offset, base) ||
|
|
pore_ORI(ctx, src, src, imm) ||
|
|
pore_STD(ctx, src, offset, base)) ? ctx->error : 0);
|
|
}
|
|
|
|
PORE_STATIC inline int
|
|
pore_BCI(PoreInlineContext *ctx,
|
|
int src, int32_t offset, int base, uint64_t imm)
|
|
{
|
|
return
|
|
((pore_LDANDI(ctx, src, offset, base, ~imm) ||
|
|
pore_STD(ctx, src, offset, base)) ? ctx->error : 0);
|
|
}
|
|
|
|
#endif // IGNORE_HW274735
|
|
|
|
|
|
// BRAIA
|
|
|
|
int
|
|
pore_BRAIA(PoreInlineContext *ctx,
|
|
uint16_t address_space, uint32_t offset);
|
|
|
|
|
|
// SCAND
|
|
|
|
int
|
|
pore_SCAND(PoreInlineContext *ctx,
|
|
int update, int capture, uint16_t length,
|
|
uint32_t select, uint32_t offset);
|
|
|
|
#endif /* __ASSEMBLER__ */
|
|
|
|
#if 0
|
|
{ /* So __cplusplus doesn't mess w/auto-indent */
|
|
#endif
|
|
#if( defined(__cplusplus) && !defined(PLIC_MODULE) )
|
|
}
|
|
#endif
|
|
|
|
#endif /* __PORE_INLINE_H__ */
|
|
|