trunk/src/emu/cpu/powerpc/ppccom.c
r17590 | r17591 | |
39 | 39 | static TIMER_CALLBACK( ppc4xx_spu_callback ); |
40 | 40 | static TIMER_CALLBACK( decrementer_int_callback ); |
41 | 41 | |
| 42 | static TIMER_CALLBACK( ppc4xx_buffered_dma_callback ); |
| 43 | |
42 | 44 | static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state); |
43 | 45 | |
44 | 46 | static void ppc4xx_dma_update_irq_states(powerpc_state *ppc); |
r17590 | r17591 | |
341 | 343 | ppc->spu.timer = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_spu_callback), ppc); |
342 | 344 | } |
343 | 345 | |
| 346 | if (cap & PPCCAP_4XX) |
| 347 | { |
| 348 | ppc->buffered_dma_timer[0] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 349 | ppc->buffered_dma_timer[1] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 350 | ppc->buffered_dma_timer[2] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 351 | ppc->buffered_dma_timer[3] = device->machine().scheduler().timer_alloc(FUNC(ppc4xx_buffered_dma_callback), ppc); |
| 352 | |
| 353 | ppc->buffered_dma_rate[0] = 10000; |
| 354 | ppc->buffered_dma_rate[1] = 10000; |
| 355 | ppc->buffered_dma_rate[2] = 10000; |
| 356 | ppc->buffered_dma_rate[3] = 10000; |
| 357 | } |
| 358 | |
344 | 359 | /* register for save states */ |
345 | 360 | device->save_item(NAME(ppc->pc)); |
346 | 361 | device->save_item(NAME(ppc->r)); |
r17590 | r17591 | |
1749 | 1764 | |
1750 | 1765 | /* update the IRQ state for each DMA channel */ |
1751 | 1766 | for (dmachan = 0; dmachan < 4; dmachan++) |
| 1767 | { |
1752 | 1768 | if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & (0x11 << (27 - dmachan)))) |
1753 | 1769 | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE); |
1754 | 1770 | else |
1755 | 1771 | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE); |
| 1772 | |
| 1773 | // DMA chaining interrupts |
| 1774 | switch (dmachan) |
| 1775 | { |
| 1776 | case 0: |
| 1777 | if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & 0x80000)) |
| 1778 | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE); |
| 1779 | else |
| 1780 | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE); |
| 1781 | break; |
| 1782 | |
| 1783 | case 1: |
| 1784 | case 2: |
| 1785 | case 3: |
| 1786 | if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & (1 << (7 - dmachan)))) |
| 1787 | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE); |
| 1788 | else |
| 1789 | ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE); |
| 1790 | break; |
| 1791 | } |
| 1792 | } |
1756 | 1793 | } |
1757 | 1794 | |
1758 | 1795 | |
r17590 | r17591 | |
1773 | 1810 | if ((dmaregs[DCR4XX_DMACT0] & 0xffff) != 0) |
1774 | 1811 | return FALSE; |
1775 | 1812 | |
1776 | | /* set the complete bit and handle interrupts */ |
1777 | | ppc->dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan); |
1778 | | // ppc->dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan); |
1779 | | ppc4xx_dma_update_irq_states(ppc); |
| 1813 | // if chained mode |
| 1814 | if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CH) |
| 1815 | { |
| 1816 | dmaregs[DCR4XX_DMADA0] = dmaregs[DCR4XX_DMASA0]; |
| 1817 | dmaregs[DCR4XX_DMACT0] = dmaregs[DCR4XX_DMACC0]; |
| 1818 | dmaregs[DCR4XX_DMACR0] &= ~PPC4XX_DMACR_CH; |
| 1819 | |
| 1820 | switch (dmachan) |
| 1821 | { |
| 1822 | case 0: |
| 1823 | ppc->dcr[DCR4XX_DMASR] |= 0x00080000; |
| 1824 | break; |
| 1825 | |
| 1826 | case 1: |
| 1827 | case 2: |
| 1828 | case 3: |
| 1829 | ppc->dcr[DCR4XX_DMASR] |= 1 << (7 - dmachan); |
| 1830 | break; |
| 1831 | } |
| 1832 | |
| 1833 | ppc4xx_dma_update_irq_states(ppc); |
| 1834 | |
| 1835 | INT64 numdata = dmaregs[DCR4XX_DMACT0]; |
| 1836 | if (numdata == 0) |
| 1837 | numdata = 65536; |
| 1838 | |
| 1839 | INT64 time = (numdata * 1000000) / ppc->buffered_dma_rate[dmachan]; |
| 1840 | |
| 1841 | ppc->buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); |
| 1842 | } |
| 1843 | else |
| 1844 | { |
| 1845 | /* set the complete bit and handle interrupts */ |
| 1846 | ppc->dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan); |
| 1847 | // ppc->dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan); |
| 1848 | ppc4xx_dma_update_irq_states(ppc); |
| 1849 | |
| 1850 | ppc->buffered_dma_timer[dmachan]->adjust(attotime::never, FALSE); |
| 1851 | } |
1780 | 1852 | return TRUE; |
1781 | 1853 | } |
1782 | 1854 | |
1783 | 1855 | |
1784 | 1856 | /*------------------------------------------------- |
| 1857 | buffered_dma_callback - callback that fires |
| 1858 | when buffered DMA transfer is ready |
| 1859 | -------------------------------------------------*/ |
| 1860 | |
| 1861 | static TIMER_CALLBACK( ppc4xx_buffered_dma_callback ) |
| 1862 | { |
| 1863 | powerpc_state *ppc = (powerpc_state *)ptr; |
| 1864 | int dmachan = param; |
| 1865 | |
| 1866 | static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 }; |
| 1867 | UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; |
| 1868 | INT32 destinc; |
| 1869 | UINT8 width; |
| 1870 | |
| 1871 | width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PW_MASK) >> 26]; |
| 1872 | destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0; |
| 1873 | |
| 1874 | if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TD) |
| 1875 | { |
| 1876 | /* peripheral to memory */ |
| 1877 | |
| 1878 | switch (width) |
| 1879 | { |
| 1880 | /* byte transfer */ |
| 1881 | case 1: |
| 1882 | do |
| 1883 | { |
| 1884 | UINT8 data = 0; |
| 1885 | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
| 1886 | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 1); |
| 1887 | ppc->program->write_byte(dmaregs[DCR4XX_DMADA0], data); |
| 1888 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1889 | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 1890 | break; |
| 1891 | |
| 1892 | /* word transfer */ |
| 1893 | case 2: |
| 1894 | do |
| 1895 | { |
| 1896 | UINT16 data = 0; |
| 1897 | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
| 1898 | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 2); |
| 1899 | ppc->program->write_word(dmaregs[DCR4XX_DMADA0], data); |
| 1900 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1901 | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 1902 | break; |
| 1903 | |
| 1904 | /* dword transfer */ |
| 1905 | case 4: |
| 1906 | do |
| 1907 | { |
| 1908 | UINT32 data = 0; |
| 1909 | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
| 1910 | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 4); |
| 1911 | ppc->program->write_dword(dmaregs[DCR4XX_DMADA0], data); |
| 1912 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1913 | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 1914 | break; |
| 1915 | } |
| 1916 | } |
| 1917 | else |
| 1918 | { |
| 1919 | /* memory to peripheral */ |
| 1920 | |
| 1921 | // data is read from destination address! |
| 1922 | switch (width) |
| 1923 | { |
| 1924 | /* byte transfer */ |
| 1925 | case 1: |
| 1926 | do |
| 1927 | { |
| 1928 | UINT8 data = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]); |
| 1929 | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
| 1930 | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 1, data); |
| 1931 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1932 | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 1933 | break; |
| 1934 | |
| 1935 | /* word transfer */ |
| 1936 | case 2: |
| 1937 | do |
| 1938 | { |
| 1939 | UINT16 data = ppc->program->read_word(dmaregs[DCR4XX_DMADA0]); |
| 1940 | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
| 1941 | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 2, data); |
| 1942 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1943 | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 1944 | break; |
| 1945 | |
| 1946 | /* dword transfer */ |
| 1947 | case 4: |
| 1948 | do |
| 1949 | { |
| 1950 | UINT32 data = ppc->program->read_dword(dmaregs[DCR4XX_DMADA0]); |
| 1951 | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
| 1952 | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 4, data); |
| 1953 | dmaregs[DCR4XX_DMADA0] += destinc; |
| 1954 | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
| 1955 | break; |
| 1956 | } |
| 1957 | } |
| 1958 | } |
| 1959 | |
| 1960 | |
| 1961 | /*------------------------------------------------- |
1785 | 1962 | ppc4xx_dma_fetch_transmit_byte - fetch a byte |
1786 | 1963 | to send to a peripheral |
1787 | 1964 | -------------------------------------------------*/ |
r17590 | r17591 | |
1848 | 2025 | /* check for unsupported features */ |
1849 | 2026 | if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TCE)) |
1850 | 2027 | fatalerror("ppc4xx_dma_exec: DMA_TCE == 0"); |
1851 | | if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CH) |
1852 | | fatalerror("ppc4xx_dma_exec: DMA chaining not implemented"); |
1853 | 2028 | |
1854 | 2029 | /* transfer mode */ |
1855 | 2030 | switch ((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TM_MASK) >> 21) |
r17590 | r17591 | |
1860 | 2035 | { |
1861 | 2036 | /* buffered DMA with external peripheral */ |
1862 | 2037 | |
1863 | | width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PW_MASK) >> 26]; |
1864 | | destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0; |
| 2038 | INT64 numdata = dmaregs[DCR4XX_DMACT0]; |
| 2039 | if (numdata == 0) |
| 2040 | numdata = 65536; |
1865 | 2041 | |
1866 | | if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TD) |
| 2042 | INT64 time; |
| 2043 | if (numdata > 100) |
1867 | 2044 | { |
1868 | | /* peripheral to memory */ |
1869 | | |
1870 | | switch (width) |
1871 | | { |
1872 | | /* byte transfer */ |
1873 | | case 1: |
1874 | | do |
1875 | | { |
1876 | | UINT8 data = 0; |
1877 | | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
1878 | | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 1); |
1879 | | ppc->program->write_byte(dmaregs[DCR4XX_DMADA0], data); |
1880 | | dmaregs[DCR4XX_DMADA0] += destinc; |
1881 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
1882 | | break; |
1883 | | |
1884 | | /* word transfer */ |
1885 | | case 2: |
1886 | | do |
1887 | | { |
1888 | | UINT16 data = 0; |
1889 | | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
1890 | | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 2); |
1891 | | ppc->program->write_word(dmaregs[DCR4XX_DMADA0], data); |
1892 | | dmaregs[DCR4XX_DMADA0] += destinc; |
1893 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
1894 | | break; |
1895 | | |
1896 | | /* dword transfer */ |
1897 | | case 4: |
1898 | | do |
1899 | | { |
1900 | | UINT32 data = 0; |
1901 | | if (ppc->ext_dma_read_handler[dmachan] != NULL) |
1902 | | data = (*ppc->ext_dma_read_handler[dmachan])(ppc->device, 4); |
1903 | | ppc->program->write_dword(dmaregs[DCR4XX_DMADA0], data); |
1904 | | dmaregs[DCR4XX_DMADA0] += destinc; |
1905 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
1906 | | break; |
1907 | | } |
| 2045 | time = (numdata * 1000000) / ppc->buffered_dma_rate[dmachan]; |
1908 | 2046 | } |
1909 | 2047 | else |
1910 | 2048 | { |
1911 | | /* memory to peripheral */ |
| 2049 | time = 0; // let very short transfers occur instantly |
| 2050 | } |
1912 | 2051 | |
1913 | | // data is read from destination address! |
1914 | | switch (width) |
1915 | | { |
1916 | | /* byte transfer */ |
1917 | | case 1: |
1918 | | do |
1919 | | { |
1920 | | UINT8 data = ppc->program->read_byte(dmaregs[DCR4XX_DMADA0]); |
1921 | | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
1922 | | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 1, data); |
1923 | | dmaregs[DCR4XX_DMADA0] += destinc; |
1924 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
1925 | | break; |
1926 | | |
1927 | | /* word transfer */ |
1928 | | case 2: |
1929 | | do |
1930 | | { |
1931 | | UINT16 data = ppc->program->read_word(dmaregs[DCR4XX_DMADA0]); |
1932 | | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
1933 | | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 2, data); |
1934 | | dmaregs[DCR4XX_DMADA0] += destinc; |
1935 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
1936 | | break; |
1937 | | |
1938 | | /* dword transfer */ |
1939 | | case 4: |
1940 | | do |
1941 | | { |
1942 | | UINT32 data = ppc->program->read_dword(dmaregs[DCR4XX_DMADA0]); |
1943 | | if (ppc->ext_dma_write_handler[dmachan] != NULL) |
1944 | | (*ppc->ext_dma_write_handler[dmachan])(ppc->device, 4, data); |
1945 | | dmaregs[DCR4XX_DMADA0] += destinc; |
1946 | | } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); |
1947 | | break; |
1948 | | } |
1949 | | } |
| 2052 | ppc->buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); |
1950 | 2053 | } |
1951 | 2054 | else /* buffered DMA with internal peripheral (SPU) */ |
1952 | 2055 | { |
r17590 | r17591 | |
2360 | 2463 | specific external DMA read handler configuration |
2361 | 2464 | -------------------------------------------------*/ |
2362 | 2465 | |
2363 | | void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler) |
| 2466 | void ppc4xx_set_dma_read_handler(device_t *device, int channel, ppc4xx_dma_read_handler handler, int rate) |
2364 | 2467 | { |
2365 | 2468 | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
2366 | 2469 | ppc->ext_dma_read_handler[channel] = handler; |
| 2470 | ppc->buffered_dma_rate[channel] = rate; |
2367 | 2471 | } |
2368 | 2472 | |
2369 | 2473 | /*------------------------------------------------- |
r17590 | r17591 | |
2371 | 2475 | specific external DMA write handler configuration |
2372 | 2476 | -------------------------------------------------*/ |
2373 | 2477 | |
2374 | | void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler) |
| 2478 | void ppc4xx_set_dma_write_handler(device_t *device, int channel, ppc4xx_dma_write_handler handler, int rate) |
2375 | 2479 | { |
2376 | 2480 | powerpc_state *ppc = *(powerpc_state **)downcast<legacy_cpu_device *>(device)->token(); |
2377 | 2481 | ppc->ext_dma_write_handler[channel] = handler; |
| 2482 | ppc->buffered_dma_rate[channel] = rate; |
2378 | 2483 | } |
2379 | 2484 | |
2380 | 2485 | |