310 lines
9.5 KiB
Java
310 lines
9.5 KiB
Java
|
package vue;
|
||
|
|
||
|
// Java imports
|
||
|
import java.util.*;
|
||
|
|
||
|
// VIP state
|
||
|
class VIP {
|
||
|
|
||
|
// Instance fields
|
||
|
byte[] vram; // Video memory
|
||
|
|
||
|
// Private fields
|
||
|
private JavaVue vue; // Emulation state
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Constructors //
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Default constructor
|
||
|
VIP(JavaVue vue) {
|
||
|
vram = new byte[0x40000];
|
||
|
this.vue = vue;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Package Methods //
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Process the simulation
|
||
|
void emulate(int cycles) {
|
||
|
|
||
|
}
|
||
|
|
||
|
// Read a value from the CPU bus
|
||
|
int read(int address, int type) {
|
||
|
address &= 0x0007FFFF;
|
||
|
|
||
|
// VRAM
|
||
|
if (address < 0x00040000)
|
||
|
return JavaVue.readBuffer(vram, address, type);
|
||
|
|
||
|
// Mirrors of character memory
|
||
|
if (address >= 0x00078000)
|
||
|
return JavaVue.readBuffer(vram,
|
||
|
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
||
|
address & 0x00001FFF,
|
||
|
type);
|
||
|
|
||
|
// I/O register or unmapped
|
||
|
int value = readRegister(address);
|
||
|
if (type < 2 && (address & 1) == 1)
|
||
|
value >>= 8;
|
||
|
switch (type) {
|
||
|
case Vue.S8 : return value << 24 >> 24;
|
||
|
case Vue.U8 : return value & 0x000000FF;
|
||
|
case Vue.S16: return value << 16 >> 16;
|
||
|
case Vue.S32: return value | readRegister(address + 2) << 16;
|
||
|
}
|
||
|
return value; // U16
|
||
|
}
|
||
|
|
||
|
// Read bytes from the CPU bus
|
||
|
void readBytes(int address, byte[] dest, int offset, int length) {
|
||
|
address &= 0x0007FFFF;
|
||
|
|
||
|
// Perform the operation
|
||
|
while (length > 0) {
|
||
|
int count;
|
||
|
|
||
|
// VRAM
|
||
|
if (address < 0x00040000) {
|
||
|
count = Math.min(length, 0x00040000 - address);
|
||
|
JavaVue.readBytes(vram, address, dest, offset, count);
|
||
|
}
|
||
|
|
||
|
// Mirrors of character memory
|
||
|
else if (address >= 0x00078000) {
|
||
|
count = Math.min(length, 0x2000 - (address & 0x1FFF));
|
||
|
JavaVue.readBytes(vram,
|
||
|
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
||
|
address & 0x00001FFF,
|
||
|
dest, offset, count);
|
||
|
}
|
||
|
|
||
|
// I/O register or unmapped
|
||
|
else {
|
||
|
count = Math.min(length, 0x00078000 - address);
|
||
|
|
||
|
// Read all registers in the range
|
||
|
while (count > 0) {
|
||
|
int value = readRegister(address);
|
||
|
|
||
|
// Odd address
|
||
|
if ((address & 1) == 1) {
|
||
|
dest[offset] = (byte) (value >> 8);
|
||
|
address++;
|
||
|
count --;
|
||
|
length --;
|
||
|
offset ++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Even address
|
||
|
int size = count == 1 ? 1 : 2;
|
||
|
dest[offset] = (byte) value;
|
||
|
if (size == 2)
|
||
|
dest[offset + 1] = (byte) (value >> 8);
|
||
|
address += size;
|
||
|
count -= size;
|
||
|
length -= size;
|
||
|
offset += size;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Advance to the next region
|
||
|
address += count;
|
||
|
length -= count;
|
||
|
offset += count;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// System reset
|
||
|
void reset() {
|
||
|
|
||
|
}
|
||
|
|
||
|
// Determine the number of CPU cycles until a breakpoint could trigger
|
||
|
int until(int cycles) {
|
||
|
return cycles;
|
||
|
}
|
||
|
|
||
|
// Write a value to the CPU bus
|
||
|
void write(int address, int type, int value) {
|
||
|
address &= 0x0007FFFF;
|
||
|
|
||
|
// VRAM
|
||
|
if (address < 0x00040000) {
|
||
|
JavaVue.writeBuffer(vram, address, type, value);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Mirrors of character memory
|
||
|
if (address >= 0x00078000) {
|
||
|
JavaVue.writeBuffer(vram,
|
||
|
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
||
|
address & 0x00001FFF,
|
||
|
type, value);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// I/O register or unmapped
|
||
|
if (type < 2 && (address & 1) == 1)
|
||
|
value <<= 8;
|
||
|
writeRegister(address, value);
|
||
|
if (type == Vue.S32)
|
||
|
writeRegister(address + 2, value >> 16);
|
||
|
}
|
||
|
|
||
|
// Write bytes to the CPU bus
|
||
|
void writeBytes(int address, byte[] src, int offset, int length) {
|
||
|
address &= 0x0007FFFF;
|
||
|
|
||
|
// Perform the operation
|
||
|
while (length > 0) {
|
||
|
int count;
|
||
|
|
||
|
// VRAM
|
||
|
if (address < 0x00040000) {
|
||
|
count = Math.min(length, 0x00040000 - address);
|
||
|
JavaVue.writeBytes(vram, address, src, offset, count);
|
||
|
}
|
||
|
|
||
|
// Mirrors of character memory
|
||
|
else if (address >= 0x00078000) {
|
||
|
count = Math.min(length, 0x2000 - (address & 0x1FFF));
|
||
|
JavaVue.writeBytes(vram,
|
||
|
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
||
|
address & 0x00001FFF,
|
||
|
src, offset, count);
|
||
|
}
|
||
|
|
||
|
// I/O register or unmapped
|
||
|
else {
|
||
|
count = Math.min(length, 0x00078000 - address);
|
||
|
|
||
|
// Write all registers in the range
|
||
|
while (count > 0) {
|
||
|
int value = src[offset] & 0xFF;
|
||
|
|
||
|
// Odd address
|
||
|
if ((address & 1) == 1) {
|
||
|
writeRegister(address, value << 8);
|
||
|
address++;
|
||
|
count --;
|
||
|
length --;
|
||
|
offset ++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Even address
|
||
|
int size = count == 1 ? 1 : 2;
|
||
|
if (size == 2)
|
||
|
value |= src[offset + 1] << 8;
|
||
|
writeRegister(address, value);
|
||
|
address += size;
|
||
|
count -= size;
|
||
|
length -= size;
|
||
|
offset += size;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Advance to the next region
|
||
|
address += count;
|
||
|
length -= count;
|
||
|
offset += count;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Private Methods //
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Read an I/O register
|
||
|
private int readRegister(int address) {
|
||
|
|
||
|
// Process by register
|
||
|
switch (address & ~1) {
|
||
|
case 0x0005F800: break; // INTPND
|
||
|
case 0x0005F802: break; // INTENB
|
||
|
case 0x0005F804: break; // INTCLR
|
||
|
case 0x0005F820: break; // DPSTTS
|
||
|
case 0x0005F822: break; // DPCTRL
|
||
|
case 0x0005F824: break; // BRTA
|
||
|
case 0x0005F826: break; // BRTB
|
||
|
case 0x0005F828: break; // BRTC
|
||
|
case 0x0005F82A: break; // REST
|
||
|
case 0x0005F82E: break; // FRMCYC
|
||
|
case 0x0005F830: break; // CTA
|
||
|
case 0x0005F840: break; // XPSTTS
|
||
|
case 0x0005F842: break; // XPCTRL
|
||
|
case 0x0005F844: break; // VER
|
||
|
case 0x0005F848: break; // SPT0
|
||
|
case 0x0005F84A: break; // SPT1
|
||
|
case 0x0005F84C: break; // SPT2
|
||
|
case 0x0005F84E: break; // SPT3
|
||
|
case 0x0005F860: break; // GPLT0
|
||
|
case 0x0005F862: break; // GPLT1
|
||
|
case 0x0005F864: break; // GPLT2
|
||
|
case 0x0005F866: break; // GPLT3
|
||
|
case 0x0005F868: break; // JPLT0
|
||
|
case 0x0005F86A: break; // JPLT1
|
||
|
case 0x0005F86C: break; // JPLT2
|
||
|
case 0x0005F86E: break; // JPLT3
|
||
|
case 0x0005F870: break; // BKCOL
|
||
|
}
|
||
|
|
||
|
// Unmapped
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Write an I/O register
|
||
|
private void writeRegister(int address, int value) {
|
||
|
|
||
|
// Process by register
|
||
|
switch (address & ~1) {
|
||
|
case 0x0005F800: break; // INTPND
|
||
|
case 0x0005F802: break; // INTENB
|
||
|
case 0x0005F804: break; // INTCLR
|
||
|
case 0x0005F820: break; // DPSTTS
|
||
|
case 0x0005F822: break; // DPCTRL
|
||
|
case 0x0005F824: break; // BRTA
|
||
|
case 0x0005F826: break; // BRTB
|
||
|
case 0x0005F828: break; // BRTC
|
||
|
case 0x0005F82A: break; // REST
|
||
|
case 0x0005F82E: break; // FRMCYC
|
||
|
case 0x0005F830: break; // CTA
|
||
|
case 0x0005F840: break; // XPSTTS
|
||
|
case 0x0005F842: break; // XPCTRL
|
||
|
case 0x0005F844: break; // VER
|
||
|
case 0x0005F848: break; // SPT0
|
||
|
case 0x0005F84A: break; // SPT1
|
||
|
case 0x0005F84C: break; // SPT2
|
||
|
case 0x0005F84E: break; // SPT3
|
||
|
case 0x0005F860: break; // GPLT0
|
||
|
case 0x0005F862: break; // GPLT1
|
||
|
case 0x0005F864: break; // GPLT2
|
||
|
case 0x0005F866: break; // GPLT3
|
||
|
case 0x0005F868: break; // JPLT0
|
||
|
case 0x0005F86A: break; // JPLT1
|
||
|
case 0x0005F86C: break; // JPLT2
|
||
|
case 0x0005F86E: break; // JPLT3
|
||
|
case 0x0005F870: break; // BKCOL
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|