• Please review our updated Terms and Rules here

DPB, Offset value - Does BDOS automatically assume 2 heads?

cj7hawk

Veteran Member
Joined
Jan 25, 2022
Messages
1,135
Location
Perth, Western Australia.
Hi all,

Just a dumb question here, but as I virtualised all the disks in my system, they are all "single sided" - ie, Heads are not specified in the DPB, so I just treat all my disks as logical block addressing to some extent, and match sectors to the record size - ie, 128 bytes.

As I try to make my system dual-work with real CP/M and LokiOS, I note that Offset seems to be doubled - ie, it's like it's assuming two heads, so each "track" that I offset is doubled. If I have 32 sectors(records) per track, 128 byte sectors ( 4K per track ) and we consider that logical blocks start at 0, then 0-31 is track0, and 32-63 is track1 and so on.

So if I want my directory to start with record 32, then I offset by 1 track, eg, 32 spt - so with an offset of 1, it tries to read logical sector 32, or Track 1, Sector 0.

However when I do the same with real CP/M, if I set 1 into the offset, it offsets by 2 tracks single-sided. That is, it things the first directory entry is on logical sector 64 - ie, Track 2 Sector 0, not Track 1 sector 0.

Is this how CP/M is supposed to do it? That it assumes all track offsets to be double sided? Or have I missed something in the rest of the DPB?

Thanks
David
 
That certainly doesn't sound right to me. If anything, it should assume 1 head and leave the BIOS to sort out the track to head mapping...

Dave
 
That's what I would have thought, especially as many early drives were single head, but when the BDOS kept failing, and even locking into infinite loops ( There are some badly written sections! ) I eventually noticed that if I selected a disk post-paging in the DR BDOS, then reset the disk system, then began another operation, eg, open, read, etc. Then it didn't crash immediately. Instead it only read the directory of my M: drive and A: and L: crashed. Looking further, I found that the A: was now reading Track 2,sector 0 instead of where it should have been reading Track 1, sector 0, hence it was reading as though the offset was twice as big. I changed the offset from 1 to 0 to test, and it tried then reading from 0 instead.

Of course, this may be a symptom, not the cause, but I haven't been exposed to this enough to know whether the tracks in the offset are "double sided" or "single sided" tracks... (eg, Whether Head 0=track0, Head1 = track 1 etc. ) Also I might have messed up another field in the BIOS... Not sure.

David
 
I was doing a little more thinking - and the head issue has to be a function of the BIOS as there are so many different ways of thinking about a 'disk'.

You can determine the head number by the following ways:

1. By decoding the sector number. Sectors > n mean the next head. So sectors 1..26 are head 0 and sectors 27..52 are head 1. The track will always be 0 for the first track.

2. By decoding the track. Each even track (0, 2, 4, ...) is head 0 with each odd track (1, 3, 5, ...) being head 1.

3. By decoding the track. Tracks 0..77 (say) are head 0 with tracks 78 onwards being head 1.

In the first case, each disk track looks like it has twice as many sectors as it really has on one side.

Just thinking aloud...

Dave
 
I was doing a little more thinking - and the head issue has to be a function of the BIOS as there are so many different ways of thinking about a 'disk'.

You can determine the head number by the following ways:

1. By decoding the sector number. Sectors > n mean the next head. So sectors 1..26 are head 0 and sectors 27..52 are head 1. The track will always be 0 for the first track.

2. By decoding the track. Each even track (0, 2, 4, ...) is head 0 with each odd track (1, 3, 5, ...) being head 1.

3. By decoding the track. Tracks 0..77 (say) are head 0 with tracks 78 onwards being head 1.

In the first case, each disk track looks like it has twice as many sectors as it really has on one side.

Just thinking aloud...

Dave

You are correct - It's not the BIOS though that is causing this, it's the BDOS - The BDOS is 'doubling' up on the BIOS's "Offset" value, and I didn't know why.

I just figured it out though - I was assuming that the "offset" was calculated and applied by the BIOS, but it is also calculated and applied by the DR BDOS.

Because I was calculating and applying it under SELDSK in my BIOS, my BDOS didn't care and wasn't aware of it. But I made a mistake in my BIOS with that - BDOS also calculated the offset and adds it to the track.

As a result, OFFSET got added twice as soon as I switched from my BDOS to the DR BDOS.

That is something I need to fix :(... At least I worked out why it was failing, and it was no doubt messing with a few things.... But I have to go right back through my OS and fix it in the BIOS and BDOS, so that it's correctly aligned with CP/M.

:(

At least I'm on the right track. Once I fix that, I should be able to switch from my BDOS to the DR BDOS and then start making sure mine works the same, in the same environment. Once the OS is debugged fully- or at least presents the same results expected from a DR CP/M, I can tackle compatability issues more easily.

David.
 
The DRI BDOS just takes the DPB.OFF value and passes it to the BIOS SETTRK routine. No interpretation or calculation is done. It then starts examining the directory at sector 1 (i.e. 0, the first). The BDOS never accesses anything before the track DPB.OFF, and all accesses it does make are by logical record number relative to track DPB.OFF sector 0. The logical record number is then translated (by the BDOS) into track (plus DPB.OFF) and sector (via SECTRN) numbers using the information in the DPB, which are then passed to the BIOS SETTRK and SETSEC (via SECTRN) routines. Since the BIOS provides the DPB, it has total control over what is passed to it via SETTRK and SETSEC. This really means that the BIOS is responsible for constructing a sensible DPB and for making and required conversions of track and sector into what is needed by the hardware - including side, cylinder/head, RAM address, LBA, whatever. Basically, the BIOS writer has to match the DPB to the SETTRK/SETSEC routines (actually, SETTRK and SETSEC normally just store the values, it is READ and WRITE that actually translate those).
 
Yes, once I figured that out, I located the code that did it -

EX DE,HL ;HL = curtrk+offset [U] LD HL,(offset)[/U] ADD HL,DE LD B,H ;track set up LD C,L CALL settrkf ;note that BC - curtrk is difference to move in bios

But I already had this in my BIOS:

SELDSK: ; 18 - Select disc drive - C Register = disk 0...F. Enter with E=0 or E=FF. ; If bit 0 of E is 0, then the disc is logged in as if new; if the format has to be determined from the boot sector, for example, this will be done. ;If bit 0 if E is 1, then the disc has been logged in before. The disc is not accessed; the DPH address (or zero) is returned immediately. ;SELDSK returns the address of a Disc Parameter Header in HL. The exact format of a DPH varies between CP/M versions; note that under CP/M 3, ; the DPH is in memory bank 0 and probably not visible to programs. If the disc could not be selected it returns HL=0. LD A,C AND $0FH ; limit to 16 drives. Recursive selection after that. LD (DISKNO),A ; Store the drive selected. OUT (DRIVE),A LD HL,DPBASE ; Set the Disk Parameter Header in HL. RLC A ; Disk Parameter Header is 16 bytes, so we need to select the right one from a table. RLC A RLC A RLC A ; Multiply A by 16. Bit 7 should have cycled bacl to Bit 0 each time do don't need to mask it. ADD A,L LD L,A ; LD A,$00 ADC A,H LD H,A ; HL now contains the correct DPBASE table. ;; LD E,0 ; I need to better understand this parameter. OK, This is not a parameter I set, but that I act on. ; I will use a BIOS to address the disk format in each case... No need for multiple disk formats. ; The specific DISK BIOS for that drive can handle it. PUSH HL POP IY ; Get HL (DPBASE in IX ). LD A,(IY+10) ; Get the Track Offset. LD E,A LD A,(IY+11) LD D,A ; Store the location of the DPC from the DP Header. PUSH DE POP IX ; IX now containts the Disk Parameter Block for the selected Disk Header. LD A,(IX+13) ; Location of OFF (Track Offset) for the selected disk. LD (TRACKOFF_L),A LD A,(IX+14) LD (TRACKOFF_H),A ret ; As we return from this routine, HL contains the DPH. DE is the DPB. ; Also IY is the DPH, IX is the DPB. TRACKOFF_L: db $00 ; Store the Track Offset for the currently selected disk here. TRACKOFF_H: db $00 ; It's a 16 bit number.

and

SETTRK: ;27: Set track number - Track in BC - Is a word - Starts at 0. LD (TRACK),BC LD IX,TRACKOFF_L LD A,(IX+0) ADD A,C LD C,A OUT (TRACKPORT),A ; Set for 256 tracks currently, but if I need more, I should clear A and ADC A,B Then out the upper byte. ; LD A,(IX+1) ; ADC A,B ; LD B,A ; OUT (TRACKPORT),A ; But this is the code for 16 bit track selection. After adding the OFF Track Offset. ret ; I should add OFF from the DPB Disk Parameter Block to the track... So when the disk is selected, I should save that number in memory.

So it was my error - I had assumed that the BIOS took care of the offset, not the BDOS. This isn't documented outside of the code that I could find, so I put it in where it seemed most logical.

Hence, the offset got added twice, and was always doubled up.

:(

In hindsight, I can see that this assumption was poorer than assuming the OS took care of it, otherwise it makes it more challenging for the OS to access the protected area to write it - but since I was building the boot sectors by hand, it seemed like a good idea at the time.

It's not a bad thing though... I've written everything from scratch so far. The emulator, the assembler, the tools, the OS... It's a great way to learn how to make an OS and better understand how much work and effort was involved back in the 80s to do it... Also, so many other things aren't well documented, that you only learn from doing it like this, such as why they used a bit pattern for the directory allocations in the DPB... Until I came to writing that code, it seemed like a positively stupid idea, and then when I started writing it, it made complete sense.

It will be perfect knowledge if I ever find a hot-tub time machine and regress to the 80s. In the mean time, I use it to extent my architectural and design thinking as an exercise.

Well, it would sound a lot cooler if I didn't stumble and make so many dumb mistakes as I progress :)
 
Ah yes. The BIOS states the fact to the BDOS and the BDOS complies...

At least you are away now...

If you don't make mistakes - it just means that you never do anything!

Dave
 
So initially, it started working last night. Stuff that worked before, like MBASIC and Wordstar 3.3 still work. Stuff that didn't work like Zork and other infocom programs still gets stuck in the same infinite loop of loading up the data file information over and over again, so I'm not entirely sure of where the problem lies. It occurs under LokiOS and it occurs under CP/M and initially seems to be the same... So maybe something still wrong in my BIOS ( though by this time, it should be pretty much abstracted if it works with both CP/M and LokiOS, or it could be my disk image simulation and the file size, or something like that, since I don't think the number of extents is affecting it anymore - outside of any disk format issues I'm getting.

But at least I can dual-boot the system now, and I just need a way to reboot into CP/M from LokiOS with a single command, rather than with multiple commands like I do now ( eg, one command moves the BDOS, another the CCP, then a third changes the hook vector at 0005 and switches, but rather I need to recompile them as direct replacements for the existing CCP and BDOS rather than running two at once so I can switch between OS types on the fly without having to redo everything... A cold boot will automatically switch back to LokiOS and another command switches into CP/M ).

I still have a few changes to make - my CCP isn't fully binary compatible with the provided image, but most of the differences are a change in the copyright string and the other text where the one I'm assembling has lower and upper case letters, while the image is entirely upper case... Which surprises me - Originally when I saw the images were different sizes, I figured I had major issues with comparing them, but I assume that DR must have had a few different CP/M images depending on which machine it was intended for, and in terms of code location, they are pretty much identical. Though my audit of the code is still incomplete.

I'm a lot closer than I was before :)

Thanks again for the help.
 
The CCP was often customized by vendors, so many copies of CCP out there are different for that reason (did not come from DRI). I've never heard of DRI supplying different CCPs for different systems - they were never usually involved in what a vendor supplied to their customers. DRI's CCP might change with the CP/M version (e.g. CP/M 2.0 -> CP/M 2.2), but other than patching for bugs I don't believe it was ever altered. Mostly, DRI supplied vendors with patches which the vendors were responsible for supplying to customers (via revised product images).
 
I still have a few changes to make - my CCP isn't fully binary compatible with the provided image, but most of the differences are a change in the copyright string and the other text where the one I'm assembling has lower and upper case letters, while the image is entirely upper case... Which surprises me

All of the sources that I've seen from DR (that were purported to 'original') used uppercase with the copyright text and all generated error messages. 'Purported' is the operative word here, but I believe that was likely the case, if for no other reason than to maximize compatibility with the upper-case only terminals of the day (like the popular ADM-3A, which without an optional EPROM, was UC only).
 
I've mentioned this before, but I have seen CP/M applications that made assumptions about the size of the CCP (the difference between the BDOS entry address and the start of the CCP), usually as a way to preserve the CCP and still use as much of memory as possible. DRI always kept their CCP 0800H bytes (until CP/M 3, where the CCP changed in other ways). I have no experience with Zork, nor can I think of a reason that Zork would need to preserve the CCP, but that could be causing problems if your CCP (or space allotted to CPP) is more than 0800H.

The one case I recall in some detail was where the program kept track of how much memory it used, and if it detected use past the "BDOS-0800H" address then it would exit via JMP 0, whereas otherwise it would exit by returning to the CCP. The problem with larger CCPs is this program would overwrite it and not know it. This caused the program to crash when exiting, which does not sound like what you're seeing with Zork. But, if it is examining things under the assumption that the CCP is in a particular range, it might make wrong choices.
 
In the simple case, I agree. However, there are some really bizarre BIOS manipulations out there. Take the National Semi BLC as an example. Directory is located on cylinder 39, side 1 and space is allocated in reverse order until cylinder 0, side 1 (0,0 isn't used), then allocated in a forward direction starting with cylinder 40, side 0.

In other words, the BIOS does a lot of finagling.
 
Back
Top