.TOC	"VFIELD.MIC -- Variable Length Bit Field Instructions"
.TOC	"Revision 8.0"

;	Bob Supnik

.nobin
;****************************************************************************
;*									    *
;*  COPYRIGHT (c) 1982, 1983, 1984 BY					    *
;*  DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS.		    *
;*  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 WHICH IS NOT SUPPLIED BY DIGITAL.		    *
;*									    *
;****************************************************************************

.TOC	"	Revision History"

; 08	14-Feb-84	[RMS]	Editorial changes for pass 2
;	22-Sep-83	[RMS]	Editorial changes
;	14-Sep-83	[RMS]	Added subroutine to compress INSV
; 07	26-Aug-83	[RMS]	Removed SC branches
;	19-Aug-83	[RMS]	Editorial changes from code review
; 06	10-Aug-83	[RMS]	Revised for SC delayed branches
; 05	31-May-83	[RMS]	Removed third at/dl field
;	14-Apr-83	[RMS]	Saved word in FFC
;	23-Mar-83	[RMS]	Fixed bug in testing for pos > 31 (JW)
;	17-Mar-83	[RMS]	Revised for new mreq, dl functions
; 04	13-Mar-83	[RMS]	Major code compression
;	27-Dec-82	[RMS]	Removed SC restriction on W-bus writes
;	9-Dec-82	[RMS]	Removed extraneous ..e linkages
;	28-Nov-82	[RMS]	Editorial changes
; 03	24-Nov-82	[RMS]	Revised allocation limits and constraints
;	12-Oct-82	[RMS]	Revised allocation limits
;	8-Oct-82	[RMS]	Removed extraneous label
;	20-Sep-82	[RMS]	Revised definition of PR[E]
; 02	14-Sep-82	[RMS]	Revised allocation limits
;	6-Sep-82	[RMS]	Editorial changes
;	31-Aug-82	[RMS]	Revised for G(RN+1) restriction
;				Editorial changes to case statements
;	26-Aug-82	[RMS]	Revised for W5 restriction
;	25-Aug-82	[RMS]	Revised for today's spec changes
;	19-Aug-82	[RMS]	Revised for SC& test restriction
;	18-Aug-82	[RMS]	Corrected assembly errors
;	17-Aug-82	[RMS]	Revised for new nomenclature
;				Revised for SC& test restriction
; 01	16-Aug-82	[RMS]	Initial edit for MicroVAX

.bin
;= REGION 2 63F
;= BEGIN VFIELD
.nobin

;	This module implements the variable length bit field class instructions.
;	The instructions in this class are:
;
;	Opcode	 Instruction							N Z V C		Exceptions
;	------	 -----------							-------		----------
;
;	EC	 CMPV pos.rl, size.rb, base.vb, {field.rv}, src.rl		* * 0 *		rsv
;
;	ED	 CMPZV pos.rl, size.rb, base.vb, {field.rv}, src.rl		* * 0 *		rsv
;
;	EE	 EXTV pos.rl, size.rb, base.vb, {field.rv}, dst.wl		* * 0 -		rsv
;
;	EF	 EXTZV pos.rl, size.rb, base.vb, {field.rv}, dst.wl		* * 0 -		rsv
;
;	F0	 INSV src.rl, pos.rl, size.rb, base.vb, {field.wv}		- - - -		rsv
;
;	EB	 FFC startpos.rl, size.rb, base.vb, {field.rv}, findpos.wl	0 * 0 0		rsv
;	EA	 FFS startpos.rl, size.rb, base.vb, {field.rv}, findpos.wl	0 * 0 0		rsv
;
.bin

.nobin
.TOC	"	FFS, FFC, CMPV, CMPZV, EXTV, EXTZV"

;	These instructions find the first bit in, compare an operand to, or
;	extract, a variable length bit field.
;	The condition codes are set according to the result.
;
;	Mnemonic      Opcode	Operation				Fork	AT/DL	CC	Dispatch
;	--------      ------	---------				----	-----	--	--------
;	FFS		EA	dst.wl <-- first one in			fse	rr/lb 	aaaa	FFS
;					field(pos.rl, size.rb, base.vb)
;	FFC		EB	dst.wl <-- first zero in		fse	rr/lb 	aaaa	FFS
;					field(pos.rl, size.rb, base.vb)
;
;	CMPV		EC	sext{field(pos.rl, size.rb, base.vb)} -	fse	rr/lb 	jizj	CMPV
;					src2.rl
;	CMPZV		ED	zext{field(pos.rl, size.rb, base.vb)} -	fse	rr/lb 	jizj	CMPV
;					src2.rl
;
;	EXTV		EE	dst.wl <--				fse	rr/lb 	iiip	CMPV
;					sext{field(pos.rl, size.rb, base.vb)}
;	EXTZV		EF	dst.wl <--				fse	rr/lb 	iiip	CMPV
;					zext{field(pos.rl, size.rb, base.vb)}
;
;	Entry conditions:
;		W0	=	first (position) operand
;		W2	=	second (size) operand
;		DL	=	data type of second operand (byte)
;
;	Exit conditions (FFS, FFC):
;		The ALU condition codes are set.
;		W0 contains the result.
;		The next microstate is WDEST.
;		(CMPV, CMPZV):
;		The PSL condition codes are set.
;		The next microstate is IID.
;		(EXTV, EXTZV):
;		W0 contains the result.
;		The next microstate is WDEST.
;
;	Condition codes:
;		(FFS, FFC)		(CMPV, CMPZV)		(EXTV, EXTZV)
;		N <-- 0			N <-- field LSS src2	N <-- dst LSS 0
;		Z <-- {bit not found}	Z <-- field EQL src2	Z <-- dst EQL 0
;		V <-- 0			V <-- 0			V <-- 0
;		C <-- 0			C <-- field LSSU src2	C <-- C
;
;	Size/performance tradeoffs:
;		The final search loop of FFS/FFC may be optimized by searching multiple
;		bits at a time after closing in on the proper byte.  For example, searching
;		two bits at a time costs two extra words, three bits, six extra words, etc.
;
.bin

;	FFS, FFC operation:
;
;		dst.wl <-- position of first one (zero) bit in field(pos.rl, size.rb, base.vb)

FFS..:						; opcode = EA
;FFC:						; opcode = EB
	;********** Hardware dispatch **********;
	W[3]<--W[0],				; make extra copy of position,
	GOTO[FIELD.TO.W0]			; join common code

;	CMPV, CMPZV operation:
;
;		?ext{field(pos.rl, size.rb, base.vb)} - src2.rl

CMPV..:						; opcode = EC
;CMPZV:						; opcode = ED

;	EXTV, EXTZV operation:
;
;		dst.wl <-- ?ext{field(pos.rl, size.rb, base.vb)}

;EXTV:						; opcode = EE
;EXTZV:						; opcode = EF

;	All the field instructions (except INSV) use common code to
;	extract field(pos.rl, size.rb, base.vb) to W0.

FIELD.TO.W0:
	;---------------------------------------;
	W[4]<--W[2]-1, SET.ALUCC		; calc size-1, set alu cc's

	;---------------------------------------;
	WBUS<--ZEXT.W[4].SHFR.[5], SET.ALUCC,	; test if size-1 < 32, set alu cc's
	IF[ALU.N]_[FIELD.0]			; branch out if size-1 < 0

	;---------------------------------------;
	P[ATDL]<--K[ATDL.VB],			; set up .vb for GSD third specifier
	IF[NOT.ALU.Z]_[FIELD.RSRV.OPER]		; branch out if size-1 >= 32

	;---------------------------------------;
	W[2]<--W[0], SET.ALUCC,			; save position, test sign, set alu cc's
	CALL.CASE.SPEC[GSD..]			; parse base operand to W0, VA

	;---------------------------------------;
	W(6)&, WBUS<--SEXT.W[2].SHFR.[3],	; convert position to signed byte offset,
	IF[RMODE]_[FIELD.RMODE]			; branch out if reg mode 

;	Field in memory.

;	At this point,
;		W2	=	position
;		W4	=	size - 1 (0..31)
;		W6	=	sext(position)/8
;		VA	=	address of operand, not register mode

