-
Notifications
You must be signed in to change notification settings - Fork 0
Contador de Programa
[English]
O Contador de Programa (PC) é o componente responsável por armazenar o endereço de memória da instrução atual e da próxima. Ele também lida com saltos, endereços de carga/armazenamento e substituições em nível de sistema.
O PC recebe todas as suas entradas regulares pela esquerda e envia suas saídas pela direita. A parte superior contém a interface CSR, que fornece substituições para certos sinais de controle e envia ao Controlador de CSR informações importantes sobre o PC.
O PC possui quatro saídas de uso geral. A primeira é o Endereço de Saída, que se conecta diretamente aos Dispositivos de E/S por meio do Barramento de Endereço. Essa saída pode conter valores para diferentes funções dependendo do contexto. Durante o processo de busca de instrução, ela fornece o endereço da próxima instrução. Durante instruções de carga e armazenamento, ela encaminha um endereço calculado internamente a partir de suas entradas. Em caso de carga de sistema, um endereço vindo do Controlador de CSR é utilizado.
Depois, há duas saídas, uma para cada registrador do PC. A "próxima" é usada para armazenar o endereço após uma instrução JAL ou JALR, enquanto a "atual" é usada para a instrução AUIPC ou para algumas operações do Controlador de CSR.
Por fim, há o deslocamento de byte, que indica o byte inicial dos dados em operações de carga. Isso é um resquício da arquitetura RISC I, onde a instrução de carga coleta a palavra inteira da memória, mesmo que a instrução exija apenas um valor de byte ou short. Se o byte estiver no início da palavra, o deslocamento é 0; caso contrário, pode haver deslocamento de até 3 bytes para cargas de byte e até 2 bytes para cargas de short. Esse comportamento será explicado com mais detalhes no Capítulo do Buffer de Entrada.
A imagem acima mostra o circuito interno do Contador de Programa. O circuito foi dividido em três partes.
A primeira parte é responsável pelos cálculos de endereço usados em saltos, desvios e cargas. Um pequeno somador é usado para somar o PC atual ou o valor do Barramento A ao valor imediato. Se o Controlador de CSR estiver presente, esse resultado é transmitido a ele para que endereços desalinhados possam ser tratados corretamente.
Ter o Controlador de CSR também ativa a segunda parte do circuito (destacada em vermelho). Essa seção fornece controle adicional para saltos e cargas iniciadas pelo Controlador de CSR. Se o Controlador de CSR não estiver presente, essa parte pode ser ignorada ou até removida completamente — embora alguns sinais possam precisar ser reconectados.
A parte superior do circuito restante contém os registradores próximo e atual. O registrador próximo é implementado como um contador, o que significa que possui sinais de entrada extras que permitem incrementar automaticamente quando o sinal de escrita está ativo e nenhum salto está sendo executado. Para realizar saltos, o próximo PC recebe o endereço de destino do salto a partir do resultado calculado (ou do endereço de destino do sistema, se o Controlador de CSR estiver presente).
Note que, como as instruções no DRISC-V são sempre alinhadas por palavra (4 bytes), os dois bits menos significativos do contador são omitidos. No entanto, durante instruções de carga/armazenamento (sinalizadas pelo sinal Forward Address), esses dois bits são armazenados em um registrador especial chamado Deslocamento de Byte, que se conecta à saída correspondente mencionada anteriormente.
Um dos sinais visíveis no meio do circuito é Usar Deslocamento. Ele é ativado durante instruções de armazenamento porque, ao contrário das cargas, operações de armazenamento envolvendo dados menores que uma palavra não são necessariamente alinhadas por palavra. Nesses casos, o endereço completo calculado é encaminhado ao barramento de endereço.
timescale 1s/1s
//Entradas e Saídas
module program_counter(
input reset,
input clock,
input write,
input jump,
input pc_relative,
input use_offset,
input forward_address,
input [31:0] immediate,
input [31:0] address_in,
input system_jump,
input system_load,
input [31:0] system_address_target,
output reg [1:0] data_offset,
output [31:0] calculated_address,
output [31:0] next,
output [31:0] current,
output [31:0] address_bus
);
//Registradores
reg [29:0] next_reg;
reg [29:0] current_reg;
//Parte 1 do circuito
assign calculated_address = pc_relative ? current + immediate : address_in + immediate;
//Força a saída para 32 bits
assign next = {next_reg, 2'b00};
assign current = {current_reg, 2'b00};
//Seleção da saída para o barramento de endereço
assign address_bus = forward_address ?
(system_load ? system_address_target :
use_offset ? calculated_address : {calculated_address[31:2], 2'b00}) :
{next_reg, 2'b00};
always@(posedge clock) begin
if(reset) begin
current_reg <= 30'b0;
next_reg <= 30'b0;
data_offset <= 2'b0;
end
//Aqui está o comportamento de atualização dos registradores
else if(write) begin
if(system_jump) next_reg <= system_address_target[31:2];
else if(jump) next_reg <= calculated_address[31:2];
else next_reg <= next_reg + 1;
current_reg <= next_reg;
end
if(forward_address) begin
data_offset <= calculated_address[1:0];
end
end
endmodule-
- 1.1 Introduction
- 1.2 RISC-V Implementation
- 1.2.1 Available Instruction Set
- 1.2.2 Available Non-ISA Features
-
- 2.1 ALU
- 2.2 Register File
- 2.3 Program Counter
- 2.4 Input Buffer
- 2.5 RAM
- 2.6 Operation Controller
- 2.7 CSR Controller
-
- 3.1 Input Devices
- 3.1.1 Keyboard
- 3.1.2 Switches and Joystick
- 3.1.3 Random Number Generator
- 3.1.4 Real-Time Device
- 3.2 Output Devices
- 3.2.1 Screen
- 3.2.2 Terminal
- 3.2.3 Software Interrupt Register
- 3.1 Input Devices