Here we discuss what MEMU emulates, and to what degree :-
MEMU emulates the fixed ROM slot, and 8 paged ROM slots.
It preloads the
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
-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
to change this :-
|20||α-δ, a-p||MTX512 + 256KB RAM upgrade|
|24||α-δ, a-t||MTX512 + 320KB RAM upgrade|
|36||α-δ, a-F||MTX512 + 512KB RAM upgrade|
Logical memory map, as seen in
RELCPMH=0 mode :-
|2||ROM 2 sub-pages||c||b||2|
Logical memory map, as seen in
RELCPMH=1 mode :-
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.
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.
-subpage command line argument can be used to set
the subpage on the command line, prior to using
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
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
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.
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 :-
(is shift 9 on the host PC keyboard, but it is shift 8 on the MTX keyboard. This isn't a problem for MEMU. If you press type
(by typing shift 9 on the host, MEMU presses shift 8 in the emulated MTX keyboard, thus producing the expected result.
^is shift 6 on the host PC keyboard, but it is unshifted on the MTX keyboard. eg:
=is unshifted on the host PC keyboard, but it is shift - on the MTX keyboard. This is a huge problem, because if I try to workaround this by lying about the shift state, due to the way the keyboard sense bits are typically scanned in MTX software, I observe intermittant incorrect typing errors. So therefore, to type certain MTX characters, you must type different things on the host PC keyboard. This remapping is done to ensure an unshifted host PC keypress corresponds to an unshifted MTX keypress and a shifted host PC keypresses corresponds to a shifted MTX keypress.
Insertkey presses MTX
HOMEkey. The MTX numeric keypad is physically laid out so that the
HOMEbutton is in the middle and the arrows are grouped around it. Therefore MEMU maps the host PC numeric keypad (on the far right) so that 5 corresponds to
HOMEand the arrows around it work as advertised. So that games like Qogo and Reveal work as advertised, the whole host PC keypad maps to the whole MTX keypad, based on key position, not what is written on the keys.
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
-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
typically next to the right Ctrl key.
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
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
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 :-
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
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
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.
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.
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
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
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.
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.
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
It LOADs, SAVEs and VERIFYs using a file of the given name,
.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
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
By default, this file is called
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.
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 &
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
command line arguments, or you refer to
.com files on the
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
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
Note that SDX FDC emulation can emulate 40 track or 80 track drives,
as specified by the
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
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 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
^C can prevent it
writing out the Silicon Disc content, so close a MEMU window instead.
-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
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.
-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.
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
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
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 :-
-mon-wincommand line argument. A larger window with a better aspect ratio can be selected using the
-mon-win-bigcommand line argument. Correctly emulates the terminal by responding to various control and escape sequences. Renders this to the window, using (hopefully) pixel perfect character renditions, in colour. Supports
-mon-win-mono, which reverts back to the green screen monochrome display, with underline, bright and inverse attributes. Responds to key presses made in the window and makes them available to CP/M programs.
-mon-thcommand line argument. Also correctly emulates the terminal. Renders this to the text mode screen. Only able to reproduce printable ASCII characters, although it does render them in the correct colours. Responds to key presses made in the text mode screen and makes them available to CP/M programs. If you're running in an XTerm or Gnome Terminal, its easy to cut-n-paste from the text mode window. Tip: resize your terminal window to 80x24 before running MEMU.
-mon-consolecommand line argument. Does not correctly emulate the terminal. All it does it pass the output directly to
stdout. It takes cooked input from
stdinand makes this available to CP/M programs. Unfortunately, as its cooked, it will already have been edited and echoed, and the CP/M program will probably echo it again. Also, the emulation is suspended whilst the CP/M program is waiting for keyboard input. This mode is useful when running non-interactive CP/M programs, for example, the
M80.COMMacro Assembler. When a CP/M program asks if a key is pressed, the answer is yes, unless the
-mon-console-nokeycommand line argument is used.
Here is an example of
Contrast this with the hopefully pixel perfect
The terminal driver emulation code currently understands everything
except write masks and the
It also understands the
escape sequences only found in the SCPM ROM.
There are inaccuracies in the FDX User Manual.
ch is shown as an argument to
when it is actually an argument to
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 (
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.
The Memotech FDX and SDX (with SCPM ROM) ran CP/M 2.2.
The examples shown here assume
memu.exe are on the
CP/M isn't hardware, but its emulated as if it was.
In the real FDX/SDX, when a program did
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
ERA, and which loads your chosen
MEMU doesn't emulate this.
Instead, you load the CP/M executable up into memory, then start
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
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
RCHECK.COM won't work.
We only support A:, and any attempt to use other disks will fail.
-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
Only host files matching the CP/M 8.3 upper-case naming convention
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
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
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
Newword is known to use the keyboard driver routine.
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 :-
AFDSC.MACcode used to make the SDX SCPM ROM.
USER DIR "*.BAS"
USER LOAD "FILE.BAS"
USER SAVE "FILE.BAS"
USER RUN "FILE.RUN"
USER READ "FILE.DAT",24*1024
USER WRITE "FILE.DAT",24*1024,3*1024
USER ERA "FILE.DAT"
USER ERA "*.BAK"
USER REN "NEWFILE.DAT"="OLDFILE.DAT"
USER STAT "FILE.DAT"
USER STAT "FILE.DAT",RO
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.
-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 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.
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
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
command line argument.
On my Linux system, Z80 CPU speed rises to anything between
30MHz to 60MHz, depending on the use of
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.