News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Executioner

Z80 Documentation Errors

Started by Executioner, 06:34, 04 October 12

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Executioner

There's a lot of information available about the Z80. Unfortunately, a lot of it has conflicting information, for example:

Sean Young's The Undocumented Z80 Documented contains the following:

QuoteThe INI/INIR/IND/INDR instructions use BC after decrementing B, and the OUTI/OTIR/OUTD/OTDR
instructions before.

Can someone please confirm this is NOT the case, it's the other way around.

Another error is in http://www.z80.info/z80ins.txt where it states:

QuoteMODE 0        -    INTA(6)        ODL(3)        ODH(4)        SWH(3)        SWL(3)        6
                  (CALL INSERTED)            SP-1 --->    SP-1 --->

            -    INTA(6)        SWH(3)        SWL(3)                        4
                  (RST INSERTED)
                    SP-1 --->    SP-1 --->

    MODE 1            INTA(7)        SWH(3)        SWL(3)                        4
                (RST 38H
                INTERNAL)
                    SP-1 --->    SP-1 --->

    MODE 2        -    INTA(7)        SWH(3)        SWL(3)         MRL(3)        MRH(3)        6
                (VECTOR
                SUPPLIED)
                    SP-1 --->    SP-1 --->

This shows the timing for interrupt mode 0 as being different from the other types (ie. INTA(6) instead of INTA(7)) which also appears to be incorrect from my testing. The first cycle is always 2 + normal instruction timing (ie. 7 for RST, but 6 for call).

I'm trying to do a completely new Z80 core based on T-State timing and then apply the internal gate-array logic used for the WAIT signal in order to improve the Z80 core in JEMU, and it's all a bit hard with incorrect and conflicting information. I think I have it working correctly and PlusTest shows all timings as correct for the CPC. I've also gone through all instructions on the VZ-200 to test their timing and they are correct, but I'd hate to get a fundamental thing like interrupt timing wrong.



gerald

#1
Regarding the IO instructions, BC is decremented after the in/out (attached extract from Z80 microprocessor family databook 1st edition)
I can at least confirm this for INI

EDIT : looks like this doc is wrong regarding OUTI/OUTD.

arnoldemu

Quote from: gerald on 09:35, 04 October 12
Regarding the IO instructions, BC is decremented after the in/out (attached extract from Z80 microprocessor family databook 1st edition)
I can at least confirm this for INI
um0080.pdf from zilog's website states for outi:

"The contents of the HL register pair are placed on the address bus to select a
location in memory. The byte contained in this memory location is
temporarily stored in the CPU. Then, after the byte counter (B) is
decremented, the contents of register C are placed on the bottom half (A0
through A7) of the address bus to select the I/O device at one of 256
possible ports. Register B may be used as a byte counter, and its
decremented value is placed on the top half (A8 through A15) of the
address bus. The byte to be output is placed on the data bus and written to a
selected peripheral device. Finally, the register pair HL is incremented."

B is decremented *before* ;)

INI:

"The contents of register C are placed on the bottom half (A0 through A7) of
the address bus to select the I/O device at one of 256 possible ports.
Register B may be used as a byte counter, and its contents are placed on the
top half (A8 through A15) of the address bus at this time. Then one byte
from the selected port is placed on the data bus and written to the CPU. The
contents of the HL register pair are then placed on the address bus and the
input byte is written to the corresponding location of memory. Finally, the
byte counter is decremented and register pair HL is incremented."

So even Zilog can't agree with itself in it's doc but it seems to say B decremented before with OUTI and B decremented after with INI.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

but then is documentation.. what really happens? ;)
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

gerald

Some test on real HW, checked with logic analyser :


  INST                   IO   MEM
                        ADDR  ADDR

  ld BC, &FF0F
  ld HL, &4000
  INI                   FF0F 4000
  INI                   FE0F 4001
  INI                   FD0F 4002
  INI                   FC0F 4003

  ld BC, &FF1F
  ld HL, &4000
  OUTI                  FE1F 4000
  OUTI                  FD1F 4001
  OUTI                  FC1F 4002
  OUTI                  FB1F 4003

  ld BC, &FF2F
  ld HL, &4000
  IND                   FF2F 4000
  IND                   FE2F 3FFF
  IND                   FD2F 3FFE
  IND                   FC2F 3FFD

  ld BC, &FF3F
  ld HL, &4000
  OUTD                  FE1F 4000   
  OUTD                  FD1F 3FFF
  OUTD                  FC1F 3FFE
  OUTD                  FB1F 3FFD


OUTI/OUTD decrement B, then does the IO access
INI/IND  does the IO access, then decrement B

I did not test the R versions as these does not look friendly to the CPC, but B behaviour should be identical.

rpalmer

There is no error in regards to the doco for INI/OUTI and the INIR/OUTIR.

Both use the B register and the HL register.

At the end of the INI/OUTI instruction execution, the B register is decremented and HL incremented. The INIR/OUTIR simply repeat until B = 0.

As for access I/O devices, the system design of the hardware has to become aware of what I/O allocations are taken/free.  The CPC itself has
allocated the upper I/O BUS for devices (VGA, CRT, ROM select, etc) so using B as a counter for multi-I/O requests is more or less pointless. However,
bits 8 to 10 are usable, so a small series of I/O can be used.

rpalmer

cngsoft

Arnoldemu and Gerald are right, INI/IND/INIR/INDR decrease B after storing the byte from the hardware port into memory, and reversely, OUTI/OUTD/OTIR/OTDR decrease B before sending the memory byte to the hardware port. This is why Executioner's optimized keyboard reading routine is based on LD B,$F4: IND rather than LD B,$F5: IND; similarly, demos like "Camembert 3 Meeting" tweak the CRTC with LD B,$BC... OUT (C),x: INC B: INC B: OUTI: DEC B: OUT (C),y rather than LD B,$BC... OUT (C),x: INC B: OUTI: OUT (C),y.
(if you can't see the banner right now my server is currently offline)

Executioner

So it looks as though Sean Young got it the wrong way around... He does have an excuse since he never had a CPC to test it on so couldn't tell what was on the top half of the address bus. I knew it was an error, but just wanted to confirm. Yes, I has written a keyboard scan routine in the past using IND  ::) but had forgotten about it. And I've seen many a demo using OUTI/OUTD with B set +1.

As for the other question... I'm assuming there's a typo in z80ins.txt since the RST instruction uses one more T-State in the first M cycle than CALL. The INTA(6) is correct for CALL, but should be INTA(7) for the RST version.

With the /WAIT signal held low for all but one of the 4 T-States my new Z80 core appears to work perfectly with Plustest for both the instruction timing and interrupt delay tests.

Powered by SMFPacks Menu Editor Mod