CP/M pages
Home -> CP/M -> Dk'Tronics Silicon Disk

Dk'Tronics Silicon Disk

The Dk'Tronics Silicon Disk is one of the few peripherals I've heard of which adds an extra block device to CPC6128 CP/M Plus. Since CPC CP/M doesn't have the FID system for adding new drivers, this has to be done by patching.

The patching is a two-step process. In BASIC the user types |SETCPMPLUS to create a CP/M program, PATCHER.COM. Then, under CP/M, PATCHER.COM is used to convert the standard EMS file (C10CPM3.EMS) to the patched version for the Silicon Disk (CPM3SEMI.EMS).

PATCHER.COM applies its changes to the first .EMS file it finds; the user is responsible for ensuring it's only given a genuine C10CPM3.EMS and not any other EMS file.

The patches

PATCHER.COM contains (at offset 689h) a table of changes to make. Each change is formed:

	DW	start	;Address of first byte to change
	DW	end	;Address of last byte to change
	DB	data	;Replacement bytes

The addresses are as if the EMS file was loaded at 0100h.


The first few changes are to the initialisation code at the start of the EMS file:

	DW	107h	;Replace a call to 0BD19h (MC_WAIT_FLYBACK) with a
	DW	108h	;call to initialise the ramdisc.
	DW	7100h

	DW	1C5h	;Remove the LDIR that clears memory between
	DW	1C6h	;0FE58h and 0FF9Fh (this has been populated by the. 
	DW	0	;initialisation call).

	DW	1D5h	;Place a RET at the start of the firmware version	
	DW	1D5h	;check, so that CP/M will run on a 464/664.
	DB	0C9h

	DW	358h	;Display the Silicon Disk sign-on message.
	DW	359h
	DW	0FE80h	

The first change sets up the call to the code that initialises the ramdisc. This code consists of 512 bytes added to the end of the EMS file; since it is not trying to fit in spare space within the existing CP/M system, it is not as constrained for memory as the other patches.

The initialisation code copies itself to 0100h, and runs from there. The first thing it does is probe for available memory. There are two possible memory ranges: 192k (banks CC-CF, D4-D7, DC-DF) and 256k (banks E4-E7, EC-EF, F4-F7, FC-FF). The ramdisc can occupy either or both. If neither range is available, no drive is added to the system, and a minimal version of the sign-on routine (which displays no message) is constructed at 0FE80h.

Assuming that memory was found, the DPH for the new drive is added to the drive table. The first memory bank of the ramdisc is paged in, and the system checks that the first byte of each directory entry is either 0E5h or 00h-0Fh. If it is not, the entire first bank is cleared to 0E5h. This means that the presence of CP/M disc labels or date stamps will cause the ramdisc to be erased on boot.

The appropriate DPB for the size of ramdisc is copied to 0FF53h and the sign-on message altered to hold the correct size. The full version of the sign-on code is copied to 0FE80h.

Finally memory from 0FF64h to 0FF9Fh is blanked and the code resumes the normal initialisation sequence by jumping to MC_WAIT_FLYBACK.

Helper functions

After initialisation, the next two patches are helper functions, which occupy free space between CP/M modules. One is at 03E9h, in the gap between the CD and TE modules; the other at 0EE2h, in the gap at the end of DD. The first one backs up 128 bytes of memory at 8080h (which is normally used by the font) so it becomes available as a transfer buffer. The second reverses this, restoring the font.

Disk access

The disk access functions follow; these are placed between 8960h and 89FFh, in memory that's probably reserved for the system message table. Since they page memory, they switch to a local stack, which grows down from 3CFEh.

As you'd expect for a RAMdisc, the actual functions are quite simple. READ pages in the correct bank, copies 128 bytes to the transfer buffer at 8080h, and then uses the CP/M XMOVE and MOVE functions to copy the data to the right place. WRITE performs similar operations in reverse order; XMOVE and MOVE to get the data to 8080h, then page in the correct bank and copy the data there.

The other two operations are LOGIN (which consists simply of

	EX	DE, HL	;DPH is passed in DE, should be returned in HL on
	RET		;success

) and INIT (a simple RET).

Banked BIOS

The next few changes allocate space for the extra DPB. In a stock CPC CP/M Plus, the stack grows down from 0FF64h. In CPM3SEMI this is lowered to 0FF53h, freeing up 17 bytes for the drive DPB.

Space also needs to be allocated for the DPH. The existing subroutine at 3FE0h is moved to 3FD0h (removing 16 apparently unused bytes) and then the new DPH occupies 3FD7h - 3FF9h.

The new drive also requires space for an allocation vector. This is placed at 3C89h, in memory intended for patches to the BDOS.


I first became aware of CPM3SEMI from another patch: BPAT and BCPAT are patches by TRiPsoft that add 720k drive support either to the original C10CPM3, or to the modified CPM3SEMI.

The two patches seem to have been constructed by converting the original and patched EMS files to hex; then the patch is built from those lines that are different. Consequently a single byte's difference will cause 16 bytes to be included in the patch file.

Looking at the way the changes were done, it seems to me likely that the patch was written for the CPM3SEMI version of the EMS file, and then adapted for C10CPM3.

The actual patch seems to be fairly minimal:

	At 03E4h: The five unused bytes between the CD module and the first
		  CPM3SEMI helper function are replaced with:

		RES	2,C	;Reset head to 0
		JP	0E56h	;Send command to FDC

	At 0D39h: The call to 0E56h is replaced with a call to 03E4h. 

The effect of these two changes is to select head 0 when performing a floppy drive seek.

Apart from these changes, BCPAT.HEX contains a large number of changed bytes in the 6400h-64FFh range, where a stock EMS file would contain zeroes. I don't know if these have any purpose, or whether they are an artefact of the patching process.

Oddly, BPAT.HEX (the patch for stock CP/M) extends its patched C10CPM3.EMS file with the 512 bytes of Silicon Disk initialisation code from CPM3SEMI.EMS. We can speculate as to the reason; one possibility is that if both patches were created in the same session, the patch for CPM3SEMI was created first. Then the programmer loaded C10CPM3 into memory, made the appropriate changes, and accidentally wrote the result based on the larger size of CPM3SEMI.

John Elliott, 26 February 2019