mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-06 16:14:42 +00:00
118 lines
3.7 KiB
Verilog
118 lines
3.7 KiB
Verilog
// Ein einfaches System-on-a-chip (SOC)
|
|
// (c) 2015 Till Harbaum
|
|
|
|
// Einfacher VGA-Controller mit 160x100 Pixeln. Der zugrunde liegende VGA-Modus
|
|
// von 640x400 Pixel wird durch Zusammenfassung von je view Zeilen uns Spalten
|
|
// zu 160x100 Pixel "Retro-Auflösung". Das Abdunkeln jeder zweiten Zeile erzeugt
|
|
// Röhren-Fernseher-artige "Scanlines"
|
|
|
|
// http://tinyvga.com/vga-timing/640x400@70Hz
|
|
|
|
module vga (
|
|
// Pixeltakt
|
|
input pclk,
|
|
|
|
// Prozessorschnittstelle
|
|
input cpu_clk,
|
|
input cpu_wr,
|
|
input [13:0] cpu_addr,
|
|
input [7:0] cpu_data,
|
|
|
|
// Ausgang zum VGA-Bildschirm
|
|
output reg hs,
|
|
output reg vs,
|
|
output [5:0] r,
|
|
output [5:0] g,
|
|
output [5:0] b
|
|
);
|
|
|
|
// 640x400 70HZ VESA laut http://tinyvga.com/vga-timing/640x400@70Hz
|
|
parameter H = 640; // Breite des sichtbaren Bereiches
|
|
parameter HFP = 16; // Nicht nutzbarer Bereich vor H-Sync
|
|
parameter HS = 96; // Breite des H-Sync
|
|
parameter HBP = 48; // Nicht nutzbarer Bereich nach H-Sync
|
|
|
|
parameter V = 400; // Höhe des sichtbaren Bereiches
|
|
parameter VFP = 12; // Nicht nutzbarer Bereich vor V-Sync
|
|
parameter VS = 2; // Höhe des V-Sync
|
|
parameter VBP = 35; // Nicht nutzbarer Bereich nach V-Sync
|
|
|
|
reg[9:0] h_cnt; // horizontaler Pixelzaehler
|
|
reg[9:0] v_cnt; // vertikaler Pixelzaehler
|
|
|
|
// Beide Zaehler starten mit dem Beginn des sichtbaren Bildbereiches
|
|
|
|
// horizontaler Pixelzaehler
|
|
always@(posedge pclk) begin
|
|
if(h_cnt==H+HFP+HS+HBP-1) h_cnt <= 10'd0;
|
|
else h_cnt <= h_cnt + 10'd1;
|
|
|
|
// Erzeugung des negativen H-Sync-Signals
|
|
if(h_cnt == H+HFP) hs <= 1'b0;
|
|
if(h_cnt == H+HFP+HS) hs <= 1'b1;
|
|
end
|
|
|
|
// vertikaler Pixelzaehler
|
|
always@(posedge pclk) begin
|
|
// der vertikale Zustand aendert sich am Anfang jeder Zeile
|
|
if(h_cnt == H+HFP) begin
|
|
if(v_cnt==VS+VBP+V+VFP-1) v_cnt <= 10'd0;
|
|
else v_cnt <= v_cnt + 10'd1;
|
|
|
|
// Erzeugung des positiven V-Sync-Signals
|
|
if(v_cnt == V+VFP) vs <= 1'b1;
|
|
if(v_cnt == V+VFP+VS) vs <= 1'b0;
|
|
end
|
|
end
|
|
|
|
// 16000 Bytes interner Videospeicher fuer 160x100 Pixel je 8 Bit (RGB 332)
|
|
reg [7:0] vmem [160*100-1:0];
|
|
|
|
reg [13:0] video_counter;
|
|
reg [7:0] pixel;
|
|
|
|
// VRAM schreiben vis CPU-Schnittstelle
|
|
always @(posedge cpu_clk)
|
|
if(cpu_wr)
|
|
vmem[cpu_addr] <= cpu_data;
|
|
|
|
// VRAM lesen zur Bilddarstellung
|
|
always@(posedge pclk) begin
|
|
// Videozaehler wird zu Beginn des V-Sync zurueckgeetzt, ansonsten
|
|
// im sichtbaren Bereich bei jedem vierten Pixel hochgezaehlt. Am Ende
|
|
// der ersten drei von vier Zeilen wird der Zaehler wieder um eine Zeile
|
|
// zurueck gesetzt, da jeweils vier der 400 VGA-Zeilen gleich angezeigt
|
|
// werden, um auf 100 Pixelzeilen zu kommen
|
|
|
|
// sichtbarer Bildbereich?
|
|
if((v_cnt < V) && (h_cnt < H)) begin
|
|
// Videozaehler nach jedem vierten Pixel erhoehen
|
|
if(h_cnt[1:0] == 2'd3)
|
|
video_counter <= video_counter + 14'd1;
|
|
|
|
pixel <= vmem[video_counter]; // Speicherinhalt lesen
|
|
end else begin
|
|
// Zaehlermanipulation am Ende der Zeile ausserhalb
|
|
// des sichtbaren Bereiches
|
|
if(h_cnt == H+HFP) begin
|
|
// am Beginn des V-Sync Videozaehler zurueck setzen. Am Ende der
|
|
// ersten drei von vier Zeilen den Zaehler eine Zeile zurueck setzen,
|
|
// um jede Zeile insgesamt viermal auszugeben
|
|
if(v_cnt == V+VFP)
|
|
video_counter <= 14'd0;
|
|
else if((v_cnt < V) && (v_cnt[1:0] != 2'd3))
|
|
video_counter <= video_counter - 14'd160;
|
|
end
|
|
|
|
pixel <= 8'h00; // Farbe ausserhalb des sichtbaren Bereiches: schwarz
|
|
end
|
|
end
|
|
|
|
// Aufteilen der 8 RGB-Bits auf die drei Grundfarben, jede zweite Zeile abdunkeln
|
|
// fuer "Scanlines"
|
|
assign r = v_cnt[0]?{ pixel[7:5], 3'b000 }:{ 1'b0, pixel[7:5], 2'b00 };
|
|
assign g = v_cnt[0]?{ pixel[4:2], 3'b000 }:{ 1'b0, pixel[4:2], 2'b00 };
|
|
assign b = v_cnt[0]?{ pixel[1:0], 4'b0000 }:{ 1'b0, pixel[1:0], 3'b000 };
|
|
|
|
endmodule
|