2011-01-18 10:28:10 +00:00
|
|
|
using System;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.IO;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using BizHawk.Emulation.CPUs.Z80;
|
|
|
|
|
|
|
|
//http://www.ticalc.org/pub/text/calcinfo/
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Consoles.Calculator
|
|
|
|
{
|
|
|
|
public class TI83 : IEmulator
|
|
|
|
{
|
|
|
|
//hardware
|
2013-04-16 00:42:57 +00:00
|
|
|
private readonly Z80A cpu = new Z80A();
|
|
|
|
private readonly byte[] rom;
|
|
|
|
private byte[] ram;
|
|
|
|
private int romPageLow3Bits;
|
|
|
|
private int romPageHighBit;
|
|
|
|
private bool maskOn;
|
|
|
|
private bool onPressed;
|
|
|
|
private int keyboardMask;
|
|
|
|
|
|
|
|
private int disp_mode;
|
|
|
|
private int disp_move;
|
|
|
|
private uint disp_x, disp_y;
|
|
|
|
private int m_LinkOutput, m_LinkState;
|
|
|
|
private bool m_CursorMoved;
|
2011-08-02 22:41:47 +00:00
|
|
|
|
2011-01-18 10:28:10 +00:00
|
|
|
//-------
|
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
public byte ReadMemory(ushort addr)
|
|
|
|
{
|
2011-08-02 22:41:47 +00:00
|
|
|
byte ret;
|
2011-01-18 10:28:10 +00:00
|
|
|
int romPage = romPageLow3Bits | (romPageHighBit << 3);
|
|
|
|
//Console.WriteLine("read memory: {0:X4}", addr);
|
|
|
|
if (addr < 0x4000)
|
2011-08-02 22:41:47 +00:00
|
|
|
ret = rom[addr]; //ROM zero-page
|
2011-01-18 10:28:10 +00:00
|
|
|
else if (addr < 0x8000)
|
2011-08-02 22:41:47 +00:00
|
|
|
ret = rom[romPage * 0x4000 + addr - 0x4000]; //other rom page
|
|
|
|
else ret = ram[addr - 0x8000];
|
|
|
|
|
2012-12-10 00:43:43 +00:00
|
|
|
if (CoreComm.MemoryCallbackSystem.HasRead)
|
2012-10-13 20:15:28 +00:00
|
|
|
{
|
2012-12-10 00:43:43 +00:00
|
|
|
CoreComm.MemoryCallbackSystem.TriggerRead(addr);
|
2012-10-13 20:15:28 +00:00
|
|
|
}
|
|
|
|
|
2011-08-02 22:41:47 +00:00
|
|
|
return ret;
|
2011-07-10 01:55:37 +00:00
|
|
|
}
|
2011-01-18 10:28:10 +00:00
|
|
|
|
|
|
|
public void WriteMemory(ushort addr, byte value)
|
|
|
|
{
|
|
|
|
if (addr < 0x4000)
|
|
|
|
return; //ROM zero-page
|
|
|
|
else if (addr < 0x8000)
|
|
|
|
return; //other rom page
|
|
|
|
else ram[addr - 0x8000] = value;
|
2012-10-13 20:15:28 +00:00
|
|
|
|
2012-12-10 00:43:43 +00:00
|
|
|
if (CoreComm.MemoryCallbackSystem.HasWrite)
|
2012-10-13 20:15:28 +00:00
|
|
|
{
|
2012-12-10 00:43:43 +00:00
|
|
|
CoreComm.MemoryCallbackSystem.TriggerWrite(addr);
|
2012-10-13 20:15:28 +00:00
|
|
|
}
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void WriteHardware(ushort addr, byte value)
|
|
|
|
{
|
|
|
|
switch (addr)
|
|
|
|
{
|
|
|
|
case 0: //PORT_LINK
|
|
|
|
romPageHighBit = (value >> 4) & 1;
|
|
|
|
m_LinkOutput = value & 3;
|
|
|
|
m_LinkState = m_LinkOutput ^ 3;
|
|
|
|
break;
|
|
|
|
case 1: //PORT_KEYBOARD:
|
2011-07-10 01:55:37 +00:00
|
|
|
lagged = false;
|
2011-01-18 10:28:10 +00:00
|
|
|
keyboardMask = value;
|
2011-04-24 04:46:07 +00:00
|
|
|
//Console.WriteLine("write PORT_KEYBOARD {0:X2}",value);
|
2011-01-18 10:28:10 +00:00
|
|
|
break;
|
|
|
|
case 2: //PORT_ROMPAGE
|
|
|
|
romPageLow3Bits = value & 0x7;
|
|
|
|
break;
|
|
|
|
case 3: //PORT_STATUS
|
|
|
|
maskOn = ((value & 1) == 1);
|
|
|
|
break;
|
|
|
|
case 16: //PORT_DISPCTRL
|
|
|
|
//Console.WriteLine("write PORT_DISPCTRL {0}",value);
|
|
|
|
WriteDispCtrl(value);
|
|
|
|
break;
|
|
|
|
case 17: //PORT_DISPDATA
|
|
|
|
//Console.WriteLine("write PORT_DISPDATA {0}",value);
|
|
|
|
WriteDispData(value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public byte ReadHardware(ushort addr)
|
|
|
|
{
|
|
|
|
switch (addr)
|
|
|
|
{
|
|
|
|
case 0: //PORT_LINK
|
2011-07-10 01:55:37 +00:00
|
|
|
return (byte)((romPageHighBit << 4) | (m_LinkState << 2) | m_LinkOutput);
|
2011-01-18 10:28:10 +00:00
|
|
|
case 1: //PORT_KEYBOARD:
|
|
|
|
//Console.WriteLine("read PORT_KEYBOARD");
|
|
|
|
return ReadKeyboard();
|
|
|
|
case 2: //PORT_ROMPAGE
|
|
|
|
return (byte)romPageLow3Bits;
|
|
|
|
case 3: //PORT_STATUS
|
|
|
|
{
|
|
|
|
//Console.WriteLine("read PORT_STATUS");
|
|
|
|
byte ret = 0;
|
|
|
|
// Bits:
|
|
|
|
// 0 - Set if ON key is down and ON key is trapped
|
|
|
|
// 1 - Update things (keyboard etc)
|
|
|
|
// 2 - Unknown, but used
|
|
|
|
// 3 - Set if ON key is up
|
|
|
|
// 4-7 - Unknown
|
|
|
|
//if (onPressed && maskOn) ret |= 1;
|
|
|
|
//if (!onPressed) ret |= 0x8;
|
|
|
|
ret |= 0x8; //on key is up
|
|
|
|
ret |= 0x2; //link isnt emulated
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 4: //PORT_INTCTRL
|
2011-04-24 04:46:07 +00:00
|
|
|
//Console.WriteLine("read PORT_INTCTRL");
|
2011-01-18 10:28:10 +00:00
|
|
|
return 0xFF;
|
|
|
|
|
|
|
|
case 16: //PORT_DISPCTRL
|
2011-04-24 04:46:07 +00:00
|
|
|
//Console.WriteLine("read DISPCTRL");
|
2011-01-18 10:28:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 17: //PORT_DISPDATA
|
|
|
|
return ReadDispData();
|
|
|
|
}
|
|
|
|
return 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte ReadKeyboard()
|
|
|
|
{
|
2012-12-10 00:43:43 +00:00
|
|
|
if (CoreComm.InputCallback != null) CoreComm.InputCallback();
|
2011-01-18 10:28:10 +00:00
|
|
|
//ref TI-9X
|
2011-07-10 01:55:37 +00:00
|
|
|
|
2011-01-18 10:28:10 +00:00
|
|
|
int ret = 0xFF;
|
2011-04-24 04:46:07 +00:00
|
|
|
//Console.WriteLine("keyboardMask: {0:X2}",keyboardMask);
|
2011-01-18 10:28:10 +00:00
|
|
|
if ((keyboardMask & 1) == 0)
|
|
|
|
{
|
|
|
|
if (Controller.IsPressed("DOWN")) ret ^= 1;
|
|
|
|
if (Controller.IsPressed("LEFT")) ret ^= 2;
|
|
|
|
if (Controller.IsPressed("RIGHT")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("UP")) ret ^= 8;
|
|
|
|
}
|
|
|
|
if ((keyboardMask & 2) == 0)
|
|
|
|
{
|
|
|
|
if (Controller.IsPressed("ENTER")) ret ^= 1;
|
|
|
|
if (Controller.IsPressed("PLUS")) ret ^= 2;
|
|
|
|
if (Controller.IsPressed("MINUS")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("MULTIPLY")) ret ^= 8;
|
|
|
|
if (Controller.IsPressed("DIVIDE")) ret ^= 16;
|
2011-04-24 04:46:07 +00:00
|
|
|
if (Controller.IsPressed("EXP")) ret ^= 32;
|
2011-01-18 10:28:10 +00:00
|
|
|
if (Controller.IsPressed("CLEAR")) ret ^= 64;
|
|
|
|
}
|
|
|
|
if ((keyboardMask & 4) == 0)
|
|
|
|
{
|
2011-04-24 04:46:07 +00:00
|
|
|
if (Controller.IsPressed("DASH")) ret ^= 1;
|
2011-07-10 01:55:37 +00:00
|
|
|
if (Controller.IsPressed("3")) ret ^= 2;
|
2011-01-18 10:28:10 +00:00
|
|
|
if (Controller.IsPressed("6")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("9")) ret ^= 8;
|
2011-07-10 01:55:37 +00:00
|
|
|
if (Controller.IsPressed("PARACLOSE")) ret ^= 16;
|
|
|
|
if (Controller.IsPressed("TAN")) ret ^= 32;
|
|
|
|
if (Controller.IsPressed("VARS")) ret ^= 64;
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
if ((keyboardMask & 8) == 0)
|
|
|
|
{
|
|
|
|
if (Controller.IsPressed("DOT")) ret ^= 1;
|
|
|
|
if (Controller.IsPressed("2")) ret ^= 2;
|
|
|
|
if (Controller.IsPressed("5")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("8")) ret ^= 8;
|
2011-07-10 01:55:37 +00:00
|
|
|
if (Controller.IsPressed("PARAOPEN")) ret ^= 16;
|
|
|
|
if (Controller.IsPressed("COS")) ret ^= 32;
|
|
|
|
if (Controller.IsPressed("PRGM")) ret ^= 64;
|
|
|
|
if (Controller.IsPressed("STAT")) ret ^= 128;
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
if ((keyboardMask & 16) == 0)
|
|
|
|
{
|
|
|
|
if (Controller.IsPressed("0")) ret ^= 1;
|
|
|
|
if (Controller.IsPressed("1")) ret ^= 2;
|
|
|
|
if (Controller.IsPressed("4")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("7")) ret ^= 8;
|
2011-07-10 01:55:37 +00:00
|
|
|
if (Controller.IsPressed("COMMA")) ret ^= 16;
|
|
|
|
if (Controller.IsPressed("SIN")) ret ^= 32;
|
|
|
|
if (Controller.IsPressed("MATRIX")) ret ^= 64;
|
|
|
|
if (Controller.IsPressed("X")) ret ^= 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((keyboardMask & 32) == 0)
|
|
|
|
{
|
|
|
|
if (Controller.IsPressed("STO")) ret ^= 2;
|
|
|
|
if (Controller.IsPressed("LN")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("LOG")) ret ^= 8;
|
|
|
|
if (Controller.IsPressed("SQUARED")) ret ^= 16;
|
|
|
|
if (Controller.IsPressed("NEG1")) ret ^= 32;
|
|
|
|
if (Controller.IsPressed("MATH"))
|
|
|
|
ret ^= 64;
|
|
|
|
if (Controller.IsPressed("ALPHA")) ret ^= 128;
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
if ((keyboardMask & 64) == 0)
|
|
|
|
{
|
|
|
|
if (Controller.IsPressed("GRAPH")) ret ^= 1;
|
|
|
|
if (Controller.IsPressed("TRACE")) ret ^= 2;
|
|
|
|
if (Controller.IsPressed("ZOOM")) ret ^= 4;
|
|
|
|
if (Controller.IsPressed("WINDOW")) ret ^= 8;
|
|
|
|
if (Controller.IsPressed("Y")) ret ^= 16;
|
|
|
|
if (Controller.IsPressed("2ND")) ret ^= 32;
|
|
|
|
if (Controller.IsPressed("MODE")) ret ^= 64;
|
|
|
|
if (Controller.IsPressed("DEL")) ret ^= 128;
|
|
|
|
}
|
2011-04-24 04:46:07 +00:00
|
|
|
|
2011-01-18 10:28:10 +00:00
|
|
|
return (byte)ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
byte ReadDispData()
|
|
|
|
{
|
|
|
|
if (m_CursorMoved)
|
|
|
|
{
|
|
|
|
m_CursorMoved = false;
|
|
|
|
return 0x00; //not accurate this should be stale data or something
|
|
|
|
}
|
|
|
|
|
|
|
|
byte ret;
|
|
|
|
if (disp_mode == 1)
|
|
|
|
{
|
|
|
|
ret = vram[disp_y * 12 + disp_x];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int column = 6 * (int)disp_x;
|
|
|
|
int offset = (int)disp_y * 12 + (column >> 3);
|
|
|
|
int shift = 10 - (column & 7);
|
|
|
|
ret = (byte)(((vram[offset] << 8) | vram[offset + 1]) >> shift);
|
|
|
|
}
|
|
|
|
|
|
|
|
doDispMove();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteDispData(byte value)
|
|
|
|
{
|
2013-04-16 00:42:57 +00:00
|
|
|
int offset;
|
2011-01-18 10:28:10 +00:00
|
|
|
if (disp_mode == 1)
|
|
|
|
{
|
|
|
|
offset = (int)disp_y * 12 + (int)disp_x;
|
|
|
|
vram[offset] = value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int column = 6 * (int)disp_x;
|
|
|
|
offset = (int)disp_y * 12 + (column >> 3);
|
|
|
|
if (offset < 0x300)
|
|
|
|
{
|
|
|
|
int shift = column & 7;
|
|
|
|
int mask = ~(252 >> shift);
|
|
|
|
int Data = value << 2;
|
|
|
|
vram[offset] = (byte)(vram[offset] & mask | (Data >> shift));
|
|
|
|
if (shift > 2 && offset < 0x2ff)
|
|
|
|
{
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
shift = 8 - shift;
|
|
|
|
|
|
|
|
mask = ~(252 << shift);
|
|
|
|
vram[offset] = (byte)(vram[offset] & mask | (Data << shift));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
doDispMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
void doDispMove()
|
|
|
|
{
|
|
|
|
switch (disp_move)
|
|
|
|
{
|
|
|
|
case 0: disp_y--; break;
|
|
|
|
case 1: disp_y++; break;
|
|
|
|
case 2: disp_x--; break;
|
|
|
|
case 3: disp_x++; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
disp_x &= 0xF; //0xF or 0x1F? dunno
|
|
|
|
disp_y &= 0x3F;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteDispCtrl(byte value)
|
|
|
|
{
|
|
|
|
if (value <= 1)
|
|
|
|
disp_mode = value;
|
|
|
|
else if (value >= 4 && value <= 7)
|
|
|
|
disp_move = value - 4;
|
|
|
|
else if ((value & 0xC0) == 0x40)
|
|
|
|
{
|
|
|
|
//hardware scroll
|
|
|
|
}
|
|
|
|
else if ((value & 0xE0) == 0x20)
|
|
|
|
{
|
|
|
|
disp_x = (uint)(value & 0x1F);
|
|
|
|
m_CursorMoved = true;
|
|
|
|
}
|
|
|
|
else if ((value & 0xC0) == 0x80)
|
|
|
|
{
|
|
|
|
disp_y = (uint)(value & 0x3F);
|
|
|
|
m_CursorMoved = true;
|
|
|
|
}
|
|
|
|
else if ((value & 0xC0) == 0xC0)
|
|
|
|
{
|
|
|
|
//contrast
|
|
|
|
}
|
|
|
|
else if (value == 2)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else if (value == 3)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-10 00:43:43 +00:00
|
|
|
public TI83(CoreComm comm, GameInfo game, byte[] rom)
|
2011-01-18 10:28:10 +00:00
|
|
|
{
|
2012-12-10 00:43:43 +00:00
|
|
|
CoreComm = comm;
|
2011-01-18 10:28:10 +00:00
|
|
|
cpu.ReadMemory = ReadMemory;
|
|
|
|
cpu.WriteMemory = WriteMemory;
|
|
|
|
cpu.ReadHardware = ReadHardware;
|
|
|
|
cpu.WriteHardware = WriteHardware;
|
|
|
|
cpu.IRQCallback = IRQCallback;
|
|
|
|
cpu.NMICallback = NMICallback;
|
2011-08-04 03:20:54 +00:00
|
|
|
|
|
|
|
this.rom = rom;
|
|
|
|
|
|
|
|
//different calculators (different revisions?) have different initPC. we track this in the game database by rom hash
|
|
|
|
//if( *(unsigned long *)(m_pRom + 0x6ce) == 0x04D3163E ) m_Regs.PC.W = 0x6ce; //KNOWN
|
|
|
|
//else if( *(unsigned long *)(m_pRom + 0x6f6) == 0x04D3163E ) m_Regs.PC.W = 0x6f6; //UNKNOWN
|
|
|
|
|
|
|
|
if (game["initPC"])
|
|
|
|
startPC = ushort.Parse(game.OptionValue("initPC"), NumberStyles.HexNumber);
|
|
|
|
|
|
|
|
HardReset();
|
|
|
|
SetupMemoryDomains();
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void IRQCallback()
|
|
|
|
{
|
|
|
|
//Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", cpu.RegisterI, cpu.InterruptMode);
|
|
|
|
cpu.Interrupt = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NMICallback()
|
|
|
|
{
|
|
|
|
Console.WriteLine("NMI");
|
|
|
|
cpu.NonMaskableInterrupt = false;
|
|
|
|
}
|
|
|
|
|
2011-06-11 22:15:08 +00:00
|
|
|
|
2012-12-10 00:43:43 +00:00
|
|
|
public CoreComm CoreComm { get; private set; }
|
2011-06-11 22:15:08 +00:00
|
|
|
|
2011-01-18 10:28:10 +00:00
|
|
|
protected byte[] vram = new byte[0x300];
|
|
|
|
class MyVideoProvider : IVideoProvider
|
|
|
|
{
|
2013-04-16 00:42:57 +00:00
|
|
|
private readonly TI83 emu;
|
2011-01-18 10:28:10 +00:00
|
|
|
public MyVideoProvider(TI83 emu)
|
|
|
|
{
|
|
|
|
this.emu = emu;
|
|
|
|
}
|
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
public int[] GetVideoBuffer()
|
|
|
|
{
|
2011-01-18 10:28:10 +00:00
|
|
|
//unflatten bit buffer
|
2011-07-10 01:55:37 +00:00
|
|
|
int[] pixels = new int[96 * 64];
|
|
|
|
int i = 0;
|
|
|
|
for (int y = 0; y < 64; y++)
|
2011-01-18 10:28:10 +00:00
|
|
|
for (int x = 0; x < 96; x++)
|
|
|
|
{
|
|
|
|
int offset = y * 96 + x;
|
|
|
|
int bufbyte = offset >> 3;
|
|
|
|
int bufbit = offset & 7;
|
|
|
|
int bit = ((emu.vram[bufbyte] >> (7 - bufbit)) & 1);
|
2011-07-10 01:55:37 +00:00
|
|
|
if (bit == 0)
|
|
|
|
unchecked { pixels[i++] = (int)0xFFFFFFFF; }
|
2011-01-18 10:28:10 +00:00
|
|
|
else
|
|
|
|
pixels[i++] = 0;
|
2011-07-10 01:55:37 +00:00
|
|
|
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
return pixels;
|
|
|
|
}
|
2012-06-25 02:50:34 +00:00
|
|
|
public int VirtualWidth { get { return 96; } }
|
2011-01-18 10:28:10 +00:00
|
|
|
public int BufferWidth { get { return 96; } }
|
|
|
|
public int BufferHeight { get { return 64; } }
|
|
|
|
public int BackgroundColor { get { return 0; } }
|
|
|
|
}
|
2011-07-10 01:55:37 +00:00
|
|
|
public IVideoProvider VideoProvider {
|
|
|
|
get { return new MyVideoProvider(this); } }
|
2011-01-18 10:28:10 +00:00
|
|
|
|
2011-06-02 02:59:18 +00:00
|
|
|
public ISoundProvider SoundProvider { get { return NullSound.SilenceProvider; } }
|
sound api changes. added a new ISyncSoundProvider, which works similarly to ISoundProvider except the source (not the sink) determines the number of samples to process. Added facilities to metaspu, dcfilter, speexresampler to work with ISyncSoundProvider. Add ISyncSoundProvider to IEmulator. All IEmulators must provide sync sound, but they need not provide async sound. When async is needed and an IEmulator doesn't provide it, the frontend will wrap it in a vecna metaspu. SNES, GB changed to provide sync sound only. All other emulator cores mostly unchanged; they just provide stub fakesync alongside async, for now. For the moment, the only use of the sync sound is for realtime audio throttling, where it works and sounds quite nice. In the future, sync sound will be supported for AV dumping as well.
2012-10-11 00:44:59 +00:00
|
|
|
public ISyncSoundProvider SyncSoundProvider { get { return new FakeSyncSound(NullSound.SilenceProvider, 735); } }
|
|
|
|
public bool StartAsyncSound() { return true; }
|
|
|
|
public void EndAsyncSound() { }
|
2011-01-18 10:28:10 +00:00
|
|
|
|
|
|
|
public static readonly ControllerDefinition TI83Controller =
|
|
|
|
new ControllerDefinition
|
|
|
|
{
|
2012-02-21 00:40:44 +00:00
|
|
|
Name = "TI83 Controller",
|
2011-01-18 10:28:10 +00:00
|
|
|
BoolButtons = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9","DOT",
|
|
|
|
"ON","ENTER",
|
|
|
|
"DOWN","LEFT","UP","RIGHT",
|
|
|
|
"PLUS","MINUS","MULTIPLY","DIVIDE",
|
2011-04-24 04:46:07 +00:00
|
|
|
"CLEAR", "EXP", "DASH", "PARACLOSE", "TAN", "VARS", "PARAOPEN",
|
2011-07-10 01:55:37 +00:00
|
|
|
"COS", "PRGM", "STAT", "COMMA", "SIN", "MATRIX", "X",
|
|
|
|
"STO", "LN", "LOG", "SQUARED", "NEG1", "MATH", "ALPHA",
|
|
|
|
"GRAPH", "TRACE", "ZOOM", "WINDOW", "Y", "2ND", "MODE", "DEL"
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return TI83Controller; } }
|
|
|
|
|
|
|
|
IController controller;
|
|
|
|
public IController Controller
|
|
|
|
{
|
|
|
|
get { return controller; }
|
2011-07-10 01:55:37 +00:00
|
|
|
set { controller = value; }
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
//configuration
|
|
|
|
ushort startPC;
|
|
|
|
|
2012-09-20 19:52:47 +00:00
|
|
|
public void FrameAdvance(bool render, bool rendersound)
|
2011-01-18 10:28:10 +00:00
|
|
|
{
|
2011-07-10 01:55:37 +00:00
|
|
|
lagged = true;
|
|
|
|
//I eyeballed this speed
|
2011-01-18 10:28:10 +00:00
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
onPressed = Controller.IsPressed("ON");
|
|
|
|
//and this was derived from other emus
|
|
|
|
cpu.ExecuteCycles(10000);
|
|
|
|
cpu.Interrupt = true;
|
|
|
|
}
|
2011-07-10 01:55:37 +00:00
|
|
|
Controller.UpdateControls(Frame++);
|
|
|
|
if (lagged)
|
|
|
|
{
|
|
|
|
_lagcount++;
|
|
|
|
islag = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
islag = false;
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void HardReset()
|
|
|
|
{
|
|
|
|
cpu.Reset();
|
|
|
|
ram = new byte[0x8000];
|
2011-07-10 01:55:37 +00:00
|
|
|
for (int i = 0; i < 0x8000; i++)
|
2011-01-18 10:28:10 +00:00
|
|
|
ram[i] = 0xFF;
|
|
|
|
cpu.RegisterPC = startPC;
|
|
|
|
|
|
|
|
cpu.IFF1 = false;
|
|
|
|
cpu.IFF2 = false;
|
|
|
|
cpu.InterruptMode = 2;
|
2011-07-10 01:55:37 +00:00
|
|
|
|
2011-01-18 10:28:10 +00:00
|
|
|
maskOn = false;
|
|
|
|
romPageHighBit = 0;
|
|
|
|
romPageLow3Bits = 0;
|
|
|
|
keyboardMask = 0;
|
|
|
|
|
|
|
|
disp_mode = 0;
|
|
|
|
disp_move = 0;
|
|
|
|
disp_x = disp_y = 0;
|
|
|
|
}
|
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
private int _lagcount = 0;
|
|
|
|
private bool lagged = true;
|
|
|
|
private bool islag = false;
|
|
|
|
public int Frame { get; set; }
|
2011-07-30 20:49:36 +00:00
|
|
|
|
|
|
|
public void ResetFrameCounter()
|
|
|
|
{
|
|
|
|
Frame = 0;
|
2012-11-25 15:41:40 +00:00
|
|
|
_lagcount = 0;
|
|
|
|
islag = false;
|
2011-07-30 20:49:36 +00:00
|
|
|
}
|
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
public int LagCount { get { return _lagcount; } set { _lagcount = value; } }
|
|
|
|
public bool IsLagFrame { get { return islag; } }
|
|
|
|
|
2012-10-03 15:31:04 +00:00
|
|
|
public bool DeterministicEmulation { get { return true; } }
|
2011-01-18 10:28:10 +00:00
|
|
|
|
2012-09-14 22:28:38 +00:00
|
|
|
public byte[] ReadSaveRam() { return null; }
|
|
|
|
public void StoreSaveRam(byte[] data) { }
|
|
|
|
public void ClearSaveRam() { }
|
2011-01-18 10:28:10 +00:00
|
|
|
public bool SaveRamModified
|
|
|
|
{
|
|
|
|
get { return false; }
|
|
|
|
set { }
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SaveStateText(TextWriter writer)
|
|
|
|
{
|
2011-07-10 01:55:37 +00:00
|
|
|
writer.WriteLine("[TI83]\n");
|
|
|
|
writer.WriteLine("Frame {0}", Frame);
|
|
|
|
cpu.SaveStateText(writer);
|
|
|
|
writer.Write("RAM ");
|
|
|
|
ram.SaveAsHex(writer);
|
|
|
|
writer.WriteLine("romPageLow3Bits {0}", romPageLow3Bits);
|
|
|
|
writer.WriteLine("romPageHighBit {0}", romPageHighBit);
|
|
|
|
writer.WriteLine("disp_mode {0}", disp_mode);
|
|
|
|
writer.WriteLine("disp_move {0}", disp_move);
|
|
|
|
writer.WriteLine("disp_x {0}", disp_x);
|
|
|
|
writer.WriteLine("disp_y {0}", disp_y);
|
|
|
|
writer.WriteLine("m_CursorMoved {0}", m_CursorMoved);
|
|
|
|
writer.WriteLine("maskOn {0}", maskOn);
|
|
|
|
writer.WriteLine("onPressed {0}", onPressed);
|
|
|
|
writer.WriteLine("keyboardMask {0}", keyboardMask);
|
|
|
|
writer.WriteLine("m_LinkOutput {0}", m_LinkOutput);
|
|
|
|
writer.WriteLine("m_LinkState {0}", m_LinkState);
|
|
|
|
writer.WriteLine("lag {0}", _lagcount);
|
2012-07-30 14:42:52 +00:00
|
|
|
writer.WriteLine("islag {0}", islag);
|
2011-07-14 01:18:04 +00:00
|
|
|
writer.WriteLine("vram {0}", Util.BytesToHexString(vram));
|
2011-07-10 01:55:37 +00:00
|
|
|
writer.WriteLine("[/TI83]");
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void LoadStateText(TextReader reader)
|
|
|
|
{
|
2011-07-10 01:55:37 +00:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
string[] args = reader.ReadLine().Split(' ');
|
|
|
|
if (args[0].Trim() == "") continue;
|
|
|
|
if (args[0] == "[TI83]") continue;
|
|
|
|
if (args[0] == "[/TI83]") break;
|
|
|
|
if (args[0] == "Frame")
|
|
|
|
Frame = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "[Z80]")
|
|
|
|
cpu.LoadStateText(reader);
|
|
|
|
else if (args[0] == "RAM")
|
|
|
|
ram.ReadFromHex(args[1]);
|
|
|
|
else if (args[0] == "romPageLow3Bits")
|
|
|
|
romPageLow3Bits = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "romPageHighBit")
|
|
|
|
romPageHighBit = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "disp_mode")
|
|
|
|
disp_mode = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "disp_move")
|
|
|
|
disp_move = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "disp_x")
|
|
|
|
disp_x = uint.Parse(args[1]);
|
|
|
|
else if (args[0] == "disp_y")
|
|
|
|
disp_y = uint.Parse(args[1]);
|
|
|
|
else if (args[0] == "m_CursorMoved")
|
|
|
|
m_CursorMoved = bool.Parse(args[1]);
|
|
|
|
else if (args[0] == "maskOn")
|
|
|
|
maskOn = bool.Parse(args[1]);
|
|
|
|
else if (args[0] == "onPressed")
|
|
|
|
onPressed = bool.Parse(args[1]);
|
|
|
|
else if (args[0] == "keyboardMask")
|
|
|
|
keyboardMask = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "m_LinkOutput")
|
|
|
|
m_LinkOutput = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "m_LinkState")
|
|
|
|
m_LinkState = int.Parse(args[1]);
|
|
|
|
else if (args[0] == "lag")
|
|
|
|
_lagcount = int.Parse(args[1]);
|
2012-07-30 14:42:52 +00:00
|
|
|
else if (args[0] == "islag")
|
|
|
|
islag = bool.Parse(args[1]);
|
2011-07-14 01:18:04 +00:00
|
|
|
else if (args[0] == "vram")
|
|
|
|
vram = Util.HexStringToBytes(args[1]);
|
2011-07-10 01:55:37 +00:00
|
|
|
else
|
|
|
|
Console.WriteLine("Skipping unrecognized identifier " + args[0]);
|
|
|
|
}
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SaveStateBinary(BinaryWriter writer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public void LoadStateBinary(BinaryReader reader)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public byte[] SaveStateBinary()
|
|
|
|
{
|
|
|
|
return new byte[0];
|
|
|
|
}
|
2011-01-21 03:59:50 +00:00
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
public string SystemId { get { return "TI83"; } }
|
2011-04-21 00:57:55 +00:00
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
private IList<MemoryDomain> memoryDomains;
|
|
|
|
private const ushort RamSizeMask = 0x7FFF;
|
2011-04-21 00:57:55 +00:00
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
private void SetupMemoryDomains()
|
|
|
|
{
|
|
|
|
var domains = new List<MemoryDomain>();
|
|
|
|
var MainMemoryDomain = new MemoryDomain("Main RAM", ram.Length, Endian.Little,
|
|
|
|
addr => ram[addr & RamSizeMask],
|
|
|
|
(addr, value) => ram[addr & RamSizeMask] = value);
|
|
|
|
domains.Add(MainMemoryDomain);
|
|
|
|
memoryDomains = domains.AsReadOnly();
|
|
|
|
}
|
2011-04-21 00:57:55 +00:00
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
public IList<MemoryDomain> MemoryDomains { get { return memoryDomains; } }
|
|
|
|
public MemoryDomain MainMemory { get { return memoryDomains[0]; } }
|
2011-02-21 09:48:53 +00:00
|
|
|
|
2011-07-10 01:55:37 +00:00
|
|
|
public void Dispose() { }
|
|
|
|
}
|
2011-01-18 10:28:10 +00:00
|
|
|
}
|