Hello, Guest the thread was called849 times and contains 41 replays

last post from mega65 at the

MAP instruction

  • For tonight, I had a re-read of this entire thread, to try let it all sink in. After doing so, I tried reflecting on my initial post, to see if I could summarise answers to those initial Q's I had, via the knowledge everyone has shared here. Sometimes these new insights can lead more questions too :D

    Pre-req readings on the mapping topic:

    • c65 manual
      • 1.5.1 Composite System Memory Map
        - This gives some examples of common mapping states of the system (E.g., c64-mode, c65 mode)
        - There isn't much explanation on exactly 'how' those specific mapping states were accomplished.
        - Kinda wish the mega65 serial debug monitor could also reveal the presently mapped 8KB blocks, in addition to MAPL and MAPH. Perhaps an extra "BLOCKS" column? (just to assist in studying the present state of mapping of the system)

      • 1.5.2 System Memory Map
        - Shows how the banks of 64kb have been allocated
        - Of most interest are:
        - 2 banks of System RAMs (from 0KB - 128KB)
            (incorrectly described in the c65 manual's diagram as System ROMs)
        - 2 banks of System ROMs (from 128KB to 256KB)

      • 1.5.3 C65 System Memory Layout
        - This elaborates in more detail the contents of those first 4 banks of 64kb (the 2x64kb RAMs and the 2x64kb ROMs)
        - I'm guessing the usage of RAM shown here is more specific to C65-mode, and perhaps it is used/allocated differently for other modes (c64-mode, monitor mode?)

    • C65GS System Notes
      • 5.0 Memory Maps
        - Doesn't say a great deal about the MAP mechanism, but does talk about other ways to perform 32-bit addressing that are mega65-specific
        - I haven't explored these options yet, I'll save that for another time

      • 6.2 The MAP Opcode
        - Does elaborate on MAP, with an erroneous description of register usage and half of an example
        - It hints at the megabyte selection, but doesn't elaborate on it

    So reflecting on all this and the 2 examples I tried to dissect, I think the biggest point of confusion has occurred because both examples make use of a mega65-specific "megabyte selection" mechanism, and that mechanism hasn't been properly explained yet (or not in the sources I've covered so far, maybe elsewhere? Via .md files in the repo? I'll check later). So let me first attempt to document my understanding of that:

    Megabyte Selection mechanism:

    Both examples I tried to dissect in this thread were actually calling MAP twice. The first MAP call was selecting the megabyte to use for the offset, while the 2nd MAP call was deciding where within that selected megabyte to treat as our absolute offset.

    Here's my diagram for the megabyte selector register usage:

    Note that:

    • A-register will contain bits 20-27 of your MAPL offset (which equates to the megabyte selected)
    • X-register will contain an 0x0F token value, to indicate that we intend to make a 'megabyte selection' in the A-register
    • Y-register will contain bits 20-27 of your MAPH offset (which equates to the megabyte selected)
    • Z-register will contain an 0x0F token value, to indicate that we intend to make a 'megabyte selection' in the Y-register

    Once this first MAP is done to select the megabyte, the examples then select bits 8-19 of the MAPL/MAPH offset via a 2nd call to MAP, with registers used as described in the c65 manual.

    I've run out of time tonight to revise my two examples, but I think they will finally make more sense when I take this 'megabyte selection' mechanism into consideration now...

  • I've been having a read through Paul's past blog posts (from oldest to newest), to see if the topic of "megabyte selection" ever got documented there.

    I finally caught sight of the topic, but only in passing, while he was describing the mapping of the ethernet read buffer:


    So on the whole, so far, I don't think this 'megabyte selection' MAP behaviour has been whole-heartedly documented anywhere. So I'm thinking that my efforts to diagram and document it in the prior post are a good start.

    Finding myself being in more of a reading-mode these days on the mega65. While that has been rewarding in its own way, it can also feel a little frustrating, as nothing of any great excitement can be achieved by merely reading. I suppose my brain is hoping all this reading will rekindle my past mega65 memories, and perhaps push that understanding a few inches further.

    Still, at least at this point, I can say I "kinda get" the c65/mega65 MAP behaviour, including the megabyte selection. Still feels like I'll need to encounter multiple use-cases for that understanding to completely solidify, and perhaps try make use of it through my own examples too.

    At this point though, I also begin to wonder, is the MAP mechanism right for my needs, or should I be exploring other mechanisms available in the mega65 to address 28-bit memory instead.

    My end-goal was to try port my sf2-reu demo into the mega65. After all this reading, I'm still not quite sure how I'll go about that :)

  • If you understand the MAP instruction (for C65) you're on the good path. With this MAP thingy, C65 can address 1Mbyte of memory space. You can see why, because there are offsets (for both of lower and upper "region" but it does not matter here too much) bits 8-19, thus the offset is 20 bit, the lower 8 bit of the CPU generated address is never changed by the "MMU". Thus in theory, you can have $FFF00 as the offset if I didn't messed it up now here as the explanation :) If you have CPU address like $FFFF and you add them together, indeed, it would overflow the 1Mbyte space, but in case the space just "wraps around". So the access is always within the 1Mbyte-range. That was with the C65.

    For M65, I guess, Paul wanted to keep the core C65 concept as much as possible. But he wanted more memory space. Thus for restricting the access within 1Mbyte, he introduced to ability to tell WHICH 1mbyte of the memory space we're talking about. Since there are 256 possibilities to select this "slice" on M65, the total memory space of M65 is 256*1Mbyte = 256Mbyte. So now you can see, why this "strange" memory space max is got, even if you think about the M65 CPU "linear addressing space" where it's possible to directly access 32 bit addresses, but in that case - I guess - still the lower 28 bits count (=256 Mbyte) only. The only remaining question, how to tell M65 the "1Mbyte slice" within the 256 possible to be used. Basically the theory was to use "hijacked" combination of the normal MAP instruction which does not make too much sense, and that was "re-defined" for this "mbyte selection". That is the "TOKEN" thingy etc, you also mentioned. It's just an made-up combination so M65 knows, it's not the offset settings (what C65 would do always with MAP opcode) but the "mbyte selection".

    Well, hopefully I wasn't too boring, as far as I can see, you already figured out these anyway.

    About your question, that is it the best way ... Well, it depends. if you want to execute code, you need to do that, since M65 would not able to execute code (in general) outside of the 16 bit world what its cpu thinks as being the addressing space, and what the MMU translates to real addresses then (MMU now even included the VIC-III ROM mapping etc too!). Not even counting if you have code outside of the 1Mbyte first "slice". But, I assume you are more focused in data exchange (like ethernet buffer) rather than execution of code from the "higher memory area". In that case, you can still use DMA to transfer data, or, you can use the "linear addressing mode", like:

    NOP ; LDA (zp_loc),Z

    In this case the "magic" sign (NOP followed by a (ZP),Z addressing mode opcode) causes the M65 interpret the meaning of the opcode. The "zp_loc" (zero page location, though you can re-map the zero page even on C65, better to call that as "base page", see register B for more details) now holds a 4 byte address (!!!) thus it means 32 bit address, though the first 28 is used only, AFAIK. Then register Z is added to the value as well. It's kinda powerful stuff in my opinion. For example, I managed to software emulate i8080 CPU only, on M65 using this addressing mode, and with the fact, that the low word of the 4 byte address can be easily incremented with the "INW" opcode (that also exists on C65 btw). Thus, I managed to run CP/M program with i8080 software CPU emulation on the M65, which was the Microsoft CP/M MBASIC for demonstration. It would be PAINFULLY slow, if I have to alter memory configuration all the time (without this "direct" or "linear" addressing), since the emulated memory for i8080 wanted to be a "clean" and empty 64K, but still I need address space for the emulator code itself ... Btw, this can be done quite differently but also cleverly on the 65816 CPU, maybe even much better (though there, the opcodes are somewhat slower on the same clock speed ...).

    Anyway. I guess, you're right, documentation must be made, there are many things not so much known currently, or hard to figure out, or at least find information on it ...

  • M65 specific example (surely does not work on C65) to show how to avoid MAPing things:

    1. LDZ #0
    2. loop:
    3. NOP ; LDA (my_zp_loc),Z
    4. STA my_buffer,Z
    5. INZ
    6. BNE loop

    That stupid example would read 256 bytes from linear/real/phyiscal (whatever) address stored at four bytes at "my_zp_loc" in the zero (base) page, and copies that to a buffer (my_buffer) which is CPU addressable chunk of memory. Note, that you don't need ANY "MAP" here, as the LDA uses a linear addressing mode operation which bypasses any CPU translation and such. In fact, you can even change the STA to a similar operation with another ZP loc, to be able to copy between two arbitrary memory regions of the M65 without the need to be being MAPed at all ... Though, this method is kinda slow (compared to using DMA), I mean, using DMA is a better solution, especially in larger memory areas, maybe not for some bytes, but certainly for more ... Certainly, for few bytes (maybe this example is bad, and DMA would benefit here already ...) it does not worth too much to use DMA with all of the preparation works for that ...

  • Hello all,

    It sounds like you have all gotten to the bottom of how it works for the most part. To make life easier for others, it would be great to collate this info into the MEGA65 User Guide / Programmer's Reference Guide, if someone is willing to help with this process.

    It would also be great for someone to write a nice little BASIC 10 program that lets you type in an mapped and natural address where you want something to appear, and have it calculate the MAP register values, and show them on the screen.

    As for reading the status of the MAP instruction, it is indeed impossible on real C65s, which is one of several reasons why the MAP instruction was never a great idea. I intend to make a MEGA65 Hypervisor trap that will allow you to request the current values of the MAP into the registers, to make it a bit less annoying to use.

    Liebe Grüße,


    PS: I'll be at the CCC Camp talking about the MEGA65 phone later in the month, if anyone is in the Berlin area and would like to catch up while I am there.

  • Well, yes, C65's "MMU" is kinda strange in my opinion. To the "OS" needs (kernal, etc) most things at least can be handled with the legacy-C64 way of the "CPU port" (though on C65 it's handled by VIC-III, but never mind from the programmer's view point), or the VIC-III ROM mapping. Surely, still, some kind of other mechanism is still needed eg to access the second 64K of RAM etc etc, that's true! But because of most of the logic to "map" ROMs etc can be done other way, I am not so sure why this is done in a strange way. I still prefer the idea what many computer uses, including C64DTV, MSX2(Z80), Enterprise(Z80), etc to have 4*16K pages of CPU "window", and there are n*16K of memory space (let's call those "segments" for example), and any of the segments can be mapped to any of the CPU windows. Still the compatibility with C64's memory handling etc can be done in the old-fashion way (eg what C64DTV does, which is a bit closer example then Z80 based examples). Even with 4*byte registers for 4*CPU windows, that's still 4 byte info (much like the C65's MAP expects in four CPU registers) but can give you 4Mbyte address space, much more clean, and no "just two offsets upper/lower" restriction etc. Though, that's true, that C65's solution can give finer mapping to allow map areas on 256 byte boundaries in terms of offset, when it's only 16K with my examples. Anyway, C65 did this way, and unless we don't want to be compatible with C65, we still need to maintain this legacy after all ... Surely this is kinda off-topic now from me, and it's just my personal opinion anyway.

  • Okay, I can provide quick explanation of the MB selection via MAP.

    To set the MB offset for the lower half: X=$0F, A=<MB>. Similarly for the upper half: Z=$0F, Y=<MB>.

    This approach was taken, because it makes no sense to ask the C65 to have a non-zero offset, but then request the mapping of no 8KB blocks to use it.

    Relevant piece of fthe VHDL:

    -- purpose: change memory map, C65-style

    procedure c65_map_instruction is

    variable offset : unsigned(15 downto 0);

    begin -- c65_map_instruction

    -- This is how this instruction works:

    -- Mapper Register Data

    -- 7 6 5 4 3 2 1 0 BIT



    --| OFF15 | OFF14 | OFF13 | OFF12 | OFF11 | OFF10 | OFF9 | OFF8 |



    --| BLK3 | BLK2 | BLK1 | BLK0 | OFF19 | OFF18 | OFF17 | OFF16 |



    --| OFF15 | OFF14 | OFF13 | OFF12 | OFF11 | OFF10 | OFF9 | OFF8 |



    --| BLK7 | BLK6 | BLK5 | BLK4 | OFF19 | OFF18 | OFF17 | OFF16 |



    -- C65GS extension: Set the MegaByte register for low and high mobies

    -- so that we can address all 256MB of RAM.

    if reg_x = x"0f" then

    reg_mb_low <= reg_a;

    end if;

    if reg_z = x"0f" then

    reg_mb_high <= reg_y;

    end if;

    reg_offset_low <= reg_x(3 downto 0) & reg_a;

    reg_map_low <= std_logic_vector(reg_x(7 downto 4));

    reg_offset_high <= reg_z(3 downto 0) & reg_y;

    reg_map_high <= std_logic_vector(reg_z(7 downto 4));

    -- Inhibit all interrupts until EOM (opcode $EA, which used to be NOP)

    -- is executed.

    map_interrupt_inhibit <= '1';

    -- Flush ZP/stack cache because memory map may have changed

    cache_flushing <= '1';

    cache_flush_counter <= (others => '0');

    end c65_map_instruction;

    Of course, on the MEGA65 there is almost always more than one way to do things: You can simply use a M65-mode DMA job, which lets you specify the source and destination MB in the DMA job itself:

    Take a look at, for example:


    It uses $D705 to trigger the DMA in MEGA65 enhanced mode. You must then prefix the normal C65-style DMA job with one or more option codes. Option code $0B = use DMAgic rev B style list format, $0A = use DMAgic rev A style list format. Option codes $80 and $81 specify the source and destination MB offsets. The option list is then always terminated with a $00 byte.

    Relevant registers and documentation from iomap.txt:

    C65 $D700 DMA:ADDRLSBTRIG DMAgic DMA list address LSB, and trigger DMA (when written)

    C65 $D701 DMA:ADDRMSB DMA list address high byte (address bits 8 -- 15).

    C65 $D702 DMA:ADDRBANK DMA list address bank (address bits 16 -- 22). Writing clears \$D704.

    GS $D703.0 DMA:EN018B DMA enable F018B mode (adds sub-command byte)

    GS $D704 DMA:ADDRMB DMA list address mega-byte

    GS $D705 DMA:ETRIG Set low-order byte of DMA list address, and trigger Enhanced DMA job (uses DMA option list)

    GS $D705 - Enhanced DMAgic job option $00 = End of options

    GS $D705 - Enhanced DMAgic job option $06 = Use $86 $xx transparency value (don't write source bytes to destination, if byte value matches $xx)

    GS $D705 - Enhanced DMAgic job option $07 = Disable $86 $xx transparency value.

    GS $D705 - Enhanced DMAgic job option $0A = Use F018A list format

    GS $D705 - Enhanced DMAgic job option $0B = Use F018B list format

    GS $D705 - Enhanced DMAgic job option $80 $xx = Set MB of source address

    GS $D705 - Enhanced DMAgic job option $81 $xx = Set MB of destination address

    GS $D705 - Enhanced DMAgic job option $82 $xx = Set source skip rate (/256ths of bytes)

    GS $D705 - Enhanced DMAgic job option $83 $xx = Set source skip rate (whole bytes)

    GS $D705 - Enhanced DMAgic job option $84 $xx = Set destination skip rate (/256ths of bytes)

    GS $D705 - Enhanced DMAgic job option $85 $xx = Set destination skip rate (whole bytes)

    GS $D705 - Enhanced DMAgic job option $86 $xx = Don't write to destination if byte value = $xx, and option $06 enabled

    GS $D70E DMA:ADDRLSB DMA list address low byte (address bits 0 -- 7) WITHOUT STARTING A DMA JOB (used by Hypervisor for unfreezing DMA-using tasks)

    The funny skip rate stuff is to allow the DMA job to be used to copy textures if you wanted to make a wolfenstein type game, and set the video mode up cleverly enough (there's a challenge for someone :).

    The transparency value stuff is also to allow texture copying with holes, as well as I am sure various other bizarre uses people will find.

    It would be great for someone to write this up in a nice way with some examples to put in the relevant chapter of the M65 User Guide / Programmer's Reference Guide.


    PS: A note to the admins: The citations appear for me as medium grey on almost identically luma blue, which makes them impossible to read while editing. This is in Firefox.


  • Btw DMA ... actually I still have to hope to have modulo and minterm support for DMA :) No idea if *any* C65 supported, but these is place for it in the documentation of C65, there is "place" in the DMA list etc, so why not, after all even C65 didn't do it (so not used by anyone -> no compatibility problem if used differently on M65 ...), M65 is a very well expanded C65, well over the C65 feature set. What I could do to figure out (from the doc at least), I've tried how "it should/would have been worked", but I can be wrong, for sure. These can be useful with pair of other M65 features quite well, btw!

  • Thanks for the additional input Paul. It'll take a few re-reads for it all to sink in for me. Finished re-reading your blog today, just to refresh my memory on as much as I could. In the process, my learning curve on MAP cooled off so might have to re-read this whole thread to refresh on that :-)

    As for helping out by supplementing the official docs, I did try download the repo for the docs last weekend. Had some trouble building it, didnt manage to sort out all the errors, but it did spit out a pdf, which I enjoyed browsing through, definitely gave me flashbacks of the c64 reference manual, well done there :-)

    Still, all this latex shmatex stuff is new and foreign to me, so my mind fears further learning curves needed simply to contribute to a document.

    Who knows, maybe it's a piece of cake once you dip your toe in the water. Maybe I can brave it in time.

    As for Mega65 having support for reading the current MAP settings, I know you mentioned the hypervisor trap approach, fair enough, that sounds like a good way for a piece of software to assess the current state of MAP.

    But I did notice in the mega65's serial debugger, that it is already aware of *some* of the MAP's state (i.e., the MAPL and MAPH values it displays when you list all the registers).

    These are values that not even the C65's in-built monitor can see, so I'm guessing that the Mega65's serial debugger has greater access to the internal MAP details than the c65 monitor does.

    If that were the case, would it then also be possible to also show a BLOCKS byte in this register output too? (containing the bitfield values of which 8kb blocks are presently mapped?).

    Just thought this might be a nice way to assess the current MAP state while you're in a debugging frame of mind?

  • In terms of contributing to the user's guide, if you can even just write plain unformatted text with examples, we can massage it into latex.

    As for reading the MAP status, the issue is that there is no register that lets you read their status on the C65. The serrial debug interface that shows the status obliquely shows the block status, in that the upper 4 bits of MAPLO and MAPHI *are* the bits for mapping each 8KB block or not. The poor serial debugger has its own ROM currently maxed out, or we could add a more verbose explanation. The monitor in the freeze menu is a different story, and we could have a mapping editor/viewer in there. Add an issue to the github repo :)



  • I have just posted a link to the latest usersguide.pdf in the hardware thread. Maybe it (also) belongs here? Anyways, please download and lets talk about additions :)



    "VHDL schreiben ist wie in Mordor zu arbeiten. Es gibt viel Streben und viel Rauch, aber nur wenig Erfolg. Und Erfolg sieht meist schlimmer aus als Misserfolg" PGS 2019

  • Thanks Deft and Adtbm for the user guide pdf, having a quick browse through that now, looks good. Appreciate that you've even put in a section on how to program the FPGA's, very considerate! :D

    Pondering where a good home for some of the details covered in this thread could be:

    • Possibly within "Appendix D - 45GS02 Microprocessor" - "Extended Memory Support" - "Using the MAP instruction to access >1MiB".
      - The current description there is informative, but doesn't elaborate on the specifics:
      • Usage of the a, x, y, z registers for megabyte selection
      • Usage of a, x, y, z registers for for offset and 8KB block selection within the currently selected megabyte
      • It makes mention of the use of a 3rd call to MAP, used to disable mapping initially. This is new to me, so I'd be interested in more detail on that

    • As this section's intention may have been to give a brief overview of the various ways to access extended memory, perhaps these details could have their own "Memory mapping" section somewhere else?

    As for what kinds of details to poach from this thread, I'll probably need to re-read it again myself to remember the penny-dropping highlight moments for me. Offhand, I think things like this would be nice:

    • The c65 manual's bit-field diagram and explanation for the offset+8kb block selection feels worth poaching
    • My bit-field diagram and explanation of "Megabyte selection mechanism" earlier in this thread (done in the same style as the c65 manual), including the usage of the registers seems worth poaching too
    • Gabor's terminology/formula clicked for me:

      Physical Address = CPU Address + Offset
    • A breakdown of how terms like "Megabyte selection" and "Bank" selection relate to the physical address. Perhaps an example like this:
      .| +--- BANK

      Bank = $D
      Megabyte-selection = $FF
    • A walkthrough of an example that demonstrates all 3 MAP calls mentioned in the appendix: 1) disabling of mapping, 2) megabyte selection, 3) offset + 8KB block selection

    I'll give this some more thought later.

  • Ok, I'll aim for at the very least a text file summary for the main juicy points of this thread.

    Aah, thanks for pointing out the upper 4-bits of MAPL and MAPH. I initially was hoping to see the values there, but was surprised when I didn't. Now I'm suspecting it may be because I was using Xemu's serial debugger, and that may not have implemented this aspect and left these upper 4-bits set to zero. I'll give this a try on the nexys board this coming weekend.

    I also did raise a card for the freeze-monitor idea, though I should be happy enough for now if I can see if via the upper 4-bits. If that genuinely turns out to be something missing in Xemu, then maybe I'd better make a card for Gabor too ;)

  • Be careful with Xemu, I don't think I implemented even near all things and maybe there are implementation detail differences as well. Honestly I just "played" with Nexys4DDR board + M65 bitstream, and I tried to "mimic" what it does for real. But here can be slight differences, many unimplemented commands/layout/output/answer differences, and also, M65 may evolved since then, that code is quite long untouched in Xemu/M65. Surely, as usual, if you find anything you think should be done differently/etc, just tell me.

  • Gabor's terminology/formula clicked for me:

    Physical Address = CPU Address + Offset

    Actually I "formula" should be (for MAP, but do not forget that a cpu_address may be not MAPed, or VIC-III ROM mapping overrides this, or you bypass this address translation totally with "linear address mode" etc):

    physical_address = (((map_offset << 8) + cpu_address) & $FFFFF) | (megabyte_selection << 20)

    So, "map_offset" is chosen from the "lower" or "upper" offset based on the highest bit of the CPU address (thus lower or upper 32K). Since the offset does not represents the lower 8 bits, I used the "<<" shift operation for offset. The cpu_address is added to the map_offset, and the result is truncated to fit into 1 mbyte (ie, 20 bits, that is the "& $FFFFF" part). And at last, the upper 8 bits of the physical address is come from the "mbyte_selection (thus the "<< 20") while the lower 20 bits from the previous explanation.

    I'm not sure if it helps, but in general, I mean for a documentation or something.

  • Be careful with Xemu, I don't think I implemented even near all things and maybe there are implementation detail differences as well. Honestly I just "played" with Nexys4DDR board + M65 bitstream, and I tried to "mimic" what it does for real. But here can be slight differences, many unimplemented commands/layout/output/answer differences, and also, M65 may evolved since then, that code is quite long untouched in Xemu/M65. Surely, as usual, if you find anything you think should be done differently/etc, just tell me.

    No probs, will keep you posted in how things fare for me once I get the nexys board up and running on the weekend.

    I saw that Paul had gotten the vnc server stuff working again, I'm wondering if I can give that a try this weekend. Feels like it could be a more convenient way to hook the nexys board up to my laptop, and not need an extra tv/monitor nearby to see the mega65's screen.

  • Be careful with Xemu, I don't think I implemented even near all things and maybe there are implementation detail differences as well. Honestly I just "played" with Nexys4DDR board + M65 bitstream, and I tried to "mimic" what it does for real. But here can be slight differences, many unimplemented commands/layout/output/answer differences, and also, M65 may evolved since then, that code is quite long untouched in Xemu/M65. Surely, as usual, if you find anything you think should be done differently/etc, just tell me.

    It would really be super helpful to know what works and what not. Once we are done assembling, testing and shipping the pre-series machines I would like to work on having complete devkits for Windows, Linux and -if possible- OSX. We already have so many tools and options, but they are all spread over the net. I would love to see XEMU as a central part of the devkit, so people can start developing for the MEGA65 before they have one. If we manage to deliver free tasty packages that are easy to start with, the first coding competitions can start. We already have prices ready that will help more people to build the platform themselves.

    Is anyone from the community willing help in bundling and maintaining the devkits? LGB-Z what would you need from us??



    "VHDL schreiben ist wie in Mordor zu arbeiten. Es gibt viel Streben und viel Rauch, aber nur wenig Erfolg. Und Erfolg sieht meist schlimmer aus als Misserfolg" PGS 2019

  • Great work. Not for being critical here, but I would start with the big picture first, though it's maybe only my view of things. Ie talk about the global memory map and how it is solved to map memory for C64 (what C65 and thus M65 as well wants to compatible with), then how C65 solves the problem and what M65 extends on it still ... But I know it can be debated that bigger -> smaller direction of explaining things is better or the opposite, maybe it's just taste of a given reader what it preferred ....