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.
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.
CurtirCurtir
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.
CurtirCurtir
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.
CurtirCurtir
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;}
CurtirCurtir
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:
CurtirCurtir
#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;
}
CurtirCurtir
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.
CurtirCurtir
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.
CurtirCurtir
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.
CurtirCurtir
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.
CurtirCurtir
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.
CurtirCurtir