6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 12:04 pm

All times are UTC




Post new topic Reply to topic  [ 37 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Tue Jul 10, 2012 10:55 pm 
Offline

Joined: Tue Jul 10, 2012 10:42 pm
Posts: 7
As many here already know: the source code of Prince of Persia for Apple II has been released some time ago:

https://github.com/jmechner/Prince-of-Persia-Apple-II/

Unfortunately so far nothing has been done with it which is a very sad thing for anybody that loves software.

I want to compile it and run it in an emulator....I have tried to compile it using cc65 in order to generate a disk image an load it in an emulator but so far no success since some of the assembly keyword are not recognized by cc65: This seems to be a dead end.

Since 6502 has a relatively small set of instructions I could write an emulator that would be dedicated to running POP but that seems overkill for now (even thought I would be fun and would help to understand the architecture a great deal).

For now I would like to just compile and run in an emulator:

I wonder if there is someone here with experience in Apple II development that would give me pointers:

1. What assembler should I use to compile the assembler to machine code ?
2. Can it even be done on an Apple II ? Or the dev process involved developing on an other platform and cross compiling ? I was unable to find something in Jordan Mechner's note that suggest he cross-compiled.

Any kind of pointer would be welcome....


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 1:28 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8509
Location: Midwestern USA
fabiensanglard wrote:
As many here already know: the source code of Prince of Persia for Apple II has been released some time ago:

https://github.com/jmechner/Prince-of-Persia-Apple-II/

Unfortunately so far nothing has been done with it which is a very sad thing for anybody that loves software.

I want to compile it and run it in an emulator....I have tried to compile it using cc65 in order to generate a disk image an load it in an emulator but so far no success since some of the assembly keyword are not recognized by cc65: This seems to be a dead end.

Since 6502 has a relatively small set of instructions I could write an emulator that would be dedicated to running POP but that seems overkill for now (even thought I would be fun and would help to understand the architecture a great deal).

For now I would like to just compile and run in an emulator:

I wonder if there is someone here with experience in Apple II development that would give me pointers:

1. What assembler should I use to compile the assembler to machine code ?
2. Can it even be done on an Apple II ? Or the dev process involved developing on an other platform and cross compiling ? I was unable to find something in Jordan Mechner's note that suggest he cross-compiled.

Any kind of pointer would be welcome....

First, welcome to the forum.

As for an emulator, the one that is popular around here is Michal Kowalski's program. You should be able to edit and assemble (not compile) the Prince Of Persia source code in this simulator. As for testing the object code, you probably need either an Apple II simulator or the actual hardware. The Kowalski simulator's I/O is a generic console and no mass storage.

Good luck!

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 2:43 am 
Offline

Joined: Tue Jul 10, 2012 10:42 pm
Posts: 7
Thanks BigDumbDinosaur.

I just tried Michal Kowalski's program but it seems the Prince of Persia assembly is not supported:

- * comments lines are not recognized.
- org directive is not supported (only .org is).

I started to fix the files manually (removing the comments and changing "org" directives to the correct ".org" directive) but the assembler kept on failing and I had to remove more and more parts of the code...

Too bad Mechner did not mention what assembler he used....


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 2:49 am 
Offline
User avatar

Joined: Mon Aug 08, 2011 2:48 pm
Posts: 808
Location: Croatia
If org means where the code should be located, then you should replace it with *=


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 5:45 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hi Fabien - welcome!
I had a quick look in case I could massage the sources into a form suitable for ca65, but it looks like quite a challenge.
We see:
- dum and dend pseudo ops
- colon as a comment character
- * as a comment character
- ]byte as a valid identifier
- org and lst (without leading dot) pseudo ops
- usr pseudo op
- ds and db used with and without a quantity

Could it be Merlin assembler?

Cheers
Ed

Edit: maybe it's Merlin 8/16
Edit: Jordan says 'ProDos/Merlin'


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 7:24 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8509
Location: Midwestern USA
BigEd wrote:
Hi Fabien - welcome!
I had a quick look in case I could massage the sources into a form suitable for ca65, but it looks like quite a challenge.
We see:
- dum and dend pseudo ops
- colon as a comment character
- * as a comment character
- ]byte as a valid identifier
- org and lst (without leading dot) pseudo ops
- usr pseudo op
- ds and db used with and without a quantity

Could it be Merlin assembler?

Cheers
Ed

Edit: maybe it's Merlin 8/16
Edit: Jordan says 'ProDos/Merlin'

I thought it might be Merlin, but I don't recognize all of the syntax. Merlin for the Commodore 8-bitters was a bit idiosyncratic, as I (dimly) recall, but not to this extent.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 8:02 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Sounds like you need to pick a target assembler and write a translation script in something like NAWK to convert the source code into something that will assemble. Its better to translate automagically so all the code is changed consistently rather than doing it by hand and missing the odd bit here and there.

Its usually not that hard to convert assembler as its 'line' oriented (e.g. all the data for one instruction is one the same text line).

You have plenty of assemblers to pick from including Kowalski's, mine (http://www.obelisk.demon.co.uk/dev65/), Andre's and many more. Depends on which operating system you want to work on.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 10:16 am 
Offline

Joined: Tue Jun 26, 2012 6:18 pm
Posts: 26
Hi Fabien,

to answer your questions it would help if you could tell us what system you use for developing (Windows, Linux, ..) and what will be your target system (Apple//e ..).
fabiensanglard wrote:
2. Can it even be done on an Apple II ?
It was done on an AppleII but I do not recommend it. It will take you ages to assemble the source files while it takes a couple of seconds on a modern PC. Better use a cross assembler.
The big question is: how familiar are you with the Apple//e? To understand the code you need to know the Apple//e softswitches for bank switching by heart. The code uses 128kb and makes a lot of jumps from one bank to the other. Knowing the (slightly weird) AppleII hires graphics is also important. Note that double hires is only used for the credits while the game itself is running in standard hires. There is a problem when you want to load the game from disk. Either you are able to assemble a DOS 3.3 or ProDOS disk directly with your assembler (I personally don't know of any assembler that will do the trick) or you will have to use your own boot loader (so-called RWTS = read-write-track-sector). Unfortunately the POP source comes without the RWTS, although you will find a lot of calls to it. It was developed using a (then modern) 3.5" floppy disk drive, but was released for the Apple//e with a standard 5.1/4" disk drive. Even worse, the original RWTS was special in that way that it would store 18 sectors on a track whereas the standard DOS would only have 16. Some POP source files therefore deal with exactly that: how to use this proprietary format. In addition you will also notice that the source files exist twice. I'm afraid you must find out whether there are any differences and if so which one is the last and stable version. For this, you may want to use the POP disk images floating around somewhere in an emulator and compare the object code with a debugger.

If you have any questions: don't hesitate, just ask. I'm sure people will be able to help you with most of your problems. And don't forget, please, to inform us of your progress.

Cheers
Miles


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 11, 2012 10:57 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Very interesting project - I second the call for updates!

Also agree with Bitwise that any translation effort is best automated. I started with a handful of 'sed' commands before noticing the novel pseudo-ops mentioned above. I see there are several more - lup for looping, xc for 65c02, and so on. See
http://www.textfiles.com/apple/DOCUMENT ... rlin.docs2
and nearby files. (Which also tells me that ] is a marker for variables.)

It might be interesting to see what we're missing.

Cheers
Ed

The commands I tried before I got a grip on the magnitude of the task:
sed -i.orig 's/^\*/; */;s/lst/.list/;s/^\sorg/.org/;s/^:/; :/' *.S
/opt/cc65/bin/ca65 --feature labels_without_colons SOUND.S 2>&1 | head -33
rm *.S; rename s/.orig// *.orig


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 12, 2012 4:14 pm 
Offline

Joined: Tue Jul 10, 2012 10:42 pm
Posts: 7
For now I am trying to read the source code and understand the overall architecture. Some of the directive/pseudo-code are hard to decipher Especially the way the .S module communicate with each other:

The main loop is in MASTER.S:
https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/MASTER.S

It has a jump table at the beginning, (with org=$f880)

Code:
 jmp FIRSTBOOT
 jmp LOADLEVEL
 jmp RELOAD
 jmp LoadStage2
 jmp RELOAD

 jmp ATTRACTMODE
 jmp CUTPRINCESS
 jmp SAVEGAME
 jmp LOADGAME
 jmp DOSTARTGAME


