PDA

View Full Version : Installing CP/M 3 (Plus?) on a home-built Z80 computer



Pages : [1] 2 3

nockieboy
December 1st, 2017, 11:51 PM
Hi everyone,

I've got a Z80-based computer that I've built with 256KB of memory (made up of 128KB RAM and 128KB ROM), divided into 16 x 16KB banks that I can map in any combination to the 4 pages accessible by the Z80's 16-bit address bus. It currently runs CP/M 2.2.

As the MMU was a recent addition, I thought my next step should be to get CP/M 3 up and running as it supports banked memory. The plan is to fix the upper 16KB page and allow CP/M to swap the lower 48KB as one block, giving it Bank 0 and Bank 1 (the minimum requirement for CP/M 3.)

My knowledge of CP/M (and assembly - although not programming in general) is extremely limited and I'm learning as I go. From what I can gather from the documents, I need to write a new CPMLDR.COM file with a modified CBIOS in it to allow CP/M 3 to interface with the hardware in my computer (the CompactFlash drive specifically) so it can load CP/M 3 on boot. Makes sense. Then I need to write a more fleshed-out CBIOS for CP/M 3 itself and build a CPM3.COM file for CPMLDR to load into memory and execute. Also makes sense.

However, I'd appreciate a little guidance on how to complete these tasks if possible. I have CP/M 2.2 with a working CBIOS already. I've read in the CP/M 3 System Guide that you can convert the CBIOS from 2.2 to 3. This would obviously make sense as I'll likely be building the CPMLDR and CPM 3 .COM files in CP/M 2.2, and there's no point re-inventing the wheel.

Initially I had a look online to find examples of LDRBIOS assembly files but all I can find relating to the LDRBIOS I need to build CPMLDR are written in 8080. Yes, I know the Z80 can understand 8080 opcodes but I can't (I'm still learning Z80 opcodes!) :rolleyes:

The guide talks about extra jump points, which I've added, to the BIOS jump table - I'm about to start working my way through the functions and making sure they do what CP/M 3 expects (though I'm looking initially to create a non-banked version of CP/M 3 first.) But the LDRBIOS.ASM comments talk about 'boot' being null, then elsewhere that it should get its start value from @mxtpa and... :confused:

Anyone done this before and can remember what they did? I just need a few pointers really as I don't know enough about the subject to confidently make the edits I need to.

I've attached a zip file with the two .ASM files - CPM3_CBIOS64.ASM is the full CBIOS for CP/M 3 that I'm building based off of the CP/M 2.2 CBIOS, LDRBIOS.ASM is an example BIOS for CPMLDR (stripped down) that I'm trying to convert to work with my system and get CPM 3 running.

Any help would be greatly appreciated!

File Attachment: 42234

durgadas311
December 2nd, 2017, 09:46 AM
I haven't looked at your BIOS yet, but I do have CP/M 3 for the Z89/Z90 computers online at https://github.com/durgadas311/MmsCpm3 which might help. This example is a bit extreme, as the BIOS supports many different disk and hardware options, through linkable modules. The main BIOS (mbios3.asm) is tailored for the H89 platform, but might be a possible starting point. There's also a wiki there, where I try to describe more details. If you think it's useful, let me know and I can help you adapt it. Or at least explain parts of it. In this case, the loader is created by linking in a BIOS disk module and a bootstrap module for the specific disk to boot from.

I should note that all of that code uses "Intel mnemonics extended for the Z80", so you will have that hurdle to understand and/or utilize it. There is a Z80.LIB macro library for RMAC, though.

nockieboy
December 3rd, 2017, 01:35 AM
Thanks durgadas311, any examples are a great help to me as I find it much easier learning from a working example than from a sequence of instructions that often miss important steps out because of assumptions about the reader's prior knowledge.

I'm going to have some time hopefully tomorrow to take a good look at the BIOS. It makes most sense to me to use the CP/M 2.2 BIOS and 'upgrade' it to work with CP/M 3 - then I'll pare it down to the minimum required for CPMLDR and get that built too.

MarsMan2020
December 3rd, 2017, 09:13 AM
John Monahan has some write-ups on bringing up CPM/3 his S100Computers website:

Floppy - www.s100computers.com/Software%20Folder/CPM3%20BIOS%20Installation/CPM3%20FLOPPY%20BIOS%20Software.htm
IDE/CF card - http://www.s100computers.com/Software%20Folder/CPM3%20BIOS%20Installation/CPM3%20HDISK%20BIOS%20Software.htm

Note that John's IDE write-up uses a 'holes' version of the LBA translation routine out of simplicity, which does not work with cpmtools, if you scroll down to the 'A New Simplified CF-CARD CPM3 Image.' there is information on the LBA translation routines needed to avoid the holes.

Chuck(G)
December 3rd, 2017, 09:55 AM
I've never verified this, but I've long suspected that if one writes a BIOS/XIOS for MP/M II, then the job's pretty much done for CP/M 3. Truth or delusion? :) (i.e., I've done for former, but not the latter)

nockieboy
December 3rd, 2017, 12:07 PM
John Monahan has some write-ups on bringing up CPM/3 his S100Computers website:

Floppy - www.s100computers.com/Software%20Folder/CPM3%20BIOS%20Installation/CPM3%20FLOPPY%20BIOS%20Software.htm
IDE/CF card - http://www.s100computers.com/Software%20Folder/CPM3%20BIOS%20Installation/CPM3%20HDISK%20BIOS%20Software.htm

Note that John's IDE write-up uses a 'holes' version of the LBA translation routine out of simplicity, which does not work with cpmtools, if you scroll down to the 'A New Simplified CF-CARD CPM3 Image.' there is information on the LBA translation routines needed to avoid the holes.

Wow that's a really detailed resource - thanks for that, MarsMan2020. :)

I've already got CPM 2.2 running on my system - so the BIOS is set up to work with the CompactFlash card and I'm hoping it won't take much to convert it for use with CPM 3. Now I know that CPM 3 has a few changes to the drive tables compared to 2.2, but aside from those and the jump table modifications (and coding the associated extra functions where necessary), I don't think there's much more I need to do to get a working CPM3 BIOS?

nockieboy
December 4th, 2017, 03:41 AM
Okay, I've had a go at LDRBIOS.ASM and converted it to Z80 opcodes, with a couple of tweaks (a DJNZ and LDIR where the 8080 version had loops).

From what I can gather from the comments in the file, I don't need to do anything else as this BIOS will run alongside my CP/M 2.2 CBIOS and uses the functions in that to access the CompactFlash and other machine-specific IO features?

Anyone care to take a look at the file and give it a quick sanity check for me? If it's okay, I guess I just need to compile a CPMLDR.COM file using this assembly to run at 0100H and I'll be able to run it in CP/M 2.2? Do I need to compile a new CPM3.SYS with a full CBIOS first before I can run CP/M 3 from CP/M 2.2?

File attachment: 42282

EDIT: Update as I've tried to create CPMLDR.COM with LINK and got the following error/s:



A>LINK CPMLDR[L100]=CPMLDR,LDRBIOS
LINK 1.31

UNDEFINED SYMBOLS:

@CIVEC @COVEC @AOVEC @LOVEC @BNKBF @CRDMA @CRDSK @FX
@RESEL @VINFO @USRCD @ERMDE @DATE @HOUR @MIN @SEC
@MXTPA

ABSOLUTE 0000
CODE SIZE 0AC7 (0100-0BC6)
DATA SIZE 0000
COMMON SIZE 0000
USE FACTOR 22

A>


I've obviously misunderstood the symbols in LDRBIOS.ASM - these need to be explicitly set in the assembly file?

durgadas311
December 4th, 2017, 05:48 AM
If CPMLDR.COM is truly stand-alone (does not depend on the CP/M 2.2 used to start it) then you should be OK. This image is often placed on boot tracks of a disk so that you can boot directly into CP/M 3. For my Kaypro version, I used a modified CP/M 2.2 boot disk (to avoid critical memory areas) and then made that CCP "auto execute" the CPMLDR command (by patching the command buffer in the CCP). For test purposes, you can usually just invoke CPMLDR from CP/M 2.2 CCP, provided there are no memory conflicts (i.e. CPMLDR.COM is stand-alone). The first instruction in CPMLDR.COM should probably be a DI, or at least before the LDRBIOS cold boot entry is called.

nockieboy
December 4th, 2017, 08:22 AM
The first instruction in CPMLDR.COM should probably be a DI, or at least before the LDRBIOS cold boot entry is called.

Ah, thanks. I'll add that in. Is there anywhere I can look up EXTRN assembly directives so I can work out what I need to do to fix them in my LDRBIOS source? They're throwing 'undefined symbol' errors when I try to link/compile CPMLDR with my BIOS, as shown in my previous post.

durgadas311
December 4th, 2017, 08:54 AM
Your undefined symbols look like SCB. Since the loader is not exactly CP/M 3, I'm not sure what those resolve to. Perhaps the loader is pre-initializing the SCB for CP/M 3. I'll have to check the loader submit files, but there probably needs to be another module to link with it. Maybe see if there is a submit file on my github repository that might lend a clue. Probably looking for an SCB.ASM or SCB.REL.

Alphasite
December 4th, 2017, 09:25 AM
There should be an SCB.MAC or SCB.ASM.

nockieboy
December 4th, 2017, 09:46 AM
Sorry, what's an SCB? Will SCB.MAC/ASM be a generic file, or another hardware specific one?

EDIT: Ah - System Control Block? Found a reference to SCB.Z80 online.. Just need to find one now. Not in front of a computer at the moment. How would I include that with the LINK command I was using to build the CPMLDR.COM file?

durgadas311
December 4th, 2017, 10:31 AM
I would suggest reading the CP/M 3 system manual, and perhaps programmers manual, for more about SCB. Also, there may be different versions of SCB.ASM out there. I'm not sure that the one used for the BIOS is the same as what is needed for the LOADER. There is some good information in the DRI manual about bringing up CP/M 3. The SCB used for the BIOS has a "dummy" base address for the SCB, which GENCPM (or some other component) recognizes and translates into a real address. I'm not sure what the LOADER needs SCB for, so not sure what sort of base address it needs.

Basically, though, the SCB is a block of memory, mostly maintained by the BDOS, that exports various bits of information. In some cases, external entities like the BIOS and CCP may alter information in the SCB or pre-init values during boot.

Alphasite
December 4th, 2017, 11:23 AM
Odd, I posted a reply and it seems to have disappeared.

There's a copy here:

http://v1050.classiccmp.org/src/index.html#SCB.ASM

It's part of the standard distribution.

I can't find the SUB file I used to build CPMLDR for my system so I can't say if I linked SCB.REL or not.

I'm still trying to recover my build environment.

nockieboy
December 4th, 2017, 01:37 PM
Odd, I posted a reply and it seems to have disappeared.

There's a copy here:

http://v1050.classiccmp.org/src/index.html#SCB.ASM

It's part of the standard distribution.

I can't find the SUB file I used to build CPMLDR for my system so I can't say if I linked SCB.REL or not.

I'm still trying to recover my build environment.

Ah, thanks Alphasite - that's a handy resource. I managed to find an SCB.Z80 - funnily enough - in the CP/M 3 distribution files I have, as you've mentioned. :rolleyes: As far as linking it with LDRBIOS.ASM to create CPMLDR.COM, I've taken a shortcut and just copied the contents into LDRBIOS.ASM as it's just a group of equates. I've managed to successfully build a CPMLDR.COM file as a result but, no surprise, it crashes the emulator when I run it. I've got to go through the equates and make sure they're matching up to the correct addresses for the SCB in my computer and try it out on that, but I just feel there's probably a million other things I need to be matching up as well that could cause it all to fall over.

durgadas311
December 4th, 2017, 02:04 PM
I'd still recommend going the through the instructions in the DRI manuals and make sure you didn't miss something. Again, the "base address" in SCB.ASM is actually a fake one, and what the loader needs depends on how it's used. BDOS3 does not exist when the loader starts, and once BDOS3 (and BIOS3) runs the loader never executes again, so anything the loader does with the SCB is limited. Unless these EXTRNs are actually for something else, in which case SCB.ASM is the wrong way to resolve them.

durgadas311
December 4th, 2017, 02:18 PM
I'm taking a look now at the CPMLDR.ASM I got from www.cpm.z80.de and I don't see any references to the SCB. That file contains a strip-down CP/M 2.2 BDOS with a loader program front-end. I wonder now where those undefined symbols come from. Does your loader BIOS have CP/M 3 code in it (references to the SCB)? I'll go back and review your earlier posts to try and see what you are doing.

durgadas311
December 4th, 2017, 02:33 PM
I think you'll need to work on LDRBIOS.ASM more. I see the EXTRN declarations there for SCB symbols, but those are never used - except @MXTPA. Also, it looks like your cold boot routine does nothing but return immediately. That probably won't work, you'll need to be sure to reclaim all your hardware away from the previous CP/M instance. That might only be critical if interrupts are setup and enabled (on device hardware), but probably you'll need to some amount of hardware reconditioning - in case any of the hardware is in an undefined state. You really want to minimize this as well, especially to ensure any crash is unlikely to write to disk. Also, use of "ORG" may be contradictory to use of RMAC/LINK. You need to let LINK resolve the first address in your BIOS so that it is placed immediately after the last byte of CPMLDR.REL. Typically, a relocatable program segment will simply start with CSEG (and no ORG). It appears that the loader uses only CSEG, which makes it simpler. I think the only place you'd use absolute addresses in LDRBIOS.ASM is if there were some memory-mapped spaces or a ROM BIOS memory region you needed to access. If such things exist, you'll also need to make sure your CP/M 3 image avoids placing anything there.

update: I see you did comment-out the ORG statement, so that is not the problem. So maybe just work on the cold boot code. Also, I see some calls to BDOS although I'm not sure if they are getting executed. The loader does not setup 0005H, as far as I can tell, so you might end up calling the wrong BDOS. Especially if you're using @MXTPA to do that, when that symbol will not have been initialized. I'm not sure how one is supposed to call the loader BDOS from the loader BIOS, if that is even possible.

nockieboy
December 5th, 2017, 01:18 AM
update: I see you did comment-out the ORG statement, so that is not the problem. So maybe just work on the cold boot code. Also, I see some calls to BDOS although I'm not sure if they are getting executed. The loader does not setup 0005H, as far as I can tell, so you might end up calling the wrong BDOS. Especially if you're using @MXTPA to do that, when that symbol will not have been initialized. I'm not sure how one is supposed to call the loader BDOS from the loader BIOS, if that is even possible.

Well, I'm trying to 'upgrade' my existing CP/M 2.2 installation to CP/M 3 - there's an archive here (http://www.cpm.z80.de/download/cpm3on2.zip) from cpm.z80.de that is set up to allow CP/M 3 to run from CP/M 2.2, that's what I've been using and where LDRBIOS.ASM comes from.

I'm trying to learn assembly and CP/M at the same time as trying to get CP/M 3 running on my SBC - I'm starting to feel I've bitten off more than I can chew. Unfortunately, the CP/M System Guide doesn't give a step-by-step tutorial on how to upgrade 2.2 to 3 (well, the instructions given are too high-level for me) and that's what I need. I don't have the assembly knowledge or familiarity with the CP/M tools/system/code to do much more than copy and paste blocks of code from the 2.2 CBIOS to the 3 BIOS and hope it works.

I'm going to take a break and go work on some more features for the monitor ROM - then hopefully I can come back and take a fresh look at this. As I understand it though, this is what I have to do:

1. Create a CPMLDR.COM file, by:
a) Creating a working LDRBIOS.ASM
b) Compile in RMAC and link to create CPMLDR.COM file

2. Create a full BIOS for CP/M 3, by:
a) Taking the CP/M 2.2 CBIOS and modifying it with the extra CP/M 3 jumps
b) Modify the extra routines to return null etc
c) Tweak a couple of existing routines to return expected values for CP/M 3
d) Compile in RMAC and link to create CPM3.SYS file

3. At this point, I should be able to run CP/M 3 in CP/M 2.2 by running CPMLDR.COM.

4. Modify boot sector of CF card to run CPMLDR.COM using COPYSYS?

durgadas311
December 5th, 2017, 03:26 AM
I understand the frustration, this sort of thing is not really easy - despite what the instructions might imply. And to do this while learning (about Z80 ASM and CP/M) is even harder. If I had a virtual machine to match your hardware, I could probably be of more help. I'm strapped for spare time right now, though.

another area to pay attention to, when creating the BIOS3 code, is the DPH and associated structures. There are some subtle differences and new structures which need to be carefully handled.

I'l try to find some time this weekend to take a closer look at your BIOS code and see if I can help by inspection. If you've got something to document your hardware, that might be nice. either "programmer notes" or a schematic.

nockieboy
December 5th, 2017, 04:46 AM
I understand the frustration, this sort of thing is not really easy - despite what the instructions might imply. And to do this while learning (about Z80 ASM and CP/M) is even harder. If I had a virtual machine to match your hardware, I could probably be of more help. I'm strapped for spare time right now, though.

another area to pay attention to, when creating the BIOS3 code, is the DPH and associated structures. There are some subtle differences and new structures which need to be carefully handled.

I'l try to find some time this weekend to take a closer look at your BIOS code and see if I can help by inspection. If you've got something to document your hardware, that might be nice. either "programmer notes" or a schematic.

You sir are a star. :D

I don't have a single schematic for the design - the schematics are quite modular. However, here's a summary of features that should help:

The SBC has a flexible MMU, which splits the Z80's 64KB memory space into 4 16KB 'Areas', each able to be independently mapped to any 16KB Bank in the 256K available physical memory (128KB SRAM in lower half, 128KB EEPROM in upper half.) With the addition of a CompactFlash card, the SBC has permanent storage allowing it to run CP/M 2.2. It uses an ATmega328 microcontroller to enhance its IO potential:

Z80 microprocessor at 2, 4 or 8 MHz clockspeed, software-selectable
128K SRAM (00000h-1FFFFh)
128K ROM (20000h-3FFFFh)
MMU provides access to 256KB physical memory in 16x16KB Banks, mappable to the Z80 in any arrangement as 4x16KB Areas
Z80 SIO/2 providing two serial interfaces, with interrupt-driven Rx channels to prevent unnecessary polling of the Rx buffer when not in use
CompactFlash adapter with 64MB CF card providing 8x 8MB drives for file storage
OS - Custom ROM monitor providing NASCOM BASIC, memory and Intel HEX file input utilities & CP/M 2.2
I2C bus via Support Module - currently supports Real Time Clock module
Fully-expandable interrupt system
Z80 CTC for clock/timer functions and user-programmable triggerable interrupts
Z80 PIO for 2-channel parallel IO

Memory & IO Map:

Power-up Memory Map:

Area 0 - 0000-3FFF ROM (Bank 0F - DMI monitor)
Area 1 - 4000-7FFF RAM (Bank 01)
Area 2 - 8000-BFFF RAM (Bank 02)
Area 3 - C000-FFFF RAM (Bank 03)

As the MMU allows full configuration of the memory space, this memory map is only applicable at first power-on. i.e. the RAMMODE command copies the DMI from Bank 0F to Bank 00, then maps Area 00 to Bank 00.

Memory Map in CP/M mode:

Area 0 - Bank 0 (SRAM)
Area 1 - Bank 1 (SRAM)
Area 2 - Bank 2 (SRAM)
Area 3 - Bank 3 (SRAM)

Breakdown of the CP/M memory map:

0000-0100 Scratch storage & interrupt vectors
0100-D800 TPA
D800-E5FF CP/M
E600-FFFF BIOS

I/O Map

00-07 SIO/2 dual-port serial interface
08-0F Reserved for PSG
10-17 CompactFlash interface
18-1F CTC 4-channel programmable clock/timer
20-27 PIO 2-channel parallel I/O
28-2F Unused
30-37 Unused
38-3F Memory Management Unit

The CompactFlash storage and format is identical to Grant Searle's design here (http://searle.hostei.com/grant/cpm/index.html) and uses the same routines to read/write. In fact the SBC is based loosely on Grant's design, with some modifications to the IO mapping and RAM/ROM select (in my SBC it's managed via the MMU.)

The MMU is controlled via an
OUT ($38),n command, where n is a control byte made up of the following:

B7 - low = MMU active, high = MMU inactive
B6 - not used
B5, B4 = Area select
B3-B0 = Bank select

So
OUT ($38),02 would map Bank 02 (SRAM 8000-BFFFh) to Area 0 (0000-3FFFh).

Also, I've attached the current CBIOS for CP/M 2.2 - this works with my SBC to allow CP/M 2.2 to run without problems.

Attachment: 42303

durgadas311
December 9th, 2017, 05:56 AM
I did some looking around. I see that you are using Z80 vectored interrupts, but it appears the only interrupts are for serial input. I don't know if one of your serial channels is automated in any way (i.e. input may occur spontaneously at any time - like during the loader execution). To be safe, I would suggest that your loader BIOS either keep interrupts disabled or re-initialize the Z80 and SIO vector pieces for valid routines within your loader BIOS.

Another thing I noticed is that the loader BDOS expects your loader BIOS to work in CP/M 3 version structures. This means the DPH and the DPB need to be compatible with CP/M 3. This also means you could let the loader BDOS handle deblocking, if you wanted, by initializing (to non-zero) the physical sector bytes at the end of the DPB. The loader BDOS does not do any bank-switching, but it does depend on a "move" entry point to the BIOS, which is a simple (DE)-to-(HL)x(BC) move routine. The only BIOS routines that seem to be needed are COLD BOOT, CONOUT, disk setup and read, and MOVE. The loader BDOS also expects the DIRBCB and DTABCB buffer control bock chains to be valid. So, the loader BIOS is not really CP/M 2.2 nor is it a full-featured CP/M 3 BIOS.

Looking at the latest LDRBIOS.ASM that I have, I would do the following:

1) Remove all EXTRNs, and any code that uses those symbols.
2) Change all "unused" BIOS entries into a trap for debugging. since you already have routines to print a HEX address, you could change all the unused JP entries into "CALL TRAP" and have the TRAP routine pop the address and print it in an error message and then die (DI; HLT) - so you know what's being called.
3) Remove all code no longer used after (2).
4) Make (cold) BOOT do *at least* a DI (and make sure nothing enables interrupts). The loader won't use console input, but if you have other uses for that special channel then you'll need to handle it. You can either do polled input or re-initialize the interrupt vector to something inside the loader BIOS. Also, do not change the stack pointer - keep the loader's stack. Be sure to return from BOOT, do not try to "start CP/M" yourself.
5) Do not use DSEG - keep all code/data in CSEG.
6) Do not rely on the CP/M 2.2 BIOS for anything. The BDOS, including loader BDOS, remembers the BIOS structures and uses them, which won't work while the loader is overwriting the CP/M 2.2 BIOS with CP/M 3. Let alone you won't be able to call into the 2.2 BIOS.

Here's a picture that may help:
42398

While the loader is running, it is overwriting the area used by the 2.2 BIOS with the CP/M 3 resident BIOS/BDOS. This means that any attempts to access code or data in the 2.2 BIOS area will result in a crash (either jumping to invalid code or using corrupted data). This is why the loader BIOS must be stand-alone. But since you don't need any of the write and deblocking code, or any of the extra I/O, it should be simple and small.

Does this make sense?

nockieboy
December 9th, 2017, 06:34 AM
Does this make sense?

Right now, having just skim-read your post, no it doesn't really. :rolleyes: But that's no surprise as I'm so new to CP/M and assembly that it'll probably take me a few days of reviewing what you've written and breaking it down before I get a grasp of it all. I'm hoping to get some time tomorrow or perhaps during the week to review what you've written and develop a plan of action. I'll be back with questions, no doubt!

Thanks so much for taking the time to look at it, durgadas - your help is much appreciated!!

durgadas311
December 14th, 2017, 01:09 PM
Here's what I think the LDRBIOs needs to be, with minimal "gratuitous" changes. CPMLDR.ASM supports BDOS deblocking, but this BIOS still does that and tells the BDOS the physical sector size is 128. It also does not fully implement the DIR/DTA BCBs since only DIRBCB is used in this case. I also am not sure how much of the serial I/O code can go away.

42466

Also, since I don't use Z80 mnemonics, I can't be sure the changes are 100% correct, but I'm sure your assembler will tell you. Of course, I can't be certain this will work, either. Take a look and review it, let me know if you have questions.

This LDRBIOS is derived from you CP/M 2.2 BIOS "cbios64.asm". I added extra entry points and traps for unused ones. It prints enough messages that you should be able to tell how far it gets. If the CP/M LOADER message get printed, that means that the LDRBIOS cold boot completed. If you enabled the memory map printing in GENCPM, that message gets printed after opening CPM3.SYS and reading the first few records. And of course if your CP/M 3 BIOS prints a sign-on message, that indicates you made it to the CP/M 3 cold boot routine. From there, it is debugging your CP/M BIOS.

nockieboy
December 14th, 2017, 01:55 PM
Here's what I think the LDRBIOs needs to be, with minimal "gratuitous" changes.

Sorry durgadas, I got sidetracked by another mini-project (I've implemented in-circuit programming of the ROM to save me swapping the ROM out every time I want to update the monitor). I've put off working on the CP/M 3 upgrade as much as I can now, so I started looking at CP/M earlier this evening, so your post couldn't have come at a better time! Thank you so much for your help!



CPMLDR.ASM supports BDOS deblocking, but this BIOS still does that and tells the BDOS the physical sector size is 128. It also does not fully implement the DIR/DTA BCBs since only DIRBCB is used in this case. I also am not sure how much of the serial I/O code can go away.

Ah yes, don't worry about the serial I/O code - I know exactly what it's for and can just DIsable interrupts for CPMLDR. The serial I/O interrupt tells the system that a character is waiting to be read in the port A or port B buffers (i.e. the user has tapped a key in the terminal or a data stream is waiting in the B buffer from the ATmega368 support module).

Not sure what you mean by the DIRBCB/DTABCB comments - I will go away and read up on this next.



Also, since I don't use Z80 mnemonics, I can't be sure the changes are 100% correct, but I'm sure your assembler will tell you. Of course, I can't be certain this will work, either. Take a look and review it, let me know if you have questions.

Absolutely - will do! :D



This LDRBIOS is derived from you CP/M 2.2 BIOS "cbios64.asm". I added extra entry points and traps for unused ones. It prints enough messages that you should be able to tell how far it gets. If the CP/M LOADER message get printed, that means that the LDRBIOS cold boot completed. If you enabled the memory map printing in GENCPM, that message gets printed after opening CPM3.SYS and reading the first few records. And of course if your CP/M 3 BIOS prints a sign-on message, that indicates you made it to the CP/M 3 cold boot routine. From there, it is debugging your CP/M BIOS.

So... just to be clear (it's been a long day and I'm going to bed!)... To test out our new BIOS I need to compile LDRBIOS.ASM into LDRBIOS.REL using RMAC? Then use LINK to link CPMLDR.REL (supplied with the CP/M source files) with LDRBIOS.REL to create CPMLDR.COM?

durgadas311
December 14th, 2017, 05:45 PM
Based on the CPMLDR.ASM I have, assuming it is what produced CPMLDR.REL, you should do this:

RMAC LDRBIOS.ASM
LINK CPMLDR=CPMLDR,LDRBIOS[OC,NR]

although, does RMAC support Z80 mnemonics? Back in the old days, we just stuck with Intel + Z80.LIB so I never tried anything else.

The DIRBCB/DTABCB are just constructs created for CP/M 3 to handle disk buffers. It's a structure (BCB = Buffer Control Block) that allows several buffers to be managed by the BDOS, basically in a least-recently-used manner. One set used for directory, the other for data.

nockieboy
December 16th, 2017, 02:31 AM
Based on the CPMLDR.ASM I have, assuming it is what produced CPMLDR.REL, you should do this:

RMAC LDRBIOS.ASM
LINK CPMLDR=CPMLDR,LDRBIOS[OC,NR]

although, does RMAC support Z80 mnemonics? Back in the old days, we just stuck with Intel + Z80.LIB so I never tried anything else.

I think it does... well, I got this when I tried RMAC just now:


026C
00DH USE FACTOR
END OF ASSEMBLY

That appeared at the end of a (very) long console output of the PRN file, I'm guessing. Couldn't see any errors with my untrained eye..

The next line - LINK CPMLDR=... etc - produces this response:


A>LINK CPMLDR=CPMLDR,LDRBIOS[OC,NR]
LINK 1.31

ABSOLUTE 0000
CODE SIZE 0C6C (0100-0D6B)
DATA SIZE 0000
COMMON SIZE 0000
USE FACTOR 27

A>

So it appears to have compiled okay. Running CPMLDR seems to do nothing though?


A>cpmldr

A>sysinfo
Processor: Z80
System: CP/M 2.2
Top of TPA: D800
BIOS start: E600

It just returns to the console - a subsequent SYSINFO shows that 2.2 is still running, seemingly with no ill-effects and no trap error messages etc from CPMLDR. Am I missing something painfully obvious? :sleepy: I was hoping that it would at least attempt to load the CPM3.SYS file and (most likely) crash as I haven't compiled CP/M 3 with the new BIOS?

durgadas311
December 16th, 2017, 04:45 AM
Hmmm, do you have a special, modern, version of RMAC? I tried just now on a virtual CP/M machine with RMAC 1.1 and it chokes on nearly every line. I'm guess that the RMAC result you got, 026C, is too small for the BIOS as well, indicating something went wrong. My failed attempt returned 0278 so something must be different between our two setups. The PRN file showed the first successfully assembled code was the "JP BOOT" and the "CALL TRAP". Intel mnemonics interpret "JP" as "Jump if Plus" and you follow that with a CALL TRAP with "trap" undefined (due to invalid op code at that routine) and you have a chance (depending on the CPU flags when CCP executes the loader) that the "JP BOOT" will fall-through to the "CALL TRAP" ("CALL 0000H") which simply returns to the native CP/M immediately. There are also many other opportunities to jump/call 0000H in this mangled code stream.

But, what have you been using to assemble your Z80 code up to now? Does that tool produce REL files?

I'd be interested to see your PRN file and look at what code it actually produced. Strange that it did not spew a ton of errors.

nockieboy
December 16th, 2017, 09:35 AM
Hmmm, do you have a special, modern, version of RMAC?

Hmm.. not that I know of. I can't remember where I got it from as it wasn't in the original CP/M 2.2 file archive that I had. I suspect it was from a CP/M 3 archive or something...


I tried just now on a virtual CP/M machine with RMAC 1.1 and it chokes on nearly every line. I'm guess that the RMAC result you got, 026C, is too small for the BIOS as well, indicating something went wrong. My failed attempt returned 0278 so something must be different between our two setups. The PRN file showed the first successfully assembled code was the "JP BOOT" and the "CALL TRAP". Intel mnemonics interpret "JP" as "Jump if Plus" and you follow that with a CALL TRAP with "trap" undefined (due to invalid op code at that routine) and you have a chance (depending on the CPU flags when CCP executes the loader) that the "JP BOOT" will fall-through to the "CALL TRAP" ("CALL 0000H") which simply returns to the native CP/M immediately. There are also many other opportunities to jump/call 0000H in this mangled code stream.

But, what have you been using to assemble your Z80 code up to now? Does that tool produce REL files?

I've been using TASM, through the DOSBox emulator (and I suspect it is TASM 3.1, from here (http://www.ticalc.org/archives/files/fileinfo/15/1504.html)) - I don't do any code editing in CP/M as I don't have anything other than ED in CP/M 2.2 (which is a royal pain in the arse). I don't think I can use Wordstar or anything like that as I'm accessing the SBC through a terminal (PuTTY) rather than a CRT, so I don't have any graphics or cursor-positioning commands other than the extreme basics.

EDIT: And no, it doesn't produce .REL files as far as I can tell. :/


I'd be interested to see your PRN file and look at what code it actually produced. Strange that it did not spew a ton of errors.

I'll see if I can get it copied via the terminal and post here shortly.

nockieboy
December 16th, 2017, 09:47 AM
Okay, here's the LDRBIOS.PRN file:

42495

Here's RMAC:


A>RMAC
CP/M RMAC ASSEM 1.1
A:.ASM-NO SOURCE FILE PRESENT

durgadas311
December 16th, 2017, 10:45 AM
Looks like you got pretty much the same errors I got. The first character in a line indicates the error (blank means no error). Not sure why the code is different, although I did notice that the EOF (Ctrl-Z) was not present in the file you assembled, so that might have something to do with it.

If you must use RMAC, you will have to revert to Intel mnemonics plus Z80.LIB for Z80 instruction macros. I'm not aware of other assemblers that might be available, for example whether Microsoft's CP/M-80 assembler supports Z80.

daver2
December 16th, 2017, 10:55 AM
There are loads of errors in the listing file...

Look in column 1 of the listing file and compare them with the descriptions on page 165 of http://www.cpm.z80.de/manuals/mac.pdf.

For example 'S' = syntax error. 'U' = Undefined symbol. 'L' = Label error. 'P' = Phase error. 'V' = Value error. 'E' = Expression error.

Looking at the list of errors, RMAC doesn't support the Zilog mnemonics. Didn't I find a Z80 MACRO library for you a while ago (or was it for someone else) I can't remember? Somewhere I think there is a set of Z80 library macros to enhance the assembler.

EDIT: Just got beaten there...

Dave

nockieboy
December 16th, 2017, 11:14 AM
Looks like you got pretty much the same errors I got. The first character in a line indicates the error (blank means no error). Not sure why the code is different, although I did notice that the EOF (Ctrl-Z) was not present in the file you assembled, so that might have something to do with it.

If you must use RMAC, you will have to revert to Intel mnemonics plus Z80.LIB for Z80 instruction macros. I'm not aware of other assemblers that might be available, for example whether Microsoft's CP/M-80 assembler supports Z80.

Erm... well, I'm not using RMAC because I have to, just because it was the program that was mentioned in the CP/M 3 System Guide.

nockieboy
December 16th, 2017, 11:17 AM
There are loads of errors in the listing file...

Look in column 1 of the listing file and compare them with the descriptions on page 165 of http://www.cpm.z80.de/manuals/mac.pdf.

For example 'S' = syntax error. 'U' = Undefined symbol. 'L' = Label error. 'P' = Phase error. 'V' = Value error. 'E' = Expression error.

Looking at the list of errors, RMAC doesn't support the Zilog mnemonics. Didn't I find a Z80 MACRO library for you a while ago (or was it for someone else) I can't remember? Somewhere I think there is a set of Z80 library macros to enhance the assembler.

EDIT: Just got beaten there...

Dave

Hi Dave! Welcome to the ongoing mayhem that is me fumbling around trying to get CP/M 3 up and running... ;)

