Como é possível dirigir monitores VGA com frequências de clock de pixel tão altas?

12

Estou trabalhando em um circuito digital usando componentes discretos para conduzir um monitor VGA de 640x480 no modo de texto 80x30.

Para uma tela de 640x480, o clock do pixel é 25.175MHz, com um período em torno de 40ns. Eu não entendo como devo fornecer um novo pixel para a tela com tanta frequência.

A arquitetura básica para o meu circuito é a seguinte:

  1. O contador binário para pixels horizontais conta de 25,175 MHz a 800 (640 pixels visíveis + 160 para varanda frontal, sincronização, varanda traseira). Em 800, aumente o contador de linhas verticais (e redefina em 525 linhas)

  2. Usando a posição horizontal e vertical, derive as coordenadas x, y do caractere atual.

  3. Usando a coordenada x, y do caractere, indexe na memória de vídeo para recuperar o caractere ASCII.

  4. Use o caractere ASCII para indexar na ROM de caracteres para obter um padrão de bits para o caractere

  5. Use o registro de deslocamento paralelo ao serial para converter a linha de caracteres de 8 pixels em bits individuais na frequência do clock de pixels

Se você seguir a cadeia, ele será: Contador -> RAM -> ROM -> Paralelo ao registro de troca serial

Usando os componentes mais rápidos que posso encontrar, os atrasos de propagação e o tempo de acesso somam cerca de 15ns + 20ns + 70ns + 15ns = 120ns, muito maior que o período de 40ns para 25MHz.

Em resoluções e taxas de atualização ainda mais altas, você pode ter relógios de pixel bem acima de 100MHz, que serão um período de 10ns.

Como é possível fornecer novos pixels para a tela a cada 10ns, quando o tempo de acesso à RAM / ROM já está bem acima, nem mesmo considerando todos os outros sinais em seu sistema?

supershirobon
fonte
7
Você usa RAM de vídeo dedicada e o relógio diretamente em seu sinal de vídeo. Você trabalha para descobrir o que exibir muito antes de realmente exibi-lo.
Hearth
2
Leia sobre Maximite . Ele apenas usa o hardware periférico de um MCU e alguns resistores para controlar uma porta VGA. Comece examinando o periférico PIC32 que ele usa. Funciona bem. (Eu tenho um Maximite aqui.)
jonk
"The Cheap Video Cookbook" por "Don Lancaster"
Jasen

Respostas:

17

Há duas razões principais para você achar esse desafio.

Primeiro, você está usando peças mais antigas e mais discretas (integração em menor escala) do que as que seriam usadas na era do VGA.

Mas a seguir, você os está usando de maneira atípica. Especificamente, sua abordagem não é o pipelinedque significa que você precisa adicionar vários atrasos ao determinar seu intervalo e, portanto, avaliar.

Por outro lado, projetos digitais síncronos que tentam atingir velocidade tentam fazer o mínimo possível entre os registros.

Enquanto os detalhes provavelmente diferem um pouco, falando mal, seria algo parecido com isto:

  • Você incrementa ou redefine o endereço e entra em um registro.
  • Você trava o endereço na memória síncrona
  • Você trava a saída da memória síncrona
  • Você trava isso no endereço do gerador de caracteres síncronos
  • Você trava a saída do gerador de caracteres no registro de saída
  • aplique a pesquisa da paleta ...
  • no DAC síncrono ...

Quando você divide uma tarefa dessa maneira, você obtém apenas um atraso combinatório mais algum atraso de propagação e registra os tempos de configuração e espera que precisam caber entre os relógios.

Um design criado dessa maneira levará muitos relógios para produzir uma saída - a latência será realmente maior do que um design puramente combinatório. Mas produz uma nova saída correta em cada ciclo de um relógio muito mais rápido.

E ei, é um vídeo, não importa realmente se o CRT está desenhando uma dúzia de pixels atrás do contador de pixels - é claro que você leva isso em consideração no tempo dos sinais de sincronização para que eles estejam corretos quando comparados com os dados realmente sai do DAC.

Na prática, quase todos os sistemas digitais complexos funcionam dessa maneira, como é uma ótima idéia - até que uma CPU em pipeline atinja uma dependência de um resultado computacional anterior ou de uma ramificação condicional ... Então as coisas ficam interessantes, como eles falavam sobre na próxima aula de uma aula de sistemas digitais - mas felizmente sua situação de VGA é muito mais simples, especialmente se você ainda não se preocupa com os efeitos de lacrimejamento, se o buffer de caracteres mudar enquanto a tela está sendo desenhada.

Por uma questão prática, se você deseja criar isso, faça-o em um FPGA. Isso forçará as memórias síncronas se você usar as internas, ou os registros síncronos de E / S se você usar memória externa. Você terá muitos estímulos para um design adequado, o tecido em si será mais rápido do que suas peças discretas e, é claro, se você cometer um erro, precisará apenas mexer os polegares enquanto recompila, em vez de passar um longo dia re-conectando .

Chris Stratton
fonte
"especialmente se você ainda não se preocupa com os efeitos de lacrimejamento, se o buffer de caracteres mudar enquanto a tela está sendo desenhada" - é por isso que desde os primeiros dias dos coprocessadores de vídeo, os coprocessadores tinham uma maneira de informar ao processo principal que eles não eram atualmente despejando sua memória na tela e, se quiserem alterar o buffer de vídeo, devem fazê-lo agora.
John Dvorak
Eu acho que você está complicando demais isso. Ele já afirmou que está usando um registrador de deslocamento de 8 bits que gera um bit por pixel de clock. Presumivelmente, este é um registro de deslocamento de 8 bits com trava. Isso significa que ele só precisa buscar um novo byte uma vez a cada relógio de 8 pixels, por isso uma taxa de 3,125 MHz. Isso dá a você 320ns para obter os dados na trava do registro de turnos, que é muito maior do que os 120ns que ele disse que seriam necessários.
Chris_F
Para um caso monocromático de baixa resolução muito simples, sim, o tempo dos bytes não seria muito desafiador, mas uma parte importante da questão era que o solicitante estava tentando entender como o desempenho de sistemas "reais" típicos de resolução não trivial é possível. E a resposta é a mesma que todos os outros sistemas digitais úteis: tecnologia mais rápida e design síncrono em pipeline.
22419 Chris Stratton
2

Usando os componentes mais rápidos que posso encontrar, os atrasos de propagação e o tempo de acesso somam cerca de 15ns + 20ns + 70ns + 15ns = 120ns, muito maior que o período de 40ns para 25MHz.

Você esquece que um adaptador gráfico nunca desenharia apenas um único pixel - mas pelo menos uma linha de varredura completa. Assim, este seria um problema completamente pipeleable.

Além disso, não esqueça que há cinco décadas produzindo hardware de vídeo até agora. Seu problema geralmente seria resolvido com um tipo especial de RAM, no qual você renderiza suas cartas em uma porta e é sequencialmente lido em um DAC de sinal de vídeo. Esse hardware é muito, muito mais rápido do que você está vendo.

A arquitetura básica para o meu circuito é a seguinte:

  1. O contador binário para pixels horizontais conta de 25,175 MHz a 800 (640 pixels visíveis + 160 para varanda frontal, sincronização, varanda traseira). Em 800, aumente o contador de linhas verticais (e redefina em 525 linhas)

  2. Usando a posição horizontal e vertical, derive as coordenadas x, y do caractere atual.

Não, por que você faria isso? Você simplesmente colocaria o pixel da linha em uma área contígua da memória e o distribuiria linearmente para o seu DAC - se for uma implementação de CPU / MCU, você nem deixaria sua CPU fazer isso, mas uma unidade de DMA programada fazer nada além de pegar um valor após o outro e colocá-lo em uma porta de dados paralela, sem nenhuma interação do núcleo da CPU.

  1. Usando a coordenada x, y do caractere, indexe na memória de vídeo para recuperar o caractere ASCII.

Ah, você quer renderizar rapidamente - boa escolha, mas incomum a custos modernos de RAM. Em vez disso, basta renderizar o personagem em um buffer de quadro antecipadamente, ou se seu dispositivo for extremamente fino, canalize diretamente (veja minha explicação do DMA acima) a linha de caracteres para o DAC.

Marcus Müller
fonte
1
Enquanto coisas modernas tendem a preferir buffers pré-renderizados, eles são obviamente uma péssima escolha se você está tentando trabalhar sem muito esforço. Se você estiver fazendo isso em um FPGA, poderá fazer com que a máquina de estado do DMA pegue os endereços do mapa da célula de caracteres e depois leia os glifos de caracteres correspondentes.
R .. GitHub Pare de ajudar o gelo
concordo plenamente aqui! portanto, minha seção de resposta na terceira pergunta.
Marcus Müller
2

Além do pipelining (que é muito o que você deve fazer), você está perdendo algo importante ...

O registro de deslocamento de entrada paralela e saída serial apresenta pontos de 25 Mhz, com certeza, mas se os seus caracteres tiverem 8 pixels de largura, sua entrada será de apenas ~ 3,2 MHz, que é facilmente acessível para a série LS da era VGA, por tudo isso você precisa ter o próximo byte pronto quando o registro de turno terminar com o atual (é aqui que o pipeline entra).

Gere um clock de pixel a ~ 25MHz e um clock de memória a 1/8 para acionar o buffer de texto e a CG ROM e, em seguida, canalize esse acesso à memória e à CG ROM.

Um truque adicional, a saída do buffer de texto será repetida para cada linha em qualquer linha de texto, portanto, talvez você possa registrar os 80 bytes de texto em um buffer de anel e parar de ler o ram nas próximas 7 linhas (assumindo um número 8). caractere de linha), isso permite liberar a memória para a CPU usar, ao custo de precisar de 80 bytes de memória RAM pendurados na lateral da coisa.

Dan Mills
fonte
1

Então, obviamente, isso não funciona; você precisa de um pipeline.

1) Armazene os caracteres contiguamente na memória. Comece no canto superior esquerdo.

2) Busque um personagem durante o intervalo de apagamento. Continue buscando caracteres em ordem de memória.

3) Pipeline cada caractere decodificado mais o índice de linha na ROM.

4) Pipeline a saída da ROM para um buffer.

5) Faça o pipeline do buffer para um registro de turno. Leia os pixels continuamente em intervalos de 40ns.

(Isso implica que você precisa carregar um novo caractere no registrador de turnos a cada 320ns, o que pode ser possível sem a canalização de todo o resto do sistema.)

6) Durante o apagamento horizontal, retorne ao início da linha ou avance para o próximo caractere (ou seja, início da próxima linha).

Recurso de bônus: como você só precisa de um caractere a cada 320ns, você também pode ler um par de caracteres + cor e executar caracteres coloridos no estilo MSDOS ou Spectrum.

pjc50
fonte