📄 video.v
字号:
// FPGA PACMAN video hardware
//
// Version : beta2
//
// Copyright(c) 2002,2003 Tatsuyuki Satoh , All rights reserved
//
// Important !
//
// This program is freeware for non-commercial use.
// An author does no guarantee about this program.
// You can use this under your own risk.
//
// 2003. 2. 6 beta2 export Xilinx dependent BlockSelectRAMs
// remove object timing patch.
// fix cpu I/F timing
// 2003. 2. 7 beta2 minimize
//
//
// Signal Assign of Video Memory
//
// 1.tilemap code RAM
//
// Area : 4000-43ff
// Size : 8bit x 1024word
// RD Timng: ??? (2H, 333ns-@)
// WR Timng: ??? (2H, 333ns-@)
// Address : AB[9:0]
// Dout : DB_I
// Din : (DI)
// CS : TRAM_CS
// WE : TRAM_WE
// OE : ~TRAM_WE
//
//
// 2.tilemap color RAM
//
// parts :
// Area : 4400-47ff
// Size : 8bit x 1024word
// RD Timng: ??? (2H, 333ns-@)
// WR Timng: ??? (2H, 333ns-@)
// Address : AB[9:0]
// Dout : DB_I
// Din : (DI)
// CS : CRAM_CS
// WE : CRAM_WE
// OE : ~CRAM_WE
//
//
// 3.work & object RAM
//
// parts : 4R,4M
// Area : 4c00-4fff
// Size : 8bit x 1024word
// RD Timng: ??? (2H, 333ns-@)
// WR Timng: ??? (2H, 333ns-@)
// Address : AB[9:0]
// Dout : DB_I
// Din : (DI)
// CS : WRAM_CS
// WE : WRAM_WE
// OE : ~WRAM_WE
//
//
// 4.object position RAM
//
// parts : 3F,3E
// Area : 5060-506f
// Size : 8bit x 16word
// RD Timng: 2H fall -> 2H raise , 333ns-@
// WR Timng: ??? (2H fall -> 2H raise ? , 333ns-@)
// Address : AB[3:0]
// Dout : PRAM_DI
// Din : PRAM_DO (inverted di)
// CS : always select
// WE : PRAM_WE
// OE : ~PRAM_WE
//
// 5.object line RAM
//
// parts : (1A,1B,1C,1D) or (2A,2B,2B,2D)
// Area : none
// Size : 4bit x 256word
// RD Timng: pclk.up to pclk.dn , 166ns
// WR Timng: pclk.dn to pclk.up , 166ns
// Address : LRAM_A
// Dout : LRAM_DI
// Din : LRAM_DO
// CS&OE : LRAM_CS
// WE : LRAM_WE(~pclk)
//
//
// 6.color lockup table ROM
//
// parts : 4A
// Area : none
// Size : 4bit x 256word
// RD Timng: non-buffer,GATED ROM
// Address : CLUT_A
// Din : CLUT_D
// CS&OE : always on
//
// 7.palette ROM
//
// parts : 7F
// Area : none
// Size : 8bit x 32word
// RD Timng: non-buffer,GATED ROM
// Address : PAL_A
// Din : n.c. (output are {B220,B470,G220,G470,G1K,R220,R470,R1K})
// CS&OE : always on
//
// 8.object pattern ROM : async 8192 x 8bit
//
// parts : 5E,5H,5F,5J
// Area : none
// Size : 8bit x 8192word
// RD Timng: 2H.up -> 2H.up (666ns-@)
// Address : CA
// Din : CD
// other : CA_as,CA_en
//
module video(
// CPU interface
A,di,vdo,n_rd,WAIT_N,
// decoder input
csvram, //chip select video RAM 4000-4fff,c000-cfff
csxyram, //chip select object XY RAM 5060-506f
// VIDEO input
pclk,flip,
// VIDEO output
hc,vb,hs,vs,
// pattern ROM address & data
CA,CD,CA_as,CA_en,
// TILE,COLOR,WORK RAM
AB,DB_I,
TRAM_WE,TRAM_CS,
CRAM_WE,CRAM_CS,
WRAM_WE,WRAM_CS,
// object Line RAM
LRAM_A, LRAM_DO , LRAM_DI , LRAM_CS , LRAM_WE,
// Object Position RAM
PRAM_DO,PRAM_DI,PRAM_WE,
// ColorLookupTable ROM
CLUT_A,CLUT_DI,
// PaletteROM
PAL_A
);
// CPU interface
input [11:0] A;
input [7:0] di;
output [7:0] vdo;
input WAIT_N;
input n_rd;
// decoder input
input csvram,csxyram;
// VIDEO input
input pclk; // 6.144MHz video clock
input flip; // screen flip register
// VIDEO output
output [8:0] hc;// H-counter
output vb; // V-BLANK
output hs; // H-SYNC
output vs; // V-SYNC
output [12:0] CA;
input [7:0] CD;
output CA_as,CA_en;
output [11:0] AB; // shared address , CPU & VIDEO & sound timming
input [7:0] DB_I; // shared data-in , (DB_O == di)
output TRAM_WE,TRAM_CS; // TileCode RAM
output CRAM_WE,CRAM_CS; // TileColor RAM
output WRAM_WE,WRAM_CS; // Work&Object RAM
// object Line RAM
output [7:0] LRAM_A; // Address
output [3:0] LRAM_DO; // DataOut
input [3:0] LRAM_DI; // DataIn
output LRAM_CS;
output LRAM_WE;
// object position RAM
output [7:0] PRAM_DO;
input [7:0] PRAM_DI;
output PRAM_WE;
// ColorLookupTable ROM
output [7:0] CLUT_A;
input [3:0] CLUT_DI;
// PaletteROM
output [3:0] PAL_A;
//
// H timming generator
//
// counter = 0-255,384-511
// hblank = 400(0x190)-495(0x1ef)
// hsync = 416(0x1a0)-447(0x1bf)
//
reg [8:0] hcnt;
reg hblank,hsync;
always @(posedge pclk)
begin
//hblank
if( hcnt == 399)
hblank <= 1;
if(hcnt[6:0] == 7'h6f)
hblank <= 0;
//hsync
if( hblank && hcnt[6:0] == 7'h20)
hsync <= 1;
if(hcnt[4:0] == 5'h1f)
hsync <= 0;
//H counter
hcnt <= (hcnt==255) ? 384 : hcnt + 1;
end
//
// V timming generator
//
// counter = 0-255,504-511
// vblank = 240(0x0f0)-255(0x0ff)-504(0x1f8)-511(0x1fe)-015(0x0f)
// vsync = 504-511
//
reg [8:0] vcnt;
reg vblank;
wire vsync;
always @(posedge hsync)
begin
// V blank
if(vcnt==239)
vblank <= 1;
if( vcnt[5:0] == 6'h0f)
vblank <= 0;
// V counter
vcnt <= (vcnt==255) ? 504 : vcnt+1;
end
assign vsync = vcnt[8]; //504-511
//
// output timming signal
//
assign hc = hcnt;
assign vb = vblank;
assign hs = hsync;
assign vs = vsync;
//
// AB[11:0] multiplexed address bus
//
// +---------------+----+----+-----+-----+----+----+----+-----+----+----+----+----+
// | output |AB11|AB10| AB9 | AB8 |AB7 |AB6 |AB5 | AB4 |AB3 |AB2 |AB1 |AB0 |
// +---------------+----+----+-----+-----+----+----+----+-----+----+----+----+----+
// |CPU Address | A11| A10| A9 | A8 | A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |2H=0
// |object Address | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |64H |32H |16H | 4H |2H=1,HC=400-495
// |Left&Right tile| 0 | 4H | 64Hp| 64Hp|64Hp|64Hp| 8Hp|128Vp|64Vp|32Vp|16Vp| 8Vp|2H=1,HC=384-399,496-511
// |Center tile | 0 | 4H |128Vp|128Vp|32Vp|16Vp| 8Vp|128Hp|64Hp|32Hp|16Hp| 8Hp|2H=1,HC=0-255
// +---------------+----+----+-----+-----+----+----+----+-----+----+----+----+----+
//
// parts 5S
//
// flipped address
wire [7:3] hcp = hcnt[7:3] ^ { flip,flip,flip,flip,flip };
wire [7:3] vcp = vcnt[7:3] ^ { flip,flip,flip,flip,flip };
// address bus
wire [11:0] ab_obj = { 8'b11111111,hcnt[6:4],hcnt[2]}; // object draw
wire [11:0] ab_lr = { 1'b0,hcnt[2],hcp[6],hcp[6],hcp[6],hcp[6],hcp[3],vcp[7:3] }; // L&R tile
wire [11:0] ab_ctr = { 1'b0,hcnt[2],vcp[7:3],hcp[7:3] }; // center tile
// multiplex
wire [11:0] AB_tile = (hcnt[8]) ? ab_lr : ab_ctr; // L,R / center
wire [11:0] AB_video = (hblank ) ? ab_obj : AB_tile;// object / tile
//
// Shared Address Bus
//
assign AB = (hcnt[1]) ? AB_video : A[11:0];// video / CPU
//
// CPU write enable
//
wire vram_we = csvram & n_rd & (~hcnt[1]);
wire yx_we = csxyram & n_rd & (~hcnt[1]);
//
//
// VRAM Address decoder
//
//
wire cs_code = AB[11:10]==2'b00; // 4000-43ff , tile code RAM
wire cs_col = AB[11:10]==2'b01; // 4400-47ff , tile color RAM
wire cs_obj = AB[11:10]==2'b11; // 4c00-4fff , work / object RAM
wire code_we = cs_code & vram_we;
wire col_we = cs_col & vram_we;
wire obj_we = cs_obj & vram_we;
wire [7:0] DR; // output DATA from object XY RAM
wire yxram_ce = hblank | ~hcnt[1]; // chip enable to object XY RAM
//
// DB_I[7:0] : shared data bus in
//
// parts 6S
//
// data output for cpu
reg [7:0] cpu_do;
always @(posedge pclk)
begin
if( hcnt[1:0] == 2'b01) // (2H raise)
begin
cpu_do <= DB_I;
end
end
//assign vdo = ~WAIT_N ? cpu_do : 8'h00;
assign vdo = (csvram & ~n_rd) ? cpu_do : 8'h00;
//
// object V match & offset ,or tile V pos
//
// parts 1F,2F,3E,4D,1H,2H,4E,5L,5H,4F
//
reg [7:0] tile_code; // latch of tile code / object code,flipV,flipH
reg match; // object Y position match
reg [3:0] cv; // V address low
reg obj_sel; // 4H delayed HBLANK == tile / object selector
// object V+Y or tile V pos
wire [7:0] cv_add = vcnt[7:0]+(yxram_ce ? DR : 8'h00);
always @(posedge pclk)
begin
if( hcnt[2:0] == 3'b011) // (4H raise)
begin
// latch tile code / object code+flip data from RAM
tile_code <= DB_I;
// latch Y position , match & delayed hblank
cv <= cv_add[3:0];
// latch object V match flag
match <= (cv_add[7:4] == 4'b1111);
// latch hblank for object selector
obj_sel <= hblank;
end
end
//
// pixel data ROM address geneator
//
wire flipv = obj_sel ? tile_code[1] : flip; // V flip : object / tile
wire fliph = obj_sel ? tile_code[0] : flip; // H flip : object / tile
//
assign CA[12] = obj_sel;
assign CA[11:6] = tile_code[7:2]; // object code / tile code[7:2]
assign CA[5] = obj_sel ? cv[3]^flipv : tile_code[1]; // object 8V / tile code[1]
assign CA[4] = obj_sel ? hcnt[3] : tile_code[0]; // object 8H / tile code[0]
assign CA[3] = hcnt[2] ^ fliph; // 4H byte select
assign CA[2:0] = cv[2:0] ^ { flipv,flipv,flipv}; // 4V,2V,1V
assign CA_as = hcnt[1:0] == 2'b00; // CA assert timming
assign CA_en = hcnt[1:0] == 2'b10; // CD latch timming
//
// object LRAM access enable signal , latch color data from RAM
//
// parts 3P,2P,4B,
//
reg obj_on; // LRAM access enable
reg hblank8; // display enable
reg [4:0] clut_sel; // Color Lookup Page Select from color RAM
reg fliph8;
always @(posedge pclk)
begin
if(hcnt[2:0] == 3'b111) // 1H==2H==4H==1
begin
// delayed HBLANK == display outout enable
hblank8 <= hblank;
// object line RAM enable
obj_on <= match | ~hcnt[8];
// latch color RAM & H-flip for pixel generator
clut_sel <= DB_I[4:0];
fliph8 <= fliph;
end
end
//
// object line RAM address generator
//
// parts 4C,1E,2E
//
// load enable for reset tile Hpos or object Hpos
wire cntr_ld = (~obj_on | hblank8) & (hcnt[3:0] == 4'b0111);
reg [7:0] RA_I;
always @(posedge pclk)
begin
if( cntr_ld )
begin
// H pos add + latch
RA_I <= yxram_ce ? DR : 255;
end else begin
// H pos countup
RA_I <= RA_I + 1;
end
end
//
//pixel data -> 2bpp pixel selector
//
// parts 5B,5C,5H,5A
//
reg [7:0] pixel_byte;
always @(posedge pclk)
begin
if( hcnt[1:0] == 2'b11 )
begin
pixel_byte <= CD;
end else begin
if( fliph8 )
begin // flip , right shift
pixel_byte[6:4] <= pixel_byte[7:5];
pixel_byte[2:0] <= pixel_byte[3:1];
end else begin // noflip , left shift
pixel_byte[7:5] <= pixel_byte[6:4];
pixel_byte[3:1] <= pixel_byte[2:0];
end
end
end
// 2bpp pixel data
wire [1:0] pixel = fliph8 ?
{ pixel_byte[4],pixel_byte[0] } : // flip
{ pixel_byte[7],pixel_byte[3] } ; // no flip
//
// Color Lookup Table ROM
//
wire clut_bank = 0; // ColorBack , solder-selecter 0,1 or hblank8
wire [3:0] clut_d; // data
wire [3:0] pal_code; // palette code from pixel data
reg [3:0] pal_obj; // palette code of object LRAM
//
// priority selector
//
// parts 3A,3B,3E
//
assign pal_code = (pal_obj==4'b0000) ? clut_d : pal_obj;
//
// object LRAM (line ram)
//
wire [3:0] lram_wd = (hblank8 & ~vblank) ? pal_code : 4'b0000;
assign LRAM_A = RA_I;
assign LRAM_DO = lram_wd;
assign LRAM_CS = obj_on;
assign LRAM_WE = ~pclk;
// part (3C or 3D) , lineRAM output latch
always @(negedge pclk)
begin
pal_obj <= obj_on ? LRAM_DI : 4'b0000;
end
//
// Palette Lookup Table
//
wire [3:0] pal_ad = (hblank8 | vblank) ? 4'h0 : pal_code;
//wire [7:0] pal_do; // data output from PaletteRAM
//assign { b,g,r } = pal_do; // RGB output
//
// VIDEO Memory controll
//
// tile code RAM ,4000-43ff : 8bit x 1024word
assign TRAM_WE = code_we;
assign TRAM_CS = cs_code;
// tile color RAM ,4400-47ff : 8bit x 1024word
assign CRAM_WE = col_we;
assign CRAM_CS = cs_col;
// work , object code,flip & color ram , 4c00-4fff : 8bit x 1024word
assign WRAM_WE = obj_we;
assign WRAM_CS = cs_obj;
// object YX RAM , 5060-506f : 8bit x 16word
assign PRAM_DO = ~di;
assign DR = PRAM_DI;
assign PRAM_WE = yx_we;
// ColorLookupTable ROM
assign CLUT_A = {clut_bank,clut_sel,pixel};
assign clut_d = CLUT_DI;
// PaletteROM
assign PAL_A = pal_ad;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -