(MESS) AVR8 core updates: [Sandro Ronco]

- added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes.
- added ATMEGA644 interrupt vectors.
- fixed Z flag in CPC, SBC and SBCI opcodes.
- fixed V and C flags in SBIW opcode.
- fixed pop/push order in CALL, RCALL, RET and RETI opcodes.
- fixed Timer 1 CTC mode.

(MESS) uzebox: added video emulation and joystick input. [Sandro Ronco]
This commit is contained in:
Sandro Ronco 2012-12-25 09:22:58 +00:00
parent b0b86fc563
commit b021bed2bf
3 changed files with 416 additions and 77 deletions

View File

@ -9,10 +9,14 @@
the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the
existing timing is 100% correct.
Unimplemented opcodes: CPSR, LD Z+, ST -Z/-Y/-X, ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, ICALL, EICALL,
JMP, CALL
Unimplemented opcodes: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL
- Changelist -
23 Dec. 2012 [Sandro Ronco]
- Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes
- Fixed Z flag in CPC, SBC and SBCI opcodes
- Fixed V and C flags in SBIW opcode
30 Oct. 2012
- Added FMUL, FMULS, FMULSU opcodes [MooglyGuy]
- Fixed incorrect flag calculation in ROR opcode [MooglyGuy]
@ -664,8 +668,8 @@ void avr8_device::set_irq_line(UINT16 vector, int state)
if(SREG_R(AVR8_SREG_I))
{
SREG_W(AVR8_SREG_I, 0);
push((m_pc >> 8) & 0x00ff);
push(m_pc & 0x00ff);
push((m_pc >> 8) & 0x00ff);
m_pc = vector;
m_shifted_pc = vector << 1;
}
@ -717,6 +721,37 @@ void avr8_device::update_interrupt(int source)
}
static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] =
{
{ ATMEGA644_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK },
{ ATMEGA644_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK },
{ ATMEGA644_INT_T0COMPA, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0A_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0A_MASK },
{ ATMEGA644_INT_T0OVF, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_TOIE0_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_TOV0_MASK },
{ ATMEGA644_INT_T1CAPT, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_ICIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_ICF1_MASK },
{ ATMEGA644_INT_T1COMPB, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1B_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1B_MASK },
{ ATMEGA644_INT_T1COMPA, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1A_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1A_MASK },
{ ATMEGA644_INT_T1OVF, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_TOIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_TOV1_MASK },
{ ATMEGA644_INT_T2COMPB, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2B_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2B_MASK },
{ ATMEGA644_INT_T2COMPA, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2A_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2A_MASK },
{ ATMEGA644_INT_T2OVF, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_TOIE2_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_TOV2_MASK }
};
void atmega644_device::update_interrupt(int source)
{
CInterruptCondition condition = s_mega644_int_conditions[source];
int intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0;
intstate = (m_r[condition.m_intreg] & condition.m_intmask) ? intstate : 0;
set_irq_line(condition.m_intindex << 1, intstate);
if (intstate)
{
m_r[condition.m_regindex] &= ~condition.m_regmask;
}
}
//**************************************************************************
// REGISTER HANDLING
//**************************************************************************
@ -1010,6 +1045,11 @@ void avr8_device::timer1_tick()
if (count == ocr1[reg])
{
if (reg == 0)
{
count = 0;
increment = 0;
}
m_r[AVR8_REGIDX_TIFR1] |= ocf1[reg];
update_interrupt(int1[reg]);
}
@ -1540,6 +1580,41 @@ WRITE8_MEMBER( avr8_device::regs_w )
{
switch( offset )
{
case AVR8_REGIDX_R0:
case AVR8_REGIDX_R1:
case AVR8_REGIDX_R2:
case AVR8_REGIDX_R3:
case AVR8_REGIDX_R4:
case AVR8_REGIDX_R5:
case AVR8_REGIDX_R6:
case AVR8_REGIDX_R7:
case AVR8_REGIDX_R8:
case AVR8_REGIDX_R9:
case AVR8_REGIDX_R10:
case AVR8_REGIDX_R11:
case AVR8_REGIDX_R12:
case AVR8_REGIDX_R13:
case AVR8_REGIDX_R14:
case AVR8_REGIDX_R15:
case AVR8_REGIDX_R16:
case AVR8_REGIDX_R17:
case AVR8_REGIDX_R18:
case AVR8_REGIDX_R19:
case AVR8_REGIDX_R20:
case AVR8_REGIDX_R21:
case AVR8_REGIDX_R22:
case AVR8_REGIDX_R23:
case AVR8_REGIDX_R24:
case AVR8_REGIDX_R25:
case AVR8_REGIDX_R26:
case AVR8_REGIDX_R27:
case AVR8_REGIDX_R28:
case AVR8_REGIDX_R29:
case AVR8_REGIDX_R30:
case AVR8_REGIDX_R31:
m_r[offset] = data;
break;
case AVR8_REGIDX_TCCR0B:
verboselog(m_pc, 0, "AVR8: TCCR0B = %02x\n", data );
changed_tccr0b(data);
@ -1707,6 +1782,11 @@ WRITE8_MEMBER( avr8_device::regs_w )
m_r[offset] = data;
break;
case AVR8_REGIDX_GPIOR1:
case AVR8_REGIDX_GPIOR2:
m_r[offset] = data;
break;
case AVR8_REGIDX_PORTA:
m_io->write_byte(0x00, data);
m_r[AVR8_REGIDX_PORTA] = data;
@ -1755,6 +1835,40 @@ READ8_MEMBER( avr8_device::regs_r )
//printf("offset %04x\n", offset);
switch( offset )
{
case AVR8_REGIDX_R0:
case AVR8_REGIDX_R1:
case AVR8_REGIDX_R2:
case AVR8_REGIDX_R3:
case AVR8_REGIDX_R4:
case AVR8_REGIDX_R5:
case AVR8_REGIDX_R6:
case AVR8_REGIDX_R7:
case AVR8_REGIDX_R8:
case AVR8_REGIDX_R9:
case AVR8_REGIDX_R10:
case AVR8_REGIDX_R11:
case AVR8_REGIDX_R12:
case AVR8_REGIDX_R13:
case AVR8_REGIDX_R14:
case AVR8_REGIDX_R15:
case AVR8_REGIDX_R16:
case AVR8_REGIDX_R17:
case AVR8_REGIDX_R18:
case AVR8_REGIDX_R19:
case AVR8_REGIDX_R20:
case AVR8_REGIDX_R21:
case AVR8_REGIDX_R22:
case AVR8_REGIDX_R23:
case AVR8_REGIDX_R24:
case AVR8_REGIDX_R25:
case AVR8_REGIDX_R26:
case AVR8_REGIDX_R27:
case AVR8_REGIDX_R28:
case AVR8_REGIDX_R29:
case AVR8_REGIDX_R30:
case AVR8_REGIDX_R31:
return m_r[offset];
case AVR8_REGIDX_SPL:
case AVR8_REGIDX_SPH:
case AVR8_REGIDX_TCNT1L:
@ -1769,10 +1883,22 @@ READ8_MEMBER( avr8_device::regs_r )
case AVR8_REGIDX_DDRC:
case AVR8_REGIDX_DDRD:
case AVR8_REGIDX_GPIOR0:
case AVR8_REGIDX_GPIOR1:
case AVR8_REGIDX_GPIOR2:
case AVR8_REGIDX_EEDR:
case AVR8_REGIDX_SREG:
return m_r[offset];
// TODO: consider the DDRx
case AVR8_REGIDX_PINA:
return m_io->read_byte(AVR8_REG_A);
case AVR8_REGIDX_PINB:
return m_io->read_byte(AVR8_REG_B);
case AVR8_REGIDX_PINC:
return m_io->read_byte(AVR8_REG_C);
case AVR8_REGIDX_PIND:
return m_io->read_byte(AVR8_REG_D);
default:
verboselog(m_pc, 0, "AVR8: Unknown Register Read: %02x\n", (UINT8)offset);
return 0;
@ -1919,7 +2045,7 @@ void avr8_device::execute_run()
SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
SREG_W(AVR8_SREG_N, BIT(res,7));
SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0);
SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
break;
case 0x0800:
@ -1934,7 +2060,7 @@ void avr8_device::execute_run()
SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
SREG_W(AVR8_SREG_N, BIT(res,7));
SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0);
SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
break;
case 0x0c00:
@ -1957,9 +2083,15 @@ void avr8_device::execute_run()
case 0x1000:
switch(op & 0x0c00)
{
case 0x0000: // CPSR Rd,Rr
//output += sprintf( output, "CPSE R%d, R%d", RD5(op), RR5(op) );
unimplemented_opcode(op);
case 0x0000: // CPSE Rd,Rr
rd = m_r[RD5(op)];
rr = m_r[RR5(op)];
if (rd == rr)
{
op = (UINT32)m_program->read_word(m_shifted_pc + 2);
opcycles += is_long_opcode(op) ? 2 : 1;
m_pc += is_long_opcode(op) ? 2 : 1;
}
break;
case 0x0400: // CP Rd,Rr
rd = m_r[RD5(op)];
@ -2056,7 +2188,7 @@ void avr8_device::execute_run()
SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7)));
SREG_W(AVR8_SREG_N, BIT(res,7));
SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0);
SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0);
SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7))));
break;
case 0x5000: // SUBI Rd,K
@ -2129,7 +2261,12 @@ void avr8_device::execute_run()
opcycles = 2;
break;
case 0x0001: // LD Rd,Z+
unimplemented_opcode(op);
pd = ZREG;
m_r[RD5(op)] = m_data->read_byte(pd);
pd++;
m_r[31] = (pd >> 8) & 0x00ff;
m_r[30] = pd & 0x00ff;
opcycles = 2;
break;
case 0x0002: // LD Rd,-Z
pd = ZREG;
@ -2226,8 +2363,12 @@ void avr8_device::execute_run()
opcycles = 2;
break;
case 0x0002: // ST -Z,Rd
//output += sprintf( output, "ST -Z , R%d", RD5(op) );
unimplemented_opcode(op);
pd = ZREG;
pd--;
m_data->write_byte(pd, m_r[RD5(op)]);
m_r[31] = (pd >> 8) & 0x00ff;
m_r[30] = pd & 0x00ff;
opcycles = 2;
break;
case 0x0009: // ST Y+,Rd
pd = YREG;
@ -2238,8 +2379,12 @@ void avr8_device::execute_run()
opcycles = 2;
break;
case 0x000a: // ST -Y,Rd
//output += sprintf( output, "ST -Y , R%d", RD5(op) );
unimplemented_opcode(op);
pd = YREG;
pd--;
m_data->write_byte(pd, m_r[RD5(op)]);
m_r[29] = (pd >> 8) & 0x00ff;
m_r[28] = pd & 0x00ff;
opcycles = 2;
break;
case 0x000c: // ST X,Rd
m_data->write_byte(XREG, m_r[RD5(op)]);
@ -2253,8 +2398,12 @@ void avr8_device::execute_run()
opcycles = 2;
break;
case 0x000e: // ST -X,Rd
//output += sprintf( output, "ST -X , R%d", RD5(op) );
unimplemented_opcode(op);
pd = XREG;
pd--;
m_data->write_byte(pd, m_r[RD5(op)]);
m_r[27] = (pd >> 8) & 0x00ff;
m_r[26] = pd & 0x00ff;
opcycles = 2;
break;
case 0x000f: // PUSH Rd
push(m_r[RD5(op)]);
@ -2397,8 +2546,8 @@ void avr8_device::execute_run()
break;
case 0x000e: // CALL k
case 0x000f:
push(((m_pc + 1) >> 8) & 0x00ff);
push((m_pc + 1) & 0x00ff);
push((m_pc + 2) & 0x00ff);
push(((m_pc + 2) >> 8) & 0x00ff);
offs = KCONST22(op) << 16;
m_pc++;
m_shifted_pc += 2;
@ -2485,14 +2634,14 @@ void avr8_device::execute_run()
switch(op & 0x00f0)
{
case 0x0000: // RET
m_pc = pop();
m_pc |= pop() << 8;
m_pc = pop() << 8;
m_pc |= pop();
m_pc--;
opcycles = 4;
break;
case 0x0010: // RETI
m_pc = pop();
m_pc |= pop() << 8;
m_pc = pop() << 8;
m_pc |= pop();
m_pc--;
SREG_W(AVR8_SREG_I, 1);
opcycles = 4;
@ -2535,8 +2684,11 @@ void avr8_device::execute_run()
switch(op & 0x00f0)
{
case 0x0000: // ICALL
//output += sprintf( output, "ICALL" );
unimplemented_opcode(op);
push((m_pc + 1) & 0x00ff);
push(((m_pc + 1) >> 8) & 0x00ff);
m_pc = ZREG;
m_pc--;
opcycles = 3;
break;
case 0x0010: // EICALL
//output += sprintf( output, "EICALL" );
@ -2598,11 +2750,11 @@ void avr8_device::execute_run()
pd = rd;
pd |= rr << 8;
pd -= KCONST6(op);
SREG_W(AVR8_SREG_V, BIT(pd,15) & NOT(BIT(rr,7)));
SREG_W(AVR8_SREG_V, NOT(BIT(pd,15)) & BIT(rr,7));
SREG_W(AVR8_SREG_N, BIT(pd,15));
SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V));
SREG_W(AVR8_SREG_Z, (pd == 0) ? 1 : 0);
SREG_W(AVR8_SREG_C, NOT(BIT(pd,15)) & BIT(rr,7));
SREG_W(AVR8_SREG_C, BIT(pd,15) & NOT(BIT(rr,7)));
m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff;
m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff;
opcycles = 2;
@ -2662,8 +2814,8 @@ void avr8_device::execute_run()
break;
case 0xd000: // RCALL k
offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff));
push(((m_pc + 1) >> 8) & 0x00ff);
push((m_pc + 1) & 0x00ff);
push(((m_pc + 1) >> 8) & 0x00ff);
m_pc += offs;
opcycles = 3;
break;