Ah yes, I missed that - not knowing anything about RMAC etc meant I missed that it was throwing all those errors! Definitely looks like RMAC doesn't like Z80 mnemonics. I don't recall you finding a Z80 MACRO library for me? Though my memory is particularly crap and getting worse all the time...

I'll have a hunt later for some Z80 library macros and get back to you guys. :)

durgadas311
December 16th, 2017, 11:41 AM
RMAC only understands Intel mnemonics. You can extend it with a macro library to do the (new) Z80 instructions, but the instruction format is coerced to work with the macros. These were called "Z80 extensions to Intel mnemonics". The Zilog mnemonics require a completely different parser and thus RMAC won't be able to assemble Zilog mnemonics. The assembler directives are also different.

Also, RMAC uses different symbol rules so I think many of the labels/symbols in your code will have to change as well. This includes changes to satisfy uniqueness, since RMAC does not allow arbitrary length labels. In addition, RMAC may not support the expression syntax. Bottom line, I'd suggest that you either hunt down a Z80 assembler that can produce REL files or else take the hit and switch back to Intel mnemonics (and RMAC assembler syntax).

Here's the Z80.LIB macro library I use. It is loaded using "MACLIB Z80" in the ASM file. Note, this provides *most* of the official Z80 instructions, and possibly a couple undocumented ones, but is no way complete. I forget where we got it, but I did extend it a bit.

42511

durgadas311
December 16th, 2017, 11:45 AM
For editing on CP/M I use Magic Wand. But it is screen-oriented and so requires a "terminal" config for the control/escape codes your terminal accepts. I have a H19 version (VT52-like) and a Kaypro one (ADM3-like). I also have the terminal module source, so you could configure it for your terminal codes. Let me know if you want to go down that rabbit hole...

daver2
December 16th, 2017, 11:49 AM
>>> Hi Dave! Welcome to the ongoing mayhem that is me fumbling around trying to get CP/M 3 up and running...

Thanks. I have been reading your thread - but just too busy to respond. Never mind, I have broken up for Christmas now - but my wife may have a few things to say about 'relocating computers for the christmas festivities'...

Z80.LIB is mentioned at http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Assembler%20Collection.htm but (as duragas311 has already stated) be prepared for the long haul... You may be 'better' served by trying to assemble and link externally to CP/M as you currently do - but you will have to find a relocating assembler/linker to link together the supplied CP/M relocatable object file(s) with yours...

I assume the following to be true...

CPMLDR.ASM produces CPMLDR.REL

LDRBIOS.ASM produces LDRBIOS.REL

CPMLDR.REL when combined with LDRBIOS.REL produces CPMLDR.COM

I assume CPMLDR.ASM is a Digital Research supplied file - therefore this will be written using INTEL mnemonics. [EDIT: Just checked the CP/M V3 sources and this is correct - although CPMLDR.REL seemed to be supplied by Digital research in the distribution; with CPMLDR.ASM being supplied with the source].

LDRBIOS.ASM is your own creation, therefore uses Zilog mnemonics.

If this is true, you either have to assemble CPMLDR.ASM under CP/M (RMAC) to produce CPMLDR.REL and copy that to your development machine where you would assembler your LDRBIOS.ASM to produce LDRBIOS.REL and link with CPMLDR.REL to produce CPMLDR.COM or assemble your LDRBIOS.ASM on your development machine to produce LDRBIOS.REL and copy that to CP/M and use CP/Ms linker to produce CPMLDR.COM.

The bottom line is you will need both an Intel and Zilog mnemonic assembler to produce the .REL files and a separate linker to combine them and produce a .COM file.

I would suggest drawing out the development process, identifying the input and output files, the tools (assembler, linker etc) to convert the files and the machines upon which the tools execute (this will identify the file copying necessary between machines).

I hope this makes sense?

Dave

nockieboy
December 16th, 2017, 01:26 PM
For editing on CP/M I use Magic Wand. But it is screen-oriented and so requires a "terminal" config for the control/escape codes your terminal accepts. I have a H19 version (VT52-like) and a Kaypro one (ADM3-like). I also have the terminal module source, so you could configure it for your terminal codes. Let me know if you want to go down that rabbit hole...

I probably will later, but I've had a real problem focusing on getting CP/M 3 running and another distraction wouldn't do me any good at the moment. :D Thanks for the Z80.lib macro library - I suspect it will come in handy!


Never mind, I have broken up for Christmas now - but my wife may have a few things to say about 'relocating computers for the christmas festivities'...

Yeah, I know the feeling, mine keeps making random nagging noises about similar things - I've still got another week to go, workwise. :shock:


Z80.LIB is mentioned at http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Assembler%20Collection.htm but (as duragas311 has already stated) be prepared for the long haul... You may be 'better' served by trying to assemble and link externally to CP/M as you currently do - but you will have to find a relocating assembler/linker to link together the supplied CP/M relocatable object file(s) with yours...

Am I right in thinking that so long as I can get an assembler to produce the .REL files, I can just link them in CP/M 2.2 using LINK?


I assume the following to be true...

CPMLDR.ASM produces CPMLDR.REL

LDRBIOS.ASM produces LDRBIOS.REL

CPMLDR.REL when combined with LDRBIOS.REL produces CPMLDR.COM

Well, I've been using the CPMLDR.REL file supplied with the CP/M distribution files, but yes, your assumptions are correct.


I assume CPMLDR.ASM is a Digital Research supplied file - therefore this will be written using INTEL mnemonics. [EDIT: Just checked the CP/M V3 sources and this is correct - although CPMLDR.REL seemed to be supplied by Digital research in the distribution; with CPMLDR.ASM being supplied with the source].

LDRBIOS.ASM is your own creation, therefore uses Zilog mnemonics.

Yup. Spot on. I've been using TASM from the very beginning so I'm familiar with its directives and general format and it's been the primary method by which I've learned assembly so far, hence the attachment to Z80 mnemonics. :D


If this is true, you either have to assemble CPMLDR.ASM under CP/M (RMAC) to produce CPMLDR.REL and copy that to your development machine where you would assembler your LDRBIOS.ASM to produce LDRBIOS.REL and link with CPMLDR.REL to produce CPMLDR.COM or assemble your LDRBIOS.ASM on your development machine to produce LDRBIOS.REL and copy that to CP/M and use CP/Ms linker to produce CPMLDR.COM.

The bottom line is you will need both an Intel and Zilog mnemonic assembler to produce the .REL files and a separate linker to combine them and produce a .COM file.

Yeah. Exactly what I was thinking. :shock: ;) I think I need to draw a diagram. Where's my crayons...


I would suggest drawing out the development process, identifying the input and output files, the tools (assembler, linker etc) to convert the files and the machines upon which the tools execute (this will identify the file copying necessary between machines).

Great minds and all that. :D ;)


I hope this makes sense?

Yes, absolutely. I'll head off and have a hunt around for some relocatable assemblers. It does seem that Linux has more options than Windows in this respect, so I might set up an Ubuntu VM as a dev environment, but if I don't have to go to those lengths I'll try to avoid it.

Thanks for your help durgadas311 and Dave - I'll be back. :D

durgadas311
December 16th, 2017, 01:58 PM
Did a little searching, this might be what you need... it actually claims to generate REL files. http://48k.ca/zmac.html

nockieboy
December 16th, 2017, 02:09 PM
Did a little searching, this might be what you need... it actually claims to generate REL files. http://48k.ca/zmac.html

I've just been looking myself and found the following in the manual for Z80ASM - an assembler I use in my (SIMH Altair) CP/M 2.2 emulator on the desktop to produce COM files for the SBC...

1) One pass operation (optional second pass)
2) Powerful nested macros, conditionals, and include files
3) Relocatable format allows extended math on externals
and relocatables
4) Up to 15 different data, program, and common areas
5) Zilog/Mostek mnemonics
6) Throughput of over 6000 Lines/Minute (8"SS/SD, 2Mhz)
7) Optional alphabetized symbol table
8) Optional alphabetized cross-reference
9) Directly generates a .COM, .HEX, or .REL file
10) Labels Significant to 16 characters
11) Supports time and date in listing
12) User Configurable
13) Supports ZCPR3 and CP/M+ error reporting

The bits in bold are the points of interest - it takes Zilog/Mostek mnemonics? Actually, as I've just written that, I realise that MOSTEK were licensed to create Z80's as well, weren't they? So it's not the same as saying Z80/8080 mnemonics.. My bad.

I'll go take a look at your suggestion, durgadas311 - looks promising. :)

EDIT: Actually, having looked at the link you supplied, it looks like it could do the job nicely. I'll give it a go tomorrow if I can find time (Sunday roasts don't cook themselves, unfortunately.) :D

daver2
December 16th, 2017, 02:13 PM
Z80ASM was my first thought - but (for a non-CP/M environment) ZMAC does look interesting.

Yep, MOSTEK were a ZILOG second-source for silicon - but the MOSTEK documentation describes the Z80 instructions the same way as the Zilog documentation does. They needn't be compatible (!) at the mnemonic level - but they were!

Dave

durgadas311
December 16th, 2017, 04:38 PM
I was able to build zmac on my linux system (took some minor fiddling with YACC/LEX), and was able to compile LDRBIOS.ASM after making a few changes/fixes. I did nothing with the REL file, but my assumption is that it is correct. The listing file looked correct.

Here's an updated LDRBIOS.ASM:

42519

UPDATE: I copied the REL file to my virtual H89 and used LINK on it. It complains about some "UNRECOGNIZED ITEM"s but seemed to succeed. I examined the code in SID and it looked viable.

MORE UPDATE: I found an old program to list out a REL file, and dumped the contents. The "UNRECOGNIZED ITEM"s seem to be related to code like this:

CP (serABuf+SER_BUFSIZE) & $FF

in other words, a "relocatable byte value". The value is getting forced to 00 so it will not work. It will take a little thinking to figure a new way to write that expression to avoid the relocatable attribute. Unfortunately, the ZMAC assembler does not complain - and probably generates valid REL bits - but DRI tools don't understand it. This is in console input code, so maybe it won't impact CP/M 3 Loader execution.

nockieboy
December 17th, 2017, 01:25 AM
I was able to build zmac on my linux system (took some minor fiddling with YACC/LEX), and was able to compile LDRBIOS.ASM after making a few changes/fixes. I did nothing with the REL file, but my assumption is that it is correct. The listing file looked correct.

Here's an updated LDRBIOS.ASM:

42519

UPDATE: I copied the REL file to my virtual H89 and used LINK on it. It complains about some "UNRECOGNIZED ITEM"s but seemed to succeed. I examined the code in SID and it looked viable.

MORE UPDATE: I found an old program to list out a REL file, and dumped the contents. The "UNRECOGNIZED ITEM"s seem to be related to code like this:

CP (serABuf+SER_BUFSIZE) & $FF

in other words, a "relocatable byte value". The value is getting forced to 00 so it will not work. It will take a little thinking to figure a new way to write that expression to avoid the relocatable attribute. Unfortunately, the ZMAC assembler does not complain - and probably generates valid REL bits - but DRI tools don't understand it. This is in console input code, so maybe it won't impact CP/M 3 Loader execution.

Not sure it would make any difference at all, but couldn't CP (serABuf+SER_BUFSIZE) & $FF be replaced with CP (serAInPtr-1) & $FF?

On a side note, I'm assuming the & $FF part clears the MSB so the CP is done against the LSB of the result of the calculation in parentheses? So it converts the 16-bit result of the calculation to an 8-bit value compatible with the CP command?

But yes, if it comes to it none of the interrupt routines are needed for LDRBIOS - but they will be required for CP/M 3 in the full BIOS and won't that cause the same problems when we try to build it?

daver2
December 17th, 2017, 04:01 AM
A 'C' compiler or assembler warning is a run-time error waiting to occur!

You can change the expression all you like, as long as the mathematics work out right it doesn't generally matter. My rule is 'make the expression as readable (to the human) as possible'.

The expression effectively evaluates to a BYTE VALUE. The byte value (as you have correctly worked out) is the least significant byte of the value in parentheses.

I suspect your problems with the expression stems from the fact that some items are declared after the code that uses them - so the assembler doesn't know the value of some of the components of the expression during pass 1. There are generally 'rules' for dealing with expressions like this - don't! I would load the 16-bit address of the relocatable item into a register pair and work out the expression itself 'in code' rather than leaving it to the assembler and linker to work out (incorrectly in this case) what you are trying to do.

Dave

durgadas311
December 17th, 2017, 04:16 AM
Yes, this will be needed - in some form - for the CP/M 3 BIOS. We could just eliminate the serial interrupts and these routines for the loader.

The problem is that the byte used in the CP instruction is *relocatable* - meaning that it's value will change depending on where the starting address of LDRBIOS lands at LINK time. If it were a constant, it would not cause a problem. I seem to recall this same problem from "the old days" - REL file format did not support 8-bit relocatable items. It would be interesting to see how support was added, but if any of the DRI tools are involved (i.e. LINK.COM) then we need to avoid this sort of expression.

There is also a linker program mentioned in the ZMAC docs, I'll see if that could be used. You'll still have to do the final stage of the CP/M 3 build in CP/M, unless you are going to write your own GENCPM program.

A couple ways to avoid the 8-bit relocatable objects by changing the code:


bufAend DW serABuf+SER_BUFSIZE
...
LD A,(bufAend)
CP L
JR NZ,...

or...detect the end of the buffer without using the address (i.e. use an index value for the current position, which is a constant ranging 0 thru SER_BUFSIZE-1, instead of using a pointer). Using an index might not be any less efficient, and might actually be faster (you only have to manipulate 16-bit values at the end, when you access the character, so most instructions are working on bytes - and if you make SER_BUFSIZE a power of 2 then the math becomes even simpler).

or...align serABuf (and serBBuf) on a 256-byte boundary so that the (8-bit) end address is a constant. Although, that is tricky in a relocatable file since the starting address may not be aligned on 256-byte pages.

nockieboy
December 17th, 2017, 04:42 AM
Yes, this will be needed - in some form - for the CP/M 3 BIOS. We could just eliminate the serial interrupts and these routines for the loader.

The problem is that the byte used in the CP instruction is *relocatable* - meaning that it's value will change depending on where the starting address of LDRBIOS lands at LINK time. If it were a constant, it would not cause a problem. I seem to recall this same problem from "the old days" - REL file format did not support 8-bit relocatable items. It would be interesting to see how support was added, but if any of the DRI tools are involved (i.e. LINK.COM) then we need to avoid this sort of expression.

There is also a linker program mentioned in the ZMAC docs, I'll see if that could be used. You'll still have to do the final stage of the CP/M 3 build in CP/M, unless you are going to write your own GENCPM program.

A couple ways to avoid the 8-bit relocatable objects by changing the code:


bufAend DW serABuf+SER_BUFSIZE
...
LD A,(bufAend)
CP L
JR NZ,...

or...detect the end of the buffer without using the address (i.e. use an index value for the current position, which is a constant ranging 0 thru SER_BUFSIZE-1, instead of using a pointer). Using an index might not be any less efficient, and might actually be faster (you only have to manipulate 16-bit values at the end, when you access the character, so most instructions are working on bytes - and if you make SER_BUFSIZE a power of 2 then the math becomes even simpler).

or...align serABuf (and serBBuf) on a 256-byte boundary so that the (8-bit) end address is a constant. Although, that is tricky in a relocatable file since the starting address may not be aligned on 256-byte pages.

Defining bufAend seems like the simplest solution to the problem, though it's still relying on serABuf which isn't defined until near the end of the 1st pass?

daver2
December 17th, 2017, 05:00 AM
Be careful you don't end up with something that is based on something else which is itself relocatable... you end up with a relocatable item again...

The general way relocatable items work is that you havecac16-bit vale computed by the assembler which has a 16 bit value added to it by the linker based on a specific item that is relocatable. In this case, you don't seem to be able to do this - hence the problem.

If you break your code down into smaller bits, it should work. E.g.:

LD DE, relocatable item.
ADD DE,offset value ; although this specific instruction doesn't exist!
Compare the E register to what's in A (which, in turn, came from L).

Dave

durgadas311
December 17th, 2017, 05:32 AM
Defining bufAend seems like the simplest solution to the problem, though it's still relying on serABuf which isn't defined until near the end of the 1st pass?

Yes, that is the least amount of change to code design. The assembler doesn't need to know the value on the first pass. It will still be relocatable, but is 16-bit instead of 8-bit, and LINK should take care of everything and the "LD A,(bufAend)" will get the fully-relocated (byte) value at runtime.

I looked at the "ld80" that was referenced on the ZMAC web page. It does not appear to support SPR or PRL output formats - in which case it can't be used to link BNKBIOS3.SPR. So, fixing the code so that it is compatible with DRI REL tools looks to be the right approach.

I looked at the code a bit, and it appears that ZMAC (or more modern REL formats) fixed this problem by effectively storing the entire expression in the REL file. So, DRI tools won't understand that extension since it was invented after they were created. I'm not sure if these extension came from MicroSoft in the MS-DOS era or if they were created by some outside group and might not even be "standard".

nockieboy
December 17th, 2017, 05:32 AM
Would this work as an alternative?



LD DE,serABuf ; Get serABuf value
LD A,SER_BUFSIZE ; Get size of buffer into accumulator
ADD A,E ; Add the LSB of serABuf to get size
LD E,A ; Store it back in E

; DE is now serABuf+SER_BUFSIZE (with no carry - but it's the LSB we're interested in anyway)

LD A,L ; Get LSB of buffer pointer
CP E ; Check it's within buffer

Although - what happens if (having been placed in the appropriate place in memory) the buffer straddles a page boundary? Checking just the LSB of the pointer and buffer end will return false results in that situation, so I will have to modify this code to do a full 16-bit check against serABuf+SER_BUFSIZE anyway.

nockieboy
December 17th, 2017, 05:37 AM
Yes, that is the least amount of change to code design. The assembler doesn't need to know the value on the first pass. It will still be relocatable, but is 16-bit instead of 8-bit, and LINK should take care of everything and the "LD A,(bufAend)" will get the fully-relocated (byte) value at runtime.

Ah okay - sounds like the best solution then.


I looked at the "ld80" that was referenced on the ZMAC web page. It does not appear to support SPR or PRL output formats - in which case it can't be used to link BNKBIOS3.SPR. So, fixing the code so that it is compatible with DRI REL tools looks to be the right approach.

So I'll need to run through LDRBIOS.ASM and convert it to 8080 mnemonics?

durgadas311
December 17th, 2017, 05:46 AM
Ah okay - sounds like the best solution then.



So I'll need to run through LDRBIOS.ASM and convert it to 8080 mnemonics?

No, you'll just have to use LINK.COM on CP/M in order to create the BNKBIOS3.SPR file. The next step will be GENCPM which has to be run on CP/M anyway, so not much difference.

durgadas311
December 17th, 2017, 05:51 AM
Although - what happens if (having been placed in the appropriate place in memory) the buffer straddles a page boundary? Checking just the LSB of the pointer and buffer end will return false results in that situation, so I will have to modify this code to do a full 16-bit check against serABuf+SER_BUFSIZE anyway.

Your check for buffer end is based on equal/not-equal. So, as long as the buffer is < 256 bytes in length, you won't have an issue with page boundaries (the 8-bit buffer end value is unique).

nockieboy
December 17th, 2017, 05:59 AM
Your check for buffer end is based on equal/not-equal. So, as long as the buffer is < 256 bytes in length, you won't have an issue with page boundaries (the 8-bit buffer end value is unique).

Ahhh okay, I missed that. :D

nockieboy
December 19th, 2017, 12:35 AM
Okay, had a day and a half break away from this (learning about ANSI terminal codes to apply some sort of formatting and colour to the console output) - now I'm back. :sleepy:

I just need to recap where I am with this and what I need to do next, before I get completely lost in CP/M source files... :shock:

This is what I understand to be the next steps (please correct me, it's bound to be wrong!):


I have an LDRBIOS.ASM file, with modified serial interrupts to sidestep the recent relocatable-byte issue, primarily geared towards getting a working CPMLDR.COM file working. I need to get this assembled using ZMAC to produce a LDRBIOS.REL file.
I need to modify a BIOSKRNL.ASM file with the code from LDRBIOS.ASM and compile it (using RMAC?) to produce a BIOS3.SPR file?
I need to create CPM3.SYS using GENCPM on the BIOS3.SPR file?

durgadas311
December 19th, 2017, 03:53 AM
For #1, yes that sounds correct.

For #2, assuming BIOSKRNL.ASM is a complete CP/M 3 Banked-memory BIOS (with CSEG/DSEG defining resident and banked portions of code and data), and assuming Zilog Mnemonics, you will need to produce a BIOSKRNL.REL using ZMAC, then on CP/M use LINK to produce BNKBIOS3.SPR from BIOSKRNL.REL. I'm assuming you will need to, at least, link in SCB.REL as we previously discussed. I think you need:


LINK BNKBIOS3=BIOSKRNL,SCB[B,OS,NR]

For #3, take a look at the section "System Generation" in the CP/M Plus "System Guide". The questions asked by GENCPM are fairly simple, as long as your BIOS doesn't defer too much allocation to GENCPM. This, of course, has to be run on CP/M. GENCPM will produce CPM3.SYS, which is a complete image of banked and resident portions of BDOS and BIOS. CPMLDR knows how to read that image and load it into memory, and run it. So, minimal content for a CP/M 3 disk (the way your are booting it) is CPMLDR.COM, CPM3.SYS, and CCP.COM. This is assuming you are going to start CP/M 3 from a running CP/M 2.2 instance.

Probably the trickiest part of #2 will be getting the right parts of the BIOS in CSEG (common/resident part) vs. DSEG (banked part). The easiest, but least efficient, is to just put it all in CSEG - provided that does not produce more than 16K of code when combined with RESBDOS3. But, to give you the largest possible TPA for programs, you'll want to move more code (and data) into DSEG. But that requires careful consideration of the context in which the code is run - and any requirements of the BDOS. The "System Guide" is pretty good about specifying whether code and data structures require common memory or a specific bank - and under what conditions. Each BIOS entry should be classified by how it is called (which bank is selected). It still requires keeping a clear head and thinking through the execution of the BIOS function and all the places that data is accessed (for example, the DPB is returned "by reference" and must be accessible from user programs as well as BNKBDOS, so it must reside in common memory).

nockieboy
December 19th, 2017, 11:29 AM
For #1, yes that sounds correct.

Okay, I've run ZMAC on the most recent version of LDRBIOS.ASM and got no errors (in fact no response at all!) In the /zout folder, there's quite a few files that have been created, however. Here's the .LST output and the .REL file:

42575

Haven't done anything else with it yet, but the next step is to see if I can get CPMLDR.COM created. Then I'll need to port the relevant code from LDRBIOS.ASM into BIOSKRNL.ASM. I haven't looked at that file yet (it's described as a template) but I'm guessing it'll have extra functions for banking etc. I was intending originally to just get a non-banked version of CP/M 3 up and running first, but am happy to go straight ahead and start writing bank-switching routines etc.


For #2, assuming BIOSKRNL.ASM is a complete CP/M 3 Banked-memory BIOS (with CSEG/DSEG defining resident and banked portions of code and data), and assuming Zilog Mnemonics, you will need to produce a BIOSKRNL.REL using ZMAC, then on CP/M use LINK to produce BNKBIOS3.SPR from BIOSKRNL.REL. I'm assuming you will need to, at least, link in SCB.REL as we previously discussed. I think you need:


LINK BNKBIOS3=BIOSKRNL,SCB[B,OS,NR]

Right. Hopefully I'll get some time to look at BIOSKRNL.ASM later in the week. Finally feel like I'm making a little progress though. :D I know next to nothing about LINK, however. Don't I need to specify a start address (i.e. 0100h) at some point - either in the ZMAC/RMAC assembly prior to producing the .REL files or whilst LINKing them in CP/M?


Probably the trickiest part of #2 will be getting the right parts of the BIOS in CSEG (common/resident part) vs. DSEG (banked part). The easiest, but least efficient, is to just put it all in CSEG - provided that does not produce more than 16K of code when combined with RESBDOS3. But, to give you the largest possible TPA for programs, you'll want to move more code (and data) into DSEG. But that requires careful consideration of the context in which the code is run - and any requirements of the BDOS. The "System Guide" is pretty good about specifying whether code and data structures require common memory or a specific bank - and under what conditions. Each BIOS entry should be classified by how it is called (which bank is selected). It still requires keeping a clear head and thinking through the execution of the BIOS function and all the places that data is accessed (for example, the DPB is returned "by reference" and must be accessible from user programs as well as BNKBDOS, so it must reside in common memory).

Righto. I can't really see it going past 16K, but I've been wrong before on this subject. So that's what CSEG and DSEG are for? Okay, well, assembling and linking a valid CPMLDR is my first task - will see if I get any errors trying to do that then I'll be back! :D

durgadas311
December 19th, 2017, 12:37 PM
I still see one more place that needs to be fixed in GETFROMCHARB, that still produces the unsupported REL components. See line 580 (as numbered by ZMAC) of the listing file.

Generally, use of CSEG/DSEG and ORG are mutually exclusive. The point of REL files, most of the time, is to let the linker decide the addresses. In most case, you'll break things by adding ORG statements to a file that's used as relocatable. The "OC" and "OS" linker options tell LINK certain defaults, such as ORG 0100H in the case of "OC".

LINK.COM will assemble the listed components in the order they appear on the command, and assign addresses accordingly. In this case, that is the desired behavior. The SPR files are also relocatable, albeit by "page" (256 byte) only. "SPR" == "System Page Relocatable". GENCPM will assemble the SPR files (RESBDOS3.SPR, BNKBDOS3.SPR, and BNKBIOS3.SPR) into an image and relocate addresses based on where they will be loaded into memory - by CPMLDR. So, both LINK and GENCPM will do relocation of the code, but for different purposes.

nockieboy
December 19th, 2017, 01:12 PM
I still see one more place that needs to be fixed in GETFROMCHARB, that still produces the unsupported REL components. See line 580 (as numbered by ZMAC) of the listing file.

Thanks durgadas311, I missed that! Okay, here's the output from LINK this time around:


A>LINK CPMLDR[L100]=CPMLDR,LDRBIOS
LINK 1.31

ABSOLUTE 0000
CODE SIZE 1B86 (0100-1C85)
DATA SIZE 0000
COMMON SIZE 0000
USE FACTOR 35

A>

CPMLDR.COM is 8K in size. Running it clears the screen and prints the message, "Preparing MMU..." with a CR & LF, then freezes the system. I presume this is normal as I don't have a CPM3.SYS or CPM3.COM file yet?

durgadas311
December 19th, 2017, 01:47 PM
If CPMLDR got to the point of looking for CPM3.SYS or CCP.COM, and did not find them, it should have spit a specific error message. Your BIOS prints several messages showing the progress of the initialization, so if only this one is seen it would suggest to me that the system crashed after enabling the MMU (last output to the MMU port clears the disable bit). Another possibility is that the LDRBIOS MMU initialization is not the same as what was in use when CP/M 2.2 loaded and ran LDRBIOS.COM - in which case enabling the MMU with a different mapping will "pull the rug out from under itself". Maybe make sure that the LDRBIOS is initializing the MMU correctly, given that it is running as a program inside CP/M 2.2. Also, keep in mind that the BIOS3 code will need to also understand the initial mapping, since that must be known as "bank 0" for the rest of it's lifetime.

Maybe the LDRBIOS should not initialize from scratch, but just use the values in 0055H-0059H. That will only work if the values stored in 0055H... are strictly kept in sync. You will still need to establish "bank 0" and "bank 1" for use in CP/M 3, and CPMLDR will need to load into "bank 0".

nockieboy
December 19th, 2017, 11:54 PM
If CPMLDR got to the point of looking for CPM3.SYS or CCP.COM, and did not find them, it should have spit a specific error message. Your BIOS prints several messages showing the progress of the initialization, so if only this one is seen it would suggest to me that the system crashed after enabling the MMU (last output to the MMU port clears the disable bit). Another possibility is that the LDRBIOS MMU initialization is not the same as what was in use when CP/M 2.2 loaded and ran LDRBIOS.COM - in which case enabling the MMU with a different mapping will "pull the rug out from under itself". Maybe make sure that the LDRBIOS is initializing the MMU correctly, given that it is running as a program inside CP/M 2.2. Also, keep in mind that the BIOS3 code will need to also understand the initial mapping, since that must be known as "bank 0" for the rest of it's lifetime.

Maybe the LDRBIOS should not initialize from scratch, but just use the values in 0055H-0059H. That will only work if the values stored in 0055H... are strictly kept in sync. You will still need to establish "bank 0" and "bank 1" for use in CP/M 3, and CPMLDR will need to load into "bank 0".

My bad. I didn't have time to think about the output last night, so should have held back on posting. Looked again this morning and yes, it was the MMU-mapping section of code causing the problem. The MMU was being disabled, then the areas re-mapped (to identical banks as they already were under CP/M 2.2) and the MMU enabled again. The issue was, as soon as the MMU was disabled, the rug was pulled (to use your excellent comparison) from under the code and it crashed.

I've updated the MMU code section to not disable the MMU and just set the new bank mappings 'on the fly'. I could (in theory) remove that section of code entirely, but as I have a custom-made 'BANK' command in CP/M 2.2, it's entirely possible the user may have messed around with the memory map before trying to load CP/M 3, so a reset-to-default is an important safety measure.

Here's the output I'm getting now when I run CPMLDR:


A>cpmldr
Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M BIOS 1.2.74 by J.Nock 2017
Based on original CP/M BIOS 1.0 by G.Searle 2007-13

CP/M 2.2 Copyright 1979 (c) by Digital Research

(lots of empty lines removed for readability)

CP/M V3.0 Loader
Copyright (C) 1982, Digital Resea[
▒"▒ ▒y▒ڥ2▒ ▒2▒ :▒ 2▒ {2▒ !" "▒ 9"@1▒!I ▒y▒2▒▒K!▒▒▒▒dڛ_^#V*▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒6 ▒▒▒▒< B ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒}▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒[[D▒▒▒I :▒▒�▒▒

▒y!▒ ▒4▒ ▒5~▒▒yµ5▒▒
▒6▒y▒ � ͒:▒ ▒▒▒▒!▒
▒▒▒Oͻ▒▒▒▒MD▒▒2 ▒>▒▒
BDOS ERR:
CPMLDR error: failed to read CPM3.SYS

EDIT:


Maybe the LDRBIOS should not initialize from scratch, but just use the values in 0055H-0059H. That will only work if the values stored in 0055H... are strictly kept in sync. You will still need to establish "bank 0" and "bank 1" for use in CP/M 3, and CPMLDR will need to load into "bank 0".

Yeah, I don't trust the values in 0055H-0059H at all. The BANK command is a little glitchy at the moment, albeit only in the way it reports the existing memory map - at CP/M 2.2 startup, the values are being overwritten by something (Area 0's value at 0055H should be 00h, but it's always something else - so something is overwriting it. I need to find a safer spot in memory to save these values.)

durgadas311
December 20th, 2017, 05:12 AM
OK, looks like things are working a lot better now. What you are seeing actually looks very familiar to me. I would see that sort of output when the loader would crash.

I see the signon message from CPMLDR, but am curious why the last few characters seem to be lost. The message in the source is:


189 signon:
190 db cr
191 db lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf
192 db lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf
193 db 'CP/M V3.0 Loader',cr,lf
194 db 'Copyright (C) 1982, Digital Research'
195 db cr,lf,'$'

So that explains the large number of blank lines - they are trying to "clear display" in a way independent of terminal type. But I'm wondering why the "rch" is missing off the end of the message. Is your posing a "screen shot" or an actual capture of the characters being output? Could some ESC codes have been output and caused the "rch" to be overwritten on the screen?

Anyway, if this is like what I also saw, the "BDOS ERR:" at the end is a red-herring. What would happen is that the crash would cause it to hit "conout" code somewhere, and start dumping random chunks of memory out to the console. Of course, you said that there is no CPM3.SYS file, so there should eventually be an error message - but that should read "CPMLDR error: failed to open CPM3.SYS" and not "failed to read". That being said, if there were a CPM3.SYS file but it was corrupted, and the "Display Load Map at Cold Boot" option was enabled, then the loader might dump garbage as the "load map" is actually stored as a block of text in CPM3.SYS. CPMLDR uses 0080H for the buffer to read the load map, and so if that buffer were not terminated ('$') but used in a call to BDOS function 9 then it would just keep outputting characters - overflowing into 0100H and that could eventually make it into the error messages. However, I don't think "failed to read" is the first text it hits in that scenario.

So, is there a file named CPM3.SYS that might not have valid contents? If CPM3.SYS does not exist, then we probably need to consider that the loader is crashing somehow, probably when trying to open the file. Could be some buffering (deblocking) issue, or maybe interrupts not working correctly.

Do you have any way to dump or examine memory at this point? Might be good to do an autopsy and see how far it got.

---
Regarding the memory mapping, you may want to work on hardening that. If a user can change memory mapping, you probably need to make sure you have a clean path back to normal. If warm-boot does not reset the mapping, then you run the risk of loading CPMLDR into an "invalid" mapping and then you either have to keep that mapping forever or crash. Is there a reason that a user-mapping needs to persist beyond a warm boot? In fact, it is even tricky for the user program to return to CP/M if it has altered the mapping and not restored it.

Also, for CP/M 3, user control over mapping is strictly verboten. At the very least it is "caveat emptor" (i.e. "You *will* shoot your eye out").

nockieboy
December 20th, 2017, 06:10 AM
Is your posing a "screen shot" or an actual capture of the characters being output? Could some ESC codes have been output and caused the "rch" to be overwritten on the screen?

It's a cut 'n' paste of the text in the terminal window - so about as accurate as it can get, I'm guessing. Below is an actual screenshot of the terminal window, for what it's worth.

42586


So, is there a file named CPM3.SYS that might not have valid contents?

No, unfortunately not. There WAS one on the drive, but I deleted it before linking the new CPMLDR file, so unless it's picking up the deleted file (which I highly doubt), then it's not reading any file, valid or otherwise.


Do you have any way to dump or examine memory at this point? Might be good to do an autopsy and see how far it got.

I have a memory viewer/editor I wrote myself in the monitor ROM, but it resides in area 0 (bottom 16K) so I can't switch it in and start examining anything lower than 4000h in RAM. Plus the fact I have to power off the SBC to restart it with this particular crash (I can't get back to the CP/M command line via soft or hard reset), none of the memory contents survive the restart unfortunately.

I know next to nothing about DDT - but perhaps I could use it to run CPMLDR and debug it?


Regarding the memory mapping, you may want to work on hardening that. If a user can change memory mapping, you probably need to make sure you have a clean path back to normal. If warm-boot does not reset the mapping, then you run the risk of loading CPMLDR into an "invalid" mapping and then you either have to keep that mapping forever or crash. Is there a reason that a user-mapping needs to persist beyond a warm boot? In fact, it is even tricky for the user program to return to CP/M if it has altered the mapping and not restored it.

Also, for CP/M 3, user control over mapping is strictly verboten. At the very least it is "caveat emptor" (i.e. "You *will* shoot your eye out").

I'll make it bullet-proof once CP/M 3 is up and running by removing the BANK command entirely. It only exists as an exercise in porting code from the monitor ROM to CP/M 2.2.

durgadas311
December 20th, 2017, 06:44 AM
It's a cut 'n' paste of the text in the terminal window - so about as accurate as it can get, I'm guessing. Below is an actual screenshot of the terminal window, for what it's worth.

42586


OK, so if the output stream did include ESC (screen control) codes, we might not be seeing the true output. Having that could help debug where it is crashing. I was wondering if there was any way to actually capture the output stream from the SIO.

Debugging this with DDT might be tricky. DDT runs under the (2.2) BDOS/BIOS, and once CPMLDR initializes it expects that 2.2 BDOS/BIOS to never be used again. Seems like console input would be a problem, at least, since the loader has redirected interrupts away from the 2.2 BIOS.

You might have to start debugging by modifying CPMLDR.ASM and print more progress messages. I can't think of any reason why CPMLDR would try to use a deleted file, but if we knew the result of the OPEN that would tell us more. Basically, try to determine where the crash is happening - or where the garbage output comes from.

nockieboy
December 20th, 2017, 07:37 AM
Okay well for giggles I just thought I'd copy in ANY old CPM3.SYS file (in this case, from the SIMH Altair emulator) and see what happens. Not sure this is very productive, but the errors are slightly different:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Resea[
▒"▒ ▒y▒ڥ2▒ ▒2▒ :▒ 2▒ {2▒ !" "▒ 9"@1▒!I ▒y▒2▒▒K!▒▒▒▒dڛ_^#V*▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒6 ▒▒▒▒< B ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒}▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒[[D▒▒▒I :▒▒�▒▒

▒y!▒ ▒4▒ ▒5~▒▒yµ5▒▒
▒6▒y▒ � ͒:▒ ▒▒▒▒!▒
▒▒▒Oͻ▒▒▒▒MD▒▒2 ▒>▒▒
BDOS ERR:
BNKBIOS3 SPR ED00 0A00
BNKBIOS3 SPR AD00 1300
RESBDOS3 SPR E700 0600
BNKBDOS3 SPR 7F00 2E00

57K TPA

CPMLDR error: failed to read CPM3.SYS

Didn't bother copying the blank space or prior messages re: MMU and SIO setup, nothing prior to the information above has changed from the previous attempt.

nockieboy
December 20th, 2017, 07:54 AM
Okay, not sure this is much more use but here goes - I've modified conout in LDRBIOS.ASM to ONLY output the hex value of every char sent to it to print to the terminal. I've run the new CPMLDR with this modification and below is the result:


A>cpmldr
0C507265706172696E67204D4D552E2E2E0D0A0C5365747469 6E67204D4D55206C6F636B20627974652E2E2E0D0A0C496E69 7469616C6973696E672053494F2E2E2E0D00C5A3830204D494 E49434F4D2049492043502F4D2042494F5320312E322E37342 06279204A2E4E6F636B20323031370D0A4261736564206F6E2 06F726967696E616C2043502F4D2042494F5320312E3020627 920472E536561726C6520323030372D31330D0A0D0A43502F4 D20322E3220436F70797269676874203139373920286329206 279204469676974616C2052657365617263680D0A0D0A0A0A0 A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A43502F4D2 056332E30204C6F616465720D0A436F7079726967687420284 32920313938322C204469676974616C600F600F04410D0F5B0 FBB11030057EFED0D13010000000000000000000000000000E B22DA2020EB79FE0EDAA50232DD20AF32B220202020203AD92 0202020202032B92020202020207B32B520202020202100002 22020202020200422DC2020202020203922400331920321492 0E579FE32D2CA024B21DC02C3CF02DE64DA9B075F160019195 E23562ADA202020EBE9E803E803BB03E803E803E803E803E80 3E803DF03E803E803E803FB081220182020202020202020E80 3E803E803E80336202020E803E803E803E8033C20202042202 02020202020E803E803E803E803E803E803E803E803E803E80 3E803E803E803E803E803E803E803E803E803E803E803E803E 8037D02C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C 7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7C 7C7C7C7C7C7C7C7C7C7C7C7600F600F600F00300D0F5B0F9D0 30303DB038E034920202020203AEE03B7C29E03C5CD0C0BC17 921D52020202020FE7FC834FE20D0357EB7C879FE08C2B5033 5C9FE0AC03600C979FE202020C292030E20CD92033AD520E60 7C2C103C921D620200ABEC803C54FCDBB03C1C3CF03EB4D44C 3CF03322004C93E01C3E503000D0A42444F53204552523A200 D0A20424E4B42494F533320535052202045443030202030413 0300D0A20424E4B42494F53332053505220204144303020203 13330300D0A2052455342444F5333205350522020453730302 020303630300D0A20424E4B42444F533320535052202037463 0302020324530300D0A200A0D2035374B205450410A0D0D0A4 3504D4C4452206572726F723A20206661696C656420746F207 26561642043504D332E5359530D0A

So this will likely match up in some way to the previous log I posted (still with the random CPM3.SYS file present), but this is about as complete a capture I can get of the output from CPMLDR (although it's not exactly readable.) I'm hoping this will be of some help? :confused:

durgadas311
December 20th, 2017, 11:57 AM
I think this is helpful. I looked at the output data along side a pristine copy of CPMLDR (assuming your CPMLDR.REL was created from the same source I have). BTW, there appears to be some hiccup in the output, there are an odd number hex digits which I wouldn't expect. I think I found where something got dropped, and worked around it. Anyway...

There appears to be corruption at the end of the CPMLDR "signon" message, such that the terminating '$' is not seen (the last part of the message is overwritten). This essentially then does a memory dump of that part of CPMLDR, which is convenient. Assuming your console output never alters the data (i.e. there is no post-processing of characters after CP/M prints them), it appears that something corrupted CPMLDR.COM. Mostly it seems there are "blanks" (0x20) *inserted* in places they should not be. One thought is that whatever you use to transfer files into the CP/M system may not be "binary safe" and is doing something odd when it sees certain bit patterns. Another possible cause is that you are using PIP to copy CPMLDR.COM and not using the "O" option to tell it to copy binary data. Unfortunately, I can't tell how much of the corruption was done when trying to run the corrupted code and how much is original in CPMLDR.COM. But, those are some places to look. I always use the "[OV]" flags for PIP when copying non-text files. If neither of these could be the cause, we'll have to start looking at your CPMLDR.REL to see if it is valid.

durgadas311
December 20th, 2017, 12:26 PM
I noticed one more thing. CPMLDR uses a tiny stack, and the bulk of the stack space is provided by the BDOS when it is called. This stack resides immediately after the signon message, and the signon message is not printed until after the BIOS cold boot call. So, if the BIOS cold boot uses "too much" stack, it will corrupt the signon message. That doesn't explain the other corruption, but is probably something to fix straight-away. Probably have the BIOS cold boot use it's own stack - which could probably co-reside with the disk buffers (unless disk I/O is done during cold start).

durgadas311
December 20th, 2017, 04:57 PM
I just realized what the "inserted blanks" are from. This is simply tab-expansion being done by the BDOS. The places where I see a string of blanks are places where there is a 0x09 (TAB character) in the code. So, I think the only problem is the stack overflow happening in LDRBIOS cold boot.

nockieboy
December 21st, 2017, 12:23 AM
No, wasn't using PIP at all.

Okay, I've made a new CPMLDR with a stack of 128 bytes (should be enough!) for the cold boot. Here's a précis of the changes I've made to the LDRBIOS.ASM file:


;================================================= ===============================================
; Cold boot
;================================================= ===============================================
boot: ; Must return to loader when finished!
DI ; Disable interrupts.

; Set up stack
LD HL,STACK ; Load stack into HL
LD SP,HL ; Initialise the stack pointer

; Set up the memory map as follows:
.... etc

Then, at the end of the file:


; Define cold-boot stack size to avoid stack overflow
STACK: .ds 128

And here's what happens with CPMLDR:


A>cpmldr
0C507265706172696E67204D4D552E2E2E0D0A0C5365747469 6E67204D4D55206C6F636B20627974652E2E2E0D0A0C496E69 7469616C6973696E672053494F2E2E2E0D00C5A3830204D494 E49434F4D2049492043502F4D2042494F5320312E322E37342 06279204A2E4E6F636B20323031370D0A4261736564206F6E2 06F726967696E616C2043502F4D2042494F5320312E3020627 920472E536561726C6520323030372D31330D0A0D0A43502F4 D20322E3220436F70797269676874203139373920286329206 279204469676974616C2052657365617263680D0A
A>
Bdos Err On Q: Select

The Bdos Err message appeared when I pressed a key. Without the debug hex output in conout, this is what comes out:


Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M BIOS 1.2.74 by J.Nock 2017
Based on original CP/M BIOS 1.0 by G.Searle 2007-13

CP/M 2.2 Copyright 1979 (c) by Digital Research

A>

Whenever I touch a key, the terminal is cleared and the above output appears again. There is a brief pause before the A> prompt appears, so it seems to me the CCP is loading but there's a problem with the serial interrupts now? To my untrained and inexperienced mind, this makes sense as it's loading the (random) CPM3.SYS file, in which I have no idea how the BIOS is configured, causing the crash/reset every time the serial interrupt is triggered. Does that sound about right?

daver2
December 21st, 2017, 12:46 AM
Isn't your stack now zero bytes in length?

Remember, the stack grows 'downwards' in memory.

Dave

nockieboy
December 21st, 2017, 01:11 AM
Isn't your stack now zero bytes in length?

Remember, the stack grows 'downwards' in memory.

Dave

Darnit Dave, you're right! :D Schoolboy error!


; Set up stack
LD HL,STACK ; Load stack into HL
LD DE,128
ADD HL,DE
LD SP,HL ; Initialise the stack pointer

That should work, shouldn't it?

Output from CPMLDR is now:


A>cpmldr
Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M BIOS 1.2.74 by J.Nock 2017
Based on original CP/M BIOS 1.0 by G.Searle 2007-13

CP/M 2.2 Copyright 1979 (c) by Digital Research
;

... and it does nothing when I press keys now.

daver2
December 21st, 2017, 02:10 AM
Two steps forwards and one step back...

At least you now have a valid stack (well, assuming it is mapped into the memory area under all circumstances).

Dave

durgadas311
December 21st, 2017, 04:29 AM
OK, well maybe I should have been more specific. Cold boot needs it's own stack, but a stack is already in-use when cold boot is called - and cold boot must return to that stack and address. By changing to a new stack without saving/restoring the old, you have ensured that it will crash when cold boot hits the RET instruction (stack underrun). What you need is:


--- ldrbios.asm 2017-12-17 03:29:38.952933589 -0600
+++ ldrbios.asm.new 2017-12-21 07:25:29.406343693 -0600
@@ -239,6 +239,8 @@
;================================================= ===============================================
boot: ; Must return to loader when finished!
DI ; Disable interrupts.
+ LD (savestk),SP
+ LD SP,stack

; Set up the memory map as follows:
; Area 0 - Bank 0 (RAM)
@@ -350,6 +352,7 @@
LD (serBInPtr),HL
LD (serBRdPtr),HL

+ LD SP,(savestk)
IM 2
EI ; Enable interrupts

@@ -1115,6 +1118,8 @@
.db 0
.dw 0
hstbuf: .ds 512 ;host buffer
+stack: .ds 0
+savestk: .ds 2

serABuf: .ds SER_BUFSIZE ; SIO A Serial buffer
serAInPtr .DW 00h

This patch uses the disk buffer "hstbuf" as the stack, which should be OK since no disk I/O is done during cold boot in the loader.

nockieboy
December 21st, 2017, 04:43 AM
Ah, sorry - I'm inexperienced when it comes to assembly. :(

Okay, here's the output from CPMLDR now:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR ED00 0A00
BNKBIOS3 SPR AD00 1300
RESBDOS3 SPR E700 0600
BNKBDOS3 SPR 7F00 2E00

57K TPA

CPMLDR error: failed to read CPM3.SYS

A warm-reset returns me to the B> prompt, where I can't type anything, likely because the serial interrupts are not configured for my hardware in CPM3.SYS? But with the CPMLDR error, it appears not to be reading that file...?

daver2
December 21st, 2017, 04:56 AM
The source code for CPMLDR.ASM is here http://www.classiccmp.org/cpmarchives/cpm/Software/rlee/D/DIGITAL%20RESEARCH/CPM_3-0/SOURCES/CPMLDR.ASM.

It would appear that CPM3.SYS has been found (otherwise the error would have indicated an 'open' error, but that the read of CPM3.SYS failed for some reason.

When CPMLDR.ASM reports an error, it disables the interrupts (DI) and halts (HLT); so that is completely end of go!

You could consider modifying CPMLDR.ASM yourself and add better error reporting (e.g. Which BDOS function actually failed and what the error code actually was. This might give you further clues as to where to look next.

Dave

daver2
December 21st, 2017, 05:10 AM
It looks like that the first record of CPM3.SYS is read into the disk buffer and 6 bytes copied to local storage for later use.

The next record is then read into the disk buffer and the string message it contains printed out (presumably some sort of sign-on message.

I assume one of these two disk reads is failing before it even starts the main loading of CPM3.SYS...

Dave

durgadas311
December 21st, 2017, 05:21 AM
As I understand it, this CPM3.SYS file you are using is actually not valid for this platform, so we know it won't work. It did print the load map, so it read that much of the file. CPMLDR prints this error message for *any* return from BDOS READ other than success - which means EOF is also an error. It's possible that the data in the file has confused the loader and it tries to read more from the file than exists. I'm assuming you are not actually getting a disk read error. Also, it's entirely possible that the loader did actually load the CPM3.SYS image, but since it is not valid for this platform it crashed and ended up printing this message "accidentally". Seems highly improbable, but I've seen such improbable things before.

Might be time to create a CPM3.SYS that you know is good. Maybe make a dummy CP/M 3 BIOS that just prints a message and "DI; HLT" in the cold boot, then build a CPM3.SYS to use for testing the loader.

nockieboy
December 21st, 2017, 05:28 AM
As I understand it, this CPM3.SYS file you are using is actually not valid for this platform, so we know it won't work.

Yes indeed, I'm just using any old CPM3.SYS file to see if CPMLDR is working properly, fully expecting it to crash when it tries to execute CPM3.SYS.


Might be time to create a CPM3.SYS that you know is good. Maybe make a dummy CP/M 3 BIOS that just prints a message and "DI; HLT" in the cold boot, then build a CPM3.SYS to use for testing the loader.

Exactly what I was thinking. I've got a BIOSKRNL.ASM file - I need to modify this and turn it into a fully-fledged BIOS for CP/M 3, based off of what we've done so far with the LDRBIOS? But I also need to write a BNKBIOS3.ASM file for my hardware, too?

durgadas311
December 21st, 2017, 05:35 AM
You can keep the BIOS in a single file. Use CSEG and DSEG to identify the resident and banked portions, respectively. When you link the "BNKBIOS3.SPR" file, you use the [B,OS,NR] LINK options which setup the SPR with the information needed by GENCPM. (technically, only "B" may be needed). But for confirming that the loader works, I'd write a painfully simple BIOS that does nothing but print a message and halt. That way, you don't start to wonder whether your CP/M 3 BIOS is failing or it is the loader.

daver2
December 21st, 2017, 05:39 AM
I didn't see the load map printed, so it obviously got past the point I thought it had stopped at. That will teach me to read a few more posts backwards before replying!

Dave

nockieboy
December 21st, 2017, 06:09 AM
You can keep the BIOS in a single file. Use CSEG and DSEG to identify the resident and banked portions, respectively. When you link the "BNKBIOS3.SPR" file, you use the [B,OS,NR] LINK options which setup the SPR with the information needed by GENCPM. (technically, only "B" may be needed). But for confirming that the loader works, I'd write a painfully simple BIOS that does nothing but print a message and halt. That way, you don't start to wonder whether your CP/M 3 BIOS is failing or it is the loader.

Okay. Sorry durgadas311, you're going to have to be a little more explicit with me - remember, I've never done this before and feel like I'm fumbling around for the next step. :rolleyes: So I still need to create a BIOS, whether it be a simple test function or a fully-fledged BIOS that handles the MMU and banking, in the form of a BNKBIOS3.ASM file. I need to compile this with ZMAC (yes?) to produce a .REL file, which I can then use LINK on to create the .SPR file? Is that even vaguely right?


I didn't see the load map printed, so it obviously got past the point I thought it had stopped at. That will teach me to read a few more posts backwards before replying!

Dave

Haha! No worries, Dave! :D This part of the chat is progressing quite quickly as I've got a few hours spare to focus on the issue! :)

durgadas311
December 21st, 2017, 07:12 AM
OK, here's what I was thinking of. I assembled this with ZMAC but didn't do anything more with it.

42593

So, you should then take DMYBIOS3.REL and create BNKBIOS3.SPR using:

LINK BNKBIOS3=DMYBIOS3[B,OS,NR]

And then put this SPR and RESBDOS3.SPR and BNKBDOS3.SPR on the disk and run GENCPM. Unless I've missed some obscure dependency in GENCPM, that should go without error (I'm trying to think how GENCPM does optional configuration of buffers... it might need some references to internal structures).

nockieboy
December 21st, 2017, 07:54 AM
So, you should then take DMYBIOS3.REL and create BNKBIOS3.SPR using:

LINK BNKBIOS3=DMYBIOS3[B,OS,NR]

Okie dokie - here's the output from LINK:


A>LINK BNKBIOS3=DMYBIOS3[B,OS,NR]
LINK 1.31

ABSOLUTE 0000
CODE SIZE 00C4 (0000-00C3)
DATA SIZE 0000
COMMON SIZE 0000
USE FACTOR 02

A>


And then put this SPR and RESBDOS3.SPR and BNKBDOS3.SPR on the disk and run GENCPM. Unless I've missed some obscure dependency in GENCPM, that should go without error (I'm trying to think how GENCPM does optional configuration of buffers... it might need some references to internal structures).

It errors out - here's how far I got with GENCPM:


A>gencpm


CP/M 3.0 System Generation
Copyright (C) 1982, Digital Research

Default entries are shown in (parens).
Default base is Hex, precede entry with # for decimal

Create a new GENCPM.DAT file (N) ? Y

Display Load Map at Cold Boot (Y) ? Y

Number of console columns (#80) ?
Number of lines in console page (#24) ?
Backspace echoes erased character (N) ?
Rubout echoes erased character (Y) ?

Initial default drive (A:) ?

Top page of memory (FF) ?
Bank switched memory (Y) ? N

Double allocation vectors (Y) ?

Accept new system definition (Y) ?

ERROR: Unable to open: BIOS3 .SPR

A>

Of course - there is no BIOS3.SPR, and I selected non-banked CP/M.

Here's what happens if I just select default options:


A>gencpm


CP/M 3.0 System Generation
Copyright (C) 1982, Digital Research

Default entries are shown in (parens).
Default base is Hex, precede entry with # for decimal

Create a new GENCPM.DAT file (N) ?

Display Load Map at Cold Boot (Y) ?

Number of console columns (#80) ?
Number of lines in console page (#24) ?
Backspace echoes erased character (N) ?
Rubout echoes erased character (Y) ?

Initial default drive (A:) ?

Top page of memory (FF) ?
Bank switched memory (Y) ?
Common memory base page (C0) ?

Long error messages (Y) ?

Accept new system definition (Y) ?

BNKBIOS3 SPR FF00H 0100H
BNKBIOS3 SPR C000H 0000H
RESBDOS3 SPR F900H 0600H
BNKBDOS3 SPR 9200H 2E00H

*** CP/M 3.0 SYSTEM GENERATION DONE ***
A>cpmldr

<screen clears etc>

You've reached CP/M 3 BIOS...

daver2
December 21st, 2017, 08:14 AM
It did what it was supposed to do (i.e. print the message out that you got).

Dave

nockieboy
December 21st, 2017, 08:22 AM
It did what it was supposed to do (i.e. print the message out that you got).

Dave

Yep, it sure did - working on the BIOS now...

nockieboy
December 21st, 2017, 09:05 AM
Okay, slight confusion with the BIOS for CP/M 3:

I've got an interrupt-driven function that reads chars from the SIO port into a buffer, as per previous uploads of my CP/M 2.2 BIOS. How should I write CONST, CONIN, CONOST in the CP/M 3 BIOS to be compatible? It appears from the CONST and CONOST functions that CP/M 3 tries to handle retrieving chars from the SIO and sending them to it itself? Surely CONST and CONOST aren't needed as I'm using an interrupt-driven method to fill a buffer - all I need to do is write CONST and CONOST to return 0FFh in the accumulator if those buffers are non-zero?

durgadas311
December 21st, 2017, 09:48 AM
When using interrupt driven console input, you'll need to return that status of the input buffer for CONST. CONOST is not dependent on interrupts so you'd just check the SIO Tx status. These routines need to return meaningful results. I guess that is what you were saying.

You might want to consider whether you really need interrupt driven console input. Maybe you need it for the debug serial port, so it's an easy addition. But for minimal implementation you could just use standard SIO input. But since you've already got the routine written, it probably doesn't make sense to remove it - unless it is causing problems.

Keep in mind that the DPH and DPB structures change for CP/M 3. Also, although it represents more code change, you can let the BDOS do the deblocking since it has more context. The BIOS routines then act only on physical sectors, which greatly simplifies the BIOS.

nockieboy
December 21st, 2017, 12:44 PM
When using interrupt driven console input, you'll need to return that status of the input buffer for CONST. CONOST is not dependent on interrupts so you'd just check the SIO Tx status. These routines need to return meaningful results. I guess that is what you were saying.

So would this be okay for CONOST?


;-----------------------------------------------------------------------------------------------
; Return console output status
;-----------------------------------------------------------------------------------------------
conost:
CALL CKSIOA ; Find out status of SIO A Tx
XOR A ; Clear accumulator
RET Z ; Tx is engaged, return zero in A
LD A,0FFh ; Tx is free, return FFh in A
RET

;-----------------------------------------------------------------------------------------------
CKSIOA
SUB A
OUT (SIOA_C),A
IN A,(SIOA_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
RRCA ; Rotates RX status into Carry Flag,
BIT 1,A ; Set Zero flag if still transmitting character
RET



Keep in mind that the DPH and DPB structures change for CP/M 3. Also, although it represents more code change, you can let the BDOS do the deblocking since it has more context. The BIOS routines then act only on physical sectors, which greatly simplifies the BIOS.

Err okay. Aren't the DPH and DPB structures specified in LDRBIOS.ASM that you wrote/edited in a format compatible with CP/M 3 though? Couldn't I just copy those over?

durgadas311
December 21st, 2017, 01:49 PM
For CONOST, you can't do a "XOR A" before the "RET Z" as the XOR will destroy the Zero status from CKSIOA. I think just make it simpler by:


;-----------------------------------------------------------------------------------------------
; Return console output status
;-----------------------------------------------------------------------------------------------
conost:
CALL CKSIOA ; Find out status of SIO A Tx
RET Z ; Tx is engaged, return zero in A
LD A,0FFh ; Tx is free, return FFh in A
RET

;-----------------------------------------------------------------------------------------------
CKSIOA
SUB A
OUT (SIOA_C),A
IN A,(SIOA_C) ; Status byte D2=TX Buff Empty, D0=RX char ready
AND A,$04 ; Zero if still transmitting character
RET

Regarding the DPH and DPB, yes the sizes of those structures are the same as in LDRBIOS. However, somethings may need to be different. If you are going to let BDOS do the deblocking, then the PSH/PSM bytes at the end of the DPB need to be set appropriately (If you don't set PSH/PSM then you can set the dtabcb field of the DPH to 0ffffh). The DPH will require some different values, too, since CPMLDR basically uses the DPH only to get the DPB and dirbcb. You'll need to setup a separate BCB and buffers for dtabcb, and you probably want to have at least two buffers in each BCB. You'll also need to, at least, disable directory hashing - although it would help since your disks have large directories. The BCBs must be in a "list head" format as described for banked systems in the System Guide. The BCB structures can be in banked memory, and the directory buffers also, but the data buffers must be in common memory (since your hardware does not support direct bank-to-bank moves). ALV and CSV buffers can be in banked memory (DSEG).

nockieboy
December 22nd, 2017, 12:59 AM
For CONOST, you can't do a "XOR A" before the "RET Z" as the XOR will destroy the Zero status from CKSIOA.

Ah yes, you're right (of course) - I forgot (or didn't know, to be honest) that XOR messes with the flags. It's little details like this that makes assembly such a challenging and rewarding language to learn!


I think just make it simpler by:

Marvellous - thanks durgadas311. That's a nice improvement on what I had! :D


Regarding the DPH and DPB, yes the sizes of those structures are the same as in LDRBIOS. However, somethings may need to be different. If you are going to let BDOS do the deblocking, then the PSH/PSM bytes at the end of the DPB need to be set appropriately (If you don't set PSH/PSM then you can set the dtabcb field of the DPH to 0ffffh). The DPH will require some different values, too, since CPMLDR basically uses the DPH only to get the DPB and dirbcb. You'll need to setup a separate BCB and buffers for dtabcb, and you probably want to have at least two buffers in each BCB. You'll also need to, at least, disable directory hashing - although it would help since your disks have large directories. The BCBs must be in a "list head" format as described for banked systems in the System Guide. The BCB structures can be in banked memory, and the directory buffers also, but the data buffers must be in common memory (since your hardware does not support direct bank-to-bank moves). ALV and CSV buffers can be in banked memory (DSEG).

:huh: I'm assuming that the CP/M 3 System Guide will explain how to do all that in explicit steps suitable for an idiot like me with the most basic of assembly knowledge (and even less of CP/M) to follow? If not, I could be driving you round the bend with stupid questions in the future, like...:


Is there any reason I wouldn't want the BDOS doing the deblocking?
Directory hashing sounds like a good thing - am I going to have to acquire a god-like level of knowledge of CP/M disk routines to enable it? Is it easy to disable in the first instance?
If I can get conout,conin,const,conost working in BNKBIOS3.ASM, would that be enough to get me to the CP/M 3 CCP? (So long as I don't try accessing the disk?)

... and manyn+1 more. ;)

EDIT:

Like, what to do with the boot: function for cold booting in BNKBIOS3?

I've got the example (MYBIOS3) which just halts the Z80 after printing the sign-on message, but I'm presuming that at the end of the boot: function I need to pass execution over to the CCP somehow. I've tried the following:


JP ccp

... where CCP was set to 0100h, but (perhaps obviously), that just seems to execute CPMLDR again. The CPM 3 System Guide states that the BIOS loads the CCP into TPA at system cold and warm start. How does it do this? I've taken a look at BIOSKRNL.ASM which is, apparently, a template provided by DRI and its boot: function looks like this:


boot:
lxi sp,boot$stack
mvi c,15 ; initialize all 16 character devices
c$init$loop:
push b ! call ?cinit ! pop b
dcr c ! jp c$init$loop

call ?init ; perform any additional system initialization
; and print signon message

lxi b,16*256+0 ! lxi h,@dtbl ; init all 16 logical disk drives
d$init$loop:
push b ; save remaining count and abs drive
mov e,m ! inx h ! mov d,m ! inx h ; grab @drv entry
mov a,e ! ora d ! jz d$init$next ; if null, no drive
push h ; save @drv pointer
xchg ; XDPH address in <HL>
dcx h ! dcx h ! mov a,m ! sta @RDRV ; get relative drive code
mov a,c ! sta @ADRV ; get absolute drive code
dcx h ; point to init pointer
mov d,m ! dcx h ! mov e,m ; get init pointer
xchg ! call ipchl ; call init routine
pop h ; recover @drv pointer
d$init$next:
pop b ; recover counter and drive #
inr c ! dcr b ! jnz d$init$loop ; and loop for each drive
jmp boot$1

cseg ; following in resident memory

boot$1:
call set$jumps
call ?ldccp ; fetch CCP for first time
jmp ccp

Now ZMAC throws a fit if I try to use external references like ?init or any of the extrn or public keywords - it completely falls over trying to assemble the BIOSKRNL.ASM file. So I started creating a BNKBIOS3.ASM file based on MYBIOS3.ASM (as that works at least as far as printing the sign-on message!) I've included all the aforementioned files below, but suffice to say that my BNKBIOS3.ASM is not printing anything, yet functionally it is no different from MYBIOS3 except for setting a few serial buffer values to zero before printing the first message. I've commented-out the SIO setup currently as it's already set up in CP/M 2.2.

42602

There's clearly something very obviously wrong with my BNKBIOS3.ASM file - what I'm expecting from it is that when I run CPMLDR, I should at least see the message "BNKBIOS3:" printed in the terminal.

durgadas311
December 22nd, 2017, 05:38 AM
I spent a little time fleshing-out a possible CP/M 3 BIOS for you. NOTE: there are some features missing and so it certain will not work as-is. At the very least you'll need to add code to read the CCP.COM file into bank 1. One clue for that: the SCB "@mxtpa" parameter should be the entry point for the BDOS, so you can make BDOS calls.

Hashing is also not setup, as you'll need to do some sort of allocation of space for that or else add 16K of zero-bytes to the size of the BNKBIOS3.SPR file.

See if you can get something from this, in combination with the System Guide. Again, a very rough draft...

42605

nockieboy
December 22nd, 2017, 10:19 AM
I spent a little time fleshing-out a possible CP/M 3 BIOS for you. NOTE: there are some features missing and so it certain will not work as-is. At the very least you'll need to add code to read the CCP.COM file into bank 1. One clue for that: the SCB "@mxtpa" parameter should be the entry point for the BDOS, so you can make BDOS calls.

Hashing is also not setup, as you'll need to do some sort of allocation of space for that or else add 16K of zero-bytes to the size of the BNKBIOS3.SPR file.

See if you can get something from this, in combination with the System Guide. Again, a very rough draft...

42605

Thanks very much durgadas311 - sounds like it's a starter for ten! If I'm not back on here before Christmas Day, I just want to wish you and Dave (and your families) a very merry Christmas and thanks for the help. :)

daver2
December 22nd, 2017, 10:31 AM
Thanks very much - and the same to you and your family.

I am 'slowly' packing things away for Christmas Day - so various bits of the insides of PDP-8's, PDP-11s and other machines are going away until 2018...

Regards,

Dave

durgadas311
December 22nd, 2017, 12:07 PM
Thank you! Merry Christmas to all.

I got the snow shoveling done, but the cat won't pull the sleigh or clear the ice rink.

42607

nockieboy
December 23rd, 2017, 02:41 PM
I spent a little time fleshing-out a possible CP/M 3 BIOS for you. NOTE: there are some features missing and so it certain will not work as-is. At the very least you'll need to add code to read the CCP.COM file into bank 1. One clue for that: the SCB "@mxtpa" parameter should be the entry point for the BDOS, so you can make BDOS calls.

Okay, so with 5 minutes spare tonight and with the assistance of some alcohol, I've put the following together as an attempt to load CCP.COM. This would go at the end of the boot: function:


open$func equ 15 ;open function

boot:
... all the existing boot stuff, then:
LD C,open$func ; Open the CCP.COM file
LD DE,ccpfcb
CALL @mxtpa
JP 0100H

ccpfcb:
db 0,'CCP COM',0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0

Am I heading in the right direction with that, or is it a complete stab in the dark?


I am 'slowly' packing things away for Christmas Day - so various bits of the insides of PDP-8's, PDP-11s and other machines are going away until 2018...

The earliest computer I had back in the day was a broken ZX81 donated to me by a friend of my mum - I could keep it if I could fix it. I was still at primary school and unable to fix it (but reading the manual ignited my interest in programming which, a Christmas later, I was able to cut my teeth on an Amstrad CPC464.) I was completely unaware of things like the PDPs and NASCOMs and 70's computing..


I got the snow shoveling done, but the cat won't pull the sleigh or clear the ice rink.

You have SNOW?!?! Wow! We're lucky here to get snow in February-March these days - and even then it's just a dusting that brings the country grinding to a halt. :rolleyes:

durgadas311
December 23rd, 2017, 05:56 PM
Here's what I have in my CP/M 3 BIOSes (this is Intel mnemonics of course):


139 lxi d,ccp$com
140 mvi c,15 ;open file
141 call bdose
142 inr a
143 jz noccp
144 xra a
145 sta fcb$nr
146 lxi d,ccp
147 mvi c,26 ;set DMA address
148 call bdose
149 mvi e,128 ;read upto 128 records (16K)
150 mvi c,44 ;set multi-sector count
151 call bdose
152 lxi d,ccp$com
153 mvi c,20 ;read record(s)
154 call bdose

And for "bdose" I use:


115 bdose: lhld @mxtpa
116 pchl

I think the premise is that the BDOS will always read into "Bank 1", and that's also where it needs to be. "ccp$com" is the FCB for CCP.COM, and "fcb$nr" is the next record field of that FCB. "ccp" is defined as 0100H, which is also where you jump to start the CCP. "nocpp" prints an error message and then dies (DI + HLT). The CCP was often saved into bank 0 to avoid having to re-read the disk on every warm boot, but with a flash drive it's probably not as objectionable.

Also note, that both cold and warm boot need to this, and typically it is the last thing those entries do.

Yeah, we got a little snow, and it is likely to stay around since the temps will be well below freezing for the next week or more. I spent a lot of time in the "Pacific NorthWest", which my Brit friends tell me is a lot like UK, but I'm happy these days in Minne-freezing-sota.

nockieboy
December 24th, 2017, 01:48 AM
Here's what I have in my CP/M 3 BIOSes (this is Intel mnemonics of course):


139 lxi d,ccp$com
140 mvi c,15 ;open file
141 call bdose
142 inr a
143 jz noccp
144 xra a
145 sta fcb$nr
146 lxi d,ccp
147 mvi c,26 ;set DMA address
148 call bdose
149 mvi e,128 ;read upto 128 records (16K)
150 mvi c,44 ;set multi-sector count
151 call bdose
152 lxi d,ccp$com
153 mvi c,20 ;read record(s)
154 call bdose

And for "bdose" I use:


115 bdose: lhld @mxtpa
116 pchl

I think the premise is that the BDOS will always read into "Bank 1", and that's also where it needs to be. "ccp$com" is the FCB for CCP.COM, and "fcb$nr" is the next record field of that FCB. "ccp" is defined as 0100H, which is also where you jump to start the CCP. "nocpp" prints an error message and then dies (DI + HLT). The CCP was often saved into bank 0 to avoid having to re-read the disk on every warm boot, but with a flash drive it's probably not as objectionable.

Okay, a (likely stupid) question springs up:

You mention "fcb$nr" being the next record field of the CCP.COM FCB. I'm a little confused re: the terminology here; what is it, exactly? Do I need to modify my ccpfcb definition (current version below)?


ccpfcb: .DB 0,'CCP COM',0,0,0,0,0,0
.DW 0,0,0,0,0,0,0,0,0

fcb$nr: ??


Yeah, we got a little snow, and it is likely to stay around since the temps will be well below freezing for the next week or more. I spent a lot of time in the "Pacific NorthWest", which my Brit friends tell me is a lot like UK, but I'm happy these days in Minne-freezing-sota.

Not as far north-west as Vancouver by any chance? (Although that's Canada, eh?) :D A work colleague of mine retired out there a few years back - hasn't regretted it. They get loads of snow too! (I love the snow, if you haven't already guessed!) It's very temperate here - bit boring really. Makes for very grey and dreary Christmases.

durgadas311
December 24th, 2017, 03:55 AM
Here's the CCP FCB from the same code:


356 ccp$com db 1,'CCP COM',0,0,0,0
357 ds 16
358 fcb$nr db 0,0,0,0

I used to like to lay-out the FCB in a consistent fashion that reflected it's fields, to help make sure I was using it correctly and I allocated enough space for it. For example, the "ds 16" is the allocation map for the FCB, which is pretty much never used in a program.

One more thing to pay attention to (I think I left a comment in the code) is that you need to make sure both banks have "page 0" setup (jumps to BIOS and BDOS, plus anything else kept there). If your interrupt vector page is there, that also needs to be copied. Out of paranoia - or frustration with bugs - I would ensure Page 0 was reinitialized every warm boot, in addition to cold boot.

I lived all over the PNW: Portand, Seattle/Tacoma, Bellingham (less than an hour from Vancouver and right across the bay from Victoria, BC). There are some small pockets of sunshine in that region, so not all is the stereo-typical "rainy Seattle". Beautiful country though, sights you won't see in the UK. Vancouver is literally squeezed between mountains and the sea (Puget Sound, et al.). Like most of that area, the climate tends to be tempered by the ocean, so not the cold weather I see here (I'm looking at a -10F to +10F range the next 10 days). They get cold air from Alaska combined with moist air off the Pacific, which will vary between frigid rain and snow. Of course, your friend knows best actually living in Vancouver. Eh.

daver2
December 24th, 2017, 05:15 AM
If you are using a Z80 CPU (and you are) you don't have to have your interrupt vectors in banked memory - you can place them anywhere (e.g. In common memory) by initialising the Z80s 'I' register accordingly. If all your interrupts are used by the BIOS, you could place your interrupt vectors there (depending upon which interrupt mode you are operating under of course).

This may save a headache...

Dave

nockieboy
December 24th, 2017, 05:37 AM
If you are using a Z80 CPU (and you are) you don't have to have your interrupt vectors in banked memory - you can place them anywhere (e.g. In common memory) by initialising the Z80s 'I' register accordingly. If all your interrupts are used by the BIOS, you could place your interrupt vectors there (depending upon which interrupt mode you are operating under of course).

This may save a headache...

Dave

That sounds like a cunning plan! I'm using interrupt mode 2 and, as far as I'm aware, only the BIOS will be using interrupts (the new CP/M 3 BIOS doesn't use them to poll the SIO like the CP/M 2.2 one did, so that just leaves communication from the ATmega328, which isn't an issue at the moment until I get CP/M 3 up and running.)

So, I've moved the INTVEC bytes into CSEG:


INTVEC: .DW serialInt ; Location of Z80 IM2 interrupt vector(s)

And am updating the interrupt vector as follows:


; Interrupt vector relocated to safe memory
LD HL,INTVEC
LD A,H ; high byte of INTVEC
LD I,A

But ahh... just realised, I'm going to have to set the proper interrupt vector low-byte address in the SIO too. Sooo...


IVL: .DB INTVEC+1 ; Interrupt vector LOW byte

... just after the INTVEC definition above should sort that, as I see durgadas311 has done an excellent job of using IVL to set the interrupt vector in the SIO setup table.

Okay, final silly question of the day - how do I assemble this file and link SCB.ASM into it? I'm still not familiar enough with ZMAC/LINK etc to really understand what I should be doing with these things? I've attached BIOS3 and the version of SCB.ASM I have in the zip below. Not sure the SCB is correct as-is?

42618

durgadas311
December 24th, 2017, 06:36 AM
You can create SCB.REL from SCB.ASM using RMAC, possibly zmac. Nothing special there, just need to get SCB.REL.

For IVL, I think you'll need to do something different in order get around the REL file extensions used by zmac, as we ran into before. You may need to do something like


LD HL,INTVEC
LD A,L
LD (sioBi+XXX),A

Where "XXX" is the offset of the IVL byte in sioBi. This will need to be done first-off, before initializing the SIO.

I did not do a complete review of BIOS3.ASM, but one thing I noticed is that the setup of page 0 is not getting done. You need to setup the jumps at 0000H and 0005H, at least, before things will work. That setup is required in both (all) memory banks. This is needed on both warm and cold boots.

Also, I noticed that "conin" (etc) use the interrupt buffer - so you are still using interrupts for both the console and ATmega328(?) - or else there are changes needed for console input to work.

nockieboy
December 24th, 2017, 06:49 AM
You can create SCB.REL from SCB.ASM using RMAC, possibly zmac. Nothing special there, just need to get SCB.REL.

Ah okay, that's fine then. I guess I just need to link SCB.REL into BNKBIOS3?


A>LINK BNKBIOS3=BIOS3,SCB[B,OS,NR]

.. or something similar?


For IVL, I think you'll need to do something different in order get around the REL file extensions used by zmac, as we ran into before. You may need to do something like


LD HL,INTVEC
LD A,L
LD (sioBi+XXX),A

Where "XXX" is the offset of the IVL byte in sioBi. This will need to be done first-off, before initializing the SIO.

Thought it was too easy. :rolleyes: Have moved the below code before the SIO set up code in boot:


; Interrupt vector relocated to safe memory
LD HL,INTVEC
LD A,H ; high byte of INTVEC
LD I,A
LD A,L
LD (sioBi+$07),A ; Set the interrupt low-byte vector in sioBi

I'm not quite counting on my fingers, but I'm hoping $07 is the correct offset to use?


sioBi: .db $00,$18 ; Ch RESET
.db $04,$C4 ; BAUD - CLK/64
.db $01,$18 ; INT on Rx
.db $02,IVL ; INT vector (LO)


I did not do a complete review of BIOS3.ASM, but one thing I noticed is that the setup of page 0 is not getting done. You need to setup the jumps at 0000H and 0005H, at least, before things will work. That setup is required in both (all) memory banks. This is needed on both warm and cold boots.

Yep, that's on my to-do list. :)


Also, I noticed that "conin" (etc) use the interrupt buffer - so you are still using interrupts for both the console and ATmega328(?) - or else there are changes needed for console input to work.

Ah, I missed that - I'll change it if I can so that it doesn't need the interrupt anymore. I don't really see the advantage of using the interrupt if CP/M polls the SIO itself routinely - it's not as if CP/M is a multi-tasking system.

Though, perhaps it would be easier to just leave the interrupts in there and modify the const:/conost: functions? Not sure which would be easiest/best.

durgadas311
December 24th, 2017, 07:16 AM
Yes, your LINK command looks correct. And the SIO interrupt vector also.

Regarding interrupts, it's kind of a personal choice. Console output doesn't change, just console input (and status).

nockieboy
December 24th, 2017, 07:43 AM
Thanks durgadas311! Have a good one! :)

nockieboy
December 26th, 2017, 01:49 AM
Hope everyone had a great Christmas day yesterday. :)

I had five minutes to spare this morning so I thought I'd try and build CPM3.SYS again using the new BIOS3.ASM and SCB.ASM. I've included the source files, ZMAC assembly output files (.REL and .LST) for BIOS3 and SCB in the zip file here for those following along at home: 42647

So - I've done some work on BIOS3.ASM to (hopefully) get it near working-order and thought I'd have a go at LINKing it with SCB as I haven't tried that yet. Assembled both BIOS3.ASM and SCB.ASM in ZMAC in Windows, then copied the .REL files over to the SBC's CP/M 2.2 operating system and LINKed them. Here's what I got:


A>LINK BNKBIOS3=BIOS3,SCB[B,OS,NR]
LINK 1.31
UNRECOGNIZED ITEM
UNRECOGNIZED ITEM
UNRECOGNIZED ITEM
UNRECOGNIZED ITEM
UNRECOGNIZED ITEM
UNRECOGNIZED ITEM

@SEC FE5C @MIN FE5B @DATE FE58 @HOUR FE5A
@BNKBF FE35 @AIVEC FE26 @CIVEC FE22 @ERMDE FE4B
@AOVEC FE28 @COVEC FE24 @LOVEC FE2A @MXTPA FE62
@FX FE43 @MEDIA FE54 @CRDMA FE3C @BFLGS FE57
@CRDSK FE3E @ERDSK FE51 @RESEL FE41 @USRCD FE44
@VINFO FE3F @MLTIO FE4A

ABSOLUTE 0000
CODE SIZE 0AA7 (0000-0AA6)
DATA SIZE 0C59 (0B00-1758)
COMMON SIZE 0000
USE FACTOR 14

A>

I'm not sure what the unrecognised items are..? I've had a scan through BIOS3.LST and SCB.LST and can't see any obvious error messages? Does LINK provide any sort of debug output file? I can't see anything in CP/M other than the BNKBIOS3.REL and .SPR files, but can't really read those in CP/M? BNKBIOS3.SPR is 8K in size, so it's not pre-allocating the hash buffers (which is expected behaviour.)

Anyhow - just thought I'd have a play and see if I could get a CPM3.SYS up and running with my new files, but failed (it appears!)

Merry Christmas,

Jon

durgadas311
December 26th, 2017, 04:19 AM
The "UNRECOGNIZED ITEM" is the error LINK gives for those relocatable expressions that RMAC (and LINK) does not support. Listing lines 253 and 269 are the culprits. It looks like you just didn't remove the "IVL" stuff after you changed the code to no longer need it. Probably you can ignore these error, or else remove the IVL stuff and recompile.

nockieboy
December 27th, 2017, 03:34 AM
The "UNRECOGNIZED ITEM" is the error LINK gives for those relocatable expressions that RMAC (and LINK) does not support. Listing lines 253 and 269 are the culprits. It looks like you just didn't remove the "IVL" stuff after you changed the code to no longer need it. Probably you can ignore these error, or else remove the IVL stuff and recompile.

Aha - yes, sorted now - links without errors. Here's the console output I'm getting now:


A>LINK BNKBIOS3=BIOS3,SCB[B,OS,NR]
LINK 1.31

@SEC FE5C @MIN FE5B @DATE FE58 @HOUR FE5A
@BNKBF FE35 @AIVEC FE26 @CIVEC FE22 @ERMDE FE4B
@AOVEC FE28 @COVEC FE24 @LOVEC FE2A @MXTPA FE62
@FX FE43 @MEDIA FE54 @CRDMA FE3C @BFLGS FE57
@CRDSK FE3E @ERDSK FE51 @RESEL FE41 @USRCD FE44
@VINFO FE3F @MLTIO FE4A

ABSOLUTE 0000
CODE SIZE 0AA6 (0000-0AA5)
DATA SIZE 0C59 (0B00-1758)
COMMON SIZE 0000
USE FACTOR 14

A>gencpm


CP/M 3.0 System Generation
Copyright (C) 1982, Digital Research

Default entries are shown in (parens).
Default base is Hex, precede entry with # for decimal

Create a new GENCPM.DAT file (N) ?

Display Load Map at Cold Boot (Y) ?

Number of console columns (#80) ?
Number of lines in console page (#24) ?
Backspace echoes erased character (N) ?
Rubout echoes erased character (Y) ?

Initial default drive (A:) ?

Top page of memory (FF) ?
Bank switched memory (Y) ?
Common memory base page (C0) ?

Long error messages (Y) ?

Accept new system definition (Y) ?

BNKBIOS3 SPR F500H 0B00H
BNKBIOS3 SPR B300H 0D00H
RESBDOS3 SPR EF00H 0600H
BNKBDOS3 SPR 8500H 2E00H

*** CP/M 3.0 SYSTEM GENERATION DONE ***
A>cpmldr
Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M BIOS 1.2.74 by J.Nock 2017
Based on original CP/M BIOS 1.0 by G.Searle 2007-13

CP/M 2.2 Copyright 1979 (c) by Digital Research



CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F500 0B00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EF00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA

... and there it stops. Think I've got some debug-printing to add to the BIOS (or even CPMLDR BIOS?) to find out what's going on and where it's falling over. (CPM3.SYS was created using GENCPM and all the default options.)

durgadas311
December 27th, 2017, 04:29 AM
OK, so pretty much the first thing in your BIOS3 code is to print the MMU message, so either the loader is not finished or else BIOS3 is hung/crashed in "printInLine".

I did notice one thing, which will be a problem a little later in the boot, when setting up Page 0 (and same problem in "bdose"). "@mxtpa" is a location that *contains* the address of the BDOS entry, that is not BDOS entry itself. So, when putting the JUMP at 0005H you need:

LD HL,(@mxtpa)

I notice from the load map that BNKBDOS3 extends down to address 8500H. Maybe check to be sure that does not interfere with the loader - especially it's stack. CPMLDR and the loader BDOS have stack space allocated internally, so those are not susceptible. I don't think I have your latest LDRBIOS.ASM, but make certain that it does not use high memory for stack, and that it always restores the caller's stack when returning (if it setup it's own stack).

Also, keep in mind that you are still on the loader stack when you reach "boot". That will be a problem when you start switching banks and loading CCP, since that stack is in low memory. Both boot entries need to set the stack, probably (nearly) immediately. You'll need a large enough stack to handle either boot path, and it needs to be in common memory. It could be the same as your interrupt stack - if you are careful to not allow (or depend on) interrupts during the boot path.

So far, I've not seen anything that would explain the hang, but some important issues to fix.

nockieboy
December 27th, 2017, 06:00 AM
OK, so pretty much the first thing in your BIOS3 code is to print the MMU message, so either the loader is not finished or else BIOS3 is hung/crashed in "printInLine".

Yes - looking like a stack issue?


I did notice one thing, which will be a problem a little later in the boot, when setting up Page 0 (and same problem in "bdose"). "@mxtpa" is a location that *contains* the address of the BDOS entry, that is not BDOS entry itself.

Well spotted - fixed that now. :)


I notice from the load map that BNKBDOS3 extends down to address 8500H. Maybe check to be sure that does not interfere with the loader - especially it's stack. CPMLDR and the loader BDOS have stack space allocated internally, so those are not susceptible. I don't think I have your latest LDRBIOS.ASM, but make certain that it does not use high memory for stack, and that it always restores the caller's stack when returning (if it setup it's own stack).

Also, keep in mind that you are still on the loader stack when you reach "boot". That will be a problem when you start switching banks and loading CCP, since that stack is in low memory. Both boot entries need to set the stack, probably (nearly) immediately. You'll need a large enough stack to handle either boot path, and it needs to be in common memory. It could be the same as your interrupt stack - if you are careful to not allow (or depend on) interrupts during the boot path.

So far, I've not seen anything that would explain the hang, but some important issues to fix.

Hm.. not sure I fully understand what I'm doing with the stacks between LDRBIOS/BIOS3 etc., so that's screaming out to me that the issue is something to do with the stack. Here's the current LDRBIOS.ASM that I'm using in CPMLDR: 42665

I think it's almost certain to be an issue with how I'm (not) handling the stack/s, but I'm not sure what I'm doing wrong.

durgadas311
December 27th, 2017, 06:45 AM
I don't immediately see anything wrong with LDRBIOS. We probably need to know where it is hung/crashed. So I guess make the above changes (@mxtpa fix and set a stack in both boot and wboot) and then figure out where it is dying.

nockieboy
December 27th, 2017, 08:28 AM
Okay, it seems that code execution is never getting to BIOS3. I've made the changes re: @mxtpa and the stacks for boot: and wboot: and added a message to print before anything is done in BIOS3 (aside from saving the stack and creating a local one), but that message is never getting shown. I've also changed the sign-on messages to be more accurate. Here's the console output:


A>cpmldr
Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M Plus LDRBIOS 1.0

CP/M Plus Copyright 1979 (c) by Digital Research

[screen-clearing spaces removed]

CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F500 0B00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EF00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA

And here's the latest versions of BIOS3 (42669) and LDRBIOS (42668). I'm doing pretty much exactly the same thing with the stack in BIOS3 as in LDRBIOS, aside from setting aside 64 bytes for the stack in BIOS3 instead of using hstbuf as in LDRBIOS...

durgadas311
December 27th, 2017, 08:44 AM
My working theory was/is that somewhere during the load some active part of memory is getting overwritten, causing a crash or hang. But, the loader should only be loading above 8500H and we can't find anything still being used there. Also, a simplified BIOS3 did load correctly. So, it's probably going to take adding debug to CPMLDR/LDRBIOS in order to determine the point of failure. It may be something other than actual load of the system, too. I forget what additional actions are being taken in CPMLDR.

Alphasite
December 27th, 2017, 06:41 PM
Here's what I have in my CP/M 3 BIOSes (this is Intel mnemonics of course):


139 lxi d,ccp$com
140 mvi c,15 ;open file
141 call bdose
142 inr a
143 jz noccp
144 xra a
145 sta fcb$nr
146 lxi d,ccp
147 mvi c,26 ;set DMA address
148 call bdose
149 mvi e,128 ;read upto 128 records (16K)
150 mvi c,44 ;set multi-sector count
151 call bdose
152 lxi d,ccp$com
153 mvi c,20 ;read record(s)
154 call bdose

And for "bdose" I use:


115 bdose: lhld @mxtpa
116 pchl

I think the premise is that the BDOS will always read into "Bank 1", and that's also where it needs to be. "ccp$com" is the FCB for CCP.COM, and "fcb$nr" is the next record field of that FCB. "ccp" is defined as 0100H, which is also where you jump to start the CCP. "nocpp" prints an error message and then dies (DI + HLT). The CCP was often saved into bank 0 to avoid having to re-read the disk on every warm boot, but with a flash drive it's probably not as objectionable.

Also note, that both cold and warm boot need to this, and typically it is the last thing those entries do.

Yeah, we got a little snow, and it is likely to stay around since the temps will be well below freezing for the next week or more. I spent a lot of time in the "Pacific NorthWest", which my Brit friends tell me is a lot like UK, but I'm happy these days in Minne-freezing-sota.

I took a look at my CP/M Plus BIOS source and this is what I have in BIOSKRNL.MAC:



extrn ?ldccp,?rlccp ;load & reload ccp for boot & wboot


And at the end of the BIOS BOOT entry:



call ?ldccp ;fetch ccp for first time
boot$2:
...
jp ccp


And at the end of the BIOS WBOOT entry:



call ?rlccp ;reload ccp
jp boot$2


?ldccp and ?rlccp are in BOOT.MAC which is modified from the distribution source:



?ldccp:
; First time, load the A:CCP.COM file into TPA
xor a ; zero extent
ld (ccp$fcb+15),a
ld hl,0 ; start at beginning of file
ld (fcb$nr),hl
ld de,ccp$fcb ; open file containing CCP
ld c,15
call bdos
inc a ; error if no file
jr z,no$CCP
ld de,100h ; start of TPA
ld c,26
call bdos
ld de,128 ; allow up to 16k
ld c,44
call bdos
ld de,ccp$fcb ; load the thing
ld c,20
call bdos

if not banked
ret
else

ld hl,0100h ; copy CCP to bank 2 for reloading
ld bc,ccp$size
ld a,(@cbnk) ; save current bank
push af
ld$1:
ld a,tpa$bank ; select TPA
call ?bnksl
ld a,(hl) ; get a byte
push psw
ld a,2 ; select extra bank
call ?bnksl
pop af ; save the byte
ld (hl),a
inc hl ; inc the count
dec bc
ld a,b ; test for done
or c
jr nz,ld$1
pop af ; restore original bank
jp ?bnksl
endif

no$CCP: ; here if we couldn't find the file
ld hl,ccp$msg ; report this...
call ?pmsg
call ?conin ; get a response
jr ?ldccp ; and try again

ccp$msg: db cr,lf,'BIOS Error on A: No CCP.COM file',0


ccp$fcb: db 1,'CCP ','COM',0,0,0,0
ds 16
fcb$nr: db 0,0,0

?rlccp:
if not banked
jp ?ldccp
else
ld hl,0100h
ld bc,ccp$size ;clone from other bank
rl$1:
ld a,2 ; select extra bank
call ?bnksl
ld a,(hl) ; get a byte
push af
ld a,tpa$bank ; select TPA
call ?bnksl
pop af ; save the byte
ld (hl),a
inc hl ; bump pointer
dec bc ; drop count
ld a,b ; test for done
or c
jr nz,rl$1
ret
endif

durgadas311
December 28th, 2017, 03:53 AM
Yes, it was common practice to load CCP.COM only once, during cold boot, into Bank 0 and then copy it from memory into Bank 1 on each warm boot. However, I was not suggesting that level of complexity for a couple reasons, one is that it is not required to make CP/M 3 work and the other is that with a "disk" in flash memory it was of less benefit. This is something to try once we get everything else working, but it may be of negligible performance gain. I did not want to introduce unnecessary complexity until we got the basics working. Same is true for directory hash buffers and character I/O redirection.

nockieboy
December 28th, 2017, 04:29 AM
Thanks for that Alpha, there's some interesting snippets that I've added to my BIOS3.ASM file from that source code, including copying the CCP to both Banks. :)

I think it's academic at the moment, however, as CPMLDR isn't getting to the point where it is successfully passing execution to BIOS3 - I'm getting no messages printed out from BIOS3 at all, including debug messages before ANY memory banking work or loading of CCP is even considered.

I'm going to have to go back and look closely at LDRBIOS and the CPMLDR source to work out how it's working and how it links to CPM3.SYS and the BIOS within it.

durgadas311
December 28th, 2017, 04:50 AM
I would caution against adding the "CCP to both banks" code right now. The simplest approach is to just read CCP.COM off "disk" every time. Later, once the basics are working, you'll want to look into other enhancements, including this and directory HASH buffers. Note, the HASH buffers will take up quite a bit of space, and given you only have 2 banks (really, only one "system" bank) you may prefer to use that space for HASH buffers instead of saving the CCP. But both may be unnecessary if your solid-state disk is fast enough. If it were me, I would not yet commit that memory just to make warm boot a little (possibly negligibly) faster. Plus it is more to debug.

nockieboy
December 28th, 2017, 06:17 AM
I would caution against adding the "CCP to both banks" code right now. The simplest approach is to just read CCP.COM off "disk" every time. Later, once the basics are working, you'll want to look into other enhancements, including this and directory HASH buffers. Note, the HASH buffers will take up quite a bit of space, and given you only have 2 banks (really, only one "system" bank) you may prefer to use that space for HASH buffers instead of saving the CCP. But both may be unnecessary if your solid-state disk is fast enough. If it were me, I would not yet commit that memory just to make warm boot a little (possibly negligibly) faster. Plus it is more to debug.

Yeah, fair point durgadas311. Have commented it out for the moment.

Alphasite
December 28th, 2017, 10:46 AM
Yeah, fair point durgadas311. Have commented it out for the moment.

It won’t include the code to copy the CCP to the alternate bank if banked is false when you assemble it.

I seem to remember you were getting everything working in non-banked mode first. But durgadas311 is correct that you might not want to load the CCP in the alternate bank if your flash storage is fast enough.

nockieboy
December 29th, 2017, 04:19 AM
I seem to remember you were getting everything working in non-banked mode first. But durgadas311 is correct that you might not want to load the CCP in the alternate bank if your flash storage is fast enough.

Originally I intended to get an unbanked version up and running first as that is what the CP/M System Guide (and logic) suggests. I think the current version of the BIOS is banked, though - I don't believe it adds too much complexity, but now I've said that all the future bugs will likely to be regarding banking... :rolleyes:

I've been looking at CPMLDR.ASM, the source for the CPMLDR, to work out how it passes execution to the LDRBIOS (and thus how it should be returned from the LDRBIOS), but I'm struggling with the Intel opcodes being used and my general lack of experience with the environment. It seems that CPMLDR is loading CPM3.SYS, but the BIOS3 code in CPM3.SYS is not getting executed, so that's my area of focus for the moment.

durgadas311
December 29th, 2017, 05:13 AM
It is possible, I don't know how likely, that the CPM3.SYS is "incorrect" and instead of jumping to the BIOS3 cold boot routine it ends up off in the weeds. You should be able to load CPM3.SYS under DDT and dump the header block (the "load record"), and check the values stored there. From CPMLDR.ASM, it appears to be this:


mem$top: ds 1
res$len: ds 1
bank$top: ds 1
bank$len: ds 1
osentry$adr: ds 2

The last one, "osentry$adr", should indicate the final (loaded) address of the BIOS cold boot entry. "mem$top" should always be "00", indicating 64K. "bank$top" should be "C0" in your case. You should be able to verify the $len fields from the load map - although that doesn't tell if they are "right", only if they are consistent. You also might try printing some values from the loader to see if they look correct (especially the address it tries to jump to).

nockieboy
December 29th, 2017, 07:06 AM
I read something somewhere sometime ago about CP/M and serial numbers... apparently there was a serial number embedded in the code in CP/M3.SYS and various other components and, if they didn't match, the system wouldn't work...? I've just come across this line whilst converting CPMLDR.ASM from 8080 to Z80 mnemonics:


SERIAL: DEFB 0,0,0,0,0,0

This is at the start of the BDOS interface module section, at line 241 in the CPMLDR.ASM file. Any chance this could be an issue as well?

So, in terms of changing/editing the loader - I'm assuming CPMLDR.ASM doesn't need to be linked with anything else? I can just assemble it in ZMAC to get the .REL file and link that with LDRBIOS.REL?

durgadas311
December 29th, 2017, 09:10 AM
The "serial" data is just a placeholder. I know of no standard CP/M software that checks the serial, let alone prevents operation of the system. That was usually left up to vendors, if they desired it. Or for tracking the origin of distribution diskettes. I've run CP/M without serial numbers a lot.

You should only need to link CPMLDR.REL and LDRBIOS.REL. I think zmac will auto-detect the mnemonics, but you might need to add a commandline option to force Intel mnemonics. The Linux version uses "-8". Worst case, you'll need to use RMAC.

nockieboy
December 29th, 2017, 11:46 AM
The "serial" data is just a placeholder. I know of no standard CP/M software that checks the serial, let alone prevents operation of the system. That was usually left up to vendors, if they desired it. Or for tracking the origin of distribution diskettes. I've run CP/M without serial numbers a lot.

I won't worry about that then - thanks. :)


You should only need to link CPMLDR.REL and LDRBIOS.REL. I think zmac will auto-detect the mnemonics, but you might need to add a commandline option to force Intel mnemonics. The Linux version uses "-8". Worst case, you'll need to use RMAC.

Well I've converted CPMLDR.ASM to Z80 mnemonics, as much for my own ease of understanding as anything else - problem is, ZMAC won't assemble it without these errors:


.\ZMAC -z --rel CPMLDR.ASM
CPMLDR.ASM(258) : 'dircnt' Undeclared
LD (DIRCNT),A

CPMLDR.ASM(1071) : 'seek$dir' Undeclared
CALL SEEK$DIR

CPMLDR.ASM(1149) : 'rd$dir' Undeclared
CALL RD$DIR ; Read the directory record

CPMLDR.ASM(1426) : 'set$lret1' Undeclared
JP SET$LRET1

CPMLDR.ASM(1564) : '1$1111b' Undeclared
AND 1$1111B ; non zero is auto drive select

CPMLDR.ASM(1628) : '0100$0000b' Undeclared
LD C,0100$0000B

CPMLDR.ASM(1924) : 'getbuffa' Undeclared
CALL GETBUFFA

7 errors (see listing if no diagnostics appeared here)

None of the functions exist in CPMLDR.ASM - either the original 8080 version or my Z80 version, so I'm at a loss as to what to do with these if they don't relate to some other linked assembly?

As for the LD and AND errors - I'm a little confused about the format of the binary values from 8080 version. Is 0100$0000B the same as 01000000B? Thought I'd better ask before I assume and create more errors...

Here's my Z80 version of CPMLDR.ASM for info: 42723

Chuck(G)
December 29th, 2017, 11:53 AM
The problem that you're having is that DRI's assemblers treat "$" in a label as a "nothing" character--you can insert them to your heart's content and they'll be "invisible".

Thus, "GEBUFFA" = "GET$BUFFA" only in DRI-ese assembly. It's one of their peculiarities and has existed since the first version of ASM came out. In other assemblers, they're treated as separate symbols.

So you have two choices--insert the "$" in symbols that have left the character out--or remove the "$" in symbols altogether.

durgadas311
December 29th, 2017, 12:47 PM
Personally, I'd avoid trying to convert the mnemoincs (and dealing with all the possible errors introduced). If it won't compile with ZMAC, I'd use RMAC since we know that works and is what the code was written for.

I see another issue is that the '!' conjoin character is not accepted by ZMAC. Probably lots of other incompatibilities as well. I think you risk a lot of ratholes by trying to convert CPMLDR.ASM to work on ZMAC.

Chuck(G)
December 29th, 2017, 01:11 PM
...seems that we as a community have been here many times before.

After the 8086 and Z8000 began to gain some traction, a number of outfits (including Intel) came out with "Convert (8085/Z80) code to (8086, Z8000...) programs.

The problem was that to be absolutely certain that the converter worked, you had to go over the converted code line-by-line, comparing it with the original,. Pretty much just as much work as converting the code manually--and with a less-efficient result, since most often, the converter didn't take full advantage of the target processor's facilities.

daver2
December 29th, 2017, 01:28 PM
If you check, DIRCNT is DIR$CNT and SEEK$DIR is SEEKDIR etc.

I would suggest doing a global search and replace of $ for NULL *** but *** there are a few valid uses of '$' within the source that this will corrupt. You will have to put them manually back in.

The code to execute the loaded code is a bit 'unconventional' by loading up the stack pointer to point to a word containing the is entry point and RETurning to it. there is no RETurn therefore from the entry point.

Dave

Chuck(G)
December 29th, 2017, 02:02 PM
Dave, isn't that what I said in #124?

nockieboy
December 29th, 2017, 02:35 PM
Yep, I get the concerns about using automated 8080/Z80 translators - I've checked the code as best I can and removed the odd ADD A,A or similar, now I've sorted the labelling issues thanks to your help guys and got the Z80 CPMLDR.ASM assembling and linking (apparently) properly. I'd modified LDRBIOS.ASM as well to show which address it was returning to once it had completed boot:, and after I've added a 64-byte stack space into CPMLDR.ASM, I get the output below. Seems an odd way to set up the stack so it just runs into the signon data - why is done like that? The code is only 1B7A in length - it's not as if they couldn't afford to add another 64 bytes for the stack (like I have!)?


A>LINK CPMLDR[L100]=CPMLDR,LDRBIOS
LINK 1.31

ABSOLUTE 0000
CODE SIZE 1B7A (0100-1C79)
DATA SIZE 0000
COMMON SIZE 0000
USE FACTOR 36

A>cpmldr
Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M Plus LDRBIOS 1.0

CP/M Plus Copyright 1982 (c) by Digital Research
LDRBIOS returning to: 0106

<blank lines removed for brevity>

CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

CPMLDR error: failed to read CPM3.SYS

So it appears the Z80 version of CPMLDR.ASM is working as per the 8080 version, maybe tomorrow I'll be able to start making some sense of what is (or isn't) going on...

EDIT: Well, almost - it's not reading CPM3.SYS properly. Here's the latest CPMLDR.ASM and LDRBIOS.ASM for anyone who's interested: 42724 42725

durgadas311
December 29th, 2017, 02:43 PM
Aren't you getting a different result with the "z80" version of CPMLDR? Before (original CPMLDR.REL), you were getting the load map printed and it hung (or silently crashed). This is spitting out a read error message before getting the load map.

durgadas311
December 29th, 2017, 02:48 PM
Looking at the way CPMLDR "returns" to BIOS3, one thing to check is whether the loader stack is getting *underrun*. That could corrupt the area used to store "osentry$adr" and thus cause a crash or hang.

durgadas311
December 29th, 2017, 07:21 PM
I see one problem with the Intel-to-Z80 translation. There is at least one instruction of the form:


lxi d,(reccnt-extnum)

which got translated into Z80 as:


LD DE,(RECCNT-EXTNUM)

and has a completely different meaning. The parenthesis for DRI assemblers is simply arithmetic grouping, but for Z80 it means indirection and changes the instruction completely. I'm not sure if there are more of these around, you'll need to check.

This would explain why the Z80/ZMAC version of CPMLDR does not work, but not why the original problem (hang after printing load map) is occurring. Once you fix CPMLDR you can then start debugging the previous problem.

Chuck(G)
December 29th, 2017, 07:38 PM
Good spotting! Use square brackets when you want to group expressions, IIRC.

I always thought that Zilog should have used brackets to indicate indirection in the original syntax, but the bell has been rung.

nockieboy
December 30th, 2017, 02:30 AM
Marvellous, well spotted durgadas311! Okay, it's assembling fine and the console output now matches the original 8080 CPMLDR output:


A>LINK CPMLDR[L100]=CPMLDR,LDRBIOS
LINK 1.31

ABSOLUTE 0000
CODE SIZE 1B7A (0100-1C79)
DATA SIZE 0000
COMMON SIZE 0000
USE FACTOR 36

A>cpmldr
Preparing MMU...
Setting MMU lock byte...
Initialising SIO...
Z80 MINICOM II CP/M Plus LDRBIOS 1.0

CP/M Plus Copyright 1982 (c) by Digital Research
LDRBIOS returning to: 0106

<blanks removed for brevity>

CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F500 0B00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EF00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA

Okay, so LDRBIOS is returning to 0106h and CPMLDR continues to load CPM3.SYS - then the system crashes. Durgadas311 - you mentioned the stack may be getting underrun in CPMLDR in post #131 (http://www.vcfed.org/forum/showthread.php?60896-Installing-CP-M-3-(Plus-)-on-a-home-built-Z80-computer&p=491793#post491793)? Could you expand on that a little bit for me please? Do you mean there could be an unmatched POP in the execution sequence somewhere?

durgadas311
December 30th, 2017, 04:26 AM
Stack underrun was just one idea, based on the theory that CPM3.SYS is getting loaded completely (which I'm not sure has been confirmed). It just so happens that the loader stack has the load parameters (mem$top, res$len, bank$top, bank$len, and osentry$adr) immediately above it, so if the stack did get underrun it could corrupt that data, specifically osentry$adr. But that's a bit of a stretch since usually stack underrun causes an immediate crash as you try to return to the wrong (invalid) address. One suspect I thought of was "printInline" since it messes with the return address and thus could easily survive stack underrun - but I don't see anything wrong with that routine, nor do I see it used outside of cold boot (this would have to be happening sometime after reading the load record).

So, I think it's back to adding some sort of progress indicator in order to find out just where things are getting hung. You could do something as simple as outputting a single character for each key point in the loader. But maybe first printout the osentry$adr value just before "returning" to it, as well as right after copying the data from the buffer (i.e. in the EXECUTE code as well as just before the "Read display info" comment).

nockieboy
December 30th, 2017, 05:46 AM
So, I think it's back to adding some sort of progress indicator in order to find out just where things are getting hung. You could do something as simple as outputting a single character for each key point in the loader. But maybe first printout the osentry$adr value just before "returning" to it, as well as right after copying the data from the buffer (i.e. in the EXECUTE code as well as just before the "Read display info" comment).

Here's the output from the latest debug-build of CPMLDR. I've just shown the last (most relevant) bit of the console output from CPMLDR, which shows the value of osentry$adr (which looks wrong!):


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F500 0B00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EF00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA

CPMLDR: Executing - OSENTRYADR = 0200


Here's the latest CPMLDR for info (and yes, I know I've probably not used the most efficient method to print the values from PHEX:, but I'm working with what I know - which is very little! ;) )

42731

EDIT:

Not sure if this is an error or not (but it sure looks like one to me) - line 123 in CPMLDR.ASM:


LD SP,OSENTRYADR

... shouldn't that be:


LD SP,(OSENTRYADR)

????

I've changed it in CPMLDR.COM and got the following output:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F400 0C00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EE00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA

CPMLDR: Executing - OSENTRYADR = F400▒_▒▒ ▒▒Җ▒-▒!▒▒~▒s▒▒▒2▒▒▒:▒▒!޾▒'▒▒▒▒▒▒▒▒▒▒▒*▒▒~▒▒w*▒▒MD͉ ▒"▒▒▒:
▒!"1▒"'▒1▒▒ ▒2▒▒ɯ2▒▒t▒>▒G=O*▒▒▒#~▒2▒~▒w▒▒▒▒▒▒~▒▒t▒~▒p2
▒4ͩ ▒▒:▒g:▒͇:▒▒▒_g:▒͇!]~▒
CPMLDR error: failed to read CPM3.SYS

I guess the real change is that instead of trying to jump to 0200h, OSENTRYADR contains F400h which the modified CPMLDR is trying to jump to and crashing again. *shrug*

durgadas311
December 30th, 2017, 07:02 AM
Unfortunately, this debug message is printing the *address of* osentry$adr, not the contents of it. In this case, you *do* want parenthesis:


LD HL,(OSENTRYADR)

nockieboy
December 30th, 2017, 07:31 AM
Unfortunately, this debug message is printing the *address of* osentry$adr, not the contents of it. In this case, you *do* want parenthesis:


LD HL,(OSENTRYADR)

Yep, noticed that myself - see the edit I made to my post above. :)

durgadas311
December 30th, 2017, 07:43 AM
Well, it looks like it is jumping to the correct address, so it would seem that the RESBIOS3 code is not actually at F400, at least at the time that the RET is made. If the memory map could not have changed, then it may be that the CPM3.SYS file is either corrupted or not properly generated (or loaded). There still could be some corruption of that data above the loader stack, causing the BIOS3 to be loaded into the wrong address.

durgadas311
December 30th, 2017, 08:48 AM
Wait, did you actually make the change you asked about? This is not correct:


LD SP,(OSENTRYADR)

In that case, the correct code is to get the *address of* osentry$adr. So do not change that instruction.

nockieboy
December 30th, 2017, 09:22 AM
Wait, did you actually make the change you asked about? This is not correct:


LD SP,(OSENTRYADR)

In that case, the correct code is to get the *address of* osentry$adr. So do not change that instruction.

Yes, I DID make that change, but was starting to think I need to change it back - your post has just confirmed that for me! :) I'll get it updated in a short while - I imagine the console output will be identical to previous posts, but I guess now I need to start looking at confirming somehow that BIOS3 is actually at FE00h? That should be location of the cold boot jump, shouldn't it?

EDIT: Perhaps instead of showing the address of osentry$adr, I should dump 256 bytes from FE00h?

daver2
December 30th, 2017, 09:41 AM
The code *** SHOULD BE *** "LD SP,OSENTRYADR" and not "LD SP,(OSENTRYADR)". Just to confirm...

The next thing it does is a RETurn - so this is setting up the stack pointer to an 'imaginary' stack that has been pre-loaded with the address to transfer to (via the RET instruction).

This should (by the looks of what you are seeing) jump to F400. Why looking at FE00?

Within the COLD start of your BIOS - the stack pointer at this point in time should be considered invalid. You appear to save the current value of the stack pointer (that is OK) and then load it up again (after disabling interrupts), so that looks OK to me too.

Dave

nockieboy
December 30th, 2017, 09:58 AM
The code *** SHOULD BE *** "LD SP,OSENTRYADR" and not "LD SP,(OSENTRYADR)". Just to confirm...

Yep, sorted.


The next thing it does is a RETurn - so this is setting up the stack pointer to an 'imaginary' stack that has been pre-loaded with the address to transfer to (via the RET instruction).

Just seems like an unnecessarily fancy way of doing a JP (OSENTRYADR)?


This should (by the looks of what you are seeing) jump to F400. Why looking at FE00?

Ignore that, Dave - in a previous console log I'd done it showed an address of FE00 - I still had that in my head when I wrote that post. :rolleyes: The log posted below prints the page from F400.


Within the COLD start of your BIOS - the stack pointer at this point in time should be considered invalid. You appear to save the current value of the stack pointer (that is OK) and then load it up again (after disabling interrupts), so that looks OK to me too.

Dave

Yes, a local stack is set up for BIOS3 immediately after disabling interrupts - so, in theory at least, if CPMLDR is jumping to the right address (F400), the cold boot should be being executed... Which is telling, because it doesn't seem to be.

Here's the latest console log from CPMLDR - this time I've made it dump a page of RAM from F400. Looks to me an awful lot like it's jumping to F400, then getting stuck in a loop jumping back to F400 continuously....


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F400 0C00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EE00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA

CPMLDR: OSENTRYADR = F400
CPMLDR: Page Dump from F400h
C300F40000F40000F4002CF9C310F9
C36BF4C36BF4C36AF4C38FF9C374F9
C392F9C397F9C39CF9C3EBF9C318FA
C367F4C3A7F9C325F9C36AF4C367F4
C363F4C366F4C3E9F5C3EDF5C3EEF5
C3C5F5C3EFF5C3CAF5C3A3F9C3C9F5
C30000C30000C30000210000C9AF3D
C9AFC9000000000000000000000000
34F5000051B311B313B3FFFF000000
0000000000000000000045F5000052
B411B313B3FFFF0000000000000000
000000000045F5000053B511B313B3
FFFF00000000000000000000000000
45F5000054B611B313B3FFFF000000
0000000000000000000045F5000055
B711B313B3FFFF0000000000000000
000000000045F5000056B811B313B3
FFFF00000000000000000000000000
45F5000057B911B313B3FFFF000000
0000000000000000000056F5000058
BA11B313B3FFFF0080000000000000
000000000000010002038000051F01
FF07FF01F000000000000203800005
1F01FF04FF01F00000000000020300
000040CBF700180484011803E105EA
001804C40118020003E105EA000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000EBEDB0EBC9C5E53210B38787
4F060021E1F5090E380604EDB3E1C1
C90011223304152633216CF4C9C9C9
C9F3ED73C3F531C3F5CD50FA0C4249
4F53333A20507265706172696E6720
4D4D552E2E2E0D0A003E00D3383E11
D3383E22D3383E33D338CDABF7216B
F57CED477D327EF5CD50FA0C42494F
53333A20496E697469616C6973696E
672053494F2E2E2E0D0A003A6AF5FE
38CA61F63E84C363F63EC43270F521
6DF50E02060AEDB32177F50E03060C
EDB3CD50FA0C5A3830204D494E4943
4F4D2049492043502F4D20506C7573
2042494F5320312E302E3020627920
4A2E4E6F636B20323031370D0A0D0A
43502F4D20506C757320436F707972
696768742031393832202863292062
79204469676974616C205265736561
7263680D0A00CD45FA3E01D3113EEF
D317CD45FA3E82D3113EEFD317AF32
A4FA32E7FA2164FA22A0FA22A2FA21
A7FA22E3FA22E5FAED5EFBC324F7ED
73C3F531C3F5CDABF7AF32FEFE2100
00220EFF0E0F11EFFECD7EF73CCA82
F71100010E1ACD7EF71180000E2CCD
7EF711EFFE0E14CD7EF7ED7BC3F5C3
000121000101800C3A10B3F53E01CD
CAF57EF53E00CDCAF5F177230B78B1
20ECF1CDCAF5C300012AFEF3E9CD50
FA0C42494F53204572726F72206F6E
20413A204E6F204343502E434F4D20
66696C650D0A00F3763E04D338CDB6
F73E00D3383EC33200002103F42201
003205002AFEF3220600C9F5E597D3
02DB020F302B2AA0FA233AA5FABD20
032164FA22A0FADB00773AA4FA3C32
A4FAFE3238083E05D3023EE8D302E1
F1FBED4D2AE3FA233AE8FABDC20EF8
21A7FA22E3FADB01773AE7FA3C32E7
FAFE32DA28F83E05D3033EE8D3037E
FE23CC33F8E1F1FBED4DF3CDE9F8FE
23CA52F8FE25CA4AF83AE7FAFE05D2
34F8C9CDE9F8FE45CC53F8C9CDE9F8
FE23CAA2F832EAFACDE9F8FE23CAA2
F832EBFACDCAF83269F5CDE9F8FE23
CAA2F832EAFACDE9F8FE23CAA2F832
EBFACDCAF83268F52A68F5E5CDE9F8
E1FE23CAA2F877233AE7FAFE00C28E
F8C932EEFAE6F00F0F0F0FCDB2F83A
EEFAE60FFE0ADAC0F8D609F640C3C2
F8F6304FCD10F93AEEFAC93AEAFACD
E1F8E60F07070707573AEBFACDE1F8
E60FB2C9D630FE0AD8D607C92AE5FA
233AE8FABDC2F7F821A7FA22E5FA3A
E7FA3D32E7FAFE05D20EF93E05D303
3EEAD3037EC9F5CD64F928FB79D300
F1C9CD6CF928FB79D301F1C9CD64F9
C8AF3DC9CD59F928FB2AA2FA233AA5
FABD20032164FAF322A2FA3AA4FA3D
32A4FAFE0530083E05D3023EEAD302
7EFBE1C9E53AA4FAB72802AF3DE1C9
97D302DB02E604C997D303DB03E604
C921000079FE083805AF3204B3C932
04B3216CF4011900093D20FCC90100
00ED4305B3C9ED4307B3C9ED430DB3
3A10B3320FB3C96069C92A05B32929
2929293A07B3B53200B33A04B3CB0F
CB0F6FE6033202B37DE6C0B43201B3
3EE03203B33A00B3D3133A01B3D314
3A02B3D3153A03B3D3163E01D312C9
F5C5E5CD45FACDAAF93E20D317CD45
FA3A0FB3CDCAF506000E102A0DB3ED
B2EDB2AFCDCAF5E1C1F1AF3209B3C9
F5C5E5CD45FACDAAF93E30D317CD45
FA3A0FB3CDCAF506000E102A0DB3ED
B3EDB3AFCDCAF5E1C1F1AF3209B3C9
F5DB17E680FE8028F8F1C9E3F5C57E
FE0028074FCD10F92318F423C1F1E3
C90000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000A0FA00000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
00000000000000000000000000E3FA
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000004343502020
2020434F4D00000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000C303E6
0100C306D8F233EAECAC000938CC62
B3E2CBA0A8E0FA3CAA4E0C2BE83EB2
22ACEA08BC8A8B82C26BC8882D22A2
8B0F00823330BE8F0C978AEECE7D9E
2A0BE9E3B8B8A9EEA03AEFB836CF33
0AEA040FC32A9B0001020303AC3A00
202020202020202020202000000039
002020202020202020202020000000
000028B2E30D0A20424E4B42494F53
332053505220204634303020203043
30300D0A20424E4B42494F53332053
50522020423330302020304430300D
0A2052455342444F53332053505220
20454530302020303630300D0A2042
4E4B42444F53332053505220203835
30302020324530300D0A200A0D2035
394B205450410A0D24242424243143
03CD000C0E0DCD4F030E0911A702CD
4F030E0F11F401CD4F03FEFF111802
CAEB01118000CDD801CDDE01218000
1143030E067E1213230DC23401CDDE
010E09118000CD4F033A4403673A43
03CDBC013A4603B7CA5F01673A4503
CDBC01215D007EFE24C26F01237EFE
42CCF2010E09116E02CD4F032A4703
7CCD440B7DCD440B1186020E09CD4F
033E0F4721FFF3237EC5E5CD440BE1
C110F511A4020E09C5E5CD4F03E1C1
3E0F477DFEFFC2900111A4020E09CD
4F03314703C9B7571E007C1767EB01
80FF09EBD5E5CDD801CDDE01E1D125
C2C301C90E1ACD4F03C90E1411F401
CD4F03B7114302C80E09CD4F03F376
FFC90043504D332020202053595301
000080260027002800570058000000
000000001C0000000D0A43504D4C44
52206572726F723A20206661696C65
6420746F206F70656E2043504D332E
5359530D0A240D0A43504D4C445220
6572726F723A20206661696C656420
746F20726561642043504D332E5359
530D0A240D0A43504D4C44523A204F
53454E545259414452203D20240D0A
43504D4C44523A2050616765204475
6D702066726F6D2046343030680D0A
240D0A0A0A0A0A0A0A0A0A0A0A0A0A
0A0A0A0A0A0A0A0A0A0A0A43502F4D
2056332E30204C6F616465720D0A43
6F7079726967687420284329203139
38322C204469676974616C20526573
65617263680D0A2430323131383200

durgadas311
December 30th, 2017, 10:02 AM
Yes, dumping 256 bytes at the address contained in osentry$adr would be the next step (should be 0F400H according to current data).

The file CPM3.SYS contains the CP/M image in reverse order, and the loader will read records from the file in order but place them in memory from the top downwards. So if you go examining CPM3.SYS you'll want to keep that in mind. The first record should be the load data, the second should be the load map message, and the third onwards will be the system image, resident (high, CSEG) section first. So, the record containing the BIOS entry jump table will be many records into the file.

One thought I had was that something corrupted the load data and so things did not load correctly. If the length of the resident section was too small, it might account for what we see (too large and we would see the "read failed" message from a premature EOF). So another thing to try might be to dump the 4 bytes before osentry$adr as well, just before jumping to the BIOS3 cold boot entry. We can then compare those to the expected values (from the load map message or by dumping the first record of CPM3.SYS).

FYI, but not to distract from the debug, your LDRBIOS contains hex dump routines and you could call those out as "public" in LDRBIOS.ASM and then as "extrn" in CPMLDR.ASM and call them directly. But again, probably not worth the risk to make that change now.

durgadas311
December 30th, 2017, 10:04 AM
Just crossed-paths with your next post...

Your BIOS3 looks bad. The cold start entry is a jump to itself - that is bad. Then there is some corruption for a few jump entries. Maybe post the latest listing file for BIOS3.ASM as we can look at what is getting assembled. Probably include the REL file, too.

daver2
December 30th, 2017, 10:09 AM
+1...

"Jump to self" = not going anywhere fast!

Can you post your latest BIOS assembly code so we are all working from the same page (no pun intended).

We need to work out if your BIOS assembled/linked wrongly, failed to load correctly, or got corrupt somewhere down the line.

EDIT: It may also be worth posting the CPM3.SYS file for us to look at".

EDIT2: What durgadas311 said...

Dave

nockieboy
December 30th, 2017, 10:26 AM
Okay, here's some files:
42732 - this is a zip of all the relevant .LST and .REL files
42733 - this is a zip of the relevant .ASM files.

I've included SCB as well as I'm not convinced the problem isn't there (though I know little about how it all fits together.)

CPM3.SYS will take a while longer - I'm going to have to work out a way to get that off the SBC. :confused: I've not got any way I can send it back up the line or print its contents to the console (have I?)

durgadas311
December 30th, 2017, 10:55 AM
Looking at the hex dump of F400, along side the BIOS3.lst file, I see that 9 of the first 10 bytes have been "corrupted":


C300F40000F40000F4002CF9C310F9

I'm not sure where the pattern comes from, but it seems to be 3 instances of:


DW 0F400H
DB 0

Any ideas where that could have come from? Since CPM3.SYS is already relocated, that was either put there by the loader (corrupted at runtime) or is corrupted in the CPM3.SYS file. The REL file contains the correct tags, so either the LINK did this, or GENCPM, or loader at runtime. Might be good to examine both BNKBIOS3.SPR and CPM3.SYS.

You could examine these using DDT on CP/M 2.2, although its a bit trickier. For BNKBIOS3.SPR, it should be fairly easy to locate the BIOS jump table, it should be at 0200H (as loaded by DDT). For CPM3.SYS, you'll have to figure out the location within the file. Based on the last load map, there are 24 records in the resident BIOS, and two records of header, so the BIOS jump table should be near 0D80H (check around that area) - if my calculations are correct.

daver2
December 30th, 2017, 11:07 AM
I have also come to exactly the same conclusion.

At some point (assuming it is part of the build), the BIOS3 will go from 'correct' to 'not correct' and we need to look at what is going wrong.

if everything is correct 'on the disk' so to speak, it must be the run-time that is corrupting things.

Yep, BNKBIOS3.SPR is the next place to look.

EDIT: My CPM3.SYS looks a bit 'short'???

Dave

nockieboy
December 30th, 2017, 11:27 AM
EDIT: My CPM3.SYS looks a bit 'short'???

Dave

Yes, it was - I realised after I edited it into the post that it wasn't quite right, so I removed it again. Will have to think of other ways I can view the files on the SBC. Might have to make a hex file viewer, unless anyone knows of something similar already in existence for CP/M?

daver2
December 30th, 2017, 11:31 AM
Ah, that's what happened to it! I wasn't going mad when I thought I saw a post that I downloaded a file from :-)...

