• Please review our updated Terms and Rules here

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

Rats, that routine needs a better fix. Let's replace it with this:

Code:
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?
 
Okay, that gives me:

Code:
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
Code:
JP ccp
though?
 
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.
 
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:

Code:
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
 
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).
 
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
 
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:

Code:
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.
 
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
 
Sorry daver, missed your questions about H and L:

Code:
After BDOS 20, A = 01
HL = 1901

This time around, however, the console output carried on with the following:

Code:
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:

Code:
CP/M Error On K: Invalid Drive
BDOS Function = 15  File = CCP     .COMLoading CCP...
Bank 1 selected...
seldsk called...
 
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.

Code:
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: View attachment BIOS3.ASM.txt
 
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
 
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.
 
Yeah, weird stuff is happening and it's likely because of my diagnostic prints...

Latest console log:

Code:
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:

Code:
;----------------------------------------------------------------------------------------------
; 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
 
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
 
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
 
Okay, I've tweaked the PHEX code to preserve the C register without using the stack. Here's the result:

Code:
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:

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!
 
Back
Top