-----------------------------------------
For a while now, I've been wanting to add support for 4A50 bankswitching to batari Basic. I've decided to work on this project in the Atari 2600 BASIC forum, so anyone who's interested can follow the process to see what's involved, offer comments or suggestions, etc. I apologize in advance for all of the boring parts, because I tend to want to explain things more than I probably should.
It must be stressed that this will be an unofficial modification to batari Basic version 1.0, and any specifics about how 4A50 bankswitching works in batari Basic will undoubtedly change quite a bit if or when 4A50 bankswitching support gets officially added to batari Basic.
Before beginning, it's a good idea to briefly review 4A50 bankswitching. It's very flexible as far as ways to trigger a bank switch, and I'm focusing exclusively on the traditional "hotspots" method, so by no means is this a comprehensive description. See supercat's blog for additional ways to trigger a bank switch. Note that some of the following information differs from what's in supercat's blog, based on information he sent to me last year. In particular, the changes relate to the amount of ROM, and which portions of ROM are available in which bank regions. I'm hoping supercat will step in and throttle me-- I mean, *correct* me-- if I give out any erroneous information.
The 4A50 Cartridge and Bankswitching
------------------------------------
The 4A50 cartridge contains 128K of ROM and 32K of RAM. Programs can also be 64K, and possibly 32K as well, but in those cases the ROM would be replicated as needed (i.e., doubled or quadrupled to fill 128K). The following description assumes a ROM size of 128K. The description would be the same for 64K or 32K, except the second 64K segment would be identical to the first 64K segment for a 64K program; and the second, third, and fourth 32K segments would be identical to the first 32K segment for a 32K program.
Note that we must use five-digit hex addresses-- or more precisely, 17-bit binary addresses-- to refer to all 128K of ROM: $00000 through $0FFFF for the first 64K, and $10000 through $1FFFF for the second 64K. Of course, this applies *only* to the ORG addresses that tell the assembler where to put the assembled code within the physical ROM image, since the logical addresses within the actual 6502 (or 6507) program code cannot exceed two bytes (lo-byte/hi-byte).
The 4A50 bankswitching scheme divides the Atari 2600's 4K cartridge area into four distinct regions:
$F000 through $F7FF = Lower bank region (2K).
$F800 through $FDFF = Middle bank region (1.5K).
$FE00 through $FEFF = Upper bank region (256 bytes).
$FF00 through $FFFF = Non-banked or fixed region (256 bytes).
(The 6507 CPU has only 13 address pins, so there are several addresses which are equivalent to the ones shown above. Some programmers prefer to use $1000 instead of $F000, but I'm going to use $F000.)
There are some restrictions on how this 128K of ROM can be accessed:
$00000 through $0FFFF = 1st 64K -- Accessible only through the lower bank region.
$10000 through $17FFF = 1st 32K of 2nd 64K -- Accessible only through the upper bank region.
$18000 through $1FFFF = 2nd 32K of 2nd 64K -- Accessible only through the middle and upper bank regions.
For the 2K lower bank region, memory is accessed in 2K segments that begin on 2K boundaries. Thus, the first 64K of ROM is divided up into 32 banks, 2K each, which are accessible only at $F000.
The 1.5K middle bank region has a similar rule-- the segments must begin on 2K boundaries-- but only the first 1.5K of each 2K segment is used. The remaining 512 bytes of each 2K segment form two "leftover" pages which are accessible only through the 256-byte upper bank region. Thus, the second 32K of the second 64K of ROM can be divided up into 16 banks, 2K each, of which the first 1.5K is accessible at $F800, and the two leftover pages are accessible only at $FE00.
The 256-byte upper bank region may access any 256-byte page within the second 64K of ROM, even including the last 256 bytes which are "frozen" at the fixed region at $FF00. As expected, the 256-byte pages must begin on page boundaries. Thus, the first 32K of the second 64K of ROM is divided up into 32 pages, 256 bytes each, which are accessible only at $FE00; and the second 32K of the second 64K of ROM can also be divided up into 32 pages, accessible at $FE00.
On the other hand, the 32K of *RAM* is accessible through any of the three bank regions, subject to the same rules about the 2K boundaries and page boundaries.
Given the restrictions described above, each of the three bank regions has a specific amount of ROM or RAM that it can access, as follows:
$F000 through $F7FF = Lower bank region -- May access 64K of ROM, or 32K of RAM.
$F800 through $FDFF = Middle bank region -- May access 24K of ROM, or 24K of RAM.
$FE00 through $FEFF = Upper bank region -- May access 64K of ROM, or 32K of RAM.
Or, to put it another way:
1st 64K of ROM -- All 64K can be accessed only at $F000, 2K at a time.
2nd 64K of ROM -- 1st 32K can be accessed only at $FE00, 1 page at a time.
" " " " -- 24K of 2nd 32K may be accessed either at $F800, 1.5K at a time, or at $FE00, 1 page at a time.
" " " " -- 8K of 2nd 32K can be accessed only at $FE00, 1 page at a time.
Accessing the following hotspots will select the indicated ROM segment at the indicated region:
+-----------------------------------------+ | Lower bank region: 2K, $F000-$F7FF | +--------------------+--------------------+ | $6E00 = ROM $00000 | $6E10 = ROM $08000 | | $6E01 = ROM $00800 | $6E11 = ROM $08800 | | $6E02 = ROM $01000 | $6E12 = ROM $09000 | | $6E03 = ROM $01800 | $6E13 = ROM $09800 | | $6E04 = ROM $02000 | $6E14 = ROM $0A000 | | $6E05 = ROM $02800 | $6E15 = ROM $0A800 | | $6E06 = ROM $03000 | $6E16 = ROM $0B000 | | $6E07 = ROM $03800 | $6E17 = ROM $0B800 | | $6E08 = ROM $04000 | $6E18 = ROM $0C000 | | $6E09 = ROM $04800 | $6E19 = ROM $0C800 | | $6E0A = ROM $05000 | $6E1A = ROM $0D000 | | $6E0B = ROM $05800 | $6E1B = ROM $0D800 | | $6E0C = ROM $06000 | $6E1C = ROM $0E000 | | $6E0D = ROM $06800 | $6E1D = ROM $0E800 | | $6E0E = ROM $07000 | $6E1E = ROM $0F000 | | $6E0F = ROM $07800 | $6E1F = ROM $0F800 | +--------------------+--------------------+ +-----------------------------------------+ | Middle bank region: 1.5K, $F800-$FDFF | +--------------------+--------------------+ | $6F10 = ROM $18000 | $6F18 = ROM $1C000 | | $6F11 = ROM $18800 | $6F19 = ROM $1C800 | | $6F12 = ROM $19000 | $6F1A = ROM $1D000 | | $6F13 = ROM $19800 | $6F1B = ROM $1D800 | | $6F14 = ROM $1A000 | $6F1C = ROM $1E000 | | $6F15 = ROM $1A800 | $6F1D = ROM $1E800 | | $6F16 = ROM $1B000 | $6F1E = ROM $1F000 | | $6F17 = ROM $1B800 | $6F1F = ROM $1F800 | +--------------------+--------------------+ +-----------------------------------------------------------------------------------+ | Upper bank region: 256 bytes, $FE00-$FEFF | +--------------------+--------------------+--------------------+--------------------+ | $6C00 = ROM $10000 | $6C40 = ROM $14000 | $6C80 = ROM $18000 | $6CC0 = ROM $1C000 | | $6C01 = ROM $10100 | $6C41 = ROM $14100 | $6C81 = ROM $18100 | $6CC1 = ROM $1C100 | | $6C02 = ROM $10200 | $6C42 = ROM $14200 | $6C82 = ROM $18200 | $6CC2 = ROM $1C200 | | $6C03 = ROM $10300 | $6C43 = ROM $14300 | $6C83 = ROM $18300 | $6CC3 = ROM $1C300 | | $6C04 = ROM $10400 | $6C44 = ROM $14400 | $6C84 = ROM $18400 | $6CC4 = ROM $1C400 | | $6C05 = ROM $10500 | $6C45 = ROM $14500 | $6C85 = ROM $18500 | $6CC5 = ROM $1C500 | | $6C06 = ROM $10600 | $6C46 = ROM $14600 | $6C86 = ROM $18600 | $6CC6 = ROM $1C600 | | $6C07 = ROM $10700 | $6C47 = ROM $14700 | $6C87 = ROM $18700 | $6CC7 = ROM $1C700 | | $6C08 = ROM $10800 | $6C48 = ROM $14800 | $6C88 = ROM $18800 | $6CC8 = ROM $1C800 | | $6C09 = ROM $10900 | $6C49 = ROM $14900 | $6C89 = ROM $18900 | $6CC9 = ROM $1C900 | | $6C0A = ROM $10A00 | $6C4A = ROM $14A00 | $6C8A = ROM $18A00 | $6CCA = ROM $1CA00 | | $6C0B = ROM $10B00 | $6C4B = ROM $14B00 | $6C8B = ROM $18B00 | $6CCB = ROM $1CB00 | | $6C0C = ROM $10C00 | $6C4C = ROM $14C00 | $6C8C = ROM $18C00 | $6CCC = ROM $1CC00 | | $6C0D = ROM $10D00 | $6C4D = ROM $14D00 | $6C8D = ROM $18D00 | $6CCD = ROM $1CD00 | | $6C0E = ROM $10E00 | $6C4E = ROM $14E00 | $6C8E = ROM $18E00 | $6CCE = ROM $1CE00 | | $6C0F = ROM $10F00 | $6C4F = ROM $14F00 | $6C8F = ROM $18F00 | $6CCF = ROM $1CF00 | | $6C10 = ROM $11000 | $6C50 = ROM $15000 | $6C90 = ROM $19000 | $6CD0 = ROM $1D000 | | $6C11 = ROM $11100 | $6C51 = ROM $15100 | $6C91 = ROM $19100 | $6CD1 = ROM $1D100 | | $6C12 = ROM $11200 | $6C52 = ROM $15200 | $6C92 = ROM $19200 | $6CD2 = ROM $1D200 | | $6C13 = ROM $11300 | $6C53 = ROM $15300 | $6C93 = ROM $19300 | $6CD3 = ROM $1D300 | | $6C14 = ROM $11400 | $6C54 = ROM $15400 | $6C94 = ROM $19400 | $6CD4 = ROM $1D400 | | $6C15 = ROM $11500 | $6C55 = ROM $15500 | $6C95 = ROM $19500 | $6CD5 = ROM $1D500 | | $6C16 = ROM $11600 | $6C56 = ROM $15600 | $6C96 = ROM $19600 | $6CD6 = ROM $1D600 | | $6C17 = ROM $11700 | $6C57 = ROM $15700 | $6C97 = ROM $19700 | $6CD7 = ROM $1D700 | | $6C18 = ROM $11800 | $6C58 = ROM $15800 | $6C98 = ROM $19800 | $6CD8 = ROM $1D800 | | $6C19 = ROM $11900 | $6C59 = ROM $15900 | $6C99 = ROM $19900 | $6CD9 = ROM $1D900 | | $6C1A = ROM $11A00 | $6C5A = ROM $15A00 | $6C9A = ROM $19A00 | $6CDA = ROM $1DA00 | | $6C1B = ROM $11B00 | $6C5B = ROM $15B00 | $6C9B = ROM $19B00 | $6CDB = ROM $1DB00 | | $6C1C = ROM $11C00 | $6C5C = ROM $15C00 | $6C9C = ROM $19C00 | $6CDC = ROM $1DC00 | | $6C1D = ROM $11D00 | $6C5D = ROM $15D00 | $6C9D = ROM $19D00 | $6CDD = ROM $1DD00 | | $6C1E = ROM $11E00 | $6C5E = ROM $15E00 | $6C9E = ROM $19E00 | $6CDE = ROM $1DE00 | | $6C1F = ROM $11F00 | $6C5F = ROM $15F00 | $6C9F = ROM $19F00 | $6CDF = ROM $1DF00 | | $6C20 = ROM $12000 | $6C60 = ROM $16000 | $6CA0 = ROM $1A000 | $6CE0 = ROM $1E000 | | $6C21 = ROM $12100 | $6C61 = ROM $16100 | $6CA1 = ROM $1A100 | $6CE1 = ROM $1E100 | | $6C22 = ROM $12200 | $6C62 = ROM $16200 | $6CA2 = ROM $1A200 | $6CE2 = ROM $1E200 | | $6C23 = ROM $12300 | $6C63 = ROM $16300 | $6CA3 = ROM $1A300 | $6CE3 = ROM $1E300 | | $6C24 = ROM $12400 | $6C64 = ROM $16400 | $6CA4 = ROM $1A400 | $6CE4 = ROM $1E400 | | $6C25 = ROM $12500 | $6C65 = ROM $16500 | $6CA5 = ROM $1A500 | $6CE5 = ROM $1E500 | | $6C26 = ROM $12600 | $6C66 = ROM $16600 | $6CA6 = ROM $1A600 | $6CE6 = ROM $1E600 | | $6C27 = ROM $12700 | $6C67 = ROM $16700 | $6CA7 = ROM $1A700 | $6CE7 = ROM $1E700 | | $6C28 = ROM $12800 | $6C68 = ROM $16800 | $6CA8 = ROM $1A800 | $6CE8 = ROM $1E800 | | $6C29 = ROM $12900 | $6C69 = ROM $16900 | $6CA9 = ROM $1A900 | $6CE9 = ROM $1E900 | | $6C2A = ROM $12A00 | $6C6A = ROM $16A00 | $6CAA = ROM $1AA00 | $6CEA = ROM $1EA00 | | $6C2B = ROM $12B00 | $6C6B = ROM $16B00 | $6CAB = ROM $1AB00 | $6CEB = ROM $1EB00 | | $6C2C = ROM $12C00 | $6C6C = ROM $16C00 | $6CAC = ROM $1AC00 | $6CEC = ROM $1EC00 | | $6C2D = ROM $12D00 | $6C6D = ROM $16D00 | $6CAD = ROM $1AD00 | $6CED = ROM $1ED00 | | $6C2E = ROM $12E00 | $6C6E = ROM $16E00 | $6CAE = ROM $1AE00 | $6CEE = ROM $1EE00 | | $6C2F = ROM $12F00 | $6C6F = ROM $16F00 | $6CAF = ROM $1AF00 | $6CEF = ROM $1EF00 | | $6C30 = ROM $13000 | $6C70 = ROM $17000 | $6CB0 = ROM $1B000 | $6CF0 = ROM $1F000 | | $6C31 = ROM $13100 | $6C71 = ROM $17100 | $6CB1 = ROM $1B100 | $6CF1 = ROM $1F100 | | $6C32 = ROM $13200 | $6C72 = ROM $17200 | $6CB2 = ROM $1B200 | $6CF2 = ROM $1F200 | | $6C33 = ROM $13300 | $6C73 = ROM $17300 | $6CB3 = ROM $1B300 | $6CF3 = ROM $1F300 | | $6C34 = ROM $13400 | $6C74 = ROM $17400 | $6CB4 = ROM $1B400 | $6CF4 = ROM $1F400 | | $6C35 = ROM $13500 | $6C75 = ROM $17500 | $6CB5 = ROM $1B500 | $6CF5 = ROM $1F500 | | $6C36 = ROM $13600 | $6C76 = ROM $17600 | $6CB6 = ROM $1B600 | $6CF6 = ROM $1F600 | | $6C37 = ROM $13700 | $6C77 = ROM $17700 | $6CB7 = ROM $1B700 | $6CF7 = ROM $1F700 | | $6C38 = ROM $13800 | $6C78 = ROM $17800 | $6CB8 = ROM $1B800 | $6CF8 = ROM $1F800 | | $6C39 = ROM $13900 | $6C79 = ROM $17900 | $6CB9 = ROM $1B900 | $6CF9 = ROM $1F900 | | $6C3A = ROM $13A00 | $6C7A = ROM $17A00 | $6CBA = ROM $1BA00 | $6CFA = ROM $1FA00 | | $6C3B = ROM $13B00 | $6C7B = ROM $17B00 | $6CBB = ROM $1BB00 | $6CFB = ROM $1FB00 | | $6C3C = ROM $13C00 | $6C7C = ROM $17C00 | $6CBC = ROM $1BC00 | $6CFC = ROM $1FC00 | | $6C3D = ROM $13D00 | $6C7D = ROM $17D00 | $6CBD = ROM $1BD00 | $6CFD = ROM $1FD00 | | $6C3E = ROM $13E00 | $6C7E = ROM $17E00 | $6CBE = ROM $1BE00 | $6CFE = ROM $1FE00 | | $6C3F = ROM $13F00 | $6C7F = ROM $17F00 | $6CBF = ROM $1BF00 | $6CFF = ROM $1FF00 | +--------------------+--------------------+--------------------+--------------------+
Likewise, accessing the following hotspots will select the indicated RAM at the indicated region:
+---------------------------------------+ | Lower bank region: 2K, $F000-$F7FF | +-------------------+-------------------+ | $6E40 = RAM $0000 | $6E48 = RAM $4000 | | $6E41 = RAM $0800 | $6E49 = RAM $4800 | | $6E42 = RAM $1000 | $6E4A = RAM $5000 | | $6E43 = RAM $1800 | $6E4B = RAM $5800 | | $6E44 = RAM $2000 | $6E4C = RAM $6000 | | $6E45 = RAM $2800 | $6E4D = RAM $6800 | | $6E46 = RAM $3000 | $6E4E = RAM $7000 | | $6E47 = RAM $3800 | $6E4F = RAM $7800 | +-------------------+-------------------+ +---------------------------------------+ | Middle bank region: 1.5K, $F800-$FDFF | +-------------------+-------------------+ | $6F40 = RAM $0000 | $6F48 = RAM $4000 | | $6F41 = RAM $0800 | $6F49 = RAM $4800 | | $6F42 = RAM $1000 | $6F4A = RAM $5000 | | $6F43 = RAM $1800 | $6F4B = RAM $5800 | | $6F44 = RAM $2000 | $6F4C = RAM $6000 | | $6F45 = RAM $2800 | $6F4D = RAM $6800 | | $6F46 = RAM $3000 | $6F4E = RAM $7000 | | $6F47 = RAM $3800 | $6F4F = RAM $7800 | +-------------------+-------------------+ +-------------------------------------------------------------------------------+ | Upper bank region: 256 bytes, $FE00-$FEFF | +-------------------+-------------------+-------------------+-------------------+ | $6D00 = RAM $0000 | $6D20 = RAM $2000 | $6D40 = RAM $4000 | $6D60 = RAM $6000 | | $6D01 = RAM $0100 | $6D21 = RAM $2100 | $6D41 = RAM $4100 | $6D61 = RAM $6100 | | $6D02 = RAM $0200 | $6D22 = RAM $2200 | $6D42 = RAM $4200 | $6D62 = RAM $6200 | | $6D03 = RAM $0300 | $6D23 = RAM $2300 | $6D43 = RAM $4300 | $6D63 = RAM $6300 | | $6D04 = RAM $0400 | $6D24 = RAM $2400 | $6D44 = RAM $4400 | $6D64 = RAM $6400 | | $6D05 = RAM $0500 | $6D25 = RAM $2500 | $6D45 = RAM $4500 | $6D65 = RAM $6500 | | $6D06 = RAM $0600 | $6D26 = RAM $2600 | $6D46 = RAM $4600 | $6D66 = RAM $6600 | | $6D07 = RAM $0700 | $6D27 = RAM $2700 | $6D47 = RAM $4700 | $6D67 = RAM $6700 | | $6D08 = RAM $0800 | $6D28 = RAM $2800 | $6D48 = RAM $4800 | $6D68 = RAM $6800 | | $6D09 = RAM $0900 | $6D29 = RAM $2900 | $6D49 = RAM $4900 | $6D69 = RAM $6900 | | $6D0A = RAM $0A00 | $6D2A = RAM $2A00 | $6D4A = RAM $4A00 | $6D6A = RAM $6A00 | | $6D0B = RAM $0B00 | $6D2B = RAM $2B00 | $6D4B = RAM $4B00 | $6D6B = RAM $6B00 | | $6D0C = RAM $0C00 | $6D2C = RAM $2C00 | $6D4C = RAM $4C00 | $6D6C = RAM $6C00 | | $6D0D = RAM $0D00 | $6D2D = RAM $2D00 | $6D4D = RAM $4D00 | $6D6D = RAM $6D00 | | $6D0E = RAM $0E00 | $6D2E = RAM $2E00 | $6D4E = RAM $4E00 | $6D6E = RAM $6E00 | | $6D0F = RAM $0F00 | $6D2F = RAM $2F00 | $6D4F = RAM $4F00 | $6D6F = RAM $6F00 | | $6D10 = RAM $1000 | $6D30 = RAM $3000 | $6D50 = RAM $5000 | $6D70 = RAM $7000 | | $6D11 = RAM $1100 | $6D31 = RAM $3100 | $6D51 = RAM $5100 | $6D71 = RAM $7100 | | $6D12 = RAM $1200 | $6D32 = RAM $3200 | $6D52 = RAM $5200 | $6D72 = RAM $7200 | | $6D13 = RAM $1300 | $6D33 = RAM $3300 | $6D53 = RAM $5300 | $6D73 = RAM $7300 | | $6D14 = RAM $1400 | $6D34 = RAM $3400 | $6D54 = RAM $5400 | $6D74 = RAM $7400 | | $6D15 = RAM $1500 | $6D35 = RAM $3500 | $6D55 = RAM $5500 | $6D75 = RAM $7500 | | $6D16 = RAM $1600 | $6D36 = RAM $3600 | $6D56 = RAM $5600 | $6D76 = RAM $7600 | | $6D17 = RAM $1700 | $6D37 = RAM $3700 | $6D57 = RAM $5700 | $6D77 = RAM $7700 | | $6D18 = RAM $1800 | $6D38 = RAM $3800 | $6D58 = RAM $5800 | $6D78 = RAM $7800 | | $6D19 = RAM $1900 | $6D39 = RAM $3900 | $6D59 = RAM $5900 | $6D79 = RAM $7900 | | $6D1A = RAM $1A00 | $6D3A = RAM $3A00 | $6D5A = RAM $5A00 | $6D7A = RAM $7A00 | | $6D1B = RAM $1B00 | $6D3B = RAM $3B00 | $6D5B = RAM $5B00 | $6D7B = RAM $7B00 | | $6D1C = RAM $1C00 | $6D3C = RAM $3C00 | $6D5C = RAM $5C00 | $6D7C = RAM $7C00 | | $6D1D = RAM $1D00 | $6D3D = RAM $3D00 | $6D5D = RAM $5D00 | $6D7D = RAM $7D00 | | $6D1E = RAM $1E00 | $6D3E = RAM $3E00 | $6D5E = RAM $5E00 | $6D7E = RAM $7E00 | | $6D1F = RAM $1F00 | $6D3F = RAM $3F00 | $6D5F = RAM $5F00 | $6D7F = RAM $7F00 | +-------------------+-------------------+-------------------+-------------------+
Of course, we probably wouldn't want to refer to all of those individual addresses to trigger a bank switch. Instead, we'd most likely do something like the following (in assembly):
low_ROM_bank = $6E00 ; LDX desired_bank_number LDA low_ROM_bank,X
I won't attempt to describe any of the other ways that a bank switch can be triggered in the 4A50 scheme.
Problem 1: Organizing the Memory
--------------------------------
Before we can add support for 4A50 bankswitching to batari Basic, there are a number of problems, issues, or questions that we must resolve. The first question is, how should we organize the memory in the ROM image?
When writing an Atari 2600 program in assembly language, we must tell the assembler where the code is supposed to go in the Atari's memory. Since the Atari 2600 doesn't *have* any built-in memory for storing programs the way a computer does, and instead uses plug-in ROM cartridges that occupy a specific address range, there really isn't much choice of where to put the programs-- the ROM must always start at $F000 (or if it's a 2K ROM, it can start at either $F000 or $F800).
With a bankswitched cartridge, things aren't so simple, because the banks must occupy consecutive memory locations within the physical ROM image, but we also need the addresses within each bank to conform to wherever the 6507 CPU will see them when we switch to that bank. Fortunately, the DASM assembler has an ORG statement for defining the physical address within the ROM image, and a RORG statement for defining the logical address of the code. With a 2K or 4K ROM image, the ORG and RORG addresses can be the same, in which case we could just omit any RORG statements. But with bankswitching, we need to use both types of statements.
For example, let's consider a 16K cartridge that uses F6 bankswitching. If we want the 16K ROM image to end at address $FFFF, then we start at address $C000. But in F6 bankswitching, each bank is a 4K segment that gets switched in at address $F000. Thus, we could use the following ORG and RORG statements:
ORG $C000; Start of 1st 4K bank RORG $F000; Each 4K bank will be accessed at $F000 ; ORG $D000; Start of 2nd 4K bank RORG $F000 ; ORG $E000; Start of 3rd 4K bank RORG $F000 ; ORG $F000; Start of 4th 4K bank RORG $F000
We could actually begin with an ORG statement of $0000, or $1000, or anything else, as long as we use RORG statements that begin each 4K bank at $F000, or some address equivalent to $F000 in the 6507's 13-bit address space. For example, some programmers like to use $1000 for the first RORG statement, $3000 for the second RORG statement, $5000 for the third RORG statement, etc., so each bank contains unique logical addresses. However, 4A50 bankswitching has too many banks for us to assign unique logical addresses to each one, so we'll just reuse the same logical addresses as appropriate.
In some bankswitching schemes, a bank can be switched into only one possible locations, so there's no choice of what RORG addresses to use. But in other bankswitching schemes, a bank can be switched into two or more possible locations, so there are two or more possible RORG addresses for that bank. In the 4A50 bankswitching scheme, most of the banks or pages must be switched into specific locations (as described previously), but some of the banks or pages could be switched into either of two different locations. We need to know which of these locations will be used *before* we compile the program, so the DASM assembler will use the correct logical addresses.
To keep things as simple as possible, I'm assuming that the 24K of ROM which *can* be accessed in the middle bank region, *will* be accessed there. That way, if someone decides to put program code in those segments, it will execute correctly when switched into the middle bank region. This won't prevent anyone from putting *data* in those segments and accessing them one page at a time in the upper bank region, as long as they refer to the data using addresses that fall within the upper bank region. Furthermore, if we're careful about how we let the programmer declare the start of a new bank, then the programmer can choose whether certain portions of code or data will be accessed in the middle bank region or upper bank region. In any case, our *default* memory configuration will be as follows:
ORG $00000; Start of 1st 64K (32 banks of 2K) RORG $F000; Each 2K bank will be accessed at $F000 ; ORG $00800; 2nd bank of 1st 64K RORG $F000 ; ; etc. ; ORG $0F800; Last bank of 1st 64K RORG $F000 ; ;---------------------------------------------------------------- ; ORG $10000; Start of 1st half of 2nd 64K (128 pages) RORG $FE00; Each page will be accessed at $FE00 ; ORG $10100; 2nd page of 2nd 64K RORG $FE00 ; ; etc. ; ORG $17F00; Last page of 1st half of 2nd 64K RORG $FE00 ; ;---------------------------------------------------------------- ; ORG $18000; Start of 2nd half of 2nd 64K (16 banks of 2K) RORG $F800; 1st 1.5K of each bank will be accessed at $F800 ; ORG $18600; 1st page of leftover ROM RORG $FE00; Each leftover page will be accessed at $FE00 ; ORG $18700; 2nd page of leftover ROM RORG $FE00 ; ORG $18800; 2nd bank of 2nd half of 2nd 64K RORG $F800 ; ORG $18E00; 1st leftover page of 2nd bank RORG $FE00 ; ORG $18F00; 2nd leftover page of 2nd bank RORG $FE00 ; ; etc. ; ORG $1F800; Last bank of 2nd 64K RORG $F800 ; ORG $1FE00; 1st leftover page of last bank RORG $FE00 ; ;---------------------------------------------------------------- ; ORG $1FF00; Last page of ROM RORG $FF00; Fixed at $FF00 ; ORG $1FFFA; Beginning of 6502 vectors RORG $FFFA ; NMI_Vector WORD $4A50; Identifies this as a 4A50 cartridge ; RES_Vector WORD Boot_Up; Points to the program's "Boot_Up" routine ; IRQ_Vector WORD BRK_Handler; Points to an optional "BRK_Handler" routine ; END
The specs say $1FFF8-$1FFF9 should contain the 4A50 version number, stored lo-byte/hi-byte. The current version number is $0001, but supercat has stated that it's being ignored right now, so I've simply omitted it above. Furthermore, supercat has stated that the version number, and possibly also the $4A50 identifier, might get moved somewhere below $1FF00, to avoid taking up any more of the last 256 bytes than absolutely necessary, since those are the only bytes of ROM which are always accessible to all banks and pages within the cartridge. The names of the "Boot_Up" and "BRK_Handler" routines are given for descriptive purposes only, and the "BRK_Handler" routine is optional anyway, since most programs just put the same address in both the RES and IRQ vectors (and sometimes in the NMI vector as well).
Obviously, we'll want the actual organization of memory to be as transparent to batari Basic programmers as possible, so they can write programs without having to worry about these sorts of details-- after all, that's probably one reason why they're programming in batari Basic instead of in assembly language!
On the other hand, anyone who's writing a bankswitched program-- whether in batari Basic or assembly-- should be at least *somewhat* aware of how the banks are organized in whichever bankswitching scheme they're using, to help them code their program as efficiently as possible. With 4A50 bankswitching, this will be especially important.
Up next: The Includes File and the Include Files!
Michael
Edited by SeaGtGruff, Mon Feb 11, 2008 2:10 AM.
















