[comp.sys.apple2] Xapple2

kanarick@bbn.com (Craig M. Kanarick) (03/06/90)

I just started writing an X application that would run all of
the old Apple ][+ software (][+ because that is what I have).  I
am interested in hearing from anyone who has performed a similar
exercise.  I am also willling to send mail to anyone who wants
to hear how I am going about it.

-- Craig

------------------------------------------------------------------------------
Craig M. Kanarick				"Do I love you?  Yes, I
kanarick@bbn.com				 love you.  All this talking,
		             			 talking, is only bravado..."
BBN Systems and Technologies Corporation	 - The Blue Nile
------------------------------------------------------------------------------

kanarick@bbn.com (Craig M. Kanarick) (03/07/90)

In article <53040@bbn.COM> I write:
>
>I just started writing an X application that would run all of
>the old Apple ][+ software (][+ because that is what I have).  I
>am interested in hearing from anyone who has performed a similar
>exercise.  I am also willling to send mail to anyone who wants
>to hear how I am going about it.
>
>-- Craig
>

Well, the response that I got from this posting was a little more than
I expected, so rather thatn mail back to all of you, I am just going
to post how I am going to do it.

Basically, I have written, in C, a 6502 emulator.  It has an array of
16-bit values, and is the memory of the Apple.  I also have 5 16-bit
registers, and a program counter.  Basically, the emulator is just a
big case statement, each branch being one 6502 instruction (yes, there
are a lot, because each instruction/addressing mode pair is a seperate
branch).  I am about halfway done with this part.  Essentially, I just
start by executing the instruction at memory[0] and continue down,
exectuting memory[program_counter].

When I get the emulator done, I will dupm the Apple ROM into my
Masscomp, and *poof*, I have an Apple.  Of course, I will have to trap
out any and all I/O, but this is not a big deal, since I only really
care about DOS, graphics, and maybe the paddle port.  Writing an X
interface is then the last step, also a rather mundane programming
task.  It shouldn't be too hard, no?  Just give me a few years.

One person has already volunteered to help, and I really appreciate that.
If anyone else would like to work on this project, let me know.  I am
doing this in my spare (yah, sure) time, and would love some help.  Maybe
we can really get this thing going...

-- Craig


------------------------------------------------------------------------------
Craig M. Kanarick				"Do I love you?  Yes, I
kanarick@bbn.com				 love you.  All this talking,
		             			 talking, is only bravado..."
BBN Systems and Technologies Corporation	 - The Blue Nile
------------------------------------------------------------------------------

tbrakitz@phoenix.Princeton.EDU (Byron Rakitzis) (03/08/90)

In article <53134@bbn.COM> kanarick@vax.bbn.com (Craig M. Kanarick) writes:

>Basically, I have written, in C, a 6502 emulator.  It has an array of
>16-bit values, and is the memory of the Apple.  I also have 5 16-bit
>registers, and a program counter.  Basically, the emulator is just a
>big case statement, each branch being one 6502 instruction (yes, there
>are a lot, because each instruction/addressing mode pair is a seperate
>branch).  I am about halfway done with this part.  Essentially, I just

I wrote a rudimentary 6502 emulator in C last summer which I have not
gotten around to debugging yet. The code is really messy, and I'm not
very proud of it, but there's a MUCH better way to go about finding
the next instruction! 

1) I keep a 256-valued array of struct containing the info:
	instruction, addressing mode, cycles.
This way, by checking the array for any particular opcode, I can
determine in constant time what the instruction, opcode is supposed to
be. 

2) (the sneaky part) the "instruction" datum is simply an index to
another array of pointer to function! So, each function is an
instruction which does the obvious thing (load, rol whatever) and the
trick is to set up the addressing mode first (just pass the right
pointers to accumulator, memory, whatever) and then in one statement 
execute_instruction[x](), go there!

If anybody wants the code they are free to have it, but it doesn't
work and I really can't be bothered to look at it. It was written in
great haste at the end of the summer, but most of the grungy work is
done. 

-- 
Just try taking your VAX down to Jiffy-Lube these days!
			
Byron "Bo knows parallel computational geometry" Rakitzis. 
				(tbrakitz@phoenix.Princeton.EDU)

fadden@cory.Berkeley.EDU (Andy McFadden) (03/08/90)

In article <14340@phoenix.Princeton.EDU> tbrakitz@phoenix.Princeton.EDU (Byron Rakitzis) writes:
>In article <53134@bbn.COM> kanarick@vax.bbn.com (Craig M. Kanarick) writes:
>
>>Basically, I have written, in C, a 6502 emulator.  It has an array of
[snip]
>
>I wrote a rudimentary 6502 emulator in C last summer which I have not
>gotten around to debugging yet. The code is really messy, and I'm not
>very proud of it, but there's a MUCH better way to go about finding
>the next instruction! 
[snip snip]
>2) (the sneaky part) the "instruction" datum is simply an index to
>another array of pointer to function! So, each function is an
[...]
>execute_instruction[x](), go there!

Sneaky, yes.  Efficient, no.  With this method you get procedure call
overhead with every single 6502 instruction.  Not a good way to go.

It's faster to do things like
switch (mem[pc++]) {
case LDA_ABS:
    loc = mem[pc++] + (mem[pc++] >> 8);
    reg[ACC] = mem[loc];
    break;
case ...
}

Which automatically increments the PC with each instruction, so that when
it hits the "break", a while loop takes it back around to the top of the
case statement, and it's ready for the next insruction.

>Byron "Bo knows parallel computational geometry" Rakitzis. 
>				(tbrakitz@phoenix.Princeton.EDU)

What ought to be fun is writing some $c000 page stuff...  Make certain ranges
look like an intelligent disk device, then just run standard ProDOS 8.  Rewrite
the device code to make UNIX system calls, then use a disk image file to
actually read from (I did something like this once for some SSI games...
changed disk sector read/writes into read/write offsets of a file).

You would also have to use something like curses and watch the text page for
activity, so that things which stored values directly to the screen actually
printed out.  Using 128K of RAM would be easily done by just watching accesses
to the $c000 page; make memory act just like it would on a //.

Doing this, you could boot your Apple II off of a 3.5" disk drive... all under
UNIX.  Standard, off the shelf programs would work.  The more effort, the
better they would run.

-- 
fadden@cory.berkeley.edu (Andy McFadden)
...!ucbvax!cory!fadden

pnakada@oracle.com (Paul Nakada) (03/08/90)

In article <22777@pasteur.Berkeley.EDU> fadden@cory.Berkeley.EDU (Andy McFadden) writes:

   >2) (the sneaky part) the "instruction" datum is simply an index to
   >another array of pointer to function! So, each function is an
   [...]
   >execute_instruction[x](), go there!

   Sneaky, yes.  Efficient, no.  With this method you get procedure call
   overhead with every single 6502 instruction.  Not a good way to go.

   It's faster to do things like
   switch (mem[pc++]) {
   case LDA_ABS:
       loc = mem[pc++] + (mem[pc++] >> 8);
       reg[ACC] = mem[loc];
       break;
   case ...
   }

   Which automatically increments the PC with each instruction, so that when
   it hits the "break", a while loop takes it back around to the top of the
   case statement, and it's ready for the next insruction.

   >Byron "Bo knows parallel computational geometry" Rakitzis. 
   >				(tbrakitz@phoenix.Princeton.EDU)

   What ought to be fun is writing some $c000 page stuff...  Make certain ranges
   look like an intelligent disk device, then just run standard ProDOS 8.  Rewrite
   the device code to make UNIX system calls, then use a disk image file to
   actually read from (I did something like this once for some SSI games...
   changed disk sector read/writes into read/write offsets of a file).

   You would also have to use something like curses and watch the text page for
   activity, so that things which stored values directly to the screen actually
   printed out.  Using 128K of RAM would be easily done by just watching accesses
   to the $c000 page; make memory act just like it would on a //.

   Doing this, you could boot your Apple II off of a 3.5" disk drive... all under
   UNIX.  Standard, off the shelf programs would work.  The more effort, the
   better they would run.


Andy, I think you might want to be careful about those pc++
expressions.  I'm, not totally sure about this, but isn't there some
problem with the order of evaulation of the expression?  In any case,
something to consider.

On another note, the great thing about prodos is that all calls are
made through the prodos entry vector $BF00.  So to emulate Prodos, you
just have to trap any jsr to $BF00 and execute native code to emulate
whatever prodos would do.. No need to steal or have resident ANY
Prodos code, or play with the disk I/O softswitches... of course this
would only work with programs strictly adhering to Prodos convention.

-Paul Nakada
pnakada@oracle.com

tbrakitz@phoenix.Princeton.EDU (Byron Rakitzis) (03/08/90)

In article <22777@pasteur.Berkeley.EDU> fadden@cory.Berkeley.EDU.UUCP (Andy McFadden) writes:
>In article <14340@phoenix.Princeton.EDU> tbrakitz@phoenix.Princeton.EDU (Byron Rakitzis) writes:
>>

>>2) (the sneaky part) the "instruction" datum is simply an index to
>>another array of pointer to function! So, each function is an
>[...]
>>execute_instruction[x](), go there!
>
>Sneaky, yes.  Efficient, no.  With this method you get procedure call
>overhead with every single 6502 instruction.  Not a good way to go.
>

If you have a clever compiler, and if you store the pertinent
information in global variables (everything should really be in
globals: your mem[] array and a few register globals (pc, sp, a, x,
y)) then it is not less efficient. It should use a "JSR" like
instruction which does not chew up stack space (except for the return
address). 

Of course, if you are using a VAX, then 'CALLS' is all you got...
(I know there is another instruction, JSB, which does not use the
stack, but this does not conform to UNIX paramater passing
conventions. Hence, I've never heard of a compiler which uses JSB
instead of CALLS)

Now that I look at it again, perhaps a big switch() is okay too, but
at least with my method you don't have to worry about a compiler
making a good jump table. You are guaranteed that it will be good. 
-- 
Just try taking your VAX down to Jiffy-Lube these days!
			
Byron "Bo knows parallel computational geometry" Rakitzis. 
				(tbrakitz@phoenix.Princeton.EDU)