aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/libpore/pgas.h
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/libpore/pgas.h')
-rw-r--r--roms/skiboot/libpore/pgas.h1169
1 files changed, 1169 insertions, 0 deletions
diff --git a/roms/skiboot/libpore/pgas.h b/roms/skiboot/libpore/pgas.h
new file mode 100644
index 000000000..5d1dbf384
--- /dev/null
+++ b/roms/skiboot/libpore/pgas.h
@@ -0,0 +1,1169 @@
+/* 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__