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.
GUSTAVO TUDELA FRUSSA
2612240
RELATO:
As principais dificuldades encontradas foram encontrar o tamanho necessário da matriz que simularia o funcionamento da pipeline, e ajustar o próprio para que ele não estourasse a pilha de memória, alterando o valor da variável “num_instruções”.
CÓDIGO (em c++):
#include <iostream>
//////////Gustavo Tudela Frussa RA: 2612240
int main()
{
int num_instru;
int i;
int j;
printf(“Digite a quantidade de instruçõesn”);
scanf(“%d”, &num_instru);
printf(“n”);
int mat[num_instru][6+num_instru]; //// cria uma matriz de tamanho i = número de instruções; e j = número de deslocamentos + numero de tarefas
for(i=0;i<num_instru;i++){ /////////// preenche a matriz com zeros
for(j=0;j<6+num_instru;j++){
mat[i][j] = 0;
}
}
for(i=0;i<num_instru;i++){ //////////// altera os zeros de acordo com o deslocamento das instruções
for(j=0;j<7;j++){
mat[i][j+i] = j+1;
}
}
for(i=0;i < num_instru; i++){ //////// apresenta a matriz que simula a pipeline para o usuário
for(j=0;j< num_instru+6;j++){
printf(“%d”,mat[i][j]);
}
printf(“n”);
}
printf(“n”);
printf(“Tarefas: n”);
printf(“1: Buscar n”);
printf(“2: Codificar n”);
printf(“3: Calcular n”);
printf(“4: Executar n”);
printf(“5: Armazenar n”);
printf(“6: Apresentar n”);
printf(“7: Encerrar n”);
return 0;
}
CurtirCurtir
Antonio Totti Goncalves RA: 2706571
1 – Desafio de programação da disciplina de Organização de Computadores:
Implementar na forma de simulação o funcionamento do pipeline em um sistema computacional. Exemplos: Fig. 1 e Fig.2.
Deverá conter UCP; fila com “n instruções”; possibilidade de criação de novas instruções; divisão de um pipeline em 7 tarefas diferentes; contador de tempo das instruções.
R:d#include
#include <string.h>
#define MAX_INST 10
#define N_ESTAGIOS 7
#define MAX_TEMPO 25
#define TAM_INST 50
const char* estagios[N_ESTAGIOS] = {“BI”, “DI”, “CO”, “BO”, “EX”, “EO”, “GR”};
void simular_pipeline(char instrucoes[MAX_INST][TAM_INST], int qtd) {
char pipeline[MAX_INST][MAX_TEMPO][4];
for (int i = 0; i < qtd; i++) {
for (int t = 0; t < MAX_TEMPO; t++) {
strcpy(pipeline[i][t], ” “);
}
}
for (int inst = 0; inst < qtd; inst++) {
for (int estagio = 0; estagio < N_ESTAGIOS; estagio++) {
int tempo = inst + estagio;
if (tempo < MAX_TEMPO) {
strcpy(pipeline[inst][tempo], estagios[estagio]);
}
}
}
printf(“nSimulacao do Pipeline (com %d instrucoes)nn”, qtd);
printf(“Tempo -> “);
for (int t = 0; t < MAX_TEMPO; t++) {
printf(“%3d “, t + 1);
}
printf(“n”);
for (int inst = 0; inst < qtd; inst++) {
printf(“Inst %2d: “, inst + 1);
for (int t = 0; t < MAX_TEMPO; t++) {
printf(“%s “, pipeline[inst][t]);
}
printf(“n”);
}
printf(“nInstrucoes digitadas:n”);
for (int i = 0; i < qtd; i++) {
printf(“Inst %2d: %sn”, i + 1, instrucoes[i]);
}
printf(“nTotal de ciclos (clocks): %dn”, qtd + N_ESTAGIOS – 1);
}
int main() {
int n;
char instrucoes[MAX_INST][TAM_INST];
printf(“Quantas instrucoes voce deseja simular (max %d)? “, MAX_INST);
scanf(“%d”, &n);
setbuf(stdin,NULL);
if (n <= 0 || n > MAX_INST) {
printf(“Numero invalido. Deve ser entre 1 e %d.n”, MAX_INST);
return 1;
}
printf(“nDigite as instrucoes (ex: ADD R1, R2, R3):n”);
for (int i = 0; i < n; i++) {
printf(“Instrucao %d: “, i + 1);
fgets(instrucoes[i], TAM_INST, stdin);
instrucoes[i][strcspn(instrucoes[i], “n”)] = ”; // Remove o n do final
}
simular_pipeline(instrucoes, n);
return 0;
}
Após a implementação, faça um relato sobre: às dificuldades encontradas; como o a técnica de pipeline auxilia na concorrência de um sistema computacional.
R: Implementar o simulador de pipeline apresentou como principal desafio a visualização da execução simultânea de diversas instruções em diferentes estágios. A organização da tabela, o controle temporal de cada instrução e a implementação de uma entrada de dados livre de falhas também demandaram atenção considerável.
Apesar dessas dificuldades, o projeto foi fundamental para a compreensão prática do funcionamento de um pipeline. Ao invés da execução sequencial de cada instrução em sua totalidade, o processador as divide em etapas, iniciando o processamento da instrução seguinte antes da conclusão da anterior. Essa sobreposição permite que múltiplas instruções sejam processadas concorrentemente, otimizando a velocidade global do sistema.
Através da implementação, foi possível observar concretamente o ganho de desempenho proporcionado pelo pipeline, que utiliza de forma mais eficiente o tempo e os recursos da unidade central de processamento (CPU).
CurtirCurtir
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: Pedro Henrique Romano Gedminas
Ra: 2768500
Codigo:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h> // para sleep()#define MAX_INSTRUCOES 20#define ESTAGIOS 7// Nomes dos estágios do pipelineconst char* estagios[] = {“IF”, “ID”, “EX1”, “EX2”, “MEM1”, “MEM2”, “WB”};typedef struct {char nome[10];int tempoInicio;int tempoFim;} Instrucao;void simularPipeline(Instrucao instrucoes[], int n) {int tempo = 0;printf(“Simulando pipeline de %d instrucoes:n”, n);printf(“Tempo |”);for (int i = 0; i < n; i++)printf(” %s “, instrucoes[i].nome);printf(“n”);int fim = n + ESTAGIOS;for (tempo = 0; tempo < fim; tempo++) {printf(“%5d |”, tempo + 1);for (int i = 0; i < n; i++) {if (tempo >= i && tempo < i + ESTAGIOS)printf(” %s “, estagios[tempo – i]);elseprintf(” “);}printf(“n”);usleep(500000); // 0.5 segundo por ciclo}}int main() {Instrucao fila[MAX_INSTRUCOES];int n = 0;char opcao;printf(“Simulador de Pipeline com 7 Estagiosn”);do {printf(“Digite o nome da instrucao %d: “, n + 1);scanf(“%s”, fila[n].nome);n++;printf(“Deseja adicionar outra instrucao? (s/n): “);scanf(” %c”, &opcao);} while ((opcao == ‘s’ || opcao == ‘S’) && n < MAX_INSTRUCOES);simularPipeline(fila, n);return 0;}
Durante a implementação em C, a principal dificuldade foi o controle das instruções em ciclos paralelos, além de garantir que cada instrução começasse no ciclo correto e que os estágios fossem respeitados. O pipeline permite o processamento simultâneo de várias instruções, o que aumenta a eficiência do sistema, como simulado neste projeto.
CurtirCurtir
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define MAX_INSTRUCOES 20
#define MAX_ESTAGIOS 7
const char *estagios[MAX_ESTAGIOS] = {“BI”, “DI”, “CO”, “BO”, “EI”, “EO”, “FIM”};
typedef struct {
int id;
int estagio_atual;
bool concluida;
int tempo_inicio;
int tempo_fim;
int src; // registrador de origem (leitura)
int dst; // registrador de destino (escrita)
bool em_bolha;
} Instrucao;
Instrucao fila[MAX_INSTRUCOES];
int total_instrucoes = 0;
int clock_global = 0;
bool tem_dependencia(int atual_idx) {
Instrucao *inst_atual = &fila[atual_idx];
for (int i = 0; i < atual_idx; i++) {
Instrucao *inst_anter = &fila[i];
if (!inst_anter->concluida && inst_anter->dst == inst_atual->src) {
return true;
}
}
return false;
}
void adicionar_instrucao() {
if (total_instrucoes >= MAX_INSTRUCOES) {
printf(“Limite de instruções atingido!n”);
return;
}
Instrucao nova;
nova.id = total_instrucoes + 1;
nova.estagio_atual = 0;
nova.concluida = false;
nova.tempo_inicio = clock_global;
nova.tempo_fim = -1;
nova.em_bolha = false;
printf(“Instrução %d:n”, nova.id);
printf(” Registrador de origem (src): “);
scanf(“%d”, &nova.src);
printf(” Registrador de destino (dst): “);
scanf(“%d”, &nova.dst);
fila[total_instrucoes] = nova;
total_instrucoes++;
}
void executar_ciclo() {
printf(“nClock %d:n”, clock_global);
for (int i = 0; i < total_instrucoes; i++) {
Instrucao *inst = &fila[i];
if (inst->concluida) continue;
if (inst->em_bolha) {
printf(” Instrução %d em bolha (aguardando dependência)n”, inst->id);
if (!tem_dependencia(i)) {
inst->em_bolha = false;
}
continue;
}
if (inst->estagio_atual == 1 && tem_dependencia(i)) {
inst->em_bolha = true;
printf(” Instrução %d entra em bolha por dependêncian”, inst->id);
continue;
}
printf(” Instrução %d está em %sn”, inst->id, estagios[inst->estagio_atual]);
inst->estagio_atual++;
if (inst->estagio_atual == MAX_ESTAGIOS – 1) {
inst->concluida = true;
inst->tempo_fim = clock_global;
}
}
clock_global++;
printf(“———————–n”);
}
bool todas_concluidas() {
for (int i = 0; i < total_instrucoes; i++) {
if (!fila[i].concluida) return false;
}
return true;
}
void mostrar_tempos() {
printf(“nResumo dos tempos:n”);
for (int i = 0; i < total_instrucoes; i++) {
Instrucao *inst = &fila[i];
printf(“Instrução %d: início=%d, fim=%d, duração=%dn”,
inst->id, inst->tempo_inicio, inst->tempo_fim,
inst->tempo_fim – inst->tempo_inicio + 1);
}
}
void menu() {
int opcao;
do {
printf(“1. Adicionar instruçãon”);
printf(“2. Executar 1 ciclon”);
printf(“3. Executar até o fimn”);
printf(“4. Mostrar temposn”);
printf(“0. Sairn”);
printf(“Escolha: “);
scanf(“%d”, &opcao);
switch (opcao) {
case 1: adicionar_instrucao(); break;
case 2: executar_ciclo(); break;
case 3: while (!todas_concluidas()) executar_ciclo(); break;
case 4: mostrar_tempos(); break;
case 0: printf(“Encerrando…n”); break;
default: printf(“Opção inválida!n”);
}
} while (opcao != 0);
}
int main() {
menu();
return 0;
}
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
Aluno: João Pedro Diniz Nacur RA: a2819511
_______________________________________________________________________________________#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#define ESTAGIOS 7
#define INSTRUCAO 5
typedef struct{
int id;
char status[20];
} comandos;
int main(){
setlocale(LC_ALL, “Portuguese”);
// 1 – criando vetores e variaveis
comandos pipeline[ESTAGIOS];
comandos fila[INSTRUCAO];
char nomes_estagios[ESTAGIOS][30] = {
“1 – Busca”,
“2 – Decodifica”,
“3 – Calc. Endereco”,
“4 – Busca Operando”,
“5 – Executa”,
“6 – Escreve”,
“7 – Finaliza”
};
int i, tempo = 0, instru_atual = 0, finalizados = 0, id_terminou;
//esvaziar o pipeline
for(i = 0; i < ESTAGIOS; i++){
pipeline[i].id = 0; //zerando
strcpy(pipeline[i].status, “Vazio”); //deixa como status de vazio
}
//definir status e criando comando
for(i = 0; i < INSTRUCAO; i++){
fila[i].id = i + 1;
strcpy(fila[i].status, “Aguardando”); //todos estão no aguardo
}
printf(” Simulador Completo de Pipeline \n\n”);
//quando concluido, ele finaliza todo o programa
while(finalizados < INSTRUCAO){
printf(“[TEMPO: %02d ]\n”, tempo);
//retirando quem ja finalizou
if(pipeline[ESTAGIOS – 1].id != 0) {
id_terminou = pipeline[ESTAGIOS – 1].id;
strcpy(fila[id_terminou – 1].status, “Concluída”); // Atualiza status
finalizados++; // Conta como finalizada
}
//de trás para frente
for(i = ESTAGIOS – 1; i > 0; i–) {
pipeline[i] = pipeline[i – 1];
}
/*Verifique sua Fila de Instruções. Se houver instruções esperando, tire a primeira da
fila e coloque no Estágio 1.*/
if(instru_atual < INSTRUCAO){
pipeline[0] = fila[instru_atual];
strcpy(pipeline[0].status, “Processando”); // Muda status de Aguardando para Processando
instru_atual++;
} else
{
pipeline[0].id = 0;
strcpy(pipeline[0].status, “Vazio”);
}
//imprimir a interface
for (i = 0; i < ESTAGIOS; i++) {
if (pipeline[i].id == 0) {
printf(“%-25s : [ – ]\n”, nomes_estagios[i]);
} else {
printf(“%-25s : [ Instrução %d | %s ]\n”, nomes_estagios[i], pipeline[i].id, pipeline[i].status);
}
}
printf(“\n”);
}
printf(“Simulação concluida com sucesso em %d ciclos de tempo!\n”, tempo);
return 0;
}Dificuldade: Eu estive em dúvida de como estruturar o algoritmo. Precisando revisar e criar um algoritmo primeiro no portugol e depois passar em C. Também aprendendo vendo vídeos e pesquisando como faz pipeline e fila em C.
CurtirCurtir
Aluna: Gabriela Godoy Pimenta
RA: 2819503
#include <stdio.h>
#include <string.h>
typedef struct {
int id;
char tipo[50];
int ciclo_entrada;
} Instrucao;
int main() {
Instrucao pipeline[7];
Instrucao fila[100];
int total_na_fila = 0;
int proxima_da_fila = 0;
int relogio = 0;
for (int i = 0; i < 7; i++) {
pipeline[i].id = 0;
}
fila[0].id = 1;
strcpy(fila[0].tipo, “SOMA”);
total_na_fila++;
fila[1].id = 2;
strcpy(fila[1].tipo, “LEITURA”);
total_na_fila++;
fila[2].id = 3;
strcpy(fila[2].tipo, “SUBTRACAO”);
total_na_fila++;
for (int ciclo = 1; ciclo <= 10; ciclo++) {
relogio = ciclo;
printf(“\n—-CICLO DE CLOCK: %d\n—-“, relogio);
if (pipeline[6].id != 0) {
int tempo_total = relogio – pipeline[6].ciclo_entrada;
printf(“<- [CONCLUÍDA] Instrucao %d (%s) terminou! Levou %d ciclos.\n”,
pipeline[6].id, pipeline[6].tipo, tempo_total);
}
for (int i = 6; i >= 1; i–) {
pipeline[i] = pipeline[i – 1];
}
pipeline[0].id = 0;
if (proxima_da_fila < total_na_fila) {
pipeline[0] = fila[proxima_da_fila];
pipeline[0].ciclo_entrada = relogio;
printf(“-> [ENTROU] Instrucao %d (%s) entrou na Etapa 1.\n”, pipeline[0].id, pipeline[0].tipo);
proxima_da_fila++;
}
printf(“\nEstado das Etapas:\n”);
for (int i = 0; i < 7; i++) {
if (pipeline[i].id != 0) {
printf(” Etapa %d: Instrucao %d (%s)\n”, i + 1, pipeline[i].id, pipeline[i].tipo);
} else {
printf(” Etapa %d: [VAZIO]\n”, i + 1);
}
}
}
return 0;
}
CurtirCurtir
Aluno: Théo Lopes Mansano
RA: 2779790
Desafio Pipeline:
Instruções já determinadas:
Usei o Online GDB para fazer o codigo.
#include <stdio.h>
#include <string.h>
#define TAM 5
#define ETAPAS 7
// Estrutura da instrução
typedef struct {
char nome[20];
int tempo;
} Instrucao;
int main() {
// Fila de instruções
Instrucao fila[TAM] = {
{“ADD”, 0},
{“SUB”, 0},
{“MUL”, 0},
{“DIV”, 0},
{“LOAD”, 0}
};
// Pipeline com 7 etapas
char pipeline[ETAPAS][20] = {
“Busca”,
“Decodifica”,
“Leitura”,
“Execucao”,
“Memoria”,
“Escrita”,
“Final”
};
printf(“=== SIMULADOR DE PIPELINE ===\n\n”);
// Simulação da UCP
for(int i = 0; i < TAM; i++) {
printf(“Instrucao: %s\n”, fila[i].nome);
// Passa pelas 7 etapas
for(int j = 0; j < ETAPAS; j++) {
fila[i].tempo++;
printf(“Etapa %d: %s | Tempo: %d\n”,
j + 1,
pipeline[j],
fila[i].tempo);
}
printf(“————————–\n”);
}
return 0;
}
Quais foram as dificuldades?
Vantagens:
Integração entre sistemas: pipelines conectam ferramentas diferentes, como banco de dados, APIs, ambientes de nuvem, containers e plataformas de BI.
CurtirCurtir
Aluno: Gabriel Vinícius Henrique
RA: 2819490
Relato: A principal dificuldade encontrada foi compreender como deveria ser implementado a matriz e manipulá-la.
Código em C:
#include <stdio.h>
#include <stdlib.h>
// Struct das instruções
struct instruction {
char nome;
int estagio;
} typedef instruction;
int create_instruction(instruction *fila, int n) {
int i;
for (i = 0; i < n; i++) {
fila[i].nome = ‘A’ + i;
fila[i].estagio = 0;
}
return 0;
}
int show_instruction(instruction *fila, int n) {
int i;
for (i = 0; i < n; i++) {
printf(“%c:%d “, fila[i].nome, fila[i].estagio);
}
printf(“\n”);
return 0;
}
int main() {
int n;
printf(“Quantas intrucoes deseja criar: “); // Pergunta quantas instruções o usuário deseja criar
do {
scanf(“%d”, &n);
} while(n < 1 || n > 26);
instruction *fila = (instruction *) malloc(n * sizeof(instruction)); // Aloca a fila de instrucoes
int i, j;
create_instruction(fila, n); // Cria as instrucoes e define o estagio como 0
show_instruction(fila, n); // Mostra a fila de instrucoes
for (i = 0; i < n * n; i++) {
for (j = 0; j <= i; j++) {
if (fila[j].estagio >= 7) {
fila[j].estagio = 7; // Se o estagio for maior que 7, define como 7
} else {
fila[j].estagio++; // Incrementa o estagio da instrucao
}
}
show_instruction(fila, n); // Mostra a fila de instrucoes
printf(“\n”);
}
free(fila);
return 0;
}
CurtirCurtir
Nome: Kauan Reis de Lima
RA: 2819538
1 – Desafio de programação da disciplina de Organização de Computadores:
Implementar na forma de simulação o funcionamento do pipeline em um sistema computacional. Exemplos: Fig. 1 e Fig.2.
Deverá conter UCP; fila com “n instruções”; possibilidade de criação de novas instruções; divisão de um pipeline em 7 tarefas diferentes; contador de tempo das instruções.
Código em C:
#include <stdio.h>
#include <string.h>
#define NUM_ESTAGIOS 7
#define MAX_INSTRUCOES 20
int main() {
char pipeline[NUM_ESTAGIOS][4] = {“–“, “–“, “–“, “–“, “–“, “–“, “–“};
char nomes_estagios[NUM_ESTAGIOS][4] = {“BI”, “DI”, “CO”, “BO”, “EI”, “EO”, “GR”};
char fila_instrucoes[MAX_INSTRUCOES][4];
int fila_inicio = 0; // Aponta para a primeira instrução da fila
int fila_fim = 0; // Aponta para a posição onde a próxima instrução será inserida
for (int i = 1; i <= 5; i++) {
sprintf(fila_instrucoes[fila_fim], “I%d”, i);
fila_fim++;
}
int relogio = 1; // Contador de tempo (ciclos)
int instrucoes_concluidas = 0;
int total_esperado = 6; // 5 iniciais + 1 que criaremos no meio do caminho
printf(“SIMULADOR DE PIPELINE EM C (MATRIZ)\n\n”);
// Imprimindo o cabeçalho da matriz
printf(“Tempo | “);
for (int i = 0; i < NUM_ESTAGIOS; i++) {
printf(“[%s] “, nomes_estagios[i]);
}
printf(“\n—————————————————-\n”);
// O loop roda até que a última instrução saia do último estágio
while (instrucoes_concluidas < total_esperado) {
// 3. Possibilidade de criação de novas instruções
if (relogio == 3) {
strcpy(fila_instrucoes[fila_fim], “I6”);
fila_fim++;
}
// LOGICA DO PIPELINE
// Passo A: Verifica se a instrução no último estágio (índice 6) vai ser concluída
if (strcmp(pipeline[NUM_ESTAGIOS – 1], “–“) != 0) {
instrucoes_concluidas++;
}
// Passo B: Move as instruções um estágio para frente (de trás para frente)
for (int i = NUM_ESTAGIOS – 1; i > 0; i–) {
strcpy(pipeline[i], pipeline[i – 1]);
}
// Passo C: O primeiro estágio recebe da fila, se houver
if (fila_inicio < fila_fim) {
// Copia a instrução do início da fila para o estágio 0
strcpy(pipeline[0], fila_instrucoes[fila_inicio]);
fila_inicio++; // Avança a fila
} else {
// Se a fila esvaziou, insere uma bolha
strcpy(pipeline[0], “–“);
}
// O “%-2d” alinha o número à esquerda, e o “%2s” alinha a string
printf(” T=%-2d | “, relogio);
for (int i = 0; i < NUM_ESTAGIOS; i++) {
printf(“[%2s] “, pipeline[i]);
}
printf(“\n”);
relogio++; // Avança o clock
}
printf(“\nSimulacao concluida em %d ciclos de clock.\n”, relogio – 1);
return 0;
}
Após a implementação, faça um relato sobre: às dificuldades encontradas; como o a técnica de pipeline auxilia na concorrência de um sistema computacional.
Dificuldade: A principal dificuldade na implementação do simulador foi conciliar a natureza sequencial da linguagem de programação com o comportamento paralelo do hardware físico. Para que as instruções não fossem sobrescritas antes da hora, foi necessário aplicar uma lógica de movimentação reversa, atualizando os estágios do pipeline de trás para frente. Além disso, houve o desafio de gerenciar as chamadas “bolhas”, criando uma lógica para inserir espaços vazios e manter o relógio do sistema rodando até que a última instrução saísse do processador.
Pipeline: A técnica de pipeline auxilia na concorrência de um sistema computacional ao permitir que múltiplas instruções sejam executadas simultaneamente, sobrepondo as diferentes fases do seu processamento. Em vez de o processador concluir uma instrução inteira para depois começar a próxima, ele funciona como uma linha de montagem: assim que o primeiro estágio (como a “busca” da instrução) termina e repassa a tarefa, ele já fica livre para processar a instrução seguinte. Isso maximiza o uso do hardware, já que quase todas as partes do processador trabalham ativamente a cada ciclo de clock, evitando ociosidade. Consequentemente, embora a técnica não torne uma instrução individualmente mais rápida, ela aumenta de forma expressiva a vazão (throughput) do sistema, sendo capaz de entregar, em cenários ideais, uma instrução concluída a cada ciclo.
CurtirCurtir
Nome: Aires Silvestre Cambumba
RA: 2898217
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h> // Para rodar o Sleep no Windows
#else
#include <unistd.h> // Para rodar o usleep no Linux/macOS
#endif
// Função para simular o pulso de clock (pausa de meio segundo)
void pulso_clock() {
#ifdef _WIN32
Sleep(600);
#else
usleep(600000);
#endif
}
int main() {
int num_instru;
int i, j, ciclo;
printf(“Digite a quantidade de instrucoes: “);
scanf(“%d”, &num_instru);
// Criação dos nomes das instruções (Requisito do desafio)
// Uma matriz de strings para dar nome a cada instrução criada
char nome_instrucoes[num_instru][30];
for(i = 0; i < num_instru; i++) {
sprintf(nome_instrucoes[i], “Instrucao_%d”, i + 1);
}
// O total de ciclos necessário é: 6 (tarefas restantes) + número de instruções
int total_ciclos = 6 + num_instru;
// Cria e limpa a matriz com zeros (Sua lógica original)
int mat[num_instru][total_ciclos];
for(i = 0; i < num_instru; i++) {
for(j = 0; j < total_ciclos; j++) {
mat[i][j] = 0;
}
}
// Preenche a matriz deslocando as 7 tarefas (Sua lógica perfeita!)
for(i = 0; i < num_instru; i++) {
for(j = 0; j < 7; j++) {
mat[i][j + i] = j + 1;
}
}
// Nomes das 7 tarefas para exibir no painel
char *tarefas[] = {
“Vazio”,
“Buscar”,
“Codificar”,
“Calcular”,
“Executar”,
“Armazenar”,
“Apresentar”,
“Encerrar”
};
printf(“\n— INICIANDO SIMULACAO DA UCP (PIPELINE) —\n”);
pulso_clock();
// SIMULAÇÃO DINÂMICA: Transforma as COLUNAS da matriz em TEMPO REAL
for(ciclo = 0; ciclo < total_ciclos; ciclo++) {
printf(“\n=========================================\n”);
printf(” CICLO DE CLOCK CONTADOR: %d \n”, ciclo + 1);
printf(“\n=========================================\n”);
// Varre cada instrução para saber o que ela faz NESTE ciclo
for(i = 0; i < num_instru; i++) {
int ID_tarefa = mat[i][ciclo];
if(ID_tarefa == 0) {
// Se o ciclo atual ainda não chegou na vez da instrução
if(ciclo < i) {
printf(” %s -> [ AGUARDANDO NA FILA ]\n”, nome_instrucoes[i]);
} else {
printf(” %s -> [ CONCLUIDA COM SUCESSO ]\n”, nome_instrucoes[i]);
}
} else {
// Exibe a tarefa correspondente ao número (1 a 7)
printf(” %s -> [ Tarefa %d: %s ]\n”,
nome_instrucoes[i], ID_tarefa, tarefas[ID_tarefa]);
}
}
pulso_clock(); // Aguarda o próximo ciclo de clock
}
printf(“\n================ RELATORIO FINAL ================\n”);
printf(” O pipeline terminou com Sucesso!\n”);
printf(” Tempo total de execucao: %d ciclos de clock.\n”, total_ciclos);
printf(“=================================================\n”);
return 0;
}
1. Dificuldades Encontradas na Implementação (Sugestões comuns)
while/for) bem estruturados.2. Como a técnica de Pipeline auxilia na concorrência?
O pipeline funciona de forma análoga a uma linha de montagem industrial.
Paralelismo a Nível de Instrução (ILP): Em vez de esperar que uma instrução passe por todas as 7 tarefas para só então iniciar a próxima, o pipeline permite que, assim que a Instrução 1 libera a Tarefa 1 e passa para a Tarefa 2, a Instrução 2 já possa entrar na Tarefa
Maximização do Hardware: Ele garante que diferentes partes da UCP (unidade de busca, decodificação, execução, escrita em memória, etc.) trabalhem de forma concorrente e simultânea, evitando que blocos de silício fiquem ociosos.
Rendimento (Throughput): O pipeline não diminui o tempo que uma instrução leva para ser executada individualmente (latência), mas aumenta drasticamente a quantidade de instruções concluídas por unidade de tempo. Em um estado ideal (pipeline cheio), o sistema entrega a conclusão de uma instrução por ciclo de clock, independentemente de ela ter 7 estágios.
CurtirCurtir
#include<stdio.h>
#include<stdlib.h>
#include<locale.h>
struct instrucao{
int numero_instrucao, entrada, saida;
};
typedef struct instrucao instrucao;
instrucao fila[20];
struct estagio{
int ocupado;
struct instrucao dado; // Guarda os dados da instrução
};
typedef struct estagio estagio;
estagio pipeline[7];
int main(){
setlocale(LC_ALL, “Portuguese”);
int i, inicio = 0, fim = 0, ciclo = 0, proxima_instrucao = 1, tempo_gasto;
for(i=0; i<7; i++){
pipeline[i].ocupado = 0;
pipeline[i].dado.numero_instrucao = 0; // nenhuma instrução nesse estágio ainda
}
for(i=0; i<7; i++){
fila[fim].numero_instrucao = proxima_instrucao;
fila[fim].entrada = 0; // a instrução ainda não foi iniciada
fila[fim].saida = 0;
fim++; //final da fila vai para a proxima posição livre
proxima_instrucao++;
}
while(inicio < fim || pipeline[6].ocupado){
ciclo++;
printf(“\nClock: %d\n”, ciclo);
if(pipeline[6].ocupado){
pipeline[6].dado.saida = ciclo; // qual instrução que terminou o pipeline
printf(“\nInstrução %d concluída”, pipeline[6].dado.numero_instrucao);
tempo_gasto = pipeline[6].dado.saida – pipeline[6].dado.entrada;
printf(“\nTempo gasto: %d\n”, tempo_gasto);
}
for(i=6; i>=1; i–){ //mover as intruções de um estágio para frente quando concluido algum estágio
pipeline[i] = pipeline[i-1];
}
if(inicio < fim){ //entrada de novas instruções
pipeline[0].ocupado = 1; // 0 – ocupado e 1 – Livre
pipeline[0].dado = fila[inicio];
pipeline[0].dado.entrada = ciclo;
inicio++;
}else{ // se todas as instruções tiverem sido concluidas
pipeline[0].ocupado = 0;
pipeline[0].dado.numero_instrucao = 0;
}
if(ciclo == 4){
for(i=0; i<2; i++){
fila[fim].numero_instrucao = proxima_instrucao;
fila[fim].entrada = 0;
fila[fim].saida = 0;
fim++;
proxima_instrucao++;
}
}
for(i=0; i<7; i++){ //apresentação da tecnica de pipeline
printf(“\nEstágio: %d”, i+1);
if(pipeline[i].ocupado){
printf(“\nInstrução: %d”, pipeline[i].dado.numero_instrucao);
}else{
printf(“\nVazio”);
}
}
printf(“\n”);
fflush(stdout);
}
printf(“\nSimulação encerrada.”);
return 0;
}
CurtirCurtir
Atividade 9
Aluno: Magno Elano Pereira de Oliveira
#include <stdio.h>
#include <string.h>
#define MAX_INSTRUCOES 20
#define ESTAGIOS 7
// Estrutura da instrução
typedef struct {
char nome[30];
int concluida;
} Instrucao;
int main() {
Instrucao fila[MAX_INSTRUCOES];
// Pipeline com 7 estágios
char pipeline[ESTAGIOS][30] = {
“Vazio”,”Vazio”,”Vazio”,
“Vazio”,”Vazio”,”Vazio”,
“Vazio”
};
int qtd, clock = 0;
int inseridas = 0;
int concluidas = 0;
printf(“====================================\n”);
printf(“SIMULADOR DE PIPELINE – UCP\n”);
printf(“====================================\n”);
printf(“Quantidade inicial de instrucoes: “);
scanf(“%d”, &qtd);
if(qtd > MAX_INSTRUCOES)
qtd = MAX_INSTRUCOES;
// Cadastro das instruções
for(int i = 0; i < qtd; i++) {
printf(“Nome da instrucao %d: “, i + 1);
scanf(“%s”, fila[i].nome);
fila[i].concluida = 0;
}
inseridas = qtd;
// Simulação do pipeline
while(concluidas < qtd) {
clock++;
printf(“\n====================================\n”);
printf(“CLOCK %d\n”, clock);
printf(“====================================\n”);
// Verifica se a instrução terminou
if(strcmp(pipeline[6], “Vazio”) != 0) {
printf(“Instrucao %s concluida!\n”, pipeline[6]);
concluidas++;
}
// Move as instruções para o próximo estágio
for(int i = ESTAGIOS – 1; i > 0; i–) {
strcpy(pipeline[i], pipeline[i – 1]);
}
// Insere nova instrução
if(inseridas > 0) {
strcpy(pipeline[0],
fila[qtd – inseridas].nome);
inseridas–;
} else {
strcpy(pipeline[0], “Vazio”);
}
// Exibe estado atual do pipeline
printf(“\nEstado do Pipeline:\n”);
printf(“BI (Busca Instr.): %s\n”, pipeline[0]);
printf(“DI (Decodificacao): %s\n”, pipeline[1]);
printf(“CO (Calculo Oper.): %s\n”, pipeline[2]);
printf(“BO (Busca Operando): %s\n”, pipeline[3]);
printf(“EI (Execucao): %s\n”, pipeline[4]);
printf(“EO (Escrita Resultado): %s\n”, pipeline[5]);
printf(“FIM: %s\n”, pipeline[6]);
}
printf(“\n====================================\n”);
printf(“PROCESSAMENTO CONCLUIDO!\n”);
printf(“Total de clocks: %d\n”, clock);
printf(“====================================\n”);
return 0;
} Relatório – Simulação de Pipeline Objetivo
O objetivo desta atividade foi desenvolver uma simulação do funcionamento de uma Unidade Central de Processamento (UCP) utilizando a técnica de pipeline. O programa foi implementado em linguagem C e permite a execução simultânea de várias instruções em diferentes estágios de processamento. Funcionamento do Programa
O sistema recebe uma fila contendo diversas instruções e as distribui em um pipeline composto por sete estágios:
A cada ciclo de clock, todas as instruções avançam uma posição dentro do pipeline até que completem seu processamento. Dificuldades Encontradas
Durante o desenvolvimento da atividade, as principais dificuldades foram:
Como o Pipeline Auxilia na Concorrência
A técnica de pipeline aumenta a eficiência do processador ao permitir que várias instruções sejam executadas simultaneamente em diferentes estágios. Enquanto uma instrução está sendo executada, outra pode estar sendo decodificada e uma terceira sendo buscada na memória.
Dessa forma, há melhor aproveitamento dos recursos da UCP e aumento da quantidade de instruções processadas por unidade de tempo, melhorando o desempenho geral do sistema computacional. Conclusão
A implementação da simulação permitiu compreender de forma prática o funcionamento do pipeline em processadores. Foi possível observar como a divisão das tarefas em estágios contribui para a execução concorrente das instruções e para o aumento da eficiência do sistema. A atividade demonstrou a importância dessa técnica na arquitetura dos computadores modernos.
CurtirCurtir
1 – Conceitue e exemplifique Pipeline Pipeline é uma técnica de hardware que permite que a CPU realize a busca de uma ou mais instruções além da próxima a ser executada, processando múltiplas instruções simultaneamente em diferentes estágios. Exemplo: Imagine uma linha de produção de bifes com 3 etapas (cortar, cozinhar, embrulhar). No pipeline, quando a etapa 1 termina o primeiro bife e passa para a etapa 2, a etapa 1 já começa o segundo bife. Assim, vários bifes são feitos ao mesmo tempo sem esperar um terminar completamente. Em 5 ciclos de clock, 5 instruções são iniciadas (mesmo que cada uma demore mais de 1 ciclo para finalizar).
2 – Em qual arquitetura a técnica de Pipeline é mais fácil de ser implementada? O pipeline é mais fácil e eficiente de ser implementado na arquitetura RISC (Reduced Instruction Set Computer). Isso ocorre porque as instruções RISC são simples, têm tamanho fixo e levam aproximadamente o mesmo tempo para serem executadas, facilitando a divisão em estágios uniformes.
3 – O que é microcódigo ou microprogramação? Em qual arquitetura esta característica está mais presente? Microcódigo é uma camada intermediária entre o hardware da CPU e a arquitetura do conjunto de instruções visível ao programador. Consiste em um conjunto de instruções ao nível do hardware que implementam as instruções de código de máquina de nível superior. Microprogramação é o ato de escrever microcódigo — programar estrategicamente a unidade de controle do processador a nível de operações. Esta característica está mais presente na arquitetura CISC (Complex Instruction Set Computer), que utiliza microprogramação para executar instruções complexas.
4 – Conceitue Arquitetura RISC e CISC. Cite as diferenças das duas arquiteturas. RISC significa Reduced Instruction Set Computer. CISC significa Complex Instruction Set Computer. Principais diferenças: Conjunto de instruções: RISC tem conjunto reduzido e simples; CISC tem conjunto amplo e complexo Tempo de execução: RISC executa 1 ciclo de clock por instrução; CISC executa vários ciclos de clock Microcódigo: RISC não possui (execução direta no hardware); CISC possui microprogramação Registradores: RISC tem muitos registradores (mais de 500); CISC tem menos registradores Consumo de energia: RISC tem baixo consumo (eficiente energeticamente); CISC tem alto consumo Complexidade do hardware: RISC tem baixa complexidade; CISC tem alta complexidade Exemplos: RISC inclui ARM, MIPS, SPARC, RISC-V; CISC inclui x86 (Intel, AMD) Uso típico: RISC é usado em dispositivos móveis e embarcados; CISC é usado em desktops, notebooks e servidores.
5 – Em que fases estão distribuídas as execuções dentro de um processador RISC? Um processador RISC com pipeline possui 5 estágios/fases: 1. IF (Instruction Fetch) – Busca da instrução na memória 2. ID (Instruction Decode) – Decodificação da instrução 3. EX (Execute) – Execução na ULA (Unidade Lógico-Aritmética) 4. MEM (Memory Access) – Acesso à memória de dados 5. WB (Write Back) – Escrita nos registradores Em máquinas RISC, estas fases são executadas em paralelo — uma fase não precisa esperar a outra terminar para iniciar.
6 – Cite um Sistema Operacional que faz uso de um processador RISC? RISC OS — sistema operacional originalmente desenvolvido pela Acorn Computers Ltd, projetado especificamente para rodar no chipset ARM (arquitetura RISC). Linux também roda em processadores RISC — existem distribuições Linux para ARM (Debian, Ubuntu, Fedora, Manjaro) e o primeiro SoC RISC-V compatível com Linux foi lançado pela SiFive.
7 – O que é um processador Híbrido? Cite um modelo de um processador híbrido. Um processador híbrido combina diferentes tipos de núcleos ou arquiteturas em um único chip para otimizar desempenho e eficiência energética — geralmente núcleos “fortes” (performance) e núcleos “fracos” (eficiência). Modelo exemplo: Intel Pentium Pro — internamente é um processador RISC (mais rápido), mas externamente se comporta como CISC para compatibilidade com software x86. Outro exemplo moderno: Intel Core com arquitetura big.LITTLE (núcleos Performance + Efficiency) ou AMD APU Ryzen.
8 – Como resolver os problemas dos gargalos na técnica de pipeline? Os gargalos (hazards) no pipeline são resolvidos com as seguintes técnicas: Data Hazard (dependência de dados): Forwarding: encaminha resultado diretamente entre estágios, evitando espera Stalling: inserir “bolha” (ciclo NOP) para aguardar dado disponível Reordering: compilador reorganiza instruções para evitar dependência direta Control Hazard (desvios/Branches): Branch Prediction: CPU prevê se desvio será tomado (baseado em histórico) Delay Slot: compilador insere instrução útil após o desvio que sempre será executada Stalling: adiar instruções até saber o desvio Structural Hazard (conflito de recursos): Duplicação de unidades: duas memórias separadas (uma para instruções, outra para dados) — Arquitetura Harvard Aumentar estágios do pipeline para maior paralelismo Solução geral: Quebrar instruções em vários passos, onde cada passo consome 1 ciclo de clock.
CurtirCurtir
#include <stdio.h>
#include <string.h>
#include <locale.h>
#define maxinstrucoes 50
#define numestagios 7
int main()
{
//Nomes dos estágios do pipeline
char estagios[numestagios][100] = {
“fi (busca)”, “di (decodificacao)”, “co (calc operandos)”,
“fo (busca operandos)”, “ei (execucao)”, “wo (escrita)”, “ch (verificacao)”
};
setlocale (LC_ALL, “Portuguese”);
//Variáveis da fila de espera
char fila[maxinstrucoes][100];
int totalfila = 0, iniciofila = 0, fimfila = 0;
//Variáveis do pipeline
char pipelinenomes[numestagios][100];
int pipelinetempo[numestagios], pipelineocupado[numestagios], i;
//Inicializando o pipeline
for (i = 0; i < numestagios; i++) {
pipelineocupado[i] = 0;
pipelinetempo[i] = 0;
}
//3 instruções como exemplo, para não precisar digitar
strcpy(fila[fimfila], “add r1, r2”); fimfila++;
totalfila++;
strcpy(fila[fimfila], “sub r3, r4”); fimfila++;
totalfila++;
strcpy(fila[fimfila], “load r5, 100”); fimfila++;
totalfila++;
int clock = 0, opcao = 0;
char novonome[100];
//Menu para o simulador
while (opcao != 3) {
printf(“\n—Menu do simulador—\n”);
printf(“1- Avançar 1 ciclo de clock\n”);
printf(“2- Adicionar instrução\n”);
printf(“3- Sair\n”);
printf(“Escolha uma opção:\n “);
scanf(“%d”, &opcao);
if (opcao == 2)
{
//Adicionar uma nova instrução na fila
if (totalfila < maxinstrucoes)
{
printf(“digite o comando (ex: mov, , mul, div, and): “);
scanf(“%s”, novonome);
strcpy(fila[fimfila], novonome);
fimfila = (fimfila + 1) % maxinstrucoes;
totalfila++;
printf(“Instrução adicionada na fila!\n”);
}
else
{
printf(“Erro: A fila está cheia!\n”);
}
}
else if (opcao == 1)
{
clock++; // avançar o tempo
// Para aumentar o tempo das instruções que já estão dentro do pipeline
for (i = 0; i < numestagios; i++)
{
if (pipelineocupado[i] == 1) //Se estiver ocupado o programa soma +1 no tempo de vida da instrução em específico
{
pipelinetempo[i]++;
}
}
if (pipelineocupado[6] == 1) //Se houver alguém no último estágio, significa que ele terminou
{
printf(“\n[!] ‘%s’ Terminou! ciclos totais: %d\n”, pipelinenomes[6], pipelinetempo[6]);
pipelineocupado[6] = 0;
}
for (i = 5; i >= 0; i–) //Move as instruções para o próximo estágio (de trás para frente para garantir que a posição da frente seja esvaziada)
{
if (pipelineocupado[i] == 1 && pipelineocupado[i+1] == 0)
{
strcpy(pipelinenomes[i+1], pipelinenomes[i]);
pipelinetempo[i+1] = pipelinetempo[i];
pipelineocupado[i+1] = 1;
pipelineocupado[i] = 0;
}
}
if (pipelineocupado[0] == 0 && totalfila > 0) //Se o primeiro estágio estiver vazio, puxa a próxima instrução da fila
{
strcpy(pipelinenomes[0], fila[iniciofila]);
pipelinetempo[0] = 1;
pipelineocupado[0] = 1;
iniciofila = (iniciofila + 1)%maxinstrucoes;
totalfila–;
}
printf(“\nTempo: %d\n”, clock);
for (i = 0; i < numestagios; i++)
{
printf(“[%s]: “, estagios[i]);
if (pipelineocupado[i] == 1)
{
printf(“%s (Tempo: %d)”, pipelinenomes[i], pipelinetempo[i]);
} else
{
printf(“Vazio”);
}
printf(“\n”);
}
}
}
printf(“Fim\n”);
return 0;
}
Dificuldades encontradas: A maior dificuldade foi em como simular um hardware (físico) que opera simultaneamente utilizando algoritmos (computacional) que rodam de maneira sequencial/linear e em programar todo esse processo. Além disso, a lógica do pipeline é diferente quando escrita em linguagem C, o que torna a programação ainda mais complicada e confusa.
A técnica de pipeline ajuda na concorrência porque ao invés de o computador esperar uma instrução passar por todas as etapas para depois começar a próxima, ele deixa várias instruções entrarem na fila ao mesmo tempo, cada uma em uma fase diferente, o que faz o resultado final aparecer muito antes. Depois que a fila fica cheia, o processador consegue terminar uma instrução a cada ciclo (clock). Isso melhora o uso do sistema porque nenhuma parte do chip fica parada esperando a outra terminar, fazendo o computador poder realizar mais tarefas ao mesmo tempo com o máximo de eficiência.
CurtirCurtir
_______________________________________________________________________________________
1 – Desafio de programação da disciplina de Organização de Computadores:
Código:
#include <stdio.h>
#include <string.h>
#include <locale.h>
#define MAX_INSTRUCOES 100
#define TAREFAS 7
int pipeline[TAREFAS], clock=0, proxima=0;
// instrucao struct
struct instrucao{
int id;
char nome[10];
int estagio_atual;
};
typedef struct instrucao instrucao;
instrucao fila_espera[MAX_INSTRUCOES];
int total_instrucoes = 0;
// funcao para adicionar instrucoes
void adicionar_instrucao(int id, char nome[]){
fila_espera[total_instrucoes].id = id;
strcpy(fila_espera[total_instrucoes].nome, nome);
fila_espera[total_instrucoes].estagio_atual = 0;
total_instrucoes++;
}
// funcao para setar -1 vazio em todo o pipeline
void iniciar_pipeline(){
int i;
for(i=0; i<TAREFAS; i++){
pipeline[i] = -1;
}
}
// funcao para printar o pipeline
void print_pipeline(){
int i;
printf(“\n\n”);
for(i=0; i<TAREFAS; i++){
printf(“T%d: %d | “, i+1, pipeline[i]);
}
}
// funcao que faz o sistema dos ciclos de pipeline
void ciclo_clock(){
int i;
// refaz o pipeline de traz pra frente
for(i = TAREFAS – 1; i > 0; i–){
pipeline[i] = pipeline[i – 1];
}
// traz a nova instrucao pra casa 0 do pipeline
if(proxima < total_instrucoes){
pipeline[0] = fila_espera[proxima].id;
proxima++;
} else {
pipeline[0] = -1;
}
clock++;
}
// funcao que ve se o pipeline esta vazio, ou seja acabou tudo
int pipeline_vazio() {
int i;
for(i = 0; i < TAREFAS; i++) {
if(pipeline[i] != -1) {
return 0;
}
}
return 1;
}
int main(){
setlocale(LC_ALL, “Portuguese”);
int i, novo_id, opc;
char novo_nome[10];
// inicia o pipeline declarando todos os campos como vazio
iniciar_pipeline();
do{
// menu inicial
printf(“\n\n—MENU—“);
printf(“\n1- Adicionar instrução”);
printf(“\n2- Executar pipeline”);
printf(“\n0- Sair”);
scanf(“%d”, &opc);
switch(opc){
case 1:
// cria uma nova instrucao
printf(“\nDigite o ID da nova instrução: “);
scanf(“%d”, &novo_id);
getchar();
printf(“\nDigite o nome da nova instrução: “);
fgets(novo_nome, 10, stdin);
adicionar_instrucao(novo_id, novo_nome);
break;
case 2:
// faz todo o ciclo do pipeline ate a funcao acabar
while(proxima < total_instrucoes || !pipeline_vazio()) {
ciclo_clock();
printf(“\n\n— Ciclo de Clock: %d —“, clock);
print_pipeline();
}
break;
}
} while(opc != 0);
return 0;
}
Lógica utilizada:
Dificuldades e erros:
Como a técnica de pipeline auxilia na concorrência de um sistema computacional
O pipeline permite que várias instruções estejam sendo processadas ao mesmo tempo, cada uma em uma etapa diferente.
Sem o pipeline, uma instrução precisaria terminar todas as etapas antes que a próxima pudesse começar, o que faria com que a execução fosse mais lenta e deixando partes do processador sem utilização durante vários momentos.
Com o pipeline assim que uma instrução avança para a próxima etapa, outra já pode ocupar a etapa anterior. Dessa forma, várias instruções conseguem avançar simultaneamente pelo sistema
Isso não faz com que uma instrução individual termine mais rápido, mas aumenta a quantidade de instruções processadas em um mesmo período de tempo, melhorando o aproveitamento dos recursos do processador.
CurtirCurtir
Atividade 09 – Desafio de Pipeline
RA: a2888289
1. O desafio de programação solicita a implementação simulada de um pipeline dividido em 7 tarefas diferentes, contendo uma UCP, uma fila com “n instruções”, contador de tempo e a possibilidade de criar novas instruções. Abaixo está o código de simulação desenvolvido para cumprir esses requisitos:
Python
import time class Instrucao: def __init__(self, id, nome): self.id = id self.nome = nome self.etapa_atual = 0 self.tempo_gasto = 0 class PipelineSimulador: def __init__(self): # 7 Tarefas baseadas no modelo do desafio (BI, DI, CO, BO, EI, EO + WB) self.etapas = ["BI", "DI", "CO", "BO", "EI", "EO", "WB"] self.fila_instrucoes = [] self.pipeline = [None] * 7 self.ciclos_de_tempo = 0 def adicionar_instrucao(self, nome): id_inst = len(self.fila_instrucoes) + 1 nova_ins = Instrucao(id_inst, nome) self.fila_instrucoes.append(nova_ins) print(f"Instrução {id_inst} ({nome}) adicionada à fila.") def rodar_ciclo(self): self.ciclos_de_tempo += 1 print(f"\n--- Ciclo de Tempo: {self.ciclos_de_tempo} ---") for i in range(6, -1, -1): instrucao = self.pipeline[i] if instrucao is not None: if i == 6: print(f"[{instrucao.nome}] Concluiu a última etapa: {self.etapas[i]}") self.pipeline[i] = None else: if self.pipeline[i+1] is None: self.pipeline[i+1] = instrucao self.pipeline[i] = None instrucao.etapa_atual += 1 print(f"[{instrucao.nome}] Avançou para a etapa: {self.etapas[i+1]}") if self.pipeline[0] is None and len(self.fila_instrucoes) > 0: for inst in self.fila_instrucoes: if inst.etapa_atual == 0 and inst not in self.pipeline: self.pipeline[0] = inst print(f"[{inst.nome}] Entrou no Pipeline na etapa: {self.etapas[0]}") break def exibir_estado_visual(self): estado = [] for slot in self.pipeline: if slot is None: estado.append("[ Vazio ]") else: estado.append(f"[ {slot.nome} ]") print("Estado do Pipeline: " + " -> ".join(estado)) # Inicialização e teste da simulação simulador = PipelineSimulador() simulador.adicionar_instrucao("Instrucao 1") simulador.adicionar_instrucao("Instrucao 2") simulador.adicionar_instrucao("Instrucao 3") for _ in range(15): simulador.rodar_ciclo() simulador.exibir_estado_visual() time.sleep(0.1)CurtirCurtir