		***********************************************
		*   I D L E D   ( V 2 )   I n t e r n a l s   *
		***********************************************



	I N T R O D U C T I O N
	-----------------------

IDLED's name comes from IDLE conjoined with LED.
The subtitle is "Poetry in Motion, a Poem in 64 Words."

This document should be used in conjunction with the IDLED_LIST.pdf file which
contains a listing of IDLED with descriptions of the registers, stacks, and
patches etc.

IDLED was designed as an exercise in getting as much bang for your buck
as 'humanly' possible.  It was designed to specifically to run on a real
PDP-11/70 in a museum environment as well as emulators like the PiDP11 or
BlinkenBone.  It was also designed to fit in the boot block of any supported
PDP-11 device, which means it needed to fit into 64 words (for example on the
TA60 cassette tape).  Also, to match the DEC boot standard, the first word had
to be a NOP (no-operation) leaving only 63 words for actual code and data.
The job of IDLED is to simulate the RSX-11M/M-PLUS idle LEDs as seen on the
PDP-11/70 (and the PDP-11/45).

IDLED is designed (by default) to run completely within the first 256 words
(locations 000000-000777) of the PDP-11 memory.  It will only run on hardware
which has a Display and Switch Register (in the I/O page at address 177570).
All such systems also had the Processor Status Word (PSW) at address 177776.

I met Oscar Vermeulen (of PiDP fame) at the Vintage Computer Festival (VCF) in
Zurich on the 12th November 2023.  There he told me how he and Mark Matlock had
tried (but not succeeded) to fathom out how IDLED does what it does.

So ... this is how.



	H o w   I D L E D +   P l u g s   i n t o   I D L E D
	-----------------------------------------------------

IDLED+ is a plug-in for IDLED.  It is stored in locations 000176-000575.
It adds switch selection (SR15-SR8) of the LED patterns including different
ones for the Display Register.

When loaded at address 000176, it overwrites the 'BR 30' with it's own
entry point.  When started, and enabled, it changes the CMPB at address
000132 to CMP (to compare all switches SR15-SR0).  Depending on the switch
settings (SR14-SR8) IDLED+ will overwrite the initial patterns (@000106 and
000112) and the rotate routines (@000144-000152).

IDLED has one address which needs to be changed when IDLED+ is loaded
and that is where the 'WAIT' instructions go.  This is because IDLED+ has
code at addresses 000376 and 000400 (and up to 000575).

If IDLED+ is not loaded, IDLED will simply reset itself if SR6 is changed.
[See the description of '132', below.]



	I D L E D   P r o g r a m   F l o w
	-----------------------------------

IDLED can be started from the following addresses:-
	000000 (NOP)
	000002 (BR 170)
	000170 (see below)

IDLED also supports power-fail and recovery if your hardware does.
If the power fails or is restored, the PC will be loaded with 000002
and the PSW will be loaded with 000340 (IPL7) from vector 000024.
Which means IDLED will be completely restarted in both cases.

Boot:	If started from address 0, 2, or from a power-fail/recovery
	we always end up at address 000170.  The PSW bits are undefined.

170:	The current-mode SP will be loaded with 000704 which is also a branch
	instruction to address 4, where we go next.  We might be in USER mode
	but as long as the KSP is valid at this point (probably from a previous
	run) we don't care.

004:	An illegal instruction will be executed (000014) which will
	cause a trap to the vector at address 10 (000174) in kernel mode with
	interrupts disabled (IPL7).  The new PSW (from address 12) also contains
	the version number in the low-order 4 bits (the NZVC flags) [version 2].
	These bits are not actually used by IDLED and are only for comment.

174:	The SP will be loaded with 000714 which is also a branch to address 30.
	And that's where we go now.

030:	Here we load up all the registers and create the 'WAIT' code:-

		R5 = 000400 - The PC address which should be shown in the
			      ADDRESS LEDs.  This is one bit (bit 8).
			      This address will be changed to 000600 if
			      IDLED+ is in use because IDLED+ has code at
			      address 000400.  This will soon be changed
			      to 000376 to point to the WAIT instruction.

		R4 = 177570 - Address of the Display and Switch Register.
			      This remains constant throughout.

		R3 = (SR)   - Contents of the Switch Register.
			      This is used later to see if any switches have
			      been changed.

		R0 = 000130 - Address of the 'JMP (R5)' instruction which is
			      stored after the WAIT instruction (coming next).

		A WAIT instruction is stored at address 000376 and the
		'JMP (R5)' instruction is stored at address 000400.  R5 is set
		to 000376.  Oh, and it's the WAIT instruction which displays the
		LED pattern in the DATA LEDs (from R0).

		SR7 is tested.  If it is OFF we skip past the memory filler to
		address 000104.  Thus we avoid overwriting any memory above
		001000.  If the hardware does not support a switch register
		(at address 177570) we will also skip the memory-filling code.

060:	Here we fill memory with WAIT instructions (called MULTI-MODE).

	Addresses 000400 to the end of memory (e.g. 157776) will be set to
	a WAIT instruction.  The stack pointer (SP) is now set to THIS address.
	Eight words before the end of memory, the 'JMP (R5)' instruction will
	overwrite the WAIT instruction.  This allows a stack of 8 words which
	should always be enough.  R0 is now set to 000132 for debugging
	purposes.  R0 will be updated at the first clock interrupt, so this is
	not really necessary.

	066:	The 'BIC (SP),(SP)' ensures that we terminate when a location
		cannot be read from and/or written to.  See 004 below.

	The trick to finding the end of memory uses the PDP-11 definition
	that there must be a hole at the end of memory (e.g. at 160000) which
	will cause a memory time-out interrupt if it is read from or written to.
	When a time-out occurs, we trap to the vector at address 000004 which
	returns from the interrupt with the N-flag set (and ZVC as well).

	The memory-fill loop terminates when it sees the N-flag set.

	Later, when we RTI from the WAIT instruction, the next WAIT will be
	'WAITed' at.  Thus the ADDRESS LEDs will increment by 2 until the
	'JMP (R5)' is reached (see 166 below).

076:	This instruction (BITB #132,@#340) is really just a way of branching
	past the clock (LTC) vector to address 000104.  However, when dis-
	assembling it will be more readable.  It also read-tests location 340.
100:	The clock will interrupt to address 000132 with interrupts disabled.

104:	Here we create the Pattern Double-word at the top of the stack.
	IDLED+ overwrites this code with call-outs to different patterns
	depending on the Switch Register contents.

114:	Here we reset the tick counter (R2 = -2), enable clock interrupts, and
	switch to user-mode with interrupts enabled.  After that, we start
	WAITing for the clock to interrupt [ with a 'JMP (R5)' ].  Note that
	we never use the user-mode stack.  We only switch to user mode so we
	see it in the console LEDs.  If the clock fails to interrupt (e.g.
	there is no LTC CSR) then we will display 000132 in the DATA LEDs.

132:	50 (or 60) times per second, the clock will interrupt to HERE (at IPL7).

	First, we see if any switches have been changed.  If so, we restart
	the program from address 000174 (see above).  We don't need to
	restart at address 000170 because interrupts are already disabled.

	Next we see if the tick counter has expired.  If not, we dismiss
	(ignore) the interrupt.

142:	Here we do the actual LED pattern update.  We also update the pattern
	in the Display Register.  This code may be overwritten by IDLED+.
	The Display Register shows LEDs counting down for ever.  This is
	the opposite direction to the ADDRESS LEDs in multi-mode.

156:	Here we reset the clock tick counter (we make sure it is never greater
	than about 1 second between LED updates).

166:	Here we simply return from the interrupt.  Most likely to the 'JMP (R5)'
	instruction at address 000400.  In multi-mode, the address LEDs will
	increment by 2 until we reach the 'JMP (R5)' instruction near the top
	of memory.



	O t h e r   V e c t o r s
	-------------------------

004:	This is where we trap if we access non-existent memory (e.g if there
	is no SR or PSW or we are filling memory).

	014:	We get here when (among others) we access non-existent memory
		The first instruction (at 014) is because we have one word free
		here and it is useful to put a HALT here for debugging.  We set
		all the flags to 1 (N=1, Z=1, V=1, C=1) when we RTI (at IPL7).

114:	This is the memory parity vector.  If a memory parity error is detected
	by the hardware, this will cause an odd-address trap which would normally
	trap to 4.  On a real PDP-11/70, this vector is quite important.
	What is intended is that if a memory parity error occurs, the CPU will
	halt with a double-error.  Worst case is that the trap to 4 will be taken,
	interrupts will be disabled, and the RTI will attempt to return to the
	odd-address and trap again.



Enjoy!

Mike Hill, 14th November 2023.
