|
@@ -0,0 +1,489 @@
|
|
|
+/*
|
|
|
+ * To change this license header, choose License Headers in Project Properties.
|
|
|
+ * To change this template file, choose Tools | Templates
|
|
|
+ * and open the template in the editor.
|
|
|
+ */
|
|
|
+package cache;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ * @author Juninho Carlos
|
|
|
+ */
|
|
|
+public class Cache {
|
|
|
+
|
|
|
+ private long escritaCache; //Ultimo contador que fiz
|
|
|
+ private long leituraCache; //done
|
|
|
+ private long escritaRedundancia; //done
|
|
|
+ private long leituraRedundancia;
|
|
|
+
|
|
|
+ private long contadorDeCiclos; //feito
|
|
|
+ private long contadorDeWB; //feito
|
|
|
+ private long contadorDeWBForcado; //feito
|
|
|
+
|
|
|
+ private long contadorDeLeituraEspecial; //feito
|
|
|
+
|
|
|
+ private long contadorDeHit; //feito
|
|
|
+ private long contadorDeMiss; //feito
|
|
|
+
|
|
|
+ private long ContadorIncachavel;
|
|
|
+
|
|
|
+ private long escritaSDRAM;
|
|
|
+ private long leituraSDRAM;
|
|
|
+
|
|
|
+ private Redundancia redundancia;
|
|
|
+ private Conjunto[] conjuntos;
|
|
|
+
|
|
|
+ public Cache() {
|
|
|
+ this.redundancia = new Redundancia();
|
|
|
+
|
|
|
+ this.escritaCache = 0;
|
|
|
+ this.escritaRedundancia = 0;
|
|
|
+
|
|
|
+ this.leituraCache = 0;
|
|
|
+ this.leituraRedundancia = 0;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ this.contadorDeCiclos = 0;
|
|
|
+ this.contadorDeWB = 0;
|
|
|
+ this.contadorDeWBForcado = 0;
|
|
|
+ this.contadorDeLeituraEspecial = 0;
|
|
|
+
|
|
|
+ this.contadorDeHit = 0;
|
|
|
+ this.contadorDeMiss = 0;
|
|
|
+
|
|
|
+ this.ContadorIncachavel = 0;
|
|
|
+
|
|
|
+ this.escritaSDRAM = 0;
|
|
|
+ this.leituraSDRAM = 0;
|
|
|
+
|
|
|
+ this.conjuntos = new Conjunto[32];
|
|
|
+ for (int i = 0; i < 32; i++) {
|
|
|
+ this.conjuntos[i] = new Conjunto();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getEscritaSDRAM(){
|
|
|
+ return this.escritaSDRAM;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getLeituraSDRAM(){
|
|
|
+ return this.leituraSDRAM;
|
|
|
+ }
|
|
|
+ public long getContadorIncachavel(){
|
|
|
+ return this.ContadorIncachavel;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getcontadorLeituraEspecial(){
|
|
|
+ return this.contadorDeLeituraEspecial;
|
|
|
+ }
|
|
|
+ public long getWBForcado(){
|
|
|
+ return this.contadorDeWBForcado;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getHit(){
|
|
|
+ return this.contadorDeHit;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getMiss(){
|
|
|
+ return this.contadorDeMiss;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getEscritaCache(){
|
|
|
+ return this.escritaCache;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getEscritaRedundancia(){
|
|
|
+ return this.escritaRedundancia;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getLeituraCache(){
|
|
|
+ return this.leituraCache;
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getLeituraRedundancia(){
|
|
|
+ return this.leituraRedundancia;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param address endereço solicitado à cache
|
|
|
+ * @param read true -> leitura(lw), false -> escrita(sw)
|
|
|
+ */
|
|
|
+ public void requisicaoParaCache(long address, boolean read) {
|
|
|
+ Requisicao end = new Requisicao(address, read);
|
|
|
+ // System.out.println("pal = "+end.palavra);
|
|
|
+ if (isHit(end)) { //Verifica se é hit, e, se for, atualiza o bit de sujeira, caso necessário.
|
|
|
+
|
|
|
+ this.contadorDeHit++;
|
|
|
+
|
|
|
+ // System.err.println("HIT: endereco: " + end.endereco);
|
|
|
+ // System.err.println("");
|
|
|
+ if (read) {
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.hit_read;
|
|
|
+ } else {
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.hit_write; //contabiliza ciclos, inclusive os da comparação
|
|
|
+ }
|
|
|
+
|
|
|
+ int bloco = this.conjuntos[end.conjunto].getBlocoFromReq(end);
|
|
|
+
|
|
|
+ boolean erro = this.conjuntos[end.conjunto].getBloco(bloco).getErroFromPalavra(end.palavra);
|
|
|
+ if(!read){
|
|
|
+ if(erro){
|
|
|
+ this.escritaRedundancia++;
|
|
|
+ }else{
|
|
|
+ this.escritaCache++;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(erro){
|
|
|
+ this.leituraRedundancia++;
|
|
|
+ }else{
|
|
|
+ this.leituraCache++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //Tem que atualizar bit de sujeira caso seja escrita
|
|
|
+ //Deu hit e tem que verificar se tá na cache ou na redundancia
|
|
|
+ //contadorDeHit++;
|
|
|
+ } else {
|
|
|
+ //Deu miss
|
|
|
+ //System.err.println("MISS " + address);
|
|
|
+ this.contadorDeMiss++;
|
|
|
+
|
|
|
+ if (read) {
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.leitura_miss;
|
|
|
+ } else {
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.escrita_miss;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.requisicaoDeBlocoNoConjunto(end);
|
|
|
+ //conjuntos[end.conjunto].requisicaoDeBlocoNoConjunto(end,this.redundancia);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void inserirErroRedundancia(int conjunto, int bloco, int palavra) {
|
|
|
+ this.redundancia.inserirErro(conjunto, bloco, palavra);
|
|
|
+ }
|
|
|
+
|
|
|
+ private ArrayList<Integer> escreverBlocoNaRed(Requisicao requisicao, int bloco) {
|
|
|
+
|
|
|
+ Requisicao req = new Requisicao(requisicao.endereco, requisicao.read);
|
|
|
+
|
|
|
+ ArrayList<Integer> enderecosToWB = new ArrayList<>();
|
|
|
+ Conjunto c = this.conjuntos[req.conjunto];
|
|
|
+ for (int i = 0; i < 32; i++) {
|
|
|
+ Requisicao aux = req;
|
|
|
+ aux.palavra = i;
|
|
|
+ if (c.getBloco(bloco).getErroDasPalavraDoBloco()[i]) {
|
|
|
+
|
|
|
+ this.contadorDeCiclos += 3; //1 ciclo para escreve, um para ler, outro para comparar
|
|
|
+ this.leituraRedundancia++;
|
|
|
+ this.escritaRedundancia++;
|
|
|
+
|
|
|
+ Integer numToWB = redundancia.escreverPalavraNaRedMiss(aux, bloco);
|
|
|
+ if (numToWB != null && numToWB == -1) {
|
|
|
+ //Deu bosta
|
|
|
+ ArrayList<Integer> bosta = new ArrayList<>();
|
|
|
+ bosta.add(-1);
|
|
|
+ return bosta;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (numToWB != null) {
|
|
|
+ if (!c.arrayHasTheValue(enderecosToWB, numToWB)) {
|
|
|
+ enderecosToWB.add(numToWB);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ this.escritaCache++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return enderecosToWB;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void leituraEspecial(int tag, int bloco) {
|
|
|
+ this.leituraRedundancia += 32;
|
|
|
+ this.redundancia.leituraEspecial(tag, tag % 4, bloco);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Escreve palavra com erro na redundancia e faz os wb forçados/LE dos
|
|
|
+ * blocos necessários
|
|
|
+ *
|
|
|
+ * @param req
|
|
|
+ * @param c
|
|
|
+ *
|
|
|
+ * Retorna true quando detecta o erro na redundacia e false quando ñ tem
|
|
|
+ * erro na red
|
|
|
+ */
|
|
|
+ private boolean trataBlocoComErro(Requisicao req, Conjunto c, int bloco) {
|
|
|
+ ArrayList<Integer> enderecosToWB = escreverBlocoNaRed(req, bloco);
|
|
|
+
|
|
|
+ if (enderecosToWB.size() == 1 && enderecosToWB.get(0) == -1) { //Tentou escrever na Red e deu erro
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (enderecosToWB.size() > 0) { //Tratar WBs ou LE
|
|
|
+ //Requisicao r = new Requisicao(RR, true)
|
|
|
+ // System.err.println("Fazendo WB forçado");
|
|
|
+ // System.err.println("conjuntos wbackado/LE: " + enderecosToWB.toString());
|
|
|
+ // System.err.println("bloco: " + bloco);
|
|
|
+
|
|
|
+ for (Integer integer : enderecosToWB) {
|
|
|
+ this.leituraEspecial(integer, bloco);
|
|
|
+ Conjunto wb = this.conjuntos[integer];
|
|
|
+
|
|
|
+ if (wb.getBlocos()[bloco].isSujo()) {
|
|
|
+ //Faz WB-FORCADO
|
|
|
+ // System.err.println("Fazendo WB-forcado do conjunto " + integer);
|
|
|
+
|
|
|
+ this.contadorDeWBForcado++;
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.WB;
|
|
|
+ this.leituraRedundancia += 32;
|
|
|
+ this.escritaSDRAM += 32;
|
|
|
+ wb.desalocaBloco(bloco);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // System.err.println("Fazendo LE do conjunto " + integer);
|
|
|
+ //Contabilizar leitura especial
|
|
|
+ this.contadorDeLeituraEspecial++;
|
|
|
+ this.leituraRedundancia+=32;
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.leitura_especial;
|
|
|
+ wb.desalocaBloco(bloco);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ public long getWB(){
|
|
|
+ return this.contadorDeWB;
|
|
|
+ }
|
|
|
+ public long getCiclos(){
|
|
|
+ return this.contadorDeCiclos;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void tratarWB(Requisicao req, int numBloco) {
|
|
|
+ Conjunto c = this.conjuntos[req.conjunto];
|
|
|
+
|
|
|
+ if (c.getBloco(numBloco).hasErrorInBloco()) {
|
|
|
+ this.leituraEspecial(req.conjunto, numBloco);
|
|
|
+ if(!c.getBloco(numBloco).isSujo()){
|
|
|
+ //Só contabiliza leitura especial se o bloco tiver erro
|
|
|
+ this.contadorDeLeituraEspecial++;
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.leitura_especial;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (c.getBloco(numBloco).isSujo()) {
|
|
|
+ //Contabilizar um WB
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.WB;
|
|
|
+ this.contadorDeWB++;
|
|
|
+ this.escritaSDRAM += 32;
|
|
|
+ // System.err.println("fazer WB");
|
|
|
+ }
|
|
|
+ c.desalocaBloco(numBloco);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void tratarErroNaRed(Requisicao req, int numBloco) {
|
|
|
+ Conjunto c = this.conjuntos[req.conjunto];
|
|
|
+ this.leituraEspecial(req.conjunto, c.getRR());
|
|
|
+ c.getBloco(numBloco).setarComoInvalido();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void contabilizaEscrita(Conjunto c, Requisicao req, int bloco){
|
|
|
+ if(!req.read){
|
|
|
+ if(c.getBloco(bloco).getErroDasPalavraDoBloco()[req.palavra]){
|
|
|
+ this.escritaRedundancia++;
|
|
|
+ }else{
|
|
|
+ this.escritaCache++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void contabilizaLeitura(int conjunto,int numBloco, int palavra){
|
|
|
+ boolean erro = this.conjuntos[conjunto].getBloco(numBloco).getErroFromPalavra(palavra);
|
|
|
+ if(erro){
|
|
|
+ this.leituraRedundancia++;
|
|
|
+ }else{
|
|
|
+ this.leituraCache++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void requisicaoDeBlocoNoConjunto(Requisicao req) {
|
|
|
+ //Se está nesse método,é porque deu miss
|
|
|
+ Conjunto c = this.conjuntos[req.conjunto];
|
|
|
+ boolean flagAlocaBloco = true;
|
|
|
+
|
|
|
+ if (c.hasBlocoLivre()) { //USA RR
|
|
|
+ // System.err.println("Vai usar RR. Vai para o bloco: "+c.getRR());
|
|
|
+ if (c.getBloco(c.getRR()).isCachavel()) {
|
|
|
+
|
|
|
+ this.leituraSDRAM +=32;
|
|
|
+
|
|
|
+ if(req.read){
|
|
|
+ this.contabilizaLeitura(req.conjunto, c.getRR(), req.palavra);
|
|
|
+ }
|
|
|
+
|
|
|
+ //Caso seja um bloco ocupado, precisa fazer verificar a necessidade de WB
|
|
|
+ if (c.isBlocoOcupado(c.getRR())) {
|
|
|
+ // System.err.println("O bloco já estava ocupado. Vai fazer WB");
|
|
|
+ this.tratarWB(req, c.getRR()); //Aqui já contabiliza ciclos e WB
|
|
|
+ }
|
|
|
+ if (c.getBloco(c.getRR()).hasErrorInBloco()) { //Verifica se tem erro nas palavras do bloco
|
|
|
+ // System.err.println("Tem erro no bloco");
|
|
|
+ flagAlocaBloco = !this.trataBlocoComErro(req, c, c.getRR());//Contabiliza escrita na cache
|
|
|
+ }else{
|
|
|
+ this.escritaCache += 32;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flagAlocaBloco) {
|
|
|
+ // System.err.println("Vai alocar o bloco");
|
|
|
+ // System.err.println("");
|
|
|
+ this.contabilizaEscrita(c,req,c.getRR());
|
|
|
+
|
|
|
+ c.alocarBloco(req, c.getRR());
|
|
|
+ } else {
|
|
|
+ // System.err.println("ñ Vai alocar o bloco");
|
|
|
+ // System.err.println("");
|
|
|
+ this.contadorDeWBForcado++;
|
|
|
+ this.escritaSDRAM += 32;
|
|
|
+ //Não foi colocado em Cache pois tem erro na red
|
|
|
+ if (req.read) {
|
|
|
+ this.contadorDeCiclos += 1 + 1; //1 ciclo para devolver + 1 para acessar vetor de erros
|
|
|
+ } else {
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.escrita_1_palavra_na_SDRAM;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.tratarErroNaRed(req,c.getRR());
|
|
|
+ //Aqui falta contabilizar algumas coisas (tempo se for write)
|
|
|
+ }
|
|
|
+ //Atualiza as variáves da política de substituição de bloco
|
|
|
+ c.lru.atualizaLRU(c.getRR());
|
|
|
+ c.atualizaRR();
|
|
|
+ } else {
|
|
|
+ this.ContadorIncachavel++;
|
|
|
+
|
|
|
+
|
|
|
+ c.atualizaRR();
|
|
|
+ // System.err.println("Incachavel");
|
|
|
+ //Só contabiliza o custo da operação na memória principal
|
|
|
+ if (req.read) {
|
|
|
+ this.contadorDeCiclos += 1;
|
|
|
+ this.leituraSDRAM += 1;
|
|
|
+ } else {
|
|
|
+ this.escritaSDRAM += 1;
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.escrita_1_palavra_na_SDRAM;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //Usa LRU
|
|
|
+ // System.err.println("Vai usar LRU. Vai para o bloco: "+c.lru.getBlocoFromLru());
|
|
|
+ int blocoSelecionado = c.lru.getBlocoFromLru();
|
|
|
+ if (c.getBloco(blocoSelecionado).isCachavel()) {
|
|
|
+
|
|
|
+ this.leituraSDRAM +=32;
|
|
|
+ if(req.read){
|
|
|
+ this.contabilizaLeitura(req.conjunto, blocoSelecionado, req.palavra);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (c.getBloco(blocoSelecionado).hasErrorInBloco()) {
|
|
|
+ // System.err.println("Tem erro no bloco");
|
|
|
+ //Faz WB do bloco que foi selecionado para ser retirado da Cache
|
|
|
+ this.tratarWB(req, blocoSelecionado); //Já contabiliza ciclos e WB
|
|
|
+
|
|
|
+ //Escreve novo bloco na cache e os endereços com erro na red. Além disso, faz WBF e LE
|
|
|
+ flagAlocaBloco = !this.trataBlocoComErro(req, c, blocoSelecionado); //Contabiliza escrita
|
|
|
+
|
|
|
+ if (flagAlocaBloco) {
|
|
|
+ // System.err.println("Vai alocar o bloco\n");
|
|
|
+ // System.err.println("");
|
|
|
+ this.contabilizaEscrita(c, req,blocoSelecionado);
|
|
|
+ c.alocarBloco(req, c.getRR());
|
|
|
+ } else {
|
|
|
+ // System.err.println("ñ Vai alocar o bloco\n");
|
|
|
+ // System.err.println("");
|
|
|
+ //Não foi colocado em Cache pois tem erro na red
|
|
|
+ this.contadorDeWBForcado++;
|
|
|
+ this.tratarErroNaRed(req,blocoSelecionado);
|
|
|
+
|
|
|
+ if (req.read) {
|
|
|
+ this.contadorDeCiclos += 1;
|
|
|
+ } else {
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.escrita_1_palavra_na_SDRAM;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else{ //Caso o bloco não tenha erro, tratar as usual
|
|
|
+ this.escritaCache += 32;
|
|
|
+ //Caso o Bloco esteja Sujo, precisa fazer WB
|
|
|
+ if (c.getBlocos()[blocoSelecionado].isSujo()) {
|
|
|
+ //Contabilizar WB
|
|
|
+ this.tratarWB(req, blocoSelecionado); //Já contabiliza WB
|
|
|
+ c.alocarBloco(req, blocoSelecionado);
|
|
|
+ } else {//Caso precise só trocar o bloco, pois está limpo
|
|
|
+ // Contabiliza nada aqui, pois o bloco tá limpo
|
|
|
+ c.alocarBloco(req, blocoSelecionado);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //System.err.println("Incachavel");
|
|
|
+ //Só contabiliza o custo da operação na memória principal
|
|
|
+ this.ContadorIncachavel++;
|
|
|
+ if(req.read){
|
|
|
+ this.leituraSDRAM+=1;
|
|
|
+ this.contadorDeCiclos += 1;
|
|
|
+ }else{
|
|
|
+ this.escritaSDRAM+=1;
|
|
|
+ this.contadorDeCiclos += ConstanteDeTempo.escrita_1_palavra_na_SDRAM;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //Atualiza politica de substituição LRU
|
|
|
+ c.lru.atualizaLRU(blocoSelecionado);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Insere erro na memória cache
|
|
|
+ * @param conjunto - Número do conjunto
|
|
|
+ * @param bloco - Número do bloco
|
|
|
+ * @param palavra - Número da palavra
|
|
|
+ */
|
|
|
+ public void inserirErro(int conjunto, int bloco, int palavra) {
|
|
|
+ this.conjuntos[conjunto].getBlocos()[bloco].inserirErro(palavra);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Conjunto[] getConjuntos() {
|
|
|
+ return this.conjuntos;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isHit(Requisicao address) {
|
|
|
+ return conjuntos[address.conjunto].verificaHit(address);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Redundancia getRedundancia() {
|
|
|
+ return this.redundancia;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String toString() {
|
|
|
+ String s = "";
|
|
|
+ Bloco[] b;
|
|
|
+ int i = 0;
|
|
|
+ for (Conjunto conjunto : conjuntos) {
|
|
|
+ s += "Conjunto " + i + "\n";
|
|
|
+ //s += conjunto;
|
|
|
+ b = conjunto.getBlocos();
|
|
|
+ int j = 0;
|
|
|
+ for (Bloco bloco : b) {
|
|
|
+ s += "Bloco " + j + "\n";
|
|
|
+ s += bloco + "\n";
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+ s += "\n\n\n";
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ return s; //To change body of generated methods, choose Tools | Templates.
|
|
|
+ }
|
|
|
+
|
|
|
+}
|