22 July 2022, 21:38 | #1 |
Registered User
Join Date: Feb 2019
Location: Munich, Germany
Posts: 63
|
DDFSTRT/DDFSTOP for Hires reverse calculation.
I'm trying to extract display/bitmap width information from the copperlist, and while my code works fine for lo-res, it doesn't handle hi-res.
const fetchWidth = hires ? ((((DDFSTOP - DDFSTRT) >>> 2) + 2) << 4) : ((((DDFSTOP - DDFSTRT) >>> 3) + 1) << 4); Let me give you a simple example. Workbench 1.3: DDF: 3c d0 DIW: 0581 40c1 (modulo 0) gives fetchWidth: 624 displayWidth: 640 which is clearly incorrect. However: HRM says, standard hires DDF is 3C D4, which would give 640 pixels width. What am I missing here? I have 2 more examples which also don't work: Workbench 2.0: DDF: 38 d8 DIW: 2c81 2cc1 (modulo 76) gives fetchWidth: 672 displayWidth: 640. Workbench 2.0 with 690px overscan: DDF: 30 d8 DIW: 2c6e 2cc7 (modulo 88) gives fetchWidth: 704 displayWidth: 690. |
22 July 2022, 23:08 | #2 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
For OCS and hires:
const fetchWidth = (((DDFSTOP&0xfc)-(DDFSTRT&0xfc)+0xc)&0xf8)*4; It's not exactly the same in ECS+ (there is 1 bit more in DDF, so the mask is different) or FMODE>0 ('blocks' are different), but you get the idea. (I'm not even 100% sure if that is valid for all combinations, but I think so.. ) The difficulty is that the hardware does not use a 'formula', but starts (and finishes) fetches using match values of the Agnus counter and DDF registers, but using defined 'blocks' and minimum fetch per block. What I wrote is the closest thing the hardware does under the conditions listed. Last edited by ross; 22 July 2022 at 23:52. Reason: added informations |
23 July 2022, 00:06 | #3 |
Registered User
Join Date: Feb 2019
Location: Munich, Germany
Posts: 63
|
Thanks.
I'd be willing to implement a more "complete" display emulator, but the WinUAE source is unfortunately quite difficult to comprehend. Do you know of a somewhat simple implementation of the bitplane/display logic? Also, it seems my lores calculation may also be flawed. You got one for that, too? Last edited by Bartman; 23 July 2022 at 00:18. |
23 July 2022, 00:47 | #4 | ||
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
Fetches start at DDFSTRT, no matter what, bitplanes DMA have priority over anything. From that moment a 'block' of n slots start, with n depending on FMODE: FMODE=1x n=8, FMODE=2x n=16, FMODE=4x n=32. The starting alignment depends on the most valid low bit in DDF: bit 2 in OCS, bit 1 in ECS+. The blocks are divided into sub-blocks according to the resolution: with FMODE=1x -> 1*8 in lores, 2*4 in hires, 4*2 in shres (this is because the pixels have to be emitted more often); of course there are fewer bplanes available in higher resolutions. As FMODE increases, the width of the sub-blocks also increases [2x, 4x, equally spaced], so that higher resolutions have more slots (and more bitplanes) usable [the DMA slots are packed to the right of the (sub-)block, by writing BPL1DAT exactly when you need to output a valid and complete pixel sequence of 16, 32 or 64 pixels]. You can notice that the blocks are more 'distant' in higher fetch mode. but the bits per fetch are greater (2x=32bit per slot, or 4x=64bit per slot) so the pixels emitted are always at the correct frequency; of course there are many more free slots for other DMA channels in this cases. When DDFSTOP matches, the sequencer define a latest block to be fetched after the executing block,and then stop. This is the reason why a start of $3c do the last block fetch starting from $d4 (with DDFSTOP = $d0). It complete [with FMODE=1x] the penultimate fetch block of 8 slots from $cc, then do a last one from $d4, for a grand total of max($dc-$3c)=$a0 slots -> 160*16/4=640pixes. Sorry if the grammar is awful, I hope you understand something EDIT: Quote:
EDIT2: @Toni: yes I simplified a bit, I have not considered the delay for the start of the first 'block' (4 cycles), what happens for some particular start and stop values, what happens for values that overrun (or underrun)... But it's just to give a general idea and to specify what happens when the values are set 'correctly'. Last edited by ross; 23 July 2022 at 09:00. |
||
23 July 2022, 00:56 | #5 |
HOL/FTP busy bee
Join Date: Sep 2006
Location: Germany
Age: 46
Posts: 31,518
|
I only skimmed over this conversation, but I wonder if there is a way to use this information to tell for example WinUAE how to save screenshots that have the 'correct' resolution.
Quick reason why I care: Often I need to check at which position the actual image data starts and how wide and high it is. That often results in a lot of educated guesses and checking for 2 pixel wide black borders. Afterwards I need to check if it's lo-res or hi-res (you get an eye for it, but often it involves halving the resolution and checking if it's the same). If all that stuff could be automated it would save a lot of time, so I'm just curious if it is at all possible. |
23 July 2022, 22:20 | #6 |
Registered User
Join Date: Feb 2019
Location: Munich, Germany
Posts: 63
|
Thanks again. I now got a rudimentary Denise emulator working.
|
25 July 2022, 18:57 | #7 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Before anyone complains: this is a prank
I said that the formula to use would be complex, but in fact for the first time on these screens, here it is: Code:
//res: #define LORES 0 #define HIRES 1 #define SHRES 2 //chipset: #define OCS 0 #define ECS 1 #define AGA 2 int fetchWidth (int DDFSTRT, int DDFSTOP, int chipset, int res, int FMODE) { return ((((DDFSTOP&=chipset?0xfe:0xfc)-(DDFSTRT&=chipset?0xfe:0xfc)+((((chipset\ ==AGA)?(((FMODE&=3)<=1)?(FMODE&=3):(FMODE&=3)-1):0)>((chipset==OCS)?res&1:res))\ ?(8<<(((chipset==AGA)?(((FMODE&=3)<=1)?(FMODE&=3):(FMODE&=3)-1):0)-((chipset==\ OCS)?res&1:res)))-1:8-1))>>(3+((((chipset==AGA)?(((FMODE&=3)<=1)?(FMODE&=3):(\ FMODE&=3)-1):0)>((chipset==OCS)?res&1:res))?((chipset==AGA)?(((FMODE&=3)<=1)?(\ FMODE&=3):(FMODE&=3)-1):0)-((chipset==OCS)?res&1:res):0)))+1)<<(4+((chipset==\ AGA)?(((FMODE&=3)<=1)?(FMODE&=3):(FMODE&=3)-1):0)+((((chipset==OCS)?res&1:res)\ >((chipset==AGA)?(((FMODE&=3)<=1)?(FMODE&=3):(FMODE&=3)-1):0))?((chipset==OCS)\ ?res&1:res)-((chipset==AGA)?(((FMODE&=3)<=1)?(FMODE&=3):(FMODE&=3)-1):0):0)); } |
25 July 2022, 19:15 | #8 |
Global Moderator
Join Date: Nov 2001
Location: Derby, UK
Age: 48
Posts: 9,355
|
I just puked a little bit looking at that formila!
|
25 July 2022, 19:18 | #9 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
|
25 July 2022, 19:19 | #10 |
HOL/FTP busy bee
Join Date: Sep 2006
Location: Germany
Age: 46
Posts: 31,518
|
|
25 July 2022, 19:21 | #11 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
|
25 July 2022, 20:21 | #12 |
Registered User
Join Date: Feb 2017
Location: Denmark
Posts: 1,098
|
A bit disappointed that you didn't express it more clearly as an irreducible polynomial in GF(2^8). That would have been much more readable
Tried refactoring it a bit (maybe not the best chosen variable names), but should give same results: Code:
int fetchWidth2 (int DDFSTRT, int DDFSTOP, int chipset, int res, int FMODE) { if (chipset == OCS) { res &= 1; DDFSTRT &= 0xFC; DDFSTOP &= 0xFC; } else { DDFSTRT &= 0xFE; DDFSTOP &= 0xFE; } if (chipset == AGA) { FMODE &= 3; if (FMODE > 1) FMODE--; } else { FMODE = 0; } int blockSizeShift = 3; int pixelsPerFetchShift = 4 + FMODE; const int fetchDiff = FMODE - res; if (fetchDiff > 0) blockSizeShift += fetchDiff; else if (fetchDiff < 0) pixelsPerFetchShift -= fetchDiff; return (((DDFSTOP - DDFSTRT + (1<<blockSizeShift) - 1) >> blockSizeShift) + 1) << pixelsPerFetchShift; } Last edited by paraj; 25 July 2022 at 21:26. Reason: Remove unncessary variable |
25 July 2022, 20:24 | #13 |
HOL/FTP busy bee
Join Date: Sep 2006
Location: Germany
Age: 46
Posts: 31,518
|
That's far too easy to read for Amiga code
|
25 July 2022, 20:37 | #14 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
This is the original function, written this way to generate 'the monster'. Code:
int fetchWidth (int DDFSTRT, int DDFSTOP, int chipset, int res, int FMODE) { // validate bits FMODE &= 3; DDFSTRT &= chipset ? 0xfe : 0xfc; DDFSTOP &= chipset ? 0xfe : 0xfc; res=(chipset==OCS)?res&1:res; // fetch=log2(fetch_width)-4; fetch_width=16,32,64 int fetch = (chipset == AGA) ? ((FMODE <= 1) ? FMODE:FMODE-1) :0; // sub-block (OCS/ECS) and large-block (AGA) stop pad int pad = (fetch > res) ? (8 << (fetch - res))-1 :8-1; // OCS/ECS/(AGA) sub-block int sub = (res > fetch) ? res - fetch :0; // AGA large-block int large = (fetch > res) ? fetch - res :0; // DMA fetched blocks int blocks = ((DDFSTOP - DDFSTRT + pad)>> (3 + large)) +1; // 16 pixels per fetch_width per sub-block per block return blocks << (4 + fetch + sub); } Last edited by ross; 25 July 2022 at 22:35. Reason: crossed out the out of context '8 planes' :) |
|
25 July 2022, 20:40 | #15 | |
HOL/FTP busy bee
Join Date: Sep 2006
Location: Germany
Age: 46
Posts: 31,518
|
Quote:
|
|
25 July 2022, 21:33 | #16 |
Registered User
Join Date: Feb 2017
Location: Denmark
Posts: 1,098
|
Yeah, knew you were BSing when I saw repeated FMODE&=3 and figured it might be interesting to see what it could be reduced to (also for going the other way when you need to).
OCS 8 planes? (I know about the 7-planes thing where Agnus only fetches 4 planes but 6 are active, but that shouldn't affect this calculation IIRC). |
25 July 2022, 21:53 | #17 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
Setting bit for 8 bplanes does nothing in OCS/ECS. |
|
25 July 2022, 22:12 | #18 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Yes, this could be achieved by studying the function, interesting is that it is not bijective, so there can be many solutions.
This is probably what confuses most. But the key is the 'pad' variable (I haven't found a better name...) that basically define where the penultimate block is 'active' and DDFSTOP could match to define the last fetch. This works differently with AGA 'large' blocks because it is not like before in a predefined range (in OCS/ECS there are only sub-blocks). The side effect is that you could have odd numbers of block fetches in HIRES or SHRES in AGA, that's impossible in OCS/ECS. |
26 July 2022, 15:48 | #19 |
Global Moderator
Join Date: Nov 2001
Location: Derby, UK
Age: 48
Posts: 9,355
|
Now we just need it in assembler
|
26 July 2022, 23:53 | #20 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
It's simple, but ..how about a small competition for those who make the smaller (68000) version?
So with the DDF registers with usual values, chipset and res limited to those of the #define and FMODE a word value (which can therefore also contain the bits not strictly related to the fetches of the bitplanes). It does not matter to save the used registers, RTS counted (because it could be anywhere in code..). input: d0.w=DDFSTRT, d1.w=DDFSTOP, d2.w=chipset, d3.w=res, d4.w=FMODE output: d0.w: fetchWidth Do not post code immediately!, leave some suspense and post only number of byte used |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Exact functioning of DDFSTRT & STOP? | TommoH | Coders. Asm / Hardware | 19 | 04 July 2023 21:31 |
OCS + DDFSTRT=$30 - Losing spr6? | Antiriad_UK | Coders. Asm / Hardware | 5 | 18 December 2019 14:43 |
diwstrt, ddfstrt and hires | leonard | Coders. Asm / Hardware | 6 | 02 December 2019 00:38 |
7th sprite corrupt with DDFSTRT of 0x30 | FSizzle | Coders. Asm / Hardware | 9 | 11 November 2017 17:36 |
DDFSTOP question | FrenchShark | Coders. General | 5 | 08 August 2009 20:42 |
|
|