diff options
author | Miodrag Milanovic <mmicko@gmail.com> | 2013-12-30 07:21:37 +0000 |
---|---|---|
committer | Miodrag Milanovic <mmicko@gmail.com> | 2013-12-30 07:21:37 +0000 |
commit | a0d7e3ca1daf5133d584bfcb576e609e27352ea1 (patch) | |
tree | b56c854221c413e9f8860b9b0e44da4c8b330e22 /src | |
parent | 0e95be33eea15f37217c2a3bf9579ab39273af05 (diff) |
-AVR8 improvements: [Felipe Sanches]
- Added ELPM instructions
- Added fuse bits macros
- Added reset logic to decide initial program counter based on
fuse bits configuration
- Added initial support for ATMEGA1280 and ATMEGA2560
- Use register names in the disassembly of IN and OUT instructions
(MESS) New driver : Replicator 1 [Felipe Sanches]
(MESS) Replicator 1 driver: [Felipe Sanches]
- status: no sound / not working
- general skeleton.
- basic memory mapping
- shift-register interfacing from PORTC writes to the LCD device
- avr8 fuses configuration
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/cpu/avr8/avr8.c | 1224 | ||||
-rw-r--r-- | src/emu/cpu/avr8/avr8.h | 381 | ||||
-rw-r--r-- | src/emu/cpu/avr8/avr8dasm.c | 14 | ||||
-rw-r--r-- | src/mess/drivers/craft.c | 10 | ||||
-rw-r--r-- | src/mess/drivers/replicator.c | 682 | ||||
-rw-r--r-- | src/mess/mess.lst | 3 | ||||
-rw-r--r-- | src/mess/mess.mak | 4 | ||||
-rw-r--r-- | src/targets/mess.lst | 3 |
8 files changed, 2137 insertions, 184 deletions
diff --git a/src/emu/cpu/avr8/avr8.c b/src/emu/cpu/avr8/avr8.c index ecaf238c72d..05d31369a5e 100644 --- a/src/emu/cpu/avr8/avr8.c +++ b/src/emu/cpu/avr8/avr8.c @@ -9,9 +9,25 @@ 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: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL + Unimplemented opcodes: SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL - Changelist - + 29 Dec. 2013 [Felipe Sanches] + - Added crude boilerplate code for Timer/Counter #4 + + 25 Dec. 2013 [Felipe Sanches] + - Updated AVR8_REGIDX_* enum based on ATMEGA640/1280/2560 datasheet + + 24 Dec. 2013 [Felipe Sanches] + - update data memory mapping so that all 0x200 register addresses are accessible + + 23 Dec. 2013 [Felipe Sanches] + - Added ELPM instructions + - Added fuse bits macros + - Added reset logic to decide initial program counter based on fuse bits configuration + - Added initial support for ATMEGA1280 and ATMEGA2560 + - Use register names in the disassembly of IN and OUT instructions + 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 @@ -109,6 +125,26 @@ enum WGM02_FAST_PWM_CMP }; +enum +{ + WGM4_NORMAL = 0, + WGM4_PWM_8_PC, + WGM4_PWM_9_PC, + WGM4_PWM_10_PC, + WGM4_CTC_OCR, + WGM4_FAST_PWM_8, + WGM4_FAST_PWM_9, + WGM4_FAST_PWM_10, + WGM4_PWM_PFC_ICR, + WGM4_PWM_PFC_OCR, + WGM4_PWM_PC_ICR, + WGM4_PWM_PC_OCR, + WGM4_CTC_ICR, + WGM4_RESERVED, + WGM4_FAST_PWM_ICR, + WGM4_FAST_PWM_OCR +}; + static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; #define SREG_R(b) ((m_r[AVR8_REGIDX_SREG] & (1 << (b))) >> (b)) @@ -140,6 +176,8 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; #define SPREG ((m_r[AVR8_REGIDX_SPH] << 8) | m_r[AVR8_REGIDX_SPL]) // I/O Defines +#define AVR8_OCR1CH (m_r[AVR8_REGIDX_OCR1CH]) +#define AVR8_OCR1CL (m_r[AVR8_REGIDX_OCR1CL]) #define AVR8_OCR1BH (m_r[AVR8_REGIDX_OCR1BH]) #define AVR8_OCR1BL (m_r[AVR8_REGIDX_OCR1BL]) #define AVR8_OCR1AH (m_r[AVR8_REGIDX_OCR1AH]) @@ -271,6 +309,51 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; #define AVR8_TIFR2_TOV2_SHIFT 0 #define AVR8_TIFR2_MASK (AVR8_TIFR2_TOV2_MASK | AVR8_TIFR2_OCF2B_MASK | AVR8_TIFR2_OCF2A_MASK) +#define AVR8_TCCR4B (m_r[AVR8_REGIDX_TCCR4B]) +#define AVR8_TCCR4B_FOC4A_MASK 0x80 +#define AVR8_TCCR4B_FOC4A_SHIFT 7 +#define AVR8_TCCR4B_FOC4B_MASK 0x40 +#define AVR8_TCCR4B_FOC4B_SHIFT 6 +#define AVR8_TCCR4B_FOC4C_MASK 0x20 +#define AVR8_TCCR4B_FOC4C_SHIFT 5 +#define AVR8_TCCR4B_WGM4_32_MASK 0x18 +#define AVR8_TCCR4B_WGM4_32_SHIFT 3 +#define AVR8_TCCR4B_CS_MASK 0x07 +#define AVR8_TCCR4B_CS_SHIFT 0 +#define AVR8_TIMER4_CLOCK_SELECT ((AVR8_TCCR4B & AVR8_TCCR4B_CS_MASK) >> AVR8_TCCR4B_CS_SHIFT) + +#define AVR8_TCCR4A (m_r[AVR8_REGIDX_TCCR4A]) +#define AVR8_TCCR4A_COM4A_MASK 0xc0 +#define AVR8_TCCR4A_COM4A_SHIFT 6 +#define AVR8_TCCR4A_COM4B_MASK 0x30 +#define AVR8_TCCR4A_COM4B_SHIFT 4 +#define AVR8_TCCR4A_WGM4_10_MASK 0x03 +#define AVR8_TCCR4A_WGM4_10_SHIFT 0 +#define AVR8_TCCR4A_COM4A ((AVR8_TCCR4A & AVR8_TCCR4A_COM4A_MASK) >> AVR8_TCCR4A_COM4A_SHIFT) +#define AVR8_TCCR4A_COM4B ((AVR8_TCCR4A & AVR8_TCCR4A_COM4B_MASK) >> AVR8_TCCR4A_COM4B_SHIFT) +#define AVR8_TCCR4A_WGM2_10 (AVR8_TCCR4A & AVR8_TCCR4A_WGM2_10_MASK) + +#define AVR8_WGM4_32 ((AVR8_TCCR4B & AVR8_TCCR4B_WGM4_32_MASK) >> AVR8_TCCR4B_WGM4_32_SHIFT) +#define AVR8_WGM4_10 ((AVR8_TCCR4A & AVR8_TCCR4A_WGM4_10_MASK) >> AVR8_TCCR4A_WGM4_10_SHIFT) +#define AVR8_WGM4 ((AVR8_WGM4_32 << 2) | AVR8_WGM4_10) + +#define AVR8_TIMSK4 (m_r[AVR8_REGIDX_TIMSK4]) +#define AVR8_TIMSK4_OCIE4B_MASK 0x04 +#define AVR8_TIMSK4_OCIE4A_MASK 0x02 +#define AVR8_TIMSK4_TOIE4_MASK 0x01 +#define AVR8_TIMSK4_OCIE4B ((AVR8_TIMSK4 & AVR8_TIMSK4_OCIE4B_MASK) >> 2) +#define AVR8_TIMSK4_OCIE4A ((AVR8_TIMSK4 & AVR8_TIMSK4_OCIE4A_MASK) >> 1) +#define AVR8_TIMSK4_TOIE4 (AVR8_TIMSK4 & AVR8_TIMSK4_TOIE4_MASK) + +#define AVR8_TIFR4 (m_r[AVR8_REGIDX_TIFR4]) +#define AVR8_TIFR4_OCF4B_MASK 0x04 +#define AVR8_TIFR4_OCF4B_SHIFT 2 +#define AVR8_TIFR4_OCF4A_MASK 0x02 +#define AVR8_TIFR4_OCF4A_SHIFT 1 +#define AVR8_TIFR4_TOV4_MASK 0x01 +#define AVR8_TIFR4_TOV4_SHIFT 0 +#define AVR8_TIFR4_MASK (AVR8_TIFR4_TOV4_MASK | AVR8_TIFR4_OCF4B_MASK | AVR8_TIFR4_OCF4A_MASK) + #define AVR8_OCR0A m_r[AVR8_REGIDX_OCR0A] #define AVR8_OCR0B m_r[AVR8_REGIDX_OCR0B] #define AVR8_TCNT0 m_r[AVR8_REGIDX_TCNT0] @@ -278,6 +361,7 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; #define AVR8_OCR1A ((AVR8_OCR1AH << 8) | AVR8_OCR1AL) #define AVR8_OCR1B ((AVR8_OCR1BH << 8) | AVR8_OCR1BL) +#define AVR8_OCR1C ((AVR8_OCR1CH << 8) | AVR8_OCR1CL) #define AVR8_ICR1 ((AVR8_ICR1H << 8) | AVR8_ICR1L) #define AVR8_TCNT1 ((AVR8_TCNT1H << 8) | AVR8_TCNT1L) #define AVR8_WGM1 (((AVR8_TCCR1B & 0x18) >> 1) | (AVR8_TCCR1A & 0x03)) @@ -288,6 +372,21 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; #define AVR8_TCNT2 m_r[AVR8_REGIDX_TCNT2] #define AVR8_WGM2 (((AVR8_TCCR2B & 0x08) >> 1) | (AVR8_TCCR2A & 0x03)) +#define AVR8_TCNT3L m_r[AVR8_REGIDX_TCNT3L] +#define AVR8_TCNT3H m_r[AVR8_REGIDX_TCNT3H] + +#define AVR8_ICR4 ((AVR8_ICR4H << 8) | AVR8_ICR4L) +#define AVR8_ICR4H (m_r[AVR8_REGIDX_ICR4H]) +#define AVR8_ICR4L (m_r[AVR8_REGIDX_ICR4L]) +#define AVR8_OCR4AH m_r[AVR8_REGIDX_OCR4AH] +#define AVR8_OCR4AL m_r[AVR8_REGIDX_OCR4AL] +#define AVR8_OCR4A ((AVR8_OCR4AH << 8) | AVR8_OCR4AL) +#define AVR8_OCR4B m_r[AVR8_REGIDX_OCR4B] +#define AVR8_TCNT4 m_r[AVR8_REGIDX_TCNT4] + +#define AVR8_TCNT4L m_r[AVR8_REGIDX_TCNT4L] +#define AVR8_TCNT4H m_r[AVR8_REGIDX_TCNT4H] + #define AVR8_GTCCR_PSRASY_MASK 0x02 #define AVR8_GTCCR_PSRASY_SHIFT 1 @@ -313,21 +412,35 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; const device_type ATMEGA88 = &device_creator<atmega88_device>; const device_type ATMEGA644 = &device_creator<atmega644_device>; +const device_type ATMEGA1280 = &device_creator<atmega1280_device>; +const device_type ATMEGA2560 = &device_creator<atmega2560_device>; //************************************************************************** // INTERNAL ADDRESS MAP //************************************************************************** -static ADDRESS_MAP_START( avr8_internal_map, AS_DATA, 8, avr8_device ) +static ADDRESS_MAP_START( atmega88_internal_map, AS_DATA, 8, atmega88_device ) AM_RANGE(0x0000, 0x00ff) AM_READWRITE( regs_r, regs_w ) ADDRESS_MAP_END +static ADDRESS_MAP_START( atmega644_internal_map, AS_DATA, 8, atmega644_device ) + AM_RANGE(0x0000, 0x00ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( atmega1280_internal_map, AS_DATA, 8, atmega1280_device ) + AM_RANGE(0x0000, 0x01ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( atmega2560_internal_map, AS_DATA, 8, atmega2560_device ) + AM_RANGE(0x0000, 0x01ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + //------------------------------------------------- // atmega88_device - constructor //------------------------------------------------- atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : avr8_device(mconfig, "ATMEGA88", tag, owner, clock, ATMEGA88, 0x0fff, ADDRESS_MAP_NAME(avr8_internal_map), "atmega88", __FILE__) + : avr8_device(mconfig, "ATMEGA88", tag, owner, clock, ATMEGA88, 0x0fff, ADDRESS_MAP_NAME(atmega88_internal_map), CPU_TYPE_ATMEGA88, "atmega88", __FILE__) { } @@ -336,7 +449,25 @@ atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag, //------------------------------------------------- atmega644_device::atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : avr8_device(mconfig, "ATMEGA644", tag, owner, clock, ATMEGA644, 0xffff, ADDRESS_MAP_NAME(avr8_internal_map), "atmega644", __FILE__) + : avr8_device(mconfig, "ATMEGA644", tag, owner, clock, ATMEGA644, 0xffff, ADDRESS_MAP_NAME(atmega644_internal_map), CPU_TYPE_ATMEGA644, "atmega644", __FILE__) +{ +} + +//------------------------------------------------- +// atmega1280_device - constructor +//------------------------------------------------- + +atmega1280_device::atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : avr8_device(mconfig, "ATMEGA1280", tag, owner, clock, ATMEGA1280, 0x1ffff, ADDRESS_MAP_NAME(atmega1280_internal_map), CPU_TYPE_ATMEGA1280, "atmega1280", __FILE__) +{ +} + +//------------------------------------------------- +// atmega2560_device - constructor +//------------------------------------------------- + +atmega2560_device::atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : avr8_device(mconfig, "ATMEGA2560", tag, owner, clock, ATMEGA2560, 0x3ffff, ADDRESS_MAP_NAME(atmega2560_internal_map), CPU_TYPE_ATMEGA2560, "atmega2560", __FILE__) { } @@ -344,14 +475,19 @@ atmega644_device::atmega644_device(const machine_config &mconfig, const char *ta // avr8_device - constructor //------------------------------------------------- -avr8_device::avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 addr_mask, address_map_constructor internal_map, const char *shortname, const char *source) +avr8_device::avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 addr_mask, address_map_constructor internal_map, UINT8 cpu_type, const char *shortname, const char *source) : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_shifted_pc(0), m_program_config("program", ENDIANNESS_LITTLE, 8, 22), m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0, internal_map), - m_io_config("io", ENDIANNESS_LITTLE, 8, 2), + m_io_config("io", ENDIANNESS_LITTLE, 8, 4), m_eeprom(NULL), + m_cpu_type(cpu_type), + m_lfuses(0x62), + m_hfuses(0x99), + m_efuses(0xFF), + m_lock_bits(0xFF), m_pc(0), - m_shifted_pc(0), m_timer0_top(0), m_timer0_increment(1), m_timer0_prescale(0), @@ -364,6 +500,10 @@ avr8_device::avr8_device(const machine_config &mconfig, const char *name, const m_timer2_increment(1), m_timer2_prescale(0), m_timer2_prescale_count(0), + m_timer4_top(0), + m_timer4_increment(1), + m_timer4_prescale(0), + m_timer4_prescale_count(0), m_spi_active(false), m_spi_prescale(0), m_spi_prescale_count(0), @@ -387,6 +527,41 @@ void avr8_device::static_set_config(device_t &device, const avr8_config &config) static_cast<avr8_config &>(avr8) = config; } +//------------------------------------------------- +// static_set_low_fuses +//------------------------------------------------- + +void avr8_device::set_low_fuses(const UINT8 byte) +{ + m_lfuses = byte; +} + +//------------------------------------------------- +// static_set_high_fuses +//------------------------------------------------- + +void avr8_device::set_high_fuses(const UINT8 byte) +{ + m_hfuses = byte; +} + +//------------------------------------------------- +// static_set_extended_fuses +//------------------------------------------------- + +void avr8_device::set_extended_fuses(const UINT8 byte) +{ + m_efuses = byte; +} + +//------------------------------------------------- +// static_set_lock_bits +//------------------------------------------------- + +void avr8_device::set_lock_bits(const UINT8 byte) +{ + m_lock_bits = byte; +} //------------------------------------------------- // unimplemented_opcode - bail on unspuported @@ -395,7 +570,8 @@ void avr8_device::static_set_config(device_t &device, const avr8_config &config) void avr8_device::unimplemented_opcode(UINT32 op) { - fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, m_pc); +// debugger_break(machine()); + fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, m_shifted_pc); } @@ -443,7 +619,9 @@ void avr8_device::device_start() state_add(STATE_GENPC, "GENPC", m_shifted_pc).noshow(); state_add(STATE_GENFLAGS, "GENFLAGS", m_r[AVR8_REGIDX_SREG]).callimport().callexport().formatstr("%8s").noshow(); state_add(AVR8_SREG, "STATUS", m_r[AVR8_REGIDX_SREG]).mask(0xff); - state_add(AVR8_PC, "PC", m_shifted_pc).mask(0xffff); + state_add(AVR8_PC, "PC", m_shifted_pc).mask(m_addr_mask); + state_add(AVR8_SPH, "SPH", m_r[AVR8_REGIDX_SPH]).mask(0xff); + state_add(AVR8_SPL, "SPL", m_r[AVR8_REGIDX_SPL]).mask(0xff); state_add(AVR8_R0, "R0", m_r[ 0]).mask(0xff); state_add(AVR8_R1, "R1", m_r[ 1]).mask(0xff); state_add(AVR8_R2, "R2", m_r[ 2]).mask(0xff); @@ -492,6 +670,10 @@ void avr8_device::device_start() save_item(NAME(m_timer2_increment)); save_item(NAME(m_timer2_prescale)); save_item(NAME(m_timer2_prescale_count)); + save_item(NAME(m_timer4_top)); + save_item(NAME(m_timer4_increment)); + save_item(NAME(m_timer4_prescale)); + save_item(NAME(m_timer4_prescale_count)); save_item(NAME(m_addr_mask)); save_item(NAME(m_interrupt_pending)); save_item(NAME(m_icount)); @@ -509,10 +691,31 @@ void avr8_device::device_start() void avr8_device::device_reset() { + logerror("AVR low fuse bits: 0x%02X\n", m_lfuses); + logerror("AVR high fuse bits: 0x%02X\n", m_hfuses); + logerror("AVR extended fuse bits: 0x%02X\n", m_efuses); + logerror("AVR lock bits: 0x%02X\n", m_lock_bits); + + switch ((m_hfuses & (BOOTSZ1|BOOTSZ0)) >> 1){ + case 0: m_boot_size = 4096; break; + case 1: m_boot_size = 2048; break; + case 2: m_boot_size = 1024; break; + case 3: m_boot_size = 512; break; + default: break; + } + + if (m_hfuses & BOOTRST){ + m_shifted_pc = 0x0000; + logerror("Booting AVR core from address 0x0000\n"); + } else { + m_shifted_pc = (m_addr_mask + 1) - 2*m_boot_size; + logerror("AVR Boot loader section size: %d words\n", m_boot_size); + } + m_r[AVR8_REGIDX_SPL] = 0; m_r[AVR8_REGIDX_SPH] = 0; - for (int i = 0; i < 256; i++) + for (int i = 0; i < 0x200; i++) { m_r[i] = 0; } @@ -536,17 +739,30 @@ void avr8_device::device_reset() m_timer2_prescale = 0; m_timer2_prescale_count = 0; + m_timer4_top = 0; + m_timer4_increment = 1; + m_timer4_prescale = 0; + m_timer4_prescale_count = 0; + AVR8_TIMSK1 = 0; AVR8_OCR1AH = 0; AVR8_OCR1AL = 0; AVR8_OCR1BH = 0; AVR8_OCR1BL = 0; + AVR8_OCR1CH = 0; + AVR8_OCR1CL = 0; AVR8_ICR1H = 0; AVR8_ICR1L = 0; AVR8_TCNT1H = 0; AVR8_TCNT1L = 0; AVR8_TCNT2 = 0; + AVR8_TIMSK4 = 0; + AVR8_TCNT4H = 0; + AVR8_ICR4H = 0; + AVR8_ICR4L = 0; + AVR8_TCNT4L = 0; + m_interrupt_pending = false; m_elapsed_cycles = 0; @@ -751,6 +967,38 @@ void atmega644_device::update_interrupt(int source) } } +//TODO: review this! +void atmega1280_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; + } +} + +//TODO: review this! +void atmega2560_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 @@ -768,7 +1016,7 @@ void avr8_device::timer_tick(int cycles) { UINT8 out_bit = (m_r[AVR8_REGIDX_SPDR] & (1 << m_spi_prescale_countdown)) >> m_spi_prescale_countdown; m_spi_prescale_countdown--; - m_io->write_byte(0x01, (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0)); + m_io->write_byte(AVR8_IO_PORTB, (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0)); m_r[AVR8_REGIDX_PORTB] = (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0); m_spi_prescale_count -= m_spi_prescale; } @@ -803,6 +1051,17 @@ void avr8_device::timer_tick(int cycles) m_timer2_prescale_count -= m_timer2_prescale; } } + + if (m_timer4_prescale != 0) + { + m_timer4_prescale_count++; + if (m_timer4_prescale_count == m_timer4_prescale) + { + timer4_tick(); + m_timer4_prescale_count -= m_timer4_prescale; + } + } + } } @@ -1476,6 +1735,264 @@ void avr8_device::update_ocr2(UINT8 newval, UINT8 reg) // Nothing needs to be done? All handled in timer callback } +/************************************************************************************************/ + +void avr8_device::timer4_tick() +{ + /* TODO: Handle comparison, setting OC1x pins, detection of BOTTOM and TOP */ + + UINT16 count = (m_r[AVR8_REGIDX_TCNT4H] << 8) | m_r[AVR8_REGIDX_TCNT4L]; + + // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer + //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT, + //(m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT }; + UINT16 ocr4[2] = { (m_r[AVR8_REGIDX_OCR4AH] << 8) | m_r[AVR8_REGIDX_OCR4AL], + (m_r[AVR8_REGIDX_OCR4BH] << 8) | m_r[AVR8_REGIDX_OCR4BL] }; +//TODO UINT8 ocf4[2] = { (1 << AVR8_TIFR4_OCF4A_SHIFT), (1 << AVR8_TIFR4_OCF4B_SHIFT) }; +//TODO UINT8 int4[2] = { AVR8_INTIDX_OCF4A, AVR8_INTIDX_OCF4B }; + INT32 increment = m_timer4_increment; + + for(INT32 reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++) + { + switch(AVR8_WGM4) + { + case WGM4_FAST_PWM_8: + case WGM4_FAST_PWM_9: + case WGM4_FAST_PWM_10: + if (count == m_timer4_top){ + //printf("[T4] tick WGM4_FAST_PWM_8: %d\n", count); + count=0; + } + break; + + case WGM4_CTC_OCR: + //printf("[T4] tick WGM4_CTC_OCR: %d\n", count); + if (count == 0xffff) + { + m_r[AVR8_REGIDX_TIFR4] |= AVR8_TIFR4_TOV4_MASK; + update_interrupt(AVR8_INTIDX_TOV4); + count = 0; + increment = 0; + } + + if (count == ocr4[reg]) + { + if (reg == 0) + { + count = 0; + increment = 0; + } +//TODO m_r[AVR8_REGIDX_TIFR4] |= ocf4[reg]; +//TODO update_interrupt(int4[reg]); + } + else if (count == 0) + { + if (reg == 0) + { +//TODO m_r[AVR8_REGIDX_TIFR4] &= ~AVR8_TIFR4_TOV4_MASK; +//TODO update_interrupt(AVR8_INTIDX_TOV4); + } + +//TODO m_r[AVR8_REGIDX_TIFR4] &= ~ocf4[reg]; +//TODO update_interrupt(int4[reg]); + } + break; + + case WGM1_FAST_PWM_OCR: + if(count == ocr4[reg]) + { + if (reg == 0) + { +//TODO m_r[AVR8_REGIDX_TIFR4] |= AVR8_TIFR4_TOV4_MASK; +//TODO update_interrupt(AVR8_INTIDX_TOV4); + count = 0; + increment = 0; + } + +//TODO m_r[AVR8_REGIDX_TIFR4] |= ocf4[reg]; +//TODO update_interrupt(int4[reg]); + } + else if(count == 0) + { + if (reg == 0) + { +//TODO m_r[AVR8_REGIDX_TIFR4] &= ~AVR8_TIFR4_TOV4_MASK; +//TODO update_interrupt(AVR8_INTIDX_TOV4); + } + +//TODO m_r[AVR8_REGIDX_TIFR4] &= ~ocf4[reg]; +//TODO update_interrupt(int4[reg]); + } + break; + + default: +// printf("[T4] tick Unknown waveform generation mode: %d\n", count); + + verboselog(m_pc, 0, "update_timer4_compare_mode: Unknown waveform generation mode: %02x\n", wgm4); + break; + } + /* + switch(compare_mode[reg]) + { + case 0: + //verboselog(m_pc, 0, "update_timer4_compare_mode: Normal port operation (OC1 disconnected)\n"); + break; + + case 1: + case 2: + // TODO + break; + + case 3: + break; + } + */ + } + + count += increment; + m_r[AVR8_REGIDX_TCNT4H] = (count >> 8) & 0xff; + m_r[AVR8_REGIDX_TCNT4L] = count & 0xff; +} + +void avr8_device::update_timer4_clock_source() +{ + debugger_break(machine()); + switch(AVR8_TIMER4_CLOCK_SELECT) + { + case 0: // Counter stopped + m_timer4_prescale = 0; + //printf("[T4]: Counter stopped\n"); + break; + case 1: // Clk/1; no prescaling + m_timer4_prescale = 1; + //printf("[T4]: prescale = 1\n"); + break; + case 2: // Clk/8 + m_timer4_prescale = 8; + //printf("[T4]: prescale = 8\n"); + break; + case 3: // Clk/64 + m_timer4_prescale = 64; + //printf("[T4]: prescale = 64\n"); + break; + case 4: // Clk/256 + m_timer4_prescale = 256; + //printf("[T4]: prescale = 256\n"); + break; + case 5: // Clk/1024 + m_timer4_prescale = 1024; + //printf("[T4]: prescale = 1024\n"); + break; + case 6: // T0 trigger, falling edge + case 7: // T0 trigger, rising edge + //printf("[T4]: update_timer4_clock_source: T0 Trigger mode not implemented yet\n"); + m_timer4_prescale = 0; + verboselog(m_pc, 0, "update_timer4_clock_source: T0 Trigger mode not implemented yet\n"); + break; + } + + if (m_timer4_prescale_count > m_timer4_prescale) + { + m_timer4_prescale_count = m_timer4_prescale - 1; + } +} + +void avr8_device::update_timer4_waveform_gen_mode() +{ + //printf("[T4] AVR8_WGM4 = %d\n", AVR8_WGM4); + + switch(AVR8_WGM4) + { + case WGM4_NORMAL: + m_timer4_top = 0xffff; + break; + + case WGM4_PWM_8_PC: + case WGM4_FAST_PWM_8: + m_timer4_top = 0x00ff; + break; + + case WGM4_PWM_9_PC: + case WGM4_FAST_PWM_9: + m_timer4_top = 0x01ff; + break; + + case WGM4_PWM_10_PC: + case WGM4_FAST_PWM_10: + m_timer4_top = 0x03ff; + break; + + case WGM4_PWM_PFC_ICR: + case WGM4_PWM_PC_ICR: + case WGM4_CTC_ICR: + case WGM4_FAST_PWM_ICR: + m_timer4_top = AVR8_ICR4; + break; + + case WGM4_PWM_PFC_OCR: + case WGM4_PWM_PC_OCR: + case WGM4_CTC_OCR: + case WGM4_FAST_PWM_OCR: + m_timer4_top = AVR8_OCR4A; + break; + + default: + m_timer4_top = 0; + verboselog(m_pc, 0, "update_timer4_waveform_gen_mode: Unsupported waveform generation type: %d\n", AVR8_WGM4); + break; + } +} + + +void avr8_device::changed_tccr4a(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR4A; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR4A = data; + + if(changed & AVR8_TCCR4A_WGM4_10_MASK) + { + // TODO + update_timer4_waveform_gen_mode(); + } +} + +void avr8_device::changed_tccr4b(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR4B; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR4B = data; + + if(changed & AVR8_TCCR4B_FOC4A_MASK) + { + // TODO +// timer4_force_output_compare(AVR8_REG_A); + } + + if(changed & AVR8_TCCR4B_FOC4B_MASK) + { + // TODO +// timer4_force_output_compare(AVR8_REG_B); + } + + if(changed & AVR8_TCCR4B_WGM4_32_MASK) + { + update_timer4_waveform_gen_mode(); + } + + if(changed & AVR8_TCCR4B_CS_MASK) + { + update_timer4_clock_source(); + } +} + +/************************************************************************************************/ + + /****************/ /* SPI Handling */ /****************/ @@ -1578,6 +2095,8 @@ void avr8_device::change_spsr(UINT8 data) WRITE8_MEMBER( avr8_device::regs_w ) { + //printf("<<< WRITE offset [%04x]=%02x >>>\n", offset, data); + switch( offset ) { case AVR8_REGIDX_R0: @@ -1615,6 +2134,74 @@ WRITE8_MEMBER( avr8_device::regs_w ) m_r[offset] = data; break; + case AVR8_REGIDX_PORTA: + m_io->write_byte(AVR8_IO_PORTA, data); + m_r[AVR8_REGIDX_PORTA] = data; + break; + + case AVR8_REGIDX_PORTB: + m_io->write_byte(AVR8_IO_PORTB, data); + m_r[AVR8_REGIDX_PORTB] = data; + break; + + case AVR8_REGIDX_PORTC: + m_io->write_byte(AVR8_IO_PORTC, data); + m_r[AVR8_REGIDX_PORTC] = data; + break; + + case AVR8_REGIDX_PORTD: + m_io->write_byte(AVR8_IO_PORTD, data); + m_r[AVR8_REGIDX_PORTD] = data; + break; + + case AVR8_REGIDX_PORTE: + m_io->write_byte(AVR8_IO_PORTE, data); + m_r[AVR8_REGIDX_PORTE] = data; + break; + + case AVR8_REGIDX_PORTF: + m_io->write_byte(AVR8_IO_PORTF, data); + m_r[AVR8_REGIDX_PORTF] = data; + break; + + case AVR8_REGIDX_PORTG: + m_io->write_byte(AVR8_IO_PORTG, data); + m_r[AVR8_REGIDX_PORTG] = data; + break; + + case AVR8_REGIDX_PORTH: + m_io->write_byte(AVR8_IO_PORTH, data); + m_r[AVR8_REGIDX_PORTH] = data; + break; + + case AVR8_REGIDX_PORTJ: + m_io->write_byte(AVR8_IO_PORTJ, data); + m_r[AVR8_REGIDX_PORTJ] = data; + break; + + case AVR8_REGIDX_PORTK: + m_io->write_byte(AVR8_IO_PORTK, data); + m_r[AVR8_REGIDX_PORTK] = data; + break; + + case AVR8_REGIDX_PORTL: + m_io->write_byte(AVR8_IO_PORTL, data); + m_r[AVR8_REGIDX_PORTL] = data; + break; + + case AVR8_REGIDX_DDRA: + case AVR8_REGIDX_DDRB: + case AVR8_REGIDX_DDRC: + case AVR8_REGIDX_DDRD: + case AVR8_REGIDX_EEARL: + case AVR8_REGIDX_EEARH: + case AVR8_REGIDX_SREG: + case AVR8_REGIDX_RAMPZ: + case AVR8_REGIDX_SPH: + case AVR8_REGIDX_SPL: + m_r[offset] = data; + break; + case AVR8_REGIDX_TCCR0B: verboselog(m_pc, 0, "AVR8: TCCR0B = %02x\n", data ); changed_tccr0b(data); @@ -1635,14 +2222,6 @@ WRITE8_MEMBER( avr8_device::regs_w ) update_ocr0(AVR8_OCR0B, AVR8_REG_B); break; - case AVR8_REGIDX_TIMSK0: - verboselog(m_pc, 0, "AVR8: TIMSK0 = %02x\n", data ); - m_r[AVR8_REGIDX_TIMSK0] = data; - update_interrupt(AVR8_INTIDX_OCF0A); - update_interrupt(AVR8_INTIDX_OCF0B); - update_interrupt(AVR8_INTIDX_TOV0); - break; - case AVR8_REGIDX_TIFR0: verboselog(m_pc, 0, "AVR8: TIFR0 = %02x\n", data ); m_r[AVR8_REGIDX_TIFR0] &= ~(data & AVR8_TIFR0_MASK); @@ -1655,34 +2234,128 @@ WRITE8_MEMBER( avr8_device::regs_w ) AVR8_TCNT0 = data; break; - case AVR8_REGIDX_TCCR1B: - verboselog(m_pc, 0, "AVR8: TCCR1B = %02x\n", data ); - changed_tccr1b(data); + case AVR8_REGIDX_TIFR1: + verboselog(m_pc, 0, "AVR8: TIFR1 = %02x\n", data ); + m_r[AVR8_REGIDX_TIFR1] &= ~(data & AVR8_TIFR1_MASK); + update_interrupt(AVR8_INTIDX_ICF1); + update_interrupt(AVR8_INTIDX_OCF1A); + update_interrupt(AVR8_INTIDX_OCF1B); + update_interrupt(AVR8_INTIDX_TOV1); break; - case AVR8_REGIDX_TCCR1A: - verboselog(m_pc, 0, "AVR8: TCCR1A = %02x\n", data ); - changed_tccr1a(data); + case AVR8_REGIDX_TIFR2: + verboselog(m_pc, 0, "AVR8: TIFR2 = %02x\n", data ); + m_r[AVR8_REGIDX_TIFR2] &= ~(data & AVR8_TIFR2_MASK); + update_interrupt(AVR8_INTIDX_OCF2A); + update_interrupt(AVR8_INTIDX_OCF2B); + update_interrupt(AVR8_INTIDX_TOV2); break; - case AVR8_REGIDX_OCR1BH: - verboselog(m_pc, 0, "AVR8: OCR1BH = %02x\n", data ); - update_ocr1((AVR8_OCR1B & 0x00ff) | (data << 8), AVR8_REG_B); + case AVR8_REGIDX_GTCCR: + if (data & AVR8_GTCCR_PSRASY_MASK) + { + data &= ~AVR8_GTCCR_PSRASY_MASK; + m_timer2_prescale_count = 0; + } break; - case AVR8_REGIDX_OCR1BL: - verboselog(m_pc, 0, "AVR8: OCR1BL = %02x\n", data ); - update_ocr1((AVR8_OCR1B & 0xff00) | data, AVR8_REG_B); + case AVR8_REGIDX_EECR: + if (data & AVR8_EECR_EERE) + { + UINT16 addr = (m_r[AVR8_REGIDX_EEARH] & AVR8_EEARH_MASK) << 8; + addr |= m_r[AVR8_REGIDX_EEARL]; + m_r[AVR8_REGIDX_EEDR] = m_eeprom[addr]; + } break; - case AVR8_REGIDX_OCR1AH: - verboselog(m_pc, 0, "AVR8: OCR1AH = %02x\n", data ); - update_ocr1((AVR8_OCR1A & 0x00ff) | (data << 8), AVR8_REG_A); + case AVR8_REGIDX_GPIOR0: + verboselog(m_pc, 1, "AVR8: GPIOR0 Write: %02x\n", data); + m_r[AVR8_REGIDX_GPIOR0] = data; break; - case AVR8_REGIDX_OCR1AL: - verboselog(m_pc, 0, "AVR8: OCR1AL = %02x\n", data ); - update_ocr1((AVR8_OCR1A & 0xff00) | data, AVR8_REG_A); + case AVR8_REGIDX_GPIOR1: + case AVR8_REGIDX_GPIOR2: + m_r[offset] = data; + break; + + case AVR8_REGIDX_SPSR: + change_spsr(data); + break; + + case AVR8_REGIDX_SPCR: + change_spcr(data); + break; + + case AVR8_REGIDX_SPDR: + { + m_r[AVR8_REGIDX_SPDR] = data; + m_spi_active = true; + m_spi_prescale_countdown = 7; + m_spi_prescale_count = 0; + break; + } + + case AVR8_REGIDX_WDTCSR: + verboselog(m_pc, 0, "AVR8: WDTCSR = %02x\n", data ); + //TODO: changed_wdtcsr(data); + break; + + case AVR8_REGIDX_CLKPR: + verboselog(m_pc, 0, "AVR8: CLKPR = %02x\n", data ); + //TODO: changed_clkpr(data); + break; + + case AVR8_REGIDX_PRR0: + verboselog(m_pc, 0, "AVR8: PRR0 = %02x\n", data ); + //TODO: changed_prr0(data); + break; + + case AVR8_REGIDX_PRR1: + verboselog(m_pc, 0, "AVR8: PRR1 = %02x\n", data ); + //TODO: changed_prr1(data); + break; + + case AVR8_REGIDX_OSCCAL: + verboselog(m_pc, 0, "AVR8: OSCCAL = %02x\n", data ); + //TODO: changed_osccal(data); + break; + + case AVR8_REGIDX_PCICR: + verboselog(m_pc, 0, "AVR8: PCICR = %02x\n", data ); + //TODO: changed_pcicr(data); + break; + + case AVR8_REGIDX_EICRA: + verboselog(m_pc, 0, "AVR8: EICRA = %02x\n", data ); + //TODO: changed_eicra(data); + break; + + case AVR8_REGIDX_EICRB: + verboselog(m_pc, 0, "AVR8: EICRB = %02x\n", data ); + //TODO: changed_eicrb(data); + break; + + case AVR8_REGIDX_PCMSK0: + verboselog(m_pc, 0, "AVR8: PCMSK0 = %02x\n", data ); + //TODO: changed_pcmsk0(data); + break; + + case AVR8_REGIDX_PCMSK1: + verboselog(m_pc, 0, "AVR8: PCMSK1 = %02x\n", data ); + //TODO: changed_pcmsk1(data); + break; + + case AVR8_REGIDX_PCMSK2: + verboselog(m_pc, 0, "AVR8: PCMSK2 = %02x\n", data ); + //TODO: changed_pcmsk2(data); + break; + + case AVR8_REGIDX_TIMSK0: + verboselog(m_pc, 0, "AVR8: TIMSK0 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK0] = data; + update_interrupt(AVR8_INTIDX_OCF0A); + update_interrupt(AVR8_INTIDX_OCF0B); + update_interrupt(AVR8_INTIDX_TOV0); break; case AVR8_REGIDX_TIMSK1: @@ -1694,145 +2367,359 @@ WRITE8_MEMBER( avr8_device::regs_w ) update_interrupt(AVR8_INTIDX_TOV1); break; - case AVR8_REGIDX_TIFR1: - verboselog(m_pc, 0, "AVR8: TIFR1 = %02x\n", data ); - m_r[AVR8_REGIDX_TIFR1] &= ~(data & AVR8_TIFR1_MASK); - update_interrupt(AVR8_INTIDX_ICF1); - update_interrupt(AVR8_INTIDX_OCF1A); - update_interrupt(AVR8_INTIDX_OCF1B); - update_interrupt(AVR8_INTIDX_TOV1); + case AVR8_REGIDX_TIMSK2: + verboselog(m_pc, 0, "AVR8: TIMSK2 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK2] = data; + update_interrupt(AVR8_INTIDX_OCF2A); + update_interrupt(AVR8_INTIDX_OCF2B); + update_interrupt(AVR8_INTIDX_TOV2); break; - case AVR8_REGIDX_TCNT1H: - AVR8_TCNT1H = data; + case AVR8_REGIDX_TIMSK3: + verboselog(m_pc, 0, "AVR8: TIMSK3 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK3] = data; + update_interrupt(AVR8_INTIDX_OCF3A); + update_interrupt(AVR8_INTIDX_OCF3B); + update_interrupt(AVR8_INTIDX_TOV3); + break; + + case AVR8_REGIDX_TIMSK4: + verboselog(m_pc, 0, "AVR8: TIMSK4 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK4] = data; + update_interrupt(AVR8_INTIDX_OCF4A); + update_interrupt(AVR8_INTIDX_OCF4B); + update_interrupt(AVR8_INTIDX_TOV4); + break; + + case AVR8_REGIDX_TIMSK5: + verboselog(m_pc, 0, "AVR8: TIMSK5 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK5] = data; + update_interrupt(AVR8_INTIDX_OCF5A); + update_interrupt(AVR8_INTIDX_OCF5B); + update_interrupt(AVR8_INTIDX_TOV5); + break; + + case AVR8_REGIDX_XMCRA: + verboselog(m_pc, 0, "AVR8: XMCRA = %02x\n", data ); + //TODO: changed_xmcra(data); + break; + + case AVR8_REGIDX_XMCRB: + verboselog(m_pc, 0, "AVR8: XMCRB = %02x\n", data ); + //TODO: changed_xmcrb(data); + break; + + case AVR8_REGIDX_ADCL: + verboselog(m_pc, 0, "AVR8: ADCL = %02x\n", data ); + //TODO: changed_adcl(data); + break; + + case AVR8_REGIDX_ADCH: + verboselog(m_pc, 0, "AVR8: ADCH = %02x\n", data ); + //TODO: changed_adch(data); + break; + + case AVR8_REGIDX_ADCSRA: + verboselog(m_pc, 0, "AVR8: ADCSRA = %02x\n", data ); + //TODO: changed_adcsra(data); + break; + + case AVR8_REGIDX_ADCSRB: + verboselog(m_pc, 0, "AVR8: ADCSRB = %02x\n", data ); + //TODO: changed_adcsrb(data); + break; + + case AVR8_REGIDX_ADMUX: + verboselog(m_pc, 0, "AVR8: ADMUX = %02x\n", data ); + //TODO: changed_admux(data); + break; + + case AVR8_REGIDX_DIDR0: + verboselog(m_pc, 0, "AVR8: DIDR0 = %02x\n", data ); + //TODO: changed_didr0(data); + break; + + case AVR8_REGIDX_DIDR1: + verboselog(m_pc, 0, "AVR8: DIDR1 = %02x\n", data ); + //TODO: changed_didr1(data); + break; + + case AVR8_REGIDX_DIDR2: + verboselog(m_pc, 0, "AVR8: DIDR2 = %02x\n", data ); + //TODO: changed_didr2(data); + break; + + case AVR8_REGIDX_TCCR1A: + verboselog(m_pc, 0, "AVR8: TCCR1A = %02x\n", data ); + changed_tccr1a(data); + break; + + case AVR8_REGIDX_TCCR1B: + verboselog(m_pc, 0, "AVR8: TCCR1B = %02x\n", data ); + changed_tccr1b(data); + break; + + case AVR8_REGIDX_TCCR1C: + verboselog(m_pc, 0, "AVR8: TCCR1C = %02x\n", data ); + //TODO: changed_tccr1c(data); break; case AVR8_REGIDX_TCNT1L: AVR8_TCNT1L = data; break; - case AVR8_REGIDX_TCCR2B: - verboselog(m_pc, 0, "AVR8: TCCR2B = %02x\n", data ); + case AVR8_REGIDX_TCNT1H: + AVR8_TCNT1H = data; break; - case AVR8_REGIDX_TCCR2A: - verboselog(m_pc, 0, "AVR8: TCCR2A = %02x\n", data ); - changed_tccr2a(data); + case AVR8_REGIDX_ICR1L: + //TODO: ICR1L break; - case AVR8_REGIDX_OCR2A: - update_ocr2(data, AVR8_REG_A); + case AVR8_REGIDX_ICR1H: + //TODO: ICR1H break; - case AVR8_REGIDX_OCR2B: - update_ocr2(data, AVR8_REG_B); + case AVR8_REGIDX_OCR1AL: + verboselog(m_pc, 0, "AVR8: OCR1AL = %02x\n", data ); + update_ocr1((AVR8_OCR1A & 0xff00) | data, AVR8_REG_A); break; - case AVR8_REGIDX_TIMSK2: - verboselog(m_pc, 0, "AVR8: TIMSK2 = %02x\n", data ); - m_r[AVR8_REGIDX_TIMSK2] = data; - update_interrupt(AVR8_INTIDX_OCF2A); - update_interrupt(AVR8_INTIDX_OCF2B); - update_interrupt(AVR8_INTIDX_TOV2); + case AVR8_REGIDX_OCR1AH: + verboselog(m_pc, 0, "AVR8: OCR1AH = %02x\n", data ); + update_ocr1((AVR8_OCR1A & 0x00ff) | (data << 8), AVR8_REG_A); break; - case AVR8_REGIDX_TIFR2: - verboselog(m_pc, 0, "AVR8: TIFR2 = %02x\n", data ); - m_r[AVR8_REGIDX_TIFR2] &= ~(data & AVR8_TIFR2_MASK); - update_interrupt(AVR8_INTIDX_OCF2A); - update_interrupt(AVR8_INTIDX_OCF2B); - update_interrupt(AVR8_INTIDX_TOV2); + case AVR8_REGIDX_OCR1BL: + verboselog(m_pc, 0, "AVR8: OCR1BL = %02x\n", data ); + update_ocr1((AVR8_OCR1B & 0xff00) | data, AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR1BH: + verboselog(m_pc, 0, "AVR8: OCR1BH = %02x\n", data ); + update_ocr1((AVR8_OCR1B & 0x00ff) | (data << 8), AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR1CL: + verboselog(m_pc, 0, "AVR8: OCR1CL = %02x\n", data ); + update_ocr1((AVR8_OCR1C & 0xff00) | data, AVR8_REG_C); + break; + + case AVR8_REGIDX_OCR1CH: + verboselog(m_pc, 0, "AVR8: OCR1CH = %02x\n", data ); + update_ocr1((AVR8_OCR1C & 0x00ff) | (data << 8), AVR8_REG_C); + break; + + case AVR8_REGIDX_TCCR3A: + verboselog(m_pc, 0, "AVR8: TCCR3A = %02x\n", data ); +//TODO: changed_tccr3a(data); + break; + + case AVR8_REGIDX_TCCR3B: + verboselog(m_pc, 0, "AVR8: TCCR3B = %02x\n", data ); +//TODO: changed_tccr3b(data); + break; + + case AVR8_REGIDX_TCCR3C: + verboselog(m_pc, 0, "AVR8: TCCR3C = %02x\n", data ); +//TODO: changed_tccr3c(data); + break; + + case AVR8_REGIDX_TCNT3L: + AVR8_TCNT3L = data; + break; + + case AVR8_REGIDX_TCNT3H: + AVR8_TCNT3H = data; + break; + + case AVR8_REGIDX_ICR3L: + //TODO: ICR3L + break; + + case AVR8_REGIDX_ICR3H: + //TODO: ICR3H + break; + + case AVR8_REGIDX_OCR3AL: + verboselog(m_pc, 0, "AVR8: OCR3AL = %02x\n", data ); +//TODO: update_ocr3((AVR8_OCR3A & 0xff00) | data, AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR3AH: + verboselog(m_pc, 0, "AVR8: OCR3AH = %02x\n", data ); +//TODO: update_ocr3((AVR8_OCR3A & 0x00ff) | (data << 8), AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR3BL: + verboselog(m_pc, 0, "AVR8: OCR3BL = %02x\n", data ); +//TODO: update_ocr3((AVR8_OCR3B & 0xff00) | data, AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR3BH: + verboselog(m_pc, 0, "AVR8: OCR3BH = %02x\n", data ); +//TODO: update_ocr3((AVR8_OCR3B & 0x00ff) | (data << 8), AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR3CL: + verboselog(m_pc, 0, "AVR8: OCR3CL = %02x\n", data ); +//TODO: update_ocr3((AVR8_OCR3C & 0xff00) | data, AVR8_REG_C); + break; + + case AVR8_REGIDX_OCR3CH: + verboselog(m_pc, 0, "AVR8: OCR3CH = %02x\n", data ); +//TODO: update_ocr3((AVR8_OCR3C & 0x00ff) | (data << 8), AVR8_REG_C); + break; + + case AVR8_REGIDX_TCCR4A: + verboselog(m_pc, 0, "AVR8: TCCR4A = %02x\n", data ); + changed_tccr4a(data); + break; + + case AVR8_REGIDX_TCCR4B: + verboselog(m_pc, 0, "AVR8: TCCR4B = %02x\n", data ); + changed_tccr4b(data); + break; + + case AVR8_REGIDX_TCCR4C: + verboselog(m_pc, 0, "AVR8: TCCR4C = %02x\n", data ); +//TODO: changed_tccr4c(data); + break; + + case AVR8_REGIDX_TCNT4L: + AVR8_TCNT4L = data; + break; + + case AVR8_REGIDX_TCNT4H: + AVR8_TCNT4H = data; + break; + + case AVR8_REGIDX_ICR4L: + //TODO: ICR4L + break; + + case AVR8_REGIDX_ICR4H: + //TODO: ICR4H + break; + + case AVR8_REGIDX_OCR4AL: + verboselog(m_pc, 0, "AVR8: OCR4AL = %02x\n", data ); +//TODO: update_ocr4((AVR8_OCR4A & 0xff00) | data, AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR4AH: + verboselog(m_pc, 0, "AVR8: OCR4AH = %02x\n", data ); +//TODO: update_ocr4((AVR8_OCR4A & 0x00ff) | (data << 8), AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR4BL: + verboselog(m_pc, 0, "AVR8: OCR4BL = %02x\n", data ); +//TODO: update_ocr4((AVR8_OCR4B & 0xff00) | data, AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR4BH: + verboselog(m_pc, 0, "AVR8: OCR4BH = %02x\n", data ); +//TODO: update_ocr4((AVR8_OCR4B & 0x00ff) | (data << 8), AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR4CL: + verboselog(m_pc, 0, "AVR8: OCR4CL = %02x\n", data ); +//TODO: update_ocr4((AVR8_OCR4C & 0xff00) | data, AVR8_REG_C); + break; + + case AVR8_REGIDX_OCR4CH: + verboselog(m_pc, 0, "AVR8: OCR4CH = %02x\n", data ); +//TODO: update_ocr4((AVR8_OCR4C & 0x00ff) | (data << 8), AVR8_REG_C); + break; + + case AVR8_REGIDX_TCCR2A: + verboselog(m_pc, 0, "AVR8: TCCR2A = %02x\n", data ); + changed_tccr2a(data); + break; + + case AVR8_REGIDX_TCCR2B: + verboselog(m_pc, 0, "AVR8: TCCR2B = %02x\n", data ); + changed_tccr2b(data); break; case AVR8_REGIDX_TCNT2: AVR8_TCNT2 = data; break; - case AVR8_REGIDX_GTCCR: - if (data & AVR8_GTCCR_PSRASY_MASK) - { - data &= ~AVR8_GTCCR_PSRASY_MASK; - m_timer2_prescale_count = 0; - } + case AVR8_REGIDX_OCR2A: + update_ocr2(data, AVR8_REG_A); break; - case AVR8_REGIDX_SPL: - case AVR8_REGIDX_SPH: - case AVR8_REGIDX_DDRA: - case AVR8_REGIDX_DDRB: - case AVR8_REGIDX_DDRC: - case AVR8_REGIDX_DDRD: - case AVR8_REGIDX_EEARL: - case AVR8_REGIDX_EEARH: - case AVR8_REGIDX_SREG: - m_r[offset] = data; + case AVR8_REGIDX_OCR2B: + update_ocr2(data, AVR8_REG_B); break; - case AVR8_REGIDX_EECR: - if (data & AVR8_EECR_EERE) - { - UINT16 addr = (m_r[AVR8_REGIDX_EEARH] & AVR8_EEARH_MASK) << 8; - addr |= m_r[AVR8_REGIDX_EEARL]; - m_r[AVR8_REGIDX_EEDR] = m_eeprom[addr]; - } + case AVR8_REGIDX_ASSR: + verboselog(m_pc, 0, "AVR8: ASSR = %02x\n", data ); + //TODO: changed_assr(data); break; - case AVR8_REGIDX_GPIOR0: - verboselog(m_pc, 1, "AVR8: GPIOR0 Write: %02x\n", data); - m_r[offset] = data; + case AVR8_REGIDX_TWBR: + verboselog(m_pc, 0, "AVR8: TWBR = %02x\n", data ); + //TODO: changed_twbr(data); break; - case AVR8_REGIDX_GPIOR1: - case AVR8_REGIDX_GPIOR2: - m_r[offset] = data; + case AVR8_REGIDX_TWSR: + verboselog(m_pc, 0, "AVR8: TWSR = %02x\n", data ); + //TODO: changed_twsr(data); break; - case AVR8_REGIDX_PORTA: - m_io->write_byte(0x00, data); - m_r[AVR8_REGIDX_PORTA] = data; + case AVR8_REGIDX_TWAR: + verboselog(m_pc, 0, "AVR8: TWAR = %02x\n", data ); + //TODO: changed_twar(data); break; - case AVR8_REGIDX_PORTB: - m_io->write_byte(0x01, data); - m_r[AVR8_REGIDX_PORTB] = data; + case AVR8_REGIDX_TWDR: + verboselog(m_pc, 0, "AVR8: TWDR = %02x\n", data ); + //TODO: changed_twdr(data); break; - case AVR8_REGIDX_PORTC: - m_io->write_byte(0x02, data); - m_r[AVR8_REGIDX_PORTC] = data; + case AVR8_REGIDX_TWCR: + verboselog(m_pc, 0, "AVR8: TWCR = %02x\n", data ); + //TODO: changed_twcr(data); + m_r[AVR8_REGIDX_TWCR] = data; break; - case AVR8_REGIDX_PORTD: - m_io->write_byte(0x03, data); - m_r[AVR8_REGIDX_PORTD] = data; + case AVR8_REGIDX_TWAMR: + verboselog(m_pc, 0, "AVR8: TWAMR = %02x\n", data ); + //TODO: changed_twamr(data); break; - case AVR8_REGIDX_SPSR: - change_spsr(data); + case AVR8_REGIDX_UCSR0A: + verboselog(m_pc, 0, "AVR8: UCSR0A = %02x\n", data ); + //TODO: changed_ucsr0a(data); break; - case AVR8_REGIDX_SPCR: - change_spcr(data); + case AVR8_REGIDX_UCSR0B: + verboselog(m_pc, 0, "AVR8: UCSR0B = %02x\n", data ); + //TODO: changed_ucsr0b(data); break; - case AVR8_REGIDX_SPDR: - { - m_r[AVR8_REGIDX_SPDR] = data; - m_spi_active = true; - m_spi_prescale_countdown = 7; - m_spi_prescale_count = 0; + case AVR8_REGIDX_UCSR0C: + verboselog(m_pc, 0, "AVR8: UCSR0C = %02x\n", data ); + //TODO: changed_ucsr0c(data); break; - } - +/* + case AVR8_REGIDX_: + verboselog(m_pc, 0, "AVR8: = %02x\n", data ); + //TODO: changed_(data); + break; +*/ default: - verboselog(m_pc, 0, "AVR8: Unknown Register Write: %02x = %02x\n", (UINT8)offset, data); + verboselog(m_pc, 0, "AVR8: Unknown Register Write: %03x = %02x\n", offset, data); break; } } READ8_MEMBER( avr8_device::regs_r ) { - //printf("offset %04x\n", offset); +// printf("--- READ offset %04x ---\n", offset); + switch( offset ) { case AVR8_REGIDX_R0: @@ -1869,38 +2756,91 @@ READ8_MEMBER( avr8_device::regs_r ) case AVR8_REGIDX_R31: return m_r[offset]; - case AVR8_REGIDX_SPL: - case AVR8_REGIDX_SPH: - case AVR8_REGIDX_TCNT1L: - case AVR8_REGIDX_TCNT1H: - case AVR8_REGIDX_TCNT2: case AVR8_REGIDX_PORTA: case AVR8_REGIDX_PORTB: case AVR8_REGIDX_PORTC: case AVR8_REGIDX_PORTD: + case AVR8_REGIDX_PORTE: + case AVR8_REGIDX_PORTF: + case AVR8_REGIDX_PORTG: + case AVR8_REGIDX_PORTH: + case AVR8_REGIDX_PORTJ: + case AVR8_REGIDX_PORTK: + case AVR8_REGIDX_PORTL: case AVR8_REGIDX_DDRA: case AVR8_REGIDX_DDRB: case AVR8_REGIDX_DDRC: case AVR8_REGIDX_DDRD: + case AVR8_REGIDX_DDRE: + case AVR8_REGIDX_DDRF: + case AVR8_REGIDX_DDRG: + case AVR8_REGIDX_DDRH: + case AVR8_REGIDX_DDRJ: + case AVR8_REGIDX_DDRK: + case AVR8_REGIDX_DDRL: + case AVR8_REGIDX_TWCR:/*TODO: needed for Replicator 1 <------- BLOQUEIA PROGRESSO DA EXECUĂĂO DO FIRMWARE no endereço 105EC*/ + case AVR8_REGIDX_UCSR0B:/*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_SPDR: /*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_SPSR: /*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_ADCSRA: /*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_ADCSRB: /*TODO: needed for Replicator 1 */ case AVR8_REGIDX_GPIOR0: case AVR8_REGIDX_GPIOR1: case AVR8_REGIDX_GPIOR2: case AVR8_REGIDX_EEDR: + case AVR8_REGIDX_SPL: + case AVR8_REGIDX_SPH: case AVR8_REGIDX_SREG: + case AVR8_REGIDX_EECR: /*TODO: needed for Replicator 1 */ return m_r[offset]; + case AVR8_REGIDX_TWSR: + //quick hack: by returning a value != 0x08 we induce an error state that makes the object code jump out of the wait loop and continue execution failing the 2-wire write operation. + //TODO: implement-me! + return 0x00; /*TODO: needed for Replicator 1 */ + // TODO: consider the DDRx case AVR8_REGIDX_PINA: - return m_io->read_byte(AVR8_REG_A); + return m_io->read_byte(AVR8_REG_A); + case AVR8_REGIDX_PINB: - return m_io->read_byte(AVR8_REG_B); + return m_io->read_byte(AVR8_REG_B); + case AVR8_REGIDX_PINC: - return m_io->read_byte(AVR8_REG_C); + return m_io->read_byte(AVR8_REG_C); + case AVR8_REGIDX_PIND: - return m_io->read_byte(AVR8_REG_D); + return m_io->read_byte(AVR8_REG_D); + + case AVR8_REGIDX_PINE: + return m_io->read_byte(AVR8_REG_E); + + case AVR8_REGIDX_PINF: + return m_io->read_byte(AVR8_REG_F); + + case AVR8_REGIDX_PING: + return m_io->read_byte(AVR8_REG_G); + + case AVR8_REGIDX_PINH: + return m_io->read_byte(AVR8_REG_H); + + case AVR8_REGIDX_PINJ: + return m_io->read_byte(AVR8_REG_J); + + case AVR8_REGIDX_PINK: + return m_io->read_byte(AVR8_REG_K); + + case AVR8_REGIDX_PINL: + return m_io->read_byte(AVR8_REG_L); + + case AVR8_REGIDX_TCNT1L: + case AVR8_REGIDX_TCNT1H: + case AVR8_REGIDX_TCNT2: + case AVR8_REGIDX_UCSR0A: + return m_r[offset]; default: - verboselog(m_pc, 0, "AVR8: Unknown Register Read: %02x\n", (UINT8)offset); + printf("[%08X] AVR8: Unknown Register Read: 0x%03X\n", m_shifted_pc, offset); return 0; } } @@ -1961,6 +2901,7 @@ void avr8_device::execute_run() UINT8 rr = 0; UINT8 res = 0; UINT16 pd = 0; + UINT32 pd32 = 0; INT16 sd = 0; INT32 opcycles = 1; @@ -2289,12 +3230,17 @@ void avr8_device::execute_run() opcycles = 3; break; case 0x0006: // ELPM Rd,Z - //output += sprintf( output, "ELPM R%d, Z", RD5(op) ); - unimplemented_opcode(op); + m_r[RD5(op)] = m_program->read_byte((m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG); + opcycles = 3; break; case 0x0007: // ELPM Rd,Z+ - //output += sprintf( output, "ELPM R%d, Z+", RD5(op) ); - unimplemented_opcode(op); + pd32 = (m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG; + m_r[RD5(op)] = m_program->read_byte(pd32); + pd32++; + m_r[AVR8_REGIDX_RAMPZ] = (pd32 >> 16) & 0x00ff; + m_r[31] = (pd32 >> 8) & 0x00ff; + m_r[30] = pd32 & 0x00ff; + opcycles = 3; break; case 0x0009: // LD Rd,Y+ pd = YREG; @@ -2303,7 +3249,7 @@ void avr8_device::execute_run() m_r[29] = (pd >> 8) & 0x00ff; m_r[28] = pd & 0x00ff; opcycles = 2; - break; + break; case 0x000a: // LD Rd,-Y pd = YREG; pd--; @@ -2658,7 +3604,9 @@ void avr8_device::execute_run() break; case 0x00a0: // WDR //output += sprintf( output, "WDR" ); - unimplemented_opcode(op); + //unimplemented_opcode(op); //TODO: necessary for emulating the Replicator 1 + //printf("Watchdot Reset!\n"); + opcycles = 1; break; case 0x00c0: // LPM m_r[0] = m_program->read_byte(ZREG); diff --git a/src/emu/cpu/avr8/avr8.h b/src/emu/cpu/avr8/avr8.h index bd7e5acfad1..48fe5577941 100644 --- a/src/emu/cpu/avr8/avr8.h +++ b/src/emu/cpu/avr8/avr8.h @@ -46,6 +46,23 @@ #define MCFG_CPU_AVR8_CONFIG(_config) \ avr8_device::static_set_config(*device, _config); + +//************************************************************************** +// FUSE BITS CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CPU_AVR8_LFUSE(byte) \ + ((avr8_device*) device)->set_low_fuses(byte); + +#define MCFG_CPU_AVR8_HFUSE(byte) \ + ((avr8_device*) device)->set_high_fuses(byte); + +#define MCFG_CPU_AVR8_EFUSE(byte) \ + ((avr8_device*) device)->set_extended_fuses(byte); + +#define MCFG_CPU_AVR8_LOCK(byte) \ + ((avr8_device*) device)->set_lock_bits(byte); + //************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -73,6 +90,12 @@ public: // inline configuration helpers static void static_set_config(device_t &device, const avr8_config &config); + // fuse configs + void set_low_fuses(UINT8 byte); + void set_high_fuses(UINT8 byte); + void set_extended_fuses(UINT8 byte); + void set_lock_bits(UINT8 byte); + // public interfaces virtual void update_interrupt(int source); UINT64 get_elapsed_cycles() @@ -83,9 +106,18 @@ public: // register handling DECLARE_WRITE8_MEMBER( regs_w ); DECLARE_READ8_MEMBER( regs_r ); + UINT32 m_shifted_pc; protected: - avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 address_mask, address_map_constructor internal_map, const char *shortname, const char *source); + enum + { + CPU_TYPE_ATMEGA88, + CPU_TYPE_ATMEGA644, + CPU_TYPE_ATMEGA1280, + CPU_TYPE_ATMEGA2560 + }; + + avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 address_mask, address_map_constructor internal_map, UINT8 cpu_type, const char *shortname, const char *source); // device-level overrides virtual void device_start(); @@ -115,10 +147,19 @@ protected: const address_space_config m_io_config; UINT8 *m_eeprom; + // bootloader + UINT16 m_boot_size; + UINT8 m_cpu_type; + + // Fuses + UINT8 m_lfuses; + UINT8 m_hfuses; + UINT8 m_efuses; + UINT8 m_lock_bits; + // CPU registers UINT32 m_pc; - UINT32 m_shifted_pc; - UINT8 m_r[256]; + UINT8 m_r[0x200]; // internal timers UINT8 m_timer0_top; @@ -136,6 +177,11 @@ protected: UINT16 m_timer2_prescale; UINT16 m_timer2_prescale_count; + UINT16 m_timer4_top; + INT32 m_timer4_increment; + UINT16 m_timer4_prescale; + UINT16 m_timer4_prescale_count; + // SPI bool m_spi_active; UINT8 m_spi_prescale; @@ -209,6 +255,26 @@ protected: void update_ocr2(UINT8 newval, UINT8 reg); void timer2_force_output_compare(int reg); + // timer 3 +/* + void timer3_tick(); + void changed_tccr3a(UINT8 data); + void changed_tccr3b(UINT8 data); + void update_timer3_waveform_gen_mode(); + void update_timer3_clock_source(); + void update_ocr3(UINT8 newval, UINT8 reg); + void timer3_force_output_compare(int reg); +*/ + + // timer 4 + void timer4_tick(); + void changed_tccr4a(UINT8 data); + void changed_tccr4b(UINT8 data); + void update_timer4_waveform_gen_mode(); + void update_timer4_clock_source(); + //void update_ocr4(UINT8 newval, UINT8 reg); + //void timer4_force_output_compare(int reg); + // address spaces address_space *m_program; address_space *m_data; @@ -218,6 +284,8 @@ protected: // device type definition extern const device_type ATMEGA88; extern const device_type ATMEGA644; +extern const device_type ATMEGA1280; +extern const device_type ATMEGA2560; // ======================> atmega88_device @@ -239,6 +307,28 @@ public: virtual void update_interrupt(int source); }; +// ======================> atmega1280_device + +class atmega1280_device : public avr8_device +{ +public: + // construction/destruction + atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void update_interrupt(int source); +}; + +// ======================> atmega2560_device + +class atmega2560_device : public avr8_device +{ +public: + // construction/destruction + atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void update_interrupt(int source); +}; + /*************************************************************************** REGISTER ENUMERATION ***************************************************************************/ @@ -282,7 +372,8 @@ enum AVR8_X, AVR8_Y, AVR8_Z, - AVR8_SP, + AVR8_SPH, + AVR8_SPL, }; enum @@ -348,7 +439,7 @@ enum // Used by I/O register handling enum { - AVR8_REGIDX_R0 = 0, + AVR8_REGIDX_R0 = 0x00, AVR8_REGIDX_R1, AVR8_REGIDX_R2, AVR8_REGIDX_R3, @@ -380,7 +471,6 @@ enum AVR8_REGIDX_R29, AVR8_REGIDX_R30, AVR8_REGIDX_R31, - AVR8_REGIDX_PINA = 0x20, AVR8_REGIDX_DDRA, AVR8_REGIDX_PORTA, @@ -393,12 +483,22 @@ enum AVR8_REGIDX_PIND, AVR8_REGIDX_DDRD, AVR8_REGIDX_PORTD, - + AVR8_REGIDX_PINE, + AVR8_REGIDX_DDRE, + AVR8_REGIDX_PORTE, + AVR8_REGIDX_PINF, + AVR8_REGIDX_DDRF, + AVR8_REGIDX_PORTF, + AVR8_REGIDX_PING, + AVR8_REGIDX_DDRG, + AVR8_REGIDX_PORTG, AVR8_REGIDX_TIFR0 = 0x35, AVR8_REGIDX_TIFR1, AVR8_REGIDX_TIFR2, - - AVR8_REGIDX_PCIFR = 0x3b, + AVR8_REGIDX_TIFR3, + AVR8_REGIDX_TIFR4, + AVR8_REGIDX_TIFR5, + AVR8_REGIDX_PCIFR = 0x3B, AVR8_REGIDX_EIFR, AVR8_REGIDX_EIMSK, AVR8_REGIDX_GPIOR0, @@ -412,53 +512,66 @@ enum AVR8_REGIDX_TCNT0, AVR8_REGIDX_OCR0A, AVR8_REGIDX_OCR0B, - - AVR8_REGIDX_GPIOR1 = 0x4a, + //0x49: Reserved + AVR8_REGIDX_GPIOR1 = 0x4A, AVR8_REGIDX_GPIOR2, AVR8_REGIDX_SPCR, AVR8_REGIDX_SPSR, AVR8_REGIDX_SPDR, - + //0x4F: Reserved AVR8_REGIDX_ACSR = 0x50, - + AVR8_REGIDX_OCDR, + //0x52: Reserved AVR8_REGIDX_SMCR = 0x53, AVR8_REGIDX_MCUSR, AVR8_REGIDX_MCUCR, - + //0x56: Reserved AVR8_REGIDX_SPMCSR = 0x57, - - AVR8_REGIDX_SPL = 0x5d, + //0x58: Reserved + //0x59: Reserved + //0x5A: Reserved + AVR8_REGIDX_RAMPZ = 0x5B, + AVR8_REGIDX_EIND, + AVR8_REGIDX_SPL, AVR8_REGIDX_SPH, AVR8_REGIDX_SREG, - AVR8_REGIDX_WDTCSR, +//-------------------------- + AVR8_REGIDX_WDTCSR = 0x60, AVR8_REGIDX_CLKPR, - - AVR8_REGIDX_PRR = 0x64, - - AVR8_REGIDX_OSCCAL = 0x66, - + //0x62: Reserved + //0x63: Reserved + AVR8_REGIDX_PRR0 = 0x64, + AVR8_REGIDX_PRR1, + AVR8_REGIDX_OSCCAL, + //0x67: Reserved AVR8_REGIDX_PCICR = 0x68, AVR8_REGIDX_EICRA, - - AVR8_REGIDX_PCMSK0 = 0x6B, + AVR8_REGIDX_EICRB, + AVR8_REGIDX_PCMSK0, AVR8_REGIDX_PCMSK1, AVR8_REGIDX_PCMSK2, AVR8_REGIDX_TIMSK0, AVR8_REGIDX_TIMSK1, AVR8_REGIDX_TIMSK2, - + AVR8_REGIDX_TIMSK3, + AVR8_REGIDX_TIMSK4, + AVR8_REGIDX_TIMSK5, + AVR8_REGIDX_XMCRA, + AVR8_REGIDX_XMCRB, + //0x76: Reserved + //0x77: Reserved AVR8_REGIDX_ADCL = 0x78, AVR8_REGIDX_ADCH, AVR8_REGIDX_ADCSRA, AVR8_REGIDX_ADCSRB, AVR8_REGIDX_ADMUX, - - AVR8_REGIDX_DIDR0 = 0x7e, + AVR8_REGIDX_DIDR2, + AVR8_REGIDX_DIDR0, AVR8_REGIDX_DIDR1, AVR8_REGIDX_TCCR1A, AVR8_REGIDX_TCCR1B, AVR8_REGIDX_TCCR1C, - + //0x83: Reserved AVR8_REGIDX_TCNT1L = 0x84, AVR8_REGIDX_TCNT1H, AVR8_REGIDX_ICR1L, @@ -467,56 +580,246 @@ enum AVR8_REGIDX_OCR1AH, AVR8_REGIDX_OCR1BL, AVR8_REGIDX_OCR1BH, - - AVR8_REGIDX_TCCR2A = 0xb0, + AVR8_REGIDX_OCR1CL, + AVR8_REGIDX_OCR1CH, + //0x8E: Reserved + //0x8F: Reserved + AVR8_REGIDX_TCCR3A = 0x90, + AVR8_REGIDX_TCCR3B, + AVR8_REGIDX_TCCR3C, + //0x93: Reserved + AVR8_REGIDX_TCNT3L = 0x94, + AVR8_REGIDX_TCNT3H, + AVR8_REGIDX_ICR3L, + AVR8_REGIDX_ICR3H, + AVR8_REGIDX_OCR3AL, + AVR8_REGIDX_OCR3AH, + AVR8_REGIDX_OCR3BL, + AVR8_REGIDX_OCR3BH, + AVR8_REGIDX_OCR3CL, + AVR8_REGIDX_OCR3CH, + //0x9E: Reserved + //0x9F: Reserved + AVR8_REGIDX_TCCR4A = 0xA0, + AVR8_REGIDX_TCCR4B, + AVR8_REGIDX_TCCR4C, + //0xA3: Reserved + AVR8_REGIDX_TCNT4L = 0xA4, + AVR8_REGIDX_TCNT4H, + AVR8_REGIDX_ICR4L, + AVR8_REGIDX_ICR4H, + AVR8_REGIDX_OCR4AL, + AVR8_REGIDX_OCR4AH, + AVR8_REGIDX_OCR4BL, + AVR8_REGIDX_OCR4BH, + AVR8_REGIDX_OCR4CL, + AVR8_REGIDX_OCR4CH, + //0xAE: Reserved + //0xAF: Reserved + AVR8_REGIDX_TCCR2A = 0xB0, AVR8_REGIDX_TCCR2B, AVR8_REGIDX_TCNT2, AVR8_REGIDX_OCR2A, AVR8_REGIDX_OCR2B, - - AVR8_REGIDX_ASSR = 0xb6, - - AVR8_REGIDX_TWBR = 0xb8, + //0xB5: Reserved + AVR8_REGIDX_ASSR = 0xB6, + //0xB7: Reserved + AVR8_REGIDX_TWBR = 0xB8, AVR8_REGIDX_TWSR, AVR8_REGIDX_TWAR, AVR8_REGIDX_TWDR, AVR8_REGIDX_TWCR, AVR8_REGIDX_TWAMR, - - AVR8_REGIDX_UCSR0A = 0xc0, + //0xBE: Reserved + //0xBF: Reserved + AVR8_REGIDX_UCSR0A = 0xC0, AVR8_REGIDX_UCSR0B, AVR8_REGIDX_UCSR0C, - - AVR8_REGIDX_UBRR0L = 0xc4, + //0xC3: Reserved + AVR8_REGIDX_UBRR0L = 0xC4, AVR8_REGIDX_UBRR0H, - AVR8_REGIDX_UDR0 + AVR8_REGIDX_UDR0, + //0xC7: Reserved + AVR8_REGIDX_UCSR1A = 0xC8, + AVR8_REGIDX_UCSR1B, + AVR8_REGIDX_UCSR1C, + //0xCB: Reserved + AVR8_REGIDX_UBRR1L = 0xCC, + AVR8_REGIDX_UBRR1H, + AVR8_REGIDX_UDR1, + //0xCF: Reserved + AVR8_REGIDX_UCSR2A = 0xD0, + AVR8_REGIDX_UCSR2B, + AVR8_REGIDX_UCSR2C, + //0xD3: Reserved + AVR8_REGIDX_UBRR2L = 0xD4, + AVR8_REGIDX_UBRR2H, + AVR8_REGIDX_UDR2, + //0xD7: Reserved + //0xD8: Reserved + //0xD9: Reserved + //0xDA: Reserved + //0xDB: Reserved + //0xDC: Reserved + //0xDD: Reserved + //0xDE: Reserved + //0xDF: Reserved + //0xE0: Reserved + //0xE1: Reserved + //0xE2: Reserved + //0xE3: Reserved + //0xE4: Reserved + //0xE5: Reserved + //0xE6: Reserved + //0xE7: Reserved + //0xE8: Reserved + //0xE9: Reserved + //0xEA: Reserved + //0xEB: Reserved + //0xEC: Reserved + //0xED: Reserved + //0xEE: Reserved + //0xEF: Reserved + //0xF0: Reserved + //0xF1: Reserved + //0xF2: Reserved + //0xF3: Reserved + //0xF4: Reserved + //0xF5: Reserved + //0xF6: Reserved + //0xF7: Reserved + //0xF8: Reserved + //0xF9: Reserved + //0xFA: Reserved + //0xFB: Reserved + //0xFC: Reserved + //0xFD: Reserved + //0xFE: Reserved + //0xFF: Reserved + AVR8_REGIDX_PINH = 0x100, + AVR8_REGIDX_DDRH, + AVR8_REGIDX_PORTH, + AVR8_REGIDX_PINJ, + AVR8_REGIDX_DDRJ, + AVR8_REGIDX_PORTJ, + AVR8_REGIDX_PINK, + AVR8_REGIDX_DDRK, + AVR8_REGIDX_PORTK, + AVR8_REGIDX_PINL, + AVR8_REGIDX_DDRL, + AVR8_REGIDX_PORTL }; +enum { + AVR8_IO_PORTA = 0, + AVR8_IO_PORTB, + AVR8_IO_PORTC, + AVR8_IO_PORTD, + AVR8_IO_PORTE, + AVR8_IO_PORTF, + AVR8_IO_PORTG, + AVR8_IO_PORTH, + AVR8_IO_PORTJ, + AVR8_IO_PORTK, + AVR8_IO_PORTL +}; + +//TODO: AVR8_REG_* and AVR8_IO_PORT* seem to serve the same purpose and thus should be unified. Verify this! enum { AVR8_REG_A = 0, AVR8_REG_B, AVR8_REG_C, AVR8_REG_D, + AVR8_REG_E, + AVR8_REG_F, + AVR8_REG_G, + AVR8_REG_H, + AVR8_REG_J, + AVR8_REG_K, + AVR8_REG_L, }; enum { AVR8_INTIDX_SPI, + AVR8_INTIDX_OCF0B, AVR8_INTIDX_OCF0A, AVR8_INTIDX_TOV0, + AVR8_INTIDX_ICF1, + AVR8_INTIDX_OCF1B, AVR8_INTIDX_OCF1A, AVR8_INTIDX_TOV1, + AVR8_INTIDX_OCF2B, AVR8_INTIDX_OCF2A, AVR8_INTIDX_TOV2, +//------ TODO: review this -------- + AVR8_INTIDX_OCF3B, + AVR8_INTIDX_OCF3A, + AVR8_INTIDX_TOV3, + + AVR8_INTIDX_OCF4B, + AVR8_INTIDX_OCF4A, + AVR8_INTIDX_TOV4, + + AVR8_INTIDX_OCF5B, + AVR8_INTIDX_OCF5A, + AVR8_INTIDX_TOV5, +//--------------------------------- + AVR8_INTIDX_COUNT, }; +//lock bit masks +enum +{ + LB1 = (1 << 0), + LB2 = (1 << 1), + BLB01 = (1 << 2), + BLB02 = (1 << 3), + BLB11 = (1 << 4), + BLB12 = (1 << 5), +}; + +//extended fuses bit masks +enum +{ + BODLEVEL0 = (1 << 0), + BODLEVEL1 = (1 << 1), + BODLEVEL2 = (1 << 2), +}; + +//high fuses bit masks +enum +{ + BOOTRST = (1 << 0), + BOOTSZ0 = (1 << 1), + BOOTSZ1 = (1 << 2), + EESAVE = (1 << 3), + WDTON = (1 << 4), + SPIEN = (1 << 5), + JTAGEN = (1 << 6), + OCDEN = (1 << 7), +}; + +//low fuses bit masks +enum +{ + CKSEL0 = (1 << 0), + CKSEL1 = (1 << 1), + CKSEL2 = (1 << 2), + CKSEL3 = (1 << 3), + SUT0 = (1 << 4), + SUT1 = (1 << 5), + CKOUT = (1 << 6), + CKDIV8 = (1 << 7), +}; + #define AVR8_EECR_EERE 0x01 #define AVR8_EEARH_MASK 0x01 diff --git a/src/emu/cpu/avr8/avr8dasm.c b/src/emu/cpu/avr8/avr8dasm.c index b356ccf1c71..cadb528f64c 100644 --- a/src/emu/cpu/avr8/avr8dasm.c +++ b/src/emu/cpu/avr8/avr8dasm.c @@ -30,6 +30,8 @@ CPU_DISASSEMBLE( avr8 ) UINT32 op = oprom[pos++]; op |= oprom[pos++] << 8; UINT32 addr = 0; + const char* register_names[0x40] = {"PINA", "DDRA", "PORTA", "PINB", "DDRB", "PORTB", "PINC", "DDRC", "PORTC", "PIND", "DDRD", "PORTD", "PINE", "DDRE", "PORTE", "PINF", "DDRF", "PORTF", "PING", "DDRG", "PORTG", "TIFR0", "TIFR1", "TIFR2","TIFR3", "TIFR4", "TIFR5", "PCIFR", "EIFR", "EIMSK", "GPIOR0", "EECR", "EEDR", "EEARL", "EEARH", "GTCCR", "TCCR0A", "TCCR0B", "TCNT0", "OCR0A", "OCR0B", "0x29", "GPIOR1", "GPIOR2", "SPCR", "SPSR", "SPDR", "0x2F", "ACSR", "OCDR", "0x32", "SMCR", "MCUSR", "MCUCR", "0x36", "SPMCSR", "0x38", "0x39", "0x3A", "RAMPZ", "EIND", "SPL", "SPH", "SREG"}; + switch(op & 0xf000) { case 0x0000: @@ -478,11 +480,19 @@ CPU_DISASSEMBLE( avr8 ) case 0xb000: if(op & 0x0800) { - output += sprintf( output, "OUT 0x%02x, R%d", ACONST6(op), RD5(op) ); + if (ACONST6(op) < 0x40 ) { + output += sprintf( output, "OUT %s, R%d", register_names[ACONST6(op)], RD5(op) ); + } else { + output += sprintf( output, "OUT 0x%02x, R%d", ACONST6(op), RD5(op) ); + } } else { - output += sprintf( output, "IN R%d, 0x%02x", RD5(op), ACONST6(op) ); + if (ACONST6(op) < 0x40 ) { + output += sprintf( output, "IN R%d, %s", RD5(op), register_names[ACONST6(op)] ); + } else { + output += sprintf( output, "IN R%d, 0x%02x", RD5(op), ACONST6(op) ); + } } break; case 0xc000: diff --git a/src/mess/drivers/craft.c b/src/mess/drivers/craft.c index f6a89221f62..c6a15b7a04e 100644 --- a/src/mess/drivers/craft.c +++ b/src/mess/drivers/craft.c @@ -106,11 +106,11 @@ WRITE8_MEMBER(craft_state::port_w) { switch( offset ) { - case 0x00: // Port A + case AVR8_IO_PORTA: // Port A // Unhandled break; - case 0x01: // Port B + case AVR8_IO_PORTB: // Port B { UINT8 old_port_b = m_port_b; UINT8 pins = data; @@ -129,13 +129,13 @@ WRITE8_MEMBER(craft_state::port_w) break; } - case 0x02: // Port C + case AVR8_IO_PORTC: // Port C video_update(); m_port_c = data; m_latched_color = m_port_c; break; - case 0x03: // Port D + case AVR8_IO_PORTD: // Port D { m_port_d = data; UINT8 audio_sample = (data & 0x02) | ((data & 0xf4) >> 2); @@ -189,7 +189,7 @@ static ADDRESS_MAP_START( craft_data_map, AS_DATA, 8, craft_state ) ADDRESS_MAP_END static ADDRESS_MAP_START( craft_io_map, AS_IO, 8, craft_state ) - AM_RANGE(0x00, 0x03) AM_READWRITE( port_r, port_w ) + AM_RANGE(AVR8_IO_PORTA, AVR8_IO_PORTD) AM_READWRITE( port_r, port_w ) ADDRESS_MAP_END /****************************************************\ diff --git a/src/mess/drivers/replicator.c b/src/mess/drivers/replicator.c new file mode 100644 index 00000000000..70ece6e4a5c --- /dev/null +++ b/src/mess/drivers/replicator.c @@ -0,0 +1,682 @@ +/* + Replicator 1 desktop 3d printer + + driver by Felipe CorrĂȘa da Silva Sanches <fsanches@metamaquina.com.br> + + Licensed under GPLv2 or later. + + NOTE: Even though the MAME/MESS project has been adopting a non-commercial additional licensing clause, I do allow commercial usage of my portion of the code according to the plain terms of the GPL license (version 2 or later). This is useful if you happen to use my code in another project or in case the other MAME/MESS developers happen to drop the non-comercial clause completely. I suggest that other developers consider doing the same. --Felipe Sanches + +Changelog: + + 2013 DEC 28 [Felipe Sanches]: + * LCD now works. We can see the firmware boot screen :-) + + 2013 DEC 24 [Felipe Sanches]: + * declaration of internal EEPROM + + 2013 DEC 18 [Felipe Sanches]: + * Initial driver skeleton + +*/ + +// TODO: +// * figure out what's wrong with the keypad inputs (interface seems to be blocked in the first screen) +// * fix avr8 timer/counter #4 so that we get the buzzer to work +// * figure-out correct size of internal EEPROM +// * emulate an SD Card +// * implement avr8 WDR (watchdog reset) opcode + +#define LOG_PORTS 0 + +//Port A bits: +//Bit 0 unused +//Bit 1 unused +#define A_AXIS_DIR (1 << 2) +#define A_AXIS_STEP (1 << 3) +#define A_AXIS_EN (1 << 4) +#define A_AXIS_POT (1 << 5) +#define B_AXIS_DIR (1 << 6) +#define B_AXIS_STEP (1 << 7) + +//Port B bits: +#define SD_CS (1 << 0) +#define SCK_1280 (1 << 1) +#define MOSI_1280 (1 << 2) +#define MISO_1280 (1 << 3) +#define EX2_PWR_CHECK (1 << 4) +#define EX2_HEAT (1 << 5) +#define EX2_FAN (1 << 6) +#define BLINK (1 << 7) + +//Port C bits: +#define EX2_1280 (1 << 0) +#define EX1_1280 (1 << 1) +#define LCD_CLK (1 << 2) +#define LCD_DATA (1 << 3) +#define LCD_STROBE (1 << 4) +#define RLED (1 << 5) +#define GLED (1 << 6) +#define DETECT (1 << 7) + +//Port D bits: +#define PORTD_SCL (1 << 0) +#define PORTD_SDA (1 << 1) +#define EX_RX_1280 (1 << 2) +#define EX_TX_1280 (1 << 3) +//Bit 4 unused +//Bit 5 unused +//Bit 6 unused +//Bit 7 unused + +//Port E bits: +#define RX_1280 (1 << 0) +#define TX_1280 (1 << 1) +#define THERMO_SCK (1 << 2) +#define THERMO_CS1 (1 << 3) +#define THERMO_CS2 (1 << 4) +#define THERMO_DO (1 << 5) +//Bit 6 unused +//Bit 7 unused + +//Port F bits: +#define X_AXIS_DIR (1 << 0) +#define X_AXIS_STEP (1 << 1) +#define X_AXIS_EN (1 << 2) +#define X_AXIS_POT (1 << 3) +#define Y_AXIS_DIR (1 << 4) +#define Y_AXIS_STEP (1 << 5) +#define Y_AXIS_EN (1 << 6) +#define Y_AXIS_POT (1 << 7) + +//Port G bits: +#define EX4_1280 (1 << 0) +#define EX3_1280 (1 << 1) +#define B_AXIS_EN (1 << 2) +//Bit 3 unused +#define CUTOFF_SR_CHECK (1 << 4) +#define BUZZ (1 << 5) +//Bit 6 unused +//Bit 7 unused + +//Port H bits: +#define CUTOFF_TEST (1 << 0) +#define CUTOFF_RESET (1 << 1) +#define EX1_PWR_CHECK (1 << 2) +#define EX1_HEAT (1 << 3) +#define EX1_FAN (1 << 4) +#define SD_WP (1 << 5) +#define SD_CD (1 << 6) +//Bit 7 unused + +//Port J bits: +#define BUTTON_CENTER (1 << 0) +#define BUTTON_RIGHT (1 << 1) +#define BUTTON_LEFT (1 << 2) +#define BUTTON_DOWN (1 << 3) +#define BUTTON_UP (1 << 4) +#define POTS_SCL (1 << 5) +#define B_AXIS_POT (1 << 6) +//Bit 7 unused + +//Port K bits: +#define Z_AXIS_DIR (1 << 0) +#define Z_AXIS_STEP (1 << 1) +#define Z_AXIS_EN (1 << 2) +#define Z_AXIS_POT (1 << 3) +#define EX7_1280 (1 << 4) +#define EX6_1280 (1 << 5) +#define EX5_1280 (1 << 6) +#define HBP_THERM (1 << 7) + +//Port L bits: +#define X_MIN (1 << 0) +#define X_MAX (1 << 1) +#define Y_MIN (1 << 2) +#define Y_MAX (1 << 3) +#define HBP (1 << 4) +#define EXTRA_FET (1 << 5) +#define Z_MIN (1 << 6) +#define Z_MAX (1 << 7) + + +#include "emu.h" +#include "cpu/avr8/avr8.h" +#include "video/hd44780.h" +#include "rendlay.h" +#include "debugger.h" + +#define MASTER_CLOCK 16000000 + +/****************************************************\ +* I/O devices * +\****************************************************/ + +class replicator_state : public driver_device +{ +public: + replicator_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_lcdc(*this, "hd44780") + { + } + + virtual void machine_start(); + + UINT8 m_port_a; + UINT8 m_port_b; + UINT8 m_port_c; + UINT8 m_port_d; + UINT8 m_port_e; + UINT8 m_port_f; + UINT8 m_port_g; + UINT8 m_port_h; + UINT8 m_port_j; + UINT8 m_port_k; + UINT8 m_port_l; + + UINT8 shift_register_value; + + required_device<avr8_device> m_maincpu; + required_device<hd44780_device> m_lcdc; + + DECLARE_READ8_MEMBER(port_r); + DECLARE_WRITE8_MEMBER(port_w); + DECLARE_DRIVER_INIT(replicator); + virtual void machine_reset(); + virtual void palette_init(); +}; + +void replicator_state::machine_start() +{ +} + +READ8_MEMBER(replicator_state::port_r) +{ + switch( offset ) + { + case AVR8_IO_PORTA: + { +#if LOG_PORTS + printf("[%08X] Port A READ (A-axis signals + B-axis STEP&DIR)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTB: + { +#if LOG_PORTS + printf("[%08X] Port B READ (SD-CS; 1280-MISO/MOSI/SCK; EX2-FAN/HEAT/PWR-CHECK; BLINK)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTC: + { +#if LOG_PORTS + printf("[%08X] Port C READ (1280-EX1/EX2; LCD-signals; R&G-LED; DETECT)\n", m_maincpu->m_shifted_pc); +#endif + return DETECT; //indicated that the Interface board is present. + break; + } + case AVR8_IO_PORTD: + { +#if LOG_PORTS + printf("[%08X] Port D READ (SDA/SCL; 1280-EX-TX/RX)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTE: + { +#if LOG_PORTS + printf("[%08X] Port E READ (1280-TX/RX; THERMO-signals)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTF: + { +#if LOG_PORTS + printf("[%08X] Port F READ (X-axis & Y-axis signals)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTG: + { +#if LOG_PORTS + printf("[%08X] Port G READ (BUZZ; Cutoff-sr-check; B-axis EN; 1280-EX3/EX4)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTH: + { +#if LOG_PORTS + printf("[%08X] Port H READ (cuttoff-text/reset; EX1-FAN/HEAT/PWR-CHECK; SD-CD/SD-WP)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTJ: + { +#if LOG_PORTS + printf("[%08X] Port J READ (Interface buttons; POTS-SCL; B-axis-POT)\n", m_maincpu->m_shifted_pc); +#endif + return ioport("keypad")->read(); + break; + } + case AVR8_IO_PORTK: + { +#if LOG_PORTS + printf("[%08X] Port K READ (Z-axis signals; HBP-THERM; 1280-EX5/6/7)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + case AVR8_IO_PORTL: + { +#if LOG_PORTS + printf("[%08X] Port L READ (HBP; EXTRA-FET; X-MIN/MAX; Y-MIN/MAX; Z-MIN/MAX)\n", m_maincpu->m_shifted_pc); +#endif + return 0x00; + break; + } + } + return 0; +} + +WRITE8_MEMBER(replicator_state::port_w) +{ + switch( offset ) + { + case AVR8_IO_PORTA: + { + if (data == m_port_a) break; + +#if LOG_PORTS + UINT8 old_port_a = m_port_a; + UINT8 changed = data ^ old_port_a; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & A_AXIS_DIR) printf("[A] A_AXIS_DIR: %s\n", data & A_AXIS_DIR ? "HIGH" : "LOW"); + if(changed & A_AXIS_STEP) printf("[A] A_AXIS_STEP: %s\n", data & A_AXIS_STEP ? "HIGH" : "LOW"); + if(changed & A_AXIS_EN) printf("[A] A_AXIS_EN: %s\n", data & A_AXIS_EN ? "HIGH" : "LOW"); + if(changed & A_AXIS_POT) printf("[A] A_AXIS_POT: %s\n", data & A_AXIS_POT ? "HIGH" : "LOW"); + if(changed & B_AXIS_DIR) printf("[A] B_AXIS_DIR: %s\n", data & B_AXIS_DIR ? "HIGH" : "LOW"); + if(changed & B_AXIS_STEP) printf("[A] B_AXIS_STEP: %s\n", data & B_AXIS_STEP ? "HIGH" : "LOW"); +#endif + + m_port_a = data; + break; + } + case AVR8_IO_PORTB: + { + if (data == m_port_b) break; + +#if LOG_PORTS + UINT8 old_port_b = m_port_b; + UINT8 changed = data ^ old_port_b; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & SD_CS) printf("[B] SD Card Chip Select: %s\n", data & SD_CS ? "HIGH" : "LOW"); + if(changed & SCK_1280) printf("[B] 1280-SCK: %s\n", data & SCK_1280 ? "HIGH" : "LOW"); + if(changed & MOSI_1280) printf("[B] 1280-MOSI: %s\n", data & MOSI_1280 ? "HIGH" : "LOW"); + if(changed & MISO_1280) printf("[B] 1280-MISO: %s\n", data & MISO_1280 ? "HIGH" : "LOW"); + if(changed & EX2_PWR_CHECK) printf("[B] EX2-PWR-CHECK: %s\n", data & EX2_PWR_CHECK ? "HIGH" : "LOW"); + if(changed & EX2_HEAT) printf("[B] EX2_HEAT: %s\n", data & EX2_HEAT ? "HIGH" : "LOW"); + if(changed & EX2_FAN) printf("[B] EX2_FAN: %s\n", data & EX2_FAN ? "HIGH" : "LOW"); + if(changed & BLINK) printf("[B] BLINK: %s\n", data & BLINK ? "HIGH" : "LOW"); +#endif + + m_port_b = data; + break; + } + case AVR8_IO_PORTC: + { + if (data == m_port_c) break; + + UINT8 old_port_c = m_port_c; + UINT8 changed = data ^ old_port_c; +#if LOG_PORTS + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & EX2_1280) printf("[C] EX2_1280: %s\n", data & EX2_1280 ? "HIGH" : "LOW"); + if(changed & EX1_1280) printf("[C] EX1_1280: %s\n", data & EX1_1280 ? "HIGH" : "LOW"); + if(changed & LCD_CLK) printf("[C] LCD_CLK: %s\n", data & LCD_CLK ? "HIGH" : "LOW"); + if(changed & LCD_DATA) printf("[C] LCD_DATA: %s\n", data & LCD_DATA ? "HIGH" : "LOW"); + if(changed & LCD_STROBE) printf("[C] LCD_STROBE: %s\n", data & LCD_STROBE ? "HIGH" : "LOW"); + if(changed & RLED) printf("[C] RLED: %s\n", data & RLED ? "HIGH" : "LOW"); + if(changed & GLED) printf("[C] GLED: %s\n", data & GLED ? "HIGH" : "LOW"); + if(changed & DETECT) printf("[C] DETECT: %s\n", data & DETECT ? "HIGH" : "LOW"); +#endif + + if (changed & LCD_CLK){ + /* The LCD is interfaced by an 8-bit shift register (74HC4094). */ + if (data & LCD_CLK){//CLK positive edge + shift_register_value = (shift_register_value << 1) | ((data & LCD_DATA) >> 3); + //printf("[%08X] ", m_maincpu->m_shifted_pc); + //printf("[C] LCD CLK positive edge. shift_register=0x%02X\n", shift_register_value); + } + } + + if(changed & LCD_STROBE){ + if (data & LCD_STROBE){ //STROBE positive edge + bool RS = (shift_register_value >> 1) & 1; + bool RW = (shift_register_value >> 2) & 1; + bool enable = (shift_register_value >> 3) & 1; + UINT8 lcd_data = shift_register_value & 0xF0; + + if (enable && RW==0){ + if (RS==0){ + m_lcdc->control_write(space, 0, lcd_data); + } else { + m_lcdc->data_write(space, 0, lcd_data); + } + } + } + } + m_port_c = data; + + break; + } + case AVR8_IO_PORTD: + { + if (data == m_port_d) break; + +#if LOG_PORTS + UINT8 old_port_d = m_port_d; + UINT8 changed = data ^ old_port_d; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & PORTD_SCL) printf("[D] PORTD_SCL: %s\n", data & PORTD_SCL ? "HIGH" : "LOW"); + if(changed & PORTD_SDA) printf("[D] PORTD_SDA: %s\n", data & PORTD_SDA ? "HIGH" : "LOW"); + if(changed & EX_RX_1280) printf("[D] EX_RX_1280: %s\n", data & EX_RX_1280 ? "HIGH" : "LOW"); + if(changed & EX_TX_1280) printf("[D] EX_TX_1280: %s\n", data & EX_TX_1280 ? "HIGH" : "LOW"); +#endif + + m_port_d = data; + break; + } + case AVR8_IO_PORTE: + { + if (data == m_port_e) break; + +#if LOG_PORTS + UINT8 old_port_e = m_port_e; + UINT8 changed = data ^ old_port_e; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & RX_1280) printf("[E] 1280-RX: %s\n", data & RX_1280 ? "HIGH" : "LOW"); + if(changed & TX_1280) printf("[E] 1280-TX: %s\n", data & TX_1280 ? "HIGH" : "LOW"); + if(changed & THERMO_SCK) printf("[E] THERMO-SCK: %s\n", data & THERMO_SCK ? "HIGH" : "LOW"); + if(changed & THERMO_CS1) printf("[E] THERMO-CS1: %s\n", data & THERMO_CS1 ? "HIGH" : "LOW"); + if(changed & THERMO_CS2) printf("[E] THERMO-CS2: %s\n", data & THERMO_CS2 ? "HIGH" : "LOW"); + if(changed & THERMO_DO) printf("[E] THERMO-DO: %s\n", data & THERMO_DO ? "HIGH" : "LOW"); +#endif + + m_port_e = data; + break; + } + case AVR8_IO_PORTF: + { + if (data == m_port_f) break; + +#if LOG_PORTS + UINT8 old_port_f = m_port_f; + UINT8 changed = data ^ old_port_f; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & X_AXIS_DIR) printf("[F] X_AXIS_DIR: %s\n", data & X_AXIS_DIR ? "HIGH" : "LOW"); + if(changed & X_AXIS_STEP) printf("[F] X_AXIS_STEP: %s\n", data & X_AXIS_STEP ? "HIGH" : "LOW"); + if(changed & X_AXIS_EN) printf("[F] X_AXIS_EN: %s\n", data & X_AXIS_EN ? "HIGH" : "LOW"); + if(changed & X_AXIS_POT) printf("[F] X_AXIS_POT: %s\n", data & X_AXIS_POT ? "HIGH" : "LOW"); + if(changed & Y_AXIS_DIR) printf("[F] Y_AXIS_DIR: %s\n", data & Y_AXIS_DIR ? "HIGH" : "LOW"); + if(changed & Y_AXIS_STEP) printf("[F] Y_AXIS_STEP: %s\n", data & Y_AXIS_STEP ? "HIGH" : "LOW"); + if(changed & Y_AXIS_EN) printf("[F] Y_AXIS_EN: %s\n", data & Y_AXIS_EN ? "HIGH" : "LOW"); + if(changed & Y_AXIS_POT) printf("[F] Y_AXIS_POT: %s\n", data & Y_AXIS_POT ? "HIGH" : "LOW"); +#endif + + m_port_f = data; + break; + } + case AVR8_IO_PORTG: + { + if (data == m_port_g) break; + +#if LOG_PORTS + UINT8 old_port_g = m_port_g; + UINT8 changed = data ^ old_port_g; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & EX4_1280) printf("[G] EX4_1280: %s\n", data & EX4_1280 ? "HIGH" : "LOW"); + if(changed & EX3_1280) printf("[G] EX3_1280: %s\n", data & EX3_1280 ? "HIGH" : "LOW"); + if(changed & B_AXIS_EN) printf("[G] B_AXIS_EN: %s\n", data & B_AXIS_EN ? "HIGH" : "LOW"); + if(changed & CUTOFF_SR_CHECK) printf("[G] CUTOFF_SR_CHECK: %s\n", data & CUTOFF_SR_CHECK ? "HIGH" : "LOW"); + if(changed & BUZZ) printf("[G] BUZZ: %s\n", data & BUZZ ? "HIGH" : "LOW"); +#endif + + m_port_g = data; + break; + } + case AVR8_IO_PORTH: + { + if (data == m_port_h) break; + +#if LOG_PORTS + UINT8 old_port_h = m_port_h; + UINT8 changed = data ^ old_port_h; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + if(changed & CUTOFF_TEST) printf("[H] CUTOFF_TEST: %s\n", data & CUTOFF_TEST ? "HIGH" : "LOW"); + if(changed & CUTOFF_RESET) printf("[H] CUTOFF_RESET: %s\n", data & CUTOFF_RESET ? "HIGH" : "LOW"); + if(changed & EX1_PWR_CHECK) printf("[H] EX1_PWR_CHECK: %s\n", data & EX1_PWR_CHECK ? "HIGH" : "LOW"); + if(changed & EX1_HEAT) printf("[H] EX1_HEAT: %s\n", data & EX1_HEAT ? "HIGH" : "LOW"); + if(changed & EX1_FAN) printf("[H] EX1_FAN: %s\n", data & EX1_FAN ? "HIGH" : "LOW"); + if(changed & SD_WP) printf("[H] SD_WP: %s\n", data & SD_WP ? "HIGH" : "LOW"); + if(changed & SD_CD) printf("[H] SD_CD: %s\n", data & SD_CD ? "HIGH" : "LOW"); +#endif + + m_port_h = data; + break; + } + case AVR8_IO_PORTJ: + { + if (data == m_port_j) break; + +#if LOG_PORTS + UINT8 old_port_j = m_port_j; + UINT8 changed = data ^ old_port_j; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + + if(changed & BUTTON_CENTER) printf("[J] BUTTON_CENTER: %s\n", data & BUTTON_CENTER ? "HIGH" : "LOW"); + if(changed & BUTTON_RIGHT) printf("[J] BUTTON_RIGHT: %s\n", data & BUTTON_RIGHT ? "HIGH" : "LOW"); + if(changed & BUTTON_LEFT) printf("[J] BUTTON_LEFT: %s\n", data & BUTTON_LEFT ? "HIGH" : "LOW"); + if(changed & BUTTON_DOWN) printf("[J] BUTTON_DOWN: %s\n", data & BUTTON_DOWN ? "HIGH" : "LOW"); + if(changed & BUTTON_UP) printf("[J] BUTTON_UP: %s\n", data & BUTTON_UP ? "HIGH" : "LOW"); + if(changed & POTS_SCL) printf("[J] POTS_SCL: %s\n", data & POTS_SCL ? "HIGH" : "LOW"); + if(changed & B_AXIS_POT) printf("[J] B_AXIS_POT: %s\n", data & B_AXIS_POT ? "HIGH" : "LOW"); +#endif + + m_port_j = data; + break; + } + case AVR8_IO_PORTK: + { + if (data == m_port_k) break; + +#if LOG_PORTS + UINT8 old_port_k = m_port_k; + UINT8 changed = data ^ old_port_k; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + + if(changed & Z_AXIS_DIR) printf("[K] Z_AXIS_DIR: %s\n", data & Z_AXIS_DIR ? "HIGH" : "LOW"); + if(changed & Z_AXIS_STEP) printf("[K] Z_AXIS_STEP: %s\n", data & Z_AXIS_STEP ? "HIGH" : "LOW"); + if(changed & Z_AXIS_EN) printf("[K] Z_AXIS_EN: %s\n", data & Z_AXIS_EN ? "HIGH" : "LOW"); + if(changed & Z_AXIS_POT) printf("[K] Z_AXIS_POT: %s\n", data & Z_AXIS_POT ? "HIGH" : "LOW"); + if(changed & EX7_1280) printf("[K] EX7_1280: %s\n", data & EX7_1280 ? "HIGH" : "LOW"); + if(changed & EX6_1280) printf("[K] EX6_1280: %s\n", data & EX6_1280 ? "HIGH" : "LOW"); + if(changed & EX5_1280) printf("[K] EX5_1280: %s\n", data & EX5_1280 ? "HIGH" : "LOW"); + if(changed & HBP_THERM) printf("[K] HBP_THERM: %s\n", data & HBP_THERM ? "HIGH" : "LOW"); +#endif + + m_port_k = data; + break; + } + case AVR8_IO_PORTL: + { + if (data == m_port_l) break; + +#if LOG_PORTS + UINT8 old_port_l = m_port_l; + UINT8 changed = data ^ old_port_l; + + printf("[%08X] ", m_maincpu->m_shifted_pc); + + if(changed & X_MIN) printf("[L] X_MIN: %s\n", data & X_MIN ? "HIGH" : "LOW"); + if(changed & X_MAX) printf("[L] X_MAX: %s\n", data & X_MAX ? "HIGH" : "LOW"); + if(changed & Y_MIN) printf("[L] Y_MIN: %s\n", data & Y_MIN ? "HIGH" : "LOW"); + if(changed & Y_MAX) printf("[L] Y_MAX: %s\n", data & Y_MAX ? "HIGH" : "LOW"); + if(changed & HBP) printf("[L] HBP: %s\n", data & HBP ? "HIGH" : "LOW"); + if(changed & EXTRA_FET) printf("[L] EXTRA_FET: %s\n", data & EXTRA_FET ? "HIGH" : "LOW"); + if(changed & Z_MIN) printf("[L] Z_MIN: %s\n", data & Z_MIN ? "HIGH" : "LOW"); + if(changed & Z_MAX) printf("[L] Z_MAX: %s\n", data & Z_MAX ? "HIGH" : "LOW"); +#endif + + m_port_l = data; + break; + } + } +} + +/****************************************************\ +* Address maps * +\****************************************************/ + +static ADDRESS_MAP_START( replicator_prg_map, AS_PROGRAM, 8, replicator_state ) + AM_RANGE(0x0000, 0x1FFFF) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( replicator_data_map, AS_DATA, 8, replicator_state ) + AM_RANGE(0x0200, 0x21FF) AM_RAM /* ATMEGA1280 Internal SRAM */ +ADDRESS_MAP_END + +static ADDRESS_MAP_START( replicator_io_map, AS_IO, 8, replicator_state ) + AM_RANGE(AVR8_IO_PORTA, AVR8_IO_PORTL) AM_READWRITE( port_r, port_w ) +ADDRESS_MAP_END + +/****************************************************\ +* Input ports * +\****************************************************/ + +static INPUT_PORTS_START( replicator ) + PORT_START("keypad") + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CENTER") PORT_CODE(KEYCODE_M) + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_D) + PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LEFT") PORT_CODE(KEYCODE_A) + PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DOWN") PORT_CODE(KEYCODE_S) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("UP") PORT_CODE(KEYCODE_W) +INPUT_PORTS_END + +/****************************************************\ +* Machine definition * +\****************************************************/ + +DRIVER_INIT_MEMBER(replicator_state, replicator) +{ +} + +void replicator_state::machine_reset() +{ + shift_register_value = 0; + m_port_a = 0; + m_port_b = 0; + m_port_c = 0; + m_port_d = 0; + m_port_e = 0; + m_port_f = 0; + m_port_g = 0; + m_port_h = 0; + m_port_j = 0; + m_port_k = 0; + m_port_l = 0; +} + +const avr8_config atmega1280_config = +{ + "eeprom" +}; + +void replicator_state::palette_init() +{ +//These colors were picked with the color picker in Inkscape, based on a photo of the LCD used in the Replicator 1 3d printer: + palette_set_color(machine(), 0, MAKE_RGB(0xCA, 0xE7, 0xEB)); + palette_set_color(machine(), 1, MAKE_RGB(0x78, 0xAB, 0xA8)); +} + +static const gfx_layout hd44780_charlayout = +{ + 5, 8, /* 5 x 8 characters */ + 256, /* 256 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + { 3, 4, 5, 6, 7}, + { 0, 8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8}, + 8*8 /* 8 bytes */ +}; + +static GFXDECODE_START( replicator ) + GFXDECODE_ENTRY( "hd44780:cgrom", 0x0000, hd44780_charlayout, 0, 1 ) +GFXDECODE_END + +static MACHINE_CONFIG_START( replicator, replicator_state ) + + MCFG_CPU_ADD("maincpu", ATMEGA1280, MASTER_CLOCK) + MCFG_CPU_AVR8_CONFIG(atmega1280_config) + MCFG_CPU_PROGRAM_MAP(replicator_prg_map) + MCFG_CPU_DATA_MAP(replicator_data_map) + MCFG_CPU_IO_MAP(replicator_io_map) + + MCFG_CPU_AVR8_LFUSE(0xFF) + MCFG_CPU_AVR8_HFUSE(0xDA) + MCFG_CPU_AVR8_EFUSE(0xF4) + MCFG_CPU_AVR8_LOCK(0x0F) + + /*TODO: Add an ATMEGA8U2 for USB-Serial communications */ + + /* video hardware */ + MCFG_SCREEN_ADD("screen", LCD) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ + MCFG_SCREEN_UPDATE_DEVICE("hd44780", hd44780_device, screen_update) + MCFG_SCREEN_SIZE(120, 18*2) //4x20 chars + MCFG_SCREEN_VISIBLE_AREA(0, 120-1, 0, 18*2-1) + + MCFG_PALETTE_LENGTH(2) + MCFG_GFXDECODE(replicator) + MCFG_DEFAULT_LAYOUT(layout_lcd) + + MCFG_HD44780_ADD("hd44780") + MCFG_HD44780_LCD_SIZE(4, 20) + + /*TODO: + Add sound config: + - A buzzer connected to the PG5 pin that is driven by Timer/Counter #4 + */ + +MACHINE_CONFIG_END + +ROM_START( replica1 ) + ROM_REGION( 0x20000, "maincpu", 0 ) /* Main program store */ + ROM_LOAD( "mighty_one_v7.5.0.bin", 0x0000, 0x1EF9A, CRC(0d36d9e7) SHA1(a53899775b4c4eea87b6903758ebb75f06710a69) ) /*Sailfish firmware image - Metamaquian build v7.5 */ + ROM_LOAD( "atmegaboot_168_atmega1280.bin", 0x1F000, 0x0F16, CRC(c041f8db) SHA1(d995ebf360a264cccacec65f6dc0c2257a3a9224) ) /*Arduino MEGA bootloader*/ + + ROM_REGION( 0x1000, "eeprom", ROMREGION_ERASEFF ) /* on-die 4kbyte eeprom */ + //ROM_LOAD( "eeprom.raw", 0x0000, 0x1000, CRC(c71c0011) SHA1(1ceaf73df40e531df3bfb26b4fb7cd95fb7bff1d) ) /* blank EEPROM data */ +ROM_END + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ +CONS(2012, replica1, 0, 0, replicator, replicator, replicator_state, replicator, "Makerbot", "Replicator 1 desktop 3d printer", GAME_NOT_WORKING|GAME_NO_SOUND) diff --git a/src/mess/mess.lst b/src/mess/mess.lst index 81126325205..9bd56a4a377 100644 --- a/src/mess/mess.lst +++ b/src/mess/mess.lst @@ -309,6 +309,9 @@ wofch // CPS Changer (Tenchi Wo Kurau II) odyssey2 // Magnavox Odyssey 2 - 1978-1983 odyssey3 // Magnavox Odyssey 3 / Command Center (prototype) +// Makerbot +replica1 // Makerbot Replicator 1 desktop 3d printer + // Hartung, Watara, ... gmaster // Hartung Gamemaster diff --git a/src/mess/mess.mak b/src/mess/mess.mak index e2309604a3a..d6207f4e0e1 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -598,6 +598,7 @@ DRVLIBS += \ $(MESSOBJ)/kyocera.a \ $(MESSOBJ)/luxor.a \ $(MESSOBJ)/magnavox.a \ + $(MESSOBJ)/makerbot.a \ $(MESSOBJ)/matsushi.a \ $(MESSOBJ)/mattel.a \ $(MESSOBJ)/mb.a \ @@ -1398,6 +1399,9 @@ $(MESSOBJ)/luxor.a: \ $(MESSOBJ)/magnavox.a: \ $(MESS_DRIVERS)/odyssey2.o \ +$(MESSOBJ)/makerbot.a: \ + $(MESS_DRIVERS)/replicator.o \ + $(MESSOBJ)/mattel.a: \ $(MESS_DRIVERS)/aquarius.o \ $(MESS_VIDEO)/aquarius.o \ diff --git a/src/targets/mess.lst b/src/targets/mess.lst index 86c75733479..51d297f2636 100644 --- a/src/targets/mess.lst +++ b/src/targets/mess.lst @@ -399,6 +399,9 @@ @magnavox /mess/drivers/odyssey2 +@makerbot +/mess/drivers/replicator + @mattel /mess/drivers/aquarius /mess/drivers/juicebox |