View File

@ -9,10 +9,14 @@
the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the
existing timing is 100% correct.
Unimplemented opcodes: CPSR, LD Z+, ST Z+, ST -Z/-Y/-X, ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, ICALL,
EICALL, JMP, CALL, SBIW
Unimplemented opcodes: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL
- Changelist -
23 Dec. 2012 [Sandro Ronco]
- Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes
- Fixed Z flag in CPC, SBC and SBCI opcodes
- Fixed V and C flags in SBIW opcode
30 Oct. 2012
- Added FMUL, FMULS, FMULSU opcodes [MooglyGuy]
- Fixed incorrect flag calculation in ROR opcode [MooglyGuy]
@ -71,7 +75,7 @@ public:
static void static_set_config(device_t &device, const avr8_config &config);
// public interfaces
void update_interrupt(int source);
virtual void update_interrupt(int source);
UINT64 get_elapsed_cycles()
{
return m_elapsed_cycles;
@ -232,6 +236,8 @@ class atmega644_device : public avr8_device
public:
// construction/destruction
atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void update_interrupt(int source);
};
/***************************************************************************
@ -308,6 +314,36 @@ enum
AVR8_INT_ANALOG_COMP,
AVR8_INT_TWI,
AVR8_INT_SPM_RDY,
// ATMEGA644
ATMEGA644_INT_RESET = 0,
ATMEGA644_INT_INT0,
ATMEGA644_INT_INT1,
ATMEGA644_INT_INT2,
ATMEGA644_INT_PCINT0,
ATMEGA644_INT_PCINT1,
ATMEGA644_INT_PCINT2,
ATMEGA644_INT_PCINT3,
ATMEGA644_INT_WDT,
ATMEGA644_INT_T2COMPA,
ATMEGA644_INT_T2COMPB,
ATMEGA644_INT_T2OVF,
ATMEGA644_INT_T1CAPT,
ATMEGA644_INT_T1COMPA,
ATMEGA644_INT_T1COMPB,
ATMEGA644_INT_T1OVF,
ATMEGA644_INT_T0COMPA,
ATMEGA644_INT_T0COMPB,
ATMEGA644_INT_T0OVF,
ATMEGA644_INT_SPI_STC,
ATMEGA644_INT_USART_RX,
ATMEGA644_INT_USART_UDRE,
ATMEGA644_INT_USART_TX,
ATMEGA644_INT_ADC,
ATMEGA644_INT_EE_RDY,
ATMEGA644_INT_ANALOG_COMP,
ATMEGA644_INT_TWI,
ATMEGA644_INT_SPM_RDY,
};
// Used by I/O register handling

View File

@ -1,3 +1,15 @@
/***************************************************************************
Belogic Uzebox
driver by Sandro Ronco
TODO:
- Sound
- SDCard
- Mouse
****************************************************************************/
#include "emu.h"
#include "cpu/avr8/avr8.h"
@ -5,30 +17,10 @@
#include "imagedev/cartslot.h"
// overclocked to 8 * NTSC burst frequency
#define VERBOSE_LEVEL (0)
#define ENABLE_VERBOSE_LOG (0)
#if ENABLE_VERBOSE_LOG
INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...)
{
if( VERBOSE_LEVEL >= n_level )
{
va_list v;
char buf[ 32768 ];
va_start( v, s_fmt );
vsprintf( buf, s_fmt, v );
va_end( v );
logerror( "%08x: %s", machine.device("maincpu")->safe_pc(), buf );
}
}
#else
#define verboselog(x,y,z,...)
#endif
#define MASTER_CLOCK 28618180
#define INTERLACED 0
class uzebox_state : public driver_device
{
public:
@ -38,30 +30,150 @@ public:
{
}
virtual void machine_start();
required_device<avr8_device> m_maincpu;
DECLARE_READ8_MEMBER(port_r);
DECLARE_WRITE8_MEMBER(port_w);
DECLARE_DRIVER_INIT(uzebox);
DECLARE_READ8_MEMBER(port_a_r);
DECLARE_WRITE8_MEMBER(port_a_w);
DECLARE_READ8_MEMBER(port_b_r);
DECLARE_WRITE8_MEMBER(port_b_w);
DECLARE_READ8_MEMBER(port_c_r);
DECLARE_WRITE8_MEMBER(port_c_w);
DECLARE_READ8_MEMBER(port_d_r);
DECLARE_WRITE8_MEMBER(port_d_w);
virtual void machine_start();
virtual void machine_reset();
void line_update();
UINT32 screen_update_uzebox(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
private:
int m_vpos;
UINT64 m_line_start_cycles;
UINT32 m_line_pos_cycles;
UINT8 m_port_a;
UINT8 m_port_b;
UINT8 m_port_c;
UINT8 m_port_d;
UINT16 m_joy_data[2];
bitmap_rgb32 m_bitmap;
};
void uzebox_state::machine_start()
{
machine().primary_screen->register_screen_bitmap(m_bitmap);
}
READ8_MEMBER(uzebox_state::port_r)
void uzebox_state::machine_reset()
{
return 0;
m_vpos = 0;
m_line_start_cycles = 0;
m_line_pos_cycles = 0;
m_port_a = 0;
m_port_b = 0;
m_port_c = 0;
m_port_d = 0;
m_joy_data[0] = m_joy_data[1] = 0;
}
WRITE8_MEMBER(uzebox_state::port_w)
WRITE8_MEMBER(uzebox_state::port_a_w)
{
// xxxx ---- NC
// ---- x--- SNES controller clk
// ---- -x-- SNES controller latch
// ---- --x- SNES controller P2 data
// ---- ---x SNES controller P1 data
UINT8 changed = m_port_a ^ data;
if (changed & data & 0x04)
{
m_joy_data[0] = ioport("P1")->read();
m_joy_data[1] = ioport("P2")->read();
}
else if (changed & 0x08)
{
if (changed & data & 0x08)
{
m_joy_data[0] >>= 1;
m_joy_data[1] >>= 1;
}
m_port_a = (m_joy_data[0] & 0x01) | ((m_joy_data[1] & 0x01) << 1);
}
m_port_a = (data & 0x0c) | (m_port_a & 0x03);
}
READ8_MEMBER(uzebox_state::port_a_r)
{
return m_port_a | 0xf0;
}
WRITE8_MEMBER(uzebox_state::port_b_w)
{
// xxx- ---- SDCard
// ---x ---- AD725 CE
// ---- x--- AD725 4FSC
// ---- -xx- NC
// ---- ---x AD725 HSYNC
if (m_port_b & 0x10)
if ((m_port_b ^ data) & m_port_b & 0x01)
{
line_update();
UINT32 cycles = (UINT32)(m_maincpu->get_elapsed_cycles() - m_line_start_cycles);
if (cycles < 1000 && m_vpos >= 448)
m_vpos = INTERLACED ? ((m_vpos ^ 0x01) & 0x01) : 0;
else if (cycles > 1000)
m_vpos += 2;
m_line_start_cycles = m_maincpu->get_elapsed_cycles();
m_line_pos_cycles = 0;
}
m_port_b = data;
}
READ8_MEMBER(uzebox_state::port_b_r)
{
return m_port_b;
}
WRITE8_MEMBER(uzebox_state::port_c_w)
{
// xx-- ---- blue
// --xx x--- green
// ---- -xxx red
line_update();
m_port_c = data;
}
READ8_MEMBER(uzebox_state::port_c_r)
{
return m_port_c;
}
WRITE8_MEMBER(uzebox_state::port_d_w)
{
// x--- ---- sound
// -x-- ---- SDCard CS
// ---x ---- LED
// --x- x--- NC
// ---- -x-- power
// ---- --xx UART MIDI
m_port_d = data;
}
READ8_MEMBER(uzebox_state::port_d_r)
{
return m_port_d;
}
/****************************************************\
* Address maps *
\****************************************************/
@ -75,7 +187,10 @@ static ADDRESS_MAP_START( uzebox_data_map, AS_DATA, 8, uzebox_state )
ADDRESS_MAP_END
static ADDRESS_MAP_START( uzebox_io_map, AS_IO, 8, uzebox_state )
AM_RANGE(0x00, 0x03) AM_READWRITE( port_r, port_w )
AM_RANGE(AVR8_REG_A, AVR8_REG_A) AM_READWRITE( port_a_r, port_a_w )
AM_RANGE(AVR8_REG_B, AVR8_REG_B) AM_READWRITE( port_b_r, port_b_w )
AM_RANGE(AVR8_REG_C, AVR8_REG_C) AM_READWRITE( port_c_r, port_c_w )
AM_RANGE(AVR8_REG_D, AVR8_REG_D) AM_READWRITE( port_d_r, port_d_w )
ADDRESS_MAP_END
/****************************************************\
@ -83,14 +198,60 @@ ADDRESS_MAP_END
\****************************************************/
static INPUT_PORTS_START( uzebox )
PORT_START( "P1" )
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START1 ) PORT_NAME("P1 Start") PORT_PLAYER(1)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(1)
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(1)
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(1)
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(1)
PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "P2" )
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(2)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(2)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(2)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START2 ) PORT_NAME("P1 Start") PORT_PLAYER(2)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(2)
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(2)
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(2)
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(2)
PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED )
INPUT_PORTS_END
/****************************************************\
* Video hardware *
\****************************************************/
void uzebox_state::line_update()
{
UINT32 cycles = (UINT32)(m_maincpu->get_elapsed_cycles() - m_line_start_cycles) / 2;
for (UINT32 x = m_line_pos_cycles; x < cycles; x++)
{
if (m_bitmap.cliprect().contains(x, m_vpos))
m_bitmap.pix32(m_vpos, x) = MAKE_RGB(pal3bit(m_port_c >> 0), pal3bit(m_port_c >> 3), pal2bit(m_port_c >> 6));
if (!INTERLACED)
if (m_bitmap.cliprect().contains(x, m_vpos + 1))
m_bitmap.pix32(m_vpos + 1, x) = MAKE_RGB(pal3bit(m_port_c >> 0), pal3bit(m_port_c >> 3), pal2bit(m_port_c >> 6));
}
m_line_pos_cycles = cycles;
}
UINT32 uzebox_state::screen_update_uzebox(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
return 0;
}
@ -98,14 +259,6 @@ UINT32 uzebox_state::screen_update_uzebox(screen_device &screen, bitmap_rgb32 &b
* Machine definition *
\****************************************************/
DRIVER_INIT_MEMBER(uzebox_state,uzebox)
{
}
void uzebox_state::machine_reset()
{
}
const avr8_config atmega644_config =
{
"eeprom"
@ -122,14 +275,12 @@ static MACHINE_CONFIG_START( uzebox, uzebox_state )
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60.08)
MCFG_SCREEN_REFRESH_RATE(59.99)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1395))
MCFG_SCREEN_SIZE(634, 480)
MCFG_SCREEN_VISIBLE_AREA(0, 633, 0, 479)
MCFG_SCREEN_SIZE(870, 525)
MCFG_SCREEN_VISIBLE_AREA(150, 870-1, 40, 488-1)
MCFG_SCREEN_UPDATE_DRIVER(uzebox_state, screen_update_uzebox)
MCFG_PALETTE_LENGTH(0x1000)
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("avr8")
MCFG_SOUND_ADD("dac", DAC, 0)
@ -142,11 +293,11 @@ static MACHINE_CONFIG_START( uzebox, uzebox_state )
MACHINE_CONFIG_END
ROM_START( uzebox )
ROM_REGION( 0x10000, "maincpu", 0 ) /* Main program store */
ROM_CART_LOAD("cart1", 0x0000, 0x10000, ROM_OPTIONAL)
ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) /* Main program store */
ROM_CART_LOAD("cart1", 0x0000, 0x10000, ROM_OPTIONAL | ROM_FILL_FF)
ROM_REGION( 0x200, "eeprom", ROMREGION_ERASE00 ) /* on-die eeprom */
ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
CONS(2010, uzebox, 0, 0, uzebox, uzebox, uzebox_state, uzebox, "Belogic", "Uzebox", GAME_NO_SOUND | GAME_NOT_WORKING)
CONS(2010, uzebox, 0, 0, uzebox, uzebox, driver_device, 0, "Belogic", "Uzebox", GAME_NO_SOUND | GAME_NOT_WORKING)