- Introduction
- Defining the STFLE feature bits
- Defining the feat900
FEATUREbuild macros - Verifying
FEATUREbuild macro sanity - Defining the facility.c run-time tables and functions
5a. TheFTtable
5b. TheFT2table
5c.modxxxModification Check functions
5d.instrxxxUpdate Opcode Table functions - Coding the facility instructions themselves
6a.DEF_INSTinopcode.h
6b.UNDEF_INSTandGENx___x___x900inopcode.c
6c. The actualesame.cinstruction function itself
IBM's z/Architecture supports the concept of Facilities, many of which have a corresponding facility list bit assigned to them, available to the program via the STORE FACILITY LIST EXTENDED (STFLE) instruction.
Hercules's support of z/Architecture facilities is controlled
by the facility.c, stfl.h, feat900.h and featchk.h source files:
- stfl.h defines the actual STFLE facility list bits themselves
- feat900.h defines the
FEATURE...build macros - featchk.h enforces
FEATURE...build macro sanity - facility.c implements the
facilitycommand and table-based control of facility bits and instructions
The stfl.h header defines the actual STFLE feature bits themselves. The #define
macros contain the bit numbers in their name since many of the defined facilities have very
similar names. This reduces the likelihood of using the wrong macro name in the code.
The stfl.h header looks like this:
#define STFL_000_N3_INSTR 0 /* Instructions marked N3
are installed */
#define STFL_001_ZARCH_INSTALLED 1 /* z/Arch mode is available on
this processor */
#define STFL_002_ZARCH_ACTIVE 2 /* z/Architecture architecural
mode active. When bit 2 and
168 are both zero, ESA/390
mode is active. When bit 2
is zero and bit 168 is one,
ESA/390-compatibility mode
is active. */
#define STFL_003_DAT_ENHANCE_1 3 /* DAT-Enhancement Facility 1
is installed. */
#define STFL_004_IDTE_SC_SEGTAB 4 /* IDTE selective clearing
when segtab invalidated. Bit
3 is one if bit 4 is one. */
...etc...
#define STFL_153_UNASSIGNED 153 /* Unassigned */
#define STFL_154_UNASSIGNED 154 /* Unassigned */
#define STFL_155_MSA_EXTENSION_9 155 /* Message-security-assist-
extension-9 installed.
Bits 76 and 77 are one
when bit 155 is one. */
#define STFL_156_IBM_INTERNAL 156 /* IBM internal use */
//efine STFL_nnn_UNASSIGNED 157-167 /* Unassigned or IBM internal*/
#define STFL_168_ESA390_COMPAT_MODE 168 /* ESA/390-compatibility-mode.
Bit 168 can only be 1 when
bit 2 is zero. */
#define STFL_IBM_LAST_BIT 168 /* Last defined IBM facility */
#define STFL_IBM_BY_SIZE (ROUND_UP( STFL_IBM_LAST_BIT, 8 ) / 8)
#define STFL_IBM_DW_SIZE (ROUND_UP( STFL_IBM_BY_SIZE, sizeof( DW )) / sizeof( DW ))
Please note the comments on some of the definitions (e.g.
"Bits 76 and 77 are one when bit 155 is one"). It is very important to
document such conditions as their enforcement is one of the primary purposes
of the facility command, controlled via the FT2 table
and corresponding modxxx functions.
Our FEATURE... build macros control actual code generation for a given build
architecture according to whether the macro is defined or not in each architecture's
"feature" header (e.g. feat370.h for System/370, feat390.h
for ESA/390 or feat900.h for z/Architecture).
The FEATURE_xxx... #defines for facilities contain the bit numbers in their name,
just like the STFL_xxx... #defines in header stfl.h do:
...
#define FEATURE_037_FP_EXTENSION_FACILITY /*@SRO*/
//efine FEATURE_038_OP_CMPSC_FACILITY
#define FEATURE_040_LOAD_PROG_PARAM_FACILITY
#define FEATURE_041_DFP_ROUNDING_FACILITY
#define FEATURE_041_FPR_GR_TRANSFER_FACILITY
#define FEATURE_041_FPS_ENHANCEMENT_FACILITY
#define FEATURE_041_FPS_SIGN_HANDLING_FACILITY
#define FEATURE_041_IEEE_EXCEPT_SIM_FACILITY
#define FEATURE_042_DFP_FACILITY /*DFP*/
#define FEATURE_043_DFP_HPERF_FACILITY
...etc...
The featchk.h header not only #defines our all-important
_FEATURE_xxx... underscore macros (depending on whether or not the given
feature is #defined for any of the build architectures), but also enforces
feature definition sanity.
For example, it checks to make sure that if the Constrained-Transactional-Execution Facility FEATURE is #defined, that the Transactional-Execution Facility FEATURE is also #defined:
#if defined( FEATURE_050_CONSTR_TRANSACT_FACILITY )
#define _FEATURE_050_CONSTR_TRANSACT_FACILITY
#endif
...
#if defined( FEATURE_073_TRANSACT_EXEC_FACILITY )
#define _FEATURE_073_TRANSACT_EXEC_FACILITY
#endif
...
#if defined( FEATURE_050_CONSTR_TRANSACT_FACILITY ) && !defined( FEATURE_073_TRANSACT_EXEC_FACILITY )
#error Constrained-transactional-execution facility requires Transactional-execution facility
#endifThe same facility dependency concept (one facility being dependent on, or implying, another)
is also enforced at runtime (but accomplished differently of course) by the
modxxx function declared in the
facility's FT2 table entry.
The code in facility.c controls virtually all aspects of Hercules's
facility support, creating (initializing) the facility list bit strings in SYSBLK,
allowing user control over the setting or clearing (enabling or disabling) of any
given facility via the facility command, as well disabling or enabling instructions
associated with a given facility.
The FT table is an architecture dependent table that gets built differently
for each #defined build architecture (OPTION_370_MODE, OPTION_390_MODE and
OPTION_900_MODE) depending on which FEATURE_999_XXX... facilities are #defined
for each build architecture.
During Hercules startup and initialization, bldcfg.c's build_config
function calls into facility.c's init_facilities_lists function
to initialize the sysblk.facility_list variable in SYSBLK. It first merges the
three separate architecture dependent FT tables into one master internal
architecture independent table called factab
(the FT2 table controls this merging),
and it is this master factab table
that is then used to initialize each architecture's sysblk.facility_list variable
in SYSBLK depending on whether the given facility is enabled or not for that
particular architecture or not.
The format of the FT table is quite simple:
- Supported: which architecture(s) the given facility applies to
- Default: which architecture(s) have the facility enabled by default
- Required: which architecture(s) REQUIRE the facility (which prevents it from being disabled)
- Short name: the abbreviated "name" of the facility as used by the
FACILITY_ENABLEDmacro (which is just the stfl.h header #define name without the "STFL_"):
/*-------------------------------------------------------------------*/
/* Temporary ARCH_DEP Facility Table */
/*-------------------------------------------------------------------*/
static FACTAB ARCH_DEP( facs_tab )[] = /* Arch-DEPENDENT table */
{
/*-------------------------------------------------------------------*/
/* Sup Def Req Short Name... */
/*-------------------------------------------------------------------*/
...
#if defined( FEATURE_018_LONG_DISPL_INST_FACILITY )
FT( Z90X, Z900, Z900, 018_LONG_DISPL_INST )
#endif
...etc...The Sup (Supported), Def (Default) and Req (Required) parameters use one of eight defined values #defined at the very beginning of facility.c:
- NONE (no architectures or facility disabled)
- S370 (S/370 only)
- E390 (ESA/390 only)
- Z900 (z/Arch only)
- Z390 (both ESA/390 and z/Arch)
- Z39X (E390 + Z900 + optionally S370)
- Z90X (Z900 + optionally S370)
- MALL (all architectures)
The FT2 table defines additional information for each facility defined to the
system, such as the name of the facility's modxxx
Modification Check function, the name of the facility's
instrxxx Update Opcode Table function
and the facility's "Long" name (description).
The information in the FT2 table is "merged" with each architecture's
FT table (by the init_facilities_lists function
called by bldcfg.c's build_config function during Hercules
startup and initialization) to create the master factab table used to
initialize the sysblk.facility_list variable in SYSBLK.
The modxxx parameter defines the
name of the facility's Modification Check function which defines the function
that controls the enabling and disabling of that particular facility bit when
the given facility requires or implies one or more other facility bits also
being set. Refer to the next section just below for more information about the
modxxx Modification Check function.
The instrxxx Update Opcode Table function
parameter defines the function which controls the enabling or disabling of the actual
instructions themselves defined by the facility. That is to say, certain facilities
define new z/Architecture instructions which only exist if that given facility exists
(i.e. if that particular facility list bit is one). If the facility doesn't exist (i.e.
if the facility list bit is off or zero), then the instructions that facility introduced
do not exist, and attempts to execute such instructions cause an immediate "Operation
Exception" Program Check interruption.
/*-------------------------------------------------------------------*/
/* The ACTUAL facilities table, initialized by init_facilities_lists */
/*-------------------------------------------------------------------*/
/* The individual ARCH_DEP( facs_tab ) tables are merged into this */
/* table to yield the actual facilities table the system will use. */
/* Refer to init_facilities_lists() function for how this is done. */
/*-------------------------------------------------------------------*/
static FACTAB factab[] =
{
/*----------------------------------------------------------------------------*/
/* (func) (func) Short Name... Long Description... */
/*----------------------------------------------------------------------------*/
...
FT2( modlong, instr18, 018_LONG_DISPL_INST, "Long-Displacement Facility" )
FT2( modlong, NULL, 019_LONG_DISPL_HPERF, "Long-Displacement Facility Has High Performance" )
...etc...
FT2( NULL, instr21, 021_EXTENDED_IMMED, "Extended-Immediate Facility" )
...etc...The "Long name" is simply the official descriptive name of the given facility and is used
by the facility command when a display of the available facilities is requested.
(The facility command supports listing available facilities by either SHORT or LONG name.)
The modxxx Modification Check functions are defined in the FT2
table entries and control the enabling or disabling of a given facility for those
facilities which are dependent on one or more other facilities.
For example, facility 18 is the "Long-Displacement Facility" and facility 19 is the "Long-Displacement Facility Has High Performance" facility. If the "Long-Displacement Facility Has High Performance" (bit 19) is enabled then it follows that the "Long-Displacement Facility" (bit 18) must necessarily also be enabled. That is to say, you cannot have facility 19 enabled without facility 18 also being enabled.
On the other hand, you may have facility 18 enabled but not facility 19. That is allowed. But having 19 enabled without also having 18 enabled too, is invalid.
It is the modxxx Modification Check function's job to enforce such restrictions,
and such functions are defined in the first parameter of the FT2
table. The actual function itself that does the enforcement looks like this:
static bool modlong ( bool enable, int bitno, int archnum, ...
...
/*-------------------------------------------------------------------*/
/* modlong */
/*-------------------------------------------------------------------*/
/* bit 19 implies bit 18 */
/*-------------------------------------------------------------------*/
FAC_MOD_OK_FUNC ( modlong )
{
if (enable)
{
if (bitno == STFL_019_LONG_DISPL_HPERF)
{
if (!FACILITY_ENABLED_ARCH( 018_LONG_DISPL_INST, archnum ))
return HHC00890E( STFL_018_LONG_DISPL_INST );
}
}
else // disabling
{
if (bitno == STFL_018_LONG_DISPL_INST)
{
if (FACILITY_ENABLED_ARCH( 019_LONG_DISPL_HPERF, archnum ))
return HHC00890E( STFL_019_LONG_DISPL_HPERF );
}
}
return true;
}Please note that the above function not only prevents enabling bit 19 unless bit 18 is first enabled, but also prevents bit 18 from being disabled as well, unless bit 19 is disabled beforehand.
For those facilities which introduce new z/Architecture instructions to go along
with the facility, the instrxxx function (defined as the second parameter of
the FT2 table) defines the list of instructions that only
exist when the given facility is enabled.
The function is called by the init_facilities_lists function at Hercules startup
(as well as by the facility command too whenever a facility is manually enabled
or disabled) to patch (update) the opcode.c instruction table to either enable or
disable the given set of instructions depending on whether the given facility is
enabled or disabled for that architecture.
This eliminates the need for each individual instruction from having to manually
check whether the given facility is enabled or not (via the FACILITY_ENABLED( ... )
macro) and then having to manually call the program_interrupt function to throw
an operation exception if it's not. Instead, this is all handled automatically
by each facility's defined instrxxx function, which looks like this:
static void instr21 ( int arch, bool enable );
...
BEG_DIS_FAC_INS_FUNC( instr21 )
{
DIS_FAC_INS( C208, "AGFI C208 ADD IMMEDIATE (64 <- 32)" );
DIS_FAC_INS( C209, "AFI C209 ADD IMMEDIATE (32)" );
...etc...
DIS_FAC_INS( B907, "LGHR B907 LOAD HALFWORD (64 <- 16)" );
DIS_FAC_INS( B927, "LHR B927 LOAD HALFWORD (32 <- 16)" );
...etc...
DIS_FAC_INS( C204, "SLGFI C204 SUBTRACT LOGICAL IMMEDIATE (64 <- 32)" );
DIS_FAC_INS( C205, "SLFI C205 SUBTRACT LOGICAL IMMEDIATE (32)" );
}
END_DIS_FAC_INS_FUNC()The first parameter of the DIS_FAC_INS macro is obviously the instruction's
hexadecimal opcode, and the second parameter is simply a unique descriptive name
for that particular instruction.
Implementing a new instruction in Hercules involves updating three source files:
the opcode.h header (which declares its existence), the
opcode.c instruction dispatch table (directing the run_cpu
instruction execution loop in cpu.c to jump to the
actual instruction function itself), and of course the actual instruction
function itself (which does not necessarily have to be in source file esame.c
but may instead be in a completely different source file, possibly its own).
Within header file opcode.h, simply insert a new DEF_INST macro
for your new instruction, guarded with the appropriate
#if defined( FEATURE_999_xxxx...) statement (where _999_xxx... is of course
the named of the FEATURE macro you defined in your feat900.h
header):
#if defined( FEATURE_049_PROCESSOR_ASSIST_FACILITY )
DEF_INST( perform_processor_assist );
#endifWithin the opcode.c source file, insert a UNDEF_INST macro for
your new instruction guarded with an appropriate
#if !defined( FEATURE_999_xxxx...) statement:
#if !defined( FEATURE_049_PROCESSOR_ASSIST_FACILITY )
UNDEF_INST( perform_processor_assist );
#endifThen about halfway down, update the appropriate GENx___x___x900 macro statement
for your instruction's opcode, defining the name of your instruction function,
the instruction's decoder format and its mnemonic:
/*B2E8*/ GENx___x___x900 (perform_processor_assist,RRF_M,"PPA"),Note that each x___ spot in the macro's name corresponds to a given build architecture.
The first x___ being replaced with x370 if the given instruction is defined to the
System/370 architecture, the second being replaced with x390 if the instruction is
defined to the ESA/390 architecture and the third spot being replaced with x900 if the
instruction is defined to z/Architecture. The /*B2E8*/ is of course just a helpful
comment documenting the instruction's opcode.
Depending on its complexity, this is perhaps the easiest part: coding the actual instruction function itself.
All you need to be careful to do is to wrap (guard) your function with the
appropriate #if defined( FEATURE_999_xxx...) and #endif statements so that
it is only compiled if that particular FEATURE is #defined for the given build
architecture:
#if defined( FEATURE_021_EXTENDED_IMMED_FACILITY )
/*-------------------------------------------------------------------*/
/* B907 LGHR - Load Long Halfword Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST( load_long_halfword_register )
{
int r1, r2; /* Values of R fields */
RRE( inst, regs, r1, r2 );
/* Load sign-extended halfword from second operand register */
regs->GR_G( r1 ) = (S64)(S16)(regs->GR_LHL( r2 ));
} /* end DEF_INST( load_long_halfword_register ) */
#endif /* defined( FEATURE_021_EXTENDED_IMMED_FACILITY ) */Please note that under normal circumstances there is no need to code any
if (FACILITY_ENABLED( ... )) statement anywhere in your instruction if
your instruction is only defined when the given facility is enabled, as
this is handled automatically by the associated facility.c
BEG_DIS_FAC_INS_FUNC function
(controlled by the instrxxx
second parameter of the FT2 table.)
When the facility is enabled, the instruction is defined and will be called.
When the facility is not enabled, the instruction is not defined and will
automatically program-check if the guest attempts to execute it. That's one
of the primary purposes of the code in facility.c.
Thus you can be assured that if your instruction is called, the corresponding
facility is indeed enabled. Otherwise your instruction function would never
have been called! Thus any use of the FACILITY_ENABLED( ... ) macro is
completely unnecessary.
