CP/M v2.2 and 3.1 for the PCW16                                 USERF functions
===============================================================================

  This file describes the programming interfaces made available by CP/M on
the PCW16. It is not necessary to know about these to use the system.

  Ideally, CP/M programs should avoid these functions and be absolutely 
portable. However, utilities specific to the PCW16 may well need to use these
functions.

Portability
-----------

  Too many utilities for the old PCW were written in a very non-portable way.
You should avoid replicating this behaviour on the PCW16. Mistakes to avoid 
include:

- Assuming that you are running on a PCW16. If you want to use PCW16 
 facilities, you should check the BIOS signature (see "BIOS signature" at the
 end of this file). It may also be wise to check the value returned by 
 the CD_VERSION call (USERF 00E3h).

- Assuming that the BIOS, BDOS, SCB or USERF are at a particular address. 
 I suspect this will be the largest single cause of "old" PCW utilities failing
 on the PCW16. Disc utilities are especially prone to this; the version of 
 MSDISC that I have will not work on the PCW16 or Spectrum +3 for this reason.
 
 For example, the command 

   RANDOMIZE PEEK (64504!) 

   so often seen in BASIC programs will not read the "seconds" counter on a 
  PCW16. The command:

   RANDOMIZE PEEK ( 256 * PEEK(2) - 8 )

    gets it right on PCW16s, other PCWs, Spectrum +3s, and other CP/M 3 
  computers.

- Assuming that the first device in the system is CRT and the second is LPT.
 In the current EML file, they are deliberately the other way round, and in
 a future version they may well be different again.

The BIOS and USERF
------------------

  Under CP/M 2, you should (ideally) only assume the existence of the CP/M 2
set of BIOS calls. If necessary, you may also use the CP/M 3 calls XMOVE and
MOVE to copy data between the different memory banks.

  Under CP/M 3, all the BIOS calls are implemented, but USERF is only 
partially available. 

  There is one extra BIOS call that can be used under CP/M 2 and 3. It is used
to find the address of Rosanne's stack pointer, and can be used if your program
needs to make calls to Rosanne:

	ld	hl,(1)		;Address of BIOS
        ld      l,63h           ;Address of this function (BIOSCTL)
        ld      a,2             ;Get stack pointer. You must NOT call this
				;function except with A=2.
        call    pchl            ;Make the call
        ld      e,(hl)
        inc     hl
        ld      d,(hl)          ;DE = Rosanne stack pointer

  The following USERF calls are present:

* CALL USERF   Call to Rosanne.
  DEFW 003Bh

* CALL USERF   (DD_INIT)
  DEFW 0080h   Initialise the floppy disc driver. No parameters. Corrupts
               AF/BC/DE/HL

* CALL USERF   (DD_READ_SECTOR)
  DEFW 0086h   Enter with: B = CP/M bank of read buffer; 
                           C = 0;
                           D = track (0 based);
                           E = sector (0 based);
                          HL = CP/M address of buffer;
                          IX = address of XDPB.
		Returns Carry set if OK, else Carry reset and A = error
                (error numbers as on old PCW).
                Corrupts BC DE HL.
                Since Rosanne is used to do disc I/O, the XDPB is ignored and 
                the disc is assumed to have 160 tracks and 9 sectors.


* CALL USERF   (DD_WRITE_SECTOR)
  DEFW 0089h   Enter with: B = CP/M bank of data to write;
                           C = 0;
                           D = track (0 based);
                           E = sector (0 based);
                          HL = CP/M address of data;
                          IX = address of XDPB.
                Returns Carry set if OK, else Carry reset and A = error
                (error numbers as on old PCW).
                Corrupts BC DE HL.
                Since Rosanne is used to do disc I/O, the XDPB is ignored and
                the disc is assumed to have 160 tracks and 9 sectors.

* CALL USERF   (DD_CHECK_SECTOR)
  DEFW 008Ch   Enter with: B = CP/M bank of data to compare;
                           C = 0;
                           D = track (0 based);
                           E = sector (0 based);
                          HL = CP/M address of data to compare;
                          IX = address of XDPB.
                If error, returns Carry reset and A=error number.
                If Carry set, Zero set, data in memory matched data on disc.
                If Carry set, Zero clear, data did not match.
                Corrupts BC DE HL.
                Since Rosanne is used to do disc I/O, the XDPB is ignored and
                the disc is assumed to have 160 tracks and 9 sectors.

