Usando Quartus e ModelSim

Sempre me interessei por circuitos digitais e, em particular, por linguagens de descrição de hardware - HDL. Há muito tempo faço parte da lista de futuros livros de leitura de David M. Harris e Sarah L. Harris, “Circuitos digitais e arquitetura de computadores”, aproveitando o tempo livre no auto-isolamento, e cheguei a este livro maravilhoso. No processo de leitura, encontrei algumas dificuldades e, em particular, como escrever e depurar códigos no Quartus Prime. No processo de busca, o site marsohod.org me ajudou bastante, mas o processo de simulação de circuitos neste site é descrito usando as ferramentas internas Quartus e nas versões modernas do programa, essas ferramentas internas não estão disponíveis e você precisa usar o ModelSim. Para sistematizar de alguma forma o conhecimento adquirido com o Quartus e o ModelSim, decidi escrever este artigo. No processo deste artigo, como exemplo, analisarei o problema do livro "Digital Circuitry and Computer Architecture" de David M. Harris e Sarah L. Harris, especificamente o problema 3.26 sobre a máquina de água com gás. Neste artigo, mostrarei como instalar o Quartus, criar um projeto, escrever um código e simulá-lo. Todo mundo que está interessado nisso, seja bem-vindo sob o gato.



imagem



Formulação do problema



Você foi persuadido a projetar uma máquina de refrigerantes para o escritório. As bebidas são parcialmente cobertas pelo sindicato, portanto custam apenas 5 rublos. A máquina aceita moedas de 1, 2 e 5 rublos. Assim que o cliente pagar a quantia necessária, a máquina distribuirá a bebida e retornará a mudança. Projete uma máquina de estado para uma máquina de refrigerantes. As entradas da máquina são de 1, 2 e 5 rublos, a saber, qual dessas moedas está inserida.



Suponha que apenas uma moeda seja inserida por relógio. A máquina tem saídas: despeje refrigerante, retorne 1 rublo, retorne 2 rublos, retorne 2 por 2 rublos. Assim que 5 rublos (ou mais) são coletados na máquina, ele define o sinal "Pour GASING", bem como os sinais retornando a alteração correspondente. A máquina deve estar pronta para aceitar moedas novamente.



Teoria



Máquinas de estado finito ou máquina de estado finito (FSM) pertencem à classe de circuitos seriais síncronos, que representam a grande maioria dos circuitos de circuitos digitais. É assim que você deve implementar seus projetos (pelo menos no início). Este método fornece repetibilidade e verificação do circuito e é independente das relações de atraso dos vários elementos do circuito. As regras para a construção de circuitos sequenciais síncronos declaram que um circuito é um circuito sequencial síncrono se seus elementos atenderem às seguintes condições:



  • Cada elemento do circuito é um registro ou um circuito combinacional.
  • Pelo menos um elemento do circuito é um registrador.
  • Todos os registros são cronometrados com um único sinal de relógio.
  • Cada caminho cíclico contém pelo menos um registro.


Uma máquina de estados possui vários estados, que são armazenados em registradores. Quando um sinal de relógio chega, a máquina de estado pode mudar seu estado, e como exatamente o estado mudará depende dos sinais de entrada e do estado atual. No caso mais simples, pode não haver nenhum sinal de entrada, portanto o divisor de frequência funciona. Existem duas classes principais de máquinas de estados finitos: um autômato Moore, no qual os sinais de saída dependem apenas do estado atual do autômato, e um autômato Mealy, no qual os sinais de saída dependem do estado atual e dos sinais de entrada. Em princípio, qualquer máquina de estados finitos pode ser implementada de acordo com o esquema de Moore e o esquema de Miley, a diferença entre eles será que o autômato Moore terá mais estados e haverá um relógio atrás do autômato Mily.Para o circuito da máquina de refrigerante, usarei o circuito de Miles. Vamos declarar a máquina de estado:

Símbolo Descrição
S 0 O estado inicial, a quantidade acumulada de 0 rublos.
S 1 A quantidade acumulada é de 1 esfrega.
S 2 Acumulado 2 rublos.
S 3 Acumulado 3 rublos.
S 4 Acumulado 4 rublos.


O sinal de entrada será um barramento de dois bits, com a seguinte codificação da denominação da moeda:

Símbolo Valor Descrição
Eu 1 01 1 RUB
I 2 dez RUB 2
I 5 onze 5 esfregar