It seems EQ.S (https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01%20POP%20Source/Source/EQ.S) references those methods but I cannot figure out how the assembler connect them:

Code:
master = $f880
dum master

_firstboot ds 3
_loadlevel ds 3
_reload ds 3
_loadstage2 ds 3
 ds 3


According to this document: http://www.cs.utah.edu/~schmelze/atari/atasm/atasm.pdf ds reserves space storage....What is the purpose of this ?

My understanding was that a label in .S file is still valid when the assembler assembles an other .S file. So it can replace a JMP/JSR with the location of the instruction. Those _LABEL ds 3 seem to be useless.....


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 12, 2012 4:43 pm 
Offline

Joined: Tue Jul 10, 2012 10:42 pm
Posts: 7
@Miles J:

To reply to your questions: I know next to nothing about Apple II or Apple //e. But:

1. It is a very sad thing to see the source code of a game of this magnitude and nothing done with it. This is the equivalent of Doom Source Code in a lot of regard. I believe that if it was provided with a working building toolchain many more people would be encouraged to try it and learn 6502.
2. I am a pretty decent C software developer with a taste for understanding things to the deep down. I see this a a really good exercice to increase my skills.

Anyway, if I can get this code to compile and run a lot of people will probably tinker with it.

The system needed to build is not a problem, I have a Mac that I can boot under Windows and if linux is needed it is just on VM away.

I am still split between trying to cross-compile or write something in C to assemble the source code into a bytecode with a virtual machine so the end result could run on a desktop machine. The label and 6502 instructions are pretty easy to understand but some of the assembler directives and inter .S communication are much more difficult since I do not have the programer manual explaining those.....


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 12, 2012 5:16 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hi Fabien
you can find Merlin docs at:
http://www.apple-iigs.info/doc/fichiers/merlin816.pdf
http://apple2.org.za/gswv/a2zine/Docs/MerlinManual.txt
http://www.textfiles.com/apple/DOCUMENT ... rlin.docs1
http://www.textfiles.com/apple/DOCUMENT ... rlin.docs2
http://www.textfiles.com/apple/DOCUMENT ... rlin.docs3
Cheers
Ed


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 12, 2012 6:15 pm 
Offline

Joined: Tue Jul 10, 2012 10:42 pm
Posts: 7
Holy grail !!!

Thanks :) !


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 12, 2012 9:02 pm 
Offline

Joined: Tue Jun 26, 2012 6:18 pm
Posts: 26
Hi Fabien!
fabiensanglard wrote:
I see this a a really good exercice to increase my skills.
It sure is. :)
fabiensanglard wrote:
I am still split between trying to cross-compile or write something in C to assemble the source code into a bytecode with a virtual machine so the end result could run on a desktop machine.
Please allow me to recommend cross-assembling first. The program might use self-modifying code which will not easily translate to bytecode. You also would have to convert the graphics, too, which in itself is a hard thing to do. Since you'll find a decent AppleII emulator on all platforms today (a lot of them written in Java) I wouldn't worry about a virtual machine as the emulator already is a virtual machine. :)
fabiensanglard wrote:
I know next to nothing about Apple II or Apple //e
Oookay... Where do we start? .. <scratch head> ..
The memory of the AppleII is basically organized like this: ($.... = hexadecimal = 0x.... in C)

$0000 - $00ff: zero page
$0100 - $01ff: stack
$0200 - $02ff: used as an input buffer by Applesoft (Basic) otherwise free
$0300 - $03ff: vectors are put here
$0400 - $07ff: text and low-resolution graphics display buffer page 1
$0800 - $0bff: text and low-resolution graphics display buffer page 2
$0c00 - $1fff: free
$2000 - $3fff: high-resolution graphics display buffer page 1
$4000 - $5fff: high-resolution graphics display buffer page 2
$6000 - $bfff: free
$c000 - $cfff: IO (and additional ROM)
$d000 - $ffff: ROM or language card RAM (s.b.)

Note: low-resolution is usually abbreviated to lores, and high-resolution is called hires.
Note: if you don't use the text display or the hires graphics display this memory is also free as long as you do not use certain peripheral devices, since they put some data between $400 and $7ff (in ram that is not displayed on screen).

If you want to switch from text display to hires display you need what is called a 'softswitch.' This is a switch (flip-flop etc) that gets activated by simply accessing a memory location assigned to it. For example, there are two softswitches to choose between text or graphics:
LDA $c050 will select graphics
LDA $c051 will select text
Note: you can also write
BIT $c050
or (in this case) also
STA $c050
it doesn't matter.

If you want hires you write
LDA $c057
For lores you would do
LDA $c056
Full screen mode is selected by
LDA $c052
Mixed mode (4 bottom lines of text)
LDA $c053

At the beginning of file 'MASTER.S' you will see a list with the following elements:
Code:
HIRESon = $c057
HIRESoff = $c056
PAGE2on = $c055
PAGE2off = $c054
MIXEDon = $c053
MIXEDoff = $c052
TEXTon = $c051
TEXToff = $c050
You also spot the 'PAGE2on' and 'PAGE2off.' In addition to the display mode you can select a dedicated memory area for display. (If you know the C64 then this is sort of writing a value to $d018). There are only two possibilities:
$0400 - $07ff: text and low-resolution graphics display buffer page 1
$0800 - $0bff: text and low-resolution graphics display buffer page 2
and
$2000 - $3fff: high-resolution graphics display buffer page 1
$4000 - $5fff: high-resolution graphics display buffer page 2
What POP does is it selects page 1 and then writes data (shapes etc) to page 2. Then it switches to page 2 and writes to page 1. This is known as 'double buffering' and is used to reduce flicker. See the following example:

Code:
*-------------------------------
*
* Credit line disappears
*
*-------------------------------
CleanScreen

* Switch to DHires page 2
* (credit line disappears)

 lda PAGE2on

* Copy DHires page 2 back to hidden page 1

 jsr copy2to1

* Display page 1

 lda PAGE2off
]rts rts
As seen before, the 6502 can only address memory from $0000 .. $ffff. This equals to 65536 bytes = 64 kilo bytes. Now the Apple//e (enhanced) and Apple//c came with more than 64kb. This was only possible using bank switching. This means that a certain area was assigned (at least) twice to different RAM/ROM chips. The original RAM chip (main memory) was found on the motherboard. while the additional 64kb were put in an extra chip and called auxiliary ram. This was necessary because the video generator could then access both chips simultaneously (2 bytes per clock cycle) to display the double high-resolution of 560x192. With only one chip the standard resolution (hires = 280x192) was restricted to one byte per clock cycle. The first cards that used this were video cards that could display 80 column text instead of 40. Here the same trick applies: two bytes are read, one from the text memory on the motherboard and one from the video card. The questions was how to integrate the additional ram into memory. The solution was simple (from a hardware designers point of view). First you would have to select a special bank switching mode: 80 column store. This is done by using
STA $c001
This time it only works with STA, not LDA or BIT. This is true for all softswitches between $c000 and $c00f.
STA $c000
will switch back to normal memory mode. During the 80 column store mode the softswitches $c054 and $c055 (page selector) do no longer select the display area but which memory the 6502 will see (read and write): either the memory on the motherboard (STA $c054) or the aux memory (STA $c055). If you select graphics display (STA $c050) and hires (STA $c057) then this will also apply to $2000..$3fff. Since the display selector is deactivated in this mode, text page 1 or hires page 1 will always be displayed (IIRC). For the first 80 column cards you only needed an additional 1kb. Later on this was expanded to a full 64kb. Since the 80 column mode only works with $400..$7ff and $2000..$3fff another method is needed to access the remaining memory.
STA $c003
does the trick. Almost. Using this softswitch you can access $200..$bfff of the aux ram for _read_ access.
STA $c002
will switch back to main ram.
STA $c005
will allow _write_ access to $200..$bfff of the aux ram
STA $c004
will switch back to main ram.
Now what happens when your program resides in main memory, say at address $6000, and you do
STA $c003
Your program will probably crash because the processor will also read the program data now from aux not main. Therefore $0000..$01ff are excluded because here you find the important zero page and also the stack. What you could do is, you could write a short program that resides in this area ($0000..$01ff) and loads from/stores to aux memory. Note: the 80column mode will override $c002.. So it is possible to access the aux mem at $6000 and the main mem at $400 at the same time. Best to think of these modes as separate windows into the memory that can overlap if wanted.
The area found at $d000 .. $ffff is special because you will find the ROM here as well as a ram extension known as language card (l.c. in POP). It was meant to be used as a replacement for the Integer Basic on old AppleIIs (e.g. with Applesoft Basic or Pascal) hence the name. To activate it you must select the lc card with softswitches between $c080 and $c08f)
LDA $c080 = read bank 2
LDA $c081 = (twice) write bank2, read rom 12
LDA $c082 = read rom 12
LDA $c083 = (twice) write/read bank 2
LDA $c088 = read bank 1
LDA $c089 = (twice) write bank1, read rom 12
LDA $c08a = read rom 12
LDA $c08b = (twice) write/read bank 1
twice means, well, doing it twice:
LDA $c081
LDA $c081
Since $d000..$ffff only offers room for 3kb but 4kb were wanted, the area $d000..$dfff was divided into two banks 1 and 2. That's what
RWBANK2 = $c083
RWBANK1 = $c08b
is for. See the example from the code:
Code:
* switch in bank 2

 bit RWBANK2
 bit RWBANK2 ;2nd 4k bank
This will select the second bank of the language card. Now take a look again at softswitches $c002..$c005. They will select the area $0200..$bfff. The remaining $0000..$01ff and $d000..$ffff can be selected using
STA $c008 = read/write main zp/stack + lc
STA $c009 = read/write aux zp/stack + lc
Note: with an additional 64kb there are in fact two lc cards. As long as your DOS resides in one of the language cards you can safely select the aux memory between $0200..$bfff. This is what POP does:
Code:
setaux sta RAMRDaux
 sta RAMWRTaux
 rts

setmain sta RAMRDmain
 sta RAMWRTmain
 rts

So much for now. HTH

Cheers
Miles


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 12, 2012 10:36 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Quote:
It has a jump table at the beginning, (with org=$f880)


Code:
jmp FIRSTBOOT
jmp LOADLEVEL
jmp RELOAD
jmp LoadStage2
jmp RELOAD

jmp ATTRACTMODE
jmp CUTPRINCESS
jmp SAVEGAME
jmp LOADGAME
jmp DOSTARTGAME



It seems EQ.S (https://github.com/jmechner/Prince-of-P ... ource/EQ.S) references those methods but I cannot figure out how the assembler connect them:


Code:
master = $f880
dum master

_firstboot ds 3
_loadlevel ds 3
_reload ds 3
_loadstage2 ds 3
ds 3



According to this document: http://www.cs.utah.edu/~schmelze/atari/atasm/atasm.pdf ds reserves space storage....What is the purpose of this ?

My understanding was that a label in .S file is still valid when the assembler assembles an other .S file. So it can replace a JMP/JSR with the location of the instruction. Those _LABEL ds 3 seem to be useless.....


Well...no. I have not studied the POP source code closely, but I think I can decipher this. MASTER.S starts with a jump table at $F880. Each entry is three bytes long (1 byte opcode and 2 bytes address). EQ.S defines a 'dummy section starting at $F880 (the start addresses match; this is important).

The DS pseudo op means "define storage". What it actually does is assign the current value of the program counter to the label preceeding it (if any) and then advances the program counter by whatever value follows it.

A Merlin 'dummy' section never generates code, but the value of any labels defined in it are available for use anywhere else. Usually a dummy section is used to define RAM memory space to be used for named variables of various sizes. Here it's being used for something else: to let other source files know jump table addresses without actually having to assemble the jump table. There's a one-for-one correspondence between the actual jump table (in MASTER.S) and the description of the jump table (in EQ.S). A separate source file can include (PUT) EQ.S to learn everything it needs to know about the actual jump table without the overhead of assembling any part of MASTER.S.

So it appears (still without my having read the whole thing) that at least one purpose of EQ.S is to communicate to other source files anything they need to know about other, seperately assembled, source files. Sort of manually created link file, maybe.

My $0.02.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 37 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 16 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: