Multiplicador 8×8
Exercício lab5a
State Machine

Na continuação da construção do multiplicador 8×8, o objetivo desta etapa é examinar a implementação de uma máquina de estados, não há codificação nesta etapa.

O projeto resolvido desta etapa, pode ser baixado diretamente no github <clicando neste link aqui> e no diretório raiz IVER10_1 temos todos os arquivos e instruções dos exercícios.

Se você caiu de paraquedas por aqui e precisa saber como instalar o software Questa para trabalhar com Verilog, leia a série “Instalando Quartus com Questa”, <clicando neste link aqui>.

Objetivo desta etapa:

Examinar a implementação da máquina de estados.

Até o momento, você montou todos os componentes necessários para construir o multiplicador 8×8 bits, faltando a etapa para controlar a máquina de estados.

Tem um projeto na pasta lab5a chamado “mult_control”.

Neste laboratório você estará mais sozinho, não há instruções passo a passo. O arquivo “mult_control.v” contém a entidade de nível superior junto com algumas outras estruturas, conforme indicado abaixo:

// Declaração do "mult_control"
module mult_control (
	input clk, reset_a, start,				// Declarando entradas "clk", "reset_a", "start", "count"
	input [1:0] count,
	output reg [1:0] input_sel, shift_sel,	// Declarando signais de saída "in_sel", "shift_sel", 
	output reg [2:0] state_out,				//       "state_out", "done", "clk_ena" and "sclr_n"
	output reg done, clk_ena, sclr_n
);

	// Declarando as variaveis "current_state" and "next_state" para serem variáveis de estado.
	reg [2:0] current_state, next_state;
	
	// Declaração dos parametros e estados, 6 valores:  "idle", "lsb", "mid", "msb", "calc_done" and "err"
	parameter idle=0, lsb=1, mid=2, msb=3, calc_done=4, err=5;

	// Create processo sequencial para controlar as transições de estado e garantindo que o "current_state" receba o valor de "next state" 
	// na subida de borda do clock. Utilizado para controle de "clear" assíncrono.
	always @(posedge clk, posedge reset_a) begin
		if (reset_a)
			current_state <= idle;
		else
			current_state <= next_state;
	end
		
	// Criação do processo combinacional e declarações "case" para determinar o próximo estado, baseado no estado atual e entradas.
	always @ *
		case (current_state)
			idle : 
				if (start)
					next_state = lsb;
				else
					next_state = idle;
			lsb : 
				if (count == 0 && start == 0)
					next_state = mid;
				else
					next_state = err;
			mid : 
				if (start == 0 && count == 2)
					next_state = msb;
				else if (start == 0 && count == 1)
					next_state = mid;
				else
					next_state = err;
			msb : 
				if (count == 3 && start == 0)
					next_state = calc_done;
				else
					next_state = err;
			calc_done :
				if (!start)
					next_state = idle;
				else
					next_state = err;
			err : 
				if (start)
					next_state = lsb;
				else
					next_state = err;
		endcase

	// Criação do processo para "Mealy output logic" para o "input_sel", "shift_sel", "done", "clk_ena" e "sclr_n"  (estado atual e funções de saída)
	always @* begin
		// Inicializando as saídas para valores default, então só vai funcionar quando ocorrerem mudanças.
		input_sel = 2'bxx;
		shift_sel = 2'bxx;
		done = 1'b0;
		clk_ena = 1'b0;
		sclr_n = 1'b1;		
		case (current_state)
			idle : 
				if (start) begin
					clk_ena = 1'b1;
					sclr_n = 1'b0;
				end
			lsb : 
				if (count == 0 && start == 0) begin
					input_sel = 2'd0;
					shift_sel = 2'd0;
					clk_ena = 1'b1;
				end
			mid : 
				if (count == 2 && start == 0) begin
					input_sel = 2'd2;
					shift_sel = 2'd1;
					clk_ena = 1'b1;
				end
				else if (count == 1 && start == 0) begin
					input_sel = 1'd1;
					shift_sel = 1'd1;
					clk_ena = 1'b1;
				end
			msb : 
				if (count == 3 && start == 0) begin
					input_sel = 2'd3;
					shift_sel = 2'd2;
					clk_ena = 1'b1;
				end
			calc_done :
				if (!start)
					done = 1'b1;
			err : 
				if (start) begin
					clk_ena = 1'b1;
					sclr_n = 1'b0;
				end
		endcase
	end

	// Criando o processo para "Moore output logic" para o "state_out".
	always @(current_state) begin
		// Inicializa "state_out" para seu valor default caso somente cubra quando ele mude.
		state_out = 3'd0;
		case (current_state)
			idle : ;
			lsb : state_out = 3'd1;
			mid : state_out = 3'd2;
			msb : state_out = 3'd3;
			calc_done : state_out = 3'd4;
			err : state_out = 3'd5;
		endcase
	end

endmodule 

Esta máquina de estados irá gerenciar todas as operações que ocorrem dentro do multiplicador 8×8,usando 6 estados definidos: “IDLE”, “LSB”, “MID”, “MSB”, “CALC_DONE” e “ERR”. Observe o diagrama de estado da Figura abaixo, com outras definições de seu comportamento.

Caso minhas notas sejam de grande valia para ti, vou ficar muito agradecido se você clicar nos anúncios desta página e conferir o que meus patrocinadores tem para lhe oferecer.

No estado “LSB”:

A máquina de estado multiplica os 4 bits mais baixos dos dois estados de 8 bits. multiplicandos

((a[3..0] * b[3..0] ) * 20 )

E este resultado intermediário é salvo em um acumulador.

No estado “MID”:

A máquina de estado realiza multiplicação cruzada

((a[3..0] * b[7..4] ) * 24 ) e (( a[7..4] * b[3..0] ) * 24 )

Isto é feito em ciclos de clock sucessivos. Os produtos de ambas as operações de multiplicação são somados ao conteúdo do acumulador à medida que são concluídos e enviados de volta para o acumulador.

No estado “MSB”:

A máquina de estado multiplica os 4 bits mais altos dos dois estados de 8 bits. multiplicandos

((a[7..4] * b[7..4] ) * 28 )

Este resultado intermediário é adicionado ao conteúdo do acumulador e enviado de volta para o acumulador.

O produto abaixo, é o resultado final:

result [15..0] = ( dataa[7..0] * datab[7..0] )
result [15..0] = ( (a[7..4]*24) + (a[3..0]*20) ) * ( (b[7..4]*24) + (b[3..0]*20) ) =
( (a[7..4] * b[7..4]) * 28 ) + ( (a[7..4] * b[3..0]) * 24 ) + 
( (a[3..0] * b[7..4]) * 24 ) + ( (a[3..0] * b[3..0]) * 20 )

Máquina de estado em “CALC_DONE”:

Nesse estado é ativada a saída “done_flag” para indicar que o resultado foi calculado e está pronto para leitura pela lógica downstream.

Máquina de estado em “ERR”:

Neste estado, é indicado que entradas incorretas foram recebidas.

Sinais “start” e “count”:

Há dois sinais para a máquina de estados: “start” e “count”. O sinal “start” é iniciado por um ciclo de clock, definindo o início da operação de multiplicação 8×8 para o próximo ciclo de clock.O sinal “start” é ativado somente por um ciclo de clock, enquanto que o sinal “count” é usado pela máquina de estado para rastrear os ciclos de multiplicação.

Sinal “mult_control”:

A saída “mult_control” de controle da máquina de estado serve para gerenciar os outros blocos no projeto.

Máquina de estado representando o multiplicador, fonte Intel, Clique para ampliar.

Se você chegou até aqui, continue com o próximo exercício:
Multiplicador 8×8 Exercício lab5b Montagem final“,
que terá as considerações finais.

Publicado por Renato de Pierri em 03/12/2023

Fonte: Manual de exercícios de Introdução ao Verilog, da Intel.

Last updated by at .