MDV Low Level Routines

Anything QL Software or Programming Related.
Post Reply
User avatar
tofro
Font of All Knowledge
Posts: 2701
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: MDV Low Level Routines

Post by tofro »

Martin_Head wrote: Some of these may get lost to things like screen display generation and RAM refresh cycles. But I have no idea how many.
RAM refresh shouldn't really matter. Screen/ULA contention does, however. And it's about 50% in contended memory, if I remember right. On 0 wait-state RAM extensions or from ROM, it's full speed.


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
tcat
Super Gold Card
Posts: 633
Joined: Fri Jan 18, 2013 5:27 pm
Location: Prague, Czech Republic

Re: MDV Low Level Routines

Post by tcat »

Hi,
3600uS/0.13uS = 27692 cycles. So you have about 27500 clock cycles to play with. Some of these may get lost to things like screen display generation and RAM refresh cycles. But I have no idea how many.
Aha, in slower contended memory I have only half the cycles, 27500/2 = 13750, this would be the situation on standard 128K QL, or if it runs in that memory area.

Tomas


User avatar
janbredenbeek
Super Gold Card
Posts: 632
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: MDV Low Level Routines

Post by janbredenbeek »

Martin_Head wrote: I'm not sure if a 'lea blkBuff,a0' would be quicker than a 'movea.l'
These instructions do different things. LEA means 'load effective address' and only accepts an address as parameter. In the above example, LEA will load A0 with the address of blkBuff. But 'movea.l blkBuff,a0' loads the contents of the location pointed to by blkBuff into A0! I'm not sure whether this was intended by Tomas, but if blkBuff is really the start address of the buffer (and not a pointer holding the start address) he should have used 'movea.l #blkBuff,a0' (note the hash).
This of course assumes that blkBuff is an absolute address. On the QL, user code should generally be position independent (only the system ROM is guaranteed to have a fixed address!) so you SHOULD use LEA buffer(PC),A0 to get the correct address (the GST assembler will by default generate position-indepentent code so the (PC) is not necessary here). As you cannot use relative addresses as immediate data to a movea, lea is the only option here...

cheers, Jan.


User avatar
janbredenbeek
Super Gold Card
Posts: 632
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: MDV Low Level Routines

Post by janbredenbeek »

Silvester wrote:Interesting thread, folks :-)

I also did a complete commented disassembly of the JS MDV routines if it's of any interest: http://www.dilwyn.me.uk/docs/disassem/jsromasm.zip

It was quite a while ago now, I think most of my brain cells that held that info have since disintegrated (like the sponge in a old MDV cartridge).
I'm quite surprised how much I still know about the QL code and 68K assembly even after 30 years! But thanks anyway, I have several disassemblies now but didn't know about yours. It looks fairly good commented, even better than the JS disassemblies I've seen so far...
The one thing I do recall though was being convinced that the calls to FS.FLUSH and FS.CHECK are reversed. They perform the oppposite function. ie. to flush MDV files - call check, and vice-versa !

Have I lost my mind, can anyone confirm?
Hmm... reading from my own comments on the MDV driver, FS.CHECK tests bit 0-1 of the slave block flags, giving 'not complete' if any is zero (which means 'block not available' or 'block has no data') and FS.FLUSH tests if bit 2 or 3 is set (meaning 'pending write or read operation'). It looks like FS.CHECK waits for read operations while FS.FLUSH also waits for write and verify operations. So it appears to me okay... But remember that TK2 replaces the MDV driver with its own code.
One thing that's different in JM and JS is the physical MDV I/O code. In JM, you'll find at some point a loop like BTST D6,(A3); DBNE D0,loop which waits for a 'ready to read' signal. In JS, there is a BTST D6,(A3); BNE.S repeated 19 times! I'm still wondering why the shorter DBNE was replaced with this repeated instructions three(!) times. Perhaps because of timing issues?

cheers, Jan.


tcat
Super Gold Card
Posts: 633
Joined: Fri Jan 18, 2013 5:27 pm
Location: Prague, Czech Republic

Re: MDV Low Level Routines

Post by tcat »

Martin_Head wrote: I'm not sure if a 'lea blkBuff,a0' would be quicker than a 'movea.l'
janbredenbeek wrote: These instructions do different things. LEA means 'load effective address' and only accepts an address as parameter. In the above example, LEA will load A0 with the address of blkBuff.
cheers, Jan.
Hi,

I initially thought it nice to code two moves into a single lea

Code: Select all

lea.l       blkBuff(pc,d7.w),a1   ;A1 = blkBuff+d7*4
But that would not work as blkBuff contains Pointer to Block Address, perhaps I should rename the label to blkPtr?

Tomas


Silvester
Gold Card
Posts: 436
Joined: Thu Dec 12, 2013 10:14 am
Location: UK

Re: MDV Low Level Routines

Post by Silvester »

It looks fairly good commented, even better than the JS disassemblies I've seen so far...
Thanks, in idle times I'd like to add to it. I did it because I wanted a version to assemble and hack. I've now had a look at your version - better comments, mine are a bit terse.

Regarding my last post, I've added an edit (a Doh! moment). It was done 20 years ago - I now have better info to hand.


David
User avatar
janbredenbeek
Super Gold Card
Posts: 632
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: MDV Low Level Routines

Post by janbredenbeek »

tcat wrote: Hi,

I initially thought it nice to code two moves into a single lea

Code: Select all

lea.l       blkBuff(pc,d7.w),a1   ;A1 = blkBuff+d7*4
This is pc-relative with index and will treat blkBuff as an 8-bit offset from the next instruction and add the value of D7 (sign-extended) to it to get the value for A1. It is often used in tables with fixed values in the code section.
But that would not work as blkBuff contains Pointer to Block Address, perhaps I should rename the label to blkPtr?
If blkBuff is a pointer, you should do

Code: Select all

movea.l BlkBuff,a1 ; load start address of buffer into a1
adda.w d7,a1 ; index to buffer
...but I'm curious where the actual blkBuff pointer in memory is. Somewhere in the code? That's self-modifying code and considered dirty programming :o . EXECable programs have a code- and data space and should really only write to data space. When you load it using EXEC the data space immediately follows the code but you shouldn't rely on that as it will be different when you load it using HOT_RES (in the ALCHP/RESPR area) and start it with a hotkey! You should use the registers A4 to A6 which will be set up as your job starts. A6 points to the start of the job area (not necessarily the code!), A6+A4 the start of the data area (I used ADDA.L A4,A6 so I could address my data area using A6, much like S*Basic) and A6+A5 the end of the data area. This way, I can put my programs anywhere in memory (even ROM) and start multiple instances without confusion.
Of course, if your code is going to be resident it's a different story and you have to find a way to store your data elsewhere, which is not always easy (sv locations which seem to be unused might be used by other software sooner or later)...

Jan.


User avatar
janbredenbeek
Super Gold Card
Posts: 632
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: MDV Low Level Routines

Post by janbredenbeek »

Silvester wrote: Thanks, in idle times I'd like to add to it. I did it because I wanted a version to assemble and hack. I've now had a look at your version - better comments, mine are a bit terse.

Regarding my last post, I've added an edit (a Doh! moment). It was done 20 years ago - I now have better info to hand.
Well I wrote my disassembly back in 1987/88 when I had lots of spare time. I must also say that Ian Logan's Spectrum ROM disassembly was a big inspiration in terms of style :) . I've only made it to one third of the ROM so there's still a lot of work to do, it will probably be a pensioner's project or so :D

cheers, Jan.


Silvester
Gold Card
Posts: 436
Joined: Thu Dec 12, 2013 10:14 am
Location: UK

Re: MDV Low Level Routines

Post by Silvester »

janbredenbeek wrote:
I'm still wondering why the shorter DBNE was replaced with this repeated instructions three(!) times. Perhaps because of timing issues?
It reduced latency (making JS 33% quicker to react to read buffer ready signal). To do loop DBNE=18, to pass through to subsequent read BNE.S=12.
janbredenbeek wrote:
But remember that TK2 replaces the MDV driver with its own code.
Yes, I did a listing for TK223. It intercepts microdrive FLUSH on first IO call (d3=0) with a preamble to ensure complete flush is done when the JS routine is subsequently called.


David
Post Reply