

module apple_vid1(sysclk, CLOCK_50,clk32, reset_in, kbd_clk, kbd_dat, 
		  v_ad, ram_dat, mem_ce, mem_rw,
		  vga_h_sync, vga_v_sync,
		  vga_R, vga_G, vga_B,
		  serioclk, ces, BusCycle, kbd_is_available, SW, card_status
		  );

   input CLOCK_50, clk32, sysclk, reset_in, kbd_clk, kbd_dat;
   output vga_h_sync, vga_v_sync;
   output [3:0] vga_R;
   output [3:0] vga_G;
   output [3:0] vga_B;
   output 	mem_ce,mem_rw,serioclk;
   output [3:0] ces;
   output [2:0] card_status; // LEDs for ramcard
   inout [7:0] 	ram_dat;
	input	[9:0]	SW;

   output [16:0] v_ad;

   output kbd_is_available;

	
   wire [16:0] 	 v_ad;
   wire 	 inDisplayArea, rw;
   reg [6:0] 	 CounterX = 0;
   reg [9:0] 	 CounterY = 0;
   reg 		 vga_HS, vga_VS;
   reg 		 R,G,B;
   reg 		 ram_we = 1'b1;

   reg [6:0] 	 shiftreg;
   reg [1:0] 	 colorbits;
   reg 		 high_bit;
   reg 		 BLANK,BLANK1;
   output [4:0]  BusCycle;
   reg [4:0] 	 BusCycle = 0;

     //wire [7:0] ram_dat;
   reg  [7:0] 	 char_code;
   wire [3:0] 	 addr_sum;
   reg 			 PAGE2;
   wire [15:0] 	 final_ram_addr;
   wire [7:0] 	 kbd_data;

   wire [7:0] 	 di, do;
   wire [15:0] 	 cpu_addr;
   wire 	 cpu_access_time;
   wire 	 memory_access_time;
   wire kbd_access;

   reg 		 cpu_write_cycle;
	reg [4:0]   flash_count;
	wire cpu_drives_address;
		 
   
 //  assign 	 memory_access_time = ShiftCounter[0] ^ ShiftCounter[1] ;

   assign 	 memory_access_time = (BusCycle == 1) || (BusCycle == 2) ||
		 (BusCycle == 15) || (BusCycle == 16) || (BusCycle == 7);
   
	 
   assign 	 cpu_access_time =  (BusCycle == 7) || (BusCycle == 8);
	assign   cpu_drives_address = (BusCycle == 7) || (BusCycle == 8) ||(BusCycle == 6) || (BusCycle == 5);
   
   assign 	 mem_ce = ~memory_access_time;
   assign 	 mem_rw = ~((BusCycle == 7) && cpu_write_cycle);
   
   assign 	 kbd_is_available = kbd_available;

   wire 	 LDPS;
   assign 	 LDPS =
	 (BusCycle == 3) || (BusCycle == 17); // 
//	ShiftCounter[2] & ShiftCounter[1];

   assign 	 addr_sum = {~CounterX[5],~CounterX[5],CounterX[4],CounterX[3]} + 
		 {CounterY[8],CounterY[7],CounterY[8],CounterY[7]} + 1;


   assign 	 vga_R = BLANK1 ? 4'h0 : (GR && ~HIRES) ? lowres_color_val[11:8] : {R,R,R,R};
   assign 	 vga_G = BLANK1 ? 4'h0 : (GR && ~HIRES) ? lowres_color_val[7:4] : {G,G,G,G};
   assign 	 vga_B = BLANK1 ? 4'h0 : (GR && ~HIRES) ? lowres_color_val[3:0] : {B,B,B,B};

   assign 	 vga_h_sync = SW[3]? ~resampled_vsync  : ~vga_HS;
   assign 	 vga_v_sync = ~vga_VS;

//   assign char_code = {addr_sum ,CounterX[2:0]};

   assign 	 ram_dat = (cpu_access_time && ~rw) ? do : 8'hz;

	reg inverse;
	reg flash;
	
   wire [6:0] 	 high_vid_addr;
   assign 	 high_vid_addr = (HIRES & GR) ? {2'b00, PAGE2, ~PAGE2, CounterY[3:1]} : 
		 {5'b00000, PAGE2, ~PAGE2}	;
   assign 	 v_ad = //~cpu_access_time ? //
			// ShiftCounter[2] ? 
			~cpu_drives_address ? 
		 {high_vid_addr, CounterY[6:4], addr_sum ,CounterX[2:0]} :
		 // ShiftCounter[2] high during the last 3 states out of 7
		final_ram_addr; // cpu_addr;
   //	  final_ram_addr; // fist 4 states of shifter	 


   //assign ram_dat[4:0] = BusCycle;

   wire 	 HBL, VBL;
   wire 	 odd;
   assign 	 odd = BusCycle[0];
   reg [2:0] 	 ShiftCounter;
   wire [7:0] 	 video_data;
   reg [7:0] 	 video_shift_data;
	//wire AltCharSet = SW[4];
	reg AltCharSet;
   
   always @(posedge clk32) begin
	
	if(GR)			// no need to check HIRES: we don't shift lowres at all
	     video_shift_data <= ram_dat;
	else
	     video_shift_data <= video_data;
	 
	if(LDPS) begin	
	 low_color_nibble <= CounterY[3]? ram_dat[7:4] : ram_dat[3:0];
   	 char_code <= ram_dat;
	 flash  <= AltCharSet ? 0 : (char_code[6] & ~char_code[7]);
	 BLANK1 <= BLANK;
	 inverse <=  ~char_code[7]; //	: ~(char_code[7] | (char_code[6] & char_code[7]));
	end
	end



wire [6:0] final_char_code = AltCharSet ? char_code : { (char_code[6] & char_code[7]), char_code[5:0]} ;

reg [3:0] low_color_nibble;
wire [11:0] lowres_color_val;


wire GR;

assign GR = ~(TEXT || ( MIXED &&  CounterY[6] && CounterY[8]));


lores_color_map lores_color_map ( 
	.nibble(low_color_nibble), 
	.RGB_val(lowres_color_val)
	);

`ifdef ROM2K
CharROM2k	CharROM2k_inst (
	.address ( {1'b0, char_code, CounterY[3:1] }),
	.clock ( clk32),
	.q ( video_data )
	);
`else
charrom_2esmall charrom_2esmall (
	.address( { final_char_code, CounterY[3:1] }),
	.clock( clk32),
	.q( video_data)
	);
`endif	   

   always @(posedge clk32) 
     begin
	//	if(reset_in)
	//	BusCycle <= 5'b0;
	//else 
	if (BusCycle == 27)
	  BusCycle <= 0;
	else
	  BusCycle <= BusCycle + 1;
     end

   always @(posedge clk32)
     if(BusCycle == 8)
       cpu_write_cycle <= (rw == 0);
 
   // 7 shift states divide 32 MHz
   always @(posedge clk32)
     if( odd ) begin
	if((ShiftCounter[2] & ShiftCounter[1]) | reset_in | (BusCycle == 3))
	  begin
	     ShiftCounter <= 3'b000;
	  end 
	else
	  ShiftCounter <= ShiftCounter+1;
     end
/*
   always @(posedge clk32) 
	if( odd ) begin
     if(BusCycle == 3) begin
	     ShiftCounter <= 3'b000;
	  end else
	  ShiftCounter <= ShiftCounter+1;
    end
*/
   always @(posedge clk32)
   // if(odd & (ShiftCounter == 0)) begin
	if(LDPS) begin
	BLANK <= (HBL | VBL);
	if(!CounterX[6]) begin
	   CounterX <= 7'b1000000;
	   VBL_delayed <= VBL;
	   if(CounterY == 10'b1111111111) begin
	     	CounterY <= 10'b0111110100;
			flash_count = flash_count +1;
	   end 	else
	     CounterY <= CounterY+1;
	   
	end else
	  CounterX <= CounterX + 1;
     end	

   assign HBL = ~CounterX[5] & (~CounterX[4] | ~CounterX[3]); // up to 011000
   assign VBL = (CounterY[8] & CounterY[7]); // as in real Apple

	reg VBL_delayed;
	wire apple_pixel_out = shiftreg[0] ^ ((inverse ^ flashing) && ~GR);
	wire flashing = flash ? flash_count[4] : 1'b0;
	

   always @(posedge clk32)    begin
		vga_HS <= (CounterX[6:2]==5'b10010); // change this value to move the display horizontally
		vga_VS <= (CounterY==10'b1111000000); // change this value to move the display vertically

		if(SW[2]) begin //debugging
			if(VBL_delayed) begin
			   R <= 0;
			   G <= 0;
			   B <= 0;		
			end else begin
				R <= pixel_out;
				G <= pixel_out;
				B <= pixel_out;
			end	
		end else begin
			if(BLANK1) begin
			   R <= 0;
			   G <= 0;
			   B <= 0;		
			end else begin
				R <= apple_pixel_out;
				G <= apple_pixel_out;
				B <= apple_pixel_out;		
			end
		 end	
	end

   always @(posedge clk32)
    if( odd ) begin 
		if (LDPS) begin 
//	if((BusCycle == 1) || (BusCycle == 15)) begin
	   		shiftreg <= video_shift_data[6:0];
	   		high_bit <= video_shift_data[7];
		end  else begin
	//if( odd ) begin
	 		shiftreg <= {1'b0,shiftreg[6:1]};
		end
   end


///// VGA compatibility

wire pixel_out;
reg resampled_vsync;
reg VGA_clk;

linebuff linebuff (
	.data(apple_pixel_out),
	.rdaddress({~CounterY[0], VGA_pixel_count}),
	.rdclock(CLOCK_50),
	.wraddress({CounterY[0],Apple_pixel_count}),
	.wrclock(clk32),
	.wren(~BLANK1),
	.q(pixel_out));

reg [9:0] VGA_pixel_count;
reg [9:0] Apple_pixel_count;

wire AppleLineStart = (CounterX[6:0] == 7'b1011000);
wire VGALineStart =   (CounterX[6:0] == 7'b1010100);

always @ (posedge CLOCK_50) begin
	resampled_vsync <= vga_HS;
	
	if(VGALineStart ) begin
		VGA_pixel_count <= 0;
		VGA_clk <= 0;
	end	else begin		
		if(	VGA_clk )
			VGA_pixel_count <= VGA_pixel_count +1; 
		VGA_clk = ~VGA_clk;
	end	
end

 always @(posedge clk32)
	if(AppleLineStart)
		Apple_pixel_count <= 0;
	else 
		Apple_pixel_count <=  Apple_pixel_count + 1;


   /////////////////////////////////////////////////// end of video part ************************************

assign card_status = {card_ram_we, card_ram_rd, bank1};

	ramcard ramcard (
    .mclk28(clk32), 
    .reset_in(reset_in), 
    .strobe(BusCycle == 7), 
    .addr(cpu_addr), 
    .ram_addr(final_ram_addr), 
    .we(~rw), 
    .card_ram_we(card_ram_we), 
    .card_ram_rd(card_ram_rd), 
    .bank1(bank1)
    );


	wire 	 io_access = (cpu_addr[15:8] == 8'b11000000);
	reg TEXT,MIXED,HIRES, mode_80COL,mode_80STORE;
	reg RAMRD, RAMWRT, ALTZP;
	
	always @(posedge clk32) 
	 if(reset_in) begin
		PAGE2 <= 0;
		HIRES <= 0;
		AltCharSet <= 0;
		mode_80COL <= 0;
	 end else begin
	
		if((BusCycle == 7) && io_access)begin
		  if(cpu_write_cycle) begin			// writes that switch
			case(cpu_addr[7:0])
				8'h00: mode_80STORE <= 0;
				8'h01: mode_80STORE <= 1;
				8'h02: RAMRD <= 0;
				8'h03: RAMRD <= 1;				
				8'h04: RAMWRT <= 0;
				8'h05: RAMWRT <= 1;				
				8'h08: ALTZP <= 0;
				8'h09: ALTZP <= 1;				

				8'h0C: 	mode_80COL <= 0;
				8'h0D:	mode_80COL <= 1;
				
				8'h0E: 	AltCharSet <= 0;
				8'h0F:	AltCharSet <= 1;

			endcase
		  end else begin			// reads that switch
		
		  case(cpu_addr[7:0])
			8'h50:		TEXT <= 0;
			8'h51:		TEXT <= 1;

			8'h52:		MIXED <= 0;
			8'h53:		MIXED <= 1;

			8'h54:		PAGE2 <= 0;
			8'h55:		PAGE2 <= 1;

			8'h56:		HIRES <= 0;
			8'h57:		HIRES <= 1;
		  endcase
		end
	  end
	end


//***************************** keyboard intface ********************
   wire [6:0] ascii;
   wire kbd_available;
	wire read_kbd;
   assign kbd_data = {kbd_available, ascii};
   assign kbd_access = (cpu_addr[15:4] == 12'hC00);
   assign read_kbd = (cpu_addr == 16'hC010);
   assign 	 di = kbd_access ? kbd_data : ram_dat;

   kbd_intf kbd_intf (
    .mclk25(clk32), 
    .reset_in(reset_in), 
    .PS2_Clk(kbd_clk), 
    .PS2_Data(kbd_dat), 
  //  .shift(shift), 
    .ascii(ascii), 
    .kbd_available(kbd_available), 
    .read_kb(read_kbd)
    );

 
   wire cpuclk = ( BusCycle == 8);
   reg 	nmi = 0;
   reg 	irq = 0;
   wire rdy = 1;
   

   bc6502 cpu0(.reset(reset_in), .clk(cpuclk), .nmi(nmi), .irq(irq),
		.rdy(rdy), .di(di), .do(do), .rw(rw), .ma(cpu_addr), .sync(sync) );



endmodule
 	
