| Previous | 199869 Revisions | Next |
| r19803 Tuesday 25th December, 2012 at 09:22:58 UTC by Sandro Ronco |
|---|
| (MESS) AVR8 core updates: [Sandro Ronco] - added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes. - added ATMEGA644 interrupt vectors. - fixed Z flag in CPC, SBC and SBCI opcodes. - fixed V and C flags in SBIW opcode. - fixed pop/push order in CALL, RCALL, RET and RETI opcodes. - fixed Timer 1 CTC mode. (MESS) uzebox: added video emulation and joystick input. [Sandro Ronco] |
| [src/emu/cpu/avr8] | avr8.c avr8.h |
| [src/mess/drivers] | uzebox.c |
| r19802 | r19803 | |
|---|---|---|
| 9 | 9 | the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the |
| 10 | 10 | existing timing is 100% correct. |
| 11 | 11 | |
| 12 | Unimplemented opcodes: CPSR, LD Z+, ST Z+, ST -Z/-Y/-X, ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, ICALL, | |
| 13 | EICALL, JMP, CALL, SBIW | |
| 12 | Unimplemented opcodes: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL | |
| 14 | 13 | |
| 15 | 14 | - Changelist - |
| 15 | 23 Dec. 2012 [Sandro Ronco] | |
| 16 | - Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes | |
| 17 | - Fixed Z flag in CPC, SBC and SBCI opcodes | |
| 18 | - Fixed V and C flags in SBIW opcode | |
| 19 | ||
| 16 | 20 | 30 Oct. 2012 |
| 17 | 21 | - Added FMUL, FMULS, FMULSU opcodes [MooglyGuy] |
| 18 | 22 | - Fixed incorrect flag calculation in ROR opcode [MooglyGuy] |
| r19802 | r19803 | |
| 71 | 75 | static void static_set_config(device_t &device, const avr8_config &config); |
| 72 | 76 | |
| 73 | 77 | // public interfaces |
| 74 | void update_interrupt(int source); | |
| 78 | virtual void update_interrupt(int source); | |
| 75 | 79 | UINT64 get_elapsed_cycles() |
| 76 | 80 | { |
| 77 | 81 | return m_elapsed_cycles; |
| r19802 | r19803 | |
| 232 | 236 | public: |
| 233 | 237 | // construction/destruction |
| 234 | 238 | atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 239 | ||
| 240 | virtual void update_interrupt(int source); | |
| 235 | 241 | }; |
| 236 | 242 | |
| 237 | 243 | /*************************************************************************** |
| r19802 | r19803 | |
| 308 | 314 | AVR8_INT_ANALOG_COMP, |
| 309 | 315 | AVR8_INT_TWI, |
| 310 | 316 | AVR8_INT_SPM_RDY, |
| 317 | ||
| 318 | // ATMEGA644 | |
| 319 | ATMEGA644_INT_RESET = 0, | |
| 320 | ATMEGA644_INT_INT0, | |
| 321 | ATMEGA644_INT_INT1, | |
| 322 | ATMEGA644_INT_INT2, | |
| 323 | ATMEGA644_INT_PCINT0, | |
| 324 | ATMEGA644_INT_PCINT1, | |
| 325 | ATMEGA644_INT_PCINT2, | |
| 326 | ATMEGA644_INT_PCINT3, | |
| 327 | ATMEGA644_INT_WDT, | |
| 328 | ATMEGA644_INT_T2COMPA, | |
| 329 | ATMEGA644_INT_T2COMPB, | |
| 330 | ATMEGA644_INT_T2OVF, | |
| 331 | ATMEGA644_INT_T1CAPT, | |
| 332 | ATMEGA644_INT_T1COMPA, | |
| 333 | ATMEGA644_INT_T1COMPB, | |
| 334 | ATMEGA644_INT_T1OVF, | |
| 335 | ATMEGA644_INT_T0COMPA, | |
| 336 | ATMEGA644_INT_T0COMPB, | |
| 337 | ATMEGA644_INT_T0OVF, | |
| 338 | ATMEGA644_INT_SPI_STC, | |
| 339 | ATMEGA644_INT_USART_RX, | |
| 340 | ATMEGA644_INT_USART_UDRE, | |
| 341 | ATMEGA644_INT_USART_TX, | |
| 342 | ATMEGA644_INT_ADC, | |
| 343 | ATMEGA644_INT_EE_RDY, | |
| 344 | ATMEGA644_INT_ANALOG_COMP, | |
| 345 | ATMEGA644_INT_TWI, | |
| 346 | ATMEGA644_INT_SPM_RDY, | |
| 311 | 347 | }; |
| 312 | 348 | |
| 313 | 349 | // Used by I/O register handling |
| r19802 | r19803 | |
|---|---|---|
| 9 | 9 | the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the |
| 10 | 10 | existing timing is 100% correct. |
| 11 | 11 | |
| 12 | Unimplemented opcodes: CPSR, LD Z+, ST -Z/-Y/-X, ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, ICALL, EICALL, | |
| 13 | JMP, CALL | |
| 12 | Unimplemented opcodes: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL | |
| 14 | 13 | |
| 15 | 14 | - Changelist - |
| 15 | 23 Dec. 2012 [Sandro Ronco] | |
| 16 | - Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes | |
| 17 | - Fixed Z flag in CPC, SBC and SBCI opcodes | |
| 18 | - Fixed V and C flags in SBIW opcode | |
| 19 | ||
| 16 | 20 | 30 Oct. 2012 |
| 17 | 21 | - Added FMUL, FMULS, FMULSU opcodes [MooglyGuy] |
| 18 | 22 | - Fixed incorrect flag calculation in ROR opcode [MooglyGuy] |
| r19802 | r19803 | |
| 664 | 668 | if(SREG_R(AVR8_SREG_I)) |
| 665 | 669 | { |
| 666 | 670 | SREG_W(AVR8_SREG_I, 0); |
| 671 | push(m_pc & 0x00ff); | |
| 667 | 672 | push((m_pc >> 8) & 0x00ff); |
| 668 | push(m_pc & 0x00ff); | |
| 669 | 673 | m_pc = vector; |
| 670 | 674 | m_shifted_pc = vector << 1; |
| 671 | 675 | } |
| r19802 | r19803 | |
| 717 | 721 | } |
| 718 | 722 | |
| 719 | 723 | |
| 724 | static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] = | |
| 725 | { | |
| 726 | { ATMEGA644_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK }, | |
| 727 | { ATMEGA644_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK }, | |
| 728 | { ATMEGA644_INT_T0COMPA, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0A_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0A_MASK }, | |
| 729 | { ATMEGA644_INT_T0OVF, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_TOIE0_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_TOV0_MASK }, | |
| 730 | { ATMEGA644_INT_T1CAPT, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_ICIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_ICF1_MASK }, | |
| 731 | { ATMEGA644_INT_T1COMPB, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1B_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1B_MASK }, | |
| 732 | { ATMEGA644_INT_T1COMPA, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1A_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1A_MASK }, | |
| 733 | { ATMEGA644_INT_T1OVF, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_TOIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_TOV1_MASK }, | |
| 734 | { ATMEGA644_INT_T2COMPB, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2B_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2B_MASK }, | |
| 735 | { ATMEGA644_INT_T2COMPA, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2A_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2A_MASK }, | |
| 736 | { ATMEGA644_INT_T2OVF, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_TOIE2_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_TOV2_MASK } | |
| 737 | }; | |
| 738 | ||
| 739 | void atmega644_device::update_interrupt(int source) | |
| 740 | { | |
| 741 | CInterruptCondition condition = s_mega644_int_conditions[source]; | |
| 742 | ||
| 743 | int intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0; | |
| 744 | intstate = (m_r[condition.m_intreg] & condition.m_intmask) ? intstate : 0; | |
| 745 | ||
| 746 | set_irq_line(condition.m_intindex << 1, intstate); | |
| 747 | ||
| 748 | if (intstate) | |
| 749 | { | |
| 750 | m_r[condition.m_regindex] &= ~condition.m_regmask; | |
| 751 | } | |
| 752 | } | |
| 753 | ||
| 754 | ||
| 720 | 755 | //************************************************************************** |
| 721 | 756 | // REGISTER HANDLING |
| 722 | 757 | //************************************************************************** |
| r19802 | r19803 | |
| 1010 | 1045 | |
| 1011 | 1046 | if (count == ocr1[reg]) |
| 1012 | 1047 | { |
| 1048 | if (reg == 0) | |
| 1049 | { | |
| 1050 | count = 0; | |
| 1051 | increment = 0; | |
| 1052 | } | |
| 1013 | 1053 | m_r[AVR8_REGIDX_TIFR1] |= ocf1[reg]; |
| 1014 | 1054 | update_interrupt(int1[reg]); |
| 1015 | 1055 | } |
| r19802 | r19803 | |
| 1540 | 1580 | { |
| 1541 | 1581 | switch( offset ) |
| 1542 | 1582 | { |
| 1583 | case AVR8_REGIDX_R0: | |
| 1584 | case AVR8_REGIDX_R1: | |
| 1585 | case AVR8_REGIDX_R2: | |
| 1586 | case AVR8_REGIDX_R3: | |
| 1587 | case AVR8_REGIDX_R4: | |
| 1588 | case AVR8_REGIDX_R5: | |
| 1589 | case AVR8_REGIDX_R6: | |
| 1590 | case AVR8_REGIDX_R7: | |
| 1591 | case AVR8_REGIDX_R8: | |
| 1592 | case AVR8_REGIDX_R9: | |
| 1593 | case AVR8_REGIDX_R10: | |
| 1594 | case AVR8_REGIDX_R11: | |
| 1595 | case AVR8_REGIDX_R12: | |
| 1596 | case AVR8_REGIDX_R13: | |
| 1597 | case AVR8_REGIDX_R14: | |
| 1598 | case AVR8_REGIDX_R15: | |
| 1599 | case AVR8_REGIDX_R16: | |
| 1600 | case AVR8_REGIDX_R17: | |
| 1601 | case AVR8_REGIDX_R18: | |
| 1602 | case AVR8_REGIDX_R19: | |
| 1603 | case AVR8_REGIDX_R20: | |
| 1604 | case AVR8_REGIDX_R21: | |
| 1605 | case AVR8_REGIDX_R22: | |
| 1606 | case AVR8_REGIDX_R23: | |
| 1607 | case AVR8_REGIDX_R24: | |
| 1608 | case AVR8_REGIDX_R25: | |
| 1609 | case AVR8_REGIDX_R26: | |
| 1610 | case AVR8_REGIDX_R27: | |
| 1611 | case AVR8_REGIDX_R28: | |
| 1612 | case AVR8_REGIDX_R29: | |
| 1613 | case AVR8_REGIDX_R30: | |
| 1614 | case AVR8_REGIDX_R31: | |
| 1615 | m_r[offset] = data; | |
| 1616 | break; | |
| 1617 | ||
| 1543 | 1618 | case AVR8_REGIDX_TCCR0B: |
| 1544 | 1619 | verboselog(m_pc, 0, "AVR8: TCCR0B = %02x\n", data ); |
| 1545 | 1620 | changed_tccr0b(data); |
| r19802 | r19803 | |
| 1707 | 1782 | m_r[offset] = data; |
| 1708 | 1783 | break; |
| 1709 | 1784 | |
| 1785 | case AVR8_REGIDX_GPIOR1: | |
| 1786 | case AVR8_REGIDX_GPIOR2: | |
| 1787 | m_r[offset] = data; | |
| 1788 | break; | |
| 1789 | ||
| 1710 | 1790 | case AVR8_REGIDX_PORTA: |
| 1711 | 1791 | m_io->write_byte(0x00, data); |
| 1712 | 1792 | m_r[AVR8_REGIDX_PORTA] = data; |
| r19802 | r19803 | |
| 1755 | 1835 | //printf("offset %04x\n", offset); |
| 1756 | 1836 | switch( offset ) |
| 1757 | 1837 | { |
| 1838 | case AVR8_REGIDX_R0: | |
| 1839 | case AVR8_REGIDX_R1: | |
| 1840 | case AVR8_REGIDX_R2: | |
| 1841 | case AVR8_REGIDX_R3: | |
| 1842 | case AVR8_REGIDX_R4: | |
| 1843 | case AVR8_REGIDX_R5: | |
| 1844 | case AVR8_REGIDX_R6: | |
| 1845 | case AVR8_REGIDX_R7: | |
| 1846 | case AVR8_REGIDX_R8: | |
| 1847 | case AVR8_REGIDX_R9: | |
| 1848 | case AVR8_REGIDX_R10: | |
| 1849 | case AVR8_REGIDX_R11: | |
| 1850 | case AVR8_REGIDX_R12: | |
| 1851 | case AVR8_REGIDX_R13: | |
| 1852 | case AVR8_REGIDX_R14: | |
| 1853 | case AVR8_REGIDX_R15: | |
| 1854 | case AVR8_REGIDX_R16: | |
| 1855 | case AVR8_REGIDX_R17: | |
| 1856 | case AVR8_REGIDX_R18: | |
| 1857 | case AVR8_REGIDX_R19: | |
| 1858 | case AVR8_REGIDX_R20: | |
| 1859 | case AVR8_REGIDX_R21: | |
| 1860 | case AVR8_REGIDX_R22: | |
| 1861 | case AVR8_REGIDX_R23: | |
| 1862 | case AVR8_REGIDX_R24: | |
| 1863 | case AVR8_REGIDX_R25: | |
| 1864 | case AVR8_REGIDX_R26: | |
| 1865 | case AVR8_REGIDX_R27: | |
| 1866 | case AVR8_REGIDX_R28: | |
| 1867 | case AVR8_REGIDX_R29: | |
| 1868 | case AVR8_REGIDX_R30: | |
| 1869 | case AVR8_REGIDX_R31: | |
| 1870 | return m_r[offset]; | |
| 1871 | ||
| 1758 | 1872 | case AVR8_REGIDX_SPL: |
| 1759 | 1873 | case AVR8_REGIDX_SPH: |
| 1760 | 1874 | case AVR8_REGIDX_TCNT1L: |
| r19802 | r19803 | |
| 1769 | 1883 | case AVR8_REGIDX_DDRC: |
| 1770 | 1884 | case AVR8_REGIDX_DDRD: |
| 1771 | 1885 | case AVR8_REGIDX_GPIOR0: |
| 1886 | case AVR8_REGIDX_GPIOR1: | |
| 1887 | case AVR8_REGIDX_GPIOR2: | |
| 1772 | 1888 | case AVR8_REGIDX_EEDR: |
| 1773 | 1889 | case AVR8_REGIDX_SREG: |
| 1774 | 1890 | return m_r[offset]; |
| 1775 | 1891 | |
| 1892 | // TODO: consider the DDRx | |
| 1893 | case AVR8_REGIDX_PINA: | |
| 1894 | return m_io->read_byte(AVR8_REG_A); | |
| 1895 | case AVR8_REGIDX_PINB: | |
| 1896 | return m_io->read_byte(AVR8_REG_B); | |
| 1897 | case AVR8_REGIDX_PINC: | |
| 1898 | return m_io->read_byte(AVR8_REG_C); | |
| 1899 | case AVR8_REGIDX_PIND: | |
| 1900 | return m_io->read_byte(AVR8_REG_D); | |
| 1901 | ||
| 1776 | 1902 | default: |
| 1777 | 1903 | verboselog(m_pc, 0, "AVR8: Unknown Register Read: %02x\n", (UINT8)offset); |
| 1778 | 1904 | return 0; |
| r19802 | r19803 | |
| 1919 | 2045 | SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); |
| 1920 | 2046 | SREG_W(AVR8_SREG_N, BIT(res,7)); |
| 1921 | 2047 | SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); |
| 1922 | SREG_W(AVR8_SREG_Z, (res == 0) ? | |
| 2048 | SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0); | |
| 1923 | 2049 | SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); |
| 1924 | 2050 | break; |
| 1925 | 2051 | case 0x0800: |
| r19802 | r19803 | |
| 1934 | 2060 | SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); |
| 1935 | 2061 | SREG_W(AVR8_SREG_N, BIT(res,7)); |
| 1936 | 2062 | SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); |
| 1937 | SREG_W(AVR8_SREG_Z, (res == 0) ? | |
| 2063 | SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0); | |
| 1938 | 2064 | SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); |
| 1939 | 2065 | break; |
| 1940 | 2066 | case 0x0c00: |
| r19802 | r19803 | |
| 1957 | 2083 | case 0x1000: |
| 1958 | 2084 | switch(op & 0x0c00) |
| 1959 | 2085 | { |
| 1960 | case 0x0000: // CPSR Rd,Rr | |
| 1961 | //output += sprintf( output, "CPSE R%d, R%d", RD5(op), RR5(op) ); | |
| 1962 | unimplemented_opcode(op); | |
| 2086 | case 0x0000: // CPSE Rd,Rr | |
| 2087 | rd = m_r[RD5(op)]; | |
| 2088 | rr = m_r[RR5(op)]; | |
| 2089 | if (rd == rr) | |
| 2090 | { | |
| 2091 | op = (UINT32)m_program->read_word(m_shifted_pc + 2); | |
| 2092 | opcycles += is_long_opcode(op) ? 2 : 1; | |
| 2093 | m_pc += is_long_opcode(op) ? 2 : 1; | |
| 2094 | } | |
| 1963 | 2095 | break; |
| 1964 | 2096 | case 0x0400: // CP Rd,Rr |
| 1965 | 2097 | rd = m_r[RD5(op)]; |
| r19802 | r19803 | |
| 2056 | 2188 | SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); |
| 2057 | 2189 | SREG_W(AVR8_SREG_N, BIT(res,7)); |
| 2058 | 2190 | SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); |
| 2059 | SREG_W(AVR8_SREG_Z, (res == 0) ? | |
| 2191 | SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0); | |
| 2060 | 2192 | SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); |
| 2061 | 2193 | break; |
| 2062 | 2194 | case 0x5000: // SUBI Rd,K |
| r19802 | r19803 | |
| 2129 | 2261 | opcycles = 2; |
| 2130 | 2262 | break; |
| 2131 | 2263 | case 0x0001: // LD Rd,Z+ |
| 2132 | unimplemented_opcode(op); | |
| 2264 | pd = ZREG; | |
| 2265 | m_r[RD5(op)] = m_data->read_byte(pd); | |
| 2266 | pd++; | |
| 2267 | m_r[31] = (pd >> 8) & 0x00ff; | |
| 2268 | m_r[30] = pd & 0x00ff; | |
| 2269 | opcycles = 2; | |
| 2133 | 2270 | break; |
| 2134 | 2271 | case 0x0002: // LD Rd,-Z |
| 2135 | 2272 | pd = ZREG; |
| r19802 | r19803 | |
| 2226 | 2363 | opcycles = 2; |
| 2227 | 2364 | break; |
| 2228 | 2365 | case 0x0002: // ST -Z,Rd |
| 2229 | //output += sprintf( output, "ST -Z , R%d", RD5(op) ); | |
| 2230 | unimplemented_opcode(op); | |
| 2366 | pd = ZREG; | |
| 2367 | pd--; | |
| 2368 | m_data->write_byte(pd, m_r[RD5(op)]); | |
| 2369 | m_r[31] = (pd >> 8) & 0x00ff; | |
| 2370 | m_r[30] = pd & 0x00ff; | |
| 2371 | opcycles = 2; | |
| 2231 | 2372 | break; |
| 2232 | 2373 | case 0x0009: // ST Y+,Rd |
| 2233 | 2374 | pd = YREG; |
| r19802 | r19803 | |
| 2238 | 2379 | opcycles = 2; |
| 2239 | 2380 | break; |
| 2240 | 2381 | case 0x000a: // ST -Y,Rd |
| 2241 | //output += sprintf( output, "ST -Y , R%d", RD5(op) ); | |
| 2242 | unimplemented_opcode(op); | |
| 2382 | pd = YREG; | |
| 2383 | pd--; | |
| 2384 | m_data->write_byte(pd, m_r[RD5(op)]); | |
| 2385 | m_r[29] = (pd >> 8) & 0x00ff; | |
| 2386 | m_r[28] = pd & 0x00ff; | |
| 2387 | opcycles = 2; | |
| 2243 | 2388 | break; |
| 2244 | 2389 | case 0x000c: // ST X,Rd |
| 2245 | 2390 | m_data->write_byte(XREG, m_r[RD5(op)]); |
| r19802 | r19803 | |
| 2253 | 2398 | opcycles = 2; |
| 2254 | 2399 | break; |
| 2255 | 2400 | case 0x000e: // ST -X,Rd |
| 2256 | //output += sprintf( output, "ST -X , R%d", RD5(op) ); | |
| 2257 | unimplemented_opcode(op); | |
| 2401 | pd = XREG; | |
| 2402 | pd--; | |
| 2403 | m_data->write_byte(pd, m_r[RD5(op)]); | |
| 2404 | m_r[27] = (pd >> 8) & 0x00ff; | |
| 2405 | m_r[26] = pd & 0x00ff; | |
| 2406 | opcycles = 2; | |
| 2258 | 2407 | break; |
| 2259 | 2408 | case 0x000f: // PUSH Rd |
| 2260 | 2409 | push(m_r[RD5(op)]); |
| r19802 | r19803 | |
| 2397 | 2546 | break; |
| 2398 | 2547 | case 0x000e: // CALL k |
| 2399 | 2548 | case 0x000f: |
| 2400 | push(((m_pc + 1) >> 8) & 0x00ff); | |
| 2401 | push((m_pc + 1) & 0x00ff); | |
| 2549 | push((m_pc + 2) & 0x00ff); | |
| 2550 | push(((m_pc + 2) >> 8) & 0x00ff); | |
| 2402 | 2551 | offs = KCONST22(op) << 16; |
| 2403 | 2552 | m_pc++; |
| 2404 | 2553 | m_shifted_pc += 2; |
| r19802 | r19803 | |
| 2485 | 2634 | switch(op & 0x00f0) |
| 2486 | 2635 | { |
| 2487 | 2636 | case 0x0000: // RET |
| 2488 | m_pc = pop(); | |
| 2489 | m_pc |= pop() << 8; | |
| 2637 | m_pc = pop() << 8; | |
| 2638 | m_pc |= pop(); | |
| 2490 | 2639 | m_pc--; |
| 2491 | 2640 | opcycles = 4; |
| 2492 | 2641 | break; |
| 2493 | 2642 | case 0x0010: // RETI |
| 2494 | m_pc = pop(); | |
| 2495 | m_pc |= pop() << 8; | |
| 2643 | m_pc = pop() << 8; | |
| 2644 | m_pc |= pop(); | |
| 2496 | 2645 | m_pc--; |
| 2497 | 2646 | SREG_W(AVR8_SREG_I, 1); |
| 2498 | 2647 | opcycles = 4; |
| r19802 | r19803 | |
| 2535 | 2684 | switch(op & 0x00f0) |
| 2536 | 2685 | { |
| 2537 | 2686 | case 0x0000: // ICALL |
| 2538 | //output += sprintf( output, "ICALL" ); | |
| 2539 | unimplemented_opcode(op); | |
| 2687 | push((m_pc + 1) & 0x00ff); | |
| 2688 | push(((m_pc + 1) >> 8) & 0x00ff); | |
| 2689 | m_pc = ZREG; | |
| 2690 | m_pc--; | |
| 2691 | opcycles = 3; | |
| 2540 | 2692 | break; |
| 2541 | 2693 | case 0x0010: // EICALL |
| 2542 | 2694 | //output += sprintf( output, "EICALL" ); |
| r19802 | r19803 | |
| 2598 | 2750 | pd = rd; |
| 2599 | 2751 | pd |= rr << 8; |
| 2600 | 2752 | pd -= KCONST6(op); |
| 2601 | SREG_W(AVR8_SREG_V, BIT(pd,15) & | |
| 2753 | SREG_W(AVR8_SREG_V, NOT(BIT(pd,15)) & BIT(rr,7)); | |
| 2602 | 2754 | SREG_W(AVR8_SREG_N, BIT(pd,15)); |
| 2603 | 2755 | SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); |
| 2604 | 2756 | SREG_W(AVR8_SREG_Z, (pd == 0) ? 1 : 0); |
| 2605 | SREG_W(AVR8_SREG_C, | |
| 2757 | SREG_W(AVR8_SREG_C, BIT(pd,15) & NOT(BIT(rr,7))); | |
| 2606 | 2758 | m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff; |
| 2607 | 2759 | m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff; |
| 2608 | 2760 | opcycles = 2; |
| r19802 | r19803 | |
| 2662 | 2814 | break; |
| 2663 | 2815 | case 0xd000: // RCALL k |
| 2664 | 2816 | offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); |
| 2817 | push((m_pc + 1) & 0x00ff); | |
| 2665 | 2818 | push(((m_pc + 1) >> 8) & 0x00ff); |
| 2666 | push((m_pc + 1) & 0x00ff); | |
| 2667 | 2819 | m_pc += offs; |
| 2668 | 2820 | opcycles = 3; |
| 2669 | 2821 | break; |
| r19802 | r19803 | |
|---|---|---|
| 1 | /*************************************************************************** | |
| 1 | 2 | |
| 3 | Belogic Uzebox | |
| 4 | ||
| 5 | driver by Sandro Ronco | |
| 6 | ||
| 7 | TODO: | |
| 8 | - Sound | |
| 9 | - SDCard | |
| 10 | - Mouse | |
| 11 | ||
| 12 | ****************************************************************************/ | |
| 13 | ||
| 2 | 14 | #include "emu.h" |
| 3 | 15 | #include "cpu/avr8/avr8.h" |
| 4 | 16 | #include "sound/dac.h" |
| 5 | 17 | #include "imagedev/cartslot.h" |
| 6 | 18 | |
| 7 | 19 | // overclocked to 8 * NTSC burst frequency |
| 20 | #define MASTER_CLOCK 28618180 | |
| 8 | 21 | |
| 9 | #define | |
| 22 | #define INTERLACED 0 | |
| 10 | 23 | |
| 11 | #define ENABLE_VERBOSE_LOG (0) | |
| 12 | ||
| 13 | #if ENABLE_VERBOSE_LOG | |
| 14 | INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...) | |
| 15 | { | |
| 16 | if( VERBOSE_LEVEL >= n_level ) | |
| 17 | { | |
| 18 | va_list v; | |
| 19 | char buf[ 32768 ]; | |
| 20 | va_start( v, s_fmt ); | |
| 21 | vsprintf( buf, s_fmt, v ); | |
| 22 | va_end( v ); | |
| 23 | logerror( "%08x: %s", machine.device("maincpu")->safe_pc(), buf ); | |
| 24 | } | |
| 25 | } | |
| 26 | #else | |
| 27 | #define verboselog(x,y,z,...) | |
| 28 | #endif | |
| 29 | ||
| 30 | #define MASTER_CLOCK 28618180 | |
| 31 | ||
| 32 | 24 | class uzebox_state : public driver_device |
| 33 | 25 | { |
| 34 | 26 | public: |
| r19802 | r19803 | |
| 38 | 30 | { |
| 39 | 31 | } |
| 40 | 32 | |
| 41 | virtual void machine_start(); | |
| 42 | ||
| 43 | 33 | required_device<avr8_device> m_maincpu; |
| 44 | 34 | |
| 45 | DECLARE_READ8_MEMBER(port_r); | |
| 46 | DECLARE_WRITE8_MEMBER(port_w); | |
| 47 | DECLARE_DRIVER_INIT(uzebox); | |
| 35 | DECLARE_READ8_MEMBER(port_a_r); | |
| 36 | DECLARE_WRITE8_MEMBER(port_a_w); | |
| 37 | DECLARE_READ8_MEMBER(port_b_r); | |
| 38 | DECLARE_WRITE8_MEMBER(port_b_w); | |
| 39 | DECLARE_READ8_MEMBER(port_c_r); | |
| 40 | DECLARE_WRITE8_MEMBER(port_c_w); | |
| 41 | DECLARE_READ8_MEMBER(port_d_r); | |
| 42 | DECLARE_WRITE8_MEMBER(port_d_w); | |
| 43 | ||
| 44 | virtual void machine_start(); | |
| 48 | 45 | virtual void machine_reset(); |
| 46 | void line_update(); | |
| 49 | 47 | UINT32 screen_update_uzebox(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); |
| 48 | ||
| 49 | private: | |
| 50 | int m_vpos; | |
| 51 | UINT64 m_line_start_cycles; | |
| 52 | UINT32 m_line_pos_cycles; | |
| 53 | UINT8 m_port_a; | |
| 54 | UINT8 m_port_b; | |
| 55 | UINT8 m_port_c; | |
| 56 | UINT8 m_port_d; | |
| 57 | UINT16 m_joy_data[2]; | |
| 58 | bitmap_rgb32 m_bitmap; | |
| 50 | 59 | }; |
| 51 | 60 | |
| 52 | 61 | void uzebox_state::machine_start() |
| 53 | 62 | { |
| 63 | machine().primary_screen->register_screen_bitmap(m_bitmap); | |
| 54 | 64 | } |
| 55 | 65 | |
| 56 | ||
| 66 | void uzebox_state::machine_reset() | |
| 57 | 67 | { |
| 58 | return 0; | |
| 68 | m_vpos = 0; | |
| 69 | m_line_start_cycles = 0; | |
| 70 | m_line_pos_cycles = 0; | |
| 71 | m_port_a = 0; | |
| 72 | m_port_b = 0; | |
| 73 | m_port_c = 0; | |
| 74 | m_port_d = 0; | |
| 75 | m_joy_data[0] = m_joy_data[1] = 0; | |
| 59 | 76 | } |
| 60 | 77 | |
| 61 | WRITE8_MEMBER(uzebox_state::port_w) | |
| 78 | ||
| 79 | WRITE8_MEMBER(uzebox_state::port_a_w) | |
| 62 | 80 | { |
| 81 | // xxxx ---- NC | |
| 82 | // ---- x--- SNES controller clk | |
| 83 | // ---- -x-- SNES controller latch | |
| 84 | // ---- --x- SNES controller P2 data | |
| 85 | // ---- ---x SNES controller P1 data | |
| 86 | ||
| 87 | UINT8 changed = m_port_a ^ data; | |
| 88 | ||
| 89 | if (changed & data & 0x04) | |
| 90 | { | |
| 91 | m_joy_data[0] = ioport("P1")->read(); | |
| 92 | m_joy_data[1] = ioport("P2")->read(); | |
| 93 | } | |
| 94 | else if (changed & 0x08) | |
| 95 | { | |
| 96 | if (changed & data & 0x08) | |
| 97 | { | |
| 98 | m_joy_data[0] >>= 1; | |
| 99 | m_joy_data[1] >>= 1; | |
| 100 | } | |
| 101 | ||
| 102 | m_port_a = (m_joy_data[0] & 0x01) | ((m_joy_data[1] & 0x01) << 1); | |
| 103 | } | |
| 104 | ||
| 105 | m_port_a = (data & 0x0c) | (m_port_a & 0x03); | |
| 63 | 106 | } |
| 64 | 107 | |
| 108 | READ8_MEMBER(uzebox_state::port_a_r) | |
| 109 | { | |
| 110 | return m_port_a | 0xf0; | |
| 111 | } | |
| 112 | ||
| 113 | WRITE8_MEMBER(uzebox_state::port_b_w) | |
| 114 | { | |
| 115 | // xxx- ---- SDCard | |
| 116 | // ---x ---- AD725 CE | |
| 117 | // ---- x--- AD725 4FSC | |
| 118 | // ---- -xx- NC | |
| 119 | // ---- ---x AD725 HSYNC | |
| 120 | ||
| 121 | if (m_port_b & 0x10) | |
| 122 | if ((m_port_b ^ data) & m_port_b & 0x01) | |
| 123 | { | |
| 124 | line_update(); | |
| 125 | ||
| 126 | UINT32 cycles = (UINT32)(m_maincpu->get_elapsed_cycles() - m_line_start_cycles); | |
| 127 | if (cycles < 1000 && m_vpos >= 448) | |
| 128 | m_vpos = INTERLACED ? ((m_vpos ^ 0x01) & 0x01) : 0; | |
| 129 | else if (cycles > 1000) | |
| 130 | m_vpos += 2; | |
| 131 | ||
| 132 | m_line_start_cycles = m_maincpu->get_elapsed_cycles(); | |
| 133 | m_line_pos_cycles = 0; | |
| 134 | } | |
| 135 | ||
| 136 | m_port_b = data; | |
| 137 | } | |
| 138 | ||
| 139 | READ8_MEMBER(uzebox_state::port_b_r) | |
| 140 | { | |
| 141 | return m_port_b; | |
| 142 | } | |
| 143 | ||
| 144 | WRITE8_MEMBER(uzebox_state::port_c_w) | |
| 145 | { | |
| 146 | // xx-- ---- blue | |
| 147 | // --xx x--- green | |
| 148 | // ---- -xxx red | |
| 149 | ||
| 150 | line_update(); | |
| 151 | m_port_c = data; | |
| 152 | } | |
| 153 | ||
| 154 | READ8_MEMBER(uzebox_state::port_c_r) | |
| 155 | { | |
| 156 | return m_port_c; | |
| 157 | } | |
| 158 | ||
| 159 | WRITE8_MEMBER(uzebox_state::port_d_w) | |
| 160 | { | |
| 161 | // x--- ---- sound | |
| 162 | // -x-- ---- SDCard CS | |
| 163 | // ---x ---- LED | |
| 164 | // --x- x--- NC | |
| 165 | // ---- -x-- power | |
| 166 | // ---- --xx UART MIDI | |
| 167 | ||
| 168 | m_port_d = data; | |
| 169 | } | |
| 170 | ||
| 171 | READ8_MEMBER(uzebox_state::port_d_r) | |
| 172 | { | |
| 173 | return m_port_d; | |
| 174 | } | |
| 175 | ||
| 176 | ||
| 65 | 177 | /****************************************************\ |
| 66 | 178 | * Address maps * |
| 67 | 179 | \****************************************************/ |
| r19802 | r19803 | |
| 75 | 187 | ADDRESS_MAP_END |
| 76 | 188 | |
| 77 | 189 | static ADDRESS_MAP_START( uzebox_io_map, AS_IO, 8, uzebox_state ) |
| 78 | AM_RANGE(0x00, 0x03) AM_READWRITE( port_r, port_w ) | |
| 190 | AM_RANGE(AVR8_REG_A, AVR8_REG_A) AM_READWRITE( port_a_r, port_a_w ) | |
| 191 | AM_RANGE(AVR8_REG_B, AVR8_REG_B) AM_READWRITE( port_b_r, port_b_w ) | |
| 192 | AM_RANGE(AVR8_REG_C, AVR8_REG_C) AM_READWRITE( port_c_r, port_c_w ) | |
| 193 | AM_RANGE(AVR8_REG_D, AVR8_REG_D) AM_READWRITE( port_d_r, port_d_w ) | |
| 79 | 194 | ADDRESS_MAP_END |
| 80 | 195 | |
| 81 | 196 | /****************************************************\ |
| r19802 | r19803 | |
| 83 | 198 | \****************************************************/ |
| 84 | 199 | |
| 85 | 200 | static INPUT_PORTS_START( uzebox ) |
| 201 | PORT_START( "P1" ) | |
| 202 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) | |
| 203 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) | |
| 204 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) | |
| 205 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START1 ) PORT_NAME("P1 Start") PORT_PLAYER(1) | |
| 206 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) | |
| 207 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) | |
| 208 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) | |
| 209 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) | |
| 210 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) | |
| 211 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) | |
| 212 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(1) | |
| 213 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(1) | |
| 214 | PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 215 | ||
| 216 | PORT_START( "P2" ) | |
| 217 | PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(2) | |
| 218 | PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(2) | |
| 219 | PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(2) | |
| 220 | PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_START2 ) PORT_NAME("P1 Start") PORT_PLAYER(2) | |
| 221 | PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) | |
| 222 | PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) | |
| 223 | PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) | |
| 224 | PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) | |
| 225 | PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(2) | |
| 226 | PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(2) | |
| 227 | PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) | |
| 228 | PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) | |
| 229 | PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED ) | |
| 86 | 230 | INPUT_PORTS_END |
| 87 | 231 | |
| 88 | 232 | /****************************************************\ |
| 89 | 233 | * Video hardware * |
| 90 | 234 | \****************************************************/ |
| 91 | 235 | |
| 236 | void uzebox_state::line_update() | |
| 237 | { | |
| 238 | UINT32 cycles = (UINT32)(m_maincpu->get_elapsed_cycles() - m_line_start_cycles) / 2; | |
| 239 | ||
| 240 | for (UINT32 x = m_line_pos_cycles; x < cycles; x++) | |
| 241 | { | |
| 242 | if (m_bitmap.cliprect().contains(x, m_vpos)) | |
| 243 | m_bitmap.pix32(m_vpos, x) = MAKE_RGB(pal3bit(m_port_c >> 0), pal3bit(m_port_c >> 3), pal2bit(m_port_c >> 6)); | |
| 244 | if (!INTERLACED) | |
| 245 | if (m_bitmap.cliprect().contains(x, m_vpos + 1)) | |
| 246 | m_bitmap.pix32(m_vpos + 1, x) = MAKE_RGB(pal3bit(m_port_c >> 0), pal3bit(m_port_c >> 3), pal2bit(m_port_c >> 6)); | |
| 247 | } | |
| 248 | ||
| 249 | m_line_pos_cycles = cycles; | |
| 250 | } | |
| 251 | ||
| 92 | 252 | UINT32 uzebox_state::screen_update_uzebox(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) |
| 93 | 253 | { |
| 254 | copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); | |
| 94 | 255 | return 0; |
| 95 | 256 | } |
| 96 | 257 | |
| r19802 | r19803 | |
| 98 | 259 | * Machine definition * |
| 99 | 260 | \****************************************************/ |
| 100 | 261 | |
| 101 | DRIVER_INIT_MEMBER(uzebox_state,uzebox) | |
| 102 | { | |
| 103 | } | |
| 104 | ||
| 105 | void uzebox_state::machine_reset() | |
| 106 | { | |
| 107 | } | |
| 108 | ||
| 109 | 262 | const avr8_config atmega644_config = |
| 110 | 263 | { |
| 111 | 264 | "eeprom" |
| r19802 | r19803 | |
| 122 | 275 | |
| 123 | 276 | /* video hardware */ |
| 124 | 277 | MCFG_SCREEN_ADD("screen", RASTER) |
| 125 | MCFG_SCREEN_REFRESH_RATE( | |
| 278 | MCFG_SCREEN_REFRESH_RATE(59.99) | |
| 126 | 279 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1395)) |
| 127 | MCFG_SCREEN_SIZE(634, 480) | |
| 128 | MCFG_SCREEN_VISIBLE_AREA(0, 633, 0, 479) | |
| 280 | MCFG_SCREEN_SIZE(870, 525) | |
| 281 | MCFG_SCREEN_VISIBLE_AREA(150, 870-1, 40, 488-1) | |
| 129 | 282 | MCFG_SCREEN_UPDATE_DRIVER(uzebox_state, screen_update_uzebox) |
| 130 | 283 | |
| 131 | MCFG_PALETTE_LENGTH(0x1000) | |
| 132 | ||
| 133 | 284 | /* sound hardware */ |
| 134 | 285 | MCFG_SPEAKER_STANDARD_MONO("avr8") |
| 135 | 286 | MCFG_SOUND_ADD("dac", DAC, 0) |
| r19802 | r19803 | |
| 142 | 293 | MACHINE_CONFIG_END |
| 143 | 294 | |
| 144 | 295 | ROM_START( uzebox ) |
| 145 | ROM_REGION( 0x10000, "maincpu", 0 ) /* Main program store */ | |
| 146 | ROM_CART_LOAD("cart1", 0x0000, 0x10000, ROM_OPTIONAL) | |
| 296 | ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) /* Main program store */ | |
| 297 | ROM_CART_LOAD("cart1", 0x0000, 0x10000, ROM_OPTIONAL | ROM_FILL_FF) | |
| 147 | 298 | |
| 148 | 299 | ROM_REGION( 0x200, "eeprom", ROMREGION_ERASE00 ) /* on-die eeprom */ |
| 149 | 300 | ROM_END |
| 150 | 301 | |
| 151 | 302 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ |
| 152 | CONS(2010, uzebox, 0, 0, uzebox, uzebox, | |
| 303 | CONS(2010, uzebox, 0, 0, uzebox, uzebox, driver_device, 0, "Belogic", "Uzebox", GAME_NO_SOUND | GAME_NOT_WORKING) |
| Previous | 199869 Revisions | Next |