I don't think POP is running in double high res, seems to be "normal" high resolution.
Yes, only the credits are shown in double hires (560x192 pixels, 16 colours). The game itself uses standard hires (280x192 pixels, 6 colours).
I will have to find where in 0x00 page is the bank switching routine.
Oops, sorry but that was meant to be an example of how one might do it. In fact there are many different ways how to accomplish this task. You could also place a routine at $400. Since the softswitches $c000 and $c001 (80 column store = window at $400..$7ff) override the other softswitches the processor can safely access $400..$7ff of the main ram while you flip around the rest of $200..$bfff at the same time. Now file 'MASTER.S' says at the beginning
org = $f880
* M A S T E R
* (3.5" version)
* Sits in main l.c.
This means that this part of the program is put at the very end of the language card in the main memory on the motherboard. This is a safe place for switching $200..$bfff in and out, and this is exactly what POP does.
Well, for a better support it might be a good idea if you could tell us whether you are familiar with any 6502 based home computer system like the C64, Atari XL, BBC Micro etc. It might be easier to explain things if we can find some common ground. For example, if you are familiar with the Commodore 1541 floppy disk drive then explaining the AppleII disk drive is rather simple.
Well, here is a list of things I recommend to do (and which you have probably done already
- Download the game as disk images (*.dsk). I know of two versions, one working with two drives (my personal choice) and another which comes with an additional boot disk. Note: both versions need three disks to store the whole game. Page 4 you mentioned of popsource009.pdf states that the total disk space is about 252.5K. A single AppleII floppy disk will contain only 140K. So you will need at least 2 disks for your final program.
- Get yourself an AppleII emulator. Look for one that will allow you to save the current state of the VM as well as reloading it. This way you cannot only cheat during the game (naughty, naughty!
) but study your program again and again until you find out what's going wrong. Of course, the emulator should come with a debugger..
- Play the game. Just to get a feel for it. It's fun.
- Additional material about the AppleII you may find useful:
Watch out for the "AppleIIe Reference Manual" as well as "Inside the IIe". These books probably cover all you need to know about the AppleIIe. And, of course, you can always ask.
Now the tricky bit:
As teamtempest said: the source files of POP were not assembled in one go but separately. This was the usual approach in those days. I think I once read somewhere that it took Andrew Braybrook, author of the famous C64 game 'Uridium', about half an hour(!) to assemble the source file for his game. Then he would have to look for bugs, start the editor, load the source file, make some corrections, and start the whole process again. No wonder why a great amount of development then was done using a pencil and a sheet of paper...
What's more: since the whole game will take up as much as 252.5K you cannot just create one single executable program. As a matter of fact, there is not even something you could call an executable file. These things did/do not exist on the AppleII. All you have is a bootable floppy disk image. Of course, there were several disk operating systems like DOS3.3, the successor ProDOS and ApplePascal (= UCSD Pascal), but they all came with their own file system and all of them had to be loaded from disk first. There is no DOS stored in the ROM of the AppleII. The old DOS3.3 was loaded during the boot process into $9600..$bfff. ProDOS, more advanced, would load itself into the language card just like the ApplePascal system. Games, on the other hand, would use every single byte of the memory which usually meant to throw away the file system and load the sectors directly from disk bypassing the need for any directory or file allocation table etc. POP works the same way. There is no file system on the disk. Data and program are stored in specific sectors and loaded via the RWTS. Take a look at the following code:
First, the program will tell the RWTS from which disk to load (as there are two disks). Second, POP tells the RWTS that it wants to load from track #2. Then it calls the RWTS (named rw18 here which means 'read-write-18 sectors' indicating a special disk layout at GCR level). The following bytes are parameters. The routine rw18 will pop the return address and use this as a pointer to the parameter list. The first byte is the rwts command: read a group of sectors. In this case the command is followed by a list of addresses (high byte only) which correspond to the sectors on the disk: load the first sector to address $e000, load the second sector to address $e100 ... . The NULL-byte 00 means: don't load this sector. The list always contains 18 addresses since the (special) POP track also contains 18 sectors. This is a problem, as mentioned before, because standard disk images (*.dsk) will only allow 16 sectors per track.
After the routine rw18 has finished reading, it will push back the return address incremented by the total number of parameter list bytes (here: 19) and jump back to the program.
What does this mean for you?
1) You cannot just assemble the source files and expect them to run. Instead you must place the object code inside a disk image and load it from disk via your own RWTS.
2) Your assembler must support two important pseudo instructions: OBJ and SAVE (can be named differently)
While ORG will allow you to assemble a source file for a specific address, OBJ will actually write the generated object code to this address. Note: the addresses of ORG and OBJ can not only but must be different! SAVE will allow you to store some part of the virtual memory of the assembler in a file. For example:
SAVE "POP disk image 1.dsk", $0, $22fff
This will store the content of the virtual memory $0..$22fff into a file "POP disk image 1.dsk". You have to use this instruction at least twice to create two disk images. This is the easiest and fastest way to put your program onto the disk. If your assembler does not support instructions like these: throw it away and get another one. The following is an actual example:
; boot sector
; this boot program will load
; sectors 1..15 to addresses $900..$17ff
; look here: the code will be assembled to be used at address $800
; but it will be written at the very beginning of the virtual memory
obj $00000 ; address on DOS-disk ==> track #0, sector #0
hex 01 ; load one sector
; reset 6502
; reset softswitches
sta $c000 ; disable 80col store
sta $c002 ; read main 47.5
sta $c004 ; write main 47.5
sta $c006 ; enable slot $c100
sta $c008 ; read main ZP+LC
sta $c00c ; display 40col
sta $c00e ; disable altcharset
bit $c05f ; annunciator #3 on
bit $c051 ; text
bit $c052 ; no mixed
bit $c054 ; page 1
bit $c056 ; lores
; clear text screen
lda #32 + $80
?0: sta $400, x
sta $500, x
sta $600, x
sta $700, x
; load basic system
lda #$60 ; patch RTS
sta boot + 1
lda $2b ; slot
sta ?11 + 2 ; patch JSR instruction
?10: ldy #14 ; load 15 sectors
lda .boot_sector, y
sta $3d ; sector
sta $27 ; address high
?11: jsr $ff5c ; read sector
dec ?10 + 1 ; dec number of sectors
; clear memory
?20: sta $0, x
sta $100, x
sta $200, x
sta $300, x
sta $c050 ; switch on lores
; fill screen with magenta pixels to show we are here..
lda #$11 ; colour = magenta
?30: sta $400, x
sta $500, x
sta $600, x
sta $700, x
.endless: jmp .endless ; example ends here
.boot_sector: hex 0d0b09070503010e0c0a080604020f
even 256 ; fill rest of sector with 0
; here you will usually find the RWTS
hex 0101010101010101 ; just to indicate first sector
org $0a00 ; will be loaded at address $a00
obj $00200 ; but is the second sector on the disk
hex 0202020202020202 ; just to indicate second sector
org $0b00 ; ...
; end of track #0
sav "test.dsk", 0, $22fff ; save the virtual memory as a disk image (140kb)
This example will load the whole track #0 at $800..$17ff with the first sector (boot sector) being loaded by the autostart ROM and the rest using the boot rom of the floppy disk drive. Note: this is just one way of doing it. There are lots. Unfortunately, the RWTS of POP is not included in the source files. And you cannot use the calls to rw18 since you do not have disk images that work with 18 sectors.
To sum up (again, sorry for being repetitive):
If you want to assemble an executable (= bootable) disk image, it's good to have an assembler that will offer pseudo instructions which will allow easy creation of a disk image. In addition, you definitely need a proper RWTS to load the program and the data from disk. Otherwise your program will not work. To achieve this, however, you must determine where to put the RWTS in memory (address and length) first. I'm afraid there are a few steps to go before you can even see the credits on the screen. But it's manageable.