Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Para responder a esta pregunta hay dos observaciones importantes. La primera es que mientras KCPSM6 está atendiendo una interrupción, no está
haciendo ningún progreso en la ejecución del programa principal (es decir, ¡el programa principal ha sido interrumpido!). En segundo lugar, KCPSM6 sólo
puede dar servicio a una interrupción a la vez, lo que significa que si se produce otra interrupción mientras KCPSM6 está ocupado ejecutando el ISR, la
nueva interrupción se perderá o tendrá que esperar, ninguna de las dos cosas es ideal. En términos generales, un esquema de interrupción no es adecuado
si el ritmo al que se producen las interrupciones es demasiado rápido para que puedan ser atendidas y para que el programa principal progrese
adecuadamente.
Está claro que la definición de "demasiado rápido" depende de lo exigentes que sean tanto el programa principal como el ISR, pero la única constante
absoluta es que cada instrucción KCPSM6 siempre tarda 2 ciclos de reloj en ejecutarse. Así que al menos puedes determinar fácilmente la tasa de
ejecución del código para una frecuencia de reloj dada y compararla con las demandas de tu programa y tu tasa de interrupción esperada.
Por ejemplo, considere el uso de interrupciones generadas a intervalos de 1ms para su uso como referencia de tiempo para un reloj de tiempo real. Con un
KCPSM6 funcionando a una frecuencia de reloj de 66MHz ejecutará 33.000.000 de instrucciones por segundo y por lo tanto podrá ejecutar 33.000
instrucciones entre cada interrupción. Se trata claramente de un gran número y es muy poco probable que impida la capacidad de progresar
adecuadamente a través de cualquier programa estando siempre listo para atender la siguiente interrupción. Pero supongamos que las interrupciones se
generan a intervalos de 1µs con el objetivo de lograr una resolución de tiempo más fina. Ahora el KCPSM6 sólo podría ejecutar 33 instrucciones entre cada
interrupción (es decir, ¡menos instrucciones de las que se pueden imprimir en una cara de un papel!). A menos que la ISR sea muy breve no se completará
a tiempo. Incluso si la ISR fuera sólo de 12 instrucciones, significaría que más de un tercio de la potencia de cálculo se consumiría en el servicio de la
simple ISR y eso significa que el programa principal se ejecutaría proporcionalmente más lento con una "vacilación" asociada causada por las continuas
interrupciones. Esto puede seguir siendo aceptable para la aplicación, pero sin duda está al borde de ser inadecuado y hará muy difícil ampliar las
características implementadas por el código del programa.
Cuando las interrupciones tienen sentido entonces es una característica muy útil de KCPSM6 para explotar. Sin embargo, cuando no son adecuadas, la
ventaja de utilizar una FPGA Xilinx es que existen muy buenas alternativas. El mayor error que la gente comete a menudo es luchar con soluciones
Mayor uso del hardware - Simplemente se implementan circuitos que realizan lo que se hubiera conseguido con el ISR basado en software, de forma que
se evitan las interrupciones o se reduce enormemente su frecuencia. Por ejemplo, un bloque contador/temporizador basado en hardware puede ser muy
sencillo de implementar en hardware y luego KCPSM6 puede leer valores de tiempo de él cuando lo necesite. La complejidad de un reloj en tiempo real
podría seguir implementándose en software, pero la resolución de la temporización la gestionaría mejor el hardware, que es rápido por naturaleza. Las
interrupciones podrían utilizarse ocasionalmente cuando un comparador de hardware coincide con un valor de tiempo establecido por KCPSM6.
¡Divide y vencerás! - Si un procesador KCPSM6 está dedicado al 100% a una tarea, en realidad siempre está ejecutando una ISR. Esto tiene sentido si el
ISR es relativamente complejo como para plantearse implementarlo en hardware. Dado que KCPSM6 es tan pequeño (26 Slices), dedicar un procesador
diferente a cada tarea exigente puede ser a menudo la solución más fácil y mejor. De hecho, PicoBlaze se utiliza a menudo para dar servicio a las
interrupciones de un procesador más grande como MicroBlaze.
Cuando el KCPSM6 responde a una interrupción ejecuta el equivalente a una instrucción CALL así como las tareas específicas de la interrupción tales
como preservar los estados de las banderas. El vector de interrupción es la dirección a la que efectivamente llama el KCPSM6 y tiene el valor por defecto
de 3FF hex. Sin embargo, esto se puede ajustar a cualquier valor dentro del rango de la memoria de programa disponible en su diseño utilizando el
genérico 'interrupt_vector' en la descripción de su diseño HDL.
procesador: mapa
genérico kcpsm6 hwbuild => X "00",
interrupt_vector => X Declaración del componente (parte de) mostrando
(
"3FF",
scratch_pad_memory_size => 64) los valores por defecto de los tres genéricos.
3FF es la última ubicación en una memoria de programa de 1K y es coherente con KCPSM, KCPSM-II y KCPSM3. Así que para la compatibilidad
directa con los programas de legado PicoBlaze esta es la mejor dirección para empezar y por lo tanto la razón por la que es el valor predeterminado.
Por supuesto, puedes modificar el programa y el vector.
Generalmente la dirección más conveniente es alguna cercana al final de la memoria de programa disponible pero dejando suficiente espacio para el ISR.
Esto significa que el ISR puede empezar a dar servicio a la interrupción inmediatamente. También es conveniente desde una perspectiva de
programación porque la directiva ADDRESS debe ser usada para alinear el inicio del código ISR con el vector de interrupción y tener esto como la última
¿Qué son valores erróneos? Si tratas de poner tu ISR en algún lugar en el medio de tu programa, entonces probablemente encontrarás que siempre estás
teniendo que ajustar la directiva ADDRESS y 'interrupt_vector', lo cual es una pérdida de tiempo inconveniente, así como propenso a errores. ¡La peor
dirección sería cero! Bajo ninguna circunstancia querrás que tu ISR se ejecute al encenderse o después de un reset (RETURNI sólo debería usarse
después de una interrupción).
La simplicidad del método de "bucle abierto" es obvia, pero también hay que reconocer que cualquier sistema de bucle abierto tiene sus limitaciones. En
este caso existe la posibilidad de que el KCPSM6 pase por alto una petición de interrupción y por lo tanto no la atienda. Esto puede ocurrir si el programa
KCPSM6 ha deshabilitado deliberadamente las interrupciones o si ya está atendiendo una ISR previa. El KCPSM6 también ignorará la entrada de
interrupción mientras se encuentre en modo reposo. Por lo tanto, esta técnica sólo se debe utilizar si se puede predecir que KCPSM6 siempre estará listo
para responder a una solicitud de interrupción o si es aceptable que se pierdan interrupciones.
Consulte las páginas 83-85 para obtener instrucciones relacionadas con las interrupciones.
La entrada 'interrupt' se muestrea en los flancos de reloj ascendentes que la dirección interrupt_vector => X "FF0",
clk
interrumpir
interrupt_ack
bram_enable
Se conservan las banderas Z y C. Se conserva la selección de banco. Todo se restablecerá con la instrucción RETURNI.
Funciones de simulación HDL usuario a la hora de definir niveles lógicos válidos para los controles
'interrupt', 'sleep' y 'reset'. Así que por favor, asegúrate de que todas
las señales están definidas al inicio de tu simulación, ya sea en tu
diseño o en tu banco de pruebas de simulación.
Dado que KCPSM6 es una parte totalmente integrada de su diseño de hardware, se simulará junto con el resto de su diseño en un simulador HDL como
iSim o XSim. Esto significa que puedes ver cómo KCPSM6 interactúa con tu diseño de la misma manera fundamental en la que podrías comprobar el
funcionamiento de una máquina de estados dedicada.
Además de poder observar cualquiera de las señales de
entrada y salida que conectan el KCPSM6 al resto de tu
diseño, el KCPSM6 contiene algunas señales adicionales
específicamente para fines de simulación.
Cada instrucción tarda 2 ciclos de reloj en ejecutarseCódigos de operación de instrucción descodificados y mostrados como cadenas de
texto.
El contenido de los registros. En este ejemplo podemos ver que 's3' se carga con el contenido Banco de registros 'A', Estados de banderas e
de 's1' seguido de la suma del contenido de 's2'.
interrupción.
Sugerencia - Los programas KCPMS6 a menudo contienen código que se utiliza para ralentizar deliberadamente el progreso a través del programa para dar
servicio a la aplicación correctamente, ya sea utilizando bucles de retardo de software o sondeo de señales de estado. Por ejemplo, cuando se comunica
con una UART que tiene una velocidad BAUD de 115200, cada carácter tardará 86,8µms en recibirse, lo que equivaldría a 8.680 ciclos de reloj de un reloj
de sistema de 100MHz. Debido a esto, no es raro que los usuarios se confundan por lo que perciben como una "falta de actividad" en su diseño simulado
simplemente porque KCPSM6 está tomando tantos ciclos de reloj. Así que si esta es la situación, puede ser necesario alterar el código PSM para que la
simulación HDL sea práctica, pero obviamente tendrás que recordar restaurar el código correcto para la aplicación real. En la práctica, la mayoría del código
Para que pueda entrar en producción con la definición de hardware más simplificada de su memoria de programa y asegurarse de que JTAG Loader no
se activa accidentalmente, se proporciona un conjunto de plantillas de "producción". El nombre de cada plantilla de producción describe la familia de
destino ('S6' para Spartan-6, 'V6' para Virtex-6 y '7S' para la serie 7) y el tamaño de la memoria de programa implementada (1K, 2K o 4K instrucciones).
También hay un caso especial que sustituye completamente la BRAM por 18 rebanadas de ROM distribuida y proporciona una implementación muy
eficiente para programas de hasta 256 instrucciones. Haga una copia del archivo apropiado y renómbrelo 'ROM_form.vhd'. A continuación, utilice este
archivo con el ensamblador y su archivo PSM para generar la definición de memoria simplificada.
kcpsm6 tu_programa
[17:0]
instrucción bram_enable active instrucción
[11:0]
direcci Sugerencia - No se
dirección
necesitan genéricos
ón para la memoria fija.
clk
Sugerencia - Las descripciones de cada una de las instrucciones contienen ejemplos de código PSM. Así que, por favor, no se detenga demasiado
en las descripciones formales pero breves de la sintaxis del ensamblador, porque la mayor parte de esto debería quedar claro a través de los
ejemplos y se convertirá en algo natural para usted una vez que empiece a escribir su propio código. El ensamblador KCPSM6 te proporcionará
rápidamente información cuando proceses tu código, así que sólo tienes que probarlo y dejar que te ayude a aprender la sintaxis precisa de forma
interactiva; ¡pronto serás un experto!
Para complementar esta documentación, se proporciona el siguiente material de referencia adicional en el paquete
KCPSM6 (archivo ZIP)...
all_kcpsm6_syntax.psm - Proporciona un archivo PSM (aunque no es un programa real) en el que hay ejemplos de toda la sintaxis PSM
soportada.
por el ensamblador KCPSM6 incluyendo todas las formas válidas de instrucciones, operandos y directivas.
Sugerencia - 'all_kcpsm6_syntax.psm' contiene las descripciones más completas de la sintaxis PSM y las directivas del
ensamblador. En cambio, este documento centra sus descripciones en el conjunto de instrucciones KCPSM6.
kcpsm6_assembler_readme.txt - Este documento será más atractivo para el usuario avanzado, en particular aquellos que prefieren invocar el
ensamblador como parte de un flujo por lotes. Como tal, este documento es más bien clínico y objetivo.
Sugerencia - Este archivo documenta los problemas y limitaciones conocidos, pero esperamos que no te los encuentres.
Directorios
UART_and_PicoTermEstos directorios incluyen diseños sencillos pero totalmente documentados en los que
No se han definido
Aunque no se muestra en este
ejemplo, las listas también TABLAS Lista de
identifican el archivo PSM en el
cadenas
STRING de texto Cadena
que se definió el elemento. Esto nombre
ayuda cuando se utilizan KCPSM6_version$ "v2.00"
directivas INCLUDE. datestamp$ "19 abr
2012"
timestamp$ "16:16:54"
Página Copyright 2010-2014 Xilinx
Sugerencia
00B 22000 - Las constantes y cadenas
JUMP 'datestamp' y 'timestamp', junto con HWBUILD, proporcionan todo lo necesario para
000[start]
implementar un esquema de informes de versiones para las unidades de producción, así como para realizar un seguimiento
a lo largo del desarrollo.
Sintaxis PSM
comentario e ignorado ignora las líneas blanco en los archivos FMT formatearán en línea con las instrucción más larga. Se
por el ensamblador. vacías, así que y LOG. instrucciones. Los ve bien ☺
utilice un comentarios en líneas que
Las directivas del ensamblador siguen la misma sintaxis básica, pero sólo se utilizan para dirigir al ensamblador y facilitar la escritura y comprensión del
código.
DEFAULT_JUMP
INCLUDE aaa / CONSTANTE
"fichero.psm" nombre, kk / DIRECCIÓN proporciona
NOTA - 'all_kcpsm6_syntax.psm' aaa / NAMEREG nombreantiguo,
un archivo nombrenuevo
PSM (aunque / CADENA
no es nombre$,
un programa "texto"
real) que/ describe
TABLA nombre#, [kk,kk,kk,..]
con más
/ INST hhhhhh detalle todas las directivas y tiene ejemplos de toda la sintaxis soportada. Dado que es un archivo PSM válido puedes
ensamblarlo y luego mirar también los archivos FMT y LOG que genera KCPSM6.
La directiva NAMEREG es una función opcional que puede ayudarte a saber qué datos esperas que contenga un s9
determinado registro. Antes de la directiva NAMEREG, un registro tendrá un nombre por defecto como 'sB'. Una vez
renombrado, sólo el nuevo nombre identificará el registro y ese nombre distingue entre mayúsculas y minúsculas s8
exactamente como usted lo definió. Cambiar el nombre no tiene ningún efecto en el contenido del registro o en cómo
se puede utilizar.
SUBvelocidad, 01
ADD sB, 42 ;
; Velocidad NAMEREG, sB
NAMEREG sB, Estado ;
; CARGAR sB, 19
;
INPUT Estado,
flags_port COMPARE
Estado, 12
;
NAMEREG Estado,
velocidad
;
s
ó
l
o
p
u
e
d
e
c
o
n
t
e
n
e
r
d
e
l
Página Copyright 2010-2014 Xilinx
aaa : Dirección de 12 bits 000
a FFF kk : Constante de 8
sX kk
CARGA sX, kk sX = kk
C Sin
cambios
Z Sin
cambios
CARGA sX, sY sX = kY
sX sY
C Sin
Ejemplos
cambios
LOAD sA, 8E El ensamblador KCPSM6 permite valores constantes en todas las instrucciones que requieren que se definan en
LOAD s4, 42'd Z Sin binario o utilizando un único carácter que se convierte a su valor equivalente ASCII.
hexadecimal (por defecto), decimal,
LOAD s9, 10001110'b cambios
Una vez ejecutado este ejemplo....
LOAD s6, "k"
s7', 's9' y 'sA' contendrán 8E hex. sA'
LOAD s7, sA
contendrá 2A hex.
LOAD s5, CR
s6' contendrá 77 hex (el código ASCII para 'k') y 's5' contendrá 0D hex (el código ASCII para Carriage Return) .
Sugerencia - Cargar un registro consigo mismo no tiene otro efecto que el de tardar 2 ciclos de reloj, pero puede ser una forma útil de crear un retardo
conocido.
Notas
sX' y 'sY' definen cualquiera de los 16 registros en el rango de 's0' a 'sF' en el banco de registro activo. Consulte la sección "Uso de los bancos de
registros" para ver cómo cambiar entre los bancos de registros "A" y "B" y las técnicas para copiar valores de los registros de un banco a los registros del
otro.
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la operación AND y en el que se devuelve el
resultado. El segundo operando define la segunda entrada de la operación AND y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
El indicador de cero (Z) se activará si los 8 bits del resultado devuelto a 'sX'
son cero. La bandera de acarreo (C) se borrará (C=0) en todos los casos.
s Y o kk 7 6 5 4 3 2 1 0
AND s X , kk sX = sX Y kk
AND sX, sY sX = sX Y sY
C sX 7 6 5 4 3 2 1 0
'0'
Ejemplos
= '00' ? Referenci
CARGAR sA, CA = 1 1 0 0 1 0 1 0
sA = 42, Z=0, C=0. a
CA Y sA, 53 53 = 0 1 0 1 0 0 1 1 Z
CA Y 53 = 0 1 0 0 0 0 1 0 = 42
A B AYB
LOAD sA, CA CA = 1 1 0 0 1 0 1 0 0 0 0
LOAD sB, 14 sA = 00, Z=1, C=0. 14 = 0 0 0 1 0 1 0 0 0 1 0
AND sA, sB CA Y 14 = 0 0 0 0 0 0 0 0 = 00 1 0 0
1 1 1
AND s5, 00001111'b Sugerencia - Esto borrará el nibble superior de 's5' y podría utilizarse para convertir los
caracteres ASCII '0' a '9' (30 a 39 hex) en sus valores numéricos equivalentes (00 a 09
hex).
CONSTANTE bit2, 00000100'b Sugerencia - 'AND' proporciona una manera de borrar bits a '0'. En este ejemplo se borra el bit2 del registro s0.
AND s0, ~bit2 Observe cómo todos los bits de una CONSTANTE pueden invertirse localmente utilizando ~ antes del
nombre. Por lo tanto la constante realmente aplicada en este caso es 11111011'b. (ver 'OR' para fijar
Y s5, FF bits).
Página Copyright 2010-2014 Xilinx
Sugerencia de codificación - Borra el indicador de acarreo sin cambiar el contenido del registro (véase también HWBUILD).
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la operación OR y en el que se devuelve el
resultado. El segundo operando define la segunda entrada de la operación OR y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
El indicador de cero (Z) se activará si los 8 bits del resultado devuelto a 'sX'
son cero. La bandera de acarreo (C) se borrará (C=0) en todos los casos.
s Y o kk 7 6 5 4 3 2 1 0
OR sX, kk sX = sX O kk
OR s X , sY sX = sX O sY
C sX 7 6 5 4 3 2 1 0
'0'
Ejemplos
= '00' ?
Referencia
LOAD sA, CA CA = 1 1 0 0 1 0 1 0 Z
OR sA, 53 sA = DB, Z=0, C=0. 53 = 0 1 0 1 0 0 1 1
CA O 53 = 1 1 0 1 1 0 1 1 = DB A B AOB
0 0 0
LOAD sA, CA CA = 1 1 0 0 1 0 1 0
sA = DE, Z=0, C=0. 0 1 1
LOAD sB, 14 14 = 0 0 0 1 0 1 0 0
1 0 1
OR sA, sB CA O 14 = 1 1 0 1 1 1 1 0 = DE
1 1 1
Sugerencia - Esto establece 2 bits en el nibble superior de 's5' y podría ser utilizado para convertir el numérico
OR s5, 00110000'b
valores 00 a 09 hex en sus caracteres equivalentes ASCII '0' a '9' (30 a 39 hex).
CONSTANTE bit2, 00000100'b Sugerencia - 'OR' permite poner bits a '1'. La directiva CONSTANT proporciona una forma cómoda de nombrar
OR s0, bit2 los bits que desee controlar de esta manera (véase "AND" para borrar bits).
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la operación XOR y en el que se devuelve el
resultado. El segundo operando define la segunda entrada de la operación XOR y puede ser una constante de 8 bits 'kk' o un registro
'sY'.
El indicador de cero (Z) se activará si los 8 bits del resultado devuelto a 'sX'
son cero. La bandera de acarreo (C) se borrará (C=0) en todos los casos.
s Y o kk 7 6 5 4 3 2 1 0
C sX 7 6 5 4 3 2 1 0
'0'
Ejemplos
= '00' ?
Referenci
CARGA sA, CA CA a
sA = 99, Z=0, C=0. = 1 1 0 0 1 0 1 0 Z
XOR sA, 53 53 = 0 1 0 1 0 0 1 1
CA XOR 53 = 1 0 0 1 1 0 0 1 = 99 A B A XOR B
0 0 0
CARGA sA, CA CA = 1 1 0 0 1 0 1 0
0 1 1
CARGAR sB, 14 sA = DE, Z=0, C=0. 14 = 0 0 0 1 0 1 0 0
1 0 1
XOR sA, sB CA XOR 14 = 1 1 0 1 1 1 1 0 = DE
1 1 0
CONSTANTE estroboscópica, Sugerencia - La instrucción XOR puede utilizarse para conmutar el estado de los bits de un registro. En
00000001'b este ejemplo, el bit menos significativo de 's0' se conmuta dos veces y se envía a un puerto.
XOR s0, strobe Asumiendo que el LSB era '0' al principio, esto habrá generado un pulso positivo ('1') en el LSB del
OUTPUT s0, ctrl_port puerto de salida, mientras que el resto de bits no se verán afectados. La directiva CONSTANT
XOR s0, strobe
Página s0, 0 ctrl_port
OUTPUT Copyright 2010-2014 Xilinx
proporciona una forma conveniente de nombrar los bits que se desea controlar de esta manera.
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la función de suma y en el que se devuelve el
resultado. El segundo operando define la segunda entrada de la suma y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
La bandera cero (Z) se activará si el resultado de 8 bits devuelto a 'sX'
es cero. La bandera de acarreo (C) se activará si la suma resulta en
un desbordamiento.
sX
ADD sX, kk sX = sX + kk
s Y o kk
ADD sX, sY sX = sX + sY
Fijar si resultado sX
> 'FF C
= '00' ?
Z
Ejemplos
LOAD sA, 8E
ADD sA, 43 8E + 43 = D1sA = D1 que no es cero (Z=0) y sin desbordamiento (C=0).
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la función de suma y en el que se devuelve el
resultado. El segundo operando define la segunda entrada de la suma y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
El indicador de cero (Z) se activará si el resultado de 8 bits devuelto a 'sX' es cero y el indicador de cero se activó antes de
la instrucción ADDCY. El indicador de acarreo (C) se activará si la suma produce un desbordamiento.
sX
ADDCY sX, kk sX = sX + kk + C s Y o kk
k k k k k k k k
ADDCY sX, sY sX = sX + sY + C Transferencia de
C
la operación anterior
Fijar si resultado sX
Ejemplos > 'FF C
El primer operando debe especificar un registro 'sX' del que se restará el segundo operando y al que se devolverá el resultado. El
segundo operando define el valor a restar del primer operando y puede ser una constante de 8 bits 'kk' o un registro 'sY'. La bandera
cero (Z) se activará si el resultado de 8 bits devuelto a 'sX' es cero.
La bandera de carry (C) se activará si el resultado de la resta es negativo. Por lo tanto, la bandera de carry representa un desbordamiento o un "préstamo"
para completar la operación.
sX
SUB sX, kk sX = sX - kk
s Y o kk
SUB sX, sY sX = sX - sY
Fijar si resultado sX
< '00' C
= '00' ?
Z
Ejemplos
LOAD sA, 8E
SUB sA, 43 8E - 43 = 4BsA = 4B que no es cero (Z=0) y sin desbordamiento (C=0).
LOAD sA, 8E
ADD sA, sA 8E - 8E = 00sA = 00 que es cero (Z=1) pero todavía no había desbordamiento (C=0).
LOAD sA, 8E 8E - B5 = 1D9sA = D9 que no es cero (Z=0) pero hubo un desbordamiento (C=1).
SUB sA, B5 Esto equivale a 142 - 181 = -39, donde D9 hexadecimal es la representación del complemento a dos de
-39. Sin embargo, es responsabilidad del usuario implementar e interpretar los valores y operaciones
El primer operando debe especificar un registro 'sX' del que se restará el segundo operando y la bandera de acarreo y al que se devuelve el
resultado. El segundo operando define el valor a restar del primer operando y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
La bandera cero (Z) se activará si el resultado de 8 bits devuelto a 'sX' es cero y la bandera cero se activó antes de la instrucción SUBCY.
La bandera de carry (C) se activará si el resultado de la resta es negativo. Por lo tanto, la bandera de carry representa un desbordamiento o un "préstamo"
para completar la operación.
sX
SUBCY sX, kk sX = sX - kk - C s Y o kk
k k k k k k k k
SUBCY sX, s Y sX = sX - sY - C Transferencia de
C
la operación anterior
Fijar si resultado sX
Ejemplos < '00' C
[sB, sA] = A2 7B
LOAD sA, 7B 7B - B9(-)C2 = C2, Z=0, C=1. A2 - A1 - 1 =
LOAD sB, A2 - A1 B9 = 00C2
SUB Página
sA, B9
Copyright 2010-2014 Xilinx
SUBCY sB, A1
00sB = 00, Z=0, [sB, sA] = A2 7B
C=0. LOAD sA, 7B
LOAD sB, A2 - A2 7B = 0000
SUB sA, sA
7B - 7B00 = 00,Z = 1 , C=0. A2 -
SUBCY sB, sB
A20 = 00 = 00, Z=1, C=0.
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la operación AND (sX no se verá afectado por la
operación). El segundo operando define la segunda entrada de la operación AND y puede ser una constante de 8 bits "kk" o un registro "sY".
El indicador cero (Z) se activará si los 8 bits del resultado temporal son cero.
La bandera de acarreo (C) se activará si el resultado temporal contiene un número impar de bits con valor '1' (el OR exclusivo del resultado temporal de 8 bits).
LOAD sA, 51
TEST sA, FF Z=0, C=1.
El primer operando debe especificar un registro 'sX' cuyo valor proporciona una entrada a la operación AND (sX no se verá afectado por la
operación). El segundo operando define la segunda entrada de la operación AND y puede ser una constante de 8 bits "kk" o un registro "sY".
La bandera cero (Z) se activará si los 8 bits del resultado temporal son cero y la bandera cero se activó antes de la instrucción TESTCY.
La bandera de acarreo (C) se activará si el resultado temporal junto con el estado previo de la bandera de acarreo contiene un número impar de bits puestos a
'1'.
Ejemplos
¿Raro
C ? Llevar de
C operación anterior
Página Copyright 2010-2014 Xilinx
CARGA sA, CA
[sB, sA] = 11001010 0101001
CARGAR sB, 52
TEST sA, 00000100'b
Tanto el bit13 como el bit3 de la palabra de 16
TESTCY sB, 00100000'b
bits son '0'. Z=1, C=0 (par).
El primer operando debe especificar un registro 'sX' del que se restará el segundo operando (el valor de sX no se verá afectado por la operación). El
segundo operando define el valor a restar del primer operando y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
El indicador cero (Z) se activará si el resultado temporal de 8 bits es cero y ambos operandos son iguales o "coincidentes".
La bandera de acarreo (C) se activará si el resultado temporal de la resta es negativo y, por tanto, indica cuando 'sX' es menor que el segundo operando.
sX
COMPARAR sX, kk temp = sX - kk
Estados de
abanderamien Comparación COMPARAR sX, sY temp = sX - sY s Y o kk
to
Z C
Fijar si temp < temp
0 0 sX > kk o sX > s Y
'00' C
x 1 sX < kk o sX < s Y
1 x sX = kk o sX = s Y
= '00' ?
Z
Ejemplos
Sugerencias
LOAD sA, 8E
COMPARE sA, 8E Los valores son iguales, Utilice 'Z' para determinar cuándo los valores son iguales o 'coinciden'.
JUMP Z, igual
Z=1, C=0. La bandera 'C' puede utilizarse para determinar cuándo sX es menor que el segundo
operando. Por lo tanto, también se puede utilizar para determinar cuando s X e s
m a y o r o igual que el segundo operando'. Así que cuando compare los contenidos
de dos registros asígnelos a 'sX' y 'sY' de tal forma que pueda usar 'C' para identificar
LOAD sA, 8E cual es menor. Esto evitará el requerimiento de probar ambas banderas 'C' y 'Z'.
COMPARE sA, 98 sA < 98, Z=0, C=1.
JUMP C, menor_que
Página Copyright 2010-2014 Xilinx
El
ensambla
dor
KSPSM6
permite
especifica
r
constante
s en
caractere
s
hexadeci
males,
decimales
y ASCII,
por
ejemplo
COMPAR
E s0, "Q"
sX, sY
la resta utilizada para realizar la comparación y éstas pueden influir tanto en el resultado de 8 bits antes de ser descartado como en los nuevos estados de
las banderas. Aunque cada registro sólo contiene un valor de 8 bits, se puede utilizar cualquier combinación de registros para contener valores mayores
segmentados en bytes. Por ejemplo, un valor de 32 bits puede almacenarse en 4 registros. Aunque no hay ninguna restricción sobre qué registros, y
ninguna manera formal de describir la asignación, es una práctica común asignar registros adyacentes y referirse a ellos como un "conjunto de registros"
como [sD, sC, sB, sA].
El primer operando debe especificar un registro 'sX' del que se restarán el segundo operando y la bandera de acarreo (sX no se verá afectado por la
operación). El segundo operando define el valor a restar del primer operando y puede ser una constante de 8 bits 'kk' o un registro 'sY'.
El indicador de cero (Z) se activará si el resultado temporal de 8 bits es cero y el indicador de cero se activó antes de la instrucción
COMPARECY. La bandera de acarreo (C) se activará si el resultado
temporal de la resta es negativo. sX
sX
SL 0 sX C '0' Z =? SL0 sX desplaza un '0' al LSB. La bandera Z sólo se activará si bits(7:1)
también son todos '0' después del desplazamiento.
sX
SL 1 sX C '1' Z =0 SL1 sX desplaza un '1' al LSB. Esto significa que la bandera Z
se borrará siempre (Z=0) con esta instrucción.
sX
SLX sX C Z =? SLX sX replica el estado existente del LSB. La bandera Z sólo se
activará si los 8 bits del registro son cero.
sX
SLA sX C C Z =? SLA sX desplaza el estado previo de la bandera de acarreo al
Anterior LSB al mismo tiempo que la bandera de acarreo se carga con el
MSB. La bandera Z sólo se activará si los 8 bits del registro son
cero.
Ejemplos
Un desplazamiento a la izquierda inyectando un '0' tiene el efecto de multiplicar un valor por 2. La instrucción 'SLA' permite desplazar valores multibyte
contenidos en varios registros.
LOAD sB, 14 SLA s B SL 0 sA
LOAD sA, B5 [sB,sA] = 14B5 = 530110 = 0001 0100 1011 0101 sB sA
SL0 sA C C '0'
SLA sB
[sB,sA] = 296A = 1060210 = 0010 1001 0110 1010
y
LOAD sF, 00000001'b e
bucle: SALIDA sF, Da salida a un patrón simple que se muestra a la derecha en el l
puerto SLX sF puerto "to". El proceso termina cuando se han establecido los 8 bits d
Página
JUMP NC, bucle Copyright 2010-2014 Xilinx
esplazamiento final establece la bandera de acarreo. 00000001
00000011
00000111
00001111
00011111
00111111
01111111
11111111
sX
SR0 sX '0' C Z =? SR0 sX desplaza un '0' al MSB. La bandera Z sólo se activará si
bits(6:0) también son todos '0' después del desplazamiento.
sX
SR1 sX '1' C Z =0 SR1 sX desplaza un '1' al MSB. Esto significa que la bandera Z
siempre se borrará (Z=0) con esta instrucción.
sX
SRX sX C Z =? SRX sX replica el estado existente del MSB. La bandera Z sólo se
activará si los 8 bits del registro son cero.
sX
SRA sX C C Z =? SRA sX desplaza el estado anterior de la bandera de acarreo al
Anterior MSB al mismo tiempo que la bandera de acarreo se carga con el
LSB. La bandera Z sólo se activará si los 8 bits del registro son
Ejemplos cero.
Un desplazamiento a la derecha tiene el efecto de dividir un valor por 2. La instrucción "SRA" permite desplazar valores multibyte contenidos en
varios registros. Cuando se utiliza el complemento a 2 para representar valores con signo, "SRX" implementa la extensión de signo.
LOAD sB, ED SRX s SRA sA
LOAD sA, 2A [sB,sA] = ED2A = -482210 = 1110 1101 0010 1010 B sA
SL0 sA sB C C
SLA sB
[sB,sA] = F695 = -241110 = 1111 0110 1001 0101
10000000
01000000
LOAD sF, 10000000'b 00100000
bucle: SALIDA sF, Salidas a 'puerto' un patrón simple 'caminar 1' como se ilustra en el lado
puerto SR0 sF
derecho.
JUMP NC, bucle
00000001
00000000
Página Copyright 2010-2014 Xilinx
00010000
proceso termina cuando el '1' se desplaza a la bandera de acarreo.
00001000
00000100
00000010
00000001
00000000
Página Copyright 2010-2014 Xilinx
RL sX
RR sX
Las instrucciones "RL" y "RR" desplazan el contenido del registro especificado (sX) un bit a la izquierda o a la derecha. El bit que se desplaza de un extremo
del registro al otro también se copia en la bandera de acarreo (C). El indicador de cero (Z) se activará sólo si los 8 bits del contenido del registro son cero.
Tenga en cuenta que como las instrucciones de rotación sólo reorganizan el contenido existente de 'sX', la bandera cero sólo se activará si 'sX' contenía
cero al entrar en la operación de rotación.
Ejemplo
Las operaciones de rotación se utilizan normalmente en la generación de patrones o secuencias de bits, como en el control
de motores paso a paso.
CARGAR s6, 03
bucle: OUTPUT s6, En este ejemplo podemos imaginar un motor paso a paso que tiene 8
motor_ctrl CALL bobinas dispuestas en un círculo de tal manera que la bobina asignada
step_delay INPUT s0, al bit0 es adyacente a la bobina asignada al bit7. La posición del motor
direction TEST s0, está definida por las bobinas que están siendo energizadas y en este
01 caso es beneficioso energizar dos bobinas adyacentes de un motor al
JUMP NZ, move_right mismo tiempo (de ahí el valor inicial de 03 cargado en 's6').
RL s6
JUMP bucle
Página
mover_derecha: RR s6 Copyright 2010-2014 Xilinx
determinar en qué dirección debe girar el motor y esto se traduce en la
dirección en la que gira el patrón "11", ya sea hacia la izquierda o hacia
la derecha.
00000011
00000110
00001100
00011000
00110000 Izquierda
01100000
11000000
10000001
00000011
00000110
00000011
10000001 Derecha
11000000
01100000
s7 s7
REGBANK B - Selecciona el banco B activo.
s6 s6
s2 s2
Sugerencia - Si utiliza la directiva NAMEREG en su código, probablemente
querrá asignar nombres diferentes a los registros que siguen a la instrucción s1 s1
REGBANK para reflejar que ya no está accediendo a la misma información.
s0 s0
El KCPSM3 sólo tenía un banco de registros, por lo que una técnica habitual consistía en conservar el contenido de los registros en la memoria scratch pad
antes de volver a utilizar dichos registros en una subrutina. Los valores eran entonces recuperados de la memoria para restaurar sus valores antes de
volver al programa principal. Ésta sigue siendo una técnica perfectamente válida en los programas KCPSM6, pero puede dar lugar a un número significativo
de instrucciones STORE y FETCH que consumen espacio de código y ralentizan la ejecución del programa. Cambiando al banco 'B' de registros al inicio de
una subrutina intensa, o al atender una interrupción, puedes proveerte de 16 registros temporales en un ciclo de instrucción (2 ciclos de reloj del sistema)
preservando automáticamente el contenido de los registros del banco 'A'.
Aunque es útil tener dos bancos de registros aislados e independientes, esto Banco Activo Banco inactivo
también presenta un reto cuando se trata de pasar datos entre un programa
principal y una subrutina. Una vez más, una posible solución es asignar
posiciones de memoria particulares al bloc de notas a las que accedan ambas
secciones de código cuando utilicen bancos de registros diferentes, pero esto
sF sF
requiere una posición de memoria y un par de instrucciones STORE y FETCH
para cada byte de datos. Por esta razón, la instrucción 'Send To Alternate sE sE
Register' ('STAR') le proporciona una forma de pasar información desde un
registro del banco activo (sY) a un registro del banco inactivo (sX) o de sD sD
preestablecer una constante en un registro del banco inactivo.
Sugerencia - Al igual que las instrucciones "LOAD", las instrucciones "STAR" no
afectan a los estados de las banderas. Sin embargo, debe reconocerse que s2 s2 0 0 1 1 0 1 1 1
'STAR s0, s0' no es equivalente a una instrucción 'no-operación' porque cada
referencia a 's0' está en un banco diferente (es decir, 's0' en el banco inactivo s1 s1
probablemente cambiará).
s0 s0
Ejemplo (Efecto ilustrado en el diagrama)
's1' en el
STAR sE, s1 sE' en el banco inactivo se carga con una copia de 's1' en el banco activo.
STAR s1, 37 banco
Página Copyright 2010-2014 Xilinx
inactivo se carga con el valor constante 37 hex (observe que 's1' en el banco activo no cambia). C Sin cambios
STAR sX , kk
REQUISITOS DE CODIFICACIÓN DEL
Z Sin cambios
El registro alternativo 'sX' debe especificarse utilizando un nombre por defecto 's0' a 'sF'. Las directivas
NAMEREG no se aplican a la especificación de "sX". El registro activo actual "sY" debe especificarse utilizando un
STAR sX , sY
ENSAMBLADOR
al utilizar la instrucción STAR
nombre activo para un registro (es decir, NAMEREG se aplica normalmente). Se trata de reglas de codificación
deliberadas que pretenden minimizar el
probabilidad de errores de codificación (es decir, obligan a pensar detenidamente qué banco está activo).
[7:0]
D 11 clk
[7:0]
C 10 [7:0] [7:0]
puerto_ out_port Puertos de
[7:0]
de_entr
B 01
write_strobe salida
ada
[7:0]
A 00
read_strobe [3] CE
[1] k_write_strobe [7:0]
D Z
[0] [7:0] = PUERTO 08
port_id
CE
[2] [7:0]
D Y
interrupt interrupt_ack
= PUERTO 04
sleep
reset CE
[1] [7:0]
D X
clk
= PUERTO 02
puerto_de_entrada
Sugerencia 1 - Asigne las direcciones de los puertos de entrada de forma que el multiplexor de
selección de datos que alimenta 'in_port' utilice el número mínimo de señales 'port_id' para realizar Hay 2 ciclos de reloj disponibles
la selección, por ejemplo, las direcciones de puerto '00' a '0F' proporcionan 16 puertos de entrada y para descodificar la dirección de
sólo requieren que 'port_id(3:0)' sean entradas de selección para el multiplexor, lo que resulta en puerto 'pp' o '(sY)' y presentar la
diseños más pequeños y rápidos. información solicitada al 'in_port'.
Pista 2 - A menos que haya una razón específica para no hacerlo, el multiplexor de selección de datos Datos capturados en 'sX' en
de entrada debe incluir un registro pipeline (es decir, su declaración case debe estar dentro de un este flanco de reloj
proceso con reloj). De esta forma, los datos se seleccionan durante el primer ciclo de reloj de 'port_id' y ascendente.
se presentan a 'in_port' durante el segundo ciclo de reloj. No definir un registro de canalización en
cualquier punto de la ruta de 'port_id' a 'in_port' es la razón más común por la que los diseños
PicoBlaze no alcanzan el rendimiento requerido (una 'ruta falsa' durante un ciclo de reloj) .
Pista 3 - 'read_strobe' puede ignorarse en la mayoría de los casos y nunca necesita formar parte del multiplexor que alimenta 'in_port'. Sin embargo, algunas
Página Copyright 2010-2014 Xilinx
funciones como un búfer FIFO necesitan saber cuándo han sido leídas y es en esas situaciones en las que 'read_strobe' junto con una decodificación del valor
apropiado de 'port_id' se utilizaría para generar un pulso "el puerto ha sido leído" para confirmar cuándo ha tenido lugar una lectura.
puerto_salida
Z Sin cambios C Sin cambios
write_strobe write_strobe pp
s Y o pp
[7:0]
clk port_id port_id Hay 2 ciclos de reloj disponibles para
decodificar la dirección del puerto
'pp' o '(sY)' p solo 3-
Ten en cuenta que 'out_port' y 'port_id' variarán durante la ejecución de otras instrucciones pero u bits de
'write_strobe' sólo estará activo durante una instrucción OUTPUT. e 'port_id'
r junto con
Sugerencia - En la mayoría de los casos se utiliza una dirección de puerto fija 'pp' por lo que las t 'write_str
directivas CONSTANT proporcionan un ideal por qué realizar un seguimiento de sus o obe' son
asignaciones de puerto y hacer su código más fácil de escribir, entender y mantener. decodific
0 ados.
Ejemplos 5
Si quieres que tus diseños sean pequeños y rápidos, asigna Se pueden
CONSTANTE LED_puerto, h utilizar valores
05 direcciones de puerto que faciliten funciones lógicas más
pequeñas. e decimales para
; x especificar las
CARGA s3, 3A
direcciones de
SALIDA s3, puerto_lED En este ejemplo un conjunto de 8 LEDs son mapeados al y
Página Copyright 2010-2014 Xilinx
los puertos, pero normalmente es más fácil trabajar con valores
hexadecimales o binarios a la hora de definir el hardware.
En este ejemplo se requiere que el KCPSM6 escriba datos de 8 bits a un dispositivo externo. Los datos
Utilización de puertos de salida de
son naturalmente variables y se presentan a la interfaz del dispositivo mediante la salida al puerto 20
propósito general......
hex. Entonces se requiere que el KCPSM6 genere la secuencia correcta de señales de control;
'Dev_write' se pone a Alto antes de que se genere un pulso en el 'Dev_clk' seguido de que 'Dev_write' se
devuelva a Bajo. Estas señales se controlan mediante la salida de la secuencia apropiada de valores
kcpsm6
constantes al puerto 08 hex que definen los estados de bit0 y bit1.
[7:0] (Esta técnica de conducción de señales de control suele denominarse
puerto_sali
"golpeteo de bits").
da PUERTO 20
CE
write_strobe [7:0]
[5] D
Dev_data[7:0] Datos válidos
[1]
08
PUERTO [0]
Dev_write
CE
[7:0] Dev_clk
[3] D
[7:0]
clk port_id OUTPUT s1,
Puerto_datos_dispositivo
Para cada instrucción OUTPUT de LOAD s0, 00000010'b
la forma de onda de la secuencia OUTPUT s0, Dev_control_port
CONSTANT Puerto_datos_dev, 20 de control hay una instrucción LOAD s0, 00000011'b
CONSTANT Puerto_de_control_dev, LOAD correspondiente que OUTPUT s0, Dev_control_port
08 prepara 's0' con el valor constante LOAD s0, 00000010'b
OUTPUT s0, Dev_control_port
Página Copyright 2010-2014 Xilinx LOAD s0, 00
r
e
q
u
e
r
i
d
o
.
clk
instruction SALIDA CARG SALIDA CARG SALIDA CARG SALIDA CARG SALIDA
AR AR AR AR
puerto_salida datos 02 03 02 00
write_strobe
Dev_data[7:0] Datos
válidos
Dev_write
Dev_clk
16 ciclos de
reloj
Hay una serie de aplicaciones en las que es beneficioso que el KPCSM6 ralentice la generación de formas de onda. Por ejemplo, la velocidad de
comunicación con un dispositivo de memoria SPI Flash puede ser de 33MHz como máximo. Por lo tanto, si el reloj del sistema es de 200 MHz, habría que
dividirlo al menos por un factor de 6 y KCPSM6 podría ayudar a conseguirlo de forma natural. Sin embargo, si necesitas un mayor rendimiento de "golpeo
de bits" sin simplemente aumentar la frecuencia del reloj del sistema, entonces claramente hay un límite cuando se utilizan los puertos de salida de
propósito general.
Una posible solución que se ha utilizado en diseños basados en KCPSM3 en el pasado, y que sigue
OUTPUT s1, Dev_data_port
siendo aplicable a los diseños KCPSM6, es reordenar el código. Como se muestra a la izquierda, los
LOAD s2, 00000010'b
valores constantes se han precargado en un conjunto de registros para que la forma de onda pueda
LOAD s3, 00000011'b
generarse con una ráfaga de instrucciones OUTPUT secuenciales. Aunque esto da como resultado la
LOAD s0, 00000000'b
mayor velocidad de transición posible de las señales durante la generación de la secuencia, también
OUTPUT s2, Dev_control_port
requiere el uso de más registros y la misma cantidad de tiempo para ejecutar el código.
OUTPUT s3, Dev_control_port
OUTPUT s2, Dev_control_port
Sugerencia - Para generar pulsos de un solo ciclo de reloj puede utilizar el ciclo de reloj único 'write_strobe'
OUTPUT s0, Dev_control_port
Página Copyright 2010-2014 Xilinx
calificado por
el 'port_id' en lugar de establecer y restablecer un bit de datos de un puerto de salida completo.
Volviendo al mismo ejemplo de escritura de datos a un dispositivo externo podemos ver que el puerto 08 hex ahora ha sido asignado a un puerto de salida
optimizado para constante mediante el uso de 'k_write_strobe' mientras que el puerto 20 hex sigue asociado a 'write_strobe' porque los datos son
naturalmente variables. Así que hay muy poca diferencia en el hardware siempre y cuando recuerdes que sólo port_id[3:0] se define durante una
instrucción OUTPUTK. Ten en cuenta también que ahora podrías tener dos puertos de salida diferentes con la misma dirección; uno para datos variables
y otro para valores constantes (ver página 79).
Utilización de un puerto de salida con optimización constante y un puerto de salida de propósito general......
kcpsm6
[7:0]
puerto_sali PUERTO 20
da
CE
write_strobe [5]
[7:0]
D Dev_data[7:0] Datos válidos
[1]
PUERTO 08 Dev_write
[0]
k_write_strobe CE Dev_clk
[3] [7:0]
[7:0] D
clk port_id
La instrucción OUTPUTK tiene dos operandos. El primer operando es el valor constante de 8 bits "kk" que se presentará en "puerto_salida" y, por lo tanto,
debe estar comprendido entre "00" y "FF" hexadecimal. El segundo operando debe especificar la dirección del puerto que se presentará en port_id[3:0] y
por lo tanto debe estar en el rango de '0' a 'F' hex. Esta instrucción no afecta al contenido de los registros utilizados ni al estado de las banderas.
Ejemplos
Estos ejemplos muestran cómo el ensamblador KCPSM6 permite definir y especificar la constante y el
CONSTANT token, 61 puerto de múltiples maneras. ¡Las cuatro instrucciones 'OUTPUTK' mostradas son en realidad la misma!
CONSTANT control_port, 0A
El valor de la constante 'kk' puede especificarse inmediatamente utilizando hexadecimal, decimal o un
OUTPUTK 61, A carácter ASCII. Alternativamente se puede utilizar el nombre asignado a una constante por una directiva
OUTPUTK 97'd, 10'd CONSTANT.
OUTPUTK "a", A
OUTPUTK token, puerto_de_control La dirección de puerto 'p' también puede especificarse inmediatamente usando hexadecimal o decimal,
A continuación se muestra un ejemplo de puerto híbrido. En este caso se requiere que el KCPSM6 envíe información a un transmisor UART para ser
observada en una terminal PC. Como es lógico, la información será una serie de caracteres ASCII, pero muchos de ellos serán cadenas o constantes
predefinidas, mientras que otros representarán los datos variables que se mostrarán. Este ejemplo también ilustra un posible uso del control 'sleep' y la
directiva 'STRING' en el ensamblador KCPSM6.
[7:0]
puerto_sa datos_e salida_ser
hwbuild => X "41", lida n ie
write_strobe escribir_a_ua
[3] rt escribir_buffer
k_write_strobe
[7:0]
buffer_half_full
port_id
dormir PUERTO clk
08
clk
Para crear un puerto híbrido la dirección del puerto debe estar en el rango de '00' a '0F' hex y en este ejemplo se ha utilizado 08 hex en una decodificación
optimizada de 'port_id' (es decir, sólo se está observando realmente port_id[3] para minimizar la función lógica que realiza la decodificación). A continuación,
tanto "write_strobe" como "k_write_strobe" se utilizan para calificar la dirección del puerto de modo que una instrucción "OUTPUT sX, 08" o "OUTPUT kk, 8"
dará lugar a la escritura de datos en el búfer FIFO dentro de la macro del transmisor UART.
'
s
l
e
e
p
'
i
n
t
e
r
r
u
p
c
i
o
n
e
s
s
o
n
l
Página Copyright 2010-2014 Xilinx