| 1 |
215 |
creep |
////////////////////////////////////////////////////////////////////////////
|
| 2 |
|
|
//// ////
|
| 3 |
|
|
//// t2600 IP Core ////
|
| 4 |
|
|
//// ////
|
| 5 |
|
|
//// This file is part of the t2600 project ////
|
| 6 |
|
|
//// http://www.opencores.org/cores/t2600/ ////
|
| 7 |
|
|
//// ////
|
| 8 |
|
|
//// Description ////
|
| 9 |
|
|
//// Video module ////
|
| 10 |
|
|
//// ////
|
| 11 |
|
|
//// TODO: ////
|
| 12 |
|
|
//// - Everything? ////
|
| 13 |
|
|
//// ////
|
| 14 |
|
|
//// Author(s): ////
|
| 15 |
|
|
//// - Gabriel Oshiro Zardo, gabrieloshiro@gmail.com ////
|
| 16 |
|
|
//// - Samuel Nascimento Pagliarini (creep), snpagliarini@gmail.com ////
|
| 17 |
|
|
//// ////
|
| 18 |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 19 |
|
|
//// ////
|
| 20 |
|
|
//// Copyright (C) 2001 Authors and OPENCORES.ORG ////
|
| 21 |
|
|
//// ////
|
| 22 |
|
|
//// This source file may be used and distributed without ////
|
| 23 |
|
|
//// restriction provided that this copyright statement is not ////
|
| 24 |
|
|
//// removed from the file and that any derivative work contains ////
|
| 25 |
|
|
//// the original copyright notice and the associated disclaimer. ////
|
| 26 |
|
|
//// ////
|
| 27 |
|
|
//// This source file is free software; you can redistribute it ////
|
| 28 |
|
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
| 29 |
|
|
//// Public License as published by the Free Software Foundation; ////
|
| 30 |
|
|
//// either version 2.1 of the License, or (at your option) any ////
|
| 31 |
|
|
//// later version. ////
|
| 32 |
|
|
//// ////
|
| 33 |
|
|
//// This source is distributed in the hope that it will be ////
|
| 34 |
|
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
| 35 |
|
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
| 36 |
|
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
| 37 |
|
|
//// details. ////
|
| 38 |
|
|
//// ////
|
| 39 |
|
|
//// You should have received a copy of the GNU Lesser General ////
|
| 40 |
|
|
//// Public License along with this source; if not, download it ////
|
| 41 |
|
|
//// from http://www.opencores.org/lgpl.shtml ////
|
| 42 |
|
|
//// ////
|
| 43 |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 44 |
|
|
|
| 45 |
|
|
`include "timescale.v"
|
| 46 |
|
|
|
| 47 |
222 |
creep |
module video(clk, reset_n, io_lines, enable, mem_rw, address, data, pixel);
|
| 48 |
215 |
creep |
parameter [3:0] DATA_SIZE = 4'd8;
|
| 49 |
|
|
parameter [3:0] ADDR_SIZE = 4'd10; // this is the *local* addr_size
|
| 50 |
|
|
|
| 51 |
|
|
localparam [3:0] DATA_SIZE_ = DATA_SIZE - 4'd1;
|
| 52 |
|
|
localparam [3:0] ADDR_SIZE_ = ADDR_SIZE - 4'd1;
|
| 53 |
|
|
|
| 54 |
|
|
input clk; // master clock signal, 1.19mhz
|
| 55 |
|
|
input reset_n;
|
| 56 |
|
|
input [15:0] io_lines; // inputs from the keyboard controller
|
| 57 |
|
|
input enable; // since the address bus is shared an enable signal is used
|
| 58 |
|
|
input mem_rw; // read == 0, write == 1
|
| 59 |
|
|
input [ADDR_SIZE_:0] address; // system address bus
|
| 60 |
|
|
inout [DATA_SIZE_:0] data; // controler <=> riot data bus
|
| 61 |
222 |
creep |
output [11:0] pixel;
|
| 62 |
215 |
creep |
|
| 63 |
|
|
reg [DATA_SIZE_:0] data_drv; // wrapper for the data bus
|
| 64 |
|
|
|
| 65 |
|
|
assign data = (mem_rw || !reset_n) ? 8'bZ : data_drv; // if under writing the bus receives the data from cpu, else local data.
|
| 66 |
|
|
|
| 67 |
|
|
reg VSYNC; // vertical sync set-clear
|
| 68 |
216 |
creep |
reg [2:0] VBLANK; // vertical blank set-clear
|
| 69 |
222 |
creep |
reg WSYNC; // SEMI-strobe wait for leading edge of horizontal blank
|
| 70 |
215 |
creep |
reg RSYNC; // s t r o b e reset horizontal sync counter
|
| 71 |
216 |
creep |
reg [5:0] NUSIZ0; // number-size player-missile 0
|
| 72 |
|
|
reg [5:0] NUSIZ1; // number-size player-missile 1
|
| 73 |
|
|
reg [6:0] COLUP0; // color-lum player 0
|
| 74 |
|
|
reg [6:0] COLUP1; // color-lum player 1
|
| 75 |
|
|
reg [6:0] COLUPF; // color-lum playfield
|
| 76 |
|
|
reg [6:0] COLUBK; // color-lum background
|
| 77 |
|
|
reg [4:0] CTRLPF; // control playfield ball size & collisions
|
| 78 |
221 |
creep |
// D0 = REF (reflect playfield)
|
| 79 |
|
|
// D1 = SCORE (left half of playfield gets color of player 0, right half gets color of player 1)
|
| 80 |
|
|
// D2 = PFP (playfield gets priority over players so they can move behind the playfield)
|
| 81 |
|
|
// D4 & D5 = BALL SIZE
|
| 82 |
216 |
creep |
reg REFP0; // reflect player 0
|
| 83 |
|
|
reg REFP1; // reflect player 1
|
| 84 |
|
|
reg [3:0] PF0; // playfield register byte 0
|
| 85 |
|
|
reg [7:0] PF1; // playfield register byte 1
|
| 86 |
|
|
reg [7:0] PF2; // playfield register byte 2
|
| 87 |
215 |
creep |
reg RESP0; // s t r o b e reset player 0
|
| 88 |
|
|
reg RESP1; // s t r o b e reset player 1
|
| 89 |
|
|
reg RESM0; // s t r o b e reset missile 0
|
| 90 |
|
|
reg RESM1; // s t r o b e reset missile 1
|
| 91 |
|
|
reg RESBL; // s t r o b e reset ball
|
| 92 |
216 |
creep |
reg [3:0] AUDC0; // audio control 0
|
| 93 |
|
|
reg [4:0] AUDC1; // audio control 1
|
| 94 |
|
|
reg [4:0] AUDF0; // audio frequency 0
|
| 95 |
|
|
reg [3:0] AUDF1; // audio frequency 1
|
| 96 |
|
|
reg [3:0] AUDV0; // audio volume 0
|
| 97 |
|
|
reg [3:0] AUDV1; // audio volume 1
|
| 98 |
|
|
reg [7:0] GRP0; // graphics player 0
|
| 99 |
|
|
reg [7:0] GRP1; // graphics player 1
|
| 100 |
|
|
reg ENAM0; // graphics (enable) missile 0
|
| 101 |
|
|
reg ENAM1; // graphics (enable) missile 1
|
| 102 |
|
|
reg ENABL; // graphics (enable) ball
|
| 103 |
|
|
reg [3:0] HMP0; // horizontal motion player 0
|
| 104 |
|
|
reg [3:0] HMP1; // horizontal motion player 1
|
| 105 |
|
|
reg [3:0] HMM0; // horizontal motion missile 0
|
| 106 |
|
|
reg [3:0] HMM1; // horizontal motion missile 1
|
| 107 |
|
|
reg [3:0] HMBL; // horizontal motion ball
|
| 108 |
|
|
reg VDELP0; // vertical delay player 0
|
| 109 |
|
|
reg VDEL01; // vertical delay player 1
|
| 110 |
|
|
reg VDELBL; // vertical delay ball
|
| 111 |
|
|
reg RESMP0; // reset missile 0 to player 0
|
| 112 |
|
|
reg RESMP1; // reset missile 1 to player 1
|
| 113 |
215 |
creep |
reg HMOVE; // s t r o b e apply horizontal motion
|
| 114 |
|
|
reg HMCLR; // s t r o b e clear horizontal motion registers
|
| 115 |
|
|
|
| 116 |
216 |
creep |
reg [1:0] CXM0P; // read collision MO P1 M0 P0
|
| 117 |
|
|
reg [1:0] CXM1P; // read collision M1 P0 M1 P1
|
| 118 |
|
|
reg [1:0] CXP0FB; // read collision P0 PF P0 BL
|
| 119 |
|
|
reg [1:0] CXP1FB; // read collision P1 PF P1 BL
|
| 120 |
|
|
reg [1:0] CXM0FB; // read collision M0 PF M0 BL
|
| 121 |
|
|
reg [1:0] CXM1FB; // read collision M1 PF M1 BL
|
| 122 |
|
|
reg CXBLPF; // read collision BL PF unused
|
| 123 |
|
|
reg [1:0] CXPPMM; // read collision P0 P1 M0 M1
|
| 124 |
|
|
reg INPT0; // read pot port
|
| 125 |
|
|
reg INPT1; // read pot port
|
| 126 |
|
|
reg INPT2; // read pot port
|
| 127 |
|
|
reg INPT3; // read pot port
|
| 128 |
|
|
reg INPT4; // read input
|
| 129 |
222 |
creep |
reg INPT5; // read input
|
| 130 |
216 |
creep |
|
| 131 |
222 |
creep |
reg [5:0] hor_counter; // this counter is the "current pixel". when it reaches 39 the wsync register must be driven to zero
|
| 132 |
|
|
|
| 133 |
216 |
creep |
always @(posedge clk or negedge reset_n) begin
|
| 134 |
215 |
creep |
if (reset_n == 1'b0) begin
|
| 135 |
222 |
creep |
hor_counter <= 6'd0;
|
| 136 |
|
|
end
|
| 137 |
|
|
else begin
|
| 138 |
|
|
if (hor_counter == 6'd39) begin
|
| 139 |
|
|
hor_counter <= 6'd0;
|
| 140 |
|
|
WSYNC <= 1'b0;
|
| 141 |
|
|
end
|
| 142 |
|
|
else begin
|
| 143 |
|
|
hor_counter <= hor_counter + 6'd1;
|
| 144 |
|
|
end
|
| 145 |
|
|
end
|
| 146 |
|
|
end
|
| 147 |
|
|
|
| 148 |
|
|
always @(posedge clk or negedge reset_n) begin
|
| 149 |
|
|
if (reset_n == 1'b0) begin
|
| 150 |
215 |
creep |
data_drv <= 8'h00;
|
| 151 |
222 |
creep |
WSYNC <= 1'b0;
|
| 152 |
215 |
creep |
end
|
| 153 |
|
|
else begin
|
| 154 |
216 |
creep |
if (mem_rw == 1'b0) begin // reading!
|
| 155 |
215 |
creep |
case (address)
|
| 156 |
216 |
creep |
6'h00: data_drv <= {CXM0P, 6'b000000};
|
| 157 |
|
|
6'h01: data_drv <= {CXM1P, 6'b000000};
|
| 158 |
|
|
6'h02: data_drv <= {CXP0FB, 6'b000000};
|
| 159 |
|
|
6'h03: data_drv <= {CXP1FB, 6'b000000};
|
| 160 |
|
|
6'h04: data_drv <= {CXM0FB, 6'b000000};
|
| 161 |
|
|
6'h05: data_drv <= {CXM1FB, 6'b000000};
|
| 162 |
|
|
6'h06: data_drv <= {CXBLPF, 7'b000000};
|
| 163 |
|
|
6'h07: data_drv <= {CXPPMM, 6'b000000};
|
| 164 |
|
|
6'h08: data_drv <= {INPT0, 7'b000000};
|
| 165 |
|
|
6'h09: data_drv <= {INPT1, 7'b000000};
|
| 166 |
|
|
6'h0A: data_drv <= {INPT2, 7'b000000};
|
| 167 |
|
|
6'h0B: data_drv <= {INPT3, 7'b000000};
|
| 168 |
|
|
6'h0C: data_drv <= {INPT4, 7'b000000};
|
| 169 |
|
|
6'h0D: data_drv <= {INPT5, 7'b000000};
|
| 170 |
|
|
default: ;
|
| 171 |
215 |
creep |
endcase
|
| 172 |
|
|
end
|
| 173 |
216 |
creep |
else begin // writing!
|
| 174 |
215 |
creep |
case (address)
|
| 175 |
216 |
creep |
6'h00: begin
|
| 176 |
217 |
creep |
VSYNC <= data[1];
|
| 177 |
215 |
creep |
end
|
| 178 |
216 |
creep |
6'h01: begin
|
| 179 |
217 |
creep |
VBLANK <= {data[7:6], data[1]};
|
| 180 |
215 |
creep |
end
|
| 181 |
216 |
creep |
6'h02: begin
|
| 182 |
217 |
creep |
WSYNC <= 1'b1; // STROBE
|
| 183 |
215 |
creep |
end
|
| 184 |
216 |
creep |
6'h03: begin
|
| 185 |
217 |
creep |
RSYNC <= 1'b1; // STROBE
|
| 186 |
215 |
creep |
end
|
| 187 |
216 |
creep |
6'h04: begin
|
| 188 |
217 |
creep |
NUSIZ0 <= data[5:0];
|
| 189 |
216 |
creep |
end
|
| 190 |
|
|
6'h05: begin
|
| 191 |
217 |
creep |
NUSIZ1 <= data[5:0];
|
| 192 |
216 |
creep |
end
|
| 193 |
|
|
6'h06: begin
|
| 194 |
217 |
creep |
COLUP0 <= data[7:1];
|
| 195 |
216 |
creep |
end
|
| 196 |
|
|
6'h07: begin
|
| 197 |
217 |
creep |
COLUP1 <= data[7:1];
|
| 198 |
216 |
creep |
end
|
| 199 |
|
|
6'h08: begin
|
| 200 |
217 |
creep |
COLUPF <= data[7:1];
|
| 201 |
216 |
creep |
end
|
| 202 |
|
|
6'h09: begin
|
| 203 |
217 |
creep |
COLUBK <= data[7:1];
|
| 204 |
216 |
creep |
end
|
| 205 |
|
|
6'h0a: begin
|
| 206 |
217 |
creep |
CTRLPF <= {data[5:4], data[2:0]};
|
| 207 |
216 |
creep |
end
|
| 208 |
|
|
6'h0b: begin
|
| 209 |
217 |
creep |
REFP0 <= data[3];
|
| 210 |
216 |
creep |
end
|
| 211 |
|
|
6'h0c: begin
|
| 212 |
217 |
creep |
REFP1 <= data[3];
|
| 213 |
216 |
creep |
end
|
| 214 |
217 |
creep |
6'h0d: begin
|
| 215 |
|
|
PF0 <= data[7:4 ];
|
| 216 |
|
|
end
|
| 217 |
|
|
6'h0e: begin
|
| 218 |
|
|
PF1 <= data;
|
| 219 |
|
|
end
|
| 220 |
|
|
6'h0f: begin
|
| 221 |
|
|
PF2 <= data;
|
| 222 |
|
|
end
|
| 223 |
|
|
6'h10: begin
|
| 224 |
|
|
RESP0 <= 1'b1; // STROBE
|
| 225 |
|
|
end
|
| 226 |
|
|
6'h11: begin
|
| 227 |
|
|
RESP1 <= 1'b1; // STROBE
|
| 228 |
|
|
end
|
| 229 |
|
|
6'h12: begin
|
| 230 |
|
|
RESM0 <= 1'b1; // STROBE
|
| 231 |
|
|
end
|
| 232 |
|
|
6'h13: begin
|
| 233 |
|
|
RESM1 <= 1'b1; // STROBE
|
| 234 |
|
|
end
|
| 235 |
|
|
6'h14: begin
|
| 236 |
|
|
RESBL <= 1'b1; // STROBE
|
| 237 |
|
|
end
|
| 238 |
|
|
6'h15: begin
|
| 239 |
|
|
AUDC0 <= data[3:0];
|
| 240 |
|
|
end
|
| 241 |
|
|
6'h16: begin
|
| 242 |
|
|
AUDC1 <= data[4:0];
|
| 243 |
|
|
end
|
| 244 |
|
|
6'h17: begin
|
| 245 |
|
|
AUDF0 <= data[4:0];
|
| 246 |
|
|
end
|
| 247 |
|
|
6'h18: begin
|
| 248 |
|
|
AUDF1 <= data[3:0];
|
| 249 |
|
|
end
|
| 250 |
|
|
6'h19: begin
|
| 251 |
|
|
AUDV0 <= data[3:0];
|
| 252 |
|
|
end
|
| 253 |
|
|
6'h1A: begin
|
| 254 |
|
|
AUDV1 <= data[3:0];
|
| 255 |
|
|
end
|
| 256 |
|
|
6'h1B: begin
|
| 257 |
|
|
GRP0 <= data;
|
| 258 |
|
|
end
|
| 259 |
|
|
6'h1C: begin
|
| 260 |
|
|
GRP1 <= data;
|
| 261 |
|
|
end
|
| 262 |
|
|
6'h1D: begin
|
| 263 |
|
|
ENAM0 <= data[1];
|
| 264 |
|
|
end
|
| 265 |
|
|
6'h1E: begin
|
| 266 |
|
|
ENAM1 <= data[1];
|
| 267 |
|
|
end
|
| 268 |
|
|
6'h1F: begin
|
| 269 |
|
|
ENABL <= data[1];
|
| 270 |
|
|
end
|
| 271 |
|
|
6'h20: begin
|
| 272 |
|
|
HMP0 <= data[7:4];
|
| 273 |
|
|
end
|
| 274 |
|
|
6'h21: begin
|
| 275 |
|
|
HMP1 <= data[7:4];
|
| 276 |
|
|
end
|
| 277 |
|
|
6'h22: begin
|
| 278 |
|
|
HMM0 <= data[7:4];
|
| 279 |
|
|
end
|
| 280 |
|
|
6'h23: begin
|
| 281 |
|
|
HMM1 <= data[7:4];
|
| 282 |
|
|
end
|
| 283 |
|
|
6'h24: begin
|
| 284 |
|
|
HMBL <= data[7:4];
|
| 285 |
|
|
end
|
| 286 |
|
|
6'h25: begin
|
| 287 |
|
|
VDELP0 <= data[0];
|
| 288 |
|
|
end
|
| 289 |
|
|
6'h26: begin
|
| 290 |
|
|
VDEL01 <= data[0];
|
| 291 |
|
|
end
|
| 292 |
|
|
6'h27: begin
|
| 293 |
|
|
VDELBL <= data[0];
|
| 294 |
|
|
end
|
| 295 |
|
|
6'h28: begin
|
| 296 |
|
|
RESMP0 <= data[1];
|
| 297 |
|
|
end
|
| 298 |
|
|
6'h29: begin
|
| 299 |
|
|
RESMP1 <= data[1];
|
| 300 |
|
|
end
|
| 301 |
|
|
6'h2a: begin
|
| 302 |
|
|
HMOVE <= 1'b1; // STROBE
|
| 303 |
|
|
end
|
| 304 |
|
|
6'h2b: begin
|
| 305 |
|
|
HMCLR <= 1'b1; // STROBE
|
| 306 |
|
|
end
|
| 307 |
221 |
creep |
6'h2c: begin // cxclr STROBE
|
| 308 |
|
|
CXM0P <= 2'b0; // read collision MO P1 M0 P0
|
| 309 |
|
|
CXM1P <= 2'b0; // read collision M1 P0 M1 P1
|
| 310 |
|
|
CXP0FB <= 2'b0; // read collision P0 PF P0 BL
|
| 311 |
|
|
CXP1FB <= 2'b0; // read collision P1 PF P1 BL
|
| 312 |
|
|
CXM0FB <= 2'b0; // read collision M0 PF M0 BL
|
| 313 |
|
|
CXM1FB <= 2'b0; // read collision M1 PF M1 BL
|
| 314 |
|
|
CXBLPF <= 2'b0; // read collision BL PF unused
|
| 315 |
|
|
CXPPMM <= 2'b0; // read collision P0 P1 M0 M1
|
| 316 |
217 |
creep |
end
|
| 317 |
215 |
creep |
default: begin
|
| 318 |
|
|
end
|
| 319 |
|
|
endcase
|
| 320 |
|
|
end
|
| 321 |
|
|
end
|
| 322 |
|
|
end
|
| 323 |
|
|
|
| 324 |
|
|
endmodule
|
| 325 |
|
|
|