Do you have DUMP.COM on your CP/M system?

A>DUMP CPM3.SYS

Dave

nockieboy
December 30th, 2017, 11:35 AM
Ah, that's what happened to it! I wasn't going mad when I thought I saw a post that I downloaded a file from :-)...

Do you have DUMP.COM on your CP/M system?

A>DUMP CPM3.SYS

Dave

Yes, I do! I assumed it was to dump memory, not programs... shows there's some truth in old saying about me and asses. ;)

durgadas311
December 30th, 2017, 11:38 AM
Can you look at the files on CP/M 2.2 under DDT? That should give us the information immediately.

nockieboy
December 30th, 2017, 11:40 AM
Okay, here's a dump of CPM3.SYS (thanks Dave for pointing me to DUMP!)

42741

EDIT: On inspection, it looks like 0C80 is the problem location. The CPM3.SYS file is corrupt somehow.

nockieboy
December 30th, 2017, 11:40 AM
Can you look at the files on CP/M 2.2 under DDT? That should give us the information immediately.

I can - if you don't mind telling me what commands I need to use?

daver2
December 30th, 2017, 11:41 AM
eee-aaaah...

I am going out for my evening walk. You should be able to find your BIOS jump table in the CPM3.SYS file - and it should be intact.

If it is - the loading process has done it in.

