ASM: Ejecuar un JP a una dirección de memoria almacenada en otra (puntero)

Página 2/3
1 | | 3

Por theNestruo

Expert (111)

Imagen del theNestruo

28-07-2019, 11:30

Llego tarde a la fiesta; ya te han dado bastantes alternativas... Si quieres una más, similar a las dos priemras que se han comentado pero sin perder DE, así lo hago yo:

; -----------------------------------------------------------------------------
; Emulates the instruction "jp [[hl]]" or "call [[hl]]"
; param hl: pointer to the address
; touches a
JP_HL_INDIRECT:
	ld	a, [hl] ; hl = [hl]
	inc	hl
	ld	h, [hl]
	ld	l, a
	; jr	JP_HL ; (falls through)
; ------VVVV----falls through--------------------------------------------------

; -----------------------------------------------------------------------------
; Simply "jp [hl]", but can be used to emulate the instruction "call [hl]"
; param hl: address
JP_HL:
	jp	[hl]
; -----------------------------------------------------------------------------

No obstante, en cuanto a temas de rendimiento, lo que dice WYZ es lo más óptimo. Si no quieres hacer código automodificable o estás en ROM... puedes hacer una "minirutina" automodificable gastando 1 byte extra de RAM para poner ese JP. Sería tal que así:

jp_puntero_pantalla: rb 1
puntero_pantalla: rw 1

En la inicialización, cargar ese "JP" con ld a, $c3 / ld [jp_puntero_pantalla], a y, cuando tengas que invocarlo, jp jp_puntero_pantalla o call jp_puntero_pantalla.

Por Visualedu

Resident (33)

Imagen del Visualedu

31-07-2019, 01:04

Hola, gracias a todos por vuestras aportaciones!!
actualmente tengo la versión de Manel46 que se adapta muy bien a lo que necesito.

La solución del código automodificante (theNestruo y Mortimer) me encanta para casos en los que tenga se defina la dirección en puntero_pantalla y luego se llame muchas veces a dicha rutina. Sin embargo en este caso se cambia constantemente la dirección por lo que modificaría constantemente la rutina (tantas veces como la llame) por lo que no tengo claro si optimiza la versión actual.

WYZ, jó, me ha costado entender tu idea y me he puesto a repasar un manual Smile.

El código que indicas para una ROM:
LD HL,[puntero]
PUSH HL
RET

¿no sería un equivalente a jp (hl)?

Si lo que intento es simular un 'call [hl]' se me ha ocurrido esto (con mejora de theNestruo Smile )

ld hl,ETIQUETA_RET
push hl ;Subo a la pila la dirección siguiente a jp (hl)

ld hl,(punteroPantalla) ;Cargo en el registro HL la rutina a la que quiero llamar (dicha rutina finaliza con RET)
ld a, [hl]
inc hl
ld h, [hl]
ld l, a

jp (hl)

ETIQUETA_RET:

Y luego como todas las direcciones a rutinas que almaceno en punteroPantalla finalizan en RET el PC continuaría en ETIQUETA_RET.

Funciona pero tengo que ver si mejora los tiempos de mi código actual.

Gracias a todos, se aprende mucho aquí Wink

Por Ritcher1986

Master (147)

Imagen del Ritcher1986

01-08-2019, 03:33

una duda, porqué se carga en el acumulador el contenido de hl, no se puede cargar directamente en el registro l?
ld l,(hl)
inc hl
ld h,(hl)
jp (hl)
o esto no es posible?

Por assembler

Champion (378)

Imagen del assembler

01-08-2019, 08:46

Al hacer eso ya cambiarías el registro HL y no apuntaria al mismo sitio, asi que la lectura de H seria incorrecta

Por [WYZ]

Champion (406)

Imagen del [WYZ]

02-08-2019, 22:37

Pues además de explicarme mal me he hecho un lio, pero la idea está ahí Smile

un CALL etiqueta, hace lo siguiente:

Quote:

Pushes the address after the CALL instruction (PC+3) onto the stack and jumps to the label. Can also take conditions.

y RET:

Quote:

Pops the top of the stack into the program counter. Note that RET can be either conditional or unconditional.

Es decir, en pseudocódigo:

CALL LABEL = PUSH PC+3 ; JP LABEL
RET = POP [TOP_STACK]

Si lo que quieres es emular un CALL (HL), entonces sería algo así:

;CALL (HL)
			LD 	HL,CALL_RET_ADDRESS
			PUSH 	HL
			LD 	HL,(PUNTERO)
			JP 	(HL) -> terminas la rutina con un RET...
CALL_RET_ADDRESS: 	...y continua el programa por aquí

Espero no haberme equivocado oO.

Por Manel46

Champion (431)

Imagen del Manel46

03-08-2019, 09:49

[WYZ], es correcto tu código, pero debe ser "LD HL,PUNTERO", sin paréntesis en puntero.
un CALL N, almacena en la pila la dirección de retorno. Lo que haces con el PUSH, es quivalente.
Se puede hacer una macro con esto.

Por theNestruo

Expert (111)

Imagen del theNestruo

03-08-2019, 23:02

Siempre he pensado que la instrucción JP (HL) se merece el precio al mnemónico más confuso de todo el conjunto de instrucciones, ya que en realidad lo que hace es "JP HL"... Yo por lo menos siempre que leo código con JP (HL) tengo que leerlo dos veces para asegurarme que lo estoy leyendo bien.

Manel46 wrote:

[WYZ], es correcto tu código, pero debe ser "LD HL,PUNTERO", sin paréntesis en puntero.
un CALL N, almacena en la pila la dirección de retorno. Lo que haces con el PUSH, es quivalente.
Se puede hacer una macro con esto.

Creo que aquí te ha ocurrido exactamente eso; te la ha jugado el mnemónico. Si ese bloque de código fuera sin la indirección (sin los paréntesis) tendrías "LD HL,nn / JP (HL)", lo que equivale a un sencillo "JP nn"... que combinado con el "LD HL,mm / PUSH HL" anterior, reduce el bloque entero de código a un sencillo "CALL nn" (que entiendo que no es lo que se quiere)

Como comentaba en otro post anterior, yo declaro una rutina "JP_HL: JP (HL)" en algún sitio de un código, y cuando se quiere emular la instrucción "CALL (HL)", basta con hacer un CALL a dicha rutina: "CALL JP_HL". En este ejemplo en particular sería: "LD HL,(PUNTERO) / CALL JP_HL"
Ocupa menos, tarda menos ciclos (creo, no lo he medido), y personalmente lo encuentro más claro...

Por Manel46

Champion (431)

Imagen del Manel46

04-08-2019, 00:48

JP HL, no existe, pero sjasm lo ensambla igual que JP (HL), #E9. Lo he verificado.
Lo de antes funciona perfectamente, también lo verifiqué.
No es lo mismo LD HL,(PUNTERO), que LD HL,PUNTERO, quede claro esto. Smile

Por theNestruo

Expert (111)

Imagen del theNestruo

04-08-2019, 09:34

Manel46 wrote:

JP HL, no existe, pero sjasm lo ensambla igual que JP (HL), #E9. Lo he verificado.

Quizá me expliqué mal. No quería decir que "JP HL" exista, sino que el mnemónico de "JP (HL)" debería haber sido "JP HL", ya que la instrucción no salta a (HL) (a la dirección de memoria contenida en la dirección de memoria apuntada por HL), sino a HL (la dirección de memoria contenida en HL).
Se ve más claro lo que quiero decir si pensamos que "JP nnnn" representa un hipotético "LD PC, nnnn".
Si "LD PC, nnnn" es "JP nnnn", una instrucción que hiciera el equivalente a lo que sería "LD PC, HL" debería llamarse "JP HL"... y sin embargo se llama "JP (HL)" (y, además, no existe ninguna instrucción equivalente a lo que sería "LD PC, (HL)").

SJASM debe pensar parecido (que el nombre de la instrucción es confuso) y por eso permite escribir el alias "JP HL" Smile

Manel46 wrote:

Lo de antes funciona perfectamente, también lo verifiqué.
No es lo mismo LD HL,(PUNTERO), que LD HL,PUNTERO, quede claro esto. Smile

Sí, si está claro.
Precisamente por eso me choca que indicaras que el código de [WYZ] debía ser sin indirección ("LD HL, PUNTERO"); ya que en ese caso:

	LD HL, CALL_RET_ADDRESS
	PUSH HL
	LD HL, PUNTERO	; HL = PUNTERO (sin indirección)
	JP (HL)		; PC = HL = PUNTERO, así que estas dos instrucciones equivalen a JP PUNTERO
CALL_RET_ADDRESS:

Es decir:

	LD HL, CALL_RET_ADDRESS
	PUSH HL		; [Stack top] = CALL_RET_ADDRESS, ..., ...
	JP, PUNTERO	; Cuando llegue al RET => PC = [Stack top] = CALL_RET_ADDRESS, por lo que estas tres instrucciones equivalen a CALL PUNTERO
CALL_RET_ADDRESS:

Y al final se tiene:

	CALL PUNTERO
CALL_RET_ADDRESS:	; (ya no se usa; se puede eliminar)

De ahí que el código de [WYZ] sólo tenga sentido con la indirección ("LD HL, (PUNTERO)")

Por Manel46

Champion (431)

Imagen del Manel46

04-08-2019, 10:44

theNestruo wrote:

Quizá me expliqué mal. No quería decir que "JP HL" exista, sino que el mnemónico de "JP (HL)" debería haber sido "JP HL", ya que la instrucción no salta a (HL) (a la dirección de memoria contenida en la dirección de memoria apuntada por HL), sino a HL (la dirección de memoria contenida en HL).

No. Tanto si es JP (HL) como JP HL, salta a la dirección contenida en (HL).
Esto lo usé hace tiempo, para arrancar una rom. Los dos primeros bytes son el indicativo de rom, #41,#42 ( A, B), y los dos siguentes, es la dirección de inicio. O sea que haciendo:
LD HL,#4002
JP (HL)
Arrancamos la rom.
Una rom se arranca sola, por supuesto. Esto era en un cargador de roms especial.

Página 2/3
1 | | 3