Following my question on booting CP/M automatically on RC2014 Z80, I'd like to run a program after CP/M starts, similar to how autoexec.bat works on DOS.

I see that CP/M 3 has PROFILE.SUB which would solve the problem, but the RC2014 CF comes with CP/M 2.2.

There's a project similar to the RC2014 Z80 called Z80-MBC, which seems to have achieved this, but the instructions are specific to that project and I'm not sure how to translate that to RC2014 Z80 CP/M.

  • Well, they are simply changing the CP/M's CCP, which was a common way, but that's only possible if the CCP is stored in a changeable media - IIRC your RC2014 has not. In fact, all I know are based on the fact that CP/M is stored on changable media and loaded into RAM.
    – Raffzahn
    Jan 4, 2023 at 14:43
  • With RC2014, CP/M is stored on a 128MB CF. I thought perhaps I could modify the data on the CF to change the CCP. Jan 4, 2023 at 15:04
  • 2
    You can create a0:$$$.SUB as SUBMIT would have written it. It is my understanding the CCP uses this if present. Jan 4, 2023 at 15:43
  • @ThorbjørnRavnAndersen Could you elaborate a little more on what you mean? > "a0:$$$.SUB as SUBMIT would have written it" Jan 4, 2023 at 16:15
  • 3
    @NickBolton: When CCP runs, it checks whether $$$.SUB exists. If so, it reads the last 128 bytes of the file into its line buffer, shrinks the file by 128 bytes (deleting it if the size would become zero), and executes the contents of the line buffer. If the first 128 bytes of $$$.SUB contained a command that would $$$.SUB, then unless the system lost power between the time that program was launched and the time it was able to rewrite the file, the system would on power-up process whatever the next action in $$$.SUB would be.
    – supercat
    Jan 4, 2023 at 17:04

4 Answers 4


This is explained by Digital Research in CP/M 2.2 Application Note 01. At cold start, with the CCP and BDOS loaded, the memory at CCP+7 should be populated with the length of the command, followed by the command itself, and then a zero byte.

If the CCP is only loaded from disk at cold boot, this can be done by patching the CCP image on disk. This would require you to know whereabouts on the disk the CCP is stored; this is system dependent and there will be exceptions to any general advice I could give. A 'classic' CP/M 2 system would have the BIOS, BDOS and CCP in the lowest-numbered tracks of the disc, before the directory. A sector editor such as DU89.COM would allow you to examine the contents of these tracks and search for a byte sequence which you know to be in the CCP. Once the CCP had been located, you could use the sector editor to read, modify, and write back the first sector of the CCP.

In Digital Research's example, the system image is generated as the file CPM64.COM, modified by the user using DDT.COM and then written to the boot floppy with SYSGEN.COM.

Alternatively, the BIOS could be modified to store the correct values in the CCP at cold start.

The same technique applies to CP/M-86 v1.x, except that the command buffer is three bytes higher in memory, at CCP+0Ah.

  • Could you explain a little more about "patching the CCP image on disk"? Thanks Jan 4, 2023 at 16:35

CP/M 2.2 itself contained no feature to autorun an application at boot time.

That being said, there exist multiple solutions that folks came up with in order to do this. The most common that I'm aware of:

  1. Patching the CCP (Command Processor) so that it had the needed command and would start it automatically.
  2. Use of an alternative shell that supports an autorun feature. One example that I had some experience with is ZCPR (http://gaby.de/ftp/pub/cpm/znode51/specials/manuals/zcpr3.pdf) that replaced CP/M's CCP with itself and provided additional functionality.

In my work on be able to use RunCPM as a Github Action (because it transparently maps the underlying file system to CP/M disks) I found that the emulated command processor supported the standard CP/M '$$$.SUB' facility on the A drive and this could be used to inject commands even if the emulator did not support this from the command line, so I had a closer look.

'A0:$$$.SUB' is what the SUBMIT.COM command generates given an input batch file.

The format is simple: The list of commands is reversed, and converted to a set of 128-byte records. Each record contains first a byte stating the length of the command, the actual command and a trailing zero (not counted) plus padding up to 128 characters. The command processor then at each command prompt takes the last record, truncates the file to be one record shorter, and executes the command. If an error occurs the file is deleted.

I wrote this unoptimized Perl-snippet which may be useful:

perl -e 'print join("\n", reverse @ARGV)' "$@" | perl -ne 's/[\r\n]//g; printf "%-128s", chr(length($_)).$_.chr(0)' > 'A/0/$$$.SUB'

This mechanism was probably chosen for being short and simple in a period where every byte counted.

If you can inject such a file onto the disk or disk image that the emulator considers A:, it should be executed when the emulator starts.


I found a really simple solution to emulate autoexec.bat on CP/M 2.2.

Create the file a:autoexec.sub (I used ed), which contains two lines:

c:submit autoexec

Note: Replace b:foobar with whatever program you want to run when CP/M starts.

After creating the file, run the command:

c:submit autoexec

This will start your program, and if the computer resets, it'll always run that program when CP/M starts.

Disclaimer/warning: You may not be able to exit out of your program, since this creates an endless loop; when your program exits, the submit command will run again and the batch will start over. I think this solution can be improved, since it's probably a bit of a hack. I found that just holding any key down at boot stops the submit command from running, but that may not work for you. I have no idea why that seems to break the loop.

How this works:

  1. The submit command runs the first line of the autoexec.sub (our program).
  2. Before the 2nd command runs, $$$.sub is created in a: which contains the remaining batched commands to run (c:submit autoexec).
  3. When the computer is reset, if $$$.sub exists, CCP (console command processor) runs the remaining batched commands saved in the $$$.sub file (in our case, c:submit autoexec) and the loop restarts.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .