ChannelF: Several fixes:

* F8 CPU now complements when transferring from A to IO
* Audio now working correctly
* F8 SIGN flag now set correctly on IO reads
This commit is contained in:
Matt Burgess 2021-11-24 09:00:29 +00:00
parent 726ecef5a6
commit b06b37de7e
9 changed files with 141 additions and 283 deletions

View File

@ -59,8 +59,10 @@
case 0x29: JMP(); break; // A <- H'ii'; PC0l <- H'jj'; PC0h <- (A)
case 0x2A: DCI(); break; // DC0h <- ii; increment PC0; DC0l <- jj; increment PC0
case 0x2B: NOP(); break; // No operation (4 cycles - fetch next opcode)
case 0x2C: XDC(); break; // DC0 <-> DC1
case 0x2C: XDC(); break; // DC0 <-> DC1
case 0x2D: ILLEGAL(); break; // No instruction - do a NOP
case 0x2E: ILLEGAL(); break; // No instruction - do a NOP
case 0x2F: ILLEGAL(); break; // No instruction - do a NOP
case 0x30: DS(0); break; // SR <- (SR) + H'FF'
@ -77,7 +79,8 @@
case 0x3B: DS(11); break; // SR <- (SR) + H'FF'
case 0x3C: DS_ISAR(); break; // SR <- (SR) + H'FF' (SR pointed to by the ISAR)
case 0x3D: DS_ISAR_INC(); break; // SR <- (SR) + H'FF' (SR pointed to by the ISAR); ISAR incremented
case 0x3E: DS_ISAR_DEC(); break; // SR <- (SR) + H'FF' (SR pointed to by the ISAR); ISAR decremented
case 0x3E: DS_ISAR_DEC(); break; // SR <- (SR) + H'FF' (SR pointed to by the ISAR); ISAR decremented
case 0x3F: ILLEGAL(); break; // No instruction - do a NOP
case 0x40: LR_A_R(0); break; // A <- (SR)
case 0x41: LR_A_R(1); break; // A <- (SR)
@ -93,8 +96,9 @@
case 0x4B: LR_A_R(11); break; // A <- (SR)
case 0x4C: LR_A_ISAR(); break; // A <- (SR) (SR pointed to by the ISAR)
case 0x4D: LR_A_ISAR_INC(); break; // A <- (SR) (SR pointed to by the ISAR); ISAR incremented
case 0x4E: LR_A_ISAR_DEC(); break; // A <- (SR) (SR pointed to by the ISAR); ISAR decremented
case 0x4E: LR_A_ISAR_DEC(); break; // A <- (SR) (SR pointed to by the ISAR); ISAR decremented
case 0x4F: ILLEGAL(); break; // No instruction - do a NOP
case 0x50: LR_R_A(0); break; // SR <- (A)
case 0x51: LR_R_A(1); break; // SR <- (A)
case 0x52: LR_R_A(2); break; // SR <- (A)
@ -109,7 +113,8 @@
case 0x5B: LR_R_A(11); break; // SR <- (A)
case 0x5C: LR_ISAR_A(); break; // SR <- (A) (SR pointed to by the ISAR)
case 0x5D: LR_ISAR_A_INC(); break; // SR <- (A) (SR pointed to by the ISAR); ISAR incremented
case 0x5E: LR_ISAR_A_DEC(); break; // SR <- (A) (SR pointed to by the ISAR); ISAR decremented
case 0x5E: LR_ISAR_A_DEC(); break; // SR <- (A) (SR pointed to by the ISAR); ISAR decremented
case 0x5F: ILLEGAL(); break; // No instruction - do a NOP
case 0x60: LISU(0); break; // ISARU <- 0'e' (octal)
case 0x61: LISU(1); break; // ISARU <- 0'e' (octal)
@ -181,7 +186,10 @@
case 0x9F: BF_OZCS(); break; // Branch on false - no overflow and not zero and no carry and negative
case 0xA0: INS_0(0); break; // A <- (I/O Port 0 or 1)
case 0xA1: INS_0(1); break; // A <- (I/O Port 0 or 1)
case 0xA1: INS_0(1); break; // A <- (I/O Port 0 or 1)
case 0xA2: ILLEGAL(); break; // F8 Guide To Programming suggests port 3 cannot be read
case 0xA3: ILLEGAL(); break; // F8 Guide To Programming suggests port 4 cannot be read
case 0xA4: INS_1(4); break; // DB <- Port Address (4 thru 15)
case 0xA5: INS_1(5); break; // DB <- Port Address (4 thru 15)
@ -197,7 +205,10 @@
case 0xAF: INS_1(15); break; // DB <- Port Address (4 thru 15)
case 0xB0: OUTS_0(0); break; // I/O Port 0 or 1 <- (A)
case 0xB1: OUTS_0(1); break; // I/O Port 0 or 1 <- (A)
case 0xB1: OUTS_0(1); break; // I/O Port 0 or 1 <- (A)
case 0xB2: ILLEGAL(); break; // F8 Guide To Programming suggests port 3 cannot be written to
case 0xB3: ILLEGAL(); break; // F8 Guide To Programming suggests port 4 cannot be written to
case 0xB4: OUTS_1(4); break; // DB <- Port Address (4 thru 15)
case 0xB5: OUTS_1(5); break; // DB <- Port Address (4 thru 15)
@ -226,7 +237,8 @@
case 0xCB: AS(11); break; // A <- (A) + (r) Binary
case 0xCC: AS_IS(); break; // A <- (A) + (r addressed via ISAR) Binary
case 0xCD: AS_IS_INC(); break; // A <- (A) + (r addressed via ISAR) Binary; Increment ISAR
case 0xCE: AS_IS_DEC(); break; // A <- (A) + (r addressed via ISAR) Binary; Decrement ISAR
case 0xCE: AS_IS_DEC(); break; // A <- (A) + (r addressed via ISAR) Binary; Decrement ISAR
case 0xCF: ILLEGAL(); break; // No instruction - do a NOP
case 0xD0: ASD(0); break; // A <- (A) + (r) Decimal
case 0xD1: ASD(1); break; // A <- (A) + (r) Decimal
@ -242,7 +254,8 @@
case 0xDB: ASD(11); break; // A <- (A) + (r) Decimal
case 0xDC: ASD_IS(); break; // A <- (A) + (r addressed via ISAR) Decimal
case 0xDD: ASD_IS_INC(); break; // A <- (A) + (r addressed via ISAR) Decimal; Increment ISAR
case 0xDE: ASD_IS_DEC(); break; // A <- (A) + (r addressed via ISAR) Decimal; Decrement ISAR
case 0xDE: ASD_IS_DEC(); break; // A <- (A) + (r addressed via ISAR) Decimal; Decrement ISAR
case 0xDF: ILLEGAL(); break; // No instruction - do a NOP
case 0xE0: XS(0); break; // A <- (A) XOR (r)
case 0xE1: XS(1); break; // A <- (A) XOR (r)
@ -258,7 +271,8 @@
case 0xEB: XS(11); break; // A <- (A) XOR (r)
case 0xEC: XS_IS(); break; // A <- (A) XOR (r addressed via ISAR)
case 0xED: XS_IS_INC(); break; // A <- (A) XOR (r addressed via ISAR); Increment ISAR
case 0xEE: XS_IS_DEC(); break; // A <- (A) XOR (r addressed via ISAR); Decrement ISAR
case 0xEE: XS_IS_DEC(); break; // A <- (A) XOR (r addressed via ISAR); Decrement ISAR
case 0xEF: ILLEGAL(); break; // No instruction - do a NOP
case 0xF0: NS(0); break; // A <- (A) AND (r)
case 0xF1: NS(1); break; // A <- (A) AND (r)
@ -275,8 +289,7 @@
case 0xFC: NS_IS(); break; // A <- (A) AND (r addressed via ISAR)
case 0xFD: NS_IS_INC(); break; // A <- (A) AND (r addressed via ISAR); Increment ISAR
case 0xFE: NS_IS_DEC(); break; // A <- (A) AND (r addressed via ISAR); Decrement ISAR
default: ILLEGAL(); break; // Illegal Opcode
case 0xFF: ILLEGAL(); break; // No instruction - do a NOP
}
}
}

View File

@ -19,11 +19,12 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
public void IN_Func(byte dest, byte src)
{
Regs[dest] = ReadHardware(Regs[src]);
Regs[dest] = ReadHardware((byte)(Regs[src]));
}
/// <summary>
/// Helper method moving from IO to A and setting flags accordingly
/// Helper method moving from IO pins to accumulator
/// (complement and flags set)
/// </summary>
/// <param name="dest"></param>
/// <param name="src"></param>
@ -33,19 +34,31 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
FlagO = false;
FlagC = false;
// data is complemented between I/O pin and accumulator.
// data is complemented between I/O pins and accumulator.
Regs[dest] = (byte)(Regs[src] ^ 0xFF);
FlagS = Regs[dest].Bit(7);
FlagS = !Regs[dest].Bit(7);
FlagZ = (Regs[dest] & 0xFF) == 0;
}
/// <summary>
/// Helper method moving from accumulator to IO pins
/// (complement)
/// </summary>
/// <param name="dest"></param>
/// <param name="src"></param>
public void OUT_Func(byte dest, byte src)
{
// data is complemented between accumulator and I/O pins.
WriteHardware(Regs[dest], (byte)(Regs[src] ^ 0xFF));
}
public void ClearFlags_Func()
{
FlagC = false;
FlagO = false;
FlagS = false;
FlagZ = false;
FlagZ = true;
}
/// <summary>

View File

@ -761,16 +761,11 @@
}
/// <summary>
/// Illegal Opcode
/// Illegal Opcode - just do a short cycle NOP
/// </summary>
private void ILLEGAL()
{
PopulateCURINSTR(
// S
ROMC_00_S, // DB <- ((PC0)); PC0++
IDLE,
IDLE,
END);
NOP();
}
/// <summary>
@ -1739,12 +1734,14 @@
/// <param name="index"></param>
private void INS_0(byte index)
{
Regs[IO] = index; // latch port index early
PopulateCURINSTR(
// S
ROMC_1C_S, // Idle
OP_IN, A, index, // A <- ((Port index - 0/1))
OP_IN, ALU0, IO, // A <- ((Port index - 0/1))
IDLE,
OP_LR_A_DB_IO, A, A, // A <- (A) - flags set as result of IN or INS operation
OP_LR_A_DB_IO, A, ALU0, // A <- (A) - flags set as result of IN or INS operation
// S
ROMC_00_S, // DB <- ((PC0)); PC0++
IDLE,
@ -1796,11 +1793,13 @@
/// <param name="index"></param>
private void OUTS_0(byte index)
{
Regs[IO] = index; // latch port index early
PopulateCURINSTR(
// S
ROMC_1C_S, // Idle
IDLE,
OP_OUT, index, A, // Port <- (A)
OP_OUT, IO, A, // Port <- (A)
IDLE,
// S
ROMC_00_S, // DB <- ((PC0)); PC0++

View File

@ -515,15 +515,11 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
// A <- (I/O Port 0 or 1)
case OP_IN:
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
//instr_pntr++; // dest == A
//Regs[ALU0] = cur_instr[instr_pntr++]; // src
//IN_Func(A, ALU0);
break;
// I/O Port 0 or 1 <- (A)
case OP_OUT:
WriteHardware(cur_instr[instr_pntr++], (byte)Regs[cur_instr[instr_pntr++]]);
//OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
OUT_Func(IO, A);
break;
// instruction fetch
@ -725,7 +721,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
// port must move the current contents of the data bus into the addressed port
// CYCLE LENGTH: L
case ROMC_1A:
WriteHardware(Regs[IO], (byte)Regs[DB]);
OUT_Func(IO, DB);
break;
// During the prior cycle, the data bus specified the address of an I/O port. The device containing the addressed I/O port
@ -734,7 +730,6 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
// CYCLE LENGTH: L
case ROMC_1B:
IN_Func(DB, IO);
//Regs[DB] = ReadHardware(Regs[IO]);
break;
// None

View File

@ -45,6 +45,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
if (tone == 0)
{
// silence
amplitude = 0;
}
else
{

View File

@ -5,6 +5,60 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF
{
public ControllerDefinition ChannelFControllerDefinition
{
get
{
ControllerDefinition definition = new ControllerDefinition
{
Name = "ChannelF Controller"
};
string pre = "P1 ";
// sticks
var stickR = new List<string>
{
// P1 (right) stick
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
};
foreach (var s in stickR)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Right Controller";
}
pre = "P2 ";
var stickL = new List<string>
{
// P2 (left) stick
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
};
foreach (var s in stickL)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Left Controller";
}
// console
var consoleButtons = new List<string>
{
"RESET", "START", "HOLD", "MODE", "TIME"
};
foreach (var s in consoleButtons)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Console";
}
return definition;
}
}
public bool[] StateConsole = new bool[5];
public string[] ButtonsConsole =
{
@ -82,12 +136,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
for (int i = 0; i < ButtonsConsole.Length; i++)
{
var key = ButtonsConsole[i];
bool prevState = StateConsole[i]; // CTRLConsole.Bit(i);
bool prevState = StateConsole[i]; // CTRLConsole.Bit(i);
bool currState = _controller.IsPressed(key);
if (currState != prevState)
{
StateConsole[i] = currState;
noInput = false;
if (key == "RESET" && StateConsole[i] == true)
{
CPU.Reset();
return true;
}
}
}
@ -118,59 +178,5 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
return noInput;
}
public ControllerDefinition ChannelFControllerDefinition
{
get
{
ControllerDefinition definition = new ControllerDefinition
{
Name = "ChannelF Controller"
};
string pre = "P1 ";
// sticks
var stickR = new List<string>
{
// P1 (right) stick
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
};
foreach (var s in stickR)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Right Controller";
}
pre = "P2 ";
var stickL = new List<string>
{
// P2 (left) stick
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
};
foreach (var s in stickL)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Left Controller";
}
// console
var consoleButtons = new List<string>
{
"RESET", "START", "HOLD", "MODE", "TIME"
};
foreach (var s in consoleButtons)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Console";
}
return definition;
}
}
}
}

