Emulation

Here we discuss what MEMU emulates, and to what degree :-

Memory map

MEMU emulates the fixed ROM slot, and 8 paged ROM slots. It preloads the OS, BASIC and ASSEM ROMs. MEMU currently uses the normal OS ROM image, and not the version with the patch that prevents it writing signatures on RAM pages during initialisation (needed to avoid corruption of the RAM disk). I may change this in the future. It preloads the SDX ROM if you have enabled SDX support using the -sdx command line option. The SDX ROM is placed in ROM 3, I may change this to ROM 5 in the future.

By default MEMU emulates 64KB RAM, but you can use -mem-blocks to change this :-

-mem-blocksRAM pages Comment
2 α-β MTX500
4 α-δ MTX512
20 α-δ, a-pMTX512 + 256KB RAM upgrade
24 α-δ, a-tMTX512 + 320KB RAM upgrade
36 α-δ, a-FMTX512 + 512KB RAM upgrade

Logical memory map, as seen in RELCPMH=0 mode :-

R2,R1,R00x0000..0x1fff0x2000..0x3fff 0x4000..0x7fff0x8000..0xbfff0xc000..0xffff P3,P2,P1,P0
0 OS BASIC γ β α 0
1 ASSEM a δ 1
2 ROM 2 sub-pagesc b 2
3 SDX ROM e d 3
4 ROM 4 g f 4
5 ROM 5 i h 5
6 ROM 6 k j 6
7 ROM 7 m l 7
  o n 8
q p 9
s r A
u t B
w v C
y x D
A z E
C B F

Logical memory map, as seen in RELCPMH=1 mode :-

0x0000..0x3fff0x4000..0x7fff0x8000..0xbfff0xc000..0xffff P3,P2,P1,P0
δ γ β α 0
a b c 1
d e f 2
g h i 3
j k l 4
m n o 5
p q r 6
s t u 7
v w x 8
y z A 9
B C D A
E F   B
      C
      D
      E
      F

It should be noted that MEMU correctly implements the memory map rules, as documented in p246 and p247 of the manual, as correctly implemented by MTX500 (32KB) and MTX512 (64KB), REMEMOTECH and REMEMOrizer.

Sub-pages

The original ROM card supported 4 8KB ROM chips. These appeared in ROM slot 2 in subpages 0 to 3. The subpage register starts as 0, but is changed by attempting to write to 0x0000-0x1fff whilst in RELCPMH=0 mode (ie: attempting to write to the OS ROM). Videowalls could use a later ROM card with 4 32KB ROMs. These also appeared in ROM slot 2 in subpages 0 to 15. The RSCPM boot ROM initialised RAM Disc from the data in these ROMs, and then booted CP/M from RAM Disc. MEMU supports 16 subpages in ROM 2. The -subpage command line argument can be used to set the subpage on the command line, prior to using -mem to initialise the contents from a file.

eg: for HiSoft Pascal :-

$ memu -iobyte 0x20 -addr 0x2000 -subpage 0 -mem roms/pascal0.rom \
                                 -subpage 1 -mem roms/pascal1.rom \
       -iobyte 0x00 -addr 0x0000 -subpage 0 \
       -vid-win-big -snd-portaudio

VDP chip

In MEMU, the VDP chip is always emulated, but it is optional whether its output is displayed to the user. To display it use the -vid-win command line argument. As 256x192 pixels is quite small, you can use the -vid-win-big option, which doubles the size of the window.

The emulation of the display includes a border, as some games communicate information through it. eg: Surface Scanner flashes it when an alien picks up one of your men.

The emulation covers Graphics Mode 1, Graphics Mode 2 (which most games used) and Text Mode (which MTX BASIC used). It does not yet cover Multicolor Mode (which nobody used).

The VDP has an undocumented feature in Graphics Mode 2, whereby the 2nd and 3rd thirds of the screen can be made to use the pattern generator table and/or pattern colour tables normally only used for the 1st third of the screen. Presumably an attempt by the chip designers to allow the use of less VDP memory. MEMU understands and supports this.

The emulation of sprites includes correct implementation of the "no more than 4 sprites on a line" limitation. This limitation was usually a royal pain for games designers. However, some games put 4 sprites on a line (eg: at the top or bottom of the screen) to ensure no other sprites will be visible there.

The emulation of sprites includes a correct implementation of sprite priority, and pixel by pixel coincidence checking. Some games use this for collision detection.

The sprite emulation when SIZE=1, correctly understands that the pattern number in the sprite attribute table should be a multiple of 4, and ignores the bottom 2 bits, as the hardware does. Surface Scanner has a bug in that incorrectly sets these bits - as the hardware ignores them, so must MEMU.

MEMU includes two palettes. The default palette best reflects what Richard F. Drushel and I remember seeing on the old TVs. It is possible, with -vid-win-hw-palette to select a different palette, which is richer, and Marat Fazyullin suggests better reflects the actual values used in the VDP chip itself. Here is a side by side comparison :-

consider compared to

When the VDP window is on display, the key presses and releases it receives are used to form the emulation of the MTX keyboard. The emulation of the MTX keyboard is covered in detail next.

Screen refresh happens at 50Hz, which agrees with the PAL standard, as used in the UK, as produced by the TMS9929A chip. You can use the -vid-ntsc to refresh at 60Hz, which agrees with the NTSC standard, as used in the USA, as produced by the TMS9918 chip.

F9+w is a diagnostic keypress that can be used to snapshot the current screen to a file called memuNNNNNN.bmp. The value increments each time a file is saved. F9+x can be used to toggle auto-snapshot mode. When this mode is enabled, it's as if you triggered a snapshot on every frame. This is a quick way to collect frames you can then use to make a video.

MTX Keyboard

Keys pressed and released in the VDP window or the Monitor window are used to generate the emulation of the MTX keyboard.

MEMU attempts to map the host PC keyboard to the MTX emulated keyboard as closesly as possible, but there are several problems :-

Tables showing the effect of the above follow...

The effect of the shift-state problem :-

Use host keypress  to produce MTX keystroke
-----------------  ------------------------
^                  =
=                  ^
'                  @
@                  '
#                  :
shift `            `

-kbd-remap works around the shift state problem. It assumes the keyboard had different keycaps to any of the real MTX keyboards. In this new MTX keyboard, shifted PC keys are shifted keys on the MTX keyboard. To make this work, MEMU has to patch the keyboard mapping tables in the ROMs, and create a new key that never existed on the original keyboards. The result is a better typing experience in MTX BASIC and at the CP/M prompt. However, if you use a program with its own keyboard mapping tables (eg: various games, FDXB.COM, etc...), the improved mapping doesn't work.

-kbd-country allows you to specify country code of the MTX keyboard (0=English, 1=France, 2=German, 3=Swedish). These are bits 3 and 2 returned when reading port 6. This is feature is incomplete at this time, as MEMU doesn't know how to map international PC keypresses to keys on non-English MTX keyboards.

Mapping of the middle part of the host PC keyboard :-

Middle part of PC keyboard   MTX keypad
--------------------------   ----------
PgUp      End     Pause      7 PAGE   8 EOL     9 BRK
Tab       Up      Delete     4 TAB    5 UP      6 DEL
Left      Home    Right      1 LEFT   2 HOME    3 RIGHT
Insert    Down    PgDn       0 INS    . DOWN    ENT CLS

Mapping of the number pad of the host PC keyboard :-

PC number pad                MTX keypad
-------------                ----------
Num Lock  /       *          7 PAGE   8 EOL     9 BRK
Home      Up      PgUp       4 TAB    5 UP      6 DEL
Left      Middle  Right      1 LEFT   2 HOME    3 RIGHT
End       Down    PgDn       0 INS    . DOWN    ENT CLS

MEMU doesn't cope well with keyboards that don't have a number pad. To try to ease this a little, the Alt and AltGr keys on a PC keyboard (under XWindows) and the alt key on a Mac are treated as the Home key. This is important as Home is used by most games as the fire key. Unfortunately, I tried, but I can't get AltGr on Windows to work the same way - when its pressed, the up arrow key doesn't work properly.

