Trailing-Edge
-
PDP-10 Archives
-
bb-ee87b-sb
-
10,7/dil/dixutl.bli
There are 21 other files named dixutl.bli in the archive. Click here to see a list.
%TITLE 'DIX Utility Routines'
MODULE dixutl
! COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1983, 1985.
! ALL RIGHTS RESERVED.
!
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND
! COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
! THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR
! ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
! AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE
! SOFTWARE IS HEREBY TRANSFERRED.
!
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT
! NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL
! EQUIPMENT CORPORATION.
!
! DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF
! ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
!++
! .chapter >DIXUTL
!
! The module DIXUTL contains base routines common to all data types and
! which must be included in all images -- utility routines, as it were.
!
! FACILITY: Data Conversion Routines (DIX)
!
! ABSTRACT:
!
! ENVIRONMENT:
!
! AUTHOR: David Dyer-Bennet, Creation Date: 11-Jan-82
!--
(IDENT = '2.0(50)' ! \.p;\
! **EDIT**
%REQUIRE ('DIXSWI.REQ') ! [%O'34']
%BLISS36 (
, ENTRY ( ! ; Entry symbols:
dixpeh, dixadr, dixctp, dixcfd, ! \
dixdbd, dixifd, dixcpy, dixfbt, dixsbt, ! \
dixstd, dixbof, dixfbd, dixbpu, dixajx ! \
)
)
) =
BEGIN
%SBTTL 'Declarations'
!++
! .hl 1 Require files
!--
REQUIRE 'DIXREQ.REQ'; ! \
!++
! .hl 1 Library files
!--
%sbttl 'Edit History' ! [7] Add this entire subsection
!++
! .hl 1 Edit History
!--
LIBRARY 'VERSION';
! ; .autotable
!++ COPY
new_version (1, 0)
edit (7, '23-Aug-82', 'David Dyer-Bennet')
%( Change version and revision standards everywhere.
Files: All. )%
edit (10, '22-Sep-82', 'David Dyer-Bennet')
%( Always use long_relative addressing on VAX. )%
Edit (%O'30', '19-Jan-83', 'David Dyer-Bennet')
%( Update copyright notices, add mark at end of edit histories.
)%
Edit (%O'34', '19-May-83', 'David Dyer-Bennet')
%( Add DIXSWI require file to headings of all modules. DIXSWI
contains the BLISS32 addressing-mode declarations and the TOPS-10
OTS declaration to avoid invoking the losing default of .REQUESTING
the OTS library from whatever directory the compiler was called from
when the build ran.
)%
Edit (%O'35', '8-June-83', 'Charlotte L. Richardson')
%( Declare version 1 complete. All modules.
)%
new_version (1, 1)
new_version (2, 0)
Edit (%O'36', '11-Apr-84', 'Sandy Clemens')
%( Put all Version 2 DIX development files under edit control. Some of
the files listed below have major code edits, or are new modules. Others
have relatively minor changes, such as cleaning up a comment.
FILES: COMDIX.VAX-COM, COMPDX.CTL, DIXCST.BLI, DIXDEB.BLI,
DIXDN.BLI (NEW), DIXFBN.BLI, DIXFP.BLI, DIXGBL.BLI, DIXGEN.BLI,
DIXHST.BLI, DIXINT.PR1, DIXINT.PR2, DIXLIB.BLI, DIXPD.BLI (NEW),
DIXREQ.REQ, DIXSTR.BLI, DIXUTL.BLI, DXCM10.10-CTL, MAKDIXMSG.BLI,
STAR36.BLI, VERSION.REQ.
)%
Edit (%O'50', '8-Oct-84', 'Sandy Clemens')
%( Add new format of COPYRIGHT notice. FILES: ALL )%
! **EDIT**
!-- .autoparagraph
mark_versions ('DIX')
!++
! .hl 1 Debugging declarations
!--
!!dix$module_debug (off);
dix$module_debug (on);
!++
! .hl 1 Macros
!--
!++
! .hl 1 Literals
!--
!++
! .hl 1 Own storage
!--
! [7] Remove version number word
!++
! .hl 1 Global data
!--
!++
! .hl 2 Miscellaneous structures
! Small structures are grouped together in this section.
!--
GLOBAL
!
! ; Table of maximum data type codes within each class, used for
! ; error checking:
!
dix$at_max_dt_cod : VECTOR [dix$k_max_class + 1] ! \>\Wanted 1-origin.
PSECT (readonly_psect) ! \\Place in read-only storage.
PRESET ( [dt_string] = dt_class_string_max,
[dt_fbin] = dt_class_fbin_max,
[dt_fp] = dt_class_fp_max,
[dt_dnum] = dt_class_dnum_max,
[dt_pdec] = dt_class_pdec_max),
!
! ; Table of bits per unit for each supported system type:
!
dix$ag_sys_bpunit : VECTOR [sys_max + 1] ! \>\Really wanted 1-origin.
PSECT (readonly_psect) ! \\Place in read-only storage.
PRESET ( [sys_lcg] = 36, [sys_8bit] = 8);
%SBTTL 'Data type tables'
!++
! .hl 2 Data type tables
!
! Data tables for the various data type classes.
!
! These tables are indexed by the within-class part of the data type code.
!
! There is one table here for each class of data type supported. It
! contains information needed in all versions of the library; but it
! does not contain extensive data needed only when conversions
! involving that class are being performed.
!
! The tables are used mostly in error checking within utility
! routines.
!--
!++
! .hl 3 Alphanumeric strings
! The format of this table is defined in DIXLIB (>dtt_st>).
!
! The values used to initialize it are also there: they reside in
! macro >dt_class_string_def>. The table is initialized by declaring
! a macro here which is called when dt_class_string_def gets expanded;
! thus we control exactly how the table is initialized, although the
! data is entered in the library.
!--
MACRO
decl_string_item ! \.P;Macro \:
!++
! This macro gets called for each string data type when dt_class_string_def
! gets expanded. This definition of the macro produces preset-items
! which will statically initialize the dix$adtt_st structure.
!--
( ! ; Arguments:
class_code, item_name, short_name, type_code, byt_siz, sys_orig, length_spec ! \\.
) =
[type_code, std$v_byt_siz] = byt_siz,
[type_code, std$v_sys_orig] = sys_orig,
[type_code, std$v_lng_indic] = length_spec,
%;
GLOBAL ! ;.P;Global table
dix$adtt_st : ! \>\ the string data type table.
dtt_st ! \Type is\.
PSECT (readonly_psect) ! \Assign to \.
PRESET ( ! ; Initialize by calling
dt_class_string_def ! \\.
[0, std$v_byt_siz] = 0 ! Previous macro call leaves trailing ","
); ! End PRESET
!++
! .hl 3 Fixed-point binary
!
! The format of this table is defined in DIXLIB (>dtt_fbin>).
!
! The values used to initialize it are also there: they reside in
! macro >dt_class_fbin_def>. The table is initialized by declaring
! a macro here which is called when dt_class_fbin_def gets expanded;
! thus we control exactly how the table is initialized, although the
! data is entered in the library.
!--
MACRO
decl_fbin_item ! \.P;Macro \:
!++
! This macro gets called for each fbin data type when dt_class_fbin_def
! gets expanded. This definition of the macro produces preset-items
! which will statically initialize the dix$adtt_fbin structure.
!--
( ! ; Arguments:
class_code, item_name, short_name, type_code, length_type, fld_signed, ! \\
min_lng, max_lng, min_scale, max_scale, bpm_code ! \\.
) =
[type_code, fbd$v_variable] = %QUOTE %IF length_type EQL fbd$k_lng_variable
%THEN 1 %ELSE 0 %FI,
[type_code, fbd$v_signed] = %QUOTE %IF fld_signed EQL fbd$k_signed
%THEN 1 %ELSE 0 %FI,
[type_code, fbd$v_min_lng] = min_lng,
[type_code, fbd$v_max_lng] = max_lng,
[type_code, fbd$v_min_scale] = min_scale,
[type_code, fbd$v_max_scale] = max_scale,
[type_code, fbd$v_bpm_program] = UPLIT bpm_code,
! bpm_code provides parens
%;
GLOBAL ! ;.P;Global table
dix$adtt_fbin : ! \>\ the fbin data type table.
dtt_fbin ! \Type is\.
PSECT (readonly_psect) ! \Assign to \.
PRESET ( ! ; Initialize by calling
dt_class_fbin_def ! \\.
[0, fbd$v_bpm_program] = 0 ! Previous macro call leaves trailing ","
); ! End PRESET
!++
! .HL 3 Floating point
!
! The format of this table is defined in DIXLIB (>dtt_fp>).
!
! The values used to initialize it are also there: they reside in
! macro >dt_class_fp_def>. The table is initialized by declaring
! a macro here which is called when dt_class_fp_def gets expanded;
! thus we control exactly how the table is initialized, although the
! data is entered in the library.
!--
MACRO
decl_fp_item ! \.p;Macro \:
!++
! This macro gets called for each FP data type when dt_class_fp_def gets
! expanded. This definition of the macro produces preset items which will
! statically initialize the dix$adtt_fp structure.
!--
( ! ; Arguments:
class_code, item_name, short_name, type_code, representation, ! \\
exp_offset, mant_bits, fpm_code ! \\
) =
[type_code, fpd$v_representation] = representation,
[type_code, fpd$v_exp_offset] = exp_offset,
[type_code, fpd$v_mant_bits] = mant_bits,
[type_code, fpd$v_fpm_program] = UPLIT fpm_code,
%;
GLOBAL ! ;.P;Global table
dix$adtt_fp : ! \>\ the fp data type table.
dtt_fp ! \Type is\.
PSECT (readonly_psect) ! \Assign to \.
PRESET ( ! ; Initialize by calling
dt_class_fp_def ! \\.
[0, fpd$v_fpm_program] = 0 ! Previous macro call leaves trailing ","
); ! end Preset
!++
! .HL 3 Display numeric
!
! The format of this table is defined in DIXLIB (>dtt_dn>).
!
! The values used to initialize it are also there: they reside in
! macro >dt_class_dnum_def>. The table is initialized by declaring a
! macro here which is called when dt_class_dnum_def gets expanded;
! thus we control exactly how the table is initialized, although the
! data is entered in the library.
!--
MACRO
decl_dnum_item ! \.p;Macro \:
!++
! This macro gets called for each DNUM data type when dt_class_dnum_def
! gets expanded. This definition of the macro produces PRESET items which
! will statically initialize the dix$adtt_dn structure.
!--
( ! ; Arguements:
class_code, item_name, short_name, type_code, byte_size, ! \\
sys_orig, sign_type, char_set_name, max_length ! \\.
) =
[type_code, dnd$v_byt_siz] = byte_size,
[type_code, dnd$v_sys_orig] = sys_orig,
[type_code, dnd$v_sign_type] = sign_type,
[type_code, dnd$v_ovp_max_index] = %NAME ('ovp$k_', char_set_name, '_max'),
[type_code, dnd$v_max_length] = max_length,
[type_code, dnd$v_char_set] = %NAME ('cs_', char_set_name),
%;
GLOBAL ! ;.P;Global table
dix$adtt_dn : ! \>\ the display numeric data type table
dtt_dn ! \Type is \.
PSECT (readonly_psect) ! \Assign to \.
PRESET ( ! ; Initialize by calling
dt_class_dnum_def ! \\.
[0, dnd$v_byt_siz] = 0 ! Previous macro call leaves trailing ","
); ! End PRESET
!++
! .hl 3 Packed decimal
!
! The format of this table is defined in DIXLIB (>dtt_pd>).
!
! The values used to initialize the table are also there: they reside in
! macro >dt_class_pdec_def>. The table is initialized by declaring a macro
! here which is called when dt_class_pdec_def gets expanded; thus we control
! exactly how the table is initialized, although the data is entered in the
! library.
!--
MACRO
decl_pdec_item ! \.p;Macro \:
!++
! This macro gets called for each PDEC data type when dt_class_pdec_def
! gets expanded. This definition of the macro produces PRESET items which
! will statically initialize the dix$adtt_pd structure.
!--
(
class_code, item_name, short_name, type_code, byte_size, ! \\
nibble_size, sys_orig, max_length, sign_set ! !\\.
) =
[type_code, pdd$v_byt_siz] = byte_size,
[type_code, pdd$v_nbl_siz] = nibble_size,
[type_code, pdd$v_sys_orig] = sys_orig,
[type_code, pdd$v_max_length] = max_length,
[type_code, pdd$v_sign_set] = %NAME ('ss_', sign_set),
%;
GLOBAL ! ;.P;Global table
dix$adtt_pd : ! \>\ the packed numeric data type table
dtt_pd ! \Type is \.
PSECT (readonly_psect) ! \Assign to \.
PRESET ( ! ; Initialize by calling
dt_class_pdec_def ! \\.
[0, pdd$v_byt_siz] = 0 ! Previous macro call leavs trailing ","
); ! End PRESET
%SBTTL 'GLOBAL ROUTINE dix$$port_hand'
GLOBAL ROUTINE dix$$port_hand ! \.!=;.hl 1 \
! ; .index dix$$port_hand
!++
! By convention, this handler should be enabled by all portal
! routines to the DIX. (User interface routines use a different
! handler, in module DILINT.)
!
! This handler traps any signals that get up this high and
! returns them to the routine calling the enabling routine as the
! function return value (if any). This prevents errors from being
! "lost" in the sense of not being reported to the caller.
!
! Routine Value:
! Information for CHF, as described in BLISS condition handling
! documentation.
!
! Formal arguments:
! .list 1
!--
(
sig_vec, ! \.le;\: Signal vector, as
! ; described in BLISS condition
! ; handling documentation.
mech_vec, ! \.le;\: Mechanism vector, as
! ; described in BLISS condition
! ; handling documentation.
enabl_vec ! \.le;\: Enable vector, as
! ; described in BLISS condition
! ; handling documentation. The first
! ; parameter specified by the enabler is a
! ; local data segment in the enabler that
! ; can be used for temporary storage of
! ; error information.
) = ! ; .end list
BEGIN
MAP
sig_vec : REF VECTOR,
mech_vec : REF VECTOR,
enabl_vec : REF VECTOR;
BIND
cond = sig_vec [1] : condition_value,
return_value = mech_vec [ %BLISS16 (1) %BLISS36 (1) %BLISS32 (3)],
error_temp = .enabl_vec [1] : condition_value;
dix$routine_debug (off);
! ; .hl 2 Flow of code
IF .cond NEQ dix$unwind_cond ! ; .P;If not unwinding,
THEN
BEGIN
error_temp = .cond; ! ; store away condition value,
SETUNWIND () ! ; initiate unwind.
END
ELSE ! ; .P;When called during unwind,
return_value = .error_temp ! ; return condition value saved earlier.
END; ! END OF DIX$$PORT_HAND
%SBTTL 'GLOBAL ROUTINE dix$$copy_structure'
GLOBAL ROUTINE dix$$copy_structure ! \.!=;.hl 1 \
! ; .index dix$$copy_structure
!++
! Copy a structure. This is necessary because BLISS assignment only works
! on field references, which work on at most a fullword.
!
! Routine value: none
! Formal arguments:
! .list 1
!--
(
src_adr, ! \.le;\: Address of structure to copy
str_siz, ! \.le;\: Length in fullwords of structure
dst_adr ! \.le;\: Address of destination field
) : NOVALUE = ! ; .end list
BEGIN ! dix$$copy_structure
dix$routine_debug (off);
LOCAL
src_pnt,
dst_pnt;
dst_pnt = .dst_adr;
INCRA src_pnt FROM .src_adr TO .src_adr + (.str_siz - 1 ) * %UPVAL BY %UPVAL DO
BEGIN ! INCRA
.dst_pnt = ..src_pnt;
dst_pnt = .dst_pnt + %UPVAL;
END; ! INCRA
END; ! Dix$$copy_structure
%SBTTL 'GLOBAL ROUTINE dix$$get_argadr (LCG version)'
! LCG version of DIX$$GET_ARGADR
%IF %BLISS (BLISS36)
%THEN
GLOBAL ROUTINE dix$$get_argadr ! \.!=;.hl 1 \
! ; .index dix$$get_argadr
!++
! This routine is present only in the LCG/36 bit version.
!
! When passed the contents of a formal parameter of a routine
! called with the DEC-10/20 standard calling sequence, return the
! actual address of the first word of the argument, regardless of
! whether the field passed is display or computational.
!
! If an error (such as invalid format in the descriptors) is
! detected, signal that error to the calling routine (no handler
! is enabled at this level).
!
! Routine Value:
! The address of the first word of the actual argument.
!
! Side Effects:
! May signal a condition:
! dix$_unkargtyp
!
! Formal arguments:
! .list 1
!--
(
formal_param ! \.le;\: The value of a formal
! ; parameter from another routine
! ; called with the standard calling sequence.
) = ! ; .end list
BEGIN
BUILTIN
MACHOP, INCP;
MAP
formal_param : scs_arg;
BIND
arg_descr = .formal_param [scs$v_adr] : scs_descr;
REGISTER
arg_adr: REF scs_descr;
! ; .hl 2 Flow of Code
MACHOP (%O'415', arg_adr, formal_param, 0, on);
! ; This XMOVEI will place the adr of
! ; the argument (or its descriptor)
! ; in arg_adr.
SELECTONEU .formal_param [scs$v_type] OF
! ; .P;Process one alternative based on type field in scs argument
! ; list entry passed to us:
SET
[scs$k_for36_bool, scs$k_sbf36, scs$k_float36, scs$k_float72, !
scs$k_unspecified, ! [2] Treat unspecified as by ref
scs$k_sbf72, scs$k_fcmplx36, scs$k_asciz] :
!
! ; Argument is passed by reference; the address in the
! ; arg list is the address of the entry.
!
.arg_adr; ! ; Return address from arg list.
[scs$k_display] :
!
! ; Argument is passed by descriptor. Must
! ; retrieve address from pointer in descriptor.
!
BEGIN
LOCAL
byt_pntr;
byt_pntr = .arg_adr [scs$v_bytpntr]; ! ; Make local copy of byte pointer from descriptor.
INCP (byt_pntr); ! ; Increment to point to first byte of string.
MACHOP (%O'201', arg_adr, byt_pntr, 0, on);
! ; This MOVEI will force an effective adr
! ; calculation on the byte-pointer word
! ; and store the result in arg_adr;
! ; Thus the actual argument address becomes known.
! ; Note: I don't certify this to work in
! ; an extended addressing environment.
.arg_adr ! ; Return the address
END;
[OTHERWISE] :
!
! ; None of the above. We don't recognize the type specified.
!
SIGNAL (dix$_unkargtyp); ! \So \ to tell user.
TES ! Value of SELECTONE is value of dix$$get_argadr
END; ! END OF DIX$$GET_ARGADR
%FI ! %IF %BLISS (BLISS36)
%SBTTL 'GLOBAL ROUTINE dix$$fetch_bits'
GLOBAL ROUTINE dix$$fetch_bits ! \.!=;.hl 1 \
! ; .index dix$$fetch_bits
!++
! This routine fetches strings of bits (in order of significance) from any
! foreign record (or, for that matter, anywhere else; that's where it's useful)
! in local memory. It cannot fetch more than %BPVAL bits at a crack. It can,
! however, fetch across unit boundaries.
!
! Routine value:
! The bits fetched, or undefined if something failed (signal generated)
!
! Side Effects:
! Signal generated on error:
! List of conditions TBS
!
! Formal arguments:
!--
( ! ; .list 1
p_unit, ! \.le;\: Address of unit containing
! ; low-order bit to fetch
p_offset, ! \.le;\: Offset within that unit to !
! ; low-order bit
p_num_bits ! \.le;\: Number of bits to fetch
! ; (0 < .p_num_bits <= %bpval)
) = ! ; .end list
BEGIN
LOCAL
result,
unit,
offset,
bits_this_cycle,
bits_left;
!
! Initialize local variables
!
result = 0;
unit = .p_unit;
offset = .p_offset;
bits_left = .p_num_bits;
DO
BEGIN
bits_this_cycle = MIN (.bits_left, %BPVAL - .offset);
result <.p_num_bits - .bits_left, .bits_this_cycle> =
.(.unit) <.offset, .bits_this_cycle, 0>;
bits_left = .bits_left - .bits_this_cycle;
unit = .unit + %UPVAL;
offset = 0;
END
WHILE .bits_left GTR 0;
.result ! Value returned
END;
%SBTTL 'GLOBAL ROUTINE dix$$stuff_bits'
GLOBAL ROUTINE dix$$stuff_bits ! \.!=;.hl 1 \
! ; .index dix$$stuff_bits
!++
! This routine stuffes strings of bits (in order of significance) into any
! foreign record (or, for that matter, anywhere else; that's where it's useful)
! in local memory. It cannot stuff more than %BPVAL bits at a crack. It can,
! however, stuff across unit boundaries.
!
! Routine value:
! None
!
! Side Effects:
! Signal generated on error:
! List of conditions TBS
!
! Formal arguments:
!--
( ! ; .list 1
p_unit, ! \.le;\: Address of unit
! ; containing low-order bit to stuff
p_offset, ! \.le;\: Offset within that unit
! ; to low-order bit
p_num_bits, ! \.le;\: Number of bits to stuff
! ; (0 < .p_num_bits <= %bpval)
p_source_value ! \.le;\: Value to stuff
) : NOVALUE = ! ; .end list
BEGIN
LOCAL
unit,
offset,
bits_this_cycle,
bits_left;
!
! Initialize local variables.
!
unit = .p_unit;
offset = .p_offset;
bits_left = .p_num_bits;
DO
BEGIN
bits_this_cycle = MIN (.bits_left, %BPVAL - .offset);
(.unit) <.offset, .bits_this_cycle> =
.p_source_value <.p_num_bits - .bits_left, .bits_this_cycle>;
bits_left = .bits_left - .bits_this_cycle;
unit = .unit + %UPVAL;
offset = 0;
END
WHILE .bits_left GTR 0;
END;
%SBTTL 'Global Routine dix$$bit_offset'
GLOBAL ROUTINE dix$$bit_offset ! \.!=;.hl 1 \
! ; .index dix$$bit_offset
!++
! Given a unit and a bit offset (possibly large, positive or negative),
! compute the unit addressed and the offset within it.
!
! Routine value: NONE
!
! Formal arguments:
!--
( ! ; .s 1.list 1
in_unit, ! \.le;\: Base memory address
in_offset, ! \.le;\: bit offset from that address
out_unit_addr, ! \.le;\: Adr to write unit to
out_offset_addr ! \.le;\: Adr to write offset to
) : NOVALUE = ! ; .end list
BEGIN ! GLOBAL ROUTINE dix$$bit_offset
.out_unit_addr = .in_unit;
.out_offset_addr = .in_offset;
WHILE ..out_offset_addr LSS 0 DO
BEGIN
.out_offset_addr = ..out_offset_addr + %BPUNIT;
.out_unit_addr = ..out_unit_addr - 1;
END;
.out_unit_addr = ..out_unit_addr + ..out_offset_addr / %BPUNIT;
.out_offset_addr = ..out_offset_addr MOD %BPUNIT;
END; ! GLOBAL ROUTINE dix$$bit_offset
%SBTTL 'ROUTINE dix$$check_alignment'
ROUTINE dix$$check_alignment ! \.!=;.hl 1 \
! ; .index dix$$check_alignment
!++
! Check to see if the original-system alignment as described by the user
! is valid for the data type specified. If not, signal an alignment error.
! If so, return with no value.
!
! Routine value: None.
!
! Formal arguments:
!--
( ! ;.s 1.list 1
data_type, ! \.le;\: Data type of field
sys_origin, ! \.le;\: Code for system of origin
alignment ! \.le;\: Alignment value
) : NOVALUE = ! ;.END LIST
BEGIN ! ROUTINE dix$$check_alignment
MAP
data_type: data_type_sep;
CASE .data_type [dt_class_sep] FROM 1 TO dix$k_max_class OF ! ; Case on dt_class
SET ! ;.lm +4.!Cases
[dt_string]: ! \
!++
! Strings on the VAX must be byte aligned. Other systems can be
! aligned any old which way. String:
!--
IF .sys_origin EQL sys_8bit AND .alignment NEQ 0 THEN
SIGNAL (dix$_align);
[dt_fbin]: ! \
!++
! Fixed binary fields are all unit-aligned except for the variable
! length ones, which may be anywhere.
!
! On the lcg systems, variable length fields must fit in a word. This
! should be checked for when variable length fbin fields get implemented.
!--
IF NOT .dix$adtt_fbin [.data_type [dt_code_sep], fbd$v_variable] AND
.alignment NEQ 0 THEN
SIGNAL (dix$_align);
[dt_fp]: ! \
!++
! Floating-point fields are always unit-aligned.
!--
IF .alignment NEQ 0 THEN
SIGNAL (dix$_align);
[dt_dnum]: ! \
!++
! Display Numeric fields on the VAX must be byte aligned.
! Other systems can be aligned in any way.
!--
IF .sys_origin EQL sys_8bit AND .alignment NEQ 0 THEN
SIGNAL (dix$_align);
[dt_pdec]: ! \
!++
! Packed Decimal fields on the VAX must be byte aligned.
! Other systems can be aligned in any way.
!--
IF .sys_origin EQL sys_8bit AND .alignment NEQ 0 THEN
SIGNAL (dix$_align);
TES; ! ;.lm -4.!Cases
END; ! ROUTINE dix$$check_alignment
%SBTTL 'GLOBAL ROUTINE DIX$$CHECK_TYPE'
GLOBAL ROUTINE dix$$check_type ! \.!=;.hl 1 \
! ; .index dix$$check_type
!++
! Check the type-dependent information required in a foreign field
! descriptor. If this routine returns, the arguments passed were ok.
! If they are not ok, an appropriate condition is signalled.
!
! Routine value: None
!
! Side effects:
!
! Signals conditions as appropriate:
! .s 1.list 0, "o"
! dix$_invdattyp ! Class or type within class invalid
! dix$_invlng ! Length invalid for type specified
! dix$_invscal ! Scale invalid for type specified
! dix$_unksys ! Unknown system of origin
! .end list
!
! Formal arguments:
!--
( ! ;.s 1.list 1
dat_typ, ! \.le;\: Data type code
sys_orig, ! \.le;\: System of origin
fld_lng, ! \.le;\: Field length
scale ! \.le;\: Scale factor
) ! ;.end list
: NOVALUE = !
BEGIN ! Routine dix$$check_type
MAP
dat_typ : data_type_sep;
!
! ; .hl 2 Flow of Code
! ; Check validity of data class code.
!
IF .dat_typ [dt_class_sep] LSS 1 OR .dat_typ [dt_class_sep] GTR dix$k_max_class
THEN
SIGNAL (dix$_invdattyp); ! \
!
! ; .p;Check validity of within-class data type code.
!
IF .dat_typ [dt_code_sep] LSS 1 OR .dat_typ [dt_code_sep] GTR dix$at_max_dt_cod [.dat_typ [dt_class_sep]]
THEN
SIGNAL (dix$_invdattyp); ! \
!
! ; .p;Check system of origin.
!
IF .sys_orig LSS 1 OR .sys_orig GTR sys_max
THEN
SIGNAL (dix$_unksys); ! \
!++
! Check for necessity, presence, and validity of field length and
! scale factor.
!
! This code will be implemented piecemeal as data types are
! implemented which require it.
!--
CASE .dat_typ [dt_class_sep] FROM 1 TO dix$k_max_class OF
SET
[dt_string] :
!++
! Strings require length specification sometimes (we
! tell by the value in dix$adtt_st). Lengths must be
! positive if required.
!
! Scale factors are never used.
!--
IF .dix$adtt_st [.dat_typ [dt_code_sep], std$v_lng_indic] EQL std$k_lng_spec
! Length must be specified
AND .fld_lng LSS 1
THEN ! Length negative or 0
SIGNAL (dix$_invlng); ! \.p;\ if length is invalid.
[dt_fbin] :
!++
! Fixed-point binary always requires a scale factor. It
! requires a length if fbd$v_variable is set. The legal range
! of scale factors and lengths is stored for each data type.
!--
BEGIN ! Case dt_fbin
IF .dix$adtt_fbin [.dat_typ [dt_code_sep], fbd$v_variable]
THEN
BEGIN ! Type is variable-length
IF .fld_lng LSS .dix$adtt_fbin [.dat_typ [dt_code_sep], fbd$v_min_lng] OR
.fld_lng GTR .dix$adtt_fbin [.dat_typ [dt_code_sep], fbd$v_max_lng]
THEN
SIGNAL (dix$_invlng); ! \.p;\ if length is invalid.
END; ! Type is variable-length
IF .scale LSS .dix$adtt_fbin [.dat_typ [dt_code_sep], fbd$v_min_scale] OR
.scale GTR .dix$adtt_fbin [.dat_typ [dt_code_sep], fbd$v_max_scale]
THEN
SIGNAL (dix$_invscal); ! \.p;\ if scale is invalid.
END; ! Case dt_fbin
[dt_fp]: ! \.p;\
BEGIN ! ;.LM +4.!Case dt_fp
IF .fld_lng NEQ 0 THEN SIGNAL (dix$_invlng); ! ; Field length must be 0.
IF .scale NEQ 0 THEN SIGNAL (dix$_invscal); ! ; Scale factor must be 0.
END; ! ;.LM -4.!Case dt_fp
[dt_dnum]: ! \.p;\
!++
! Display numeric fields require a length specification.
! A maximum length is specified for each data type in the
! dix$adtt_dn table in the dnd$v_max_length entry. The
! field length must be less than or equal to the maximum
! length for the data type. For any field with a separate
! sign, the field length must be greater than or equal to 2.
! For any other sign type the field length must be greater
! than 1.
!--
BEGIN
IF (SELECTONE .dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_sign_type] OF
SET
[dnd$k_lead_sep, dnd$k_trail_sep] : .fld_lng LSS 2;
[OTHERWISE] : .fld_lng LSS 1;
TES)
OR
(.fld_lng GTR .dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_max_length])
THEN ! Length out of range
SIGNAL (dix$_invlng); ! \.p;\ if length is invalid.
!++
! The scale factor must be valid. The legal scale
! factor range is dependant upon the data type and the
! length of the specified field. The following formula
! defines the valid scale factor values:
! .literal
! (-m + l) <= s <= m
! .end literal
! where "m" is the maximum field length for the given data
! type (minus 1 for a data type with a separate sign), "l"
! is the field length specified (minus 1 for a data type
! with a separate sign), and "s" is the specified scale
! factor. Note that the maximum field length value for
! each data type is located in the table dix$adtt_dn.
!--
SELECTONE .dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_sign_type] OF
SET
[dnd$k_lead_sep, dnd$k_trail_sep] :
IF (.scale GTR .dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_max_length] - 1)
OR (.scale LSS -.dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_max_length] + .fld_lng)
THEN SIGNAL (dix$_invscal); ! \.p;\ if scale is invalid.
[OTHERWISE] :
IF (.scale GTR .dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_max_length])
OR (.scale LSS -.dix$adtt_dn[.dat_typ[dt_code_sep], dnd$v_max_length] + .fld_lng)
THEN SIGNAL (dix$_invscal); ! \.p;\ if scale is invalid.
TES
END;
[dt_pdec]: ! \.p;\
!++
! Packed decimal fields require a length specification.
! A maximum length is specified for each data type in the
! dix$adtt_pd table in the pdd$v_max_length entry. The
! field length must be less than or equal to the maximum
! length for the data type and greater than or equal to one.
!--
BEGIN
IF .fld_lng LSS 1 OR
.fld_lng GTR .dix$adtt_pd[.dat_typ[dt_code_sep], pdd$v_max_length]
THEN ! Length out of range
SIGNAL (dix$_invlng); ! \.p;\ if length is invalid.
!++
! The scale factor must be valid. The legal scale factor range
! is dependant upon the data type and the length of the specified
! field. The following formula defines the valid scale factor
! values:
! .literal
! (-m + 1) <= s <= m
! .end literal
! where "m" is the maximum field length for the given data type,
! "l" is the field length specified, and "s" is the specified
! scale factor. Note the the maximum field length value for each
! data type is located in the table dix$adtt_pd.
!--
IF (.scale GTR .dix$adtt_pd[.dat_typ[dt_code_sep], pdd$v_max_length])
OR (.scale LSS -.dix$adtt_pd[.dat_typ[dt_code_sep], pdd$v_max_length] + .fld_lng)
THEN SIGNAL (dix$_invscal) ! \.p;\ if scale is invalid.
END;
TES;
END; ! Routine dix$$check_type
%SBTTL 'GLOBAL ROUTINE DIX$$CHECK_FFD'
GLOBAL ROUTINE dix$$check_ffd ! \.!=;.hl 1 \
! ; .index dix$$check_ffd
!++
! Perform the checks on an FFD that are to be performed on each entry from
! a user routine that passes an FFD. If the FFD passes, the routine returns
! with no value. If the FFD fails, an appropriate condition is signalled.
!
! The checks performed by dix$$check_type are used here. In addition,
! Alignment checks are performed based on the data type.
!
! Routine value: None.
!
! Side effects:
!
! May signal any condition signalled by dix$$check_type.
!
! Formal arguments:
!--
( ! ; .s 1.list 1
ffd ! \.le;\: The address of a foreign field descriptor
) ! ; .end list
: NOVALUE =
BEGIN ! Routine dix$$check_ffd
MAP
ffd : REF forgn_descr;
dix$$check_type (.ffd [ffd$v_type], .ffd [ffd$v_sys_orig], .ffd [ffd$v_length], .ffd [ffd$v_scale]);
dix$$check_alignment (.ffd [ffd$v_type], .ffd [ffd$v_sys_orig], .ffd [ffd$v_align]);
END; ! Routine dix$$check_ffd
%SBTTL 'GLOBAL ROUTINE dix$$des_by_det'
GLOBAL ROUTINE dix$$des_by_det ! \.!=;.hl 1 \
! ; .index dix$$des_by_det
!++
!
! Make DIX Descriptor From Detailed Description
!
! Level = 1, DD = 1. Portal routine.
! Algorithm: Brute force. All information necessary is available.
!
! Routine value: Status value.
!
! Side Effects:
!
! May signal any condition signalled by dix$$check_type or dix$$check_alignment.
! May signal dix$_invbytsiz.
!
! Formal arguments:
!--
( ! ;.s 1.list 1
res_ffd, ! \.le;\: (by reference, written) The DIX descriptor to be produced
con_rec, ! \.le;\: (by reference) The record in which the field exists
sys_orig, ! \.le;\: (integer) A code for
! ; the system on which the record
! ; originated
byt_siz, ! \.le;\: (integer) The byte size to interpret the offset in
byt_off, ! \.le;\: (integer) The offset to the
! ; field in the record, in bytes (as
! ; defined above)
bit_off, ! \.le;\: (integer) The bit offset to
! ; the field within the selected
! ; byte
dat_typ, ! \.le;\: (integer) The code for the data type of the field
fld_lng, ! \.le;\: (integer) The length of
! ; the field in the natural
! ; units for the data type (value
! ; ignored if field is not variable length)
scal_fac ! \.le;\: (integer) The scale factor
! ; of the field if it is a fixed-point
! ; binary or display-numeric field
! ; (including packed decimal)
) = ! ; .end list
BEGIN
MAP
res_ffd : REF forgn_descr;
LOCAL
bit_disp;
!++
! .hl 2 Flow of Code
! This routine is an exception to the rule that checking of user
! arguments should be done at the interface level. The arguments for
! FFD making are checked here to avoid a horrible amount of code
! duplication in the routines for the umpteen interfaces to this.
!--
dix$$check_type (.dat_typ, .sys_orig, .fld_lng, .scal_fac); ! \\ Signals if fails
IF (.byt_siz LSS 1) OR (.byt_siz GTR .dix$ag_sys_bpunit [.sys_orig]) THEN
SIGNAL (dix$_invbytsiz); ! \ If byte size too small or large,
!
! ; Compute bit offset to lsb of field
!
bit_disp = (CASE .sys_orig FROM 1 to sys_ult OF
SET
[sys_8bit]: .byt_siz * .byt_off + .bit_off; ! ; On VAX this is simple
[sys_lcg]: (((.dix$ag_sys_bpunit [.sys_orig] - 1) - .byt_siz + 1)
! ; On LCG, not so simple
! ; Offset to first byte in first unit
+ .dix$ag_sys_bpunit [.sys_orig]*(.byt_off/(.dix$ag_sys_bpunit [.sys_orig]/.byt_siz))
! ; Offset to that byte in unit containing LSB of field
- .byt_siz*(.byt_off MOD (.dix$ag_sys_bpunit [.sys_orig]/.byt_siz))
! ; Offset to byte containing LSB of field
+ .bit_off); ! ; Include specified bit offset
[INRANGE, OUTRANGE]: ! ; If no known system,
SIGNAL (dix$_unksys); ! \
TES);
! ; .p;Compute FFD fields from bit displacement
res_ffd [ffd$v_unit] = .con_rec + .bit_disp/%BPUNIT;
res_ffd [ffd$v_offset] = .bit_disp MOD %BPUNIT;
res_ffd [ffd$v_align] = .bit_disp MOD .dix$ag_sys_bpunit [.sys_orig];
res_ffd [ffd$v_length] = .fld_lng;
res_ffd [ffd$v_scale] = .scal_fac;
res_ffd [ffd$v_type] = .dat_typ;
res_ffd [ffd$v_sys_orig] = .sys_orig;
dix$$check_alignment (.dat_typ, .sys_orig, .res_ffd [ffd$v_align]);
dix$success_cond
END; ! END OF dix$$des_by_det
%SBTTL 'GLOBAL ROUTINE dix$$incr_des'
GLOBAL ROUTINE dix$$incr_des ! \.!=;.hl 1 \
! ; .index dix$$incr_des
!++
! Increment String Descriptor.
!
! Level = 3, DD = 3.
!
! Algorithm: based on data type specified, increment spot pointed to by
! descriptor past one character, taking into account synchronization and
! alignment (this is a problem with all DEC-10/20 strings, and with
! PASCAL packed arrays of characters in packed records).
!
! Routine Value: None
!
! Side Effects: Signals if error detected.
!
! Formal arguments:
!--
( ! ;.s 1.list 1
ffd ! \.le;\: Address of descriptor pointing to
! ; string-type field. Descriptor is modified.
) : NOVALUE = ! ;.end list
BEGIN
LOCAL
delta,
byt_siz;
MAP
ffd : REF forgn_descr;
BIND
orig_bpu = dix$ag_sys_bpunit [.ffd [ffd$v_sys_orig]];
! ; Currently, this routine deals with class string, class display
! ; numeric and class packed decimal data only.
byt_siz =
(SELECTONE .ffd[ffd$v_dt_class] OF
SET
[dt_string] : .dix$adtt_st [.ffd [ffd$v_dt_type], std$v_byt_siz];
[dt_dnum] : .dix$adtt_dn [.ffd [ffd$v_dt_type], dnd$v_byt_siz];
[dt_pdec] : .dix$adtt_pd [.ffd [ffd$v_dt_type], pdd$v_byt_siz];
TES);
!
! ; Since this routine is roughly third level in the conversion routines, no
! ; check is necessary for validity of data type.
!
CASE .ffd [ffd$v_sys_orig] FROM 1 TO sys_max OF
SET
[sys_lcg] :
!
! 36-bit system specific
!
BEGIN
IF .ffd [ffd$v_align] LSSU .byt_siz
THEN
BEGIN ! Byte is at start of next word
delta = 2*.orig_bpu - .ffd [ffd$v_align];
ffd [ffd$v_align] = .orig_bpu;
END
ELSE
delta = 0;
delta = .delta - .byt_siz;
ffd [ffd$v_align] = .ffd [ffd$v_align] - .byt_siz;
END; ! 36-bit system-specific
[sys_8bit] :
!
! 8-bit system specific
!
BEGIN ! 8-bit system-specific
ffd [ffd$v_align] = (.ffd [ffd$v_align] + .byt_siz) MOD .orig_bpu;
delta = .byt_siz
END; ! 8-bit system-specific
!
! We could insert a check for invalid sys_orig here with an OUTRANGE
! CASE label. I'm not sure if we want to or not.
!
TES; ! Value of CASE is not used
!
! Common to all systems
!
delta = .delta + .ffd [ffd$v_offset];
WHILE .delta LSS 0 DO ! Grind down if we moved backwards
BEGIN
ffd [ffd$v_unit] = .ffd [ffd$v_unit] - 1;
delta = .delta + %BPUNIT
END;
ffd [ffd$v_unit] = .ffd [ffd$v_unit] + .delta/%BPUNIT;
ffd [ffd$v_offset] = .delta MOD %BPUNIT;
END; ! END OF dix$$incr_des
%SBTTL 'GLOBAL ROUTINE dix$$adj_xi_scal'
GLOBAL ROUTINE dix$$adj_xi_scal ! \.!=;.hl 1 \
! ; .index dix$$adj_xi_scal
!++
! Adjust XI Field to correspond to given Scale.
!
! Algorithm: Keeping the decimal point aligned, shift the decimal
! places of the XI field. In order to facilitate this, copy the XI
! digits into a temporary XI field (xi_tmp) as they are shifted.
!
! Routine value: Status value, either dix$_rounded or dix$status_cond.
!
! Formal Arguements:
!--
( ! ; .s 1 .list 1
dst_scal, ! \.le;\: the destination scale desired
xi_field ! \.le;\: the address of the XI field (the XI field is modified)
) = ! ; .end list
BEGIN ! begin dix$$adj_xi_scal routine
MAP xi_field : REF xi;
LOCAL c1,
shift : INITIAL(0),
xi_tmp : xi,
lowsig_lost;
lowsig_lost = 0; ! initialize
shift = .dst_scal - .xi_field[xi$v_scale]; ! calculate required shift
IF .shift GTR 0 ! if it is a positive shift
THEN BEGIN
INCR c1 FROM 0 TO .shift - 1 DO ! then shift in low order zeros
xi_tmp[xi$v_digit, .c1] = 0;
INCR c1 FROM xi$k_digits - .shift + 1 TO xi$k_digits DO ! be sure high order
IF .xi_field[xi$v_digit, .c1] NEQ 0 ! digits shifted out are zero
THEN SIGNAL (dix$_toobig); ! if not, signal an error.
END
ELSE IF .shift LSS 0 ! If it's a negative shift
THEN BEGIN ! then shift in high order zeros
INCR c1 FROM xi$k_digits + .shift + 1 TO xi$k_digits DO
xi_tmp[xi$v_digit, .c1] = 0;
INCR c1 FROM 0 TO -.shift - 1 DO ! & make sure low order digits shifted out
IF .xi_field[xi$v_digit, .c1] NEQ 0 ! are also zero, if any aren't zero then we
THEN BEGIN ! will lose a non-zero low order digit
lowsig_lost = 1; ! so indicate rounded and
EXITLOOP ! don't waste any time looking for more
END;
END;
! Now that the shift has been aligned, fill the rest of xi_tmp
! with the digits from xi_field. What we are doing here is making
! a temporary copy of the XI form which has the scale adjusted for
! our use.
IF .shift GEQ 0
THEN INCR c1 FROM 0 TO xi$k_digits - .shift DO
xi_tmp[xi$v_digit, .c1 + .shift] = .xi_field[xi$v_digit, .c1]
ELSE ! (if shift < 0)
INCR c1 FROM 0 TO xi$k_digits + .shift DO
xi_tmp[xi$v_digit, .c1] = .xi_field[xi$v_digit, .c1 - .shift];
INCR c1 FROM 0 TO xi$k_digits DO ! copy scale-adjusted temp XI form into
xi_field[xi$v_digit, .c1] = .xi_tmp[xi$v_digit, .c1]; ! perm XI form
(IF .lowsig_lost ! return status dix$_rounded if we
THEN dix$_rounded ! lost low order significant digits,
ELSE dix$success_cond) ! else return success status
END; ! end of routine DIX$$ADJ_XI_SCAL
END ! End of module
ELUDOM