misc/magicard.cpp: Added required devices and default NVRAM contents. (#9970)

* cpu/pic16c5x: Expose driven lines to I/O handlers in mask.
* machine/ds1207.cpp: Added DS1207 Time Key device.
* machine/msm6242.cpp: Fixed interrupt output pulse duration.
* machine/scc66470.cpp: Added Philips SCC66470 Video and System controller device.

Machines promoted to working
-------------------------------
Puzzle Me!
Lucky 7 (Impera) V04/91a

Clones promoted to working
-------------------------------
Magic Card Export 94 (V2.11a, set 3)
Magic Card - Wien (Sicherheitsversion 1.2)
unknown Poker 'TE06'
This commit is contained in:
Paul-Arnold 2022-08-18 14:41:08 +01:00 committed by GitHub
parent 266b918349
commit 0a18e66463
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 3417 additions and 627 deletions

View File

@ -1179,6 +1179,18 @@ if (MACHINES["DS1205"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/ds1207.h,MACHINES["DS1207"] = true
---------------------------------------------------
if (MACHINES["DS1207"]~=null) then
files {
MAME_DIR .. "src/devices/machine/ds1207.cpp",
MAME_DIR .. "src/devices/machine/ds1207.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/ds1302.h,MACHINES["DS1302"] = true
@ -3105,6 +3117,17 @@ if (MACHINES["SAA1043"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/scc66470.h,MACHINES["SCC66470"] = true
---------------------------------------------------
if (MACHINES["SCC66470"]~=null) then
files {
MAME_DIR .. "src/devices/machine/scc66470.cpp",
MAME_DIR .. "src/devices/machine/scc66470.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/scc68070.h,MACHINES["SCC68070"] = true

View File

@ -51,6 +51,8 @@
* hap (12-Feb-2017) Ver 1.16 *
* - Added basic support for the old GI PIC1650 and PIC1655. *
* - Made RTCC(aka T0CKI) pin an inputline handler. *
* pa (12-Jun-2022) Ver 1.17 *
* - Port callback functions pass tristate value in mem_mask. *
* *
* *
* **** Notes: **** *
@ -449,7 +451,7 @@ void pic16c5x_device::STORE_REGFILE(offs_t addr, uint8_t data) /* Write to in
}
else if (m_picmodel != 0x1655) { /* A is input-only on 1655 */
data &= 0x0f; /* 4-bit port (only lower 4 bits used) */
m_write_a(PIC16C5x_PORTA, data & (uint8_t)(~m_TRISA), 0xff);
m_write_a(PIC16C5x_PORTA, data & (uint8_t)(~m_TRISA) & 0x0f, (uint8_t)(~m_TRISA) & 0x0f);
}
PORTA = data;
break;
@ -458,7 +460,7 @@ void pic16c5x_device::STORE_REGFILE(offs_t addr, uint8_t data) /* Write to in
m_write_b(PIC16C5x_PORTB, data, 0xff);
}
else {
m_write_b(PIC16C5x_PORTB, data & (uint8_t)(~m_TRISB), 0xff);
m_write_b(PIC16C5x_PORTB, data & (uint8_t)(~m_TRISB), (uint8_t)(~m_TRISB));
}
PORTB = data;
break;
@ -467,7 +469,7 @@ void pic16c5x_device::STORE_REGFILE(offs_t addr, uint8_t data) /* Write to in
m_write_c(PIC16C5x_PORTC, data, 0xff);
}
else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) {
m_write_c(PIC16C5x_PORTC, data & (uint8_t)(~m_TRISC), 0xff);
m_write_c(PIC16C5x_PORTC, data & (uint8_t)(~m_TRISC), (uint8_t)(~m_TRISC));
}
PORTC = data; /* also writes to RAM */
break;
@ -756,12 +758,12 @@ void pic16c5x_device::tris()
switch(m_opcode.b.l & 0x7)
{
case 5: if (m_TRISA == m_W) break;
else { m_TRISA = m_W | 0xf0; m_write_a(PIC16C5x_PORTA, PORTA & (uint8_t)(~m_TRISA) & 0x0f, 0xff); break; }
else { m_TRISA = m_W | 0xf0; m_write_a(PIC16C5x_PORTA, PORTA & (uint8_t)(~m_TRISA) & 0x0f, (uint8_t)(~m_TRISA) & 0x0f); break; }
case 6: if (m_TRISB == m_W) break;
else { m_TRISB = m_W; m_write_b(PIC16C5x_PORTB, PORTB & (uint8_t)(~m_TRISB), 0xff); break; }
else { m_TRISB = m_W; m_write_b(PIC16C5x_PORTB, PORTB & (uint8_t)(~m_TRISB), (uint8_t)(~m_TRISB)); break; }
case 7: if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) {
if (m_TRISC == m_W) break;
else { m_TRISC = m_W; m_write_c(PIC16C5x_PORTC, PORTC & (uint8_t)(~m_TRISC), 0xff); break; }
else { m_TRISC = m_W; m_write_c(PIC16C5x_PORTC, PORTC & (uint8_t)(~m_TRISC), (uint8_t)(~m_TRISC)); break; }
}
else {
illegal(); break;

View File

@ -0,0 +1,646 @@
// license:BSD-3-Clause
// copyright-holders:Paul-Arnold
/*
* ds1207.c
*
* Time Key
*
* Based on ds1204 by smf.
*
* File format is as follows:
* 00-01 unique command pattern
* 02-09 identification pattern
* 0a-11 security match
* 12-41 secure memory data
* 42-43 days left
* 44-4b start time (from time_t)
* 4c control
*
* Control bits:
* bit 0 - OSC ENABLED
* bit 1 - OSC RUNNING
* bit 2 - DAYS LOCKED
* bit 3 - DAYS EXPIRED
*
* The unique command pattern can be user specific but a number of off the shelf devices exist.
* For these devices the pattern should be as follows:
* DS1207-G01 0x00 0xb0
* DS1207-G02 0x04 0xb0
* DS1207-G03 0x08 0xb0
* DS1207-G04 0x0c 0xb0
* DS1207-G05 0x10 0xb0
*/
#include "emu.h"
#include "ds1207.h"
#define LOG_LINES (1U << 1)
#define LOG_STATE (1U << 2)
#define LOG_DATA (1U << 3)
//#define VERBOSE (LOG_LINES | LOG_STATE | LOG_DATA)
#include "logmacro.h"
#define LOGLINES(...) LOGMASKED(LOG_LINES, __VA_ARGS__)
#define LOGSTATE(...) LOGMASKED(LOG_STATE, __VA_ARGS__)
#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__)
// device type definition
DEFINE_DEVICE_TYPE(DS1207, ds1207_device, "ds1207", "DS1207 Time Key")
ds1207_device::ds1207_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, DS1207, tag, owner, clock),
device_nvram_interface(mconfig, *this),
device_rtc_interface(mconfig, *this),
m_region(*this, DEVICE_SELF),
m_rst(0),
m_clk(0),
m_dqw(0), m_dqr(0), m_state(0), m_bit(0)
{
}
void ds1207_device::device_reset()
{
adjust_days_left(); // compensate for time machine has been turned off
}
void ds1207_device::device_start()
{
new_state(STATE_STOP);
m_dqr = DQ_HIGH_IMPEDANCE;
std::fill_n(m_command, std::size(m_command), 0);
std::fill_n(m_compare_register, std::size(m_compare_register), 0);
m_last_update_time = 0;
m_startup_time = 0;
std::fill_n(m_day_clock, std::size(m_day_clock), 0);
save_item(NAME(m_rst));
save_item(NAME(m_clk));
save_item(NAME(m_dqw));
save_item(NAME(m_dqr));
save_item(NAME(m_state));
save_item(NAME(m_bit));
save_item(NAME(m_command));
save_item(NAME(m_compare_register));
save_item(NAME(m_unique_pattern));
save_item(NAME(m_identification));
save_item(NAME(m_security_match));
save_item(NAME(m_secure_memory));
save_item(NAME(m_day_clock));
save_item(NAME(m_days_left));
save_item(NAME(m_start_time));
save_item(NAME(m_device_state));
save_item(NAME(m_startup_time));
save_item(NAME(m_last_update_time));
}
void ds1207_device::nvram_default()
{
std::fill_n(m_unique_pattern, std::size(m_unique_pattern), 0);
std::fill_n(m_identification, std::size(m_identification), 0);
std::fill_n(m_security_match, std::size(m_security_match), 0);
std::fill_n(m_secure_memory, std::size(m_secure_memory), 0);
std::fill_n(m_days_left, std::size(m_days_left), 0);
std::fill_n(m_start_time, std::size(m_start_time), 0);
m_device_state = 0;
int expected_bytes = sizeof(m_unique_pattern) + sizeof(m_identification) + sizeof(m_security_match) + sizeof(m_secure_memory)
+ sizeof(m_days_left) + sizeof(m_start_time) + sizeof(m_device_state);;
if(!m_region.found())
{
logerror("ds1207(%s) region not found\n", tag());
}
else if(m_region->bytes() != expected_bytes)
{
logerror("ds1207(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_bytes);
}
else
{
uint8_t *region = m_region->base();
memcpy(m_unique_pattern, region, sizeof(m_unique_pattern));
region += sizeof(m_unique_pattern);
memcpy(m_identification, region, sizeof(m_identification));
region += sizeof(m_identification);
memcpy(m_security_match, region, sizeof(m_security_match));
region += sizeof(m_security_match);
memcpy(m_secure_memory, region, sizeof(m_secure_memory));
region += sizeof(m_secure_memory);
memcpy(m_days_left, region, sizeof(m_days_left));
region += sizeof(m_days_left);
memcpy(m_start_time, region, sizeof(m_start_time));
region += sizeof(m_start_time);
memcpy(&m_device_state, region, sizeof(m_device_state));
region += sizeof(m_device_state);
}
}
bool ds1207_device::nvram_read(util::read_stream &file)
{
size_t actual;
bool result = !file.read(m_unique_pattern, sizeof(m_unique_pattern), actual) && actual == sizeof(m_unique_pattern);
result = result && !file.read(m_identification, sizeof(m_identification), actual) && actual == sizeof(m_identification);
result = result && !file.read(m_security_match, sizeof(m_security_match), actual) && actual == sizeof(m_security_match);
result = result && !file.read(m_secure_memory, sizeof(m_secure_memory), actual) && actual == sizeof(m_secure_memory);
result = result && !file.read(m_days_left, sizeof(m_days_left), actual) && actual == sizeof(m_days_left);
result = result && !file.read(m_start_time, sizeof(m_start_time), actual) && actual == sizeof(m_start_time);
result = result && !file.read(&m_device_state, sizeof(m_device_state), actual) && actual == sizeof(m_device_state);
return result;
}
bool ds1207_device::nvram_write(util::write_stream &file)
{
size_t actual;
bool result = !file.write(m_unique_pattern, sizeof(m_unique_pattern), actual) && actual == sizeof(m_unique_pattern);
result = result && !file.write(m_identification, sizeof(m_identification), actual) && actual == sizeof(m_identification);
result = result && !file.write(m_security_match, sizeof(m_security_match), actual) && actual == sizeof(m_security_match);
result = result && !file.write(m_secure_memory, sizeof(m_secure_memory), actual) && actual == sizeof(m_secure_memory);
result = result && !file.write(m_days_left, sizeof(m_days_left), actual) && actual == sizeof(m_days_left);
result = result && !file.write(m_start_time, sizeof(m_start_time), actual) && actual == sizeof(m_start_time);
result = result && !file.write(&m_device_state, sizeof(m_device_state), actual) && actual == sizeof(m_device_state);
return result;
}
void ds1207_device::new_state(uint8_t state)
{
m_state = state;
m_bit = 0;
}
void ds1207_device::writebit(uint8_t *buffer)
{
if(m_clk)
{
uint16_t index = m_bit / 8;
uint8_t mask = 1 << (m_bit % 8);
if(m_dqw)
{
buffer[ index ] |= mask;
}
else
{
buffer[ index ] &= ~mask;
}
m_bit++;
}
}
void ds1207_device::readbit(uint8_t *buffer)
{
if(!m_clk)
{
uint16_t index = m_bit / 8;
uint8_t mask = 1 << (m_bit % 8);
if(buffer[ index ] & mask)
{
m_dqr = 1;
}
else
{
m_dqr = 0;
}
}
else
{
m_bit++;
}
}
WRITE_LINE_MEMBER(ds1207_device::write_rst)
{
const uint8_t this_state = state ? 1 : 0;
if(m_rst != this_state)
{
m_rst = this_state;
LOGLINES("%s: DS1270 rst=%d\n", machine().describe_context(), m_rst);
if(m_rst)
{
new_state(STATE_PROTOCOL);
}
else
{
switch(m_state)
{
case STATE_WRITE_IDENTIFICATION:
LOGSTATE("%s: DS1270 reset during write identification (bit=%u)\n", machine().describe_context(), m_bit);
break;
case STATE_WRITE_SECURITY_MATCH:
LOGSTATE("%s: DS1270 reset during write security match (bit=%u)\n", machine().describe_context(), m_bit);
break;
case STATE_WRITE_SECURE_MEMORY:
LOGSTATE("%s: DS1270 reset during write secure memory (bit=%u)\n", machine().describe_context(), m_bit);
break;
}
new_state(STATE_STOP);
m_dqr = DQ_HIGH_IMPEDANCE;
}
}
}
WRITE_LINE_MEMBER(ds1207_device::write_clk)
{
const uint8_t this_state = state ? 1 : 0;
if(m_clk != this_state)
{
m_clk = this_state;
LOGLINES("%s: DS1270 clk=%d (bit=%u)\n", machine().describe_context(), m_clk, m_bit);
if(m_clk)
{
m_dqr = DQ_HIGH_IMPEDANCE;
}
switch(m_state)
{
case STATE_PROTOCOL:
writebit(m_command);
if(m_bit == 24)
{
LOGDATA("%s: DS1270 -> command %02x %02x %02x (%02x %02x)\n", machine().describe_context(),
m_command[ 0 ], m_command[ 1 ], m_command[ 2 ], m_unique_pattern[ 0 ], m_unique_pattern[ 1 ]);
if(m_command[ 2 ] == m_unique_pattern[ 1 ] && (m_command[ 1 ] & ~3) == m_unique_pattern[ 0 ])
{
set_start_time();
adjust_time_into_day();
if(m_command[ 0 ] == COMMAND_READ && (m_command[ 1 ] & 3) == CYCLE_NORMAL)
{
new_state(STATE_READ_IDENTIFICATION);
}
else if(m_command[ 0 ] == COMMAND_READ_DAY_CLOCK && (m_command[ 1 ] & 3) == CYCLE_PROGRAM)
{
new_state(STATE_READ_DAY_CLOCK);
}
else if(m_command[ 0 ] == COMMAND_READ_DAYS_REMAINING && (m_command[ 1 ] & 3) == CYCLE_PROGRAM)
{
new_state(STATE_READ_DAYS_REMAINING);
}
else if(!(m_device_state & DAYS_EXPIRED))
{
if(m_command[ 0 ] == COMMAND_WRITE && (m_command[ 1 ] & 3) == CYCLE_NORMAL)
{
new_state(STATE_READ_IDENTIFICATION);
}
else if((m_command[ 1 ] & 3) == CYCLE_PROGRAM)
{
if(m_command[ 0 ] == COMMAND_WRITE)
{
new_state(STATE_WRITE_IDENTIFICATION);
}
else if(m_command[ 0 ] == COMMAND_WRITE_DAYS_REMAINING)
{
if(!(m_device_state & DAYS_LOCKED))
{
new_state(STATE_WRITE_DAYS_REMAINING);
}
else
{
new_state(STATE_STOP);
}
}
else if(m_command[ 0 ] == COMMAND_LOCK_DAYS_COUNT)
{
m_device_state |= DAYS_LOCKED;
new_state(STATE_STOP);
}
else if(m_command[ 0 ] == COMMAND_STOP_OSCILLATOR)
{
if(!(m_device_state & DAYS_LOCKED))
{
m_device_state &= ~(OSC_ENABLED | OSC_RUNNING);
}
new_state(STATE_STOP);
}
else if(m_command[ 0 ] == COMMAND_ARM_OSCILLATOR)
{
m_device_state |= OSC_ENABLED;
}
else
{
new_state(STATE_STOP);
}
}
else
{
new_state(STATE_STOP);
}
}
else
{
new_state(STATE_STOP);
}
}
else
{
new_state(STATE_STOP);
}
}
break;
case STATE_READ_IDENTIFICATION:
readbit(m_identification);
if(m_bit == 64)
{
LOGDATA("%s: DS1270 <- identification %02x %02x %02x %02x %02x %02x %02x %02x\n", machine().describe_context(),
m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ],
m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ]);
new_state(STATE_WRITE_COMPARE_REGISTER);
}
break;
case STATE_WRITE_COMPARE_REGISTER:
writebit(m_compare_register);
if(m_bit == 64)
{
LOGDATA("%s: DS1207 -> compare register %02x %02x %02x %02x %02x %02x %02x %02x (%02x %02x %02x %02x %02x %02x %02x %02x)\n", machine().describe_context(),
m_compare_register[ 0 ], m_compare_register[ 1 ], m_compare_register[ 2 ], m_compare_register[ 3 ],
m_compare_register[ 4 ], m_compare_register[ 5 ], m_compare_register[ 6 ], m_compare_register[ 7 ],
m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ],
m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ]);
if(memcmp(m_compare_register, m_security_match, sizeof(m_compare_register)) == 0)
{
if(m_command[ 0 ] == COMMAND_READ)
{
new_state(STATE_READ_SECURE_MEMORY);
}
else
{
new_state(STATE_WRITE_SECURE_MEMORY);
}
}
else
{
new_state(STATE_OUTPUT_GARBLED_DATA);
}
}
break;
case STATE_READ_SECURE_MEMORY:
readbit(m_secure_memory);
if(m_bit == 384)
{
new_state(STATE_STOP);
}
break;
case STATE_WRITE_SECURE_MEMORY:
writebit(m_secure_memory);
if(m_bit == 384)
{
new_state(STATE_STOP);
}
break;
case STATE_WRITE_IDENTIFICATION:
writebit(m_identification);
if(m_bit == 64)
{
LOGDATA("%s: DS1207 -> identification %02x %02x %02x %02x %02x %02x %02x %02x\n", machine().describe_context(),
m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ],
m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ]);
new_state(STATE_WRITE_SECURITY_MATCH);
}
break;
case STATE_WRITE_SECURITY_MATCH:
writebit(m_security_match);
if(m_bit == 64)
{
LOGDATA("%s: DS1207 >- security match %02x %02x %02x %02x %02x %02x %02x %02x\n", machine().describe_context(),
m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ],
m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ]);
new_state(STATE_STOP);
}
break;
case STATE_OUTPUT_GARBLED_DATA:
if(!m_clk && m_command[ 0 ] == COMMAND_READ)
{
m_dqr = machine().rand() & 1;
m_bit++;
}
else if(m_clk && m_command[ 0 ] == COMMAND_WRITE)
{
m_bit++;
}
if(m_bit == 64)
{
if(m_command[ 0 ] == COMMAND_READ)
{
LOGDATA("%s: DS1207 <- random\n", machine().describe_context());
}
else
{
LOGDATA("%s: DS1207 -> ignore\n", machine().describe_context());
}
new_state(STATE_STOP);
}
break;
case STATE_READ_DAY_CLOCK:
readbit(m_day_clock);
if(m_bit == 20)
{
new_state(STATE_STOP);
}
break;
case STATE_READ_DAYS_REMAINING:
readbit(m_days_left);
if(m_bit == 9)
{
new_state(STATE_STOP);
}
break;
case STATE_WRITE_DAYS_REMAINING:
writebit(m_days_left);
if(m_bit == 9)
{
new_state(STATE_STOP);
}
break;
}
}
}
WRITE_LINE_MEMBER(ds1207_device::write_dq)
{
const uint8_t this_state = state ? 1 : 0;
if(m_dqw != this_state)
{
m_dqw = this_state;
LOGLINES("%s: DS1270 dqw=%u\n", machine().describe_context(), m_dqw);
}
}
READ_LINE_MEMBER(ds1207_device::read_dq)
{
if(m_dqr == DQ_HIGH_IMPEDANCE)
{
LOGLINES("%s: DS1270 dqr=high impedance\n", machine().describe_context());
return 0;
}
LOGLINES("%s: DS1270 dqr=%d (bit=%u)\n", machine().describe_context(), m_dqr, m_bit);
return m_dqr;
}
void ds1207_device::adjust_time_into_day()
{
if(!(m_device_state & DAYS_EXPIRED) && (m_device_state & OSC_ENABLED) && (m_device_state & OSC_RUNNING))
{
uint64_t day_clock = ((uint64_t)m_day_clock[ 0 ]) | (((uint64_t)m_day_clock[ 1 ]) << 8) | (((uint64_t)m_day_clock[ 2 ]) << 16);
const uint64_t cur_time = machine().time().as_ticks(32768) / 2700;
const uint64_t diff_time = cur_time - m_last_update_time;
m_last_update_time = cur_time;
day_clock += diff_time;
m_day_clock[ 0 ] = day_clock & 0xff;
m_day_clock[ 1 ] = (day_clock >> 8) & 0xff;
m_day_clock[ 2 ] = (day_clock >> 16) & 0xff;
if(day_clock >= 1048576)
{
adjust_days_left();
}
}
}
void ds1207_device::adjust_days_left()
{
if(!(m_device_state & DAYS_EXPIRED) && (m_device_state & OSC_ENABLED) && (m_device_state & OSC_RUNNING))
{
const uint64_t current_time = m_startup_time + machine().time().as_ticks(1);
uint64_t start_time = 0;
for(int i = 0; i < 8 ; i++)
{
start_time <<= 8;
start_time |= m_start_time[ 7 - i ];
}
if(current_time > start_time)
{
uint64_t time_diff = current_time - start_time;
const uint16_t days_elapsed = time_diff / (24*60*60);
time_diff %= (24*60*60);// seconds into day
const uint32_t day_clock = (time_diff * 32768)/2700;// time into day
m_day_clock[ 0 ] = day_clock & 0xff;
m_day_clock[ 1 ] = (day_clock >> 8) & 0xff;
m_day_clock[ 2 ] = (day_clock >> 16) & 0xff;
if(days_elapsed > 0)
{
uint16_t days_left = m_days_left[ 0 ] | (m_days_left[ 1 ] << 8);
if(days_elapsed > days_left)
{
days_left = 0xffff;
m_device_state |= DAYS_EXPIRED;
}
else
{
days_left -= days_elapsed;
}
m_days_left[ 0 ] = days_left & 0xff;
m_days_left[ 1 ] = (days_left >> 8) & 0x1;
start_time += days_elapsed * 24 * 60 * 60;
for(int i = 0; i < 8 ; i++)
{
m_start_time[ i ] = (start_time >> (i * 8)) & 0xff;
}
}
}
}
}
void ds1207_device::set_start_time()
{
if(!(m_device_state & DAYS_EXPIRED) && m_device_state & OSC_ENABLED && !(m_device_state & OSC_RUNNING))
{
const uint64_t current_time = m_startup_time + machine().time().as_ticks(1);
for(int i = 0; i < 8 ; i++)
{
m_start_time[ i ] = (current_time >> (i * 8)) & 0xff;
}
m_day_clock [ 0 ] = m_day_clock[ 1 ] = m_day_clock[ 2 ] = 0;
m_device_state |= OSC_RUNNING;
}
}
void ds1207_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
const int month_to_day_conversion[ 12 ] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
// put the seconds
uint64_t m_startup_time = second;
// put the minutes
m_startup_time += minute * 60;
// put the hours
m_startup_time += hour * 60 * 60;
// put the days (note -1) */
m_startup_time += (day - 1) * 60 * 60 * 24;
// take the months - despite popular beliefs, leap years aren't just evenly divisible by 4 */
if(((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)) && month > 2)
{
m_startup_time += (month_to_day_conversion[ month - 1 ] + 1) * 60 * 60 * 24;
}
else
{
m_startup_time += (month_to_day_conversion[ month - 1 ]) * 60 * 60 * 24;
}
// put the years
int year_count = (year - 1969);
for(int i = 0; i < year_count - 1 ; i++)
{
m_startup_time += (((((i+1970) % 4) == 0) && (((i+1970) % 100) != 0)) || (((i+1970) % 400) == 0)) ? 60*60*24*366 : 60*60*24*365;
}
}