PC keyboard F1-F8 become the MTX keyboard F1-F8.

Certain special keys, such as F9-F12, turn special diagnostic features on or off, see the Diagnostics page.

Older PC keyboards have a limitation in that 3 keypresses at once can cause the phantom appearance of a 4th keypress. Newer keyboard detect when this would be the case, and suppress the 3rd keypress. The MTX joystick appears to press the arrow keys. This means moving diagonally and pressing fire counts as 3 keypresses, and will not work as expected. Read the article on why Keyboards Are Evil for a full explanation. This is an unavoidable limitation, and MEMU suffers from it. Perhaps you should consider using a joystick.

On Windows, you don't get independant notification of left and right shift keys, so both are treated as the left shift key, and to simulate pressing of right shift, press the "applications" key (aka VK_APPS), typically next to the right Ctrl key.

Auto-type

MEMU has an auto-type feature, whereby keystrokes and/or files containing keystrokes (and embedded commands such as delays) may be supplied on the command line. You can use commands such as this to LOAD a program :-

$ memu -s -v -kbd-type "<Wait20><ALPHALOCK>LOAD \"Snakes\"<RET>"

Or this, to drive CP/M :-

$ ./fullcpm.sh -kbd-type "<Wait200>dir A:<RET>"

Keystrokes may also be in files. So if you want to "type in" a listing into MTX BASIC, you could put the listing and associated commands into a file, and :-

$ memu -s -v -kbd-type-file my-listing-file.autotype

Each line of the file is assumed to have a <RET> at the end.

These arguments can be used together and multiple times, and are processed in the order specified.

Keystrokes are chosen to match the characters in the command line arguments or files, but certain character sequences are translated to MTX keys :-

<ESC>              <BS>  <PAGE>  <EOL>   <BRK>     <F1>  <F5>
<CTRL>       <LINEFEED>  <TAB>   <UP>    <DEL>     <F2>  <F6>
<ALPHALOCK>       <RET>  <LEFT>  <HOME>  <RIGHT>   <F3>  <F7>
<LSHIFT>       <RSHIFT>  <INS>   <DOWN>  <ENTCLS>  <F4>  <F8>

<LT>

Why is there <LT> in the table above? If you typed IF N<10 THEN, this would be fine. If you intend PRINT "<EOL>", then to avoid interpretation of the end-of-line key, you'd have to specify it as PRINT "<LT>EOL>".

There are some addition commands you can embed :-

<WaitN>            wait N 50ths of a second
<Press>            only press, (not release) each key going forwards
<Release>          (don't press) only release each key going forwards
<PressAndRelease>  press and release each key going forwards, the default
<PressTimeN>       delay for N 50ths of a second after pressing, default N=1
<ReleaseTimeN>     delay for N 50ths of a second after releasing, default N=1
<ReturnTimeN>      delay for an extra N 50ths of a second after releasing the return key, default N=25
<AutoShift>        press left shift if character requires it, the default
<NoAutoShift>      leave the shift keys alone

Delays are particularly important to get right. MTX BASIC, CP/M and most programs do not implement a keyboard buffer.

So now the initial example makes sense, it :-

  1. waits 0.4s for MTX BASIC to start.
  2. presses ALPHALOCK to turn automatic capitalization off. (so that MTX BASIC does not turn Snakes into SNAKES).
  3. Auto-shift (enabled by default) tells MEMU to press left-shift when typing a capital letter or shifted keypress.
  4. types in the LOAD command.

Note that although it is possible to type in MTX BASIC programs using this feature, most listings of BASIC programs don't actually list the keystrokes required to type them in. This is typically the case for programs including assembler. If you want to type these in, you need to massage them first from

10 PRINT "Before delay"
20 CODE

401B         LD BC,1000
401E LOOP:   DEC BC
401F         LD A,B
4020         OR C
4021         JR NZ,LOOP
4023         RET

Symbols:
LOOP    401E

30 PRINT "After delay"

to this :-

<Wait20><ALPHALOCK>
10 PRINT "Before delay"
ASSEM 20

LD BC,1000<EOL>
LOOP: DEC BC<EOL>
LD A,B<EOL>
OR C<EOL>
JR NZ,LOOP<EOL>
<HOME><EOL>
<HOME><EOL>
30 PRINT "After delay"

MEMU includes a couple of sample files with .autotype file extension.

Joystick

On a real Memotech MTX, the first joystick port is electrically wired so that a joystick plugged into it presses the LEFT, RIGHT, UP, DOWN and HOME keys. The second joystick port is electrically wired so that a joystick plugged into it presses Z, C, B, M and SPACE.

On Linux, if you enable joystick support, then it uses the built-in Joystick Driver and open the /dev/input/js0 device.

On other UNIXes (eg: MacOSX), there is no joystick support. If you try to enable it, rather than halt MEMU, nothing happens.

On Windows, then it uses the DirectInput8 API provided by DirectX version 8 or later. It uses the first joystick it finds attached.

It is possible to build versions of MEMU which do not have joystick support, and do not depend upon joystick related installed headers or libraries.

By default

This behavior is equivalent to specifying a command line argument of :-

-joy-buttons "<LEFT><RIGHT><UP><DOWN><HOME> "

You can get the physical joystick to emulate the second joystick, or to work better for certain games. eg: Astromilon uses Z=Left, C=Right, T=Thrust and Space=Fire, so use :-

-joy-buttons "ZCT_ "

Notice how the key names are parsed in the same way as in the auto-type feature, as described above.

MEMU does have a small limit on the number of buttons you can configure in this way, and of course each joystick only has a certain number of buttons. MEMU configures as many as it can.

Most joystick drivers understand the idea that the stick must move a tiny amount before it is considered to have moved at all. If you find the stick sensitivity a problem, you can use the -joy-central n option to specify what percentage of the full swing the stick must move before a directional button is pressed.

Sound chip

If you use the -snd-portaudio command line argument, MEMU emulates the SN76489A sound chip using the PortAudio audio I/O library. MEMU looks at the virtual sound registers and synthesizes a waveform comprising the sum of the square waves of the appropriate amplitude and frequencies.

As MEMU synthesizes the waveform when PortAudio asks it to, it is possible to miss effects created when programs write to the sound chip in rapid succession. This is hard to fix, and would require that I model the history of updates to the sound chip, not just the current status. Toado is affected by this current limitation.

There is an important PortAudio latency setting. If this value is too small, you can get sound dropouts. If its too big, then the sound effects can lag behind game action. MEMU automatically picks a default value for this, based on what PortAudio recommends and what works on the authors machines, but unfortunately we can't know in advance what setting is best on everyones machines. Therefore, if the sound drops out, you may want to force the use of a larger value.

Unfortunately, the appropriate latency value depends on the sound card hardware, the driver types, the operating system, and the overall load of the system.

If you run MEMU with the -diag-console -diag-snd-latency arguments, you will be shown the recommended device low latency setting and the recommended high latency setting. A good value need not be lower than the low latency setting and there is no point it being higher than the high latency setting. A good value is lower rather than higher. You will also be shown the value which MEMU has chosen to use. If you have told MEMU to use a particular value, you'll be shown that too.

You can force MEMU to use a specific latency value (within the low to high range). If the low value was 0.01s and the high value was 0.05s, and you experienced dropouts, you could try 0.02s or higher, eg :-

$ memu -vid-win-big -snd-portaudio -snd-latency 0.02 games/SOMEGAME.RUN

You want the lowest value which doesn't exhibit dropouts.

Z80 CTC

MEMU has an emulation of the Z80 CTC.

I looked at other implementations, but these didn't quite match what I remembered, and didn't quite match what I read in the Zilog Z80 CTC Technical Manual, so I wrote my own.

This understands the interrupt enable bit, counter verses timer mode, both 16 and 256 timer prescalers. It doesn't understand the distinction between rising and falling edges, and the timer trigger bit, but these don't seem to be significant.

Importantly, it understands that in timer mode, the input is the CTC clock, which is actually the 4MHz system clock, and is the same for all channels. It is not the per channel counter inputs. I suspect MacTX may have got this wrong (it has various references to 13 in the code).

In the MTX, the counter input for channel 0 is the VDP interrupt, and this is correctly emulated. Various games use this to synchronise screen update with the vertical retrace interval. Counter inputs for channels 1 and 2 is 4MHz/13, which is not emulated. The counter input for channel 3 is the cassette, which is not emulated. CTC channels 1 and 2 have outputs which feed the DART serial clocks, but these are also not emulated.

MEMU detects writes to CTC channel 2 and ensures that interrupts are considered a certain fixed number of Z80 clock cycles afterwards. This slight hack allows the PANEL debuggers single step feature to work. It also allows VDEB.COM to work, as it uses the same trick.

Cassette tape

Not emulated. MEMU does not handle sound of any kind via the cassette ports.

Instead MEMU intercepts use of the cassette load and save routine in the MTX ROM at location 0x0aae. It LOADs, SAVEs and VERIFYs using a file of the given name, with .mtx appended, in the current directory. If no filename is given, it uses the .mtx file specified on the command line (if there was one) and failing that it uses default.mtx.

MEMU has a special hack to support a patched version of the "Z" ZX Spectrum Emulator, which I originally wrote. When Sinclair Basic LOADs, SAVEs or VERIFYs a file on tape, it accesses a ZX Spectrum format .tap file. By default, this file is called memu.tap.

Printer

Emulated by writing to a file. The port 0 and port 4 hardware interface is emulated. The CBIOS and CP/M interfaces above of that are emulated also.

Initial code from William Brendling.

PIO port

Not emulated.

Serial ports

The Linux and MacOSX versions of MEMU include DART emulation. This emulation works best with UNIX style named pipes. Named pipes on Windows require a completely different Windows specific API and seem follow a client-server model rather than the UNIX style model in which the pipe is created and then either side (producer or consumer) can connect first. So, no Windows support for now.

The input and output of each serial port can be specified as a file, device or named pipe.

So to create a node ring network with two nodes, you can :-

$ mkfifo link1
$ mkfifo link2
$ ./memu -rom7 roms/node.rom -serial1-in link1 -serial1-out link2 -s -v &
$ ./memu -rom7 roms/node.rom -serial1-in link2 -serial1-out link1 -s -v &

Floppy Disc Controllers

An FDX contained SJM's FDC and an SDX contained TB's FDC, and these were controlled through I/O ports, and a driver loaded into high CP/M memory by the FDX BOOT ROM or the SDX BOOT ROM. Alternatively (or also) the normal SDX ROM installed in the SDX disk drive would provide USER commands to MTX BASIC.

Normally MEMU is run in para-virtualised mode where CP/M BDOS is emulated. This mode is enabled when you use the -cpm or -sdx command line arguments, or you refer to .com files on the command line. Because emulation occurs at the CP/M and driver level, no access to FDC hardware actually occurs. This approach has the benefit that accesses may be made directly to files on the host filesystem, without having to manipulate images of floppy disks.

If you don't enable the above mode, and you use the -sdx-mfloppy argument, and you have ROMs loaded appropriately for SDX systems, then when these access SDX FDC ports, then Bill Brendlings emulation of the SDX FDC will read or write the indicated file. This approach requires you to manipulate images of Memotech floppy disks, using tools that understand CP/M filesystems, such as cpmtools.

Note that SDX FDC emulation can emulate 40 track or 80 track drives, as specified by the -sdx-tracks and -sdx-tracks2 arguments.

If you put an image of a 40 track disk in an 80 track drive, then the SDX FDC emulation in MEMU makes each track appear twice, which is much as it would appear in reality. The SDX FDC driver in the CP/M boot ROM double-steps when an 80 track drive is configured to a 40 track type code. The SDX FDC driver in the SDX ROM however has no such feature - the ROM is assembled for a particular disk type code, which is not reconfigurable, and it expects that a 40 track drive contains a 40 track disk and a 80 track drive contains an 80 track disk (only).

If you have Memotech floppy disks, or images of them, you may find MFLOPPY useful.

SD Card

MEMU does not emulate the SD Card hardware found in REMEMOTECH or REMEMOrizer.

This wouldn't be too hard to add. Just haven't had the need to do so as yet.

Silicon Discs

Silicon Discs were memory cards, of various sizes, accessed from the FDX via I/O port accesses.

The hardware is now emulated. You have 4 drives, each of which is fully populated with 8MB of memory. F: maps to drive 0, G: to drive 1, H: maps to drive 2 and I: maps to drive 3. You can configure them to be any of the Silicon Disc config type codes from 40 (=256KB) to 4F (=8MB). Note that if you've configured a drive as a RAM Disc, because this also uses a drive letter in the range F: to I:, you won't be able to access a Silicon Disc.

If you're using MEMUs CP/M emulation, or SDX emulation, then CP/M calls themselves are emulated in terms of host file accesses, and any Silicon Disc drivers will not be used, and the emulated hardware will not be touched.

You can use the -sidisc-file n fn command line argument to associate a filename with a drive. When MEMU starts, it will try to read the file and pre-initialise the Silicon Disc content with it. MEMU proceeds silently if for some reason this cannot be done. When MEMU terminates, if anything has ever been written to the drive, it writes the drive content to the file. MEMU proceeds silently if for some reason this cannot be done. Killing MEMU using kill or ^C can prevent it writing out the Silicon Disc content, so close a MEMU window instead.

The -sidisc-no-save flag tells MEMU not to bother to save the Silicon Disc content on termination.

Silicon Discs are (by their very nature) non-removable disks. Therefore MEMU provides no mechanism to change their content whilst it is running. If we were to allow this, disk corruption would occur.

It is no accident that the 8MB Silicon Disc type code 4F has the same geometry as the REMEMOTECH and REMEMOrizer SD Card partition type codes 18-1F. You can easily use MEMU to test the SD Card partitions, by accessing them as Silicon Disc type 4F drives.

MEMU has a special flag -sidisc-huge. The original Sidisc hardware only supported (and only needed to support) a 2 byte sector register, resulting in a 65536 sector x 128 bytes per sector capacity limit, ie: 8MB. This married nicely with the same CP/M software limitation. With the -sidisc-huge flag, if you supply a file that is larger, then it can be addressed. There is now a 3 byte sector register, resulting in 16777216 sector x 128 bytes per sector, ie: 2GB capacity limit. MEMU reads Sidisc file content into memory, so 2GB will probably run out of memory, but certainly sizes greater than 8MB can be accomodated. It is not anticipated that (m)any people will be interested in this feature, but it can be handy when developing software that uses SD Card or CF Disk (which can be have much more than 8MB of storage) using Sidisc in its place.

Speculator

The Speculator uses a small RAM representing Spectrum hardware. This sits behind a small number of Spectrum specific ports. Ports also exist to allow the Speculator code the opposite kind of access.

eg: Spectrum code outputs to port 0FEH to set the border colour. Speculator code inputs from port 07EH to read this value, then programs VDP register 7.

At this time, ports 01FH, 0FEH, 07EH, 07FH, 0FBH, 0xxFEH, 0xx7EH, and 0FFH are emulated. The xx's signify that a full 16 bit I/O address decode is performed, which is needed for the emulated keyboard support.

The original Speculator hardware partially address decodes ports x11xxxxx and xxx11111 binary, and the original Speculator code tests all these port ranges. We therefore require modified Speculator code which doesn't test everything, much as the Tatung Einstein version didn't.

The immediate and delayed NMI mechanism is emulated, although the exact amount of time the NMI is delayed by isn't accurate.

MEMU supports the ability to load from, or save to, a ZX Spectrum .sna snapshot file. This is done using diagnostic keypresses F9+l or F9+s.

MEMU doesn't support the enhanced Speculator hardware found in REMEMOrizer. Supporting this would slow MEMU down quite a bit, as it performs bus-snooping in order to track what parts of the Spectrum screen memory are being updated.

80 column card and monitor

MEMU does a basic emulation of the 80 column card hardware, and the screen buffer memory behind it. This emulation provides CRTC registers to read, and allows code to modify a subset of the ones which would really be modifiable. This emulation layer is only likely to be exploited by very low level programs, such as the VDEB.COM debugger.

MEMU also emulates the driver code which CP/M uses to write to the the 80 column card. When CP/M programs use BDOS calls 1, 2, 6 and 9, this would normally have involved CP/M BDOS calling the 80 column card driver code, which would normally have been present in high memory. In MEMU, the CP/M BDOS emulation directly calls the emulation of the 80 column card.

3 different qualities of emulation are available, which may be used in certain combinations :-

Here is an example of -mon-th :-

Contrast this with the hopefully pixel perfect -mon-win-big :-

The terminal driver emulation code currently understands everything except write masks and the DOT and VCT graphics commands.

It also understands the ^[Q and ^[R escape sequences only found in the SCPM ROM.

There are inaccuracies in the FDX User Manual. ch is shown as an argument to ^Z HME when it is actually an argument to ^[ ESC. The arguments to the ^[W set write mask command are shown as being binary, in fact they are ASCII. I can be confident the emulation reflects reality, as I have the source to the 80 column card driver (ACRT.MAC) and the 56 column SCPM driver (ASCRT.MAC, which I happen to have wrote).

In the "use a window" mode, key presses and releases are made available to CP/M programs, but note that at present, the UK keyboard layout is assumed. So shift-2 is ", shift-3 is £ and shift-' is @. Something to fix/improve in the future.

CP/M emulation

The Memotech FDX and SDX (with SCPM ROM) ran CP/M 2.2.

The examples shown here assume memu or memu.exe are on the PATH.

CP/M isn't hardware, but its emulated as if it was. In the real FDX/SDX, when a program did CALL 5, it jumped into CP/M BDOS code, which then used supporting driver code to access keyboard, screen, disk, silicon disk and other devices. It also understood the CP/M disk format. In MEMU, when a program does CALL 5, MEMU suspends the emulation, looks at the Z80 registers, does the equivelent of the CP/M BDOS function requested, updates Z80 registers, and then resumes the emulation. Effectively, CP/M BDOS functions are performed in 0 cycles of Z80 time.

One special CP/M program is the CCP (="Control Command Processor"?). This is the thing with the prompt, which responds to commands such as DIR and ERA, and which loads your chosen CP/M executable. MEMU doesn't emulate this. Instead, you load the CP/M executable up into memory, then start MEMU executing. eg: SDIR.COM is my special version of the DIR command :-

$ memu -iobyte 0x80 -addr 0x0100 -mem SDIR.COM \
       -mon-console -cpm -cpm-tail '*.COM'
A:SDIR    .COM     A:CONFIG  .COM

In the following shorthand form, MEMU notices the file ends in .COM, enables the CP/M emulation, sets the IOBYTE correctly, reads the file to 0x0100, parses the rest of the arguments as CP/M command tail, and starts execution from 0x0100 :-

$ memu -mon-console SDIR.COM '*.COM'
A:SDIR    .COM     A:CONFIG  .COM

The CP/M BDOS emulation supports the keyboard and console. It does not support reader or punch devices.

It doesn't support changing the CP/M IO byte (which is something different to the MTX memory map IOBYTE).

As disc emulation is done at the file level, the CP/M disc/directory layout is not emulated, so programs like CONFIG.COM and RCHECK.COM won't work.

We only support A:, and any attempt to use other disks will fail. The -cpm-drive-a path command line argument can be used to tell MEMU where to look in the host filesystem for the CP/M files. This doesn't affect the -mem argument.

Only host files matching the CP/M 8.3 upper-case naming convention are visible. It is possible (through the -cpm-invert-case command line argument) to invert the case so that lowercase files on the host are visible to CP/M and when CP/M writes files they are mapped to lowercase filenames.

Combining the above in some examples :-

$ ls cpm-files
GROTTO.SAV  rcheck.com  sidisc.com
TAP.SAV     sdir.com    stat.com
$ memu -mon-console cpm-files/sdir.com '*.*'
$ memu -mon-console -cpm-drive-a cpm-files cpm-files/sdir.com '*.*'
A:GROTTO  .SAV     A:TAP     .SAV
$ memu -mon-console -cpm-drive-a cpm-files -cpm-invert-case cpm-files/sdir.com '*.*'
A:RCHECK  .COM     A:SDIR    .COM     A:SIDISC  .COM
A:STAT    .COM

Note that CP/M files without file extension map to host files whose names do not end with a trailing dot. Host files with trailing dots (possible on Linux, but not on Windows) are not visible to CP/M as files with no extension. Host files with no dots in them are visible to CP/M as files with no extension.

Directories are not supported (CP/M 2.2 has no such concept).

Readonly and system bits are not supported.

The user is 0, and cannot be changed.

CP/M expects text files to have CR LF at the end of each line. Although this may be common on Windows, UNIX text files only have LF. Many Windows programs are tolerant of the UNIX style, but CP/M programs probably won't be. M80.COM, for example, expects CR LF.

CP/M files are always a whole number of 128 byte sectors long. If MEMU reads an incomplete sector from the host, it pads the rest with ^Z (=0x1a) characters. When writing a text file, if it isn't an exact multiple of 128 bytes, CP/M programs write ^Z to indicate end of text content in the file.

Calling BDOS with illegal arguments can terminate the emulation.

The emulation of CP/M also includes a CBIOS jump table. CBIOS is a hardware dependent layer of functionality below the hardware independant implementation of CP/M. Entrypoints relating to keyboard and screen are intercepted and emulated. Other entrypoints are not implemented, and if used, MEMU will terminate.

In addition, calls to the vectors in very high memory which call the raw keyboard and screen driver code are intercepted and supported.

The BDOS implementation appears to be at 0xfe00, thus giving CP/M programs 0xfd00 bytes (just over 63KB) of transient program area. This is more than the 54KB or 59KB that FDX or SDX users had. However, if a program happens to use the raw keyboard driver routine, they should only use 0xef00 bytes (just under 60KB) because the driver stores the returned key at 0xf001. Newword is known to use the keyboard driver routine.

SDX system

The normal SDX addon to the MTX was a disk controller card (possibly with extra memory) connected to a disk drive. Earlier SDXs will have used 5.25" or 3.5" drives, formatted as type 03. Later SDXs will have used 3.5" drives, formatted as type 07.

On the card was the SDX ROM, containing the following :-

The user would issue ROM 3 to reinitialise the SDX system. You would do this after a disk change, and is much like pressing ^C on CP/M.

If the -sdx command line argument is used, MEMU installs the SDX ROM into the slot for ROM 3, and then patches it so that it doesn't attempt to initialise the FDC chip, and doesn't try to load and patch CP/M BDOS. Instead it intercepts attempts to use CP/M BDOS, and emulates them using the same code as is used in the CP/M emulation.

Some later SDX systems (including my own) have a CP/M boot ROM in slot 4 and the normal SDX ROM in slot 5. MEMUs emulation of SDX places its (patched) ROM image in slot 3.

SDX support isn't installed by default as it reduces the amount of memory available to BASIC programs by quite a lot.

In MEMU, attempts to use USER STAT, USER FORMAT and USER SYSCOPY will result in a "Mistake" error. MEMU doesn't emulate enough of CP/M BDOS (ie: it doesn't emulate allocation maps or DPBs) and in this mode, it doesn't emulate the FDC.

Time

MEMU understands that the Z80 chip ran at 4MHz. But this can be changed by passing the -speed command line argument (eg: for a 6MHz CPU, use -speed 6000000).

MEMU is written to pace the execution of Z80 instructions against real time. If it notices that more instructions have been executed than should have been in a given amount of real time, it sleeps to slow itself down. On my Linux system, emulated CPU speed typically varies between 3.9MHz and 4.2MHz.

To remove any pacing of execution speed pass the -fast command line argument. On my Linux system, Z80 CPU speed rises to anything between 30MHz to 60MHz, depending on the use of -vid-win-big verses -vid-win. This also speeds up the rate at which other hardware devices change, including the rate at which video frames are refreshed. The net effect is that games speed up and become unplayable. However, for non-interactive programs, this is quite a handy option.