For some time I wanted to create a Z80 assembly program, using (more or less) a system of that era, even if emulated. For me that means Spectrum+GENS/MONS (assembler/monitor), but another option that I found more comfortable in the early 90s, when I was using a COBRA computer is replacing the Spectrum BASIC with OPUS. OPUS is an operating system1 for Spectrum compatible computers, that was mainly used as a development environment for assembly programming.
For an easier start, I intended to use OS routines for.. "routine" tasks, such as displaying text and reading ASCII characters from the keyboard. While trying this I found some typos in the (Romanian language) OPUS manual that is available on the Internet, but good news is that I found two more manuals (Romanian and English) in my library, that seem more correct.. or (at first glance) corrected. At least two routines (APIs?) that have the wrong addresses in Manual-Opus appear at the right addresses in one of my manuals.
First trouble is at section "10.2 Conversions"2: the PRITA routine for displaying A register in hex appears in the manual at #0BD03. The correct address (that works in OPUS v3.1 and OPUS v3.2) is #00D0, confirmed by the other two versions of the manual. Somewhat funny, in yet another(!) edition of the OPUS manual, in the (Romanian) hobBIT magazine issue 5/1991, that routine appears to be at #0000!
The second problem proved more difficult. Section "10.4 Keyboard reading", KEYBRD (read ASCII character from keyboard, with blinking cursor) appears at #3047 (same in hobBIT) but it does not work (CRASH/RESET when CALLed). This is the one that got me looking for another manual. I knew I had my own OPUS manual "stashed somewhere" and vaguely remembered some hand-written notes in it (not by my hand). Searching went better than expected, I found two other manuals, one in English, another one in Romanian. Both show #3074 as KEYBRD address (last 2 digits reversed) and in the Romanian one there is indeed a hand-written note with #3076! For the OPUS I am using, this last one proves to be the right address. A cursory look shows that at #3074 seems to be the end of another routine. (POP HL then RET; no wonder it crashed when I tried, it looses the return address).
Note: There are two more keyboard input routines, or I could write my own but KEYBRD seems the most desirable, mainly because of the blinking cursor. And besides, my curiosity is now aroused!
At first I was happy of finding my answer and started writing "the tale", but while doing that I realised that maybe my OPUS version was modified by the same person that wrote on my manual. This OPUS was copied from a friend along with that photocopied manual in the early 90s and at some point I copied it from cassette to PC. Could it be that the original OPUS really has KEYBRD at #3074? There are two different manuals supporting this, and the two others (Manual-Opus and hobBIT magazine) seem to be simply an inversion error based on the same address. It is rather strange that only my manual has the correct address.
I then remembered that someone posted more OPUS versions on the RomanianHomeComputer group and I found the archive containing versions 3.0, 3.1, 3.2 and 4.0. The 3.2 version from that archive is identical to my own, so KEYBRD is still at #3076. But version 3.1 does have this routine at #3074, so I assume that all the manuals are for v3.1. In v3.0 and v4.0 neither address works (#3074, #3076, #3047) and at a glance none of them seems to to be a subroutine entry point.
With KEYBRD mystery solved, I looked at the other 2 subroutines and...
INCH, #03FA does not read keyboard in either version. Besides, a disassembly at #03FA (that's why I like OPUS! Any look to the code is just a few keystrokes away) shows that this routine begins by checking a bit at memory address pointed to by IY (not a good sign) and if that bit is 0 it returns, otherwise... I think it makes a sound and then returns. Oops, it really does make a sound, looking thru the manual for the CALLed #03B5 I notice that at precisely #03FA is "CLICK" that "if sound is on [...] generates a key click sound". So this is obviously an overlook in all manuals, it is impossible to have 2 different routines at the same address! And indeed, at #03B5 the manual shows PIPEN, similar to BASIC BEEP.
Finally, KRESS, #0426 works as specified in the manual, starting with v3.1. What's more, disassembling KPRESS I discovered the right address for INCH: #03F3 and that one seems to work in all available versions.
It was an interesting puzzle, started from writing a few words about documentation differences and ended up being a whole story.
Why weren't the mistakes discovered, how come so many manuals have the same errors? I assume that, back then, those few programmers that really used OPUS as an OS would rather write their own routines (except for SAVE/LOAD4). Especially since most programs were supposed to run under BASIC (or even stand-alone). What's more, I think that main use of OPUS was for its Monitor (similar to MONS but with one advantage that RAM is not affected by RESET, plus many other handy features).
To avoid certain content-scrapers that don't respect robots.txt, to access files below you must use "OPUS" for user and "COBRA" for password. Case sensitive! :)
UPDATE 2020-05-20: While digging through my archives I found some files (system images) for COBRA along with a CP/M program that I assume should load them and then configure the computer in Spectrum mode:
D0>devil COSYS ======================= COBRA SYSTEM LOADER ======================= (c) 1991 by DEVILS Press : 1 - BASIC with SCAMP printer 2 - BASIC with ROBOTRON printer 3 - BASIC with DISK system 4 - OPUS by DEVILS 5 - CP/M
1 just as Spectrum BASIC is the operating system of Spectrum (and compatible) computers
2 The original manual is in Romanian but I translated the terms used in the story (and the English version of the manual is now available, see "Related files")
3 In OPUS, the # character is used to prefix hexadecimal numbers (like 0x... in C). The prefix for decimal numbers is £ (Symbol Shift + X).
5 "save bytes to tape" and "load bytes from tape" routines are at precisely the same addresses and using the same arguments in OPUS just as in BASIC.