00001 /**********************************************************/ 00002 /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 00003 /* 00004 Copyright: 1993 - Grupo de Voz (DAET) ETSII/IT-Bilbao 00005 00006 Nombre fuente................ DMA.C 00007 Nombre paquete............... - 00008 Lenguaje fuente.............. C (Borland C/C++ 3.1) 00009 Estado....................... Completado 00010 Dependencia Hard/OS.......... DMA 00011 Codigo condicional........... - 00012 00013 Codificacion................. Borja Etxebarria 00014 00015 Version dd/mm/aa Autor Proposito de la edicion 00016 ------- -------- -------- ----------------------- 00017 2.0.3 25/08/94 Borja bug en lectura count_l1 y addr 00018 2.0.2 15/03/94 Borja optimizar lectura count_l1 00019 2.0.1 15/03/94 Borja algunos comentarios nuevos 00020 2.0.0 28/02/94 Borja Unificado DMA8 con DMA16 00021 1.0.1 19/02/94 Borja acceso a puertos mediante PORTS.H 00022 1.0.0 06/08/93 Borja Codificacion inicial. 00023 00024 ======================== Contenido ======================== 00025 Definicion de macros y funciones para manejo basico DMA. 00026 Definicion de funciones para la programacion del DMA 00027 de 8 y 16 bits del AT. No se han implementado todas las 00028 funciones ni modos de funcionamiento, solo los necesarios 00029 para trabajar con perifericos tipo sblaster o scanner. Por 00030 ejemplo, se programa siempre modo de transferencia SINGLE, 00031 ya que los modos BLOCK o DEMAND no siempre funcionan. 00032 Ademas no se implementan opciones para reprogramar el 00033 registro COMMAND ni para efectuar el MASTER_RESET, ya que 00034 en principio no hay que tocarlos (programados por BIOS al 00035 arrancar). 00036 El codigo no es optimo en absoluto :) 00037 .................... 00038 Macro and function definitions for 8 and 16 bit DMA management. 00039 Only some of the modes and functionality of the DMA has been 00040 programmed, enough to work with sound cards or scanners. For 00041 example, only SINGLE transfer mode has been considered, as 00042 BLOCK and DEMAND modes do not always work. More over there are 00043 also no function to program the COMMAND register nor to perform 00044 a MASTER_RESET, as normally it't not necessary to play with this 00045 registers (they are programmed by your computer BIOS on startup). 00046 This is not optimal code at all! 00047 =========================================================== 00048 */ 00049 /*/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\*/ 00050 /**********************************************************/ 00051 00052 #include "dma.h" 00053 00054 #include "ports.h" /* leer/escribir puertos */ 00055 #include "intrs.h" /* desconectar interrupciones */ 00056 00057 /**********************************************************/ 00058 /* Declara e inicializa las siguientes variables 00059 00060 UINT8 dma16_0x01, dma16_0xC0; 00061 00062 en funcion de {channel} canal DMA (0-7) en cuestion. 00063 Dado un canal DMA en {channel} que debe estar en el rango 0-7, 00064 esta macro configura las dos variables {dma16_0x01} y 00065 {dma16_0xC0} en funcion del tipo de canal DMA. Los canales 00066 DMA de 8 bits (0 a 3) ponen a 0 estas 2 variables, mientras 00067 que los canales DMA de 16 bits (4 a 7) pone 0x01 en la primera, 00068 y 0xC0 en la segunda variable. 00069 Ademas, se modifica {channel} para que sea siempre un valor entre 0 y 3, 00070 quedando identificados los canales de 16 bits por las otras 2 00071 variables. 00072 Los dos valores dma16_??? se utilizan en muchos macros definidos despues. */ 00073 #define DMA_DMA16_INFO() \ 00074 UINT8 dma16_01h, dma16_C0h; \ 00075 dma16_01h = ((UINT8)(channel)) >> 2; \ 00076 dma16_C0h = (dma16_01h) ? 0xC0 : 0; \ 00077 channel &= 0x3 00078 00079 /* puertos para registros DMA-8bits. Se indica (I/O). 00080 Los registros de DMA-16bits se obtienen a partir de estos, 00081 haciendo (0xC0 | ({dma8_reg} << 1)) (usar DMA_REG()). 00082 Cuando un registro depende del canal DMA, la variable UINT8 {channel} 00083 debe estar en scope, y valer siempre de 0 a 3. */ 00084 #define DMAx_REG_STATUS 0x08 /* (I) registro de estado */ 00085 #define DMAx_REG_COMMAND 0x08 /* (O) registro de orden */ 00086 #define DMAx_REG_REQUEST 0x09 /* (O) registro de peticion */ 00087 #define DMAx_REG_SMASK 0x0A /* (O) registro de mascara simple */ 00088 #define DMAx_REG_MMASK 0x0F /* (O) registro de mascara multiple */ 00089 #define DMAx_REG_CLEARB 0x0C /* (O) registro clear byte pointer flag */ 00090 #define DMAx_REG_MODE 0x0B /* (O) registro de modo */ 00091 #define DMAx_REG_ADDR (channel << 1) /* (I/O) reg. direccion */ 00092 #define DMAx_REG_COUNT ( DMAx_REG_ADDR + 1 ) /* (I/O) reg. cuenta */ 00093 00094 /* {devuelve} la direccion de un registro DMA 8/16 bits en base a los 00095 registros DMA-8 bits. En UINT8 {reg} se envia el registro DMAx_REG_???. */ 00096 #define DMA_REG(reg) (dma16_C0h | ((reg) << dma16_01h)) 00097 00098 /* estos son los registros DMA definitivos, para 8 o 16 bits, que 00099 se calculan en funcion de {channel}, {dma16_01h} y {dma16_C0h} */ 00100 #define DMA_REG_STATUS DMA_REG(DMAx_REG_STATUS) 00101 #define DMA_REG_COMMAND DMA_REG(DMAx_REG_COMMAND) 00102 #define DMA_REG_REQUEST DMA_REG(DMAx_REG_REQUEST) 00103 #define DMA_REG_SMASK DMA_REG(DMAx_REG_SMASK) 00104 #define DMA_REG_MMASK DMA_REG(DMAx_REG_MMASK) 00105 #define DMA_REG_CLEARB DMA_REG(DMAx_REG_CLEARB) 00106 #define DMA_REG_MODE DMA_REG(DMAx_REG_MODE) 00107 #define DMA_REG_ADDR DMA_REG(DMAx_REG_ADDR) 00108 #define DMA_REG_COUNT DMA_REG(DMAx_REG_COUNT) 00109 00110 /* registros de pagina DMA-8 bits. ver DMA8_REG_PAGE() y DMA_REG_PAGE() */ 00111 #define DMA8_REG_PAGE0 0x87 /* (I/O) pagina DMA canal 0 */ 00112 #define DMA8_REG_PAGE1 0x83 /* (I/O) pagina DMA canal 1 */ 00113 #define DMA8_REG_PAGE2 0x81 /* (I/O) pagina DMA canal 2 */ 00114 #define DMA8_REG_PAGE3 0x82 /* (I/O) pagina DMA canal 3 */ 00115 /*{devuelve} cual es le registro de pagina para el canal {channel} de 00116 DMA de 8 bits. {channel} debe estar en el rango 0 a 3 */ 00117 #define DMA8_REG_PAGE \ 00118 ((channel==0)?DMA8_REG_PAGE0:(channel==1)?DMA8_REG_PAGE1: \ 00119 (channel==2)?DMA8_REG_PAGE2:DMA8_REG_PAGE3) 00120 /* registros de pagina DMA-16 bits. ver DMA16_REG_PAGE() y DMA_REG_PAGE() */ 00121 #define DMA16_REG_PAGE0 0x88 /* (I/O) pagina DMA canal 4 */ 00122 #define DMA16_REG_PAGE1 0x8B /* (I/O) pagina DMA canal 5 */ 00123 #define DMA16_REG_PAGE2 0x89 /* (I/O) pagina DMA canal 6 */ 00124 #define DMA16_REG_PAGE3 0x8A /* (I/O) pagina DMA canal 7 */ 00125 /*{devuelve} cual es le registro de pagina para el canal {channel} de 00126 DMA de 16 bits. {channel} debe estar en el rango 0 a 3 */ 00127 #define DMA16_REG_PAGE \ 00128 ((channel==0)?DMA16_REG_PAGE0:(channel==1)?DMA16_REG_PAGE1: \ 00129 (channel==2)?DMA16_REG_PAGE2:DMA16_REG_PAGE3) 00130 00131 /* {devuelve} el registro de pagina DMA8/16 bits, para el canal 00132 DMA indicado (siempre de 0 a 3, incluso para los de 16 bits. en 00133 dma16_01h ya esta indicado si es de 16 bits) */ 00134 #define DMA_REG_PAGE (dma16_01h?DMA16_REG_PAGE:DMA8_REG_PAGE) 00135 00136 /* macros para programacion del DMA */ 00137 00138 /* genera byte para enmascarar de forma simple el canal {channel} (0 a 3) */ 00139 #define DMA_MASK_ON ((channel) | 0x04) 00140 00141 /* genera byte para desenmascarar de forma simple el canal {channel} */ 00142 #define DMA_MASK_OFF (channel) 00143 00144 /* genera mascara multiple, para los cuatro canales a la vez. 00145 Enviar TRUE en s(i) para enmascarar la linea {i}, o FALSE para no 00146 enmascararla */ 00147 #define DMA_MULTI_MASK(s0,s1,s2,s3) \ 00148 ((s0)?0x01:0x00)|((s1)?0x02:0x00)|((s2)?0x04:0x00)|((s3)?0x08:0x00) 00149 00150 /* metodos de transferencia posibles */ 00151 #define DMA_XFER_DEMAND 0x00 00152 #define DMA_XFER_SINGLE 0x40 00153 #define DMA_XFER_BLOCK 0x80 00154 #define DMA_XFER_CASCADE 0xC0 00155 00156 /* genera valor para establecer el modo DMA para el canal {channel} (0-3). 00157 {xfermode}=DMA_XFER_???? (???? = SINGLE,DEMAND,BLOCK,CASCADE) 00158 {decrement}==TRUE si queremos que transfiera hacia atras 00159 {autoinit}==TRUE activa la autoinicializacion al terminal el ciclo DMA 00160 {write}==TRUE activa Puerto--->Memoria. 00161 {write}==FALSE activa Memoria-->Puerto */ 00162 #define DMA_MODE(xfermode,increment,autoinit,write) \ 00163 ( (channel) | (xfermode) | ((decrement) ? 0x20 : 0) | \ 00164 ((autoinit) ? 0x10 : 0) | ((write) ? 0x04 : 0x08) ) 00165 00166 /* genera valor de pagina para la direccion lineal {lmem}. */ 00167 #define DMA_ADDR_PAGE(lmem) ((UINT8)((lmem)>>16) & (~dma16_01h)) 00168 /* genera valor LSB para la direccion lineal {lmem} */ 00169 #define DMA_ADDR_LSB(lmem) (UINT8)(((UINT16)(lmem)) >> dma16_01h) 00170 /* genera valor MSB para la direccion lineal {lmem} */ 00171 #define DMA_ADDR_MSB(lmem) (UINT8)((UINT32)(lmem) >> (8 + dma16_01h)) 00172 00173 /* genera valor LSB para el contador {count_l1} */ 00174 #define DMA_COUNT_LSB(count_l1) (UINT8)(count_l1) 00175 /* genera valor MSB para el contador {count_1} */ 00176 #define DMA_COUNT_MSB(count_l1) (UINT8)(((UINT16)(count_l1)) >> 8) 00177 00178 /*{devuelve} valor para hacer solicitud soft (SREQ) de dma por el 00179 canal {channel} */ 00180 #define DMA_SREQ (0x04 | (channel)) 00181 00182 /* {devuelve} un valor distinto de cero si se ha producido un 00183 TerminalCount(fin) en el canal {channel}, siendo {b} el valor leido del 00184 registro de estado */ 00185 #define DMA_GET_STATUS_TC(b) ( (b) & (0x01 << (channel)) ) 00186 00187 /* {devuelve} un valor distinto de cero si se ha producido una 00188 solicitud de DMA en el canal {channel}, siendo {b} el valor leido del 00189 registro de estado */ 00190 #define DMA_GET_STATUS_REQ(b) ( (b) & (0x10 << (channel)) ) 00191 00192 /*a partir de los valores {lsb} y {msb} leidos, forma la cuenta actual 00193 del DMA (elementos que quedan por transferir menos 1) */ 00194 #define DMA_COUNT_L1(msb,lsb) ((((UINT16)(msb))<<8) | ((UINT16)(lsb))) 00195 00196 /*reconstruye la direccion a partir de la pagina {page}, el byte 00197 alto de direccion {msb} y el bajo {lsb}. Se utiliza {dma16_01h} */ 00198 #define DMA_ADDRESS(page,msb,lsb) \ 00199 ((((UINT32)page)<<16)|((UINT32)((((UINT16)(msb))<<8)|(lsb))<<(dma16_01h))) 00200 00201 /**********************************************************/ 00202 /* resetea el byte pointer flag del controlador DMA, para que cuando 00203 se introduzca un valor de 2 bytes, este sincronizado (primero LSB 00204 y luego MSB). No es necesario hacerlo, pero si se hace por ejemplo antes 00205 de leer la cuenta DMA o la direccion actual no viene naada mal .... 00206 .................... 00207 Resets the byte pointer flag of the DMA controler; after this, you 00208 can introduce/get two-byte values through the 8 bit port (LSB first, MSB 00209 later). Normally it's not necessary to do this, as it's suppoused 00210 that the controller is correctly syncronithed, but it's convenient 00211 to do this before reading DMA count or the actual address. */ 00212 00213 VOID dma_resetb( VOID ) 00214 { 00215 UINT8 channel = 0; /* es necesario que este definido */ 00216 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00217 00218 00219 OUTPORT8(DMA_REG_CLEARB,0x00); /* byte reset */ 00220 } 00221 00222 00223 /**********************************************************/ 00224 /* Configura el DMA: Permite programar todos los valores necesarios 00225 para poner en funcionamiento un canal DMA. El resto de funciones 00226 dma_set_???() simplemente son versiones reducidas de esta funcion 00227 que solo reprograman ciertas partes del controlador. 00228 00229 {channel} canal DMA a programar. Puede ser 0, 1, 2 o 3 (canales 00230 de 8 bits) o 4, 5, 6, 7 (canales de 16 bits). 00231 {decrement} distinto de cero para hacer el DMA hacia atras. Si es 00232 cero, el DMA se realiza hacia alante, que es lo mas normal. 00233 {autoinit} distinto de cero para modo de autoinicializacion 00234 (usar constantes DMA_AUTO_INIT y DMA_SINGLE_CICLE) 00235 {writetomem} distinto de cero para escribir a memoria desde 00236 un puerto. cero para leer de memoria y escribir en un puerto. 00237 (usar constantes DMA_WRITE_TO_MEM y DMA_READ_FROM_MEM) 00238 {lmem} direccion (en formato lineal de 32 bits) del buffer DMA. Tener 00239 en cuenta que en los canales de 16 bits, debe ser una direccion 00240 par!!!!! 00241 {count_l1} numero de elementos (bytes en DMA8 o words en DMA16) 00242 menos 1, que tiene el buffer DMA 00243 {enable_dma} distinto de cero para activar el dma. cero para no 00244 activarlo (aunque se programa) 00245 (usar constantes DMA_ENABLE y DMA_DISABLE) 00246 00247 {lmem} se debe obtener a partir de un buffer de memoria reservado 00248 por el usuario, teniendo en cuenta que no debe cruzar ningun 00249 banco de 64kb para los canales de 8 bits, o un banco de 128kb 00250 para los canales de 16 bits. Utilizar las funciones fixmem() o 00251 fixlen() definidas en LMEM.C para fijar estas condiciones, asi como 00252 la longitud ({count_l1}+1) del buffer (tener en cuenta, que para 00253 canales de 16 bits, count indica words). 00254 Si el dma no se activa ({enable_dma}==0) se debe hacer 00255 dma_enable(ch) para activarlo. 00256 NOTA: La macro DMA_IS_DMA16(ch) definida en DMA.H {devuelve} 00257 TRUE cuando el canal {ch} es de 16 bits, o FALSE sin es de 8. 00258 .................... 00259 Configures DMA channel: This function allows a quite complete 00260 configuration of the DMA controller. The other dma_set_???() 00261 functions are reduced versions of this one, valid to reprogram 00262 just some part of the DMA controller. 00263 00264 {channel} is the DMA channel to programm. This can be 0, 1, 2 or 3 00265 for 8 bit channels, and 4, 5, 6, 7 for 16 bits channels. 00266 {decrement} if !=0 runs the DMA buffer backwards. If zero, DMA 00267 runs forwards, that is the usual way. You can use the 00268 defines DMA_INCREMENT and DMA_DECREMENT for clearer code. 00269 {autoinit} if !=0 selects the auto-initialize mode. Otherwise, 00270 selects the single cicle mode. You can use DMA_AUTO_INIT and 00271 DMA_SINGLE_CICLE for clearer source code. 00272 {writetomem} if !=0 selects port-to-memory tranfer. If 0, selects 00273 memory-to-port transfer. You can use DMA_WRITE_TO_MEM and 00274 DMA_READ_FROM_MEM to get clearer source code. 00275 {lmem} this is the DMA buffer 32-bit linear address. For 16bit 00276 DMA channels this must be a even address!!! 00277 {count_l1} number of elements minus one (count-1) of the DMA buffer. 00278 In 8 bit DMA channels, one element is one byte. In 16 bit DMA 00279 channels, one element is one word (two bytes). 00280 {enable_dma} if !=0 enables DMA channel. if ==0, keeps disabled the 00281 DMA channel, but it is programmed (you can enable it later). 00282 You can use DMA_ENABLE y DMA_DISABLE to get clearer code. 00283 00284 {lmem} must be a linear pointer to a memory area reserved by the user 00285 in the first megabyte of memory. The whole buffer ({count_l1}+1 elements) 00286 _must_ be in the same memory page (ie. 64kb blocks in 8 bit channels 00287 and 128kb blocks in 16 bit channels). You can use the functions 00288 fixmem() or fixlen() defined in LMEM.C to fix this requeriment and 00289 to determinte the length ({count_1}+1) of the buffer (remember that 00290 for 16 bit DMA channelss, {count_l1} refers to words). 00291 If the DMA channels is not activated ({enable_dma}==0) you can 00292 use dma_enable(ch) later to enable it. 00293 NOTE: macro DMA_IS_DMA16(ch) defined in DMA.H {returns} TRUE 00294 when {ch} is a 16 bit DMA channel (ch=4,5,6,7), or FALSE when it 00295 is a 8 bit channel (ch=0,1,2,3). */ 00296 00297 VOID dma_set( UINT8 channel, BOOL decrement, BOOL autoinit, BOOL writetomem, 00298 UINT32 lmem, UINT16 count_l1, BOOL enable_dma ) 00299 { 00300 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00301 INT_DISABLE(); /* desconecta interrupciones */ 00302 OUTPORT8(DMA_REG_SMASK,DMA_MASK_ON); /* enmascara linea DMA */ 00303 OUTPORT8(DMA_REG_MODE,DMA_MODE(DMA_XFER_SINGLE,decrement, 00304 autoinit,writetomem)); /* modo DMA */ 00305 OUTPORT8(DMA_REG_CLEARB,0x00); /* byte reset */ 00306 /* direccion buffer de transferencia */ 00307 OUTPORT8(DMA_REG_ADDR, DMA_ADDR_LSB(lmem)); 00308 OUTPORT8(DMA_REG_ADDR, DMA_ADDR_MSB(lmem)); 00309 OUTPORT8(DMA_REG_PAGE, DMA_ADDR_PAGE(lmem)); 00310 /* longitud buffer transferencia */ 00311 OUTPORT8(DMA_REG_COUNT, DMA_COUNT_LSB(count_l1)); 00312 OUTPORT8(DMA_REG_COUNT, DMA_COUNT_MSB(count_l1)); 00313 if (enable_dma) /* conectar DMA ? */ 00314 OUTPORT8(DMA_REG_SMASK, DMA_MASK_OFF); /* desenmascara linea */ 00315 INT_ENABLE(); /* conectar interrupciones */ 00316 } 00317 00318 /**********************************************************/ 00319 /* establece el modo de funcionamiento del DMA, en funcion 00320 de {autoinit} y {writetomem}. Ver dma_set() para mas informacion. 00321 .................... 00322 Selects the working mode of the DMA, based on {autoinit} and 00323 {writetomem}. Refer to dma_set() for more information. */ 00324 00325 VOID dma_set_mode( UINT8 channel, BOOL decrement, BOOL autoinit, BOOL writetomem, 00326 BOOL enable_dma ) 00327 { 00328 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00329 INT_DISABLE(); /* desconecta interrupciones */ 00330 OUTPORT8(DMA_REG_SMASK,DMA_MASK_ON); /* enmascara linea DMA */ 00331 OUTPORT8(DMA_REG_MODE,DMA_MODE(DMA_XFER_SINGLE,decrement, 00332 autoinit,writetomem)); /* modo DMA */ 00333 if (enable_dma) /* conectar DMA ? */ 00334 OUTPORT8(DMA_REG_SMASK, DMA_MASK_OFF); /* desenmascara linea */ 00335 INT_ENABLE(); /* conectar interrupciones */ 00336 } 00337 00338 /**********************************************************/ 00339 /* establece el buffer para el DMA en funcion de {lmem} y 00340 {count_l1}. Ver dma_set() para mas informacion. 00341 .................... 00342 Configures the DMA memory buffer based on {lmem} and {count_l1}. 00343 Refer to dma_set() for more information */ 00344 00345 VOID dma_set_buff( UINT8 channel, UINT32 lmem, UINT16 count_l1, 00346 BOOL enable_dma ) 00347 { 00348 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00349 INT_DISABLE(); /* desconecta interrupciones */ 00350 OUTPORT8(DMA_REG_SMASK,DMA_MASK_ON); /* enmascara linea DMA */ 00351 OUTPORT8(DMA_REG_CLEARB,0x00); /* byte reset */ 00352 /* direccion buffer de transferencia */ 00353 OUTPORT8(DMA_REG_ADDR, DMA_ADDR_LSB(lmem)); 00354 OUTPORT8(DMA_REG_ADDR, DMA_ADDR_MSB(lmem)); 00355 OUTPORT8(DMA_REG_PAGE, DMA_ADDR_PAGE(lmem)); 00356 /* longitud buffer transferencia */ 00357 OUTPORT8(DMA_REG_COUNT, DMA_COUNT_LSB(count_l1)); 00358 OUTPORT8(DMA_REG_COUNT, DMA_COUNT_MSB(count_l1)); 00359 if (enable_dma) /* conectar DMA ? */ 00360 OUTPORT8(DMA_REG_SMASK, DMA_MASK_OFF); /* desenmascara linea */ 00361 INT_ENABLE(); /* conectar interrupciones */ 00362 } 00363 00364 /**********************************************************/ 00365 /* establece la direccion del buffer DMA en funcion de {lmem}. 00366 Ver dma_set() para mas informacion. 00367 .................... 00368 Configures the DMA memory buffer address based on {lmem}. 00369 Refer to dma_set() for more information */ 00370 00371 VOID dma_set_buff_addr( UINT8 channel, UINT32 lmem, BOOL enable_dma ) 00372 { 00373 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00374 INT_DISABLE(); /* desconecta interrupciones */ 00375 OUTPORT8(DMA_REG_SMASK,DMA_MASK_ON); /* enmascara linea DMA */ 00376 OUTPORT8(DMA_REG_CLEARB,0x00); /* byte reset */ 00377 /* direccion buffer de transferencia */ 00378 OUTPORT8(DMA_REG_ADDR, DMA_ADDR_LSB(lmem)); 00379 OUTPORT8(DMA_REG_ADDR, DMA_ADDR_MSB(lmem)); 00380 OUTPORT8(DMA_REG_PAGE, DMA_ADDR_PAGE(lmem)); 00381 if (enable_dma) /* conectar DMA ? */ 00382 OUTPORT8(DMA_REG_SMASK, DMA_MASK_OFF); /* desenmascara linea */ 00383 INT_ENABLE(); /* conectar interrupciones */ 00384 } 00385 00386 /**********************************************************/ 00387 /* establece la cuenta del buffer DMA {count_l1}. 00388 Ver dma_set() para mas informacion. 00389 .................... 00390 Configures the DMA memory buffer length based on {count_l1}. 00391 Refer to dma_set() for more information */ 00392 00393 VOID dma_set_buff_count( UINT8 channel, UINT16 count_l1, 00394 BOOL enable_dma ) 00395 { 00396 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00397 INT_DISABLE(); /* desconecta interrupciones */ 00398 OUTPORT8(DMA_REG_SMASK,DMA_MASK_ON); /* enmascara linea DMA */ 00399 OUTPORT8(DMA_REG_CLEARB,0x00); /* byte reset */ 00400 /* longitud buffer transferencia */ 00401 OUTPORT8(DMA_REG_COUNT, DMA_COUNT_LSB(count_l1)); 00402 OUTPORT8(DMA_REG_COUNT, DMA_COUNT_MSB(count_l1)); 00403 if (enable_dma) /* conectar DMA ? */ 00404 OUTPORT8(DMA_REG_SMASK, DMA_MASK_OFF); /* desenmascara linea */ 00405 INT_ENABLE(); /* conectar interrupciones */ 00406 } 00407 00408 /**********************************************************/ 00409 /* Dado el canal DMA {channel} (0,1,2,3,4,5,6,7), 00410 esta funcion enmascara la linea, por lo que detiene el DMA en 00411 la linea indicada. 00412 .................... 00413 This function masks the DMA line identified by {channel} (0,1,2, 00414 3,4,5,6,7). */ 00415 00416 VOID dma_disable( UINT8 channel ) 00417 { 00418 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00419 OUTPORT8(DMA_REG_SMASK,DMA_MASK_ON); /* enmascara linea DMA */ 00420 } 00421 00422 /**********************************************************/ 00423 /* Dado el canal DMA en {channel} (0,1,2,3,4,5,6,7), 00424 esta funcion desenmascara la linea DMA por el canal indicado 00425 con lo que el DMA podra funcionar. 00426 .................... 00427 This function unmasks the DMA line identified by {channel} (0,1,2, 00428 3,4,5,6,7). Once the channel is unmasked, it will carry out 00429 any requested DMA transfer (of course the channel must be previously 00430 configured with dma_set()) */ 00431 00432 VOID dma_enable( UINT8 channel ) 00433 { 00434 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00435 OUTPORT8(DMA_REG_SMASK, DMA_MASK_OFF); /* desenmascara linea */ 00436 } 00437 00438 /**********************************************************/ 00439 /* esta funcion efectua por software una peticion de ciclo DMA 00440 en la linea indicada. 00441 .................... 00442 This function performs a software DMA cicle request through the 00443 DMA line {channel}. */ 00444 00445 VOID dma_sreq( UINT8 channel ) 00446 { 00447 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00448 OUTPORT8(DMA_REG_REQUEST,DMA_SREQ); 00449 } 00450 00451 /**********************************************************/ 00452 /* {devuelve} la cuenta DMA (elementos a transferir - 1) 00453 para terminar el ciclo DMA (envia un TerminalCount TC) por 00454 el canal {channel}. El DMA podra recomenzar de nuevo automaticamente 00455 si se encuentra en modo de autoinicializacion. 00456 El valor devuelto indica el numero de bytes (DMA8) o words (DMA16) 00457 que aun quedan por tranferir, menos 1. 00458 Por si las moscas, no esta de mas efectuar un dma_resetb() antes de 00459 esta funcion... 00460 .................... 00461 {returns} the DMA count (items to transfer - 1) left to complete the 00462 DMA cicle (i.e., to send a TerminalCount TC) for DMA channel number 00463 {channel}. The DMA operation can restart automatically again when 00464 the cicle completes if it has been previously programmed in auto- 00465 initialize mode. 00466 The value returned by this function is the number of bytes (DMA8) or 00467 words (DMA16) left to transfer minus 1. 00468 It's not a bad idea to call dma_resetb() before calling this 00469 function. */ 00470 00471 UINT16 dma_get_count_l1( UINT8 channel ) 00472 { 00473 UINT8 lsb1, msb1, lsb2, msb2; 00474 UINT16 port; 00475 00476 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00477 port = DMA_REG_COUNT; 00478 00479 INT_DISABLE(); 00480 lsb1 = INPORT8(port); 00481 msb1 = INPORT8(port); 00482 lsb2 = INPORT8(port); 00483 msb2 = INPORT8(port); 00484 INT_ENABLE(); 00485 00486 /* comprobar si lsb ha llegado a 0 y empezado de nuevo en 0xFF, 00487 pues al ir decrementando la cuenta el acarreo puede modificar msb 00488 entre IN(lsb) e IN(msb) */ 00489 00490 /* Secuencia: lsb1 * msb1 # lsb2 * msb2. 00491 Los puntos peligrosos son *, aunque puede haber cambio en #. 00492 Si msb2==msb1, significa que ni en # ni en *(2) ha habido cambio, 00493 por lo que la segunda lectura es segura */ 00494 if (msb2==msb1) 00495 return DMA_COUNT_L1(msb2,lsb2); 00496 00497 /* si msb2!=msb1, ha habido cambio en # o en *(2), por lo que la 00498 segunda lectura no ha sido segura. ¨pero es segura la primera lectura? 00499 puede que se produzca algun cambio en *(1) pero no son peligrosos a 00500 no ser que se produzca el acarreo. Como en # o *(2) se produce el acarreo, 00501 significa que por lo menos tiene que haber 0xFF lecturas entre *(1) y *(2) 00502 para que se produzcan dos acarreos y la primera lectura sea dudosa. Pero 00503 una transferencia DMA de 256 bytes entre 4 inports() no creo que sucedan 00504 ni en el Sinclair Spectrum. Por tanto, damos a la primera lectura como 00505 valida */ 00506 00507 return DMA_COUNT_L1(msb1,lsb1); 00508 } 00509 00510 /**********************************************************/ 00511 /* {devuelve} la direccion de memoria de la siguiente transferencia 00512 DMA que se va a efectuar por el canal {channel}, en formato de memoria 00513 lineal (32 bits). 00514 Por si las moscas, no esta de mas efectuar un dma_resetb() antes 00515 de esta funcion... 00516 .................... 00517 {returns} the memory address of the next memory position to be 00518 transfered (read or write) by the DMA controller using 00519 channel {channel}. This memory address is expressed as a linear 00520 address (32 bit). 00521 It's not a bad idea to call dma_resetb() before calling this 00522 function. */ 00523 00524 UINT32 dma_get_addr( UINT8 channel ) 00525 { 00526 UINT8 lsb1, msb1, lsb2, msb2, page; 00527 UINT16 port; 00528 00529 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00530 port = DMA_REG_ADDR; 00531 page = INPORT8(DMA_REG_PAGE); 00532 00533 INT_DISABLE(); 00534 lsb1 = INPORT8(port); 00535 msb1 = INPORT8(port); 00536 lsb2 = INPORT8(port); 00537 msb2 = INPORT8(port); 00538 INT_ENABLE(); 00539 00540 /* comprobar si lsb es 0, pues al ir decrementando/incrementando la 00541 cuenta el acarreo puede modificar msb entre IN(lsb) e IN(msb). Ver 00542 comentarios en dma_get_count_l1() para explicacion detallada del 00543 metodo seguido */ 00544 if (msb2==msb1) 00545 return DMA_ADDRESS(page,msb2,lsb2); 00546 00547 return DMA_ADDRESS(page,msb1,lsb1); 00548 } 00549 00550 /**********************************************************/ 00551 /* {devuelve} el registro de estado DMA. Al leer este registro, 00552 se resetea su valor. 00553 .................... 00554 {returns} the DMA status register. This register is cleared when 00555 you read it! */ 00556 00557 UINT8 dma_get_status( VOID ) 00558 { 00559 UINT8 channel = 0; /* es necesario que este definido */ 00560 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00561 return INPORT8(DMA_REG_STATUS); 00562 } 00563 00564 /**********************************************************/ 00565 /* {devuelve} FALSE si no hay peticion DMA pendiente por la linea 00566 {channel}. Se lee el registro de estado y por tanto se resetea, 00567 borrando los posibles flags para otros canales. Usar 00568 dma_get_status_dmareq() si se quieren mirar varios canales. 00569 .................... 00570 {returns} FALSE if there is no DMA request pending on DMA line 00571 {channel}. The status register must be read to test for this, and 00572 it is automatically cleared. This deletes the flags for _all_ DMA 00573 channels!!!. You should use dma_get_status_dmareq() if you want 00574 to check for various channels */ 00575 00576 BOOL dma_get_dmareq( UINT8 channel ) 00577 { 00578 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00579 return (DMA_GET_STATUS_REQ(INPORT8(DMA_REG_STATUS))!=0); 00580 } 00581 00582 /**********************************************************/ 00583 /* {devuelve} FALSE si no hay peticion DMA pendiente por la linea 00584 {channel}. El registro de estado, previamente leido con dma_get_status() 00585 se debe enviar en {status} 00586 .................... 00587 {returns} FALSE if there isn't any DMA request pending on line {channel}. 00588 The status register, previosly read using dma_get_status(), must 00589 be sent in {status}. */ 00590 00591 BOOL dma_get_status_dmareq( UINT8 status, UINT8 channel ) 00592 { 00593 channel &= 0x3; /* limita canales a rango 0-3 */ 00594 return (DMA_GET_STATUS_REQ(status)!=0); 00595 } 00596 00597 /**********************************************************/ 00598 /* {devuelve} FALSE si aun no se ha terminado el ciclo DMA. 00599 Cuando termina el ciclo, se emite un TerminalCount(TC) que 00600 se almacena en un flag interno del controlador DMA, y 00601 se detiene el DMA; en tal situacion esta funcion devuelve 00602 TRUE y borra el flag interno, pero si esta en modo de 00603 autoinicializacion el DMA comenzara de nuevo, aunque el flag no 00604 se borrara hasta que se lea con esta funcion. 00605 Se lee el registro de estado y por tanto se resetea, 00606 borrando los posibles flags para otros canales. Usar 00607 dma_get_status_tc() si se quieren mirar varios canales 00608 .................... 00609 {returns} FALSE if DMA cicle has not finished yet. 00610 When the DMA cicle ends, a TerminalCount (TC) flag is raised 00611 and the DMA transfer stops. This flag is stored in the DMA 00612 controller. This function {returns} the value of this flag 00613 for DMA channel {channel}, and the flag is reset. 00614 If auto-inititialize mode is programmed, the DMA transfer will 00615 restart again and the TC flag will go on raised until you 00616 read it. 00617 TC flags for all channels are stored in a internal status register. 00618 When we read this register it is cleared, reseting the flags for 00619 _all_ DMA channels. You can use dma_get_status_tc() if you 00620 want to test for more than one DMA channels. */ 00621 00622 BOOL dma_get_tc( UINT8 channel ) 00623 { 00624 DMA_DMA16_INFO(); /* genera informacion 8/16 bits */ 00625 return (DMA_GET_STATUS_TC(INPORT8(DMA_REG_STATUS))!=0); 00626 } 00627 00628 /**********************************************************/ 00629 /* {devuelve} FALSE si aun no se ha terminado el ciclo DMA. 00630 Ver dma_get_tc() para mas informacion. 00631 El registro de estado, previamente leido con dma_get_status() 00632 se debe enviar en {status} 00633 .................... 00634 {returns} FALSE if DMA cicle is still working. 00635 Refer to dma_get_tc() for detailed information. 00636 You must send the status register to this function in the {status} 00637 parameter. You can get this register using dma_get_status(). */ 00638 00639 BOOL dma_get_status_tc( UINT8 status, UINT8 channel ) 00640 { 00641 channel &= 0x3; /* limita canales a rango 0-3 */ 00642 return (DMA_GET_STATUS_TC(status)!=0); 00643 } 00644 00645 /**********************************************************/ 00646