filename | test/dmac.c |
changeset | 815:866c103d72cd |
prev | 812:8cc61d5ea1f8 |
author | nkeynes |
date | Fri Dec 02 18:18:04 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | SH4 shadow-mode tweaks - Fix exceptions generated by the translator to account for the excepting instruction(s) in the cycle counts. - Compare floating point regs bitwise rather than with FP comparisons (otherwise can fail due to nan != nan) - Dump the translated block when we abort with an inconsistency |
file | annotate | diff | log | raw |
nkeynes@185 | 1 | /** |
nkeynes@561 | 2 | * $Id$ |
nkeynes@185 | 3 | * |
nkeynes@185 | 4 | * DMA support code |
nkeynes@185 | 5 | * |
nkeynes@185 | 6 | * Copyright (c) 2006 Nathan Keynes. |
nkeynes@185 | 7 | * |
nkeynes@185 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@185 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@185 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@185 | 11 | * (at your option) any later version. |
nkeynes@185 | 12 | * |
nkeynes@185 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@185 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@185 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@185 | 16 | * GNU General Public License for more details. |
nkeynes@185 | 17 | */ |
nkeynes@185 | 18 | |
nkeynes@815 | 19 | #include <assert.h> |
nkeynes@185 | 20 | #include "dma.h" |
nkeynes@185 | 21 | #include "asic.h" |
nkeynes@185 | 22 | |
nkeynes@185 | 23 | #define DMA_BASE 0xFFA00000 |
nkeynes@185 | 24 | |
nkeynes@185 | 25 | #define DMA_SAR(c) (DMA_BASE+0x00+(c<<4)) |
nkeynes@185 | 26 | #define DMA_DAR(c) (DMA_BASE+0x04+(c<<4)) |
nkeynes@185 | 27 | #define DMA_TCR(c) (DMA_BASE+0x08+(c<<4)) |
nkeynes@185 | 28 | #define DMA_CHCR(c) (DMA_BASE+0x0C+(c<<4)) |
nkeynes@185 | 29 | #define DMA_OR (DMA_BASE+0x40) |
nkeynes@185 | 30 | |
nkeynes@185 | 31 | #define ASIC_BASE 0xA05F6000 |
nkeynes@185 | 32 | #define PVR_DMA_DEST (ASIC_BASE+0x800) |
nkeynes@185 | 33 | #define PVR_DMA_COUNT (ASIC_BASE+0x804) |
nkeynes@185 | 34 | #define PVR_DMA_CTL (ASIC_BASE+0x808) |
nkeynes@185 | 35 | #define PVR_DMA_REGION (ASIC_BASE+0x884) |
nkeynes@185 | 36 | |
nkeynes@753 | 37 | #define SORT_DMA_TABLE (ASIC_BASE+0x810) |
nkeynes@753 | 38 | #define SORT_DMA_DATA (ASIC_BASE+0x814) |
nkeynes@753 | 39 | #define SORT_DMA_TABLEBITS (ASIC_BASE+0x818) |
nkeynes@753 | 40 | #define SORT_DMA_DATASIZE (ASIC_BASE+0x81C) |
nkeynes@753 | 41 | #define SORT_DMA_CTL (ASIC_BASE+0x820) |
nkeynes@753 | 42 | #define SORT_DMA_COUNT (ASIC_BASE+0x860) |
nkeynes@753 | 43 | |
nkeynes@815 | 44 | #define AICA_RAM_BASE 0xA0800000 |
nkeynes@815 | 45 | #define AICA_RAM_SIZE 0x00200000 |
nkeynes@812 | 46 | |
nkeynes@812 | 47 | #define G2DMABASE 0xA05F7800 |
nkeynes@812 | 48 | #define G2DMATIMEOUT (G2DMABASE+0x90) |
nkeynes@812 | 49 | #define G2DMAMAGIC (G2DMABASE+0xBC) |
nkeynes@812 | 50 | #define G2DMAEXT(x) (G2DMABASE+(0x20*(x))) |
nkeynes@812 | 51 | #define G2DMAHOST(x) (G2DMABASE+(0x20*(x))+0x04) |
nkeynes@812 | 52 | #define G2DMASIZE(x) (G2DMABASE+(0x20*(x))+0x08) |
nkeynes@812 | 53 | #define G2DMADIR(x) (G2DMABASE+(0x20*(x))+0x0C) |
nkeynes@812 | 54 | #define G2DMAMODE(x) (G2DMABASE+(0x20*(x))+0x10) |
nkeynes@812 | 55 | #define G2DMACTL1(x) (G2DMABASE+(0x20*(x))+0x14) |
nkeynes@812 | 56 | #define G2DMACTL2(x) (G2DMABASE+(0x20*(x))+0x18) |
nkeynes@812 | 57 | #define G2DMASTOP(x) (G2DMABASE+(0x20*(x))+0x1C) |
nkeynes@812 | 58 | |
nkeynes@185 | 59 | void dmac_dump_channel( FILE *f, unsigned int channel ) |
nkeynes@185 | 60 | { |
nkeynes@185 | 61 | fprintf( f, "DMAC SAR: %08X Count: %08X Ctl: %08X OR: %08X\n", |
nkeynes@185 | 62 | long_read(DMA_SAR(channel)), long_read(DMA_TCR(channel)), |
nkeynes@185 | 63 | long_read(DMA_CHCR(channel)), long_read(DMA_OR) ); |
nkeynes@185 | 64 | } |
nkeynes@185 | 65 | |
nkeynes@185 | 66 | |
nkeynes@185 | 67 | /** |
nkeynes@185 | 68 | * Setup the DMAC for a transfer. Assumes 32-byte block transfer. |
nkeynes@185 | 69 | * Caller is responsible for making sure no-one else is using the |
nkeynes@185 | 70 | * channel already. |
nkeynes@185 | 71 | * |
nkeynes@185 | 72 | * @param channel DMA channel to use, 0 to 3 |
nkeynes@185 | 73 | * @param source source address (if a memory source) |
nkeynes@185 | 74 | * @param dest destination address (if a memory destination) |
nkeynes@185 | 75 | * @param length number of bytes to transfer (must be a multiple of |
nkeynes@185 | 76 | * 32. |
nkeynes@185 | 77 | * @param direction 0 = host to device, 1 = device to host |
nkeynes@185 | 78 | */ |
nkeynes@185 | 79 | void dmac_prepare_channel( int channel, uint32_t source, uint32_t dest, |
nkeynes@185 | 80 | uint32_t length, int direction ) |
nkeynes@185 | 81 | { |
nkeynes@185 | 82 | uint32_t control; |
nkeynes@185 | 83 | |
nkeynes@185 | 84 | if( direction == 0 ) { |
nkeynes@185 | 85 | /* DMA Disabled, IRQ disabled, 32 byte transfer, burst mode, |
nkeynes@185 | 86 | * Memory => Device, Source addr increment, dest addr fixed |
nkeynes@185 | 87 | */ |
nkeynes@185 | 88 | control = 0x000012C0; |
nkeynes@185 | 89 | } else { |
nkeynes@185 | 90 | /* DMA Disabled, IRQ disabled, 32 byte transfer, burst mode, |
nkeynes@185 | 91 | * Device => Memory, Source addr fixed, dest addr increment |
nkeynes@185 | 92 | */ |
nkeynes@185 | 93 | control = 0x000043C0; |
nkeynes@185 | 94 | } |
nkeynes@185 | 95 | long_write( DMA_CHCR(channel), control ); |
nkeynes@185 | 96 | long_write( DMA_SAR(channel), source ); |
nkeynes@185 | 97 | long_write( DMA_DAR(channel), dest ); |
nkeynes@185 | 98 | long_write( DMA_TCR(channel), (length >> 5) ); |
nkeynes@185 | 99 | control |= 0x0001; |
nkeynes@185 | 100 | long_write( DMA_CHCR(channel), control ); /* Enable DMA channel */ |
nkeynes@185 | 101 | long_write( DMA_OR, 0x8201 ); /* Ensure the DMAC config is set */ |
nkeynes@185 | 102 | } |
nkeynes@185 | 103 | |
nkeynes@185 | 104 | |
nkeynes@185 | 105 | int pvr_dma_write( unsigned int target, char *buf, int len, int region ) |
nkeynes@185 | 106 | { |
nkeynes@185 | 107 | uint32_t addr =(uint32_t)buf; |
nkeynes@185 | 108 | int result; |
nkeynes@185 | 109 | if( (addr & 0xFFFFFFE0) != addr ) { |
nkeynes@185 | 110 | fprintf( stderr, "Address error: Attempting DMA from %08X\n", addr ); |
nkeynes@185 | 111 | return -1; |
nkeynes@185 | 112 | } |
nkeynes@185 | 113 | long_write( PVR_DMA_CTL, 0 ); /* Stop PVR dma if it's already running */ |
nkeynes@185 | 114 | asic_clear(); |
nkeynes@185 | 115 | |
nkeynes@185 | 116 | dmac_prepare_channel( 2, (uint32_t)buf, 0, len, 0 ); /* Allocate channel 2 */ |
nkeynes@185 | 117 | long_write( PVR_DMA_DEST, target ); |
nkeynes@185 | 118 | long_write( PVR_DMA_COUNT, len ); |
nkeynes@185 | 119 | long_write( PVR_DMA_REGION, region ); |
nkeynes@185 | 120 | |
nkeynes@185 | 121 | CHECK_IEQUALS( target, long_read(PVR_DMA_DEST) ); |
nkeynes@185 | 122 | CHECK_IEQUALS( len, long_read(PVR_DMA_COUNT) ); |
nkeynes@185 | 123 | CHECK_IEQUALS( 0, long_read(PVR_DMA_REGION) ); |
nkeynes@185 | 124 | CHECK_IEQUALS( (uint32_t)buf, long_read(DMA_SAR(2)) ); |
nkeynes@185 | 125 | CHECK_IEQUALS( len/32, long_read(DMA_TCR(2)) ); |
nkeynes@185 | 126 | CHECK_IEQUALS( 0x12C1, long_read(DMA_CHCR(2)) ); |
nkeynes@185 | 127 | |
nkeynes@185 | 128 | long_write( PVR_DMA_CTL, 1 ); |
nkeynes@185 | 129 | result = asic_wait(EVENT_PVR_DMA); |
nkeynes@185 | 130 | |
nkeynes@185 | 131 | if( result != 0 ) { |
nkeynes@185 | 132 | fprintf( stderr, "PVR DMA failed (timeout)\n" ); |
nkeynes@185 | 133 | asic_dump(stderr); |
nkeynes@185 | 134 | fprintf( stderr, "Dest: %08X Count: %08X Ctl: %08X\n", long_read(PVR_DMA_DEST), |
nkeynes@185 | 135 | long_read(PVR_DMA_COUNT), long_read(PVR_DMA_CTL) ); |
nkeynes@185 | 136 | dmac_dump_channel(stderr, 2); |
nkeynes@185 | 137 | long_write( PVR_DMA_CTL, 0 ); |
nkeynes@185 | 138 | } |
nkeynes@185 | 139 | |
nkeynes@185 | 140 | CHECK_IEQUALS( 0, long_read(PVR_DMA_CTL) ); |
nkeynes@185 | 141 | CHECK_IEQUALS( ((uint32_t)buf)+len, long_read(DMA_SAR(2)) ); |
nkeynes@185 | 142 | CHECK_IEQUALS( 0, long_read(DMA_TCR(2)) ); |
nkeynes@185 | 143 | CHECK_IEQUALS( 0x12C3, long_read(DMA_CHCR(2)) ); |
nkeynes@185 | 144 | CHECK_IEQUALS( target, long_read(PVR_DMA_DEST) ); |
nkeynes@185 | 145 | CHECK_IEQUALS( 0, long_read(PVR_DMA_COUNT) ); |
nkeynes@185 | 146 | CHECK_IEQUALS( 0, long_read(PVR_DMA_REGION) ); |
nkeynes@185 | 147 | |
nkeynes@185 | 148 | return result; |
nkeynes@185 | 149 | } |
nkeynes@753 | 150 | |
nkeynes@753 | 151 | int sort_dma_write( char *sorttable, int tablelen, char *data, int datalen, int bitwidth, int datasize ) |
nkeynes@753 | 152 | { |
nkeynes@753 | 153 | int result; |
nkeynes@753 | 154 | uint32_t tableaddr = (uint32_t)sorttable; |
nkeynes@753 | 155 | uint32_t dataaddr = (uint32_t)data; |
nkeynes@753 | 156 | |
nkeynes@753 | 157 | long_write( SORT_DMA_CTL, 0 ); |
nkeynes@753 | 158 | asic_clear(); |
nkeynes@753 | 159 | |
nkeynes@753 | 160 | long_write( SORT_DMA_TABLE, tableaddr ); |
nkeynes@753 | 161 | long_write( SORT_DMA_DATA, dataaddr ); |
nkeynes@753 | 162 | long_write( SORT_DMA_TABLEBITS, bitwidth ); |
nkeynes@753 | 163 | long_write( SORT_DMA_DATASIZE, datasize ); |
nkeynes@753 | 164 | long_write( SORT_DMA_CTL, 1 ); |
nkeynes@753 | 165 | result = asic_wait2(EVENT_SORT_DMA, EVENT_SORT_DMA_ERR); |
nkeynes@753 | 166 | if( result == -1 ) { |
nkeynes@753 | 167 | fprintf( stderr, "SORT DMA failed (timeout)\n" ); |
nkeynes@753 | 168 | asic_dump(stderr); |
nkeynes@753 | 169 | fprintf( stderr, "Table: %08X Count: %08X Ctl: %08X\n", long_read(SORT_DMA_TABLE), long_read(SORT_DMA_COUNT), |
nkeynes@753 | 170 | long_read(SORT_DMA_CTL) ); |
nkeynes@753 | 171 | long_write( SORT_DMA_CTL, 0 ); |
nkeynes@753 | 172 | } |
nkeynes@753 | 173 | CHECK_IEQUALS( 0, long_read(SORT_DMA_CTL) ); |
nkeynes@753 | 174 | return result; |
nkeynes@753 | 175 | } |
nkeynes@812 | 176 | |
nkeynes@812 | 177 | int aica_dma_transfer( uint32_t aica_addr, char *data, uint32_t size, int writeFlag ) |
nkeynes@812 | 178 | { |
nkeynes@812 | 179 | long_write( G2DMATIMEOUT, 0 ); |
nkeynes@812 | 180 | long_write( G2DMAMAGIC, 0x4659404f ); |
nkeynes@812 | 181 | long_write( G2DMACTL1(0), 0 ); |
nkeynes@812 | 182 | long_write( G2DMAEXT(0), aica_addr ); |
nkeynes@812 | 183 | long_write( G2DMAHOST(0), ((uint32_t)data) ); |
nkeynes@812 | 184 | long_write( G2DMASIZE(0), ((size+31)&0x7FFFFFE0) | 0x80000000 ); |
nkeynes@812 | 185 | long_write( G2DMADIR(0), (writeFlag ? 0 : 1) ); |
nkeynes@812 | 186 | long_write( G2DMAMODE(0), 0 ); |
nkeynes@812 | 187 | |
nkeynes@812 | 188 | long_write( G2DMACTL1(0), 1 ); |
nkeynes@812 | 189 | long_write( G2DMACTL2(0), 1 ); |
nkeynes@812 | 190 | if( asic_wait( EVENT_G2_DMA0 ) != 0 ) { |
nkeynes@812 | 191 | fprintf( stderr, "Timeout waiting for G2 DMA event\n" ); |
nkeynes@812 | 192 | return -1; |
nkeynes@812 | 193 | } |
nkeynes@812 | 194 | // CHECK_IEQUALS( 0, long_read( G2DMACTL1(0) ) ); |
nkeynes@812 | 195 | CHECK_IEQUALS( 0, long_read( G2DMACTL2(0) ) ); |
nkeynes@812 | 196 | return 0; |
nkeynes@812 | 197 | } |
nkeynes@812 | 198 | |
nkeynes@812 | 199 | int aica_dma_write( uint32_t aica_addr, char *data, uint32_t size ) |
nkeynes@812 | 200 | { |
nkeynes@812 | 201 | return aica_dma_transfer( aica_addr, data, size, 1 ); |
nkeynes@812 | 202 | } |
nkeynes@812 | 203 | |
nkeynes@812 | 204 | int aica_dma_read( char *data, uint32_t aica_addr, uint32_t size ) |
nkeynes@812 | 205 | { |
nkeynes@812 | 206 | return aica_dma_transfer( aica_addr, data, size, 0 ); |
nkeynes@812 | 207 | } |
nkeynes@815 | 208 | |
nkeynes@815 | 209 | int memcpy_to_aica( uint32_t aica_addr, void *data, size_t size ) |
nkeynes@815 | 210 | { |
nkeynes@815 | 211 | assert( (aica_addr & 0x03) == 0 ); |
nkeynes@815 | 212 | uint32_t *src = (uint32_t *)data; |
nkeynes@815 | 213 | uint32_t *dest = (uint32_t *)aica_addr; |
nkeynes@815 | 214 | while( size > 0 ) { |
nkeynes@815 | 215 | int i; |
nkeynes@815 | 216 | if( g2_fifo_wait() != 0 ) { |
nkeynes@815 | 217 | return -1; |
nkeynes@815 | 218 | } |
nkeynes@815 | 219 | irq_disable(); |
nkeynes@815 | 220 | for( i=0; i<8 && size > 0; i++ ) { |
nkeynes@815 | 221 | *dest++ = *src++; |
nkeynes@815 | 222 | size -= 4; |
nkeynes@815 | 223 | } |
nkeynes@815 | 224 | irq_enable(); |
nkeynes@815 | 225 | } |
nkeynes@815 | 226 | return 0; |
nkeynes@815 | 227 | } |
.