lunes, 12 de octubre de 2020

Get key cpctelera

 cpct_keyID getKey() {

  // Traverse the keystatus vector from end to start, to help
  // the compiler better optimize this code
  u8 i = 10, *keys = cpct_keyboardStatusBuffer + 9;
  u16 keypressed;
 
  // Wait for a keypress
  do { cpct_scanKeyboard(); } while ( ! cpct_isAnyKeyPressed() );

  // Analyse which key has been pressed and return its keycode
  do {
    // We analyse groups of keys byte by byte (8 by 8, 1 bit per key)
    // If no single key is pressed in this group, all bits will be on, and the byte will be 0xFF
    // Then, XORing the byte with 0xFF will result in 0 unless some key from this group is pressed
    keypressed = *keys ^ 0xFF;
    if (keypressed)
       return (keypressed << 8) + (i - 1); // Convert to cpct_keyID format: 8 first bits = key mask, 8 next bits, keyboard row (0-9)
    --keys;
  } while(--i);

  // No key was pressed
  return 0;
}

 cpct_keyID getKey() {

  // Traverse the keystatus vector from end to start, to help
  // the compiler better optimize this code
  u8 i = 10, *keys = cpct_keyboardStatusBuffer + 9;
  u16 keypressed;
 
  // Wait for a keypress
  do { cpct_scanKeyboard(); } while ( ! cpct_isAnyKeyPressed() );

  // Analyse which key has been pressed and return its keycode
  do {
    // We analyse groups of keys byte by byte (8 by 8, 1 bit per key)
    // If no single key is pressed in this group, all bits will be on, and the byte will be 0xFF
    // Then, XORing the byte with 0xFF will result in 0 unless some key from this group is pressed
    keypressed = *keys ^ 0xFF;
    if (keypressed)
       return (keypressed << 8) + (i - 1); // Convert to cpct_keyID format: 8 first bits = key mask, 8 next bits, keyboard row (0-9)
    --keys;
  } while(--i);

  // No key was pressed
  return 0;
}

domingo, 11 de octubre de 2020

Includes en cpctelera

 Fran Gallego:

include hace lo que todos los includes hacen en cualquier lenguaje


es lo mismo que si copiaras y pegaras el archivo que incluyes


Pero es que eso es idéntico en C y en C++


Por eso, se usa para incluir sólo declaraciones, no definiciones


Como en C


no pones en los ficheros de cabecera definiciones


sólo declaraciones


El concepto es el mismo


Todos los ficheros se compilan siempre por separado


ningún fichero sabe nada de que existan otros ficheros


Entonces, cuando quieres usar un símbolo que está en otro fichero


simplemente en el fichero que lo vas a usar, lo declaras


Para que el ensamblador sepa que ese símbolo existe, aunque no sepa cuánto vale


Es después, cuando el linker recoge todos los ficheros compilados intermedios y los junta


cuando mira dónde está cada símbolo


Si tienes dos ficheros F1 y F2


Con esta estructura de símbolos


F1

  etiqueta1::

  etiqueta2::

F2 

  otra1::

  otra2::


F1 y F2 se ensamblan por separado, individualmente


ninguno sabe de la existencia del otro


Así que si quieres que F1 pueda usar la etiqueta "otra2", por ejemplo


harías esto


F1

  .globl otra2

  etiqueta1::

  etiqueta2::

F2 

  otra1::

  otra2::


Simplemente, le dices al ensamblador "existe un símbolo otra2, que es global"


Y lo usas


como lo que haces con las llamadas a las funciones de CPCtelera


que son etiquetas, que no están en tu código


Si ahora resulta que tienes una etiqueta "cpct_doGame", que vas a usar tanto en F1 como F2


harías esto


F1

  .globl cpct_doGame

  etiqueta1::

  etiqueta2::

F2 

  .globl cpct_doGame

  otra1::

  otra2::


Pero eso ya es duplicar código


mientras sólo sea una etiqueta vale


pero si ahora resulta que quieres usar 4 símbolos en ambos ficheros, la cosa crece


F1

  .globl cpct_doGame_1

  .globl cpct_doGame_2

  .globl cpct_doGame_3

  .globl cpct_doGame_4

  etiqueta1::

  etiqueta2::

