4

The Apple II uses non-linear frame buffers for text and graphics. Rather than storing each line in sequence at

lines  0-23: $400, $428, $450, $480,¹ ..., $7D0

it stores them at

lines  0- 7:  $400, $480, $500, $580, ..., $780
lines  8-15:  $428, $4A8, $528, $5A8, ..., $7A8
lines 16-23:  $450, $4D0, $550, $5D0, ..., $7D0

In other words, if you write linearly to the frame buffer, your data will appear first on the top line of the screen, then on a line a third of the way down, then on a line two thirds of the way down, then on the second line of the screen, and so on.²

In the answers and comments for What is DRAM refresh and why is the weird Apple II video memory layout affected by it?, there is extensive debate about whether this non-linear arrangement has anything to do with DRAM refresh. One answer says probably or yes, two say no, and one has no comment on the issue; comments on all answers that take a position argue it back and forth.

It doesn't look as if a clear answer to this is coming out of that question (which is asking about a lot more than the layout, anyway) so I'm creating this question to try to get a definitive answer on just this issue.

If the frame buffer were linear, would there be any way software could do something such that any DRAM row could be made to refresh less often than it would with the current non-linear frame buffer? If so, what would that way be?

Answers should either:

  1. Clearly describe a program that on a linear frame buffer, but not on the current layout, would cause some DRAM rows to be refreshed at significantly longer intervals than they would be in usual operation; or
  2. Explain why it's not possible to produce such a program.

¹ You might note that each third row in memory is 8 bytes longer than the other two, $30 instead of $28 bytes. Three rows of 40 characters (or 40 groups of 7 pixels plus a color bit in hires) sums to 120 bytes of storage; the extra 8 are padding to make the next row line up nicely. This is not just aesthetic, but helps with the hardware design.)

² The addresses above are for the first page of text and low-res graphics; the high-res frame buffer starting at $2000 is the same arrangement with eight times as many rows. The Apple II Technical Reference Manual includes more detailed diagrams giving maps of the text, low-resolution graphics and high resolution graphics frame buffers.)

1
  • Funny thing is that I accepted YOUR answer on that question just recently! I gathered from your description of DRAM refresh that it really had nothing to do with the layout as that was just a "Woz chip optimization" perhaps not thinking much about the programmer implications of his decision. That being said, I would like to definitively hear if my suspicion (i.e. scanline had already jumped ~30 rows by the time display circuitry gets its next shot to feed the raster), or is it just simply Woz saved a chip and it has nothing to do with timings?
    – bjb
    Nov 10 '21 at 17:02
2

On the Apple II, the values of address bits 0-4 and 7-9 during each part of a frame are independent of the graphics mode. Those eight bits are used to control the DRAM row address, and need to cycle through all possible bit patterns four times per frame (excluding bit 9, the remaining bits need to cycle through all bit patterns eight times per frame).

If e.g. the row addresses that connect to bits 7-9 incremented every scan line in hi-res mode, instead of incrementing every eight scan lines regardless of graphics mode, but the within each group of 64 scan lines, the first, ninth, eigteenth, etc. lines would generate the same addresses in both modes, then the maximum time between refresh for any particular address would be increased from 24 scan lines to 31 when using 7-bit row addresses, and from 56 to 63 when using 8-bit row addresses. I think that might push timings slightly beyond spec, but probably not enough to matter. A more interesting issue, however, would be ensuring that a mode switch can't occur while a row address is being generated. If the signals on the row wires change just as the DRAM chip is sampling them, this can cause arbitrary corruption of the data on both the old and new rows. This can actually happen on the Commodore 64 in some scenarios. While such possible timing issues could have been guarded against even if row addresses were dependent upon display modes, ensuring that timing margins will always be met even in such cases is harder than simply having the row value be independent of display mode.

5
  • 1
    I don't understand what you mean by "each part of the frame," and I'm not sure I understand what you mean by "independent of graphics mode" (the sequence is always the same? Isn't that true of bits 5-7 as well?). How did you determine that the row addresses are generated from A0-4 and A7-9? And, as I asked in the question, can you give an example of sequences of mode switches with a linear buffer that would break the refresh? Or are you saying linear would have been fine as far as refresh goes, but the other corruption issue might be a reason to go non-linear?
    – cjs
    Nov 10 '21 at 22:47
  • The DRAM row address has only 7 bits, not 8. The address bus signals used, sorted by address bus position, are A0 A1 A2 A3 A7 A8 A12) I believe. I.e., no A4 or A9, and you've left out A12.
    – cjs
    Nov 11 '21 at 9:26
  • @cjs: On the Apple II and Apple II+, the DRAM row access has seven bits, but the Apple //e and Apple //c it has eight bits, but it only needs to be refreshed half as often. I wouldn't particularly expect that Woz was thinking about compatibility with 64K DRAM chips when he designed the Apple II, but the scanning layout works for such chips anyway.
    – supercat
    Nov 14 '21 at 20:31
  • @cjs: I don't know what particular factors caused Woz to favor his design over alternative possible designs where the row address would vary based upon graphics mode; for some mappings, there could be possible sequences of mode switches that could starve one or more rows, and for some mode-control designs there could be difficulties ensuring that mode switches don't cause row addresses to change at bad times. I don't know which issue would have been more or less relevant, but having the sequences of row addresses be invariable avoids the need to spend time analyzing such issues.
    – supercat
    Nov 14 '21 at 20:41
  • I'm not seeing from your answer here why, since the address bus assignments for the row bits can be moved around as well, it's not possible to come up with a linear scheme that also has the same sequence of row addresses in all modes. Wouldn't you just move around the bits that currently cause the increments to go in chunks of 1/3 screen? It rather looks to me as if the 1/3 screen jumps are done to deal with the 3× row ≠ 128 bytes issue.
    – cjs
    Nov 15 '21 at 0:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.