]> git.ozlabs.org Git - minimigmac.git/blob - fpga/video.v
Initial commit
[minimigmac.git] / fpga / video.v
1 module video(input              pixclk,
2              input              reset,
3              input [15:0]       pixels,
4              output reg         req_pix,
5              input              ack_pix,
6              output             _hsync,
7              output             _vsync,
8              output [3:0]       red,
9              output [3:0]       green,
10              output [3:0]       blue,
11              output             hblank);
12
13         /* Max coordinate size in bits - 1 */
14         parameter csize = 9;
15
16         /* Fixed CRTC params for now. Based on a 640x480 VGA signal with
17          * added borders to center the Mac's 512x342.
18          * 
19          * The added border is 64 pixels left and right and 69 pixels top
20          * and bottom.
21          * 
22          * The constants are used as count-down and thus include a -1 to
23          * account for the 0 state.
24          */
25         parameter hdisp_frontp          =   8 - 1;
26         parameter hdisp_hsync           =  96 - 1;
27         parameter hdisp_backp           =  40 - 1;
28         parameter hdisp_lbord           =   8 + 64 - 1;
29         parameter hdisp_display         = 512 - 1;
30         parameter hdisp_rbord           =   8 + 64 - 1;
31
32         parameter vdisp_frontp          =   2 - 1;
33         parameter vdisp_vsync           =   2 - 1;
34         parameter vdisp_backp           =  25 - 1;
35         parameter vdisp_tbord           =   8 + 69 - 1;
36         parameter vdisp_display         = 342 - 1;
37         parameter vdisp_bbord           =   8 + 69 - 1;
38
39         /* Corresponding stages */
40         localparam hstage_frontp        = 0;
41         localparam hstage_hsync         = 1;
42         localparam hstage_backp         = 2;
43         localparam hstage_lbord         = 3;
44         localparam hstage_display       = 4;
45         localparam hstage_rbord         = 5;
46
47         localparam vstage_frontp        = 0;
48         localparam vstage_vsync         = 1;
49         localparam vstage_backp         = 2;
50         localparam vstage_tbord         = 3;
51         localparam vstage_display       = 4;
52         localparam vstage_bbord         = 5;
53
54         /* Running h/v counters */
55         reg [csize:0]           hcnt;
56         reg [csize:0]           vcnt;
57         reg [csize:0]           hnextcnt;
58         reg [csize:0]           vnextcnt;
59
60         /* State machines */
61         reg [2:0]               hstage;
62         reg [2:0]               vstage;
63
64         /* Output latches */
65         reg                     _hsync_r;
66         reg                     _vsync_r;
67         reg                     pix_r;
68
69         /* Pixel shift reg */
70         reg [15:0]              pix_shift;
71         wire                    vid_on;
72
73         /* Request/ack protocol helpers */
74         wire                    pix_req_reset;  
75
76         /* Obtain the new count for the next stage */
77         always@(hstage) begin
78                 case(hstage)
79                         hstage_frontp:  hnextcnt = hdisp_hsync;
80                         hstage_hsync:   hnextcnt = hdisp_backp;
81                         hstage_backp:   hnextcnt = hdisp_lbord;
82                         hstage_lbord:   hnextcnt = hdisp_display;       
83                         hstage_display: hnextcnt = hdisp_rbord;
84                         hstage_rbord:   hnextcnt = hdisp_frontp;
85                         default:        hnextcnt = hdisp_frontp;
86                 endcase
87         end
88         always@(vstage) begin
89                 case(vstage)
90                         vstage_frontp:  vnextcnt = vdisp_vsync;
91                         vstage_vsync:   vnextcnt = vdisp_backp;
92                         vstage_backp:   vnextcnt = vdisp_tbord;
93                         vstage_tbord:   vnextcnt = vdisp_display;       
94                         vstage_display: vnextcnt = vdisp_bbord;
95                         vstage_bbord:   vnextcnt = vdisp_frontp;
96                         default:        vnextcnt = vdisp_frontp;
97                 endcase
98         end
99
100         /* H counter */
101         always@(posedge pixclk or posedge reset) begin
102                 if (reset) begin
103                         hcnt <= 0;
104                         hstage <= hstage_frontp;                        
105                 end else begin
106                         if (hcnt == 0) begin
107                                 hcnt <= hnextcnt;
108                                 if (hstage == hstage_rbord)
109                                   hstage <= hstage_frontp;
110                                 else
111                                   hstage <= hstage + 1;
112                         end else
113                           hcnt <= hcnt - 1;
114                 end
115         end
116         
117         /* V counter */
118         always@(posedge pixclk or posedge reset) begin
119                 if (reset) begin
120                         vcnt <= 0;
121                         vstage <= vstage_frontp;                        
122                 end else begin
123                         if (hstage == hstage_rbord && hcnt == 0) begin
124                                 if (vcnt == 0) begin
125                                         vcnt <= vnextcnt;
126                                         if (vstage == vstage_bbord)
127                                           vstage <= vstage_frontp;
128                                         else
129                                           vstage <= vstage + 1;
130                                 end else begin
131                                         vcnt <= vcnt - 1;
132                                 end
133                         end                     
134                 end
135         end
136
137         /* Visible signal */
138         assign vid_on = hstage == hstage_display &&
139                         vstage == vstage_display;       
140
141         /* Pixel request, async clear */
142         assign pix_req_reset = reset | ack_pix;
143
144         /* Generate pixel request. NOTE: This relies on the display
145          * width being a multiple of 16
146          */
147         always@(posedge pixclk or posedge pix_req_reset) begin
148                 if (pix_req_reset) begin
149                         req_pix <= 0;
150                 end else begin
151                         if (vstage == vstage_display) begin
152                                 if (hstage == hstage_backp && hcnt == 0) begin
153                                         req_pix <= 1;
154                                 end else if (hstage == hstage_display &&
155                                          hcnt[3:0] == 4'b1111 &&
156                                              hcnt[csize:4]) begin
157                                         req_pix <= 1;
158                                 end
159                         end
160                         
161                 end
162         end     
163
164         /* Shift register */
165         always@(posedge pixclk or posedge reset) begin
166                 if (reset) begin
167                         pix_shift <= 0;
168                 end else begin
169                         if (hcnt[3:0] == 0)
170                           pix_shift <= pixels;
171                         else
172                           pix_shift[15:1] <= pix_shift[14:0];                   
173                 end
174         end
175
176         /* Output latches */    
177         always@(posedge pixclk or posedge reset) begin
178                 if (reset) begin
179                         _hsync_r <= 1;
180                         _vsync_r <= 1;
181                         pix_r <= 0;
182                 end else begin
183                         _hsync_r <= ~(hstage == hstage_hsync);                  
184                         _vsync_r <= ~(vstage == vstage_vsync);
185                         pix_r <= vid_on & ~pix_shift[15];                       
186                 end
187         end
188
189         /* Output wires */
190         assign _hsync = _hsync_r;
191         assign _vsync = _vsync_r;
192         assign red = { pix_r, pix_r, pix_r, pix_r };
193         assign green = { pix_r, pix_r, pix_r, pix_r };
194         assign blue = { pix_r, pix_r, pix_r, pix_r };
195         assign hblank = hstage != hstage_display;
196 endmodule