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)