diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index eda9a815572..a7b3461ba50 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2239,6 +2239,7 @@ files { createMESSProjects(_target, _subtarget, "elektor") files { + MAME_DIR .. "src/mame/drivers/avrmax.cpp", MAME_DIR .. "src/mame/drivers/ec65.cpp", MAME_DIR .. "src/mame/drivers/elekscmp.cpp", MAME_DIR .. "src/mame/drivers/junior.cpp", diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp index 6d48a21d84a..69096da7059 100644 --- a/src/devices/cpu/avr8/avr8.cpp +++ b/src/devices/cpu/avr8/avr8.cpp @@ -1655,6 +1655,13 @@ void avr8_device::timer2_tick() { switch (wgm2) { + case WGM02_NORMAL: + if (count == 0xff) + { + m_r[AVR8_REGIDX_TIFR2] |= AVR8_TIFR2_TOV2_MASK; + } + break; + case WGM02_FAST_PWM: if (reg == 0) { @@ -1868,11 +1875,12 @@ void avr8_device::timer4_tick() void avr8_device::update_timer_clock_source(uint8_t t, uint8_t clock_select) { - static const int s_prescale_values[8] = + static const int s_prescale_values[2][8] = { - 0, 1, 8, 64, 256, 1024, -1, -1 + { 0, 1, 8, 64, 256, 1024, -1, -1 }, // T0/T1/T3/T4/T5 + { 0, 1, 8, 32, 64, 128, 256, 1024 } // T2 }; - m_timer_prescale[t] = s_prescale_values[clock_select]; + m_timer_prescale[t] = s_prescale_values[(t == 2) ? 1 : 0][clock_select]; LOGMASKED((LOG_TIMER0 + t), "%s: update_timer_clock_source: t = %d, cs = %d\n", t, machine().describe_context(), clock_select); diff --git a/src/devices/cpu/avr8/avr8ops.hxx b/src/devices/cpu/avr8/avr8ops.hxx index 19114961d48..fe42b3156a2 100644 --- a/src/devices/cpu/avr8/avr8ops.hxx +++ b/src/devices/cpu/avr8/avr8ops.hxx @@ -523,7 +523,7 @@ void avr8_device::populate_add_flag_cache() flags |= (((rd & 8) && (rr & 8)) || ((rr & 8) && !(res & 8)) || (!(res & 8) && (rd & 8))) ? AVR8_SREG_MASK_H : 0; flags |= (((rd & 0x80) && (rr & 0x80) && !(res & 0x80)) | (!(rd & 0x80) & !(rr & 0x80) & (res & 0x80))) ? AVR8_SREG_MASK_V : 0; flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; flags |= (((rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && !(res & 0x80)) || (!(res & 0x80) && (rd & 0x80))) ? AVR8_SREG_MASK_C : 0; m_add_flag_cache[(rd << 8) | rr] = flags; @@ -544,7 +544,7 @@ void avr8_device::populate_adc_flag_cache() flags |= (((rd & 8) && (rr & 8)) || ((rr & 8) && !(res & 8)) || (!(res & 8) && (rd & 8))) ? AVR8_SREG_MASK_H : 0; flags |= (((rd & 0x80) && (rr & 0x80) && !(res & 0x80)) | (!(rd & 0x80) & !(rr & 0x80) & (res & 0x80))) ? AVR8_SREG_MASK_V : 0; flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; flags |= (((rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && !(res & 0x80)) || (!(res & 0x80) && (rd & 0x80))) ? AVR8_SREG_MASK_C : 0; m_adc_flag_cache[(c << 16) | (rd << 8) | rr] = flags; @@ -564,7 +564,7 @@ void avr8_device::populate_sub_flag_cache() flags |= ((!(rd & 8) && (rr & 8)) || ((rr & 8) && (res & 8)) || ((res & 8) && !(rd & 8))) ? AVR8_SREG_MASK_H : 0; flags |= (((rd & 0x80) && !(rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && (rr & 0x80) && (res & 0x80))) ? AVR8_SREG_MASK_V : 0; flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; flags |= ((!(rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && (res & 0x80)) || ((res & 0x80) && !(rd & 0x80))) ? AVR8_SREG_MASK_C : 0; m_sub_flag_cache[(rd << 8) | rr] = flags; @@ -587,7 +587,7 @@ void avr8_device::populate_sbc_flag_cache() flags |= ((!(rd & 8) && (rr & 8)) || ((rr & 8) && (res & 8)) || ((res & 8) && !(rd & 8))) ? AVR8_SREG_MASK_H : 0; flags |= (((rd & 0x80) && !(rr & 0x80) && !(res & 0x80)) || (!(rd & 0x80) && (rr & 0x80) && (res & 0x80))) ? AVR8_SREG_MASK_V : 0; flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; flags |= (res == 0) ? (z ? AVR8_SREG_MASK_Z : 0) : 0; flags |= ((!(rd & 0x80) && (rr & 0x80)) || ((rr & 0x80) && (res & 0x80)) || ((res & 0x80) && !(rd & 0x80))) ? AVR8_SREG_MASK_C : 0; m_sbc_flag_cache[(z << 17) | (c << 16) | (rd << 8) | rr] = flags; @@ -603,7 +603,7 @@ void avr8_device::populate_bool_flag_cache() { uint8_t flags = 0; flags |= (res & 0x80) ? AVR8_SREG_MASK_N : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; m_bool_flag_cache[res] = flags; } @@ -619,8 +619,8 @@ void avr8_device::populate_shift_flag_cache() flags |= (rd & 1) ? AVR8_SREG_MASK_C : 0; flags |= (res == 0) ? AVR8_SREG_MASK_Z : 0; flags |= (rd & 0x80) ? AVR8_SREG_MASK_N : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_C)) ? AVR8_SREG_MASK_V : 0; - flags |= ((SREG & AVR8_SREG_MASK_N) != (SREG & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_C)) ? AVR8_SREG_MASK_V : 0; + flags |= (bool(flags & AVR8_SREG_MASK_N) != bool(flags & AVR8_SREG_MASK_V)) ? AVR8_SREG_MASK_S : 0; m_shift_flag_cache[(rd << 8) | res] = flags; } } diff --git a/src/mame/drivers/avrmax.cpp b/src/mame/drivers/avrmax.cpp new file mode 100644 index 00000000000..a6cbf326050 --- /dev/null +++ b/src/mame/drivers/avrmax.cpp @@ -0,0 +1,235 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/****************************************************************************** + +AVR-Max Chess Computer, aka "SHAH" +In Germany it was named AVR-Max-Schachzwerg + +The chess engine is H.G. Muller's micro-Max 4.8, ATMega88 port and prototype +hardware design by Andre Adrian. PCB finalization by Elektor, published in +Elektor magazine in 2009. + +Moves are confirmed by pressing GO twice. FN 1 = new game, FN 2 = set level, +FN 3 = principle variation. + +Hardware notes: +- PCB label 081101-1 (c)Elektor v1.4 +- Atmel ATMega88P-20PU @ ~8MHz, 8KB internal ROM +- 4-digit 7seg display, button panel, no sound + +TODO: +- AVR8 SLEEP opcode is not working, it's used for power-saving here and was + harmless to hack out, but needs to be put back when it's emulated +- add Elektor CC2 version with custom LCD screen + +******************************************************************************/ + +#include "emu.h" +#include "cpu/avr8/avr8.h" +#include "video/pwm.h" + +// internal artwork +#include "avrmax.lh" // clickable + + +namespace { + +class avrmax_state : public driver_device +{ +public: + avrmax_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_display(*this, "display"), + m_inputs(*this, "IN.%u", 0) + { } + + void avrmax(machine_config &config); + +protected: + virtual void machine_start() override; + +private: + // devices/pointers + required_device m_maincpu; + required_device m_display; + required_ioport_array<4> m_inputs; + + // address maps + void main_map(address_map &map); + void data_map(address_map &map); + void io_map(address_map &map); + + // I/O handlers + void update_display(); + void mux_w(u8 data); + void led_w(u8 data); + u8 input_r(); + + u8 m_inp_mux = 0; + u8 m_led_data = 0; +}; + +void avrmax_state::machine_start() +{ + // register for savestates + save_item(NAME(m_inp_mux)); + save_item(NAME(m_led_data)); +} + + + +/****************************************************************************** + I/O +******************************************************************************/ + +void avrmax_state::update_display() +{ + m_display->matrix(m_inp_mux, m_led_data); +} + +void avrmax_state::mux_w(u8 data) +{ + // PC0-PC3: input mux/digit select + m_inp_mux = ~data & 0xf; + update_display(); +} + +void avrmax_state::led_w(u8 data) +{ + // PD0-PD7: 7seg data + m_led_data = ~data; + update_display(); +} + +u8 avrmax_state::input_r() +{ + u8 data = 0; + + // PB0-PB3: multiplexed inputs + for (int i = 0; i < 4; i++) + if (BIT(m_inp_mux, i)) + data |= m_inputs[i]->read(); + + return ~data & 7; +} + + + +/****************************************************************************** + Address Maps +******************************************************************************/ + +void avrmax_state::main_map(address_map &map) +{ + map(0x0000, 0x1fff).rom(); +} + +void avrmax_state::data_map(address_map &map) +{ + map(0x0100, 0x04ff).ram(); +} + +void avrmax_state::io_map(address_map &map) +{ + map(AVR8_IO_PORTB, AVR8_IO_PORTB).r(FUNC(avrmax_state::input_r)); + map(AVR8_IO_PORTC, AVR8_IO_PORTC).w(FUNC(avrmax_state::mux_w)); + map(AVR8_IO_PORTD, AVR8_IO_PORTD).w(FUNC(avrmax_state::led_w)); +} + + + +/****************************************************************************** + Input Ports +******************************************************************************/ + +static INPUT_PORTS_START( avrmax ) + PORT_START("IN.0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("A1") PORT_CODE(KEYCODE_A) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("E5") PORT_CODE(KEYCODE_E) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("FN") PORT_CODE(KEYCODE_N) + + PORT_START("IN.1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("B2") PORT_CODE(KEYCODE_B) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("F6") PORT_CODE(KEYCODE_F) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("CL") PORT_CODE(KEYCODE_DEL) PORT_CODE(KEYCODE_BACKSPACE) + + PORT_START("IN.2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("C3") PORT_CODE(KEYCODE_C) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("G7") PORT_CODE(KEYCODE_G) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("GO") PORT_CODE(KEYCODE_ENTER) PORT_CODE(KEYCODE_ENTER_PAD) + + PORT_START("IN.3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("D4") PORT_CODE(KEYCODE_D) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYPAD) PORT_NAME("H8") PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_UNUSED) +INPUT_PORTS_END + + + +/****************************************************************************** + Machine Configs +******************************************************************************/ + +void avrmax_state::avrmax(machine_config &config) +{ + /* basic machine hardware */ + ATMEGA88(config, m_maincpu, 8000000); // internal R/C clock + m_maincpu->set_addrmap(AS_PROGRAM, &avrmax_state::main_map); + m_maincpu->set_addrmap(AS_DATA, &avrmax_state::data_map); + m_maincpu->set_addrmap(AS_IO, &avrmax_state::io_map); + m_maincpu->set_eeprom_tag("eeprom"); + + /* video hardware */ + PWM_DISPLAY(config, m_display).set_size(4, 8); + m_display->set_segmask(0xf, 0xff); + config.set_default_layout(layout_avrmax); +} + + + +/****************************************************************************** + ROM Definitions +******************************************************************************/ + +ROM_START( avrmax ) + ROM_REGION( 0x2000, "maincpu", 0 ) + ROM_LOAD( "elektor_081101-41.ic1", 0x0000, 0x2000, CRC(86d2a654) SHA1(3c235b8f6f735eaf408f54cbf44872166e7161d5) ) + + // HACK: changed SLEEP to NOP + ROM_FILL( 0x025c, 2, 0x00 ) + ROM_FILL( 0x0f8e, 2, 0x00 ) + ROM_FILL( 0x0fde, 2, 0x00 ) + ROM_FILL( 0x1020, 2, 0x00 ) + ROM_FILL( 0x1060, 2, 0x00 ) + ROM_FILL( 0x129a, 2, 0x00 ) + + ROM_REGION( 0x200, "eeprom", ROMREGION_ERASE00 ) +ROM_END + +ROM_START( avrmaxg ) + ROM_REGION( 0x2000, "maincpu", 0 ) + ROM_LOAD( "elektor_081101-41_d.ic1", 0x0000, 0x2000, CRC(18ec7a56) SHA1(a018421aa0ad8cce3d852f7519dec3691f3c55a0) ) + + // HACK: changed SLEEP to NOP + ROM_FILL( 0x025c, 2, 0x00 ) + ROM_FILL( 0x0f8e, 2, 0x00 ) + ROM_FILL( 0x0fde, 2, 0x00 ) + ROM_FILL( 0x1020, 2, 0x00 ) + ROM_FILL( 0x1060, 2, 0x00 ) + ROM_FILL( 0x129a, 2, 0x00 ) + + ROM_REGION( 0x200, "eeprom", ROMREGION_ERASE00 ) +ROM_END + +} // anonymous namespace + + + +/****************************************************************************** + Drivers +******************************************************************************/ + +// YEAR NAME PARENT CMP MACHINE INPUT STATE INIT COMPANY, FULLNAME, FLAGS +CONS( 2009, avrmax, 0, 0, avrmax, avrmax, avrmax_state, empty_init, "Elektor", "AVR-Max Chess Computer", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_NO_SOUND_HW ) +CONS( 2009, avrmaxg, avrmax, 0, avrmax, avrmax, avrmax_state, empty_init, "Elektor", "AVR-Max-Schachzwerg", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_NO_SOUND_HW ) // German 'text' diff --git a/src/mame/drivers/ec65.cpp b/src/mame/drivers/ec65.cpp index 68882ce4b38..c18395857b2 100644 --- a/src/mame/drivers/ec65.cpp +++ b/src/mame/drivers/ec65.cpp @@ -304,6 +304,6 @@ ROM_START( ec65k ) ROM_END /* Driver */ -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1985, ec65, 0, 0, ec65, ec65, ec65_state, empty_init, "Elektor Electronics", "EC-65", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) -COMP( 1986, ec65k, ec65, 0, ec65k, ec65, ec65k_state, empty_init, "Elektor Electronics", "EC-65K", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1985, ec65, 0, 0, ec65, ec65, ec65_state, empty_init, "Elektor", "EC-65", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) +COMP( 1986, ec65k, ec65, 0, ec65k, ec65, ec65k_state, empty_init, "Elektor", "EC-65K", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/elekscmp.cpp b/src/mame/drivers/elekscmp.cpp index 0031f8ee9c0..e0f7e012ee8 100644 --- a/src/mame/drivers/elekscmp.cpp +++ b/src/mame/drivers/elekscmp.cpp @@ -227,5 +227,5 @@ ROM_END /* Driver */ -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1977, elekscmp, 0, 0, elekscmp, elekscmp, elekscmp_state, empty_init, "Elektor Electronics", "Elektor SC/MP", MACHINE_SUPPORTS_SAVE ) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1977, elekscmp, 0, 0, elekscmp, elekscmp, elekscmp_state, empty_init, "Elektor", "Elektor SC/MP", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/fidel_cc1.cpp b/src/mame/drivers/fidel_cc1.cpp index e02be278761..07f07b27bd6 100644 --- a/src/mame/drivers/fidel_cc1.cpp +++ b/src/mame/drivers/fidel_cc1.cpp @@ -113,16 +113,12 @@ private: void ppi_portb_w(u8 data); void ppi_portc_w(u8 data); - u8 m_led_select; - u8 m_7seg_data; + u8 m_led_select = 0; + u8 m_7seg_data = 0; }; void cc1_state::machine_start() { - // zerofill - m_led_select = 0; - m_7seg_data = 0; - // register for savestates save_item(NAME(m_led_select)); save_item(NAME(m_7seg_data)); diff --git a/src/mame/drivers/junior.cpp b/src/mame/drivers/junior.cpp index fbdbf395a62..7968da1ee4d 100644 --- a/src/mame/drivers/junior.cpp +++ b/src/mame/drivers/junior.cpp @@ -226,5 +226,5 @@ ROM_END /* Driver */ -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1980, junior, 0, 0, junior, junior, junior_state, empty_init, "Elektor Electronics", "Junior Computer", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1980, junior, 0, 0, junior, junior, junior_state, empty_init, "Elektor", "Junior Computer", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/layout/avrmax.lay b/src/mame/layout/avrmax.lay new file mode 100644 index 00000000000..c07dbb1a516 --- /dev/null +++ b/src/mame/layout/avrmax.lay @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 5200fed5866..0f7dad2115a 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -3092,6 +3092,10 @@ avigo_es // 1997 Avigo (Spanish) avigo_fr // 1997 Avigo (French) avigo_it // 1997 Avigo (Italian) +@source:avrmax.cpp +avrmax +avrmaxg + @source:avt.cpp avtbingo // (c) 1985 AVT avtnfl // (c) 1989 AVT diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 9f0687632ee..33b3008b6c9 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -96,6 +96,7 @@ attache.cpp aussiebyte.cpp ave_arb.cpp avigo.cpp +avrmax.cpp ax20.cpp b16.cpp b2m.cpp