Acceso a ROM para obtener los patrones de bits de los caracteres
¡Ay qué bonicas son las prácticas de Periféricos cuando comienzan a funcionar!
Ya os comenté el otro día cómo acceder a memoria de video y juguetear con ella, y el tema de hoy está bastante relacionado con ello (siempre basado en TurboC sobre MS-DOS, si usais otros compiñadores compiladores y no tira... no es mi culpa :P)
Bueno, resulta que cuando escribimos un carácter en la memoria de video, por ejemplo, la ’M’ de motagirl, no estamos escribiendo en realidad esa M, sino un 77, que es su código ASCII (podeis consultarlos todos aqui).
En realidad, para lo que sirve ese 77 es para indexar una tabla presente en la BIOS, donde se encuentra un patrón de bits para cada carácter (1 indica pixel relleno, 0 indica pixel vacío). La tabla tiene 256 carácteres,y cada carácter consta de 16bytes, siendo la M tal que así:
00000000
00000000
01100011
01110111
01111111
01111111
01101011
01100011
01100011
01100011
01100011
01100011
00000000
00000000
00000000
00000000
(Si os alejais un poco se ve algo mejor)
¿Y cómo podemos acceder a la tabla? La dirección nos la puede dar una función de la BIOS. Para invocarla, es necesario poner unos determinados códigos en los registros de la CPU (ax: 0x1130, bx: 0x0600), llamamos a la función usando una interrupción software (para la Bios de video, la 0x10) y esta amablemente nos dejará los valores deseados en otros registros de la CPU (es: segmento, bp: offset). Para ello, creamos una estructura de tipo REGPACK, a la que llamaremos rp y que actuará como pseudoregistros (y que no se nos olvide el #include del dos.h :P) :
struct REGPACK rp;
rp.r_ax=0x1130;
rp.r_bx=0x0600;
intr(0x10,&rp);
Y esto nos dará , como dije antes, la dirección de la tabla de patrones de bits de los caracteres, con el segmento en ES y el offset en BP.
Ahora sólo necesitamos montarnos nuestro punterillo a dicha dirección:
char* lista = (char *)MK_FP(rp.r_es,rp.r_bp);
Y ya tenemos nuestro puntero mágico apuntando al inicio de la tabla.¿Y para acceder a una posición concreta? Bueno, supongamos que quiero ir a la letra M, a la que, como dije antes, corresponde el código 77. Pues simplemente tendría que "saltar" los 76 caracteres anteriores, a 16 bytes cada uno. Podría hacerlo así:
lista = (lista+77*16);
Con eso estaría apuntando al inicio de los 16*8 bits de los que consta el patrón de la M. (Nótese que estamos usando un puntero a char, es decir, que cada vez que avancemos una posicion (por ejemplo, lista= lista+1) estaremos avanzando 8bits)¿Y cómo "pinto" el patrón de bits? Esto ya es más chispeante ^^
Necesitamos crearnos una bonita función o equivalente que devuelva un determinado bit (0 o 1) de un char (1byte, 8bits). Un ejemplo de cómo hacerlo podría ser esto:
(*p & (1<>n;
que devuelve el enésimo (n) bit de un char* p, usándo máscaras y desplazamientos.
Entonces, para obtener (por pantalla,o a un archivo) el patrón de bits, simplemente debemos apuntar a la letra deseada (lista = (lista+77*16);), y recorrer sus 16 filas mostrando bit a bit las 8 columnas (las columnas en orden decreciente, por que si no sale como reflejado en un espejo). Dicho así queda un poco raro, pero en realidad cada carácter no es más que un churro de 16bytes que tenemos que sacar por pantalla en cachos de 8 en 8 bytes.
Si alguien tiene curiosidad, he subido un archivo con el volcado de todos los patrones aquí. (Hecho a base de un bucle de 256 (caracteres), otro anidado de 16 (filas) y otro más anidado , de 8 (columnas)) . Los primeros treintayalgún patrones no tienen mucho sentido porque son caracteres no imprimibles, las letras ·de verdad"se ven más claras :)
En breve (aka cuando lo termine xD) colgaré otro post explicando cómo pasar esa tabla a RAM, modificarla con tus propios caracteres customizados, y toquetear las interrupciones para que los patrones usados sean los tuyos y no los de la BIOS :)
[Siguiente capítulo: Modificación de los patrones de bits de los caracteres]
4 comentarios
caxarro -
meloncito -
La práctica ya la tengo casi hecha, lo unico que me ha tocado los bowlins es que la copia la he tenido que hacer en memoria estática (char copia[4096]), ya que si lo hacía con el malloc, me petada asignando los valores.
Lo hacía asi:
copia=(char *) malloc (256*16*sizeof(char));
Nada, y petaba : /, pero bueno, da igual, estar está en RAM xDD
Debiarko -
Debiarko -