News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

VSync help! (Sharp MZ-80A !)

Started by kelp7, 09:49, 06 February 14

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

kelp7

I'm not going to fill up your forum too much more with the non-CPC related stuff but just wanted to share one quick thing which I tried this morning. Have just tried the following code:



LD HL,&D000
LD DE,&D001
LD BC,&004F
LD (HL),01
LDIR
LOOP:
LD A,(&E002)
RLA
JR C,LOOP
LOOP2:
LD A,(&E002)
RLA
JR NC,LOOP2
LD A,(&E015)
LD A,(&E014)
JR LOOP



Basically this prints two lines of character 'A' to screen memory, waits for Vsync to happen, then waits for it to finish (so I know I'm on the top line of the display). Then I very quickly switch the inverse video mode on (by reading address &E015) and very soon after switch it back to standard video mode for the rest of the screen display. I wanted to see if I could turn one single scan-line into inverse video mode and then put the rest of the display back to standard video. This does sort of seem to happen. But what I witnessed was a very flickery line of 1-pixel height covering about 80 pixels length (10 letter 'A's). I don't know why it is flickering so much but am glad to see that the rest of the screen from vertical pixel line number 2 onwards are stable and in standard-video-mode. The only thing I can think of (regarding the flickering) is that the hardware simply doesn't like the display being changed more than once per scanline.


Anyway, thanks to everyone for all your help and discussions in this thread, this has put me on a good path to discovering new things with this machine!


Cheers
kelp

arnoldemu

Quote from: kelp7 on 11:27, 23 March 14
I'm not going to fill up your forum too much more with the non-CPC related stuff but just wanted to share one quick thing which I tried this morning. Have just tried the following code:



LD HL,&D000
LD DE,&D001
LD BC,&004F
LD (HL),01
LDIR
LOOP:
LD A,(&E002)
RLA
JR C,LOOP
LOOP2:
LD A,(&E002)
RLA
JR NC,LOOP2
LD A,(&E015)
LD A,(&E014)
JR LOOP



Basically this prints two lines of character 'A' to screen memory, waits for Vsync to happen, then waits for it to finish (so I know I'm on the top line of the display). Then I very quickly switch the inverse video mode on (by reading address &E015) and very soon after switch it back to standard video mode for the rest of the screen display. I wanted to see if I could turn one single scan-line into inverse video mode and then put the rest of the display back to standard video. This does sort of seem to happen. But what I witnessed was a very flickery line of 1-pixel height covering about 80 pixels length (10 letter 'A's). I don't know why it is flickering so much but am glad to see that the rest of the screen from vertical pixel line number 2 onwards are stable and in standard-video-mode. The only thing I can think of (regarding the flickering) is that the hardware simply doesn't like the display being changed more than once per scanline.


Anyway, thanks to everyone for all your help and discussions in this thread, this has put me on a good path to discovering new things with this machine!


Cheers
kelp
Interesting that the display starts after end of vsync. There is no border? On CPC there are a few lines of top border before the display starts. The flicker you see comes because of the vsync wait code. It takes a few cycles for each time you check. This means the vsync comes at any time between the rotate instruction the jump relative and the load instruction. This is why it flickers because the position changes each frame. On CPC we use halt instruction to wait for interrupt which comes at a fixed position in the display and then use a number of fixed length instructions to get to the point we want. See if you can do that with interrupts. The length is down to the time for the two load instructions. Put some nops in there to make it longer. So it seems you can turn it on off as much as you want on a line. Try repeating the load instructions to switch back and forth perhaps to make a pattern. We do this with out instructions on CPC to make split raster's etc.

Keep going your finding out what state the vsync is, how long its active for, its position relative to the display and inverse can be turned on and off as you wish.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

kelp7

Quote from: arnoldemu on 17:56, 23 March 14
Interesting that the display starts after end of vsync. There is no border? On CPC there are a few lines of top border before the display starts. The flicker you see comes because of the vsync wait code. It takes a few cycles for each time you check. This means the vsync comes at any time between the rotate instruction the jump relative and the load instruction. This is why it flickers because the position changes each frame. On CPC we use halt instruction to wait for interrupt which comes at a fixed position in the display and then use a number of fixed length instructions to get to the point we want. See if you can do that with interrupts. The length is down to the time for the two load instructions. Put some nops in there to make it longer. So it seems you can turn it on off as much as you want on a line. Try repeating the load instructions to switch back and forth perhaps to make a pattern. We do this with out instructions on CPC to make split raster's etc.

Keep going your finding out what state the vsync is, how long its active for, its position relative to the display and inverse can be turned on and off as you wish.


Thanks arnoldemu, your support has been impeccable and has got me on the right track. I actually got a bit further on this afternoon and modified the routine to only wait for vsync to begin (not to bother waiting for it to finish) to see what would happen and it seemed to make no difference. Just waiting for it to start was enough to do what I needed. Then I added in a typical small loop (LD B,&FF, NOP, DJNZ back to the NOP) and I have actually managed to see something that no-one has ever seen on this machine before now. I had one complete full set of letter 'A' in inverse video and the next line on the screen was normal standard-video-mode letter 'A'. Well, mostly. It stretched into the 2nd line of A's a bit as well obviously as I haven't got the timing right yet. But weirdly the flickery bit was still there. It's not just a random flicker either, it has a sort of pulsing pattern to it, seems to go through a cycle of different patterns of flickery lines (1 pixel height) every 0.5 seconds! Rather strange but I'm gonna push this NOP loop around a bit and see what I get.


Thanks for all your help and hope I'm not 'misusing' your forum too much!


kelp

kelp7

#53
Oh yeah, and you're correct : there are no borders at all on this machine!
kelp


[EDIT] : also i re-read your part about the reason behind the flicker and I think that would make sense. I guess because I'm trying to maintain a stable image I have to make sure the very same set of events happen once every 50th second. Because the timing is out a bit each time I get the same pattern but it flickers as it changes each frame. Hmm, could be interesting to sort out but maybe you're right and interrupts may be the way to go. Unfortunately the interrupts in the MZ are handled by an 8253 timer chip, never played with one of those before and it looks complex!


kelp7

#54
Interestingly, things get better if I only wait for VSync to begin and not have a bit of code in there to wait for it to finish as well. Guess it's all down to timing, I've managed to get many splits horizontally at different parts of the screen just by having the right length of delay loop. Here is my first example of code (not yet commented / annotated) on my new site where I'm going to build up a nice library of routines:


Sharp MZ-80A Secrets


hoping to put graphics routines and sound / music routines up there and it should turn into a reasonable resource for this machine.


Also, I managed to splice a display character with another earlier on, so am starting to really see things that no-one's seen on the Sharp before (as far as I understand). I managed to show the top half of the letter 'A' with the bottom half of the letter 'B' underneath it. All stable too without any flickering...

steve

Congratulations on your success and your new site, I notice you did not mention any help from sharp forums so I went looking for them and found this http://sharpusersclub.org/modules.php?op=modload&name=XForum&file=index

And here someone has announced the uploading of his MZ 80k software library, maybe it would help you further http://www.vintage-computer.com/vcforum/showthread.php?35135-My-entire-Sharp-MZ-80K-software-library-now-online

kelp7

#56
Thanks Steve. Yes, I was a member of the Sharp Users Club for a few years in recent times but time (plus house buying, plus birth of son) meant I couldn't keep up with it any longer. I have been on their website forum for a long time too and it was always slow moving but nowadays there's very little activity whatsoever, hence my wandering around other 8-bit forums which are far more active :-)


[EDIT] : Just trying out different layouts for the website at the moment, have annotated the first listing. Trying to make it look good (!) but am hand coding html in Notepad, heh...

arnoldemu

Good to read how your investigations are going! good to hear you have also found a way to split characters!



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

kelp7

#58
Hey arnoldemu, I've just uploaded another routine to my site. In this routine I am using "RES 0,(HL)" and "SET 0,(HL)". Reading up on these commands suggests that actually, despite being quite dedicated commands, they use up quite a few clock cycles or T-States. Would it just be quicker for me to "LD A,0" and "LD ($E002),A" ? Or is there a neat way of switching a single bit in a byte on or off which I'm missing that might be quicker?
Thanks
kelp


[EDIT] : Also, is it better just to use "LD A,(&E002)" anyway rather than storing &E002 in HL and then using "LD A,(HL)" ?

arnoldemu

Quote from: kelp7 on 09:29, 26 March 14
Hey arnoldemu, I've just uploaded another routine to my site. In this routine I am using "RES 0,(HL)" and "SET 0,(HL)". Reading up on these commands suggests that actually, despite being quite dedicated commands, they use up quite a few clock cycles or T-States. Would it just be quicker for me to "LD A,0" and "LD ($E002),A" ? Or is there a neat way of switching a single bit in a byte on or off which I'm missing that might be quicker?
Thanks
kelp


[EDIT] : Also, is it better just to use "LD A,(&E002)" anyway rather than storing &E002 in HL and then using "LD A,(HL)" ?
I think it would be better to use res/set to switch single bits.
Otherwise you need to read, set it and then write it back which would be slower.

I will compare it to cpc.

LD A,(&e002) uses 4 cycles.
res/set use 2 cycles.

So res/set would be faster *if* you have setup hl before and you're doing lots of these.

I would be interested to know how the instruction timings work on the mz80a.

There is one way to find this out:



inverse on
instruction to test
inverse off

then look at the size of the bar on the screen

repeat this for all other commands.

You should be able to see a rough correlation and in particular you should be able to see if they are all forced to be multiples of NOPs like on CPC.

This will also help you if you wanted for example to make changes 1 line at a time. On CPC we know it's 64 NOPs per line and each instruction is a multiple of a NOP. That means we can count instruction timings and know exactly how much time it takes.

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

redbox

Quote from: arnoldemu on 10:11, 26 March 14
I would be interested to know how the instruction timings work on the mz80a.

I'd be interested in this too.

Nice to see a Z80 computer being investigated - I'd not known anything about the MZ-80A before but it's good to see some new knowledge emerging from this thread.

kelp7

#61
Quote from: arnoldemu on 10:11, 26 March 14
This will also help you if you wanted for example to make changes 1 line at a time. On CPC we know it's 64 NOPs per line and each instruction is a multiple of a NOP. That means we can count instruction timings and know exactly how much time it takes.


Wow, okay, this is a nice big project for me. I will definitely be doing this! I guess I need to expand out my website a little bit and perhaps have categories (as you do on your own site), would you mind if I based the design of my site a little bit on yours? I'll probably keep the tables and screenshots but having a front page on the site with perhaps Sources, Timings and Other stuff (probably games when I get time to do some!).


One thing I've found is that the screen doesn't seem to like multiple changes on a single scanline (you get a lot of the flickering I was mentioning before) but this might just be down to wrong number of NOPs or whatever. I guess if I'm trying timings of single instructions this could be difficult to see 'visibly' as a line on the screen.... I'll let you know how I get on though!


[EDIT] : oh and I've just uploaded my code for character split

kelp7

Quote from: redbox on 10:52, 26 March 14
I'd be interested in this too.

Nice to see a Z80 computer being investigated - I'd not known anything about the MZ-80A before but it's good to see some new knowledge emerging from this thread.


Thanks! Yeah, I've been interested in taking my m/l coding further for years now with this machine but could never quite find the time. I think it could turn out to be perhaps a little under-rated and hopefully I can make some games for it too which show what the machine *could* have had in its heyday.


What I'd really like is a really great emulator for the machine but I almost certainly don't have the coding prowess to produce one. The best I've found is Michael Franzen's multi-emulator but I'm still not convinced it emulates all the hardware (particularly as it is made to emulate various machines, not just Sharp).


Thanks
kelp

kelp7

Struggling a bit with this at the moment. This machine can be a pain to code for with respect to the display. I really really wish it had some interrupts that were tied to the display as you mention the CPC does. I tried the instruction timing as you suggested but see absolutely nothing on the screen. So I tried experimenting a bit and wrote a routine that turned inverse on, then wrote 100H bytes to memory via a pre-setup LDIR (keep setting hl, bc and de in the loop) and then turn inverse off again. See a bar this time on the screen but it flickers. Changed the BC part of the LDIR up and down and get remarkably different results. I think if you don't have exactly the right amount of delay then the machine really doesn't like it.


But that's not the worst part, I think you probably only have enough time at 2mhz to change every alternate line. I suppose that's not such a big set back, I'm pleased just to be able to change anything on this machine's display really.


Anyway, I replaced the loop which sits in-between the inverse on / inverse off with several NOPs (typed in manually to the assembler). Can see a part of a line being turned on but it's very flickery. Ended up typing in 64 NOPs to compare with CPC and get one complete scanline in inverse and a large portion of the 2nd line (which flickers, the 1st line doesn't flicker however). Guess we're talking less than 64 NOPs on this machine for a scanline. It has some very strange properties though because, for instance, if I changed it to 63 NOPs I might not see any line at all! Certain values seem to draw nothing (perhaps it's somehow flickering or drawing in a way that sits the wrong side of the beam perhaps) and then perhaps 62 NOPs will bring most of the line back onto the screen again.


