ZX80 scanline timing

Discussion of development of software for any "obsolete" computer or video game system.
Post Reply
lidnariq
Posts: 9383
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

ZX80 scanline timing

Post by lidnariq » Fri Nov 22, 2019 12:50 am

So, I mostly understand how the ZX80 draws video: It tries to load a byte from the "display file", and any time that the byte both has D6 clear and comes from a place where A15 is high, it's loaded by the display hardware and then the data bus is replaced with a NOP before the Z80 loads the instruction. Four CPU cycles later, the NOP finishes, the CPU tries to load the next instruction, and so on, until it reaches a HLT (where D6 is high) and that pauses the CPU until the next scanline...

Internally, the HLT instruction looks like an endless series of NOP instructions, and the Z80's DRAM refresh circuitry keeps on counting during this time. The CPU's A6 line is connected to its own /IRQ pin, so when the DRAM refresh counter "R" overflows from 127 to 0, that triggers an IRQ, which in turn starts drawing for the next scanline.

But what I don't understand is the context in which the IRQ handler at 0x38 occurs. What sets up all the registers for the handler there?

Would it be practical to replace the 6.5MHz resonator with e.g. an 8MHz one? Obviously this'd require firmware changes to still emit 16kHz video. (Instead of 207±1 T states, it'd require 255±1 T states). Is there enough leeway in R to manage that? Are there other problems? Would the ZX81's NMI generator help make enough more things compatible with it, or would it still only be good enough for BASIC?

nocash
Posts: 1210
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: ZX80 scanline timing

Post by nocash » Fri Nov 22, 2019 4:36 am

What is the goal there? It would squeeze the picture horizontally, and, even with patched BIOS, existing software wouldn't really benefit from it. The CPU is somewhat halt'ed during drawing+hblank+upper/lower borders, it can execute code only during vsync (ie. something like 2-5 scanlines). If the software isn't aware of the faster oscillator then it would merely finish vblank a bit faster; not knowing that it could squeeze a few more opcodes into vblank.

The one thing that would benefit out-of-the-box would be the classic ZX80 approach: Disable the screen, do your calculations for computing the optimal travel route to Uranus (or whatever you were interested in), wait some minutes until the calculation is done, and then switch the screen back on, and display the result : )

Anyways, the drawing entrypoint is at 01ADh, below is the drawing code from zx80 space invaders - that it is calling the drawing function at 01ADh twice (once for upper border and screen, and then once again for lower border).

Code: Select all

bios_draw equ 01adh
@@mainloop:
 ld   (iy-mem+nonsense),30h
 pop  hl                ;\get task count (lower 2 bits)
 inc  l    ;task        ; (located at/above stack_top!)
 push hl                ;/
 in   a,(0feh)          ;-start v-retrace, set linectr=0
 ld   a,l  ;task        ;\
 and  03h               ;
 call z,move_enemy_row  ;
 cp   01h               ; execute current task
 call z,move_bullets    ;
 cp   02h               ;
 call z,player_controls ;
 cp   03h               ;
 call z,enemy_attack    ;/
 out  (0ffh),a          ;-terminate v-retrace (any out) (FFh=NMI compatible)
 ld   a,-19             ;\
 ld   b,24+1            ; draw upper border and screen
 ld   hl,vram-1+8000h   ;
 call bios_draw         ;/
 ld   a,-16             ;\
 inc  b   ;=1           ;
 dec  hl  ;=vram+2FFh   ; draw lower border
 dec  (iy-mem+nonsense) ;
 call bios_draw         ;/
 jr   @@mainloop
Changing the reload value for R (ie. the LD A,0ddh opcode at 01B2h) would be no problem. But for changing the initial value (that gets's passed to the LD R,A opcode at 01B0h), you would need to insert a SUB A,nn opcode somewhere... that might work if you use a 8Kbyte ROM (or find some discard-able bytes in the 4Kbyte one).
The hardware increments only lower 7bit of R register, so you have a 6bit counter range when waiting for bit6=0 (or 7bit range might work when replacing it by an external comparator for checking bit0-6 = all zero).
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

lidnariq
Posts: 9383
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: ZX80 scanline timing

Post by lidnariq » Fri Nov 22, 2019 11:24 am

nocash wrote:
Fri Nov 22, 2019 4:36 am
What is the goal there?
Curiosity, really. Getting more familiar with Z80 asm. And establishing whether it'd be interesting to provide it as a switchable option in a recreation of one.
Changing the reload value for R (ie. the LD A,0ddh opcode at 01B2h) would be no problem. But for changing the initial value (that gets passed to the LD R,A opcode at 01B0h), you would need to insert a SUB A,nn opcode somewhere...
As far as I can tell, the initial value for A there is set at 0198h - why couldn't it be patched there instead of modifying the value subsequently?
The hardware increments only lower 7bit of R register, so you have a 6bit counter range when waiting for bit6=0 (or 7bit range might work when replacing it by an external comparator for checking bit0-6 = all zero).
I guess since the refresh address is on the address bus for the entirety of T3 and T4, and /IRQ is tested at the end of each instruction, there's no need to assert /IRQ for more than one count of R.

But given that 0DDh=-35 is sufficient for 207 T states, it looks like no extra hardware conditions would be necessary for the extended timing to extend it to 255 T states...

nocash
Posts: 1210
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: ZX80 scanline timing

Post by nocash » Sat Nov 23, 2019 6:50 am

lidnariq wrote:
Fri Nov 22, 2019 11:24 am
As far as I can tell, the initial value for A there is set at 0198h - why couldn't it be patched there instead of modifying the value subsequently?
Yes, for the INPUT prompt it's at 0198h and also 01A4h (for the 2nd call to 01ADh). But patching that locations won't help for the programs with animated video (like the above space invaders code) which are calling 01ADh directly. Or maybe some do even do the EI + JP HL directly without using the code at 01ADh, then patching the incoming values would be yet more problematic.

The lower 6bit range in R should be enough for slight overclocking, but I really don't know what an overclocked ZX80 would be good for... unless you have a specific project in mind where you need higher dotclock or more vsync time.

Writing code for execution during vsync can be about as challenging as Atari 2600 code, ie. to get constant vsync time and stable picture for conditional code, you would need to add delays when condition=false. If you aren't particulary interested in that challenge then you might be better off with adding a NMI generator and ZX81 bios rom. That way you get more cpu time (during upper/lower border, ie. during vblank instead of only vsync), and the picture will be stable without needing to compensate conditional code by delays.
homepage - patreon - you can think of a bit as a bottle that is either half full or half empty

Post Reply