// ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014
//
// address generation module for video data fetching

/*
    This file is part of ZX-Evo Base Configuration firmware.

    ZX-Evo Base Configuration firmware is free software:
    you can redistribute it and/or modify it under the terms of
    the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ZX-Evo Base Configuration firmware is distributed in the hope that
    it will be useful, but WITHOUT ANY WARRANTY; without even
    the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZX-Evo Base Configuration firmware.
    If not, see <http://www.gnu.org/licenses/>.
*/

`include "../include/tune.v"

module video_addrgen(

	input  wire        clk, // 28 MHz clock


	output reg  [20:0] video_addr, // DRAM arbiter signals
	input  wire        video_next, //


	input  wire        line_start, // some video sync signals
	input  wire        int_start,  //
	input  wire        vpix,       //

	input  wire        scr_page, // which screen to use


	input  wire        mode_atm_n_pent, // decoded modes
	input  wire        mode_zx,         //
	input  wire        mode_p_16c,      //
	input  wire        mode_p_hmclr,    //
	                                    //
	input  wire        mode_a_hmclr,    //
	input  wire        mode_a_16c,      //
	input  wire        mode_a_text,     //
	input  wire        mode_a_txt_1page,//

	output wire [ 2:0] typos // Y position in text mode symbols
);

	wire mode_ag;

	assign mode_ag = mode_a_16c | mode_a_hmclr;



	wire line_init, frame_init;

	wire gnext,tnext,ldaddr;

	reg line_start_r;
	reg frame_init_r;
	reg line_init_r;

	always @(posedge clk)
		line_start_r <= line_start;

	assign line_init  = line_start_r & vpix;
	assign frame_init = int_start;

	reg [13:0] gctr;

	reg [7:0] tyctr; // text Y counter
	reg [6:0] txctr; // text X counter

	reg not_used;




	always @(posedge clk)
		frame_init_r <= frame_init;

	always @(posedge clk)
		line_init_r <= line_init;


	assign gnext = video_next | frame_init_r;
	assign tnext = video_next | line_init_r;
	assign ldaddr = mode_a_text ? tnext : gnext;

	// gfx counter
	//
	initial gctr <= 0;
	//
	always @(posedge clk)
	if( frame_init )
		gctr <= 0;
	else if( gnext )
		gctr <= gctr + 1;


	// text counters
	always @(posedge clk)
	if( frame_init )
		tyctr <= 8'b0011_0111;
	else if( line_init )
		tyctr <= tyctr + 1;

	always @(posedge clk)
	if( line_init )
		txctr <= 7'b000_0000;
	else if( tnext )
		txctr <= txctr + 1;


	assign typos = tyctr[2:0];


// zx mode:
// [0] - attr or pix
// [4:1] - horiz pos 0..15 (words)
// [12:5] - vert pos

	wire [20:0] addr_zx;   // standard zx mode
	wire [20:0] addr_phm;  // pentagon hardware multicolor
	wire [20:0] addr_p16c; // pentagon 16c

	wire [20:0] addr_ag; // atm gfx: 16c (x320) or hard multicolor (x640) - same sequence!

	wire [20:0] addr_at; // atm text

	wire [11:0] addr_zx_pix;
	wire [11:0] addr_zx_attr;
	wire [11:0] addr_zx_p16c;


	assign addr_zx_pix  = { gctr[12:11], gctr[7:5], gctr[10:8], gctr[4:1] };

	assign addr_zx_attr = { 3'b110, gctr[12:8], gctr[4:1] };

	assign addr_zx_p16c = { gctr[13:12], gctr[8:6], gctr[11:9], gctr[5:2] };


	assign addr_zx =   { 6'b000001, scr_page, 2'b10, ( gctr[0] ? addr_zx_attr : addr_zx_pix ) };

	assign addr_phm =  { 6'b000001, scr_page, 1'b1, gctr[0], addr_zx_pix };

	assign addr_p16c = { 6'b000001, scr_page, ~gctr[0], gctr[1], addr_zx_p16c };


	assign addr_ag = { 5'b00000, ~gctr[0], scr_page, 1'b1, gctr[1], gctr[13:2] };

	//                           5 or 1     +0 or +2  ~4,0  +0k or +2k
//	assign addr_at = { 5'b00000, ~txctr[0], scr_page, 1'b1, txctr[1], 2'b00, tyctr[7:3], txctr[6:2] };
//	assign addt_et = { 5'b00001,  1'b0    , scr_page, 1'b0, txctr[0], txctr[1], 0, --//00           };

	assign addr_at = { 4'b0000,
	                   mode_a_txt_1page, // if 1page, 8 and 10 pages instead of 5,1 and 7,3
	                   mode_a_txt_1page ? 1'b0 : ~txctr[0], // 5 or 1 pages for usual mode
	                   scr_page,         // actually not used
	                   ~mode_a_txt_1page, // 5,1 (not 4,0) pages for usual mode
	                   mode_a_txt_1page ? txctr[0] : txctr[1], // 0,+2 interleave for even-odd or 0,+1 for 1page
	                   mode_a_txt_1page ? txctr[1] : 1'b0, // sym/attr interleave 0,+1 for 1page
	                   1'b0,
	                   tyctr[7:3],
	                   txctr[6:2]
	                   };











	initial video_addr <= 0;
	//
	always @(posedge clk) if( ldaddr )
	begin
		{ video_addr[20:15], not_used, video_addr[13:0] } <=
			( {21{mode_zx     }} & addr_zx  )  |
			( {21{mode_p_16c  }} & addr_p16c)  |
			( {21{mode_p_hmclr}} & addr_phm )  |
			( {21{mode_ag     }} & addr_ag  )  |
			( {21{mode_a_text }} & addr_at  )  ;
	end

	always @(posedge clk)
		video_addr[14] <= scr_page;



endmodule