Hope what i've just written makes sense!


I wonder if I should start utilising the 8253 for its counter interrupts? Would that help me in any of these graphics tasks?


kelp

TFM

Take a look at the CTC-AY, this will give you all the interrupts you need.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

kelp7

Would love to but not programming an Amstrad at the mo :(
Looks nice though :)

TFM

Yes. It's an amazing device. Guess soon we'll have games using it. And the pricing is more than fair.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

arnoldemu

#67
Yes try using the 8253.

Normally you would setup the appropiate counter with a value.
Set it to repeat mode. (not "one-shot").
Then enable the interrupt so it triggers the z80.

Now setup an interrupt. You may need to use interrupt mode 2 of z80, don't know.

Setup a int routine to do something so you know it's working.

change inverse on/off or something like that.

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

Axelay

Quote from: kelp7 on 21:02, 31 March 14
Struggling a bit with this at the moment. This machine can be a pain to code for with respect to the display. I really really wish it had some interrupts that were tied to the display as you mention the CPC does. I tried the instruction timing as you suggested but see absolutely nothing on the screen. So I tried experimenting a bit and wrote a routine that turned inverse on, then wrote 100H bytes to memory via a pre-setup LDIR (keep setting hl, bc and de in the loop) and then turn inverse off again. See a bar this time on the screen but it flickers. Changed the BC part of the LDIR up and down and get remarkably different results. I think if you don't have exactly the right amount of delay then the machine really doesn't like it.
So are you saying that you start with a delay, try to turn inverse on in the middle of the screen, wait a bit, then turn it off a few scan lines later, and you get quite different results with minor adjustments to that initial delay, rather than say, the start and end of the inversion, flickery though it may be, moving a little later or earlier along the lines they are on?  Where inverse is flickering, is it the whole scan line or part of it - are parts of the line constantly inverse, or not inverse with a flickery section in between?


I'm just wondering if perhaps inverse can only be set once per line, then I'd suppose it should be the whole line flickering, but if parts of a flickery line are stable as inverse or not, then it's sounding a bit weird if small changes to the initial delay produce quite different results.


Something else I'm wondering about your test code, since I've not used memory mapped IO before, but how does LD A,(&E015) *set* inverse on, rather than simply read the state of the mapped IO?

kelp7

Quote from: Axelay on 10:49, 01 April 14
So are you saying that you start with a delay, try to turn inverse on in the middle of the screen, wait a bit, then turn it off a few scan lines later, and you get quite different results with minor adjustments to that initial delay, rather than say, the start and end of the inversion, flickery though it may be, moving a little later or earlier along the lines they are on?  Where inverse is flickering, is it the whole scan line or part of it - are parts of the line constantly inverse, or not inverse with a flickery section in between?


In this particular case I turned inverse on first thing after waiting for vsync. So the inverse is happening at the top line of the screen. Then do a different sort of delay (using LDIR this time (instead of a decrement-counter loop) to write &100 bytes to memory somewhere) then turn inverse off. I do get some very strange effects. You're right that part of the line can be stable and then the end of the line (or the middle, depending on the delay) can be flickering.

Quote from: Axelay on 10:49, 01 April 14
I'm just wondering if perhaps inverse can only be set once per line, then I'd suppose it should be the whole line flickering, but if parts of a flickery line are stable as inverse or not, then it's sounding a bit weird if small changes to the initial delay produce quite different results.


