-
Notifications
You must be signed in to change notification settings - Fork 2.1k
src/devices/bus/a2bus/a2frob.cpp: Add Apple II frob device #13596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
#include "emu.h" | ||
|
||
#include "a2bus.h" | ||
#include "bus/vcs/rom.h" | ||
#include "bus/vcs/vcs_slot.h" | ||
#include "bus/vcs_ctrl/ctrl.h" | ||
#include "cpu/m6502/m6507.h" | ||
#include "emupal.h" | ||
#include "screen.h" | ||
#include "softlist_dev.h" | ||
#include "sound/tiaintf.h" | ||
#include "speaker.h" | ||
#include "../../mame/atari/tia.h" | ||
|
||
#include "machine/mos6530.h" | ||
|
||
//#define VERBOSE (LOG_GENERAL) | ||
#include "logmacro.h" | ||
|
||
#include "a2frob.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The module’s own header should be the first thing after the prefix header.
- Group included headers by module, order from most dependent to least dependent, and sort within groups.
- Things that are inline code (e.g. logmacro.h) come after declaration headers.
This is all documented: https://docs.mamedev.org/contributing/cxx.html#structural-organization
Also, you can’t have things in src/devices depending on things in src/mame.
|
||
virtual bool take_c800() override { return false; } | ||
|
||
u8 m_frob_mem[0x1000] = { 0 }; // 4k frob memory | ||
|
||
u8 read_frob_mem(offs_t offset) { return !m_frob_apple_control ? 0 : m_frob_mem[offset & 0xfff]; } | ||
|
||
void write_frob_mem(offs_t offset, u8 data) { m_frob_mem[offset & 0xfff] = data; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don’t intermix data members and member functions. Keep each grouped separately.
public: | ||
void a2600_write_fff0(offs_t offset, u8 data) | ||
{ | ||
m_byte_for_apple = data; | ||
m_byte_waiting_flag_apple = 1; | ||
} | ||
|
||
u8 a2600_read_fff2(offs_t offset) | ||
{ | ||
if (!machine().side_effects_disabled()) m_byte_waiting_flag_vcs = 0; | ||
return m_byte_for_vcs; | ||
} | ||
|
||
u8 a2600_read_fff1(offs_t offset) | ||
{ | ||
return (m_byte_waiting_flag_apple ? 0 : 1) << 7 | (m_byte_waiting_flag_vcs << 6); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have you made this stuff public
?
Also, you need to use synchronize
barriers to get data from one CPU to the other to avoid things being seen in the wrong order. The card CPU should see the flag indicating that the mailbox for the host CPU is full as soon as it writes it, but the host CPU should not see the flag or the updated value until your on the other side of a sync barrier. The same applies for communication in the opposite direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
synchronize() doesn't work the opposite direction*, some drivers do trickery with machine().scheduler().perfect_quantum(x) to make sure the 'opposite' side comms answer timing is correct.
*:
scheduler runs CPUs in serial, CPU A, then CPU B.
let's say CPU A: 1ms.
scheduler runs CPU B.
At 0.5ms point, CPU B wants to write to a latch that shared with CPU A. CPU A however, is already in the future (from CPU B perspective). And if synchronize() is used here, AFAIK it will be delayed until another 0.5ms has passed. If CPU B were to verify its own written latch value during this time, things will go wrong. -- actually, not sure what would happen here. I think CPU B -> CPU C comms here would go fine with a synchronize()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And to solve that properly (since you don’t know in advance whether a CPU is going to attempt to communicate across scheduling domains), you need an efficient way to roll back and retry a smaller timeslice until you get an “acceptable” delay. But since the CPUs themselves don’t know who’s ahead at any given time, putting both directions through synchronize
at least means that whichever CPU is ahead will try to end its timeslice early when possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for CPU B to be ahead of CPU A? And I don't mean slight deviations with icount < 0.
eg. you have 3 CPUs in a driver. Then the scheduler runs the CPUs in this order A,B.C.A,B,C,A,B,C, etc. (or A,B,C,B,C,B,C if CPU B does a synchronize()). It doesn't eenie meenie miney mo them. CPU B is never ahead of CPU A. CPU C is never ahead of CPU A or B.
The order is the same as the machine config order. It's why for arcade drivers with a 1-way soundlatch, it's important to list the audiocpu after maincpu.
u8 a2600_frob_base_device::read_c0nx(u8 offset) | ||
{ | ||
// offset 0 is read from frob status (bits 7 = write ok, 6 = read ok) (other bits will float) | ||
switch (offset & 0x1) | ||
{ | ||
case 0: | ||
return ((m_byte_waiting_flag_vcs ? 0 : 1) << 7) | | ||
(m_byte_waiting_flag_apple << 6); | ||
break; | ||
case 1: | ||
if (!machine().side_effects_disabled()) | ||
{ | ||
m_byte_waiting_flag_apple = 0; // clear byte waiting for apple | ||
} | ||
return m_byte_for_apple; | ||
default: | ||
return 0; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment about needing sync barriers applies. Host CPU should see the flag indicating the mailbox for the card CPU is full as soon as it writes it, but should not see the mailbox full from the card CPU until it’s on the other side of a sync barrier.
m_bidirectional_active = BIT(data, 5); | ||
m_frob_page = BIT(data, 0, 4); | ||
// printf("m_frob_apple_control = %x m_frob_page = %x\n",m_frob_apple_control, m_frob_page); | ||
break; | ||
case 1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use logmacro.h helpers for configurable logging, not commented prints. Commented code always rots.
void a2600_frob_base_device::switch_A_w(uint8_t data) | ||
{ | ||
/* Left controller port */ | ||
m_joy1->joy_w( data >> 4 ); | ||
|
||
/* Right controller port */ | ||
m_joy2->joy_w( data & 0x0f ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use consistent formatting for function calls.
Adding a driver for the FrobCo Frob Atari 2600 ROM emulator for the Apple II.
https://forums.atariage.com/topic/380267-the-frob-livesagain/