diff options
| author | 2020-07-16 16:07:06 +0200 | |
|---|---|---|
| committer | 2020-07-16 16:10:58 +0200 | |
| commit | a20013147862dc9381860e97692546690db7e319 (patch) | |
| tree | 669e52e8ddce41e4069384eb12308534177bdad1 | |
| parent | b2aba645fbded4a58c0f5391d3c73fed203299af (diff) | |
-avr8: Added support for Timer 1 'Fast PWM with ICR' mode. [Ryan Holtz]
New working machines
--------------------
Phasor [Ryan Holtz]
| -rw-r--r-- | scripts/target/mame/mess.lua | 1 | ||||
| -rw-r--r-- | src/devices/cpu/avr8/avr8.cpp | 74 | ||||
| -rw-r--r-- | src/mame/drivers/lft_craft.cpp | 4 | ||||
| -rw-r--r-- | src/mame/drivers/lft_phasor.cpp | 266 | ||||
| -rw-r--r-- | src/mame/mame.lst | 3 | ||||
| -rw-r--r-- | src/mame/mess.flt | 1 |
6 files changed, 344 insertions, 5 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 32c549c15ca..65d23dcfc92 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2501,6 +2501,7 @@ files { MAME_DIR .. "src/mame/drivers/68ksbc.cpp", MAME_DIR .. "src/mame/drivers/lft_chiptune.cpp", MAME_DIR .. "src/mame/drivers/lft_craft.cpp", + MAME_DIR .. "src/mame/drivers/lft_phasor.cpp", MAME_DIR .. "src/mame/drivers/dcebridge.cpp", MAME_DIR .. "src/mame/drivers/homez80.cpp", MAME_DIR .. "src/mame/drivers/p112.cpp", diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp index ab00d9bd804..cbd56d599e8 100644 --- a/src/devices/cpu/avr8/avr8.cpp +++ b/src/devices/cpu/avr8/avr8.cpp @@ -1376,10 +1376,9 @@ inline void avr8_device::timer1_tick() static const uint8_t s_ocf1[2] = { (1 << AVR8_TIFR1_OCF1A_SHIFT), (1 << AVR8_TIFR1_OCF1B_SHIFT) }; static const uint8_t s_int1[2] = { AVR8_INTIDX_OCF1A, AVR8_INTIDX_OCF1B }; + const uint16_t icr1 = AVR8_ICR1; int32_t increment = m_timer_increment[1]; - LOGMASKED(LOG_TIMER1_TICK, "%s: AVR8_WGM1: %d\n", machine().describe_context(), AVR8_WGM1); - for (int32_t reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++) { switch (m_wgm1) @@ -1484,10 +1483,79 @@ inline void avr8_device::timer1_tick() m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) & ~(2 << reg)); break; } + } + break; + + case WGM1_FAST_PWM_ICR: + if (m_timer1_count == m_ocr1[reg]) + { + switch (m_timer1_compare_mode[reg] & 3) + { + case 0: /* Normal Operation; OC1A/B disconnected */ + break; + + case 1: /* Toggle OC1A on compare match */ + if (reg == 0) + { + LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1%c on match\n", machine().describe_context()); + m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) ^ (2 << reg)); + } + break; - m_r[AVR8_REGIDX_TIFR1] &= ~s_ocf1[reg]; + case 2: /* Clear OC1A/B on compare match */ + LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1%c on match\n", machine().describe_context(), reg ? 'B' : 'A'); + m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) & ~(2 << reg)); + break; + + case 3: /* Set OC1A/B on compare match */ + LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1%c on match\n", machine().describe_context(), reg ? 'B' : 'A'); + m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) | (2 << reg)); + break; + } + + m_r[AVR8_REGIDX_TIFR1] |= s_ocf1[reg]; update_interrupt(s_int1[reg]); } + else if (m_timer1_count == 0) + { + if (reg == 0) + { + m_r[AVR8_REGIDX_TIFR1] &= ~AVR8_TIFR1_TOV1_MASK; + update_interrupt(AVR8_INTIDX_TOV1); + } + + switch (m_timer1_compare_mode[reg] & 3) + { + case 0: /* Normal Operation; OC1A/B disconnected */ + break; + + case 1: /* Toggle OC1A at BOTTOM*/ + if (reg == 0) + { + LOGMASKED(LOG_TIMER1, "%s: timer1: Toggle OC1A at BOTTOM\n", machine().describe_context()); + m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) ^ (2 << reg)); + } + break; + + case 2: /* Set OC1A/B at BOTTOM*/ + LOGMASKED(LOG_TIMER1, "%s: timer1: Set OC1%c at BOTTOM\n", machine().describe_context(), reg ? 'B' : 'A'); + m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) | (2 << reg)); + break; + + case 3: /* Clear OC1A/B at BOTTOM */ + LOGMASKED(LOG_TIMER1, "%s: timer1: Clear OC1%c at BOTTOM\n", machine().describe_context(), reg ? 'B' : 'A'); + m_io->write_byte(AVR8_IO_PORTB, m_io->read_byte(AVR8_IO_PORTB) & ~(2 << reg)); + break; + } + } + + if (m_timer1_count == icr1 && reg == 1) + { + m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK; + update_interrupt(AVR8_INTIDX_TOV1); + m_timer1_count = 0; + increment = 0; + } break; default: diff --git a/src/mame/drivers/lft_craft.cpp b/src/mame/drivers/lft_craft.cpp index 7ef48745cf0..d965d0a2327 100644 --- a/src/mame/drivers/lft_craft.cpp +++ b/src/mame/drivers/lft_craft.cpp @@ -2,7 +2,7 @@ // copyright-holders:Ryan Holtz /********************************************************************** - ATmega88-based demo platform by Linus Ã…kesson + Craft, an ATmega88-based demo by Linus Ãkesson **********************************************************************/ @@ -243,4 +243,4 @@ ROM_START( craft ) ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */ -CONS(2008, craft, 0, 0, craft, empty_input, lft_craft_state, empty_init, "Linus Ã…kesson", "Craft", MACHINE_IMPERFECT_GRAPHICS) +CONS(2008, craft, 0, 0, craft, empty_input, lft_craft_state, empty_init, "Linus Ãkesson", "Craft", MACHINE_IMPERFECT_GRAPHICS) diff --git a/src/mame/drivers/lft_phasor.cpp b/src/mame/drivers/lft_phasor.cpp new file mode 100644 index 00000000000..d6d4dffd0e2 --- /dev/null +++ b/src/mame/drivers/lft_phasor.cpp @@ -0,0 +1,266 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/********************************************************************** + + Phasor, an ATmega88-based demo by Linus Ãkesson + +**********************************************************************/ + +#include "emu.h" +#include "cpu/avr8/avr8.h" +#include "sound/dac.h" +#include "sound/volt_reg.h" +#include "screen.h" +#include "emupal.h" +#include "speaker.h" + +#define MASTER_CLOCK 17734470 + +#define SAMPLES_PER_FRAME (355255) + +class lft_phasor_state : public driver_device +{ +public: + lft_phasor_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_dac(*this, "dac") + , m_screen(*this, "screen") + , m_palette(*this, "palette") + { + } + + void phasor(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + + void prg_map(address_map &map); + void data_map(address_map &map); + void io_map(address_map &map); + + uint8_t port_r(offs_t offset); + void port_w(offs_t offset, uint8_t data); + + void init_palette(palette_device &palette) const; + void video_update(); + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + required_device<avr8_device> m_maincpu; + required_device<dac_byte_interface> m_dac; + required_device<screen_device> m_screen; + required_device<palette_device> m_palette; + + enum port : uint8_t + { + PORT_A, + PORT_B, + PORT_C, + PORT_D, + + PORT_COUNT + }; + + uint8_t m_ports[PORT_COUNT]; + + uint64_t m_last_cycles; + uint64_t m_frame_start_cycle; + + uint8_t m_latched_sample; + bool m_in_blanking; + uint64_t m_blanking_start; + uint32_t m_sample_x; + uint32_t m_sample_y; + std::unique_ptr<uint8_t[]> m_samples; +}; + +//************************************************************************** +// GPIO +//************************************************************************** + +uint8_t lft_phasor_state::port_r(offs_t offset) +{ + return m_ports[offset]; +} + +void lft_phasor_state::port_w(offs_t offset, uint8_t data) +{ + m_ports[offset] = data; + + switch (offset) + { + case AVR8_IO_PORTB: + video_update(); + break; + + case AVR8_IO_PORTC: + m_dac->write(data & 0x3f); + break; + + case AVR8_IO_PORTD: + //video_update(); + m_latched_sample = data; + break; + } +} + +//************************************************************************** +// MEMORY +//************************************************************************** + +void lft_phasor_state::prg_map(address_map &map) +{ + map(0x0000, 0x1fff).rom(); +} + +void lft_phasor_state::data_map(address_map &map) +{ + map(0x0100, 0x04ff).ram(); +} + +void lft_phasor_state::io_map(address_map &map) +{ + map(AVR8_IO_PORTA, AVR8_IO_PORTD).rw(FUNC(lft_phasor_state::port_r), FUNC(lft_phasor_state::port_w)); +} + +//************************************************************************** +// VIDEO +//************************************************************************** + +void lft_phasor_state::init_palette(palette_device &palette) const +{ + for (int i = 0; i < 0x10; i++) + { + uint8_t gray = (uint8_t)i; + gray |= gray << 4; + palette.set_pen_color(i, rgb_t(gray, gray, gray)); + } +} + +void lft_phasor_state::video_update() +{ + const uint64_t cycles = machine().time().as_ticks(MASTER_CLOCK); + + if (cycles == m_last_cycles) + return; + + if (m_latched_sample == 0 && !m_in_blanking) + { + m_in_blanking = true; + m_blanking_start = cycles; + } + else if (m_latched_sample != 0 && m_in_blanking) + { + m_in_blanking = false; + const uint64_t blank_duration = cycles - m_blanking_start; + if (blank_duration < 80) // Approximate length of hblank + { + m_sample_y++; + m_sample_x = 0; + } + else + { + m_sample_y = 0; + m_sample_x = 0; + m_frame_start_cycle = machine().time().as_ticks(MASTER_CLOCK); + } + } + + if (m_last_cycles < cycles && !m_in_blanking) + { + const uint8_t shift = (m_ports[PORT_B] & 4); + uint32_t sample_pix = m_sample_y * 1135 + m_sample_x; + for (uint64_t idx = m_last_cycles; idx < cycles && sample_pix < SAMPLES_PER_FRAME; idx++) + { + m_samples[sample_pix++] = (m_latched_sample >> shift) & 0x0f; + m_sample_x++; + } + } + + m_last_cycles = cycles; +} + +uint32_t lft_phasor_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + const pen_t *pens = m_palette->pens(); + for(int y = 0; y < 313; y++) + { + uint32_t *dst = &bitmap.pix32(y); + uint8_t *src = &m_samples[y * 1135]; + for(int x = 0; x < 1135; x++) + { + *dst++ = pens[*src++]; + } + } + return 0; +} + +//************************************************************************** +// MACHINE +//************************************************************************** + +static INPUT_PORTS_START( empty_input ) +INPUT_PORTS_END + +void lft_phasor_state::machine_start() +{ + m_samples = std::make_unique<uint8_t[]>(SAMPLES_PER_FRAME); + + save_item(NAME(m_ports)); + save_item(NAME(m_last_cycles)); + save_item(NAME(m_frame_start_cycle)); + + save_item(NAME(m_latched_sample)); + save_item(NAME(m_in_blanking)); + save_item(NAME(m_blanking_start)); + save_item(NAME(m_sample_x)); + save_item(NAME(m_sample_y)); + save_pointer(NAME(m_samples), SAMPLES_PER_FRAME); +} + +void lft_phasor_state::machine_reset() +{ + memset(m_ports, 0, PORT_COUNT); + + m_frame_start_cycle = 0; + m_last_cycles = 0; + + m_latched_sample = 0; + m_in_blanking = true; + m_blanking_start = 0; + m_sample_x = 0; + m_sample_y = 0; + memset(&m_samples[0], 0, SAMPLES_PER_FRAME); +} + +void lft_phasor_state::phasor(machine_config &config) +{ + ATMEGA88(config, m_maincpu, MASTER_CLOCK); + m_maincpu->set_addrmap(AS_PROGRAM, &lft_phasor_state::prg_map); + m_maincpu->set_addrmap(AS_DATA, &lft_phasor_state::data_map); + m_maincpu->set_addrmap(AS_IO, &lft_phasor_state::io_map); + m_maincpu->set_eeprom_tag("eeprom"); + + PALETTE(config, m_palette, FUNC(lft_phasor_state::init_palette), 0x10); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(MASTER_CLOCK, 1135, 0, 1064, 313, 6, 310); + m_screen->set_screen_update(FUNC(lft_phasor_state::screen_update)); + + SPEAKER(config, "avr8").front_center(); + voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref", 0)); + vref.add_route(0, m_dac, 1.0, DAC_VREF_POS_INPUT); + vref.add_route(0, m_dac, -1.0, DAC_VREF_NEG_INPUT); + + DAC_6BIT_R2R(config, m_dac, 0).add_route(0, "avr8", 0.5); +} + +ROM_START( phasor ) + ROM_REGION( 0x2000, "maincpu", 0 ) + ROM_LOAD( "phasor.bin", 0x0000, 0x2000, CRC(300ef49b) SHA1(36b26137f5e8359dc9c2b746621a98bdd6634d2f) ) + ROM_REGION( 0x200, "eeprom", 0 ) + ROM_LOAD( "eeprom.raw", 0x0000, 0x0200, CRC(49036547) SHA1(d98c4d02771e80499c56dd71ad3d07597102f9b7) ) +ROM_END + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */ +CONS(2010, phasor, 0, 0, phasor, empty_input, lft_phasor_state, empty_init, "Linus Ãkesson", "Phasor", MACHINE_IMPERFECT_GRAPHICS) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 16e6335b766..7954540088a 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -19366,6 +19366,9 @@ hwchiptn // The Hardware Chiptune Project, by [lft] and k @source:lft_craft.cpp craft // Craft, by [lft] (2008) +@source:lft_phasor.cpp +phasor // Phasor, by [lft] (2010) + @source:lg-dvd.cpp lggp40 // diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 1775631c5b7..8997cfc60ba 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -495,6 +495,7 @@ lee1214.cpp lft.cpp lft_chiptune.cpp lft_craft.cpp +lft_phasor.cpp lg-dvd.cpp lilith.cpp lisa.cpp |