Yep, this is the bit I don't fully understand. When I substituted my LDIR delay with just a bunch of NOPs manually typed in (rather than a loop burning NOPs because I wanted more accuracy in what I was seeing), I would get quite wildly varying results. Maybe I should just do all this again and take proper notes this time as to what happens! Apologies for my vagueness so far!

Quote from: Axelay on 10:49, 01 April 14
Something else I'm wondering about your test code, since I've not used memory mapped IO before, but how does LD A,(&E015) *set* inverse on, rather than simply read the state of the mapped IO?


Yeah, this is probably a little beyond me now too but essentially you can only read from that memory mapped I/O address, it's not a writeable address. When you read from that address the machine switches on inverse. When you read from the other address (&E014) it switches inverse off. I have a more detailed book at home which I could refer to which may explain this better. I'll post a bit of documentation up later on tonight....

kelp7

and thanks arnoldemu, I think i'll have to dig further into 8253 and how interrupts work on this machine.
kelp

kelp7

I realise I already posted the bit from the book I was talking about above earlier in this whole thread, here again is what it says (not much to go on as to why it's about reading those addresses rather than writing to them):


Quote from: kelp7 on 10:44, 06 March 14
Lastly, to quote from a really good book I have on the machine:


INVERSE VIDEO FACILITY (MZ80A)


The serial video train in the MZ80A is presented to the screen in exactly the same way as in the MZ80K except that the serial video train is gated with a signal (1 or 0) from a 7474 toggle. The toggle uses CS E014 and A0 to switch its output from zero to one and from one to zero. This inverts the video train and so gives the facility to have the screen display as


1. Light characters on a dark background
2. Dark characters on a light background


(Light on dark being standard)


Reading address E014H gives standard video e.g. A=PEEK($E014)
Reading address E015H gives inverse video. e.g A=PEEK($E015)


(the $E014 & $E015 are memory mapped I/O address - kelp7)

arnoldemu

Quote from: Axelay on 10:49, 01 April 14

Something else I'm wondering about your test code, since I've not used memory mapped IO before, but how does LD A,(&E015) *set* inverse on, rather than simply read the state of the mapped IO?
it all depends on how the hardware decodes the signals on the z80 bus.

For an I/O instruction there will be an address in a15-a0, the data in d7-d0, iorq then rd for read or wr for write.
For a memory mapped instruction there will be address in a15-a0, data in d7-d0, then just rd/wr.

So, it's just different way to interpret the signal.

In addition since this operation is always "yes", you don't need to do a write. You just need to recognise a15-a0 and rd, or perhaps just a15-a0, so a read/write perform the same job.

Reading back the data from a device also depends on 1) if it stores the data 2) it decodes a read and puts the data onto the bus.

So reading to do a write may seem crazy but it's just a mapping of signals.

In fact, it may be possible to also do this:

LD BC,&E014
IN A,(C)

LD BC,&E015
IN A,(C)

@kelp7: Please try this it may do the same.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

kelp7

I already tried the IN instruction before now and didn't get a result. I'll try again to be sure I was doing it correctly but pretty certain the IN had no effect at all.

kelp7

Quote from: arnoldemu on 09:26, 02 April 14
In fact, it may be possible to also do this:

LD BC,&E014
IN A,(C)

LD BC,&E015
IN A,(C)

@kelp7: Please try this it may do the same.


Just to confirm, this definitely does not work. So I guess this is down to how the machine is hardwired.

Powered by SMFPacks Menu Editor Mod