CP/M does networks!? Who knew? Well, it does, it's called (perhaps not-too-creatively) CP/Net, and, like the rest of Digital Research's products, it has been freely available for many years. The problem has always been assembling, compiling and installing it.
Well, that used to be a problem. Not anymore. Udo Munk, developer of the best-in-class Z80Pack Z80 emulator, has done all the hard work, making it possible for even the most technically incompetent (speaking from experience) of us to become CP/M network admins in just a few minutes' time. And as an added bonus, through the magic of Z80Pack, you can connect your CP/Net network up to the Internet and access it from anywhere in the world. Not even Gary Kildall could have imagined that!
This tutorial assumes that you are running Linux as your host OS, that you already have Z80Pack installed to ~/z80pack/, and that you have basic familiarity with opening and using a command terminal. If you are running Windows, the differences should be trivial. And if you don't yet have Z80Pack installed, there are easy-to-follow instructions at the site, or you can use our quick installation script to get it done for you.
Ready? Here we go.
In this first part, you're going to install a single CP/Net server and connect to it via telnet. You've got Z80Pack installed, right? Now it's time to install the server. Ready ... set ...
You're done.
Yep, CP/Net is part of the base install of Z80Pack. All we need to do is make one configuration change and then launch our server. Open a terminal window and run the following commands:
$> cd ~/z80pack/cpmsim/conf/
$> ls
You should see two files: net_client.conf.example and net_server.conf.example. We're going to enable the server, so:
$> cp net_server.conf.example net_server.conf
That's it. We're now ready to start the server.
$> cd ~/z80pack/cpmsim
$> ./mpm
Z80Pack will load and launch a CP/M session. Look for messages like console 1 listening on port 4000, telnet = on as Z80Pack starts up.
####### ##### ### ##### ### # #
# # # # # # # # ## ##
# # # # # # # # # # #
# ##### # # ##### ##### # # # #
# # # # # # # # #
# # # # # # # # # #
####### ##### ### ##### ### # #
Release 1.35, Copyright (C) 1987-2017 by Udo Munk
CPU speed is unlimited
Server network configuration:
console 1 listening on port 4000, telnet = on
console 2 listening on port 4001, telnet = on
console 3 listening on port 4002, telnet = off
console 4 listening on port 4003, telnet = off
Booting...
64K CP/M Vers. 2.2 (Z80 CBIOS V1.2 for Z80SIM, Copyright 1988-2007 by Udo Munk)
A>
At the CP/M A> prompt, run:
A>MPMLDR
to load the multi-user version of CP/M. And that's it. You can work on the server directly, but the real fun is logging in remotely. Let's do that now.
Open a new terminal window and run:
$> telnet localhost 4000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
MP/M II V2.0
Copyright (C) 1981, Digital Research
1A>
You should have connected and found yourself at a CP/M prompt (that was easy!).
You can open a second terminal and telnet to port 4001. And for the piece de resistance, with a little port forwarding you can even telnet in to your server from the Internet. What fun!
WARNING! To exit your telnet connections, do not type exit or bye. This will shut down your server, which is probably not what you desired. If you're using the standard Linux telnet client, type ^] to escape to the telnet prompt, then close to close the telnet connection without affecting the server.
$> telnet localhost 4000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
MP/M II V2.0
Copyright (C) 1981, Digital Research
1A>
telnet> close
Connection closed.
$> cd ~/z80pack/cpmsim/conf/
$> cat net_server.conf
# Console telnet flag TCP/IP port
1 1 4000
2 1 4001
3 0 4002
4 0 4003
This tells us that the four supported consoles are connected to the four TCP/IP ports 4000-4003, and that ports 4000 and 4001 are enabled for telnet access. The second two have telnet disabled and can be used for login by CP/Net clients (more on this, later). Now run:
$> telnet localhost 4001
You should find yourself again connected to your server, only this time the command prompt says, 2A>, indicating you have been assigned user 2.
To connect more telnet sessions, you'll have to enable telnet on the other consoles. Shut down all your client sessions and your server by typing BYE at the server's console. Edit conf/net_server.conf, change the telnet flags to "1", save, exit and then relaunch your server. Now you will be able to telnet to any or all of the ports 4000 - 4003.
If all you wanted was a CP/M session you can remotely connect to, you're done. Enjoy! If you want to learn how to set up and connect a CP/M client, read on.
OK, I admit it. I lied. In the first part above we weren't really running a CP/Net server, just an MP/M machine with telnet-accessible consoles. But it pretty much acts like a server and everything, so why not call it a server?
In this part we're going to be installing a CP/Net client, but it will need a real server to connect to, so we will install one of those as well. But first, if you currently have a server running, shut it down by typing A:BYE.
To kick things off we'll download the client and server packages. So open a terminal and run these commands:
$> cd ~/z80pack/cpmsim/
$> wget https://www.autometer.de/unix4fun/z80pack/ftp/cpm2-net-1.2.tgz
$> wget https://www.autometer.de/unix4fun/z80pack/ftp/mpm2-net-1.2.tgz
$> tar -xvf cpm2-net-1.2.tgz
$> tar -xvf mpm2-net-1.2.tgz
$> ls
You should see two new session launch scripts in ~/z80pack/cpmsim/: cpm2-net2 and mpm-net2. These scripts will require updating before we can run them. We'll use the nano editor here, since it comes with most Linux distros.
$> nano cpm2-net2
Change all instances of, e.g., drivea.cpm to drivea.dsk, then save and exit. Then do the same for mpm-net2.Now, we will need to enable networking and run the server:
$> cd ~/z80pack/cpmsim/conf/
$> rm *.conf
$> cp net_server.conf.example net_server.conf
$> cd ..
$> ./mpm-net2
You should see the start-up banner for the MP/M server:
console 1 listening on port 4000, telnet = on
console 2 listening on port 4001, telnet = on
console 3 listening on port 4002, telnet = off
console 4 listening on port 4003, telnet = off
Booting...
64K CP/M Vers. 2.2 (Z80 CBIOS V1.2 for Z80SIM, Copyright 1988-2007 by Udo Munk)
A>
If you see the message, bind server socket: Address already in use, check to make sure you didn't forget to shut down your other servers, then try again.
Finally, load MP/M:
A>MPMLDR
You should see lots of stuff, and then the sign-on banner:
MP/M II V2.0
Copyright (C) 1981, Digital Research
0A>
Your server is up and running. On to the client. Since we're going with default settings, we only need to swap network configuration files and start the client. Open a new terminal:
$> cd ~/z80pack/cpmsim/conf/
$> rm *.conf
$> cp net_client.conf.example net_client.conf
$> cd ..
$> ./cpm2-net2
Verify that you saw the message Connecting to localhost at port 4002 and the sign-on banner, 64K CP/M Vers. 2.2 (Z80 CBIOS V1.2 for Z80SIM, Copyright 1988-2007 by Udo Munk) then, at the A> prompt start the network, then log in and map a network resource:
A>CPNETLDR
CP/NET 1.2 Loader
=================
BIOS FA00H 0600H
BDOS EC00H 0E00H
SNIOS SPR E900H 0300H
NDOS SPR DD00H 0C00H
TPA 0000H DD00H
CP/NET 1.2 loading complete.
A>LOGIN
A>NETWORK B:=B:
A>
Both the LOGIN and NETWORK commands will return silently if successful. If you see the message Login failed, verify that you downloaded the same version of the client and server software, above.
So our server is running, our client is logged in, and we've mapped a network resource. Now it's time to play :) . On the client, run:
A>DIR B:
B: MPM SYS : RESBDOS SPR : NETWRKIF ASM : SYSTEM DAT
B: BNKBDOS SPR : TMP SPR : GENSYS OM : BNKXIOS MAC
B: MPMSTAT BRS : SPOOL RSP : ABORT RSP : SCHED RSP
B: BNKXIOS SPR : HWCLOCK RSP : RESXIOS SPR : BNKXDOS SPR
B: SERVER RSP : SPOOL BRS : XDOS SPR : SCHED BRS
B: MAIL COM : M80 COM : SYSGEN SUB : MPMSTAT RSP
B: NETWRKIF RSP
A>
Since we've mapped local drive B: to the server's B: drive, we are seeing the contents of B: on the server. Now let's check the network's status:
A>CPNETSTS
CP/NET 1.2 Status
=================
Requester ID = 11H
Network Status Byte = 10H
Disk device status:
Drive A: = LOCAL
Drive B: = Drive B: on Network Server ID = 00H
Drive C: = LOCAL
Drive D: = LOCAL
Drive E: = LOCAL
Drive F: = LOCAL
Drive G: = LOCAL
Drive H: = LOCAL
Drive I: = LOCAL
Drive J: = LOCAL
Drive K: = LOCAL
Drive L: = LOCAL
Drive M: = LOCAL
Drive N: = LOCAL
Drive O: = LOCAL
Drive P: = LOCAL
Console Device = LOCAL
List Device = LOCAL
A>
There is of course much more to running a CP/Net network. Udo Munk, the author of Z80Pack, has made full documentation available at the Z80Pack website. The two best places to begin are the CP/NET Network Operating System Reference Manual and the MP/M 2 manual.
Yes! This is great and all, but you want more. More servers! More clients! More!
As mentioned above, it is possible to connect up to four clients to a server. But each client must be manually configured to connect to a specific server port.
$> cat conf/net_client.conf.example
# example for network client configuration
#
# Console host TCP/IP port
#1 www.unix4fun.org 4052
1 localhost 4002
As you can see, the default setting for a client hardwires it to port 4002. To connect additional clients, you must manually change the port setting to 4001, etc., before launching the client.
And just by the way, as the configuration file shows us, we could connect our client to a server on the internet, or even to a local network address, allowing CP/Net to piggyback over TCP/IP networks! Cool, no? (Just don't try the example shown; Udo Munk no longer runs that server.)
It is also possible to install multiple servers. But in order to prevent servers from stepping on each other's ports, you must manually configure each server's port assignments in net_server.conf, and make sure each port you wish to connect a client to has telnet disabled.
As you can imagine, all this manual downloading and installation, and constant reconfiguring of port settings and swapping in and out of configuration files can become tedious (not to mention error prone) like real quick. But, hey, I got your back. Nathanael's Super-Duper Client Installation Script (or "NaSuDuClInSc", for short :) ) and Nathanael's Super-Duper Server Installation Script ("NaSuDuSerInSc") are here for you.
Click on each of the links above to see the scripts. Save each script to ~/z80pack/cpmsim/; we'll call ours client_install and server_install. Then chmod +x each one.
First, shut down all clients and servers currently running by type A:BYE in each one. Then since we will no longer be needing the client and server we installed above, let's adios them.
$> cd ~/z80pack/cpmsim
$> rm cpm2-net2
$> rm mpm-net2
Now run the server installation script:
$> ./server_install
The script will download and install the server software, place a network configuration file for it in conf/library/ and then create a session launch script called mpm-server1.
Now run the client installation script twice to create two clients.
$> ./client_install
$> ./client_install
and you will have two session launch scripts called cpm2-client1 and cpm2-client2.
You can run the server and client install scripts repeatedly to install additional servers and clients and they will be assigned sequential names such as mpm-server2, mpm-server3, cpm2-client3, etc. The install and launch session scripts will automatically handle all the configuration stuff; all you need to do is to run the session script when you wish to run a particular server or client.
Note that each client is configured to connect to a specific server, so that if you wish to run a specific client, you should make sure its assigned server is already running. It might be good to look briefly at how these install scripts set things up.
Those familiar with Z80Pack know that it stores virtual disk images in disks/library/ and that a session install script will create links to those images in disks/. Network configuration is handled by the server and client install scripts in the same way: a config file is placed in conf/library/ for each client and server, and that client's or server's session launch script will place a link to it in conf/.
On installation, each server is assigned a range of ports, with the telnet flags enabled for Consoles 1 and 2, disabled for Consoles 3 and 4.
Server | Console 1 (T) | Console 2 (T) | Console 3 (-T) | Console 4 (-T) |
---|---|---|---|---|
mpm-server1 | 4000 | 4001 | 4002 | 4003 |
mpm-server2 | 4004 | 4005 | 4006 | 4007 |
mpm-server3 | 4008 | 4009 | 4010 | 4011 |
mpm-server4 | 4012 | 4013 | 4014 | 4015 |
On the client side, each pair of clients is configured to connect as follows:
Client | Port | Server |
---|---|---|
cpm2-client1 | 4002 | mpm-server1 |
cpm2-client2 | 4003 | mpm-server1 |
cpm2-client3 | 4006 | mpm-server2 |
cpm2-client4 | 4007 | mpm-server2 |
cpm2-client5 | 4010 | mpm-server3 |
cpm2-client6 | 4011 | mpm-server3 |
cpm2-client7 | 4014 | mpm-server4 |
cpm2-client8 | 4015 | mpm-server4 |
Of course these are just default settings which you are free to change should you want to. Just edit the .conf files in conf/library/.
Now let's run our server and clients:
$> ./mpm-server1
At the A> prompt, load MP/M:A>mpmldr
Server's up and waiting! Open a second terminal.
$> ./cpm2-client1
Look for a message saying, Connecting to localhost at port 4002. Load CP/Net and login in.
A>cpnetldr
CP/NET 1.2 Loader
=================
BIOS FA00H 0600H
BDOS EC00H 0E00H
SNIOS SPR E900H 0300H
NDOS SPR DD00H 0C00H
TPA 0000H DD00H
CP/NET 1.2 loading complete.
A>login
A>
Now the second client. In a third terminal do:
$> ./cpm2-client2
This time you should see, Connecting to localhost at port 4003. Again, load CP/Net and login.
Th-th-th-that's all, folks! Through the wonders of Z80Pack, you can set up as simple or complex a CP/Net network as you'd like, and all you have to do is run a couple of scripts and edit a few configuration files.
So what's next? The fun, of course, of learning how to administer a CP/Net network. For that, the Z80Pack website has made full documentation available. Start by reading through the CP/Net Network Operating System manual, the CP/M 2.2 Operating System Manual and the MP/M 2 User's Guide, then explore the wealth of other resources available at the site. To discuss with other CP/M afficianados, head on over to the very active comp.os.cpm. And to download CP/M software, try my own archive, the *HUMONGOUS* CP/M Software Archives.
These scripts have only been tested with Bash. For Windows users, they shouldn't be too difficult to convert.
Save this script to whatever directory you want Z80Pack installed inside of. E.g., if you want Z80Pack to be installed to ~/z80pack-1.36/ then save this script in ~. Then just run it. If there is a more recent version of Z80Pack available, or if for some reason you want to install an older version, then change the zver variable accordingly. Note that currently this script generates an "unexpected end of file" message at the end. This error is harmless and can be ignored.
#!/bin/bash # Variables zver=1.36 # set to the version you wish to install zroot=~/cpm # set to the location where you want z80pack-1.36/ zloc=$zroot/z80pack-$zver osenv=linux # Your operating environment; one of linux, cygwin, osx, solaris or bsd function main { echo " ------------------------------ " echo " Installing Z80Pack " echo " ------------------------------ " # Obtain and unpack Z80Pack mkdir -p $zroot cd $zroot wget https://www.autometer.de/unix4fun/z80pack/ftp/z80pack-$zver.tgz tar xvf z80pack-$zver.tgz rm z80pack-$zver.tgz } function buildit { echo " ------------------------------ " echo " Building $component " echo " ------------------------------ " # build it cd $zloc/$component/ # two steps to accomodate frontpanel cd srcsim/ # which doesn't have a srcsim subdir make -f Makefile.$osenv make -f Makefile.$osenv clean # Backup disk images if [ -d ../disks ] then cd ../disks mkdir -p backups cp -p library/* backups/ fi } function cpmsim { component=cpmsim ; buildit # Compile support programs mkdir -p ~/bin cd $zloc/cpmsim/srctools make make install make clean # Make sure ~/bin is in your search path: export PATH=PATH:~/bin } function frontpanel { # --- FRONTPANEL --- # front panel requires the following: # sudo apt-get install g++ # sudo apt-get install libjpeg9-dev # sudo apt-get install libglu1-mesa-dev # sudo apt-get install libxmu-dev component=frontpanel ; buildit echo " ------------------------------ " echo " Enter your admin password: " echo " ------------------------------ " sudo cp libfrontpanel.so /usr/lib/ # or a shared library path on your system. } function altairsim { component=altairsim ; buildit # Install additional cd $zloc/altairsim/ for mits in dbl.hex dbl.asm dbl.prn; do wget https://www.autometer.de/unix4fun/z80pack/ftp/altair/$mits done for mits in mits-cpm22.tgz mits-cpm14.tgz mits-basic40.tgz mits-basic50.tgz mits-cpm-tools.tgz mits-cpm-ws30.tgz mits-dos.tgz do wget https://www.autometer.de/unix4fun/z80pack/ftp/altair/$mits tar -xvf $mits rm $mits done # Make scripts cat > mits-cpm22 <<EOL #!/bin/sh # rm -f disks/drive[abcd].dsk ln disks/library/mits-cpm22-56k.dsk disks/drivea.dsk ln disks/library/mits-cpm-tools.dsk disks/drivec.dsk # ./altairsim -x dbl.hex $* EOL chmod +x mits-cpm22 cat > mits-cpm14 <<EOL #!/bin/sh # rm -f disks/drive[abcd].dsk ln disks/library/mits-cpm14-24k.dsk disks/drivea.dsk ln disks/library/mits-cpm-tools.dsk disks/drivec.dsk # ./altairsim -x dbl.hex $* EOL chmod +x mits-cpm14 cat > mits-dos <<EOL #!/bin/sh # rm -f disks/drive[a].dsk ln disks/library/mits-dos.dsk disks/drivea.dsk # ./altairsim -x dbl.hex $* EOL chmod +x mits-dos } function cromemcosim { component=cromemcosim ; buildit } function webfrontend { cd $zloc/webfrontend/civetweb/ make -f Makefile.$osenv make -f Makefile.$osenv clean } function imsaisim { component=imsaisim ; buildit } # --- MAIN --- main cpmsim frontpanel altairsim cromemcosim # webfrontend is not in 1.36 or earlier if [ -d $zloc/webfrontend/ ] && webfrontend imsaisim exit 0
#!/bin/bash # Variables zver=1.36 # The latest version of Z80Pack zloc=~/cpm/z80pack-$zver confdir=conf conflib=$confdir/library # Create dir cd $zloc mkdir -p $conflib # skip existing clients clientnum=1 while [ -f cpm2-client$clientnum ]; do clientnum=$(( $clientnum + 1 )) ; done # Fetch and install wget https://www.autometer.de/unix4fun/z80pack/ftp/cpm2-net-1.2.tgz # --transform replaces the string 'net2' with 'clientx' in all extracted # filenames. Unfortunately, 'client$clientnum' is interpreted literally, # so the files first need to be extracted to 'clientx' then renamed. tar --transform='flags=r;s|net2|clientx|' -xvf cpm2-net-1.2.tgz mv disks/library/cpm2-clientx.dsk disks/library/cpm2-client$clientnum.dsk rm cpm2-clientx # We will rebuild this later # Build configuration files # Create network configuration file confile=$conflib/cpm2-client$clientnum.conf listenport=$((4000 + clientnum*2 - ((clientnum-1) % 2))) cat > $confile <<EOL # Network client configuration for Client $clientnum # # Console host TCP/IP port 1 localhost $listenport EOL # Build launch script script=cpm2-client$clientnum cat > $script <<EOL #!/bin/bash # rm -f disks/drive[a].dsk ln disks/library/cpm2-client$clientnum.dsk disks/drivea.dsk # rm -f $confdir/*.conf ln $conflib/cpm2-client$clientnum.conf $confdir/net_client.conf # ./cpmsim $* EOL chmod +x $script #cleanup rm cpm2-net-1.2.tgz
#!/bin/bash # Variables zver=1.36 # The latest version of Z80Pack #basedir=~/cpm/z80pack/cpmsim confdir=conf conflib=$confdir/library # Create dir # cd $basedir mkdir -p $conflib # skip existing servers servernum=1 while [ -f mpm-server$servernum ]; do servernum=$(( $servernum + 1 )) ; done # Fetch and install; rename extracted files wget https://www.autometer.de/unix4fun/z80pack/ftp/mpm-net-1.2.tgz # --transform replaces the string 'net2' with 'serverx' in all extracted # filenames. Unfortunately, 'server$servernum' is interpreted literally, # so the files first need to be extracted to 'serverx' then renamed. tar --transform='flags=r;s|net2|serverx|' -xvf mpm-net-1.2.tgz mv disks/library/mpm-serverx-1.dsk disks/library/mpm-server$servernum-1.dsk mv disks/library/mpm-serverx-2.dsk disks/library/mpm-server$servernum-2.dsk rm mpm-serverx # We will rebuild this later # Build configuration files # Create network configuration file confile=$conflib/mpm-server$servernum.conf baseport=$(( 4000 + (servernum-1)*4)) cat > $confile <<EOL # Network server configuration for MP/M Server $servernum # # console: # of the console port, 1-4 # telnet flag: 1 = telnet option negotiation on, 0 = off # TCP/IP port: every console needs a different port; every server a unique range # # Console telnet flag TCP/IP port 1 1 $((baseport+0)) 2 1 $((baseport+1)) 3 0 $((baseport+2)) 4 0 $((baseport+3)) EOL # Build launch script script=mpm-server$servernum cat > $script <<EOL #!/bin/sh # rm -f disks/drive[ab].dsk ln disks/library/mpm-server$servernum-1.dsk disks/drivea.dsk ln disks/library/mpm-server$servernum-2.dsk disks/driveb.dsk # rm -f $confdir/*.conf ln $conflib/mpm-server$servernum.conf $confdir/net_server.conf # ./cpmsim $* EOL chmod +x $script #cleanup rm mpm-net-1.2.tgz