1170 lines
36 KiB
C
1170 lines
36 KiB
C
/* IBM_PROLOG_BEGIN_TAG */
|
|
/* This is an automatically generated prolog. */
|
|
/* */
|
|
/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/pgas.h $ */
|
|
/* */
|
|
/* OpenPOWER HostBoot Project */
|
|
/* */
|
|
/* COPYRIGHT International Business Machines Corp. 2012,2014 */
|
|
/* */
|
|
/* 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 __PGAS_H__
|
|
#define __PGAS_H__
|
|
|
|
#define __PGAS__
|
|
|
|
// $Id: pgas.h,v 1.21 2013/11/20 14:06:39 bcbrock Exp $
|
|
|
|
// ** WARNING : This file is maintained as part of the OCC firmware. Do **
|
|
// ** not edit this file in the PMX area, the hardware procedure area, **
|
|
// ** or the PoreVe area as any changes will be lost. **
|
|
|
|
/// \file pgas.h
|
|
/// \brief Pore GAS
|
|
///
|
|
/// PGAS is documented in a separate standalone document entitled <em> PGAS :
|
|
/// PORE GAS (GNU Assembler) User's and Reference Manual </em>.
|
|
///
|
|
/// This file defines support macros for the GNU PORE assembler, and the PORE
|
|
/// inline assembler and disassebler which follow the PGAS assembly syntax.
|
|
/// If the compile swith PGAS_PPC is defined in the environment then pgas.h
|
|
/// includes pgas_ppc.h which transforms a PowerPC assembler into an assembler
|
|
/// for PORE.
|
|
|
|
// These are the opcodes and mnemonics as defined by the PORE hardware
|
|
// manual. Many of them will change names slightly in PGAS.
|
|
|
|
#define PORE_OPCODE_NOP 0x0f
|
|
#define PORE_OPCODE_WAIT 0x01
|
|
#define PORE_OPCODE_TRAP 0x02
|
|
#define PORE_OPCODE_HOOK 0x4f
|
|
|
|
#define PORE_OPCODE_BRA 0x10
|
|
#define PORE_OPCODE_BRAZ 0x12
|
|
#define PORE_OPCODE_BRANZ 0x13
|
|
#define PORE_OPCODE_BRAI 0x51
|
|
#define PORE_OPCODE_BSR 0x14
|
|
#define PORE_OPCODE_BRAD 0x1c
|
|
#define PORE_OPCODE_BSRD 0x1d
|
|
#define PORE_OPCODE_RET 0x15
|
|
#define PORE_OPCODE_CMPBRA 0x56
|
|
#define PORE_OPCODE_CMPNBRA 0x57
|
|
#define PORE_OPCODE_CMPBSR 0x58
|
|
#define PORE_OPCODE_LOOP 0x1f
|
|
|
|
#define PORE_OPCODE_ANDI 0x60
|
|
#define PORE_OPCODE_ORI 0x61
|
|
#define PORE_OPCODE_XORI 0x62
|
|
|
|
#define PORE_OPCODE_AND 0x25
|
|
#define PORE_OPCODE_OR 0x26
|
|
#define PORE_OPCODE_XOR 0x27
|
|
|
|
#define PORE_OPCODE_ADD 0x23
|
|
#define PORE_OPCODE_ADDI 0x24
|
|
#define PORE_OPCODE_SUB 0x29
|
|
#define PORE_OPCODE_SUBI 0x28
|
|
#define PORE_OPCODE_NEG 0x2a
|
|
|
|
#define PORE_OPCODE_COPY 0x2c
|
|
#define PORE_OPCODE_ROL 0x2e
|
|
|
|
#define PORE_OPCODE_LOAD20 0x30
|
|
#define PORE_OPCODE_LOAD64 0x71
|
|
#define PORE_OPCODE_SCR1RD 0x32
|
|
#define PORE_OPCODE_SCR1RDA 0x73
|
|
#define PORE_OPCODE_SCR2RD 0x36
|
|
#define PORE_OPCODE_SCR2RDA 0x77
|
|
#define PORE_OPCODE_WRI 0x78
|
|
#define PORE_OPCODE_BS 0x74
|
|
#define PORE_OPCODE_BC 0x75
|
|
#define PORE_OPCODE_SCR1WR 0x39
|
|
#define PORE_OPCODE_SCR2WR 0x3a
|
|
#define PORE_OPCODE_SCAND 0x7c
|
|
|
|
|
|
// These are the PGAS versions of the PORE opcodes used in the legacy PGAS_PPC
|
|
// assembler and the current PORE inline assembler/disassembler.
|
|
|
|
#define PGAS_OPCODE_NOP PORE_OPCODE_NOP
|
|
#define PGAS_OPCODE_WAITS PORE_OPCODE_WAIT
|
|
#define PGAS_OPCODE_TRAP PORE_OPCODE_TRAP
|
|
#define PGAS_OPCODE_HOOKI PORE_OPCODE_HOOK
|
|
|
|
#define PGAS_OPCODE_BRA PORE_OPCODE_BRA
|
|
#define PGAS_OPCODE_BRAZ PORE_OPCODE_BRAZ
|
|
#define PGAS_OPCODE_BRANZ PORE_OPCODE_BRANZ
|
|
#define PGAS_OPCODE_BRAI PORE_OPCODE_BRAI
|
|
#define PGAS_OPCODE_BSR PORE_OPCODE_BSR
|
|
#define PGAS_OPCODE_BRAD PORE_OPCODE_BRAD
|
|
#define PGAS_OPCODE_BSRD PORE_OPCODE_BSRD
|
|
#define PGAS_OPCODE_RET PORE_OPCODE_RET
|
|
#define PGAS_OPCODE_CMPIBRAEQ PORE_OPCODE_CMPBRA
|
|
#define PGAS_OPCODE_CMPIBRANE PORE_OPCODE_CMPNBRA
|
|
#define PGAS_OPCODE_CMPIBSREQ PORE_OPCODE_CMPBSR
|
|
#define PGAS_OPCODE_LOOP PORE_OPCODE_LOOP
|
|
|
|
#define PGAS_OPCODE_ANDI PORE_OPCODE_ANDI
|
|
#define PGAS_OPCODE_ORI PORE_OPCODE_ORI
|
|
#define PGAS_OPCODE_XORI PORE_OPCODE_XORI
|
|
|
|
#define PGAS_OPCODE_AND PORE_OPCODE_AND
|
|
#define PGAS_OPCODE_OR PORE_OPCODE_OR
|
|
#define PGAS_OPCODE_XOR PORE_OPCODE_XOR
|
|
|
|
#define PGAS_OPCODE_ADD PORE_OPCODE_ADD
|
|
#define PGAS_OPCODE_ADDS PORE_OPCODE_ADDI
|
|
#define PGAS_OPCODE_SUB PORE_OPCODE_SUB
|
|
#define PGAS_OPCODE_SUBS PORE_OPCODE_SUBI
|
|
#define PGAS_OPCODE_NEG PORE_OPCODE_NEG
|
|
|
|
#define PGAS_OPCODE_MR PORE_OPCODE_COPY
|
|
#define PGAS_OPCODE_ROLS PORE_OPCODE_ROL
|
|
|
|
#define PGAS_OPCODE_LS PORE_OPCODE_LOAD20
|
|
#define PGAS_OPCODE_LI PORE_OPCODE_LOAD64
|
|
#define PGAS_OPCODE_LD0 PORE_OPCODE_SCR1RD /* Used by LD */
|
|
#define PGAS_OPCODE_LD0ANDI PORE_OPCODE_SCR1RDA /* Used by LDANDI */
|
|
#define PGAS_OPCODE_LD1 PORE_OPCODE_SCR2RD /* Used by LD */
|
|
#define PGAS_OPCODE_LD1ANDI PORE_OPCODE_SCR2RDA /* Used by LDANDI */
|
|
#define PGAS_OPCODE_STI PORE_OPCODE_WRI
|
|
#define PGAS_OPCODE_STD0 PORE_OPCODE_SCR1WR /* Used by STD */
|
|
#define PGAS_OPCODE_STD1 PORE_OPCODE_SCR2WR /* Used by STD */
|
|
#define PGAS_OPCODE_SCAND PORE_OPCODE_SCAND
|
|
|
|
#ifdef IGNORE_HW274735
|
|
|
|
// BSI and BCI are normally redacted due to HW274735. See also pgas.h
|
|
|
|
#define PGAS_OPCODE_BSI PORE_OPCODE_BS
|
|
#define PGAS_OPCODE_BCI PORE_OPCODE_BC
|
|
|
|
#endif // IGNORE_HW274735
|
|
|
|
// These are the programmer-visible register names as defined by the PORE
|
|
// hardware manual. All of these names (except the PC) appear differently in
|
|
// the PGAS syntax, in some cases to reduce confusion, in other cases just to
|
|
// have more traditional short mnemonics.
|
|
|
|
#define PORE_REGISTER_PRV_BASE_ADDR0 0x0
|
|
#define PORE_REGISTER_PRV_BASE_ADDR1 0x1
|
|
#define PORE_REGISTER_OCI_BASE_ADDR0 0x2
|
|
#define PORE_REGISTER_OCI_BASE_ADDR1 0x3
|
|
#define PORE_REGISTER_SCRATCH0 0x4
|
|
#define PORE_REGISTER_SCRATCH1 0x5
|
|
#define PORE_REGISTER_SCRATCH2 0x6
|
|
#define PORE_REGISTER_ERROR_MASK 0x7
|
|
#define PORE_REGISTER_EXE_TRIGGER 0x9
|
|
#define PORE_REGISTER_DATA0 0xa
|
|
#define PORE_REGISTER_PC 0xe
|
|
#define PORE_REGISTER_IBUF_ID 0xf
|
|
|
|
|
|
// PgP IBUF_ID values
|
|
|
|
#define PORE_ID_GPE0 0x00
|
|
#define PORE_ID_GPE1 0x01
|
|
#define PORE_ID_SLW 0x08
|
|
#define PORE_ID_SBE 0x04
|
|
|
|
|
|
// Condition Codes
|
|
|
|
#define PORE_CC_UGT 0x8000
|
|
#define PORE_CC_ULT 0x4000
|
|
#define PORE_CC_SGT 0x2000
|
|
#define PORE_CC_SLT 0x1000
|
|
#define PORE_CC_C 0x0800
|
|
#define PORE_CC_V 0x0400
|
|
#define PORE_CC_N 0x0200
|
|
#define PORE_CC_Z 0x0100
|
|
|
|
|
|
// Memory Spaces
|
|
|
|
#define PORE_SPACE_UNDEFINED 0xffff
|
|
#define PORE_SPACE_OCI 0x8000
|
|
#define PORE_SPACE_PNOR 0x800b
|
|
#define PORE_SPACE_OTPROM 0x0001
|
|
#define PORE_SPACE_SEEPROM 0x800c
|
|
#define PORE_SPACE_PIBMEM 0x0008
|
|
|
|
|
|
#ifdef __ASSEMBLER__
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// PGAS Base Assembler Support
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Condition Codes
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
.set CC_UGT, PORE_CC_UGT
|
|
.set CC_ULT, PORE_CC_ULT
|
|
.set CC_SGT, PORE_CC_SGT
|
|
.set CC_SLT, PORE_CC_SLT
|
|
.set CC_C, PORE_CC_C
|
|
.set CC_V, PORE_CC_V
|
|
.set CC_N, PORE_CC_N
|
|
.set CC_Z, PORE_CC_Z
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Utility Macros
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// 'Undefine' PowerPC mnemonics to trap programming errors
|
|
|
|
.macro ..undefppc1, i
|
|
.ifnc \i, ignore
|
|
.macro \i, args:vararg
|
|
.error "This is a PowerPC opcode - NOT a PGAS opcode or extended mnemonic"
|
|
.endm
|
|
.endif
|
|
.endm
|
|
|
|
.macro .undefppc, i0, i1=ignore, i2=ignore, i3=ignore
|
|
..undefppc1 \i0
|
|
..undefppc1 \i1
|
|
..undefppc1 \i2
|
|
..undefppc1 \i3
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Argument Checking Macros
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// These macros remain in the final pgas.h file because 1) they are
|
|
// required for some PGAS pseudo-ops, and 2) to support robust
|
|
// assembler macro definitions.
|
|
|
|
// Check an unsigned immediate for size
|
|
|
|
.macro ..checku, x:req, bits:req, err="Unsigned value too large"
|
|
|
|
.if (((\bits) <= 0) || ((\bits) > 63))
|
|
.error "The number of bits must be in the range 0 < bits < 64"
|
|
.endif
|
|
|
|
.iflt (\x)
|
|
.error "An unsigned value is required here"
|
|
.endif
|
|
|
|
.ifgt ((\x) - (0xffffffffffffffff >> (64 - (\bits))))
|
|
.error "\err"
|
|
.endif
|
|
|
|
.endm
|
|
|
|
// Check unsigned 16/22-bit immediates for size
|
|
//
|
|
// In general, PGAS can check immediate values for size restrictions,
|
|
// but unfortunately is not able to check address offset immediates for
|
|
// range.
|
|
|
|
.macro ..check_u16, u16
|
|
..checku (\u16), 16, "Unsigned immediate is larger than 16 bits"
|
|
.endm
|
|
|
|
.macro ..check_u24, u24
|
|
..checku (\u24), 24, "Unsigned immediate is larger than 24 bits"
|
|
.endm
|
|
|
|
// Check a 16/20/22-bit signed immediate for size
|
|
|
|
.macro ..check_s16, s16
|
|
.iflt \s16
|
|
.iflt \s16 + 0x8000
|
|
.error "Immediate value too small for a signed 16-bit field"
|
|
.endif
|
|
.else
|
|
.ifgt \s16 - 0x7fff
|
|
.error "Immediate value too large for a signed 16-bit field"
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
.macro ..check_s20, s20
|
|
.iflt \s20
|
|
.iflt \s20 + 0x80000
|
|
.error "Immediate value too small for a signed 20-bit field"
|
|
.endif
|
|
.else
|
|
.ifgt \s20 - 0x7ffff
|
|
.error "Immediate value too large for a signed 20-bit field"
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
.macro ..check_s22, s22
|
|
.iflt \s22
|
|
.iflt \s22 + 0x200000
|
|
.error "Immediate value too small for a signed 22-bit field"
|
|
.endif
|
|
.else
|
|
.ifgt \s22 - 0x1fffff
|
|
.error "Immediate value too large for a signed 22-bit field"
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// Check a putative SCOM address for bits 0 and 8:11 == 0.
|
|
|
|
.macro ..check_scom, address
|
|
.if ((\address) & 0x80f00000)
|
|
.error "Valid SCOM addresses must have bits 0 and 8:11 equal to 0."
|
|
.endif
|
|
.endm
|
|
|
|
// A register required to be D0
|
|
|
|
.macro ..d0, reg
|
|
.if (\reg != D0)
|
|
.error "Data register D0 is required here"
|
|
.endif
|
|
.endm
|
|
|
|
// A register pair required to be D0, D1 in order
|
|
|
|
.macro ..d0d1, reg1, reg2
|
|
.if (((\reg1) != D0) && ((\reg2) != D1))
|
|
.error "Register-Register ALU operations are only defined on the source pair D0, D1"
|
|
.endif
|
|
.endm
|
|
|
|
// A register pair required to be D0, D1 in any order
|
|
.macro ..dxdy, reg1, reg2, err="Expecting D0, D1 in either order"
|
|
.if !((((\reg1) == D0) && ((\reg2) == D1)) || \
|
|
(((\reg1) == D1) && ((\reg2) == D0)))
|
|
.error "\err"
|
|
.endif
|
|
.endm
|
|
|
|
// A register pair required to be A0, A1 in any order
|
|
.macro ..axay, reg1, reg2, err="Expecting A0, A1 in either order"
|
|
.if !((((\reg1) == A0) && ((\reg2) == A1)) || \
|
|
(((\reg1) == A1) && ((\reg2) == A0)))
|
|
.error "\err"
|
|
.endif
|
|
.endm
|
|
|
|
// A register pair required to be the same register
|
|
|
|
.macro ..same, dest, src
|
|
.if ((\dest) != (\src))
|
|
.error "PGAS requires the src and dest register of ADDS/SUBS to be explicit and identical"
|
|
.endif
|
|
.endm
|
|
|
|
// A "Data" register
|
|
|
|
.macro ..data, reg:req, err="Expecting a 'Data' register"
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.error "\err"
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// An "Address" register
|
|
|
|
.macro ..address, reg:req, err=:"Expecting an 'Address' register"
|
|
.if (\reg != A0)
|
|
.if (\reg != A1)
|
|
.error "\err"
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// A "Pervasive Chiplet ID" register
|
|
|
|
.macro ..pervasive_chiplet_id, reg:req, err="Expecting a 'Pervasive Chiplet ID' register"
|
|
.if (\reg != P0)
|
|
.if (\reg != P1)
|
|
.error "\err"
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// A "Branch Compare Data" register
|
|
|
|
.macro ..branch_compare_data, reg
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.if (\reg != CTR)
|
|
.error "Expecting a 'Branch Compare Data' register"
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// An "LS Destination" register; Also the set for ADDS/SUBS
|
|
|
|
.macro ..ls_destination, reg
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.if (\reg != A0)
|
|
.if (\reg != A1)
|
|
.if (\reg != P0)
|
|
.if (\reg != P1)
|
|
.if (\reg != CTR)
|
|
.error "Expecting an 'LS Destination' register"
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// An "LI Destination" register
|
|
|
|
.macro ..li_destination, reg
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.if (\reg != A0)
|
|
.if (\reg != A1)
|
|
.if (\reg != CTR)
|
|
.error "Expecting an 'LI Destination' register"
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// An "LIA Destination" register
|
|
|
|
.macro ..lia_destination, reg
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.if (\reg != A0)
|
|
.if (\reg != A1)
|
|
.if (\reg != TBAR)
|
|
.error "Expecting an 'LIA Destination' register"
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// An "MR Source" register
|
|
|
|
.macro ..mr_source, reg
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.if (\reg != A0)
|
|
.if (\reg != A1)
|
|
.if (\reg != P0)
|
|
.if (\reg != P1)
|
|
.if (\reg != CTR)
|
|
.if (\reg != PC)
|
|
.if (\reg != ETR)
|
|
.if (\reg != SPRG0)
|
|
.if (\reg != IFR)
|
|
.if (\reg != EMR)
|
|
.error "Expecting an 'MR Source' register"
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
// An "MR Destination" register
|
|
|
|
.macro ..mr_destination, reg
|
|
.if (\reg != D0)
|
|
.if (\reg != D1)
|
|
.if (\reg != A0)
|
|
.if (\reg != A1)
|
|
.if (\reg != P0)
|
|
.if (\reg != P1)
|
|
.if (\reg != CTR)
|
|
.if (\reg != PC)
|
|
.if (\reg != ETR)
|
|
.if (\reg != SPRG0)
|
|
.if (\reg != EMR)
|
|
.error "Expecting an 'MR Destination' register"
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endif
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// PORE address spaces
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// The ..set_address_space pseudo-op defines the default address
|
|
// space. It must be defined in order to use BRAA, BRAIA, BSR and
|
|
// CMPIBSR. Pseudo-ops are provided to set the default space of the
|
|
// program. Note that code assembled for PNOR will also work in the
|
|
// OCI space in the Sleep/Winkle engine.
|
|
|
|
.macro ..set_default_space, s
|
|
..check_u16 (\s)
|
|
.set _PGAS_DEFAULT_SPACE, (\s)
|
|
.endm
|
|
|
|
.macro ..check_default_space
|
|
.if (_PGAS_DEFAULT_SPACE == PORE_SPACE_UNDEFINED)
|
|
.error "The PGAS default address space has not been defined"
|
|
.endif
|
|
.endm
|
|
|
|
..set_default_space PORE_SPACE_UNDEFINED
|
|
|
|
.macro .oci
|
|
..set_default_space PORE_SPACE_OCI
|
|
.endm
|
|
|
|
.macro .pnor
|
|
..set_default_space PORE_SPACE_PNOR
|
|
.endm
|
|
|
|
.macro .seeprom
|
|
..set_default_space PORE_SPACE_SEEPROM
|
|
.endm
|
|
|
|
.macro .otprom
|
|
..set_default_space PORE_SPACE_OTPROM
|
|
.endm
|
|
|
|
.macro .pibmem
|
|
..set_default_space PORE_SPACE_PIBMEM
|
|
#ifndef PGAS_PPC
|
|
.pibmem_port (PORE_SPACE_PIBMEM & 0xf)
|
|
#else
|
|
// NB: PGAS_PPC does not support relocatable PIBMEM addressing
|
|
#endif
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Address-Generation Pseudo Ops
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// .QUADA, .QUADIA
|
|
|
|
.macro .quada, offset:req
|
|
..check_default_space
|
|
.long _PGAS_DEFAULT_SPACE
|
|
.long (\offset)
|
|
.endm
|
|
|
|
.macro .quadia, space:req, offset:req
|
|
..check_u16 (\space)
|
|
.long (\space)
|
|
.long (\offset)
|
|
.endm
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Bug workarounds
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef IGNORE_HW274735
|
|
|
|
// HW274735 documents that BC and BS are broken for the PORE-GPE0/1
|
|
// pair. This bug is unfixed in POWER8, and by default we require BSI
|
|
// and BCI to be implemented as macros on all engines. For
|
|
// compatibility we continue to require that dx == D0.
|
|
|
|
.macro bsi, dx:req, offset:req, base:req, imm:req
|
|
..d0 (\dx)
|
|
ld D0, (\offset), (\base)
|
|
ori D0, D0, (\imm)
|
|
std D0, (\offset), (\base)
|
|
.endm
|
|
|
|
.macro bci, dx:req, offset:req, base:req, imm:req
|
|
..d0 (\dx)
|
|
ldandi D0, (\offset), (\base), ~(\imm)
|
|
std D0, (\offset), (\base)
|
|
.endm
|
|
|
|
#endif // IGNORE_HW274735
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// "A"- and "IA"-form Instructions
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// BRAA (Branch Address) is a 'long branch' to an address in the
|
|
// default memory space.
|
|
|
|
.macro braa, offset:req
|
|
braia _PGAS_DEFAULT_SPACE, (\offset)
|
|
.endm
|
|
|
|
// LA (Load Address) loads the full address of an address in the
|
|
// default memory space.
|
|
|
|
.macro la, dest:req, offset:req
|
|
lia (\dest), _PGAS_DEFAULT_SPACE, (\offset)
|
|
.endm
|
|
|
|
// STA (Store Address) stores the full address of an address in the
|
|
// default memory space.
|
|
|
|
.macro sta, mem_offset:req, base:req, addr_offset:req
|
|
stia (\mem_offset), (\base), _PGAS_DEFAULT_SPACE, (\addr_offset)
|
|
.endm
|
|
|
|
// BSRIA is a subroutine branch into another memory space. This has to
|
|
// be emulated by a local subroutine branch and a BRAIA.
|
|
|
|
.macro bsria, space:req, offset:req
|
|
bsr 27742f
|
|
bra 27743f
|
|
27742:
|
|
braia (\space), (\offset)
|
|
27743:
|
|
.endm
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Extended Mnemonics, Macros and Special Cases
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// TFB<c> - Test flags and branch conditionally
|
|
//////////////////////////////////////////////////////////////////////'
|
|
|
|
.macro ..tfb, dest, target, flags
|
|
..data (\dest)
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), (\flags)
|
|
branz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro ..tfbn dest, target, flags
|
|
..data (\dest)
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), (\flags)
|
|
braz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tfbcs, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_C
|
|
.endm
|
|
|
|
.macro tfbcc, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_C
|
|
.endm
|
|
|
|
.macro tfbvs, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_V
|
|
.endm
|
|
|
|
.macro tfbvc, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_V
|
|
.endm
|
|
|
|
.macro tfbns, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_N
|
|
.endm
|
|
|
|
.macro tfbnc, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_N
|
|
.endm
|
|
|
|
.macro tfbeq, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_Z
|
|
.endm
|
|
|
|
.macro tfbne, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_Z
|
|
.endm
|
|
|
|
.macro tfbult, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_ULT
|
|
.endm
|
|
|
|
.macro tfbule, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_UGT
|
|
.endm
|
|
|
|
.macro tfbuge, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_ULT
|
|
.endm
|
|
|
|
.macro tfbugt, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_UGT
|
|
.endm
|
|
|
|
.macro tfbslt, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_SLT
|
|
.endm
|
|
|
|
.macro tfbsle, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_SGT
|
|
.endm
|
|
|
|
.macro tfbsge, dest:req, target:req
|
|
..tfbn (\dest), (\target), CC_SLT
|
|
.endm
|
|
|
|
.macro tfbsgt, dest:req, target:req
|
|
..tfb (\dest), (\target), CC_SGT
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// TEB[N]<eng> - Test Engine and branch if [not] engine.
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// All but GPE0 use a 1-hot code.
|
|
|
|
.macro tebgpe0, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), 0xf
|
|
braz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tebgpe1, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), PORE_ID_GPE1
|
|
branz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tebslw, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), PORE_ID_SLW
|
|
branz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tebsbe, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), PORE_ID_SBE
|
|
branz (\dest), (\target)
|
|
.endm
|
|
|
|
|
|
.macro tebngpe0, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), 0xf
|
|
branz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tebngpe1, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), PORE_ID_GPE1
|
|
braz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tebnslw, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), PORE_ID_SLW
|
|
braz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tebnsbe, dest:req, target:req
|
|
mr (\dest), IFR
|
|
andi (\dest), (\dest), PORE_ID_SBE
|
|
braz (\dest), (\target)
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// EXTRPRC - Extract and right-justify the PIB/PCB return code
|
|
// TPRCB[N]Z - Test PIB return code and branch if [not] zero
|
|
// TPRCBGT - Test PIB return code and branch if greater-than
|
|
// TPRCBLE - Test PIB return code and branch if less-then or equal
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// To support cases where PORE code expects or must explicitly handle
|
|
// non-0 PIB return codes, the PIB return code and parity indication
|
|
// are stored in bits 32 (parity) and 33-35 (return code) of the IFR.
|
|
// These macros extract the four PIB/PCB status bits from the IFR and
|
|
// right-justifies them into the data register provided. For EXTRPRC
|
|
// that is the total function of the macro. The TPRCB[N]Z macros
|
|
// provide a simple non-destructive test and branch for zero (success)
|
|
// and non-zero (potential problem) codes after the extraction.
|
|
//
|
|
// In complex error handling scenarios one would typically compare the
|
|
// PIB return code against an upper-bound, e.g., the offline response
|
|
// (0x2), and then take further action. If the parity error bit is set
|
|
// then this would produce an aggregate "return code" higher than any
|
|
// that one would typically want to ignore. The TPRCBGT/TPRCBLE macros
|
|
// provide this function; however the test destroys the extracted
|
|
// return code so that if further analysis is required the code will
|
|
// need to be a extracted again.
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
.macro extrprc, dest:req
|
|
..data (\dest)
|
|
mr (\dest), IFR
|
|
extrdi (\dest), (\dest), 4, 32
|
|
.endm
|
|
|
|
.macro tprcbz, dest:req, target:req
|
|
extrprc (\dest)
|
|
braz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tprcbnz, dest:req, target:req
|
|
extrprc (\dest)
|
|
branz (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tprcbgt, dest:req, target:req, bound:req
|
|
extrprc (\dest)
|
|
subs (\dest), (\dest), (\bound)
|
|
tfbugt (\dest), (\target)
|
|
.endm
|
|
|
|
.macro tprcble, dest:req, target:req, bound:req
|
|
extrprc (\dest)
|
|
subs (\dest), (\dest), (\bound)
|
|
tfbule (\dest), (\target)
|
|
.endm
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// LPCS - Load Pervasive Chiplet from Scom address
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
.macro lpcs, dest:req, scom:req
|
|
..pervasive_chiplet_id (\dest)
|
|
..check_scom (\scom)
|
|
ls (\dest), (((\scom) >> 24) & 0x7f)
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Shift/Mask extended mnemonics
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// All of the 'dot-dot' macros assume that error and identity
|
|
// checking has been done on the arguments already.
|
|
|
|
// The initial register-register rotate. If the incoming shift amount
|
|
// is 0 then the instruction generated is a simple MR.
|
|
|
|
.macro ..rotlrr, ra, rs, sh
|
|
|
|
.if (\sh) >= 32
|
|
rols (\ra), (\rs), 32
|
|
..rotlr (\ra), ((\sh) - 32)
|
|
.elseif (\sh) >= 16
|
|
rols (\ra), (\rs), 16
|
|
..rotlr (\ra), ((\sh) - 16)
|
|
.elseif (\sh) >= 8
|
|
rols (\ra), (\rs), 8
|
|
..rotlr (\ra), ((\sh) - 8)
|
|
.elseif (\sh) >= 4
|
|
rols (\ra), (\rs), 4
|
|
..rotlr (\ra), ((\sh) - 4)
|
|
.elseif (\sh) >= 1
|
|
rols (\ra), (\rs), 1
|
|
..rotlr (\ra), ((\sh) - 1)
|
|
.else
|
|
mr (\ra), (\rs)
|
|
.endif
|
|
|
|
.endm
|
|
|
|
|
|
// Subsequent rotation of the same register. The SH should never be 0
|
|
// here.
|
|
|
|
.macro ..rotlr, ra, sh
|
|
|
|
.if (\sh) >= 32
|
|
rols (\ra), (\ra), 32
|
|
..rotlr (\ra), ((\sh) - 32)
|
|
.elseif (\sh) >= 16
|
|
rols (\ra), (\ra), 16
|
|
..rotlr (\ra), ((\sh) - 16)
|
|
.elseif (\sh) >= 8
|
|
rols (\ra), (\ra), 8
|
|
..rotlr (\ra), ((\sh) - 8)
|
|
.elseif (\sh) >= 4
|
|
rols (\ra), (\ra), 4
|
|
..rotlr (\ra), ((\sh) - 4)
|
|
.elseif (\sh) >= 1
|
|
rols (\ra), (\ra), 1
|
|
..rotlr (\ra), ((\sh) - 1)
|
|
|
|
.endif
|
|
|
|
.endm
|
|
|
|
|
|
// RLDINM RA, RS, SH, MB, ME
|
|
//
|
|
// Defined as if there were an equivalent PowerPC instruction. The
|
|
// 'word' forms of the PowerPC instructions and extended mnemonics are
|
|
// undefined in order to catch programming typos.
|
|
|
|
.undefppc rlwinm, extrwi, rotlwi, rotrwi
|
|
.undefppc slwi, srwi
|
|
|
|
.macro rldinm, ra:req, rs:req, sh:req, mb:req, me:req
|
|
|
|
.if ((\sh) < 0) || ((\sh) > 63)
|
|
.error "SH must be in the range 0..63"
|
|
.endif
|
|
.if ((\mb) < 0) || ((\mb) > 63)
|
|
.error "MB must be in the range 0..63"
|
|
.endif
|
|
.if ((\me) < 0) || ((\me) > 63)
|
|
.error "ME must be in the range 0..63"
|
|
.endif
|
|
|
|
.if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1)))
|
|
|
|
// The mask is effectively 0..63, i.e., no mask. This is a
|
|
// simple rotate.
|
|
|
|
..rotlrr (\ra), (\rs), (\sh)
|
|
|
|
.else
|
|
|
|
// We need a mask step. However if SH == 0 and RA == RS we can
|
|
// bypass the rotate step.
|
|
|
|
.if ((\sh) != 0) || ((\ra) != (\rs))
|
|
..rotlrr (\ra), (\rs), (\sh)
|
|
.endif
|
|
.if ((\mb) <= (\me))
|
|
|
|
// This is a straightforward masking operation with a
|
|
// single mask.
|
|
|
|
andi (\ra), (\ra), ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me))))
|
|
.else
|
|
|
|
// This is a wrapped mask.
|
|
// It is created as 2 masks OR-ed together - 0-ME and MB-63
|
|
|
|
andi (\ra), (\ra), (((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63))))
|
|
.endif
|
|
|
|
.endif
|
|
|
|
.endm
|
|
|
|
// RLDINM Extended Mnemonics
|
|
//
|
|
// Defined as if they were equivalent to PowerPC 32-bit extended
|
|
// mnemonics
|
|
|
|
.macro extldi, ra:req, rs:req, n:req, b:req
|
|
.if ((\n) < 0)
|
|
.error "EXTLDI requires N > 0"
|
|
.endif
|
|
rldinm (\ra), (\rs), (\b), 0, ((\n) - 1)
|
|
.endm
|
|
|
|
.macro extrdi, ra:req, rs:req, n:req, b:req
|
|
.if ((\n) < 0)
|
|
.error "EXTRDI requires N > 0"
|
|
.endif
|
|
rldinm (\ra), (\rs), (((\b) + (\n)) % 64), (64 - (\n)), 63
|
|
.endm
|
|
|
|
.macro rotldi, ra:req, rs:req, n:req
|
|
rldinm (\ra), (\rs), (\n), 0, 63
|
|
.endm
|
|
|
|
|
|
.macro rotrdi, ra:req, rs:req, n:req
|
|
rldinm (\ra), (\rs), (64 - (\n)), 0, 63
|
|
.endm
|
|
|
|
|
|
.macro sldi, ra:req, rs:req, n:req
|
|
rldinm (\ra), (\rs), (\n), 0, (63 - (\n))
|
|
.endm
|
|
|
|
|
|
.macro srdi, ra:req, rs:req, n:req
|
|
rldinm (\ra), (\rs), (64 - (\n)), (\n), 63
|
|
.endm
|
|
|
|
|
|
// RLDIMI RA, RS, SH, MB, ME
|
|
//
|
|
// Defined as if there were an equivalent PowerPC instruction. The
|
|
// 'word' forms of the PowerPC instructions and extended mnemonics are
|
|
// undefined in order to catch programming typos.
|
|
//
|
|
// Note that unlike the PowerPC instructions, here RLDIMI must destroy
|
|
// RS by masking and shifting it, and RA and RS may not be the same
|
|
// register.
|
|
|
|
.undefppc rlwimi, inslwi, insrwi
|
|
|
|
.macro rldimi, ra:req, rs:req, sh:req, mb:req, me:req
|
|
|
|
..dxdy (\ra), (\rs)
|
|
|
|
// SH error checks are done by rldinm
|
|
|
|
.if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1)))
|
|
|
|
// The mask is effectively 0..63, i.e., no mask. This is a
|
|
// simple rotate of RS into RA
|
|
|
|
rotldi (\ra), (\rs), (\sh)
|
|
|
|
.else
|
|
|
|
// Rotate RS and AND with mask
|
|
|
|
rldinm (\rs), (\rs), (\sh), (\mb), (\me)
|
|
|
|
// Mask out the significant bits of RS, clear that section of
|
|
// RA, and logical OR RS into RA
|
|
|
|
.if ((\mb) <= (\me))
|
|
|
|
// This is a straightforward masking operation with a
|
|
// single mask.
|
|
|
|
andi (\ra), (\ra), \
|
|
(~((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me)))))
|
|
.else
|
|
|
|
// This is a wrapped mask.
|
|
// It is created as 2 masks OR-ed together - 0-ME and MB-63
|
|
|
|
andi (\ra), (\ra), \
|
|
(~(((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | \
|
|
((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63)))))
|
|
.endif
|
|
|
|
or (\ra), D0, D1
|
|
|
|
.endif
|
|
|
|
.endm
|
|
|
|
// RLDIMI Extended Mnemonics
|
|
//
|
|
// Defined as if they were equivalent to PowerPC 32-bit extended
|
|
// mnemonics
|
|
|
|
.macro insldi, ra:req, rs:req, n:req, b:req
|
|
.if ((\n) < 0)
|
|
.error "INSLDI requires N > 0"
|
|
.endif
|
|
rldimi (\ra), (\rs), (64 - (\b)), (\b), ((\b) + (\n) - 1)
|
|
.endm
|
|
|
|
.macro insrdi, ra:req, rs:req, n:req, b:req
|
|
.if ((\n) < 0)
|
|
.error "INSRDI requires N > 0"
|
|
.endif
|
|
rldimi (\ra), (\rs), (64 - (\b) - (\n)), (\b), ((\b) + (\n) - 1)
|
|
.endm
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// .HOOK
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// The PoreVe (PORE Virtual Environment) is a PORE simulation
|
|
// environment that allows the programmer to embed C/C++ code into the
|
|
// PORE assembler source code, and arranges for the C/C++ code to be
|
|
// executed in-line with the PORE assembly code. Instances of the
|
|
// .hook macro are inserted into the assembler input by the
|
|
// hook_extractor script, to mark the locations where hooks are
|
|
// present. The hook reference is a string that combines the source
|
|
// file name with an index number to uniquely identify the hook.
|
|
//
|
|
// .hook <file name>_<sequence number>
|
|
//
|
|
// The .hook macro marks the location of each hook in the relocatable
|
|
// binaries with special symbols. The symbol name includes the hook
|
|
// reference, which is used to locate the hook in the HookManager
|
|
// symbol table. Because hooks can be defined in macros, a hook that
|
|
// appears once in a source file may appear multiple times in the
|
|
// final binary. For this reason each hook must also be tagged with a
|
|
// unique index number to avoid symbol name collisions. The
|
|
// complexity of the .hook macro is due to the necessity to decode a
|
|
// dynamic symbol value (_PGAS_HOOK_INDEX) into its binary string form
|
|
// to create the unique symbol name. The final hook symbol has the
|
|
// form:
|
|
//
|
|
// __hook__<unique>_<reference>
|
|
//
|
|
// where <unique> is a binary string. It is then straightforward to
|
|
// locate these symbols in the 'nm' output of the final link and
|
|
// create a map of final addresses to the hook routine to call (the
|
|
// <reference>) before executing the instruction at that address.
|
|
//
|
|
// Note: The maximum nesting depth of the recursive ..hook_helper
|
|
// macro is log2(index), and the assembler supports nesting of at
|
|
// least 32 which is much more than sufficient.
|
|
|
|
.set _PGAS_HOOK_INDEX, 0
|
|
|
|
.macro .hook, reference:req
|
|
.set _PGAS_HOOK_INDEX, (_PGAS_HOOK_INDEX + 1)
|
|
..hook_helper _PGAS_HOOK_INDEX, "", \reference
|
|
.endm
|
|
|
|
.macro ..hook_helper, index, unique, reference
|
|
.ifeq \index
|
|
__hook__\unique\()_\reference\():
|
|
.elseif (\index % 2)
|
|
..hook_helper (\index / 2), 1\unique, \reference
|
|
.else
|
|
..hook_helper (\index / 2), 0\unique, \reference
|
|
.endif
|
|
.endm
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Help for Conversion from Old to New PGAS syntax
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
.macro loadp, arg:vararg
|
|
.error "PGAS now implements 'lpcs' rather then 'loadp'"
|
|
.endm
|
|
|
|
.macro loadx, arg:vararg
|
|
.error "PGAS now implements 'la' rather than 'loadx'"
|
|
.endm
|
|
|
|
#endif // __ASSEMBLER__
|
|
|
|
#ifdef PGAS_PPC
|
|
#include "pgas_ppc.h"
|
|
#endif
|
|
|
|
#endif // __PGAS_H__
|