IDE interface for Altair 8800c

Discuss construction, troubleshooting, and operation of the Altair 8800c computer

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 3rd, 2023, 8:37 pm

Now I'm looking at sectrn. Its job is to use the value of [BC] as an index into the tranTable. It does a lookup into the tranTable and returns the value that is [BC] elements into the array. That is used to translate the logical sector provided by BDOS into the physical sector required by the hardware layer. So let's see how the sectrn function in the modular code compares to the sectrn function in the Douglas code.

The current CPM3.SYS file is from the modular BIOS, so we'll test that first:

A>sid cpmldr.com
CP/M 3 SID - Version 3.0
NEXT MSZE PC END
2500 2500 0100 CBFF
#I$B
#G

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

BIOS3 SPR 8E00 1C00
BDOS3 SPR 6F00 1F00

27K TPA

*01A9
#PA914
#G8E00


CP/M Plus v3.0hd


01 PASS A914
-Z-EI A=00 B=0000 D=930F H=0000 S=6FD0 P=A914 MOV L,C
*A915
##T
-Z-EI A=00 B=0000 D=930F H=0000 S=6FD0 P=A915 MOV H,B
*A916
#T
-Z-EI A=00 B=0000 D=930F H=0000 S=6FD0 P=A916 MOV A,D
*A917
#T
-Z-EI A=93 B=0000 D=930F H=0000 S=6FD0 P=A917 ORA E
*A918
#T
--ME- A=9F B=0000 D=930F H=0000 S=6FD0 P=A918 RZ
*A919
#T
--ME- A=9F B=0000 D=930F H=0000 S=6FD0 P=A919 XCHG
*A91A
#T
--ME- A=9F B=0000 D=0000 H=930F S=6FD0 P=A91A DAD B
*A91B
#T
--ME- A=9F B=0000 D=0000 H=930F S=6FD0 P=A91B MOV L,M
*A91C
#T
--ME- A=9F B=0000 D=0000 H=9301 S=6FD0 P=A91C MVI H,00
*A91E
#T
--ME- A=9F B=0000 D=0000 H=0001 S=6FD0 P=A91E RET
*784B

The first value is 01.

I'll set a passpoint at the RET instruction, which is where we should examine [HL] for the return value. And I'll remove the passpoint at the beginning of sectrn.

#PA91E
#-PA914
#G

01 PASS A91E
--ME- A=9F B=0001 D=0001 H=0009 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0002 D=0002 H=0011 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0003 D=0003 H=0019 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0004 D=0004 H=0003 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0005 D=0005 H=000B S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0006 D=0006 H=0013 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0007 D=0007 H=001B S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0008 D=0008 H=0005 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0009 D=0009 H=000D S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=000A D=000A H=0015 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=000B D=000B H=001D S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=000C D=000C H=0007 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=000D D=000D H=000F S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=000E D=000E H=0017 S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=000F D=000F H=001F S=6FD0 P=A91E RET
*784B
#G

01 PASS A91E
--ME- A=9F B=0000 D=0000 H=0001 S=6FD2 P=A91E RET
*784B

This accurately reflects the entries in the tranTable:

01,09,11,19,03,0B,13,1B,05,0D,15,1D,07,0F,17,1F,01,09 (in hex)
-or-
01,09,17,25,03,11,19,27,05,13,21,29,07,15,23,31,01,09 (in decimal)

Let's look at the Douglas code and see what it does. Setsec is at 90EB in his code.

A>sid cpmldr.com
CP/M 3 SID - Version 3.0
NEXT MSZE PC END
2500 2500 0100 CBFF
#I$B
#G

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

BIOS3 SPR 8E00 1A00
BDOS3 SPR 6F00 1F00

27K TPA

*01A9
#P90EB
#G8E00

CP/M 3 BIOS v1.0 for Altair 8" Floppy

01 PASS 90EB
-Z-EI A=00 B=0000 D=950E H=0000 S=6FD0 P=90EB XCHG
*90EC
#T
-Z-EI A=00 B=0000 D=0000 H=950E S=6FD0 P=90EC MVI B,00
*90EE
#T
-Z-EI A=00 B=0000 D=0000 H=950E S=6FD0 P=90EE DAD B
*90EF
#T
-Z-EI A=00 B=0000 D=0000 H=950E S=6FD0 P=90EF MOV L,M
*90F0
#T
-Z-EI A=00 B=0000 D=0000 H=9501 S=6FD0 P=90F0 MOV H,B
*90F1
#T
-Z-EI A=00 B=0000 D=0000 H=0001 S=6FD0 P=90F1 RET
*784B

Here we see the RET is at 90F1, so let's set a passpoint there and remove the one at 90EB, beginning of sectrn. Run the code 'til the end of the sequence - where it starts to repeat - and see what we've got:

#P90F1
#-P90EB
#G

01 PASS 90F1
-Z-EI A=00 B=0001 D=0000 H=0009 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0002 D=0000 H=0011 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0003 D=0000 H=0019 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0004 D=0000 H=0003 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0005 D=0000 H=000B S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0006 D=0000 H=0013 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0007 D=0000 H=001B S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0008 D=0000 H=0005 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0009 D=0000 H=000D S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=000A D=0000 H=0015 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=000B D=0000 H=001D S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=000C D=0000 H=0007 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=000D D=0000 H=000F S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=000E D=0000 H=0017 S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=000F D=0000 H=001F S=6FD0 P=90F1 RET
*784B
#G

01 PASS 90F1
-Z-EI A=00 B=0000 D=0000 H=0001 S=6FD2 P=90F1 RET
*784B

Same sequence. So the two versions of the code are in agreement in sectrn.

01,09,11,19,03,0B,13,1B,05,0D,15,1D,07,0F,17,1F,01,09 (in hex)
-or-
01,09,17,25,03,11,19,27,05,13,21,29,07,15,23,31,01,09 (in decimal)

Now I need to learn how that is used to translate the logical sectors to physical sectors. This is the sequence of sectors we expect to see when reading the directory on track 2:

00,10,18,02,0A,12,1A,04,0C,14,1C,06,0E,16,1E (in hex)
-or-
00,16,24,02,10,18,26,04,12,20,28,06,14,22,30 (in decimal)

The Douglas code takes the logical sectors from BDOS, and combines them with the values it gobbled up from sectrn and spits out the proper physical sector values. But not the modular code. It parrots the values from the tranTable, as if it were adding zero to the entries instead of doing the right math. Not a translation at all. My task is to find where the actual translation occurs and fix it.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 4th, 2023, 7:38 pm

My next focus was setsec. I spent the day looking at that. At first, it was just a matter of setting a passpoint at the entry to setsec and watching every instance where it was set. This followed the same trend - the sectors followed the same (01,09,11,19,03,0B,13,1B,05,0D,15,1D,07,0F,17,1F,01,09) sequence in both the modular and the Douglas code. I could see the value to be set in the [BC] register pair.

Then I set a passpoint at the entry of the read function, and examined the @SECT memory location upon entry. What I saw was the modular code had the same @SECT value as it had at entry to the setsec function. But the Douglas code didn't. Something had changed the value of @SECT between the entry of setsec and the entry of read.

I had seen this before - that the value of @SECT had been translated before entry to the read function - but it was only now that I decided my next action would be to single-step from the entry to setsec all the way until I saw a write to @SECT, and that would tell me where the update was taking place.

What I saw surprised me. I didn't have to look far. Hindsight is always so much more clear. I'll show you what I saw:

Single-stepping the Douglas code starting at setsec, watching for anything that touches @SECT in 955B.

A>sid cpmldr.com
CP/M 3 SID - Version 3.0
NEXT MSZE PC END
2500 2500 0100 CBFF
#I$B
#G

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

BIOS3 SPR 8E00 1A00
BDOS3 SPR 6F00 1F00

27K TPA

*01A9
#P90DF (setsec)
#G8E00

CP/M 3 BIOS v1.0 for Altair 8" Floppy