F2 

  .globl cpct_doGame_1

  .globl cpct_doGame_2

  .globl cpct_doGame_3

  .globl cpct_doGame_4

  otra1::

  otra2::


Y si tienes que hacer lo mismo en 5 ficheros, va siendo más feo


y si luego necesitas en los 5 ficheros, añadir un símbolo nuevo


te toca acordarte de todos los ficheros y editarlos uno a uno


Para evitar hacer eso


creas un tercer fichero


Un fichero de cabecera


Y haces esto


FH

  .globl cpct_doGame_1

  .globl cpct_doGame_2

  .globl cpct_doGame_3

  .globl cpct_doGame_4

  .globl cpct_doGame_5

F1

  .include "FH"

  etiqueta1::

  etiqueta2::

F2 

  .include "FH"

  otra1::

  otra2::


Eso es exactamente igual que haberlo escrito en los ficheros F1 y F2


Pero la ventaja es que sólo lo escribes en un sitio y cuando lo edites lo cambias para todos los que necesitan esas declaraciones


Así puedes tener 20 ficheros que incluyan FH


y en ninguno de ellos incurres en ningún coste


es lo mismo que haberlo escrito en los 20


totalmente igual, pero más práctico


cuidado, eso sí


no pongas en FH nada que no sean directivas, como has visto


Las directivas .globl


Sólo son información para el programa ensamblador


no generan bytes en el binario resultante


no existen en código máquina


sólo es información para el ensamblador para saber cosas sobre sus símbolos, mientras ensambla


Si metes código o bytes en un fichero del que luego hagas include


como lo estás duplicando en todas partes donde haces include


en todas ellas se generará ese código o bytes


por eso hay que saber usarlo, y entender el proceso, como te cuento ahora


Porque include es eso


un copy/paste automatizado

Sumar decimales en asm

 Fran Gallego:

@Kalandras Explicación fácil


Pones un número en el acumulador (A)


que en hexadecimal no tenga números mayores de 9


es decir, ambos números hexadecimales entre 0 y 9


como si fuera decimal, en vez de hexadecimal


a partir de ese momento


haces cualquier operación con el número


por ejemplo


add b


add #20


sub #15


lo que quieras


Si es puntuación, estás sumando puntos


pero después de cada operación aritmética


ejecutas la instrucción


DAA


Esa instrucción lo que hace es ajustar el resultado de la operación aritmética


como si los dígitos A-F no existieran, como si estuvieras usando números decimales


por ejemplo


ld a, #9

add #2


Da como resultado A = 0B


pero


ld a, #9

add #2

daa


Da como resultado A = 11


Como si hubieras sumado en decimal


DAA ajusta el resultado de la operación, para que sea como si fueran decimales

sábado, 10 de octubre de 2020

Imprimir scores en cpctelera

 Fran Gallego:

Un ejemplo para un score de 4 dígitos


Si tienes el score en HL


y le sumas una puntuación que está en DE


ld hl, #0x4995

ld de, #0x0010

ld a, l

add e

daa

ld l, a

ld a, h

adc d

daa

ld h, a


con eso sumas y da 0x4995+ 0x10 = 0x5005


Es como si sumaras en decimal


Pues sacando cada dígito por separado


porque cada dígito está codificado en 4 bits


Son dígitos hexadecimales


Si tienes A = 0x95


Los primeros 4 bits son un 9 ( 1001 )


Los segundos 4 bits son un 5 ( 0101 )


Así que sólo tienes que hacer operaciones de bits para quedarte con cada parte


y luego sumarles 48 para convertirlos en ASCII


Por ejemplo, si A = 0x95 = 0b10010101


puedes hacer esto para imprimir el 5


and #0x0F

add #48

call cpct_drawCharM0_asm


Con el AND te quedas sólo con los 4 últimos bits (el 5 )


le sumas 48 y da 53 (carácter del 5 en ASCII)


y se lo pasas a drawChar para imprimir


Si quieres imprimir el 9 de A = 0x95


harías esto


rrca

rrca

rrca

rrca

and #0x0F

add #48

call cpct_drawCharM0_asm


Rotas los bits de A 4 veces para poner abajo los 4 bits de arriba


y haces lo mismo de antes


De hecho, igual este año lo comento en clase porque es algo que nunca he explicado y creo que puede ser útil