`include "../include/tune.v"
// PentEvo project (c) NedoPC 2008-2009
//
// fetches and outs video data
//
// currently only 256x192 standard zx and p16c modes supported
//
//
module fetch(
input clk,
input cend,
input line_start,
input vpix, // hpix not needed! fetch.v has its own count from line_start to the hpix window opening
input int_start, // used as initializer for counters
input [1:0] vmode, // 2'b00 - standard ZX, 2'b01 - hardware multicolor, 2'b1x - p16c
input screen, // screen 0 (pg5) or screen 1 (pg7)
// controlling data fetch (go to dram/arbiter.v)
output reg [20:0] video_addr,
input [15:0] video_data,
input video_strobe,
input video_next,
output [1:0] bw,
output reg go,
output [7:0] attr,
output [5:0] pixel
);
localparam START_FETCH = 6'd36;
// begin data fetching 16 cycles before actual start if hpix, (52-16)=36 cycles after line_start.
reg [15:0] fbuf [0:3]; // reading memory data
reg [7:0] shift [0:7]; // shifting out pixel data
reg [7:0] vcnt; // vertical line counter (0-191)
reg [3:0] hcnt; // horizontal word counter (0-15)
reg [1:0] dcnt; // displacement or pix/attr counter
reg [1:0] ddcnt; // dcnt saved for data reception
reg [5:0] scnt; // start-fetch counter
wire wordsync; // synchronize words output: every 16th dram cycle
reg [3:0] wcnt; // word (16 cycles) counter
reg [4:0] fcnt; // fetches counter; counts from 0 to 16 as each 16cycles passes, at the end stops fetching by issuing go_end
wire go_start,go_end;
reg [3:0] pixnumber; // pixel number; 0 - leftmost, 15 - rightmost
wire flash;
reg [4:0] flashctr;
reg [3:0] zxcolor;
assign attr = attrbyte;
initial
begin
go = 1'b0;
vcnt = 8'd0;
hcnt = 4'd0;
dcnt = 2'd0;
ddcnt = 2'd0;
scnt = 6'd0;
wcnt = 4'd0;
fcnt = 5'd0;
pixnumber = 4'd0;
flashctr = 5'd0;
end
// flash generator
always @(posedge clk) if( int_start )
begin
flashctr <= flashctr + 5'd1;
end
assign flash = flashctr[4];
// fetchmode generator
assign bw = vmode[1] ? 2'b01 : 2'b00;
// vertical counter
always @(posedge clk)
begin
if( int_start )
vcnt <= 8'hFF;
else if( line_start && vpix ) // line-start will also happen in the first pixel line, so we initialize counter with 0xFF
vcnt <= vcnt + 8'h01;
end
// start-fetch counter
always @(posedge clk) if( cend )
begin
if( line_start && vpix )
scnt <= (START_FETCH - 6'd2);
else if( scnt!=6'd0)
scnt <= scnt - 6'd1;
end
assign go_start = (scnt==6'd1) & cend; // start go signal 1 cycle before actual data will begin to fetch
//wordsync generation and synchronizing
always @(posedge clk) if( cend )
begin
if( go_start )
wcnt <= 4'd0;
else
wcnt <= wcnt + 4'd1;
end
assign wordsync = (wcnt==4'd1) & cend;
// fetch counter
always @(posedge clk)
begin
if( go_start )
fcnt <= 5'd0;
else if( wordsync && (~fcnt[4]) )
fcnt <= fcnt + 5'd1;
end
assign go_end = fcnt[4] & (wcnt==4'd15) & cend;
// go
always @(posedge clk)
if( go_start )
go <= 1'b1;
else if( go_end )
go <= 1'b0;
// horizontal address counters: init and increment
always @(posedge clk)
begin
if( line_start ) // initialize counters
begin
hcnt <= 4'd0;
dcnt <= 2'd0;
end
else if( video_next )
begin
ddcnt <= dcnt;
dcnt <= dcnt + 2'd1;
if( !vmode[1] ) // normal ZX standard
begin
if( dcnt[0] )
hcnt <= hcnt + 4'd1;
end
else // vmode[1] - p16c mode
begin
if( dcnt==2'd3 )
hcnt <= hcnt + 4'd1;
end
end
end
// store fetched data
always @(posedge clk) if( video_strobe )
begin
if( !vmode[1] ) // ZX mode
fbuf[{1'b0,ddcnt[0]}] <= video_data;
else // p16c mode
fbuf[ddcnt[1:0]] <= video_data;
end
// sequence video addresses
always @*
begin
video_addr[20:14] = { 6'b000001,screen }; // common part of address
if( !vmode[1] ) // ZX mode
begin
if( !dcnt[0] ) // pixel addr
video_addr[13:0] = { 2'b10, vcnt[7:6], vcnt[2:0], vcnt[5:3], hcnt[3:0] };
else // attr addr
begin
if( !vmode[0] ) // normal ZX
video_addr[13:0] = { 5'b10110, vcnt[7:3], hcnt[3:0] };
else // hardware multicolor
video_addr[13:0] = { 2'b11, vcnt[7:6], vcnt[2:0], vcnt[5:3], hcnt[3:0] };
end
end
else // p16c mode
begin
video_addr[13:0] = { dcnt[0], dcnt[1], vcnt[7:6], vcnt[2:0], vcnt[5:3], hcnt[3:0] };
end
end
// pass read data to pixel engine
always @(posedge clk) if( wordsync )
begin
shift[0] <= fbuf[0][15:8];
shift[1] <= fbuf[0][7:0];
shift[2] <= fbuf[1][15:8];
shift[3] <= fbuf[1][7:0];
shift[4] <= fbuf[2][15:8];
shift[5] <= fbuf[2][7:0];
shift[6] <= fbuf[3][15:8];
shift[7] <= fbuf[3][7:0];
end
// count pixels to be out
always @(posedge clk) if( cend )
if( wordsync )
pixnumber <= 4'd0;
else
pixnumber <= pixnumber + 4'd1;
// out pixels
reg [7:0] pixbyte,attrbyte;
reg [3:0] pix0,pix1;
always @*
begin
attrbyte = shift[ { 2'b01, pixnumber[3] } ][7:0];
pix0 = { attrbyte[6],attrbyte[5:3] };
pix1 = { attrbyte[6],attrbyte[2:0] };
if( !vmode[1] ) // ZX mode
begin
// attribute is taken
// pixels
pixbyte = shift[ { 2'b00, pixnumber[3] } ][7:0];
zxcolor = ( pixbyte[(~pixnumber[2:0])] ^ (flash & attrbyte[7]) ) ? pix1 : pix0;
end
else // p16c mode
begin
pixbyte = shift[ { pixnumber[2:1], pixnumber[3] } ][7:0];
zxcolor = pixnumber[0] ? { pixbyte[7],pixbyte[5:3] } : { pixbyte[6],pixbyte[2:0] };
end
end
// red
assign pixel[5:4] = zxcolor[1] ? ( zxcolor[3] ? 2'b11 : 2'b10 ) : 2'b00;
// green
assign pixel[3:2] = zxcolor[2] ? ( zxcolor[3] ? 2'b11 : 2'b10 ) : 2'b00;
// blue
assign pixel[1:0] = zxcolor[0] ? ( zxcolor[3] ? 2'b11 : 2'b10 ) : 2'b00;
endmodule