Skip to content

Instantly share code, notes, and snippets.

@eariassoto
Created July 2, 2016 05:22
Show Gist options
  • Save eariassoto/79e0ab90a846ca9c8e22256985f6c555 to your computer and use it in GitHub Desktop.
Save eariassoto/79e0ab90a846ca9c8e22256985f6c555 to your computer and use it in GitHub Desktop.
load y store
/// <summary>
///
/// </summary>
/// <param name="posMem"></param>
/// <param name="regFuente"></param>
/// <returns></returns>
public bool StoreWord(int posMem, int regFuente)
{
/// resultado final, sirve para
/// 1. bajar el PC
/// 2. indica si sí se hizo el SW
bool exito = true;
/// banderas de locks
bool bloqueoMiCache = false;
bool bloqueoDirecCasa = false;
bool bloqueoDirecVictima = false;
bool bloqueoDirecBloque = false;
bool bloqueoCacheModif = false;
/// Punteros que hay que liberar
object objMiCache = null;
object objDirecCasa = null;
object objDirecVictima = null;
object objDirecBloque = null;
object objCacheModif = null;
/// en caso que no se logre lock de directorio bloque victima no deja pasar
bool puedeContinuarDesdeBloqueVictima = true;
Contexto contPrincipal = contextos.ElementAt(0);
try
{
/// Intento bloquear mi caché
Monitor.TryEnter(this.cacheDatos, ref bloqueoMiCache);
if(bloqueoMiCache)
{
#region bloqueoMiCache
objMiCache = this.cacheDatos;
var direccion = getPosicion(posMem);
if (bloqueEnMiCache(direccion.numeroBloque))
{
#region hitMiCache
/// En este caso de da un HIT
int estadoMiBloque = this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO];
/// Hay que revisar el estado del bloque
/// Si está Modificado entonces modifiquelo de nuevo y ya
/// Si está compartido hay que ir a invalidar a otros lados y luego modificar
switch (estadoMiBloque)
{
case ESTADO_MODIFICADO:
/// Ya el estado esta modificado, solo cambio palabra
cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra] = contPrincipal.registro[regFuente];
break;
case ESTADO_COMPARTIDO:
/// Busco el procesador que tiene el directorio casa del bloque
/// lo intento bloquear
int numProc = getNumeroProcesador(direccion.numeroBloque);
Procesador procesadorDirecCasa = procesadores.ElementAt(numProc);
Monitor.TryEnter(procesadorDirecCasa.directorio, ref bloqueoDirecCasa);
if (bloqueoDirecCasa)
{
/// Si lo logro bloquear, esa función intentará invalidar, si lo logra
/// devuelve true y entonces puedo modificar el bloque
objDirecCasa = procesadorDirecCasa.directorio;
bool res = InvalidarCachesCompartidas(procesadorDirecCasa, direccion);
if (res)
{
/// Actualizo directorio
procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_MODIFICADO;
procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][id + 1] = 1;
/// Hago el cambio
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra] = contPrincipal.registro[regFuente];
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_MODIFICADO;
}
else
{
exito = false;
}
}
else
{
exito = false;
}
break;
}
#endregion
}
else
{
#region missMiCache
/// En caso que haya MISS
/// Primero veo el bloque víctima
int estadoBloqueVictima = cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO];
if (estadoBloqueVictima == ESTADO_COMPARTIDO || estadoBloqueVictima == ESTADO_MODIFICADO)
{
/// Intento bloquear el directorio casa del bloque víctima
int numeroBloqueVictima = blockMapDatos[direccion.numeroBloque % CACHDAT_FILAS];
Procesador procesadorBloqueVictima = procesadores.ElementAt(getNumeroProcesador(numeroBloqueVictima));
Monitor.TryEnter(procesadorBloqueVictima.directorio, ref bloqueoDirecVictima);
if (bloqueoDirecVictima)
{
#region bloqueoDirecVictima
objDirecVictima = procesadorBloqueVictima.directorio;
switch(estadoBloqueVictima)
{
case ESTADO_COMPARTIDO:
/// Actualizo directorio
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][id + 1] = 0;
/// Reviso si tengo que ponerlo UNCACHED
bool compartidoEnOtrasCaches = false;
for (int i = 1; i < 4; i++)
{
if (procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][i + 1] == 1)
{
compartidoEnOtrasCaches = true;
}
}
if (!compartidoEnOtrasCaches)
{
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][0] = ESTADO_UNCACHED;
}
/// Lo invalido en caché
this.cacheDatos[numeroBloqueVictima % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_INVALIDO;
this.blockMap[numeroBloqueVictima % CACHDAT_FILAS] = -1;
break;
case ESTADO_MODIFICADO:
/// manda a guardar el bloque a memoria
for (int i = 0; i < 4; i++)
{
procesadorBloqueVictima.memoriaPrincipal[numeroBloqueVictima % BLOQUES_COMP][i][0] = this.cacheDatos[numeroBloqueVictima % CACHDAT_FILAS][i];
}
/// Actualizo directorio
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][id + 1] = 0;
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_UNCACHED;
/// Lo invalido en caché
this.cacheDatos[numeroBloqueVictima % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_INVALIDO;
this.blockMap[numeroBloqueVictima % CACHDAT_FILAS] = -1;
break;
}
#endregion
}
else
{
puedeContinuarDesdeBloqueVictima = false;
}
}
if (puedeContinuarDesdeBloqueVictima)
{
/// Si los locks salieron bien en la parte del bloque víctima, sigo
/// Intento bloquear directorio casa del bloque que voy a cargar
int numProcBloque = getNumeroProcesador(direccion.numeroBloque);
Procesador procesadorDirecCasa = procesadores.ElementAt(numProcBloque);
Monitor.TryEnter(procesadorDirecCasa.directorio, ref bloqueoDirecBloque);
if(bloqueoDirecBloque)
{
#region bloqueoDirecBloque
/// Tengo que fijarme en el estado del bloque:
/// UNCACHED: cargo de memoria, actualizo direct, actualizo estado caché
/// MODIFICADO: busco el procesador que lo tiene modificado, intentlo bloquear su cache
/// si sí, bajo a memoria, copio en mi caché, actualizo cachés y directorio
/// COMPARTIDO: intento invalidar otras cachés y si si, cambio la mía y actualizo
objDirecBloque = procesadorDirecCasa.directorio;
int estadoBloque = procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO];
switch (estadoBloque)
{
case ESTADO_UNCACHED:
/// Cargo de memoria a mi caché
for(int i = 0; i < 4; i++)
{
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][i] = procesadorDirecCasa.memoriaPrincipal[direccion.numeroBloque % BLOQUES_COMP][i][0];
}
this.blockMapDatos[direccion.numeroBloque % CACHDAT_FILAS] = direccion.numeroBloque;
/// Actualizo directorio
procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_MODIFICADO;
procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][id + 1] = 1;
/// Modifico bloque y cambio estado
cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra] = contPrincipal.registro[regFuente];
cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_MODIFICADO;
break;
case ESTADO_MODIFICADO:
/// Busco el procesador
Procesador procesQueTieneModificado = null;
for(int i = 0; i < 3; i++)
{
if(i != this.id && procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][i + 1] == 1)
{
procesQueTieneModificado = procesadores.ElementAt(i);
}
}
/// Intento bloquear su caché
Monitor.TryEnter(procesQueTieneModificado.cacheDatos, ref bloqueoCacheModif);
if(bloqueoCacheModif)
{
objCacheModif = procesQueTieneModificado.cacheDatos;
for (int i = 0; i < 4; i++)
{
/// copio a memoria
procesadorDirecCasa.memoriaPrincipal[direccion.numeroBloque % BLOQUES_COMP][i][0] = procesQueTieneModificado.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][i];
/// cargo a mi caché
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][i] = procesadorDirecCasa.memoriaPrincipal[direccion.numeroBloque % BLOQUES_COMP][i][0];
}
/// Actualizo caché otro procesador
procesQueTieneModificado.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_INVALIDO;
procesQueTieneModificado.blockMapDatos[direccion.numeroBloque % CACHDAT_FILAS] = -1;
/// Cambio palabra, actualizo estado
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra] = contPrincipal.registro[regFuente];
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_MODIFICADO;
}
else
{
exito = false;
}
break;
case ESTADO_COMPARTIDO:
bool res = InvalidarCachesCompartidas(procesadorDirecCasa, direccion);
if (res)
{
/// Actualizo directorio
procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_MODIFICADO;
procesadorDirecCasa.directorio[direccion.numeroBloque % DIRECT_FILAS][id + 1] = 1;
/// Cambio palabra, actualizo estado
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra] = contPrincipal.registro[regFuente];
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_MODIFICADO;
}
else
{
exito = false;
}
break;
}
#endregion
}
else
{
exito = false;
}
}
else
{
exito = false;
}
#endregion
}
#endregion
}
else
{
exito = false;
}
}
finally
{
if (bloqueoMiCache)
Monitor.Exit(objMiCache);
if (bloqueoDirecCasa)
Monitor.Exit(objDirecCasa);
if (bloqueoDirecVictima)
Monitor.Exit(objDirecVictima);
if (bloqueoDirecBloque)
Monitor.Exit(objDirecBloque);
if (bloqueoCacheModif)
Monitor.Exit(objCacheModif);
if(exito == false)
contPrincipal.pc -= 4;
}
return exito;
}
/// <summary>
///
/// </summary>
/// <param name="regFuente2"></param>
/// <param name="posMem"></param>
/// <returns></returns>
public bool loadWord(int regFuente2, int posMem)
{
bool resultado = true;
/// banderas de locks
bool bloqueoMiCache = false;
bool bloqueoDirecVictima = false;
bool bloqueoDirecBloque = false;
bool bloqueoCacheBloque = false;
/// punteros a los objetos que hay que liberar
object objMiCache = null;
object objDirecVictima = null;
object objDirecBloque = null;
object objCacheBloque = null;
// en caso que no se logre lock de direc bloque victima no deja pasar
bool puedeContinuarDesdeBloqueVictima = true;
var direccion = getPosicion(posMem);
Contexto contPrincipal = contextos.ElementAt(0);
try
{
Monitor.TryEnter(this.cacheDatos, ref bloqueoMiCache);
if (bloqueoMiCache)
{
#region bloqueoMiCache
objMiCache = this.cacheDatos;
if (bloqueEnMiCache(direccion.numeroBloque))
{
/// caso que hay HIT
/// copie y vamonos
contPrincipal.registro[regFuente2] = this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra];
}
else
{
/// caso que hay un MISS
/// Hay que revisar el estado de bloque víctima
int estadoBloqueVictima = this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][CACHDAT_COL_ESTADO];
if (estadoBloqueVictima == ESTADO_COMPARTIDO || estadoBloqueVictima == ESTADO_MODIFICADO)
{
int numeroBloqueVictima = this.blockMapDatos[direccion.numeroBloque % CACHDAT_FILAS];
Procesador procesadorBloqueVictima = procesadores.ElementAt(getNumeroProcesador(numeroBloqueVictima));
Monitor.TryEnter(procesadorBloqueVictima.directorio, ref bloqueoDirecVictima);
if (bloqueoDirecVictima)
{
#region bloqueoDirecVictima
/// Logra bloquear el directorio víctima
objDirecVictima = procesadorBloqueVictima.directorio;
/// Ciclos de retraso
if (procesadorBloqueVictima == this)
{
estoyEnRetraso = true;
ciclosEnRetraso += 2; // ciclos que gasta en consulta directorio local
}
else
{
estoyEnRetraso = true;
ciclosEnRetraso += 4; // ciclos que gasta en consulta directorio remoto
}
/// Evalua el estado del bloque
/// Si está compartido, lo invalida y actualiza cachés y directorios
/// Si está modificado, hace eso mismo pero adémás guarda en memoria
switch(estadoBloqueVictima)
{
case ESTADO_COMPARTIDO:
/// Actualiza el directorio
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][id + 1] = 0;
/// Ve a ver si tiene que poner UNCACHED
bool compartidoEnOtrasCaches = false;
for (int i = 0; i < 3; i++)
{
if (procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][i + 1] == 1)
{
compartidoEnOtrasCaches = true;
}
}
if (!compartidoEnOtrasCaches)
{
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_UNCACHED;
}
/// Invalida la caché
this.cacheDatos[numeroBloqueVictima % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_INVALIDO;
this.blockMap[numeroBloqueVictima % CACHDAT_FILAS] = -1;
break;
case ESTADO_MODIFICADO:
/// Guardo en memoria
for (int i = 0; i < 4; i++)
{
procesadorBloqueVictima.memoriaPrincipal[numeroBloqueVictima % BLOQUES_COMP][i][0] = this.cacheDatos[numeroBloqueVictima % CACHDAT_FILAS][i];
}
/// Ciclos de retraso
estoyEnRetraso = true;
ciclosEnRetraso += 16;
/// Actualizo directorio
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_UNCACHED;
procesadorBloqueVictima.directorio[numeroBloqueVictima % DIRECT_FILAS][id + 1] = 0;
/// Invalido en caché
this.cacheDatos[numeroBloqueVictima % CACHDAT_FILAS][CACHDAT_COL_ESTADO] = ESTADO_INVALIDO;
this.blockMap[numeroBloqueVictima % CACHDAT_FILAS] = -1;
break;
}
#endregion
}
else
{
puedeContinuarDesdeBloqueVictima = false;
}
}
if (puedeContinuarDesdeBloqueVictima)
{
/// Significa que los locks del bloque victima se hicieron bien
int numProc = getNumeroProcesador(direccion.numeroBloque);
Procesador proceQueTieneElBloque = procesadores.ElementAt(numProc);
Monitor.TryEnter(proceQueTieneElBloque.directorio, ref bloqueoDirecBloque);
if (bloqueoDirecBloque)
{
/// Se bloqueo el directorio casa del bloque
#region bloqueoDirecBloque
objDirecBloque = proceQueTieneElBloque.directorio;
/// Ciclos de retraso
if (proceQueTieneElBloque == this)
{
estoyEnRetraso = true;
ciclosEnRetraso += 2; // ciclos que gasta en consulta directorio local
}
else
{
estoyEnRetraso = true;
ciclosEnRetraso += 4; // ciclos que gasta en consulta directorio remoto
}
/// Veo el estado del bloque
int estadoBloque = proceQueTieneElBloque.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO];
/// Si alquien lo tiene modificado
if (estadoBloque == ESTADO_MODIFICADO)
{
/// Busco el procesador
Procesador procQueLoTieneM = null;
for (int i = 0; i < 3; i++)
{
if (proceQueTieneElBloque.directorio[direccion.numeroBloque % DIRECT_FILAS][i + 1] == 1)
{
procQueLoTieneM = procesadores.ElementAt(i);
}
}
Monitor.TryEnter(procQueLoTieneM.cacheDatos, ref bloqueoCacheBloque);
if (bloqueoCacheBloque)
{
/// Logro bloquear la cache del procesador que tiene el bloque modificado
objCacheBloque = procQueLoTieneM.cacheDatos;
/// Guarda en memoria
for (int i = 0; i < 4; i++)
{
proceQueTieneElBloque.memoriaPrincipal[direccion.numeroBloque % BLOQUES_COMP][i][0] = procQueLoTieneM.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][i];
}
/// Actualiza estado de la caché
procQueLoTieneM.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][DIRECT_COL_ESTADO] = ESTADO_COMPARTIDO;
/// Actualiza el directorio
proceQueTieneElBloque.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_COMPARTIDO;
proceQueTieneElBloque.directorio[direccion.numeroBloque % DIRECT_FILAS][procQueLoTieneM.id + 1] = 1;
}
}
/// Esta validación asegura que no hizo fail de try lock en el paso anterior
if (estadoBloque != ESTADO_MODIFICADO || (estadoBloque == ESTADO_MODIFICADO && bloqueoCacheBloque))
{
/// Se trae el bloque de memoria a mi caché
for (int i = 0; i < 4; i++)
{
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][i] = proceQueTieneElBloque.memoriaPrincipal[direccion.numeroBloque % BLOQUES_COMP][i][0];
}
/// Actualizo mi caché
this.cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][DIRECT_COL_ESTADO] = ESTADO_COMPARTIDO;
this.blockMapDatos[direccion.numeroBloque % CACHDAT_FILAS] = direccion.numeroBloque;
/// Actualizo directorio
proceQueTieneElBloque.directorio[direccion.numeroBloque % DIRECT_FILAS][DIRECT_COL_ESTADO] = ESTADO_COMPARTIDO;
proceQueTieneElBloque.directorio[direccion.numeroBloque % DIRECT_FILAS][id + 1] = 1;
/// Guardo en el registro
contPrincipal.registro[regFuente2] = cacheDatos[direccion.numeroBloque % CACHDAT_FILAS][direccion.numeroPalabra];
}
else
{
resultado = false;
}
#endregion
}
else
{
resultado = false;
}
}
else
{
resultado = false;
}
}
#endregion
}
else
{
resultado = false;
}
}
finally
{
if (bloqueoMiCache)
Monitor.Exit(objMiCache);
if (bloqueoDirecVictima)
Monitor.Exit(objDirecVictima);
if (bloqueoDirecBloque)
Monitor.Exit(objDirecBloque);
if (bloqueoCacheBloque)
Monitor.Exit(objCacheBloque);
if (resultado == false)
contPrincipal.pc -= 4;
}
return resultado;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment