HALT: Why always 4ts?

edited March 2015 in Development
Instruction breakdown of halt is like that:

PC 4ts.

That means it fetches instruction byte from ram which tooks 4 ts and then does nothing and reads the ram again to do nothing again until a reset or interrupt.

if halt is already read by cpu, why it tries to read the ram again? if it's not reading the ram again and again to execute the HALT, why it still takes 4 ts to handle the interrupt?

I mean if cpu executed HALT at cycle 5, and if interrupt triggered at cycle 6, cpu will not jump to interrupt until cycle 9.

What's the technical detail behind this?
Post edited by Arda on

Comments

  • edited February 2015
    I believe the Z80 internally executes repeated NOP's until an interrupt is generated, which take 4T each.

    If this is the case, then the NOP instruction needs to complete before the interrupt is handled.

    B
    The Spectrum Resuscitation Thread - bringing dead Spectrums back to life
    zx-diagnostics - Fixing ZX Spectrums in the 21st Century (wiki)
    Sinclair FAQ Wiki
  • edited February 2015
    balford wrote: »
    I believe the Z80 internally executes repeated NOP's until an interrupt is generated, which take 4T each.

    If this is the case, then the NOP instruction needs to complete before the interrupt is handled.

    B

    Oh, right. Stupid question again, sorry. Flu got me. :)
  • edited February 2015
    balford wrote: »
    I believe the Z80 internally executes repeated NOP's until an interrupt is generated, which take 4T each.

    If this is the case, then the NOP instruction needs to complete before the interrupt is handled.

    I'd say internally if there's no interruption it executes something like "DEC PC", setting the program counter to its previous value so the same HALT instruction is read and executed again and again.
  • edited February 2015
    The Spectrum Resuscitation Thread - bringing dead Spectrums back to life
    zx-diagnostics - Fixing ZX Spectrums in the 21st Century (wiki)
    Sinclair FAQ Wiki
  • edited February 2015
    balford wrote: »
    I believe the Z80 internally executes repeated NOP's until an interrupt is generated, which take 4T each.
    Which brings up an interesting question. Or actually, 2 questions:
    • Does the Z80 continue to fetch instructions while in the HALT state? (that is: repeated memory reads). Or does it perform refresh cycles only, without actually reading the memory.
    • If so, what does the Z80 do with the opcodes read?
    In most cases this wouldn't matter, but not always. For example one could construct external hardware that changes the opcode read @ some point (I mean: reading the same memory location 1000 times need not necessarily return the same value every time). Which could make the Z80 snap out of the HALT state even though no interrupt occurred. That is, if the Z80 actually reads memory in the HALT state, and executes what is read.

    For questions like this, my preferred source is the Mostek MK3880 Technical Manual, which has this: (page 23)
    The purpose of executing NOP instructions while in the halt state is to keep the memory refresh signals active.
    Sounds logical. So R register keeps being updated, too. And thus when HALT is exit-ed, R value may say something about how long the Z80 was in the HALT state. Then:
    Each cycle in the halt state is a normal M1 (fetch) cycle
    Hmm yeah why not. Anything special / exceptional translates to: more logic = more transistors required in the CPU's design. Rather avoid that! :razz: So... the Z80 does do memory reads while HALTed. Followed by:
    except that the data received from the memory is ignored and a NOP instruction is forced internally to the CPU.
    So, the values read are discarded, and the Z80 executes NOPs internally.

    Knowing that, it's only logical then that intruction timings, interrupt sampling points, DRAM refresh etc is the same as for regular instructions. As far as possible, that is. Except of course the PC stays @ the same value for a while. Which makes me wonder about one tiny detail: the memory location fetched repeatedly, is that the "HALT" opcode's location (PC unchanged from when the HALT opcode was first fetched), or the next one (instruction after the HALT) ?

    Any questions? :smile: :grin:
  • edited February 2015
    Which brings up an interesting question. Or actually, 2 questions:
    • Does the Z80 continue to fetch instructions while in the HALT state? (that is: repeated memory reads). Or does it perform refresh cycles only, without actually reading the memory.
    • If so, what does the Z80 do with the opcodes read?
    ...

    Very interesting question and another question appears. One says that instruction like LDIR, LDDR, CPIR, CPDR, OTIR and OTDR doesn't update PC when it is repeating. Such instruction has 2-byte opcode (it's ED prefixed), so 2 memory reading must be done each time it is executed. In that case, I think, the memory is read and opcode isn't discarded but interpreted. Am I right?
    My blog (in Portuguese): Cantinho do TK90X.
  • edited February 2015
    Which brings up an interesting question. Or actually, 2 questions:
    • Does the Z80 continue to fetch instructions while in the HALT state? (that is: repeated memory reads). Or does it perform refresh cycles only, without actually reading the memory.
    • If so, what does the Z80 do with the opcodes read?

    After executing the HALT instruction the Z80 keeps doing an opcode fetch of the next instruction until there is a maskable interrupt (if enabled), a non-maskable interrupt or a reset. I don't know whether this next opcode is (a) latched inside the Z80 but ignored or (b) not latched at all. I suspect (a).
    In most cases this wouldn't matter, but not always. For example one could construct external hardware that changes the opcode read @ some point (I mean: reading the same memory location 1000 times need not necessarily return the same value every time). Which could make the Z80 snap out of the HALT state even though no interrupt occurred. That is, if the Z80 actually reads memory in the HALT state, and executes what is read.

    I thought of doing this but it is impossible. PC is incremented at the end of the HALT instruction then it stays at address HALT+1 until halt is exited.
    Which makes me wonder about one tiny detail: the memory location fetched repeatedly, is that the "HALT" opcode's location (PC unchanged from when the HALT opcode was first fetched), or the next one (instruction after the HALT)

    The latter as already mentioned. I know all about this because of the extensive tests a friend and I did on the Z80 Special Reset. For more details please see
    http://www.worldofspectrum.org/forums/showthread.php?p=811710#post811710
  • edited February 2015
    Which brings up an interesting question. Or actually, 2 questions:
    • Does the Z80 continue to fetch instructions while in the HALT state? (that is: repeated memory reads). Or does it perform refresh cycles only, without actually reading the memory.
    • If so, what does the Z80 do with the opcodes read?

    This article mentioned in this thread explains in detail that the CPU keeps fetching the instruction following the HALT, but discards it.

    EDIT: Erm, should have read rest of the thread before replying. :)
    TK90XFan wrote: »
    Very interesting question and another question appears. One says that instruction like LDIR, LDDR, CPIR, CPDR, OTIR and OTDR doesn't update PC when it is repeating. Such instruction has 2-byte opcode (it's ED prefixed), so 2 memory reading must be done each time it is executed. In that case, I think, the memory is read and opcode isn't discarded but interpreted. Am I right?

    Exactly. It was quite common trick used in many copy protections to execute an LDIR/LDDR which overwrites itself before completion and the CPU then continues executing the newly formed instruction.

    Patrik
  • edited February 2015
    Many thanks for doing, and publishing that research, Tony! :cool: Amazing that even 30+ years after the Z80 was introduced, some tidbits about how it works are surfacing. Or at least: finally being documented. :p
    TK90XFan wrote: »
    One says that instruction like LDIR, LDDR, CPIR, CPDR, OTIR and OTDR doesn't update PC when it is repeating. Such instruction has 2-byte opcode (it's ED prefixed), so 2 memory reading must be done each time it is executed. In that case, I think, the memory is read and opcode isn't discarded but interpreted. Am I right?
    Yes I'm pretty sure that's the case (and discussed on various forums many times before). The easiest way to think of those ...R(epeat) instructions is as a single instance of their non-repeating counterpart, but with an integrated JR -2 (= back to instruction start) when the end-condition isn't met. Effectively the same as N times the non-repeating instruction, but folded into 2 bytes.

    Meaning it does allow some programming tricks that wouldn't be possible if that block instruction were treated as an 'atomic' one (read: always executed whole). Or that eg. a 40KB block copy will happily allow an interrupt routine to cut in halfway, and then simply resume where it left off. Which is probably the desired behavior! Anyway it's easy to write some testcases for this, and I'm sure they'd confirm the above.

    Probably the reason for existence of those block instructions isn't speed, but code density / programmers' convenience.

    Makes you realize how 'dumb' a really Z80 is :lol: and how wasteful it uses memory bandwidth. But not surprising if you consider that @ the time of its design, transistors were expensive, and memory bandwidth (or power consumption!) weren't the limiting factors they are for today's CPUs...
  • zubzub
    edited March 2015
    Which makes me wonder about one tiny detail: the memory location fetched repeatedly, is that the "HALT" opcode's location (PC unchanged from when the HALT opcode was first fetched), or the next one (instruction after the HALT) ?

    I guess you missed [thread=47021]this thread[/thread], then...
    FUSE: the Free Unix Spectrum Emulator, also for Windows, OS X and more!
    http://fuse-emulator.sourceforge.net/
  • zubzub
    edited March 2015
    zub wrote: »
    I guess you missed [thread=47021]this thread[/thread], then...

    More helpfully, I should say that Spectaculator handles HALT correctly, and there is a HALTed flag in the SZX format. I?m not aware of any other snapshot format supporting this. I don?t know which emulators support SZX?s HALTed flag but Fuse isn?t one of them.
    FUSE: the Free Unix Spectrum Emulator, also for Windows, OS X and more!
    http://fuse-emulator.sourceforge.net/
  • zub said:

    More helpfully, I should say that Spectaculator handles HALT correctly, and there is a HALTed flag in the SZX format. I?m not aware of any other snapshot format supporting this. I don?t know which emulators support SZX?s HALTed flag but Fuse isn?t one of them.

    Correction: it turns out Spectaculator does not handle this correctly, and the wrong Program Counter (PC - 1, specifically) must be stored in SZX snapshots if the HALTed flag is set in the snapshot (and therefore, one must be added to this when loading into an emulator than models HALT correctly). Future versions of Fuse will get this right, but will still save incorrect values in snapshots for reasons of compatibility.
    FUSE: the Free Unix Spectrum Emulator, also for Windows, OS X and more!
    http://fuse-emulator.sourceforge.net/
Sign In or Register to comment.