Desafio de programação da disciplina de Organização de Computadores (Pipeline), 2023-2

Implementar na forma de simulação o funcionamento do pipeline em um sistema computacional. Exemplos: Fig. 1 e Fig.2.

Deverá conter UCP; fila com “n instruções”; possibilidade de criação de novas instruções; divisão de um pipeline em 7 tarefas diferentes; contador de tempo das instruções.

Após a implementação, faça um relato sobre: às dificuldades encontradas; como o a técnica de pipeline auxilia na concorrência de um sistema computacional.

Observações: utilize uma linguagem de programação de sua preferência. As principais linhas codificadas devem possuir comentários. O código deverá ser apresentado ao professor da disciplina.

Figura1:  slide 05 – Aula 07.

Figura 2: slide 08 – Aula 07.

Cole o código do desafio proposto no comentário.

77 comentários em “Desafio de programação da disciplina de Organização de Computadores (Pipeline), 2023-2

  1. GUSTAVO TUDELA FRUSSA

    2612240

    RELATO:

    As principais dificuldades encontradas foram encontrar o tamanho necessário da matriz que simularia o funcionamento da pipeline, e ajustar o próprio para que ele não estourasse a pilha de memória, alterando o valor da variável “num_instruções”.

    CÓDIGO (em c++): 

    #include <iostream>

    //////////Gustavo Tudela Frussa RA: 2612240

    int main()

    {

        int num_instru;

        int i;

        int j;

        printf(“Digite a quantidade de instruçõesn”);

        scanf(“%d”, &num_instru); 

        printf(“n”);

        int mat[num_instru][6+num_instru]; //// cria uma matriz de tamanho i = número de instruções; e j = número de deslocamentos + numero de tarefas

        for(i=0;i<num_instru;i++){ /////////// preenche a matriz com zeros

            for(j=0;j<6+num_instru;j++){

                mat[i][j] = 0;

            }

        }

        for(i=0;i<num_instru;i++){ //////////// altera os zeros de acordo com o deslocamento das instruções

            for(j=0;j<7;j++){

                mat[i][j+i] = j+1;

            }

        }

        for(i=0;i < num_instru; i++){ //////// apresenta a matriz que simula a pipeline para o usuário

            for(j=0;j< num_instru+6;j++){

                printf(“%d”,mat[i][j]);

            }

            printf(“n”);

        }

        printf(“n”);

        printf(“Tarefas: n”);

        printf(“1: Buscar n”);

        printf(“2: Codificar n”);

        printf(“3: Calcular n”);

        printf(“4: Executar n”);

        printf(“5: Armazenar n”);

        printf(“6: Apresentar n”);

        printf(“7: Encerrar n”);

        return 0;

    }

    Curtir

  2. Antonio Totti Goncalves RA: 2706571

    1 – Desafio de programação da disciplina de Organização de Computadores:

    Implementar na forma de simulação o funcionamento do pipeline em um sistema computacional. Exemplos: Fig. 1 e Fig.2.

    Deverá conter UCP; fila com “n instruções”; possibilidade de criação de novas instruções; divisão de um pipeline em 7 tarefas diferentes; contador de tempo das instruções.

    R:d#include

    #include <string.h>

    #define MAX_INST 10

    #define N_ESTAGIOS 7

    #define MAX_TEMPO 25

    #define TAM_INST 50

    const char* estagios[N_ESTAGIOS] = {“BI”, “DI”, “CO”, “BO”, “EX”, “EO”, “GR”};

    void simular_pipeline(char instrucoes[MAX_INST][TAM_INST], int qtd) {

        char pipeline[MAX_INST][MAX_TEMPO][4];

        for (int i = 0; i < qtd; i++) {

            for (int t = 0; t < MAX_TEMPO; t++) {

                strcpy(pipeline[i][t], ”  “);

            }

        }

        for (int inst = 0; inst < qtd; inst++) {

            for (int estagio = 0; estagio < N_ESTAGIOS; estagio++) {

                int tempo = inst + estagio;

                if (tempo < MAX_TEMPO) {

                    strcpy(pipeline[inst][tempo], estagios[estagio]);

                }

            }

        }

        printf(“nSimulacao do Pipeline (com %d instrucoes)nn”, qtd);

        printf(“Tempo -> “);

        for (int t = 0; t < MAX_TEMPO; t++) {

            printf(“%3d “, t + 1);

        }

        printf(“n”);

        for (int inst = 0; inst < qtd; inst++) {

            printf(“Inst %2d: “, inst + 1);

            for (int t = 0; t < MAX_TEMPO; t++) {

                printf(“%s  “, pipeline[inst][t]);

            }

            printf(“n”);

        }

        printf(“nInstrucoes digitadas:n”);

        for (int i = 0; i < qtd; i++) {

            printf(“Inst %2d: %sn”, i + 1, instrucoes[i]);

        }

        printf(“nTotal de ciclos (clocks): %dn”, qtd + N_ESTAGIOS – 1);

    }

    int main() {

        int n;

        char instrucoes[MAX_INST][TAM_INST];

        printf(“Quantas instrucoes voce deseja simular (max %d)? “, MAX_INST);

        scanf(“%d”, &n);

        setbuf(stdin,NULL);

        if (n <= 0 || n > MAX_INST) {

            printf(“Numero invalido. Deve ser entre 1 e %d.n”, MAX_INST);

            return 1;

        }

        printf(“nDigite as instrucoes (ex: ADD R1, R2, R3):n”);

        for (int i = 0; i < n; i++) {

            printf(“Instrucao %d: “, i + 1);

            fgets(instrucoes[i], TAM_INST, stdin);

            instrucoes[i][strcspn(instrucoes[i], “n”)] = ”; // Remove o n do final

        }

        simular_pipeline(instrucoes, n);

        return 0;

    }

    Após a implementação, faça um relato sobre: às dificuldades encontradas; como o a técnica de pipeline auxilia na concorrência de um sistema computacional.

    R: Implementar o simulador de pipeline apresentou como principal desafio a visualização da execução simultânea de diversas instruções em diferentes estágios. A organização da tabela, o controle temporal de cada instrução e a implementação de uma entrada de dados livre de falhas também demandaram atenção considerável.

    Apesar dessas dificuldades, o projeto foi fundamental para a compreensão prática do funcionamento de um pipeline. Ao invés da execução sequencial de cada instrução em sua totalidade, o processador as divide em etapas, iniciando o processamento da instrução seguinte antes da conclusão da anterior. Essa sobreposição permite que múltiplas instruções sejam processadas concorrentemente, otimizando a velocidade global do sistema.

    Através da implementação, foi possível observar concretamente o ganho de desempenho proporcionado pelo pipeline, que utiliza de forma mais eficiente o tempo e os recursos da unidade central de processamento (CPU).

    Curtir

  3. Aluno: Henrique da Silva Marques

    RA:2553910

    Codigo:

    #include <stdio.h>

    #include <string.h>

    #include <stdlib.h>

    #include <unistd.h> // para sleep()

    #define MAX_INSTRUCOES 20

    #define ESTAGIOS 7

    // Nomes dos estágios do pipeline

    const char* estagios[] = {

    “IF”, “ID”, “EX1”, “EX2”, “MEM1”, “MEM2”, “WB”

    };

    typedef struct {

    char nome[10];

    int tempoInicio;

    int tempoFim;

    } Instrucao;

    void simularPipeline(Instrucao instrucoes[], int n) {

    int tempo = 0;

    printf(“Simulando pipeline de %d instrucoes:n”, n);

    printf(“Tempo |”);

    for (int i = 0; i < n; i++)

    printf(” %s “, instrucoes[i].nome);

    printf(“n”);

    int fim = n + ESTAGIOS;

    for (tempo = 0; tempo < fim; tempo++) {

    printf(“%5d |”, tempo + 1);

    for (int i = 0; i < n; i++) {

    if (tempo >= i && tempo < i + ESTAGIOS)

    printf(” %s “, estagios[tempo – i]);

    else

    printf(” “);

    }

    printf(“n”);

    usleep(500000); // 0.5 segundo por ciclo

    }

    }

    int main() {

    Instrucao fila[MAX_INSTRUCOES];

    int n = 0;

    char opcao;

    printf(“Simulador de Pipeline com 7 Estagiosn”);

    do {

    printf(“Digite o nome da instrucao %d: “, n + 1);

    scanf(“%s”, fila[n].nome);

    n++;

    printf(“Deseja adicionar outra instrucao? (s/n): “);

    scanf(” %c”, &opcao);

    } while ((opcao == ‘s’ || opcao == ‘S’) && n < MAX_INSTRUCOES);

    simularPipeline(fila, n);

    return 0;

    }

    Dificuldades encontradas:

    Durante a implementação do simulador de pipeline, a principal dificuldade foi organizar corretamente a execução escalonada de cada instrução nos estágios, simulando a sobreposição temporal típica do pipeline real. Além disso, foi necessário controlar o tempo de início de cada instrução para evitar conflitos visuais e lógicos.

    Como o pipeline auxilia na concorrência:

    O pipeline melhora o desempenho do sistema computacional permitindo a execução paralela de instruções, cada uma em um estágio diferente. Assim, enquanto uma instrução está sendo decodificada, outra pode estar sendo buscada, outra executando e outra gravando o resultado. Isso reduz o tempo total de execução do conjunto de instruções e aumenta a eficiência do processador, sendo uma técnica fundamental na arquitetura moderna.

    Curtir

  4. Aluno: João Pedro Dias Ferreira

    RA: 2575949

    Desafio de Pipeline:

    #include #include #include #define MAX_INSTRUCOES 20 #define MAX_ESTAGIOS 7 const char *estagios[MAX_ESTAGIOS] = {“BI”, “DI”, “CO”, “BO”, “EI”, “EO”, “FIM”}; typedef struct { int id; int estagio_atual; bool concluida; int tempo_inicio; int tempo_fim; int src; // registrador de origem (leitura) int dst; // registrador de destino (escrita) bool em_bolha; } Instrucao; Instrucao fila[MAX_INSTRUCOES]; int total_instrucoes = 0; int clock_global = 0; // Verifica se há dependência entre a instrução atual e anteriores bool tem_dependencia(int atual_idx) { Instrucao *inst_atual = &fila[atual_idx]; for (int i = 0; i < atual_idx; i++) { Instrucao *inst_anter = &fila[i]; if (!inst_anter->concluida && inst_anter->dst == inst_atual->src) { return true; } } return false; } // Adiciona nova instrução com entrada do usuário void adicionar_instrucao() { if (total_instrucoes >= MAX_INSTRUCOES) { printf(“Limite de instruções atingido!n”); return; } Instrucao nova; nova.id = total_instrucoes + 1; nova.estagio_atual = 0; nova.concluida = false; nova.tempo_inicio = clock_global; nova.tempo_fim = -1; nova.em_bolha = false; printf(“Instrução %d:n”, nova.id); printf(” Registrador de origem (src): “); scanf(“%d”, &nova.src); printf(” Registrador de destino (dst): “); scanf(“%d”, &nova.dst); fila[total_instrucoes] = nova; total_instrucoes++; } // Executa um ciclo de clock void executar_ciclo() { printf(“nClock %d:n”, clock_global); for (int i = 0; i < total_instrucoes; i++) { Instrucao *inst = &fila[i]; if (inst->concluida) continue; if (inst->em_bolha) { printf(” Instrução %d em bolha (aguardando dependência)n”, inst->id); if (!tem_dependencia(i)) { inst->em_bolha = false; // pode avançar } continue; } // Se está na etapa de decodificação, verifica dependência if (inst->estagio_atual == 1 && tem_dependencia(i)) { inst->em_bolha = true; printf(” Instrução %d entra em bolha por dependêncian”, inst->id); continue; } // Executar estágio atual printf(” Instrução %d está em %sn”, inst->id, estagios[inst->estagio_atual]); inst->estagio_atual++; // Finalizou? if (inst->estagio_atual == MAX_ESTAGIOS – 1) { inst->concluida = true; inst->tempo_fim = clock_global; } } clock_global++; printf(“——————————-n”); } // Verifica se todas instruções concluíram bool todas_concluidas() { for (int i = 0; i < total_instrucoes; i++) { if (!fila[i].concluida) return false; } return true; } // Exibe tempos de execução void mostrar_tempos() { printf(“nResumo dos tempos:n”); for (int i = 0; i < total_instrucoes; i++) { Instrucao *inst = &fila[i]; printf(“Instrução %d: início=%d, fim=%d, duração=%dn”, inst->id, inst->tempo_inicio, inst->tempo_fim, inst->tempo_fim – inst->tempo_inicio + 1); } } // Menu principal void menu() { int opcao; do { printf(“n====== MENU ======n”); printf(“1. Adicionar instruçãon”); printf(“2. Executar 1 ciclon”); printf(“3. Executar até o fimn”); printf(“4. Mostrar temposn”); printf(“0. Sairn”); printf(“Escolha: “); scanf(“%d”, &opcao); switch (opcao) { case 1: adicionar_instrucao(); break; case 2: executar_ciclo(); break; case 3: while (!todas_concluidas()) executar_ciclo(); break; case 4: mostrar_tempos(); break; case 0: printf(“Encerrando…n”); break; default: printf(“Opção inválida!n”); } } while (opcao != 0); } int main() { menu(); return 0; }

    Dificuldades encontradas (resumo): 1. Controle dos estágios: Foi desafiador coordenar o avanço correto de cada instrução pelos 7 estágios do pipeline ao longo dos ciclos de clock. 2. Detecção de dependências: Implementar a verificação de conflitos de dados entre instruções (src e dst) e aplicar stalls (bolhas) exigiu lógica cuidadosa. 3. Sincronização do tempo (clock): Garantir que todas as instruções evoluam de forma paralela e ordenada, respeitando dependências e estágios, foi um desafio central. 4. Visualização da execução: Mostrar claramente o que acontece em cada ciclo e identificar onde há bolhas foi complexo sem recursos gráficos avançados. Como o pipeline auxilia na concorrência (resumo): O pipeline permite que várias instruções sejam executadas simultaneamente, cada uma em um estágio diferente. Com isso, a CPU não precisa esperar uma instrução terminar completamente para começar outra. Isso aumenta a concorrência interna e melhora o aproveitamento dos recursos do processador, reduzindo o tempo médio de execução por instrução e tornando o sistema mais eficiente.

    Curtir

  5. Arthur das Neves Ferreira RA:2706580

    include include define MAX_INSTRUCOES 10 define NUM_ESTAGIOS 7

    // Estrutura da instruçãotypedef struct {int id;char nome[20];int tempo_inicio;int tempo_fim;int ativa; // 1 = está sendo usada} Instrucao;

    // Nomes dos estágiosconst char* estagios[NUM_ESTAGIOS] = {“Busca”, “Decod”, “Busca Op”, “Exec”, “Mem”, “Escrita”, “Commit”};

    // Fila de instruçõesInstrucao fila[MAX_INSTRUCOES];int frente = 0, tras = 0, total = 0;

    // Pipeline (7 estágios)Instrucao pipeline[NUM_ESTAGIOS];

    // Tempo globalint tempo = 0;

    // Adiciona uma instrução à filavoid adicionar_instrucao(char* nome) {if (total < MAX_INSTRUCOES) {Instrucao nova;nova.id = total;strcpy(nova.nome, nome);nova.tempo_inicio = -1;nova.tempo_fim = -1;nova.ativa = 1;fila[tras] = nova;tras++;total++;}}

    // Retira instrução da filaInstrucao retirar_instrucao() {Instrucao vazia;vazia.ativa = 0;if (frente < tras) { Instrucao inst = fila[frente]; frente++; return inst; } return vazia;

    }

    // Verifica se pipeline está vazioint pipeline_vazio() {int i;for (i = 0; i < NUM_ESTAGIOS; i++) {if (pipeline[i].ativa == 1)return 0;}return 1;}

    // Inicializa pipelinevoid inicializar_pipeline() {int i;for (i = 0; i < NUM_ESTAGIOS; i++) {pipeline[i].ativa = 0;}}

    // Avança o pipelinevoid avancar_pipeline() {int i;// Finaliza a instrução no último estágio if (pipeline[NUM_ESTAGIOS - 1].ativa == 1) { pipeline[NUM_ESTAGIOS - 1].tempo_fim = tempo; printf("Instrução %s (ID %d) finalizada no tempo %dn", pipeline[NUM_ESTAGIOS - 1].nome, pipeline[NUM_ESTAGIOS - 1].id, tempo); } // Move as instruções for (i = NUM_ESTAGIOS - 1; i > 0; i--) { pipeline[i] = pipeline[i - 1]; } // Nova instrução na primeira posição if (frente < tras) { Instrucao nova = retirar_instrucao(); nova.tempo_inicio = tempo; pipeline[0] = nova; } else { pipeline[0].ativa = 0; } // Imprime estado atual printf("nTempo %d:n", tempo); for (i = 0; i < NUM_ESTAGIOS; i++) { if (pipeline[i].ativa == 1) { printf(" [%s] -> %s (ID %d)n", estagios[i], pipeline[i].nome, pipeline[i].id); } else { printf(" [%s] -> (vazio)n", estagios[i]); } } tempo++;

    }

    int main() {inicializar_pipeline();// Instruções iniciais adicionar_instrucao("ADD"); adicionar_instrucao("SUB"); adicionar_instrucao("MUL"); adicionar_instrucao("DIV"); adicionar_instrucao("AND"); adicionar_instrucao("OR"); // Loop principal while (!pipeline_vazio() || frente < tras) { avancar_pipeline(); } printf("nPipeline finalizado após %d ciclos.n", tempo); return 0;

    } Dificuldades encontradas: A principal dificuldade foi estruturar corretamente o avanço das instruções no pipeline, garantindo que cada estágio trabalhe de forma independente e sem sobrescrever instruções simultaneamente. Também foi necessário criar um controle cuidadoso da fila circular de instruções.

    Como o pipeline auxilia na concorrência de um sistema computacional: A técnica de pipeline permite que múltiplas instruções sejam processadas simultaneamente em diferentes estágios do processador. Isso reduz o tempo total de execução e aumenta o throughput do sistema, pois enquanto uma instrução está sendo executada, outra pode estar sendo decodificada ou buscada. O paralelismo entre os estágios é o que traz ganho de desempenho — semelhante a uma linha de montagem.

    Curtir

  6. Thainá Tamiris Souza Dionisio | RA: 2768810

    include include include

    // — DEFINIÇÕES GLOBAIS — define NUM_ESTAGIOS 7 define MAX_INSTRUCOES 20

    // Estrutura para uma instrução
    typedef struct {
    int id;
    int estagio_atual;
    int ciclo_inicio;
    int ciclo_fim;
    int ciclos_nos_estagios[NUM_ESTAGIOS];
    } Instrucao;

    // — VARIÁVEIS DO SIMULADOR —
    Instrucao* pipeline[NUM_ESTAGIOS];
    Instrucao fila_de_instrucoes[MAX_INSTRUCOES];
    int total_instrucoes_na_fila = 0;
    int proxima_instrucao_da_fila = 0;
    int instrucoes_completas = 0;

    const char* nomes_dos_estagios[NUM_ESTAGIOS] = {
    “Busca (IF)”, “Decodificacao (ID)”, “Busca Operando (OF)”,
    “Execucao (EX)”, “Acesso a Memoria (MEM)”, “Escrita (WB)”, “Commit (C)”
    };

    // — FUNÇÕES DO SIMULADOR —

    void exibir_pipeline(int ciclo) {
    printf(“————————————————-n”);
    printf(” ESTADO DO PIPELINE NO CICLO: %dn”, ciclo);
    printf(“————————————————-n”);
    for (int i = 0; i < NUM_ESTAGIOS; i++) { printf(“Estagio %d [%-19s]: “, i + 1, nomes_dos_estagios[i]); if (pipeline[i] != NULL) { printf(“Instrucao %dn”, pipeline[i]->id);
    } else {
    printf(“[vazio]n”);
    }
    }
    printf(“————————————————-nn”);
    }

    void avancar_pipeline(int ciclo) {
    // Processa o pipeline de trás para frente para avanço correto.// Finaliza a instrução no último estágio. if (pipeline[NUM_ESTAGIOS - 1] != NULL) { Instrucao* instrucao_finalizada = pipeline[NUM_ESTAGIOS - 1]; instrucao_finalizada->ciclo_fim = ciclo; instrucoes_completas++; printf(">>> Instrucao %d FINALIZADA no ciclo %d!n", instrucao_finalizada->id, ciclo); } // Move as outras instruções. for (int i = NUM_ESTAGIOS - 1; i > 0; i--) { pipeline[i] = pipeline[i-1]; if (pipeline[i] != NULL) { pipeline[i]->estagio_atual = i; pipeline[i]->ciclos_nos_estagios[i] = ciclo; } } // Libera o primeiro estágio. pipeline[0] = NULL;

    }

    void buscar_para_pipeline(int ciclo) {
    if (proxima_instrucao_da_fila < total_instrucoes_na_fila) {
    Instrucao* nova_instrucao = &fila_de_instrucoes[proxima_instrucao_da_fila]; pipeline[0] = nova_instrucao; pipeline[0]->estagio_atual = 0; pipeline[0]->ciclo_inicio = ciclo; pipeline[0]->ciclos_nos_estagios[0] = ciclo; printf(">>> Instrucao %d entrou no pipeline (Estagio 1: Busca).n", pipeline[0]->id); proxima_instrucao_da_fila++; }

    }

    // — FUNÇÃO PRINCIPAL —
    int main() {
    const char* NOME_ARQUIVO = “pipeline_sim.c”;
    FILE* fp = fopen(NOME_ARQUIVO, “w”);
    if (fp == NULL) {
    printf(“Erro ao criar o arquivo %sn”, NOME_ARQUIVO);
    return 1;
    }// Escreve o código no arquivo sem a maioria dos comentários fprintf(fp, "%s", "#include <stdio.h>n#include <stdlib.h>n#include <unistd.h>n" "#define NUM_ESTAGIOS 7n#define MAX_INSTRUCOES 20n" "typedef struct { int id; int estagio_atual; int ciclo_inicio; int ciclo_fim; int ciclos_nos_estagios[NUM_ESTAGIOS]; } Instrucao;n" "Instrucao* pipeline[NUM_ESTAGIOS];n" "Instrucao fila_de_instrucoes[MAX_INSTRUCOES];n" "int total_instrucoes_na_fila = 0;nint proxima_instrucao_da_fila = 0;nint instrucoes_completas = 0;n" "const char* nomes_dos_estagios[NUM_ESTAGIOS] = {"Busca (IF)","Decodificacao (ID)","Busca Operando (OF)","Execucao (EX)","Acesso a Memoria (MEM)","Escrita (WB)","Commit (C)"};n" "void exibir_pipeline(int ciclo) { printf("-------------------------------------------------\n"); printf(" ESTADO DO PIPELINE NO CICLO: %d\n", ciclo); printf("-------------------------------------------------\n"); for (int i = 0; i < NUM_ESTAGIOS; i++) { printf("Estagio %d [%-19s]: ", i + 1, nomes_dos_estagios[i]); if (pipeline[i] != NULL) { printf("Instrucao %d\n", pipeline[i]->id); } else { printf("[vazio]\n"); } } printf("-------------------------------------------------\n\n"); }n" "void avancar_pipeline(int ciclo) { if (pipeline[NUM_ESTAGIOS - 1] != NULL) { Instrucao* instr = pipeline[NUM_ESTAGIOS - 1]; instr->ciclo_fim = ciclo; instrucoes_completas++; printf(">>> Instrucao %d FINALIZADA no ciclo %d!\n", instr->id, ciclo); } for (int i = NUM_ESTAGIOS - 1; i > 0; i--) { pipeline[i] = pipeline[i-1]; if (pipeline[i] != NULL) { pipeline[i]->estagio_atual = i; pipeline[i]->ciclos_nos_estagios[i] = ciclo; } } pipeline[0] = NULL; }n" "void buscar_para_pipeline(int ciclo) { if (proxima_instrucao_da_fila < total_instrucoes_na_fila) { Instrucao* instr = &fila_de_instrucoes[proxima_instrucao_da_fila]; pipeline[0] = instr; pipeline[0]->estagio_atual = 0; pipeline[0]->ciclo_inicio = ciclo; pipeline[0]->ciclos_nos_estagios[0] = ciclo; printf(">>> Instrucao %d entrou no pipeline (Estagio 1: Busca).\n", pipeline[0]->id); proxima_instrucao_da_fila++; } }n" "int main() { int ciclo_atual = 1; for (int i = 0; i < NUM_ESTAGIOS; i++) { pipeline[i] = NULL; } printf("Digite o numero de instrucoes para simular (max %d): ", MAX_INSTRUCOES); scanf("%d", &total_instrucoes_na_fila); if (total_instrucoes_na_fila <= 0 || total_instrucoes_na_fila > MAX_INSTRUCOES) { printf("Numero invalido.\n"); exit(1); } for (int i = 0; i < total_instrucoes_na_fila; i++) { fila_de_instrucoes[i].id = i + 1; fila_de_instrucoes[i].estagio_atual = -1; } while (instrucoes_completas < total_instrucoes_na_fila) { avancar_pipeline(ciclo_atual); if (pipeline[0] == NULL) { buscar_para_pipeline(ciclo_atual); } exibir_pipeline(ciclo_atual); ciclo_atual++; usleep(500000); } printf("\n\n===============================================\n"); printf(" SIMULACAO FINALIZADA!\n"); printf("===============================================\n"); printf("Total de ciclos de clock: %d\n\n", ciclo_atual - 1); for (int i = 0; i < total_instrucoes_na_fila; i++) { Instrucao instr = fila_de_instrucoes[i]; printf("Instrucao %d: Entrou=%d, Saiu=%d, Tempo Total=%d ciclos\n", instr.id, instr.ciclo_inicio, instr.ciclo_fim, instr.ciclo_fim - instr.ciclo_inicio); } return 0; }n" ); fclose(fp); system("gcc pipeline_sim.c -o pipeline_sim && ./pipeline_sim"); return 0;

    }

    Curtir

  7. aluno: Pedro Henrique Romano Gedminas

    Ra: 2768500

    Codigo:

    #include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h> // para sleep()#define MAX_INSTRUCOES 20#define ESTAGIOS 7// Nomes dos estágios do pipelineconst char* estagios[] = {“IF”, “ID”, “EX1”, “EX2”, “MEM1”, “MEM2”, “WB”};typedef struct {char nome[10];int tempoInicio;int tempoFim;} Instrucao;void simularPipeline(Instrucao instrucoes[], int n) {int tempo = 0;printf(“Simulando pipeline de %d instrucoes:n”, n);printf(“Tempo |”);for (int i = 0; i < n; i++)printf(” %s “, instrucoes[i].nome);printf(“n”);int fim = n + ESTAGIOS;for (tempo = 0; tempo < fim; tempo++) {printf(“%5d |”, tempo + 1);for (int i = 0; i < n; i++) {if (tempo >= i && tempo < i + ESTAGIOS)printf(” %s “, estagios[tempo – i]);elseprintf(” “);}printf(“n”);usleep(500000); // 0.5 segundo por ciclo}}int main() {Instrucao fila[MAX_INSTRUCOES];int n = 0;char opcao;printf(“Simulador de Pipeline com 7 Estagiosn”);do {printf(“Digite o nome da instrucao %d: “, n + 1);scanf(“%s”, fila[n].nome);n++;printf(“Deseja adicionar outra instrucao? (s/n): “);scanf(” %c”, &opcao);} while ((opcao == ‘s’ || opcao == ‘S’) && n < MAX_INSTRUCOES);simularPipeline(fila, n);return 0;}

    Durante a implementação em C, a principal dificuldade foi o controle das instruções em ciclos paralelos, além de garantir que cada instrução começasse no ciclo correto e que os estágios fossem respeitados. O pipeline permite o processamento simultâneo de várias instruções, o que aumenta a eficiência do sistema, como simulado neste projeto.

    Curtir

  8. #include <stdio.h>

    #include <stdbool.h>

    #include <stdlib.h>

    #define MAX_INSTRUCOES 20

    #define MAX_ESTAGIOS 7

    const char *estagios[MAX_ESTAGIOS] = {“BI”, “DI”, “CO”, “BO”, “EI”, “EO”, “FIM”};

    typedef struct {

        int id;

        int estagio_atual;

        bool concluida;

        int tempo_inicio;

        int tempo_fim;

        int src; // registrador de origem (leitura)

        int dst; // registrador de destino (escrita)

        bool em_bolha;

    } Instrucao;

    Instrucao fila[MAX_INSTRUCOES];

    int total_instrucoes = 0;

    int clock_global = 0;

    bool tem_dependencia(int atual_idx) {

        Instrucao *inst_atual = &fila[atual_idx];

        for (int i = 0; i < atual_idx; i++) {

            Instrucao *inst_anter = &fila[i];

            if (!inst_anter->concluida && inst_anter->dst == inst_atual->src) {

                return true;

            }

        }

        return false;

    }

    void adicionar_instrucao() {

        if (total_instrucoes >= MAX_INSTRUCOES) {

            printf(“Limite de instruções atingido!n”);

            return;

        }

        Instrucao nova;

        nova.id = total_instrucoes + 1;

        nova.estagio_atual = 0;

        nova.concluida = false;

        nova.tempo_inicio = clock_global;

        nova.tempo_fim = -1;

        nova.em_bolha = false;

        printf(“Instrução %d:n”, nova.id);

        printf(” Registrador de origem (src): “);

        scanf(“%d”, &nova.src);

        printf(” Registrador de destino (dst): “);

        scanf(“%d”, &nova.dst);

        fila[total_instrucoes] = nova;

        total_instrucoes++;

    }

    void executar_ciclo() {

        printf(“nClock %d:n”, clock_global);

        for (int i = 0; i < total_instrucoes; i++) {

            Instrucao *inst = &fila[i];

            if (inst->concluida) continue;

            if (inst->em_bolha) {

                printf(” Instrução %d em bolha (aguardando dependência)n”, inst->id);

                if (!tem_dependencia(i)) {

                    inst->em_bolha = false;

                }

                continue;

            }

            if (inst->estagio_atual == 1 && tem_dependencia(i)) {

                inst->em_bolha = true;

                printf(” Instrução %d entra em bolha por dependêncian”, inst->id);

                continue;

            }

            printf(” Instrução %d está em %sn”, inst->id, estagios[inst->estagio_atual]);

            inst->estagio_atual++;

            if (inst->estagio_atual == MAX_ESTAGIOS – 1) {

                inst->concluida = true;

                inst->tempo_fim = clock_global;

            }

        }

        clock_global++;

        printf(“———————–n”);

    }

    bool todas_concluidas() {

        for (int i = 0; i < total_instrucoes; i++) {

            if (!fila[i].concluida) return false;

        }

        return true;

    }

    void mostrar_tempos() {

        printf(“nResumo dos tempos:n”);

        for (int i = 0; i < total_instrucoes; i++) {

            Instrucao *inst = &fila[i];

            printf(“Instrução %d: início=%d, fim=%d, duração=%dn”,

                   inst->id, inst->tempo_inicio, inst->tempo_fim,

                   inst->tempo_fim – inst->tempo_inicio + 1);

        }

    }

    void menu() {

        int opcao;

        do {

            printf(“1. Adicionar instruçãon”);

            printf(“2. Executar 1 ciclon”);

            printf(“3. Executar até o fimn”);

            printf(“4. Mostrar temposn”);

            printf(“0. Sairn”);

            printf(“Escolha: “);

            scanf(“%d”, &opcao);

            switch (opcao) {

                case 1: adicionar_instrucao(); break;

                case 2: executar_ciclo(); break;

                case 3: while (!todas_concluidas()) executar_ciclo(); break;

                case 4: mostrar_tempos(); break;

                case 0: printf(“Encerrando…n”); break;

                default: printf(“Opção inválida!n”);

            }

        } while (opcao != 0);

    }

    int main() {

        menu();

        return 0;

    }

    Curtir

  9. ALUNO: Michel Rodrigues Ferreira

    TURMA: ES11

    CÓDIGO-FONTE:

    include include include include define N_TAREFAS 7

    void cpu(int fila[], int tam_f, int n_tarefas);
    void execTarefa(int tarefa, int instrucao);
    void tarefa1(int instrucao);
    void tarefa2(int instrucao);
    void tarefa3(int instrucao);
    void tarefa4(int instrucao);
    void tarefa5(int instrucao);
    void tarefa6(int instrucao);
    void tarefa7(int instrucao);

    int main(){
    setlocale(LC_ALL, “Portuguese”);
    int tam_f = (rand() % 100) + 7;
    int fila[tam_f], i;for(i = 0; i < tam_f; i++){ fila[i] = i+1; } printf("FILA DE INSTRUÇÕES A SEREM PROCESSADAS: "); for(i = 0; i < tam_f; i++){ printf("%d ", fila[i]); } printf("nnn"); cpu(fila, tam_f, N_TAREFAS); return 0;

    }

    void cpu(int fila[], int tam_f, int n_tarefas){
    int ciclo, i;
    int quantidadeCiclos = tam_f + n_tarefas – 1;for(ciclo = 0; ciclo < quantidadeCiclos; ciclo++){ printf("n******************** CICLO %d ********************nn", ciclo+1); for(i = n_tarefas - 1; i >= 0; i--){ int indice_instrucao = ciclo - i; if(indice_instrucao >= 0 && indice_instrucao < tam_f){ int instrucao = fila[indice_instrucao]; execTarefa(i, instrucao); } } }

    }

    void execTarefa(int tarefa, int instrucao){
    switch(tarefa){
    case 0:
    tarefa1(instrucao);
    break;
    case 1:
    tarefa2(instrucao);
    break;
    case 2:
    tarefa3(instrucao);
    break;
    case 3:
    tarefa4(instrucao);
    break;
    case 4:
    tarefa5(instrucao);
    break;
    case 5:
    tarefa6(instrucao);
    break;
    case 6:
    tarefa7(instrucao);
    break;}

    }

    void tarefa1(int instrucao){
    printf(“Instrução %d executando a tarefa 1n”, instrucao);
    }

    void tarefa2(int instrucao){
    printf(“Instrução %d executando a tarefa 2n”, instrucao);
    }

    void tarefa3(int instrucao){
    printf(“Instrução %d executando a tarefa 3n”, instrucao);
    }

    void tarefa4(int instrucao){
    printf(“Instrução %d executando a tarefa 4n”, instrucao);
    }

    void tarefa5(int instrucao){
    printf(“Instrução %d executando a tarefa 5n”, instrucao);
    }

    void tarefa6(int instrucao){
    printf(“Instrução %d executando a tarefa 6n”, instrucao);
    }

    void tarefa7(int instrucao){
    printf(“Instrução %d executando a tarefa 7n”, instrucao);
    }

    ———————————————————————

    OBS: optei por nomear as tarefas executadas pelo pipeline e a lista de instruções a serem executadas apenas por números. Assim, para um pipeline de tarefas, temos as tarefas 1, 2, 3, 4, 5, 6 e 7. Para um vetor de N instruções, temos as instruções: 1, 2, 3, 4, 5, 6, …, N.

    PRINCIPAIS DIFICULDADES:

    1. Observar a necessidade de utilizar uma fórmula matemática que calcula o número de ciclos para N instruções e X tarefas. Nesse caso, cheguei a seguinte fórmula: NÚMERO DE CICLOS = N + X – 1.
    2. Definir como a iteração deveria ocorrer para alocar corretamente cada instrução em cada posição do ciclo no pipeline (p. ex., no primeiro processamento dentre todos os possíveis, a primeira e única instrução que deve entrar é a instrução 1, haja vista que todas as demais tarefas ainda não foram executadas por nenhuma instrução. Posteriormente, a instrução 1 deve ir para a tarefa 2, liberando a tarefa 1 para a instrução 2, mas ainda deixando as tarefas 3 – 7 desocupadas, e assim por diante) – essa foi a lógica mais difícil, pois foi necessário realizar vários debugs até atingir o resultado esperado.

    Curtir

  10. #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <stdbool.h>

    #define MAX_STAGE 7

    const char *STAGE_NAMES[MAX_STAGE] = {“IF”, “ID”, “T2”, “T3”, “EX”, “MEM”, “WB”};

    #define MAX_INSTR_TYPES 32

    #define MAX_QUEUE 256

    #define MAX_SRC 3

    #define MAX_REGS 64

    #define MAX_NAME_LEN 16

    // Toggle detailed per-cycle trace

    #define VERBOSE 1

    typedef struct {

        char name[MAX_NAME_LEN];

        int stage_latencies[MAX_STAGE]; // latência (n ciclos) por estágio

    } InstrType;

    typedef struct {

        InstrType *type;      // ponteiro para o tipo de instrução

        int uid;              // id único

        int program_order;    // posição no programa/fila

        int current_stage;    // índice do estágio atual (0..6) ou -1 quando fora

        int remaining_cycles; // ciclos restantes no estágio atual

        int entry_cycle;      // ciclo em que entrou em IF

        int exit_cycle;       // ciclo em que saiu de WB

        int cycles_spent;     // total de ciclos dentro do pipeline

        int dest;             // registrador destino (-1 se nenhum)

        int src_count;        // número de registradores fonte

        int srcs[MAX_SRC];    // registradores fonte

        bool completed;

    } InstrInstance;

    typedef struct {

        InstrType types[MAX_INSTR_TYPES];

        int type_count;

        InstrInstance *queue[MAX_QUEUE];

        int queue_count;

        InstrInstance *stages[MAX_STAGE]; // pipeline stage slots

        int cycle;

        int uid_counter;

        InstrInstance *completed[MAX_QUEUE];

        int completed_count;

    } PipelineCPU;

    /* ———— Utilities and factory functions ———— */

    InstrType* add_instr_type(PipelineCPU *cpu, const char *name, int latencies[MAX_STAGE]) {

        if (cpu->type_count >= MAX_INSTR_TYPES) return NULL;

        InstrType *t = &cpu->types[cpu->type_count++];

        strncpy(t->name, name, MAX_NAME_LEN-1);

        t->name[MAX_NAME_LEN-1] = ”;

        for (int i = 0; i < MAX_STAGE; ++i) t->stage_latencies[i] = latencies[i];

        return t;

    }

    InstrInstance* create_instance(PipelineCPU *cpu, InstrType *t, int dest, int srcs[], int src_count) {

        if (cpu->queue_count >= MAX_QUEUE) return NULL;

        InstrInstance *inst = malloc(sizeof(InstrInstance));

        inst->type = t;

        inst->uid = cpu->uid_counter++;

        inst->program_order = cpu->queue_count;

        inst->current_stage = -1;

        inst->remaining_cycles = 0;

        inst->entry_cycle = -1;

        inst->exit_cycle = -1;

        inst->cycles_spent = 0;

        inst->dest = dest;

        inst->src_count = src_count > MAX_SRC ? MAX_SRC : src_count;

        for (int i=0;i<inst->src_count;i++) inst->srcs[i] = srcs[i];

        inst->completed = false;

        cpu->queue[cpu->queue_count++] = inst;

        return inst;

    }

    void init_cpu(PipelineCPU *cpu) {

        cpu->type_count = 0;

        cpu->queue_count = 0;

        for (int i=0;i<MAX_STAGE;i++) cpu->stages[i] = NULL;

        cpu->cycle = 0;

        cpu->uid_counter = 0;

        cpu->completed_count = 0;

    }

    /* ———— Hazard detection (very simple RAW) ————

       Checks if ‘inst’ reads a register that some earlier instruction in pipeline still

       must write (i.e., writer hasn’t completed WB). If so, stall. This is simple and

       pedagogical (no forwarding). */

    bool detect_raw_hazard(PipelineCPU *cpu, InstrInstance *inst) {

        if (inst->src_count == 0) return false;

        for (int s=0; s<MAX_STAGE; ++s) {

            InstrInstance *other = cpu->stages[s];

            if (!other) continue;

            if (other == inst) continue;

            if (other->dest >= 0) {

                for (int i=0;i<inst->src_count;i++) {

                    if (other->dest == inst->srcs[i]) {

                        // if other is in WB and remaining_cycles==0 then it will complete this cycle: allow

                        if (s == MAX_STAGE-1 && other->remaining_cycles == 0) {

                            continue;

                        }

                        return true; // hazard exists

                    }

                }

            }

        }

        return false;

    }

    /* ———— Core step: advance simulation one cycle ———— */

    void step(PipelineCPU *cpu) {

        cpu->cycle++;

        if (VERBOSE) printf(“n=== Cycle %d ===n”, cpu->cycle);

        // Track moves to perform after scanning (avoids overwriting while iterating)

        typedef struct { int from; int to; InstrInstance *inst; } Move;

        Move moves[MAX_STAGE];

        int move_count = 0;

        // 1) Right-to-left: decrement remaining cycles and prepare possible moves

        for (int i = MAX_STAGE-1; i >= 0; –i) {

            InstrInstance *inst = cpu->stages[i];

            if (!inst) continue;

            // If first time in this stage set remaining cycles from type latency

            if (inst->remaining_cycles == 0 && inst->current_stage == i) {

                inst->remaining_cycles = inst->type->stage_latencies[i];

                if (VERBOSE) printf(“%s-%d starts stage %s (latency %d)n”, inst->type->name, inst->uid, STAGE_NAMES[i], inst->remaining_cycles);

            } else if (inst->current_stage != i) {

                // This can happen if instance was just moved into this stage this cycle: load latency and decrement below

                inst->remaining_cycles = inst->type->stage_latencies[i];

                inst->current_stage = i;

                if (VERBOSE) printf(“%s-%d begins stage %s (latency %d)n”, inst->type->name, inst->uid, STAGE_NAMES[i], inst->remaining_cycles);

            }

            // decrement one cycle of work

            if (inst->remaining_cycles > 0) {

                inst->remaining_cycles–;

                inst->cycles_spent++;

            }

            // If finished this stage (remaining_cycles == 0), try to move to next or complete

            if (inst->remaining_cycles == 0) {

                if (i == MAX_STAGE-1) {

                    // completes pipeline

                    moves[move_count++] = (Move){i, -1, inst};

                } else {

                    // try move if next stage free

                    if (cpu->stages[i+1] == NULL) {

                        moves[move_count++] = (Move){i, i+1, inst};

                    } else {

                        if (VERBOSE) printf(“%s-%d ready to leave %s but %s is busy -> structural stalln”,

                                           inst->type->name, inst->uid, STAGE_NAMES[i], STAGE_NAMES[i+1]);

                    }

                }

            }

        }

        // 2) Apply moves (remove from old stage and place to new)

        for (int m = 0; m < move_count; ++m) {

            int from = moves[m].from;

            int to = moves[m].to;

            InstrInstance *inst = moves[m].inst;

            // confirm still present at ‘from’ (could be moved earlier in this cycle)

            if (cpu->stages[from] != inst) continue;

            cpu->stages[from] = NULL;

            inst->current_stage = -1;

            inst->remaining_cycles = 0; // will be set when stage processing runs next cycle

            if (to == -1) {

                inst->exit_cycle = cpu->cycle;

                inst->completed = true;

                cpu->completed[cpu->completed_count++] = inst;

                if (VERBOSE) printf(“%s-%d COMPLETED at cycle %dn”, inst->type->name, inst->uid, cpu->cycle);

            } else {

                cpu->stages[to] = inst;

                inst->current_stage = to;

                if (VERBOSE) printf(“%s-%d moved to stage %sn”, inst->type->name, inst->uid, STAGE_NAMES[to]);

            }

        }

        // 3) Try to fetch a new instruction into IF (stage 0) if empty and there is any not fetched

        if (cpu->stages[0] == NULL) {

            // find next instruction in queue not yet entered

            InstrInstance *next = NULL;

            for (int i=0;i<cpu->queue_count;i++) {

                if (cpu->queue[i]->entry_cycle == -1) {

                    next = cpu->queue[i];

                    break;

                }

            }

            if (next != NULL) {

                cpu->stages[0] = next;

                next->current_stage = 0;

                next->entry_cycle = cpu->cycle;

                next->remaining_cycles = 0; // will be set at the start of stage processing

                if (VERBOSE) printf(“%s-%d fetched into IFn”, next->type->name, next->uid);

            }

        }

        // 4) Left-to-right pass: attempt to advance instructions that are ready (remaining_cycles==0) into next stage,

        // e.g., IF -> ID movement with ID hazards detection. This emulates ID detecting RAW that causes IF to stall.

        for (int i=0;i<MAX_STAGE-1;i++) {

            InstrInstance *inst = cpu->stages[i];

            if (!inst) continue;

            if (inst->remaining_cycles != 0) continue; // not ready to move

            if (cpu->stages[i+1] != NULL) continue; // next busy

            // If moving IF->ID (i==0), do RAW hazard detection to decide stall

            if (i == 0) {

                if (detect_raw_hazard(cpu, inst)) {

                    if (VERBOSE) printf(“%s-%d STALL in IF due to RAW hazard for IDn”, inst->type->name, inst->uid);

                    continue; // stall

                }

            }

            // perform move

            cpu->stages[i] = NULL;

            cpu->stages[i+1] = inst;

            inst->current_stage = i+1;

            inst->remaining_cycles = 0; // will be set during next iteration’s right-to-left

            if (VERBOSE) printf(“%s-%d advanced to %s (left->right pass)n”, inst->type->name, inst->uid, STAGE_NAMES[i+1]);

        }

        // 5) Print pipeline state

        if (VERBOSE) {

            printf(“Pipeline: “);

            for (int i=0;i<MAX_STAGE;i++) {

                if (cpu->stages[i]) {

                    printf(“%s:%s-%d “, STAGE_NAMES[i], cpu->stages[i]->type->name, cpu->stages[i]->uid);

                } else {

                    printf(“%s:—- “, STAGE_NAMES[i]);

                }

            }

            printf(“nCompleted: “);

            for (int i=0;i<cpu->completed_count;i++) {

                printf(“%s-%d “, cpu->completed[i]->type->name, cpu->completed[i]->uid);

            }

            printf(“n”);

        }

    }

    /* Run until pipeline empty and all queue elements entered, or a safety max cycles reached */

    void run_until_empty(PipelineCPU *cpu, int max_cycles) {

        while (true) {

            bool in_pipeline = false;

            for (int i=0;i<MAX_STAGE;i++) if (cpu->stages[i]) { in_pipeline = true; break; }

            bool not_fetched = false;

            for (int i=0;i<cpu->queue_count;i++) if (cpu->queue[i]->entry_cycle == -1) { not_fetched = true; break; }

            if (!in_pipeline && !not_fetched) break;

            if (cpu->cycle >= max_cycles) {

                printf(“Reached max cycles limit (%d)n”, max_cycles);

                break;

            }

            step(cpu);

        }

    }

    /* ———— Reporting ————- */

    void report(PipelineCPU *cpu) {

        printf(“n=== Final Report ===n”);

        // sort completed by program_order (simple O(n^2) small n)

        for (int i=0;i<cpu->completed_count-1;i++) {

            for (int j=i+1;j<cpu->completed_count;j++) {

                if (cpu->completed[i]->program_order > cpu->completed[j]->program_order) {

                    InstrInstance *t = cpu->completed[i];

                    cpu->completed[i] = cpu->completed[j];

                    cpu->completed[j] = t;

                }

            }

        }

        printf(“%-10s %-6s %-6s %-6s %-6sn”, “instr”, “entry”, “exit”, “cycles”, “type”);

        for (int i=0;i<cpu->completed_count;i++) {

            InstrInstance *inst = cpu->completed[i];

            int total = (inst->entry_cycle>=0 && inst->exit_cycle>=0) ? (inst->exit_cycle – inst->entry_cycle + 1) : -1;

            printf(“%-10s %-6d %-6d %-6d %-6sn”,

                   inst->type->name, inst->entry_cycle, inst->exit_cycle, total, inst->type->name);

        }

        printf(“Total cycles simulated: %dn”, cpu->cycle);

        printf(“Instructions completed: %dn”, cpu->completed_count);

        double throughput = cpu->cycle ? ((double)cpu->completed_count / cpu->cycle) : 0.0;

        printf(“Throughput (instrs/cycle): %.4fn”, throughput);

    }

    /* ———— Example main: build types and sample program ———— */

    int main(void) {

        PipelineCPU cpu;

        init_cpu(&cpu);

        // Build default instruction set (latency per stage; examples)

        int lat_alusimple[MAX_STAGE] = {1,1,1,1,1,1,1}; // ALU simple: 1 cycle per stage

        int lat_load[MAX_STAGE]      = {1,1,1,1,1,2,1}; // LOAD: MEM takes 2 cycles

        int lat_mul[MAX_STAGE]       = {1,1,1,1,2,1,1}; // MUL: EX takes 2 cycles

        int lat_br[MAX_STAGE]        = {1,2,1,1,1,1,1}; // BR: ID longer

        InstrType *ALU = add_instr_type(&cpu, “ALU”, lat_alusimple);

        InstrType *LOAD = add_instr_type(&cpu, “LOAD”, lat_load);

        InstrType *MUL = add_instr_type(&cpu, “MUL”, lat_mul);

        InstrType *BR = add_instr_type(&cpu, “BR”, lat_br);

        // Build a sample program (dest, srcs)

        // Program:

        // 0: LOAD r1 <- mem        (writes r1)

        // 1: ALU  r2 <- r1 + r3    (reads r1 -> RAW with LOAD)

        // 2: MUL  r4 <- r2 * r5    (reads r2 -> RAW)

        // 3: ALU  r6 <- r7 + r8    (independent)

        // 4: LOAD r9 <- mem

        // 5: ALU  r10<- r9 + r11

        // 6: BR   (branch)

        int r1 = 1, r2 = 2, r3 = 3, r4 = 4, r5 = 5, r6 = 6, r7 = 7, r8 = 8, r9 = 9, r10 = 10, r11 = 11;

        int tmp_srcs[MAX_SRC];

        // 0

        tmp_srcs[0] = -1;

        create_instance(&cpu, LOAD, r1, tmp_srcs, 0);

        // 1

        tmp_srcs[0] = r1; create_instance(&cpu, ALU, r2, tmp_srcs, 1);

        // 2

        tmp_srcs[0] = r2; create_instance(&cpu, MUL, r4, tmp_srcs, 1);

        // 3

        tmp_srcs[0] = r7; tmp_srcs[1] = r8; create_instance(&cpu, ALU, r6, tmp_srcs, 2);

        // 4

        tmp_srcs[0] = -1; create_instance(&cpu, LOAD, r9, tmp_srcs, 0);

        // 5

        tmp_srcs[0] = r9; create_instance(&cpu, ALU, r10, tmp_srcs, 1);

        // 6

        tmp_srcs[0] = -1; create_instance(&cpu, BR, -1, tmp_srcs, 0);

        // Run simulation

        run_until_empty(&cpu, 1000);

        report(&cpu);

        // Free allocated instances

        for (int i=0;i<cpu.queue_count;i++) free(cpu.queue[i]);

        return 0;

    }

    Curtir

  11. ALUNO: Arthur Valsezia dos Santos Biagi

    TURMA: ES41C

    #include <stdio.h>

    #include <locale.h>

    #include <string.h>

    // Define o limite máximo de instruções e o número de estágios do pipeline

    #define MAX_INSTRUCOES 100

    #define ESTAGIOS 7

    // Array de strings com os nomes dos estágios do pipeline

    const char *estagios[ESTAGIOS] =

    {

    “Busca”,

    “Decodificacao”,

    “Calculo”,

    “Execucao”,

    “Memoria”,

    “Saida”,

    “Conclusao”

    };

    int main()

    {

    // Define a localização para permitir acentuação em português

    setlocale(LC_ALL, “Portuguese”);

    // Declara variáveis

    int qtdInstrucoes; // Quantidade de instruções a serem simuladas

    int matriz[MAX_INSTRUCOES][MAX_INSTRUCOES] = {0}; // Matriz que representa o pipeline

    int i, j; // Contadores

    int ciclos = 0; // Contador de ciclos (clock)

    // Entrada do usuário: quantidade de instruções

    printf(“Digite a quantidade de instruções: “);

    scanf(“%d”, &qtdInstrucoes);

    // Valida se a quantidade excede o limite definido

    if (qtdInstrucoes > MAX_INSTRUCOES)

    {

    printf(“Quantidade de instruções excede o limite (%d).n”, MAX_INSTRUCOES);

    return 1; // Encerra o programa com erro

    }

    // Preenche a matriz com os estágios de cada instrução

    // Cada instrução entra em momentos diferentes (pipeline escalonado)

    for (i = 0; i < qtdInstrucoes; i++)

    {

    for (j = 0; j < ESTAGIOS; j++)

    {

    matriz[i][i + j] = j + 1; // Preenche com o valor correspondente ao estágio

    }

    }

    // Simula o ciclo de clock: imprime a evolução de cada instrução em cada ciclo

    printf(“n— Simulação do Pipeline —nn”);

    for (int tempo = 0; tempo < qtdInstrucoes + ESTAGIOS; tempo++)

    {

    for (int inst = 0; inst < qtdInstrucoes; inst++)

    {

    int fase = matriz[inst][tempo];

    if (fase != 0)

    {

    // Imprime qual estágio a instrução está executando neste ciclo

    printf(“Instrução %2d – %sn”, inst + 1, estagios[fase – 1]);

    }

    }

    ciclos++; // Incrementa o número de ciclos

    printf(“n”);

    }

    // Exibe o total de ciclos utilizados para concluir todas as instruções

    printf(“Quantidade total de ciclos (clocks): %dn”, ciclos – 1);

    return 0;

    }

    DIFICULDADES ENCONTRADAS:

    A dificuldade inicial residiu na compreensão da forma de alocar as etapas das diretrizes (instruções) no decorrer do tempo. Parecia difícil fazer com que diversas diretrizes progredissem ao mesmo tempo, mas o arranjo tabular (matriz) auxiliou na visualização de cada uma na sua fase correspondente.

    Assim que se tornou claro o funcionamento da sequenciação (escalonamento), foi possível estruturar o pipeline de acordo com o padrão apresentado na aula, com cada diretriz atravessando as sete fases em instantes separados. O modo como o resultado é exposto torna mais simples a apreensão do procedimento.

    A utilização do pipeline é um benefício porque possibilita que diversas diretrizes sejam executadas em simultâneo, cada qual num passo diferente, o que torna a operação do processador mais célere e produtiva, sem a necessidade de aguardar a conclusão de uma diretriz para que outra comece.

    Curtir

  12. ATIVIDADE 11 – DESAFIO DE PIPELINE – ES11

    NICOLAS LUCATELI MARIA

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <locale.h>

    // Definindo a capacidade máxima da fila de instruções

    #define MAX_INSTRUCOES 10

    // Estrutura para representar uma “instrução” (uma peça de roupa ou lote)

    struct Instrucao {

        int id; // Identificador da instrução/roupa

        char nome[50]; // Nome da roupa ou tarefa

        int tempo_total_execucao; // Tempo que levou para ser processada

        // O estágio do pipeline em que a instrução se encontra (0 a 7)

        // 0 = Não iniciada / 1-7 = Estágio do Pipeline / 8 = Concluída

        int estagio_pipeline;

    };

    int main() {

        // —————————————————-

        // INICIALIZAÇÃO DA FILA DE INSTRUÇÕES

        // —————————————————-

        setlocale(LC_ALL, “Portuguese”);

        int i;

        struct Instrucao fila_instrucoes[MAX_INSTRUCOES];

        int proximo_id = 1; // Contador para dar IDs únicos às novas instruções

        int num_instrucoes_na_fila = 0; // Quantidade atual de instruções na fila

        int tempo_global = 0; // Contador de “ciclos de clock” da UCP

        // Nomes dos 7 estágios do pipeline (baseado em Lavar -> Secar -> Passar -> Guardar)

        char *estagios_nomes[] = {

            “Nao Iniciada”,

            “Lavar “,  // Subtarefa de Lavar

            “Secar “, // Subtarefa de Secar

            “Passar”,         // Subtarefa de Passar

            “Guardar”,         // Subtarefa de Guardar

            “Concluida”       // Estágio final (virtual)

        };

        // —————————————————-

        // CRIAÇÃO DE INSTRUÇÕES INICIAIS

        // —————————————————-

        printf(“— SIMULACAO DE PIPELINE (Maquina de Lavar) —n”);

        // Instrução 1: Camisetas

        if (num_instrucoes_na_fila < MAX_INSTRUCOES) {

            fila_instrucoes[num_instrucoes_na_fila].id = proximo_id++;

            strcpy(fila_instrucoes[num_instrucoes_na_fila].nome, “Roupas”);

            fila_instrucoes[num_instrucoes_na_fila].tempo_total_execucao = 0;

            fila_instrucoes[num_instrucoes_na_fila].estagio_pipeline = 1; // Começa no estagio 1

            num_instrucoes_na_fila++;

        }

        // —————————————————-

        // UCP – PROCESSO DE EXECUÇÃO (LOOP PRINCIPAL)

        // —————————————————-

        printf(“Instrucoes iniciais carregadas. Pressione [ENTER] para iniciar.n”);

        getchar();

        // Loop principal da “UCP” (Unidade Central de Processamento)

        // Continua enquanto houver instruções ativas (estagio < 8)

        while (1) {

            int todas_concluidas = 1; // Flag para verificar se o processo acabou

            printf(“n======================================================n”);

            printf(“——————————————————n”);

            // 1. O Pipeline (Movimentação das Instruções)

            // Percorre todas as instruções na fila

            for(i = 0; i < num_instrucoes_na_fila; i++){

                // Verifica se a instrução ainda está no pipeline (estagio 1 a 7)

                if (fila_instrucoes[i].estagio_pipeline >= 1 && fila_instrucoes[i].estagio_pipeline <= 5) {

                    // Avança a instrução para o próximo estágio

                    fila_instrucoes[i].estagio_pipeline++;

                    fila_instrucoes[i].tempo_total_execucao++;

                    // Exibe o movimento

                    printf(“Instrucao #%d (%s) avança para %sn”,

                           fila_instrucoes[i].id,

                           fila_instrucoes[i].nome,

                           estagios_nomes[fila_instrucoes[i].estagio_pipeline]); // Usa o novo estágio

                    // Se a instrução atingiu o estágio 8 (Concluída)

                    if (fila_instrucoes[i].estagio_pipeline == 5) {

                        printf(“>>> INSTRUCAO #%d (%s) CONCLUIDA em %d ciclos.n”,

                               fila_instrucoes[i].id,

                               fila_instrucoes[i].nome,

                               fila_instrucoes[i].tempo_total_execucao);

                    }

                }

            }

            // 2. Verificação de Conclusão

            // Percorre novamente para verificar se o loop deve continuar

            for (i = 0; i < num_instrucoes_na_fila; i++) {

                if (fila_instrucoes[i].estagio_pipeline < 5) {

                    todas_concluidas = 0; // Há pelo menos uma instrução não concluída

                }

            }

            // 3. Criação de Nova Instrução (simulada)

            // 4. Parada ou Avanço

            if (todas_concluidas) {

                printf(“nTODAS AS INSTRUCOES FORAM CONCLUIDAS.n”);

                break; // Sai do loop principal da UCP

            }

            tempo_global++; // Avança o tempo global

            // Adiciona uma pausa para que a simulação seja legível

            printf(“nPressione [ENTER] para o proximo ciclo de clock…”);

            getchar();

        }

        // —————————————————-

        // RELATÓRIO FINAL

        // —————————————————-

        printf(“nn=============== RELATORIO FINAL =================n”);

        printf(“Tempo total de execucao da UCP (ciclos de clock): %dn”, tempo_global);

        printf(“—————————————————n”);

        for (i = 0; i < num_instrucoes_na_fila; i++) {

            printf(“(%s) -> Tempo Total Gasto: %d ciclosn”,

                   fila_instrucoes[i].nome,

                   fila_instrucoes[i].tempo_total_execucao);

        }

        printf(“===================================================n”);

        return 0;

    }

    DIFICULDADES ENCONTRADAS: Para chegar no resultado final, foi necessário muito pensamento crítico e análise de conteúdos relacionados ao tema, com a organização do pipeline, a elaboração do código tornou-se um pouco mais complicada, além de exigir um tempo longo para chegar ao código final. Onde essa técnica auxilia no beneficiamento e rapidez de um processo/instrução dentro de um sistema computacional, permitindo que o mesmo possa agilizar atividades e entregar resultados em um tempo menor, promovendo otimização de tarefas que antes, sem o pipeline, seriam mais dificultosas e demoradas.

    Curtir

  13. Aluno: Kauê Oliveira Albuquerque

    Código: https://docs.google.com/document/d/1_4vGazhZNjrXXQzACGKmT-XTJJKAtftSMsFCgsLY4Ag/edit?usp=sharing

    A dificuldade esteve principalmente em compreender o funcionamento da execução simultânea das instruções dentro do pipeline. Visualizar como cada etapa se sobrepõe no tempo e como as instruções progridem de forma paralela exigiu uma atenção especial, já que o comportamento dinâmico do processo nem sempre é intuitivo. Além disso, o desenvolvimento da parte matemática envolvida, especialmente no cálculo do tempo total, na identificação dos ciclos ociosos e na análise do throughput, apresentou desafios adicionais, pois demandou interpretar com precisão as relações entre os estágios e o avanço cíclico do processamento.

    Curtir

  14. ALUNO: Kevin de Camargo CardosoRA:2809354#include <stdio.h>

    #include <string.h>

    #define MAX_INSTR 50

    #define MAX_ESTAGIOS 7

    #define TAM_NOME 32

    typedef struct {

    char nome[TAM_NOME];

    int stall;

    int inicio;

    int ciclo[MAX_ESTAGIOS];

    } Instrucao;

    int main() {

    Instrucao lista[MAX_INSTR];

    const char *estagios[MAX_ESTAGIOS] = {

    “Busca”,

    “Decodifica”,

    “Computa”,

    “Busca Op”,

    “Executa Int”,

    “Executa Out”,

    “Fim”

    };

    int N;

    int ch;

    int i, j;

    printf(“Quantas instrucoes voce quer simular? “);

    if (scanf(“%d”, &N) != 1 || N <= 0 || N > MAX_INSTR) {

    printf(“Valor invalido. Encerrando.n”);

    return 1;

    }

    while ((ch = getchar()) != ‘n’ && ch != EOF);

    for (i = 0; i < N; i++) {

    printf(“nDigite o nome da instrucao %d: “, i + 1);

    if (fgets(lista[i].nome, TAM_NOME, stdin) == NULL) {

    lista[i].nome[0] = ”;

    } else {

    lista[i].nome[strcspn(lista[i].nome, “n”)] = ”;

    }

    lista[i].stall = 0;

    printf(“Em qual ciclo essa instrucao deve comecar? “);

    if (scanf(“%d”, &lista[i].inicio) != 1 || lista[i].inicio < 1) {

    printf(“Valor invalido. Usando ciclo 1.n”);

    lista[i].inicio = 1;

    }

    while ((ch = getchar()) != ‘n’ && ch != EOF);

    }

    for (i = 0; i < N; i++) {

    printf(“nQuantos stalls a instrucao “%s” deve ter? “, lista[i].nome);

    if (scanf(“%d”, &lista[i].stall) != 1 || lista[i].stall < 0) {

    printf(“Valor invalido. Usando 0 stall.n”);

    lista[i].stall = 0;

    }

    while ((ch = getchar()) != ‘n’ && ch != EOF);

    }

    for (i = 0; i < N; i++) {

    int ciclo_atual = lista[i].inicio;

    for (j = 0; j < MAX_ESTAGIOS; j++) {

    lista[i].ciclo[j] = ciclo_atual;

    ciclo_atual++;

    }

    }

    printf(“nn==== TABELA DE EXECUCAO DO PIPELINE ====nn”);

    printf(“%-14s”, “Instrucao”);

    for (j = 0; j < MAX_ESTAGIOS; j++) {

    printf(“%-16s”, estagios[j]);

    }

    printf(“n”);

    for (i = 0; i < N; i++) {

    printf(“%-14s”, lista[i].nome);

    for (j = 0; j < MAX_ESTAGIOS; j++) {

    printf(“%-16d”, lista[i].ciclo[j]);

    }

    printf(“n”);

    }

    return 0;

    }

    DIFICULDADES: Durante a implementação do simulador de pipeline, a maior dificuldade foi organizar o avanço das instruções pelos estágios sem que elas se sobrepusessem ou saíssem da ordem. Também tive problemas com entradas do usuário e ajustes no código em C, principalmente por causa das regras mais rígidas do compilador. Conforme fui testando, percebi que pequenos erros de lógica podiam bagunçar toda a simulação, então precisei revisar bastante até tudo funcionar de forma clara. O estudo do pipeline ajudou a entender melhor como um processador consegue trabalhar com várias instruções ao mesmo tempo, mesmo que cada uma esteja em uma fase diferente. Isso aumenta a concorrência dentro do sistema e deixa tudo mais rápido e organizado. No fim, a prática deixou muito mais fácil enxergar como esse processo realmente acontece dentro da UCP.

    Curtir

  15. ALUNO: Kevin de Camargo CardosoRA:2809354#include <stdio.h>

    #include <string.h>

    #define MAX_INSTR 50

    #define MAX_ESTAGIOS 7

    #define TAM_NOME 32

    typedef struct {

    char nome[TAM_NOME];

    int stall;

    int inicio;

    int ciclo[MAX_ESTAGIOS];

    } Instrucao;

    int main() {

    Instrucao lista[MAX_INSTR];

    const char *estagios[MAX_ESTAGIOS] = {

    “Busca”,

    “Decodifica”,

    “Computa”,

    “Busca Op”,

    “Executa Int”,

    “Executa Out”,

    “Fim”

    };

    int N;

    int ch;

    int i, j;

    printf(“Quantas instrucoes voce quer simular? “);

    if (scanf(“%d”, &N) != 1 || N <= 0 || N > MAX_INSTR) {

    printf(“Valor invalido. Encerrando.n”);

    return 1;

    }

    while ((ch = getchar()) != ‘n’ && ch != EOF);

    for (i = 0; i < N; i++) {

    printf(“nDigite o nome da instrucao %d: “, i + 1);

    if (fgets(lista[i].nome, TAM_NOME, stdin) == NULL) {

    lista[i].nome[0] = ”;

    } else {

    lista[i].nome[strcspn(lista[i].nome, “n”)] = ”;

    }

    lista[i].stall = 0;

    printf(“Em qual ciclo essa instrucao deve comecar? “);

    if (scanf(“%d”, &lista[i].inicio) != 1 || lista[i].inicio < 1) {

    printf(“Valor invalido. Usando ciclo 1.n”);

    lista[i].inicio = 1;

    }

    while ((ch = getchar()) != ‘n’ && ch != EOF);

    }

    for (i = 0; i < N; i++) {

    printf(“nQuantos stalls a instrucao “%s” deve ter? “, lista[i].nome);

    if (scanf(“%d”, &lista[i].stall) != 1 || lista[i].stall < 0) {

    printf(“Valor invalido. Usando 0 stall.n”);

    lista[i].stall = 0;

    }

    while ((ch = getchar()) != ‘n’ && ch != EOF);

    }

    for (i = 0; i < N; i++) {

    int ciclo_atual = lista[i].inicio;

    for (j = 0; j < MAX_ESTAGIOS; j++) {

    lista[i].ciclo[j] = ciclo_atual;

    ciclo_atual++;

    }

    }

    printf(“nn==== TABELA DE EXECUCAO DO PIPELINE ====nn”);

    printf(“%-14s”, “Instrucao”);

    for (j = 0; j < MAX_ESTAGIOS; j++) {

    printf(“%-16s”, estagios[j]);

    }

    printf(“n”);

    for (i = 0; i < N; i++) {

    printf(“%-14s”, lista[i].nome);

    for (j = 0; j < MAX_ESTAGIOS; j++) {

    printf(“%-16d”, lista[i].ciclo[j]);

    }

    printf(“n”);

    }

    return 0;

    }

    DIFICULDADES: Durante a implementação do simulador de pipeline, a maior dificuldade foi organizar o avanço das instruções pelos estágios sem que elas se sobrepusessem ou saíssem da ordem. Também tive problemas com entradas do usuário e ajustes no código em C, principalmente por causa das regras mais rígidas do compilador. Conforme fui testando, percebi que pequenos erros de lógica podiam bagunçar toda a simulação, então precisei revisar bastante até tudo funcionar de forma clara. O estudo do pipeline ajudou a entender melhor como um processador consegue trabalhar com várias instruções ao mesmo tempo, mesmo que cada uma esteja em uma fase diferente. Isso aumenta a concorrência dentro do sistema e deixa tudo mais rápido e organizado. No fim, a prática deixou muito mais fácil enxergar como esse processo realmente acontece dentro da UCP.

    Curtir

  16. Aluno: João Pedro Diniz Nacur RA: a2819511

    _______________________________________________________________________________________#include <stdio.h>

    #include <stdlib.h>

    #include <locale.h>

    #include <string.h>

    #define ESTAGIOS 7

    #define INSTRUCAO 5

    typedef struct{

    int id;

    char status[20];

    } comandos;

    int main(){

    setlocale(LC_ALL, “Portuguese”);

    // 1 – criando vetores e variaveis

    comandos pipeline[ESTAGIOS];

    comandos fila[INSTRUCAO];

    char nomes_estagios[ESTAGIOS][30] = {

            “1 – Busca”, 

            “2 – Decodifica”, 

            “3 – Calc. Endereco”, 

            “4 – Busca Operando”, 

            “5 – Executa”, 

            “6 – Escreve”, 

            “7 – Finaliza”

        };

    int i, tempo = 0, instru_atual = 0, finalizados = 0, id_terminou;

    //esvaziar o pipeline

    for(i = 0; i < ESTAGIOS; i++){

    pipeline[i].id = 0; //zerando

    strcpy(pipeline[i].status, “Vazio”); //deixa como status de vazio

    }

    //definir status e criando comando

    for(i = 0; i < INSTRUCAO; i++){

    fila[i].id = i + 1;

    strcpy(fila[i].status, “Aguardando”); //todos estão no aguardo

    }

    printf(” Simulador Completo de Pipeline \n\n”);

    //quando concluido, ele finaliza todo o programa

    while(finalizados < INSTRUCAO){

      printf(“[TEMPO: %02d ]\n”, tempo);

    //retirando quem ja finalizou

    if(pipeline[ESTAGIOS – 1].id != 0) {

                id_terminou = pipeline[ESTAGIOS – 1].id;

                strcpy(fila[id_terminou – 1].status, “Concluída”); // Atualiza status

                finalizados++; // Conta como finalizada

            }

            //de trás para frente

    for(i = ESTAGIOS – 1; i > 0; i–) {

                pipeline[i] = pipeline[i – 1]; 

            }

            /*Verifique sua Fila de Instruções. Se houver instruções esperando, tire a primeira da

    fila e coloque no Estágio 1.*/

    if(instru_atual < INSTRUCAO){

    pipeline[0] = fila[instru_atual];

    strcpy(pipeline[0].status, “Processando”); // Muda status de Aguardando para Processando

                instru_atual++;

    } else

    {

    pipeline[0].id = 0; 

                strcpy(pipeline[0].status, “Vazio”);

    }

    //imprimir a interface

    for (i = 0; i < ESTAGIOS; i++) {

                if (pipeline[i].id == 0) {

                    printf(“%-25s : [ – ]\n”, nomes_estagios[i]); 

                } else {

                    printf(“%-25s : [ Instrução %d | %s ]\n”, nomes_estagios[i], pipeline[i].id, pipeline[i].status); 

                }

            }

            printf(“\n”);

        }

        printf(“Simulação concluida com sucesso em %d ciclos de tempo!\n”, tempo);  

    return 0;

    }Dificuldade: Eu estive em dúvida de como estruturar o algoritmo. Precisando revisar e criar um algoritmo primeiro no portugol e depois passar em C. Também aprendendo vendo vídeos e pesquisando como faz pipeline e fila em C.

    Curtir

  17. Aluna: Gabriela Godoy Pimenta
    RA: 2819503

    #include <stdio.h>

    #include <string.h>

    typedef struct {

        int id;              

        char tipo[50];        

        int ciclo_entrada;  

    } Instrucao;

    int main() {

        Instrucao pipeline[7];

        Instrucao fila[100];  

        int total_na_fila = 0;    

        int proxima_da_fila = 0;  

        int relogio = 0;          

        for (int i = 0; i < 7; i++) {

            pipeline[i].id = 0;

        }

        fila[0].id = 1;

        strcpy(fila[0].tipo, “SOMA”);

        total_na_fila++;

        fila[1].id = 2;

        strcpy(fila[1].tipo, “LEITURA”);

        total_na_fila++;

        fila[2].id = 3;

        strcpy(fila[2].tipo, “SUBTRACAO”);

        total_na_fila++;

        for (int ciclo = 1; ciclo <= 10; ciclo++) {

            relogio = ciclo;

            printf(“\n—-CICLO DE CLOCK: %d\n—-“, relogio);

            if (pipeline[6].id != 0) {

                int tempo_total = relogio – pipeline[6].ciclo_entrada;

                printf(“<- [CONCLUÍDA] Instrucao %d (%s) terminou! Levou %d ciclos.\n”,

                       pipeline[6].id, pipeline[6].tipo, tempo_total);

            }

            for (int i = 6; i >= 1; i–) {

                pipeline[i] = pipeline[i – 1];

            }

            pipeline[0].id = 0;

            if (proxima_da_fila < total_na_fila) {

                pipeline[0] = fila[proxima_da_fila];

                pipeline[0].ciclo_entrada = relogio;

                printf(“-> [ENTROU] Instrucao %d (%s) entrou na Etapa 1.\n”, pipeline[0].id, pipeline[0].tipo);

                proxima_da_fila++;

            }

            printf(“\nEstado das Etapas:\n”);

            for (int i = 0; i < 7; i++) {

                if (pipeline[i].id != 0) {

                    printf(”  Etapa %d: Instrucao %d (%s)\n”, i + 1, pipeline[i].id, pipeline[i].tipo);

                } else {

                    printf(”  Etapa %d: [VAZIO]\n”, i + 1);

                }

            }

        }

        return 0;

    }

    Curtir

  18. Aluno: Théo Lopes Mansano
    RA: 2779790

    Desafio Pipeline:  

    Instruções já determinadas:  

    • IF (Instruction Fetch / Busca): Pega a próxima instrução da fila. 
    • ID (Instruction Decode / Decodificação): Descobre qual é a operação. 
    • RF (Register Fetch / Leitura de Registradores): Busca os valores dos registradores necessários. 
    • EX (Execute / Execução): Realiza o cálculo. 
    • MEM (Memory Access / Acesso à Memória): Se for uma instrução de leitura/escrita na memória. 
    • WB (Write Back / Escrita): Grava o resultado de volta no registrador de destino. 
    • UP (Update / Atualização): Atualiza o Contador de Programa e os status do sistema. 

    Usei o Online GDB para fazer o codigo. 

    #include <stdio.h> 

    #include <string.h> 

    #define TAM 5 

    #define ETAPAS 7 

    // Estrutura da instrução 

    typedef struct { 

        char nome[20]; 

        int tempo; 

    } Instrucao; 

    int main() { 

        // Fila de instruções 

        Instrucao fila[TAM] = { 

            {“ADD”, 0}, 

            {“SUB”, 0}, 

            {“MUL”, 0}, 

            {“DIV”, 0}, 

            {“LOAD”, 0} 

        }; 

        // Pipeline com 7 etapas 

        char pipeline[ETAPAS][20] = { 

            “Busca”, 

            “Decodifica”, 

            “Leitura”, 

            “Execucao”, 

            “Memoria”, 

            “Escrita”, 

            “Final” 

        }; 

        printf(“=== SIMULADOR DE PIPELINE ===\n\n”); 

        // Simulação da UCP 

        for(int i = 0; i < TAM; i++) { 

            printf(“Instrucao: %s\n”, fila[i].nome); 

            // Passa pelas 7 etapas 

            for(int j = 0; j < ETAPAS; j++) { 

                fila[i].tempo++; 

                printf(“Etapa %d: %s | Tempo: %d\n”, 

                       j + 1, 

                       pipeline[j], 

                       fila[i].tempo); 

            } 

            printf(“————————–\n”); 

        } 

        return 0; 

    Quais foram as dificuldades? 
     

    • Complexidade crescente: pipelines podem virar monstros se não forem bem planejadas. 
    • Acoplamento excessivo: uma mudança em uma etapa quebra todas as outras. 
    • Falta de observabilidade: sem logs, fica impossível entender o que deu errado. 
    • Custos escondidos: pipelines mal otimizadas podem consumir recursos demais e aumentar o custo de infraestrutura. 
    • Manutenção difícil: pipelines sem documentação ou dependentes de pessoas específicas se tornam gargalos. 

     
    Vantagens:  

    1. Redução de erros humanos: tarefas manuais são propensas a falhas. Automatizando, você evita esquecimentos, erros de digitação ou configuração. 
    1. Eficiência operacional: tarefas que demorariam horas passam a levar segundos ou minutos. 
    1. Padronização de processos: todo o time executa o mesmo fluxo, com as mesmas regras. 
    1. Escalabilidade: pipelines bem feitas conseguem lidar com volumes cada vez maiores de dados e demandas. 
    1. Transparência e rastreabilidade: logs e dashboards permitem acompanhar todo o processo e identificar onde está o problema caso algo dê errado. 

    Integração entre sistemas: pipelines conectam ferramentas diferentes, como banco de dados, APIs, ambientes de nuvem, containers e plataformas de BI.

    Curtir

  19. Aluno: Gabriel Vinícius Henrique
    RA: 2819490

    Relato: A principal dificuldade encontrada foi compreender como deveria ser implementado a matriz e manipulá-la.

    Código em C:

    #include <stdio.h>

    #include <stdlib.h>

    // Struct das instruções

    struct instruction {

        char nome;

        int estagio;

    } typedef instruction;

    int create_instruction(instruction *fila, int n) {

        int i;

        for (i = 0; i < n; i++) {

            fila[i].nome = ‘A’ + i;

            fila[i].estagio = 0;

        }

        return 0;

    }

    int show_instruction(instruction *fila, int n) {

        int i;

        for (i = 0; i < n; i++) {

            printf(“%c:%d “, fila[i].nome, fila[i].estagio);

        }

        printf(“\n”);

        return 0;

    }

    int main() {

        int n;

        printf(“Quantas intrucoes deseja criar: “); // Pergunta quantas instruções o usuário deseja criar

        do {

            scanf(“%d”, &n);

        } while(n < 1 || n > 26);

        instruction *fila = (instruction *) malloc(n * sizeof(instruction)); // Aloca a fila de instrucoes

        int i, j;

        create_instruction(fila, n); // Cria as instrucoes e define o estagio como 0

        show_instruction(fila, n); // Mostra a fila de instrucoes

        for (i = 0; i < n * n; i++) {

            for (j = 0; j <= i; j++) {

                if (fila[j].estagio >= 7) {

                    fila[j].estagio = 7; // Se o estagio for maior que 7, define como 7

                } else {

                    fila[j].estagio++; // Incrementa o estagio da instrucao

                }

            }

            show_instruction(fila, n); // Mostra a fila de instrucoes

            printf(“\n”);

        }

        free(fila);

        return 0;

    }

    Curtir

  20. Nome: Kauan Reis de Lima
    RA: 2819538

    1 – Desafio de programação da disciplina de Organização de Computadores: 

    Implementar na forma de simulação o funcionamento do pipeline em um sistema computacional. Exemplos: Fig. 1 e Fig.2. 

    Deverá conter UCP; fila com “n instruções”; possibilidade de criação de novas instruções; divisão de um pipeline em 7 tarefas diferentes; contador de tempo das instruções.

    Código em C:

    #include <stdio.h>

    #include <string.h>

    #define NUM_ESTAGIOS 7

    #define MAX_INSTRUCOES 20

    int main() {

        char pipeline[NUM_ESTAGIOS][4] = {“–“, “–“, “–“, “–“, “–“, “–“, “–“};

        char nomes_estagios[NUM_ESTAGIOS][4] = {“BI”, “DI”, “CO”, “BO”, “EI”, “EO”, “GR”};

        char fila_instrucoes[MAX_INSTRUCOES][4];

        int fila_inicio = 0; // Aponta para a primeira instrução da fila

        int fila_fim = 0;    // Aponta para a posição onde a próxima instrução será inserida

        for (int i = 1; i <= 5; i++) {

            sprintf(fila_instrucoes[fila_fim], “I%d”, i);

            fila_fim++;

        }

        int relogio = 1; // Contador de tempo (ciclos)

        int instrucoes_concluidas = 0;

        int total_esperado = 6; // 5 iniciais + 1 que criaremos no meio do caminho

        printf(“SIMULADOR DE PIPELINE EM C (MATRIZ)\n\n”);

        // Imprimindo o cabeçalho da matriz

        printf(“Tempo | “);

        for (int i = 0; i < NUM_ESTAGIOS; i++) {

            printf(“[%s] “, nomes_estagios[i]);

        }

        printf(“\n—————————————————-\n”);

        // O loop roda até que a última instrução saia do último estágio

        while (instrucoes_concluidas < total_esperado) {

            // 3. Possibilidade de criação de novas instruções

            if (relogio == 3) {

                strcpy(fila_instrucoes[fila_fim], “I6”);

                fila_fim++;

            }

            // LOGICA DO PIPELINE

            // Passo A: Verifica se a instrução no último estágio (índice 6) vai ser concluída

            if (strcmp(pipeline[NUM_ESTAGIOS – 1], “–“) != 0) {

                instrucoes_concluidas++;

            }

            // Passo B: Move as instruções um estágio para frente (de trás para frente)

            for (int i = NUM_ESTAGIOS – 1; i > 0; i–) {

                strcpy(pipeline[i], pipeline[i – 1]);

            }

            // Passo C: O primeiro estágio recebe da fila, se houver

            if (fila_inicio < fila_fim) { 

                // Copia a instrução do início da fila para o estágio 0

                strcpy(pipeline[0], fila_instrucoes[fila_inicio]);

                fila_inicio++; // Avança a fila

            } else {

                // Se a fila esvaziou, insere uma bolha

                strcpy(pipeline[0], “–“); 

            }

            // O “%-2d” alinha o número à esquerda, e o “%2s” alinha a string

            printf(” T=%-2d | “, relogio);

            for (int i = 0; i < NUM_ESTAGIOS; i++) {

                printf(“[%2s] “, pipeline[i]);

            }

            printf(“\n”);

            relogio++; // Avança o clock

        }

        printf(“\nSimulacao concluida em %d ciclos de clock.\n”, relogio – 1);

        return 0;

    }

    Após a implementação, faça um relato sobre: às dificuldades encontradas; como o a técnica de pipeline auxilia na concorrência de um sistema computacional.

    Dificuldade: A principal dificuldade na implementação do simulador foi conciliar a natureza sequencial da linguagem de programação com o comportamento paralelo do hardware físico. Para que as instruções não fossem sobrescritas antes da hora, foi necessário aplicar uma lógica de movimentação reversa, atualizando os estágios do pipeline de trás para frente. Além disso, houve o desafio de gerenciar as chamadas “bolhas”, criando uma lógica para inserir espaços vazios e manter o relógio do sistema rodando até que a última instrução saísse do processador.

    Pipeline: A técnica de pipeline auxilia na concorrência de um sistema computacional ao permitir que múltiplas instruções sejam executadas simultaneamente, sobrepondo as diferentes fases do seu processamento. Em vez de o processador concluir uma instrução inteira para depois começar a próxima, ele funciona como uma linha de montagem: assim que o primeiro estágio (como a “busca” da instrução) termina e repassa a tarefa, ele já fica livre para processar a instrução seguinte. Isso maximiza o uso do hardware, já que quase todas as partes do processador trabalham ativamente a cada ciclo de clock, evitando ociosidade. Consequentemente, embora a técnica não torne uma instrução individualmente mais rápida, ela aumenta de forma expressiva a vazão (throughput) do sistema, sendo capaz de entregar, em cenários ideais, uma instrução concluída a cada ciclo.

    Curtir

  21. Nome: Aires Silvestre Cambumba

    RA: 2898217

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #ifdef _WIN32

        #include <windows.h> // Para rodar o Sleep no Windows

    #else

        #include <unistd.h>  // Para rodar o usleep no Linux/macOS

    #endif

    // Função para simular o pulso de clock (pausa de meio segundo)

    void pulso_clock() {

        #ifdef _WIN32

            Sleep(600);

        #else

            usleep(600000);

        #endif

    }

    int main() {

        int num_instru;

        int i, j, ciclo;

        printf(“Digite a quantidade de instrucoes: “);

        scanf(“%d”, &num_instru);

        // Criação dos nomes das instruções (Requisito do desafio)

        // Uma matriz de strings para dar nome a cada instrução criada

        char nome_instrucoes[num_instru][30];

        for(i = 0; i < num_instru; i++) {

            sprintf(nome_instrucoes[i], “Instrucao_%d”, i + 1);

        }

        // O total de ciclos necessário é: 6 (tarefas restantes) + número de instruções

        int total_ciclos = 6 + num_instru;

        // Cria e limpa a matriz com zeros (Sua lógica original)

        int mat[num_instru][total_ciclos];

        for(i = 0; i < num_instru; i++) {

            for(j = 0; j < total_ciclos; j++) {

                mat[i][j] = 0;

            }

        }

        // Preenche a matriz deslocando as 7 tarefas (Sua lógica perfeita!)

        for(i = 0; i < num_instru; i++) {

            for(j = 0; j < 7; j++) {

                mat[i][j + i] = j + 1;

            }

        }

        // Nomes das 7 tarefas para exibir no painel

        char *tarefas[] = {

            “Vazio”,

            “Buscar”,

            “Codificar”,

            “Calcular”,

            “Executar”,

            “Armazenar”,

            “Apresentar”,

            “Encerrar”

        };

        printf(“\n— INICIANDO SIMULACAO DA UCP (PIPELINE) —\n”);

        pulso_clock();

        // SIMULAÇÃO DINÂMICA: Transforma as COLUNAS da matriz em TEMPO REAL

        for(ciclo = 0; ciclo < total_ciclos; ciclo++) {

            printf(“\n=========================================\n”);

            printf(”  CICLO DE CLOCK CONTADOR: %d \n”, ciclo + 1);

            printf(“\n=========================================\n”);

            // Varre cada instrução para saber o que ela faz NESTE ciclo

            for(i = 0; i < num_instru; i++) {

                int ID_tarefa = mat[i][ciclo];

                if(ID_tarefa == 0) {

                    // Se o ciclo atual ainda não chegou na vez da instrução

                    if(ciclo < i) {

                        printf(”  %s -> [ AGUARDANDO NA FILA ]\n”, nome_instrucoes[i]);

                    } else {

                        printf(”  %s -> [ CONCLUIDA COM SUCESSO ]\n”, nome_instrucoes[i]);

                    }

                } else {

                    // Exibe a tarefa correspondente ao número (1 a 7)

                    printf(”  %s -> [ Tarefa %d: %s ]\n”,

                           nome_instrucoes[i], ID_tarefa, tarefas[ID_tarefa]);

                }

            }

            pulso_clock(); // Aguarda o próximo ciclo de clock

        }

        printf(“\n================ RELATORIO FINAL ================\n”);

        printf(” O pipeline terminou com Sucesso!\n”);

        printf(” Tempo total de execucao: %d ciclos de clock.\n”, total_ciclos);

        printf(“=================================================\n”);

        return 0;

    }

    1. Dificuldades Encontradas na Implementação (Sugestões comuns)

    • Sincronismo do Deslocamento: Uma das principais dificuldades lógicas é mover as instruções pelos estágios. Se movermos do início para o fim (da Task 1 para a 7), uma instrução pode “atropelar” a outra no mesmo ciclo de código. A solução é atualizar o pipeline de trás para frente (da Task 7 para a 1).
    • Abstração do Tempo: Representar o “tempo” em hardware exige pensar em ciclos discretos (clocks), o que em software precisa ser simulado através de laços de repetição (while/for) bem estruturados.
    • Tratamento de Bolhas/Conflitos (Hazards): Embora simplificado nesta simulação, na vida real, se uma tarefa demorar mais que a outra, o pipeline trava (gera uma “bolha”), algo complexo de prever em lógica de programação pura.

    2. Como a técnica de Pipeline auxilia na concorrência?

    O pipeline funciona de forma análoga a uma linha de montagem industrial.

    Paralelismo a Nível de Instrução (ILP): Em vez de esperar que uma instrução passe por todas as 7 tarefas para só então iniciar a próxima, o pipeline permite que, assim que a Instrução 1 libera a Tarefa 1 e passa para a Tarefa 2, a Instrução 2 já possa entrar na Tarefa

    Maximização do Hardware: Ele garante que diferentes partes da UCP (unidade de busca, decodificação, execução, escrita em memória, etc.) trabalhem de forma concorrente e simultânea, evitando que blocos de silício fiquem ociosos.

    Rendimento (Throughput): O pipeline não diminui o tempo que uma instrução leva para ser executada individualmente (latência), mas aumenta drasticamente a quantidade de instruções concluídas por unidade de tempo. Em um estado ideal (pipeline cheio), o sistema entrega a conclusão de uma instrução por ciclo de clock, independentemente de ela ter 7 estágios.

    Curtir

  22. #include<stdio.h>

    #include<stdlib.h>

    #include<locale.h>

    struct instrucao{

        int numero_instrucao, entrada, saida;

    };

    typedef struct instrucao instrucao;

    instrucao fila[20];

    struct estagio{

        int ocupado;

        struct instrucao dado; // Guarda os dados da instrução

    };

    typedef struct estagio estagio;

    estagio pipeline[7];

    int main(){

        setlocale(LC_ALL, “Portuguese”);

        int i, inicio = 0, fim = 0, ciclo = 0, proxima_instrucao = 1, tempo_gasto;

        for(i=0; i<7; i++){

            pipeline[i].ocupado = 0;

            pipeline[i].dado.numero_instrucao = 0; // nenhuma instrução nesse estágio ainda

        }

        for(i=0; i<7; i++){

            fila[fim].numero_instrucao = proxima_instrucao;

            fila[fim].entrada = 0; // a instrução ainda não foi iniciada

            fila[fim].saida = 0;

            fim++; //final da fila vai para a proxima posição livre

            proxima_instrucao++;

        }

        while(inicio < fim || pipeline[6].ocupado){

            ciclo++;

            printf(“\nClock: %d\n”, ciclo);

            if(pipeline[6].ocupado){

                pipeline[6].dado.saida = ciclo; // qual instrução que terminou o pipeline

                printf(“\nInstrução %d concluída”, pipeline[6].dado.numero_instrucao);

                tempo_gasto = pipeline[6].dado.saida – pipeline[6].dado.entrada;

                printf(“\nTempo gasto: %d\n”, tempo_gasto);

            }

            for(i=6; i>=1; i–){ //mover as intruções de um estágio para frente quando concluido algum estágio

                pipeline[i] = pipeline[i-1];

            }

             if(inicio < fim){ //entrada de novas instruções

                pipeline[0].ocupado = 1; // 0 – ocupado e 1 – Livre

                pipeline[0].dado = fila[inicio];

                pipeline[0].dado.entrada = ciclo;

                inicio++;

            }else{ // se todas as instruções tiverem sido concluidas

                pipeline[0].ocupado = 0;

                pipeline[0].dado.numero_instrucao = 0;

            }

            if(ciclo == 4){

                for(i=0; i<2; i++){

                    fila[fim].numero_instrucao = proxima_instrucao;

                    fila[fim].entrada = 0;

                    fila[fim].saida = 0;

                    fim++;

                    proxima_instrucao++;

                }

            }

            for(i=0; i<7; i++){ //apresentação da tecnica de pipeline

                printf(“\nEstágio: %d”, i+1);

                if(pipeline[i].ocupado){

                   printf(“\nInstrução: %d”, pipeline[i].dado.numero_instrucao);

                }else{

                    printf(“\nVazio”);

                }

            }

           printf(“\n”);

           fflush(stdout);

        }

        printf(“\nSimulação encerrada.”);

        return 0;

    }

    • Dificuldades encontradas: A dificuldade lógica em organizar e controlar as sobreposições dos estágios, bem como sua iniciação no momento correto. Além disso, verificar se a posição estava ocupada ou não, foi bem desafiador, exigindo ajustes constantes, visando a lógica coerente e visualização clara.
    • Técnica de Pipeline: A técnica de pipeline ajuda na redução do tempo do ciclo de instrução geral, uma vez que não necessita a finalização individual de cada uma delas, sobrepondo-as, a fim de utilizar o tempo de maneira mais eficiente e veloz. Isso aplicado em largas escalas, computadores que exigem uma demanda mais eficaz, aumenta significamente o desempenho do hardware.

    Curtir

  23. Atividade 9

    Aluno: Magno Elano Pereira de Oliveira

    #include <stdio.h>

    #include <string.h>

    #define MAX_INSTRUCOES 20

    #define ESTAGIOS 7

    // Estrutura da instrução

    typedef struct {

    char nome[30];

    int concluida;

    } Instrucao;

    int main() {

    Instrucao fila[MAX_INSTRUCOES];

    // Pipeline com 7 estágios

    char pipeline[ESTAGIOS][30] = {

    “Vazio”,”Vazio”,”Vazio”,

    “Vazio”,”Vazio”,”Vazio”,

    “Vazio”

    };

    int qtd, clock = 0;

    int inseridas = 0;

    int concluidas = 0;

    printf(“====================================\n”);

    printf(“SIMULADOR DE PIPELINE – UCP\n”);

    printf(“====================================\n”);

    printf(“Quantidade inicial de instrucoes: “);

    scanf(“%d”, &qtd);

    if(qtd > MAX_INSTRUCOES)

    qtd = MAX_INSTRUCOES;

    // Cadastro das instruções

    for(int i = 0; i < qtd; i++) {

    printf(“Nome da instrucao %d: “, i + 1);

    scanf(“%s”, fila[i].nome);

    fila[i].concluida = 0;

    }

    inseridas = qtd;

    // Simulação do pipeline

    while(concluidas < qtd) {

    clock++;

    printf(“\n====================================\n”);

    printf(“CLOCK %d\n”, clock);

    printf(“====================================\n”);

    // Verifica se a instrução terminou

    if(strcmp(pipeline[6], “Vazio”) != 0) {

    printf(“Instrucao %s concluida!\n”, pipeline[6]);

    concluidas++;

    }

    // Move as instruções para o próximo estágio

    for(int i = ESTAGIOS – 1; i > 0; i–) {

    strcpy(pipeline[i], pipeline[i – 1]);

    }

    // Insere nova instrução

    if(inseridas > 0) {

    strcpy(pipeline[0],

    fila[qtd – inseridas].nome);

    inseridas–;

    } else {

    strcpy(pipeline[0], “Vazio”);

    }

    // Exibe estado atual do pipeline

    printf(“\nEstado do Pipeline:\n”);

    printf(“BI (Busca Instr.): %s\n”, pipeline[0]);

    printf(“DI (Decodificacao): %s\n”, pipeline[1]);

    printf(“CO (Calculo Oper.): %s\n”, pipeline[2]);

    printf(“BO (Busca Operando): %s\n”, pipeline[3]);

    printf(“EI (Execucao): %s\n”, pipeline[4]);

    printf(“EO (Escrita Resultado): %s\n”, pipeline[5]);

    printf(“FIM: %s\n”, pipeline[6]);

    }

    printf(“\n====================================\n”);

    printf(“PROCESSAMENTO CONCLUIDO!\n”);

    printf(“Total de clocks: %d\n”, clock);

    printf(“====================================\n”);

    return 0;

    } Relatório – Simulação de Pipeline Objetivo

    O objetivo desta atividade foi desenvolver uma simulação do funcionamento de uma Unidade Central de Processamento (UCP) utilizando a técnica de pipeline. O programa foi implementado em linguagem C e permite a execução simultânea de várias instruções em diferentes estágios de processamento. Funcionamento do Programa

    O sistema recebe uma fila contendo diversas instruções e as distribui em um pipeline composto por sete estágios:

    1. BI – Busca da Instrução;
    2. DI – Decodificação da Instrução;
    3. CO – Cálculo da Operação;
    4. BO – Busca do Operando;
    5. EI – Execução da Instrução;
    6. EO – Escrita do Resultado;
    7. FIM – Finalização.

    A cada ciclo de clock, todas as instruções avançam uma posição dentro do pipeline até que completem seu processamento. Dificuldades Encontradas

    Durante o desenvolvimento da atividade, as principais dificuldades foram:

    • Controlar corretamente a movimentação das instruções entre os estágios;
    • Garantir que nenhuma instrução fosse perdida durante a execução;
    • Implementar a contagem dos ciclos de clock;
    • Simular o paralelismo existente em um pipeline real.

    Como o Pipeline Auxilia na Concorrência

    A técnica de pipeline aumenta a eficiência do processador ao permitir que várias instruções sejam executadas simultaneamente em diferentes estágios. Enquanto uma instrução está sendo executada, outra pode estar sendo decodificada e uma terceira sendo buscada na memória.

    Dessa forma, há melhor aproveitamento dos recursos da UCP e aumento da quantidade de instruções processadas por unidade de tempo, melhorando o desempenho geral do sistema computacional. Conclusão

    A implementação da simulação permitiu compreender de forma prática o funcionamento do pipeline em processadores. Foi possível observar como a divisão das tarefas em estágios contribui para a execução concorrente das instruções e para o aumento da eficiência do sistema. A atividade demonstrou a importância dessa técnica na arquitetura dos computadores modernos.

    Curtir

  24. 1 – Conceitue e exemplifique Pipeline Pipeline é uma técnica de hardware que permite que a CPU realize a busca de uma ou mais instruções além da próxima a ser executada, processando múltiplas instruções simultaneamente em diferentes estágios. Exemplo: Imagine uma linha de produção de bifes com 3 etapas (cortar, cozinhar, embrulhar). No pipeline, quando a etapa 1 termina o primeiro bife e passa para a etapa 2, a etapa 1 já começa o segundo bife. Assim, vários bifes são feitos ao mesmo tempo sem esperar um terminar completamente. Em 5 ciclos de clock, 5 instruções são iniciadas (mesmo que cada uma demore mais de 1 ciclo para finalizar).

    2 – Em qual arquitetura a técnica de Pipeline é mais fácil de ser implementada? O pipeline é mais fácil e eficiente de ser implementado na arquitetura RISC (Reduced Instruction Set Computer). Isso ocorre porque as instruções RISC são simples, têm tamanho fixo e levam aproximadamente o mesmo tempo para serem executadas, facilitando a divisão em estágios uniformes.

    3 – O que é microcódigo ou microprogramação? Em qual arquitetura esta característica está mais presente? Microcódigo é uma camada intermediária entre o hardware da CPU e a arquitetura do conjunto de instruções visível ao programador. Consiste em um conjunto de instruções ao nível do hardware que implementam as instruções de código de máquina de nível superior. Microprogramação é o ato de escrever microcódigo — programar estrategicamente a unidade de controle do processador a nível de operações. Esta característica está mais presente na arquitetura CISC (Complex Instruction Set Computer), que utiliza microprogramação para executar instruções complexas.

    4 – Conceitue Arquitetura RISC e CISC. Cite as diferenças das duas arquiteturas. RISC significa Reduced Instruction Set Computer. CISC significa Complex Instruction Set Computer. Principais diferenças: Conjunto de instruções: RISC tem conjunto reduzido e simples; CISC tem conjunto amplo e complexo Tempo de execução: RISC executa 1 ciclo de clock por instrução; CISC executa vários ciclos de clock Microcódigo: RISC não possui (execução direta no hardware); CISC possui microprogramação Registradores: RISC tem muitos registradores (mais de 500); CISC tem menos registradores Consumo de energia: RISC tem baixo consumo (eficiente energeticamente); CISC tem alto consumo Complexidade do hardware: RISC tem baixa complexidade; CISC tem alta complexidade Exemplos: RISC inclui ARM, MIPS, SPARC, RISC-V; CISC inclui x86 (Intel, AMD) Uso típico: RISC é usado em dispositivos móveis e embarcados; CISC é usado em desktops, notebooks e servidores.

    5 – Em que fases estão distribuídas as execuções dentro de um processador RISC? Um processador RISC com pipeline possui 5 estágios/fases: 1. IF (Instruction Fetch) – Busca da instrução na memória 2. ID (Instruction Decode) – Decodificação da instrução 3. EX (Execute) – Execução na ULA (Unidade Lógico-Aritmética) 4. MEM (Memory Access) – Acesso à memória de dados 5. WB (Write Back) – Escrita nos registradores Em máquinas RISC, estas fases são executadas em paralelo — uma fase não precisa esperar a outra terminar para iniciar.

    6 – Cite um Sistema Operacional que faz uso de um processador RISC? RISC OS — sistema operacional originalmente desenvolvido pela Acorn Computers Ltd, projetado especificamente para rodar no chipset ARM (arquitetura RISC). Linux também roda em processadores RISC — existem distribuições Linux para ARM (Debian, Ubuntu, Fedora, Manjaro) e o primeiro SoC RISC-V compatível com Linux foi lançado pela SiFive.

    7 – O que é um processador Híbrido? Cite um modelo de um processador híbrido. Um processador híbrido combina diferentes tipos de núcleos ou arquiteturas em um único chip para otimizar desempenho e eficiência energética — geralmente núcleos “fortes” (performance) e núcleos “fracos” (eficiência). Modelo exemplo: Intel Pentium Pro — internamente é um processador RISC (mais rápido), mas externamente se comporta como CISC para compatibilidade com software x86. Outro exemplo moderno: Intel Core com arquitetura big.LITTLE (núcleos Performance + Efficiency) ou AMD APU Ryzen.

    8 – Como resolver os problemas dos gargalos na técnica de pipeline? Os gargalos (hazards) no pipeline são resolvidos com as seguintes técnicas: Data Hazard (dependência de dados): Forwarding: encaminha resultado diretamente entre estágios, evitando espera Stalling: inserir “bolha” (ciclo NOP) para aguardar dado disponível Reordering: compilador reorganiza instruções para evitar dependência direta Control Hazard (desvios/Branches): Branch Prediction: CPU prevê se desvio será tomado (baseado em histórico) Delay Slot: compilador insere instrução útil após o desvio que sempre será executada Stalling: adiar instruções até saber o desvio Structural Hazard (conflito de recursos): Duplicação de unidades: duas memórias separadas (uma para instruções, outra para dados) — Arquitetura Harvard Aumentar estágios do pipeline para maior paralelismo Solução geral: Quebrar instruções em vários passos, onde cada passo consome 1 ciclo de clock.

    Curtir

  25. #include <stdio.h>

    #include <string.h>

    #include <locale.h>

    #define maxinstrucoes 50

    #define numestagios 7

    int main()

    {

        //Nomes dos estágios do pipeline

        char estagios[numestagios][100] = {

            “fi (busca)”, “di (decodificacao)”, “co (calc operandos)”,

            “fo (busca operandos)”, “ei (execucao)”, “wo (escrita)”, “ch (verificacao)”

        };

        setlocale (LC_ALL, “Portuguese”);

        //Variáveis da fila de espera

        char fila[maxinstrucoes][100];

        int totalfila = 0, iniciofila = 0, fimfila = 0;

        //Variáveis do pipeline

        char pipelinenomes[numestagios][100];

        int pipelinetempo[numestagios], pipelineocupado[numestagios], i;

        //Inicializando o pipeline

        for (i = 0; i < numestagios; i++) {

            pipelineocupado[i] = 0;

            pipelinetempo[i] = 0;

        }

        //3 instruções como exemplo, para não precisar digitar

        strcpy(fila[fimfila], “add r1, r2”); fimfila++;

        totalfila++;

        strcpy(fila[fimfila], “sub r3, r4”); fimfila++;

        totalfila++;

        strcpy(fila[fimfila], “load r5, 100”); fimfila++;

        totalfila++;

        int clock = 0, opcao = 0;

        char novonome[100];

        //Menu para o simulador

        while (opcao != 3) {

            printf(“\n—Menu do simulador—\n”);

            printf(“1- Avançar 1 ciclo de clock\n”);

            printf(“2- Adicionar instrução\n”);

            printf(“3- Sair\n”);

            printf(“Escolha uma opção:\n “);

            scanf(“%d”, &opcao);

            if (opcao == 2)

                {

                //Adicionar uma nova instrução na fila

                if (totalfila < maxinstrucoes)

                {

                    printf(“digite o comando (ex: mov, , mul, div, and): “);

                    scanf(“%s”, novonome);

                    strcpy(fila[fimfila], novonome);

                    fimfila = (fimfila + 1) % maxinstrucoes;

                    totalfila++;

                    printf(“Instrução adicionada na fila!\n”);

                }

                else

                {

                    printf(“Erro: A fila está cheia!\n”);

                }

            }

            else if (opcao == 1)

                {

                clock++; // avançar o tempo

                // Para aumentar o tempo das instruções que já estão dentro do pipeline

                for (i = 0; i < numestagios; i++)

                {

                    if (pipelineocupado[i] == 1) //Se estiver ocupado o programa soma +1 no tempo de vida da instrução em específico

                    {

                        pipelinetempo[i]++;

                    }

                }

                if (pipelineocupado[6] == 1) //Se houver alguém no último estágio, significa que ele terminou

                    {

                    printf(“\n[!] ‘%s’ Terminou! ciclos totais: %d\n”, pipelinenomes[6], pipelinetempo[6]);

                    pipelineocupado[6] = 0;

                }

                for (i = 5; i >= 0; i–)  //Move as instruções para o próximo estágio (de trás para frente para garantir que a posição da frente seja esvaziada)

                {

                    if (pipelineocupado[i] == 1 && pipelineocupado[i+1] == 0)

                        {

                        strcpy(pipelinenomes[i+1], pipelinenomes[i]);

                        pipelinetempo[i+1] = pipelinetempo[i];

                        pipelineocupado[i+1] = 1;

                        pipelineocupado[i] = 0;

                    }

                }

                if (pipelineocupado[0] == 0 && totalfila > 0) //Se o primeiro estágio estiver vazio, puxa a próxima instrução da fila

                    {

                    strcpy(pipelinenomes[0], fila[iniciofila]);

                    pipelinetempo[0] = 1;

                    pipelineocupado[0] = 1;

                    iniciofila = (iniciofila + 1)%maxinstrucoes;

                    totalfila–;

                }

                printf(“\nTempo: %d\n”, clock);

                for (i = 0; i < numestagios; i++)

                    {

                    printf(“[%s]: “, estagios[i]);

                    if (pipelineocupado[i] == 1)

                    {

                        printf(“%s (Tempo: %d)”, pipelinenomes[i], pipelinetempo[i]);

                    } else

                    {

                        printf(“Vazio”);

                    }

                    printf(“\n”);

                }

            }

        }

        printf(“Fim\n”);

        return 0;

    }

    Dificuldades encontradas: A maior dificuldade foi em como simular um hardware (físico) que opera simultaneamente utilizando algoritmos (computacional) que rodam de maneira sequencial/linear e em programar todo esse processo. Além disso, a lógica do pipeline é diferente quando escrita em linguagem C, o que torna a programação ainda mais complicada e confusa.

    A técnica de pipeline ajuda na concorrência porque ao invés de o computador esperar uma instrução passar por todas as etapas para depois começar a próxima, ele deixa várias instruções entrarem na fila ao mesmo tempo, cada uma em uma fase diferente, o que faz o resultado final aparecer muito antes. Depois que a fila fica cheia, o processador consegue terminar uma instrução a cada ciclo (clock). Isso melhora o uso do sistema porque nenhuma parte do chip fica parada esperando a outra terminar, fazendo o computador poder realizar mais tarefas ao mesmo tempo com o máximo de eficiência.

    Curtir

    1. Aluno: Pedro Henrique Magalhães dos Santos
    2. RA: 2866536

    _______________________________________________________________________________________

    1 – Desafio de programação da disciplina de Organização de Computadores: 

    Código:

    #include <stdio.h>

    #include <string.h>

    #include <locale.h>

    #define MAX_INSTRUCOES 100

    #define TAREFAS 7

    int pipeline[TAREFAS], clock=0, proxima=0;

    // instrucao struct

    struct instrucao{

        int id;

        char nome[10];

        int estagio_atual;

    };

    typedef struct instrucao instrucao;

    instrucao fila_espera[MAX_INSTRUCOES];

    int total_instrucoes = 0;

    // funcao para adicionar instrucoes

    void adicionar_instrucao(int id, char nome[]){

        fila_espera[total_instrucoes].id = id;

        strcpy(fila_espera[total_instrucoes].nome, nome);

        fila_espera[total_instrucoes].estagio_atual = 0;

        total_instrucoes++;

    }

    // funcao para setar -1 vazio em todo o pipeline

    void iniciar_pipeline(){

        int i;

        for(i=0; i<TAREFAS; i++){

            pipeline[i] = -1;

        }

    }

    // funcao para printar o pipeline

    void print_pipeline(){

        int i;

        printf(“\n\n”);

        for(i=0; i<TAREFAS; i++){

            printf(“T%d: %d | “, i+1, pipeline[i]);

        }

    }

    // funcao que faz o sistema dos ciclos de pipeline

    void ciclo_clock(){

        int i;

        // refaz o pipeline de traz pra frente

        for(i = TAREFAS – 1; i > 0; i–){

            pipeline[i] = pipeline[i – 1];

        }

        // traz a nova instrucao pra casa 0 do pipeline

        if(proxima < total_instrucoes){

            pipeline[0] = fila_espera[proxima].id;

            proxima++;

        } else {

            pipeline[0] = -1;

        }

        clock++;

    }

    // funcao que ve se o pipeline esta vazio, ou seja acabou tudo

    int pipeline_vazio() {

        int i;

        for(i = 0; i < TAREFAS; i++) {

            if(pipeline[i] != -1) {

                return 0;

            }

        }

        return 1;

    }

    int main(){

        setlocale(LC_ALL, “Portuguese”);

        int i, novo_id, opc;

        char novo_nome[10];

        // inicia o pipeline declarando todos os campos como vazio

        iniciar_pipeline();

        do{

            // menu inicial

            printf(“\n\n—MENU—“);

            printf(“\n1- Adicionar instrução”);

            printf(“\n2- Executar pipeline”);

            printf(“\n0- Sair”);

            scanf(“%d”, &opc);

            switch(opc){

                case 1:

                    // cria uma nova instrucao

                    printf(“\nDigite o ID da nova instrução: “);

                    scanf(“%d”, &novo_id);

                    getchar();

                    printf(“\nDigite o nome da nova instrução: “);

                    fgets(novo_nome, 10, stdin);

                    adicionar_instrucao(novo_id, novo_nome);

                    break;

                case 2:

                    // faz todo o ciclo do pipeline ate a funcao acabar

                    while(proxima < total_instrucoes || !pipeline_vazio()) {

                        ciclo_clock();

                        printf(“\n\n— Ciclo de Clock: %d —“, clock);

                        print_pipeline();

                    }

                    break;

            }

        } while(opc != 0);

        return 0;

    }

    Lógica utilizada:

    • Código em três partes principais: criação de instruções, vetor das tarefas do pipeline e o clock (relógio que vai ficar responsável por o que acontece a cada tempo da aplicação)
    • Instruções criadas em um vetor de structs, pra que ficasse mais fácil do usuário adicionar novas como quisesse
    • Vetor do pipeline foi preenchido inicialmente com -1, para indicar que a casa estava vazio, aí em cada ciclo ele pegava os valores de cada casa e trazia da frente para trás (ao contrário), e verificava se ainda tinham instruções que não haviam sido utilizadas, caso houvesse o ID dessa instrução ocupava o 0 do vetor do pipeline, e assim por diante
    • Clock serviu para que isso acontecesse cada um de uma vez, e para que ficasse mais visível para o usuário o que estava acontecendo a cada instante, de modo que antes de se atualizar era mostrada como o pipeline estava

    Dificuldades e erros:

    • Primeira grande dificuldade foi pensar como tudo funcionaria, por ser muitas coisas, então fui fazendo um pouco de cada vez e testando, e assim adicionando novas funcionalidades, como: primeiro criei a struct da instrução e populei manualmente, depois o vetor do pipeline, depois o funcionamento em si, e por fim deixei que o usuário pudesse fazer o fluxo com o menu
    • Além disso foi difícil pensar que o pipeline deveria se atualizar ao contrário, para que os dados anteriores não fossem apagados, e junto a isso também teve a parte mais difícil que foi verificar se as instruções já haviam acabado e puxar a correta para a posição 0 do pipeline
    • Outro ponto foi que no começo eu estava tentando salvar toda a struct no vetor do pipeline, mas depois consegui corrigir criando um campo ID e salvando somente o ID no pipeline para que pudesse ver o fluxo
    • Também foi trabalhoso controlar quais instruções já haviam sido utilizadas e identificar qual deveria entrar na posição 0 do pipeline a cada ciclo, resolvi isso com a variável proxima
    • Por fim outro obstáculo que tive foi a interação do usuário, não foi a maior delas porque já tinha treinado bastante essa parte de menu e structs na disciplina de algoritmos 1, mas foi um pouco difícil fazer com que tudo funcionasse ao mesmo tempo

    Como a técnica de pipeline auxilia na concorrência de um sistema computacional

    O pipeline permite que várias instruções estejam sendo processadas ao mesmo tempo, cada uma em uma etapa diferente.

    Sem o pipeline, uma instrução precisaria terminar todas as etapas antes que a próxima pudesse começar, o que faria com que a execução fosse mais lenta e deixando partes do processador sem utilização durante vários momentos.

    Com o pipeline assim que uma instrução avança para a próxima etapa, outra já pode ocupar a etapa anterior. Dessa forma, várias instruções conseguem avançar simultaneamente pelo sistema

    Isso não faz com que uma instrução individual termine mais rápido, mas aumenta a quantidade de instruções processadas em um mesmo período de tempo, melhorando o aproveitamento dos recursos do processador.

    Curtir

  26. Atividade 09 – Desafio de Pipeline

    RA: a2888289

    1. O desafio de programação solicita a implementação simulada de um pipeline dividido em 7 tarefas diferentes, contendo uma UCP, uma fila com “n instruções”, contador de tempo e a possibilidade de criar novas instruções. Abaixo está o código de simulação desenvolvido para cumprir esses requisitos:

    Pythonimport time class Instrucao: def __init__(self, id, nome): self.id = id self.nome = nome self.etapa_atual = 0 self.tempo_gasto = 0 class PipelineSimulador: def __init__(self): # 7 Tarefas baseadas no modelo do desafio (BI, DI, CO, BO, EI, EO + WB) self.etapas = ["BI", "DI", "CO", "BO", "EI", "EO", "WB"] self.fila_instrucoes = [] self.pipeline = [None] * 7 self.ciclos_de_tempo = 0 def adicionar_instrucao(self, nome): id_inst = len(self.fila_instrucoes) + 1 nova_ins = Instrucao(id_inst, nome) self.fila_instrucoes.append(nova_ins) print(f"Instrução {id_inst} ({nome}) adicionada à fila.") def rodar_ciclo(self): self.ciclos_de_tempo += 1 print(f"\n--- Ciclo de Tempo: {self.ciclos_de_tempo} ---") for i in range(6, -1, -1): instrucao = self.pipeline[i] if instrucao is not None: if i == 6: print(f"[{instrucao.nome}] Concluiu a última etapa: {self.etapas[i]}") self.pipeline[i] = None else: if self.pipeline[i+1] is None: self.pipeline[i+1] = instrucao self.pipeline[i] = None instrucao.etapa_atual += 1 print(f"[{instrucao.nome}] Avançou para a etapa: {self.etapas[i+1]}") if self.pipeline[0] is None and len(self.fila_instrucoes) > 0: for inst in self.fila_instrucoes: if inst.etapa_atual == 0 and inst not in self.pipeline: self.pipeline[0] = inst print(f"[{inst.nome}] Entrou no Pipeline na etapa: {self.etapas[0]}") break def exibir_estado_visual(self): estado = [] for slot in self.pipeline: if slot is None: estado.append("[ Vazio ]") else: estado.append(f"[ {slot.nome} ]") print("Estado do Pipeline: " + " -> ".join(estado)) # Inicialização e teste da simulação simulador = PipelineSimulador() simulador.adicionar_instrucao("Instrucao 1") simulador.adicionar_instrucao("Instrucao 2") simulador.adicionar_instrucao("Instrucao 3") for _ in range(15): simulador.rodar_ciclo() simulador.exibir_estado_visual() time.sleep(0.1)

    Curtir

Deixe um comentário

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.