1
0
mirror of https://github.com/PDP-10/stacken.git synced 2026-03-02 17:45:26 +00:00
Files
Lars Brinkhoff 6e18f5ebef Extract files from tape images.
Some tapes could not be extracted.
2021-01-29 10:47:33 +01:00

876 lines
22 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
! PH4:<GLINDELL>NETLIB.REQ.3 20-Feb-84 20:48:35, Edit by GLINDELL
!
! Add $SIGNED_WORD_VALUE for 16-bit values
! Update copyright date
!
! NET:<VOBA.NML.DEVELOPMENT>NETLIB.REQ.5 18-Feb-82 14:46:45, Edit by VOBA
!
! Clean up code and update copyright date.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NETLIB.REQ.20 25-Nov-81 11:10:08, Edit by WEBBER
!
! Fix dot bug in %ASLI32.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NETLIB.REQ.13 19-Oct-81 11:04:48, Edit by PECKHAM
!
! Add %ADD32 routine.
! Alter %CMP routines again to furthur optimize.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NETLIB.REQ.4 13-Oct-81 21:12:50, Edit by PECKHAM
!
! Add %ASLI32 routine to aid NMLDTL in shifting a 32 bit number.
! Optimize other 32 bit macros.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NETLIB.REQ.2 9-Oct-81 14:54:17, Edit by GUNN
!
! Change second equal sign in assignment statement in %SUB32 macro
! to a minus sign.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NETLIB.REQ.13 8-Oct-81 07:05:38, Edit by PECKHAM
!
! Correct data gathering bug in macro GETN.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NETLIB.REQ.7 18-Aug-81 18:45:37, Edit by GUNN
!
! Fix all macros which declare local names to use convention of
! $$MACRO-NAME_local-name to avoid name duplication and collision
! with names of caller.
! Make all 32 bit macros consistent among themselves and with CH$ functions
! with regard to direction of data movement. $MACRO ( source , destination ).
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NETLIB.REQ.2 31-Jul-81 16:39:00, Edit by GUNN
!
! Fix %MOV32 macro. Bind under $MCB conditional not terminated by
! semicolon.
!
! NET:<DECNET20-V3P1.NMU>NETLIB.REQ.3 14-Jul-81 20:02:19, Edit by GUNN
!
! Fix bug in 32 bit definitions made in last edit.
!
! NET:<DECNET20-V3P1.NMU>NETLIB.REQ.2 6-Jul-81 09:56:28, Edit by JENNESS
!
! Fix 32 bit macros to work on 16 bit machines.
!
! NET:<DECNET20-V3P1.NMU>NETLIB.REQ.14 12-Jun-81 11:58:08, Edit by JENNESS
!
! Comment macros and general readability cleanup.
!
! <DECNET20-V3P1.BASELEVEL-2.MCB>NETLIB.REQ.4 11-Jun-81 15:51:13, Edit by SROBINSON
!
! Change various macros to make $MCB environments more efficient
!
! NET:<DECNET20-V3P1.NMU>NETLIB.REQ.2 28-May-81 12:56:58, Edit by JENNESS
!
! Add 32 bit fetch/store macros. Also a set of macros that facilitates
! 32 bit manipulations has been added.
!
! NET:<DECNET20-V3P1.NML>NETLIB.REQ.2 20-Feb-81 10:16:42, Edit by GUNN
!
! Add definition of GETW_NA.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NETLIB.REQ.5 11-Feb-81 15:41:47, Edit by GUNN
!
! Add field definition and macro, $SIGNED_BYTE_VALUE, for a signed 8 bit value.
!
%title 'NETLIB -- Procotol Message Processing Macro Library'
! COPYRIGHT (c) 1981, 1982, 1984 BY
! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
!
! 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 WHICH IS NOT SUPPLIED BY DIGITAL.
!
!++
! Facility: LSG DECnet Network Management
!
! Abstract:
!
! This file contains macros that facilitate handling
! of 8 bit bytes protocol messages.
!
! Environment: BLISS-36, BLISS-32, and BLISS-16.
!
! Author(s): Steven M. Jenness, Dale C. Gunn
!
! Creation date: 23-Oct-80
!
!--
! DECnet message processing macros
!
! N.B - These macros are here for convenience at this time only
! and are specific to BLISS-36.
!
! THEY ARE NOT TRANSPORTABLE! In time they will have to
! be moved to a machine specific library.
%sbttl 'Write Macros'
! Macro - PUTB
!
! Function - To write a 8 bit value to the next position in
! a DECnet byte string. The pointer to the byte
! string is updated to point to the next free position.
!
! Parameters -
!
! VALUE 8 Bit value to write
! POINTER Address of byte string pointer
macro
PUTB (VALUE, POINTER) =
ch$wchar_a (VALUE, POINTER) %;
! Macro - PUTW
!
! Function - To write a 16 bit value as the next two bytes in
! a DECnet byte string. The pointer to the byte
! string is updated to point to the next free position.
!
! Parameters -
!
! VALUE Address of 16 bit value to write
! POINTER Address of byte string pointer
macro
PUTW (VALUE, POINTER) =
begin
ch$wchar_a (.VALUE<0,8,0>, POINTER);
ch$wchar_a (.VALUE<8,8,0>, POINTER);
end %;
! Macro - EX_PUTW
!
! Function - To write the given value to a byte string. The
! value is written as the smallest number of bytes
! possible (1 byte for 8 bits, 2 bytes for 16 bits).
!
! Parameters -
!
! VALUE Value to write (8 or 16 bits)
! POINTER Address of byte string pointer
macro
EX_PUTW (VALUE, POINTER) =
if VALUE gtr 128
then begin
local $$EX_PUTW_X;
$$EX_PUTW_X = VALUE;
ch$wchar_a (.$$EX_PUTW_X<0,7>+128, POINTER);
ch$wchar_a (.$$EX_PUTW_X<7,7>, POINTER);
end
else ch$wchar_a (VALUE, POINTER); %;
%sbttl 'Read Macros'
! Macro - GETB
!
! Function - To get the next 8 bit value from a byte string.
! The byte pointer is updated to point to the next
! byte to read.
!
! Parameters -
!
! POINTER Address of byte string pointer
!
! Value returned -
!
! The next byte in the string.
macro
GETB (POINTER) =
begin
ch$rchar_a (POINTER)
end %;
! Macro - GETW
!
! Function - To get the next two bytes in a byte string and make
! a 16 bit value from them. The byte pointer is updated
! to point to the next byte in the string.
!
! Parameters -
!
! POINTER Address of byte string pointer
!
! Value returned -
!
! The value constructed from the next two bytes in the string.
! The first byte is the lower order 8 bits and the second byte
! is the high order 8 bits.
%if $MCB %then
macro
GETW (POINTER) =
begin
stacklocal $$GETB_X;
$$GETB_X<0,8,0> = ch$rchar_a (POINTER);
$$GETB_X<8,8,0> = ch$rchar_a (POINTER);
.$$GETB_X<0,16,0>
end %;
%fi
%if not $MCB %then
macro
GETW (POINTER) =
begin
register T1; !\ Use two statements to avoid use of commas,
register T2; !/ cause this macro gets used in other macros
T1 = ch$rchar_a (POINTER);
T2 = ch$rchar_a (POINTER);
.T2 ^ 8 or .T1
end %;
%fi
! Macro - GETW_NA
!
! Function - To get the next two bytes in a byte string and make
! a 16 bit value from them. The byte pointer is not
! updated.
!
! Parameters -
!
! POINTER Byte string pointer
!
! Value returned -
!
! The value constructed from the next two bytes in the string.
! The first byte is the lower order 8 bits and the second byte
! is the high order 8 bits.
macro
GETW_NA (POINTER) =
begin
%if $MCB
%then stacklocal
%else local %fi $$GETW_NA_X;
$$GETW_NA_X<0,8,0> = ch$rchar (POINTER);
$$GETW_NA_X<8,8,0> = ch$rchar (ch$plus (POINTER,1));
.$$GETW_NA_X<0,16,0>
end %;
! Macro - GETN
!
! Function - To get then next "N" bytes and construct a value
! from them. The bytes read are in ascending
! significance (i.e. lowest order byte is the first
! byte read).
!
! Parameters -
!
! POINTER Address of byte string pointer
! COUNT Number of bytes to read
!
! Value returned -
!
! The value constructed from the sequence of bytes read.
!
macro
GETN (POINTER, COUNT) =
begin
local $$GETN_X;
$$GETN_X = ch$rchar_a (POINTER);
incr $$GETN_P from 8 to ((COUNT-1)*8) by 8
do $$GETN_X = .$$GETN_X + ch$rchar_a (POINTER)^.$$GETN_P;
.$$GETN_X
end %;
%sbttl 'String Length Checking Macros'
! Macro - NEXTB
!
! Function - This macro checks a string length to see if it
! is long enough to contain a byte field. If it does
! it increments the string count past the next byte.
!
! Parameters -
!
! MAXIMUM Maximum number of bytes in the string
! COUNT Number of bytes already used in the string
!
! Returns -
!
! $true String contains one more byte
! $false End of string reached
!
! Side effects -
!
! The value in COUNT is updated to point beyond the next byte.
macro
NEXTB (MAXIMUM, COUNT) =
begin
local $$NEXTB_TEMP;
if MAXIMUM geq ($$NEXTB_TEMP = .COUNT + 1)
then begin
COUNT = .$$NEXTB_TEMP;
(1 eql 1)
end
else (1 eql 0)
end %;
! Macro - NEXTW
!
! Function - This macro checks a string length to see if it
! is long enough to contain a word (2 byte) field.
! If it does it increments the string count past
! the next word.
!
! Parameters -
!
! MAXIMUM Maximum number of bytes in the string
! COUNT Number of bytes already used in the string
!
! Returns -
!
! $true String contains one more word
! $false End of string reached
!
! Side effects -
!
! The value in COUNT is updated to point beyond the next word.
macro
NEXTW (MAXIMUM, COUNT) =
begin
local $$NEXTW_TEMP;
if MAXIMUM geq ($$NEXTW_TEMP = .COUNT + 2)
then begin
COUNT = .$$NEXTW_TEMP;
(1 eql 1)
end
else (1 eql 0)
end %;
! Macro - NEXTN
!
! Function - This macro checks a string length to see if it
! is long enough to contain a field of COUNT bytes.
! If it does it increments the string count past
! COUNT bytes.
!
! Parameters -
!
! MAXIMUM Maximum number of bytes in the string
! USED Number of bytes already used in the string
! COUNT Number of bytes in field
!
! Returns -
!
! $true String contains COUNT bytes
! $false End of string reached
!
! Side effects -
!
! The value in USED is updated to point beyond COUNT bytes.
macro
NEXTN (MAXIMUM, USED, COUNT) =
begin
local $$NEXTN_TEMP;
if MAXIMUM geq ($$NEXTN_TEMP = .USED + COUNT)
then begin
USED = .$$NEXTN_TEMP;
(1 eql 1)
end
else (1 eql 0)
end %;
! Macro - NEXTF
!
! Function - This macro checks a string length to see if it
! is long enough to contain a counted field.
! If it does it sets the count past the end of
! of the field.
!
! Parameters -
!
! MAXIMUM Maximum number of bytes in the string
! COUNT Number of bytes already used in the string
! POINTER Pointer into string being checked
!
! Returns -
!
! $true String contains a counted field
! $false End of string reached
!
! Side effects -
!
! The value in COUNT is updated to point beyond the
! counted field.
!
macro
NEXTF (MAXIMUM, COUNT, POINTER) =
begin
local $$NEXTF_TEMP;
if MAXIMUM geq ($$NEXTF_TEMP = .COUNT + 1)
then begin
COUNT = .$$NEXTF_TEMP + ch$rchar (POINTER);
(1 eql 1)
end
else (1 eql 0)
end %;
%sbttl '32 Bit Data Manipulation Macros'
! Macro - PUT32
!
! Function - This macro writes a 32 bit value as four bytes
! (LSB first) to a output string.
!
! Parameters -
!
! VALUE Address of 32 bit value
! POINTER Address of output byte pointer
macro
PUT32 (VALUE, POINTER) =
begin
bind $$PUT32_VALUE = VALUE : THIRTY_TWO_BIT;
PUTB (.$$PUT32_VALUE[$32BYTE1], POINTER);
PUTB (.$$PUT32_VALUE[$32BYTE2], POINTER);
PUTB (.$$PUT32_VALUE[$32BYTE3], POINTER);
PUTB (.$$PUT32_VALUE[$32BYTE4], POINTER);
end %;
! Macro - GET32
!
! Function - This macro reads a 32 bit value as four bytes
! (LSB first) from a input string.
!
! Parameters -
!
! POINTER Address of input byte pointer
! VALUE Address of 32 bit value
macro
GET32 (POINTER, VALUE) =
begin
bind $$GET32_VALUE = VALUE : THIRTY_TWO_BIT;
%if $TOPS10 or $TOPS20
%then $$GET32_VALUE = 0;
%fi
$$GET32_VALUE[$32BYTE1] = GETB (POINTER);
$$GET32_VALUE[$32BYTE2] = GETB (POINTER);
$$GET32_VALUE[$32BYTE3] = GETB (POINTER);
$$GET32_VALUE[$32BYTE4] = GETB (POINTER);
end %;
! Macro - %MOV32
!
! Function - This macro moves a 32 bit value from one 32 bit
! storage area to another.
!
! Parameters -
!
! SOURCE Address of 32 bit value to move FROM
! TARGET Address of 32 bit value to move TO
macro
%MOV32 (SOURCE, TARGET) =
begin
%if not $MCB
%then TARGET = (.SOURCE)<0,32,1>;
%else bind $$MOV32_TARGET = TARGET : THIRTY_TWO_BIT,
$$MOV32_SOURCE = SOURCE : THIRTY_TWO_BIT;
$$MOV32_TARGET[$32WORD1] = .$$MOV32_SOURCE[$32WORD1];
$$MOV32_TARGET[$32WORD2] = .$$MOV32_SOURCE[$32WORD2];
%fi
end %;
! Macro - %MOVT32
!
! Function - This macro moves a fullword value in a BLISS variable
! to a 32 bit value storage area.
! The source value is restricted to the machine word
! size.
!
! Parameters -
!
! SOURCE Address of fullword value to move FROM
! TARGET Address of 32 bit value to move TO
macro
%MOVT32 (SOURCE, TARGET) =
begin
%if not $MCB
%then TARGET = .SOURCE;
%else bind $$MOVT32_TARGET = TARGET : THIRTY_TWO_BIT;
$$MOVT32_TARGET[$32WORD1] = .SOURCE;
$$MOVT32_TARGET[$32WORD2] = 0;
%fi
end %;
! Macro - %MOVF32
!
! Function - This macro moves a 32 bit value from a 32 bit storage
! area to a BLISS variable as a fullword value.
! The destination value is truncated to the machine word
! size.
!
! Parameters -
!
! SOURCE Address of 32 bit value to move FROM
! TARGET Address of fullword value to move TO
macro
%MOVF32 (SOURCE, TARGET) =
begin
%if not $MCB
%then TARGET = (.SOURCE)<0,32>;
%else bind $$MOVF32_SOURCE = SOURCE : THIRTY_TWO_BIT;
TARGET = .$$MOVF32_SOURCE[$32WORD1];
%fi
end %;
! Macro - %MOVI32
!
! Function - This macro moves an immediate BLISS fullword value
! to a 32 bit value storage area.
!
! Parameters -
!
! VALUE Fullword value to move FROM
! TARGET Address of 32 bit value to move TO
macro
%MOVI32 (VALUE, TARGET) =
begin
%if not $MCB
%then TARGET = VALUE;
%else bind $$MOVI32_TARGET = TARGET : THIRTY_TWO_BIT;
$$MOVI32_TARGET[$32WORD1] = VALUE;
$$MOVI32_TARGET[$32WORD2] = 0;
%fi
end %;
! Macro - %ADD32
!
! Function - This macro adds one 32 bit value to another
! (VALUE1 + VALUE2) and stores the result in the
! second value.
!
! Parameters -
!
! VALUE1 Address of first 32 bit value
! VALUE2 Address of second 32 bit value
macro
%ADD32 (VALUE1, VALUE2) =
begin
%if not $MCB
%then VALUE2 = (.VALUE2)<0,32> + (.VALUE1)<0,32>;
%else linkage $$ADD32 = jsr (register = 0, register = 1);
external routine $ADD32 : $$ADD32 novalue;
$ADD32 (VALUE1, VALUE2);
%fi
end %;
! Macro - %CMP32
!
! Function - This macro compares two 32 bit values using
! the specified boolean operation.
!
! Parameters -
!
! VALUE1 Address of first 32 bit value
! BOOLEAN Bliss boolean mnemonic
! VALUE2 Address of second 32 bit value
macro
%CMP32 (VALUE1, BOOLEAN, VALUE2) =
begin
%if not $MCB
%then (.VALUE1)<0,32> BOOLEAN (.VALUE2)<0,32>
%else stacklocal $$CMP32_CV : THIRTY_TWO_BIT;
bind $$CMP32_C = $$CMP32_CV;
%MOV32 (VALUE1, $$CMP32_C);
%SUB32 (VALUE2, $$CMP32_C);
%SGN32 ($$CMP32_C) BOOLEAN 0
%fi
end %;
! Macro - %SUB32
!
! Function - This macro subtracts one 32 bit value from another
! (VALUE2 - VALUE1) and stores the result in the
! second value.
!
! Parameters -
!
! VALUE1 Address of first 32 bit value
! VALUE2 Address of second 32 bit value
macro
%SUB32 (VALUE1, VALUE2) =
begin
%if not $MCB
%then VALUE2 = (.VALUE2)<0,32> - (.VALUE1)<0,32>;
%else linkage $$SUB32 = jsr (register = 0, register = 1);
external routine $SUB32 : $$SUB32 novalue;
$SUB32 (VALUE1, VALUE2);
%fi
end %;
! Macro - %CMPI32
!
! Function - This macro compares a 32 bit value against a
! fullword value using the specified boolean operation.
!
! Parameters -
!
! VALUE Address of 32 bit value
! BOOLEAN Bliss boolean mnemonic
! FULLWORD Fullword value
macro
%CMPI32 (VALUE, BOOLEAN, FULLWORD) =
begin
%if not $MCB
%then (.VALUE)<0,32> BOOLEAN FULLWORD
%else stacklocal $$CMPI32_CV : THIRTY_TWO_BIT;
bind $$CMPI32_C = $$CMPI32_CV;
%MOVI32 (FULLWORD, $$CMPI32_C);
%SUB32 (VALUE, $$CMPI32_C);
0 BOOLEAN %SGN32 ($$CMPI32_C)
%fi
end %;
! Macro - %SUBI32
!
! Function - This macro subtracts a fullword value from a
! 32 bit value (32bit - fullword) and stores the
! result in the 32 bit location.
!
! Parameters -
!
! FULLWORD Fullword value
! VALUE Address of 32 bit value
macro
%SUBI32 (FULLWORD, VALUE) =
begin
%if not $MCB
%then VALUE = (.VALUE)<0,32> - FULLWORD;
%else local $$SUBI32_C : THIRTY_TWO_BIT;
%MOVI32 (FULLWORD, $$SUBI32_C);
%SUB32 ($$SUBI32_C, VALUE);
%fi
end %;
! Macro - %ADDI32
!
! Function - This macro adds a fullword value to a
! 32 bit value (32bit + fullword) and stores the
! result in the 32 bit location.
!
! Parameters -
!
! FULLWORD Fullword value
! VALUE Address of 32 bit value
macro
%ADDI32 (FULLWORD, VALUE) =
begin
%if not $MCB
%then VALUE = (.VALUE)<0,32> + FULLWORD;
%else local $$ADDI32_C : THIRTY_TWO_BIT;
%MOVI32 (FULLWORD, $$ADDI32_C);
%ADD32 ($$ADDI32_C, VALUE);
%fi
end %;
! Macro - %SGN32
!
! Function - This macro returns the sign of the given 32 bit value
!
! Parameters -
!
! VALUE Address of 32 bit value
macro
%SGN32 (VALUE) =
begin
%if not $MCB
%then SIGN (.VALUE<0,32,1>)
%else linkage $$SGN32 = jsr (register = 1);
external routine $SGN32 : $$SGN32;
$SGN32 (VALUE)
%fi
end %;
! Macro - %ASLI32
!
! Function - This macro shifts a 32 bit value (32bit + fullword) left by
! number of bits specified by the immediate value.
!
! Parameters -
!
! POSITION Positive value to shift
! VALUE Address of 32 bit value
macro
%ASLI32 (POSITION, VALUE) =
begin
%if not $MCB
%then VALUE = .VALUE ^ POSITION;
%else bind $$ASLI32_VALUE = VALUE : THIRTY_TWO_BIT;
decru $$ASL_INDEX from POSITION to 1
do begin
builtin ROT;
$$ASLI32_VALUE[$32WORD1] = ROT (.$$ASLI32_VALUE[$32WORD1], 1);
$$ASLI32_VALUE[$32WORD2] = ROT (.$$ASLI32_VALUE[$32WORD2], 1);
end;
%fi
end %;
%sbttl '32 Bit Structure Definition'
! Structure - THIRTY_TWO_BIT
!
! Function - Define the storage and access to a 32 bit value.
%if not $MCB
%then field THIRTY_TWO_BIT_FIELDS =
set
$32BYTE1 = [0, 0, 8, 0],
$32BYTE2 = [0, 8, 8, 0],
$32BYTE3 = [0, 16, 8, 0],
$32BYTE4 = [0, 24, 8, 0]
tes;
macro
THIRTY_TWO_BIT = block [1] field (THIRTY_TWO_BIT_FIELDS) %;
%else field THIRTY_TWO_BIT_FIELDS =
set
$32BYTE1 = [0, 0, 8, 0],
$32BYTE2 = [0, 8, 8, 0],
$32BYTE3 = [1, 0, 8, 0],
$32BYTE4 = [1, 8, 8, 0],
$32WORD1 = [0, 0, 16, 0],
$32WORD2 = [1, 0, 16, 0]
tes;
macro
THIRTY_TWO_BIT = block [2] field (THIRTY_TWO_BIT_FIELDS) %;
%fi
! Structure - SIGNED_BYTE
!
! Function - Define a signed 8 bit byte value.
$field SIGNED_BYTE =
set
VALUE = [0, 0, 8, 1] ! Signed eight bit byte
tes;
macro
$SIGNED_BYTE_VALUE =
block [1] field (SIGNED_BYTE) %;
! Structure - SIGNED_WORD
!
! Function - Define a signed 16 bit value
$field SIGNED_WORD =
set
$16VALUE = [0, 0, 16, 1] ! Signed sixteen bits
tes;
macro
$SIGNED_WORD_VALUE =
block [1] field (SIGNED_WORD) %;
%title ''
%sbttl ''
!
! [End of NETLIB.REQ]
! Local Modes:
! Mode:BLISS
! Auto Save Mode:2
! Comment Column:40
! Comment Rounding:+1
! End: