summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Ryan Holtz <ryan.holtz@arrowheadgs.com>2020-07-16 16:07:06 +0200
committer Ryan Holtz <ryan.holtz@arrowheadgs.com>2020-07-16 16:10:58 +0200
commita20013147862dc9381860e97692546690db7e319 (patch)
tree669e52e8ddce41e4069384eb12308534177bdad1
parentb2aba645fbded4a58c0f5391d3c73fed203299af (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.lua1
-rw-r--r--src/devices/cpu/avr8/avr8.cpp74
-rw-r--r--src/mame/drivers/lft_craft.cpp4
-rw-r--r--src/mame/drivers/lft_phasor.cpp266
-rw-r--r--src/mame/mame.lst3
-rw-r--r--src/mame/mess.flt1
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