Post by c128old on Jan 15, 2024 21:16:43 GMT
- No call of functions "disk reset" and "CP/M initialize" at the end of code
- Save 8502 IRQ vector table before manipulation. Reset IRQ vector table to original content at the end of bank 1 code
- No use of CP/M standard logic channal for disk access (CP/M uses e.g. data channal 11 and command channal 15 for drive A). I use hard coded logic channal 7 for all operations.
- Stack pointer for CP/M programs points to a high memory area. I guess this can cause crashes if common memory area is move from high to low end. So I use two different approaches to solve this:
- Avoid sub calls in bank 1 code
- Manipulate stack pointer to a local memory location in bank 1
- Before activating 8502 set zero page registers (0xD507 - 0xD50A) of MMU to bank 0. After returning from 8502 reset zero page registers of MMU to previous content. (See source code of ZP/M module cxio.asm)
- Before activating 8502 save speed setting register (0xD030) of VIC. Force VIC to low speed. In 8502 code set speed setting register to original setting. Before returning to Z80 force VIC to low speed. After returning from 8502 set speed register of VIC to original setting. (See source code of ZP/M module cxio.asm)
- Save memory area 0xFFD0 - 0xFFE0 before writing manipulated 8502 return code to this memory area. At the end of bank 1 code rewrite memory area 0xFFD0 - 0xFFE0 to orginal content.
I guess the most important changes are points 1, 2 and 3. I am not sure if points 4 to 7 are really neccessary.
I am not a skilled assembler programmer. This is one reason why I try to write these tools. I avoided special Z80 commands such as "LDIR" to perform mem-copy for example. So there are many things which can be improved in my code, but it is well commented.
Long answer... (you are warned)
First of all, your code works. Kudos on that.
Regarding the approach you took:
- The disk-reset I introduced because I had problems after using my code. I now know why, I'm using the 'init' function of fast8502 and this (also) closes the command channel so that subsequent attempts to talk to the drive fail!
- This item is the correct thing to do, by restoring the IRQ vector with a few Z80 codes, you solved problem 1. above :-)
- Correct. Given the way Fast8502 works, this cannot be done any other way.
- You should ALWAYS guard your stack (in terms of accessibility) and ALWAYS clean up after you used stack. Consider: you enter the routine that will move COMMON from shared-top to shared-bottom. For this your z80 code will be above 0400h (std 1k shared bottom) and below 1000h (IO mapped in, to access MMU). Moving stack to 1000 and restoring it at the end (after remapping shared to 8k top) is a good spot and you should then feel free to design with stack. Design code without stack because of fear is a bad idea ;-) Especially in the age of z64k ;-)
So, IF you take the effort to put the stack in a sensible location (you're the designer so you know exactly what you end up with, this is not an uncertainy!) then you should totally feel free to use that,. IMHO. To wit: take stack-precaution and use it, or do not and use no stack at all in the code. Why do both? - Setting zero page pointer is irrelevant because enable Low Common on MMU will overrule page 0 and 1 location (they are automatically stuck at page0bank0 and page1bank0). The MMU does that by design. You do not need to do this and you shouldn't.
- The speed register cannot be used during z80 (and also has no speed effect in z80). The speed register does not match (not guaranteed to match) with the glue-logic on the board to provide the z80 with its latched read/write value. In other words, no one would 'leave' the system running in 2Mhz on z80 under CPM because it will lock up. Thus, you also do not need to take care of this. The code you refer to in cxio is (clearly) controlled by the use$fast which is FALSE by default (and wastes even more time on the poor 2Mhz z80)
- you make it sound as if the code in the SWAP routine (FFD0 and FFE0) is a 'free-for-all'. But it is certainly not! Firstly, the stand Boot Code (in the z80 ROM of c128) relies on this code to look like it does, and secondly there are several tools which rely on this code to be like this (nice example: ted.com). By doing this you are worried that your "8502 entry jump" might cause mishap. Consider that this is impossible because: when the 8502 switches to z80, its ProgramCounter (PC) is pointing at the NOP following the instruction. Then you get the "JMP 2600", this means you have 4 bytes "free" to "manipulate" as you put it. If the 8502 were 'left off' somewhere else then no matter what you did up there in FFD0 would be irrelevant. So the idea to "save" the 8502 routine would be to save it from your own coding mishaps and these mishaps could only happen while in 8502 control, not while in z80 control.
If you don't mind: what kind of mishap are you considering, that would make it sensible to 'save' the FFD0-FFEF area?
Regarding the speed of the 8502: of course, using the 2Mhz is a boon to the 8502 side. The somewhat sobering side is, however, that at the start of IO calls the Kernal immediately disables 2Mhz. So the gain you get is, well, minute. This can be verified with BASIC on c128: regular load is not faster with 2Mhz.
The reason is twofold: for IO the VIC will slow your IO to 1Mhz (clock-stretching) anyway and for IEC bus this is likewise unmatched so Commodore used 1Mhz during disk access.
The content of Fast8502.asm source code is almost purely IEC IO related (disk, printer) and thus benefits hardly from 2Mhz.
In other words: if a compiled BIOS is 'cpm' or 'zpm' is only determined by the module you link your bios with, not by the bios code.
'I avoided special Z80 commands such as "LDIR" to perform mem-copy for example.'
But you are using special Z80 commands such as out (c) and in (c) ;-P
If I were you I would totally use the (one) advantage Z80 has on c128: compact code compared to 8502.
(I use the "z80.lib")