FIELD.MEM.1.32:
	;---------------------------------------;
	SC&, VA<--VA+W[6],			; add byte offset to base address to get
						; base byte address of field
	CALL[FIELD.CALC.VA.POS]			; calculate LONGWORD address and bit offset
						; from LONGWORD address

;	After subroutine FIELD.CALC.VA.POS,
;		W2	=	position (mod 32) of bit field relative to base LONGWORD
;		W4	=	size - 1 (0..31)
;		VA	=	address of base LONGWORD
;		SC	=	W2 + W4	=	position + size - 1	=	end bit of field
;
;	If SC > 31, the field occupies two successive longwords

	;---------------------------------------;
	W[0]<--MEM(VA), LONG,			; read first longword of field
	CASE2[SC7-4].AT.[FIELD.COMMON]		; case on SC > 31 (SC<5> set)

;= ALIGNLIST **01*	(FIELD.COMMON,	FIELD.READ.2)
;  Position < 32, size - 1 < 32 --> pos + size - 1 < 64 --> SC<7:4> = 00??

FIELD.READ.2:
	;---------------------------------------; SC<5> = 1:
	VA<--VA+K[4]				; field in two longwords, on to next

	;---------------------------------------;
	W[1]<--MEM(VA), LONG,			; read second longword,
	GOTO[FIELD.COMMON]			; join common code

;	Field in register(s).

;	At this point,
;		W2	=	position (must be 0..31)
;		W4	=	size - 1 (0..31)
;		RN	=	register number

;	Note that the register fetch done in GSD is useless, because
;	the specifier length was BYTE.

FIELD.RMODE:
	;---------------------------------------;
	WBUS<--ZEXT.W[2].SHFR.[5], SET.ALUCC	; test field position for value > 31

	;---------------------------------------;
	W[0]<--G(RN), RN<--RN+1,		; get first register for extract, incr reg ptr
	IF[NOT.ALU.Z]_[FIELD.RSRV.OPER]		; if position > 31, reserved operand fault

	;---------------------------------------;
	W[1]<--G(RN), RN<--RN-1,		; get second register, just in case, restore reg ptr
	GOTO[FIELD.COMMON]			; if position legitimate, join common code

;	Field size 0 or (33..255).

;	At this point,
;		base operand not yet parsed
;		ATDL not set
;		W3	=	saved position (FFx only)

FIELD.RSRV.OPER:
	;---------------------------------------;
	GOTO[RSRV.OPER.FLT..]			; size > 32, reserved operand fault

FIELD.0:
	;---------------------------------------;
	P[ATDL]<--K[ATDL.VB],			; set up .vb for GSD third specifier
	CALL[COPY.W0.TO.W1.GSD..]		; parse (and throw away) base operand

FIELD.CASE.ZERO:				; phony label for alignlist
	;---------------------------------------;
	W[0]<--0, SET.ALUCC,			; force zero result, set alu cc's,
	DL<--LONG,				; force dl to long for EXTxV and FFx
	CASE4[OPCODE3-0].AT.[FIELD.CASE.ZERO]	; case on FF vs CMP vs EXT

;= ALIGNLIST 1001*	(FIELD.CASE.ZERO,	FF.ZERO.EXIT,
;=			CMPV.ZERO.EXIT,		EXTV.ZERO.EXIT)

FF.ZERO.EXIT:
	;---------------------------------------; FFx:
	W[0]<--W[3],				; result is orig pos, alu cc's are 0100,
	JMP.CASE.SPEC[WDEST..]			; go write result to memory

;CMPV.ZERO.EXIT:				; CMPxV: see CMPV.EXIT

EXTV.ZERO.EXIT:
	;---------------------------------------; EXTxV:
	JMP.CASE.SPEC[WDEST..]			; result is 0, go write to memory

;	Ready to extract.

;	At this point,
;		W0 (or W1'W0) =	field surround
;		W2 	=	position (mod 32) relative to base LONGWORD
;		W4	=	size - 1 (1..32)
;		VA	=	address of base LONGWORD (if not a register)

FIELD.COMMON:
	;---------------------------------------; SC<5> = 0, SC<5> = 1:
	W[SC]<--W[2], DL<--LONG			; position to SC for shift, dl = long

	;---------------------------------------;
	W[0]<--W[1]!!W[0].SHFR.(SC)		; right justify field in W0

	;---------------------------------------;
	SC<--K[31.]-W[4]			; set up 31-(size-1) = 32-size for shift

;	Instruction breakout:  at this point,
;		W0	=	right justified field (with high order garbage)
;		W3	=	saved position (FFx only)
;		W4	=	size - 1 (0..31)
;		SC	=	32 - size

FIELD.CASE.OPCODE:				; phony label for alignlist
	;---------------------------------------;
	W[0]<--W[0].SHFL.(SC), SET.ALUCC,	; left justify field in W0, set cc's,
	CASE8[OPCODE3-0].AT.[FIELD.CASE.OPCODE]	; case on opcode<2:0>

;= ALIGNLIST 1000*	(FIELD.CASE.OPCODE,	,
;=			FIELD.FFS,	FIELD.FFC,
;=			FIELD.CMPV,	FIELD.CMPZV,
;=			FIELD.EXTV,	FIELD.EXTZV)

;	CMPV, CMPZV completion.

;	At this point,
;		W0	=	left justified field
;		SC	=	32 - size (0..31)
;		ATDL	=	?? + long
;		alu cc's =	set from W0
;
;	To complete CMPV, CMPZV:
;		sign/zero extend field,
;		fetch src2.rl operand,
;		compare, set condition codes, and exit.

FIELD.CMPV:
	;---------------------------------------; CMPV:
	W[0]<--SEXT.W[0].SHFR.(SC),		; right justify and sign extend field,
	GOTO[CMPV.EXIT]				; go finish compare

FIELD.CMPZV:
	;---------------------------------------; CMPZV:
	W[0]<--ZEXT.W[0].SHFR.(SC),		; right justify and zero extend field,
	GOTO[CMPV.EXIT]				; go finish compare

CMPV.ZERO.EXIT:					; enter here for zero size, W0 = 0
CMPV.EXIT:
	;---------------------------------------;
	P[ATDL]<--K[ATDL.RL],			; set up .rl for GSD fourth specifier
	CALL[COPY.W0.TO.W1.GSD..]		; save extracted field, parse src2

	;---------------------------------------;
	WBUS<--W[1]-W[0], SET.PSLCC, LEN(DL),	; do compare, set psl cc's,
	EXECUTE.IID				; decode next instruction

;	EXTV, EXTZV completion.

;	At this point,
;		W0	=	left justified field
;		SC	=	32 - size (0..31)
;		DL	=	longword
;		alu cc's =	set from W0
;
;	To complete EXTV, EXTZV:
;		sign/zero extend field,
;		go to WDEST to write field to dst.wl.

FIELD.EXTV:
	;---------------------------------------; EXTV:
	W[0]<--SEXT.W[0].SHFR.(SC),		; right justify and sign extend field,
	JMP.CASE.SPEC[WDEST..]			; go write result and set psl cc's

FIELD.EXTZV:
	;---------------------------------------; EXTZV:
	W[0]<--ZEXT.W[0].SHFR.(SC),		; right justify and zero extend field,
	JMP.CASE.SPEC[WDEST..]			; go write result and set psl cc's

;	FFS, FFC completion.

;	At this point,
;		W0	=	left justified field
;		W3	=	saved position
;		W4	=	size - 1 (0..31)
;		SC	=	32 - size (0..31), 0 if size = 32
;		DL	=	longword
;
;	To complete FFS, FFC:
;		if FFC, invert field so can use FFS algorithm,
;		zero extend field,
;		if field is zero, calculate answer and go to WDEST,
;		otherwise, find first one bit in field, go to WDEST.

FIELD.FFC:
	;---------------------------------------; FFC:
	W[0]<--NOT.W[0]				; complement 1's and 0's

FIELD.FFS:
	;---------------------------------------; FFS:
	W[SC]<--ZEXT.W[0].SHFR.(SC),		; right justify and zero extend field,
	SET.ALUCC				; set alu cc's and join common code

;	FFx zero test:

;	At this point,
;		W3	=	saved position
;		W4	=	size - 1 (0..31)
;		SC	=	field to search for first one
;		alu.z	=	set if field is zero
;
;	The upcoming bit search can only fail if (FFS) field = 00..00 (FFC) field = 11..11.
;	In FFC, the field is complemented BEFORE right shifting.  Garbage to the right of
;	the field is shifted off, and zeroes are shifting in, causing the zero test to work.

	;---------------------------------------;
	W[0]<--W[3],				; position to W0 for WDEST
	IF[NOT.ALU.Z]_[FF.COUNT.BY.8]		; if field not zero, go find first set bit

	;---------------------------------------;
	W[0]<--W[0]+W[4]+1,			; position is initial position + size
						; (+ 1 to compensate for size - 1)
						; alu cc's are 0100 (alu.z only)
	JMP.CASE.SPEC[WDEST..]			; go write result to memory, set psl cc's

;	FFx search.

;	At this point,
;		W0	=	base position
;		SC	=	field to search, known to contain a 1
;
;	First search a byte at a time, then one bit at a time, to find the set bit.
;	There are lots of alternatives at this point, the following is convenient.

FF.COUNT.BY.8:
	;---------------------------------------;
	WBUS<--W[SC].AND.K[0FF], SET.ALUCC	; test low byte for zero, set alu cc's

	;---------------------------------------;
	W[0]<--W[0]+K[8.],			; assume eight bits will be shifted off
	IF[NOT.ALU.Z]_[FF.COUNT.BY.1]		; if byte non-zero, go do detailed search

	;---------------------------------------;
	W[SC]<--ZEXT.W[SC].SHFR.[8.],		; shift off zero byte
	GOTO[FF.COUNT.BY.8]			; go test next byte

;	Non-zero byte found.

;	At this point,
;		W0	=	position, too high by 8
;		SC<7:0>	=	non-zero byte
;		alu cc's =	0000 (set by AND with mask<31> = 0 and non-zero result)

FF.COUNT.BY.1:
	;---------------------------------------;
	W[SC]<--ZEXT.W[SC].SHFR.[1],		; get next bit for testing
	CASE2[SC3-0].AT.[FF.SC0.0]		; test previous SC<0>

;= ALIGNLIST 1110*	(FF.SC0.0,	FF.SC0.1)

FF.SC0.0:
	;---------------------------------------; SC<0> = 0:
	W[0]<--W[0]+1, GOTO[FF.COUNT.BY.1]	; tested bit was zero, incr pos, loop

FF.SC0.1:
	;---------------------------------------; SC<0> = 1:
	W[0]<--W[0]-K[8.],			; compensate count for pre-addition
	GOTO[JMP.CASE.SPEC.WDEST..]		; go write to memory, set psl cc's

.nobin
.TOC	"	INSV"

;	This instruction inserts a source operand into a variable length bit field.
;	The condition codes are not changed.
;
;	Mnemonic      Opcode	Operation				Fork	AT/DL	CC	Dispatch
;	--------      ------	---------				----	-----	--	--------
;	INSV		F0	field(pos.rl, size.rb, base.vb)		fse	rr/ll	x	INSV
;					<-- src.rl
;
;	Entry conditions:
;		W0	=	first (source) operand
;		W2	=	second (position) operand
;		DL	=	data type of second operand (longword)
;
;	Exit conditions:
;		The source has been inserted into the specified bit field.
;		The next microstate is IID.
;
;	Condition codes:
;		N <-- N
;		Z <-- Z
;		V <-- V
;		C <-- C
;
;	Size/performance tradeoffs:
;		Many alternative structures are available.
;
.bin

;	INSV operation:
;
;		field(pos.rl, size.rb, base.vb) <-- src.rl

INSV..:						; opcode = F0
	;********** Hardware dispatch **********;
	P[ATDL]<--K[ATDL.RB],			; set up .rb to parse size
	CALL[COPY.W0.TO.W3.GSD..]		; save source in W3, parse size to W0

	;---------------------------------------;
	P[ATDL]<--K[ATDL.VB]			; set up AT/DL to parse base

	;---------------------------------------;
	W[4]<--W[0]-1, SET.ALUCC,		; calc size-1, test, set alu cc's
	CALL.CASE.SPEC[GSD..]			; parse base operand to W0, VA

	;---------------------------------------;
	WBUS<--ZEXT.W[4].SHFR.[5], SET.ALUCC,	; test for size-1 < 32
	IF[ALU.N]_[INSV.0].ELSE.[INSV.1.255]	; branch out if size-1 <0

;	Field size 0.

;	All specifiers parsed, just exit.

INSV.0:
	;---------------------------------------;
	EXECUTE.IID				; decode next instruction

;	Field size (1..255).

;	At this point,
;		W2	=	position
;		W3	=	source
;		W4	=	size - 1 (0..254)
;		VA	=	address of base operand
;		alu.z	=	set if size (1..32)

INSV.1.255:
	;---------------------------------------;
	WBUS<--W[2], SET.ALUCC,			; test sign of position, set alu cc's
	IF[NOT.ALU.Z]_[FIELD.RSRV.OPER]		; branch out if size-1 >= 32

	;---------------------------------------;
	P[ATDL]<--K[ATDL.RQ],			; set up data length of quadword
						; (longwords can be handled by mreqs)
	IF[RMODE]_[INSV.RMODE]			; branch out if register mode

	;---------------------------------------;
	W(6)&, WBUS<--SEXT.W[2].SHFR.[3]	; convert position to signed branch offset

	;---------------------------------------;
	SC&, VA<--VA+W[6],			; add byte offset to base address to get
						; base byte address of field
	CALL[FIELD.CALC.VA.POS]			; calculate LONGWORD address and bit offset
						; from LONGWORD address

;	After subroutine FIELD.CALC.VA.POS,
;		W2	=	position (mod 32) of bit field relative to base LONGWORD
;		W3	=	source
;		W4	=	size - 1 (0..31)
;		VA	=	address of base LONGWORD
;		SC	=	W2 + W4	=	position + size - 1	=	end bit of field
;
;	If SC > 31, the field occupies two successive longwords.

	;---------------------------------------;
	W[SC]<--W[2],				; put position into SC,
	CASE2[SC7-4].AT.[INSV.READ.1]		; now case on previous SC > 31 (SC<5> = 1)

;= ALIGNLIST **01*	(INSV.READ.1,	INSV.READ.2)
;  Pos < 32, size - 1 < 32 --> pos + size - 1 < 64 --> SC<7:4> = 00??

;	Field in one longword.

;	At this point,
;		W2 = SC	=	position (0..31)
;		W3	=	source
;		W4	=	size - 1 (0..31)
;		VA	=	base LONGWORD address of field
;		DL	=	quadword!!

INSV.READ.1:
	;---------------------------------------; SC<5> = 0:
	W[0]<--MEM(VA), LONG			; read lw containing field 

;	Insert field in one longword:

;	At this point,
;		W0	=	target containing old field
;		W2 = SC	=	position (0..31)
;		W3	=	source
;		W4	=	size - 1 (0..31)

;	Note that size + pos - 1 < 32 (by case statement), size > 0 (by earlier test).

INSV.COMMON.1:
	;---------------------------------------; --W3--  --W0--
	W[0]<--W[0].ROTR.(SC), DL<--LONG,	; xxxxnn  aabbcc --> xxxxnn  ccaabb
	CALL[INSV.INSERT.FIELD]			; xxxxnn  ccaabb --> xxxxnn  ccaann
						; SC now = position

	;---------------------------------------; --W3--  --W0--
	W[0]<--W[0].ROTL.(SC),			; xxxxnn  ccaann --> xxxxnn  aanncc (pos > 0)
						; nnnnnn  nnnnnn --> nnnnnn  nnnnnn (pos = 0)
	IF[RMODE]_[WRITE.RMODE..]		; branch out if register mode and write
						; (qw length forces write of entire gen reg)

	;---------------------------------------;
	MEM(VA)<--W[0], LONG,			; write result to memory
	EXECUTE.IID				; decode next instruction

;	Field in two longwords.

;	At this point,
;		W2 = SC	=	position (0..31)
;		W3	=	source
;		W4	=	size - 1 (0..31)
;		VA	=	base LONGWORD address of field
;		DL	=	quadword

INSV.READ.2:
	;---------------------------------------; SC<5> = 1:
	W[0]<--MEM(VA), LEN(DL),		; read first lw to W0, check access
	CALL[READ.MEM(VAP).TO.W1..]		; read rest of qw to W1

;	Insert field in two longwords:

;	At this point,
;		W1'W0	=	target containing old field
;		W2 = SC	=	position (0..31)
;		W3	=	source
;		W4	=	size - 1 (0..31)

INSV.COMMON.2:
	;---------------------------------------; --W3--  --W1--  --W0--  --W6--
	W[6]<--W[0]!!W[6].SHFR.(SC)		; xxnnnn  aaaabb  bbcccc!!yyyyyy --> xxnnnn  aaaabb  bbcccc  cccccyy

	;---------------------------------------; --W3--  --W1--  --W0--  --W6--
	W[0]<--W[1]!!W[0].SHFR.(SC)		; xxnnnn  aaaabb!!bbcccc  ccccyy --> xxnnnn  aaaabb  aabbbb  ccccyy

	;---------------------------------------; --W3--  --W1--  --W0--  --W6--
	W[1]<--ZEXT.W[1].SHFR.(SC),		; xxnnnn  aaaabb  aabbbb  ccccyy --> xxnnnn  0000aa  aabbbb  ccccyy
	CALL[INSV.INSERT.FIELD]			; xxnnnn  0000aa  aabbbb  ccccyy --> xxnnnn  0000aa  aannnn  ccccyy

	;---------------------------------------; --W3--  --W1--  --W0--  --W6--
	W[1]<--W[1]!!W[0].SHFL.(SC),		; xxnnnn  0000aa!!aannnn  ccccyy --> xxnnnn  aaaann  aannnn  ccccyy
	RN<--RN+1				; incr register number in case reg mode

	;---------------------------------------; --W3--  --W1--  --W0--  --W6--
	W[0]<--W[0]!!W[6].SHFL.(SC),		; xxnnnn  aaaann  aannnn!!ccccyy --> xxnnnn  aaaann  nncccc  ccccyy
	IF[RMODE]_[INSV.RMODE.2]		; branch out if register mode

WRITE.MEM(VA).QW.FROM.W1.W0..:
	;---------------------------------------;
	MEM(VA)<--W[0], LEN(DL)			; write first lw of result to memory

WRITE.MEM.QW..:
	;---------------------------------------;
	MEM(VAP)<--W[1], LONG,			; write second lw of result to memory
	EXECUTE.IID				; decode next instruction

INSV.RMODE.2:
	;---------------------------------------;
	G(RN)<--W[1], RN<--RN-1,		; write second low to memory
	GOTO[WRITE.RMODE..]			; go write first lw to memory, decode

;	Register mode start.

;	At this point,
;		W2	=	position (must be 0..31)
;		W3	=	source
;		W4	=	size - 1 (0..31)
;		RN	=	register number 

INSV.RMODE:
	;---------------------------------------;
	WBUS<--ZEXT.W[2].SHFR.[5], SET.ALUCC	; test field position for value > 31

	;---------------------------------------;
	SC&, WBUS<--W[2]+W[4],			; calculate end bit position
	IF[NOT.ALU.Z]_[FIELD.RSRV.OPER]		; if position > 31, reserved operand fault

	;---------------------------------------;
	W[0]<--G(RN), RN<--RN+1			; get first register containing field, point to second

	;---------------------------------------;
	W[1]<--G(RN), RN<--RN-1			; get second register containing field, point back to first

	;---------------------------------------;
	W[SC]<--W[2],				; position is initial shift value,
	CASE2[SC7-4].AT.[INSV.COMMON.1]		; go to common code, proper tree

;= ALIGNLIST **01*	(INSV.COMMON.1,		INSV.COMMON.2)
;  Position < 32, size - 1 < 32 --> pos + size - 1 < 64 --> SC<7:4> = 00??

;	Subroutine READ.MEM(VA).QW.TO.W1.W0

;	Entry conditions:
;		VA	=	address of memory operand
;		DL	=	quadword
;
;	Exit conditions:
;		W1'W0	=	memory operand at VA

READ.MEM(VA).QW.TO.W1.W0..:
	;---------------------------------------;
	W[0]<--MEM(VA), LEN(DL)			; read first lw to W0

READ.MEM(VAP).TO.W1..:
	;---------------------------------------;
	W[1]<--MEM(VAP), LONG,			; read second lw to W1
	RETURN					; return to caller

;	Subroutine to perform guts of insert field operation.

;	Entry conditions:
;		W0	=	right justified old field (aabbbb)
;		W2	=	position
;		W3	=	right justified field (xxnnnn)
;		W4	=	size
;
;	Exit conditions:
;		W0	=	inserted new field (aannnn)
;		SC	=	position

INSV.INSERT.FIELD:
	;---------------------------------------;
	W[SC]<--W[4]+1				; use size as shift value

	;---------------------------------------; --W3--  --W0--  (size < 32)
	W[0]<--W[3]!!W[0].SHFR.(SC),		; xxnnnn!!aabbbb  --> xxnnnn  nnnnaa
	CASE2[SC7-4].AT.[INSV.INSERT.SHFTOK]	; case on size = 32

;= ALIGNLIST **01*	(INSV.INSERT.SHFTOK,	INSV.INSERT.SHFT32)
;  SC <= 32 --> SC<7:6> = 00 --> SC<7:4> = 00??

INSV.INSERT.SHFTOK:
	;---------------------------------------; SC<5> = 0 (size < 32):
						; --W3--  --W0--
	W[0]<--W[0].ROTL.(SC),			; xxnnnn  nnnnaa  --> xxnnnn  aannnn
	GOTO[INSV.INSERT.SHFTEND]		; if size = 32, then transfer is ok

INSV.INSERT.SHFT32:
	;---------------------------------------; SC<5> = 1 (size = 32):
						; --W3--  --W0--
	W[0]<--W[3]				; nnnnnn  aabbbb  --> nnnnnn  nnnnnn

INSV.INSERT.SHFTEND:
	;---------------------------------------;
	W[SC]<--W[2], RETURN			; position is shift value, return

;	Subroutine FIELD.CALC.VA.POS

;	Entry conditions:
;		W2	=	position
;		W4	=	size - 1 (0..31)
;		SC, VA	=	base byte address of field
;
;	Exit conditions:
;		W2	=	position (mod 32) relative to base LONGWORD address of field
;		VA	=	base LONGWORD address of field
;		SC	=	W2 + W4	=	position + size - 1

FIELD.CALC.VA.POS:
	;---------------------------------------;
	W[2]<--W[2].AND.K[7],			; calculate pos (mod 8) rel to base byte addr
	CASE4[SC3-0].AT.[FIELD.ADJUST.00]	; now case on SC<1:0> = VA<1:0>

;= ALIGNLIST 1100*	(FIELD.ADJUST.00,	FIELD.ADJUST.01,
;=			 FIELD.ADJUST.10,	FIELD.ADJUST.11)

FIELD.ADJUST.01:
	;---------------------------------------; SC<1:0> = 01:
	W[2]<--W[2]+K[8.],			; field begins in byte 1, add 8 bits to pos mod 8
	GOTO[FIELD.ADJUST.VA]			; go zero out VA<1:0>

FIELD.ADJUST.10:
	;---------------------------------------; SC<1:0> = 10:
	W[2]<--W[2]+K[16.],			; field begins in byte 2, add 16 bits to pos mod 8
	GOTO[FIELD.ADJUST.VA]			; go zero out VA<1:0>

FIELD.ADJUST.11:
	;---------------------------------------; SC<1:0> = 11:
	W[2]<--W[2]+K[24.],			; field begins in byte 3, add 24 bits to pos mod 8
	GOTO[FIELD.ADJUST.VA]			; go zero out VA<1:0>

FIELD.ADJUST.VA:
	;---------------------------------------;
	VA<--VA.ANDNOT.K[3]			; force base addr to LONGWORD alignment

FIELD.ADJUST.00:
	;---------------------------------------; SC<1:0> = 00:
	SC&, WBUS<--W[2]+W[4],			; calculate end bit of field
	RETURN					; return

;= END VFIELD
