6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue May 07, 2024 1:01 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Thu Mar 03, 2011 10:43 am 
Offline

Joined: Wed Mar 02, 2011 11:47 pm
Posts: 4
TLDR: Please help me convert a C++ 65816 emulator to java.

Hi, I'm completely new to 65816 and even worse have very little experience in coding using native languages. I've decided to convert a SNES emulator from C++ to java (because I couldn't find one in java) and naturally from my lack of experience with C/pp I gravitated to the source which was the smallest. Obviously I realised it was a huge mistake. I'd like to continue going with this source, though, because it is easier for me to translate than any of the other full-featured emulators. I've decided to post some of my progress here, in hopes that someone may find it in their hearts to fix my code or give me recommendations on it. I know what you are thinking: "just read the docs, idiot!" - well to be honest, the ones I've found are extremely hard for me to understand; it is not worth it time wise for me to read a book about the 65816 then code the emulator - I'd rather just get it done in pieces. Since I am basically just reverse engineering another emulator, I'll post each class/set of classes as a module.

I'm also not sure as to whether there is a standard for specific offsets that are defined in this 65816 emu (I hope they are..)

NB. Alot of this code is based on converting c++ pointers and other syntactical deviations that it and java may have.

I've decided to go with the NIO ByteBuffer for mostly everything that I've coded up to this point. This is mainly due to the slice() method it offers which essentially gives you a pointer to a position within a parent ByteBuffer.


Memory
This is what I'm extremely sketchy about. First of all, the essentials..am I OK on the sizes?
Code:
package com.androidsnes.cpu.util;

public class Constants {

   public static int RAM_SIZE = 0x20000;
   public static int ROM_BANKS = 0xC0;
   public static int ROM_SIZE = 0x8000;
}


Reading/parsing the smc.. does this look right?

Code:
package com.androidsnes.cpu.util;

import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
import java.io.FileInputStream;

import static System.out;
/**
 * Load/map SMC into memory
 * @author RLN
 */
 
public class Loader {

   Memory mem;
   
   Loader(Memory mem) {
      this.mem = mem;
   }
   
   public void loadSMC(String fn) {
      try {
         /* open the channel for reading into partitioned byte buffers*/
         FileChannel channel = new FileInputStream(fn).getChannel();
         
         ByteBuffer[] ROM = mem.getROM();
         int c = 0, len = len2 = channel.size();
         len2 &= 512;
         
         String title;
         int type;
         int country;
         boolean palf;
         
         int[] check = new int[2], checkinv = new int[2];
         
         /* Read the first two blocks into memory */
         channel.read(ROM[c++] = ByteBuffer.allocateDirect(32768));
         channel.read(ROM[c++] = ByteBuffer.allocateDirect(32768));
         
         /* verify checksums */
         check[0] = (ROM[1].position(0x7FDE).get() | (ROM[1].position(0x7FDF).get() << 8));
         checkinv[0] = (ROM[1].position(0x7FDC).get() | (ROM[1].position(0x7FDF).get() << 8));
         check[1] = (ROM[0].position(0x7FDE).get() | (ROM[0].position(0x7FDF).get() << 8));
         checkinv[1] = (ROM[0].position(0x7FDC).get() | (ROM[0].position(0x7FDF).get() << 8));
         
         
         if(((check[0] + checkinv[0]) == 0xFFFF)
               && (check[1] + checkinv[1]) != 0xFFFF) {
            // Let's load this puppy up
            // Read the title
            byte[] titl3 = new byte[20];
            title = new String(ROM[1].position(0x7FC0).get(titl3));
            // Read the type
            type = ROM[1].position(0x7FD6).get() & 0xF;
            // Read country & define whether game is PAL or NTSC
            country = ROM[1].position(0x7FD9).get();
            palf = ((country & 0xF) >= 2) && (country & 0xF < 14);
            
            println("GAME TITLE -> " + title);
            println("ROM TYPE -> " + type);
            println("COUNTRY CODE -> " + country);
            println("IMAGE TYPE -> " + palf ? "PAL" : "NTSC");
            
            // Read the rest of the file into partitioned ROM
            while(channel.read(ROM[c++] =
                ByteBuffer.allocateDirect(32768)) != -1);
               
            memory.setHiRom(true);
         } else if((ROM[0].position(0x7FD5).get() & 1) == 1) {
            // Read the title
            byte[] titl3 = new byte[20];
            title = new String(ROM[0].position(0x7FC0).get(titl3));
            // Read the type
            type = ROM[0].position(0x7FD6).get() & 0xF;
            // Read country & define whether game is PAL or NTSC
            country = ROM[0].position(0x7FD9).get();
            palf = ((country & 0xF) >= 2);
            
            println("GAME TITLE -> " + title);
            println("ROM TYPE -> " + type);
            println("COUNTRY CODE -> " + country);
            println((len >> 15) + " banks!");
            println("IMAGE TYPE -> " + palf ? "PAL" : "NTSC");
            // WTF?
            int t;
            for(t = c; c < (len >> 16); c++)
               channel.read(ROM[(c << 1) + 1] =
                   ByteBuffer.allocateDirect(32768));
                  
            for(c = t; c < (len >> 16); c++)
               channel.read(ROM[c << 1] =
                   ByteBuffer.allocateDirect(32768));
                  
            memory.setHiRom(true);
         } else {
            // Read the title
            byte[] titl3 = new byte[20];
            title = new String(ROM[0].position(0x7FC0).get(titl3));
            // Read the type
            type = ROM[0].position(0x7FD6).get() & 0xF;
            // Read country & define whether game is PAL or NTSC
            country = ROM[0].position(0x7FD9).get();
            palf = ((country & 0xF) >= 2);
            
            println("GAME TITLE -> " + title);
            println("ROM TYPE -> " + type);
            println("COUNTRY CODE -> " + country);
            println("IMAGE TYPE -> " + palf ? "PAL" : "NTSC");
            
            // Read the rest of the file into partitioned ROM
            while(channel.read(ROM[c++] =
                ByteBuffer.allocateDirect(32768)) != -1);
            
            memory.setHiRom(false);
         }
         
         memory.setProperties(title, type, country);
      } catch (IOException e) { e.printStackTrace(); }
   }
   
}


My memory construct...
Code:
package com.androidsnes.cpu;

import java.nio.ByteBuffer;

/**
 * An object representing RAM and ROM
 * @author RLN
 */
 
public class Memory {

   /**
    * Byte buffers!
    */
   private ByteBuffer RAM;
   private ByteBuffer[] ROM;

   /**
    * Properties of the current ROM
    */
    private boolean hirom;
    private String title;
    private int type;
    private int country;
   
   /**
    * Initialize RAM and ROM
    */
   Memory(int ram_size, int rom_partitions, int rom_size) {
      RAM = ByteBuffer.allocateDirect(ram_size);
      
      for(int i = 0; i < ram_size; i += 2) {
         RAM.put(0);
         RAM.put(0);
      }
      RAM.rewind();
      
      ROM = new ByteBuffer[rom_partitions];
   }
   
   /**
    * Access!
    */
   public void setProperties(String title, int type, int country) {
      this.title = title;
      this.type = type;
      this.country = country;
   }
   
   public ByteBuffer getRAM() {
      return RAM;
   }
   
   public ByteBuffer[] getROM() {
      return ROM;
   }
   
   public ByteBuffer getROM(int bank) {
      return ROM[bank];
   }
   
   public void setHiRom(boolean t) {
      hirom = t;
   }
   
   public boolean isHiRom() {
      return hirom;
   }
}


Pointers
Okay.. according to the source I'm porting.. this part was sketchy to begin with. Now.. its beyond sketchy.. I am hoping for someone to please validate that this code is OK.. or atleast if you can't understand the code.. verify the offsets.

Code:
package com.androidsnes.cpu;

import java.nio.ByteBuffer;
import java.util.HashMap;

/**
 * For mapping and requesting pointers for 65816 via NIO ByteBuffer
 * @author RLN
 */
 
public class PointerMap {

   /**
    * Reference to RAM and ROM
    */
   Memory memory;
   
   /**
    * Maps for pointers, format-> <Bank, Ptr>
    */
   HashMap<Integer, ByteBuffer> pointers_bank1;
   HashMap<Integer, ByteBuffer> pointers_bank2;
   
   PointerMap(Memory memory) {
      this.memory = memory;
      pointers_bank1 = new HashMap<Integer, ByteBuffer>();
      pointers_bank2 = new HashMap<Integer, ByteBuffer>();
   }

   /**
    * These produce a direct pointer to a location in memory
    * This seemed optimal for transition from C++ to java
    */
   public ByteBuffer createPointer(ByteBuffer original, int pos, int lim) {
      return original.position(pos).limit(limit).slice();
   }

   public ByteBuffer createPointer(ByteBuffer original, int pos) {
      return createPointer(original, pos, original.capacity());
   }
   
   
   /**
    * Gets a pointer for easy access to offsets in memory used by 65816
    */
   public ByteBuffer getPointer(int bank, int idx) {
      // This is the memory offset from 0th index of this bank
      int ofs = idx & 0x7FFF;
      
      // Get the first bit which tells us which map to use for this bank
      HashMap<Integer, ByteBuffer> thismap =
          ((idx >> 15) == 0 ? pointers_bank1 : pointers_bank2);
      
      // Get the pointer by the associated bank
      return thismap.get(bank).position(ofs); // lets hope its not null
   }
   
   /**
    * Generate pointers for 65816
    */
   public void generatePointerMap() {
      int c;
      /* In the words of the original writer of these pointers, "I hope this works..." */
      ByteBuffer buffer;
      if(hiROM) {
         for(c = 0; c < 0x40; c++) {
            pointers_bank2.put(c, createPointer(memory.getROM(c), ((c << 1) + 1)));
            pointers_bank1.put(c, createPointer(memory.getRAM(), 0));
         }
         for(c = 0; c < 0x40; c++) { // According to author, this is probably incorrect
            buffer = memory.getROM(c+0x40);
            pointers_bank1.put(c+0x40, createPointer(buffer, c << 1));
            pointers_bank2.put(c+0x40, createPointer(buffer, ((c << 1) + 1)));
         }
         for(c = 0; c < 0x80; c++) {
            pointers_bank1.put(c+0x80, pointers_bank1.get(c));
            pointers_bank2.put(c+0x80, pointers_bank2.get(c));
         }
         
         buffer = memory.getRAM();
         
         pointers_bank1.put(0x7E, createPointer(buffer, 0));
         pointers_bank2.put(0x7E, createPointer(buffer, 0x8000));
         pointers_bank1.put(0x7F, createPointer(buffer, 0x10000));
         pointers_bank2.put(0x7F, createPointer(buffer, 0x18000));
         
         pointers_bank1.put(0xFE, createPointer(memory.getROM(0x7C), 0));
         pointers_bank2.put(0xFE, createPointer(memory.getROM(0x7D), 0));
         pointers_bank1.put(0xFE, createPointer(memory.getROM(0x7E), 0));
         pointers_bank2.put(0xFE, createPointer(memory.getROM(0x7F), 0));
      } else {
         for(c = 0; c < 0x40; c++) {
            buffer = memory.getROM(c);
            pointers_bank2.put(c, createPointer(buffer, c));
            pointers_bank1.put(c, createPointer(buffer, 0));
         }
         for(c = 0; x < 0x40; c++) {
            buffer = memory.getROM(c+0x40);
            pointers_bank1.put(c+0x40, createPointer(buffer, c+0x40));
            pointers_bank2.put(c+0x40, createPointer(buffer, c+0x40));
         }
         
         buffer = memory.getRAM();
         
         pointers_bank1.put(0x7E, createPointer(buffer, 0));;
         pointers_bank2.put(0x7E, createPointer(buffer, 0x8000));
         pointers_bank1.put(0x7F, createPointer(buffer, 0x10000));
         pointers_bank2.put(0x7F, createPointer(buffer, 0x18000));
            
         for(c = 0; c < 0x80; c++) {
            pointers_bank1.put(c+0x80, pointers_bank1.get(c));
            pointers_bank2.put(c+0x80, pointers_bank2.get(c));
         }
      }
      
   }
   
}


Opcodes
This wasn't too hard of a transition from C, as I've given each opcode its own class and I load them all dynamically. Firstly, here is the template for an opcode
Code:
package com.androidsnes.cpu;
/**
 * An abstract operation
 * @author RLN
 */
   
public class Operation {

   int opcode = 0;
   int mode = 0;
   /*Processor parentProc;
   
   Operation(Processor p) {
      parentProc = p;
   }
   
   public Processor getProcessor() {
      return parentProc;
   }*/
   
   public abstract void execute() { }

   public int getOpcode() {
      return opcode;
   }
   
   public void setOpcode(int o) {
      opcode = o;
   }
   
   public int getMode() {
      return mode;
   }
   
   public void setMode(int m) {
      mode = m;
   }
}


Secondly, here is the opcode loader/mapper
Code:
package com.androidsnes.cpu;

import java.util.HashMap;

import org.androidsnes.cpu.op.BadOperation;

/**
 * Map used to easily map instruction to opcode #
 * @author RLN
 */
public class OpcodeMap {
   /**
    * Map of opcodes HashMap<MODE, HashMap<OPCODE INDEX, OPCODE>>
    */
   HashMap<Integer, HashMap<Integer, Operation>> opcodes =
      new HashMap<Integer, HashMap<Integer, Operation>>();

   /**
    * Best Way I could think of to map the opcodes directly from C (reference used pointers)
    * Parameters: addressing mode, opcode
    */
   public Operation get(int mode, int idx) {
      return opcodes.get(mode).get(idx);
   }
   
   /**
    * Generate hashmaps of our operation objects
    * Somewhat hacky methinks
    */
   public void generateMap() {
      try {
         String s, thishex;
         Operation o;
         for(int mode1 = 0; mode1 < 4; i++) {
            HashMap<Integer, Operation> mode_ops =
               new HashMap<Integer, Operation>();
            
            for(int i = 0; i < 256; i++) {
               thishex = Integer.toHexString(i);
               thishex = thishex.substring(
                        thishex.length() - 2,
                        thishex.length())
                        .toUpperCase();
               try {
                  o = (Operation)(Class.forName(
                        "com.androidsnes.cpu.op.m"
                        +mode1+"op"+thishex)
                        .newInstance());
                  o.setOpcode(i);
                  o.setMode(mode1);
               } catch (Exception e) { o = new BadOperation(); }
                  
               mode_ops.put(i, o);
            }
            
            opcodes.put(mode1, mode_ops);
         }
      } catch (Exception e) { e.printStackTrace(); }
   }
}


thirdly, here is the implementation of an instruction
Code:
package com.androidsnes.cpu.op;

import com.androidsnes.cpu.Operation;

public class BadOperation extends Operation {

   public void execute() {
      System.out.println("BAD OPCODE: " + getOpcode());
   }
   
}


The implementation classes aren't necessary yet, as they are quite bare bones. Any and all feedback is welcome.

Also: this code might not compile as I haven't tested it.. I don't expect it to compile out-of-the-box (sounds stupid.. i know) since I'm porting it from C++ to java - I really just hope it will all come together when I'm done the 65816 part of the SNES emulator.

I know I'm asking for a lot, not giving context etc., but I basically am praying for a pro to come a long and spoonfeed me. If I am rejected, so be it. There will be more from me to come.. (even faster if someone helps me :P)


Last edited by RLN on Fri Mar 04, 2011 1:09 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 03, 2011 6:56 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 993
Location: near Heidelberg, Germany
I am not sure what I should think of this. It seems you want to write an SNES emulator for android devices (see your java package name). Are you planning to give it away for free or for money?

I don't think you will get much support, if you just post all of your source code here, piece by piece. Coding in Java normally involves some kind of up-front thinking (well, actually all coding does :-), so it would probably be better to first explain your approach. Like is your CPU running in a single loop in a single class, are your opcodes implemented as Objects or not - it seems it does looking at your OpcodeMap stuff - are they implemented statically resp. when do you instantiate a new opcode object instance, how is memory implemented and accessed. So far I've seen only glue code for the SNES, like loading files etc. which I cannot comment on anyway, as I don't know SNES. And then I am not sure if this is the correct forum - other members may correct me of course - if you need advice how to code in Java. We more tend to concentrate on 6502/65816 code issues. Again, if other forum members don't agree with me, I stand corrected.

André


André


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 03, 2011 9:06 pm 
Offline

Joined: Wed Mar 02, 2011 11:47 pm
Posts: 4
fachat wrote:
I am not sure what I should think of this. It seems you want to write an SNES emulator for android devices (see your java package name). Are you planning to give it away for free or for money?

I don't think you will get much support, if you just post all of your source code here, piece by piece. Coding in Java normally involves some kind of up-front thinking (well, actually all coding does :-), so it would probably be better to first explain your approach. Like is your CPU running in a single loop in a single class, are your opcodes implemented as Objects or not - it seems it does looking at your OpcodeMap stuff - are they implemented statically resp. when do you instantiate a new opcode object instance, how is memory implemented and accessed. So far I've seen only glue code for the SNES, like loading files etc. which I cannot comment on anyway, as I don't know SNES. And then I am not sure if this is the correct forum - other members may correct me of course - if you need advice how to code in Java. We more tend to concentrate on 6502/65816 code issues. Again, if other forum members don't agree with me, I stand corrected.

André


André
I totally understand where you're coming from. I don't need help with my java code though.. what I want to know is if my constants and offsets are right.. and if I'm loading the ROM properly. I'm not really worried about structure.. it will work itself out. But yes, the opcodes are objects and they are instantiated at load time (generateMap() is called by the Processor at load time - as is generatePointerMap()). From the emulator that I'm trying to port - it only uses one thread.

Also, I'm not sure if I'm going to try to monetize it after.. but atleast the 65816 I will make open source - so people who come after me have something to go by.. not just a low level mess without any comments :D

Also, like I said - I am basically begging to be spoonfed.. I wasn't actually expecting for someone to go through all my code at once.. but maybe someone will tell me my constant is off by 0xA.. then someone else finds that my loader is off by a few bytes - anything really helps.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 03, 2011 9:59 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8175
Location: Midwestern USA
RLN wrote:
Also, I'm not sure if I'm going to try to monetize it after...

Monetize: ain't no such word in English. :)

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


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 03, 2011 10:20 pm 
Offline

Joined: Wed Mar 02, 2011 11:47 pm
Posts: 4
BigDumbDinosaur wrote:
RLN wrote:
Also, I'm not sure if I'm going to try to monetize it after...

Monetize: ain't no such word in English. :)
ic what u did ther


Top
 Profile  
Reply with quote  
 Post subject: more codes
PostPosted: Fri Mar 04, 2011 12:50 am 
Offline

Joined: Wed Mar 02, 2011 11:47 pm
Posts: 4
finished the functions.. don't have any comments due to not knowing wtf is going on. Anyway, operations have polymorphic access to:
Code:
package com.androidsnes.cpu;

public class Functions {

   Processor p;
   
   public Functions(Processor p) {
      this.p = p;
   }
   
   public void JSR(int bank, int addr, int l) {
      p.pc--;
      if(p.l) push(p.dbr);
      push(p.pc >> 8);
      push(p.pc);
      p.pbr = bank;
      p.pc = addr;
   }
   
   public void ADCB8() {
      p.tempw = p.a.B.l + p.temp + ((p.P.c) ? 1 : 0);
      p.P.v = (!((p.a.B.l ^ p.temp) & 0x80) && ((p.a.B.l ^ p.tempw) & 0x80));
      p.a.B.l = p.tempw & 0xFF;
      setzn8(p.a.B.l);
      p.P.c = p.tempw & 0x100;
   }
   
   public void ADCB16() {
      p.templ = p.a.w + p.tempw + ((p.P.c) ? 1 : 0);
      p.P.v = (!((p.a.w ^ p.tempw) & 0x8000) && ((p.a.w ^ p.templ) & 0x8000));
      p.a.w = p.templ & 0xFFFF;
      setzn16(p.a.w);
      p.P.c = p.templ & 0x10000;
   }
   
   public void ADCBCD8() {
      p.tempw = (p.a.B.l & 0xF) + (p.temp & 0xF) + (p.P.c ? 1 : 0);
      if (p.tempw > 9) {
      p.tempw += 6;
      }
      p.tempw += ((p.a.B.l & 0xF0) + (p.temp & 0xF0));
      if (p.tempw > 0x9F) {
      p.tempw += 0x60;
      }
      p.P.v=(!((p.a.B.l ^ p.temp) & 0x80) && ((p.a.B.l ^ p.tempw) & 0x80));
      p.a.B.l = p.tempw & 0xFF;
      setzn8(p.a.B.l);
      p.P.c = p.tempw > 0xFF;
   }

   public void ADCBCD16() {
      p.templ = (p.a.w & 0xF) + (p.tempw & 0xF) + (p.P.c ? 1 : 0);
      if (p.templ > 9) {
         p.templ += 6;
      }
      p.templ += ((p.a.w & 0xF0) + (p.tempw & 0xF0));
      if (p.templ > 0x9F) {
         p.templ += 0x60;
      }
      p.templ += ((p.a.w & 0xF00) + (p.tempw & 0xF00));
      if (p.templ > 0x9FF) {
         p.templ += 0x600;
      }
      p.templ += ((p.a.w & 0xF000) + (p.tempw & 0xF000));
      if (p.templ > 0x9FFF) {
         p.templ += 0x6000;
      }
      p.P.v = (!((p.a.w ^ p.tempw) & 0x8000) && ((p.a.w ^ p.templ) & 0x8000));
      p.a.w = p.templ & 0xFFFF;
      setzn16(p.a.w);
      p.P.c = p.templ > 0xFFFF;
   }
   
   public void SBCB8() {
      p.tempw= p.a.B.l - p.temp - ((p.P.c) ? 0 : 1);
      p.P.v = (((p.a.B.l ^ p.temp) & 0x80) && ((p.a.B.l ^ p.tempw) & 0x80));
      p.a.B.l = p.tempw & 0xFF;
      setzn8(p.a.B.l);
      p.P.c = p.tempw <= 0xFF;
   }
   
   public void SBCB16() {
      p.templ = p.a.w - p.tempw - ((p.P.c) ? 0 : 1);
      p.P.v = (((p.a.w ^ p.tempw) & (p.a.w ^ p.templ)) & 0x8000);
      p.a.w = p.templ & 0xFFFF;
      setzn16(p.a.w);
      p.P.c = p.templ <= 0xFFFF;
   }
   
   public void SBCBCD8() {
      p.tempw = (p.a.B.l & 0xF) - (p.temp & 0xF) - (p.P.c ? 0 : 1);
      if (p.tempw > 9) {
         p.tempw -= 6;
      }
      p.tempw += ((p.a.B.l & 0xF0) - (p.temp & 0xF0));
      if (p.tempw > 0x9F) {
         p.tempw -= 0x60;
      }
      p.P.v = (((p.a.B.l ^ p.temp) & 0x80) && ((p.a.B.l ^ p.tempw) & 0x80));
      p.a.B.l = p.tempw & 0xFF;
      setzn8(p.a.B.l);
      p.P.c = p.tempw <= 0xFF;
   }
   
   public void SBCBCD16() {
      p.templ = (p.a.w & 0xF) - (p.tempw & 0xF) - (p.P.c ? 0 : 1);
      if (p.templ > 9) {
         p.templ-=6;
      }
      p.templ += ((p.a.w & 0xF0) - (p.tempw & 0xF0));
      if (p.templ > 0x9F) {
         p.templ -= 0x60;
      }
      p.templ += ((p.a.w & 0xF00) - (p.tempw & 0xF00));
      if (p.templ > 0x9FF) {
         p.templ -= 0x600;
      }
      p.templ += ((p.a.w & 0xF000) - (p.tempw & 0xF000));
      if (p.templ > 0x9FFF) {
         p.templ -= 0x6000;
      }
      p.P.v = (((p.a.w ^ p.tempw) & 0x8000) && ((p.a.w ^ p.templ) & 0x8000));
      p.a.w = p.templ & 0xFFFF;
      setzn16(p.a.w);
      p.P.c = p.templ <= 0xFFFF;
   }

   public void setzn8(byte v) {
      p.P.z = !(v);
      p.P.n = (v) & 0x80;
   }
   
   public void setzn16(byte v) {
      p.P.z = !(v);
      p.P.n = (v) & 0x8000;
   }

   public void push(int b) {
      p.writemem(0, p.s.w--, b);
   }
   
   public int pull() {
      return p.readmem(0, ++p.s.w)
   }
   
   public int imm() {
      return p.readfast(p.pbr,p.pc++);
   }

   public int immw() {
      return p.readfast(p.pbr, p.pc++) | (p.readfast(p.pbr, p.pc++) << 8);
   }
   public int zp() {
      return (p.templ = p.readfast(p.pbr, p.pc++) + d);
   }

   public int zpx() {
      return (p.templ = p.readfast(p.pbr, p.pc++) + d + x.w);
   }
   
   public int zpy() {
      return (p.templ = p.readfast(p.pbr , p.pc++) + d + y.w);
   }
   
   public int sr() {
      return (p.templ = p.readfast(p.pbr, p.pc++) + s.w);
   }
   
   public int abs() {
      return (p.templ = p.readfast(p.pbr, p.pc++) |
         (p.readfast(p.pbr, p.pc++) << 8) |
         (p.dbr << 16));
   }
   
   public int absx() {
      return (p.templ = (p.readfast(p.pbr ,p.pc++) |
         (p.readfast(p.pbr, p.pc++) << 8) |
         (p.dbr<<16)) + x.w);
   }
   
   public int absy() {
      return (p.templ = (p.readfast(p.pbr, p.pc++) |
         (p.readfast(p.pbr, p.pc++) << 8) |
         (p.dbr << 16)) + y.w);
   }
   
   public int along() {
      return (p.templ = (p.readfast(p.pbr,p.pc++) |
         (p.readfast(p.pbr, p.pc++) << 8) |
         (p.readfast(p.pbr, p.pc++) << 16)));
   }
   
   public int longx() {
      return (p.templ = (p.readfast(p.pbr, p.pc++) |
         (p.readfast(p.pbr, p.pc++) << 8) |
         (p.readfast(p.pbr, p.pc++) << 16)) +
         p.x.w);
   }

   public int getb() {
      return p.readmem(p.templ >> 16, p.templ)
   }
   
   public int getw() {
      return (p.readmem(p.templ >> 16, p.templ) |
      (p.readmem(p.templ >> 16, p.templ + 1) << 8));
   }
   
   public void setb(int v) {
      p.writemem(p.templ >> 16, p.templ, v)
   }
   
   public void setw(int v) {
      p.writemem(p.templ >> 16, p.templ, v);
      p.writemem(p.templ >> 16, p.templ + 1, v >> 8);
   }

   void PHP() {
      int temp=0;
      if (p.P.c) temp |= 1;
      if (p.P.z) temp |= 2;
      if (p.P.i) temp |= 4;
      if (p.P.d) temp |= 8;
      if (!p.P.e && p.P.x) temp |= 0x10;
      if (!p.P.e && p.P.m) temp |= 0x20;
      if (p.P.v) temp |= 0x40;
      if (p.P.n) temp |= 0x80;
      push(temp);
   }

   int compp() {
      int temp=0;
      if (p.P.c) temp |= 1;
      if (p.P.z) temp |= 2;
      if (p.P.i) temp |= 4;
      if (p.P.d) temp |= 8;
      if (!p.P.e && p.P.x) temp |= 0x10;
      if (!p.P.e && p.P.m) temp |= 0x20;
      if (p.P.v) temp |= 0x40;
      if (p.P.n) temp |= 0x80;
      return temp;
   }

   void PLP() {
      int temp = pull();
      p.P.c = temp & 1;
      p.P.z = temp & 2;
      p.P.i = temp & 4;
      p.P.d = temp & 8;
      if (!p.P.e) p.P.x = temp & 0x10;
      if (!p.P.e) p.P.m = temp & 0x20;
      p.P.v = temp & 0x40;
      p.P.n = temp & 0x80;
      updatemode();
   }

   public void ind() {
      p.tempw = p.readfast(p.pbr, p.pc++) + (p.readfast(p.pbr, p.pc++) << 8);
      p.templ = p.readfast(p.pbr, p.tempw) | (p.readfast(p.pbr, p.tempw+1) << 8);
   }

   public void dind() {
      p.tempw = p.readfast(p.pbr, p.pc++) + d;
      p.templ = p.readfast(0, p.tempw) |
         (p.readfast(0, p.tempw + 1) << 8) |
         (p.dbr << 16);
   }

   public void indy() {
      p.tempw = p.readfast(p.pbr, p.pc++) + d;
      p.templ = (p.readfast(0, p.tempw) | (p.readfast(0, p.tempw + 1) << 8) |
         (p.dbr << 16)) + p.y.w;
   }

   public void indsy() {
      p.tempw = p.readfast(p.pbr, p.pc++) + s.w;
      p.templ = (p.readfast(0, p.tempw) | (p.readfast(0, p.tempw + 1) << 8) |
         (p.dbr << 16)) + p.y.w;
   }

   public void indl() {
      p.tempw = p.readfast(p.pbr, p.pc++) + p.d;   
      p.templ = p.readfast(0, p.tempw) |
         (p.readfast(0, p.tempw + 1) << 8) |
         (p.readfast(0, p.tempw + 2) << 16);
   }

   public void indlj() {
      p.tempw = p.readfast(p.pbr, p.pc++) | (p.readfast(p.pbr, p.pc++) << 8);
      p.templ = p.readfast(0, p.tempw) |
         (p.readfast(0, p.tempw + 1) << 8) |
         (p.readfast(0, p.tempw + 2) << 16);
   }

   public void indly() {
      p.tempw = p.readfast(p.pbr,p.pc++) + d;
      p.templ = (p.readfast(0, p.tempw) |
         (p.readfast(0, p.tempw + 1) << 8) |
         (p.readfast(0, p.tempw + 2) << 16)) +
         p.y.w;
   }

   public void indx() {
      p.tempw = p.readfast(p.pbr, p.pc++) + (p.readfast(p.pbr, p.pc++) << 8) + p.x.w;
      p.templ = p.readfast(p.pbr, p.tempw) | (p.readfast(p.pbr,p.tempw + 1) << 8);
   }

   public void dindx() {
      p.tempw = p.readfast(p.pbr,p.pc++) + p.x.w + p.d;
      p.templ = p.readfast(0, p.tempw) |
         (p.readfast(0, p.tempw + 1) << 8) |
         (p.dbr << 16);
   }
   
      
   
   void ADC8() {
      if (p.P.d) {
         ADCBCD8();
      } else {
         ADCB8();
      }
   
   }
   void ADC16() {
      if (p.P.d) {
         ADCBCD16();
      } else {
         ADCB16();
      }
   }
   
   void AND8() {
      p.a.B.l &= p.temp;
      setzn8(p.a.B.l);
   }
   
   void AND16() {
      p.a.w &= p.tempw;
      setzn16(p.a.w);
   }
   
   void ASL8() {
      p.P.c = p.temp & 0x80;
      p.temp <<= 1;
      setzn8(p.temp);
   }
   
   void ASL16() {
      p.P.c = p.tempw & 0x8000;
      p.tempw <<= 1;
      setzn16(p.tempw);
   }
   
   void BIT8()   {
      setzn8(p.a.B.l & p.temp);
      p.P.n = p.temp & 0x80;
      p.P.v = p.temp & 0x40;
   }
   void BIT16() {
      setzn16(p.a.w & p.tempw);
      p.P.n = p.tempw & 0x8000;
      p.P.v = p.tempw & 0x4000;
   }
   
   void CMP8() {
      setzn8(p.a.B.l - p.temp);
      p.P.c=(p.a.B.l >= p.temp);
   }
   
   void CMP16() {
      setzn16(p.a.w - p.tempw);
      p.P.c = (p.a.w >= p.tempw);
   }
   
   void CPX8() {
      setzn8(p.x.B.l - p.temp);
      p.P.c = (p.x.B.l >= p.temp);
   }
   
   void CPX16() {
      setzn16(p.x.w - p.tempw);
      p.P.c = (p.x.w >= p.tempw);
   }
   
   void CPY8() {
      setzn8(p.y.B.l - p.temp);
      p.P.c = (p.y.B.l >= p.temp);
   }
   
   void CPY16() {
      setzn16(p.y.w - p.tempw);
      p.P.c = (p.y.w >= p.tempw);
   }
   
   void DEC8() {
      p.temp--;
      setzn8(p.temp);
   }
   
   void DEC16() {
      p.tempw--;
      setzn16(p.tempw);
   }
   
   void DEX8() {
      p.x.B.l--;
      setzn8(p.x.B.l);
   }
   
   void DEX16() {
      p.x.w--;
      setzn16(p.x.w);
   }
   
   void DEY8() {
      p.y.B.l--;
      setzn8(p.y.B.l);
   }
   
   void DEY16() {
      p.y.w--;
      setzn16(p.y.w);
   }
   
   void EOR8() {
      p.a.B.l ^= p.temp;
      setzn8(p.a.B.l);
   }
   
   void EOR16() {
      p.a.w ^= p.tempw;
      setzn16(p.a.w);
   }
   
   void INC8() {
      p.temp++;
      setzn8(p.temp);
   }
   
   void INC16() {
      p.tempw++;
      setzn16(p.tempw);
   }
   
   void INX8() {
      p.x.B.l++;
      setzn8(p.x.B.l);
   }
   
   void INX16() {
      p.x.w++;
      setzn16(p.x.w);
   }
   
   void INY8() {
      p.y.B.l++;
      setzn8(p.y.B.l);
   }
   
   void INY16() {
      p.y.w++;
      setzn16(p.y.w);
   }
   
   void LDA8() {
      p.a.B.l = p.temp;
      setzn8(p.a.B.l);
   }
   
   void LDA16() {
      p.a.w = p.tempw;
      setzn16(p.a.w);
   }
   
   void LDX8() {
      p.x.B.l = p.temp;
      setzn8(p.x.B.l);
   }
   
   void LDX16() {
      p.x.w=p.tempw;
      setzn16(p.x.w);
   }
   
   void LDY8() {
      p.y.B.l = p.temp;
      setzn8(p.y.B.l);
   }
   
   void LDY16() {
      p.y.w=p.tempw;
      setzn16(p.y.w);
   }
   
   void LSR8() {
      p.P.c = p.temp & 1;
      p.temp >>= 1;
      setzn8(p.temp);
   }
   
   void LSR16() {
      p.P.c = p.tempw & 1;
      p.tempw >>= 1;
      setzn16(p.tempw);
   }
   
   void ORA8() {
      p.a.B.l |= p.temp;
      setzn8(p.a.B.l);
   }
   
   void ORA16() {
      p.a.w |= p.tempw;
      setzn16(p.a.w);
   }
   
   void ROL8() {
      p.tempi = p.temp & 0x80;
      p.temp <<=1 ;
      if (p.P.c)
         p.temp |= 1;
      setzn8(p.temp);
      p.P.c = p.tempi;
   }
   
   void ROL16() {
      p.tempi = p.tempw & 0x8000;
      p.tempw <<= 1;
      if (p.P.c)
         p.tempw |= 1;
      setzn16(p.tempw);
      p.P.c = p.tempi;
   }
   
   void ROR8() {
      p.tempi = p.temp & 1;
      p.temp >>= 1;
      if (p.P.c)
         p.temp |= 0x80;
      setzn8(p.temp);
      p.P.c = p.tempi;
   }
   
   void ROR16() {
      p.tempi = p.tempw & 1;
      p.tempw >>= 1;
      if (p.P.c)
         p.tempw |= 0x8000;
      setzn16(p.tempw);
      p.P.c = p.tempi;
   }
   
   void SBC8() {
      if (p.P.d) {
         SBCBCD8();
      } else {
         SBCB8();
      }
   }
   
   void SBC16() {
      if (p.P.d) {
         SBCBCD16();
      } else {
         SBCB16();
      }
   }
   
   void STA8() {
      p.writemem(p.templ >> 16, p.templ, p.a.B.l);
   }
   
   void STA16() {
      p.writemem(p.templ >> 16, p.templ, p.a.B.l);
      p.writemem(p.templ >> 16, p.templ + 1, p.a.B.h);
   }
   
   void STX8() {
      p.writemem(p.templ >> 16, p.templ, p.x.B.l);
   }
   
   void STX16() {
      p.writemem(p.templ >> 16, p.templ, p.x.B.l);
      p.writemem(p.templ >> 16, p.templ + 1, p.x.B.h);
   }
   
   void STY8() {
      p.writemem(p.templ >> 16, p.templ, p.y.B.l);
   }
   
   void STY16() {
      p.writemem(p.templ >> 16, p.templ, p.y.B.l);
      p.writemem(p.templ >> 16, p.templ + 1, p.y.B.h);
   }
   
   void STZ8() {
      p.writemem(p.templ>>16, p.templ, 0);
   }
   
   void STZ16() {
      p.writemem(p.templ >> 16, p.templ, 0);
      p.writemem(p.templ >> 16, p.templ + 1, 0);
   }
   
   void TRB8() {
      p.P.z= !(p.a.B.l & p.temp);
      p.temp &= ~p.a.B.l;
   }
   
   void TRB16() {
      p.P.z= !(p.a.w & p.tempw);
      p.tempw &= ~p.a.w; }
   
   void TSB8() {
      p.P.z= !(p.a.B.l & p.temp);
      p.temp |= p.a.B.l;
   }
   
   void TSB16() {
      p.P.z = !(p.a.w & p.tempw);
      p.tempw |= p.a.w;
   }
}


And started the processor...

Code:
package com.androidsnes.cpu;

/**
 * Implementation of the 65816 microprocessor
 * @author RLN
 */
 
public class Processor {

   /**
    * Reference to our memory heaps
    */
   Memory memory;
   
   /**
    * Reference to operation objects
    */
   OpcodeMap opmap;

   /**
    * Reference to important indices within ROM/RAM
    */
   PointerMap pmap;
   
   /**
    * Total number of CPU cycles
    */
   int cycles;
   
   /**
    * Reference to the functions in which the 65816 interpreter will use
    */
   Functions funtions;
    /**
     * Processor state data
     */
   int pc, d;
   int bank, dbr;
   int addrMode;
   int opcode;
   
   int temp, tempb, al, ah;
   int tempw, temp2;
   
   long templ, templ2;
   int tempi, tempv;
   
   int hc;
   byte offset;
   
   /**
    * La PPU :)
    */
   PPU ppu;
   
   /**
    * Registers used by the processa
    */
   public Register a, x, y, s;
   
   /**
    * Initialize the processor - map memory, memory offsets.
    */
   public Processor(String filename) {
      // initialize memory
      memory = new Memory(Constants.RAM_SIZE,
                     Constants.ROM_BANKS,
                     Constants.ROM_SIZE);
                     
      a = new Register();
      x = new Register();
      y = new Register();
      s = new Register();
      
      // Initialize our CPU functions
      functions = new Functions(this);
      
      // Make our opcode map
      opmap = new OpcodeMap();
      opmap.generateMap();
      
      loader = new Loader(memory);
      loader.loadSMC(filename);
      // Make our pointer map
      pmap = new PointerMap(memory);
      pmap.generateMap();
      
      //init();
   }
   
   /* Sexy */
   public int readfast(int bank, int index) {
      return pmap.getPointer(bank, index).get();
   }
   
   /* Ok...?  I don't understand this on any deep level */
   public int readmem(int bank, int address) {
      if(memory.getHiRom()) {
         if((bank & 0x7F) < 0x40) {
            switch(address & 0xF000) {
               case 0:
               case 0x1000:
                  return ram[addr];
               case 0x2000:
                  return readppu(address);
               case 0x3000:
                  return 0xFF;
               case 0x4000:
                  return readio(address);
               case 0x5000:
                  return 0xFF;
               case 0x6000:
                  return 0xFF;
               case 0x7000:
                  return 0xFF;
               case 0x8000: case 0x9000: case 0xA000: case 0xB000:
               case 0xC000: case 0xD000: case 0xE000: case 0xF000:
               return memory.getROM()[((bank & 0x3F) << 1) + 1][address & 0x7FFF];
            }
         }
         if((banks & 0x7F) < 0x7E) {
            bank = (bank & 0x3F) << 1;
            if((address & 0x8000) == 1) bank |= 1;
            return rom[bank][address & 0x7FFF];
         }
         if(bank == 0x7E)
            return memory.getRAM()[address];
         if(bank == 0x7F)
            return memory.getRAM()[address + 0x10000];
         if(bank == 0xFE) {
            if((address & 0x8000) == 1)
               return memory.getROM()[0x7D][address & 0x7FFF];
            else
               return memory.getROM()[0x7C][address & 0x7FFF];
         }
         if(bank == 0xFF) {
            if((address & 0x8000) == 1)
               return memory.getROM()[0x7F][address & 0x7FFF];
            else
               return memory.getROM()[0x7E][address & 0x7FFF];
         }
      } else {
         bank &= 0x7F;
         if(bank < 0x60) {
            switch(address & 0xF000) {
               case 0:
               case 0x1000:
                  return memory.getRAM()[address];
               case 0x2000:
                  return readppu(address);
               case 0x3000:
                  return 0xFF;
               case 0x4000:
                  return readio(address);
               case 0x5000:
                  return 0xFF;
               case 0x6000:
                  return 0xFF;
               case 0x7000:
                  return 0xFF;
               case 0x8000: case 0x9000: case 0xA000: case 0xB000:
               case 0xC000: case 0xD000: case 0xE000: case 0xF000:
               return memory.getROM()[bank][address & 0x7FFF];
            }
         }
         if(bank == 0x70)
            return sram[address];
         if(bank == 0x7E)
            return memory.getRAM()[address];
         if(bank == 0x7F)
            return memory.getRAM()[address + 0x10000];
         if(bank == 0x60) // this should work for columns
            return address >> 8;
         if(bank == 0x79) // this should work for humans
            return 0xFF;
      }
   }
   
   public void writemem(int bank, int address, int val) {
      bank &= 0x7F;
      if(bank < 0x60) {
         switch(address & 0xF000) {
            case 0:
            case 0x1000:
               memory.getRAM().putByte(address, (byte)val);
               return;
            case 0x2000:
               if((address >> 8) == 0x21)
                  writeppu(address, val);
               return;
            case 0x3000: /* Shadow of the beast writes here - bug? */
               return;
            case 0x4000:
               writeio(address, val);
               return;
            case 0x6000: /* Earthbound writes here */
               return;
            case 0x7000: /* Wario's Woords writes here during NMI - leftover debugging? */
               return;
            case 0x8000: /* First Drop writes to ROM - probably a bug in the demo */
               return;
            case 0x9000: /* Mario Allstars writes to ROM */
               return;
            case 0xF000: /* Itchy and Scratchy writes to ROM */
               return;
         }
      }
      if(bank == 0x60)
         return;
      if(bank == 0x70) {
         sram[address] = val;
         return;
      }
      if(bank = 0x7E) {
         memory.getRAM().putByte(address, (byte)val);
         return;
      }
      if(bank == 0x7F) {
         memory.getRAM().putByte(address + 0x10000, (byte)val);
         return;
      }
   }
   
   public void updatemode() {
      if(P.e)
         addrMode = 3;
      else
         addrMode = (
            (P.x == 1) ? 1 : 0 |
            ((P.m == 1) ? 2 : 0));
            
      if(P.x == 1 || P.e == 1)
         x.B.h = y.B.h = 0;
   }
   
   class Register {
      public static int w;
      static class B {
         public static short l, h;
      }
   }
   
   static class P {
      public static int c,z,i,d,b,x,m,v,n,e;
   }
}


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 4 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: