#ifndef __PGAS_PPC_H__
#define __PGAS_PPC_H__
// $Id: pgas_ppc.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/pgas_ppc.h,v $
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2013
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------
// ** 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_ppc.h
/// \brief Legacy PGAS assembler implemented as PowerPC assembler macros.
///
/// PGAS is documented in a seperate standalone document entitled PGAS :
/// PORE GAS (GNU Assembler) User's and Reference Manual .
///
/// This file contains the legacy PGAS assembler, which was first implemented
/// as this set of assembler macros for the PowerPC assembler. This file is
/// included into pgas.h if the compile switch PGAS_PPC is defined in the
/// compile environment.
#ifdef __ASSEMBLER__
////////////////////////////////////////////////////////////////////////////
// PGAS Base Assembler
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Symbolic Register Mnemonics
//////////////////////////////////////////////////////////////////////
//
// PGAS uses gas symbols for register mnemonics so that they will
// appear as-is in assembler listings, but we can still do arithmetic
// on the mnemonics in the PGAS macros.
.set P0, PORE_REGISTER_PRV_BASE_ADDR0
.set P1, PORE_REGISTER_PRV_BASE_ADDR1
.set A0, PORE_REGISTER_OCI_BASE_ADDR0
.set A1, PORE_REGISTER_OCI_BASE_ADDR1
.set CTR, PORE_REGISTER_SCRATCH0
.set D0, PORE_REGISTER_SCRATCH1
.set D1, PORE_REGISTER_SCRATCH2
.set EMR, PORE_REGISTER_ERROR_MASK
.set ETR, PORE_REGISTER_EXE_TRIGGER
.set SPRG0, PORE_REGISTER_DATA0
.set PC, PORE_REGISTER_PC
.set IFR, PORE_REGISTER_IBUF_ID
//////////////////////////////////////////////////////////////////////
// Core Instruction Set
//////////////////////////////////////////////////////////////////////
// The final construction of an instruction word. The opcode is a
// 7-bit value and the operand is always a 24-bit value. Note that the
// parity bit is always 0.
.macro ..instruction, opcode, operand
.long (\opcode << 25) | (\operand)
.endm
// NOP, TRAP, RET
.macro nop
..instruction PGAS_OPCODE_NOP, 0
.endm
.macro trap
..instruction PGAS_OPCODE_TRAP, 0
.endm
.macro ret
..instruction PGAS_OPCODE_RET, 0
.endm
// WAITS, HALT, HOOKI
.macro waits, u24:req
..check_u24 (\u24)
.if ((\u24) == 0)
.error "PGAS does not allow WAITS 0; Use HALT if the intention is to halt"
.endif
..instruction PGAS_OPCODE_WAITS, (\u24)
.endm
.macro halt
..instruction PGAS_OPCODE_WAITS, 0
.endm
.macro hooki, u24:req, imm:req
..check_u24 (\u24)
..instruction PGAS_OPCODE_HOOKI, (\u24)
.quad (\imm)
.endm
.macro wait, args:vararg
.error "PGAS implements the 'waits' mnemonic instead of PORE 'wait'"
.endm
.macro hook, args:vararg
.error "PGAS implements the 'hooki' mnemonic instead of PORE 'hook'"
.endm
// BRA, LOOP
//
// Note that all branch offsets in PORE are WORD offsets, so the byte
// offsets computed by the underlying assembler need to be divided by
// 4. Unfortunately PGAS is not able to check whether the offsets fit
// in the allowed space.
.macro ..bra, opcode, target
..instruction \opcode, ((((\target) - $) / 4) & 0xffffff)
.endm
.macro bra, target:req
..bra PGAS_OPCODE_BRA, (\target)
.endm
.macro loop, target:req
..bra PGAS_OPCODE_LOOP, (\target)
.endm
// BRAZ, BRANZ
.macro ..brac, opcode, src, target
..branch_compare_data (\src)
..instruction \opcode, ((\src << 20) | ((((\target) - $) / 4) & 0xfffff))
.endm
.macro braz, src:req, target:req
..brac PGAS_OPCODE_BRAZ, (\src), (\target)
.endm
.macro branz, src:req, target:req
..brac PGAS_OPCODE_BRANZ, (\src), (\target)
.endm
// CMPIBRAEQ, CMPIBRANE
.macro ..cmpibra, opcode, src, target, imm
..d0 (\src)
..instruction \opcode, ((((\target) - $) / 4) & 0xffffff)
.quad (\imm)
.endm
.macro cmpibraeq, src:req, target:req, imm:req
..cmpibra PGAS_OPCODE_CMPIBRAEQ, (\src), (\target), (\imm)
.endm
.macro cmpibrane, src:req, target:req, imm:req
..cmpibra PGAS_OPCODE_CMPIBRANE, (\src), (\target), (\imm)
.endm
.macro cmpbra, args:vararg
.error "PGAS implements the 'cmpibraeq' mnemonic instead of PORE 'cmpbra'"
.endm
.macro cmpnbra, args:vararg
.error "PGAS implements the 'cmpibrane' mnemonic instead of PORE 'cmpnbra'"
.endm
// BRAD, BSRD
.macro ..brad, opcode, src
..data (\src)
..instruction \opcode, ((\src) << 20)
.endm
.macro brad, src:req
..brad PGAS_OPCODE_BRAD, (\src)
.endm
.macro bsrd, src:req
..brad PGAS_OPCODE_BSRD, (\src)
.endm
// ANDI, ORI, XORI
.macro ..ilogic, opcode, dest, src, imm
..data (\dest)
..data (\src)
..instruction \opcode, (((\dest) << 20) | ((\src) << 16))
.quad \imm
.endm
.macro andi, dest:req, src:req, imm:req
..ilogic PGAS_OPCODE_ANDI, (\dest), (\src), (\imm)
.endm
.macro ori, dest:req, src:req, imm:req
..ilogic PGAS_OPCODE_ORI, (\dest), (\src), (\imm)
.endm
.macro xori, dest:req, src:req, imm:req
..ilogic PGAS_OPCODE_XORI, (\dest), (\src), (\imm)
.endm
// AND, OR, XOR, ADD, SUB
.macro ..alurr, opcode, dest, src1, src2
..data (\dest)
..d0d1 (\src1), (\src2)
..instruction \opcode, ((\dest) << 20)
.endm
.macro and, dest:req, src1:req, src2:req
..alurr PGAS_OPCODE_AND, (\dest), (\src1), (\src2)
.endm
.macro or, dest:req, src1:req, src2:req
..alurr PGAS_OPCODE_OR, (\dest), (\src1), (\src2)
.endm
.macro xor, dest:req, src1:req, src2:req
..alurr PGAS_OPCODE_XOR, (\dest), (\src1), (\src2)
.endm
.macro add, dest:req, src1:req, src2:req
..alurr PGAS_OPCODE_ADD, (\dest), (\src1), (\src2)
.endm
.macro sub, dest:req, src1:req, src2:req
..alurr PGAS_OPCODE_SUB, (\dest), (\src1), (\src2)
.endm
// ADDS, SUBS
.macro ..inc, opcode, dest, src, short
..check_s16 (\short)
..ls_destination (\dest)
..same (\dest), (\src)
..instruction (\opcode), (((\dest) << 20) | ((\short) & 0xffff))
.endm
.macro adds, dest:req, src:req, short:req
..inc PGAS_OPCODE_ADDS, (\dest), (\src), (\short)
.endm
.macro subs, dest:req, src:req, short:req
..inc PGAS_OPCODE_SUBS, (\dest), (\src), (\short)
.endm
.macro addi, args:vararg
.error "PGAS implements the 'adds' mnemonic instead of PORE 'addi'"
.endm
.macro subi, args:vararg
.error "PGAS implements the 'subs' mnemonic instead of PORE 'subi'"
.endm
// NEG
.macro neg, dest:req, src:req
..data (\dest)
..data (\src)
..instruction PGAS_OPCODE_NEG, (((\dest) << 20) | ((\src) << 16))
.endm
// MR
.macro mr, dest:req, src:req
..mr_destination (\dest)
..mr_source (\src)
..instruction PGAS_OPCODE_MR, (((\dest) << 20) | ((\src) << 16))
.endm
.macro copy, args:vararg
.error "PGAS implents the 'mr' mnemonic instead of PORE 'copy'"
.endm
// ROLS
.macro rols, dest:req, src:req, short:req
..data (\dest)
..data (\src)
.if ((\short) != 1)
.if ((\short) != 4)
.if ((\short) != 8)
.if ((\short) != 16)
.if ((\short) != 32)
.error "The legal ROLS shift amounts are 1, 4, 8, 16 and 32"
.endif
.endif
.endif
.endif
.endif
..instruction PGAS_OPCODE_ROLS, (((\dest) << 20) | ((\src) << 16) | (\short))
.endm
.macro rol, args:vararg
.error "PGAS implements the 'rols' mnemonic instead of PORE 'rol'"
.endm
// LS
.macro ls, dest:req, short:req
..ls_destination (\dest)
..check_s20 (\short)
..instruction PGAS_OPCODE_LS, (((\dest) << 20) | ((\short) & 0xfffff))
.endm
.macro load20, args:vararg
.error "PGAS implements the 'ls' mnemonic instead of PORE 'load20'"
.endm
// LI, LIA
.macro ..li, dest:req
..li_destination (\dest)
..instruction PGAS_OPCODE_LI, ((\dest) << 20)
.endm
.macro li, dest:req, imm:req
..li (\dest)
.quad (\imm)
.endm
.macro lia, dest:req, space:req, offset:req
..lia_destination (\dest)
..li (\dest)
.quadia (\space), (\offset)
.endm
.macro load64, args:vararg
.error "PGAS implements the 'li' mnemonic instead of PORE 'load64'"
.endm
// LD, LDANDI, STD, STI, STIA, BSI, BCI
//
// For LD, LDANDI, and STD, PGAS does not expose the underlying
// register-specific opcodes but only provides the general form.
//
// The base register is used to determine if this is a load/store from
// the pervasive or memory address spaces. For memory space accesses
// the offset is a 22-bit unsigned value, and the final ima24 is
//
// 1
//
// PGAS will not assemble relocatable offsets, and checks that offsets
// fit in 24 bits.
//
// For pervasive accesses, it is assumed that the offset provided is a
// 32-bit SCOM address. Here the final ima24 is
//
// 000
//
// PGAS checks that the 32-bit SCOM address looks like a SCOM address
// in that SCOM adresses are required to have bits 0 and 8:11 == 0.
//
// Note that memory and pervasive base registers use a 0/1 encoding
// here, not the 4-bit encoding used elsewhere in the ISA. The bit
// appearing in the instruction is the low-order bit of the register
// encoding.
.macro ..pervasive_ima24, opcode, offset, base
..check_scom (\offset)
..instruction (\opcode), ((((\base) % 2) << 22) | ((\offset) & 0x3fffff))
.endm
.macro ..memory_ima24, opcode, offset, base
..check_u24 (\offset)
.if ((\offset) % 8)
.error "The memory space offset is not a multiple of 8 - assumed alignment error"
.endif
..instruction (\opcode), (0x800000 | (((\base) % 2) << 22) | ((\offset) & 0x3fffff))
.endm
.macro ..ima24, opcode, offset, base
.if ((\base == P0) || ((\base == P1)))
..pervasive_ima24 (\opcode), (\offset), (\base)
.elseif ((\base == A0) || ((\base == A1)))
..memory_ima24 (\opcode), (\offset), (\base)
.else
.error "Expecting either a 'Pervasive Chiplet ID' or an 'Address' register"
.endif
.endm
.macro ..ima24_select, opcode0, opcode1, dest, offset, base
..data (\dest)
.if ((\dest) == D0)
..ima24 (\opcode0), (\offset), (\base)
.else
..ima24 (\opcode1), (\offset), (\base)
.endif
.endm
.macro ld, dest:req, offset:req, base:req
..ima24_select PGAS_OPCODE_LD0, PGAS_OPCODE_LD1, (\dest), (\offset), (\base)
.endm
.macro ldandi, dest:req, offset:req, base:req, imm:req
..ima24_select PGAS_OPCODE_LD0ANDI, PGAS_OPCODE_LD1ANDI, (\dest), (\offset), (\base)
.quad (\imm)
.endm
.macro std, dest:req, offset:req, base:req
..ima24_select PGAS_OPCODE_STD0, PGAS_OPCODE_STD1, (\dest), (\offset), (\base)
.endm
.macro sti, offset:req, base:req, imm:req
..ima24 PGAS_OPCODE_STI, (\offset), (\base)
.quad (\imm)
.endm
.macro stia, offset:req, base:req, space:req, addr:req
..ima24 PGAS_OPCODE_STI, (\offset), (\base)
.quadia (\space), (\addr)
.endm
.macro ..bsi, opcode, dest, offset, base, imm
..d0 (\dest)
..ima24 (\opcode), (\offset), (\base)
.quad (\imm)
.endm
#ifdef IGNORE_HW274735
// BSI and BCI are normally redacted due to HW274735. See also pgas.h
.macro bsi, dest:req, offset:req, base:req, imm:req
..bsi PGAS_OPCODE_BSI, (\dest), (\offset), (\base), (\imm)
.endm
.macro bci, dest:req, offset:req, base:req, imm:req
..bsi PGAS_OPCODE_BCI, (\dest), (\offset), (\base), (\imm)
.endm
#endif // IGNORE_HW274735
.macro scr1rd, args:vararg
.error "PGAS implements the 'ld' mnemonic instead of the PORE 'scr1rd'"
.endm
.macro scr2rd, args:vararg
.error "PGAS implements the 'ld' mnemonic instead of the PORE 'scr2rd'"
.endm
.macro scr1rda, args:vararg
.error "PGAS implements the 'ldandi' mnemonic instead of the PORE 'scr1rda'"
.endm
.macro scr2rda, args:vararg
.error "PGAS implements the 'ldandi' mnemonic instead of the PORE 'scr2rda'"
.endm
.macro scr1wr, args:vararg
.error "PGAS implements the 'std' mnemonic instead of the PORE 'scr1wr'"
.endm
.macro scr2wr, args:vararg
.error "PGAS implements the 'std' mnemonic instead of the PORE 'scr2wr'"
.endm
.macro wri, args:vararg
.error "PGAS implements the 'sti' mnemonic instead of the PORE 'wri'"
.endm
.macro bs, args:vararg
.error "PGAS implements the 'bsi' mnemonic instead of the PORE 'bs'"
.endm
.macro bc, args:vararg
.error "PGAS implements the 'bci' mnemonic instead of the PORE 'bc'"
.endm
// SCAND
//
// The 24-bit operand here is
//
// 000000
.macro scand, update:req, capture:req, length:req, select:req, offset:req
.if (((\update) != 0) && ((\update) != 1))
.error "SCAND requires a binary value for 'update'"
.endif
.if (((\capture) != 0) && ((\capture) != 1))
.error "SCAND requires a binary value for 'capture'"
.endif
..check_u16 (\length)
..instruction PGAS_OPCODE_SCAND, ((\update << 23) | (\capture << 22) | (\length))
.long (\select)
.long (\offset)
.endm
// BRAIA, BSR, CMPIBSREQ
//
// In order to support separate compilation in PGAS programs being
// linked with the PowerPC linker it is necessary to implement BSR and
// CMPIBSREQ in terms of BRAIA. These instructions require that the
// default address space have been defined. The BSR instructions
// first take a short local subroutine branch to create a stack frame,
// then use BRAIA to branch to the (relocatable) target address. The
// return from the subroutine then branches around the BRAIA to
// complete the sequence.
.macro braia, space:req, offset:req
..instruction PGAS_OPCODE_BRAI, 0
.quadia (\space), (\offset)
.endm
.macro ..bsr, target
..bra PGAS_OPCODE_BSR, (\target)
.endm
.macro bsr, target:req
..check_default_space
..bsr (. + 8)
bra (. + 16)
braia _PGAS_DEFAULT_SPACE, (\target)
.endm
.macro cmpibsreq, src:req, target:req, imm:req
..d0 (\src)
..check_default_space
cmpibrane (\src), (. + 32), (\imm)
..bsr (. + 8)
bra (. + 16)
braia _PGAS_DEFAULT_SPACE, (\target)
.endm
#endif // __ASSEMBLER__
#endif // __PGAS_PPC_H__