View File

@ -0,0 +1,122 @@
// license:BSD-3-Clause
// copyright-holders:Paul-Arnold
/*
* ds1207.h
*
* Time Key
*
*/
#ifndef MAME_MACHINE_DS1207_H
#define MAME_MACHINE_DS1207_H
#pragma once
#include "dirtc.h"
class ds1207_device : public device_t, public device_nvram_interface, public device_rtc_interface
{
public:
// construction/destruction
ds1207_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
DECLARE_WRITE_LINE_MEMBER(write_rst);
DECLARE_WRITE_LINE_MEMBER(write_clk);
DECLARE_WRITE_LINE_MEMBER(write_dq);
DECLARE_READ_LINE_MEMBER(read_dq);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// device_nvram_interface overrides
virtual void nvram_default() override;
virtual bool nvram_read(util::read_stream &file) override;
virtual bool nvram_write(util::write_stream &file) override;
// device_rtc_interface overrides
virtual bool rtc_feature_y2k() const override { return true; }
virtual bool rtc_feature_leap_year() const override { return true; }
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override;
private:
void new_state(uint8_t state);
void writebit(uint8_t *buffer);
void readbit(uint8_t *buffer);
void set_start_time();
void adjust_days_left();
void adjust_time_into_day();
enum state_t
{
STATE_STOP,
STATE_PROTOCOL,
STATE_READ_IDENTIFICATION,
STATE_WRITE_IDENTIFICATION,
STATE_WRITE_COMPARE_REGISTER,
STATE_WRITE_SECURITY_MATCH,
STATE_READ_SECURE_MEMORY,
STATE_WRITE_SECURE_MEMORY,
STATE_OUTPUT_GARBLED_DATA,
STATE_READ_DAY_CLOCK,
STATE_READ_DAYS_REMAINING,
STATE_WRITE_DAYS_REMAINING
};
enum command_t
{
COMMAND_READ = 0x62,
COMMAND_WRITE = 0x9d,
COMMAND_READ_DAY_CLOCK = 0xf1,
COMMAND_WRITE_DAYS_REMAINING = 0xf2,
COMMAND_READ_DAYS_REMAINING = 0xf3,
COMMAND_STOP_OSCILLATOR = 0xf4,
COMMAND_ARM_OSCILLATOR = 0xf5,
COMMAND_LOCK_DAYS_COUNT = 0xf6
};
enum cycle_t
{
CYCLE_NORMAL = 1,
CYCLE_PROGRAM = 2,
CYCLE_MASK = 3
};
enum device_state_t
{
OSC_ENABLED = 1,
OSC_RUNNING = 2,
DAYS_LOCKED = 4,
DAYS_EXPIRED = 8
};
static const int8_t DQ_HIGH_IMPEDANCE = -1;
optional_memory_region m_region;
uint8_t m_rst;
uint8_t m_clk;
uint8_t m_dqw;
int8_t m_dqr;
uint8_t m_state;
uint16_t m_bit;
uint64_t m_startup_time;
uint64_t m_last_update_time;
uint8_t m_command[3];
uint8_t m_day_clock[3];
uint8_t m_compare_register[8];
uint8_t m_unique_pattern[2];
uint8_t m_identification[8];
uint8_t m_security_match[8];
uint8_t m_secure_memory[48];
uint8_t m_days_left[2];
uint8_t m_start_time[8];
uint8_t m_device_state;
};
// device type definition
DECLARE_DEVICE_TYPE(DS1207, ds1207_device)
#endif // MAME_MACHINE_DS1207_H

View File

@ -53,7 +53,6 @@ enum
MSM6242_REG_CF
};
#define TIMER_RTC_CALLBACK 1
@ -102,6 +101,8 @@ void msm6242_device::device_start()
// let's call the timer callback every tick
m_timer = timer_alloc(FUNC(msm6242_device::rtc_timer_callback), this);
m_timer->adjust(attotime::zero);
m_timer_irq_clear = timer_alloc(FUNC(msm6242_device::rtc_irq_pulse_timer_callback), this);
m_timer_irq_clear->adjust(attotime::zero);
// set up registers
m_tick = 0;
@ -176,6 +177,14 @@ void msm6242_device::set_irq(bool active)
if (!m_out_int_handler.isnull())
m_out_int_handler(active ? ASSERT_LINE : CLEAR_LINE);
if (active)
{
if (!BIT(m_reg[1], 1)) // irq is pulsed
{
m_timer_irq_clear->adjust(attotime::from_nsec(7812500));
}
}
}
@ -262,7 +271,7 @@ void msm6242_device::update_rtc_registers()
return;
// ticks
if ((m_tick % 200) != int((delta + m_tick) % 0x200))
if ((m_tick / 0x200) != int((delta + m_tick) / 0x200))
irq(IRQ_64THSECOND);
delta = bump(RTC_TICKS, delta, 0, 0x8000);
if (delta == 0)
@ -369,6 +378,17 @@ TIMER_CALLBACK_MEMBER(msm6242_device::rtc_timer_callback)
//-------------------------------------------------
// rtc_irq_pulse_timer_callback
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(msm6242_device::rtc_irq_pulse_timer_callback)
{
set_irq(false);
}
//-------------------------------------------------
// get_clock_nibble
//-------------------------------------------------
@ -519,6 +539,7 @@ void msm6242_device::write(offs_t offset, u8 data)
{
LOGIRQENABLE("%s: MSM6242 acknowledging irq\n", machine().describe_context());
set_irq(false);
m_timer_irq_clear->adjust(attotime::zero);
}
m_reg[0] = (data & 0x09) | (m_reg[0] & 0x06);
break;
@ -528,7 +549,7 @@ void msm6242_device::write(offs_t offset, u8 data)
// --x- STD
// ---x MASK
m_reg[1] = data & 0x0f;
if((data & 3) == 0) // MASK & STD = 0
if((data & 1) == 0) // MASK = 0
{
m_irq_flag = 1;
m_irq_type = (data & 0xc) >> 2;

View File

@ -83,10 +83,12 @@ private:
// incidentals
devcb_write_line m_out_int_handler;
emu_timer * m_timer;
emu_timer * m_timer_irq_clear;
u64 m_last_update_time; // last update time, in clock cycles
// methods
TIMER_CALLBACK_MEMBER(rtc_timer_callback);
TIMER_CALLBACK_MEMBER(rtc_irq_pulse_timer_callback);
u64 current_time();
void set_irq(bool active);
void irq(u8 irq_type);

View File

@ -0,0 +1,901 @@
// license:BSD-3-Clause
// copyright-holders:Paul Arnold
/***************************************************************************
Philips SCC66470 Video and System controller.
This does not render the image to the display. It is up to the user
to provide their own screen_update function. Pixel (palette offset) data
can be obtained by calling line( line number ) for each line.
Some boards have multiple video sources, the source being displayed being
selected based on pixel value...is there a nice way of doing this other
than leaving it to the board driver ?
Todo:
Add support for mosaic and RLE screens.
Add remaining pixac operations. Only BCOLOUR1/BCOLOUR2 are supported.
Add interlaced support.
Add bep ?
Verify number of cycles for each access.
***************************************************************************/
#include "emu.h"
#include "scc66470.h"
#include "screen.h"
#define CSR_REG (m_csr)
#define DCR_REG (m_dcr)
#define DCR2_REG (m_dcr2)
#define DCR_DE 15
#define DCR_CF1 14
#define DCR_CF2 13
#define DCR_FD 12
#define DCR_SM 11
#define DCR_SS 10
#define DCR_LS 9
#define DCR_CM 8
#define DCR_FG 7
#define DCR_DF 6
#define DCR_IC 5
#define DCR_DC 4
#define CSR_DI1 15
#define CSR_DI2 14
#define CSR_EW 10
#define CSR_DD1 9
#define CSR_DD2 8
#define CSR_DM1 7
#define CSR_DM2 6
#define CSR_TD 5
#define CSR_CG 4
#define CSR_DD 3
#define CSR_ED 2
#define CSR_ST 1
#define CSR_BE 0
#define DCR2_OM1 14
#define DCR2_OM2 13
#define DCR2_ID 12
#define DCR2_MF1 11
#define DCR2_MF2 10
#define DCR2_FT1 9
#define DCR2_FT2 8
#define CSR_R_DA 0x80
#define CSR_R_PA 0x20
#define CSR_R_IT2 0x04
#define CSR_R_IT1 0x02
#define SCC_INS_STOP ( 0 << 12 )
#define SCC_INS_NOP ( 1 << 12 )
#define SCC_INS_LOAD_DCP ( 2 << 12 )
#define SCC_INS_LOAD_DCP_STOP ( 3 << 12 )
#define SCC_INS_LOAD_VSR ( 4 << 12 )
#define SCC_INS_LOAD_VSR_STOP ( 5 << 12 )
#define SCC_INS_INTERRUPT ( 6 << 12 )
#define SCC_INS_LOAD_BORDER ( 14 << 11 )
#define SCC_INS_LOAD_BORDER_DSP ( 15 << 11 )
#define SCC_INS_BEP_CONTROL ( 1 << 15 )
#define PIXAC_4N 15
#define PIXAC_COL 14
#define PIXAC_EXC 13
#define PIXAC_CPY 12
#define PIXAC_CMP 11
#define PIXAC_RTL 10
#define PIXAC_SHK 9
#define PIXAC_ZOM 8
#define PIXAC_INV 3
#define PIXAC_BIT 2
#define PIXAC_TT 1
#define PIXAC_NI 0
struct horizontal_settings
{
uint32_t pixels;
uint32_t border;
};
static const horizontal_settings h_table[] =
{
//cf1 cf2 ss st
{ 512, 64 }, // 0 0 0 0
{ 512, 64 }, // 0 0 0 1
{ 512, 0 }, // 0 0 1 0
{ 512, 0 }, // 0 0 1 1
{ 640, 128 }, // 0 1 0 0
{ 640, 128 }, // 0 1 0 1
{ 640, 0 }, // 0 1 1 0
{ 640, 0 }, // 0 1 1 1
{ 720, 80 }, // 1 0 0 0
{ 720, 80 }, // 1 0 0 1
{ 720, 0 }, // 1 0 1 0
{ 720, 0 }, // 1 0 1 1
{ 768, 128 }, // 1 1 0 0
{ 720, 80 }, // 1 1 0 1
{ 768, 0 }, // 1 1 1 0
{ 768, 48 }, // 1 1 1 1
};
// device type definition
DEFINE_DEVICE_TYPE(SCC66470, scc66470_device, "scc66470", "Philips SCC66470")
//-------------------------------------------------
// scc66470_device - constructor
//-------------------------------------------------
scc66470_device::scc66470_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, SCC66470, tag, owner, clock),
device_memory_interface(mconfig, *this),
device_video_interface(mconfig, *this),
m_irqcallback(*this),
m_space_config("videoram", ENDIANNESS_BIG, 16, 21, 0, address_map_constructor(FUNC(scc66470_device::scc66470_vram), this))
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void scc66470_device::device_start()
{
m_irqcallback.resolve_safe();
m_ica_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc66470_device::process_ica), this));
m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc66470_device::process_dca), this));
save_item(NAME(m_csr));
save_item(NAME(m_dcr));
save_item(NAME(m_vsr));
save_item(NAME(m_bcr));
save_item(NAME(m_dcr2));
save_item(NAME(m_dcp));
save_item(NAME(m_swm));
save_item(NAME(m_stm));
save_item(NAME(m_reg_a));
save_item(NAME(m_reg_b));
save_item(NAME(m_pcr));
save_item(NAME(m_mask));
save_item(NAME(m_shift));
save_item(NAME(m_index));
save_item(NAME(m_fc));
save_item(NAME(m_bc));
save_item(NAME(m_tc));
save_item(NAME(m_csr_r));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void scc66470_device::device_reset()
{
m_working_dcp = 0;
m_csr = 0;
m_dcr = 0;
m_vsr = 0;
m_bcr = 0;
m_dcr2 = 0;
m_dcp = 0;
m_swm = 0;
m_stm = 0;
m_reg_a = 0;
m_reg_b = 0;
m_pcr = 0;
m_mask = 0;
m_shift = 0;
m_index = 0;
m_fc = 0;
m_bc = 0;
m_tc = 0;
m_csr_r = 0;
m_ica_timer->adjust(screen().time_until_pos(0, 0));
m_dca_timer->adjust(screen().time_until_pos(32, 784));
}
// default address map
void scc66470_device::scc66470_vram(address_map &map)
{
if(!has_configured_map(0))
{
map(0x00000000, 0x0017ffff).ram();
}
}
device_memory_interface::space_config_vector scc66470_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(0, &m_space_config)
};
}
void scc66470_device::set_vectors(uint16_t *src)
{
for(int i = 0 ; i < 4 ; i++)
{
dram_w(i, *src++, 0xffff);
}
}
void scc66470_device::dram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
space().write_word(offset<<1, data, mem_mask);
}
uint16_t scc66470_device::dram_r(offs_t offset, uint16_t mem_mask)
{
return space().read_word(offset<<1, mem_mask);
}
inline uint8_t scc66470_device::dram_byte_r(offs_t offset)
{
return space().read_byte(offset);
}
void scc66470_device::csr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_csr);
}
void scc66470_device::dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_dcr);
}
void scc66470_device::vsr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_vsr);
}
void scc66470_device::bcr_w(offs_t offset, uint8_t data)
{
m_bcr = data;
}
void scc66470_device::dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_dcr2);
}
void scc66470_device::dcp_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_dcp);
}
void scc66470_device::swm_w(offs_t offset, uint8_t data)
{
m_swm = data | data << 8;
}
void scc66470_device::stm_w(offs_t offset, uint8_t data)
{
m_stm = data;
}
void scc66470_device::reg_a_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_reg_a);
}
void scc66470_device::reg_b_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_reg_b);
perform_pixac_op();
}
void scc66470_device::pcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_pcr);
if(!BIT(m_pcr, PIXAC_COL) || !BIT(m_pcr, PIXAC_4N) || !BIT(m_pcr, PIXAC_BIT))
{
logerror("unsuppported pixac %x\n", m_pcr);
}
}
void scc66470_device::mask_w(offs_t offset, uint8_t data)
{
m_mask = data;
}
void scc66470_device::shift_w(offs_t offset, uint8_t data)
{
m_shift = data;
}
void scc66470_device::index_w(offs_t offset, uint8_t data)
{
m_index = data;
}
void scc66470_device::fc_w(offs_t offset, uint8_t data)
{
m_fc = data;
}
void scc66470_device::bc_w(offs_t offset, uint8_t data)
{
m_bc = data;
}
void scc66470_device::tc_w(offs_t offset, uint8_t data)
{
m_tc = data;
}
uint8_t scc66470_device::csr_r(offs_t offset)
{
uint8_t val = m_csr_r;
if(!machine().side_effects_disabled())
{
m_csr_r &= ~(CSR_R_IT1 | CSR_R_IT2);
if(!m_irqcallback.isnull())
{
m_irqcallback(CLEAR_LINE);
}
}
int scanline = screen().vpos();
if(scanline >= total_height() - height())
{
val |= CSR_R_DA;
}
return val;
}
uint16_t scc66470_device::reg_b_r(offs_t offset, uint16_t mem_mask)
{
return m_reg_b & mem_mask;
}
int scc66470_device::dram_dtack_cycles()
{
const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf);
if(slot_cycle == 9)
{
return 2;
}
else if(slot_cycle < 9)
{
return 2 + 9 - slot_cycle;
}
else
{
return 2 + 9 + 16 - slot_cycle;
}
}
void scc66470_device::map(address_map &map)
{
map(0x000000, 0x17ffff).rw(FUNC(scc66470_device::dram_r), FUNC(scc66470_device::dram_w));
map(0x1fffe0, 0x1fffe1).w(FUNC(scc66470_device::csr_w));
map(0x1fffe1, 0x1fffe1).r(FUNC(scc66470_device::csr_r));
map(0x1fffe2, 0x1fffe3).w(FUNC(scc66470_device::dcr_w));
map(0x1fffe4, 0x1fffe5).w(FUNC(scc66470_device::vsr_w));
map(0x1fffe7, 0x1fffe7).w(FUNC(scc66470_device::bcr_w));
map(0x1fffe8, 0x1fffe9).w(FUNC(scc66470_device::dcr2_w));
map(0x1fffea, 0x1fffeb).w(FUNC(scc66470_device::dcp_w));
map(0x1fffec, 0x1fffec).w(FUNC(scc66470_device::swm_w));
map(0x1fffef, 0x1fffef).w(FUNC(scc66470_device::stm_w));
map(0x1ffff0, 0x1ffff1).w(FUNC(scc66470_device::reg_a_w));
map(0x1ffff2, 0x1ffff3).rw(FUNC(scc66470_device::reg_b_r), FUNC(scc66470_device::reg_b_w));
map(0x1ffff4, 0x1ffff5).w(FUNC(scc66470_device::pcr_w));
map(0x1ffff7, 0x1ffff7).w(FUNC(scc66470_device::mask_w));
map(0x1ffff8, 0x1ffff8).w(FUNC(scc66470_device::shift_w));
map(0x1ffffb, 0x1ffffb).w(FUNC(scc66470_device::index_w));
map(0x1ffffc, 0x1ffffc).w(FUNC(scc66470_device::fc_w));
map(0x1ffffd, 0x1ffffd).w(FUNC(scc66470_device::bc_w));
map(0x1ffffe, 0x1ffffe).w(FUNC(scc66470_device::tc_w));
}
int scc66470_device::pixac_trigger()
{
if(BIT(m_pcr, PIXAC_COL))
{
return 1;
}
else if(BIT(m_pcr, PIXAC_CPY) && !BIT(m_pcr, PIXAC_TT))
{
return 1;
}
else
{
return 0;
}
}
void scc66470_device::perform_pixac_op()
{
if(BIT(m_pcr, PIXAC_COL) && BIT(m_pcr, PIXAC_BIT))
{
if(BIT(m_pcr, PIXAC_4N))
{
uint16_t result = m_reg_b;
m_index &= 0xf;
if(BIT(m_reg_a, 15 - m_index))
{
result = (result & 0xff) | m_fc << 8;
}
else if(!BIT(m_pcr, PIXAC_TT))
{
result = (result & 0xff) | m_bc << 8;
}
m_index++;
m_index &= 0xf;
if(BIT(m_reg_a, 15 - m_index))
{
result = (result & 0xff00) | m_fc;
}
else if(!BIT(m_pcr, PIXAC_TT))
{
result = (result & 0xff00) | m_bc;
}
m_index++;
m_reg_b = (m_reg_b & ~m_swm) | (result & m_swm);
}
}
}
uint16_t scc66470_device::ipa_r(offs_t offset, uint16_t mem_mask)
{
if(offset < 0x180000 / 2)
{
if(pixac_trigger())
{
reg_b_w(0, dram_r(offset, 0xffff), 0xffff);
}
}
return 0;
}
void scc66470_device::ipa_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if(offset < 0x180000 / 2)
{
if(pixac_trigger())
{
dram_w(offset, m_reg_b, 0xffff);
}
}
}
bool scc66470_device::display_enabled()
{
if(BIT(DCR_REG, DCR_DE))
{
return true;
}
else
{
return false;
}
}
void scc66470_device::set_vsr(uint32_t vsr)
{
m_dcr = (m_dcr & 0xfff0) | ((vsr >> 16) & 0x0f);
m_vsr = vsr;
}
uint32_t scc66470_device::get_vsr()
{
return ((m_dcr & 0xf) << 16) | m_vsr;
}
uint32_t scc66470_device::get_dcp()
{
return ((m_dcr2 & 0x0f) << 16) | m_dcp;
}
void scc66470_device::set_dcp(uint32_t dcp)
{
m_dcr2 = (m_dcr2 & 0xfff0) | (dcp & 0x0f);
m_dcp = dcp;
}
void scc66470_device::line(int line, uint8_t *line_buffer, unsigned line_buffer_size)
{
if(line_buffer_size == width())
{
if(display_enabled() && line >= (total_height() - height()))
{
uint8_t bc = m_bcr;
if(BIT(DCR_REG, DCR_CM)) //4 bits/pixel
{
bc = bc >> 4;
}
line -= total_height() - height();
if(line < border_height() || line >= (height() - border_height()))
{
std::fill_n(line_buffer, width(), bc);
if(line == height() - 1)
{
set_vsr(0);
}
}
else
{
unsigned vsr = get_vsr() & 0xfffff;
if(vsr)
{
line_buffer = std::fill_n(line_buffer, border_width(), bc);
if(BIT(DCR_REG, DCR_CM)) //4 bits/pixel
{
if(!BIT(DCR2_REG, DCR2_FT1))
{
for(int i = 0 ; i < width() - (border_width() * 2) ; i += 2)
{
uint8_t pixels = dram_byte_r(vsr++);
*line_buffer++ = (pixels >> 4) & 0x0f;
*line_buffer++ = (pixels) & 0x0f;
vsr &= 0xfffff;
}
}
}
else
{
if(!BIT(DCR2_REG, DCR2_FT1))
{
for(int i = 0 ; i < width() - (border_width() * 2) ; i += 2)
{
const uint8_t pixel = dram_byte_r(vsr++);
*line_buffer++ = pixel;
*line_buffer++ = pixel;
vsr &= 0xfffff;
}
}
}
std::fill_n(line_buffer, border_width(), bc);
if(BIT(DCR_REG, DCR_LS))
{
vsr = get_vsr() + 512;
if(BIT(DCR_REG, DCR_IC))
{
m_working_dcp = vsr - 64;
}
else
{
m_working_dcp = vsr - 16;
}
}
else
{
if(!BIT(DCR2_REG, DCR2_ID))
{
if(BIT(DCR_REG, DCR_DC))
{
m_working_dcp = vsr;
if(BIT(DCR_REG, DCR_IC))
{
vsr += 64;
}
else
{
vsr += 16;
}
}
}
}
set_vsr(vsr);
}
else
{
std::fill_n(line_buffer, line_buffer_size, 0);
}
}
}
else
{
std::fill_n(line_buffer, line_buffer_size, 0);
}
}
else
{
std::fill_n(line_buffer, line_buffer_size, 0);
}
}
TIMER_CALLBACK_MEMBER(scc66470_device::process_ica)
{
uint32_t ctrl = 0x400 / 2;
if((BIT(DCR_REG, DCR_IC) || BIT(DCR_REG, DCR_DC)) && dram_r(ctrl, 0xffff) != 0)
{
bool stop = false;
while(!stop)
{
uint16_t cmd = dram_r(ctrl++, 0xffff);
uint16_t data = dram_r(ctrl++, 0xffff);
ctrl &= 0xffffe;
switch(cmd & 0xff00)
{
case SCC_INS_STOP:
set_vsr((ctrl - 2) * 2);
stop = true;
break;
case SCC_INS_NOP:
break;
case SCC_INS_LOAD_DCP:
set_dcp(((cmd & 0xf) << 16) | (data & 0xfc));
break;
case SCC_INS_LOAD_DCP_STOP:
set_dcp(((cmd & 0xf) << 16) | (data & 0xfc));
stop = true;
break;
case SCC_INS_LOAD_VSR:
ctrl = (((cmd & 0xf) << 16) | data) / 2;
ctrl &= 0xffffe;
break;
case SCC_INS_LOAD_VSR_STOP:
ctrl = ((cmd & 0xf) << 16) | data;
ctrl &= 0xffffe;
set_vsr(ctrl);
stop = true;
break;
case SCC_INS_INTERRUPT:
m_csr_r |= CSR_R_IT1;
if(!BIT(CSR_REG, CSR_DI1))
{
if(!m_irqcallback.isnull())
{
m_irqcallback(ASSERT_LINE);
}
}
break;
default:
if((cmd & 0xf800) == SCC_INS_LOAD_BORDER)
{
m_bcr = cmd & 0xff;
}
else if((cmd & 0xf800) == SCC_INS_LOAD_BORDER_DSP)
{
m_bcr = cmd & 0xff;
m_dcr2 = (m_dcr2 & 0x90ff) | (data & 0x6f) << 8;
m_dcr = (m_dcr & 0xfaff) | (data & 0x0500);
}
else if(cmd & SCC_INS_BEP_CONTROL)
{
//need to implement ?
}
else
{
logerror("Unknown ica/dca instruction %x %x %x\n",cmd,data,ctrl);
}
}
}
}
m_working_dcp = 0;
if(BIT(DCR_REG, DCR_DC) && BIT(DCR2_REG, DCR2_ID))
{
m_working_dcp = get_dcp();
}
m_ica_timer->adjust(screen().time_until_pos(0, 0));
}
TIMER_CALLBACK_MEMBER(scc66470_device::process_dca)
{
uint32_t ctrl = (m_working_dcp / 2) & 0xffffe;
if(BIT(DCR_REG, DCR_DC) && ctrl)
{
bool stop = false;
bool new_dcp = false;
uint32_t count;
if(!BIT(DCR_REG, DCR_IC))
{
count = 16;
}
else
{
count = 64;
}
while(!stop && count)
{
uint16_t cmd = dram_r(ctrl++, 0xffff);
uint16_t data = dram_r(ctrl++, 0xffff);
ctrl &= 0xffffe;
count -= 4;
switch(cmd & 0xff00)
{
case SCC_INS_STOP:
stop = true;
break;
case SCC_INS_NOP:
break;
case SCC_INS_LOAD_DCP:
m_working_dcp = ((cmd & 0xf) << 16) | (data & 0xfc);
set_dcp(m_working_dcp);
ctrl = m_working_dcp / 2;
ctrl &= 0xffffe;
break;
case SCC_INS_LOAD_DCP_STOP:
m_working_dcp = ((cmd & 0xf) << 16) | (data & 0xfc);
set_dcp(m_working_dcp);
stop = true;
new_dcp = true;
break;
case SCC_INS_LOAD_VSR:
set_vsr(((cmd & 0xf) << 16) | data);
break;
case SCC_INS_LOAD_VSR_STOP:
set_vsr(((cmd & 0xf) << 16) | data);
stop = true;
break;
case SCC_INS_INTERRUPT:
m_csr_r |= CSR_R_IT1;
if(!BIT(CSR_REG, CSR_DI1))
{
if(!m_irqcallback.isnull())
{
m_irqcallback(ASSERT_LINE);
}
}
break;
default:
if((cmd & 0xf800) == SCC_INS_LOAD_BORDER)
{
m_bcr = cmd & 0xff;
}
else if((cmd & 0xf800) == SCC_INS_LOAD_BORDER_DSP)
{
m_bcr = cmd & 0xff;
m_dcr2 = (m_dcr2 & 0x90ff) | (data & 0x6f) << 8;
m_dcr = (m_dcr & 0xfaff) | (data & 0x0500);
}
else if(cmd & SCC_INS_BEP_CONTROL)
{
//need to implement ?
}
else
{
logerror("Unknown ica instruction %x %x %x\n",cmd,data,ctrl);
}
}
}
ctrl *= 2;
if(!new_dcp)
{
ctrl += count;
}
if(BIT(DCR_REG, DCR_DC) && BIT(DCR2_REG, DCR2_ID))
{
m_working_dcp = ctrl;
}
else
{
m_working_dcp = 0;
}
}
int scanline = screen().vpos();
if(scanline == total_height() - border_height() - 1)
{
m_csr_r ^= CSR_R_PA;
m_dca_timer->adjust(screen().time_until_pos(total_height() - height() + border_height(), 784));
}
else
{
m_dca_timer->adjust(screen().time_until_pos(scanline + 1, 784));
}
}
unsigned scc66470_device::border_width()
{
const unsigned hoffset = (BIT(DCR_REG, DCR_CF1) << 3) | (BIT(DCR_REG, DCR_CF2) << 2) | (BIT(DCR_REG, DCR_SS) << 1) | BIT(CSR_REG, CSR_ST);
return h_table[ hoffset ].border / 2;
}
int scc66470_device::border_height()
{
int height = 0;
if(!BIT(DCR_REG, DCR_FD) && BIT(CSR_REG, CSR_ST))
{
height = 20;
}
if(!BIT(DCR_REG, DCR_SS))
{
height += 15;
}
return height;
}
unsigned scc66470_device::width()
{
const unsigned hoffset = (BIT(DCR_REG, DCR_CF1) << 3) | (BIT(DCR_REG, DCR_CF2) << 2) | (BIT(DCR_REG, DCR_SS) << 1) | BIT(CSR_REG, CSR_ST);
return h_table[ hoffset ].pixels;
}
unsigned scc66470_device::height()
{
if(BIT(DCR_REG, DCR_FD))
{
return 240;
}
else
{
return 280;
}
}
unsigned scc66470_device::total_height()
{
if(BIT(DCR_REG, DCR_FD))
{
return 262;
}
else
{
return 312;
}
}

View File

@ -0,0 +1,115 @@
// license:BSD-3-Clause
// copyright-holders:Paul Arnold
/***************************************************************************
scc66470.h
***************************************************************************/
#ifndef MAME_VIDEO_SCC66470_H
#define MAME_VIDEO_SCC66470_H
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> scc66470_device
class scc66470_device : public device_t, public device_memory_interface, public device_video_interface
{
public:
auto irq()
{
return m_irqcallback.bind();
}
// construction/destruction
scc66470_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
uint16_t ipa_r(offs_t offset, uint16_t mem_mask = ~0);
void ipa_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
bool display_enabled();
void line(int line, uint8_t *line_buffer, unsigned line_buffer_size);
unsigned width();
unsigned height();
unsigned total_height();
int dram_dtack_cycles();
void dram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dram_r(offs_t offset, uint16_t mem_mask = ~0);
void map(address_map &map);
void set_vectors(uint16_t *src);
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual space_config_vector memory_space_config() const override;
devcb_write_line m_irqcallback;
uint32_t m_working_dcp;
uint16_t m_csr;
uint16_t m_dcr;
uint16_t m_vsr;
uint8_t m_bcr;
uint16_t m_dcr2;
uint16_t m_dcp;
uint16_t m_swm;
uint8_t m_stm;
uint16_t m_reg_a;
uint16_t m_reg_b;
uint16_t m_pcr;
uint8_t m_mask;
uint8_t m_shift;
uint8_t m_index;
uint8_t m_fc;
uint8_t m_bc;
uint8_t m_tc;
uint8_t m_csr_r;
private:
void scc66470_vram(address_map &map);
void set_vsr(uint32_t vsr);
void set_dcp(uint32_t dcp);
uint32_t get_vsr();
uint32_t get_dcp();
unsigned border_width();
int border_height();
void csr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void vsr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void bcr_w(offs_t offset, uint8_t data);
void dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void dcp_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void swm_w(offs_t offset, uint8_t data);
void stm_w(offs_t offset, uint8_t data);
void reg_a_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void reg_b_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void pcr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void mask_w(offs_t offset, uint8_t data);
void shift_w(offs_t offset, uint8_t data);
void index_w(offs_t offset, uint8_t data);
void fc_w(offs_t offset, uint8_t data);
void bc_w(offs_t offset, uint8_t data);
void tc_w(offs_t offset, uint8_t data);
uint8_t csr_r(offs_t offset);
uint16_t reg_b_r(offs_t offset, uint16_t mem_mask = ~0);
int pixac_trigger();
void perform_pixac_op();
inline uint8_t dram_byte_r(offs_t offset);
TIMER_CALLBACK_MEMBER(process_ica);
TIMER_CALLBACK_MEMBER(process_dca);
emu_timer *m_ica_timer;
emu_timer *m_dca_timer;
const address_space_config m_space_config;
};
// device type definition
DECLARE_DEVICE_TYPE(SCC66470, scc66470_device)
#endif // MAME_VIDEO_SCC66470_H

View File

@ -13,11 +13,12 @@
STATUS:
- Skeleton. Just enough for the CD-i to run.
- Skeleton. Just enough for the CD-i and Magicard to run.
TODO:
- Proper handling of the 68070's internal devices (UART, DMA, Timers, etc.)
- I2C could do with re-visiting.
*******************************************************************************/
@ -41,6 +42,165 @@ TODO:
#define ENABLE_UART_PRINTING (0)
//**************************************************************************
// Register defines
//**************************************************************************
enum isr_bits
{
ISR_MST = 0x80, // Master
ISR_TRX = 0x40, // Transmitter
ISR_BB = 0x20, // Busy
ISR_PIN = 0x10, // No Pending Interrupt
ISR_AL = 0x08, // Arbitration Lost
ISR_AAS = 0x04, // Addressed As Slave
ISR_AD0 = 0x02, // Address Zero
ISR_LRB = 0x01, // Last Received Bit
ISR_SSR_MASK = (ISR_MST | ISR_TRX | ISR_BB),// Mask for detecting start/stop/restart
ISR_START = (ISR_MST | ISR_TRX | ISR_BB),// Start bit request
ISR_STOP = (ISR_MST | ISR_TRX) // Stop bit request
};
enum umr_bits
{
UMR_OM = 0xc0,
UMR_OM_NORMAL = 0x00,
UMR_OM_ECHO = 0x40,
UMR_OM_LOOPBACK = 0x80,
UMR_OM_RLOOP = 0xc0,
UMR_TXC = 0x10,
UMR_PC = 0x08,
UMR_P = 0x04,
UMR_SB = 0x02,
UMR_CL = 0x01
};
enum usr_bits
{
USR_RB = 0x80,
USR_FE = 0x40,
USR_PE = 0x20,
USR_OE = 0x10,
USR_TXEMT = 0x08,
USR_TXRDY = 0x04,
USR_RXRDY = 0x01
};
enum tsr_bits
{
TSR_OV0 = 0x80,
TSR_MA1 = 0x40,
TSR_CAP1 = 0x20,
TSR_OV1 = 0x10,
TSR_MA2 = 0x08,
TSR_CAP2 = 0x04,
TSR_OV2 = 0x02
};
enum tcr_bits
{
TCR_E1 = 0xc0,
TCR_E1_NONE = 0x00,
TCR_E1_RISING = 0x40,
TCR_E1_FALLING = 0x80,
TCR_E1_BOTH = 0xc0,
TCR_M1 = 0x30,
TCR_M1_NONE = 0x00,
TCR_M1_MATCH = 0x10,
TCR_M1_CAPTURE = 0x20,
TCR_M1_COUNT = 0x30,
TCR_E2 = 0x0c,
TCR_E2_NONE = 0x00,
TCR_E2_RISING = 0x04,
TCR_E2_FALLING = 0x08,
TCR_E2_BOTH = 0x0c,
TCR_M2 = 0x03,
TCR_M2_NONE = 0x00,
TCR_M2_MATCH = 0x01,
TCR_M2_CAPTURE = 0x02,
TCR_M2_COUNT = 0x03
};
enum csr_bits
{
CSR_COC = 0x80,
CSR_NDT = 0x20,
CSR_ERR = 0x10,
CSR_CA = 0x08
};
enum cer_bits
{
CER_EC = 0x1f,
CER_NONE = 0x00,
CER_TIMING = 0x02,
CER_BUSERR_MEM = 0x09,
CER_BUSERR_DEV = 0x0a,
CER_SOFT_ABORT = 0x11
};
enum dcr1_bits
{
DCR1_ERM = 0x80,
DCR1_DT = 0x30
};
enum dcr2_bits
{
DCR2_ERM = 0x80,
DCR2_DT = 0x30,
DCR2_DS = 0x08
};
enum scr2_bits
{
SCR2_MAC = 0x0c,
SCR2_MAC_NONE = 0x00,
SCR2_MAC_INC = 0x04,
SCR2_DAC = 0x03,
SCR2_DAC_NONE = 0x00,
SCR2_DAC_INC = 0x01
};
enum ccr_bits
{
CCR_SO = 0x80,
CCR_SA = 0x10,
CCR_INE = 0x08,
CCR_IPL = 0x07
};
enum icr_bits
{
ICR_SEL = 0x40,
ICR_ESO = 0x08,
ICR_ACK = 0x04
};
enum i2c_states
{
I2C_IDLE = 0,
I2C_TX_IN_PROGRESS,
I2C_RX_IN_PROGRESS,
I2C_RX_COMPLETE,
I2C_GET_ACK,
I2C_SEND_ACK,
I2C_SEND_ACK_AND_RX,
I2C_SEND_ACK_AND_STOP,
I2C_SEND_STOP,
I2C_CHANGED_TO_RX,
I2C_SEND_RESTART
};
enum i2c_clock_states
{
I2C_SCL_IDLE = 0,
I2C_SCL_SET_0,
I2C_SCL_SET_1,
I2C_SCL_WAIT_1,
};
// device type definition
DEFINE_DEVICE_TYPE(SCC68070, scc68070_device, "scc68070", "Philips SCC68070")
@ -86,6 +246,9 @@ scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag,
, m_iack7_callback(*this)
, m_uart_tx_callback(*this)
, m_uart_rtsn_callback(*this)
, m_i2c_scl_callback(*this)
, m_i2c_sdaw_callback(*this)
, m_i2c_sdar_callback(*this)
, m_ipl(0)
, m_in2_line(CLEAR_LINE)
, m_in4_line(CLEAR_LINE)
@ -113,6 +276,9 @@ void scc68070_device::device_resolve_objects()
m_iack7_callback.resolve_safe(autovector(7));
m_uart_tx_callback.resolve_safe();
m_uart_rtsn_callback.resolve_safe();
m_i2c_scl_callback.resolve_safe();
m_i2c_sdaw_callback.resolve_safe();
m_i2c_sdar_callback.resolve_safe(0);
}
//-------------------------------------------------
@ -146,6 +312,16 @@ void scc68070_device::device_start()
save_item(NAME(m_i2c.status_register));
save_item(NAME(m_i2c.control_register));
save_item(NAME(m_i2c.clock_control_register));
save_item(NAME(m_i2c.scl_out_state));
save_item(NAME(m_i2c.scl_in_state));
save_item(NAME(m_i2c.sda_out_state));
save_item(NAME(m_i2c.sda_in_state));
save_item(NAME(m_i2c.state));
save_item(NAME(m_i2c.counter));
save_item(NAME(m_i2c.clock_change_state));
save_item(NAME(m_i2c.clocks));
save_item(NAME(m_i2c.first_byte));
save_item(NAME(m_i2c.ack_or_nak_sent));
save_item(NAME(m_uart.mode_register));
save_item(NAME(m_uart.status_register));
@ -191,6 +367,9 @@ void scc68070_device::device_start()
m_uart.tx_timer = timer_alloc(FUNC(scc68070_device::tx_callback), this);
m_uart.tx_timer->adjust(attotime::never);
m_i2c.timer = timer_alloc(FUNC(scc68070_device::i2c_callback), this);
m_i2c.timer->adjust(attotime::never);
}
//-------------------------------------------------
@ -212,9 +391,15 @@ void scc68070_device::device_reset()
m_i2c.data_register = 0;
m_i2c.address_register = 0;
m_i2c.status_register = 0;
m_i2c.status_register = ISR_PIN;
m_i2c.control_register = 0;
m_i2c.clock_control_register = 0;
m_i2c.scl_out_state = true;
m_i2c.scl_in_state = true;
m_i2c.sda_out_state = true;
m_i2c.state = I2C_IDLE;
m_i2c.clock_change_state = I2C_SCL_IDLE;
m_i2c.clocks = 0;
m_uart.mode_register = 0;
m_uart.status_register = USR_TXRDY;
@ -260,7 +445,7 @@ void scc68070_device::device_reset()
m_uart.rx_timer->adjust(attotime::never);
m_uart.tx_timer->adjust(attotime::never);
m_timers.timer0_timer->adjust(attotime::never);
set_timer_callback(0);
}
void scc68070_device::m68k_reset_peripherals()
@ -274,9 +459,15 @@ void scc68070_device::m68k_reset_peripherals()
m_uart_rx_int = false;
m_uart_tx_int = false;
m_i2c.status_register = 0;
m_i2c.status_register = ISR_PIN;
m_i2c.control_register = 0;
m_i2c.clock_control_register = 0;
m_i2c.scl_out_state = true;
m_i2c.scl_in_state = true;
m_i2c.sda_out_state = true;
m_i2c.state = I2C_IDLE;
m_i2c.clock_change_state = I2C_SCL_IDLE;
m_i2c.clocks = 0;
m_uart.command_register = 0;
m_uart.receive_pointer = -1;
m_uart.transmit_pointer = -1;
@ -291,6 +482,7 @@ void scc68070_device::m68k_reset_peripherals()
m_uart.rx_timer->adjust(attotime::never);
m_uart.tx_timer->adjust(attotime::never);
m_timers.timer0_timer->adjust(attotime::never);
m_i2c.timer->adjust(attotime::never);
update_ipl();
}
@ -370,7 +562,7 @@ WRITE_LINE_MEMBER(scc68070_device::int2_w)
update_ipl();
}
m_int1_line = state;
m_int2_line = state;
}
}
@ -558,13 +750,41 @@ TIMER_CALLBACK_MEMBER(scc68070_device::tx_callback)
uint8_t scc68070_device::lir_r()
{
// LIR priority level: 80001001
return m_lir;
return m_lir & 0x77;
}
void scc68070_device::lir_w(uint8_t data)
{
LOGMASKED(LOG_IRQS, "%s: LIR Write: %02x\n", machine().describe_context(), data);
m_lir = data;
switch (data & 0x88)
{
case 0x08:
if (m_lir & 0x08)
{
m_lir &= 0xf7;
update_ipl();
}
break;
case 0x80:
if (data & 0x80)
{
m_lir &= 0x7f;
update_ipl();
}
break;
case 0x88:
if (data & 0x88)
{
m_lir &= 0x77;
update_ipl();
}
break;
}
m_lir = (m_lir & 0x88) | (data & 0x77);
}
uint8_t scc68070_device::picr1_r()
@ -654,6 +874,35 @@ uint8_t scc68070_device::idr_r()
// I2C data register: 80002001
if (!machine().side_effects_disabled())
LOGMASKED(LOG_I2C, "%s: I2C Data Register Read: %02x\n", machine().describe_context(), m_i2c.data_register);
m_i2c.counter = 0;
m_i2c.status_register |= ISR_PIN;
m_i2c_int = false;
update_ipl();
if (m_i2c.state != I2C_RX_COMPLETE)
{
}
else
{
m_i2c.sda_out_state = (m_i2c.control_register & ICR_ACK) ? false : true;
m_i2c_sdaw_callback(m_i2c.sda_out_state);
if (m_i2c.control_register & ICR_ACK)
{
m_i2c.state = I2C_SEND_ACK_AND_RX;
m_i2c.clocks = 9;
}
else
{
m_i2c.state = I2C_SEND_ACK;
m_i2c.clocks = 1;
}
m_i2c.ack_or_nak_sent = true;
m_i2c.clock_change_state = I2C_SCL_SET_1;
set_i2c_timer();
}
return m_i2c.data_register;
}
@ -661,6 +910,18 @@ void scc68070_device::idr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Data Register Write: %02x\n", machine().describe_context(), data);
m_i2c.data_register = data;
if (m_i2c.status_register & ISR_MST && m_i2c.status_register & ISR_TRX && m_i2c.status_register & ISR_BB)
{
m_i2c.status_register |= ISR_PIN;
m_i2c_int = false;
update_ipl();
m_i2c.counter = 0;
m_i2c.state = I2C_TX_IN_PROGRESS;
m_i2c.clocks = 9;
i2c_process_falling_scl();
m_i2c.clock_change_state = I2C_SCL_SET_1;
set_i2c_timer();
}
}
uint8_t scc68070_device::iar_r()
@ -682,13 +943,154 @@ uint8_t scc68070_device::isr_r()
// I2C status register: 80002005
if (!machine().side_effects_disabled())
LOGMASKED(LOG_I2C, "%s: I2C Status Register Read: %02x\n", machine().describe_context(), m_i2c.status_register);
return m_i2c.status_register & 0xef; // hack for magicard
return m_i2c.status_register;
}
void scc68070_device::isr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Status Register Write: %02x\n", machine().describe_context(), data);
m_i2c.status_register = data;
if (data & ISR_MST)
{
if ((data & ISR_SSR_MASK) == ISR_START)
{
if ((m_i2c.status_register & ISR_SSR_MASK) == ISR_STOP || (m_i2c.status_register & ISR_SSR_MASK) == 0)
{
if (m_i2c_sdar_callback() && m_i2c.state == I2C_IDLE)
{
m_i2c.status_register = data;
if (data & ISR_PIN)
{
m_i2c_int = false;
update_ipl();
}
m_i2c.sda_out_state = false;
m_i2c_sdaw_callback(false);
m_i2c.clock_change_state = I2C_SCL_SET_0;
m_i2c.clocks = 10;
m_i2c.state = I2C_TX_IN_PROGRESS;
m_i2c.first_byte = true;
m_i2c.ack_or_nak_sent = false;
set_i2c_timer();
m_i2c.counter = 0;
}
else
{
m_i2c.status_register |= ISR_AL;
m_i2c.status_register &= ~ISR_PIN;
m_i2c_int = true;
update_ipl();
}
}
else if ((m_i2c.status_register & ISR_SSR_MASK) == ISR_MST)
{
m_i2c.status_register = data;
if (data & ISR_PIN)
{
m_i2c_int = false;
update_ipl();
}
m_i2c.sda_out_state = true;
m_i2c_sdaw_callback(true);
m_i2c.clock_change_state = I2C_SCL_SET_1;
m_i2c.clocks = 10;
m_i2c.state = I2C_SEND_RESTART;
m_i2c.first_byte = true;
m_i2c.ack_or_nak_sent = false;
set_i2c_timer();
m_i2c.counter = 0;
}
}
else if ((data & ISR_SSR_MASK) == ISR_STOP && m_i2c.status_register & ISR_BB)
{
// we should send STOP here, however, unkte06 in magicard appears to expect
// NAK followed by STOP when in read mode.
if (data & ISR_PIN)
{
m_i2c_int = false;
update_ipl();
}
if (m_i2c.ack_or_nak_sent || (m_i2c.status_register & ISR_TRX))
{
m_i2c.state = I2C_SEND_STOP;
m_i2c.sda_out_state = false;
m_i2c_sdaw_callback(false);
}
else
{
m_i2c.ack_or_nak_sent = true;
m_i2c.sda_out_state = (m_i2c.control_register&ICR_ACK) ? false : true;
m_i2c_sdaw_callback(m_i2c.sda_out_state);
m_i2c.state = I2C_SEND_ACK_AND_STOP;
m_i2c.clocks = 2;
}
m_i2c.status_register = data | ISR_BB;
m_i2c.clock_change_state = I2C_SCL_SET_1;
set_i2c_timer();
}
else if ((data & ISR_SSR_MASK) == ISR_MST)
{
m_i2c.status_register = data;
if (data & ISR_PIN)
{
m_i2c_int = false;
update_ipl();
}
}
else
{
if (data & ISR_PIN && !(m_i2c.status_register & ISR_PIN))
{
if (m_i2c.state == I2C_CHANGED_TO_RX)
{
m_i2c.state = I2C_RX_IN_PROGRESS;
m_i2c.clock_change_state = I2C_SCL_SET_1;
m_i2c.status_register = data;
m_i2c_int = false;
update_ipl();
m_i2c.counter = 0;
m_i2c.clocks = 8;
set_i2c_timer();
}
else
{
m_i2c.ack_or_nak_sent = true;
m_i2c.sda_out_state = (m_i2c.control_register&ICR_ACK) ? false : true;
m_i2c_sdaw_callback(m_i2c.sda_out_state);
m_i2c.status_register = data;
m_i2c_int = false;
update_ipl();
m_i2c.state = I2C_SEND_ACK;
m_i2c.clock_change_state = I2C_SCL_SET_1;
m_i2c.clocks = 1;
set_i2c_timer();
}
}
else
{
m_i2c.status_register = data;
if (data & ISR_PIN)
{
m_i2c_int = false;
update_ipl();
}
}
}
}
else
{
m_i2c.status_register = data;
m_i2c_int = false;
update_ipl();
m_i2c.timer->adjust(attotime::never);
m_i2c_scl_callback(1);
m_i2c_sdaw_callback(1);
m_i2c.scl_out_state = true;
m_i2c.scl_in_state = true;
m_i2c.sda_out_state = true;
m_i2c.state = I2C_IDLE;
}
}
uint8_t scc68070_device::icr_r()
@ -703,6 +1105,17 @@ void scc68070_device::icr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Control Register Write: %02x\n", machine().describe_context(), data);
m_i2c.control_register = data;
if (!(data & ICR_ESO))
{
m_i2c.timer->adjust(attotime::never);
m_i2c_scl_callback(1);
m_i2c_sdaw_callback(1);
m_i2c.scl_out_state = true;
m_i2c.scl_in_state = true;
m_i2c.sda_out_state = true;
m_i2c.state = I2C_IDLE;
}
}
uint8_t scc68070_device::iccr_r()
@ -719,6 +1132,200 @@ void scc68070_device::iccr_w(uint8_t data)
m_i2c.clock_control_register = data & 0x1f;
}
void scc68070_device::i2c_process_falling_scl()
{
switch (m_i2c.state)
{
case I2C_TX_IN_PROGRESS:
if (m_i2c.counter<8)
{
m_i2c.sda_out_state = BIT(m_i2c.data_register, 7 - m_i2c.counter);
m_i2c_sdaw_callback(m_i2c.sda_out_state);
m_i2c.counter++;
}
else
{
m_i2c.sda_out_state = true;
m_i2c_sdaw_callback(true);
m_i2c.state = I2C_GET_ACK;
}
break;
case I2C_GET_ACK:
m_i2c.status_register &= ~ISR_PIN;
m_i2c_int = true;
update_ipl();
m_i2c.state = I2C_IDLE;
if (m_i2c.first_byte)
{
m_i2c.first_byte = false;
if (BIT(m_i2c.data_register, 0))
{
m_i2c.status_register &= ~ISR_TRX;
if (!(m_i2c.status_register & ISR_LRB))
{
m_i2c.state = I2C_CHANGED_TO_RX;
}
}
}
break;
case I2C_RX_IN_PROGRESS:
if (m_i2c.counter >= 8)
{
m_i2c.status_register &= ~ISR_PIN;
m_i2c_int = true;
update_ipl();
m_i2c.state = I2C_RX_COMPLETE;
}
break;
case I2C_SEND_ACK_AND_RX:
m_i2c.sda_out_state = true;
m_i2c_sdaw_callback(true);
m_i2c.state = I2C_RX_IN_PROGRESS;
m_i2c.counter = 0;
break;
case I2C_SEND_ACK_AND_STOP:
m_i2c.sda_out_state = false;
m_i2c_sdaw_callback(false);
m_i2c.state = I2C_SEND_STOP;
break;
case I2C_SEND_ACK:
m_i2c.state = I2C_IDLE;
m_i2c.status_register &= ~ISR_PIN;
m_i2c_int = true;
update_ipl();
break;
}
}
void scc68070_device::i2c_process_rising_scl()
{
switch (m_i2c.state)
{
case I2C_GET_ACK:
if (m_i2c_sdar_callback())
{
m_i2c.status_register |= ISR_LRB;
}
else
{
m_i2c.status_register &= ~ISR_LRB;
}
break;
case I2C_SEND_STOP:
case I2C_SEND_RESTART:
m_i2c.timer->adjust(attotime::from_nsec(5000));
break;
case I2C_RX_IN_PROGRESS:
if (m_i2c.counter < 8)
{
m_i2c.data_register <<= 1;
m_i2c.data_register |= m_i2c_sdar_callback();
m_i2c.counter++;
}
break;
}
}
WRITE_LINE_MEMBER(scc68070_device::write_scl)
{
if (m_i2c.status_register & ISR_MST)
{
if (m_i2c.scl_in_state != state && state)
{
i2c_process_rising_scl();
i2c_next_state();
}
}
m_i2c.scl_in_state = state;
}
TIMER_CALLBACK_MEMBER(scc68070_device::i2c_callback)
{
i2c_next_state();
}
void scc68070_device::i2c_next_state()
{
switch (m_i2c.clock_change_state)
{
case I2C_SCL_SET_0:
if (m_i2c.state == I2C_SEND_STOP)
{
if (!m_i2c.sda_out_state)
{
m_i2c.sda_out_state = true;
m_i2c_sdaw_callback(true);
set_i2c_timer();
}
else
{
m_i2c.state = I2C_IDLE;
m_i2c.status_register &= ~(ISR_PIN | ISR_BB);
m_i2c_int = true;
update_ipl();
m_i2c.clock_change_state = I2C_SCL_IDLE;
}
}
else if (m_i2c.state == I2C_SEND_RESTART)
{
m_i2c.sda_out_state = false;
m_i2c_sdaw_callback(false);
set_i2c_timer();
m_i2c.clock_change_state = I2C_SCL_SET_0;
m_i2c.state = I2C_TX_IN_PROGRESS;
}
else
{
m_i2c.scl_out_state = false;
m_i2c_scl_callback(false);
if (m_i2c.clocks)
{
m_i2c.clocks--;
}
if (m_i2c.clocks == 0)
{
m_i2c.clock_change_state = I2C_SCL_IDLE;
}
else
{
set_i2c_timer();
m_i2c.clock_change_state = I2C_SCL_SET_1;
}
i2c_process_falling_scl();
}
break;
case I2C_SCL_SET_1:
m_i2c.clock_change_state = I2C_SCL_WAIT_1;
m_i2c.scl_out_state = true;
m_i2c_scl_callback(true);
break;
case I2C_SCL_WAIT_1:
set_i2c_timer();
m_i2c.clock_change_state = I2C_SCL_SET_0;
break;
}
}
void scc68070_device::set_i2c_timer()
{
// divider offset 0 entry is illegal
static constexpr int divider[]={ 1, 78, 90, 102, 126, 150, 174, 198,
246, 294, 342, 390, 486, 582, 678, 774,
996, 1158, 1350, 1542, 1926, 2310, 2694, 3078,
3846, 4614, 5382, 6150, 7686, 9222, 10758, 12294 };
m_i2c.timer->adjust(cycles_to_attotime(divider[m_i2c.clock_control_register]));
}
uint8_t scc68070_device::umr_r()
{
// UART mode register: 80002011
@ -870,7 +1477,8 @@ uint16_t scc68070_device::timer_r(offs_t offset, uint16_t mem_mask)
case 0x4/2:
if (!machine().side_effects_disabled())
LOGMASKED(LOG_TIMERS, "%s: Timer 0 Read: %04x & %04x\n", machine().describe_context(), m_timers.timer0, mem_mask);
return m_timers.timer0;
return 0x10000 - (attotime_to_cycles(m_timers.timer0_timer->remaining()) / 96);
case 0x6/2:
if (!machine().side_effects_disabled())
LOGMASKED(LOG_TIMERS, "%s: Timer 1 Read: %04x & %04x\n", machine().describe_context(), m_timers.timer1, mem_mask);
@ -908,6 +1516,7 @@ void scc68070_device::timer_w(offs_t offset, uint16_t data, uint16_t mem_mask)
case 0x2/2:
LOGMASKED(LOG_TIMERS, "%s: Timer Reload Register Write: %04x & %04x\n", machine().describe_context(), data, mem_mask);
COMBINE_DATA(&m_timers.reload_register);
set_timer_callback(0);
break;
case 0x4/2:
LOGMASKED(LOG_TIMERS, "%s: Timer 0 Write: %04x & %04x\n", machine().describe_context(), data, mem_mask);

View File

@ -28,105 +28,18 @@ TODO:
#include "cpu/m68000/m68000.h"
#define ISR_MST 0x80 // Master
#define ISR_TRX 0x40 // Transmitter
#define ISR_BB 0x20 // Busy
#define ISR_PIN 0x10 // No Pending Interrupt
#define ISR_AL 0x08 // Arbitration Lost
#define ISR_AAS 0x04 // Addressed As Slave
#define ISR_AD0 0x02 // Address Zero
#define ISR_LRB 0x01 // Last Received Bit
#define UMR_OM 0xc0
#define UMR_OM_NORMAL 0x00
#define UMR_OM_ECHO 0x40
#define UMR_OM_LOOPBACK 0x80
#define UMR_OM_RLOOP 0xc0
#define UMR_TXC 0x10
#define UMR_PC 0x08
#define UMR_P 0x04
#define UMR_SB 0x02
#define UMR_CL 0x01
#define USR_RB 0x80
#define USR_FE 0x40
#define USR_PE 0x20
#define USR_OE 0x10
#define USR_TXEMT 0x08
#define USR_TXRDY 0x04
#define USR_RXRDY 0x01
#define TSR_OV0 0x80
#define TSR_MA1 0x40
#define TSR_CAP1 0x20
#define TSR_OV1 0x10
#define TSR_MA2 0x08
#define TSR_CAP2 0x04
#define TSR_OV2 0x02
#define TCR_E1 0xc0
#define TCR_E1_NONE 0x00
#define TCR_E1_RISING 0x40
#define TCR_E1_FALLING 0x80
#define TCR_E1_BOTH 0xc0
#define TCR_M1 0x30
#define TCR_M1_NONE 0x00
#define TCR_M1_MATCH 0x10
#define TCR_M1_CAPTURE 0x20
#define TCR_M1_COUNT 0x30
#define TCR_E2 0x0c
#define TCR_E2_NONE 0x00
#define TCR_E2_RISING 0x04
#define TCR_E2_FALLING 0x08
#define TCR_E2_BOTH 0x0c
#define TCR_M2 0x03
#define TCR_M2_NONE 0x00
#define TCR_M2_MATCH 0x01
#define TCR_M2_CAPTURE 0x02
#define TCR_M2_COUNT 0x03
#define CSR_COC 0x80
#define CSR_NDT 0x20
#define CSR_ERR 0x10
#define CSR_CA 0x08
#define CER_EC 0x1f
#define CER_NONE 0x00
#define CER_TIMING 0x02
#define CER_BUSERR_MEM 0x09
#define CER_BUSERR_DEV 0x0a
#define CER_SOFT_ABORT 0x11
#define DCR1_ERM 0x80
#define DCR1_DT 0x30
#define DCR2_ERM 0x80
#define DCR2_DT 0x30
#define DCR2_DS 0x08
#define OCR_D 0x80
#define OCR_D_M2D 0x00
#define OCR_D_D2M 0x80
#define OCR_OS 0x30
#define OCR_OS_BYTE 0x00
#define OCR_OS_WORD 0x10
#define SCR2_MAC 0x0c
#define SCR2_MAC_NONE 0x00
#define SCR2_MAC_INC 0x04
#define SCR2_DAC 0x03
#define SCR2_DAC_NONE 0x00
#define SCR2_DAC_INC 0x01
#define CCR_SO 0x80
#define CCR_SA 0x10
#define CCR_INE 0x08
#define CCR_IPL 0x07
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
enum scc68070_ocr_bits
{
SCC68070_OCR_D = 0x80,
SCC68070_OCR_D_M2D = 0x00,
SCC68070_OCR_D_D2M = 0x80,
SCC68070_OCR_OS = 0x30,
SCC68070_OCR_OS_BYTE = 0x00,
SCC68070_OCR_OS_WORD = 0x10
};
// ======================> scc68070_device
@ -141,6 +54,9 @@ public:
auto iack7_callback() { return m_iack7_callback.bind(); }
auto uart_tx_callback() { return m_uart_tx_callback.bind(); }
auto uart_rtsn_callback() { return m_uart_rtsn_callback.bind(); }
auto i2c_scl_w() { return m_i2c_scl_callback.bind(); }
auto i2c_sda_w() { return m_i2c_sdaw_callback.bind(); }
auto i2c_sda_r() { return m_i2c_sdar_callback.bind(); }
DECLARE_WRITE_LINE_MEMBER(in2_w);
DECLARE_WRITE_LINE_MEMBER(in4_w);
@ -149,9 +65,12 @@ public:
DECLARE_WRITE_LINE_MEMBER(int1_w);
DECLARE_WRITE_LINE_MEMBER(int2_w);
DECLARE_WRITE_LINE_MEMBER(write_scl);
TIMER_CALLBACK_MEMBER(timer0_callback);
TIMER_CALLBACK_MEMBER(rx_callback);
TIMER_CALLBACK_MEMBER(tx_callback);
TIMER_CALLBACK_MEMBER(i2c_callback);
// external callbacks
void uart_rx(uint8_t data);
@ -170,6 +89,17 @@ public:
uint8_t control_register;
uint8_t reserved;
uint8_t clock_control_register;
emu_timer* timer;
bool scl_out_state;
bool scl_in_state;
bool sda_out_state;
bool sda_in_state;
uint8_t clock_change_state;
uint8_t clocks;
uint8_t state;
uint8_t counter;
bool first_byte;
bool ack_or_nak_sent;
};
struct uart_regs_t
@ -298,6 +228,10 @@ private:
void icr_w(uint8_t data);
uint8_t iccr_r();
void iccr_w(uint8_t data);
void set_i2c_timer();
void i2c_process_falling_scl();
void i2c_process_rising_scl();
void i2c_next_state();
// UART interface
uint8_t umr_r();
@ -336,6 +270,9 @@ private:
devcb_read8 m_iack7_callback;
devcb_write8 m_uart_tx_callback;
devcb_write_line m_uart_rtsn_callback;
devcb_write_line m_i2c_scl_callback;
devcb_write_line m_i2c_sdaw_callback;
devcb_read8 m_i2c_sdar_callback;
// internal state
uint8_t m_ipl;

File diff suppressed because it is too large Load Diff

View File

@ -1313,10 +1313,10 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
uint16_t *ram = (uint16_t *)m_ram.get();
LOGMASKED(LOG_WRITES, "%s: cdic_w: DMA Control Register = %04x & %04x\n", machine().describe_context(), data, mem_mask);
LOGMASKED(LOG_WRITES, "%s: Memory address counter: %08x\n", machine().describe_context(), m_scc->dma().channel[0].memory_address_counter);
LOGMASKED(LOG_WRITES, "%s: Doing copy, transferring %04x bytes %s\n", machine().describe_context(), count * 2, (m_scc->dma().channel[0].operation_control & OCR_D) ? "to main RAM" : "to device RAM");
LOGMASKED(LOG_WRITES, "%s: Doing copy, transferring %04x bytes %s\n", machine().describe_context(), count * 2, (m_scc->dma().channel[0].operation_control & SCC68070_OCR_D) ? "to main RAM" : "to device RAM");
for (uint32_t index = start / 2; index < (start / 2 + count); index++)
{
if (m_scc->dma().channel[0].operation_control & OCR_D)
if (m_scc->dma().channel[0].operation_control & SCC68070_OCR_D)
{
m_memory_space->write_word(index * 2, ram[device_index++]);
}