Post by c128old on Oct 19, 2020 16:31:52 GMT
Working on the CPM bios is really frustrating.
I'm using the C128 cpm fast distro on GtiHub (work from Linards Ticmanis), and check with the last official version from commodore.
I think I have (finally) debugged the 2 problems I had.
One is an unlikely but possible hangup introduced by Linards,
the other is a bug introduced in the last version by Von.
- Possible hangup
Linards' version very smartly (he really did a serious update on the code, and well too) moved the resident copy of CCP.COM into bank1 'under the bios'. This used to sit in bank0 and when neede would be copied to bank1 (start TPA) by the bios 'rlccp'.
By moving it to bank1 and copying it down when needed this speeds up the reload and clears up 3.2k in bank0
He does this by moving the "shared" limit from 8k down to 4k at the top so that instead of E000 showing bank0 you see F000 of bank0. For this the copy routine of course must live higher than $F000, and allows max 4k. That way 4k of mem 'under bank0 shared' in bank1 is additionally used. Cool!
Problem: during the LDIR copy command (from E000 bank1 to 0100 bank1) the interrupts are enabled. If they happen during the LDIR then the kernel is 'looking at' 4k instead of 8k. So if the reload happens while interrupt-service needs (parts of) the OS then things fail.
I did run into this bug but admittedly this was during changes in the code that made part of the startup taking just enough time so that the LDIR copy would catch an interrupt.
- bug by Von
During init (boot:) the code will initialize all peripherals. One of the IO peripherals in the table is "int65', short for initialize6551 (the USART from commodore you find in DE00, available as Swift cartridge or in an UII-firmware 3.7)
Between Aug85 and the final version the init code was 'improved' to support either an internal 6551 ('added to engineering units' as Von notes in the code) or an external 6551 (on the user-port). The one in Ultimate-ii and Swift binds at $DE00.
So CP/M 3 on c128 supports that 6551, even while that chip didn't appear until mid 90s for consumers with a c128.
However, in the 87 update the code compiles to different USARTs using a define (use$6551 false/true) and saving the requested type during "?init" in the cxio.asm.
The "?cinit" loop (in cxext.asm) has already tried to load the address from "usart$addr" before the "?init".
Result: first time the cxext routine is called the content of usart$addr is 0000
Second time it is $DE00 (or something else)
Now, it isn't clear to me what Erwine intended with this dynamic load because the setting of the usart$addr is being done using a compile-time define. Therefore ALL locations that talk to the 6551 could instead use "ld (bc),0DE00h" instead of a via-load "ld (bc),(usart$addr)"
The former is faster and this code is in speed-relevant loops (Linards improved this already).
All of this isn't a bug, other than that the code is attempting to do (first time around)
1. BC = $0000,inc BC (so $0001) Out(C), $3f --> OUT $0001, resets
2. inc BC (so $0002) Out(C), $0b --> OUT $0002, initcmd
3. inc BC (so $0003)7. Out(C), $baudrate --> OUT $0003, baud
If you read this, you probably know that Z80 is using "IO mapped IO" so that access to C128 IO channels is via 'OUT' and 'IN' (slow and cumbersome but also neatly keeping ram and io out of the way).
What I found is:
- during an attempt to do "out $0001, value" a byte is WRITTEN to RAM at D001
- same at 0002 and 0003
I ended up tracing and editing the init-code of CPM and eventually found that INDEED the memory in bank 0 at D001,2,3 is CLOBBERED.
Yes, even the original code by Von suffers from overwritten data at that location (!). This behavior did not show in the AUG85 but that makes sense because the CXEQU.lib says "space usart$adr,2 ; PTR to 6551 reg (not used before 6 Dec 85)"
In the case of the commodore original code this is "luckily" somewhere in a secondary data structure, but as soon as you start tinkering with the code you will "quickly enough" cause these 3 bytes to appear in the midst of the "init" code in cxio.
Very frustrating, I can tell you.
Also, of course the above behavior is NOT part of Vice (how would it, I've not seen this problem explained anywhere, talk about undocumented features)
If you every feel the need to do some hobby on CP/M code for C128, you now know why the result seems to die all the time.
In the mean time, if you have an Ultimate-II for your C128, I have a function-rom that will load CPM-bios from U2 and supports preload-REU, drive A/B set, RTC from REU, a file-mapped d81 drive, a 2nd file-mapped 512REU and a 16M drive (with 512 dir entries)