• CBIOS Fixes

    agp.cooper06/13/2021 at 05:50 0 comments

    CBIOS Fixes

    I have been working through Grant Searle's cbios.asm and comparing that to my cbios.asm. I found tree coding errors:

    1. Incomplete disk parameters.
    2. Stack pointer location not properly set after boot.
    3. Cold boot system reload, source and destination swapped.

    DDT is my new friend

    DDT is the Digital Research's CP/M Dynamic Debugging Tool. As exiting DDT crashed my system, it was not my favourite program. But this time I used it to trace exit from DDT and find why my system crashed. It is now one of my favourite programs.

    Clear To Send (CTS)

    My soft-coded serial is half duplex (i.e. cannot transmit and receive at the same time). It works well enough for a human typing but not for anything serious. Basically, if the interrupts are disabled I also need to disable CTS (e.i. set CTS HIGH).

    Looking at my schematic, the best way to do this via the OUT instructions. Perhaps re-purposing "P5", the port configuration is:

    • D0 -> P0
    • D1 -> P1
    • D2 -> P2
    • D3 -> P3
    • D4 -> P5
    • D5 -> P5 -> CTS
    • D6 -> DSK0
    • D1-> DSK1

    This port configuration can access 4 disks of 2 Mb each, with CTS the disks will be reduced to 1 Mb each.

    So I can jump a wire between "P5" and "CTS".

    Programming wise, I need to keep a record of port setting and clear/set P5 each time CBIOS sets and clears the interrupts.

    Uploading HEX files

    When CTS is working I can upload HEX files using:

    • ^D

    And the "Send RAW File" option in gtkterm.

    After that HEX file can be converted into a COM file using LOAD.COM.

    But CTS it is not working 100% yet.

    Is Single Character Control With CTS Possible?

    It seems to me that CTS is not acknowledge by the USB2Serial converter immediately. Two or three characters are send after CTS is disabled (goes TTL high).

    This pretty well means it can only be used to control the receive buffer level.

    This  also means that CP/M transmitted characters have to go into a buffer and transmitted later. The "transmit buffer" is easy, but the "transmit later" is awkward?

    How do I do that without extra hardware (i.e. a timer and an interrupt or some other type of polling)?

    At this point I, without hardware assistance, uploading HEX files via a standard terminal and my CP/M machine is not possible. I have to use an UART.

    Project Files

    I will have to update the projects files as well.


  • CP/M Disk

    agp.cooper10/30/2019 at 01:37 0 comments

    Emulating the new (8085) CP/M

    I had some problem getting CP/M to emulate with the new version of "cbios". Funny it was working before and "myEcho" is working. A day later I worked out that I had not initialised SOD during the boot process, so printing messages during the boot process did not work properly. Also, "conout" enables interrupts on return which could cause problems. Now fixed.

    Disk B

    For Disk B I have not installed the "boot system" so 31k of capacity is available for storage (versus 23k).

    Warm Boot after Disk Select Error

    I seem to have upset this so I will have to find out what I have done to upset it.

    Disk A

    I am pretty sure this code should still work with the updated hex files.


    my CP/M 2.2 (32k)
    A: STAT     COM
    A: R/W, Space: 17k
    A>STAT B:
    Bytes Remaining On B: 9k
    A>DIR B:
    B: ED       COM : ASM      COM : DDT      COM : LOAD     COM
    A: STAT     COM : TEMP     DAT
    A: R/W, Space: 16k
    B: R/W, Space: 9k
    A: STAT     COM
    A: R/W, Space: 17k
    B: R/W, Space: 9k
    Bdos Err On E: Select
    B: ED       COM : ASM      COM : DDT      COM : LOAD     COM
    B>ED  DDT
    DDT VERS 2.2
      0100  LXI  B,0FBC
      0103  JMP  013D
      0106  MOV  B,E
      0107  MOV  C,A
      0108  MOV  D,B
      0109  MOV  E,C
      010A  MOV  D,D
      010B  MOV  C,C
      010C  MOV  B,A
      010D  MOV  C,B
      010E  MOV  D,H

    So it appears to be working! And here it is in person:

    CP/M Input Problem

    I have been having problems getting programs to work. They display okay but he input is fails. Here is a typical problem:

    my CP/M EMU Console - Written by Alan Cooper
    my CP/M 2.2 (32k)
    A: STAT     COM
    A: R/W, Space: 17k
    B: MICRO80  COM
    A: R/W, Space: 17k
    B: R/W, Space: 26k
    MICROCHESS                  (C) 1977.

    It does not recognise the character. Some programs show the character as a 'W'. This output is the actual CP/M machine but the emulator output is identical. It seems to be getting the wrong character ('W'?). I am not ready to blame ccp.asm/bdos.asm/cbios.asm just yet. I am thinking a memory clash (the stack?). For my machine I put the system very close to the top of memory, I assumed that the space was not used, perhaps I am wrong. It is where I put the ring buffer and pointers.


    The program (micro80) overwrite RST6.5 thus I lose "getchar". This seems to be a common strategy (as it happen most of the time) to use the RST instruction to speed up the code.

    That would suggest using SIM/RIM and RST6.5 for serial IO is not going to be an effective general strategy. Fine if I write my own assembler language programs.

    But really I now have to use a UART and a timer. Time for the next version.

    Actually after looking in the micro80.hex file I cannot find a RST instruction. Looking at the Zero Page, I can see the RST0 vector points to the program entry point and bdos vector has been overwritten. I suspect that the bdos vector has been copied.

    Another problem is that code will expect a CR (0x0d) or CR/LF for CP/M and not a LF (0x0a) as for Linux. When using a terminal the line termination is configurable. But the emulator gets the LF. So really I need to insert a CR before a LF or swap the LF for a CR (in the emulator).

    Success Again

    After swapping LF for CR in the emulator, I loaded a very small basic like language called MINOL22:

    my CP/M EMU Console - Written by Alan Cooper
    my CP/M 2.2 (32k)
    ]10 A=0
    ]20 A=A+1
    ]30 PR "COUNT ";A
    ]40 IF A<10 GOTO 10
    ]50 END
    10 A=0
    20 A=A+1
    30 PR"COUNT ";A
    40 IFA<10;GOTO10
    50 END
    ]40 IF A<10; GOTO 20
    10 A=0
    20 A=A+1
    30 PR"COUNT ";A
    40 IFA<10;GOTO20
    50 END
    COUNT  1 
    COUNT  2 
    COUNT  3 
    COUNT  4 
    COUNT  5 
    COUNT  6 
    COUNT  7 
    COUNT  8 
    COUNT  9 
    COUNT  10 

    Final Update For This CP/M Machine Version

    Found a version of basic that runs on my machine...

    Read more »

  • Hardware Build

    agp.cooper10/23/2019 at 14:06 5 comments

    Assembled the Board

    I assembled the board but was short an IC socket for he second Flash ROM. I thought I had a spare USB-Serial converted but no. So I quick trip to the local electronics shop tomorrow.

    I have to write code to export the Disk data as two 16kb C arrays for my Nano Flash Programmer. So in theory it could be running tomorrow.

    Found that spare FTDI (USB to serial adapter). So I programmed Disk0 and powered up.

    No, power is up and clock is running but no response. Checked voltage levels (logic states) on the 8085 controls and they seem okay.

    Checked the Flash ROM and there were five illegal writes:

    • 0x00C0-0x00FF
    • 0x0700-0x073F
    • 0x3FC0-0x3FFF
    • 0x4600-0x463F
    • 0x6200-0x623F

    The groups are 64 bytes (not 128 bytes) groups so they were not faulty disk writes.

    Perhaps the bootstrap did not work?

    I think I will test a basic echo program next.


    I used the wrong latch for the low byte address, I used a 74HC374 instead of a 74HC373.

    Built a new board with the right chip (I cannot extract soldered in chips without damaging the PCB). Okay, progress, I got this (after changing the "bit timing" from 30 to 32):


         my CPM 2.2 (32k)


    where the !! is a shaded graphics box.

    "myCPM 2.2 (32k)" is my logon message.

    The OS responds to my typing but is not intelligible (mostly graphics boxes).

    So I think I need to try the echo program to make sure it is working.


    Part of the problem is the the Emulator uses 8080 timing rather than 8085 timing.

    Even though I calculated the correct 8085 delays for the Serial IO, I adjusted the timing to match the emulations (I assumed I had made a calculation error). No so! At this point I am tempted to write my own 8085 virtual machine. Yes, I don't really like how the one I am using has been coded.

    Anyway, I can get text out of the CPM machine but input is not working.

    As it works on the emulator I suspect the interrupt set up on the emulator does not match the hardware (reality?).

    Update 2

    I inserted a HLT at the end the Echo loop:

    • ;       Echo Loop
    •         lxi     h,signon
    •         call    prmsg
    • echo:
    •         call    const                   ; check if char available
    •         cpi     00h                     ; no char available
    •         jz      echo                    ; try again
    •         call    conin                   ; get char in A
    •         mov     c,a                     ; move char to C for conout
    • ;       mvi      a,41h                  ; Insert 'A'
    •         call    conout                  ; output char in C
    •         hlt                                    ; wait for interrupt
    •        ...
    Read more »

  • Building a CP/M System Disk

    agp.cooper10/20/2019 at 01:06 0 comments

    Building a CP/M System Disk

    To avoid rewriting the assembler codes for ccp, bdos and cbios so that they can co-exist in the same file. I can append the i8hex files and remove the "end of file markers".

    To make the hex file more readable I have changed the FSM (finite state machine) to be tolerant of illegal characters (so I can include comment lines). Just don't use ":" in any comments.

    The emulator already has code to move an image directly to disk. Just call the hex file "system.hex" and later "Disk0.hex". I just need to shift all code except the boot code down from 0x6000 into the system area of the disk.

    Successful boot (from disk using boot strap) but it still hangs on "E:". Need to find out why?

    Bdos Err On E: Select

    Well I tried two or three different ccp.asm files and no luck. Checked out the SIMH/AltairZ80 and same problem. Then I realised the source of the problem is in bdos.asm not ccp.asm! According to the manual, the error should wait for input (enter) before rebooting. I was also wondering why the copyright notice does not show?

    As for as the Select error, a reboots need to reset the user/disk ids at 0x0004. So I ANDed the value with 0xf3 to limit the disk range to 0-3. I did not want to change the user id or disk id unnecessarily.

    Next is to consider what I can fit on a 32k Flash Drive? Well not much! A change of track, I am writing a program to make a disk image (including directory structures and files) that I can upload to my Flash programmer. It will read program i8hex files one after another and save then to a disk image.


    Wrote some code to covert CPM-80 COM files into I8HEX files. Got the "makeDisk" code working to build the system, directory and normal files. The code needs a tidy up but otherwise it works. I have only set the directory UserCode to "0xE5" (means unused) rather than write "0xE5" to the whole disk (saves writing to the whole Flash ROM). Here is an example of a run proving it works:

    my CP/M EMU Console (AlanCooper@StartMail.com)
    my CP/M 2.2 (32k)
    A: STAT     COM : PIP      COM
    A: R/W, Space: 9k
    A: R/W, Space: 9k
    B: R/W, Space: 23k
    B: STAT     COM

    So I am set to assemble the PCB and test it for real.

    I have been playing around with the myCPM with mixed success. While some thins works, others (particularly exiting a program don't):

    my CP/M EMU Console (AlanCooper@StartMail.com)
    my CP/M 2.2 (32k)
    A: R/W, Space: 10k
    A: R/W, Space: 10k
    B: R/W, Space: 8k
    B: ASM      COM : DDT      COM : LOAD     COM
    DDT VERS 2.2
    0100 01 BC 0F C3 3D 01 43 4F 50 59 52 49 47 48 54 20 ....=.COPYRIGHT 
    0110 28 43 29 20 31 39 38 30 2C 20 44 49 47 49 54 41 (C) 1980, DIGITA
    0120 4C 20 52 45 53 45 41 52 43 48 20 20 20 20 20 20 L RESEARCH      
    0130 44 44 54 20 56 45 52 53 20 32 2E 32 24 31 00 02 DDT VERS 2.2$1..
    0140 C5 C5 11 30 01 0E 09 CD 05 00 C1 21 07 00 7E 3D ...0.......!..~=
    0150 90 57 1E 00 D5 21 00 02 78 B1 CA 65 01 0B 7E 12 .W...!..x..e..~.
    0160 13 23 C3 58 01 D1 C1 E5 62 78 B1 CA 87 01 0B 7B .#.X....bx.....{
    0170 E6 07 C2 7A 01 E3 7E 23 E3 6F 7D 17 6F D2 83 01 ...z..~#.o}.o...
    0180 1A 84 12 13 C3 69 01 D1 2E 00 E9 0E 10 CD 05 00 .....i..........
    0190 32 5F 1E C9 21 66 1E 70 2B 71 2A 65 1E EB 0E 11 2_..!f.p+q*e....
    01A0 CD 05 00 32 5F 1E C9 11 00 00 0E 12 CD 05 00 32 ...2_..........2
    01B0 5F 1E C9 21 68 1E 70 2B 71 2A 67 1E EB 0E 13 CD _..!h.p+q*g.....

    Yes Okay but G0 or ^C crashes. It does not seem that DDT has overwritten CBIOS etc.
    Anyway, I should move on and come back to this if it happens on real hardware.


  • Building the CP/M Memory Image

    agp.cooper10/19/2019 at 03:30 0 comments

    Building the CP/M Memory Image

    Will I have built and tested boot.asm, echo.asm and cbios.asm with echo.asm.

    So now to put them together! Well I started that, putting cpp.asm and bdos.asm (from https://github.com/brouhaha/cpm22), and my cbios.asm into a single assembler file but there are various label conflicts between the files if you put them together. So while I did put them together and compiled, I was not happy with the approach because of the risk of an error 9and the prospect of tracking the error down).

    A better approach is to load the individual i8hex files into RAM. The boot.asm file would be a single "jump cbios" instruction.

    That okay but now I am thinking about what happens when CP/M meets an unformated disk image. At the moment if the directory structure is "initialised" then no problem.

    So now I have to check the workings of the directory structure, I am guessing that if the directory structure is all zeros then it will see an empty disk.

    No, according to https://obsolescence.wixsite.com/obsolescence/cpm-internals the first char of the file name should be E5h if empty.

    Okay, I can do that. Not sure what the [cr][DMA] stuff at the end of the directory entry is?

    http://cpuville.com/Code/CPM-on-a-new-computer.html says each empty directory entry should have a e5h and he just fills his whole disk with e5h (over kill!).

    Okay, I think I know enough to proceed.

    Now the Fun! Starts

    my CP/M EMU Console - Written by Alan Cooper (AlanCooper@StartMail.com)
    Bdos Err On A: Select

    Somehow not unexpected but it does say start, cbios, ccp and bdos are talking to each other.

    Likely an error in my cbios code.


    After a bit of debugging I realised I need to see the labels/symbols matching the PC. It makes life so much easier knowing what subroutine is being called or jumped to.

    Anyway after a day I have partial success:

    my CP/M EMU Console - Written by Alan Cooper (AlanCooper@StartMail.com)
    A>SAVE 3 X.COM
    A: X       .COM
    D>DIEER        <- A type error which I corrected
    D>E:           <- Locks up when accessing an illegal drive

    The "DIEER" simply means the backspace cannot undo a character that has been sent to the console. But the "E" was deleted as the command succeed. "Delete" does not work as well. But checking the manual, it says to use ^H, and that works.

    The fail was the "E:", it locked up the machine.

    An "F:" generates a different that I cannot escape.

    • A>F:

    • Bdos Err On F: Select

    • Bdos Err On F: Select
    • ...

    Okay, fixed "E:", The "F:" issue is because a warm boot is initiated but there is no system on the disk.

    Fixed problem with switching disks:

    my CP/M EMU Console - Written by Alan Cooper (AlanCooper@StartMail.com)
    A>SAVE 80 X.COM
    A: X        COM
    A: X        COM
    A: X        COM

    I have a problem with REN? No, just don't know how to use it!

    A>SAVE 80 X.COM
    A: X        COM
    A: Y        COM

    Okay, it looks pretty good now. Next is to build a boot image.


  • My CP/M Simulator

    agp.cooper10/14/2019 at 05:12 2 comments

    My CP/M Simulator

    8080 Emulator Code

    Downloaded a public domain 8080 emu from https://www.reddit.com/r/C_Programming/comments/8loz4p/heres_a_cycleaccurate_intel_8080_emulator_i_wrote/

    The arrangement of the code suits what I need. It counts cycles so I can make the emulator run in real time.

    I have to add the code for TRAP/RST7.5/RST65./RST5.5, SIM/RIM and SID/SOD.

    Non-blocking getchar()

    Next I found some code for getch() and getche() which will work under linux (conin.h is a windows only library).

    Serial Input/Output

    I have coded the Serial Input but Serial Output need a bit of thought.

    HEX Import

    Just finished write an I8HEX import routine.

    New 8080 Emulator

    I has swapped the 8080 emulator to https://github.com/superzazu/8080.

    The reason is that is emulator has a test suite to demonstrate the "correctness" of the emulator. The previous emulator code does have some minor coding errors.

    I have made some cosmetic changes to the new emulator to remove the compiler warnings, and started coded the missing 8085 hardware and instructions.

    Not that it is really important, I note that the "superzazu" interrupt code, only allows for a single byte interrupt opcode. A real 8080 can handle one, two and three byte interrupt opcodes.

    I also simplified the function in a structure method.

    Uploaded the initial test code to my file area.


    Tested the i8080 part of the emulator with "myBoot.HEX" and it works fine. One error in myBoot.asm (I incorrectly swapped the source and destination registers).

    Just the serial out code to do.

    Update 2

    As pointed out by Ken Yap the multi-OpCode Interrupt issue is an 8085 "undocumented" feature.

    Got the echo code working this morning. Many assembler coding errors (I don't know 8085 assemble code very well yet), and a baud timing calculation error. I did not allow for some overheads.

    I really need to upgrade"superzazu"'s debug code. Otherwise the 8085 instruction I have added (i.e. SIM, RIM and interrupts TRAP, RST7.5, RST6.5 and RST5.5 seem to work, at least SIM, RIM and RST6.5 which I use.

    I think the way forward is to write assembler for a boot disk with only the boot sector and bios (i.e. less ccp and fdos), and test my bios functions. The jump to ccp will be my test program.

    In any case my "sight" understanding of the 8085 OpCodes is getting better.


  • Hardware Design

    agp.cooper10/12/2019 at 14:08 0 comments

    Hardware Design

    To keep things simple I am using what I have in my box of electronic spares.

    I have a heap of 32k x 8 RAM and 32k x 8 Flash ROM.

    I may even have an 8085 chip somewhere?! I will order some anyway.

    Once I get the prototype working I will upgrade the Flash ROM from 32kb to 256kb.

    For CP/M the O/S resides in top of RAM and programs are executed near the bottom of RAM (after 100h). Any ROM has to be above the RAM.

    But for boot up, at least initially the ROM need to start at 000h.

    To do this I designed a boot flipflop that set A15 high on reset. Upon accessing an address above 32k, the A15 line can go low.

    The flipflop uses a quad NOR gate:

    And here are the signals:

    I will come back to the hardware design later.

    As CP/M uses a console to communicate to the outside world the simplest answer is serial. So I have used a USB to Serial converter for communications and power. The USB port has enough power for CMOS versions of the chips. The main power hog is the RAM at 140 ma. Next is the AT29C256 at 50 ma and then the MSM80C85A-2 at 20 ma.

    I decided to use the 8085 SID/SOD signals (i.e. SIM/RIM opcodes) for serial communications rather than the 82C51A-2. Probably a mistake but I can use it for the next prototype if it was a mistake.

    Here is the full schematic:

    And the PCB (currently been made):

    The interrupt jumpers (left) and expansion jumpers (right) are really just test points. I don't intend to use them.

    8085 Code

    I have not done much assembler coding before so this was a bi of a challenge.

    My first attempt was pretty inefficient. So I stopped and examined the opcode more carefully. The trick seems to be to understand the flow of the 16 bit opcodes for the hl, de and  bc pairs. After that coding is much more constrained (i.e. it become obvious the best way to do something).

    The first bit of code is the boot sector code to load the operating system:

    ;   boot.asm: Load CP/M from ROM
        org 8000h                           ; executed in ROM
        jmp 8003h                           ; reset bootstrap
    ;   Calc CPM addresses
    msize       equ     32                  ; 32k RAM
    sectors     equ     16                  ; sectors per track for my system
    systrks     equ     4                   ; my boot system has 4 tracks =-int(-52/16) 
    bias        equ     (msize-20-1)*1024   ; adjusted for my system =int((52+4-4*16)/8)
    ccp         equ     3400h+bias
    cstart      equ     4a00h+bias
        lxi     sp,ccp-0080h                ; convenient place
        lxi     d,ccp-0080h                 ; start of boot dst
        lxi     h,8000h                     ; start of ROM (boot src)
        mvi     c,sectors                   ; sectors per track
        mvi     b,systrks                   ; sytem track count
        push    b                           ; save 
        mvi     b,128                       ; sector size
        mov     a,m
        inx     h
        stax    d
        inx     d
        dcr     b
        jnz     boot$copysect
        dcr     c
        jnz     boot$nextsect
        pop     b
        dcr     b
        push    b
        jnz     boot$nextsect
        hlt                                 ; halt for testing
    ;   Cold boot
        jmp     cstart
    I am currently using a85 from http://www.retrotechnology.com/restore/a85.html.

    It compiles (and runs) with no problems under linux. I only produces hex output so later I will have to convert this to a com file for CP/M.

    The next assembler task is cbios. Too big to show here, it is in my file area.

    Next Steps

    Next steps is the test the codes in a simulator. Now I have to find one that is suitable.