CP/M pages
Home -> CP/M -> Torch CPN

Torch CPN

CPN (with no slash) is a CP/M workalike distributed by Torch Computers, usually found running on a Z80 plug-in processor for the BBC Micro. It stands for "Control Program Nucleus".

While an Internet search can locate a fair amount of information about it, it's not all in easily accessible formats. So this is my attempt to gather together the points of interest to me.

Peripherals

The Torch card relies on its host BBC micro for most I/O. The Z80 I/O ports are listed at TorchIO:

00h-07h: Communication with the host / boot ROM paging (bit 2 of address is 0 to page ROM, 1 to page RAM).
		00h / 04h: Send to BBC host
		01h / 05h: Receive from BBC host
		02h / 06h: Status. Bit 7 set if host is ready to receive. Bit 1 is set if host is ready to send.
10h-17h: Z80 SIO
18h-1Fh: Serial port baud rate setting

Boot ROM

On startup, CPN is loaded from an 8K ROM - usually version 1.02 (CCCP102). This copies itself to RAM and then pages itself out.

At offset 6 in the ROM is a pointer to a table of blocks, each one formed:

	DB	type		;Block type
	DW	length		;Length of block
	DW	address		;Destination address in Z80 memory 
	DB	... data ...

Block types are:

 00h  Operating system code (BIOS / BDOS / CCP equivalents)
 01h  Zero page / jump blocks
0FEh  Version text
0FFh  End of table

API

The CPN API is patterned on CP/M 2, but with some differences:

BDOS

There is an additional method of calling the BDOS - use RST 30h with the function as an inline parameter rather than passed in C.

The BDOS entry point is at 0F840h, where on real CP/M it would be at xx06h.

The following BDOS functions are worthy of note:

C=03h (A_READ)
On CP/M this reads auxiliary input (eg, a paper tape reader or serial port). On CPN this reads console input without parsing or echoing the character returned.
C=04h (A_WRITE)
On CP/M this writes to auxiliary output (eg, a paper tape punch or serial port). On CPN this writes to the console without interpreting the output character (so tabs are not expanded, output is not echoed to the printer, and escape codes are not parsed).
C=06h (C_RAWIO)
This function has CP/M 3 semantics:
  • When called with E=0FFh it polls for input and returns 0 if there is no character, or the character if there is one.
  • When called with E=0FEh it returns console input status.
  • When called with E=0FDh it waits for a character and returns it without echoing it.
C=07h / 08h (get / set IOByte)
CPN does not implement the I/O byte. These calls successfully retrieve and store the byte at address 3, but that byte does not control where input comes from or output goes.
C=0Eh (DRV_SET)
The drive selected by this function is stored at address 4, which on a real CP/M 2 system holds the CCP current drive and user number.
C=1Bh (DRV_ALLOCVEC)
The allocation vector returned is a copy, stored in a temporary buffer.
C=1Fh (DRV_DPB)
A single fixed DPB is returned, corresponding to a drive with 32 128-byte sectors per track, 16k blocks, 257 data blocks and 256 directory entries.
C=20h (F_USERNUM)
According to the manual, user number can be 0-31.
C=28h (F_WRITEZF)
Is identical to function 22h (F_WRITERAND)

In addition to the CP/M 2 functions, CPN also implements functions numbered 6Bh-7Fh. These appear to be used for TORCHNET operations.

BIOS

The BIOS jump block is at address 0FFCCh, so unlike a real CP/M system it is not page aligned. It is followed (at 0FFFFh) by a single byte which is documented as the CPN internal version number.

The following functions are not implemented: SETTRK, SETSEC, READ, WRITE and SECTRAN.

Before the BIOS jump block, at address 0FFB4h, are some additional jumps:

FFB4	JP	CCCPCS		;Internal use only, forwards to BOOT in 1.02
FFB7	JP	TubeStat	;Get tube status.
				;Bit 0 of A set if OK to send character.
				;Bit 2 of A set if character waiting to be read.
				;Carry matches bit 0 of A
				;Zero is inverse of bit 2 of A
FFBA	JP	CInstall	;For internal use by the command processor.
FFBD	JP	LdFile		;Loads and executes a COM file.
				;Enter with BC = FCB address. Returns on 
				;failure with A=error code
FFC0	JP	UsrImm		;Sends 0Fh to the host system (User call) 
				;followed by the byte after this call. eg:
				;
				;	CALL	0FFC0h
				;	DB	10h
				;
FFC3	JP	PutImm		;Send the byte after this call to the host
FFC6	JP	GetByte		;Wait for a byte from the host and return it in
				;A.
FFC9	JP	PutByte		;Send the byte in C to the host.

Internal API

Most of CPN is implemented on the host BBC computer, with the Z80 system mainly providing wrappers around host functionality. For example, the F_OPEN call is implemented by sending byte 24h to the host, followed by 13 bytes of FCB. The host replies with a result byte and (if successful) 15 bytes of updated FCB.

In FCBs sent to the host, the first byte is 00-0Fh for the drive number rather than the usual CP/M values of 01-10h. The top bit of the drive number is set if the first byte of the passed FCB was '?'.

The commands sent to the host include:

00	Reboot (triggered by BIOS BOOT call).
01 nn	Send byte to printer 
02 fcb  Open file (12-byte FCB). 
03 fcb	Close file. Followed by 12 bytes of FCB. 
04 fcb  Search first (12-byte FCB).
05      Search next
06 fcb  Delete file. Followed by 12-byte FCB. Returns 1 byte result.
07      Read record
08      Write record
09      Create file (12-byte FCB).
0A	Rename file. Followed by 12-byte FCB, then zero, then 11-byte new name.
	Returns 1 byte result.
0B	Set file attributes. Followed by 12-byte FCB. Returns 1 byte result.
0C	Get file size. Followed by 12-byte FCB. Returns 1 byte status / high
	byte of record count. If bit 7 of status not set, a word follows
	(low word of record count).
0D      Read host memory. Followed by a word giving address. Returns a byte.
0E	Write host memory. Followed by a word giving an address and a byte
	with the new value.
0F nn	Execute user function. Followed by function number.
10	Get/set user number. Followed by one byte (user number or 0FFh). If 
	byte was 0FFh, returns one byte (user number).
11	Poll keyboard. Returns 1 byte (status) and then one byte of data if 
	status was nonzero.
12	Select input device. Followed by a byte:
		0  Keyboard
		1  Serial port
		2  Keyboard and serial port
13	Select output device	
		0  Screen
		3  Serial port
14	Call communications address. Followed by a command byte.
		0  Poll interface
		1  Interrupt
15 nn	Send byte to console
16	Query keyboard status. Returns 1 byte of status.
17	Get extent size. Pass a file handle and an extent number. The number
	of records in that extent will be returned.
18 fcb  Search first. Followed by 13 bytes of FCB.
19 fcb  Search next.

1C	Get disc configuration. Followed by a drive number.
	Returns 1 byte result code. If it is 0, a configuration word follows:
		Bits 3-0:  Physical sectors per track
		Bits 13-4: Tracks
		Bit 14:    Set if drive is a network drive
		Bit 15:    Set if drive is a fixed disc.
1D fcb  Create file. Followed by 13 bytes of FCB. The first byte (drive) is 
	00-0Fh for drive A:-P:. Returns a result byte; if that is zero, then
	15 bytes of opened FCB follow.
1E	Torchnet function.
24 fcb  Open file. Followed by 13 bytes of FCB. The first byte (drive) is 
	00-0Fh for drive A:-P:. Returns a result byte; if that is zero, then
	15 bytes of opened FCB follow.
28      Make drive read-only. Followed by one byte, 0-0Fh.
29      Get drive read-only bitmap. Returns two bytes.

User functions sent by command 0Fh include:

00	Read sector
01	Write sector
02	Format track
03	Select disc
05	Get escape status
06	Copy 40 bytes
07	Get version number
08	Format disc
09	Unslave disc caches
0A	Set debug status
0B	Get character definition
0C	Call OSWORD
0D	Read scratchpad
0E	Write scratchpad
0F	Call OSBYTE
10	Toggle printer status
11	Get printer status. Returns 1 byte.
12	Get retry count
13	Reset drives. Takes 2 byte (bitmap of drives to reset).
14	Get drive allocation vector. Takes 1 byte (drive number). 
	Returns 32 bytes.
15	Call host processor function.
16	Call host processor subroutine.
17	Reset handle table (close all files).
18	Get boot control byte.

Filesystem

The on-disc format of the filesystem used by CPN differs considerably from that used by CP/M.

The manual describes the filesystem on a floppy disc with 80 cylinders, 2 heads, 10 256-byte sectors. Cylinders are mapped to tracks in 'alternating sides' order, as on a PC. Since the BBC Micro normally uses 'out and out' order, you may well encounter Torch disc images online where the tracks are in non-obvious order.

Internally, sectors are numbered (track << 4) | (sector). This means that on a disc with fewer than 16 sectors per track, the numbers will not be contiguous. For example, the directory occupies the first 16 sectors of the disc but these are numbered 00h-09h and 10h-15h (track 0, sectors 0-9 and track 1 sectors 0-5).

As mentioned, the first 16 sectors contain the directory. Each entry is 16 bytes:

	DW	allocation	;0000h 		: End of directory
				;0001h-03FFFh	: Sector number of L3 block
				;8001h-0BFFFh	: Sector number of L2 block
				;0FFFFh		: Empty entry
	DW	length		;File size in records
	DB	user		;User number
	DB	filename	;In CP/M FCB format. Attributes on high bits
				;per CP/M, except that the 'Archive' attribute
				;is replaced with 'Execute only'.

Files of up to 255 records store their allocation in an L3 block. This contains 128 words, giving the sector numbers containing those records.

Files of 256 or more records store their allocation in an L2 block. This contains 128 words, each giving the sector number of an L3 block describing that section of the file. This system should be familiar to those who have studied UNIX / Minix filesystems.

The use of a 14-bit sector number in the allocation field suggests that the absolute maximum size of a CPN filesystem is 4Mb (16384 256-byte sectors).

The directory is followed by two sectors of allocation bitmap, containing 256 words for 256 tracks. Bit 0 of each word corresponds to sector 0 of the track, bit 1 to sector 1, and so on. Sectors that don't exist (such as sectors 10-15) will have the corresponding bit set to 1.

The largest filesystem that could be supported by an allocation bitmap of this size is 1Mb: 256 tracks of 16 sectors.

Following the allocation bitmap is a sector containing test data, and another sector containing "various other information (see Torch Systems Department document Sys-B-02)". The remainder of the disc then contains the data blocks referred to by the directory.

Links