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.

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

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. #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

  7. 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

  8. 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

  9. 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

  10. 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

  11. 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

Deixar mensagem para Arthur das Neves Ferreira Cancelar resposta

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