summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Felipe Corrêa da Silva Sanches <juca@members.fsf.org>2017-10-07 15:59:35 -0300
committer Vas Crabb <cuavas@users.noreply.github.com>2020-10-30 02:03:36 +1100
commitc82bdb636a691823c98da8601e686fdad0cc3bb9 (patch)
treef1deaabf9d436fb7cc0afd1ccc0ad90b133ae20c
parentdaf9e638a04fcceeb3f7d23b3efae3dfd68c4ea2 (diff)
new driver: TecToy Pense Bem (2017)
Equivalent to VTech Smart Start from the 80s.
-rw-r--r--scripts/target/mame/mess.lua5
-rw-r--r--src/devices/cpu/avr8/avr8.cpp57
-rw-r--r--src/devices/cpu/avr8/avr8.h13
-rw-r--r--src/mame/drivers/pensebem.cpp320
-rw-r--r--src/mame/mame.lst3
5 files changed, 398 insertions, 0 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 960fac3996d..d3ddb169b2a 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -3785,6 +3785,11 @@ files {
MAME_DIR .. "src/mame/video/comquest.cpp",
}
+createMESSProjects(_target, _subtarget, "tectoy")
+files {
+ MAME_DIR .. "src/mame/drivers/pensebem.cpp",
+}
+
createMESSProjects(_target, _subtarget, "tektroni")
files {
MAME_DIR .. "src/mame/drivers/tek405x.cpp",
diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp
index cbd56d599e8..de75492ee7d 100644
--- a/src/devices/cpu/avr8/avr8.cpp
+++ b/src/devices/cpu/avr8/avr8.cpp
@@ -593,6 +593,7 @@ static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' };
//**************************************************************************
DEFINE_DEVICE_TYPE(ATMEGA88, atmega88_device, "atmega88", "Atmel ATmega88")
+DEFINE_DEVICE_TYPE(ATMEGA168, atmega168_device, "atmega168", "Atmel ATmega168")
DEFINE_DEVICE_TYPE(ATMEGA328, atmega328_device, "atmega328", "Atmel ATmega328")
DEFINE_DEVICE_TYPE(ATMEGA644, atmega644_device, "atmega644", "Atmel ATmega644")
DEFINE_DEVICE_TYPE(ATMEGA1280, atmega1280_device, "atmega1280", "Atmel ATmega1280")
@@ -608,6 +609,11 @@ void atmega88_device::atmega88_internal_map(address_map &map)
map(0x0000, 0x00ff).rw(FUNC(atmega88_device::regs_r), FUNC(atmega88_device::regs_w));
}
+void atmega168_device::atmega168_internal_map(address_map &map)
+{
+ map(0x0000, 0x00ff).rw(FUNC(atmega168_device::regs_r), FUNC(atmega168_device::regs_w));
+}
+
void atmega328_device::atmega328_internal_map(address_map &map)
{
map(0x0000, 0x00ff).rw(FUNC(atmega328_device::regs_r), FUNC(atmega328_device::regs_w));
@@ -643,6 +649,15 @@ atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag,
}
//-------------------------------------------------
+// atmega168_device - constructor
+//-------------------------------------------------
+
+atmega168_device::atmega168_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : avr8_device(mconfig, tag, owner, clock, ATMEGA168, 0x1fff, address_map_constructor(FUNC(atmega168_device::atmega168_internal_map), this), 3)
+{
+}
+
+//-------------------------------------------------
// atmega328_device - constructor
//-------------------------------------------------
@@ -1098,6 +1113,23 @@ void avr8_device::update_interrupt(int source)
}
}
+//TODO: review this!
+void atmega168_device::update_interrupt(int source)
+{
+ const interrupt_condition &condition = s_int_conditions[source];
+
+ int intstate = 0;
+ if (m_r[condition.m_intreg] & condition.m_intmask)
+ intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0;
+
+ set_irq_line(condition.m_intindex << 1, intstate);
+
+ if (intstate)
+ {
+ m_r[condition.m_regindex] &= ~condition.m_regmask;
+ }
+}
+
void atmega328_device::update_interrupt(int source)
{
const interrupt_condition &condition = s_int_conditions[source];
@@ -1401,6 +1433,31 @@ inline void avr8_device::timer1_tick()
m_timer1_count = 0;
increment = 0;
}
+
+ 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;
+
+ 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]);
}
diff --git a/src/devices/cpu/avr8/avr8.h b/src/devices/cpu/avr8/avr8.h
index 8fde28f55d8..fc3b6be5a94 100644
--- a/src/devices/cpu/avr8/avr8.h
+++ b/src/devices/cpu/avr8/avr8.h
@@ -298,6 +298,7 @@ protected:
// device type definition
DECLARE_DEVICE_TYPE(ATMEGA88, atmega88_device)
+DECLARE_DEVICE_TYPE(ATMEGA168, atmega168_device)
DECLARE_DEVICE_TYPE(ATMEGA328, atmega328_device)
DECLARE_DEVICE_TYPE(ATMEGA644, atmega644_device)
DECLARE_DEVICE_TYPE(ATMEGA1280, atmega1280_device)
@@ -314,6 +315,18 @@ public:
void atmega88_internal_map(address_map &map);
};
+// ======================> atmega168_device
+
+class atmega168_device : public avr8_device
+{
+public:
+ // construction/destruction
+ atmega168_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void update_interrupt(int source) override;
+ void atmega168_internal_map(address_map &map);
+};
+
// ======================> atmega328_device
class atmega328_device : public avr8_device
diff --git a/src/mame/drivers/pensebem.cpp b/src/mame/drivers/pensebem.cpp
new file mode 100644
index 00000000000..fbdc9fcd803
--- /dev/null
+++ b/src/mame/drivers/pensebem.cpp
@@ -0,0 +1,320 @@
+// license:GPL-2.0+
+// copyright-holders:Felipe Sanches
+/*
+ Pense Bem (TecToy 2017)
+ driver by Felipe Correa da Silva Sanches <juca@members.fsf.org>
+
+---------------------------------------------------------------------
+
+ In the 80s Tec Toy released Pense Bem in Brazil. It is most
+ likely identical to VTech Smart Start since I think they run the
+ exact same Z8 code. The only difference must be branding in the
+ handheld case.
+
+ In 2017 Tec Toy re-released Pense Bem in Brazil but this time
+ using an Atmel ATMEGA168PB chip. It is not clear if the ATMEGA
+ code contains a copy of the Z8 ROM and emulates the Z8, or if
+ Tec Toy ported the original Z8 code retargetting it to the
+ Atmel chip. Or even if they simply reimplemented the full
+ functionality from scratch.
+
+ Inspecting the ATMEGA disasm, it does not look like an emulation
+ of the original Z8 code, but further research would be needed
+ to be sure.
+
+ As of October 2020, there's still no successfull ROM dump of the
+ original Pense Bem's Z8 ROM code, so this driver only emulates
+ the 2017 re-release.
+
+---------------------------------------------------------------------
+
+ The 2017 edition of TecToy's Pense Bem has a 2x4 programming
+ pin-header at position CN4:
+
+ CN4 - ATMEGA
+ 1 - 4 VCC
+ 2 - 15 MOSI
+ 3 - 31 TXD
+ 4 - 16 MISO
+ 5 - 30 RXD
+ 6 - 17 SCK
+ 7 - 5 GND
+ 8 - 29 RESET
+
+ R34 is the pull-up resistor for the RESET signal
+
+---------------------------------------------------------------------
+
+ Changelog:
+
+ 2020 OCT 27 [Felipe Sanches]:
+ * Fixed keyboard inputs, display & buzzer.
+ * Implementation of AVR8 Timer 1 Output Compare Match A is
+ sub-optimal resulting in bad sound quality when emulating
+ the buzzer.
+
+ 2017 OCT 07 [Felipe Sanches]:
+ * Initial driver skeleton
+
+---------------------------------------------------------------------
+
+== Notes about the hardware: ==
+=== Select keypad rows: ===
+keypad pin 1 - PORT_B5
+keypad pin 2 - PORT_B3
+keypad pin 12 - PORT_B2
+keypad pin 13 - PORT_B4
+
+=== Read keypad Columns: ===
+keypad pin 3 - PORT_E0
+keypad pin 4 - PORT_D2
+keypad pin 5 - PORT_E1
+keypad pin 6 - PORT_D7
+keypad pin 7 - PORT_D6
+keypad pin 8 - PORT_D5
+keypad pin 9 - PORT_D4
+keypad pin 10 - PORT_D3
+
+=== Display digits: ===
+digit_7 - PORT_E2
+digit_6 - PORT_E3
+digit_5 - PORT_C0
+digit_4 - PORT_C1
+digit_3 - PORT_C2
+digit_2 - PORT_C3
+digit_1 - PORT_C4
+digit_0 - PORT_C5
+
+=== Display segments: ===
+In parentheses are the resistor reference numbers on
+the PCB for each of these signals.
+
+seg_7 (R11) - PORT_D7
+seg_6 (R12) - PORT_D6
+seg_5 (R17) - PORT_D5
+seg_4 (R13) - PORT_D4
+seg_3 (R14) - PORT_D3
+seg_2 (R15) - PORT_D2
+seg_1 (R18) - PORT_E1
+seg_0 (R16) - PORT_E0
+
+=== Piezo buzzer: ===
+Port B, bit 1
+
+--------------------------------------------------------------------- */
+
+#include "emu.h"
+#include "cpu/avr8/avr8.h"
+#include "video/pwm.h"
+#include "sound/dac.h"
+#include "rendlay.h"
+#include "screen.h"
+#include "speaker.h"
+
+
+class pensebem2017_state : public driver_device
+{
+public:
+ pensebem2017_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_display(*this, "display"),
+ m_keyb_rows(*this, "ROW%u", 0U)
+ {
+ }
+
+ void pensebem2017(machine_config &config);
+
+private:
+ void prg_map(address_map &map);
+ void data_map(address_map &map);
+ void io_map(address_map &map);
+ void update_display();
+ uint8_t port_r(offs_t offset);
+ void port_w(offs_t offset, uint8_t value);
+
+ uint8_t m_port_b;
+ uint8_t m_port_c;
+ uint8_t m_port_d;
+ uint8_t m_port_e;
+
+ required_device<avr8_device> m_maincpu;
+ required_device<dac_bit_interface> m_dac;
+ required_device<pwm_display_device> m_display;
+ required_ioport_array<4> m_keyb_rows;
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+};
+
+void pensebem2017_state::machine_start()
+{
+}
+
+uint8_t pensebem2017_state::port_r(offs_t offset)
+{
+ uint8_t value;
+ int bit;
+
+ switch(offset)
+ {
+ case AVR8_IO_PORTB:
+ value = m_port_b & 0xc3;
+ for (bit=0; bit<8; bit++)
+ {
+ if (bit < 2 && !BIT(m_port_e, bit)) break;
+ if (bit >= 2 && !BIT(m_port_d, bit)) break;
+ }
+ if (BIT(m_keyb_rows[0]->read(), bit)) value |= (1 << 5);
+ if (BIT(m_keyb_rows[1]->read(), bit)) value |= (1 << 3);
+ if (BIT(m_keyb_rows[2]->read(), bit)) value |= (1 << 2);
+ if (BIT(m_keyb_rows[3]->read(), bit)) value |= (1 << 4);
+ return value;
+ default:
+ return 0xff;
+ }
+}
+
+void pensebem2017_state::port_w(offs_t offset, uint8_t data)
+{
+ switch(offset)
+ {
+ case AVR8_IO_PORTB: // buzzer + keyboard_select_rows
+ m_port_b = data;
+ m_dac->write(BIT(data, 1));
+ break;
+ case AVR8_IO_PORTC: // display
+ m_port_c = data;
+ update_display();
+ break;
+ case AVR8_IO_PORTD: // display
+ m_port_d = data;
+ break;
+ case AVR8_IO_PORTE: // display
+ m_port_e = data;
+ update_display();
+ break;
+ default:
+ break;
+ }
+}
+
+void pensebem2017_state::update_display()
+{
+ m_display->matrix(
+ ~bitswap<8>((m_port_c << 2 & 0xfc) | (m_port_e >> 2 & 0x03), 7,6,5,4,3,2,1,0),
+ ~((m_port_d & 0xfc) | (m_port_e & 0x03))
+ );
+}
+
+void pensebem2017_state::prg_map(address_map &map)
+{
+ map(0x0000, 0x3fff).rom().region("maincpu", 0); /* 16 kbytes of Flash ROM */
+}
+
+void pensebem2017_state::data_map(address_map &map)
+{
+ map(0x0000, 0x03ff).ram(); /* ATMEGA168PB Internal 1024 bytes of SRAM */
+ map(0x0400, 0xffff).ram(); /* Some additional SRAM ? This is likely an exagerated amount ! */
+}
+
+void pensebem2017_state::io_map(address_map &map)
+{
+ map(AVR8_IO_PORTA, AVR8_IO_PORTE).rw(FUNC(pensebem2017_state::port_r), FUNC(pensebem2017_state::port_w));
+}
+
+static INPUT_PORTS_START( pensebem2017 )
+ PORT_START("ROW0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("A") PORT_CODE(KEYCODE_A)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("C") PORT_CODE(KEYCODE_C)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("B") PORT_CODE(KEYCODE_B)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Desliga") PORT_CODE(KEYCODE_MINUS)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Livro") PORT_CODE(KEYCODE_L)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("D") PORT_CODE(KEYCODE_D)
+
+ PORT_START("ROW1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("1") PORT_CODE(KEYCODE_1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Adicao") PORT_CODE(KEYCODE_Q)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Subtracao") PORT_CODE(KEYCODE_W)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH_PAD)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("*") PORT_CODE(KEYCODE_ASTERISK)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS_PAD)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("+") PORT_CODE(KEYCODE_PLUS_PAD)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("0") PORT_CODE(KEYCODE_0)
+
+ PORT_START("ROW2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Multiplicacao") PORT_CODE(KEYCODE_E)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Aritmetica") PORT_CODE(KEYCODE_T)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Divisao") PORT_CODE(KEYCODE_R)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Adivinhe o Número") PORT_CODE(KEYCODE_P)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Número do Meio") PORT_CODE(KEYCODE_O)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Memória Tons") PORT_CODE(KEYCODE_I)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Siga-me") PORT_CODE(KEYCODE_U)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("Operacao") PORT_CODE(KEYCODE_Y)
+
+ PORT_START("ROW3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("2") PORT_CODE(KEYCODE_2)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("4") PORT_CODE(KEYCODE_4)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("3") PORT_CODE(KEYCODE_3)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("9") PORT_CODE(KEYCODE_9)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("8") PORT_CODE(KEYCODE_8)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("7") PORT_CODE(KEYCODE_7)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("6") PORT_CODE(KEYCODE_6)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYPAD) PORT_NAME("5") PORT_CODE(KEYCODE_5)
+INPUT_PORTS_END
+
+void pensebem2017_state::machine_reset()
+{
+ m_port_b = 0;
+ m_port_c = 0;
+ m_port_d = 0;
+ m_port_e = 0;
+}
+
+void pensebem2017_state::pensebem2017(machine_config &config)
+{
+ /* CPU */
+ ATMEGA168(config, m_maincpu, 16_MHz_XTAL); /* Actual chip is an Atmel ATMEGA168PB */
+ m_maincpu->set_addrmap(AS_PROGRAM, &pensebem2017_state::prg_map);
+ m_maincpu->set_addrmap(AS_DATA, &pensebem2017_state::data_map);
+ m_maincpu->set_addrmap(AS_IO, &pensebem2017_state::io_map);
+ m_maincpu->set_eeprom_tag("eeprom");
+ m_maincpu->set_low_fuses(0xf7);
+ m_maincpu->set_high_fuses(0xdd);
+ m_maincpu->set_extended_fuses(0xf9);
+ m_maincpu->set_lock_bits(0x0f);
+
+ /* video hardware */
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_SVG));
+ screen.set_refresh_hz(50);
+ screen.set_size(1490, 1080);
+ screen.set_visarea_full();
+ PWM_DISPLAY(config, m_display).set_size(8, 8);
+ m_display->set_segmask(0xff, 0xff);
+
+ /* sound hardware */
+ SPEAKER(config, "speaker").front_center();
+ DAC_1BIT(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.5);
+}
+
+ROM_START( pbem2017 )
+ ROM_REGION(0x20000, "maincpu", 0)
+ ROM_DEFAULT_BIOS("sept2017")
+
+ /* September 2017 release */
+ ROM_SYSTEM_BIOS(0, "sept2017", "SEPT/2017")
+ ROMX_LOAD("pensebem-2017.bin", 0x0000, 0x35b6, CRC(d394279e) SHA1(5576599394231c1f83817dd55992e3b5838ab003), ROM_BIOS(0))
+
+ /* on-die 4kbyte eeprom */
+ ROM_REGION(0x1000, "eeprom", ROMREGION_ERASEFF)
+
+ ROM_REGION(0x42e1a, "screen", 0)
+ ROM_LOAD("pensebem.svg", 0, 0x42e1a, CRC(7146c0db) SHA1(966e95742acdda05028ee7b0c1352c88abb35041))
+ROM_END
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME */
+COMP(2017, pbem2017, 0, 0, pensebem2017, pensebem2017, pensebem2017_state, empty_init, "TecToy", "Pense Bem (2017)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND)
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 30bf5078924..8cb770a0333 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -33378,6 +33378,9 @@ pengo5 // 834-0386 (c) 1982 Sega
pengob // bootleg
penta // bootleg
+@source:pensebem.cpp
+pbem2017 // 2017 TecToy Pense Bem
+
@source:pentagon.cpp
pent1024 //
pentagon //