If it is not intact, then GENCPM (or some other prior process causing GENCPM to get it wrong) is the culprit.

Dave

durgadas311
December 30th, 2017, 11:44 AM
You should get familiar with DDT, IMHO.

For this case, to dump the BIOS entry:


A> DDT BNKBIOS3.SPR
...
* D200
...
* G0
A>

Similar for CPM3.SYS, but you may have to hunt around for the exact address, if 0D80 is not it. "D" is the dump command, followed by the starting address. "G" is the "Go" command, with zero as the address it will return to CP/M.

nockieboy
December 30th, 2017, 11:45 AM
Yes, a quick text search of the CPM3.SYS.txt file has thrown up the BIOS jump table at 0C80 and the first three jump addresses are corrupt as per the memory dump from CPMLDR. So it seems there's a problem with GENCPM?

daver2
December 30th, 2017, 11:47 AM
Just saw your post before I went out (I have got my coat on ready) and had a nosy at your post.

Agreed - CPM3.SYS is corrupt.

What caused it?

Can you post a copy of the SPR files next?

Dave

nockieboy
December 30th, 2017, 11:49 AM
You should get familiar with DDT, IMHO.

For this case, to dump the BIOS entry:


A> DDT BNKBIOS3.SPR
...
* D200
...
* G0
A>

Similar for CPM3.SYS, but you may have to hunt around for the exact address, if 0D80 is not it. "D" is the dump command, followed by the starting address. "G" is the "Go" command, with zero as the address it will return to CP/M.

I know, I just haven't had much call to use DDT up til now. Have just confirmed my previous post, however - 0D80 is the address of the jump table and yes, it is corrupt as per the memory dump from CPMLDR. The question is, what could be wrong with GENCPM to be causing this?

nockieboy
December 30th, 2017, 11:58 AM
Here's the SPR files as requested for BDOS3, BIOS3, BNKBDOS3, BNKBIOS3 and RESBDOS3:

42742

durgadas311
December 30th, 2017, 12:00 PM
OK, well I tried the LINK command, as I expect it to be, on my virtual H89. The resulting BNKBIOS3.SPR is not corrupt. Unsure how this happened, so maybe we need to review your link procedure. What command did you use to create BNKBIOS3.SPR? Was it only made from BIOS3.rel and SCB.rel? I used:


link bnkbios3=bios3,scb[b,os,nr]

Or else the SPR file got corrupted afterwards.

nockieboy
December 30th, 2017, 12:01 PM
OK, well I tried the LINK command, as I expect it to be, on my virtual H89. The resulting BNKBIOS3.SPR is not corrupt. Unsure how this happened, so maybe we need to review your link procedure. What command did you use to create BNKBIOS3.SPR? Was it only made from BIOS3.rel and SCB.rel? I used:


link bnkbios3=bios3,scb[b,os,nr]

Yes, seems to be identical to what I'm using:


A>LINK BNKBIOS3=BIOS3,SCB[B,OS,NR]

EDIT: The jump table looks intact in BNKBIOS3 though?

durgadas311
December 30th, 2017, 12:08 PM
I'm not sure where to go next. I use the same files you posted here, and I get a valid jump table for the BIOS in the SPR file.


O>
O>a:link bnkbios3=bios3-2,scb[b,os,nr]
LINK 1.31

@SEC FE5C @MIN FE5B @DATE FE58 @HOUR FE5A
@BNKBF FE35 @AIVEC FE26 @CIVEC FE22 @ERMDE FE4B
@AOVEC FE28 @COVEC FE24 @LOVEC FE2A @MXTPA FE62
@FX FE43 @MEDIA FE54 @CRDMA FE3C @BFLGS FE57
@CRDSK FE3E @ERDSK FE51 @RESEL FE41 @USRCD FE44
@VINFO FE3F @MLTIO FE4A

ABSOLUTE 0000
CODE SIZE 0B12 (0000-0B11)
DATA SIZE 0C59 (0C00-1858)
COMMON SIZE 0000
USE FACTOR 16

O>a:dump bnkbios3.spr


CP/M 3 DUMP - Version 3.0
0000: 00 59 18 00 00 00 00 00 00 00 12 0B 00 00 00 00 .Y..............
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0100: C3 F0 01 C3 1A 03 C3 59 05 C3 2C 05 C3 10 05 C3 .......Y..,.....
0110: 6B 00 C3 6B 00 C3 6A 00 C3 8F 05 C3 74 05 C3 92 k..k..j.....t...
0120: 05 C3 97 05 C3 9C 05 C3 EB 05 C3 18 06 C3 67 00 ..............g.
0130: C3 A7 05 C3 25 05 C3 6A 00 C3 67 00 C3 63 00 C3 ....%..j..g..c..
0140: 66 00 C3 E9 01 C3 ED 01 C3 EE 01 C3 C5 01 C3 EF f...............
0150: 01 C3 CA 01 C3 A3 05 C3 C9 01 C3 00 00 C3 00 00 ................
Press RETURN to continue
O>

nockieboy
December 30th, 2017, 12:09 PM
What files does GENCPM require to create CPM3.SYS? And yes, my LINK also produces a valid jump table in the BNKBIOS3.SPR file (see the one in the zip file in the earlier post for confirmation.)

durgadas311
December 30th, 2017, 12:11 PM
GENCPM consumes RESBDOS3.SPR, BNKBDOS3.SPR, and BNKBIOS3.SPR

nockieboy
December 30th, 2017, 12:23 PM
I think just by a process of elimination the issue must be to do with GENCPM. The SPR files all seem normal (or at least the jump tables aren't corrupted in them). I wonder if it's worth trying to source another copy of it from elsewhere?

durgadas311
December 30th, 2017, 12:34 PM
Looking at the pattern of corruption, it is as if those 9 bytes got zeroed sometime before GENCPM relocated them. The bitmap in the SPR tells GENCPM to add F4 (in this case) to certain bytes, turning C3 00 00 00 00 00... into C3 00 F4 00 00 F4... But, GENCPM probably does not have a bug (it works elsewhere). That being said, when I run GENCPM on these SPR files, I get the same corruption. It may take some reflection to figure out what might be going wrong.

nockieboy
December 30th, 2017, 12:48 PM
Looking at the pattern of corruption, it is as if those 9 bytes got zeroed sometime before GENCPM relocated them. The bitmap in the SPR tells GENCPM to add F4 (in this case) to certain bytes, turning C3 00 00 00 00 00... into C3 00 F4 00 00 F4... But, GENCPM probably does not have a bug (it works elsewhere). That being said, when I run GENCPM on these SPR files, I get the same corruption. It may take some reflection to figure out what might be going wrong.

Yes, it's a real head-scratcher. I'm getting the same output from GENCPM in the SIMH Altair simulator too. I've got my fingers crossed that Dave's walk will have nudged a few ideas loose. ;)

daver2
December 30th, 2017, 12:49 PM
It is also just possible that one (or more) .SPR files contain something later on that ends up over the 'top of' the jump table when GENCPM relocates them? So, even though the .SPR file contains the 'correct' jump table (ready for relocation) something else is being loaded after the BIOS CSEG 'over the top of' it. Just a thought.

The other thing I did was to read the CP/M 3 System Guide manual (I know, last resort!) and searched for the text SPR. I came across something that I had not seen before about symbols assigned as FExxH being relocated to the SCB. I notice that the entire SCB.ASM file starts at 0xFE00 for its symbols. Does this ring any bells with you durgadas311?

Dave

nockieboy
December 30th, 2017, 12:56 PM
It is also just possible that one (or more) .SPR files contain something later on that ends up over the 'top of' the jump table when GENCPM relocates them? So, even though the .SPR file contains the 'correct' jump table (ready for relocation) something else is being loaded after the BIOS CSEG 'over the top of' it. Just a thought.

Dave

Interesting possibility - what comes before the BIOS? BDOS? Surely GENCPM wouldn't allow modules to overwrite each other though?

Another though just occurred whilst looking at the CPM System Guide - when I use GENCPM, the last question I get is "Accept new system definition (Y) ?" But the manual lists a whole load of memory banking-related questions, like number of memory segments, hashing and drive questions... none of these come up when I use GENCPM... Is that a problem? (I'm just using the default GENCPM answers, which includes a positive reply to the banking question.)

daver2
December 30th, 2017, 01:06 PM
A 'decent' tool shouldn't allow anything to be overwritten - or at least should generate a warning.

The way SPR files seem to work is that there is one bit for each byte that needs relocating - so this shouldn't really happen. I am just having a look at the SPR bitmap now to see if something has gone silly though.

Can you post the GENCPM.DAT file (this should be the default answer file that is being used).

Dave

durgadas311
December 30th, 2017, 01:07 PM
Yeah, GENCPM will special-case addresses that match FExx and make those relative to the SCB. But the SPR file should not have any addresses that "naturally" look like FExx (before relocation).

I keep wanting to blame this on SPR content, as daver2 suggests, but I can't reason it out. The SPR files are binary images with an appended bitmap to indicate where relocatable addresses are. So, the SPR cannot back-up the location counter like a REL file could. I could not find any such anomaly in the REL file, plus we know the SPR file is correct. I'm looking at my virtual H89 memory right now, after the GENCPM. Can't find the BIOS, but it is trial and error mostly. My thought is to either try running it under SID or else use the simulation debug tools to try and figure it out. Unfortunately, GENCPM is written in PL/M so it is more difficult to debug on a binary level.

durgadas311
December 30th, 2017, 02:07 PM
I've made some progress. Using SID to run GENCPM, I was able to determine that the corruption (zeroing of 9 bytes) occurs somewhere between loading BNKBIOS3.SPR and relocating the image (exclusive). So, after the load the jump table is OK, but before the call to relocate it is corrupt. I'll run a few more times and see if I can bisect to where it is happening.

nockieboy
December 30th, 2017, 02:09 PM
A 'decent' tool shouldn't allow anything to be overwritten - or at least should generate a warning.

The way SPR files seem to work is that there is one bit for each byte that needs relocating - so this shouldn't really happen. I am just having a look at the SPR bitmap now to see if something has gone silly though.

Can you post the GENCPM.DAT file (this should be the default answer file that is being used).

Dave

Here's the GENCPM.DAT (although the default option is not to create one, so I don't think I tend to use it?):


A>type gencpm.dat
PRTMSG = Y
PAGWID = 4F
PAGLEN = 17
BACKSPC = N
RUBOUT = Y
BOOTDRV = A
MEMTOP = FF
BNKSWT = Y
COMBAS = C0
LERROR = Y
NUMSEGS = 03
MEMSEG00 = 00,80,00
MEMSEG01 = 00,C0,02
MEMSEG02 = 00,C0,03
MEMSEG03 = 00,C0,04
MEMSEG04 = 00,C0,05
MEMSEG05 = 00,C0,06
MEMSEG06 = 00,C0,07
MEMSEG07 = 00,C0,08
MEMSEG08 = 00,C0,09
MEMSEG09 = 00,C0,0A
MEMSEG0A = 00,C0,0B
MEMSEG0B = 00,C0,0C
MEMSEG0C = 00,C0,0D
MEMSEG0D = 00,C0,0E
MEMSEG0E = 00,C0,0F
MEMSEG0F = 00,C0,10
HASHDRVA = Y
HASHDRVB = Y
HASHDRVC = Y
HASHDRVD = Y
HASHDRVE = Y
HASHDRVF = Y
HASHDRVG = Y
HASHDRVH = Y
HASHDRVI = Y
HASHDRVJ = Y
HASHDRVK = Y
HASHDRVL = Y
HASHDRVM = Y
HASHDRVN = Y
HASHDRVO = Y
HASHDRVP = Y
ALTBNKSA = N
ALTBNKSB = N
ALTBNKSC = N
ALTBNKSD = N
ALTBNKSE = N
ALTBNKSF = N
ALTBNKSG = N
ALTBNKSH = N
ALTBNKSI = N
ALTBNKSJ = N
ALTBNKSK = N
ALTBNKSL = N
ALTBNKSM = N
ALTBNKSN = N
ALTBNKSO = N
ALTBNKSP = N
NDIRRECA = 01
NDIRRECB = 01
NDIRRECC = 01
NDIRRECD = 01
NDIRRECE = 01
NDIRRECF = 01
NDIRRECG = 01
NDIRRECH = 01
NDIRRECI = 01
NDIRRECJ = 01
NDIRRECK = 01
NDIRRECL = 01
NDIRRECM = 01
NDIRRECN = 01
NDIRRECO = 01
NDIRRECP = 01
NDTARECA = 01
NDTARECB = 01
NDTARECC = 01
NDTARECD = 01
NDTARECE = 01
NDTARECF = 01
NDTARECG = 01
NDTARECH = 01
NDTARECI = 01
NDTARECJ = 01
NDTARECK = 01
NDTARECL = 01
NDTARECM = 01
NDTARECN = 01
NDTARECO = 01
NDTARECP = 01
ODIRDRVA = A
ODIRDRVB = A
ODIRDRVC = A
ODIRDRVD = A
ODIRDRVE = A
ODIRDRVF = A
ODIRDRVG = A
ODIRDRVH = A
ODIRDRVI = A
ODIRDRVJ = A
ODIRDRVK = A
ODIRDRVL = A
ODIRDRVM = A
ODIRDRVN = A
ODIRDRVO = A
ODIRDRVP = A
ODTADRVA = A
ODTADRVB = A
ODTADRVC = A
ODTADRVD = A
ODTADRVE = A
ODTADRVF = A
ODTADRVG = A
ODTADRVH = A
ODTADRVI = A
ODTADRVJ = A
ODTADRVK = A
ODTADRVL = A
ODTADRVM = A
ODTADRVN = A
ODTADRVO = A
ODTADRVP = A
OVLYDIRA = Y
OVLYDIRB = Y
OVLYDIRC = Y
OVLYDIRD = Y
OVLYDIRE = Y
OVLYDIRF = Y
OVLYDIRG = Y
OVLYDIRH = Y
OVLYDIRI = Y
OVLYDIRJ = Y
OVLYDIRK = Y
OVLYDIRL = Y
OVLYDIRM = Y
OVLYDIRN = Y
OVLYDIRO = Y
OVLYDIRP = Y
OVLYDTAA = Y
OVLYDTAB = Y
OVLYDTAC = Y
OVLYDTAD = Y
OVLYDTAE = Y
OVLYDTAF = Y
OVLYDTAG = Y
OVLYDTAH = Y
OVLYDTAI = Y
OVLYDTAJ = Y
OVLYDTAK = Y
OVLYDTAL = Y
OVLYDTAM = Y
OVLYDTAN = Y
OVLYDTAO = Y
OVLYDTAP = Y
CRDATAF = N
DBLALV = Y



I keep wanting to blame this on SPR content, as daver2 suggests, but I can't reason it out. The SPR files are binary images with an appended bitmap to indicate where relocatable addresses are. So, the SPR cannot back-up the location counter like a REL file could. I could not find any such anomaly in the REL file, plus we know the SPR file is correct. I'm looking at my virtual H89 memory right now, after the GENCPM. Can't find the BIOS, but it is trial and error mostly. My thought is to either try running it under SID or else use the simulation debug tools to try and figure it out. Unfortunately, GENCPM is written in PL/M so it is more difficult to debug on a binary level.

Let me know if you've got the same results if you've tried building CPM3.SYS with GENCPM. I'm just dumping the output CPM3.SYS file and the corrupt jump table is at 0C80.

nockieboy
December 30th, 2017, 02:11 PM
I've made some progress. Using SID to run GENCPM, I was able to determine that the corruption (zeroing of 9 bytes) occurs somewhere between loading BNKBIOS3.SPR and relocating the image (exclusive). So, after the load the jump table is OK, but before the call to relocate it is corrupt. I'll run a few more times and see if I can bisect to where it is happening.

Just missed this with my last post - excellent news! But it's sounding like a bug with GENCPM then rather than a (more fixable) issue with the ZMAC/LINK outputs?

daver2
December 30th, 2017, 02:16 PM
I am looking through the PL/M source for GENCPM at the moment.

So, what you are saying is that "call load(.bios$fcb,.bios$atts);" seems to be OK whereas when we get as far as "call reloc$module(.bios$fcb);" it has gone south?

Between those two points are "call page$chop;" and 'some other stuff'.

EDIT: It is not necessarily a bug in GENCPM if it is being fed something 'duff' in the SPR file still. There seems to be a lot of 'maths' going on with the file attributes in GENCPM...

Dave

durgadas311
December 30th, 2017, 02:56 PM
I figured out the problem. Basically, the template BIOS I gave you had a bogus implementation for the "drvtbl" function and thus it sent GENCPM off into the weeds and corrupted the BIOS image in memory. I should have reviewed the docs more, and compared better to my old BIOSes. Anyway, here is a modified BIOS3 that fixes the drvtbl function and produces a non-corrupted CPM3.SYS.

42753

Basically, GENCPM (the only user of the "drvtbl" entry?) expects the returned address to be a pointer to a table of 16 pointers to DPHs, not a table of DPHs. Garbage in, garbage out.

daver2
December 30th, 2017, 03:08 PM
And I think I have found it in GENCPM.PLM in the need$tbl procedure:

call movef(9,.(0,0,0,0,0,0,0,0,0),dph$adr+2);

Dave

nockieboy
December 31st, 2017, 01:20 AM
Awesome stuff - that's sorted the issue with the jump table!! Well spotted, durgadas311 and thanks for the corrected bios. :bigups:

I'm still not out of the woods yet, though :( - I'm getting a CCP.COM error now (looks like the filename isn't being constructed properly?)


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F400 0C00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EE00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
BIOS3: Preparing MMU...
BIOS3: Initialising SIO...
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research

CP/M Error On /: Invalid Drive
BDOS Function = 15 File = CCP C.OM


It's looking for an invalid drive and a file called CCP C.OM? Is there a missing space in one of the ccp$fcb definitions somewhere? I've added a space into the filename here:


ccp$fcb: .DB 0,'CCP COM',0,0,0,0

There were only 3 chars (CCP) + 4 chars (spaces) before the COM - I'm guessing that the string should make up the 8+3 format for CPM? So I added an extra space after CCP to make 8 chars before COM, but it doesn't seem to have made any difference to the CCP C.OM issue... I'm guessing here, admittedly.

EDIT: Actually, perhaps it does make a difference. I've just tried launching CPMLDR again and this time there was no invalid drive or filename error - the system just seems to hang after the BIOS3 signon message with no prompt.

daver2
December 31st, 2017, 03:08 AM
Did you think it was going to work just like that! He he...

Yes, you need 8+3 characters for the filename to be correct. Don't forget you need to assemble, link and generate for the change to take effect. Many is the time I have made a change and missed a step out of the build process - only to get the same error again. Under these circumstances, I doubt myself and double-check the build process before trying to chase down a bug that should no longer exist.

So, we are now getting into the COLD BOOT entry of the 'real' BIOS. Yes?

If we know it gets into the BIOS entry point, does it get to the exit point? Can you print out a message before it exits. Also, can you do a hex dump of the first page of memory (from 0x0000) just before the exit?

Dave

durgadas311
December 31st, 2017, 03:32 AM
On thing I notice, examining the boot path, is that you are saving and restoring the stack pointer in both "boot" and "wboot". This should not be done - at least the restore of the SP before jumping to CCP. If you are restoring the loader SP at that point, you are trying to start the CCP with bogus stack set somewhere in the middle of CCP code. However, the first thing CCP does is set it's own stack so it probably doesn't matter - unless you catch an interrupt (in which case you corrupt the CCP).

So, as done for the loader, try to pinpoint just where things are hanging. Confirm that it actually makes it to the "JP ccp" instruction. Also, make sure Page 0 got initialized correctly, in both banks. Also, make certain you selected Bank 1 for loading the CCP and jumping to it.

EDIT: It looks like you are still in bank 0 when you load the CCP, as well as jump to it. That's not going to work.

nockieboy
December 31st, 2017, 03:59 AM
Did you think it was going to work just like that! He he...

I know, it was an amateur mistake to make expecting it all to work fine after the last bug... :rolleyes:


Yes, you need 8+3 characters for the filename to be correct. Don't forget you need to assemble, link and generate for the change to take effect. Many is the time I have made a change and missed a step out of the build process - only to get the same error again. Under these circumstances, I doubt myself and double-check the build process before trying to chase down a bug that should no longer exist.

So, we are now getting into the COLD BOOT entry of the 'real' BIOS. Yes?

Yes, that probably explains the change in output I'm getting now. Yes indeed, we're getting to cold boot as the BIOS is printing the "BIOS3: Preparing MMU..." etc strings to the console.


If we know it gets into the BIOS entry point, does it get to the exit point? Can you print out a message before it exits. Also, can you do a hex dump of the first page of memory (from 0x0000) just before the exit?

Okay, here's the latest console dump from CPMLDR with an updated BIOS3 that has the requested debug information:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F300 0D00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR ED00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
BIOS3: Preparing MMU...
BIOS3: Initialising SIO...
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
BIOS3: About to set IDE to 8-bit...
BIOS3: IDE set to 8-bit mode...
BIOS3: IDE no write-cache set...
BIOS3: Input channel buffers set...

BIOS3: Interrupts enabled, cold boot finished, loading CCP...
C303F30100C306EDF233AAA6A8800B
39CC62B3E2CBE0F8E0FA3C8A4E0C2A
E83AB2A2A8EA48BC8283A2C26BC88C
0922A2CB8F00823330BE8F08978AEE
CEFDDE2A0BE9F3B8B8ABE3A03AEFB8
768FB30AF8040EDB2A9A0001020303
ACFA00202020202020202020202000
000037002020202020202020202020
0000000000E8B2E30D0A20424E4B42
494F53332053505220204633303020
20304430300D0A20424E4B42494F53
332053505220204233303020203044
30300D0A2052455342444F53332053
50522020454430302020303630300D
0A20424E4B42444F53332053505220
20383530302020324530300D0A200A
0D2035394B205450410A0D24242424
2431C102CD000B0E0DCDCD020E0911
2502CDCD020E0F11AB01CDCD02FEFF
11CF01CAA201118000CD8F01CD9501
21800011C1020E067E1213230DC234
01CD95010E09118000CDCD023AC202
673AC102CD73013AC402B7CA5F0167
3AC302CD7301215D007EFE24C26F01
237EFE42CCA90131C502C9B7571E00
7C1767EB0180FF09EBD5E5CD8F01CD
9501E1D125C27A01C90E1ACDCD02C9
0E1411AB01CDCD02B711FA01C80E09
CDCD02F376FFC90043504D33202020
205359530100008026002700280057
0058000000000000001E0000000D0A
43504D4C4452206572726F723A2020
6661696C656420746F206F70656E20
43504D332E5359530D0A240D0A4350
4D4C4452206572726F723A20206661
696C656420746F2072656164204350
4D332E5359530D0A240D0A0A0A0A0A
0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A
0A0A0A0A43502F4D2056332E30204C
6F616465720D0A436F707972696768
742028432920313938322C20446967
6974616C2052657365617263680D0A
243032313138320000000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
004D0F02209D018801000100855F01
0013C03B00F3000000000000EB221F
0AEB79FE0EDAE50232220AAF32F709
3A1E0A32FE097B32FA092100002249
0422210A3922800331D203218E09E5
79FE32D20A034B211C03C30F03DE64
DADB075F160019195E23562A1F0AEB
E928042804FB032804280428042804
280428041F04280428042804400957
095D0928042804280428047B092804
280428042804810987092804280428
042804280428042804280428042804
280428042804280428042804280428
0428042804280428042804B702C7C7
C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7
C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7
C7C7C7C7C7C7C7C7C7C7C7C7C7C7C7
C7C7C7C7C754204F11770500000000
54204F117705160000004F10390659
068E093A2E04B7C2DE03C5CD0C0BC1
79211A0AFE7FC834FE20D0357EB7C8
79FE08C2F50335C9FE0AC03600C979
FE09C2D2030E20CDD2033A1A0AE607
C20104C9211B0A0ABEC803C54FCDFB
03C1C30F04EB4D44C30F04324904C9
3E01C32504000D0A42444F53204552
523A202453656C656374245065726D
2E240000012F04CD0F04013C04C360
04012F04CD0F04014304CD0F04F376
7B955F7A9C57D005C97B855F7A8C57
D004C90C0DC8298FC378041ABEC023
130DC8C37F040C0DC81A771323C38A
044ACD1B0B7CB5C85E235623232322
D009232322D209232323232323EB22
F80921D8090E0DCD89042AD809EB21
E5090E11CD89042AEA097C21FD0936
FFB7CAD504360037C9CD180BAF2AD0
097723772AD2097723772377C92103
0A5E23562346C9CDEA04CD270BB7C8
4FFE03DA57040E01C357042A230A0E
02CD66060600EB21030A7323722370
C92AD0094E2346C52AD2095E235623
462A030A3A050A4F7D937C9A7998E5
D247052AE509CD6504E1E32BE3C330
052AE509CD6E04E17D937C9A7998DA
5E05E323E3E5C34705E3E52AE509CD
6504E1D5C5E5EB2AF20919444D220E
0ACD1E0BD12AD009732372C1D12AD2
097323722370C179936F789A67CDAB
05444D2AF809EBCD300B4D4422100A
CD210B2ACA094D44C3240B3AF4094F
C3660621E7094E3A010AB71F0DC2B9
05473E08964F3A000A0DCAD005B717
C3C70580C92A1F0A11100019C9CDD2
05093AFD09B7CAE8056E60C9097E23
666FC9CDB20532FB094F0600CDDA05
22030A7DB4C93AE7094F2A030AAFCD
770422030A32050A22060A3AE8094F
3A010AA14732F60921030AB677C92A
1F0A110C0019C92A1F0A110F0019C9
CD2E06EB21110019C9CD36067E3201
0AEB7E32FF09CD26063AE909A63200
0AC9CD36060E013A010A8177EB3AFF
0977C90C0DC87CB71F677D1F6FC367
060C0DC829C374063A1E0AC54F2101
00CD7306C179B56F78B467C93A1E0A
4FCD66067DE601C92ACC093A090A85
6FD024C9CD26067EE61F77C97B956F
7A9C67C9D5110A00195E2356EBD1C9
CD06053AF509B7CACF063E03CD280A
C3DB06CDE10622CC09CD1A05CDF304
2A1C0AC3E7062ADE09CDB20622CA09
C921230A7E23BEC03CC921FFFF2223
0AC92AEC09EB2A230A2322230ACDAB
06DAF4063A230AE60306058705C213
0732090AB7C0C5CDBD06C1C9C5F53A
E9092F4779A04FF1A091E61FC1C9CD
36060E10410CC5C10DAF2B05BEC249
070DC23F077932FB093AFD09B778C2
56071FC5E56F26003AE709573E0792
4FCD6606453AE909B8E1DA3C07CD26
064E2FE61FA1B0C1C92A1F0A22250A
7932270ACDF406CDD7040E00CDFB06
CDEB06CADB072A250AEBCD98063A27
0A4F06007EFEE5CA8A0779B7CAD407
78FE0DCACD07FE0CCAC2071A96E67F
C28A07C3CD071AC54ECD2307C1B7C2
8A071323040DC3A807AF3249044704
C93EFF4704C325040E0FCD7A07C8CD
26067EF5CD9806EB2A1F0A0E20CD89
04CD34074FF1770600EB210300191A
91CA180878D212083E8046777832FC
09C932FC097EB7C03AFB09B7C83A22
0AFE0FC83680C9E53AFC09B7CA3D08
1103001977AF32FC09E1C9CD26067E
4F0CCD2307CA61083E1FA1770E0FCD
7A07CDE807CD3F06AF32010AC32504
34CD34074FBED26E0835C32904CD2C
08CDFF07C35708CD3F063A010A21FF
09BEDA9308FE80C22904CD3F083A49
04B7C22904CDEE05CA2904CD00063A
F509B7C2120ACDDB06CD1A05CDF304
C356063A1E0A3CCA4B043D21020ABE
C877572AC809CD8D065FD5CD9304E1
D24B042DC82AC8094D44CD7A0622C8
09C93AFA09321E0AC9AF32080AC312
093E80473D4F2A1F0A110700EB197E
A07EA177237EA032080A7EA177CDA3
06CD2E067EA0CA12097EA17032FC09
210000220A0A3EFF32210A2A1F0A7E
E61F3D32FA09FEFFCA36097E320A0A
CDDB08CDAF083E002A1F0A77C92100
0022C809AF321E0A3D32020A218000
221C0AC3DB06CDDB08C3AF08CDE208
CDE207CD6709C9CDEB06C8CD36067E
3CC277091B1B1A77E10E40C9CDE908
C377083A1E0AC32504EB221C0AC3DB
063A220AFE0FDABE093AFE09321E0A
3A210AB7CABE092A1F0A36003A0A0A
B7CAB00977233A080AB677CD2E063A
FC09B6772A8003F92A49047D44C901
000085F1190000670B690B00000000
330C0000B011D319E219FFFF008000
051F01FB07FF01F000000001000000
1D000000FF0400000080011D001D0B
00000B00000000000017001D003E01
CD2E0AC356060024008500AB01FF00
2800AB010F2ADE09C3310A2AE009F5
CD940A3A030A5FA0320B0A7BA13203
0A220C0ACDB20622CA09CD9B0AF1F5
FE04D25C0ACD7F04CA6C0AAFCDA40A
3E02CDAC0ACD9B0ACD890436003A0B
0A3C1180002180FF193DC2760AEB2A
CA0919F1FE03C28A0A22CC09C9EB2A
1C0A018000C34B0B3AF509472F4FC9
2A0C0A11020A0E04C91104002A0C0A
19C9F5CD1A05F13DF4F304CDA40A23
23110E0A0E04C38904000000000000
000000000000000000000000000000
000000000000000000000000000000
000000000000000000000000000000
0000000000000000000000C39B0CCD
880CCD880CCD880CC3490FCD880CCD
880CCD880CC3900FC3700FC39C0FC3
A10FC3A60FC3AE0FCD880CCD880CC3
AB0FCD880CCD880CCD880CCD880CCD
880CCD880CCD880CCD880CC3830CCD
880CCD880CCD880CCD880CCD880CCD
880CCD880C000000001600000B0000
0000330C0000B011D319E219FFFF00
00000000000000000000000000440C
0000B112D319E219FFFF0000000000
000000000000000000440C0000B213
D319E219FFFF000000000000000000
0000000000440C0000B314D319E219
FFFF00000000000000000000000000
00440C0000B415D319E219FFFF0000
000000000000000000000000440C00
00B516D319E219FFFF000000000000
0000000000000000440C0000B617D3
19E219FFFF00000000000000000000
00000000550C0000B718D319E219FF
FF00008000051F01FB07FF01F00000
00010000008000051F01FF07FF01F0
000000000000008000051F01FF04FF
01F0000000000000000000002F1C70
1C00180484011803E105EA001804C4
0118025003E105EAEBEDB0EBC90E2A
CD490FE12B2B2B7CCDDC0E7DCDDC0E
F376F3ED73F11B31F11BCD9C110C50
7265706172696E67204D4D552E2E2E
0D0A003E00D3383E11D3383E22D338
3E33D338CD9C110C53657474696E67
204D4D55206C6F636B20627974652E
2E2E0D0A00AF3255003E013256003E
023257003E03325800CD9C110C496E
697469616C6973696E672053494F2E
2E2E0D0A002A010011DD00197EFE38
CA280D3E84C32A0D3EC432700C216D
0C0E02060AEDB321770C0E03060CED
B33E00ED4721040E225000CD9C110C
5A3830204D494E49434F4D20494920
43502F4D20506C7573204C44524249
4F5320312E300D0A0D0A43502F4D20
506C757320436F7079726967687420
313938322028632920627920446967
6974616C2052657365617263680D0A
00CD91113E01D3113EEFD317CD9111
3E82D3113EEFD317AF32331C32741C
21F31B222F1C22311C21341C22701C
22721CED7BF11BED5EFBCD9C110C4C
445242494F532072657475726E696E
6720746F3A2000E17CCDDC0E7DCDDC
0EE5C9F5E597D302DB020F302B2A2F
1C233A690CBD200321F31B222F1CDB
00773A331C3C32331CFE3238083E05
D3023EE8D302E1F1FBED4D2A701C23
3A6B0CBDC2470E21341C22701CDB01
773A741C3C32741CFE32DA610E3E05
D3033EE8D3037EFE23CC6C0EE1F1FB
ED4DF3CD220FFE23CA8B0EFE25CA83
0E3A741CFE05D26D0EC9CD220FFE45
CC8C0EC9CD220FFE23CADB0E32751C
CD220FFE23CADB0E32761CCD030F32
680CCD220FFE23CADB0E32751CCD22
0FFE23CADB0E32761CCD030F32670C
2A670CE5CD220FE1FE23CADB0E7723
3A741CFE00C2C70EC932791CE6F00F
0F0F0FCDEB0E3A791CE60FFE0ADAF9
0ED609F640C3FB0EF6304FCD490F3A


CP/M Error On k: Invalid Drive
BDOS Function = 15 File = CCP .COM▒!▒▒▒,▒!▒▒"▒▒▒h▒\▒!
CP/M Error On ,: Invalid Drive
BDOS Function = 15 File = CCP .COM▒!▒▒▒,▒!▒▒"▒▒▒h▒\▒!▒


Latest BIOS3.ASM here so you can see how the debug information fits into the boot process: 42758

nockieboy
December 31st, 2017, 04:04 AM
I missed your post whilst writing mine, durgadas311 - so it looks like it's a memory bank issue then? So I need to add in a switch to Bank 1 before loading the CCP (as well as tidying up the stack issue)? What would be the best way to do that?

durgadas311
December 31st, 2017, 04:07 AM
I would suggest adding this to the start of ld_ccp:


LD A,1
CALL SELMEM

nockieboy
December 31st, 2017, 04:40 AM
Thanks durgadas311. Have added that in and some debug prints as well (which I've detailed below) and I get the following in the console - looks like it's not completing the load of CCP:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F400 0C00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EE00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...

Here's the relevant section from BIOS3.ASM to show you where the debug prints are located:


ld_ccp:

; DEBUG
CALL printInline
.TEXT "Loading CCP..."
.DB CR,LF,0

; Load CCP.COM into bank 1 and jump to it.
LD A,1
CALL SELMEM ; Switch to Bank 1

; DEBUG
CALL printInline
.TEXT "Bank 1 selected..."
.DB CR,LF,0

XOR A ; Zero extent
LD (ccp$fcb+15),A
LD HL,0 ; Start at beginning of file
LD (fcb$nr),HL
LD C,open$func ; Open the CCP.COM file
LD DE,ccp$fcb
CALL bdose ; BDOS will return to this CALL, not bdose as it uses a JP
INC A
JP Z,no$CCP ; If A is zero, CCP wasn't loaded successfully
LD DE,ccp
LD C,26 ; Set DMA address
CALL bdose
LD DE,128 ; Read up to 128 records (up to 16K)
LD C,44 ; Set multi-sector count
CALL bdose
LD DE,ccp$fcb ; Load it
LD C,20 ; Read record(s)
CALL bdose

IM 2
EI ; Enable interrupts

; DEBUG
CALL printInline
.TEXT "CCP loaded..."
.DB CR,LF,0

; Pass execution to CCP
JP ccp

daver2
December 31st, 2017, 04:57 AM
Ther's not much between the message being output (Bank 1 selected...) and the CALL bdose (which is probably what is going south).

What is the value in @mxtpa that it is going to call (display before calling of course).

Dave

nockieboy
December 31st, 2017, 05:05 AM
Ther's not much between the message being output (Bank 1 selected...) and the CALL bdose (which is probably what is going south).

What is the value in @mxtpa that it is going to call (display before calling of course).

Dave

Apparently:


@mxtpa = EE06

This is from this code:


ld_ccp:

; DEBUG
CALL printInline
.TEXT "Loading CCP..."
.DB CR,LF,0

; Load CCP.COM into bank 1 and jump to it.
LD A,1
CALL SELMEM ; Switch to Bank 1

; DEBUG
CALL printInline
.TEXT "Bank 1 selected..."
.DB CR,LF,0

CALL printInline
.TEXT "@mxtpa = "
.DB 0

LD HL,(@mxtpa)
LD A,H
CALL PHEX
LD A,L
CALL PHEX


XOR A ; Zero extent
LD (ccp$fcb+15),A
LD HL,0 ; Start at beginning of file
LD (fcb$nr),HL
LD C,open$func ; Open the CCP.COM file
LD DE,ccp$fcb
CALL bdose ; BDOS will return to this CALL, not bdose as it uses a JP
INC A
JP Z,no$CCP ; If A is zero, CCP wasn't loaded successfully
LD DE,ccp
LD C,26 ; Set DMA address
CALL bdose
LD DE,128 ; Read up to 128 records (up to 16K)
LD C,44 ; Set multi-sector count
CALL bdose
LD DE,ccp$fcb ; Load it
LD C,20 ; Read record(s)
CALL bdose

IM 2
EI ; Enable interrupts

; DEBUG
CALL printInline
.TEXT "CCP loaded..."
.DB CR,LF,0

; Pass execution to CCP
JP ccp

Which places the call firmly within RESBDOS3?


BNKBIOS3 SPR F400 0C00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EE00 0600
BNKBDOS3 SPR 8500 2E00

durgadas311
December 31st, 2017, 05:08 AM
I don't think this is the problem, but I see that you are setting interrupt mode and enabling interrupts *after* you've been calling the BDOS. Generally, you should have the entire hardware initialized *before* you start calling BDOS. Cold boot used to do the IM 2/EI before ld_ccp, perhaps it still does. The general expectation is that the system is fully functional before the first call into BDOS.

I think we've confirmed @mxtpa is correct, at least that should have been used to initialize the JMP at 0005H - which looks correct in the dump of Page 0 from previous runs.

Might be good to find out how far into loading the CCP you get. Perhaps a short message after each BDOS call returns.

nockieboy
December 31st, 2017, 05:16 AM
Might be good to find out how far into loading the CCP you get. Perhaps a short message after each BDOS call returns.

It's not getting past the first bdose call - I've added debug prints after each call (all three of them) in the routine and none are showing.

Is there any reason bdose is working like this?


bdose:
LD HL,(@mxtpa)
JP (HL)

Wouldn't it be easier to just call (@mxtpa) and stick a return in bdose?

durgadas311
December 31st, 2017, 05:25 AM
There is no indirect call on the Z80, so there is no "call (@mxtpa)". Keep in mind the 8080, and by inference the Z80, are not at all symmetrical instruction sets. The Z80 mnemonics give a false impression that there is symmetry.

I'm not sure why you need to change bdose. Perhaps you can explain what you think is wrong there.

Otherwise, assuming there are no bugs in the BDOS, I expect that the OPEN call is making some calls into the BIOS. You might start putting debug messages in some of those. SELDSK is probably the first one called, but eventually it will call READ to locate CCP.COM in the directory. Try and figure out how far it gets.

daver2
December 31st, 2017, 05:37 AM
+1.

The BDOS is probably trying to read the directory to find the CCP (or something else like that)...

One step at a time...

Some other processors could use any register and any addressing mode with any instruction. Not so the Z80.

Dave

nockieboy
December 31st, 2017, 05:47 AM
Okay, I've added a few debug prints to seldsk (and chgdsk by extension) and read, including one for the initial bank swap that read tries to do before reading data from the CF card. Here's the output:


CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
...jumped to chgdsk
read called...
read: Switching to Bank 00

It would appear that read is switching to Bank 0 before reading the data from the CF card...?? Is that right?

Here's the code that produced the above:


read:
PUSH AF
PUSH BC
PUSH HL

; DEBUG
CALL printInline
.TEXT "read called..."
.DB CR,LF,0

CALL cfWait
CALL setLBAaddr

LD A,CF_READ_SEC
OUT (CF_COMMAND),A

CALL cfWait

LD A,(dmaBank)

; DEBUG
; DEBUG
CALL printInline
.TEXT "read: Switching to Bank "
.DB 0
LD A,(dmaBank)
CALL PHEX

CALL selmem ; could avoid this if dmaBank == 0
LD B,0 ; 256 bytes at a time
LD C,CF_DATA
LD HL,(dmaAddr)
INIR ; do 256 bytes
INIR ; do another 256 bytes = 512
XOR A ; back to Bank 0...
CALL selmem ; could avoid this if dmaBank == 0

POP HL
POP BC
POP AF

XOR A
LD (erflag),A
RET

daver2
December 31st, 2017, 05:51 AM
I was just looking at something 'strange' in seldsk.

If A is 0 (drive A?) then the bit of code later will point HL at the wrong place won't it? It will take an A register value of 0 as being 256...

Dave

durgadas311
December 31st, 2017, 05:57 AM
The directory buffers - used only by BDOS internally - are in Bank 0 so that switch to bank 0 makes sense. The first read should be of the first directory sector into an internal buffer. I'm assuming the READ actually completes and returns to BDOS, but knowing that is critical.

Maybe some checking of the dir buffer structures is in order, or confirmation that the DMa address is correct/sane.

durgadas311
December 31st, 2017, 05:59 AM
Yes, daver2, I think you are right. There should have been an INC A before the start of that loop. I think I remember planning to add that, but obviously I didn't. That code should probably be changed to use "dtbl" instead, but it should work as-is (with the INC added).

nockieboy
December 31st, 2017, 06:02 AM
Yes, it appears that read completes:


CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
...jumped to chgdsk
read called...
read: Switching to Bank 00
read completed, erflag = 00

nockieboy
December 31st, 2017, 06:05 AM
Yes, daver2, I think you are right. There should have been an INC A before the start of that loop. I think I remember planning to add that, but obviously I didn't. That code should probably be changed to use "dtbl" instead, but it should work as-is (with the INC added).

I've added the INC A in - just trying to get the SBC to reboot and try out the new BIOS...

nockieboy
December 31st, 2017, 06:30 AM
Wow - that was annoying. What a time for the serial interface to start playing up. :confused: :mad:

Here's an updated console log after I've added the INC A here (that's right, isn't it?):


seldsk:
; DEBUG
CALL printInline
.TEXT "seldsk called..."
.DB CR,LF,0

LD HL,$0000 ; error return
LD A,C
CP 8 ; 16 for 128MB disk, 8 for 64MB disk
JR C,chgdsk ; if invalid drive will give BDOS error
XOR A ; else reset default back to a:
LD (sekdsk),A
RET

chgdsk:
; DEBUG
CALL printInline
.TEXT "...jumped to chgdsk"
.DB CR,LF,0

LD (sekdsk),A
LD HL,dpbase
LD BC,dphlen
INC A <---- added
chgdk0:
ADD HL,BC
DEC A
JR NZ,chgdk0
RET

Log:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F300 0D00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR ED00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
...jumped to chgdsk
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
First bdose call completed...
BIOS Error on A: No CCP.COM file

Seems that's fixed the 'invalid drive' error, the first bdose call is completing, but it's now throwing an error as a result of:


INC A
JP Z,no$CCP ; If A is zero, CCP wasn't loaded successfully

...which comes directly after the first bdose call.

durgadas311
December 31st, 2017, 06:37 AM
Rats, that routine needs a better fix. Let's replace it with this:


chgdsk:
LD (sekdsk),A
ADD A,A
LD C,A
LD B,0
LD HL,dtbl
ADD HL,BC
LD E,M
INC HL
LD D,M
EX HL,DE
RET

Daver2: pls review and make sure that's correct...

nockieboy
December 31st, 2017, 06:42 AM
Rats, that routine needs a better fix. Let's replace it with this:


chgdsk:
LD (sekdsk),A
ADD A,A
LD C,A
LD B,0
LD HL,dtbl
ADD HL,BC
LD E,M
INC HL
LD D,M
EX HL,DE
RET

Daver2: pls review and make sure that's correct...

LD E,M and LD D,M aren't valid Z80 opcodes... EDIT: Do you mean L instead of M?

durgadas311
December 31st, 2017, 06:45 AM
Yes, I guess that's "(HL)" instead of "M".

nockieboy
December 31st, 2017, 06:48 AM
Okay, that gives me:


Loading CCP...
Bank 1 selected...
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
read called...
read: Switching to Bank 00
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read: Switching to Bank 01
read completed, erflag = 00
read called...
read: Switching to Bank 01
read completed, erflag = 00
read called...
read: Switching to Bank 01
read completed, erflag = 00
read called...
read: Switching to Bank 01
read completed, erflag = 00
read called...
read: Switching to Bank 01
read completed, erflag = 00
read called...
read: Switching to Bank 01
read completed, erflag = 00
CCP loaded...


... recurring. Had to shut the SBC off to stop the flood. ;) Don't I need to switch to Bank 1 before I
JP ccp though?

durgadas311
December 31st, 2017, 07:00 AM
What does the "CCP loaded" message mean? Is that immediately before the "JP ccp"? It's possible that the jump to CCP is crashing (possibly inside the CCP) and ending up jumping to 0000H and rebooting, causing the looping. I only see 6 sectors being read, which seems a little small for CCP.COM. Check to be sure that your CCP.COM is only 3072 bytes in length. It could be missing a record at the end (error during transfer?). My CCP.COM from the distro images is 3200 bytes long.

nockieboy
December 31st, 2017, 07:04 AM
What does the "CCP loaded" message mean? Is that immediately before the "JP ccp"? It's possible that the jump to CCP is crashing (possibly inside the CCP) and ending up jumping to 0000H and rebooting, causing the looping. I only see 6 sectors being read, which seems a little small for CCP.COM. Check to be sure that your CCP.COM is only 3072 bytes in length. It could be missing a record at the end (error during transfer?). My CCP.COM from the distro images is 3200 bytes long.

CCP.COM is showing up as 4K in size in CP/M. Here's the latest cold (and warm) boot code to show you where the messages are:


boot:
DI ; Disable interrupts.

LD (save$stack),SP ; Save the current stack
LD SP,boot$stack ; Set SP to internal stack

; Set up the memory map as follows:
; Area 0 - Bank 0 (RAM)
; Area 1 - Bank 1 (RAM)
; Area 2 - Bank 2 (RAM)
; Area 3 - Bank 3 (RAM)

; Bank 0 mapping
LD A,$00
OUT (MMU_IO),A ; Set Area 0 to Bank 0
LD A,$11 ;
OUT (MMU_IO),A ; Set Area 1 to Bank 1
LD A,$22 ;
OUT (MMU_IO),A ; Set Area 2 to Bank 2
LD A,$33 ;
OUT (MMU_IO),A ; Set Area 3 to Bank 3

; Set up Page Zero
CALL init_pg0

; Interrupt vector relocated to safe memory
LD HL,INTVEC
LD A,H ; high byte of INTVEC
LD I,A
LD A,L
LD (sioBi+$07),A ; Set the interrupt low-byte vector in sioBi data block

; Initialise SIO
LD A,(CLKSPD) ; Get clock from 2.2 BIOS loc
CP '8' ; 8 MHz clock - set baud at half default
JP Z,baud_8
baud_4:
LD A,$84 ; CLK/32, 1 stop bit, no parity
JP baudXt ; Jump to set baud rate
baud_8:
LD A,$C4 ; CLK/64, 1 stop bit, no parity
baudXt:
LD (sioAb),A
LD HL,sioAi
LD C,SIOA_C
LD B,sioAz
OTIR
LD HL,sioBi
LD C,SIOB_C
LD B,sioBz
OTIR

CALL printInline
.DB FF
.TEXT "Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017"
.DB CR,LF
.DB CR,LF
.TEXT "CP/M Plus "
.TEXT "Copyright"
.TEXT " 1982 (c) by Digital Research"
.DB CR,LF,0

CALL cfWait
LD A,CF_8BIT ; Set IDE to be 8-bit
OUT (CF_FEATURES),A
LD A,CF_SET_FEAT
OUT (CF_COMMAND),A

CALL cfWait
LD A,CF_NOCACHE ; No write cache
OUT (CF_FEATURES),A
LD A,CF_SET_FEAT
OUT (CF_COMMAND),A

; Set up input channel buffers
XOR A
LD (serABufUsed),A
LD (serBBufUsed),A
LD HL,serABuf
LD (serAInPtr),HL
LD (serARdPtr),HL
LD HL,serBBuf
LD (serBInPtr),HL
LD (serBRdPtr),HL

IM 2
EI ; Enable interrupts

JP ld_ccp

wboot:
LD (save$stack),SP ; Save the current stack
LD SP,boot$stack ; Set SP to internal stack

; Make certain Page Zero is initialized in all banks.
CALL init_pg0

IM 2
EI ; Enable interrupts

ld_ccp:

; DEBUG
CALL printInline
.TEXT "Loading CCP..."
.DB CR,LF,0

; Load CCP.COM into bank 1 and jump to it.
LD A,1
CALL SELMEM ; Switch to Bank 1

; DEBUG
CALL printInline
.TEXT "Bank 1 selected..."
.DB CR,LF,0

XOR A ; Zero extent
LD (ccp$fcb+15),A
LD HL,0 ; Start at beginning of file
LD (fcb$nr),HL
LD C,open$func ; Open the CCP.COM file
LD DE,ccp$fcb
CALL bdose ; BDOS will return to this CALL, not bdose as it uses a JP

; DEBUG
CALL printInline
.TEXT "First bdose call completed..."
.DB CR,LF,0

INC A
JP Z,no$CCP ; If A is zero, CCP wasn't loaded successfully
LD DE,ccp
LD C,26 ; Set DMA address
CALL bdose

; DEBUG
CALL printInline
.TEXT "Second bdose call completed..."
.DB CR,LF,0

LD DE,128 ; Read up to 128 records (up to 16K)
LD C,44 ; Set multi-sector count
CALL bdose

; DEBUG
CALL printInline
.TEXT "Third bdose call completed..."
.DB CR,LF,0

LD DE,ccp$fcb ; Load it
LD C,20 ; Read record(s)
CALL bdose

; DEBUG
CALL printInline
.TEXT "CCP loaded..."
.DB CR,LF,0

; Pass execution to CCP
JP ccp

nockieboy
December 31st, 2017, 07:06 AM
Don't know if this helps?


A>stat ccp.com

Recs Bytes Ext Acc
25 4k 1 R/W A:CCP.COM

durgadas311
December 31st, 2017, 07:08 AM
Note, "4K" is the allocation size of CCP.COM, the number of records would be a better measure. If it is less than 25 records, that would be suspicious. For 25 records, that is 6.25 physical sectors so it seems suspicious that only 6 reads are done (there should be 7).

durgadas311
December 31st, 2017, 07:09 AM
OK, so 25 records is correct. We now need to figure out why only 6 reads were done.

daver2
December 31st, 2017, 07:24 AM
We don't know if BDOS function 20 is actually working correctly or returning an error!

Can you display the value of Registers A and H when BDOS function 20 returns please. Let CP/M try and tell us why it is not happy!

Dave

durgadas311
December 31st, 2017, 07:25 AM
Also, HL will contain info on how many records were read.

nockieboy
December 31st, 2017, 07:29 AM
We don't know if BDOS function 20 is actually working correctly or returning an error!

Can you display the value of Registers A and H when BDOS function 20 returns please. Let CP/M try and tell us why it is not happy!

Dave

No problem. This time the console didn't keep repeating - what's below is all that was output:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F400 0C00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EE00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01CCP loaded...
Loading CCP...
Bank 1 selected...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01CCP loaded...

So it appears A contains 01 after BDOS 20 returns..? NB: I've removed some unnecessary debug prints since the last log print.

daver2
December 31st, 2017, 07:48 AM
A status of 01 after a BDOS 20 call means "I read less than 128 records". This is not actually an error...

But why did it read the CCP twice (unless it tries to read it to both banks)?

I also don't like the fact that it keeps doing different things. This implies we have a memory-type issue somewhere (i.e. Something is using uninitialised memory). Can I suggest trying a few boots in between turning the power off and see what it does each time. These are the worst errors to track down.

The first load of the CCP does 7 reads. The subsequent load of the CCP only does 6 reads. Where are you setting the 'ex' byte of the ccp$fcb to 0? It starts off as 0; but doesn't appear to be cleared to 0 otherwise. It shouldn't be anything other than 0 though... You are setting the 'rc' byte to 0 I note.

Dave

nockieboy
December 31st, 2017, 07:50 AM
Sorry daver, missed your questions about H and L:


After BDOS 20, A = 01
HL = 1901

This time around, however, the console output carried on with the following:


Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...
Loading CCP...
Bank 1 selected...
seldsk called...

With this next bit repeating constantly:


CP/M Error On K: Invalid Drive
BDOS Function = 15 File = CCP .COMLoading CCP...
Bank 1 selected...
seldsk called...

nockieboy
December 31st, 2017, 07:53 AM
Annoyingly, I've just restarted the SBC and the log doesn't continue forever this time... :/ I think perhaps you're right about the uninitialised memory problem.


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F300 0D00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR ED00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...
00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...

After BDOS 20, A = 01
HL = F9F6
CCP loaded...
Loading CCP...
Bank 1 selected...
00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...

After BDOS 20, A = 01
HL = F9F6
CCP loaded...

Current BIOS3.ASM source: 42761

daver2
December 31st, 2017, 08:02 AM
Something is screwed up - but the darn thing does different things every time we test it. Not good! I think I need some tea. Can you post the latest state of the BIOS source and I will have a quiet read after tea.

Can I suggest you check your diagnostic routines to make sure they aren't potentially corrupting registers. I think I may have noticed that displaying the HEX value of a register may change the C register by accident?

Can I also suggest for now that you DON'T enable interrupts after loading the CCP. It may just be that the diagnostic output may be causing a serial interrupt that is being responded to and corrupting us. Just a thought in passing...

Dave

nockieboy
December 31st, 2017, 08:09 AM
Something is screwed up - but the darn thing does different things every time we test it. Not good! I think I need some tea. Can you post the latest state of the BIOS source and I will have a quiet read after tea.

Can I suggest you check your diagnostic routines to make sure they aren't potentially corrupting registers. I think I may have noticed that displaying the HEX value of a register may change the C register by accident?

Can I also suggest for now that you DON'T enable interrupts after loading the CCP. It may just be that the diagnostic output may be causing a serial interrupt that is being responded to and corrupting us. Just a thought in passing...

Dave

Source is linked in my previous post - must have edited it in whilst you were writing. ;)

Yes, you're right, PHEX overwrites the C register - I've protected BC now by PUSHing it at the start and POPing at the end of PHEX. DI'd interrupts - roger.

nockieboy
December 31st, 2017, 08:16 AM
Yeah, weird stuff is happening and it's likely because of my diagnostic prints...

Latest console log:


CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 0read called...
read completed, erflag = 0▒Bread called...
read completed, erflag = 0

This is because I've modified PHEX: to try and protect the C register as below:


;----------------------------------------------------------------------------------------------
; PHEX takes A and prints its ASCII representation (2 chars)
; Preserves A
;----------------------------------------------------------------------------------------------
PHEX:
PUSH BC
LD (PHX_BUF),A ; Save A
AND 0F0h
RRCA
RRCA
RRCA
RRCA
CALL phex1
PUSH BC
LD A,(PHX_BUF) ; Restore A
phex1:
AND 00Fh
CP 00Ah
JP C,phex2
SUB 009h
OR 040h
JP phex3
phex2:
OR 030h
phex3:
LD C,A
CALL conout
LD A,(PHX_BUF) ; Restore A
POP BC
RET

daver2
December 31st, 2017, 08:21 AM
Thanks, didn't see that.

What I meant to say (regarding the interrupts) was "don't 'EI' them just before the 'JP ld_ccp'"...

The problem may lie anywhere where the interrupts are enabled - so don't enable them in the first place!

Eventually (hopefully) we'll get the "A>" prompt whereupon we can start playing with the interrupts...

Dave

daver2
December 31st, 2017, 08:25 AM
Only push/pop BC around the bit of code after label phex3. Don't try to be too clever!

What does conout do with registers?

Dave

nockieboy
December 31st, 2017, 08:27 AM
Okay, I've tweaked the PHEX code to preserve the C register without using the stack. Here's the result:


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F300 0D00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR ED00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...
%
CPMLDR error: failed to read CPM3.SYS

I'm losing my mind with this now - might have to take a break and leave it until next year before I look at it again. ;) Plus I need to help the boss preparing foodstuffs for a party with the family tonight, so I'm going to call this for moment and resume tomorrow, maybe, depending how the hangover feels. :D I'll try running it through a few power cycles to see if the console output is consistent and post the results tomorrow.

Thanks for all your help today - it's been much appreciated. Wishing you both a happy New Year and a good evening of fun with whatever you've got planned. :D

Oh, btw - updated PHEX code:


PHEX:
LD (PHX_BUF),A ; Save A
LD A,C
LD (PHX_C_BUF),A ; Save C
LD A,(PHX_BUF)
AND 0F0h
RRCA
RRCA
RRCA
RRCA
CALL phex1
LD A,(PHX_BUF) ; Restore A
phex1:
AND 00Fh
CP 00Ah
JP C,phex2
SUB 009h
OR 040h
JP phex3
phex2:
OR 030h
phex3:
LD C,A
CALL conout
LD A,(PHX_C_BUF) ; Restore C
LD C,A
LD A,(PHX_BUF) ; Restore A
RET

PHX_C_BUF: .db 0

Yeah, I've spotted the mistake too, Dave - after reading your post about pushing/popping around phex3. I was aware of this with the PUSH/PULL, but forgot when I switched over to using a byte of memory to store the value of C.. D'oh!

daver2
December 31st, 2017, 08:32 AM
Same to you.

We don't have anything planned for tonight - we don't go in for New Year much. TV film and some nibbles probably.

I'll go back to modifying NAS-DOS for my NASCOM 2 to use an SD card...

Must remember that drives are numbered 0... under NAS-DOS and not A... as per CP/M!

Dave

daver2
December 31st, 2017, 08:35 AM
The percent sign is interesting in your last post!!! Where did that come from I ask myself?

Dave

durgadas311
December 31st, 2017, 09:14 AM
Interesting that it seems to have ended up in the loader after jumping to CCP... perhaps it is still in Bank 0 (where the remnants of the loader are probably still).

Also, if you are using a location of memory to store C that makes the routine such that it cannot be re-entrant anymore. That may not affect this code, but just a warning. Using the stack would eliminate that, but also uses more stack and changes the way you have to write the routine.

daver2
December 31st, 2017, 09:32 AM
I was thinking whilst I was doing the washing up...

I was just about to mention myself about not using static variables to hold values because of re-entrancy problems. As stated, it shouldn't cause a problem in what you are doing...

I think the bit of code you were looking for was:



phex3:
PUSH BC
LD C,A
CALL conout
POP BC


The other thing is that you may be running out of stack space itself. You have what looks to be 64 bytes of stack space = 32 stack elements. You might like to increase this a bit to be safe. We are using quite a lot of stack for diagnostic purposes after all... We can always reduce the stack space later when the BIOS is working. I also like to use a stack check mechanism just to make sure we aren't running out of stack space. In your case you will crash through the SIO stuff which I don't think we are using yet?

My own stack check code stores a constant just below the stack area which I then routinely check for being corrupt. I also put a few stack elements below that so I have some valid stack elements to print out my 'last will and testament' to the fact that we have run out of stack space before HALting...

The other usual trick I do (!) is to PUSH more element than I POP off the stack (i.e. I forget about something). The stack gets lower and lower and ... lower and lower and ... crash!

Dave

nockieboy
January 1st, 2018, 06:23 AM
Same to you.

We don't have anything planned for tonight - we don't go in for New Year much. TV film and some nibbles probably.

I'll go back to modifying NAS-DOS for my NASCOM 2 to use an SD card...

Must remember that drives are numbered 0... under NAS-DOS and not A... as per CP/M!

Dave

Oh we don't bother that much either - just spent the evening with the boss's sister and her hubby and the kids.

The NASCOM is an intriguing machine - I didn't even know they existed until about a year go when I embarked on building this Z80-based SBC myself. Mind you, I'd have been a little too young when they first came out - had to learn to walk and talk before I developed an interest in computers! ;)


The percent sign is interesting in your last post!!! Where did that come from I ask myself?

Dave

I think that can be safely ignored. I've upped the stack size to 128 bytes, made the PUSH/PULL alteration to PHEX and I've just run through the process of launching CPMLDR from power-on 6 times, to see if the console log output is consistent. The results aren't great.

Out of 6 attempts to run CPMLDR, 4 result in the following output:


CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...


One did the above, with this on the end:


Loading CCP...
Bank 1 selected...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...

And the last one did this - almost appearing to work, with the appearance of the prompt at the end, but the system was frozen:


CP/M Plus Copyright 1982 (c) by Digital Research
Loading CCP...
Bank 1 selected...
seldsk called...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...
L!d
After BDOS 20, A = 01
HL = 0001
CCP loaded...
Bank 1 selected...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
First bdose call completed...
Second bdose call completed...
Third bdose call completed...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

After BDOS 20, A = 01
HL = 1901
CCP loaded...
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00
read called...
read completed, erflag = 00

No space
A>


So, with the lack of consistency in the results, I'm worried that this is an issue we'll never get to the bottom of. :/ I've included the full BIOS3.ASM file in this post as it exists currently, so you've got the latest version of it and the code that produces the above output. File is here: 42784


Interesting that it seems to have ended up in the loader after jumping to CCP... perhaps it is still in Bank 0 (where the remnants of the loader are probably still).

Also, if you are using a location of memory to store C that makes the routine such that it cannot be re-entrant anymore. That may not affect this code, but just a warning. Using the stack would eliminate that, but also uses more stack and changes the way you have to write the routine.

Yes, I've doubled the stack size and switched back to using the stack to protect the contents of BC when using PHEX. Again, the bank issue is interesting and perhaps is a light at the end of the tunnel - if the wrong bank is selected when the system tries to execute a piece of code in it or retrieve data from it, that would explain the inconsistency in the results of the console outputs...


I also like to use a stack check mechanism just to make sure we aren't running out of stack space. In your case you will crash through the SIO stuff which I don't think we are using yet?

The SIO stuff will have been used by the time the stack overflows into it (in theory) as the SIO is set up from those tables almost at the start of cold boot.


My own stack check code stores a constant just below the stack area which I then routinely check for being corrupt. I also put a few stack elements below that so I have some valid stack elements to print out my 'last will and testament' to the fact that we have run out of stack space before HALting...

Haha! Last will and testament... love it. :) That's not a bad idea if stack problems are suspected, will pop that onto a shelf in my memory somewhere and hopefully not forget it. ;)


The other usual trick I do (!) is to PUSH more element than I POP off the stack (i.e. I forget about something). The stack gets lower and lower and ... lower and lower and ... crash!

Dave

Oh yes, I've done that a few times when writing the monitor program for my SBC. I borrowed from the NASCOM BASIC source code to get a full command-line interpreter up and running and whilst writing various commands and utilities for the monitor program, I was having issues with some commands not handling the stack synchronously depending on how they were called (internally or by the user via the CLI) - took a while and a few paracetamol to solve those issues. ;)

daver2
January 1st, 2018, 07:51 AM
That's interesting...

You did get the prompt at one attempt!

So, assuming you never enabled the interrupts like I suggested, this would have been expected behaviour!

The "No space" message implies that something is still wrong with the disk geometry or something somewhere.

Can I suggest the following?

Modify the console status and input/output operation of the BIOS for the time being to be polled rather than interrupt driven. This should allow you to enter CP/M commands (on the odd occasions you do get the prompt) and this may allow us to get a bit further. We can then update to use interrupts later. That will inevitably produce its own problems...

I know it will be a 'ball ache' if it only gets to the prompt 1 in every 6 ish times - but it will allow progress.

In the meantime, we can check the current BIOS source and see if we can track down the problem with a consistent boot.

I notice that it still read the CCP twice - once into bank 0 with a 7-sector read and then into bank 1 with a 6-sector read???

It may be useful to know which track, sector, bank and transfer address is being used for each disk transfer (i.e. expand the diagnostic information at the beginning of every sector read).

Dave

nockieboy
January 1st, 2018, 08:25 AM
That's interesting...

You did get the prompt at one attempt!

So, assuming you never enabled the interrupts like I suggested, this would have been expected behaviour!

The "No space" message implies that something is still wrong with the disk geometry or something somewhere.

Can I suggest the following?

Modify the console status and input/output operation of the BIOS for the time being to be polled rather than interrupt driven. This should allow you to enter CP/M commands (on the odd occasions you do get the prompt) and this may allow us to get a bit further. We can then update to use interrupts later. That will inevitably produce its own problems...

I know it will be a 'ball ache' if it only gets to the prompt 1 in every 6 ish times - but it will allow progress.

In the meantime, we can check the current BIOS source and see if we can track down the problem with a consistent boot.

I notice that it still read the CCP twice - once into bank 0 with a 7-sector read and then into bank 1 with a 6-sector read???

It may be useful to know which track, sector, bank and transfer address is being used for each disk transfer (i.e. expand the diagnostic information at the beginning of every sector read).

Dave

Righto - re: changing the console IO to be polled instead of interrupt-driven... Where do I start with that? If I keep the interrupts disabled, data will still stream into the SIO - so how do I tell CP/M that it needs to poll const: regularly and call conin: if there's anything in the buffer? Not sure where to start with that.

I'm adding extra debug info to the rest of the BIOS at the moment - where would I get the extra info from that you require? setrk:, setsec:, setdma: and setbnk: look like good candidates?

nockieboy
January 1st, 2018, 08:40 AM
:(

Looks like I've managed to erase everything from my CP/M A: drive...

nockieboy
January 1st, 2018, 09:09 AM
Right, well, unfortunately due to the above accident (clearing my A drive) I now have no way of getting files into CP/M. This is a problem almost as bad as bricking a phone or tablet. The original method I used to get the file into CP/M (DOWNLOAD.COM) that is used to transfer all subsequent files to CP/M unfortunately no longer works, as I have modified and improved the hardware of the SBC to the extent that the old method will no longer work. I will have to have a think about this and write something in the monitor program to transfer an Intel Hex file to CP/M in the RAM.

Yes, I could have (and should have) backed up all the A: drive files into another drive (B: and C: are fine, but there's nothing in them that will me with this problem.)

So further development of the CP/M 3 BIOS will have to go on hold until I can sort this issue out. I'm just off to bang my head against a wall for a bit...

daver2
January 1st, 2018, 10:05 AM
Sorry to hear about the accident :-(.

CP/M will poll the BIOS for characters anyhow - so there is nothing further that you need to do to to persuade it to do it!

Yes, all the existing entry points into the BIOS provide the necessary debug information. If you think about it, they are the same data points you need within the READ routine to actually read a sector in the first place.

Dave

gertk
January 1st, 2018, 10:12 AM
Ah, that's a shame, I am following this thread to see if I could manage to get CP/M running on my homebrew Z80 VGA computer.. I have placed a DiskOnChip 2000 with a simple bootstrap that redirects to the (Z80) boot/monitor rom on the VGA card.

I would love to get CP/M on that: http://kgelabs.nl/?p=147

Hope you can manage to get it up and running again

nockieboy
January 1st, 2018, 10:55 AM
Sorry to hear about the accident :-(.

CP/M will poll the BIOS for characters anyhow - so there is nothing further that you need to do to to persuade it to do it!

Yes, all the existing entry points into the BIOS provide the necessary debug information. If you think about it, they are the same data points you need within the READ routine to actually read a sector in the first place.

Dave

Hmm - well the accident was as result of the most recent CPMLDR attempts - not something I did in error. :/

Anyhow, I've got a workable solution (I think) - I would just like to pick your brains first, Dave, before I try it?

The code snippet below is a new routine I'm working on in my SBC's monitor ROM code. The notes say it all, really, but what I'm trying to achieve is to copy a block of code from 4100H-42BFH to 0100H in RAM Bank 0 (which is 0000-3FFFH for CP/M). The DMI (monitor ROM program) runs in Area 0 (0000-3FFFH), so I've had to copy a small program to 5000H which will swap Area 0 with the DMI ROM to RAM Bank 0, then copy 4100-4300H to 0100-0300H.

This routine is run from the monitor ROM, AFTER CP/M has been successfully loaded and the system soft-reset. So CP/M is still in memory, but the monitor code takes an Intel Hex stream (the DOWNLOAD.COM file I mentioned earlier) and puts it into RAM at 4100H. My new routine will then switch out the ROM and map the low memory for CP/M back in, whilst the program running from 5000H relocates the Intel Hex data from 4100 to 0100h. This is essentially identical to the method Grant Searle uses in his minimal SBC design (http://searle.hostei.com/grant/cpm/index.html) - but mine uses banked RAM which is why his method will no longer work on my system.

When this is done, I can follow the old method to get DOWNLOAD.COM onto the drive - basically just by typing 'SAVE 2 DOWNLOAD.COM'.

That's the plan, anyway. But as my new bit of code requires a bit of shuffling of execution code, stacks and address maths, I thought I'd run it past you first for your opinion. :)


;------------------------------------------------------------------------------
; INSTALL
; Copies install_prog to 5000H and passes execution to it.
; install_prog sets up its own stack, maps Bank 0 to Area 0 (switching out the
; ROM) and copies RAM from 4100H-4300H to Bank 0, 0100H-0300H before passing
; execution over to CP/M (which needs to be resident in memory already).
;------------------------------------------------------------------------------
INSTALL:
POP HL ; Dump CLI pointer from stack
LD HL,install_prog ; Source address
LD DE,5000H ; Destination address in RAM
LD BC,[install_stack-install_prog]
LDIR ; Copy
JP 5000H ; Jump to install_prog in RAM

install_prog: LD SP,5064H+[inst_stack-install_prog]
LD A,$38
LD C,A
XOR A
OUT (C),A ; Map Area 0 -> Bank 0
LD HL,4100H ; Set source address
LD DE,0100H ; Set destination address
LD BC,0200H ; Set copy size
LDIR ; Copy

inst_stack: .EQU $

nockieboy
January 1st, 2018, 11:03 AM
Forgot to mention - haven't added the last part where it jumps to E600, which hopefully will restore control to CP/M and allow me to access the CCP and save the DOWNLOAD.COM file.

nockieboy
January 1st, 2018, 11:33 AM
Ah, that's a shame, I am following this thread to see if I could manage to get CP/M running on my homebrew Z80 VGA computer.. I have placed a DiskOnChip 2000 with a simple bootstrap that redirects to the (Z80) boot/monitor rom on the VGA card.

I would love to get CP/M on that: http://kgelabs.nl/?p=147

Hope you can manage to get it up and running again

Don't worry gertk - will have it up and running soon (with a little luck). I've got a plan to get the key file I need onto my CP/M drive. Once that's working, I'll have it up and running again in no time.

durgadas311
January 1st, 2018, 01:26 PM
Just a word of caution, if you are doing what I think you said. By loading a program into 4100H and then mapping that into area 0000H, you are no longer operating with the standard memory map. You will have to work out a way to restore the original memory or communicate that "non standard" memory map to CP/M so that it knows what it is. Too bad the hardware doesn't support "write under ROM" or "direct bank-to-bank copy" so that you can write something into memory at 0000H while the ROM is still running there.

Chuck(G)
January 1st, 2018, 01:38 PM
On a related subject, can anyone tell me what the advantage of CP/M 3.0/Plus is over CP/M 2.2? You're still restricted to a single task; you get a few more features that few programs take advantage of, and your TPA memory footprint can be somewhat larger. Have I missed anything?

I've got a couple of machinea that run 3.0 and, for the life of me, I can't figure out what makes it worth the trouble. You don't need CP/M to manage the extra memory used for a RAMDisk...

MP/M is a different kettle of fish--mutli-tasking, multi-user.

nockieboy
January 1st, 2018, 01:44 PM
Just a word of caution, if you are doing what I think you said. By loading a program into 4100H and then mapping that into area 0000H, you are no longer operating with the standard memory map. You will have to work out a way to restore the original memory or communicate that "non standard" memory map to CP/M so that it knows what it is. Too bad the hardware doesn't support "write under ROM" or "direct bank-to-bank copy" so that you can write something into memory at 0000H while the ROM is still running there.

It shouldn't be an issue - hopefully. Here's how it works, step by step:

1) SBC powers up into monitor ROM. Memory map at power-on is Area 0 = Bank 0F, Areas 1-3 = Banks 1-3. The ROM monitor uses 4000-40FF for stack and various static vars.
2) User runs CPM. This switches the ROM out by mapping Area 0 to Bank 0 (RAM) for 64K of contiguous SRAM.
3) CPM 2.2 loads to CCP.
4) User soft-resets the computer (memory is intact) and as step 1 above, the monitor ROM loads up (as Bank 0F in Area 0.)
5) User uploads the Intel Hex format data for the CP/M file DOWNLOAD.COM. This is written to RAM (Bank 1) from 4100-42BFH (this is defined in the Intel Hex file, not of my making.)
6) User runs the new routine I've created in the ROM with the appropriate command.
7) As per the code above - the routine copies the main program to 5000H and executes it (this is in RAM Bank 1).
8) Running from 5000H, the ROM is switched out and Bank 0 mapped to Area 0 again.
9) The CP/M memory map is now intact again - with the only difference that the code for DOWNLOAD.COM is still at 4100H, the currently executing code is at 5000H.
10) Currently executing code moves/copies DOWNLOAD.COM from 4100H to 0100H, and then passes execution to CCP with a jump to E600H.
11) User creates the DOWNLOAD.COM file by typing "SAVE 2 DOWNLOAD.COM".

This is a modified version of the instructions provided by Grant Searle on his website to get the initial DOWNLOAD.COM file into CP/M on his SBC (which I was able to use initially as my SBC didn't start out with an MMU). His SBC doesn't have bank switching, so I've had to modify the process to work with my SBC.

The only things I'm not 100% sure about are the code I've written - I'm hoping I've not made any silly mistakes - and the jump to E600H. As far as I can tell, it's what Grant's code did.

If I can get this working and get DOWNLOAD.COM onto A: in CP/M, I can easily restore the filesystem that was erased. Then I'll back it all up to D: drive so if this happens again, I won't have this problem! ;)

nockieboy
January 1st, 2018, 02:31 PM
Okay, all sorted. Will get CPMLDR and CPM3.SYS compiled tomorrow. In the meantime:


CP/M will poll the BIOS for characters anyhow - so there is nothing further that you need to do to to persuade it to do it!

Soooo... CP/M should continue polling the BIOS anyway and I should be able to type chars into the CCP even with interrupts disabled?

nockieboy
January 1st, 2018, 03:00 PM
On a related subject, can anyone tell me what the advantage of CP/M 3.0/Plus is over CP/M 2.2? You're still restricted to a single task; you get a few more features that few programs take advantage of, and your TPA memory footprint can be somewhat larger. Have I missed anything?

I've got a couple of machinea that run 3.0 and, for the life of me, I can't figure out what makes it worth the trouble. You don't need CP/M to manage the extra memory used for a RAMDisk...

MP/M is a different kettle of fish--mutli-tasking, multi-user.

Err... good question. For me it's as much to do with the challenge as anything else. That and the fact I spent a week designing and building an MMU for my SBC to use the entire memory space available, so it's natural to want an operating system that can make use of it too.

EDIT: System is back to how it was now, with CPM3.SYS and CPMLDR.COM assembled and ready to go. I've also copied the entire A: drive to D: now, so if the same bug occurs and wipes A: drive, I won't have this issue again (not that it will be an issue next time as it's forced me to solve a potential thorn in the project anyway!)

durgadas311
January 1st, 2018, 05:19 PM
On a related subject, can anyone tell me what the advantage of CP/M 3.0/Plus is over CP/M 2.2? You're still restricted to a single task; you get a few more features that few programs take advantage of, and your TPA memory footprint can be somewhat larger. Have I missed anything?

I've got a couple of machinea that run 3.0 and, for the life of me, I can't figure out what makes it worth the trouble. You don't need CP/M to manage the extra memory used for a RAMDisk...

MP/M is a different kettle of fish--mutli-tasking, multi-user.

Having spent a lot of time doing code and document development in CP/M, I can say from first-hand experience that CP/M Plus is a much more pleasant environment. True, most applications are not specific to CP/M Plus, but the extra TPA is a big benefit for compilers and word processors. And the better suite of CP/M utilities is also a major benefit. Re-editing of the (previous) commandline is also a big help, although it takes awhile to get proficient with the edit commands (keys) - I find these days I am too ingrained in the bash command editing and thus have not re-learned CP/M Plus command editing. Being able to use timestamps on files is also handy, and better handling of large disks and files was nice.

Alphasite
January 1st, 2018, 08:48 PM
Having spent a lot of time doing code and document development in CP/M, I can say from first-hand experience that CP/M Plus is a much more pleasant environment. True, most applications are not specific to CP/M Plus, but the extra TPA is a big benefit for compilers and word processors. And the better suite of CP/M utilities is also a major benefit. Re-editing of the (previous) commandline is also a big help, although it takes awhile to get proficient with the edit commands (keys) - I find these days I am too ingrained in the bash command editing and thus have not re-learned CP/M Plus command editing. Being able to use timestamps on files is also handy, and better handling of large disks and files was nice.

I liked the bigger TPA, the BIOS not having to deal with blocking/deblocking sectors, the ability to set disk search order, command line editing, and having the ability to set page mode so it would pause after each page was displayed. Sure, you get get some or all of these with BDOS and CCP replacements but I preferred using the originals.

nockieboy
January 2nd, 2018, 05:30 AM
Okay, new log follows with extra debug information. I've added a copy of BIOS3.ASM as well for info so you can see where the debug prints are. I've put a HALT before the jump to CCP to stop the log from repeating constantly (which it is otherwise doing as before.) BIOS: 42807

To my unknowledgeable eye, it looks like something odd is going on with the banking? :whatthat:


CP/M Plus Copyright 1982 (c) by Digital Research

ld_ccp executing...
selmem called. curBank=00 A=01
Bank 1 selected...
selmem called. curBank=00 A=00
seldsk called...
settrk: 0000
settrk: 0001
sectrn: 0000
setsec: 0000
setdma: BD59
setbnk: 01
setbnk: 00
read called... dmaBank=00
selmem called. curBank=01 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0001
setsec: 0001
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0002
setsec: 0002
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0003
setsec: 0003
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0004
setsec: 0004
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0005
setsec: 0005
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0006
setsec: 0006
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0007
setsec: 0007
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0008
setsec: 0008
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0009
setsec: 0009
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000A
setsec: 000A
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000B
setsec: 000B
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000C
setsec: 000C
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000D
setsec: 000D
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000E
setsec: 000E
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000F
setsec: 000F
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0010
setsec: 0010
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0011
setsec: 0011
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0012
setsec: 0012
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0013
setsec: 0013
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0014
setsec: 0014
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0015
setsec: 0015
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0016
setsec: 0016
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0017
setsec: 0017
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0018
setsec: 0018
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0019
setsec: 0019
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001A
setsec: 001A
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001B
setsec: 001B
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001C
setsec: 001C
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001D
setsec: 001D
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001E
setsec: 001E
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001F
setsec: 001F
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0000
settrk: 0001
sectrn: 0000
setsec: 0000
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0001
setsec: 0001
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0002
setsec: 0002
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0003
setsec: 0003
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0004
setsec: 0004
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0005
setsec: 0005
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0006
setsec: 0006
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0007
setsec: 0007
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0008
setsec: 0008
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0009
setsec: 0009
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

selmem called. curBank=00 A=01
First bdose call completed...
Second bdose call completed...
selmem called. curBank=00 A=00
selmem called. curBank=01 A=01
Third bdose call completed...
selmem called. curBank=00 A=00
settrk: 000E
sectrn: 0000
setsec: 0000
setdma: 0100
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0001
setsec: 0001
setdma: 0300
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0002
setsec: 0002
setdma: 0500
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0003
setsec: 0003
setdma: 0700
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0004
setsec: 0004
setdma: 0900
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0005
setsec: 0005
setdma: 0B00
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0006
setsec: 0006
setdma: FCF6
setbnk: 01
setbnk: 00
read called... dmaBank=00
selmem called. curBank=01 A=00
read dma: FCF6
selmem called. curBank=00 A=00
read completed, erflag=00

selmem called. curBank=00 A=01
selmem called. curBank=00 A=00
selmem called. curBank=01 A=01
Fourth bdose call (BDOS 20), A=01
HL = 1901
CCP loaded...

Chuck(G)
January 2nd, 2018, 05:44 AM
Having spent a lot of time doing code and document development in CP/M, I can say from first-hand experience that CP/M Plus is a much more pleasant environment. True, most applications are not specific to CP/M Plus, but the extra TPA is a big benefit for compilers and word processors. And the better suite of CP/M utilities is also a major benefit. Re-editing of the (previous) commandline is also a big help, although it takes awhile to get proficient with the edit commands (keys) - I find these days I am too ingrained in the bash command editing and thus have not re-learned CP/M Plus command editing. Being able to use timestamps on files is also handy, and better handling of large disks and files was nice.

So if you're going all the to implement CP/M 3, why not make a little more effort and do MP/M II? There, you get the benefit of multitasking.

durgadas311
January 2nd, 2018, 06:11 AM
So if you're going all the to implement CP/M 3, why not make a little more effort and do MP/M II? There, you get the benefit of multitasking.

I would argue that MP/M II is not a replacement for CP/M Plus. For a single user, MP/M II is actually a downgrade. CP/M Plus has a vastly superior UI. MP/M-II has a reduced TPA due to the extra layers of software. The multitasking feature is actually not very useful, as there are no practical applications to use it. CP/NET (Server) was the one big application for multitasking that I knew of. Otherwise, people used the "multi-user" features of MP/M-II but that was to run independent CP/M-like users. But the maximum TPA was significantly smaller (48K) than what most CP/M Plus implementations provided (56K). While you could run multiple users on a single Z80 box with MP/M, it was not very fast if those users were doing much more than data entry.

Also, as I thought I heard this inferred recently, MP/M cannot run on SMP hardware (without significant redesign). It is not a *multiprocessor* OS. I recall some hardware vendors of the time that provided systems with multiple Z80s, but they were all independent single-board Z80 *computers* all housed in a single enclosure, possibly having some shared memory between them. Nothing at all like modern multiprocessor (multicore) systems, and you could not run a single instance of MP/M on a batch of independent computers - they could each run their own, isolated, MP/M instances and then you'd have to build some sort of interconnect and software to support it.

daver2
January 2nd, 2018, 06:23 AM
Nice to see you are back up and running :-)!

>>> setdma: FCF6

What on earth is going on here I wonder?! Unless the last sector of this file contains something 'special' that is required to be loaded just below the BIOS???

If you don't put the HALT in though, it may be that we get a 'good' trace with CP/M producing the A> prompt. It did that once the other day.

Thinking about it the "No space" error return may have been produced in response to CP/M erroneously writing something to the disk in the first place (hence the corruption)... Then it thought it had run out of space (after doing something catastrophic).

In these circumstances - I would be tempted to remove the code for writing to the disk and ALWAYS return an error. This should remove completely (or vastly reduce the probability) of the disk becoming corrupt again due to errant behaviour.

Dave

durgadas311
January 2nd, 2018, 07:01 AM
The DMA address of FCF6 must be for a data read - vs. directory - since it is in common memory. Addresses like BD59 are probably directory reads, internal to the BDOS, in bank 0. The low-memory setdma addresses are showing the efficiency of the multi-sector read operation, as the BDOS can directly read physical sectors into the destination without any deblocking or copying. The last, partial, sector of CCP.COM is that read into FCF6 so that one record can be copied out. That all looks correct... at a high level.

But I saw some places, that I believe are the two selmem calls being done in the read path, that look wrong. I see this:


setdma: 0B00
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

Can you explain why setmda showed 0B00 but "read dma:" is showing 19FE? Could the location from which you are getting (saving) the DMA address be in banked memory and so when accessed from common memory you are getting invalid addresses?

UPDATE: I think this is another cowpie I left for you... dmaAddr, dmaBank, and curBank, need to be in common memory (CSEG). Same is probably true for the sekxxx variables, although those may not be getting accessed after switching to dmaBank.

nockieboy
January 2nd, 2018, 07:07 AM
>>> setdma: FCF6

What on earth is going on here I wonder?! Unless the last sector of this file contains something 'special' that is required to be loaded just below the BIOS???

I've just had a look at the memory at that location (from the safety of the monitor ROM) and here's what's there:


-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F
FCF- 00 00 00 00 00 00 20 24 4E 6F 20 46 69 6C 65 24 ...... $No File$
FD0- 20 72 65 71 75 69 72 65 64 24 45 52 41 53 45 20 required$ERASE
FD1- 24 20 28 59 2F 4E 29 3F 20 24 0D 0A 0D 0A 50 72 $ (Y/N)? $....Pr
FD2- 65 73 73 20 52 45 54 55 52 4E 20 74 6F 20 43 6F ess RETURN to Co
FD3- 6E 74 69 6E 75 65 20 24 20 20 28 55 73 65 72 20 ntinue $ (User
FD4- 30 29 24 00 4E 4F 4E 2D 53 59 53 54 45 4D 20 46 0)$.NON-SYSTEM F
FD5- 49 4C 45 28 53 29 20 45 58 49 53 54 24 00 00 00 ILE(S) EXIST$...
FD6- 3A 00 00 00 D0 0D 00 00 00 01 24 24 24 20 20 20 :.........$$$
FD7- 20 20 53 55 42 00 3C 12 C3 9C 0B FE 41 DA 58 0B SUB.<.....A.X.
FD8- FE 51 D2 58 0B D1 D5 13 1A B7 C2 58 0B 7E D6 40 .Q.X.......X.~.@
FD9- 12 23 7E FE 3A C2 6B 0B 23 D1 C3 5E 0B 2A 8D 03 .#~.:.k.#..^.*..
FDA- 6A 54 0E 02 7E 12 23 13 0D C2 AE 0B C9 0E 00 1A jT..~.#.........
FDB- 77 B7 79 C8 23 13 03 C3 B9 0B AF 21 9F 0D 34 FC w.y.#......!..4.
FDC- E2 09 B7 C0 3A 9F 0D 21 80 00 CD B0 0C AF 7E C9 ....:..!......~.
FDD- 01 40 B4 2A 8D 03 68 7E A1 C9 01 A0 B4 CD DD 0B .@.*..h~........
FDE- 79 B6 77 C9 01 A0 B4 CD DD 0B 79 2F A6 77 C9 2A y.w.......y/.w.*
FDF- 8D 03 68 77 C9 2A 8D 03 68 7E C9 CD 49 09 45 3E ..hw.*..h~..I.E>


Don't know if that helps. RAM is empty (all zeros) from about FB00h onwards until FCF6.


If you don't put the HALT in though, it may be that we get a 'good' trace with CP/M producing the A> prompt. It did that once the other day.

Can I just confirm your comment about making the IO polled instead of interrupt-driven? I haven't done anything with that yet, but still have interrupts disabled. So despite that, I should still be able to type into the CCP if it hasn't otherwise hung, even though the interrupts are disabled?


Thinking about it the "No space" error return may have been produced in response to CP/M erroneously writing something to the disk in the first place (hence the corruption)... Then it thought it had run out of space (after doing something catastrophic).

Yeah, it was pretty catastrophic. Talk about being caught with your pants down! :rolleyes: Still, it's sorted now and if it happens again it's no great shakes.


In these circumstances - I would be tempted to remove the code for writing to the disk and ALWAYS return an error. This should remove completely (or vastly reduce the probability) of the disk becoming corrupt again due to errant behaviour.

Dave

I guess. Righto, so I'm guessing I can't just stick a RET at the start of the write: function? What's this error of which you speak? An FF in the accumulator before RETurning, perhaps?

durgadas311
January 2nd, 2018, 07:09 AM
make sure you check my previous post. I think I found the problem.

nockieboy
January 2nd, 2018, 07:10 AM
UPDATE: I think this is another cowpie I left for you... dmaAddr, dmaBank, and curBank, need to be in common memory (CSEG). Same is probably true for the sekxxx variables, although those may not be getting accessed after switching to dmaBank.

Righto - making the changes as I finish this. ;)

nockieboy
January 2nd, 2018, 07:21 AM
Okay, I've removed the HALT from ld_ccp preventing CCP from being executed after it's loaded. I've enabled interrupts for the moment but might give it a go next with them disabled again.

I've moved the following up before the DSEG statement in BIOS3.ASM (now sits immediately after ccp$fcb and fcb$nr definitions):


dmaAddr: .ds 2 ;last dma address
dmaBank: .ds 1 ;bank for dma address
curBank: .ds 1 ;current selected bank

sekdsk: .ds 1 ;seek disk number
sektrk: .ds 2 ;seek track number
seksec: .ds 2 ;seek sector number

Updated log follows. Gets as far as 'CCP loaded...' and freezes again.


CP/M V3.0 Loader
Copyright (C) 1982, Digital Research

BNKBIOS3 SPR F200 0E00
BNKBIOS3 SPR B300 0D00
RESBDOS3 SPR EC00 0600
BNKBDOS3 SPR 8500 2E00

59K TPA
Z80 MINICOM II CP/M Plus BIOS 1.0.0 by J.Nock 2017

CP/M Plus Copyright 1982 (c) by Digital Research

ld_ccp executing...
selmem called. curBank=00 A=01
Bank 1 selected...
selmem called. curBank=00 A=00
seldsk called...
settrk: 0000
settrk: 0001
sectrn: 0000
setsec: 0000
setdma: BD59
setbnk: 01
setbnk: 00
read called... dmaBank=00
selmem called. curBank=01 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0001
setsec: 0001
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0002
setsec: 0002
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0003
setsec: 0003
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0004
setsec: 0004
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0005
setsec: 0005
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0006
setsec: 0006
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0007
setsec: 0007
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0008
setsec: 0008
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0009
setsec: 0009
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000A
setsec: 000A
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000B
setsec: 000B
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000C
setsec: 000C
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000D
setsec: 000D
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000E
setsec: 000E
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 000F
setsec: 000F
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0010
setsec: 0010
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0011
setsec: 0011
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0012
setsec: 0012
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0013
setsec: 0013
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0014
setsec: 0014
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0015
setsec: 0015
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0016
setsec: 0016
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0017
setsec: 0017
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0018
setsec: 0018
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0019
setsec: 0019
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001A
setsec: 001A
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001B
setsec: 001B
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001C
setsec: 001C
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001D
setsec: 001D
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001E
setsec: 001E
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 001F
setsec: 001F
setdma: BD59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BD59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0000
settrk: 0001
sectrn: 0000
setsec: 0000
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0001
setsec: 0001
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0002
setsec: 0002
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0003
setsec: 0003
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0004
setsec: 0004
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0005
setsec: 0005
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0006
setsec: 0006
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0007
setsec: 0007
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0008
setsec: 0008
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 0001
sectrn: 0009
setsec: 0009
setdma: BB59
setbnk: 00
setbnk: 00
read called... dmaBank=00
selmem called. curBank=00 A=00
read dma: BB59
selmem called. curBank=00 A=00
read completed, erflag=00

selmem called. curBank=00 A=01
First bdose call completed...
Second bdose call completed...
selmem called. curBank=00 A=00
selmem called. curBank=01 A=01
Third bdose call completed...
selmem called. curBank=00 A=00
settrk: 000E
sectrn: 0000
setsec: 0000
setdma: 0100
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0001
setsec: 0001
setdma: 0300
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0002
setsec: 0002
setdma: 0500
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0003
setsec: 0003
setdma: 0700
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0004
setsec: 0004
setdma: 0900
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0005
setsec: 0005
setdma: 0B00
setbnk: 01
setbnk: 01
read called... dmaBank=01
selmem called. curBank=01 A=01
read dma: 19FE
selmem called. curBank=00 A=00
read completed, erflag=00

settrk: 000E
sectrn: 0006
setsec: 0006
setdma: FCF6
setbnk: 01
setbnk: 00
read called... dmaBank=00
selmem called. curBank=01 A=00
read dma: FCF6
selmem called. curBank=00 A=00
read completed, erflag=00

selmem called. curBank=00 A=01
selmem called. curBank=00 A=00
selmem called. curBank=01 A=01
Fourth bdose call (BDOS 20), A=01
HL = 1901
CCP loaded...