Table of Contents
I acquired a TRS-80 Model 1 rig (system unit, CRT, tape recorder) for $30USD at an estate sale here in the Denver, CO area. Plugging it in i found it “charming”. I immediately wondered if a 64180/eZ80 plug in for the 1.7MHz CPU existed. Thinking this likely, i searched the interweb and like so many fell down the RETROBREW rabbit hole. Now the TRS-80 Model 1 sits unattended while another platform gets all the attention.
In the course of deciding which retro-cpu environment would be of interest, i came across a Hack-a-Day Project by AGP Cooper.
I found this project to be a do it yourself kit for implementing CP/M 2.2 upon a 8085 platform. Alan includes schematics, software, self-composed simulator, and a log of his implementation effort.
The simple but elegant “brute force” implementation of CP/M (without MOVCPM or SYSGEN) and the example silicon disks which saved a lot of trial and error and pointed the way. Specifically, it was the implementation of the FLASH “Boot ROM” as FLASH Drive “BOOT SECTOR” that directly resulted in the following 8085 implementation. The first two installments highlight Alan's effort to use the 8085 unique SID/SOD bit ports for console I/O. He succeeded to a degree that is quite remarkable considering how i struggled and sweated to implement a simple 300 baud Kansas City cassette interface using this technique, way back when.
The Initial Platform
Into the garage and out of a plastic storage bin, i retrieved an 8085 board from the 1980's. A wire-wrapped board, this was the last 8085 cpu i had built. Back then, this board was a “keyboard system controller” connecting between an 8051-based musical keyboard (not MIDI) and a Megatel Quark CPU which provided the CP/M environment for program development as well as a bit-mapped monochrome display and very fast disks.
Purpose built, the top level Architecture of this board split the memory map into two 32k segments the lower 32k occupied by EPROM (later E2 ROM), and the upper memory occupied by Static RAM. Board I/O is comprised of two 8251 USARTS, and an 8254 Triple Timer.
Natively, this board was not going to Host CP/M (which requires R/W memory in the segment occupied by my ROM. The solution was to pull out the lower 32k ROM and construct an Expansion Board which would mount in place of the socketed 32k ROM. This Expansion Board would include what seemed to me to be a typical RETROBREW 1MB memory map. That is, 512k of Flash from 00:0000H to 0F:FFFFH and 512k of Static RAM from 10:0000 to 1F:FFFFH. Additionally, a Real Time Clock Battery Backup/Supervisor would also mount on this board.
First thing the board was powered up in native format. Then many NMOS Chips replaced by CMOS, and the wait-state generator removed.
Note: When this board was built the 6MHz 8085-AH1 seemed fast and components on a companion I/O board (three Yamaha YM-2203's, 8255 hosting 8 bit DACs) was rated only to run at 5MHz. Any time these chips were selected 1 wait state was added.
I liked the physical look of the original 8085 cpu but the expansion technique would obscure this board with a less attractive daughter board which works very well. The daughter board mounted into the ROM Socket using Headers with 3 level length pins. These are commonly used to stack Arduinio boards. These pins solder to a DIP header which performs the actual connection into the boards ROM socket.
The graphic left depicts the daughter boards initial mounting of these headers. A 512k FLASH ROM (ST39SF040) mounts into the female receptacle end of the header with the pin side fitting into the original 32k ROM socket. As ROM doesn't encompass all the signaling required for the daughter boards, SIP Headers were also added to each board to provide necessary signaling.
An octal latch provided the Address lines A15 through A19. This is common for many of the CP/M compatible boards i've found in the Retrobrew-RomWBW world. The latch allows selection of any of thirty-two pages each 32kB in “length”. When A19 is low any of sixteen 32kB pages can be selected. Conversely, A19 high selects any of sixteen 32kB pages to selected into the lower 32kB address space. The graphic right depicts the allocation of the FLASH and SRAM from the architectural and system viewpoint.
As shown, FLASH ROM is allocated as two 256kB ROM Disks (A and B). At this time these “silicon disks” are programmed off board with standard CP/M Utility Files which intend to support the use of the system. In this way the 256kB Static RAM R/W Memory need not be filled with files that perform utility system functions.
The two ROM disks could have been merged into a single 512kB disk but i felt the seperate disks allowed a natural partitioning and avoided a CP/M DIR command scrolling files off screen while i frantically type control-S/control-Q.
The Static RAM
512kB of Static RAM allocates as depicts right. Writing 10H to the Page Select Latch results in memory from 0000H to 7FFFH to address the first 16 “virtual” Tracks of Drive C:. As a “DATA” (non-boot) drive the first two tracks addresses the disk directory (2kB) and the first 30kB of disk content (programs and data files).
Taken directly from Allen's project, CP/M see's all 3 disks as 16 Sector/Tracks with 128 Tracks (262,144kB) in this case, due to larger memories. The allocation as Drive C: accounts for the deployment of the first 256kB of RAM.
The last 256kB RAM allocates to the CP/M, System and the USER Programs. Writing 18H to the Page Select Latch places the first 32kB of this non-disk allocated segment as CP/M's lower 32kB TPA RAM. This is important as the interrupt vectors and the TPA start Address (100H) is in here.
If in the course of operation access to one of the drives or system/user memory is to occur; a) Interrupts are turned off; b) data accessed; c) interrupts enabled and d) TPA re-selected. As a fail-safe i write the first 256 bytes of the TPA page to each remaining 32kB SRAM Page to accommodate inadvertent error but this is not an “every-case” solution. I've considered re-configuring the Memory Decode to always select the TPA Page when below address 100H.
A 32kB page is allocated for System Structures and Buffers which will be detailed later in this presentation. The remaining 196kB could have been another disk but disk space but it was my feeling that the 64k paradigm (ignoring MP/M/CP/M3) makes data handling cumbersome. It is a simple task to provide “cross-page” block moves in the top of CP/M's address space to allow transaction of data where the procedure protects the system from errant methodology (sadly not errant logic).
The RomWBW provide sophisticated cross-page capability. CP/M3 and MPM provide well understood and long used methodology as well. The kSys system provides no more than a Interrupt Disable/Enable bracketed block move.
The RomWBW Architectural Description, linked below, provides clear and concise discussion of it's methodology, which serves to indicate the functional depth of this package as described in the document.
The schematic below left is of the base kSys CPU Board. The graphic below right is the Daughter card schematic.
As depicts in the graphic left, the expansion hardware plugs into this board's EPROM socket. The EPROM was selected any time A15 was low. This imply's the lower 32kB of 8085 Memory Space was intended for Read Only ROM storage. As such EPROMs do not require Mem Write, Interrupt or RESET signaling. Since our expansion electronics would require this signal compliment, an addtional 2 SIP headers install to provide these necessary signals.
The schematic right depicts the Expansion Board's additional 1MB of Memory (which allocates as 512kB FLASH and 512kB SRAM), as well as a Real Time Clock / Battery Supervisor (BQ4845). The CR2032 Lithium coin battery connects to the RTC/Supervisor which then routes this power to the SRAM. This way the supervisory features (power status / interrupt / Reset) can both inform and drive CPU response.
The Base Board required two new headers to provide signals not normally terminating at a ROM Socket but are required for Expansion Board Functionality. These signals are Interrupt, and Write related signalling. The RTC optionally connect to 8085 interrupts (7.5). The Flash Rom is provided an optional WR* signal to allow “In circuit programming” to occur.
Platform Software - CP/M
When the base platform was first in use it connected to a CP/M machine. Now it are one. This time there are no mechanical drives. Instead the ROM and RAM are understood to represent 128 Tracks of sixteen 128 byte Sectors. Files allocate on 128 byte boundaries.
The CBIOS Translates CP/M's Select Disk, Set Track, Set Sector requests into a Page: Offset Memory Address. As example, The “BOOT Sector” ( Track 0, Sector 1 ) is understood as ROM address 00H-7FH. Track 0, Sector 2 occurs at address 80H-FFH. This second Sector is the start of CP/M's CCP System Component with the BDOS and CBIOS following.
Sixteen 128 byte sectors results in each Track representing 2kB of memory such that 128 Tracks then represent 256kB of storage.
Booting the System
Although different, the RESET relocation implemented in Alan Coopers MyCPM was direct inspiration for the method of booting CP/M for this platform. Alan's platform jumps to 8003H upon RESET. The interesting things is there is nothing there until A15 asserts as the address generates for the JMP opcode. The JMP sets a latch which relocates the ROM base address from 0000H to 8000H (and enables RAM in from 0-7FFFH).
Analogous to Allen's approach at RESET the RESET OUT signal clears the Page Select Latch which places the FLASH ROM address 00:0000H into the 8085's address space between 0000H and 7FFFH. The 8085 begins executing the code it find at 0000H which is the BOOT code for the CP/M system.
The BOOT code exists in the initial 128 bytes of ROM. This code proceeds to initialize the two USARTS and the TIMER. The Remaining Code copies the next sequential sectors of the ROM which contains the CCP/BDOS/BIOS which is copied to the upper (non-paged, alway there) memory region starting @ E400H in one block move. The final act is jumping to the just written CP/M Cold Start initialization. Of note, the CP/M initialization write 18H to the Page Select Latch which places the first free, non-drive memory, into the lower 32k of memory. This page is dedicated for use as the lower 32kB of CP/M's “TPA”. The image right, depict the the first 256 bytes of the Flash Rom.The Code (displayed as hex) below 00:0080H is the BOOT Sector . That code displaying from 00:0080H to 00:00FFH is the first sector of CP/M's CCP. The ROM Drive stores more than BOOT and System code, the Drive also stores CP/M Utilities and other programs and files. At this time i compose a single 512kB Drive Image using HxD. Files allocate across the two ROM Drives A: and B:. Using HxD, i load in either the Program in Hex or in Binary (depending upon the format i have the program in). I then compose manually a Directory Entry. If it's a BOOT Disk the programs load in after the System which uses two track of 16 sectors (or 8kB). Another Two Tracks allocate for the File Directory. After this, Transient Programs can load. B: and C: are Data Drives, having no BOOT or System Tracks . In this case, these disk begin with their Directory so that the are 2 more tracks for file storage.
Upon First Boot
The A> prompt and the result of typing “DIR” was a moment of nostalgia. There were the remembered and familiar mix of CP/M Transient Programs. I was delighted to have the implementation of CP/M on this platform occur so readily and rapidly.
After this initial bout of nostalgic joy, it wasn't long before i found the CCP could be annoying. Three characteristics immediately reared their head:
Semi-ambiguous File specification required the “ *.* ” use, which after years of alternate console operation seemed unnatural.
For maximum usefulness, all the Utilities and commonly used files on A: User 0 needed to be in the file “Search Path”
As console screens can easily get visually cluttered, a method for “clearing the display” avoids “messy” console screens.
To deal with these issues and make CP/M a little easier to deal with i .. Modified the CCP to allow semi-ambiguous file spec with a single asterisk i.e “ stat di* ” or “ dir s* ” instead of “ stat di*.* ” or “ dir s*.* ”.
Implemented the well known mode to make A: User 0 into the search path if the file as spec'd cannot be found on current disk or user area.
As an ANSI Terminal was my dedicated target i modified the CCP to add “ CLS ” as an intrinsic CP/M CCP command.
It wasn't long before i made several more alterations to the CCP.
I removed the TYPE intrinsic command and wrote a new Transient Command TYPE.COM which pages display of text.
I added an alias for the intrinsic command ERA called DEL. This is just returning the MS-DOS 1.0 favor of allowing ERA to alias DEL on that system.
I wrote a program which executes with ever cold or warm start which checks for new files, file changes, file omission and updates a “ META FILE ” to reflect the detected change
I established another META File which correlates User Areas to User created NAMEs provided a psuedo-directory format, a historically common CP/M technique.
Wrote several system Transient programs to express Disk/User file locations as “ directories ”. MD,CD,RD (made, change and remove directory) D and PHI which provided disk directory information that includes date and file size information in their formats.
The graphic left depicts the new D.COM directory format. CP/M's dir works as usual but D.com represents an extension of the standard CP/M DIR command functionality.
D.COM appends child directory names (read from the Director META FILE) and includes CP/M Drive Directory information File Names File Size (on disk) and File Attributes.
Like CP/Ms DIR command, it allow fully ambiguous file spec (as shown), semi-ambiguous file spec “ D N*.HEX ” or specific file reference ( “ D SHODIR.COM ” ).
The graphic below left, depicts the display format of PHI.COM . PHI.COM is a “long directory format” that also appends Directory META INFO file information (Dir Names), as well as, file Time and Date information. Time and Date information reflect the time and date of a files first discovery by the Cold/Ward boot process procedure ( Z.COM ) which inserts this information into the FILE META file.
Finally PHI.com add some trailing information regarding files in alternate directories and Drive FREE SPACE. The two META FILES store into the 32k System Page (19H) and all references to these files are protected by system protocol. The DIR META file stores into Page 19 @ 6000H and the FILE META file @ 6800H. A checksum utility allows for validation system page information.
The kSys System or memory pages and drive directories is still evolving but is very stable and is in regular use. It does not impede standard CP/M program functionality, but as mentioned assumes an ANSI Terminal.
A log of console transactions between the operator and the modified CCP can be reviewed below.
As the the R/W Drive C: is really just SRAM Storage, some non-volitile memory would allow save storage for battery or operator/developer failures. Easiest approach was to added a SD Card Logger accessory card.
This particular logger is called a uMMC and can host greater that 64G SD Cards (of micro-SD) in FAT 32 Format. Being a logger it connects serially and 19.2kB is as fast as i have been able to get the card to perform across all tasks, reliably. It is very reliable at this rate. It is also take 2 minutes to back up the C: Drive (256kB) but is on a file by file interchange is usefully fast.
The uMMC has a form of User Interface that seems characterized for both terminal use and for very high level language interface. In all cases commands use either “displaying characters” or simple Controls like ESC and CR. I proceeded to add a wrapper around this protocol that integrated the SD functionality into the system in a more regular way. The graphic right depicts the available command for operating the SD from a command prompt.