Introducing VIP memory controller and Characters window, fixing Format V instructions, adjusting JNI includes
This commit is contained in:
+18
-7
@@ -265,9 +265,12 @@ static int32_t cpuGetSystemRegister(Vue *vue, int32_t index) {
|
||||
|
||||
/* Transfer program to another address */
|
||||
static void cpuJump(Vue *vue, int32_t address) {
|
||||
int level = vue->cpu.psw_np ? 2 : vue->cpu.psw_ep;
|
||||
vue->cpu.jumpFrom[level] = vue->cpu.pc;
|
||||
vue->cpu.jumpTo [level] = address;
|
||||
int level;
|
||||
if (address != vue->cpu.pc) {
|
||||
level = vue->cpu.psw_np ? 2 : vue->cpu.psw_ep;
|
||||
vue->cpu.jumpFrom[level] = vue->cpu.pc;
|
||||
vue->cpu.jumpTo [level] = address;
|
||||
}
|
||||
vue->cpu.pc = address - vue->cpu.inst.size;
|
||||
}
|
||||
|
||||
@@ -490,7 +493,9 @@ static vbool cpuWrite(Vue *vue, int32_t address, int8_t type, int32_t value) {
|
||||
cpuFloat(vue->cpu.program[vue->cpu.inst.reg1]))
|
||||
|
||||
/* Add Immediate */
|
||||
#define cpuADDI(vue) cpuADD_IMM(vue)
|
||||
#define cpuADDI(vue) \
|
||||
vue->cpu.program[vue->cpu.inst.reg2] = cpuAdd(vue, \
|
||||
vue->cpu.program[vue->cpu.inst.reg1], vue->cpu.inst.imm)
|
||||
|
||||
/* And */
|
||||
#define cpuAND(vue) \
|
||||
@@ -499,7 +504,7 @@ static vbool cpuWrite(Vue *vue, int32_t address, int8_t type, int32_t value) {
|
||||
|
||||
/* And Immediate */
|
||||
#define cpuANDI(vue) \
|
||||
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] & \
|
||||
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg1] & \
|
||||
vue->cpu.inst.imm)
|
||||
|
||||
/* Branch on Condition */
|
||||
@@ -756,7 +761,7 @@ static void cpuMULU(Vue *vue) {
|
||||
|
||||
/* Or Immediate */
|
||||
#define cpuORI(vue) \
|
||||
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] | \
|
||||
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg1] | \
|
||||
vue->cpu.inst.imm)
|
||||
|
||||
/* Return from Trap or Interrupt */
|
||||
@@ -876,7 +881,7 @@ static void cpuXH(Vue *vue) {
|
||||
|
||||
/* Exclusive Or Immediate */
|
||||
#define cpuXORI(vue) \
|
||||
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg2] ^ \
|
||||
cpuBitwise(vue, vue->cpu.program[vue->cpu.inst.reg1] ^ \
|
||||
vue->cpu.inst.imm)
|
||||
|
||||
|
||||
@@ -1182,6 +1187,12 @@ static vbool cpuFetch(Vue *vue) {
|
||||
return VUE_FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Internal Functions *
|
||||
******************************************************************************/
|
||||
|
||||
/* Process the simulation */
|
||||
static void cpuEmulate(Vue *vue, uint32_t cycles) {
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ struct Vue {
|
||||
uint16_t ecr_fecc; /* Fatal Error Cause Code */
|
||||
} cpu;
|
||||
|
||||
/* Game pak */
|
||||
/* Game pak state */
|
||||
struct {
|
||||
uint8_t *ram; /* Cartridge SRAM */
|
||||
uint32_t ramSize; /* Number of bytes in cartridge SRAM */
|
||||
@@ -254,6 +254,11 @@ struct Vue {
|
||||
int8_t wcr_rom1w; /* ROM one-wait mode */
|
||||
} pak;
|
||||
|
||||
/* VIP state */
|
||||
struct {
|
||||
uint8_t vram[0x40000]; /* Video memory */
|
||||
} vip;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
/* This file is included through vue.c and cannot be built directly. */
|
||||
#ifdef VUEAPI
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Internal Functions *
|
||||
******************************************************************************/
|
||||
|
||||
/* Process the simulation */
|
||||
static void vipEmulate(Vue *vue, uint32_t cycles) {
|
||||
vue = vue;
|
||||
cycles = cycles;
|
||||
}
|
||||
|
||||
/* Read an I/O register */
|
||||
static int32_t vipReadRegister(Vue *vue, int32_t address) {
|
||||
vue=vue;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Read an I/O register */
|
||||
static void vipWriteRegister(Vue *vue, int32_t address, int32_t value) {
|
||||
vue=vue;
|
||||
value=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 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Read a value from the CPU bus */
|
||||
static int32_t vipRead(Vue *vue, int32_t address, int32_t type) {
|
||||
int32_t value; /* Register value */
|
||||
address &= 0x0007FFFF;
|
||||
|
||||
/* VRAM */
|
||||
if (address < 0x00040000)
|
||||
return readBuffer(vue->vip.vram, 0x40000, address, type);
|
||||
|
||||
/* Mirrors of character memory */
|
||||
if (address >= 0x00078000)
|
||||
return readBuffer(vue->vip.vram, 0x40000,
|
||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
||||
(address & 0x00001FFF),
|
||||
type);
|
||||
|
||||
/* I/O register or unmapped */
|
||||
value = vipReadRegister(vue, address);
|
||||
if (type < 2 && (address & 1) == 1)
|
||||
value >>= 8;
|
||||
switch (type) {
|
||||
case VUE_S8 : return SIGN_EXTEND(value, 8);
|
||||
case VUE_U8 : return value & 0x000000FF;
|
||||
case VUE_S16: return SIGN_EXTEND(value, 16);
|
||||
case VUE_S32: return value | vipReadRegister(vue, address + 2) << 16;
|
||||
}
|
||||
return value; /* U16 */
|
||||
}
|
||||
|
||||
/* Read bytes from the CPU bus */
|
||||
static void vipReadBytes(Vue *vue, int address, uint8_t *dest, int length) {
|
||||
int32_t count, size, value; /* Working variables */
|
||||
address &= 0x0007FFFF;
|
||||
|
||||
/* Perform the operation */
|
||||
while (length > 0) {
|
||||
|
||||
/* VRAM */
|
||||
if (address < 0x00040000) {
|
||||
count = 0x00040000 - address;
|
||||
if (length < count)
|
||||
count = length;
|
||||
readBytes(vue->vip.vram, 0x40000, address, dest, count);
|
||||
}
|
||||
|
||||
/* Mirrors of character memory */
|
||||
else if (address >= 0x00078000) {
|
||||
count = 0x2000 - (address & 0x1FFF);
|
||||
if (length < count)
|
||||
count = length;
|
||||
readBytes(vue->vip.vram, 0x40000,
|
||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
||||
(address & 0x00001FFF),
|
||||
dest, count);
|
||||
}
|
||||
|
||||
/* I/O register or unmapped */
|
||||
else {
|
||||
count = 0x00078000 - address;
|
||||
if (length < count)
|
||||
count = length;
|
||||
|
||||
/* Read all registers in the range */
|
||||
while (count > 0) {
|
||||
value = vipReadRegister(vue, address);
|
||||
|
||||
/* Odd address */
|
||||
if ((address & 1) == 1) {
|
||||
*dest = value >> 8;
|
||||
address++;
|
||||
count --;
|
||||
length --;
|
||||
dest ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Even address */
|
||||
size = count == 1 ? 1 : 2;
|
||||
*dest = value;
|
||||
if (size == 2)
|
||||
dest[1] = value >> 8;
|
||||
address += size;
|
||||
count -= size;
|
||||
length -= size;
|
||||
dest += size;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Advance to the next region */
|
||||
address += count;
|
||||
length -= count;
|
||||
dest += count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* System reset */
|
||||
static void vipReset(Vue *vue) {
|
||||
vue = vue;
|
||||
}
|
||||
|
||||
/* Determine the number of CPU cycles until a breakpoint could trigger */
|
||||
static uint32_t vipUntil(Vue *vue, uint32_t cycles) {
|
||||
vue = vue;
|
||||
return cycles;
|
||||
}
|
||||
|
||||
/* Write a value to the CPU bus */
|
||||
static void vipWrite(Vue *vue, int32_t address, int32_t type, int32_t value) {
|
||||
address &= 0x0007FFFF;
|
||||
|
||||
/* VRAM */
|
||||
if (address < 0x00040000) {
|
||||
writeBuffer(vue->vip.vram, 0x40000, address, type, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mirrors of character memory */
|
||||
if (address >= 0x00078000) {
|
||||
writeBuffer(vue->vip.vram, 0x40000,
|
||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
||||
(address & 0x00001FFF),
|
||||
type, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* I/O register or unmapped */
|
||||
if (type < 2 && (address & 1) == 1)
|
||||
value <<= 8;
|
||||
vipWriteRegister(vue, address, value);
|
||||
if (type == VUE_S32)
|
||||
vipWriteRegister(vue, address + 2, value >> 16);
|
||||
}
|
||||
|
||||
/* Write bytes to the CPU bus */
|
||||
static void vipWriteBytes(Vue *vue, int address, uint8_t *src, int length) {
|
||||
int32_t count, size, value; /* Working variables */
|
||||
address &= 0x0007FFFF;
|
||||
|
||||
/* Perform the operation */
|
||||
while (length > 0) {
|
||||
|
||||
/* VRAM */
|
||||
if (address < 0x00040000) {
|
||||
count = 0x00040000 - address;
|
||||
if (length < count)
|
||||
count = length;
|
||||
writeBytes(vue->vip.vram, 0x40000, address, src, count);
|
||||
}
|
||||
|
||||
/* Mirrors of character memory */
|
||||
else if (address >= 0x00078000) {
|
||||
count = 0x2000 - (address & 0x1FFF);
|
||||
if (length < count)
|
||||
count = length;
|
||||
writeBytes(vue->vip.vram, 0x40000,
|
||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
||||
(address & 0x00001FFF),
|
||||
src, count);
|
||||
}
|
||||
|
||||
/* I/O register or unmapped */
|
||||
else {
|
||||
count = 0x00078000 - address;
|
||||
if (length < count)
|
||||
count = length;
|
||||
|
||||
/* Read all registers in the range */
|
||||
while (count > 0) {
|
||||
value = *src;
|
||||
|
||||
/* Odd address */
|
||||
if ((address & 1) == 1) {
|
||||
vipWriteRegister(vue, address, value << 8);
|
||||
address++;
|
||||
count --;
|
||||
length --;
|
||||
src ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Even address */
|
||||
size = count == 1 ? 1 : 2;
|
||||
if (size == 2)
|
||||
value |= src[1] << 8;
|
||||
vipWriteRegister(vue, address, value);
|
||||
address += size;
|
||||
count -= size;
|
||||
length -= size;
|
||||
src += size;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Advance to the next region */
|
||||
address += count;
|
||||
length -= count;
|
||||
src += count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
+45
-23
@@ -22,15 +22,6 @@ static const uint32_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Component Includes *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "cpu.c"
|
||||
#include "gamepak.c"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Module Functions *
|
||||
*****************************************************************************/
|
||||
@@ -150,6 +141,16 @@ static void writeBytes(uint8_t *data, uint32_t datlen, uint32_t address,
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Component Includes *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "cpu.c"
|
||||
#include "gamepak.c"
|
||||
#include "vip.c"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Library Functions *
|
||||
*****************************************************************************/
|
||||
@@ -167,7 +168,7 @@ uint32_t vueEmulate(Vue *vue, uint32_t maxCycles) {
|
||||
/*cycles = padUntil (vue, cycles);*/
|
||||
/*cycles = linkUntil (vue, cycles);*/
|
||||
/*cycles = timerUntil(vue, cycles);*/
|
||||
/*cycles = vipUntil (vue, cycles);*/
|
||||
cycles = vipUntil (vue, cycles);
|
||||
|
||||
/* Process all system components */
|
||||
vue->breakCode = 0;
|
||||
@@ -176,7 +177,7 @@ uint32_t vueEmulate(Vue *vue, uint32_t maxCycles) {
|
||||
/*pakEmulate (vue, cycles);*/
|
||||
/*linkEmulate (vue, cycles);*/
|
||||
/*timerEmulate(vue, cycles);*/
|
||||
/*vipEmulate (vue, cycles);*/
|
||||
vipEmulate (vue, cycles);
|
||||
/*vsuEmulate (vue, cycles);*/
|
||||
maxCycles -= cycles;
|
||||
} while (vue->breakCode == 0 && maxCycles != 0);
|
||||
@@ -288,16 +289,6 @@ VueOnAccess vueOnWrite(Vue *vue, VueOnAccess callback) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Specify a new application reference */
|
||||
void* vueSetTag(Vue *vue, void *tag) {
|
||||
void *ret;
|
||||
if (vue == NULL)
|
||||
return NULL;
|
||||
ret = vue->tag;
|
||||
vue->tag = tag;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read a value from the CPU bus */
|
||||
int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
|
||||
|
||||
@@ -307,6 +298,7 @@ int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
|
||||
|
||||
/* Perform the operation */
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: return vipRead (vue , address,type);
|
||||
case 5: return readBuffer(vue->wram , 0x10000,address,type);
|
||||
case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type);
|
||||
case 7: return readBuffer(vue->pak.rom,vue->pak.romSize,address,type);
|
||||
@@ -328,6 +320,8 @@ vbool vueReadBytes(Vue *vue, uint32_t address, uint8_t *dest, uint32_t length){
|
||||
if (length < count)
|
||||
count = length;
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: vipReadBytes(vue ,
|
||||
address, dest, count); break;
|
||||
case 5: readBytes(vue->wram , 0x10000,
|
||||
address, dest, count); break;
|
||||
case 6: readBytes(vue->pak.ram, vue->pak.ramSize,
|
||||
@@ -363,8 +357,22 @@ void vueReset(Vue *vue) {
|
||||
|
||||
/* Specify a value for a register */
|
||||
int32_t vueSetRegister(Vue *vue, int32_t index, vbool system, int32_t value) {
|
||||
return vue == NULL ? 0 :
|
||||
index == VUE_PC && system ? vue->cpu.pc = value & 0xFFFFFFFE :
|
||||
|
||||
/* Error checking */
|
||||
if (vue == NULL)
|
||||
return 0;
|
||||
|
||||
/* PC */
|
||||
if (index == VUE_PC && system) {
|
||||
if (vue->cpu.stage == CPU_EXECUTE || vue->cpu.stage == CPU_FETCH) {
|
||||
vue->cpu.fetch = -1;
|
||||
vue->cpu.stage = CPU_FETCH;
|
||||
}
|
||||
return vue->cpu.pc = value & 0xFFFFFFFE;
|
||||
}
|
||||
|
||||
/* Other */
|
||||
return
|
||||
index < 0 || index > 31 ? 0 :
|
||||
system ? cpuSetSystemRegister(vue, index, value, VUE_TRUE) :
|
||||
index == 0 ? 0 : (vue->cpu.program[index] = value)
|
||||
@@ -388,6 +396,16 @@ vbool vueSetROM(Vue *vue, uint8_t *rom, uint32_t size) {
|
||||
return VUE_TRUE;
|
||||
}
|
||||
|
||||
/* Specify a new application reference */
|
||||
void* vueSetTag(Vue *vue, void *tag) {
|
||||
void *ret;
|
||||
if (vue == NULL)
|
||||
return NULL;
|
||||
ret = vue->tag;
|
||||
vue->tag = tag;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write a value to the CPU bus */
|
||||
void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
|
||||
|
||||
@@ -397,6 +415,8 @@ void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
|
||||
|
||||
/* Perform the operation */
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: vipWrite(vue ,
|
||||
address, type, value); break;
|
||||
case 5: writeBuffer(vue->wram , 0x10000,
|
||||
address, type, value); break;
|
||||
case 6: writeBuffer(vue->pak.ram, vue->pak.ramSize,
|
||||
@@ -421,6 +441,8 @@ vbool vueWriteBytes(Vue *vue, uint32_t address, uint8_t *src, uint32_t length){
|
||||
if (length < count)
|
||||
count = length;
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: vipWriteBytes(vue ,
|
||||
address, src, count); break;
|
||||
case 5: writeBytes(vue->wram , 0x10000,
|
||||
address, src, count); break;
|
||||
case 6: writeBytes(vue->pak.ram, vue->pak.ramSize,
|
||||
|
||||
@@ -23,6 +23,7 @@ public class App {
|
||||
int hexDigitWidth; // Width in pixels of one hex digit
|
||||
Localizer localizer; // UI localization manager
|
||||
int[][] rgbBase; // Base anaglyph filter colors
|
||||
int rgbClear; // Transparent pixel color
|
||||
|
||||
|
||||
|
||||
@@ -36,11 +37,6 @@ public class App {
|
||||
static final int[] GREEN = { 0x00, 0xB4, 0x00 };
|
||||
static final int[] MAGENTA = { 0xC8, 0x00, 0xFF };
|
||||
|
||||
// Eyes
|
||||
static final int LEFT = 0;
|
||||
static final int RIGHT = 1;
|
||||
static final int CHR = 2;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -60,6 +56,7 @@ public class App {
|
||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14));
|
||||
hexDigitWidth = hexDigitWidth();
|
||||
rgbBase = new int[][] { GREEN, MAGENTA, RED };
|
||||
rgbClear = 0x003050;
|
||||
|
||||
// Additional processing
|
||||
setUseNative(useNative);
|
||||
|
||||
@@ -25,11 +25,11 @@ class BreakpointsWindow extends ChildWindow {
|
||||
private JCheckBox chkExecute; // Execute check box
|
||||
private JCheckBox chkRead; // Read check box
|
||||
private JCheckBox chkWrite; // Write check box
|
||||
private JPanel client; // Client area
|
||||
private UPanel client; // Client area
|
||||
private JLabel errAddress; // Address error text
|
||||
private JLabel errCondition; // Condition error text
|
||||
private JPanel lstBreakpoints; // Breakpoint list
|
||||
private JPanel spacer; // List termination spacer
|
||||
private UPanel lstBreakpoints; // Breakpoint list
|
||||
private UPanel spacer; // List termination spacer
|
||||
private JTextField txtAddress; // Address text box
|
||||
private JTextField txtCondition; // Condition text box
|
||||
private JTextField txtName; // Name text box
|
||||
@@ -161,31 +161,29 @@ class BreakpointsWindow extends ChildWindow {
|
||||
selectedIndex = -1;
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(new BorderLayout());
|
||||
client = new UPanel(new BorderLayout());
|
||||
client.setBackground(SystemColor.control);
|
||||
client.setFocusable(true);
|
||||
client.setPreferredSize(new Dimension(320, 240));
|
||||
|
||||
// Configure breakpoint list
|
||||
lstBreakpoints = new JPanel(new GridBagLayout()) {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaint((Graphics2D) g, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
lstBreakpoints = new UPanel(new GridBagLayout());
|
||||
lstBreakpoints.setFocusable(true);
|
||||
lstBreakpoints.setBackground(SystemColor.window);
|
||||
lstBreakpoints.addFocusListener(Util.onFocus(
|
||||
e->lstBreakpoints.repaint(), e->lstBreakpoints.repaint()));
|
||||
lstBreakpoints.addMouseListener(Util.onMouse(e->onMouseDown(e), null));
|
||||
lstBreakpoints.addPaintListener((g,w,h)->onPaint(g, w, h));
|
||||
var scr = new JScrollPane(lstBreakpoints);
|
||||
scr.getVerticalScrollBar().setUnitIncrement(
|
||||
parent.app.fntDialog.metrics.getHeight());
|
||||
client.add(scr, BorderLayout.CENTER);
|
||||
spacer = new JPanel();
|
||||
spacer = new UPanel();
|
||||
spacer.setOpaque(false);
|
||||
lstBreakpoints.add(spacer, SPACER);
|
||||
|
||||
// Configure properties pane
|
||||
var props = new JPanel(new GridBagLayout());
|
||||
var props = new UPanel(new GridBagLayout());
|
||||
props.setBackground(SystemColor.control);
|
||||
props.addMouseListener(
|
||||
Util.onMouse(e->client.requestFocus(), null));
|
||||
@@ -215,12 +213,12 @@ class BreakpointsWindow extends ChildWindow {
|
||||
errCondition = error(props);
|
||||
|
||||
// Configure buttons
|
||||
var buttons = new JPanel(new GridBagLayout());
|
||||
var buttons = new UPanel(new GridBagLayout());
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
props.add(buttons, gbc);
|
||||
var fill = new JPanel();
|
||||
var fill = new UPanel();
|
||||
fill.setOpaque(false);
|
||||
fill.addMouseListener(Util.onMouse(e->onDebug(e), null));
|
||||
gbc = new GridBagConstraints();
|
||||
@@ -448,7 +446,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Add a button to the form
|
||||
private JButton button(JPanel panel, String key, boolean last) {
|
||||
private JButton button(UPanel panel, String key, boolean last) {
|
||||
var btn = new JButton();
|
||||
if (key != null)
|
||||
parent.app.localizer.add(btn, key);
|
||||
@@ -462,7 +460,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add a check box to the form
|
||||
private JCheckBox checkBox(JPanel panel, String key, boolean last) {
|
||||
private JCheckBox checkBox(UPanel panel, String key, boolean last) {
|
||||
var chk = new JCheckBox();
|
||||
if (key != null)
|
||||
parent.app.localizer.add(chk, key);
|
||||
@@ -509,7 +507,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add an error label to the form
|
||||
private JLabel error(JPanel panel) {
|
||||
private JLabel error(UPanel panel) {
|
||||
var lbl = new JLabel();
|
||||
lbl.setForeground(Color.red);
|
||||
lbl.setVisible(false);
|
||||
@@ -524,7 +522,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add a label to the form
|
||||
private void label(JPanel panel, String key, int top) {
|
||||
private void label(UPanel panel, String key, int top) {
|
||||
var lbl = new JLabel();
|
||||
if (key != null)
|
||||
parent.app.localizer.add(lbl, key);
|
||||
@@ -594,7 +592,7 @@ class BreakpointsWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add a text box to the form
|
||||
private JTextField textBox(JPanel panel, boolean mono, int top,
|
||||
private JTextField textBox(UPanel panel, boolean mono, int top,
|
||||
Commit handler) {
|
||||
var txt = new JTextField();
|
||||
txt.setEnabled(false);
|
||||
|
||||
@@ -13,14 +13,29 @@ import util.*;
|
||||
class CharactersWindow extends ChildWindow {
|
||||
|
||||
// Instance fields
|
||||
private int color; // Selected color index
|
||||
private int color; // Selected color index
|
||||
private Point dragging; // Most recent pattern mouse position
|
||||
private int index; // Current character index
|
||||
private boolean grid; // Draw a grid around characters
|
||||
private int palette; // Palette index
|
||||
private int scale; // Display scale
|
||||
private int wide; // Number of characters per row
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
private JPanel panCharacters; // Characters panel
|
||||
private JPanel panPalette; // Palette panel
|
||||
private JPanel panPattern; // Pattern panel
|
||||
private JCheckBox chkGrid; // Grid check box
|
||||
private UPanel client; // Client area
|
||||
private UPanel panCharacters; // Characters panel
|
||||
private UPanel panPalette; // Palette panel
|
||||
private UPanel panPattern; // Pattern panel
|
||||
private JScrollPane scrCharacters; // Characters container
|
||||
private JScrollPane scrControls; // Controls panel
|
||||
private JScrollBar scrWidth; // Width template scroll bar
|
||||
private JSlider sldScale; // Scale slider
|
||||
private JSpinner spnIndex; // Index spinner
|
||||
private JSpinner spnWide; // Wide spinner
|
||||
private JTextField txtAddress; // Address text box
|
||||
private JTextField txtMirror; // Mirror text box
|
||||
private JComboBox<String> cmbPalette; // Palette drop-down
|
||||
|
||||
|
||||
|
||||
@@ -34,16 +49,21 @@ class CharactersWindow extends ChildWindow {
|
||||
|
||||
// Configure instance fields
|
||||
color = 0;
|
||||
grid = true;
|
||||
scale = 3;
|
||||
|
||||
// Template scroll bar to check control width in the current LAF
|
||||
scrWidth = new JScrollBar(JScrollBar.VERTICAL);
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(new BorderLayout());
|
||||
client = new UPanel(new BorderLayout());
|
||||
client.setBackground(SystemColor.control);
|
||||
client.setFocusable(true);
|
||||
client.setPreferredSize(new Dimension(480, 360));
|
||||
client.addComponentListener(Util.onResize(e->onResize()));
|
||||
|
||||
// Configure controls panel
|
||||
var ctrls = new JPanel(new GridBagLayout());
|
||||
var ctrls = new UPanel(new GridBagLayout());
|
||||
ctrls.setBackground(SystemColor.control);
|
||||
ctrls.addMouseListener(
|
||||
Util.onMouse(e->client.requestFocus(), null));
|
||||
@@ -54,17 +74,29 @@ class CharactersWindow extends ChildWindow {
|
||||
scrControls.getVerticalScrollBar().setUnitIncrement(20);
|
||||
client.add(scrControls, BorderLayout.WEST);
|
||||
|
||||
// Character controls
|
||||
label(ctrls, "characters.index", true);
|
||||
spinner(ctrls, 0, 2047, 0, true);
|
||||
spnIndex = spinner(ctrls, 0, 2047, 0, true);
|
||||
spnIndex.addChangeListener(e->{
|
||||
setIndex((Integer) spnIndex.getValue()); });
|
||||
label(ctrls, "characters.address", false);
|
||||
textBox(ctrls);
|
||||
txtAddress = textBox(ctrls);
|
||||
txtAddress.addFocusListener(Util.onFocus(null,
|
||||
e->onAddress(txtAddress)));
|
||||
label(ctrls, "characters.mirror", false);
|
||||
textBox(ctrls);
|
||||
txtMirror = textBox(ctrls);
|
||||
txtMirror.addFocusListener(Util.onFocus(null,
|
||||
e->onAddress(txtMirror)));
|
||||
|
||||
// Pattern panel
|
||||
var panPattern = new JPanel();
|
||||
panPattern.setBackground(Color.black);
|
||||
panPattern = new UPanel();
|
||||
panPattern.setOpaque(false);
|
||||
panPattern.setPreferredSize(new Dimension(96, 96));
|
||||
panPattern.addMouseListener(
|
||||
Util.onMouse(e->onMousePattern(e), e->onMousePattern(e)));
|
||||
panPattern.addMouseMotionListener(
|
||||
Util.onMouseMove(null, e->onMousePattern(e)));
|
||||
panPattern.addPaintListener((g,w,h)->onPaintPattern(g, w, h));
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
@@ -72,16 +104,12 @@ class CharactersWindow extends ChildWindow {
|
||||
ctrls.add(panPattern, gbc);
|
||||
|
||||
// Palette panel
|
||||
panPalette = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaintPalette((Graphics2D) g, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
panPalette = new UPanel();
|
||||
panPalette.setOpaque(false);
|
||||
panPalette.setPreferredSize(new Dimension(0, 20 + 6));
|
||||
panPalette.addMouseListener(
|
||||
Util.onMouse(e->onMouseDownPalette(e), null));
|
||||
panPalette.addPaintListener((g,w,h)->onPaintPalette(g, w, h));
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
@@ -89,27 +117,37 @@ class CharactersWindow extends ChildWindow {
|
||||
ctrls.add(panPalette, gbc);
|
||||
|
||||
// Fill the extra space above the view controls
|
||||
var spacer = new JPanel();
|
||||
var spacer = new UPanel();
|
||||
spacer.setOpaque(false);
|
||||
gbc = new GridBagConstraints();
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
gbc.weighty = 1;
|
||||
ctrls.add(spacer, gbc);
|
||||
|
||||
// View controls
|
||||
label(ctrls, "characters.grid", false);
|
||||
checkBox(ctrls).setSelected(true);
|
||||
chkGrid = checkBox(ctrls);
|
||||
chkGrid.setSelected(grid);
|
||||
chkGrid.addActionListener(e->{
|
||||
grid = chkGrid.isSelected(); onView(); });
|
||||
label(ctrls, "characters.wide", false);
|
||||
spinner(ctrls, 0, 2048, 0, false);
|
||||
spnWide = spinner(ctrls, 0, 2048, 0, false);
|
||||
spnWide.addChangeListener(e->{
|
||||
wide = (Integer) spnWide.getValue(); onView(); });
|
||||
label(ctrls, "characters.palette", false);
|
||||
select(ctrls, new String[] { "palette.generic",
|
||||
cmbPalette = select(ctrls, new String[] { "palette.generic",
|
||||
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3",
|
||||
"palette.jplt0", "palette.jplt1", "palette.jplt2", "palette.jplt3"
|
||||
});
|
||||
cmbPalette.addActionListener(e->{
|
||||
palette = cmbPalette.getSelectedIndex(); repaint(); });
|
||||
label(ctrls, "characters.scale", false);
|
||||
slider(ctrls, 1, 10, 1);
|
||||
sldScale = slider(ctrls, 1, 10, scale);
|
||||
sldScale.addChangeListener(e->{
|
||||
scale = sldScale.getValue(); onView(); });
|
||||
|
||||
// Terminate the list of controls
|
||||
spacer = new JPanel();
|
||||
spacer = new UPanel();
|
||||
spacer.setOpaque(false);
|
||||
spacer.setPreferredSize(new Dimension(0, 0));
|
||||
gbc = new GridBagConstraints();
|
||||
@@ -118,20 +156,17 @@ class CharactersWindow extends ChildWindow {
|
||||
ctrls.add(spacer, gbc);
|
||||
|
||||
// Configure characters panel
|
||||
panCharacters = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaintCharacters((Graphics2D) g, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
panCharacters = new UPanel();
|
||||
panCharacters.setBackground(SystemColor.control);
|
||||
panCharacters.addMouseListener(
|
||||
Util.onMouse(e->client.requestFocus(), null));
|
||||
var scr = new JScrollPane(panCharacters);
|
||||
client.add(scr, BorderLayout.CENTER);
|
||||
Util.onMouse(e->onMouseDownCharacters(e), null));
|
||||
panCharacters.addPaintListener((g,w,h)->onPaintCharacters(g, w, h));
|
||||
scrCharacters = new JScrollPane(panCharacters);
|
||||
client.add(scrCharacters, BorderLayout.CENTER);
|
||||
|
||||
// Configure component
|
||||
setContentPane(client);
|
||||
setIndex(0);
|
||||
pack();
|
||||
}
|
||||
|
||||
@@ -152,6 +187,64 @@ class CharactersWindow extends ChildWindow {
|
||||
// Event Handlers //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Address and Mirror text box commit
|
||||
private void onAddress(JTextField src) {
|
||||
int address;
|
||||
|
||||
// Parse the given address
|
||||
try { address = (int) Long.parseLong(src.getText(), 16); }
|
||||
catch (Exception e) {
|
||||
setIndex(index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Restrict address range
|
||||
if ((address >> 24 & 7) != 0) {
|
||||
setIndex(index);
|
||||
return;
|
||||
}
|
||||
address &= 0x0007FFFF;
|
||||
|
||||
// Character memory
|
||||
if ((address & 0x00066000) == 0x00006000)
|
||||
index = address >> 15 << 9 | address >> 4 & 511;
|
||||
|
||||
// Mirror of character memory
|
||||
else if (address >= 0x00078000)
|
||||
index = address - 0x00078000 >> 4;
|
||||
|
||||
// Common processing
|
||||
setIndex(index);
|
||||
}
|
||||
|
||||
// Characters mouse button press
|
||||
private void onMouseDownCharacters(MouseEvent e) {
|
||||
|
||||
// Common processing
|
||||
client.requestFocus();
|
||||
|
||||
// Only consider left clicks
|
||||
if (e.getButton() != MouseEvent.BUTTON1)
|
||||
return;
|
||||
|
||||
// Working variables
|
||||
int grid = this.grid ? 1 : 0;
|
||||
int size = 8 * scale + grid;
|
||||
int wide = this.wide != 0 ? this.wide :
|
||||
Math.max(1, (panCharacters.getWidth() + grid) / size);
|
||||
int col = e.getX() / size;
|
||||
int row = e.getY() / size;
|
||||
|
||||
// The pixel is not within a character
|
||||
if (col >= wide || row >= (2047 + wide) / wide)
|
||||
return;
|
||||
|
||||
// Calculate the index of the selected character
|
||||
int index = row * wide + col;
|
||||
if (index < 2048)
|
||||
setIndex(index);
|
||||
}
|
||||
|
||||
// Palette mouse button press
|
||||
private void onMouseDownPalette(MouseEvent e) {
|
||||
|
||||
@@ -183,16 +276,154 @@ class CharactersWindow extends ChildWindow {
|
||||
panPalette.repaint();
|
||||
}
|
||||
|
||||
// Pattern mouse
|
||||
private void onMousePattern(MouseEvent e) {
|
||||
int id = e.getID();
|
||||
|
||||
// Mouse release
|
||||
if (id == MouseEvent.MOUSE_RELEASED) {
|
||||
if (e.getButton() == MouseEvent.BUTTON1)
|
||||
dragging = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Mouse press
|
||||
if (id == MouseEvent.MOUSE_PRESSED) {
|
||||
if (e.getButton() != MouseEvent.BUTTON1)
|
||||
return;
|
||||
dragging = e.getPoint();
|
||||
}
|
||||
|
||||
// Not dragging
|
||||
if (dragging == null)
|
||||
return;
|
||||
|
||||
// Configure working variables
|
||||
var pix = parent.chrs[index];
|
||||
var pos = e.getPoint();
|
||||
int scale = Math.max(1, Math.min(
|
||||
panPattern.getWidth() / 8, panPattern.getHeight() / 8));
|
||||
|
||||
// Determine the bounds of the line segment
|
||||
int left = Math.min(dragging.x, pos.x) / scale;
|
||||
int right = (Math.max(dragging.x, pos.x) - 1) / scale;
|
||||
int top = Math.min(dragging.y, pos.y) / scale;
|
||||
int bottom = (Math.max(dragging.y, pos.y) - 1) / scale;
|
||||
if (left >= 8 || right < 0 || top >= 8 || bottom < 0) {
|
||||
dragging = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
// The line segment occupies a single column of pixels
|
||||
if (left == right) {
|
||||
top = Math.max(0, top );
|
||||
bottom = Math.min(7, bottom);
|
||||
|
||||
// Draw the column
|
||||
for (
|
||||
int y = top, dest = left + top * 8;
|
||||
y <= bottom;
|
||||
y++, dest += 8
|
||||
) pix[dest] = (byte) color;
|
||||
|
||||
// Update the current VRAM state
|
||||
parent.encode(index);
|
||||
dragging = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate and order the vertex coordinates
|
||||
float v0x = (float) dragging.x / scale;
|
||||
float v0y = (float) dragging.y / scale;
|
||||
float v1x = (float) pos .x / scale;
|
||||
float v1y = (float) pos .y / scale;
|
||||
if (v0x > v1x) {
|
||||
float t = v0x; v0x = v1x; v1x = t;
|
||||
t = v0y; v0y = v1y; v1y = t;
|
||||
}
|
||||
|
||||
// Determine the starting position of the line segment
|
||||
float slope = (v1y - v0y) / (v1x - v0x);
|
||||
float cur, next;
|
||||
if (v0x < 0) {
|
||||
left = 0;
|
||||
cur = v0y - slope * v0x;
|
||||
next = cur + slope;
|
||||
} else {
|
||||
cur = v0y;
|
||||
next = v0y + slope * (1 - v0x % 1);
|
||||
}
|
||||
|
||||
// Draw all columns of pixels
|
||||
int last = Math.min(7, right);
|
||||
for (int x = left; x <= last; x++) {
|
||||
|
||||
// The column is the final column in the line segment
|
||||
if (x == right)
|
||||
next = v1y;
|
||||
|
||||
// Determine the top and bottom rows of pixels
|
||||
v0y = Math.max(cur, next);
|
||||
if (v0y % 1 == 0)
|
||||
v0y--;
|
||||
top = Math.max(0, (int) Math.floor(Math.min(cur, next)));
|
||||
bottom = Math.min(7, (int) Math.floor(v0y ));
|
||||
|
||||
// Draw the column
|
||||
for (
|
||||
int y = top, dest = x + top * 8;
|
||||
y <= bottom;
|
||||
y++, dest += 8
|
||||
) pix[dest] = (byte) color;
|
||||
|
||||
// Advance to the next column
|
||||
cur = next;
|
||||
next += slope;
|
||||
}
|
||||
|
||||
// Update the current VRAM state
|
||||
parent.encode(index);
|
||||
dragging = pos;
|
||||
}
|
||||
|
||||
// Characters paint
|
||||
private void onPaintCharacters(Graphics2D g, int width, int height) {
|
||||
g.setColor(new Color(0x001830));
|
||||
g.fillRect(0, 0, 256, 512);
|
||||
var clear = new Color(parent.app.rgbClear);
|
||||
int grid = this.grid ? 1 : 0;
|
||||
var pal = parent.palettes[palette][MainWindow.RED];
|
||||
var pix = new byte[64];
|
||||
int size = scale * 8 + grid;
|
||||
int wide = this.wide != 0 ? this.wide :
|
||||
Math.max(1, (width + grid) / size);
|
||||
int tall = (2047 + wide) / wide;
|
||||
|
||||
// Draw all characters
|
||||
for (int Y = 0, y = 0, z = 0; y < tall; y++, Y += size)
|
||||
for (int X = 0, x = 0; x < wide; x++, z++, X += size) {
|
||||
if (z == 2048)
|
||||
break;
|
||||
g.setColor(clear);
|
||||
g.fillRect(X, Y, size - grid, size - grid);
|
||||
drawCharacter(g, X, Y, scale, z, pal);
|
||||
}
|
||||
|
||||
// Highlight the selected character
|
||||
int X = index % wide * size;
|
||||
int Y = index / wide * size;
|
||||
int light = SystemColor.textHighlight.getRGB() & 0x00FFFFFF;
|
||||
g.setColor(new Color(0xD0000000 | light, true));
|
||||
g.drawRect(X , Y , 8 * scale - 1, 8 * scale - 1);
|
||||
g.setColor(new Color(0x90000000 | light, true));
|
||||
g.drawRect(X + 1, Y + 1, 8 * scale - 3, 8 * scale - 3);
|
||||
g.setColor(new Color(0x50000000 | light, true));
|
||||
g.fillRect(X + 2, Y + 2, 8 * scale - 4, 8 * scale - 4);
|
||||
}
|
||||
|
||||
// Palette paint
|
||||
private void onPaintPalette(Graphics2D g, int width, int height) {
|
||||
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
||||
int left = (width - size * 4 - 18) / 2;
|
||||
var pal = parent.palettes[palette][MainWindow.RED];
|
||||
int top = (height - size - 6) / 2;
|
||||
|
||||
// Draw the color picker
|
||||
@@ -207,27 +438,85 @@ class CharactersWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Draw the color area
|
||||
g.setColor(Color.black);
|
||||
g.setColor(x == 0 ? new Color(parent.app.rgbClear) : pal[x]);
|
||||
g.fillRect(left + 3, top + 3, size , size );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Pattern paint
|
||||
private void onPaintPattern(Graphics2D g, int width, int height) {
|
||||
int scale = Math.max(1, Math.min(width >> 3, height >> 3));
|
||||
int x = (width - (scale << 3) + 1) >> 1;
|
||||
int y = (height - (scale << 3) + 1) >> 1;
|
||||
g.setColor(new Color(parent.app.rgbClear));
|
||||
g.fillRect(x, y, scale * 8, scale * 8);
|
||||
drawCharacter(g, x, y, scale, index,
|
||||
parent.palettes[palette][MainWindow.RED]);
|
||||
}
|
||||
|
||||
// Window resize
|
||||
private void onResize() {
|
||||
var viewport = scrControls.getViewport();
|
||||
int inner = viewport.getView().getPreferredSize().width;
|
||||
int outer = viewport.getExtentSize().width;
|
||||
|
||||
// The controls container does not need to be resized
|
||||
if (inner == outer)
|
||||
return;
|
||||
|
||||
// Size the controls container to match the inner component
|
||||
scrControls.setPreferredSize(new Dimension(
|
||||
scrControls.getPreferredSize().width + inner - outer, 0));
|
||||
scrControls.revalidate();
|
||||
scrControls.repaint();
|
||||
if (inner != outer) {
|
||||
scrControls.setPreferredSize(new Dimension(
|
||||
scrControls.getPreferredSize().width + inner - outer, 0));
|
||||
scrControls.revalidate();
|
||||
scrControls.repaint();
|
||||
}
|
||||
|
||||
// The number of characters per row is dynamic
|
||||
if (wide == 0) {
|
||||
var bar = scrWidth.getPreferredSize().width;
|
||||
var border = scrCharacters.getBorder();
|
||||
int grid = this.grid ? 1 : 0;
|
||||
var insets = border == null ? new Insets(0, 0, 0, 0) :
|
||||
border.getBorderInsets(scrCharacters);
|
||||
var size = new Dimension(
|
||||
scrCharacters.getWidth () - insets.left - insets.right,
|
||||
scrCharacters.getHeight() - insets.top - insets.bottom
|
||||
);
|
||||
|
||||
// Calculate the dimensions without the vertical scroll bar
|
||||
int wide = Math.max(1, (size.width + grid) / (8 * scale + grid));
|
||||
int height = (2047 + wide) / wide * (8 * scale + grid) - grid;
|
||||
|
||||
// Calculate the dimensions with the vertical scroll bar
|
||||
if (height > size.height) {
|
||||
wide = Math.max(1, (size.width-bar+grid) / (8 * scale + grid));
|
||||
height = (2047 + wide) / wide * (8 * scale + grid) - grid;
|
||||
}
|
||||
|
||||
// Configure the component
|
||||
panCharacters.setPreferredSize(
|
||||
new Dimension(wide * (8 * scale + grid) - grid, height));
|
||||
panCharacters.revalidate();
|
||||
panCharacters.repaint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// View control changed
|
||||
private void onView() {
|
||||
|
||||
// Number of characters per row is dynamic: defer to resize processing
|
||||
if (wide == 0) {
|
||||
onResize();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the space occupied by the character images
|
||||
int grid = this.grid ? 1 : 0;
|
||||
panCharacters.setPreferredSize(new Dimension(
|
||||
wide * (scale * 8 + grid) - grid,
|
||||
(2047 + wide) / wide * (scale * 8 + grid) - grid
|
||||
));
|
||||
panCharacters.revalidate();
|
||||
panCharacters.repaint();
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +526,7 @@ class CharactersWindow extends ChildWindow {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Add a check box to the controls panel
|
||||
private JCheckBox checkBox(JPanel panel) {
|
||||
private JCheckBox checkBox(UPanel panel) {
|
||||
var chk = new JCheckBox();
|
||||
chk.setBorder(null);
|
||||
chk.setFocusable(false);
|
||||
@@ -249,8 +538,21 @@ class CharactersWindow extends ChildWindow {
|
||||
return chk;
|
||||
}
|
||||
|
||||
// Draw a character
|
||||
private void drawCharacter(Graphics2D g, int X, int Y, int scale,
|
||||
int index, Color[] pal) {
|
||||
var pix = parent.chrs[index];
|
||||
for (int y = 0, src = 0; y < 8; y++)
|
||||
for (int x = 0; x < 8; x++, src++) {
|
||||
if (pix[src] == 0)
|
||||
continue;
|
||||
g.setColor(pal[pix[src]]);
|
||||
g.fillRect(X + x * scale, Y + y * scale, scale, scale);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a label to the controls panel
|
||||
private void label(JPanel panel, String key, boolean top) {
|
||||
private void label(UPanel panel, String key, boolean top) {
|
||||
var lbl = new JLabel();
|
||||
parent.app.localizer.add(lbl, key);
|
||||
var gbc = new GridBagConstraints();
|
||||
@@ -260,7 +562,7 @@ class CharactersWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add a combo box to the controls panel
|
||||
private JComboBox<String> select(JPanel panel, String[] options) {
|
||||
private JComboBox<String> select(UPanel panel, String[] options) {
|
||||
var cmb = new JComboBox<String>();
|
||||
parent.app.localizer.add(cmb, options);
|
||||
cmb.setSelectedIndex(0);
|
||||
@@ -272,8 +574,19 @@ class CharactersWindow extends ChildWindow {
|
||||
return cmb;
|
||||
}
|
||||
|
||||
// Specify the current character index
|
||||
private void setIndex(int index) {
|
||||
this.index = index;
|
||||
spnIndex.setValue(index);
|
||||
txtAddress.setText(String.format("%08X",
|
||||
index >> 9 << 15 | 0x00006000 | (index & 511) << 4));
|
||||
txtMirror .setText(String.format("%08X",
|
||||
index << 4 | 0x00078000));
|
||||
repaint();
|
||||
}
|
||||
|
||||
// Add a slider to the controls panel
|
||||
private JSlider slider(JPanel panel, int min, int max, int value) {
|
||||
private JSlider slider(UPanel panel, int min, int max, int value) {
|
||||
var sld = new JSlider(min, max, value);
|
||||
sld.setFocusable(false);
|
||||
sld.setPreferredSize(new Dimension(0, sld.getPreferredSize().height));
|
||||
@@ -286,10 +599,12 @@ class CharactersWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add a spinner to the controls panel
|
||||
private JSpinner spinner(JPanel panel, int min, int max, int value,
|
||||
private JSpinner spinner(UPanel panel, int min, int max, int value,
|
||||
boolean top) {
|
||||
var spn = new JSpinner(new SpinnerNumberModel(value, min, max, 1));
|
||||
spn.setEditor(new JSpinner.NumberEditor(spn, "#"));
|
||||
var txt = new JSpinner.NumberEditor(spn, "#");
|
||||
txt.getTextField().addActionListener(e->client.requestFocus());
|
||||
spn.setEditor(txt);
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
@@ -300,9 +615,10 @@ class CharactersWindow extends ChildWindow {
|
||||
}
|
||||
|
||||
// Add a text box to the controls panel
|
||||
private JTextField textBox(JPanel panel) {
|
||||
private JTextField textBox(UPanel panel) {
|
||||
var txt = new JTextField();
|
||||
txt.setFont(parent.app.fntMono);
|
||||
txt.addActionListener(e->client.requestFocus());
|
||||
var size = txt.getPreferredSize();
|
||||
txt.setPreferredSize(new Dimension(
|
||||
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
|
||||
|
||||
@@ -21,7 +21,7 @@ class DisassemblerPane extends JScrollPane {
|
||||
private int[] widths; // Column widths
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
private UPanel client; // Client area
|
||||
private ArrayList<Row> rows; // Disassembler output
|
||||
|
||||
|
||||
@@ -53,12 +53,7 @@ class DisassemblerPane extends JScrollPane {
|
||||
widths = new int[5];
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaint((Graphics2D) g, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
client = new UPanel();
|
||||
client.setBackground(SystemColor.window);
|
||||
client.setFocusable(true);
|
||||
client.addFocusListener(
|
||||
@@ -66,6 +61,7 @@ class DisassemblerPane extends JScrollPane {
|
||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
||||
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
|
||||
client.addMouseWheelListener(e->onMouseWheel(e));
|
||||
client.addPaintListener((g,w,h)->onPaint(g, w, h));
|
||||
|
||||
// Configure component
|
||||
setViewportView(client);
|
||||
|
||||
@@ -15,11 +15,12 @@ import vue.*;
|
||||
class MainWindow extends JFrame {
|
||||
|
||||
// Instance fields
|
||||
App app; // Containing application
|
||||
Breakpoint brkStep; // Single step internal breakpoint
|
||||
int[][][] palettes; // Raster palettes
|
||||
byte[] vram; // Snapshot of VIP memory
|
||||
Vue vue; // Emulation core context
|
||||
App app; // Containing application
|
||||
Breakpoint brkStep; // Single step internal breakpoint
|
||||
byte[][] chrs; // Decoded pixel patterns
|
||||
Color[][][] palettes; // Raster palettes
|
||||
byte[] vram; // Snapshot of VIP memory
|
||||
Vue vue; // Emulation core context
|
||||
|
||||
// Private fields
|
||||
private boolean debugMode; // Window is in debug mode
|
||||
@@ -30,10 +31,10 @@ class MainWindow extends JFrame {
|
||||
private File romFile; // Currently loaded ROM file
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Common client container
|
||||
private UPanel client; // Common client container
|
||||
private JDesktopPane desktop; // Container for child windows
|
||||
private JMenu mnuDebug; // Debug menu
|
||||
private JPanel video; // Video output
|
||||
private UPanel video; // Video output
|
||||
private JMenuItem mnuFileDebugMode; // File -> Debug mode
|
||||
private JMenuItem mnuFileGameMode; // File -> Game mode
|
||||
|
||||
@@ -74,17 +75,6 @@ class MainWindow extends JFrame {
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Static Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Calculate the address of a character by index
|
||||
static int chrAddress(int index) {
|
||||
return index >> 9 << 15 | (index & 511) << 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -95,26 +85,29 @@ class MainWindow extends JFrame {
|
||||
|
||||
// Configure instance fields
|
||||
this.app = app;
|
||||
palettes = new int[9][3][4];
|
||||
chrs = new byte[2048][64];
|
||||
palettes = new Color[9][3][4];
|
||||
pwd = Util.PWD;
|
||||
vram = new byte[0x40000];
|
||||
vue = Vue.create(app.getUseNative());
|
||||
System.out.println("Native: " +
|
||||
(vue.isNative() ? Vue.getNativeID() : "No"));
|
||||
//vue.write(0x00078000, Vue.S32, -1);
|
||||
|
||||
// Initialize palettes
|
||||
var invis = new Color(0, true);
|
||||
for (int x = 0; x < 9; x++)
|
||||
for (int y = 0; y < 3; y++)
|
||||
for (int z = 0; z < 4; z++)
|
||||
palettes[x][y][z] = invis;
|
||||
|
||||
// Configure video pane
|
||||
video = new JPanel() {
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
onPaintVideo((Graphics2D) g, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
video = new UPanel();
|
||||
video.setPreferredSize(new Dimension(384, 224));
|
||||
video.setFocusable(true);
|
||||
video.addPaintListener((g,w,h)->onPaintVideo(g, w, h));
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(new BorderLayout());
|
||||
client = new UPanel(new BorderLayout());
|
||||
client.add(video, BorderLayout.CENTER);
|
||||
|
||||
// Configure window
|
||||
@@ -258,12 +251,28 @@ class MainWindow extends JFrame {
|
||||
// Package Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Encode a character graphic
|
||||
void encode(int index) {
|
||||
int dest = index >> 9 << 15 | 0x00006000 | (index & 511) << 4;
|
||||
var pix = chrs[index];
|
||||
for (int y = 0, src = 0; y < 8; y++)
|
||||
for (int b = 0, bits = 0; b < 2; b++, vram[dest++] = (byte) bits)
|
||||
for (int x = 0; x < 4; x++, src++)
|
||||
bits = bits >> 2 | pix[src] << 6;
|
||||
vue.writeBytes(dest - 16, pix, dest - 16, 16);
|
||||
refreshDebugLite(false);
|
||||
}
|
||||
|
||||
// Refresh all debug views
|
||||
void refreshDebug(boolean seekToPC) {
|
||||
|
||||
vue.readBytes(0x00000000, vram, 0, vram.length);
|
||||
refreshCharacters();
|
||||
refreshPalettes();
|
||||
refreshDebugLite(seekToPC);
|
||||
}
|
||||
|
||||
// Refresh all debug views without retrieving video memory
|
||||
void refreshDebugLite(boolean seekToPC) {
|
||||
breakpoints.refresh();
|
||||
characters .refresh();
|
||||
cpu .refresh(seekToPC);
|
||||
@@ -403,6 +412,18 @@ class MainWindow extends JFrame {
|
||||
// Private Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Update the character patterns
|
||||
private void refreshCharacters() {
|
||||
for (int index = 0; index < 2048; index++) {
|
||||
var pix = chrs[index];
|
||||
int src = index >> 9 << 15 | 0x00006000 | (index & 511) << 4;
|
||||
for (int y = 0, dest = 0; y < 8; y++)
|
||||
for (int b = 0; b < 2; b++, src++)
|
||||
for (int x = 0, bits = vram[src]; x < 4; x++, dest++, bits >>= 2)
|
||||
pix[dest] = (byte) (bits & 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the palette composites
|
||||
private void refreshPalettes() {
|
||||
|
||||
@@ -440,9 +461,10 @@ class MainWindow extends JFrame {
|
||||
var base = app.rgbBase[y];
|
||||
var dest = palettes[x][y];
|
||||
for (int z = 1; z < 4; z++) {
|
||||
dest[z] = 0xFF000000;
|
||||
int argb = 0xFF000000;
|
||||
for (int w = 0, bits = 16; w < 3; w++, bits -= 8)
|
||||
dest[z] |= (pal[z] * base[w] + 255) / 510 << bits;
|
||||
argb |= (pal[z] * base[w] + 255) / 510 << bits;
|
||||
dest[z] = new Color(argb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class MemoryWindow extends ChildWindow {
|
||||
private int address; // Address of top row
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
private UPanel client; // Client area
|
||||
private ArrayList<Row> rows; // Rows of text
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class MemoryWindow extends ChildWindow {
|
||||
rows = new ArrayList<Row>();
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(null);
|
||||
client = new UPanel();
|
||||
client.addComponentListener(Util.onResize(e->onResize()));
|
||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
||||
client.addMouseWheelListener(e->onWheel(e));
|
||||
@@ -55,7 +55,7 @@ class MemoryWindow extends ChildWindow {
|
||||
client.setPreferredSize(new Dimension(480, 360));
|
||||
|
||||
// Configure component
|
||||
var content = new JPanel(new BorderLayout());
|
||||
var content = new UPanel(new BorderLayout());
|
||||
content.setBorder(new JScrollPane().getBorder());
|
||||
content.add(client, BorderLayout.CENTER);
|
||||
setContentPane(content);
|
||||
|
||||
@@ -24,9 +24,9 @@ class Register {
|
||||
private int value; // Current register value
|
||||
|
||||
// UI components
|
||||
JPanel expansion; // Expansion container
|
||||
UPanel expansion; // Expansion container
|
||||
JLabel btnExpand; // Expand button
|
||||
JPanel indent; // Expansion area indentation
|
||||
UPanel indent; // Expansion area indentation
|
||||
JLabel lblName; // Register name
|
||||
JTextField txtValue; // Register value
|
||||
ArrayList<JComponent> controls; // Expansion controls
|
||||
@@ -133,7 +133,7 @@ class Register {
|
||||
|
||||
// Expansion indentation
|
||||
if (index != Vue.PC) {
|
||||
indent = new JPanel();
|
||||
indent = new UPanel();
|
||||
indent.setOpaque(false);
|
||||
indent.setPreferredSize(new Dimension(0, 0));
|
||||
indent.setVisible(false);
|
||||
@@ -169,20 +169,20 @@ class Register {
|
||||
|
||||
// Expansion controls for CHCW
|
||||
private void initCHCW() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
addCheckBox("ICE", 1, false, true);
|
||||
}
|
||||
|
||||
// Expansion controls for ECR
|
||||
private void initECR() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
addTextBox("EICC", 0, 16, false, true);
|
||||
addTextBox("FECC", 16, 16, false, true);
|
||||
}
|
||||
|
||||
// Expansion controls for program registers
|
||||
private void initProgram() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
var group = new ButtonGroup();
|
||||
group.add(addRadioButton("cpu.hex" , HEX ));
|
||||
group.add(addRadioButton("cpu.signed" , SIGNED ));
|
||||
@@ -192,13 +192,13 @@ class Register {
|
||||
|
||||
// Expansion controls for PC
|
||||
private void initPC() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
|
||||
// Configure controls
|
||||
for (int x = 0; x < 2; x++) {
|
||||
|
||||
// Indentation
|
||||
indent = new JPanel();
|
||||
indent = new UPanel();
|
||||
indent.setOpaque(false);
|
||||
indent.setPreferredSize(new Dimension(0, 0));
|
||||
var gbc = new GridBagConstraints();
|
||||
@@ -234,7 +234,7 @@ class Register {
|
||||
|
||||
// Expansion controls for PSW
|
||||
private void initPSW() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
addCheckBox("Z" , 0, false, false);
|
||||
addCheckBox("FRO", 9, false, true );
|
||||
addCheckBox("S" , 1, false, false);
|
||||
@@ -254,13 +254,13 @@ class Register {
|
||||
|
||||
// Expansion controls for PIR
|
||||
private void initPIR() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
addTextBox("PT", 0, 16, true, true);
|
||||
}
|
||||
|
||||
// Expansion controls for TKCW
|
||||
private void initTKCW() {
|
||||
expansion = new JPanel(new GridBagLayout());
|
||||
expansion = new UPanel(new GridBagLayout());
|
||||
addCheckBox("OTM", 8, true, false);
|
||||
addCheckBox("FVT", 5, true, true );
|
||||
addCheckBox("FIT", 7, true, false);
|
||||
|
||||
@@ -20,7 +20,7 @@ class RegisterList extends JScrollPane {
|
||||
private boolean shown; // Component has been shown
|
||||
|
||||
// UI components
|
||||
private JPanel client; // Client area
|
||||
private UPanel client; // Client area
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class RegisterList extends JScrollPane {
|
||||
shown = true;
|
||||
|
||||
// Configure client area
|
||||
client = new JPanel(new GridBagLayout()) {
|
||||
client = new UPanel(new GridBagLayout()) {
|
||||
public Dimension getPreferredSize() {
|
||||
var ret = super.getPreferredSize();
|
||||
if (!shown) ret.height = system ? getInitialHeight() : 0;
|
||||
@@ -85,7 +85,7 @@ class RegisterList extends JScrollPane {
|
||||
}
|
||||
|
||||
// List terminator
|
||||
var spacer = new JPanel();
|
||||
var spacer = new UPanel();
|
||||
spacer.setOpaque(false);
|
||||
spacer.setPreferredSize(new Dimension(0, 0));
|
||||
var gbc = new GridBagConstraints();
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package util;
|
||||
|
||||
// Java imports
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
// Wrapper around JPanel to work around a bug in GridBagLayout
|
||||
public class UPanel extends JPanel {
|
||||
|
||||
// Instance fields
|
||||
private HashSet<PaintListener> paintListeners;
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Classes //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Functional interface for paint events
|
||||
public interface PaintListener {
|
||||
void paint(Graphics2D g, int width, int height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default constructor
|
||||
public UPanel() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
// Layout manager constructor
|
||||
public UPanel(LayoutManager layout) {
|
||||
super(layout);
|
||||
paintListeners = new HashSet<PaintListener>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Add a listener to receive paint events
|
||||
public void addPaintListener(PaintListener l) {
|
||||
if (l != null)
|
||||
paintListeners.add(l);
|
||||
}
|
||||
|
||||
// Retrieve a list of the current paint listeners
|
||||
public PaintListener[] getPaintListeners() {
|
||||
return paintListeners.toArray(
|
||||
new PaintListener[paintListeners.size()]);
|
||||
}
|
||||
|
||||
// Retrieve the maximum size of the component
|
||||
public Dimension getMaximumSize() {
|
||||
var ret = super.getMaximumSize();
|
||||
return ret != null ? ret : new Dimension();
|
||||
}
|
||||
|
||||
// Retrieve the minimum size of the component
|
||||
public Dimension getMinimumSize() {
|
||||
var ret = super.getMinimumSize();
|
||||
return ret != null ? ret : new Dimension();
|
||||
}
|
||||
|
||||
// Retrieve the preferred size of the component
|
||||
public Dimension getPreferredSize() {
|
||||
var ret = super.getPreferredSize();
|
||||
return ret != null ? ret : new Dimension();
|
||||
}
|
||||
|
||||
// Draw the component
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
var G = (Graphics2D) g;
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
for (var lst : paintListeners)
|
||||
lst.paint(G, width, height);
|
||||
}
|
||||
|
||||
// Remove a paint listener from the collection
|
||||
public void removePaintListener(PaintListener l) {
|
||||
paintListeners.remove(l);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -645,9 +645,11 @@ class CPU {
|
||||
|
||||
// Transfer program to another address
|
||||
private void jump(int address) {
|
||||
int level = psw_np != 0 ? 2 : psw_ep;
|
||||
jumpFrom[level] = pc;
|
||||
jumpTo [level] = address;
|
||||
if (address != pc) {
|
||||
int level = psw_np != 0 ? 2 : psw_ep;
|
||||
jumpFrom[level] = pc;
|
||||
jumpTo [level] = address;
|
||||
}
|
||||
pc = address - inst.size;
|
||||
}
|
||||
|
||||
@@ -712,7 +714,7 @@ class CPU {
|
||||
|
||||
// Add Immediate
|
||||
private void ADDI() {
|
||||
program[inst.reg2] = add(program[inst.reg2], inst.imm);
|
||||
program[inst.reg2] = add(program[inst.reg1], inst.imm);
|
||||
}
|
||||
|
||||
// And
|
||||
@@ -722,7 +724,7 @@ class CPU {
|
||||
|
||||
// And Immediate
|
||||
private void ANDI() {
|
||||
bitwise(program[inst.reg2] & inst.imm);
|
||||
bitwise(program[inst.reg1] & inst.imm);
|
||||
}
|
||||
|
||||
// Branch on Condition
|
||||
@@ -988,7 +990,7 @@ class CPU {
|
||||
|
||||
// Or Immediate
|
||||
private void ORI() {
|
||||
bitwise(program[inst.reg2] | inst.imm);
|
||||
bitwise(program[inst.reg1] | inst.imm);
|
||||
}
|
||||
|
||||
// Output Byte to Port
|
||||
@@ -1131,7 +1133,7 @@ class CPU {
|
||||
|
||||
// Exclusive Or Immediate
|
||||
private void XORI() {
|
||||
bitwise(program[inst.reg2] ^ inst.imm);
|
||||
bitwise(program[inst.reg1] ^ inst.imm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,11 +9,14 @@ class JavaVue extends Vue {
|
||||
// Package fields
|
||||
int breakCode; // Application breakpoint code
|
||||
int breakType; // Most recent breakpoint scenario
|
||||
CPU cpu; // Processor
|
||||
GamePak pak; // Game pak
|
||||
int[] stack; // Breakpoint condition evaluation stack
|
||||
byte[] wram; // System WRAM
|
||||
|
||||
// System components
|
||||
CPU cpu; // Processor
|
||||
GamePak pak; // Game pak
|
||||
VIP vip; // Video unit
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@@ -31,10 +34,17 @@ class JavaVue extends Vue {
|
||||
|
||||
// Default constructor
|
||||
JavaVue() {
|
||||
cpu = new CPU (this);
|
||||
pak = new GamePak(this);
|
||||
|
||||
// Configure instance fields
|
||||
stack = new int[0];
|
||||
wram = new byte[0x10000];
|
||||
|
||||
// Configure system components
|
||||
cpu = new CPU (this);
|
||||
pak = new GamePak(this);
|
||||
vip = new VIP (this);
|
||||
|
||||
// Initialize state
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -59,7 +69,7 @@ class JavaVue extends Vue {
|
||||
//cycles = pad .until(cycles);
|
||||
//cycles = link .until(cycles);
|
||||
//cycles = timer.until(cycles);
|
||||
//cycles = vip .until(cycles);
|
||||
cycles = vip .until(cycles);
|
||||
|
||||
// Process all system components
|
||||
breakCode = 0;
|
||||
@@ -67,7 +77,7 @@ class JavaVue extends Vue {
|
||||
//pad .emulate(cycles);
|
||||
//link .emulate(cycles);
|
||||
//timer.emulate(cycles);
|
||||
//vip .emulate(cycles);
|
||||
vip .emulate(cycles);
|
||||
//vsu .emulate(cycles);
|
||||
maxCycles -= cycles;
|
||||
} while (breakCode == 0 && maxCycles != 0);
|
||||
@@ -133,6 +143,7 @@ class JavaVue extends Vue {
|
||||
|
||||
// Perform the operation
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: return vip.read ( address, type);
|
||||
case 5: return readBuffer(wram , address, type);
|
||||
case 6: return readBuffer(pak.ram, address, type);
|
||||
case 7: return readBuffer(pak.rom, address, type);
|
||||
@@ -155,6 +166,7 @@ class JavaVue extends Vue {
|
||||
while (length > 0) {
|
||||
int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: vip.readBytes( address,dest,offset,count); break;
|
||||
case 5: readBytes(wram ,address,dest,offset,count); break;
|
||||
case 6: readBytes(pak.ram,address,dest,offset,count); break;
|
||||
case 7: readBytes(pak.rom,address,dest,offset,count); break;
|
||||
@@ -176,8 +188,18 @@ class JavaVue extends Vue {
|
||||
|
||||
// Specify a register value
|
||||
public int setRegister(int index, boolean system, int value) {
|
||||
|
||||
// PC
|
||||
if (index == Vue.PC && system) {
|
||||
if (cpu.stage == CPU.EXECUTE || cpu.stage == CPU.FETCH) {
|
||||
cpu.fetch = -1;
|
||||
cpu.stage = CPU.FETCH;
|
||||
}
|
||||
return cpu.pc = value & 0xFFFFFFFE;
|
||||
}
|
||||
|
||||
// Other
|
||||
return
|
||||
index == Vue.PC && system ? cpu.pc = value & 0xFFFFFFFE :
|
||||
index < 0 || index > 31 ? 0 :
|
||||
system ? cpu.setSystemRegister(index, value, true) :
|
||||
index == 0 ? 0 : (cpu.program[index] = value)
|
||||
@@ -205,6 +227,7 @@ class JavaVue extends Vue {
|
||||
// Write a value to the CPU bus
|
||||
public void write(int address, int type, int value) {
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: vip.write ( address, type, value); break;
|
||||
case 5: writeBuffer(wram , address, type, value); break;
|
||||
case 6: writeBuffer(pak.ram, address, type, value); break;
|
||||
case 7: writeBuffer(pak.rom, address, type, value); break;
|
||||
@@ -226,6 +249,7 @@ class JavaVue extends Vue {
|
||||
while (length > 0) {
|
||||
int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: vip.writeBytes( address,src,offset,count); break;
|
||||
case 5: writeBytes(wram ,address,src,offset,count); break;
|
||||
case 6: writeBytes(pak.ram,address,src,offset,count); break;
|
||||
case 7: writeBytes(pak.rom,address,src,offset,count); break;
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user