View File

@ -55,7 +55,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
// columns
var colourIndex = pOffset + (VRAM[c | (r << 7)] & 0x03);
frameBuffer[(r << 7) + c] = CMap[colourIndex];
//frameBuffer[(r << 7) + c + 1] = CMap[colourIndex];
}
}
}
@ -64,8 +63,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
public int _frameHz = 60;
public int[] CroppedBuffer = new int[102 * 58];
public int VirtualWidth => BufferWidth * 2;
public int VirtualHeight => (int)((double)BufferHeight * 1.3) * 2;
public int VirtualWidth => BufferWidth * 4;
public int VirtualHeight => (int)((double)BufferHeight * 1) * 4;
public int BufferWidth => 102; //128
public int BufferHeight => 58; //64
public int BackgroundColor => Colors.ARGB(0xFF, 0xFF, 0xFF);

View File

@ -25,7 +25,7 @@
// Rom1
return BIOS02[addr - 0x400];
}
else if (addr < 0x2000)
else if (addr < 0x1800)
{
// Cart
//return 0;

View File

@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
/// <returns></returns>
public byte ReadPort(ushort addr)
{
byte result = 1;
byte result = 0xFF;
switch (addr)
{
@ -41,13 +41,13 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
break;
case 0:
// Console Buttons - these are connected to pins 0-3 (bits 0-3) through a 7404 Hex Inverter
// sample RESET state first - this is connected directly to the RESET pin on the CPU
if (DataConsole.Bit(5))
{
CPU.Reset();
}
// Console Buttons - these are connected to pins 0-3 (bits 0-3) through a 7404 Hex Inverter
// b0: TIME
// b1: MODE
// b2: HOLD
// b3: START
// RESET button is connected directly to the RST pin on the CPU (this is handled here in the PollInput() method)
// get the 4 console buttons state
var cButtons = DataConsole & 0x0F;
@ -117,7 +117,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
result = OutputLatch[PORT5];
break;
}
return result;
@ -135,44 +134,46 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
OutputLatch[PORT0] = value;
// LS368 enable pin on bit 6
LS368Disabled = value.Bit(6);
LS368Disabled = !value.Bit(6);
if (value.Bit(5))
if (!value.Bit(5))
{
// pulse clocks the 74195 parallel access shift register which feeds inputs of 2 NAND gates
// writing data to both sets of even and odd VRAM chips (based on the row and column addresses latched into the 7493 ICs
VRAM[(latch_y * 0x80) + latch_x] = (byte)latch_colour;
VRAM[((latch_y) * 0x80) + latch_x] = (byte)latch_colour;
}
break;
case 1:
// latch pixel colour
OutputLatch[PORT1] = value;
// set pixel colour
// write data 0 = bit6
// write data 1 = bit7
latch_colour = ((value ^ 0xFF) >> 6) & 0x03;
latch_colour = ((value) >> 6) & 0x03;
break;
case 4:
// latch horiztonal column address
OutputLatch[PORT4] = value;
// latch horiztonal column address
// these are hex inverted along the way
// bit7 is not sent to the 7493s (IO47N) - make it logical 1 before hex inversion
var p1Data = value | 0x80;
latch_x = (p1Data ^ 0xFF) & 0xFF;
// bit7 is not sent to the 7493s (IO47N)
latch_x = value & 0x7F;
break;
case 5:
// latch vertical row address and sound bits
OutputLatch[PORT5] = value;
// ignore the sound bits
latch_y = value & 0x3F;
// bits 6 (ToneAN) and 7 (ToneBN) are sound generation
var audio = (value >> 6) & 0x03;
if (audio != tone)
@ -183,177 +184,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
AudioChange();
}
// remaining bits latch vertical row address
var vert = (value | 0xC0) & 0xFF;
latch_y = (vert ^ 0xFF) & 0xFF;
break;
}
}
/*
/// <summary>
/// CPU attempts to read data byte from the requested port
/// </summary>
/// <param name="addr"></param>
/// <returns></returns>
public byte ReadPort1(ushort addr)
{
switch (addr)
{
// CPU Port 0
case 0:
// Console buttons
// b0: TIME
// b1: MODE
// b2: HOLD
// b3: START
return (byte)((DataConsole ^ 0xff) | OutputLatch[PORT0]);
// CPU Port 1
case 1:
// Right controller
// b0: RIGHT
// b1: LEFT
// b2: BACK
// b3: FORWARD
// b4: CCW
// b5: CW
// b6: PULL
// b7: PUSH
byte ed1;
if ((OutputLatch[PORT0] & 0x40) == 0)
{
ed1 = DataRight;
}
else
{
ed1 = (byte) (0xC0 | DataRight);
}
return (byte) ((ed1 ^ 0xff) | OutputLatch[PORT1]);
// PSU Port 4
case 4:
// Left controller
// b0: RIGHT
// b1: LEFT
// b2: BACK
// b3: FORWARD
// b4: CCW
// b5: CW
// b6: PULL
// b7: PUSH
byte ed4;
if ((OutputLatch[PORT0] & 0x40) == 0)
{
ed4 = DataLeft;
}
else
{
ed4 = 0xff;
}
return (byte)((ed4 ^ 0xff) | OutputLatch[PORT4]);
// PSU Port 5
case 5:
return (byte) (0 | OutputLatch[PORT5]);
default:
return 0;
}
}
/// <summary>
/// CPU attempts to write data to the requested port (latch)
/// </summary>
/// <param name="addr"></param>
/// <param name="value"></param>
public void WritePort1(ushort addr, byte value)
{
switch (addr)
{
// CPU Port 0
case 0:
// b5: Executes a write to VRAM
// b6: Enable controllers data
OutputLatch[PORT0] = value;
if ((value & 0x20) != 0)
{
// write to VRAM
var offset = _x + (_y * 128);
VRAM[offset] = (byte)(_colour);
}
if ((value & 0x40) != 0)
{
//ControllersEnabled = false;
}
break;
// CPU Port 1
case 1:
// bits 6 and 7 decide pixel colour (this is not inverted)
OutputLatch[PORT1] = value;
// Write Data0 - indicates that valid data is present for both VRAM ODD0 and EVEN0
//bool data0 = value.Bit(6);
// Write Data1 - indicates that valid data is present for both VRAM ODD1 and EVEN1
//bool data1 = value.Bit(7);
_colour = (value >> 6) & 0x3;
break;
// PSU Port 4
case 4:
//
OutputLatch[PORT4] = value;
_x = (value ^ 0xff) & 0x7f;
//_x = (value | 0x80) ^ 0xFF;
/*
// video horizontal position
// 0 - video select
// 1-6 - horiz A-F
break;
// PSU port 5
case 5:
OutputLatch[PORT5] = value;
//_y = (value & 31); // ^ 0xff;
//_y = (value | 0xC0) ^ 0xff;
//_y = (value ^ 0xff) & 0x1f;
// video vertical position and sound
// 0-5 - Vertical A-F
// 6 - Tone AN, 7 - Tone BN
_y = (value ^ 0xff) & 0x3f;
// audio
var aVal = ((value >> 6) & 0x03); // (value & 0xc0) >> 6;
if (aVal != tone)
{
tone = aVal;
time = 0;
amplitude = 1;
AudioChange();
}
break;
}
}
*/
}
}