01 PASS 90DF
-Z-EI A=00 B=0001 D=0000 H=0001 S=6FD0 P=90DF MOV A,C
*90E0
##T
-Z-EI A=01 B=0001 D=0000 H=0001 S=6FD0 P=90E0 DCR A
*90E1
#T
-Z-EI A=00 B=0001 D=0000 H=0001 S=6FD0 P=90E1 STA 955B
*90E4
#T
-Z-EI A=00 B=0001 D=0000 H=0001 S=6FD0 P=90E4 RET
*7853
#G

I had overlooked the setsec function because the Digital Research setsec function simply stores the value of [BC] in the @SECT memory location(s). But the Douglas setsec does a 1-index to 0-index (decrement) translation as part of the setsec function. It also stores @SECT - which is actually named secNum - as a single byte value.

Douglas secSec:

mov a,c ;A=1-indexed sector number
dcr a ;convert to zero indexed
sta secNum
ret

Digital Research setsec:

mov l,c ! mov h,b
shld @sect
ret

That leaves me with some analysis. I could add a "dcx h" instruction just before the "shld @sect" instruction in the DRI code. But that is in the BIOSKRNL.ASM file, which is really supposed to be invariant. If I change code there, I'm moving away from the intended style of the modular codebase. So I prefer to modify the FDC2.ASM file and add something like this:

decSec:
lda @SECT
dcr a ;convert to zero indexed
sta @SECT
ret

It's a little more code, but it keeps things modular. I can call that function where needed.

I also need to make sure that all sections of code that access @TRK and @SECT in the FDC3.ASM module are able to access values properly. The DRI code stores track and sector numbers as 16-bit values but the Douglas code expects them be a single byte. So I'll need to make sure that memory loads and stores are copacetic.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 5th, 2023, 8:18 pm

I added a ' dcx h' instruction within the Digital Research setsec function so it would behave the same as the Douglas setSec function. That fixed the sector sequence problem, and I now see all directory sectors when I run the code using the debugger.

This is the current (modified) setsec function, found in BIOSKRN3.ASM:

mov l,c ! mov h,b
dcx h ;convert to zero-indexed
shld @sect
ret

Here's the flow, as seen using the SID debugger:
Code: Select all
A>sid cpmldr.com
CP/M 3 SID - Version 3.0
NEXT MSZE  PC  END
2500 2500 0100 CBFF
#I$B
#G

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

 BIOS3    SPR  8E00  1C00
 BDOS3    SPR  6F00  1F00

 27K TPA

*01A9
#L8E00
  8E00  JMP  A893       (boot)
  8E03  JMP  8E6C       (wboot)
  8E06  JMP  8F72       (const)
  8E09  JMP  8F8D       (conin)
  8E0C  JMP  8ED5       (conout)
  8E0F  JMP  8EE1       (list)
  8E12  JMP  8EDB       (auxout)
  8E15  JMP  8F93       (auxin)
  8E18  JMP  A901       (home)
  8E1B  JMP  A8D2       (seldsk)
  8E1E  JMP  A904       (settrk)
  8E21  JMP  A90A       (setsec)
  8E24  JMP  A911       (setdma)
  8E27  JMP  A928       (read)
  8E2A  JMP  A93E       (write)
  8E2D  JMP  8F0D       (listst)
  8E30  JMP  A91D       (sectrn)
  8E33  JMP  8F01       (conost)
  8E36  JMP  8F78       (auxist)
  8E39  JMP  8F07       (auxost)
  8E3C  JMP  8ECD       (devtbl)
  8E3F  JMP  9104       (devini)
  8E42  JMP  8ED1       (drvtbl)
  8E45  JMP  A95F       (multio)
  8E48  JMP  A963       (flush)
  8E4B  JMP  9282       (move)
  8E4E  JMP  9094       (time)
  8E51  JMP  9020       (selmem)
  8E54  JMP  A919       (setbnk)
  8E57  JMP  9281       (xmove)
  8E5A  JMP  0000       (userf)
  8E5D  JMP  0000       (reserv1)
  8E60  JMP  0000       (reserv2)
#PA904                                    (passpoint at settrk
#PA90A                                                  setsec
#PA928                                                    read
#PA91D                                              and sectrn)
#G8E00


CP/M Plus v3.0hd


01 PASS A904                                                 (settrk: BC is track number)
 -Z-E- A=00 B=0000 D=00C0 H=972E S=6FE0 P=A904 MOV  L,C
*A905
#T
 -Z-E- A=00 B=0000 D=00C0 H=9700 S=6FE0 P=A905 MOV  H,B
*A906
#T
 -Z-E- A=00 B=0000 D=00C0 H=0000 S=6FE0 P=A906 SHLD A983     (@TRK = 0000)
*A909
#T
 -Z-E- A=00 B=0000 D=00C0 H=0000 S=6FE0 P=A909 RET
*774F
#G

01 PASS A904                                                 (settrk)
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#T
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A905 MOV  H,B
*A906
#T
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A906 SHLD A983     (@TRK = 0002)
*A909
#T
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A909 RET
*7827
#G

01 PASS A91D                                                 (sectrn: BC is BDOS sector)
 -Z-EI A=00 B=0000 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#T
 -Z-EI A=00 B=0000 D=930F H=0000 S=6FD0 P=A91E MOV  H,B
*A91F
#T
 -Z-EI A=00 B=0000 D=930F H=0000 S=6FD0 P=A91F MOV  A,D
*A920
#T
 -Z-EI A=93 B=0000 D=930F H=0000 S=6FD0 P=A920 ORA  E
*A921
#T
 --ME- A=9F B=0000 D=930F H=0000 S=6FD0 P=A921 RZ
*A922
#T
 --ME- A=9F B=0000 D=930F H=0000 S=6FD0 P=A922 XCHG
*A923
#T
 --ME- A=9F B=0000 D=0000 H=930F S=6FD0 P=A923 DAD  B
*A924
#T
 --ME- A=9F B=0000 D=0000 H=930F S=6FD0 P=A924 MOV  L,M
*A925
#T
 --ME- A=9F B=0000 D=0000 H=9301 S=6FD0 P=A925 MVI  H,00
*A927
#T
 --ME- A=9F B=0000 D=0000 H=0001 S=6FD0 P=A927 RET           (0001 HL is 1-indexed physical sector)
*784B
#G

01 PASS A90A                                                 (setsec: BC is physical sector)
 --ME- A=9F B=0001 D=0000 H=0001 S=6FD0 P=A90A MOV  L,C
*A90B
#T
 --ME- A=9F B=0001 D=0000 H=0001 S=6FD0 P=A90B MOV  H,B
*A90C
#T
 --ME- A=9F B=0001 D=0000 H=0001 S=6FD0 P=A90C DCX  H
*A90D
#T
 --ME- A=9F B=0001 D=0000 H=0000 S=6FD0 P=A90D SHLD A985     (@SECT = 0000)
*A910
#T
 --ME- A=9F B=0001 D=0000 H=0000 S=6FD0 P=A910 RET
*7853
#G

01 PASS A928                                                 (read:  HL = @DMA)
 ----I A=01 B=9601 D=0000 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 00 00                                     ....   (track 0002, sector 0000)
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 4C 38 30 20 20 20 20 20 43 4F 4D 00 00 00 54 .L80     COM...T
96BD: 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 ................
96CD: 00 50 43 32 46 4C 4F 50 20 43 4F 4D 00 00 00 11 .PC2FLOP COM....
96DD: 08 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96ED: 00 46 4C 4F 50 32 50 43 20 43 4F 4D 00 00 00 13 .FLOP2PC COM....
96FD: 0A 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
970D: 00 41 53 4D 20 20 20 20 20 43 4F 4D 00 00 00 40 .ASM     COM...@
971D: 0C 0D 0E 0F 00 00 00 00 00 00 00 00 00 00 00 00 ................
972D: FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
973D: 00 00 00 7E 00 00 00 00 00 00 00 00 00 00 00 00 ...~............
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D                                                 (sectrn: BC is BDOS sector)
 -Z-EI A=00 B=0001 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A                                                 (setsec: BC is physical sector)
 --ME- A=9F B=0009 D=0001 H=0009 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928                                                 (read:  HL = @DMA)
 ----I A=01 B=9601 D=0001 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986                                                  (@TRK, @SECT)
A983: 02 00 08 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 44 55 4D 50 20 20 20 20 43 4F 4D 00 00 00 03 .DUMP    COM....
96BD: 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96CD: 00 58 53 55 42 20 20 20 20 43 4F 4D 00 00 00 06 .XSUB    COM....
96DD: 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96ED: 00 46 4F 52 4D 41 54 20 20 43 4F 4D 00 00 00 0E .FORMAT  COM....
96FD: 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
970D: 00 4C 53 20 20 20 20 20 20 43 4F 4D 00 00 00 18 .LS      COM....
971D: 13 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
972D: FF FF F8 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
973D: 00 00 00 7E 65 00 00 00 00 00 00 00 00 00 00 00 ...~e...........
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0002 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0011 D=0002 H=0011 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0002 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 10 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 53 55 42 4D 49 54 20 20 43 4F 4D 00 00 00 11 .SUBMIT  COM....
96BD: 15 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96CD: 00 4C 4F 41 44 20 20 20 20 43 4F 4D 00 00 00 10 .LOAD    COM....
96DD: 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96ED: 00 53 55 52 56 45 59 20 20 43 4F 4D 00 00 00 09 .SURVEY  COM....
96FD: 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
970D: 00 56 49 45 57 20 20 20 20 43 4F 4D 00 00 00 03 .VIEW    COM....
971D: 19 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
972D: FF FF FF C0 00 00 00 00 00 00 00 00 00 00 00 00 ................
973D: 00 00 00 7E 65 11 00 00 00 00 00 00 00 00 00 00 ...~e...........
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0003 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0019 D=0003 H=0019 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0003 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 18 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 4D 38 30 20 20 20 20 20 43 4F 4D 00 00 00 80 .M80     COM....
96BD: 1A 1B 1C 1D 1E 1F 20 21 00 00 00 00 00 00 00 00 ...... !........
96CD: 00 4D 38 30 20 20 20 20 20 43 4F 4D 01 00 00 1D .M80     COM....
96DD: 22 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "#..............
96ED: 00 4D 41 43 20 20 20 20 20 43 4F 4D 00 00 00 5C .MAC     COM...\
96FD: 24 25 26 27 28 29 00 00 00 00 00 00 00 00 00 00 $%&'()..........
970D: 00 4D 42 41 53 49 43 20 20 43 4F 4D 00 00 00 80 .MBASIC  COM....
971D: 2A 2B 2C 2D 2E 2F 30 31 00 00 00 00 00 00 00 00 *+,-./01........
972D: FF FF FF FF FF FF C0 00 00 00 00 00 00 00 00 00 ................
973D: 00 00 00 7E 65 11 1E 00 00 00 00 00 00 00 00 00 ...~e...........
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0004 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0003 D=0004 H=0003 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0004 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 02 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 4D 42 41 53 49 43 20 20 43 4F 4D 01 00 00 3E .MBASIC  COM...>
96BD: 32 33 34 35 00 00 00 00 00 00 00 00 00 00 00 00 2345............
96CD: 00 50 49 50 20 20 20 20 20 43 4F 4D 00 00 00 3A .PIP     COM...:
96DD: 36 37 38 39 00 00 00 00 00 00 00 00 00 00 00 00 6789............
96ED: 00 53 54 41 54 20 20 20 20 43 4F 4D 00 00 00 2A .STAT    COM...*
96FD: 3A 3B 3C 00 00 00 00 00 00 00 00 00 00 00 00 00 :;<.............
970D: 00 44 44 54 20 20 20 20 20 43 4F 4D 00 00 00 26 .DDT     COM...&
971D: 3D 3E 3F 00 00 00 00 00 00 00 00 00 00 00 00 00 =>?.............
972D: FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 ................
973D: 00 00 00 7E 65 11 1E 16 00 00 00 00 00 00 00 00 ...~e...........
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0005 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=000B D=0005 H=000B S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0005 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 0A 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 50 43 50 55 54 20 20 20 43 4F 4D 00 00 00 08 .PCPUT   COM....
96BD: 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @...............
96CD: 00 4E 53 57 50 20 20 20 20 43 4F 4D 00 00 00 58 .NSWP    COM...X
96DD: 41 42 43 44 45 46 00 00 00 00 00 00 00 00 00 00 ABCDEF..........
96ED: 00 53 59 53 47 45 4E 20 20 43 4F 4D 00 00 00 09 .SYSGEN  COM....
96FD: 47 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 G...............
970D: 00 50 43 47 45 54 20 20 20 43 4F 4D 00 00 00 07 .PCGET   COM....
971D: 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 H...............
972D: FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00 ................
973D: 00 00 00 7E 65 11 1E 16 CE 00 00 00 00 00 00 00 ...~e...........
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0006 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0013 D=0006 H=0013 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0006 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 12 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 43 52 43 20 20 20 20 20 43 4F 4D 00 00 00 11 .CRC     COM....
96BD: 49 4A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 IJ..............
96CD: 00 4D 4F 56 43 50 4D 20 20 43 4F 4D 00 00 00 53 .MOVCPM  COM...S
96DD: 4B 4C 4D 4E 4F 50 00 00 00 00 00 00 00 00 00 00 KLMNOP..........
96ED: 00 53 49 44 20 20 20 20 20 43 4F 4D 00 00 00 3E .SID     COM...>
96FD: 51 52 53 54 00 00 00 00 00 00 00 00 00 00 00 00 QRST............
970D: 00 43 50 4D 4C 44 52 20 20 43 4F 4D 00 00 00 48 .CPMLDR  COM...H
971D: 55 56 57 58 59 00 00 00 00 00 00 00 00 00 00 00 UVWXY...........
972D: FF FF FF FF FF FF FF FF FF FF FF C0 00 00 00 00 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 00 00 00 00 00 00 ...~e...........
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0007 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=001B D=0007 H=001B S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0007 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 1A 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 43 50 4D 33 4D 4F 44 31 53 59 53 00 00 00 78 .CPM3MOD1SYS...x
96BD: 5A 5B 5C 5D 5E 5F 60 61 00 00 00 00 00 00 00 00 Z[\]^_`a........
96CD: 00 43 43 50 20 20 20 20 20 43 4F 4D 00 00 00 19 .CCP     COM....
96DD: 62 63 00 00 00 00 00 00 00 00 00 00 00 00 00 00 bc..............
96ED: 00 43 50 4D 33 4D 4F 44 32 53 59 53 00 00 00 78 .CPM3MOD2SYS...x
96FD: 64 65 66 67 68 69 6A 6B 00 00 00 00 00 00 00 00 defghijk........
970D: 00 43 50 4D 33 44 55 47 20 53 59 53 00 00 00 74 .CPM3DUG SYS...t
971D: 6C 6D 6E 6F 70 71 72 73 00 00 00 00 00 00 00 00 lmnopqrs........
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 00 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 00 00 00 00 00 ...~e.....n.....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0008 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0005 D=0008 H=0005 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0008 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 04 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: 00 43 50 4D 33 20 20 20 20 53 59 53 00 00 00 78 .CPM3    SYS...x
96BD: 74 75 76 77 78 79 7A 7B 00 00 00 00 00 00 00 00 tuvwxyz{........
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=0009 D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=000D D=0009 H=000D S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0009 H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 0C 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=000A D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0015 D=000A H=0015 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=000A H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 14 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=000B D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=001D D=000B H=001D S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=000B H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 1C 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=000C D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0007 D=000C H=0007 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=000C H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 06 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=000D D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=000F D=000D H=000F S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=000D H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 0E 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=000E D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0017 D=000E H=0017 S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=000E H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 16 00                                     ....
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A91D
 -Z-EI A=00 B=000F D=930F H=0000 S=6FD0 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=001F D=000F H=001F S=6FD0 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=000F H=96AD S=6FD2 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 1E 00                                     ....
#G

01 PASS A904
 -Z-EI A=0F B=0000 D=8BCD H=8BE4 S=6FE2 P=A904 MOV  L,C
*A905
#D96AD
96AD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96BD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96CD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96DD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96ED: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
96FD: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
970D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
971D: E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 E5 ................
972D: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 ................
973D: 00 00 00 7E 65 11 1E 16 CE D5 6E 66 00 00 00 00 ...~e.....nf....
974D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
975D: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G

01 PASS A904
 -Z-EI A=00 B=0002 D=0000 H=0002 S=6FCA P=A904 MOV  L,C
*A905
#G

01 PASS A91D
 -Z-EI A=00 B=0000 D=930F H=0000 S=6FD2 P=A91D MOV  L,C
*A91E
#G

01 PASS A90A
 --ME- A=9F B=0001 D=0000 H=0001 S=6FD2 P=A90A MOV  L,C
*A90B
#G

01 PASS A928
 ----I A=01 B=9601 D=0000 H=96AD S=6FD4 P=A928 LHLD A981
*A92B
#DA983,A986
A983: 02 00 00 00                                     ....
#

...Starting the second pass.


Next step is to watch it flow through the section of code where it actually starts reading the CCP.COM file.

Also note that once I get this working, I'll move the decrement instruction from the BIOSKRN3 module into FDC3. I just wanted to start with it in the same place as it is in the Douglas code to limit the changes. Baby steps - I don't need any help confusing myself.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 6th, 2023, 10:20 pm

I made great progress this weekend.

The modular BIOS boots. (!)

There were two main things that prevented the modular BIOS from booting the Douglas FDC code. First has been described in the last couple of pages in this thread. It was the issue of decrementing the sector in the setsec function to translate 1-index sectors to 0-index sectors. Once I found and fixed that, the system was able to read the directory. Upon further tracing, I could see it was loading the CCP.COM program into TPA memory too.

But it still reported an error, saying it couldn't find CCP.COM. It was really frustrating, to tell the truth, 'cause I could see the code find CCP.COM in the directory, and I could see it load the contents of the file into memory location 0100. I stepped through that code probably a dozen times, watching different things. Nothing was wrong. And I knew the BDOS code worked, because I hadn't modified it. It was "known good code." Other versions of BIOS worked fine with the existing BDOS, so there was nothing wrong with BDOS.

Finally, I decided to start way back up in the boot code. I hadn't been there in a while - my focus was in the read function and its supporting subroutines - so I went back to the LDCCP function and traced it through. I used TW commands to "step through" the calls before LDCCP, so I got there pretty rapidly. LDCCP is in the BOOT3 module, and it's what sets up the FCB for CCP.COM and calls the BDOS open function (15). The BDOS open function reads the directory, finds the file and loads it. And like I said, I had seen that working, stepped through the flow a dozen times ad nauseum. So my focus now was to see what happened after that.

Once my focus was there, it didn't take long at all to find it. This is what SID reported:

A>sid cpmldr.com
CP/M 3 SID - Version 3.0
NEXT MSZE PC END
2500 2500 0100 CBFF
#I$B
#G

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

BIOS3 SPR 8E00 1C00
BDOS3 SPR 6F00 1F00

27K TPA

*01A9
#G8E00,A893 (set a breakpoint at boot, right after entering it from the first jump table entry)

*A893 (boot)
#T
-Z-EI A=42 B=0001 D=6F00 H=005E S=027F P=A893 LXI SP,8ECD
*A896
... (step down through it 'til we reach the init call, and then get through it with the TW command)
#TW
--ME- A=11 B=00FF D=9109 H=91D1 S=8ECD P=A8A1 CALL 9037 (call init in boot3)

CP/M Plus v3.0hd


*A8A4 (right after returning from the init call)
#L (examine listing to find ldccp address)
A8A4 LXI B,1000
A8A7 LXI H,9288
A8AA PUSH B
A8AB MOV E,M
A8AC INX H
A8AD MOV D,M
A8AE INX H
A8AF MOV A,E
A8B0 ORA D
A8B1 JZ A8C9
A8B4 PUSH H
A8B5 XCHG
A8B6 DCX H
A8B7 DCX H
A8B8 MOV A,M
A8B9 STA A982
A8BC MOV A,C
A8BD STA A981
A8C0 DCX H
A8C1 MOV D,M
A8C2 DCX H
A8C3 MOV E,M
A8C4 XCHG
A8C5 CALL 8FB1
A8C8 POP H
A8C9 POP B
A8CA INR C
A8CB DCR B
A8CC JNZ A8AA
A8CF JMP 8E63 (jmp boot$1)
A8D2 MOV A,C
A8D3 STA A981
A8D6 MOV L,C
8E63 CALL 8E78
8E66 CALL 9060 (call ?ldccp)
8E69 JMP 0100
8E6C LXI SP,8ECD
8E6F CALL 8E78
8E72 CALL 9091
8E75 JMP 0100
8E78 MVI A,C3
8E7A STA 0000
8E7D STA 0005
8E80 LXI H,8E03
#P9060 (set a passpoint at ldccp)
#G

01 PASS 9060 (?ldccp)
-Z-EI A=C3 B=0010 D=0000 H=6F06 S=8ECB P=9060 XRA A
*9061
#T
-Z-E- A=00 B=0010 D=0000 H=6F06 S=8ECB P=9061 STA 90D9
*9064
#T
-Z-E- A=00 B=0010 D=0000 H=6F06 S=8ECB P=9064 LXI H,0000
*9067
#T
-Z-E- A=00 B=0010 D=0000 H=0000 S=8ECB P=9067 SHLD 90EA
*906A
#T
-Z-E- A=00 B=0010 D=0000 H=0000 S=8ECB P=906A LXI D,90CA
*906D
#TW
-Z-E- A=00 B=0010 D=90CA H=0000 S=8ECB P=906D CALL 9095 (open)
*9070
#T
----- A=00 B=0000 D=0008 H=0000 S=8ECB P=9070 INR A
*9071
#T
----- A=01 B=0000 D=0008 H=0000 S=8ECB P=9071 ??= 20 (what?!!)
*9072
#L9061 (list the code for a sanity check)
9061 STA 90D9
9064 LXI H,0000
9067 SHLD 90EA
906A LXI D,90CA
906D CALL 9095 (call open)
9070 INR A
9071 ??= 20
9072 DCX B
9073 LXI H,90A9
9076 CALL 8FB2
9079 CALL 8E09
#

Something was not happy in the ldccp function, right after the call to open the file. Right where we were supposed to be testing to see if the CCP.COM file opened successfully. Right where it stopped working.

What a kick in the crotch.

I examined the source code, the BOOT3.ASM file. What I saw was the BOOT3 code uses a JRNZ instruction. Must be a macro for Z80 processors that isn't supported on the 8080 'cause the RMAC output was a 20 followed by 0B. SID didn't know what to make of the 20, but it interpreted the 0B as a DCX B instruction. The 0B would be the right offset for a relative jump to the intended address, so the JRNZ macro must represent a Jump Relative if Not Zero instruction. An 11-byte jump would put the PC at the right address, but the 20 opcode doesn't work on the Altair's 8080 processor, so I removed the JRNZ instruction and replaced it with a JNZ instead.

Worked first time. Didn't even need SID. It just booted and displayed the "A>" prompt.

Victory!

It still needs work though. When I type DIR, I see goofy characters. It's obviously reading stuff, and it even matches files if I type "dir ccp.com" or some other thing that matches existing files. But it's printing weird stuff on the screen. And I still need to move the decrement instruction out of BIOSKRNL.asm and into FDC3.asm, or at least I think I do. And, of course, I still need to link in the IDE3 module and debug that. So we're not all the way there yet. Still have a way to go.

But it boots. I'm calling that a win for today.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 10th, 2023, 8:38 pm

I had a couple hours this evening so I used them for BIOS development.

As I mentioned above, the modular BIOS boots now but isn't fully working. When I type "DIR," I see this:

A>dir
A:
BIOS3 : S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$ :
BIOS3
A: S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$ :
BIOS3 : S3 SP R
A: PA
$$$$ $$$ : $$$$$$$$ $$$ :
BIOS3 : PA
$$$$ $$$ : $$$$$$$$ $$$
A: S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$ :
BIOS3 : S3 SP R
A: PA
$$$$ $$$ : $$$$$$$$ $$$ :
BIOS3 : S3 SP R : PA
$$$$ $$$
A: $$$$$$$$ $$$ :
BIOS3 : S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$

Press RETURN to Continue
A>

The system boots just fine, but the directory listing is strange.

So I'll monitor what track and sector are being requested and also what is being read into memory AFTER the boot process is completed. I'll do a "DIR" command and watch what is being read. And I'll compare it with a known-good version of Mike Douglas's BIOS.

First, let's find out where everything is. Placing passpoints at setsec, settrk and setdma will illuminate where @SECT, @TRK and @DMA are in memory. And then we'll set a passpoint at the end of the read function and monitor what happens there.

A>sid cpmldr.com
CP/M 3 SID - Version 3.0
NEXT MSZE PC END
2500 2500 0100 CBFF
#I$B
#G

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

BIOS3 SPR 8E00 1C00
BDOS3 SPR 6F00 1F00

27K TPA

*01A9
#L8E00
8E00 JMP A894 (boot)
8E03 JMP 8E6C (wboot)
8E06 JMP 8F72 (const)
8E09 JMP 8F8D (conin)
8E0C JMP 8ED5 (conout)
8E0F JMP 8EE1 (list)
8E12 JMP 8EDB (auxout)
8E15 JMP 8F93 (auxin)
8E18 JMP A902 (home)
8E1B JMP A8D3 (seldsk)
8E1E JMP A905 (settrk)
8E21 JMP A90B (setsec)
8E24 JMP A912 (setdma)
8E27 JMP A929 (read)
8E2A JMP A93F (write)
8E2D JMP 8F0D (listst)
8E30 JMP A91E (sectrn)
8E33 JMP 8F01 (conost)
8E36 JMP 8F78 (auxist)
8E39 JMP 8F07 (auxost)
8E3C JMP 8ECD (devtbl)
8E3F JMP 9105 (devini)
8E42 JMP 8ED1 (drvtbl)
8E45 JMP A960 (multio)
8E48 JMP A964 (flush)
8E4B JMP 9283 (move)
8E4E JMP 9095 (time)
8E51 JMP 9020 (selmem)
8E54 JMP A91A (setbnk)
8E57 JMP 9282 (xmove)
8E5A JMP 0000 (userf)
8E5D JMP 0000 (reserv1)
8E60 JMP 0000 (reserv2)

Setting passpoints at setsec, settrk and setdma to find out where the memory locations of interest are located.

#PA905 (settrk)
#PA90B (setsec)
#PA912 (setdma)
#G8E00


CP/M Plus v3.0hd


01 PASS A905 (settrk)
-Z-E- A=00 B=0000 D=00C0 H=972F S=6FE0 P=A905 MOV L,C
*A906
#T
-Z-E- A=00 B=0000 D=00C0 H=9700 S=6FE0 P=A906 MOV H,B
*A907
#T
-Z-E- A=00 B=0000 D=00C0 H=0000 S=6FE0 P=A907 SHLD A984
*A90A
#T
-Z-E- A=00 B=0000 D=00C0 H=0000 S=6FE0 P=A90A RET
*774F

@TRK is at location A984. Notice the first time, it stored 00 there.

#G

01 PASS A905 (settrk again)
-Z-EI A=00 B=0002 D=0000 H=0002 S=6FC8 P=A905 MOV L,C
*A906
#G (so skip it, keep runnin')

01 PASS A90B (setsec)
--ME- A=93 B=0001 D=0000 H=0001 S=6FD0 P=A90B MOV L,C
*A90C
#T
--ME- A=93 B=0001 D=0000 H=0001 S=6FD0 P=A90C MOV H,B
*A90D
#T
--ME- A=93 B=0001 D=0000 H=0001 S=6FD0 P=A90D DCX H
*A90E
#T
--ME- A=93 B=0001 D=0000 H=0000 S=6FD0 P=A90E SHLD A986
*A911
#T
--ME- A=93 B=0001 D=0000 H=0000 S=6FD0 P=A911 RET
*7853

@SECT is at location A986.

#G

01 PASS A912 (setdma)
--ME- A=93 B=96AE D=0000 H=96AE S=6FD2 P=A912 MOV L,C
*A913
#T
--ME- A=93 B=96AE D=0000 H=96AE S=6FD2 P=A913 MOV H,B
*A914
#T
--ME- A=93 B=96AE D=0000 H=96AE S=6FD2 P=A914 SHLD A988
*A917
#T
--ME- A=93 B=96AE D=0000 H=96AE S=6FD2 P=A917 LDA 9036
*A91A
#T
--ME- A=00 B=96AE D=0000 H=96AE S=6FD2 P=A91A STA A98B
*A91D
#T
--ME- A=00 B=96AE D=0000 H=96AE S=6FD2 P=A91D RET
*8CE6

@DMA is at location A988. The 9036 (@CBNK) and A98B (@DBNK) locations are only used in systems with bank-memory.

Now let's find out where the fdRead function returns - the actual hardware layer code called by the "read" function in the jump table above - so we can place a passpoint there for monitoring. Before modifying the code to replace the JRNZ with a JNZ, the RZ (return on success) was at 9341 and the RET (return on failure) was at 9343. So I expect them to be very close to those locations after the code change, because the new code is only one byte longer than the old code. We'll list about ten bytes ahead of the end of the read function and simply look to find the RZ and RET with the INR A between them. That is the end of the read code function.

#L9330
9330 RET
9331 RET
9332 CALL 944F
9335 EI
9336 CALL 93E8
9339 EI
933A JNZ 9340
933D CALL 9353
9340 MVI A,00
9342 RZ
9343 INR A
9344 RET
9345 CALL 944F
9348 EI
9349 CALL 93E8
934C EI
934D JNZ 9340
9350 JMP 937A
9353 CALL 93D8
9356 CALL 95A2
9359 MOV A,M
935A ORA A
#

The returns I'm interested in appear to be at locations 9342 and 9344.

#P9342
#P9344

Now that we know where @TRK, @SECT and @DMA are stored in memory, I'm not interested in stopping in the setsec, settrk or setdma functions anymore. So here I'll remove those passpoints:

#-PA905 (settrk)
#-PA90B (setsec)
#-PA912 (setdma)

#G
01 PASS 9342
-Z-EI A=00 B=0000 D=97F8 H=972E S=6FD2 P=9342 RZ
*7767
#G

01 PASS 9342
-Z-EI A=00 B=0010 D=9C40 H=972E S=6FD2 P=9342 RZ
*7767
#G

01 PASS 9342
-Z-EI A=00 B=0020 D=A088 H=972E S=6FD2 P=9342 RZ
*7767
#G

01 PASS 9342
-Z-EI A=00 B=0030 D=A4D0 H=972E S=6FD2 P=9342 RZ
*7767


... and just keep doing this 'til we get to the "A>" prompt. That's what I'm interested in right now. It reads a few dozen sectors before it is done loading CCP.COM.

#G

01 PASS 9342
-Z-EI A=00 B=0024 D=A19A H=972E S=6FD4 P=9342 RZ
*7767
#G

01 PASS 9342
-Z-EI A=00 B=0034 D=A5E2 H=972E S=6FD4 P=9342 RZ
*7767
#G

01 PASS 9342
-Z-EI A=00 B=0008 D=9A1C H=972E S=6FD4 P=9342 RZ
*7767
#G
A>

Now we're booted. Type "DIR" and monitor @TRK, @SECT and @DMA at the end of each sector read.

A>DIR

01 PASS 9342
-Z-EI A=00 B=0000 D=97F8 H=972E S=6FD6 P=9342 RZ
*7767
#DA984,A989
A984: 02 00 00 00 AE 96 ......
#D96AE
96AE: 00 4C 38 30 20 20 20 20 20 43 4F 4D 00 00 00 54 .L80 COM...T
96BE: 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 ................
96CE: 00 50 43 32 46 4C 4F 50 20 43 4F 4D 00 00 00 11 .PC2FLOP COM....
96DE: 08 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96EE: 00 46 4C 4F 50 32 50 43 20 43 4F 4D 00 00 00 13 .FLOP2PC COM....
96FE: 0A 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
970E: 00 41 53 4D 20 20 20 20 20 43 4F 4D 00 00 00 40 .ASM COM...@
971E: 0C 0D 0E 0F 00 00 00 00 00 00 00 00 00 00 00 00 ................
972E: FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 00 ................
973E: 00 00 00 7E 65 11 1E 16 CE D5 01 0B 00 00 00 00 ...~e...........
974E: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#G
A:
BIOS3 : S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS 9342
-Z-EI A=00 B=0010 D=9C40 H=972E S=6FD6 P=9342 RZ
*7767

That's interesting. The contents of @TRK, @SECT and @DMA are exactly the same as what they were during the boot sequence after the first sector read. I'll keep looking.

One thing I must constantly remind myself is it isn't productive to trace through BDOS. I am sometimes tempted to do that, to see what BDOS does with the data returned by BIOS. This is one of those times. And I may travel around in BDOS for a while, but I must remember that the same BDOS being used here is also used by known good implementations of CP/M. So it makes sense to focus on differences in BIOS.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 11th, 2023, 7:37 pm

This afternoon, I did all the same stuff to boot CP/M using SID CPMLDR.COM. I set a passpoint at the end of the read function and ran the code until it displayed the "A>" prompt. And there, after typing "DIR," I examined locations 0080 in addition to 96AE. I read that CCP uses the contents of memory at 0080, so I thought I'd check it out and see what's there. This is what I saw:

#D96AE
96AE: 00 4C 38 30 20 20 20 20 20 43 4F 4D 00 00 00 54 .L80 COM...T
96BE: 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 ................
96CE: 00 50 43 32 46 4C 4F 50 20 43 4F 4D 00 00 00 11 .PC2FLOP COM....
96DE: 08 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96EE: 00 46 4C 4F 50 32 50 43 20 43 4F 4D 00 00 00 13 .FLOP2PC COM....
96FE: 0A 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
970E: 00 41 53 4D 20 20 20 20 20 43 4F 4D 00 00 00 40 .ASM COM...@
971E: 0C 0D 0E 0F 00 00 00 00 00 00 00 00 00 00 00 00 ................
972E: FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 00 ................
973E: 00 00 00 7E 65 11 1E 16 CE D5 01 0B 00 00 00 00 ...~e...........
974E: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#D0080
0080: 0D 0A 20 42 49 4F 53 33 20 20 20 20 53 50 52 20 .. BIOS3 SPR
0090: 20 38 45 30 30 20 20 31 43 30 30 0D 0A 20 42 44 8E00 1C00.. BD
00A0: 4F 53 33 20 20 20 20 53 50 52 20 20 36 46 30 30 OS3 SPR 6F00
00B0: 20 20 31 46 30 30 0D 0A 20 0A 0D 20 32 37 4B 20 1F00.. .. 27K
00C0: 54 50 41 0A 0D 24 24 24 24 24 24 24 24 24 24 24 TPA..$$$$$$$$$$$
00D0: 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 $$$$$$$$$$$$$$$$
00E0: 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 $$$$$$$$$$$$$$$$
00F0: 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 $$$$$$$$$$$$$$$$
0100: C3 1A 04 00 00 00 C3 1B 01 C3 06 00 07 00 00 00 ................
0110: 4C 4F 41 44 45 52 20 20 FF 00 00 79 FE 3B C2 09 LOADER ...y.;..
0120: 01 C1 C5 21 00 00 39 31 BE 03 22 9A 03 C5 EB 22 ...!..91.."...."
0130: 98 03 7C B5 F5 CC 00 02 F1 C4 30 02 D1 21 00 01 ..|.......0..!..


Then I did the same thing using the Douglas BIOS. Set passpoint at 9139, which is the end of the read function in his code. DMA is set to 9561 during bootup.

#D9561
9561: 00 4C 38 30 20 20 20 20 20 43 4F 4D 00 00 00 54 .L80 COM...T
9571: 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 ................
9581: 00 50 43 32 46 4C 4F 50 20 43 4F 4D 00 00 00 11 .PC2FLOP COM....
9591: 08 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
95A1: 00 46 4C 4F 50 32 50 43 20 43 4F 4D 00 00 00 13 .FLOP2PC COM....
95B1: 0A 0B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
95C1: 00 41 53 4D 20 20 20 20 20 43 4F 4D 00 00 00 40 .ASM COM...@
95D1: 0C 0D 0E 0F 00 00 00 00 00 00 00 00 00 00 00 00 ................
95E1: FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 00 ................
95F1: 00 00 00 7E 65 11 1E 16 CE D5 05 0B 00 00 00 00 ...~e...........
9601: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9611: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#D0080
0080: 0D 0A 20 42 49 4F 53 33 20 20 20 20 53 50 52 20 .. BIOS3 SPR
0090: 20 38 45 30 30 20 20 31 41 30 30 0D 0A 20 42 44 8E00 1A00.. BD
00A0: 4F 53 33 20 20 20 20 53 50 52 20 20 36 46 30 30 OS3 SPR 6F00
00B0: 20 20 31 46 30 30 0D 0A 20 0A 0D 20 32 37 4B 20 1F00.. .. 27K
00C0: 54 50 41 0A 0D 24 24 24 24 24 24 24 24 24 24 24 TPA..$$$$$$$$$$$
00D0: 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 $$$$$$$$$$$$$$$$
00E0: 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 $$$$$$$$$$$$$$$$
00F0: 24 24 24 24 24 24 24 24 24 24 24 24 24 24 FD 8E $$$$$$$$$$$$$$..
0100: C3 1A 04 00 00 00 C3 1B 01 C3 06 00 07 00 00 00 ................
0110: 4C 4F 41 44 45 52 20 20 FF 00 00 79 FE 3B C2 09 LOADER ...y.;..
0120: 01 C1 C5 21 00 00 39 31 BE 03 22 9A 03 C5 EB 22 ...!..91.."...."
0130: 98 03 7C B5 F5 CC 00 02 F1 C4 30 02 D1 21 00 01 ..|.......0..!..

I see the same behavior here in both versions of code. So I don't think there's a problem in the read function. It is interesting though - Notice that the data displayed appears very much like what's at location 0080. It's like the modular code makes the display show data from 0080 instead of @DMA.

When you type "DIR" using the modular BIOS, this is what is displayed on the first directory sector read:

A:
BIOS3 : S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$


So to explore the possibility that maybe @DMA is being improperly set, I checked the seldsk and setdma function calls. Passpoint at each function, watching for it right after a "DIR" request.

Douglas:

A>DIR

01 PASS 90E5
-Z-EI A=00 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
A: L80 COM : PC2FLOP COM : FLOP2PC COM : ASM COM
01 PASS 90E5
----I A=08 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
: DUMP COM
A: XSUB COM : FORMAT COM : LS COM
01 PASS 90E5
----I A=10 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
: SUBMIT COM : LOAD COM
A: SURVEY COM : VIEW COM
01 PASS 90E5
---EI A=18 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
: M80 COM : MAC COM : MBASIC COM
01 PASS 90E5
----I A=02 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G

A: PIP COM : STAT COM : DDT COM
01 PASS 90E5
---EI A=0A B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
: PCPUT COM : NSWP COM
A: SYSGEN COM : PCGET COM
01 PASS 90E5
---EI A=12 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
: CRC COM : MOVCPM COM : SID COM
A: CPMLDR COM
01 PASS 90E5
----I A=1A B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G
: CPM3 SYS : CCP COM : CPM3MOD SYS : CPM3DUG SYS
01 PASS 90E5
----I A=04 B=9561 D=0000 H=9561 S=6FD6 P=90E5 MOV H,B
*90E6
#G

A>

The only seldsk call happened during bootup. The setdma calls happened before every sector read. But they were all at the same familiar address as happened during the bootup directory read.

Next, I did the same thing using the modular code.

Modular:

A>DIR

01 PASS A912
--ME- A=93 B=96AE D=0000 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
A:
BIOS3 : S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0001 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
:
BIOS3
A: S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0002 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
:
BIOS3 : S3 SP R
A: PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0003 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
:
BIOS3 : PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0004 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G

A: S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0005 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
:
BIOS3 : S3 SP R
A: PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0006 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
:
BIOS3 : S3 SP R : PA
$$$$ $$$
A: $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0007 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G
:
BIOS3 : S3 SP R : PA
$$$$ $$$ : $$$$$$$$ $$$
01 PASS A912
--ME- A=93 B=96AE D=0008 H=96AE S=6FD6 P=A912 MOV L,C
*A913
#G


Press RETURN to Continue
A>

So @DMA is set to the memory block that has the directory data in both the Douglas and the modular code. At this point, I think that's correct behavior. At least it's the same between the two versions.

Two differences I see. One is the state of the accumulator and the other is [DE]. These are setdma function entry values. Of course, setdma only cares about [BC], so it's not significant to that particular function. But I thought it might be relevant to subsequent code flow. It doesn't appear to be though - I stepped through the code - but I'm making a note of it anyway, just in case. Still, I think it's just a side-effect of different code being used, and each leaving different left-over data in those registers.

So next time I look at this, tomorrow, I'll probably explore different avenues.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 12th, 2023, 9:32 pm

I didn't have as much time to work on BIOS today as I'd hoped, but I did at least do some research into CCP.

While I realize that BDOS and CCP are both known good programs, I think it might be useful to trace into them. Might help me learn what is happening to cause the modular BIOS "DIR" command to behave as it does. So I started SID CPMLDR.COM, set a passpoint at the end of the read function and ran it up to the point where CP/M was booted and CCP was in memory. When it displayed the "A>" prompt, I did a "DIR" and the passpoint caught right after the read function. There, I listed location 100 to see where CCP was placed in memory:

A>dir

01 PASS 9342
-Z-EI A=00 B=0000 D=97F8 H=972E S=6FD6 P=9342 RZ
*7767
#L0100
0100 JMP 041A <==
#L041A
041A LXI SP,0F2D (beginning of CCP)
041D LXI H,050C
0420 PUSH H
0421 LXI D,0D6A
0424 MVI C,31
0426 CALL 0005
0429 SHLD 038D
042C MVI L,FA
042E MOV A,M
042F STA 038F
0432 MVI L,99

...

04D9 LXI D,0DF5 (chain)
04DC MVI C,7F
04DE MOV A,C
04DF STAX D
04E0 INX D
04E1 CALL 0BAE
04E4 JMP 058B
04E7 MVI L,B5
04E9 MOV A,M
04EA ANI 02

...

0506 CALL 0BE4 (ccpcr)
0509 CALL 0C09
050C LXI H,0F2B
050F SPHL
0510 XRA A
0511 STA 0D99
0514 LXI H,050C
0517 PUSH H
0518 CALL 0BE4
051B DCX H
051C MOV A,M
051D ANI 01
051F JZ 0564 (jz prompt)
0522 LXI D,0DF5
0525 CALL 097B (call setbuf, which uses D as argument)
0528 MVI C,0F
052A CALL 09F0

...

0564 LDA 0D70 (prompt)
0567 ORA A
0568 CNZ 0C13
056B CALL 066D (call dirdrv1)
056E MVI A,3E ('>' prompt character)
0570 CALL 0916 (call putc)
0573 LXI D,B1BA
0576 CALL 0BA7
0579 ORA A
057A PUSH PSW
057B LXI B,B480
057E CNZ 0BF1
0581 CALL 094E
0584 CALL 0BEE
0587 POP PSW
0588 CNZ 0AA8

...

058B CALL 0BDA (ccparse)
058E JNZ 0596
0591 MVI L,C9
0593 MOV A,M
0594 DCX H
0595 MOV M,A
0596 MVI L,C8
0598 MOV A,M
0599 STA 0D9A
059C CALL 09F6 (call uc)
059F RZ
05A0 LXI D,0DAC
05A3 CALL 0B39 (call gcmd)
05A6 LDA 0DB6
05A9 CPI 20
05AB JNZ 0604 (jnz ccpdisk2, execute external command from disk file)
05AE LXI H,0DAC
05B1 MOV A,M
05B2 INX H
05B3 ORA M
05B4 INX H
05B5 MOV A,M
05B6 JNZ 060A (jnz ccpdisk3 - if command preceeded by drive letter)
05B9 LXI H,0637 (ccpbuiltin: begin processing built-in command)
05BC LXI D,0DAE
05BF LDA 0DB0
05C2 CPI 21 (is command shorter than 3 characters?)
05C4 CNC 0CBF (cnc tbls - is command in the built-in cmd table?)
05C7 JNZ 05E8 (jnz ccpdisk0 - if not in table, so external)
05CA LDA 0DA1 (lda option - looking for '[' in command line)
05CD ORA A
05CE MOV A,B
05CF LHLD 0D6C
05D2 SHLD 0D9D
05D5 LXI H,065A
05D8 JZ 0858 (jz tblj)
05DB CPI 04
05DD JC 0786 (jc trycom)
05E0 LXI H,0DB1
05E3 JNZ 05E8
05E6 MVI M,20
05E8 LXI B,B418 (ccpdisk0: lxi b,order)
05EB CALL 0BDD (call getflg; 0=COM 8=COM,SUB 16=SUB,COM)
05EE JZ 0604 (jz ccpdisk2)
05F1 MVI B,08
05F3 SUB B
05F4 JZ 05F9 (jz ccpdisk1; search for COM first, then SUB)
05F7 MVI B,00
05F9 PUSH B (ccpdisk1:)
05FA CALL 087A (call settype)
05FD CALL 07E4 (call exec)
0600 POP PSW (exec returns only if call was unsuccessful, so reset flags and A)
0601 CALL 087A (call settype)
0604 CALL 07E4 (ccpdisk2: call exec)
0607 JMP 0C3A (jmp perror)
060A CPI 20 (ccpdisk3:)
060C JNZ 05E8 (jnz ccpdisk0)
060F CALL 0C36 (call eoc - error if not end of command)
0612 LDA 0DAC
0615 SUI 01
0617 JC 0625 (jc ccpdrive)
061A STA 0D70 (ccpuser:)
061D MVI B,B0
061F CALL 0BF9 (call setbyte)
0622 CALL 0986 (call setuser)
0625 LDA 0DAD (ccpdrive:)
0628 DCR A
0629 RM
062A PUSH PSW
062B CALL 0980 (call select)
062E POP PSW
062F STA 0D72
0632 MVI B,AF
0634 JMP 0BF9 (jmp setbyte)

...

0666 LDA 005C (dirdrv:)
0669 DCR A
066A JP 0670 (jp dirdrv2)
066D LDA 0D72 (dirdrv1:)
0670 ADI 41
0672 JMP 0CA6 (jmp pfc - print drive letter)
0675 MVI C,00 (dir:)
0677 LXI D,0D52
067A JMP 0682 (jmp dirs1)
067D MVI C,80 (dirs:)
067F LXI D,0D4E
0682 PUSH D (dirs1:)
0683 CALL 0699 (call direct)
0686 POP D
0687 JZ 07B8 (jz nofile)
068A MOV A,L
068B CMP B
068C CNC 0C09
068F LXI H,0D4D
0692 DCR M
0693 INR M
0694 RZ (return if no files)
0695 DCR M
0696 JMP 0C05 (jmp pmsgnl)
0699 PUSH B (direct:)
069A CALL 0978 (call sbuf80 - set DMA=0080)
069D CALL 0AD8 (call gfn - parse file name)
06A0 LXI D,005D
06A3 LDAX D
06A4 CPI 20
06A6 MVI B,0B
06A8 CZ 0CB5 (cz setmatch - use "????????.???" if none)
06AB CALL 0C36 (call eoc - make sure there's nothing else)
06AE CALL 09C3 (call srchf - search for first directory entry)
06B1 POP B
06B2 RZ (return if no files found)
06B3 LDA 0D97 (dir0:)
06B6 MOV L,A
06B7 MOV B,A
06B8 INR B
06B9 PUSH H (dir1:)
06BA LXI H,000A
06BD DAD D
06BE MOV A,M
06BF POP H
06C0 ANI 80
06C2 CMP C
06C3 JZ 06CE (jz dir2 - display, if modes agree)
06C6 MVI A,01
06C8 STA 0D4D
06CB JMP 06E5 (jmp dir3 - don't print anything)
06CE DCR B (dir2: print the filename)
06CF CZ 0C08 (cz dirln)
06D2 MOV A,B
06D3 CMP L
06D4 CZ 0666 (cz dirdrv - print drive letter)
06D7 MVI A,3A (':' character)
06D9 CALL 0CA6 (call pfc - print colon)
06DC CALL 0CA4 (call space - print space)
06DF CALL 0C8D (call pfn - print filename)
06E2 CALL 0CA4 (call space)
06E5 PUSH B (dir3:)
06E6 PUSH H
06E7 CALL 0966 (call break - watch for keystroke)
06EA CALL 09C8 (call srchn - search for another match)
06ED POP H
06EE POP B
06EF JNZ 06B9 (jnz dir1)
06F2 INR A (direx:)
06F3 RET

...

0C8D INX D (pfn: print filename)
0C8E MVI H,08
0C90 CALL 0C98 (call pfn1)
0C93 CALL 0CA4 (call space)
0C96 MVI H,03
0C98 LDAX D (pfn1:)
0C99 ANI 7F
0C9B CALL 0CA6 (call pfc)
0C9E INX D
0C9F DCR H
0CA0 JNZ 0C98 (jnz pfn1 - iterate through filename)
0CA3 RET
0CA4 MVI A,20 (space:)
0CA6 PUSH B (pfc:)
0CA7 PUSH D
0CA8 PUSH H
0CA9 CALL 0916 (call putc)
0CAC POP H
0CAD POP D
0CAE POP B
0CAF RET

Basically, I just listed the first few hundred instructions, matching them with the source code. That gave me a few good addresses that would be useful as passpoints. I didn't have time to go further, but will soon.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 14th, 2023, 10:11 am

Last night, I had a few minutes and used them to step through CCP up to the point where it displayed the DIR contents. If you look through the listing in the post above, you'll find location 069A is a call to a function labeled "sbuf80." It sets @DMA to 0080, so directory contents are expected there. And stepping through the code showed exactly that.

The code I traced last night was the modular code. I'm anxious to find time to do the same using Mike's BIOS. What I expect is to see directory information at 0080 when CCP is run. The thing is, I've already seen that the contents of @DMA and 0080 are the same in the modular and the Douglas code at the end of the read function. I demonstrated that a couple of posts back. But I'm thinking maybe something copies the contents of @DMA to 0080 in the long journey through BDOS and CCP before we reach the point of displaying the directory in CCP.

I've realized that I made some assumptions about the modular BIOS code that wasn't true. I had assumed that most of the modules were invariant and that only the device drivers needed to be modified. But I am now starting to think that only the one file - BIOSKRNL - is actually invariant and that all others are machine-specific. I say this because if there is something that moves the contents of @DMA to 0080 before displaying the directory, it is more than likely in the module named MOVE.ASM. My guess is I'll find some machine-specific code there, which now that I think about it makes perfect sense because it would have to be to support bank-switching.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 14th, 2023, 1:23 pm

I don't have time to work on the BIOS right now, but I will as soon as possible, especially knowing what I just learned.

On a hunch that the DIR problem was related to a memcpy of some sort, I gave a quick look at the MOVE3.ASM module and sure enough, it contains an LDIR instruction. As you may have seen during the course of this thread, I've run into a few cases where a Z80 instruction was used in code I was attempting to run, and this is apparently also the case.

My BIOS is basically a marriage between Mike Douglas's and John Monahan's. Douglas designed the FDC board and Monahan designed the IDE board. The 88-2SIO is Martin Eberhard's. So my BIOS has CHARIO3.ASM that talks to SIO and 2SIO async boards, FDC3.ASM that talks to the floppy disk controller and IDE3.ASM that talks to the IDE board.

I started with a set of modular files provided by Monahan, and I've been stitching-in Douglas's FDC code to support the diskette drives. But one thing I overlooked was that only BIOSKRNL.ASM is provided my Digital Research and invariant. I initially thought all the files were invariant except the device drivers. And that's true, but essentially all the files except BIOSKRNL.ASM contain device drivers.

When the console didn't work, I realized that the CHARIO.ASM file was device-specific so I replaced the Monahan-specific code with Douglas's code that supported both SIO and 2SIO interfaces. That got async working. Then I found a slight difference in the sector translation between Douglas's code and the Digital Research code in BIOSKRNL, so a little modification got the system to boot. I've also seen a few cases where Z80 instructions were used in various modules, which tells me that Monahan is a Z80 guy. This deal in the MOVE3.ASM module is another one of those.

So I'll rebuild MOVE3.ASM, replacing LDIR with an 8080-compatible memcpy function very soon and report back.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

Re: IDE interface for Altair 8800c

Postby Wayne Parham » February 14th, 2023, 8:20 pm

That did it! I now have a modular version of BIOS that works!

So I'll attach the source files.

But this is still a work in progress. The IDE3 module isn't linked yet. So this is really just a port of Mike Douglas's CP/M 3 BIOS into a modular format. And I've only done quick tests - I've booted, I've copied a COM file, I've run the file and then I've deleted it. That's it. So the code needs more thorough testing. Mike did a LOT of work to make a high-performance track-buffered BIOS, and I was careful to stitch it all into the modular format - I think - but that's the point. It needs more validation to be sure. And the modules need to be "cleaned up" and references added as appropriate.

Still, it boots and runs. If you want to build it yourself, assemble each module with RMAC, then LINK 'em all with the [os] switch. Like this:

RMAC BIOSKRN3
RMAC SCB3
RMAC BOOT3
RMAC CHARIO3
RMAC MOVE3
RMAC DRVTBL3
RMAC FDC3
LINK BIOS3[os]=BIOSKRN3,SCB3,BOOT3,CHARIO3,MOVE3,DRVTBL3,FDC3

The output of that is BIOS3.SPR. It's combined with BDOS3.SPR to create CPM3.SYS. To do that, run GENCPM and answer its questions as follows:

Create a new GENCPM.DAT file (N) ? N
Display Load Map at Cold Boot (Y) ? Y

Number of console columns (#80) ? 80
Number of lines in console page (#24) ? 24
Backspace echoes erased character (N) ? N
Rubout echoes erased character (Y) ? Y
Initial default drive (A:) ? A
Top page of memory (FF) ? FE
Bank switched memory (Y) ? N
Double allocation vectors (Y) ? N
Accept new system definition (Y) ? Y

That will create a bootable CPM3.SYS for you.

I'll add IDE3 next and report back. Source files for the system as it is follows.
Wayne Parham
 
Posts: 240
Joined: March 18th, 2022, 3:01 pm

PreviousNext

Return to Altair 8800c

Who is online

Users browsing this forum: No registered users and 5 guests

cron