Vamos desenhar um diagrama de estados do nosso autômato (nos diagramas de estados do autômato Mealy, é necessário indicar os sinais de saída nas setas de transição de estado, não o farei para não confundir o diagrama, todos os sinais de saída serão descritos na tabela abaixo):



imagem



Vamos escrever a tabela de mudanças de estados e sinais de saída:

Estados Sinais de entrada
S S' insert pour_water C 1 . change1 2 . change2 2 2 . change22
S0 S1 I1 0 0 0 0
S0 S2 I2 0 0 0 0
S0 S0 I5 1 0 0 0
S1 S2 I1 0 0 0 0
S1 S3 I2 0 0 0 0
S1 S0 I5 1 1 0 0
S2 S3 I1 0 0 0 0
S2 S4 I2 0 0 0 0
S2 S0 I5 1 0 1 0
S3 S4 I1 0 0 0 0
S3 S0 I2 1 0 0 0
S3 S0 I5 1 1 1 0
S4 S0 I1 1 0 0 0
S4 S0 I2 1 1 0 0
S4 S0 I5 1 0 0 1




Quartus Prime



O Quartus possui uma edição Lite gratuita, que possui algumas limitações em relação à edição profissional; a principal limitação é não mais que 10.000 linhas de código-fonte para simular um projeto. Você pode baixá-lo, após o registro, pelo link , no momento em que este artigo foi escrito, a versão mais recente era 19.1, baseada no trabalho com esta versão, escrevi um artigo. Escolhemos a Lite Edition, versão 19.1, sistema operacional Windows (note que existe uma versão do Quartus para Linux e funciona bem, surgem problemas com o ModelSim, que é de 32 bits e usa uma versão antiga da biblioteca de exibição de fontes, portanto, primeiro recomendo usar a versão do Windows ), selecione a guia Arquivos combinados. O tamanho do arquivo para o download é muito grande - 5,6 Gb, lembre-se disso. Expanda o arquivo baixado e executesetup.bat . A instalação ocorre de maneira padrão; usamos a seleção padrão de componentes.



Criação de projeto



Para criar um novo projeto, selecione o Assistente para Arquivo -> o Novo ... do Projeto . A primeira janela do Assistente é informativa, clique em Avançar , na segunda janela, selecione onde o projeto estará localizado, seu nome "soda_machine" e o elemento de design de nível superior "soda_machine" , como na figura:



imagem



Na próxima janela, selecione "Projeto vazio" . A janela para adicionar arquivos "Adicionar arquivos" , não adicione nada. A janela para selecionar o dispositivo “Family, Devices & Board Settings” é muito importante para um projeto real, mas como nosso projeto está longe de ser real, deixamos as configurações padrão aqui, como na figura:



imagem



Janela para selecionar configurações para outras ferramentas"Configurações da ferramenta EDA" , selecione para simular o projeto para usar o formato "ModelSim-Altera" e "System Verilog HDL" como na figura:



imagem



Na última janela de informações "Resumo" , clique em Concluir .



Escrevendo código fonte



Teremos dois arquivos principais com o código-fonte, este é o próprio módulo soda_machine e sua bancada de testes. Ambos os arquivos usarão o tipo de dados insert_type , que descreve como codificamos as denominações das moedas e é lógico separá-lo em um arquivo separado. Mas existem algumas dificuldades associadas aos recursos de compilação do Quartus e ModelSim. O Quartus compila todos os arquivos de origem em uma única passagem e o ModelSim compila cada arquivo separadamente, para que, ao compilar o Quartus, não haja redefinição do tipo insert_type , usei a técnica do C / C ++ include guard com base nas diretivas do microprocessador. Além disso, esse ModelSim garantiria que o tipo insert_type usado no módulo soda_machinee no banco de testes, o mesmo, colocou sua descrição dentro do pacote soda_machine_types . Com esses requisitos em mente, o arquivo soda_machine_types.sv se parece com o seguinte:



soda_machine_types.sv
`ifndef soda_machine_types_sv_quard

package soda_machine_types;

	typedef enum logic [1:0] {I1=2'b01, I2=2'b10, I5=2'b11} insert_type;
	
endpackage

`define soda_machine_types_sv_quard
`endif




Agora, o próprio módulo soda_machine está localizado no arquivo soda_machine.sv :



soda_machine.sv
`include "soda_machine_types.sv"
import soda_machine_types::*;


module soda_machine(
	input logic clk,          // Clock 
	input logic reset,        // Active high level
	input insert_type insert,
	output logic pour_water,
	output logic change1,
	output logic change2,
	output logic change22);

	typedef enum logic [2:0] {S0, S1, S2, S3, S4} state_type;
	(* syn_encoding = "default" *) state_type state, nextstate;
	//       
	always_ff @(posedge clk, posedge reset)
	if (reset)
		state <= S0;
	else
		state <= nextstate;
	//            
	always_comb
		case (state)
			S0:
				case (insert)
					I1:
						nextstate = S1;
					I2:
						nextstate = S2;
					I5:
						nextstate = S0;
				endcase
			S1: 
				case (insert)
					I1:
						nextstate = S2;
					I2:
						nextstate = S3;
					I5:
						nextstate = S0;
				endcase
			S2:
				case (insert)
					I1:
						nextstate = S3;
					I2: 
						nextstate = S4;
					I5:
						nextstate = S0;
				endcase
			S3: 
				if (insert == I1)
					nextstate = S4;
				else
					nextstate = S0;
			S4:
				nextstate = S0;
		endcase
	//    
	assign pour_water = (state == S4) | (insert == I5) | (state == S3) & (insert == I2);
	
	assign change1 = (state == S1) & (insert == I5) | (state == S3) & (insert == I5) | (state == S4) & (insert == I2);
							
	assign change2 = (state == S2) & (insert == I5) | (state == S3) & (insert == I5);
	
	assign change22 = (state == S4) & (insert == I5);
	
endmodule




Como o estado da máquina de estado será codificado, eu deixei para o Quartus. Para indicar como a codificação deve ser feita, o atributo (* syn_encoding = "default" *) é usado , outras opções de codificação podem ser vistas aqui .



Deve-se notar que em um projeto real os sinais de saída da lógica combinacional da máquina Miles devem ser armazenados em registradores e alimentados da saída dos registradores para a saída FPGA. Os sinais de entrada devem ser sincronizados com a frequência do relógio usando sincronizadores para evitar cair em um estado metaestável.



Para adicionar arquivos ao projeto, use Arquivo -> Novo "Arquivo SystemVerilog HDL"e dê um nome apropriado ao salvar. Após adicionar esses dois arquivos, o projeto pode ser compilado com Processando -> Iniciar Compilação . Após a compilação bem-sucedida, você pode ver o esquema resultante Ferramentas -> Netlist Viewers -> RTL Viewer :



RTL Viewer
image



Para exibir o statechart da máquina de estado Ferramentas -> Visualizadores de Netlist -> Visualizador de Máquina de Estado



State Machine Viewer
image



Na guia Codificação, você pode ver que o Quartus aplicou o esquema de codificação "one-hot"; é quando um D-flip-flop separado é usado para cada estado, e o estado S 0 é codificado como 0, e não 1 como em outros estados, isso é feito para simplificar o circuito de redefinição para o inicial. Estado. Você pode perceber que o RTL Viewer não mostra exatamente um diagrama esquemático, mas um conceito. Para visualizar o diagrama esquemático, use Ferramentas -> Netlist Viewrs -> Technology Map Viewer (Pós-ajuste)



Simulação



Em princípio, no momento, temos um diagrama de uma máquina de venda automática de água com gás, mas precisamos garantir que ela funcione corretamente; para isso, escreveremos uma bancada de testes e a colocaremos no arquivo soda_machine_tb.sv :



soda_machine_tb.sv
`include "soda_machine_types.sv"
import soda_machine_types::*;

module soda_machine_tb;

	insert_type insert;
	
	logic [5:0] testvectors[10000:0];
	
	int vectornum, errors;
	
	logic clk, reset, pour_water, change1, change2, change22;
	logic pour_water_expected, change1_expected, change2_expected, change22_expected;
	//  
	soda_machine dut(
		.clk(clk),
		.reset(reset),
		.insert(insert),
		.pour_water(pour_water),
		.change1(change1),
		.change2(change2),
		.change22(change22)
	);
	//   
	always
		#5 clk = ~clk;
	//   
	initial begin
		//     
		$readmemb("../../soda_machine.tv", testvectors);
		vectornum = 0;
		errors = 0;
		clk = 1;
		//   
		reset = 1; #13; reset = 0;
	end
	//   
	always @(posedge clk) begin
		#1; {insert, pour_water_expected, change1_expected, change2_expected, change22_expected} = testvectors[vectornum];
	end
	// ,      
	always @(negedge clk)
		if (~reset) begin
			if ((pour_water !== pour_water_expected) || (change1 !== change1_expected) || (change2 !== change2_expected) ||
				(change22 !== change22_expected)) begin
				$error("%3d test insert=%b\noutputs pour_water=%b (%b expected), change1=%b (%b expected), change2=%b (%b expected), change22=%b (%b expected)", 
					vectornum + 1, insert, pour_water, pour_water_expected, change1, change1_expected, change2, change2_expected, change22, change22_expected);
				errors = errors + 1;
			end
			vectornum = vectornum + 1;
			if (testvectors[vectornum] === 6'bx) begin
				$display("Result: %3d tests completed with %3d errors", vectornum, errors);
				$stop;
			end
		end

endmodule




Para testar nosso módulo, o arquivo de vetores de teste soda_machine.tv é usado :



soda_machine.tv
01_0_0_0_0
01_0_0_0_0
01_0_0_0_0
01_0_0_0_0
01_1_0_0_0
10_0_0_0_0
10_0_0_0_0
10_1_1_0_0
11_1_0_0_0
10_0_0_0_0
10_0_0_0_0
11_1_0_0_1
10_0_0_0_0
11_1_0_1_0
01_0_0_0_0
01_0_0_0_0
01_0_0_0_0
11_1_1_1_0




Os dois primeiros bits são a entrada de inserção, os próximos 4 bits são a nossa espera pelas saídas: pour_water, change1, change2, change22. Por exemplo, no início do arquivo, uma moeda de rublo é inserida 5 vezes seguidas; na quinta moeda, esperamos o sinal de pour_water aparecer, enquanto os sinais de alteração estão inativos. O arquivo soda_machine.tv é adicionado ao projeto Arquivo -> Novo "Arquivo de Texto" .Para



a conveniência de trabalhar com o ModelSim, adicione o arquivo soda_machine_run_simulation.do com o seguinte conteúdo:



soda_machine_run_simulation.do
add wave /soda_machine_tb/dut/clk
add wave /soda_machine_tb/dut/reset
add wave /soda_machine_tb/dut/insert
add wave /soda_machine_tb/dut/state
add wave /soda_machine_tb/dut/nextstate
add wave /soda_machine_tb/dut/pour_water
add wave /soda_machine_tb/dut/change1
add wave /soda_machine_tb/dut/change2
add wave /soda_machine_tb/dut/change22
view structure
view signals
run -all
wave zoom full




Ele executará nossa simulação e exibirá as formas de onda no ModelSim. O arquivo soda_machine_run_simulation.do é adicionado ao projeto File -> New "Tcl script File"



Agora vamos configurar o projeto para que a simulação inicie automaticamente. Selecione o item de menu Atribuições -> Configurações , selecione a categoria Configurações da ferramenta EDA -> Simulação . Nas configurações do NativeLink, selecione Compilar bancada de testes: e clique no botão Bancos de teste ... na janela Bancas de teste que é aberta, clique no botão Novo ... Na janela Novas configurações da bancada de testes que é aberta, preencha o campo Nome da bancada de testes: soda_machine_tbe clique no botão de seleção de arquivo ... na parte inferior da janela, selecione nosso arquivo soda_machine_tb.sv e clique no botão Adicionar . Ele deve aparecer como na figura:



imagem



Na janela Novas Configurações do Banco de Testes , clique em OK . A janela Bancadas de teste deve ter a seguinte aparência:

imagem



Na janela Bancadas de teste , clique em OK . Nas configurações do NativeLink, defina a caixa de seleção Usar script para configurar a simulação e selecione o arquivo soda_machine_run_simulation.do . A janela Configurações

deve ficar assim:



imagem



Na janela Configurações , clique emOK , compilamos o projeto Processing -> Start Compilation , iniciamos a simulação Tools -> Run Simulation Tool -> RTL Simulation . O ModelSim deve iniciar e o projeto simulará. Aparência da guia Transcrição:



Guia Transcrição ModelSim
image



O quadro vermelho marca a saída de nossa bancada de testes sobre o número de testes realizados e os erros encontrados. Aparência da guia Wave:



Guia ModelSim Wave
image



Código fonte do projeto



O código fonte do projeto está em github.com/igoral5/soda_machine Clone o projeto e abra o projeto com Quartus File -> Open Project ...

selecione o arquivo soda_machine.qpf . Em seguida, compile o projeto Processing -> Start Compilation e inicie a simulação Tools -> Run Simulation Tool -> RTL Simulation .



All Articles