* CALL USERF   (DD_FORMAT)
  DEFW 008Fh   Enter with: B = CP/M bank of format specification;
                           C = 0;
                           D = track (0 based);
                           E = filler byte;
                          HL = CP/M address of format specification;
                          IX = address of XDPB.
                Since Rosanne is used to do disc I/O, B, HL, and IX are 
                ignored. The track will be formatted with 9 sectors, 512
                bytes each, starting at no. 1. 

* CALL USERF   (DD_LOGIN)
  DEFW 0092h   Enter with: C = 0
                          IX = address of XDPB.
               Returns either Carry set, A = 3, DE = size of double-bit 
                              allocation vector, HL = size of hash table;
               or             Carry reset, A=error no, DE HL corrupt.
               Always corrupts BC.

* CALL USERF   (DD_SEL_FORMAT)
  DEFW 0095h   Enter with: A=3, IX = address of XDPB.
               Returns Carry set, A=3, DE = size of allocation vector, HL =
                       size of hash table.

* CALL USERF   (DD_L_DPB)
  DEFW 009Eh   Enter with: HL = address of Amstrad-format boot record, IX = 
                           address of DPB to initialise.
               Returns:    Carry set, DPB initialised, A = disc type
               or          Carry reset, DPB corrupt, A = error
               Always corrupts BC, DE, HL.

* CALL USERF   (DD_L_XDPB)
  DEFW 00A1h   Parameters and results as for DD_L_DPB, but also initialises
               the XDPB fields.

* CALL USERF   (CD_SA_INIT)
  DEFW 00B6h   Set up the serial port.
               A = Handshake protocol: 1-3, or 0 for auto-detect.
               D = No. of stop bits. (0 for 1, 1 for 1.5, 2 for 2) 
               E = Parity (0=none 1=even 2=odd)
               L = No. of data bits (5-8).
               H must equal L.
               Always corrupts AF, BC, DE, HL.

* CALL USERF   (CD_SA_BAUD)
  DEFW 00B9h   Set communication speed. Enter with H = L = baudrate:
                1 =>   50,  2 =>   75,  3 =>  110,  4 => 134.5,  5 => 150, 
                6 =>  300,  7 =>  600,  8 => 1200,  9 => 1800,  10 => 2400,
               11 => 3600, 12 => 4800, 13 => 7200, 14 => 9600,  15 => 19200.
             
               Corrupts AF BC DE HL.

* CALL USERF   (CD_SA_PARAMS)
  DEFW 00BCh   Get serial parameters. Returns:
               A = Handshake protocol: 1-3, or 0 if auto-detect failed.
	       B = C = baud rate, as above.
               D = No. of stop bits. (0 for 1, 1 for 1.5, 2 for 2)
               E = Parity (0=none 1=even 2=odd)
               H = L = No. of data bits (5-8).
               H must equal L.
               Always corrupts AF, BC, DE, HL.

* CALL USERF   (TE_ASK)
  DEFW 00BFh   No entry parameters. Returns viewport top row     in B
                                                     left column in C
                                                     height-1    in D
                                                     width-1     in E
                                    Cursor row in H, column in L

* CALL USERF   (TE_RESET)
  DEFW 00C2h   No entry parameters. Corrupts AF BC DE HL.

* CALL USERF   (TE_STL_ASK)
  DEFW 00C5h   Returns A=0 if status line disabled, 0FFh if enabled. The 
               status line is not actually used for anything in PCW16 CP/M.
               Zero flag matches A.

* CALL USERF   (TE_STL_ON_OFF)
  DEFW 00C8h   Turn status line off (A = 0) or on (A <> 0). 
               Corrupts F BC DE HL.

* CALL USERF   (TE_SET_INK)
  DEFW 00CBh   Set palette. A=ink number 0-15
                            B=colour,    0-63  ( 00rrggbb)
                            C=B, for compatibility with other Amstrad systems
               Corrupts AF BC DE HL.

* CALL USERF   (TE_SET_BORDER)
  DEFW 00CEh   Set border. B=colour, 0-63 (00rrggbb). 
                           C=B, for compatibility with other Amstrad systems
               Corrupts AF BC DE HL.

* CALL USERF   (TE_SET_SPEED)
  DEFW 00D1h   Set flash speed. Has no effect because PCW16 CP/M does not 
               support flashing.

* CALL USERF   (KM_SET_EXPAND)
  DEFW 00D4h   Set expansion token. HL -> new token text, C = length of text,
               B = token number.

* CALL USERF   (KM_SET_KEY)
  DEFW 00D7h   Set the character produced by a key. Enter with:
                 B = ASCII value
                 C = keycode returned by Rosanne. This is not the key number
                    used by LOADKEYS, but an ASCII code corresponding to the
                    particular key and shift state. Exception: The keypad keys
                    return their LOADKEYS keycodes.
                 D = shift bitmap. A table will be modified if the 
                    corresponding bit is set in D:

                       Bit 0 => unshifted
                       Bit 1 => Shift
                       Bit 2 => Ctrl
                       Bit 3 => Ctrl+Shift
                       Bit 4 => Task

* CALL USERF   (KM_KT_GET)
  DEFW 00DAh   If there is a keypress, read it. If not, don't.
               Returns Carry set if it got a keypress, else Carry reset.
                 Returns B = shifts:
                             Bit 0 => Shift
                             Bit 1 => Task
                             Bit 2 => Ctrl
                             Bit 4 => Keypad
                         C = keycode, as in KM_SET_KEY.

* CALL USERF   (KM_KT_PUT)
  DEFW 00DDh   Put a keypress in the buffer.
                 Enter with B = shifts,  as in KM_KT_GET.
                            C = keycode, as in KM_KT_GET.
               There is, as yet, no support for the three software "lock" 
               states - CAPS, SHIFT and NUM - which the PCW and Spectrum+3
               support.

* CALL USERF   (KM_SET_SPEED)
  DEFW 00E0h   Set keyboard speed. H = initial delay (50ths of a second); 
                                   L = repeat delay (50ths of a second).

* CALL USERF   (CD_VERSION)
  DEFW 00E3h   returns A  = 65 ('A')
                       BC = BIOS version number 
                       HL = address of Rosanne version number in bank 0.

* CALL USERF   (CD_INFO)
  DEFW 00E6h   returns A=0    (one floppy drive)
                       B=32   (512k PCW)
                       C=0FFh (serial port present)
                      HL=0    (buffer table is not implemented)

* CALL USERF   (SCR_RUN_ROUTINE)
  DEFW 00E9h   Run a routine in screen memory. Enter with BC = address of
               the routine; returns all registers as from the routine.
               The VGA memory will be at 0000h, with the roller RAM at 0BC00h.

* CALL USERF   (FIND_FID)
  DEFW 00ECh   enter with DE = address of FID name (above 0C000h)
               returns    Carry set: HL = address of FID in bank 2
                          No Carry:  FID not found
* CALL USERF   (BANK2_RUN_ROUTINE)
  DEFW 00EFh   enter with BC = address of routine in bank 2. 
               Returns all registers as from the routine.

  It is possible to write a CP/M program that calls Rosanne. The file
CALLANNE.COM is an example of such a program. In fact, CALLANNE.COM can
be run as a CP/M .COM file or a Rosanne .PRG file, with identical effect.
Source for CALLANNE has been provided as CALLANNE.ZSM.

BIOS signature
--------------

  To check that your program is in fact running on a PCW16, you must check 
for the BIOS signature before using any non-standard calls (this includes
MOVE and XMOVE under CP/M 2). The BIOS signature is at BIOS+66, and is six
bytes:

	DEFB	'ANNE1',1Ah  

  See CALLANNE.ZSM for an example of checking the BIOS signature.

EML file format
---------------

  The EML file is an LBR-format file, and NULU (as supplied) can edit it. It 
can contain the following modules:

* CPM3    .SYS   - CP/M 3 BIOS and Digital Research BDOS. 
* ZPM3    .SYS   - CP/M 3 BIOS and ZPM3 BDOS.
* CCP     .COM   - CP/M 3 CCP (not supplied). If ?PM3.SYS and CCP.COM are both
                  present, then CP/M 3 is loaded. Otherwise, CP/M 2 is loaded.
* FIDLDR  .SYS   - Device manager for CP/M 2 
* FIDLDR3 .SYS   - Device manager for CP/M 3
* ADRIVE  .FID   - Implements the A: and B: drive
* MDRIVE  .FID   - Implements the RAMdisc
* CRTPLUS .FID   - Implements the screen and keyboard
* SIO     .FID   - Implements serial I/O.

  If (for example) you wanted to run without serial support, then you could 
remove SIO.FID from the EML file. 
_______________________________________________________________________________
