OpenCores
URL https://opencores.org/ocsvn/virtual_rs232_terminal_with_lvds_lcd/virtual_rs232_terminal_with_lvds_lcd/trunk

Subversion Repositories virtual_rs232_terminal_with_lvds_lcd

[/] [virtual_rs232_terminal_with_lvds_lcd/] [trunk/] [rtl/] [main.v] - Rev 2

Compare with Previous | Blame | View Log

`timescale 1ns / 1ps
///////////////////////////////////////////////////////////////////////////////
// Company: EnergyLabs Brasil
// Engineer: Lucas Teske
// 
// Create Date:    	16:11:50 02/04/2011 
// Design Name: 	 	LVDS LCD Virtual Terminal
// Module Name:    	main 
// Project Name:   	LVDS LCD Virtual Terminal
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Revision 0.02 - Circuito Funcionando, ainda com alguns bugs.
// Revision 0.03 - Reescrito descrições, código organizado
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////
module main(
				 input 	clk,
				 output 	[2:0] dataouta_p,
				 output 	[2:0] dataouta_n,
				 output 	clkouta1_p,
				 output 	clkouta1_n,
				 output 	led1,
				 output 	led2,
				 output 	led3,
				 output 	led4,
				 output 	TxD,
				 input 	RxD,
				 input 	PS2clk,
				 input 	PS2data
    );
 
 
//Multiplicador de Clock (DCM)
//Tenho um clock de 16MHz na entrada, periodo 62.5ns
//Multiplico ele por 4 para obter 64MHz, a tela pecisa de 60Mhz para fazer 60Hz + ou -
 
wire clo,clk4x;
DCM_SP #(
	.CLKIN_PERIOD	("62.5"),
	.CLKFX_MULTIPLY	(4)
	)
dcm_main (
	.CLKIN   	(clk),
	.CLKFB   	(clo),
	.RST     	(1'b0),
	.CLK0    	(clo),
	.CLKFX   	(clk4x)
);
defparam dcm_main.CLKIN_PERIOD = 62.5;
defparam dcm_main.CLKFX_MULTIPLY = 4;
defparam dcm_main.CLKFX_DIVIDE = 1;
 
//Parametros para o tamanho da tela
 
parameter ScreenX = 1024;
parameter ScreenY = 768;
 
//Registradores para a cor
 
reg [5:0] DataBlue = 0;
reg [5:0] DataRed = 0;
reg [5:0] DataGreen = 0;
 
//Contador de colunas e linhas
//Com esses valores você pode desenhar na tela
reg [10:0] ContadorX = 0; // Contador de colunas
reg [10:0] ContadorY = 0; // Contador de linhas
 
//Sincronia Horizontal e Vertical
//São sinais que atuam na descida, então padrão deles é 1
reg HSync = 1;
reg VSync = 1;
//Ativa a gravação de dados no LCD.
//Atente-se que o data_enable é recebido pelo LCD,
//Ele atua entre uma linha e outra ou entre uma tela e outra
reg data_enable = 1;
 
//Esse registrador é usado para fazer o fundo se mover. A cada vsync ele é incrementado.
//Somo esse registrador nos valores de R, G e B para rodar o fundo.
reg [5:0] Parallax = 0;
 
 
//Tamanho do Console Virtual e Registradores de Controle
 
//Esses registradores são usados na leitura
reg [6:0] ColunaChar = 1;
reg [5:0] LinhaChar = 1;
reg LineLock = 0;
reg CharLock = 0;
 
//Esses Registradores são usados na gravação
reg [6:0] ColunaW = 0;
reg [5:0] RefLine = 59;
reg [6:0] RefChar = 0;
 
//Definição do tamanho do console.
//Note que são apenas wires para a detecção do fim
//das colunas e linhas. Há outras alterações além 
//daqui para se aumentar o console.
 
wire MaxChars = (ColunaChar == 79);
wire MaxLines = (LinhaChar == 59);
 
//Limites do console virtual
wire OutOfBondary = ((ContadorY < 144) | (ContadorY >= 624) | (ContadorX >= 835) | (ContadorX <= 192));
 
reg [2:0] PixelChar = 7;
wire [7:0] CharByte;
wire [7:0] ActualChar;
reg Point = 0;
 
//Operadores da RAM
 
reg charwrote = 0;
reg ReadScroll = 0;
reg ReadEnable = 1;
reg [12:0] ContadorChar  = 4720; // Registrador para Gravação do caracter na RAM
reg [7:0] DataWrite;
reg WriteLocked = 0;
reg WorkLocked = 0;
reg [1:0] ScreenWork = 0;
reg CharErased = 0;
reg CharWrited = 0;
reg Scrolling = 0;
wire [17:0] LogoByte;
reg [5:0] LinhaShift = 0;
reg [5:0] LinhaRead = 0;
 
//Serial Write Data
reg WE;
wire [7:0] SerialByte;
wire SerialReady;
wire SerialIdle;
 
 
//Wires para ligar os sub-circuitos
wire [20:0] lcddata;
wire [27:0] serializerdata;
wire serial_write, TxD_busy;
wire [7:0] serial_data;
wire mod_led;
 
//Transmissor Serial
async_transmitter SerialTX(
	.clk(clk4x),
	.TxD(TxD),
	.TxD_start(serial_write),
	.TxD_data(serial_data),
	.TxD_busy(TxD_busy)
	);
 
//Receptor Serial
async_receiver SerialRX (
    .clk(clk4x), 
    .RxD(RxD), 
    .RxD_data_ready(SerialReady), 
    .RxD_data(SerialByte), 
    .RxD_idle(SerialIdle)
    );
 
//Controlador do Teclado PS2
PS2 Keyboard (
    .clk(clk4x), 
    .ps2clk(PS2clk), 
    .ps2data(PS2data), 
    .write(serial_write), 
    .dataout(serial_data),
	 .mod_led(mod_led)
    );
 
//Serializador LVDS
 
top4_tx serializador (
  	.clkint(clk4x), 
    .datain(serializerdata), 
    .rstin(1'b1), 
    .dataouta_p(dataouta_p), 
	 .dataouta_n(dataouta_n), 
    .clkouta1_p(clkouta1_p), 
    .clkouta1_n(clkouta1_n)
    );
 
 
//ROM com Logo da EnergyLabs Brasil
LogoROM LogoROM (
	.clka(clk4x),
	.ena( (((ContadorX <= 128)|(ContadorX >= (ScreenX-128))) & (ContadorY <= 128))),
	.addra({ContadorY[6:1],ContadorX[6:1]}), 
	.douta(LogoByte)); 
 
//ROM com a fonte IBM PC
fontrom  FONT_ROM (
	.clka(clk4x),
	.addra({ContadorY[2:0],ActualChar[7:0]}),
	.douta(CharByte));
 
//RAM para Buffer dos caracteres na tela
textram CharRam (
	.clka(clk4x),
	.ena(WE),
	.wea(WE), 
	.addra(ContadorChar),  
	.dina(DataWrite),  
	.clkb(clk4x),
	.enb(ReadEnable | ReadScroll),
	.addrb({(LinhaRead)*80+ColunaChar}),
	.doutb(ActualChar)); 
 
//Função da recepção de dados na Serial
always @(posedge clk4x)
begin
	//Trabalhos
	if(WorkLocked)
	begin
			case(ScreenWork)
				2'b01: //BackSpace
				begin	
						if(~CharErased)
						begin
								ContadorChar 	<= ContadorChar -1;
								if(RefChar == 0)
								begin
										RefChar 	<= 79;
										if(RefLine == 0)
											RefLine 	<= 59;
										else
											RefLine 	<= RefLine - 1;
								end
								else
										RefChar 	<= RefChar - 1;
								DataWrite 	<= 0;
								WE 			<= 1;
								WorkLocked 	<= 1;
								CharErased 	<= 1;
						end
						else
						begin
								DataWrite 	<='h00;
								WE 			<= 0;
								WorkLocked 	<= 0;
								CharErased 	<= 0;
						end
				end
				2'b10: //ClearScreen
				begin
						if(ContadorChar != 4799)
						begin
								DataWrite 	<= 'h00;
								WE 			<= 1;
								ContadorChar <= ContadorChar +1;
								if(RefChar == 79)
								begin
										RefChar 	<= 0;
										if(RefLine == 59)
											RefLine <= 0;
										else
											RefLine <= RefLine + 1;
								end
								else
										RefChar <= RefChar + 1;
						end
						else
						begin
								WE 				<= 0;
								ContadorChar 	<= 4720;
								WorkLocked 		<= 0;
								RefChar 			<= 0;
								RefLine 			<= 59;
								LinhaShift 		<= 0;
						end
				end
				2'b11: //Scroll Screen UP
				begin
						if(Scrolling == 0)
						begin
								Scrolling 		<=	1;
								WE 				<= 0;
								if(LinhaShift == 59)
									ContadorChar <= 0;
								else
									ContadorChar <= (LinhaShift+1)  * 80; // Ponto de gravação
								ReadScroll 		<= 0;
								ColunaW 			<= 0;
								if(LinhaShift == 59)
									LinhaShift 	<= 0;
								else
									LinhaShift 	<=	LinhaShift 	+	1;
						end
						else
						begin
								if(charwrote)
								begin
										//Ciclo de Posicionamento
										charwrote 	<= 0;
										WE 			<= 0;
										if(ColunaW == 79)
										begin
												Scrolling		<= 0;
												WorkLocked 		<=	0;
												RefLine 			<= 59;
												RefChar 			<= 0;
												ColunaW 			<= 0;
												ContadorChar 	<= LinhaShift * 80; // Ponto de gravação
										end
										else
										begin
												ColunaW 			<= ColunaW 	+	1;
												ContadorChar 	<= ContadorChar + 1;
										end
								end
								else
								begin
										//Ciclo de Gravação
										charwrote 	<= 1;
										DataWrite 	<= 0;
										WE 			<= 1;
								end
						end
/*						
			Aqui é a rotina antiga de shift do conteúdo da tela
			Ele reescrevia todas as linhas no endereço anterior da atual
			Muito lento, por isso refiz apenas com um registrador de deslocamento
						if(Scrolling == 0)
						begin
								Scrolling <= 1;
								LinhaW <= 1;
								ColunaW <= 0;
								ContadorChar <= 0;
								charwrote <= 0;
						end
						else
						begin	
								if(charwrote)
								begin //Ciclo de seleção
										charwrote <= 0;
										charread <= 0;
										WE <= 0;
										ReadScroll <= 1;
										if(ColunaW == 79)
										begin
												ColunaW <= 0;
												if(LinhaW == 60)
												begin
														Scrolling <= 0;
														LinhaW <= 0;
														WorkLocked <=0;
														RefLine <= 59;
														RefChar <= 0;
														ContadorChar <= 4720; // 59 * 80 = 4720
												end
												else
												begin
														ContadorChar <= LinhaW * 80;
														LinhaW <= LinhaW +1;
												end
										end
										else
										begin
												ContadorChar <= ContadorChar +2;
												ColunaW <= ColunaW + 1;
										end
								end
								else
								begin //Ciclo de Gravação
										if(charread)
										begin
												WE <= 1;
												charwrote <= 1;
												ReadScroll <= 0;
												charread <= 0;
										end
										else
										begin
												DataWrite <= ActualChar;
												charread <= 1;									
												ContadorChar <= ContadorChar -1;
										end
 
 
								end
						end
				*/
				end
			endcase
	end
	if(SerialReady & ~WriteLocked & ~WorkLocked)
	begin
			WriteLocked <= 1;
			//Checagem de BYTE recebido
			//Aqui há um pequeno problema, o Windows envia \r\n e o Linux apenas \n.
			//Não deveria dar problema, o maximo que iria acontecer é pular duas linhas.
			//Mas não funciona. Para o Windows, comente todas as linhas no Carriage Return
 
			case (SerialByte)
				'h0A: // Nova linha \n
					begin
							WorkLocked 	<= 1;
							ScreenWork 	<= 2'b11;
					end
				'h08: // BackSpace
					begin
							WorkLocked 	<= 1;
							ScreenWork 	<= 1; //BackSpace
					end
				'h09: //Horizontal Tab, acertado pra 5 espaços.
					begin
							//Não dar Tab se a linha não tiver menos do que 5 caracteres disponíveis no caso, 75 ocupados.
							if( ((RefLine * 80) - ContadorChar) < 74)
							begin
									ContadorChar 	<= ContadorChar + 5;
									RefChar 			<= RefChar + 5;									
							end
 
					end
				'h0D: // Carriage Return, retornar para  coluna 1, \r
					begin
							ContadorChar 	<= RefLine * 80; 
							RefChar 			<= 0;
					end
 
				'h0C: //Frame Feed - Apagar a tela e retornar ao caracter 0x0 da tela.
					begin
							WorkLocked 		<=1;
							ScreenWork 		<= 2; //Erase Screen
							ContadorChar 	<= 0;
					end
				default: //Caso não seja nenhum dos listados acima
				begin
						DataWrite 	<= SerialByte;
						WE 			<= 1;	
						CharWrited 	<=1;
				end
			endcase
	end
 
	if(CharWrited)
	begin
			//Caso o caractere já tenha sido gravado na RAM
			//Aqui ele posicionará o gravador um caracter 
			//adiante. Ele também irá atualizar RefLine e RefChar
			if( (ContadorChar == 4799) | (RefChar == 79) )
			begin
					WorkLocked 		<= 1;
					ScreenWork 		<= 2'b11;
					if(RefChar == 79)
					begin
						RefChar <= 0;
						if(RefLine == 59)
							RefLine <= 0;
						else
							RefLine <= RefLine + 1;
					end
			end
			else
			begin
					ContadorChar 	<= ContadorChar 	+	1;	
					RefChar 			<= RefChar 			+ 	1;				
			end
			CharWrited <= 0;
			WE <= 0;
	end
 
	if(SerialIdle)
	begin
			WriteLocked <=	0;
			if(~WorkLocked)
					WE 	<= 0;
	end	
end
 
//Ciclo de Imagem
always @(posedge clk4x)
begin
		//Como a RAM de Buffer só escreve ou lê, mas nunca os dois ao mesmo tempo,
		//Definimos aqui, que caso esteja fazendo algum trabalho, na memoria
		//O ReadEnable será 0, caso não, será o valor do data_enable
		if(WorkLocked != 1)
				ReadEnable <= data_enable;
		else
				ReadEnable <= 0;
 
		//Detectamos aqui se estamos dentro da área do console
		//Se não estamos trabalhando e apagando a tela
		if(~OutOfBondary & ~((ScreenWork == 2'b11) & (WorkLocked == 1)) )
		begin
				if((ContadorX[2:0] == 0) & ~CharLock)
				begin
						CharLock 	<= 1;
						if(MaxChars)
								ColunaChar 	<= 0;
						else
								ColunaChar 	<= ColunaChar +1;
				end
				if(ContadorX[2:0] != 0)
					CharLock 	<= 0;
 
				if(ContadorY[2:0] == 0 & ~LineLock)
				begin
						LineLock 	<= 1;
						if(MaxLines)
						begin
								LinhaChar 	<=0;
								LinhaRead 	<= LinhaShift;
						end
						else
						begin
								LinhaChar 	<= LinhaChar +1;
								if((LinhaShift+LinhaChar+1) >= 60)
									LinhaRead 	<= (LinhaShift+LinhaChar+1)-59;
								else
									LinhaRead 	<= LinhaShift+LinhaChar+1;						
						end
				end
 
				if(ContadorY[2:0] != 0)
					LineLock 	<=	0;
 
				if(ContadorX[2:0] == 2)
				begin
						PixelChar 	<= 7;
						Point 		<= CharByte[PixelChar];
				end
				else
				begin
						PixelChar 	<= PixelChar -1;
						Point 		<= CharByte[PixelChar];
				end
				if(Point)
				begin
						DataBlue 	<= 6'b111111;
						DataGreen 	<= 6'b111111;
						DataRed 		<= 6'b111111;
				end
				else
				begin
						DataRed 		<= 6'b000000;
						DataBlue 	<= 6'b000000;
						DataGreen 	<= 6'b000000;
				end
			end
			else
			begin
				if(~((ScreenWork == 2'b11) & (WorkLocked == 1)))
				begin
						if((ContadorX >= 835) | (ContadorX <= 190))
						begin
								CharLock 	<=	1;
								ColunaChar 	<= 0;
						end
						if((ContadorY < 144) | (ContadorY >= 624))
						begin
								LinhaChar 	<= 0;
								if(LinhaShift == 59)
									LinhaRead 	<= 0;
								else
									LinhaRead 	<= LinhaShift+1;
								LineLock 	<= 1;
						end
						DataBlue 	<= 0;
						DataGreen 	<= 0;
						DataRed 		<= 0;	
				end
				else
				begin
						LinhaChar 	<= 0;
						LinhaRead 	<= 0;
						ColunaChar 	<= 0;
				end
			end
 
			if(((ContadorX < 128) | (ContadorX > (ScreenX-128))) & (ContadorY < 128) & ~( ( ( (LogoByte[17:12] <= 4) | (LogoByte[5:0] <= 4) ) ) & (LogoByte[11:6] == 63)))
			begin
					DataRed 		<= LogoByte[17:12];
					DataGreen 	<= LogoByte[11:6];
					DataBlue 	<= LogoByte[5:0];
			end
			else
			begin
 
				if((ContadorY < 140) | (ContadorX > 835) | (ContadorX < 190) | (ContadorY > 623) )
				begin
						DataRed 		<= ( ( (ContadorY[5:0]+Parallax) ^ (ContadorX[5:0]+Parallax) 	) * 2	);
						DataBlue 	<= ( ( (ContadorY[5:0]+Parallax) ^ (ContadorX[5:0]+Parallax)	) * 3 );
						DataGreen 	<= ( ( (ContadorY[5:0]+Parallax) ^ (ContadorX[5:0]+Parallax)	) * 4 );
				end
				if( ( (ContadorY == 140) & (ContadorX >= 191) & (ContadorX <= 623) ) | ( (ContadorY == 623) & (ContadorX >= 191) & (ContadorX <= 623) ) | ( (ContadorX == 835) & (ContadorY >= 140) & (ContadorY <= 623) ) | ( (ContadorX == 191) & (ContadorY >= 140) & (ContadorY <= 623) ) )
				begin
						DataBlue 	<= 6'b111111;
						DataGreen 	<= 6'b111111;
						DataRed 		<= 6'b111111;		
				end
				if( (ContadorY >= 141) & (ContadorY <= 143) & (ContadorX >= 191) & (ContadorX <= 623) )
				begin
						DataBlue 	<= 6'b000000;
						DataGreen 	<= 6'b000000;
						DataRed 		<= 6'b000000;			
				end
			end
 
			//Sync Generator
 
			ContadorX <= ContadorX + 1;
 
			if((ContadorX == 0) & (ContadorY < ScreenY))
					data_enable 	<= 1;
 
			if(ContadorX == ScreenX)
			begin
					data_enable 	<= 0;
					DataBlue 		<= 0;
					DataRed 			<= 0;
					DataGreen 		<= 0;
					HSync 			<= 0;
			end
 
			if(ContadorX == (ScreenX+280))
					HSync 			<= 1;
 
			if(ContadorX == (ScreenX+300))
			begin
					if(ContadorY == ScreenY)
					begin
							VSync 		<= 0;
							data_enable <= 0;
					end
					if(ContadorY == (ScreenY+35))
					begin
							VSync 		<= 1;
							Parallax 	<= Parallax - 1;
							ContadorY 	<= 0;
							ContadorX 	<= 0;
					end
					else
							ContadorY <= ContadorY +1;
			end
 
			if(ContadorX == (ScreenX+320))
					ContadorX 	<= 0;
end
 
 
 
//Designações de pinos e leds.
assign DE 		= data_enable;
assign led1    = mod_led;
assign led2		= SerialReady;
assign led3		= ~PS2clk;
assign led4		= WorkLocked;
 
 
//Aqui fiz um pequeno jogo. O XAPP486 da Xilinx envia os dados assim:
// 			0, 	4,  	8, 	12, 	16, 	20, 	24 - Canal 0
// 			1, 	5,  	9, 	13, 	17, 	21, 	25 - Canal 1
// 			2, 	6, 	10, 	14, 	18, 	22, 	26 - Canal 2
// 			3, 	7, 	11, 	15, 	19, 	23, 	27 - Canal 3
//
//Porém, o LCD precisa deles assim:
//				6,		5,		4,		3,		2,		1,		0	- Canal 0
//				13,	12,	12,	10,	9,		8,		7	- Canal 1
//				20,	19,	18,	17,	16,	15,	14	- Canal 2
//				X,		X,		X,		X,		X,		X,		X	- Canal 3
// Nota: X <= Irrelevante
//Então fiz aqui uma associação da maneira que eu precisava.
 
assign serializerdata[0] 	= lcddata[6];  //
assign serializerdata[4] 	= lcddata[5]; 	//
assign serializerdata[8] 	= lcddata[4]; 	//
assign serializerdata[12] 	= lcddata[3];  // Canal 0 
assign serializerdata[16] 	= lcddata[2]; 	//
assign serializerdata[20] 	= lcddata[1]; 	//
assign serializerdata[24] 	= lcddata[0]; 	//
 
assign serializerdata[1] 	= lcddata[13]; //
assign serializerdata[5] 	= lcddata[12]; //
assign serializerdata[9] 	= lcddata[11]; //
assign serializerdata[13] 	= lcddata[10]; //	Canal 1
assign serializerdata[17] 	= lcddata[9];  //
assign serializerdata[21] 	= lcddata[8];  //
assign serializerdata[25] 	= lcddata[7];  //
 
assign serializerdata[2] 	= lcddata[20]; //
assign serializerdata[6] 	= lcddata[19]; //
assign serializerdata[10] 	= lcddata[18]; //
assign serializerdata[14] 	= lcddata[17]; //	Canal 3
assign serializerdata[18] 	= lcddata[16]; //
assign serializerdata[22] 	= lcddata[15]; //
assign serializerdata[26] 	= lcddata[14]; //
 
assign serializerdata[3] 	= 1'b0;			//
assign serializerdata[7] 	= 1'b0;			//
assign serializerdata[11] 	= 1'b0;			//
assign serializerdata[15] 	= 1'b0;			//	Canal 4 - Porém irrelevante
assign serializerdata[19] 	= 1'b0;			//
assign serializerdata[23] 	= 1'b0;			//
assign serializerdata[27] 	= 1'b0;			//
 
// A ordem destes bits no LCD é: Data Enable, Sincronia Vertical, Sincronia Horizontal
assign lcddata [20:18]  = { DE , VSync, HSync};
 
//A ordem de cores no LCD é: AZUL, VERDE, VERMELHO
assign lcddata [17:0] = {DataBlue, DataGreen, DataRed};
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.