-
Notifications
You must be signed in to change notification settings - Fork 7
Unstable CCF SCF Behaviour
This page documents the behaviour of the undocumented X/Y flags following a CCF/SCF instruction. The tests were performed on an Acorn Z80 Second Processor, at three different clock speeds: 2.0 MHz, 3.5 MHz and 6.0 MHz. NMOS and CMOS Z80 processors were tested, from Zilog, NEC and SGS/ST.
The test renders a 256x256 pixel graphic that shows the X or Y flag value for all values of F (Y axis) and A (X axis)
For each processor, a total of 16 test cases were generated, varying the following:
- plotting the X flag (bit 3) and the Y flag (bit 5)
- testing CCF and SCF
- testing with four different instruction sequences
The four different instruction sequences were
Sequence A:
POP AF
CCF or SCF
PUSH AF
Sequence B:
POP AF
NOP
CCF or SCF
PUSH AF
Sequence C:
POP AF
LD R,A
CCF or SCF
PUSH AF
Sequence D:
POP AF
XOR &00
CCF or SCF
PUSH AF
Sequences A, B and C cover the case where the preceding instruction doesn't update the flags, and sequence D covers the case where the preceding instruction does update the flags.
Note: Patrik Rak produced similar test in 2022 called z80ccfscr. That test explores a smaller state space:
- Flags in the range 40-4F
- CCF only
- Sequence A only
You can explore the results on the following pages:
- Results Zilog NMOS Date Code 8039
- Results Zilog NMOS Date Code 8644
- Results Zilog NMOS Date Code 8811
- Results SGS NMOS
- Results NEC NMOS
- Results Zilog CMOS
- Results ST CMOS
- Results NEC CMOS
Four of the processors exhibited stable behaviour, with no random element, and consistent as the clock speed was varied.
Three of these four processors behaved identically:
- Zilog NMOS with date Code 8039 (the oldest Zilog tested)
- Zilog CMOS
- SGS NMOS
We will refer to this behaviour as "pattern A":
if <previous instruction modified the flags> then
YF = A.5
XF = A.3
else
YF = YF | A.5
XF = XF | A.3
endif
This is the behaviour discovered by Patrik Rak in 2012. It depends on the whether or not the preceding instruction modifies the flags. This is commonly known as the "Q factor".
The fourth processor that was stable was the Zilog NMOS processor with date code 8811. This exhibited a different, much simpler, form of stable behaviour.
We will refer to this behaviour as "pattern B":
YF = A.5
XF = A.3
This is a degenerate form of pattern "A", which doesn't depend on the "Q factor".
Note: This processor is genuine and was the original processor from a Spectrum +2B. The date code matches a photo on Wikipedia link
Three of the processors exhibited unstable behaviour, where there was some kind of random element:
- Zilog NMOS with date code 8634
- ST CMOS
- NEC NMOS
The Zilog NMOS processor with date code 8634 displayed an unstable form of pattern A:
if <previous instruction modified the flags> then
YF = A.5
XF = A.3
else
YF = (YF & random) | A.5
XF = (XF & random) | A.3
endif
You can see the effect of the random element in this test result:
The NEC NMOS processor displayed a different form of unstable behaviour:
if <previous instruction modified the flags> then
YF = A.5
XF = A.3
else
YF = (YF | random) & A.5
XF = (XF | random) & A.3
endif
You can see the effect of the random element in this test result:
What's interesting is the random factor here is clearly clock speed dependent.
At 2.0 MHz:
At 3.5 MHz:
At 6.0 MHz:
This is consistent with the charge on an internal node slowly leaking away.
At low (decreasing) clock speeds the behaviour tends towards pattern "B":
YF = A.5
XF = A.3
At high (increasing) clock speeds the behaviour tends towards:
if <previous instruction modified the flags> then
YF = A.5
XF = A.3
else
YF = YF & A.5
XF = XF & A.3
endif
The ST CMOS processor shows yet another variation: the Y flag is stable and the X flag is unstable:
if <previous instruction modified the flags> then
YF = A.5
XF = A.3
else
YF = YF (i.e. unchanged)
XF = (XF & random) | A.3
endif
You can see the effect of the random element in this test result:
It's quite likely that if we tested more processors we would discover further variations.
The NEC CMOS processor is the strangest of all, and I haven't yet sat down and tried to analyse it.
I have some more processors that I plan to test:
- further Zilog (NMOS and CMOS) with different date codes
The above tests were run on a Acorn Z80 Second processor using the following BASIC/assembly language program.
10 MODE 4
20 INPUT "CPU NAME ";CPU$
30 INPUT "DATE CODE ";DATE$
40 INPUT "CLOCK SPEED ";SPEED$
50 FOR F=0 TO 1
60 FOR INSTR=0 TO 3
70 FOR CF=0 TO 1
80 code%=&E000
90 OSWRCH=&FFEE
100 FOR I%=0 TO 2 STEP 2
110 P%=code%
120 [OPT I%
130 .test
140 \ SET Y/X FLAGS
150 LD DE,&0000
160 .loop
170 PUSH DE
180 PUSH DE
190 POP AF
200 NOP
210 NOP
220 POP AF
230 ]
240 IF INSTR=1 THEN [OPT I%:NOP:]
250 IF INSTR=2 THEN [OPT I%:LD R,A:]
260 IF INSTR=3 THEN [OPT I%:XOR &00:]
270 IF CF=0 THEN [OPT I%:CCF:]
280 IF CF=1 THEN [OPT I%:SCF:]
290 [OPT I%
300 \ SAVE FLAGS
310 PUSH AF
320 POP HL
330 LD A,L
340 ]
350 IF F=1 THEN [OPT I%:RRCA:RRCA:]
360 [OPT I%
370 AND &08
380 JR NZ skip
390 LD A,25
400 CALL OSWRCH
410 LD A,71
420 CALL OSWRCH
430 LD L,D
440 LD H,&00
450 ADD HL,HL
460 ADD HL,HL
470 LD A,L
480 CALL OSWRCH
490 LD A,H
500 CALL OSWRCH
510 LD L,E
520 LD H,&00
530 ADD HL,HL
540 ADD HL,HL
550 LD A,L
560 CALL OSWRCH
570 LD A,H
580 CALL OSWRCH
590 .skip
600 INC E
610 JR NZ,loop
620 INC D
630 JR NZ,loop
640 RET
650 ]
660 NEXT
670 MODE 4
680 MOVE 0,0
690 MOVE 1023,0
700 PLOT 85,0,1023
710 PLOT 85,1023,1023
720 VDU 23,1,0;0;0;0;
730 MOVE 1100,250
740 DRAW 1100,100
750 DRAW 1250,100
760 MOVE 1100,250:DRAW 1080,230
770 MOVE 1100,250:DRAW 1120,230
780 MOVE 1250,100:DRAW 1230,120
790 MOVE 1250,100:DRAW 1230,80
800 VDU 31,33,26,ASC"F"
810 VDU 31,36,29,ASC"A"
820 VDU 28,32,31,39,0,30
830 PRINT "CPU:"'CPU$
840 VDU 31,0,3
850 PRINT "DATE:"'DATE$'
860 PRINT "CLOCK:"'SPEED$'
870 PRINT "TESTING:";
880 IF INSTR=0 PRINT "POP AF"
890 IF INSTR=1 PRINT "POP AF"'"NOP"
900 IF INSTR=2 PRINT "POP AF"'"LD R,A"
910 IF INSTR=3 PRINT "POP AF"'"XOR &00"
920 IF CF=0 PRINT "CCF" ELSE PRINT "SCF"
930 PRINT "PUSH AF"'
940 PRINT "GRAPH:"'CHR$(ASC("X")+F);" FLAG"'
950 PRINT "X AXIS:"'"A:00-FF"'
960 PRINT "Y AXIS:"'"F:00-FF"'
970 CALL test
980 REM TAKE A SCREEN SHOT
990 *MOTOR 1
1000 T=TIME
1010 REPEAT UNTIL TIME>T+20
1020 *MOTOR 0
1030 TIME=T
1040 REPEAT UNTIL TIME>T+100
1050 NEXT
1060 NEXT
1070 NEXT